From 58d2f70b7e11aadb5eab5f9fa1c081b22a59ef91 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 1 Aug 2016 21:37:45 +0200 Subject: [PATCH] Review audio module and examples --- examples/audio_music_stream.c | 1 - examples/audio_standalone.c | 11 +- src/audio.c | 181 ++++++++------------- templates/android_project/jni/basic_game.c | 8 +- 4 files changed, 76 insertions(+), 125 deletions(-) diff --git a/examples/audio_music_stream.c b/examples/audio_music_stream.c index b96b85f7d..1d86bd1ad 100644 --- a/examples/audio_music_stream.c +++ b/examples/audio_music_stream.c @@ -54,7 +54,6 @@ int main() { volume = 1.0; framesCounter = 0; - PlayMusicStream(1, "resources/audio/another_file.ogg"); } SetMusicVolume(volume); diff --git a/examples/audio_standalone.c b/examples/audio_standalone.c index f6e115db5..c716faedb 100644 --- a/examples/audio_standalone.c +++ b/examples/audio_standalone.c @@ -39,7 +39,8 @@ int main() Sound fxWav = LoadSound("resources/audio/weird.wav"); // Load WAV audio file Sound fxOgg = LoadSound("resources/audio/tanatana.ogg"); // Load OGG audio file - PlayMusicStream(0, "resources/audio/guitar_noodling.ogg"); + Music music = LoadMusicStream("resources/audio/guitar_noodling.ogg"); + PlayMusicStream(music); printf("\nPress s or d to play sounds...\n"); @@ -59,11 +60,13 @@ int main() key = 0; } - UpdateMusicStream(0); + UpdateMusicStream(music); } - UnloadSound(fxWav); // Unload sound data - UnloadSound(fxOgg); // Unload sound data + UnloadSound(fxWav); // Unload sound data + UnloadSound(fxOgg); // Unload sound data + + UnloadMusicStream(music); // Unload music stream data CloseAudioDevice(); diff --git a/src/audio.c b/src/audio.c index 2ff567372..d1c425d5f 100644 --- a/src/audio.c +++ b/src/audio.c @@ -86,13 +86,13 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define MAX_STREAM_BUFFERS 2 // Number of buffers for each audio stream +#define MAX_STREAM_BUFFERS 2 // Number of buffers for each audio stream // NOTE: Music buffer size is defined by number of samples, independent of sample size // After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds // and double-buffering system, I concluded that a 4096 samples buffer should be enough -// In case of music-stalls, just inclease this number -#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. short: 32Kb) +// In case of music-stalls, just increase this number +#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. short: 32Kb) //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -141,12 +141,12 @@ static Wave LoadWAV(const char *fileName); // Load WAV file static Wave LoadOGG(char *fileName); // Load OGG file static void UnloadWave(Wave wave); // Unload wave data -static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); -static void CloseAudioStream(AudioStream stream); // Frees mix channel -static int BufferAudioStream(AudioStream stream, void *data, int numberElements); // Pushes more audio data into mix channel - static bool BufferMusicStream(Music music, int numBuffersToProcess); // Fill music buffers with data +static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); +static void BufferAudioStream(AudioStream stream, void *data, int numSamples); +static void CloseAudioStream(AudioStream stream); + #if defined(AUDIO_STANDALONE) const char *GetExtension(const char *fileName); // Get the extension for a filename void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message (INFO, ERROR, WARNING) @@ -492,27 +492,23 @@ Music LoadMusicStream(char *fileName) // Open ogg audio stream music->ctxOgg = stb_vorbis_open_filename(fileName, NULL, NULL); - if (music->ctxOgg == NULL) - { - TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName); - } + if (music->ctxOgg == NULL) TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName); else { stb_vorbis_info info = stb_vorbis_get_info(music->ctxOgg); // Get Ogg file info - - TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); - TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels); - TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required); + //float totalLengthSeconds = stb_vorbis_stream_length_in_seconds(music->ctxOgg); // TODO: Support 32-bit sampleSize OGGs music->stream = InitAudioStream(info.sample_rate, 16, info.channels); - music->totalSamples = (unsigned int)stb_vorbis_stream_length_in_samples(music->ctxOgg)*info.channels; music->samplesLeft = music->totalSamples; - //float totalLengthSeconds = stb_vorbis_stream_length_in_seconds(music->ctxOgg); - music->ctxType = MUSIC_AUDIO_OGG; music->loop = true; // We loop by default + + TraceLog(DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate); + TraceLog(DEBUG, "[%s] OGG channels: %i", fileName, info.channels); + TraceLog(DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required); + } } else if (strcmp(GetExtension(fileName), "xm") == 0) @@ -523,17 +519,15 @@ Music LoadMusicStream(char *fileName) { jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops - music->totalSamples = (unsigned int)jar_xm_get_remaining_samples(music->ctxXm); - music->samplesLeft = music->totalSamples; - - TraceLog(INFO, "[%s] XM number of samples: %i", fileName, music->totalSamples); - TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); - // NOTE: Only stereo is supported for XM music->stream = InitAudioStream(48000, 32, 2); - + music->totalSamples = (unsigned int)jar_xm_get_remaining_samples(music->ctxXm); + music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_MODULE_XM; music->loop = true; + + TraceLog(DEBUG, "[%s] XM number of samples: %i", fileName, music->totalSamples); + TraceLog(DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); } else TraceLog(WARNING, "[%s] XM file could not be opened", fileName); } @@ -543,16 +537,14 @@ Music LoadMusicStream(char *fileName) if (jar_mod_load_file(&music->ctxMod, fileName)) { + music->stream = InitAudioStream(48000, 16, 2); music->totalSamples = (unsigned int)jar_mod_max_samples(&music->ctxMod); music->samplesLeft = music->totalSamples; + music->ctxType = MUSIC_MODULE_MOD; + music->loop = true; TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, music->samplesLeft); TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); - - music->stream = InitAudioStream(48000, 16, 2); - - music->ctxType = MUSIC_MODULE_MOD; - music->loop = true; } else TraceLog(WARNING, "[%s] MOD file could not be opened", fileName); } @@ -799,42 +791,18 @@ static void CloseAudioStream(AudioStream stream) } // Push more audio data into audio stream, only one buffer per call -// NOTE: Returns number of samples that were processed -static int BufferAudioStream(AudioStream stream, void *data, int numberElements) -{ - if (!data || !numberElements) - { - // Pauses audio until data is given - alSourcePause(stream.source); - return 0; - } - +static void BufferAudioStream(AudioStream stream, void *data, int numSamples) +{ ALuint buffer = 0; alSourceUnqueueBuffers(stream.source, 1, &buffer); - if (!buffer) return 0; - - // Reference - //void alBufferData(ALuint bufferName, ALenum format, const ALvoid *data, ALsizei size, ALsizei frequency); - - // ALuint bufferName: buffer id - // ALenum format: Valid formats are - // AL_FORMAT_MONO8, // unsigned char - // AL_FORMAT_MONO16, // short - // AL_FORMAT_STEREO8, - // AL_FORMAT_STEREO16 // stereo data is interleaved: left+right channels sample - // AL_FORMAT_MONO_FLOAT32 (extension) - // AL_FORMAT_STEREO_FLOAT32 (extension) - // ALsizei size: Number of bytes, must be coherent with format - // ALsizei frequency: sample rate - - if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numberElements*sizeof(unsigned char), stream.sampleRate); - else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numberElements*sizeof(short), stream.sampleRate); - else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numberElements*sizeof(float), stream.sampleRate); + //TraceLog(DEBUG, "Buffer to refill: %i", buffer); + + if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numSamples*sizeof(unsigned char), stream.sampleRate); + else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numSamples*sizeof(short), stream.sampleRate); + else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numSamples*sizeof(float), stream.sampleRate); alSourceQueueBuffers(stream.source, 1, &buffer); - - return numberElements; } // Fill music buffers with new data from music stream @@ -845,70 +813,49 @@ static bool BufferMusicStream(Music music, int numBuffersToProcess) int size = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts bool active = true; // We can get more data from stream (not finished) - - if (music->ctxType == MUSIC_MODULE_XM) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. - { - for (int i = 0; i < numBuffersToProcess; i++) - { - if (music->samplesLeft >= AUDIO_BUFFER_SIZE) size = AUDIO_BUFFER_SIZE/2; - else size = music->samplesLeft/2; - - // Read 2*shorts and moves them to buffer+size memory location - jar_xm_generate_samples(music->ctxXm, pcmf, size); - - BufferAudioStream(music->stream, pcmf, size*2); - - music->samplesLeft -= size; - - if (music->samplesLeft <= 0) - { - active = false; - break; - } - } - } - else if (music->ctxType == MUSIC_MODULE_MOD) - { - for (int i = 0; i < numBuffersToProcess; i++) - { - if (music->samplesLeft >= AUDIO_BUFFER_SIZE) size = AUDIO_BUFFER_SIZE/2; - else size = music->samplesLeft/2; - - jar_mod_fillbuffer(&music->ctxMod, pcm, size, 0); - - BufferAudioStream(music->stream, pcm, size*2); - - music->samplesLeft -= size; - - if (music->samplesLeft <= 0) - { - active = false; - break; - } - } - } - else if (music->ctxType == MUSIC_AUDIO_OGG) + + for (int i = 0; i < numBuffersToProcess; i++) { if (music->samplesLeft >= AUDIO_BUFFER_SIZE) size = AUDIO_BUFFER_SIZE; else size = music->samplesLeft; - for (int i = 0; i < numBuffersToProcess; i++) + switch (music->ctxType) { - // NOTE: Returns the number of samples stored per channel - int numSamples = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, size); - - BufferAudioStream(music->stream, pcm, numSamples*music->stream.channels); - - music->samplesLeft -= (numSamples*music->stream.channels); - - if (music->samplesLeft <= 0) + case MUSIC_AUDIO_OGG: { - active = false; - break; - } + // NOTE: Returns the number of samples to process (should be the same as size) + int numSamples = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, size); + + BufferAudioStream(music->stream, pcm, numSamples*music->stream.channels); + music->samplesLeft -= (numSamples*music->stream.channels); + + } break; + case MUSIC_MODULE_XM: + { + // NOTE: Output buffer is 2*numsamples elements (left and right value for each sample) + jar_xm_generate_samples(music->ctxXm, pcmf, size/2); + BufferAudioStream(music->stream, pcmf, size); // Using 32bit PCM data + music->samplesLeft -= (size/2); + + } break; + case MUSIC_MODULE_MOD: + { + // NOTE: Output buffer size is nbsample*channels (default: 48000Hz, 16bit, Stereo) + jar_mod_fillbuffer(&music->ctxMod, pcm, size/2, 0); + BufferAudioStream(music->stream, pcm, size); + music->samplesLeft -= (size/2); + + } break; + default: break; + } + + if (music->samplesLeft <= 0) + { + active = false; + break; } } - + return active; } diff --git a/templates/android_project/jni/basic_game.c b/templates/android_project/jni/basic_game.c index a1adb2873..4e8bef31e 100644 --- a/templates/android_project/jni/basic_game.c +++ b/templates/android_project/jni/basic_game.c @@ -43,7 +43,8 @@ void android_main(struct android_app *app) int framesCounter = 0; // Used to count frames - PlayMusicStream(0, "ambient.ogg"); + Music ambient = LoadMusicStream("ambient.ogg"); + PlayMusicStream(ambient); SetTargetFPS(60); // Not required on Android, already locked to 60 fps //-------------------------------------------------------------------------------------- @@ -53,7 +54,7 @@ void android_main(struct android_app *app) { // Update //---------------------------------------------------------------------------------- - UpdateMusicStream(0); + UpdateMusicStream(ambient); switch(currentScreen) { @@ -158,7 +159,8 @@ void android_main(struct android_app *app) // TODO: Unload all loaded data (textures, fonts, audio) here! - UnloadSound(fx); // Unload sound data + UnloadSound(fx); // Unload sound data + UnloadMusicStream(ambient); // Unload music stream data CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)