Cog Audio: Implement play position skip ahead when output format changes, based on how much converter output is being discarded

This commit is contained in:
Christopher Snowhill 2022-01-12 23:17:07 -08:00
parent 52b17bd4d8
commit 73348b1616
2 changed files with 17 additions and 11 deletions

View file

@ -18,7 +18,8 @@
@interface OutputNode : Node { @interface OutputNode : Node {
AudioStreamBasicDescription format; AudioStreamBasicDescription format;
unsigned long long amountPlayed; double amountPlayed;
double sampleRatio;
OutputCoreAudio *output; OutputCoreAudio *output;
BOOL paused; BOOL paused;

View file

@ -17,7 +17,8 @@
- (void)setup - (void)setup
{ {
amountPlayed = 0; amountPlayed = 0.0;
sampleRatio = 0.0;
paused = YES; paused = YES;
@ -30,7 +31,7 @@
{ {
// [output pause]; // [output pause];
amountPlayed = time*format.mBytesPerFrame*(format.mSampleRate); amountPlayed = time;
} }
- (void)process - (void)process
@ -58,11 +59,11 @@
[self setPreviousNode:[[controller bufferChain] finalNode]]; [self setPreviousNode:[[controller bufferChain] finalNode]];
n = [super readData:ptr amount:amount]; n = [super readData:ptr amount:amount];
amountPlayed += n; amountPlayed += (double)n * sampleRatio;
if (endOfStream == YES && !n) if (endOfStream == YES && !n)
{ {
amountPlayed = 0; amountPlayed = 0.0;
[controller endOfInputPlayed]; //Updates shouldContinue appropriately? [controller endOfInputPlayed]; //Updates shouldContinue appropriately?
} }
@ -78,7 +79,7 @@
- (double)amountPlayed - (double)amountPlayed
{ {
return (amountPlayed/format.mBytesPerFrame)/(format.mSampleRate); return amountPlayed;
} }
- (AudioStreamBasicDescription) format - (AudioStreamBasicDescription) format
@ -89,16 +90,20 @@
- (void)setFormat:(AudioStreamBasicDescription *)f - (void)setFormat:(AudioStreamBasicDescription *)f
{ {
format = *f; format = *f;
// Calculate a ratio and add to double(seconds) instead, as format may change
double oldSampleRatio = sampleRatio;
sampleRatio = 1.0 / (format.mSampleRate * format.mBytesPerPacket);
BufferChain *bufferChain = [controller bufferChain]; BufferChain *bufferChain = [controller bufferChain];
if (bufferChain) if (bufferChain)
{ {
InputNode *input = [bufferChain inputNode];
ConverterNode *converter = [bufferChain converter]; ConverterNode *converter = [bufferChain converter];
if (input && converter) if (converter)
{ {
// Need to clear the buffer, as it contains converted output // This clears the resampler buffer, but not the input buffer
// targeting the previous output format // We also have to jump the play position ahead accounting for
[input resetBuffer]; // the data we are flushing
if (oldSampleRatio)
amountPlayed += oldSampleRatio * [[converter buffer] bufferedLength];
[converter setOutputFormat:format]; [converter setOutputFormat:format];
[converter inputFormatDidChange:[bufferChain inputFormat]]; [converter inputFormatDidChange:[bufferChain inputFormat]];
} }