From fc95ceadf0143ad6c0f720d26bb28a45889f86d1 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 3 Sep 2019 23:08:02 +0200 Subject: [PATCH] Remove sampleLeft from Music struct... -WIP- ...moved to internal AudioBuffer structure as totalFramesProcessed, now time measure works again... but there is some problem with looping... Also note some inconsistencies between frames and samples, it seems those concepts are not considered correctly in the code. --- examples/audio/audio_module_playing.c | 22 +-- src/raudio.c | 266 +++++++++++--------------- src/raudio.h | 4 +- src/raylib.h | 1 - 4 files changed, 128 insertions(+), 165 deletions(-) diff --git a/examples/audio/audio_module_playing.c b/examples/audio/audio_module_playing.c index 0dae8aa2..557fcb09 100644 --- a/examples/audio/audio_module_playing.c +++ b/examples/audio/audio_module_playing.c @@ -46,13 +46,13 @@ int main(void) circles[i].radius = GetRandomValue(10, 40); circles[i].position.x = GetRandomValue(circles[i].radius, screenWidth - circles[i].radius); circles[i].position.y = GetRandomValue(circles[i].radius, screenHeight - circles[i].radius); - circles[i].speed = (float)GetRandomValue(1, 100)/20000.0f; + circles[i].speed = (float)GetRandomValue(1, 100)/2000.0f; circles[i].color = colors[GetRandomValue(0, 13)]; } - Music xm = LoadMusicStream("resources/chiptun1.mod"); + Music music = LoadMusicStream("resources/mini1111.xm"); - PlayMusicStream(xm); + PlayMusicStream(music); float timePlayed = 0.0f; bool pause = false; @@ -65,13 +65,13 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateMusicStream(xm); // Update music buffer with new stream data + UpdateMusicStream(music); // Update music buffer with new stream data // Restart music playing (stop and play) if (IsKeyPressed(KEY_SPACE)) { - StopMusicStream(xm); - PlayMusicStream(xm); + StopMusicStream(music); + PlayMusicStream(music); } // Pause/Resume music playing @@ -79,12 +79,12 @@ int main(void) { pause = !pause; - if (pause) PauseMusicStream(xm); - else ResumeMusicStream(xm); + if (pause) PauseMusicStream(music); + else ResumeMusicStream(music); } // Get timePlayed scaled to bar dimensions - timePlayed = GetMusicTimePlayed(xm)/GetMusicTimeLength(xm)*(screenWidth - 40); + timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)*(screenWidth - 40); // Color circles animation for (int i = MAX_CIRCLES - 1; (i >= 0) && !pause; i--) @@ -101,7 +101,7 @@ int main(void) circles[i].position.x = GetRandomValue(circles[i].radius, screenWidth - circles[i].radius); circles[i].position.y = GetRandomValue(circles[i].radius, screenHeight - circles[i].radius); circles[i].color = colors[GetRandomValue(0, 13)]; - circles[i].speed = (float)GetRandomValue(1, 100)/20000.0f; + circles[i].speed = (float)GetRandomValue(1, 100)/2000.0f; } } //---------------------------------------------------------------------------------- @@ -128,7 +128,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - UnloadMusicStream(xm); // Unload music stream buffers from RAM + UnloadMusicStream(music); // Unload music stream buffers from RAM CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) diff --git a/src/raudio.c b/src/raudio.c index 43e63bc9..2edf660a 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -124,7 +124,7 @@ // After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a // standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough // In case of music-stalls, just increase this number -#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. 16bit, Mono: 8Kb) +#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. 16bit, Mono: 8Kb) //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -189,6 +189,8 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo #define DEVICE_CHANNELS 2 #define DEVICE_SAMPLE_RATE 44100 +#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 + typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage; // Audio buffer structure @@ -205,16 +207,22 @@ struct rAudioBuffer { bool looping; // Audio buffer looping, always true for AudioStreams int usage; // Audio buffer usage mode: STATIC or STREAM - bool isSubBufferProcessed[2]; - unsigned int frameCursorPos; // Samples processed? - unsigned int bufferSizeInFrames; + bool isSubBufferProcessed[2]; // SubBuffer processed (virtual double buffer) + unsigned int frameCursorPos; // Frame cursor position + unsigned int bufferSizeInFrames; // Total buffer size in frames + unsigned int totalFramesProcessed; // Total frames processed in this buffer (required for play timming) - rAudioBuffer *next; - rAudioBuffer *prev; - unsigned char *buffer; + unsigned char *buffer; // Data buffer, on music stream keeps filling + + rAudioBuffer *next; // Next audio buffer on the list + rAudioBuffer *prev; // Previous audio buffer on the list }; -#define AudioBuffer rAudioBuffer // HACK: To avoid CoreAudio (macOS) symbol collision +#define AudioBuffer rAudioBuffer // HACK: To avoid CoreAudio (macOS) symbol collision + +// Audio buffers are tracked in a linked list +static AudioBuffer *firstAudioBuffer = NULL; +static AudioBuffer *lastAudioBuffer = NULL; // miniaudio global variables static ma_context context; @@ -223,9 +231,10 @@ static ma_mutex audioLock; static bool isAudioInitialized = false; static float masterVolume = 1.0f; -// Audio buffers are tracked in a linked list -static AudioBuffer *firstAudioBuffer = NULL; -static AudioBuffer *lastAudioBuffer = NULL; +// Multi channel playback global variables +AudioBuffer *audioBufferPool[MAX_AUDIO_BUFFER_POOL_CHANNELS] = { 0 }; +unsigned int audioBufferPoolCounter = 0; +unsigned int audioBufferPoolChannels[MAX_AUDIO_BUFFER_POOL_CHANNELS] = { 0 }; // miniaudio functions declaration static void OnLog(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message); @@ -247,19 +256,9 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch); void TrackAudioBuffer(AudioBuffer *buffer); void UntrackAudioBuffer(AudioBuffer *buffer); -//---------------------------------------------------------------------------------- -// Multi channel playback globals -//---------------------------------------------------------------------------------- -// Number of channels in the audio pool -#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 - -// Audio buffer pool -AudioBuffer *audioBufferPool[MAX_AUDIO_BUFFER_POOL_CHANNELS] = { 0 }; - -// These are used to determine the oldest playing channel -unsigned long audioBufferPoolCounter = 0; -unsigned long audioBufferPoolChannels[MAX_AUDIO_BUFFER_POOL_CHANNELS] = { 0 }; +//---------------------------------------------------------------------------------- +// miniaudio functions definitions //---------------------------------------------------------------------------------- // Log callback function @@ -319,6 +318,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const { float *framesOut = (float *)pFramesOut + (framesRead*device.playback.channels); float *framesIn = tempBuffer; + MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume); framesToRead -= framesJustRead; @@ -485,7 +485,6 @@ void InitAudioDevice(void) { // Init audio context ma_context_config contextConfig = ma_context_config_init(); - contextConfig.logCallback = OnLog; ma_result result = ma_context_init(NULL, 0, &contextConfig, &context); @@ -553,11 +552,7 @@ void InitAudioDevice(void) // Close the audio device for all contexts void CloseAudioDevice(void) { - if (!isAudioInitialized) - { - TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized"); - } - else + if (isAudioInitialized) { ma_mutex_uninit(&audioLock); ma_device_uninit(&device); @@ -567,6 +562,7 @@ void CloseAudioDevice(void) TraceLog(LOG_INFO, "Audio device closed successfully"); } + else TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized"); } // Check if device has been initialized successfully @@ -588,11 +584,11 @@ void SetMasterVolume(float volume) // Module Functions Definition - Audio Buffer management //---------------------------------------------------------------------------------- -// Create a new audio buffer. Initially filled with silence +// Initialize a new audio buffer (filled with silence) AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 bufferSizeInFrames, int usage) { AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(1, sizeof(AudioBuffer)); - audioBuffer->buffer = RL_CALLOC((bufferSizeInFrames*channels*ma_get_bytes_per_sample(format)), 1); + audioBuffer->buffer = RL_CALLOC(bufferSizeInFrames*channels*ma_get_bytes_per_sample(format), 1); if (audioBuffer == NULL) { @@ -690,6 +686,7 @@ void StopAudioBuffer(AudioBuffer *buffer) buffer->playing = false; buffer->paused = false; buffer->frameCursorPos = 0; + buffer->totalFramesProcessed = 0; buffer->isSubBufferProcessed[0] = true; buffer->isSubBufferProcessed[1] = true; } @@ -725,8 +722,10 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch) { float pitchMul = pitch/buffer->pitch; - // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches - // will make the sound faster; lower pitches make it slower. + // Pitching is just an adjustment of the sample rate. + // Note that this changes the duration of the sound: + // - higher pitches will make the sound faster + // - lower pitches make it slower ma_uint32 newOutputSampleRate = (ma_uint32)((float)buffer->dsp.src.config.sampleRateOut/pitchMul); buffer->pitch *= (float)buffer->dsp.src.config.sampleRateOut/newOutputSampleRate; @@ -869,16 +868,14 @@ void UpdateSound(Sound sound, const void *data, int samplesCount) { AudioBuffer *audioBuffer = sound.stream.buffer; - if (audioBuffer == NULL) + if (audioBuffer != NULL) { - TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer"); - return; - } - - StopAudioBuffer(audioBuffer); + StopAudioBuffer(audioBuffer); - // TODO: May want to lock/unlock this since this data buffer is read at mixing time - memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.formatConverterIn.config.channels*ma_get_bytes_per_sample(audioBuffer->dsp.formatConverterIn.config.formatIn)); + // TODO: May want to lock/unlock this since this data buffer is read at mixing time + memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.formatConverterIn.config.channels*ma_get_bytes_per_sample(audioBuffer->dsp.formatConverterIn.config.formatIn)); + } + else TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer"); } // Export wave data to file @@ -956,7 +953,7 @@ void PlaySound(Sound sound) void PlaySoundMulti(Sound sound) { int index = -1; - unsigned long oldAge = 0; + unsigned int oldAge = 0; int oldIndex = -1; // find the first non playing pool entry @@ -1184,14 +1181,8 @@ Music LoadMusicStream(const char *fileName) // OGG bit rate defaults to 16 bit, it's enough for compressed format music.stream = InitAudioStream(info.sample_rate, 16, info.channels); music.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData)*info.channels; - music.sampleLeft = music.sampleCount; music.loopCount = 0; // Infinite loop by default musicLoaded = true; - - TraceLog(LOG_INFO, "[%s] OGG total samples: %i", fileName, music.sampleCount); - TraceLog(LOG_INFO, "[%s] OGG sample rate: %i", fileName, info.sample_rate); - TraceLog(LOG_INFO, "[%s] OGG channels: %i", fileName, info.channels); - TraceLog(LOG_INFO, "[%s] OGG memory required: %i", fileName, info.temp_memory_required); } } #endif @@ -1207,14 +1198,8 @@ Music LoadMusicStream(const char *fileName) music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); music.sampleCount = (unsigned int)ctxFlac->totalSampleCount; - music.sampleLeft = music.sampleCount; music.loopCount = 0; // Infinite loop by default musicLoaded = true; - - TraceLog(LOG_DEBUG, "[%s] FLAC total samples: %i", fileName, music.sampleCount); - TraceLog(LOG_DEBUG, "[%s] FLAC sample rate: %i", fileName, ctxFlac->sampleRate); - TraceLog(LOG_DEBUG, "[%s] FLAC bits per sample: %i", fileName, ctxFlac->bitsPerSample); - TraceLog(LOG_DEBUG, "[%s] FLAC channels: %i", fileName, ctxFlac->channels); } } #endif @@ -1232,14 +1217,8 @@ Music LoadMusicStream(const char *fileName) music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels); music.sampleCount = drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels; - music.sampleLeft = music.sampleCount; music.loopCount = 0; // Infinite loop by default musicLoaded = true; - - TraceLog(LOG_INFO, "[%s] MP3 sample rate: %i", fileName, ctxMp3->sampleRate); - TraceLog(LOG_INFO, "[%s] MP3 bits per sample: %i", fileName, 32); - TraceLog(LOG_INFO, "[%s] MP3 channels: %i", fileName, ctxMp3->channels); - TraceLog(LOG_INFO, "[%s] MP3 total samples: %i", fileName, music.sampleCount); } } #endif @@ -1258,14 +1237,10 @@ Music LoadMusicStream(const char *fileName) // NOTE: Only stereo is supported for XM music.stream = InitAudioStream(48000, 16, 2); music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm); - music.sampleLeft = music.sampleCount; music.loopCount = 0; // Infinite loop by default musicLoaded = true; music.ctxData = ctxXm; - - TraceLog(LOG_INFO, "[%s] XM number of samples: %i", fileName, music.sampleCount); - TraceLog(LOG_INFO, "[%s] XM track length: %11.6f sec", fileName, (float)music.sampleCount/48000.0f); } } #endif @@ -1285,12 +1260,8 @@ Music LoadMusicStream(const char *fileName) // NOTE: Only stereo is supported for MOD music.stream = InitAudioStream(48000, 16, 2); music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod); - music.sampleLeft = music.sampleCount; music.loopCount = 0; // Infinite loop by default musicLoaded = true; - - TraceLog(LOG_INFO, "[%s] MOD number of samples: %i", fileName, music.sampleCount); - TraceLog(LOG_INFO, "[%s] MOD track length: %11.6f sec", fileName, (float)music.sampleCount/48000.0f); } } #endif @@ -1316,6 +1287,15 @@ Music LoadMusicStream(const char *fileName) TraceLog(LOG_WARNING, "[%s] Music file could not be opened", fileName); } + else + { + // Show some music stream info + TraceLog(LOG_INFO, "[%s] Music file successfully loaded:", fileName); + TraceLog(LOG_INFO, " Total samples: %i", music.sampleCount); + TraceLog(LOG_INFO, " Sample rate: %i Hz", music.stream.sampleRate); + TraceLog(LOG_INFO, " Sample size: %i bits", music.stream.sampleSize); + TraceLog(LOG_INFO, " Channels: %i (%s)", music.stream.channels, (music.stream.channels == 1)? "Mono" : (music.stream.channels == 2)? "Stereo" : "Multi"); + } return music; } @@ -1348,21 +1328,18 @@ void PlayMusicStream(Music music) { AudioBuffer *audioBuffer = music.stream.buffer; - if (audioBuffer == NULL) + if (audioBuffer != NULL) { - TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer"); - return; + // For music streams, we need to make sure we maintain the frame cursor position + // This is a hack for this section of code in UpdateMusicStream() + // NOTE: In case window is minimized, music stream is stopped, just make sure to + // play again on window restore: if (IsMusicPlaying(music)) PlayMusicStream(music); + ma_uint32 frameCursorPos = audioBuffer->frameCursorPos; + PlayAudioStream(music.stream); // WARNING: This resets the cursor position. + audioBuffer->frameCursorPos = frameCursorPos; } + else TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer"); - // For music streams, we need to make sure we maintain the frame cursor position - // This is a hack for this section of code in UpdateMusicStream() - // NOTE: In case window is minimized, music stream is stopped, just make sure to - // play again on window restore: if (IsMusicPlaying(music)) PlayMusicStream(music); - ma_uint32 frameCursorPos = audioBuffer->frameCursorPos; - - PlayAudioStream(music.stream); // <-- This resets the cursor position. - - audioBuffer->frameCursorPos = frameCursorPos; } // Pause music playing @@ -1389,7 +1366,7 @@ void StopMusicStream(Music music) case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break; #endif #if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: /* TODO: Restart FLAC context */ break; + case MUSIC_AUDIO_FLAC: drflac_seek_to_sample((drflac *)music.ctxData, 0) break; #endif #if defined(SUPPORT_FILEFORMAT_MP3) case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, 0); break; @@ -1402,8 +1379,6 @@ void StopMusicStream(Music music) #endif default: break; } - - music.sampleLeft = music.sampleCount; } // Update (re-fill) music buffers if data already processed @@ -1416,12 +1391,16 @@ void UpdateMusicStream(Music music) // NOTE: Using dynamic allocation because it could require more than 16KB void *pcm = RL_CALLOC(subBufferSizeInFrames*music.stream.channels*music.stream.sampleSize/8, 1); - int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts + int samplesCount = 0; // Total size of data streamed in L+R samples for xm floats, individual L or R for ogg shorts + + // TODO: Get the sampleLeft using totalFramesProcessed... but first, get total frames processed correctly... + //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels; + int sampleLeft = music.sampleCount - (music.stream.buffer->totalFramesProcessed*music.stream.channels); while (IsAudioStreamProcessed(music.stream)) { - if ((music.sampleLeft/music.stream.channels) >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames*music.stream.channels; - else samplesCount = music.sampleLeft; + if ((sampleLeft/music.stream.channels) >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames*music.stream.channels; + else samplesCount = sampleLeft; switch (music.ctxType) { @@ -1470,12 +1449,12 @@ void UpdateMusicStream(Music music) if ((music.ctxType == MUSIC_MODULE_XM) || (music.ctxType == MUSIC_MODULE_MOD)) { - if (samplesCount > 1) music.sampleLeft -= samplesCount/2; - else music.sampleLeft -= samplesCount; + if (samplesCount > 1) sampleLeft -= samplesCount/2; + else sampleLeft -= samplesCount; } - else music.sampleLeft -= samplesCount; + else sampleLeft -= samplesCount; - if (music.sampleLeft <= 0) + if (sampleLeft <= 0) { streamEnding = true; break; @@ -1493,13 +1472,10 @@ void UpdateMusicStream(Music music) // Decrease loopCount to stop when required if (music.loopCount > 1) { - music.loopCount--; // Decrease loop count + music.loopCount--; // Decrease loop count PlayMusicStream(music); // Play again } - else - { - if (music.loopCount == 0) PlayMusicStream(music); - } + else if (music.loopCount == 0) PlayMusicStream(music); } else { @@ -1549,7 +1525,8 @@ float GetMusicTimePlayed(Music music) { float secondsPlayed = 0.0f; - unsigned int samplesPlayed = music.sampleCount - music.sampleLeft; + //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels; + unsigned int samplesPlayed = music.stream.buffer->totalFramesProcessed*music.stream.channels; secondsPlayed = (float)samplesPlayed/(music.stream.sampleRate*music.stream.channels); return secondsPlayed; @@ -1562,14 +1539,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un stream.sampleRate = sampleRate; stream.sampleSize = sampleSize; - - // Only mono and stereo channels are supported - if ((channels > 0) && (channels < 3)) stream.channels = channels; - else - { - TraceLog(LOG_WARNING, "Init audio stream: Number of channels not supported: %i", channels); - stream.channels = 1; // Fallback to mono channel - } + stream.channels = channels; ma_format formatIn = ((stream.sampleSize == 8)? ma_format_u8 : ((stream.sampleSize == 16)? ma_format_s16 : ma_format_f32)); @@ -1579,18 +1549,14 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un if (subBufferSize < periodSize) subBufferSize = periodSize; - AudioBuffer *audioBuffer = InitAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM); + stream.buffer = InitAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM); - if (audioBuffer == NULL) + if (stream.buffer != NULL) { - TraceLog(LOG_ERROR, "InitAudioStream() : Failed to create audio buffer"); - return stream; + stream.buffer->looping = true; // Always loop for streaming buffers + TraceLog(LOG_INFO, "Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo"); } - - audioBuffer->looping = true; // Always loop for streaming buffers - stream.buffer = audioBuffer; - - TraceLog(LOG_INFO, "Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo"); + else TraceLog(LOG_ERROR, "InitAudioStream() : Failed to create audio buffer"); return stream; } @@ -1610,56 +1576,54 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) { AudioBuffer *audioBuffer = stream.buffer; - if (audioBuffer == NULL) + if (audioBuffer != NULL) { - TraceLog(LOG_ERROR, "UpdateAudioStream() : No audio buffer"); - return; - } + if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1]) + { + ma_uint32 subBufferToUpdate = 0; - if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1]) - { - ma_uint32 subBufferToUpdate = 0; + if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1]) + { + // Both buffers are available for updating. + // Update the first one and make sure the cursor is moved back to the front. + subBufferToUpdate = 0; + audioBuffer->frameCursorPos = 0; + } + else + { + // Just update whichever sub-buffer is processed. + subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0])? 0 : 1; + } - if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1]) - { - // Both buffers are available for updating. - // Update the first one and make sure the cursor is moved back to the front. - subBufferToUpdate = 0; - audioBuffer->frameCursorPos = 0; - } - else - { - // Just update whichever sub-buffer is processed. - subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0])? 0 : 1; - } + ma_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; + unsigned char *subBuffer = audioBuffer->buffer + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate); - ma_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; - unsigned char *subBuffer = audioBuffer->buffer + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate); + // TODO: Get total frames processed on this buffer... DOES NOT WORK. + audioBuffer->totalFramesProcessed += subBufferSizeInFrames; - // Does this API expect a whole buffer to be updated in one go? - // Assuming so, but if not will need to change this logic. - if (subBufferSizeInFrames >= (ma_uint32)samplesCount/stream.channels) - { - ma_uint32 framesToWrite = subBufferSizeInFrames; + // Does this API expect a whole buffer to be updated in one go? + // Assuming so, but if not will need to change this logic. + if (subBufferSizeInFrames >= (ma_uint32)samplesCount/stream.channels) + { + ma_uint32 framesToWrite = subBufferSizeInFrames; - if (framesToWrite > ((ma_uint32)samplesCount/stream.channels)) framesToWrite = (ma_uint32)samplesCount/stream.channels; + if (framesToWrite > ((ma_uint32)samplesCount/stream.channels)) framesToWrite = (ma_uint32)samplesCount/stream.channels; - ma_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8); - memcpy(subBuffer, data, bytesToWrite); + ma_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8); + memcpy(subBuffer, data, bytesToWrite); - // Any leftover frames should be filled with zeros. - ma_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; + // Any leftover frames should be filled with zeros. + ma_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; - if (leftoverFrameCount > 0) - { - memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8)); - } + if (leftoverFrameCount > 0) memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8)); - audioBuffer->isSubBufferProcessed[subBufferToUpdate] = false; + audioBuffer->isSubBufferProcessed[subBufferToUpdate] = false; + } + else TraceLog(LOG_ERROR, "UpdateAudioStream() : Attempting to write too many frames to buffer"); } - else TraceLog(LOG_ERROR, "UpdateAudioStream() : Attempting to write too many frames to buffer"); + else TraceLog(LOG_ERROR, "UpdateAudioStream() : Audio buffer not available for updating"); } - else TraceLog(LOG_ERROR, "Audio buffer not available for updating"); + else TraceLog(LOG_ERROR, "UpdateAudioStream() : No audio buffer"); } // Check if any audio stream buffers requires refill diff --git a/src/raudio.h b/src/raudio.h index 302993a9..e508d380 100644 --- a/src/raudio.h +++ b/src/raudio.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* raudio - A simple and easy-to-use audio library based on mini_al +* raudio - A simple and easy-to-use audio library based on miniaudio * * FEATURES: * - Manage audio device (init/close) @@ -20,7 +20,7 @@ * * CONTRIBUTORS: * David Reid (github: @mackron) (Nov. 2017): -* - Complete port to mini_al library +* - Complete port to miniaudio library * * Joshua Reisenauer (github: @kd7tck) (2015) * - XM audio module support (jar_xm) diff --git a/src/raylib.h b/src/raylib.h index ec6fd8a1..ed0314d3 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -434,7 +434,6 @@ typedef struct Music { void *ctxData; // Audio context data, depends on type unsigned int sampleCount; // Total number of samples - unsigned int sampleLeft; // Number of samples left to end unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop AudioStream stream; // Audio stream