diff --git a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h index 1e0357927..add6e78c7 100644 --- a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h +++ b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.h @@ -10,7 +10,7 @@ @class CSAudioQueue; -@protocol AudioQueueDelegate +@protocol CSAudioQueueDelegate - (void)audioQueueDidCompleteBuffer:(nonnull CSAudioQueue *)audioQueue; @end @@ -20,8 +20,9 @@ - (void)enqueueAudioBuffer:(nonnull const int16_t *)buffer numberOfSamples:(size_t)lengthInSamples; @property (nonatomic, readonly) Float64 samplingRate; -@property (nonatomic, weak) id delegate; +@property (nonatomic, weak) id delegate; + (Float64)preferredSamplingRate; ++ (NSUInteger)bufferSize; @end diff --git a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m index b7df1b614..8617b64a6 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 AudioQueueNumAudioBuffers 4 -#define AudioQueueStreamLength 4096 -#define AudioQueueBufferLength 512 +#define AudioQueueStreamLength 768 +#define AudioQueueBufferLength 256 +#define AudioQueueNumAudioBuffers (AudioQueueStreamLength/AudioQueueBufferLength) enum { AudioQueueCanProceed, @@ -30,7 +30,6 @@ enum { int _dequeuedCount; } - #pragma mark - #pragma mark AudioQueue callbacks and setup; for pushing audio out @@ -224,4 +223,9 @@ static void audioOutputCallback( return AudioObjectGetPropertyData([self defaultOutputDevice], &address, sizeof(AudioObjectPropertyAddress), NULL, &size, &samplingRate) ? 0.0 : samplingRate; } ++ (NSUInteger)bufferSize +{ + return AudioQueueBufferLength; +} + @end diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index fbccbad61..c8d4c0610 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -9,8 +9,14 @@ import Cocoa import AudioToolbox -class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDelegate, CSBestEffortUpdaterDelegate, NSWindowDelegate { - +class MachineDocument: + NSDocument, + NSWindowDelegate, + CSOpenGLViewDelegate, + CSOpenGLViewResponderDelegate, + CSBestEffortUpdaterDelegate, + CSAudioQueueDelegate +{ lazy var actionLock = NSLock() lazy var drawLock = NSLock() func machine() -> CSMachine! { @@ -55,8 +61,9 @@ class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDe let selectedSamplingRate = self.machine().idealSamplingRateFromRange(NSRange(location: 0, length: NSInteger(maximumSamplingRate))) if selectedSamplingRate > 0 { audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate)) + audioQueue.delegate = self self.machine().audioQueue = self.audioQueue - self.machine().setAudioSamplingRate(selectedSamplingRate) + self.machine().setAudioSamplingRate(selectedSamplingRate, bufferSize:CSAudioQueue.bufferSize() / 2) } self.bestEffortUpdater.clockRate = self.machine().clockRate @@ -73,10 +80,18 @@ class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDe super.close() } + // MARK: CSBestEffortUpdaterDelegate final func bestEffortUpdater(bestEffortUpdater: CSBestEffortUpdater!, runForCycles cycles: UInt, didSkipPreviousUpdate: Bool) { runForNumberOfCycles(Int32(cycles)) } + func runForNumberOfCycles(numberOfCycles: Int32) { + if actionLock.tryLock() { + self.machine().runForNumberOfCycles(numberOfCycles) + actionLock.unlock() + } + } + // MARK: Utilities for children func dataForResource(name : String, ofType type: String, inDirectory directory: String) -> NSData? { if let path = NSBundle.mainBundle().pathForResource(name, ofType: type, inDirectory: directory) { @@ -86,15 +101,13 @@ class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDe return nil } - // MARK: CSOpenGLViewDelegate - func runForNumberOfCycles(numberOfCycles: Int32) { - if actionLock.tryLock() { - self.machine().runForNumberOfCycles(numberOfCycles) - actionLock.unlock() - } + // MARK: CSAudioQueueDelegate + final func audioQueueDidCompleteBuffer(audioQueue: CSAudioQueue) { + bestEffortUpdater.update() } - func openGLView(view: CSOpenGLView, drawViewOnlyIfDirty onlyIfDirty: Bool) { + // MARK: CSOpenGLViewDelegate + final func openGLView(view: CSOpenGLView, drawViewOnlyIfDirty onlyIfDirty: Bool) { bestEffortUpdater.update() if drawLock.tryLock() { self.machine().drawViewForPixelSize(view.backingSize, onlyIfDirty: onlyIfDirty) diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h index 4feb5b866..7d35033a1 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h @@ -20,7 +20,7 @@ - (void)runForNumberOfCycles:(int)numberOfCycles; - (float)idealSamplingRateFromRange:(NSRange)range; -- (void)setAudioSamplingRate:(float)samplingRate; +- (void)setAudioSamplingRate:(float)samplingRate bufferSize:(NSUInteger)bufferSize; - (void)setView:(CSOpenGLView *)view aspectRatio:(float)aspectRatio; - (void)drawViewForPixelSize:(CGSize)pixelSize onlyIfDirty:(BOOL)onlyIfDirty; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 8c1b0074b..15c17ce83 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -47,19 +47,19 @@ struct SpeakerDelegate: public Outputs::Speaker::Delegate { } } -- (void)setAudioSamplingRate:(float)samplingRate { +- (void)setAudioSamplingRate:(float)samplingRate bufferSize:(NSUInteger)bufferSize { @synchronized(self) { _speakerDelegate.machine = self; - [self setSpeakerDelegate:&_speakerDelegate sampleRate:samplingRate]; + [self setSpeakerDelegate:&_speakerDelegate sampleRate:samplingRate bufferSize:bufferSize]; } } -- (BOOL)setSpeakerDelegate:(Outputs::Speaker::Delegate *)delegate sampleRate:(float)sampleRate { +- (BOOL)setSpeakerDelegate:(Outputs::Speaker::Delegate *)delegate sampleRate:(float)sampleRate bufferSize:(NSUInteger)bufferSize { @synchronized(self) { Outputs::Speaker *speaker = self.machine->get_speaker(); if(speaker) { - speaker->set_output_rate(sampleRate, 512); + speaker->set_output_rate(sampleRate, (int)bufferSize); speaker->set_delegate(delegate); return YES; }