Browse Source

REVIEWED: `UpdateMusicStream()` #2228

Trying to implement proper looping, independently of frame rate.
Ray 3 years ago
parent
commit
3ebfee5dbc
1 changed files with 64 additions and 30 deletions
  1. 64 30
      src/raudio.c

+ 64 - 30
src/raudio.c

@@ -1724,28 +1724,34 @@ void UpdateMusicStream(Music music)
     bool streamEnding = false;
     unsigned int subBufferSizeInFrames = music.stream.buffer->sizeInFrames/2;
 
-    // NOTE: Using dynamic allocation because it could require more than 16KB
+    // On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in
     unsigned int pcmSize = subBufferSizeInFrames*music.stream.channels*music.stream.sampleSize/8;
-    if (AUDIO.System.pcmCapacity < pcmSize) 
+    if (AUDIO.System.pcmBufferSize < pcmSize) 
     {
-        RL_FREE(AUDIO.System.pcm);
-        AUDIO.System.pcm = RL_CALLOC(1, pcmSize);
-        AUDIO.System.pcmCapacity = pcmSize;
+        RL_FREE(AUDIO.System.pcmBuffer);
+        AUDIO.System.pcmBuffer = RL_CALLOC(1, pcmSize);
+        AUDIO.System.pcmBufferSize = pcmSize;
     }
 
-    int frameCountToStream = 0;    // Total size of data in frames to be streamed
-
-    // TODO: Get the framesLeft using framesProcessed... 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;
-    unsigned int framesLeft = music.frameCount - music.stream.buffer->framesProcessed;
+    int framesLeft = music.frameCount - music.stream.buffer->framesProcessed;  // Frames left to be processed
+    int framesToStream = 0;                 // Total frames to be streamed
+    unsigned int framesLoopingExtra = 0;    // In case music requires to loop, we could need to add more frames from beginning to fill buffer
 
-    while (IsAudioStreamProcessed(music.stream))
+    // Check both sub-buffers to check if they require refilling
+    for (int i = 0; i < 2; i++)
     {
-        // WARNING: If audio needs to loop but the frames left are less than the actual size of buffer to fill,
-        // the buffer is only partially filled and no refill is done until next frame call, generating a silence
-        // TODO: Possible solution: In case of music loop, fill frames left + frames from start to fill the buffer to process
-        if (framesLeft >= subBufferSizeInFrames) frameCountToStream = subBufferSizeInFrames;
-        else frameCountToStream = framesLeft;
+        if ((music.stream.buffer != NULL) && !music.stream.buffer->isSubBufferProcessed[i]) continue; // No refilling required, move to next sub-buffer
+
+        if (framesLeft >= subBufferSizeInFrames) framesToStream = subBufferSizeInFrames;
+        else 
+        {
+            framesToStream = framesLeft;
+
+            // WARNING: If audio needs to loop but the frames left are less than the actual size of buffer to fill,
+            // the buffer is only partially filled and no refill is done until next frame call, generating a silence
+            // SOLUTION: In case of music loop, fill frames left + frames from start to fill the buffer to process
+            if (music.looping) framesLoopingExtra = subBufferSizeInFrames - framesLeft;
+        }
 
         switch (music.ctxType)
         {
@@ -1753,8 +1759,18 @@ void UpdateMusicStream(Music music)
             case MUSIC_AUDIO_WAV:
             {
                 // NOTE: Returns the number of samples to process (not required)
-                if (music.stream.sampleSize == 16) drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountToStream, (short *)AUDIO.System.pcm);
-                else if (music.stream.sampleSize == 32) drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountToStream, (float *)AUDIO.System.pcm);
+                if (music.stream.sampleSize == 16) drwav_read_pcm_frames_s16((drwav *)music.ctxData, framesToStream, (short *)AUDIO.System.pcmBuffer);
+                else if (music.stream.sampleSize == 32) drwav_read_pcm_frames_f32((drwav *)music.ctxData, framesToStream, (float *)AUDIO.System.pcmBuffer);
+
+                if (framesLoopingExtra > 0)
+                {
+                    drwav_seek_to_pcm_frame((drwav *)music.ctxData, 0);
+
+                    if (music.stream.sampleSize == 16) drwav_read_pcm_frames_s16((drwav *)music.ctxData, framesLoopingExtra, (short *)AUDIO.System.pcmBuffer + framesToStream*music.stream.channels);
+                    else if (music.stream.sampleSize == 32) drwav_read_pcm_frames_f32((drwav *)music.ctxData, framesLoopingExtra, (float *)AUDIO.System.pcmBuffer + framesToStream*music.stream.channels);
+                    
+                    framesToStream += framesLoopingExtra;
+                }
 
             } break;
         #endif
@@ -1762,7 +1778,9 @@ void UpdateMusicStream(Music music)
             case MUSIC_AUDIO_OGG:
             {
                 // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!)
-                stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)AUDIO.System.pcm, frameCountToStream*music.stream.channels);
+                stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)AUDIO.System.pcmBuffer, framesToStream*music.stream.channels);
+
+                // stb_vorbis_seek_start((stb_vorbis *)music.ctxData);
 
             } break;
         #endif
@@ -1772,12 +1790,16 @@ void UpdateMusicStream(Music music)
                 // NOTE: Returns the number of samples to process (not required)
                 drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountToStream*music.stream.channels, (short *)AUDIO.System.pcm);
 
+                // drflac_seek_to_pcm_frame((drflac *)music.ctxData, 0);
+
             } break;
         #endif
         #if defined(SUPPORT_FILEFORMAT_MP3)
             case MUSIC_AUDIO_MP3:
             {
-                drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountToStream, (float *)AUDIO.System.pcm);
+                drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, framesToStream, (float *)AUDIO.System.pcmBuffer);
+
+                //drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, 0);
 
             } break;
         #endif
@@ -1785,9 +1807,11 @@ void UpdateMusicStream(Music music)
             case MUSIC_MODULE_XM:
             {
                 // NOTE: Internally we consider 2 channels generation, so sampleCount/2
-                if (AUDIO_DEVICE_FORMAT == ma_format_f32) jar_xm_generate_samples((jar_xm_context_t *)music.ctxData, (float *)AUDIO.System.pcm, frameCountToStream);
-                else if (AUDIO_DEVICE_FORMAT == ma_format_s16) jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)AUDIO.System.pcm, frameCountToStream);
-                else if (AUDIO_DEVICE_FORMAT == ma_format_u8) jar_xm_generate_samples_8bit((jar_xm_context_t *)music.ctxData, (char *)AUDIO.System.pcm, frameCountToStream);
+                if (AUDIO_DEVICE_FORMAT == ma_format_f32) jar_xm_generate_samples((jar_xm_context_t *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream);
+                else if (AUDIO_DEVICE_FORMAT == ma_format_s16) jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream);
+                else if (AUDIO_DEVICE_FORMAT == ma_format_u8) jar_xm_generate_samples_8bit((jar_xm_context_t *)music.ctxData, (char *)AUDIO.System.pcmBuffer, framesToStream);
+
+                //jar_xm_reset((jar_xm_context_t *)music.ctxData);
 
             } break;
         #endif
@@ -1795,18 +1819,20 @@ void UpdateMusicStream(Music music)
             case MUSIC_MODULE_MOD:
             {
                 // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2
-                jar_mod_fillbuffer((jar_mod_context_t *)music.ctxData, (short *)AUDIO.System.pcm, frameCountToStream, 0);
+                jar_mod_fillbuffer((jar_mod_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream, 0);
+
+                //jar_mod_seek_start((jar_mod_context_t *)music.ctxData);
+
             } break;
         #endif
             default: break;
         }
 
-        UpdateAudioStream(music.stream, AUDIO.System.pcm, frameCountToStream);
+        UpdateAudioStream(music.stream, AUDIO.System.pcmBuffer, framesToStream);
 
-        framesLeft -= frameCountToStream;
-
-        if (framesLeft <= 0)
+        if (framesLeft <= subBufferSizeInFrames)
         {
+            // Streaming is ending, we filled latest frames from input
             streamEnding = true;
             break;
         }
@@ -1815,8 +1841,16 @@ void UpdateMusicStream(Music music)
     // Reset audio stream for looping
     if (streamEnding)
     {
-        StopMusicStream(music);                     // Stop music (and reset)
-        if (music.looping) PlayMusicStream(music);  // Play again
+        if (music.looping)
+        {
+            PlayMusicStream(music);     // Play again
+
+            // Set cursor offset to extra frames filled previously
+            music.stream.buffer->frameCursorPos = framesLoopingExtra;
+
+            // TODO: It's not working properly... :(
+        }
+        else StopMusicStream(music);    // Stop music (and reset)
     }
     else
     {