Пример #1
0
/** Decodes an opened OggVorbis file into an OpenAL buffer
 *  \param psTrack pointer to object which will contain the final buffer
 *  \param PHYSFS_fileHandle file handle given by PhysicsFS to the opened file
 *  \return on success the psTrack pointer, otherwise it will be free'd and a NULL pointer is returned instead
 */
static inline TRACK* sound_DecodeOggVorbisTrack(TRACK *psTrack, PHYSFS_file* PHYSFS_fileHandle)
{
#ifndef WZ_NOSOUND
	ALenum		format;
	ALuint		buffer;
	struct OggVorbisDecoderState *decoder;
	soundDataBuffer	*soundBuffer;

	if ( !openal_initialized )
	{
		return NULL;
	}

	decoder = sound_CreateOggVorbisDecoder(PHYSFS_fileHandle, true);
	if (decoder == NULL)
	{
		debug(LOG_WARNING, "Failed to open audio file for decoding");
		free(psTrack);
		return NULL;
	}

	soundBuffer = sound_DecodeOggVorbis(decoder, 0);
	sound_DestroyOggVorbisDecoder(decoder);

	if (soundBuffer == NULL)
	{
		free(psTrack);
		return NULL;
	}

	if (soundBuffer->size == 0)
	{
		debug(LOG_WARNING, "sound_DecodeOggVorbisTrack: OggVorbis track is entirely empty after decoding");
// NOTE: I'm not entirely sure if a track that's empty after decoding should be
//       considered an error condition. Therefore I'll only error out on DEBUG
//       builds. (Returning NULL here __will__ result in a program termination.)
#ifdef DEBUG
		free(soundBuffer);
		free(psTrack);
		return NULL;
#endif
	}

	// Determine PCM data format
	format = (soundBuffer->channelCount == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;

	// Create an OpenAL buffer and fill it with the decoded data
	alGenBuffers(1, &buffer);
	sound_GetError();
	alBufferData(buffer, format, soundBuffer->data, soundBuffer->size, soundBuffer->frequency);
	sound_GetError();

	free(soundBuffer);

	// save buffer name in track
	psTrack->iBufferName = buffer;
#endif

	return psTrack;
}
Пример #2
0
/** Update the given stream by making sure its buffers remain full
 *  \param stream the stream to update
 *  \return true when the stream is still playing, false when it has stopped
 */
static bool sound_UpdateStream(AUDIO_STREAM *stream)
{
    ALint state, buffer_count;

    alGetSourcei(stream->source, AL_SOURCE_STATE, &state);
    sound_GetError();

    if (state != AL_PLAYING && state != AL_PAUSED)
    {
        return false;
    }

    // Retrieve the amount of buffers which were processed and need refilling
    alGetSourcei(stream->source, AL_BUFFERS_PROCESSED, &buffer_count);
    sound_GetError();

    // Refill and reattach all buffers
    for (; buffer_count != 0; --buffer_count)
    {
        soundDataBuffer *soundBuffer;
        ALuint buffer;

        // Retrieve the buffer to work on
        alSourceUnqueueBuffers(stream->source, 1, &buffer);
        sound_GetError();

        // Decode some data to stuff in our buffer
        soundBuffer = sound_DecodeOggVorbis(stream->decoder, stream->bufferSize);

        // If we actually decoded some data
        if (soundBuffer && soundBuffer->size > 0)
        {
            // Determine PCM data format
            ALenum format = (soundBuffer->channelCount == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;

            // Insert the data into the buffer
            alBufferData(buffer, format, soundBuffer->data, soundBuffer->size, soundBuffer->frequency);
            sound_GetError();

            // Reattach the buffer to the source
            alSourceQueueBuffers(stream->source, 1, &buffer);
            sound_GetError();
        }
        else
        {
            // If no data has been decoded we're probably at the end of our
            // stream. So cleanup this buffer.

            // Then remove OpenAL's buffer
            alDeleteBuffers(1, &buffer);
            sound_GetError();
        }

        // Now remove the data buffer itself
        free(soundBuffer);
    }

    return true;
}
Пример #3
0
/** Plays the audio data from the given file
 *  \param fileHandle,volume,onFinished,user_data see sound_PlayStream()
 *  \param streamBufferSize the size to use for the decoded audio buffers
 *  \param buffer_count the amount of audio buffers to use
 *  \see sound_PlayStream() for details about the rest of the function
 *       parameters and other details.
 */
AUDIO_STREAM *sound_PlayStreamWithBuf(PHYSFS_file *fileHandle, float volume, void (*onFinished)(void *), void *user_data, size_t streamBufferSize, unsigned int buffer_count)
{
    AUDIO_STREAM *stream;
    ALuint       *buffers = (ALuint *)alloca(sizeof(ALuint) * buffer_count);
    ALint error;
    unsigned int i;

    if (!openal_initialized)
    {
        debug(LOG_WARNING, "OpenAL isn't initialized, not creating an audio stream");
        return NULL;
    }

    stream = (AUDIO_STREAM *)malloc(sizeof(AUDIO_STREAM));
    if (stream == NULL)
    {
        debug(LOG_FATAL, "sound_PlayStream: Out of memory");
        abort();
        return NULL;
    }

    // Clear error codes
    alGetError();

    // Retrieve an OpenAL sound source
    alGenSources(1, &(stream->source));

    error = sound_GetError();
    if (error != AL_NO_ERROR)
    {
        // Failed to create OpenAL sound source, so bail out...
        debug(LOG_SOUND, "alGenSources failed, most likely out of sound sources");
        free(stream);
        return NULL;
    }

    stream->fileHandle = fileHandle;

    stream->decoder = sound_CreateOggVorbisDecoder(stream->fileHandle, false);
    if (stream->decoder == NULL)
    {
        debug(LOG_ERROR, "sound_PlayStream: Failed to open audio file for decoding");
        free(stream);
        return NULL;
    }

    stream->volume = volume;
    stream->bufferSize = streamBufferSize;

    alSourcef(stream->source, AL_GAIN, stream->volume);

    // HACK: this is a workaround for a bug in the 64bit implementation of OpenAL on GNU/Linux
    // The AL_PITCH value really should be 1.0.
    alSourcef(stream->source, AL_PITCH, 1.001f);

    // Create some OpenAL buffers to store the decoded data in
    alGenBuffers(buffer_count, buffers);
    sound_GetError();

    // Fill some buffers with audio data
    for (i = 0; i < buffer_count; ++i)
    {
        // Decode some audio data
        soundDataBuffer *soundBuffer = sound_DecodeOggVorbis(stream->decoder, stream->bufferSize);

        // If we actually decoded some data
        if (soundBuffer && soundBuffer->size > 0)
        {
            // Determine PCM data format
            ALenum format = (soundBuffer->channelCount == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;

            // Copy the audio data into one of OpenAL's own buffers
            alBufferData(buffers[i], format, soundBuffer->data, soundBuffer->size, soundBuffer->frequency);
            sound_GetError();

            // Clean up our memory
            free(soundBuffer);
        }
        else
        {
            // If no data has been decoded we're probably at the end of our
            // stream. So cleanup the excess stuff here.

            // First remove the data buffer itself
            free(soundBuffer);

            // Then remove OpenAL's buffers
            alDeleteBuffers(buffer_count - i, &buffers[i]);
            sound_GetError();

            break;
        }
    }

    // Bail out if we didn't fill any buffers
    if (i == 0)
    {
        debug(LOG_ERROR, "Failed to fill buffers with decoded audio data!");

        // Destroy the decoder
        sound_DestroyOggVorbisDecoder(stream->decoder);

        // Destroy the OpenAL source
        alDeleteSources(1, &stream->source);

        // Free allocated memory
        free(stream);

        return NULL;
    }

    // Attach the OpenAL buffers to our OpenAL source
    // (i = the amount of buffers we worked on in the above for-loop)
    alSourceQueueBuffers(stream->source, i, buffers);
    sound_GetError();

    // Start playing the source
    alSourcePlay(stream->source);

    sound_GetError();

    // Set callback info
    stream->onFinished = onFinished;
    stream->user_data = user_data;

    // Prepend this stream to the linked list
    stream->next = active_streams;
    active_streams = stream;

    return stream;
}