From 3b71d1a3096526fbe88fea38e3ab5fa7eed94c50 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 16 Jun 2016 21:35:22 -0400 Subject: [PATCH] Switched to a variable-length buffer based on attempting to hit approximately a certain quality of service. --- .../Mac/Clock Signal/Audio/CSAudioQueue.h | 2 +- .../Mac/Clock Signal/Audio/CSAudioQueue.m | 40 ++++++++++++------- .../Documents/MachineDocument.swift | 5 ++- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h index add6e78c7..7e2809274 100644 --- a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h +++ b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h @@ -23,6 +23,6 @@ @property (nonatomic, weak) id delegate; + (Float64)preferredSamplingRate; -+ (NSUInteger)bufferSize; +@property (nonatomic, readonly) NSUInteger bufferSize; @end diff --git a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m index 8617b64a6..c67e2f9f1 100644 --- a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m +++ b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m @@ -9,9 +9,9 @@ #import "CSAudioQueue.h" @import AudioToolbox; -#define AudioQueueStreamLength 768 -#define AudioQueueBufferLength 256 -#define AudioQueueNumAudioBuffers (AudioQueueStreamLength/AudioQueueBufferLength) +#define AudioQueueBufferMaxLength 2048 +#define AudioQueueNumAudioBuffers 3 +#define AudioQueueMaxStreamLength (AudioQueueBufferMaxLength*AudioQueueNumAudioBuffers) enum { AudioQueueCanProceed, @@ -21,10 +21,15 @@ enum { @implementation CSAudioQueue { + NSUInteger _bufferLength; + NSUInteger _streamLength; + AudioQueueRef _audioQueue; AudioQueueBufferRef _audioBuffers[AudioQueueNumAudioBuffers]; + unsigned int _audioStreamReadPosition, _audioStreamWritePosition; - int16_t _audioStream[AudioQueueStreamLength]; + int16_t _audioStream[AudioQueueMaxStreamLength]; + NSConditionLock *_writeLock; BOOL _isInvalidated; int _dequeuedCount; @@ -45,15 +50,15 @@ enum { // TODO: if write lead is too great, skip some audio if(writeLead >= audioDataSampleSize) { - size_t samplesBeforeOverflow = AudioQueueStreamLength - (_audioStreamReadPosition % AudioQueueStreamLength); + size_t samplesBeforeOverflow = _streamLength - (_audioStreamReadPosition % _streamLength); if(audioDataSampleSize <= samplesBeforeOverflow) { - memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition % AudioQueueStreamLength], buffer->mAudioDataByteSize); + memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition % _streamLength], buffer->mAudioDataByteSize); } else { const size_t bytesRemaining = samplesBeforeOverflow * sizeof(int16_t); - memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition % AudioQueueStreamLength], bytesRemaining); + memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition % _streamLength], bytesRemaining); memcpy(buffer->mAudioData, &_audioStream[0], buffer->mAudioDataByteSize - bytesRemaining); } _audioStreamReadPosition += audioDataSampleSize; @@ -95,6 +100,11 @@ static void audioOutputCallback( _writeLock = [[NSConditionLock alloc] initWithCondition:AudioQueueCanProceed]; _samplingRate = samplingRate; + // determine buffer sizes + _bufferLength = AudioQueueBufferMaxLength; + while((Float64)_bufferLength*50.0 > samplingRate) _bufferLength >>= 1; + _streamLength = _bufferLength * AudioQueueNumAudioBuffers; + /* Describe a mono 16bit stream of the requested sampling rate */ @@ -123,7 +133,7 @@ static void audioOutputCallback( 0, &_audioQueue)) { - UInt32 bufferBytes = AudioQueueBufferLength * sizeof(int16_t); + UInt32 bufferBytes = (UInt32)(_bufferLength * sizeof(int16_t)); int c = AudioQueueNumAudioBuffers; while(c--) @@ -167,18 +177,18 @@ static void audioOutputCallback( while(1) { [_writeLock lockWhenCondition:AudioQueueCanProceed]; - if((_audioStreamReadPosition + AudioQueueStreamLength) - _audioStreamWritePosition >= lengthInSamples) + if((_audioStreamReadPosition + _streamLength) - _audioStreamWritePosition >= lengthInSamples) { - size_t samplesBeforeOverflow = AudioQueueStreamLength - (_audioStreamWritePosition % AudioQueueStreamLength); + size_t samplesBeforeOverflow = _streamLength - (_audioStreamWritePosition % _streamLength); if(samplesBeforeOverflow < lengthInSamples) { - memcpy(&_audioStream[_audioStreamWritePosition % AudioQueueStreamLength], buffer, samplesBeforeOverflow * sizeof(int16_t)); + memcpy(&_audioStream[_audioStreamWritePosition % _streamLength], buffer, samplesBeforeOverflow * sizeof(int16_t)); memcpy(&_audioStream[0], &buffer[samplesBeforeOverflow], (lengthInSamples - samplesBeforeOverflow) * sizeof(int16_t)); } else { - memcpy(&_audioStream[_audioStreamWritePosition % AudioQueueStreamLength], buffer, lengthInSamples * sizeof(int16_t)); + memcpy(&_audioStream[_audioStreamWritePosition % _streamLength], buffer, lengthInSamples * sizeof(int16_t)); } _audioStreamWritePosition += lengthInSamples; @@ -194,7 +204,7 @@ static void audioOutputCallback( - (NSInteger)writeLockCondition { - return ((_audioStreamWritePosition - _audioStreamReadPosition) < (AudioQueueStreamLength - AudioQueueBufferLength)) ? AudioQueueCanProceed : AudioQueueWait; + return ((_audioStreamWritePosition - _audioStreamReadPosition) < (_streamLength - _bufferLength)) ? AudioQueueCanProceed : AudioQueueWait; } #pragma mark - Sampling Rate getters @@ -223,9 +233,9 @@ static void audioOutputCallback( return AudioObjectGetPropertyData([self defaultOutputDevice], &address, sizeof(AudioObjectPropertyAddress), NULL, &size, &samplingRate) ? 0.0 : samplingRate; } -+ (NSUInteger)bufferSize +- (NSUInteger)bufferSize { - return AudioQueueBufferLength; + return _bufferLength; } @end diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index c8d4c0610..82cf9cc4c 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -63,7 +63,7 @@ class MachineDocument: audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate)) audioQueue.delegate = self self.machine().audioQueue = self.audioQueue - self.machine().setAudioSamplingRate(selectedSamplingRate, bufferSize:CSAudioQueue.bufferSize() / 2) + self.machine().setAudioSamplingRate(selectedSamplingRate, bufferSize:audioQueue.bufferSize / 2) } self.bestEffortUpdater.clockRate = self.machine().clockRate @@ -86,8 +86,9 @@ class MachineDocument: } func runForNumberOfCycles(numberOfCycles: Int32) { + let cyclesToRunFor = min(numberOfCycles, Int32(bestEffortUpdater.clockRate / 10)) if actionLock.tryLock() { - self.machine().runForNumberOfCycles(numberOfCycles) + self.machine().runForNumberOfCycles(cyclesToRunFor) actionLock.unlock() } }