From 2364a7d469f0d229abdadbd43b03da73d895ed1e Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Wed, 12 Feb 2025 14:56:32 -0800 Subject: [PATCH] Rubber Band DSP: Process larger blocks at a time Attempt to completely fill the input buffer of the Rubber Band library between each call to the process function, instead of processing in as small an increment as the source node provides. May reduce processing power required. Signed-off-by: Christopher Snowhill --- Audio/Chain/DSP/DSPRubberbandNode.m | 59 ++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/Audio/Chain/DSP/DSPRubberbandNode.m b/Audio/Chain/DSP/DSPRubberbandNode.m index 7c9c0417e..d035e311c 100644 --- a/Audio/Chain/DSP/DSPRubberbandNode.m +++ b/Audio/Chain/DSP/DSPRubberbandNode.m @@ -373,6 +373,13 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext; return nil; } + double streamTimestamp; + double streamTimeRatio; + if(![self peekTimestamp:&streamTimestamp timeRatio:&streamTimeRatio]) { + processEntered = NO; + return nil; + } + if(!ts || memcmp(&inputFormat, &lastInputFormat, sizeof(inputFormat)) != 0 || inputChannelConfig != lastInputChannelConfig) { lastInputFormat = inputFormat; @@ -388,8 +395,41 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext; if(samplesToProcess > blockSize) samplesToProcess = blockSize; - AudioChunk *chunk = [self readChunkAsFloat32:samplesToProcess]; - if(!chunk) { + size_t totalFrameCount = 0; + AudioChunk *chunk; + int channels = (int)(inputFormat.mChannelsPerFrame); + + BOOL isHDCD = NO; + + while(!stopping && totalFrameCount < samplesToProcess) { + AudioStreamBasicDescription newInputFormat; + uint32_t newChannelConfig; + if(![self peekFormat:&newInputFormat channelConfig:&newChannelConfig] || + memcmp(&newInputFormat, &inputFormat, sizeof(newInputFormat)) != 0 || + newChannelConfig != inputChannelConfig) { + break; + } + + chunk = [self readChunkAsFloat32:samplesToProcess - totalFrameCount]; + if(!chunk) { + break; + } + + if([chunk isHDCD]) { + isHDCD = YES; + } + + size_t frameCount = [chunk frameCount]; + NSData *sampleData = [chunk removeSamples:frameCount]; + + for (size_t i = 0; i < channels; ++i) { + cblas_scopy((int)frameCount, ((const float *)[sampleData bytes]) + i, channels, rsPtrs[i] + totalFrameCount, 1); + } + + totalFrameCount += frameCount; + } + + if(!totalFrameCount) { processEntered = NO; return nil; } @@ -398,18 +438,9 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext; bool endOfStream = [[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES; - size_t frameCount = [chunk frameCount]; - - double streamTimestamp = [chunk streamTimestamp]; + size_t frameCount = totalFrameCount; int len = (int)frameCount; - int channels = (int)(inputFormat.mChannelsPerFrame); - NSData *samples = [chunk removeSamples:frameCount]; - float *ibuf = (float *)[samples bytes]; - - for(size_t i = 0; i < channels; ++i) { - cblas_scopy(len, ibuf + i, channels, rsPtrs[i], 1); - } rubberband_process(ts, (const float * const *)rsPtrs, len, endOfStream); @@ -461,9 +492,9 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext; if(inputChannelConfig) { [outputChunk setChannelConfig:inputChannelConfig]; } - if([chunk isHDCD]) [outputChunk setHDCD]; + if(isHDCD) [outputChunk setHDCD]; [outputChunk setStreamTimestamp:streamTimestamp]; - [outputChunk setStreamTimeRatio:[chunk streamTimeRatio] * tempo]; + [outputChunk setStreamTimeRatio:streamTimeRatio * tempo]; [outputChunk assignSamples:rsOutBuffer frameCount:samplesBuffered]; samplesBuffered = 0; stretchOut += [outputChunk duration];