diff --git a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h index 2f43b2d9a..4a8d9bbe3 100644 --- a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h +++ b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h @@ -23,6 +23,6 @@ @property (nonatomic, weak, nullable) id delegate; + (Float64)preferredSamplingRate; -@property (nonatomic, readonly) NSUInteger bufferSize; +@property (nonatomic, readonly) NSUInteger preferredBufferSize; @end diff --git a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m index 47507b332..6a4f4567c 100644 --- a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m +++ b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m @@ -10,77 +10,18 @@ @import AudioToolbox; #define AudioQueueBufferMaxLength 8192 -#define AudioQueueNumAudioBuffers 3 -#define AudioQueueMaxStreamLength (AudioQueueBufferMaxLength*AudioQueueNumAudioBuffers) - -enum { - AudioQueueCanProceed, - AudioQueueWait, - AudioQueueIsInvalidated -}; @implementation CSAudioQueue { - NSUInteger _bufferLength; - NSUInteger _streamLength; - AudioQueueRef _audioQueue; - AudioQueueBufferRef _audioBuffers[AudioQueueNumAudioBuffers]; - - unsigned int _audioStreamReadPosition, _audioStreamWritePosition; - int16_t _audioStream[AudioQueueMaxStreamLength]; - - NSConditionLock *_writeLock; - BOOL _isInvalidated; - int _dequeuedCount; } -#pragma mark - -#pragma mark AudioQueue callbacks and setup; for pushing audio out +#pragma mark - AudioQueue callbacks - (void)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer { [self.delegate audioQueueDidCompleteBuffer:self]; - - [_writeLock lock]; - - const unsigned int writeLead = _audioStreamWritePosition - _audioStreamReadPosition; - const size_t audioDataSampleSize = buffer->mAudioDataByteSize / sizeof(int16_t); - - // TODO: if write lead is too great, skip some audio - if(writeLead >= audioDataSampleSize) - { - size_t samplesBeforeOverflow = _streamLength - (_audioStreamReadPosition % _streamLength); - if(audioDataSampleSize <= samplesBeforeOverflow) - { - memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition % _streamLength], buffer->mAudioDataByteSize); - } - else - { - const size_t bytesRemaining = samplesBeforeOverflow * sizeof(int16_t); - memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition % _streamLength], bytesRemaining); - memcpy(buffer->mAudioData, &_audioStream[0], buffer->mAudioDataByteSize - bytesRemaining); - } - _audioStreamReadPosition += audioDataSampleSize; - } - else - { - memset(buffer->mAudioData, 0, buffer->mAudioDataByteSize); - } - - if(!_isInvalidated) - { - [_writeLock unlockWithCondition:AudioQueueCanProceed]; - AudioQueueEnqueueBuffer(theAudioQueue, buffer, 0, NULL); - } - else - { - _dequeuedCount++; - if(_dequeuedCount == AudioQueueNumAudioBuffers) - [_writeLock unlockWithCondition:AudioQueueIsInvalidated]; - else - [_writeLock unlockWithCondition:AudioQueueCanProceed]; - } + AudioQueueFreeBuffer(_audioQueue, buffer); } static void audioOutputCallback( @@ -91,19 +32,19 @@ static void audioOutputCallback( [(__bridge CSAudioQueue *)inUserData audioQueue:inAQ didCallbackWithBuffer:inBuffer]; } +#pragma mark - Standard object lifecycle + - (instancetype)initWithSamplingRate:(Float64)samplingRate { self = [super init]; if(self) { - _writeLock = [[NSConditionLock alloc] initWithCondition:AudioQueueCanProceed]; _samplingRate = samplingRate; - // determine buffer sizes - _bufferLength = AudioQueueBufferMaxLength; - while((Float64)_bufferLength*50.0 > samplingRate) _bufferLength >>= 1; - _streamLength = _bufferLength * AudioQueueNumAudioBuffers; + // determine preferred buffer sizes + _preferredBufferSize = AudioQueueBufferMaxLength; + while((Float64)_preferredBufferSize*50.0 > samplingRate) _preferredBufferSize >>= 1; /* Describe a mono 16bit stream of the requested sampling rate @@ -133,17 +74,6 @@ static void audioOutputCallback( 0, &_audioQueue)) { - UInt32 bufferBytes = (UInt32)(_bufferLength * sizeof(int16_t)); - - int c = AudioQueueNumAudioBuffers; - while(c--) - { - AudioQueueAllocateBuffer(_audioQueue, bufferBytes, &_audioBuffers[c]); - memset(_audioBuffers[c]->mAudioData, 0, bufferBytes); - _audioBuffers[c]->mAudioDataByteSize = bufferBytes; - AudioQueueEnqueueBuffer(_audioQueue, _audioBuffers[c], 0, NULL); - } - AudioQueueStart(_audioQueue, NULL); } } @@ -158,51 +88,21 @@ static void audioOutputCallback( - (void)dealloc { - [_writeLock lock]; - _isInvalidated = YES; - [_writeLock unlock]; - - [_writeLock lockWhenCondition:AudioQueueIsInvalidated]; - [_writeLock unlock]; - - int c = AudioQueueNumAudioBuffers; - while(c--) - AudioQueueFreeBuffer(_audioQueue, _audioBuffers[c]); - if(_audioQueue) AudioQueueDispose(_audioQueue, NO); } +#pragma mark - Audio enqueuer + - (void)enqueueAudioBuffer:(const int16_t *)buffer numberOfSamples:(size_t)lengthInSamples { - if([_writeLock tryLockWhenCondition:AudioQueueCanProceed]) - { - if((_audioStreamReadPosition + _streamLength) - _audioStreamWritePosition >= lengthInSamples) - { - size_t samplesBeforeOverflow = _streamLength - (_audioStreamWritePosition % _streamLength); + AudioQueueBufferRef newBuffer; + size_t bufferBytes = lengthInSamples * sizeof(int16_t); - if(samplesBeforeOverflow < lengthInSamples) - { - memcpy(&_audioStream[_audioStreamWritePosition % _streamLength], buffer, samplesBeforeOverflow * sizeof(int16_t)); - memcpy(&_audioStream[0], &buffer[samplesBeforeOverflow], (lengthInSamples - samplesBeforeOverflow) * sizeof(int16_t)); - } - else - { - memcpy(&_audioStream[_audioStreamWritePosition % _streamLength], buffer, lengthInSamples * sizeof(int16_t)); - } + AudioQueueAllocateBuffer(_audioQueue, (UInt32)bufferBytes, &newBuffer); + memcpy(newBuffer->mAudioData, buffer, bufferBytes); + newBuffer->mAudioDataByteSize = (UInt32)bufferBytes; - _audioStreamWritePosition += lengthInSamples; - [_writeLock unlockWithCondition:[self writeLockCondition]]; - } - else - { - [_writeLock unlockWithCondition:AudioQueueWait]; - } - } -} - -- (NSInteger)writeLockCondition -{ - return ((_audioStreamWritePosition - _audioStreamReadPosition) < (_streamLength - _bufferLength)) ? AudioQueueCanProceed : AudioQueueWait; + AudioQueueEnqueueBuffer(_audioQueue, newBuffer, 0, NULL); } #pragma mark - Sampling Rate getters @@ -231,9 +131,4 @@ static void audioOutputCallback( return AudioObjectGetPropertyData([self defaultOutputDevice], &address, sizeof(AudioObjectPropertyAddress), NULL, &size, &samplingRate) ? 0.0 : samplingRate; } -- (NSUInteger)bufferSize -{ - return _bufferLength; -} - @end diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index 5ef302a53..ec845aff5 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -85,7 +85,7 @@ class MachineDocument: audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate)) audioQueue.delegate = self self.machine.audioQueue = self.audioQueue - self.machine.setAudioSamplingRate(selectedSamplingRate, bufferSize:audioQueue.bufferSize / 2) + self.machine.setAudioSamplingRate(selectedSamplingRate, bufferSize:audioQueue.preferredBufferSize / 2) } self.bestEffortUpdater.clockRate = self.machine.clockRate