@@ -204,10 +204,12 @@ struct DecoderStream {
204204 float * loadingBuffer = nullptr ;
205205
206206 // Audio thread state (only touched by audio thread)
207- ma_uint64 filePosition = 0 ;
207+ std::atomic< ma_uint64> filePosition{ 0 } ;
208208 ma_uint64 bufferStartPos = 0 ;
209209 ma_uint64 localReadPos = 0 ;
210210 ma_uint64 validFrames = 0 ;
211+
212+ bool justSeeked = false ;
211213
212214 // Async loading state (atomic for lock-free access)
213215 struct AsyncState {
@@ -330,7 +332,7 @@ struct DecoderStream {
330332 }
331333
332334 // Reset state
333- void resetState () {
335+ void resetState (bool seeking = false ) {
334336 // Reset atomic flags
335337 asyncState.nextBufferReady .store (false , std::memory_order_release);
336338 asyncState.loadingBufferReady .store (false , std::memory_order_release);
@@ -339,15 +341,17 @@ struct DecoderStream {
339341 asyncState.requestNextBuffer .store (false , std::memory_order_release);
340342 asyncState.requestLoadingBuffer .store (false , std::memory_order_release);
341343
342- asyncState.nextBufferValidFrames = 0 ;
343- asyncState.loadingBufferValidFrames = 0 ;
344- asyncState.nextBufferStartPos = 0 ;
345- asyncState.loadingBufferStartPos = 0 ;
346-
347- filePosition = 0 ;
348- bufferStartPos = 0 ;
349- localReadPos = 0 ;
350- validFrames = 0 ;
344+ if (!seeking) {
345+ asyncState.nextBufferValidFrames = 0 ;
346+ asyncState.loadingBufferValidFrames = 0 ;
347+ asyncState.nextBufferStartPos = 0 ;
348+ asyncState.loadingBufferStartPos = 0 ;
349+
350+ filePosition.store (0 , std::memory_order_relaxed);
351+ bufferStartPos = 0 ;
352+ localReadPos = 0 ;
353+ validFrames = 0 ;
354+ }
351355
352356 if (pcmBufferA) memset (pcmBufferA, 0 , TOTAL_BUFFER_FRAMES * CHANNEL_COUNT * sizeof (float ));
353357 if (pcmBufferB) memset (pcmBufferB, 0 , TOTAL_BUFFER_FRAMES * CHANNEL_COUNT * sizeof (float ));
@@ -462,7 +466,7 @@ struct DecoderStream {
462466 memcpy (&decoder, &other.decoder , sizeof (ma_decoder));
463467
464468 // Move regular members
465- filePosition = other.filePosition ;
469+ filePosition. store ( other.filePosition , std::memory_order_relaxed) ;
466470 bufferStartPos = other.bufferStartPos ;
467471 localReadPos = other.localReadPos ;
468472 validFrames = other.validFrames ;
@@ -965,7 +969,6 @@ class AudioSystem {
965969 void seekToPCMFrame (int64_t pos) {
966970 if (!exists) return ;
967971
968- // Pause async loading during seek
969972 if (asyncLoader) {
970973 asyncLoader->pauseLoading ();
971974 }
@@ -978,20 +981,24 @@ class AudioSystem {
978981 for (size_t i = 0 ; i < streams.size (); i++) {
979982 DecoderStream& s = streams[i];
980983
981- // Seek to the exact position requested
982- ma_uint64 target = std::min<ma_uint64>(
983- (ma_uint64)std::max< int64_t >(pos , (int64_t ) 0 ),
984- s. decoderLength
985- );
984+ ma_uint64 target = pos;
985+
986+ printf ( " SEEKING TO TARGET: %lld \n " , (long long )target);
987+ printf ( " Before seek - filePos: %lld, bufferStart: %lld, localRead: %lld \n " ,
988+ ( long long )s. filePosition , ( long long )s. bufferStartPos , ( long long )s. localReadPos );
986989
987- s.resetState ();
990+ s.resetState (true );
991+ s.justSeeked = true ;
988992 fillInitialBuffer (i, target);
989993
990- if (s.active && target < s.decoderLength ) {
991- s.filePosition = target;
992- }
994+ printf (" After seek - filePos: %lld, bufferStart: %lld, localRead: %lld\n " ,
995+ (long long )s.filePosition , (long long )s.bufferStartPos , (long long )s.localReadPos );
996+
997+ // Verify the math
998+ ma_uint64 calculatedFilePos = s.bufferStartPos + s.localReadPos ;
999+ printf (" Calculated filePos should be: %lld (matches: %s)\n " ,
1000+ (long long )calculatedFilePos, (calculatedFilePos == s.filePosition ) ? " YES" : " NO" );
9931001
994- // Aggressively preload both buffers synchronously
9951002 if (s.active ) {
9961003 loadNextBufferSync (i);
9971004 if (s.asyncState .nextBufferReady .load (std::memory_order_relaxed)) {
@@ -1003,7 +1010,6 @@ class AudioSystem {
10031010 mixerState = (pos < (int64_t )streams[longestDecoderIndex].decoderLength ) ? 2 : 3 ;
10041011
10051012 if (wasPlaying && mixerState == 2 ) {
1006- // Resume async loading before starting playback
10071013 if (asyncLoader) {
10081014 asyncLoader->resumeLoading ();
10091015 }
@@ -1059,6 +1065,7 @@ class AudioSystem {
10591065 void fillInitialBuffer (size_t index, ma_uint64 startFrame) {
10601066 DecoderStream& s = streams[index];
10611067
1068+ // Calculate where to start decoding (with padding before the target)
10621069 ma_uint64 decodeStart = 0 ;
10631070 if (startFrame > PADDING_FRAMES) {
10641071 decodeStart = startFrame - PADDING_FRAMES;
@@ -1070,18 +1077,28 @@ class AudioSystem {
10701077 s.bufferStartPos = decodeStart;
10711078 s.validFrames = framesRead;
10721079
1073- if (startFrame >= decodeStart) {
1080+ // Calculate the local read position within this buffer
1081+ if (startFrame >= decodeStart && startFrame < decodeStart + framesRead) {
10741082 s.localReadPos = startFrame - decodeStart;
1075- } else {
1083+ } else if (startFrame < decodeStart) {
10761084 s.localReadPos = 0 ;
1085+ } else {
1086+ // startFrame is beyond what we loaded
1087+ s.localReadPos = framesRead;
10771088 }
10781089
1090+ // Ensure localReadPos is within bounds
10791091 if (s.localReadPos >= TOTAL_BUFFER_FRAMES) {
10801092 s.localReadPos = TOTAL_BUFFER_FRAMES - 1 ;
10811093 }
10821094
1083- s.filePosition = startFrame;
1084- s.active = (startFrame < s.decoderLength && framesRead > 0 );
1095+ // Set filePosition to the ACTUAL position we'll start reading from
1096+ // This is critical - it should be bufferStart + localReadPos
1097+ // printf("before? %lld\n", s.filePosition);
1098+ s.filePosition .store (s.bufferStartPos + s.localReadPos , std::memory_order_relaxed);
1099+ // printf("after? %lld\n", s.filePosition);
1100+
1101+ s.active = (s.filePosition < s.decoderLength && framesRead > 0 );
10851102 s.asyncState .needsLoad .store (false , std::memory_order_release);
10861103 }
10871104
@@ -1093,6 +1110,7 @@ class AudioSystem {
10931110 return ;
10941111 }
10951112
1113+ // Calculate next buffer start from CURRENT buffer position, not file position
10961114 ma_uint64 nextBufferStart = s.bufferStartPos + HALF_BUFFER_FRAMES;
10971115 if (nextBufferStart > PADDING_FRAMES) {
10981116 nextBufferStart -= PADDING_FRAMES;
@@ -1177,8 +1195,11 @@ class AudioSystem {
11771195 return 0 ;
11781196 }
11791197
1180- if (s.shouldSwapBuffers () || s.isBufferLow ()) {
1181- s.trySwapBuffers ();
1198+ // Don't swap buffers immediately after seeking
1199+ if (!s.justSeeked ) {
1200+ if (s.shouldSwapBuffers () || s.isBufferLow ()) {
1201+ s.trySwapBuffers ();
1202+ }
11821203 }
11831204
11841205 ma_uint32 framesRead = 0 ;
@@ -1192,6 +1213,7 @@ class AudioSystem {
11921213 if (available == 0 ) {
11931214 if (s.filePosition < s.decoderLength ) {
11941215 if (s.asyncState .nextBufferReady .load (std::memory_order_acquire)) {
1216+ s.justSeeked = false ; // Clear flag before swapping
11951217 s.trySwapBuffers ();
11961218 continue ;
11971219 } else {
@@ -1220,9 +1242,14 @@ class AudioSystem {
12201242 }
12211243
12221244 s.localReadPos += toRead;
1223- s.filePosition += toRead;
1245+ s.filePosition . store (s. filePosition . load (std::memory_order_relaxed) + toRead, std::memory_order_relaxed) ;
12241246 framesRead += toRead;
12251247
1248+ // Clear the justSeeked flag after first successful read
1249+ if (framesRead > 0 ) {
1250+ s.justSeeked = false ;
1251+ }
1252+
12261253 if (s.filePosition >= s.decoderLength ) {
12271254 s.active = false ;
12281255 break ;
0 commit comments