Bug Fix: Rubber Band should now flush last chunk

There is a race condition with the next Node in the chain and the End of
Stream marker, considering how tiny the buffering is for these DSPs. Set
End of Stream instead after inserting the end of stream flush chunk.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-02-27 00:55:18 -08:00
parent 7b702d23a6
commit e1a3e3d2dc

View file

@ -37,6 +37,8 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
BOOL stopping, paused; BOOL stopping, paused;
BOOL processEntered; BOOL processEntered;
BOOL flushed;
BOOL observersapplied; BOOL observersapplied;
AudioStreamBasicDescription lastInputFormat; AudioStreamBasicDescription lastInputFormat;
@ -261,6 +263,7 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
tsapplynewoptions = NO; tsapplynewoptions = NO;
tsrestartengine = NO; tsrestartengine = NO;
flushed = NO;
stretchIn = 0.0; stretchIn = 0.0;
stretchOut = 0.0; stretchOut = 0.0;
@ -357,7 +360,8 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
AudioChunk *chunk = nil; AudioChunk *chunk = nil;
chunk = [self convert]; chunk = [self convert];
if(!chunk || ![chunk frameCount]) { if(!chunk || ![chunk frameCount]) {
if([self endOfStream] == YES) { if(flushed) {
endOfStream = YES;
break; break;
} }
if(paused) { if(paused) {
@ -385,7 +389,7 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
processEntered = YES; processEntered = YES;
if(stopping || [self endOfStream] == YES || [self shouldContinue] == NO) { if(stopping || flushed || [self endOfStream] == YES || [self shouldContinue] == NO) {
processEntered = NO; processEntered = NO;
return nil; return nil;
} }
@ -448,11 +452,11 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
cblas_scopy((int)frameCount, ((const float *)[sampleData bytes]) + i, channels, rsPtrs[i], 1); cblas_scopy((int)frameCount, ((const float *)[sampleData bytes]) + i, channels, rsPtrs[i], 1);
} }
endOfStream = [[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES; flushed = [[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES;
int len = (int)frameCount; int len = (int)frameCount;
rubberband_process(ts, (const float * const *)rsPtrs, len, endOfStream); rubberband_process(ts, (const float * const *)rsPtrs, len, flushed);
} }
ssize_t samplesAvailable; ssize_t samplesAvailable;
@ -481,7 +485,7 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
samplesBuffered += samplesOut; samplesBuffered += samplesOut;
} }
if(endOfStream) { if(flushed) {
if(samplesBuffered > 0) { if(samplesBuffered > 0) {
ssize_t delta = (stretchIn - stretchOut) * inputFormat.mSampleRate; ssize_t delta = (stretchIn - stretchOut) * inputFormat.mSampleRate;
if(delta > 0 && samplesBuffered > delta) { if(delta > 0 && samplesBuffered > delta) {