1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +00:00

Switched to a variable-length buffer based on attempting to hit approximately a certain quality of service.

This commit is contained in:
Thomas Harte 2016-06-16 21:35:22 -04:00
parent 2ee78d42b9
commit 3b71d1a309
3 changed files with 29 additions and 18 deletions

View File

@ -23,6 +23,6 @@
@property (nonatomic, weak) id<CSAudioQueueDelegate> delegate; @property (nonatomic, weak) id<CSAudioQueueDelegate> delegate;
+ (Float64)preferredSamplingRate; + (Float64)preferredSamplingRate;
+ (NSUInteger)bufferSize; @property (nonatomic, readonly) NSUInteger bufferSize;
@end @end

View File

@ -9,9 +9,9 @@
#import "CSAudioQueue.h" #import "CSAudioQueue.h"
@import AudioToolbox; @import AudioToolbox;
#define AudioQueueStreamLength 768 #define AudioQueueBufferMaxLength 2048
#define AudioQueueBufferLength 256 #define AudioQueueNumAudioBuffers 3
#define AudioQueueNumAudioBuffers (AudioQueueStreamLength/AudioQueueBufferLength) #define AudioQueueMaxStreamLength (AudioQueueBufferMaxLength*AudioQueueNumAudioBuffers)
enum { enum {
AudioQueueCanProceed, AudioQueueCanProceed,
@ -21,10 +21,15 @@ enum {
@implementation CSAudioQueue @implementation CSAudioQueue
{ {
NSUInteger _bufferLength;
NSUInteger _streamLength;
AudioQueueRef _audioQueue; AudioQueueRef _audioQueue;
AudioQueueBufferRef _audioBuffers[AudioQueueNumAudioBuffers]; AudioQueueBufferRef _audioBuffers[AudioQueueNumAudioBuffers];
unsigned int _audioStreamReadPosition, _audioStreamWritePosition; unsigned int _audioStreamReadPosition, _audioStreamWritePosition;
int16_t _audioStream[AudioQueueStreamLength]; int16_t _audioStream[AudioQueueMaxStreamLength];
NSConditionLock *_writeLock; NSConditionLock *_writeLock;
BOOL _isInvalidated; BOOL _isInvalidated;
int _dequeuedCount; int _dequeuedCount;
@ -45,15 +50,15 @@ enum {
// TODO: if write lead is too great, skip some audio // TODO: if write lead is too great, skip some audio
if(writeLead >= audioDataSampleSize) if(writeLead >= audioDataSampleSize)
{ {
size_t samplesBeforeOverflow = AudioQueueStreamLength - (_audioStreamReadPosition % AudioQueueStreamLength); size_t samplesBeforeOverflow = _streamLength - (_audioStreamReadPosition % _streamLength);
if(audioDataSampleSize <= samplesBeforeOverflow) if(audioDataSampleSize <= samplesBeforeOverflow)
{ {
memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition % AudioQueueStreamLength], buffer->mAudioDataByteSize); memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition % _streamLength], buffer->mAudioDataByteSize);
} }
else else
{ {
const size_t bytesRemaining = samplesBeforeOverflow * sizeof(int16_t); 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); memcpy(buffer->mAudioData, &_audioStream[0], buffer->mAudioDataByteSize - bytesRemaining);
} }
_audioStreamReadPosition += audioDataSampleSize; _audioStreamReadPosition += audioDataSampleSize;
@ -95,6 +100,11 @@ static void audioOutputCallback(
_writeLock = [[NSConditionLock alloc] initWithCondition:AudioQueueCanProceed]; _writeLock = [[NSConditionLock alloc] initWithCondition:AudioQueueCanProceed];
_samplingRate = samplingRate; _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 Describe a mono 16bit stream of the requested sampling rate
*/ */
@ -123,7 +133,7 @@ static void audioOutputCallback(
0, 0,
&_audioQueue)) &_audioQueue))
{ {
UInt32 bufferBytes = AudioQueueBufferLength * sizeof(int16_t); UInt32 bufferBytes = (UInt32)(_bufferLength * sizeof(int16_t));
int c = AudioQueueNumAudioBuffers; int c = AudioQueueNumAudioBuffers;
while(c--) while(c--)
@ -167,18 +177,18 @@ static void audioOutputCallback(
while(1) while(1)
{ {
[_writeLock lockWhenCondition:AudioQueueCanProceed]; [_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) 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)); memcpy(&_audioStream[0], &buffer[samplesBeforeOverflow], (lengthInSamples - samplesBeforeOverflow) * sizeof(int16_t));
} }
else else
{ {
memcpy(&_audioStream[_audioStreamWritePosition % AudioQueueStreamLength], buffer, lengthInSamples * sizeof(int16_t)); memcpy(&_audioStream[_audioStreamWritePosition % _streamLength], buffer, lengthInSamples * sizeof(int16_t));
} }
_audioStreamWritePosition += lengthInSamples; _audioStreamWritePosition += lengthInSamples;
@ -194,7 +204,7 @@ static void audioOutputCallback(
- (NSInteger)writeLockCondition - (NSInteger)writeLockCondition
{ {
return ((_audioStreamWritePosition - _audioStreamReadPosition) < (AudioQueueStreamLength - AudioQueueBufferLength)) ? AudioQueueCanProceed : AudioQueueWait; return ((_audioStreamWritePosition - _audioStreamReadPosition) < (_streamLength - _bufferLength)) ? AudioQueueCanProceed : AudioQueueWait;
} }
#pragma mark - Sampling Rate getters #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; return AudioObjectGetPropertyData([self defaultOutputDevice], &address, sizeof(AudioObjectPropertyAddress), NULL, &size, &samplingRate) ? 0.0 : samplingRate;
} }
+ (NSUInteger)bufferSize - (NSUInteger)bufferSize
{ {
return AudioQueueBufferLength; return _bufferLength;
} }
@end @end

View File

@ -63,7 +63,7 @@ class MachineDocument:
audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate)) audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate))
audioQueue.delegate = self audioQueue.delegate = self
self.machine().audioQueue = self.audioQueue 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 self.bestEffortUpdater.clockRate = self.machine().clockRate
@ -86,8 +86,9 @@ class MachineDocument:
} }
func runForNumberOfCycles(numberOfCycles: Int32) { func runForNumberOfCycles(numberOfCycles: Int32) {
let cyclesToRunFor = min(numberOfCycles, Int32(bestEffortUpdater.clockRate / 10))
if actionLock.tryLock() { if actionLock.tryLock() {
self.machine().runForNumberOfCycles(numberOfCycles) self.machine().runForNumberOfCycles(cyclesToRunFor)
actionLock.unlock() actionLock.unlock()
} }
} }