1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 23:52:26 +00:00

Consolidated a little more within the common code, adding sampling rate selection based on querying the machine.

This commit is contained in:
Thomas Harte 2016-06-01 19:04:07 -04:00
parent 50543e9676
commit 8623dc2833
7 changed files with 85 additions and 25 deletions

View File

@ -21,11 +21,6 @@ class Atari2600Document: MachineDocument {
self.intendedCyclesPerSecond = 1194720
}
override func windowControllerDidLoadNib(aController: NSWindowController) {
super.windowControllerDidLoadNib(aController)
atari2600.setView(openGLView, aspectRatio: 4.0 / 3.0)
}
override class func autosavesInPlace() -> Bool {
return true
}

View File

@ -16,9 +16,12 @@ class ElectronDocument: MachineDocument {
return electron
}
override func aspectRatio() -> NSSize {
return NSSize(width: 11.0, height: 10.0)
}
override func windowControllerDidLoadNib(aController: NSWindowController) {
super.windowControllerDidLoadNib(aController)
aController.window?.contentAspectRatio = NSSize(width: 11.0, height: 10.0)
self.intendedCyclesPerSecond = 2000000
@ -29,10 +32,6 @@ class ElectronDocument: MachineDocument {
self.electron.setBASICROM(NSData(contentsOfFile: basicPath)!)
}
openGLView.performWithGLContext({
self.electron.setView(self.openGLView, aspectRatio: 11.0 / 10.0)
})
establishStoredOptions()
}

View File

@ -17,6 +17,10 @@ class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDe
return nil
}
func aspectRatio() -> NSSize {
return NSSize(width: 4.0, height: 3.0)
}
@IBOutlet weak var openGLView: CSOpenGLView! {
didSet {
openGLView.delegate = self
@ -29,16 +33,24 @@ class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDe
optionsPanel?.setIsVisible(true)
}
lazy var audioQueue = AudioQueue()
var audioQueue : AudioQueue! = nil
override func windowControllerDidLoadNib(aController: NSWindowController) {
super.windowControllerDidLoadNib(aController)
// bind the content aspect ratio to remain 4:3 from now on as a default
aController.window?.contentAspectRatio = NSSize(width: 4.0, height: 3.0)
// establish the output aspect ratio and audio
let displayAspectRatio = self.aspectRatio()
aController.window?.contentAspectRatio = displayAspectRatio
openGLView.performWithGLContext({
self.machine().setView(self.openGLView, aspectRatio: Float(displayAspectRatio.width / displayAspectRatio.height))
})
// provide the audio queue
// establish and provide the audio queue, taking advice as to an appropriate sampling rate
let maximumSamplingRate = AudioQueue.preferredSamplingRate()
let selectedSamplingRate = self.machine().idealSamplingRateFromRange(NSRange(location: 0, length: NSInteger(maximumSamplingRate)))
audioQueue = AudioQueue(samplingRate: Float64(selectedSamplingRate))
self.machine().audioQueue = self.audioQueue
self.machine().setAudioSamplingRate(selectedSamplingRate)
}
override func close() {

View File

@ -10,6 +10,11 @@
@interface AudioQueue : NSObject
- (instancetype)initWithSamplingRate:(Float64)samplingRate;
- (void)enqueueAudioBuffer:(const int16_t *)buffer numberOfSamples:(size_t)lengthInSamples;
@property (nonatomic, readonly) Float64 samplingRate;
+ (Float64)preferredSamplingRate;
@end

View File

@ -85,20 +85,21 @@ static void audioOutputCallback(
[(__bridge AudioQueue *)inUserData audioQueue:inAQ didCallbackWithBuffer:inBuffer];
}
- (instancetype)init
- (instancetype)initWithSamplingRate:(Float64)samplingRate
{
self = [super init];
if(self)
{
_writeLock = [[NSConditionLock alloc] initWithCondition:AudioQueueCanProceed];
_samplingRate = samplingRate;
/*
Describe a mono, 16bit, 44.1Khz audio format
*/
AudioStreamBasicDescription outputDescription;
outputDescription.mSampleRate = 44100;
outputDescription.mSampleRate = samplingRate;
outputDescription.mFormatID = kAudioFormatLinearPCM;
outputDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
@ -113,13 +114,13 @@ static void audioOutputCallback(
// create an audio output queue along those lines
if(!AudioQueueNewOutput(
&outputDescription,
audioOutputCallback,
(__bridge void *)(self),
NULL,
kCFRunLoopCommonModes,
0,
&_audioQueue))
&outputDescription,
audioOutputCallback,
(__bridge void *)(self),
NULL,
kCFRunLoopCommonModes,
0,
&_audioQueue))
{
UInt32 bufferBytes = AudioQueueBufferLength * sizeof(int16_t);
@ -139,6 +140,11 @@ static void audioOutputCallback(
return self;
}
- (instancetype)init
{
return [self initWithSamplingRate:[[self class] preferredSamplingRate]];
}
- (void)dealloc
{
[_writeLock lock];
@ -190,4 +196,28 @@ static void audioOutputCallback(
return ((_audioStreamWritePosition - _audioStreamReadPosition) < (AudioQueueStreamLength - AudioQueueBufferLength)) ? AudioQueueCanProceed : AudioQueueWait;
}
+ (AudioDeviceID)defaultOutputDevice
{
AudioObjectPropertyAddress address;
address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
address.mScope = kAudioObjectPropertyScopeGlobal;
address.mElement = kAudioObjectPropertyElementMaster;
AudioDeviceID deviceID;
UInt32 size = sizeof(AudioDeviceID);
return AudioHardwareServiceGetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, &size, &deviceID) ? 0 : deviceID;
}
+ (Float64)preferredSamplingRate
{
AudioObjectPropertyAddress address;
address.mSelector = kAudioDevicePropertyNominalSampleRate;
address.mScope = kAudioObjectPropertyScopeGlobal;
address.mElement = kAudioObjectPropertyElementMaster;
Float64 samplingRate;
UInt32 size = sizeof(Float64);
return AudioHardwareServiceGetPropertyData([self defaultOutputDevice], &address, 0, NULL, &size, &samplingRate) ? 0.0 : samplingRate;
}
@end

View File

@ -14,6 +14,9 @@
- (void)runForNumberOfCycles:(int)numberOfCycles;
- (int)idealSamplingRateFromRange:(NSRange)range;
- (void)setAudioSamplingRate:(int)samplingRate;
- (void)setView:(CSOpenGLView *)view aspectRatio:(float)aspectRatio;
- (void)drawViewForPixelSize:(CGSize)pixelSize onlyIfDirty:(BOOL)onlyIfDirty;

View File

@ -34,8 +34,6 @@ struct SpeakerDelegate: public Outputs::Speaker::Delegate {
if(self) {
_serialDispatchQueue = dispatch_queue_create("Machine queue", DISPATCH_QUEUE_SERIAL);
_speakerDelegate.machine = self;
[self setSpeakerDelegate:&_speakerDelegate sampleRate:44100];
}
return self;
@ -49,6 +47,24 @@ struct SpeakerDelegate: public Outputs::Speaker::Delegate {
}];
}
- (int)idealSamplingRateFromRange:(NSRange)range {
@synchronized(self) {
Outputs::Speaker *speaker = self.machine->get_speaker();
if(speaker)
{
return speaker->get_ideal_clock_rate_in_range((int)range.location, (int)(range.location + range.length));
}
return (int)range.location;
}
}
- (void)setAudioSamplingRate:(int)samplingRate {
@synchronized(self) {
_speakerDelegate.machine = self;
[self setSpeakerDelegate:&_speakerDelegate sampleRate:samplingRate];
}
}
- (BOOL)setSpeakerDelegate:(Outputs::Speaker::Delegate *)delegate sampleRate:(int)sampleRate {
@synchronized(self) {
Outputs::Speaker *speaker = self.machine->get_speaker();