mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Made an attempt also to trigger updates upon audio packets being returned, and significantly to reduce the size and quantity of those. This should get down to 11ms latency if the output wave is 44100; I might need to scale up the buffer size as the sampling rate increases or this is going to get crazy at 192Khz.
This commit is contained in:
parent
00a9f1bf24
commit
2ee78d42b9
@ -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<AudioQueueDelegate> delegate;
|
||||
@property (nonatomic, weak) id<CSAudioQueueDelegate> delegate;
|
||||
|
||||
+ (Float64)preferredSamplingRate;
|
||||
+ (NSUInteger)bufferSize;
|
||||
|
||||
@end
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user