From 8907d0a9a7d989361b68c1822c074c97f679ba5c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 14 May 2018 21:56:14 -0400 Subject: [PATCH 1/3] Adds a low-pass filter to the Apple II's audio. --- Machines/AppleII/AppleII.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index eddc22d6d..fb0905c24 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -139,6 +139,9 @@ class ConcreteMachine: // decision to sample it at seven times the CPU clock (plus stretches). speaker_.set_input_rate(static_cast(master_clock / (2.0 * static_cast(audio_divider)))); + // Apply a 10Khz low-pass filter. This was picked by ear. + speaker_.set_high_frequency_cutoff(10000); + // Also, start with randomised memory contents. Memory::Fuzz(ram_, sizeof(ram_)); } From 7c2721d54d1590e629874ec9b854eb66cd0e9189 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 15 May 2018 20:43:13 -0400 Subject: [PATCH 2/3] Adjusted number again. But we'll see. --- Machines/AppleII/AppleII.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index fb0905c24..b5aa63744 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -139,8 +139,10 @@ class ConcreteMachine: // decision to sample it at seven times the CPU clock (plus stretches). speaker_.set_input_rate(static_cast(master_clock / (2.0 * static_cast(audio_divider)))); - // Apply a 10Khz low-pass filter. This was picked by ear. - speaker_.set_high_frequency_cutoff(10000); + // Apply a 6Khz low-pass filter. This was picked by ear and by an attempt to understand the + // Apple II schematic but, well, I don't claim much insight on the latter. This is definitely + // something to review in the future. + speaker_.set_high_frequency_cutoff(6000); // Also, start with randomised memory contents. Memory::Fuzz(ram_, sizeof(ram_)); From f7decd80b6a7a70dd8f52ce471e5a68bd70f5136 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 15 May 2018 21:12:43 -0400 Subject: [PATCH 3/3] As an initial step, ensured latency doesn't pile up endlessly. --- .../Mac/Clock Signal/Audio/CSAudioQueue.m | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m index b2435ab50..398cc01ae 100644 --- a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m +++ b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m @@ -27,9 +27,9 @@ static NSLock *CSAudioQueueDeallocLock; @implementation CSAudioQueue { AudioQueueRef _audioQueue; - AudioQueueBufferRef _storedBuffers[NumberOfStoredAudioQueueBuffer]; NSLock *_storedBuffersLock; CSWeakAudioQueuePointer *_weakPointer; + int _enqueuedBuffers; } #pragma mark - AudioQueue callbacks @@ -39,16 +39,19 @@ static NSLock *CSAudioQueueDeallocLock; */ - (BOOL)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer { [_storedBuffersLock lock]; - for(int c = 0; c < NumberOfStoredAudioQueueBuffer; c++) { - if(!_storedBuffers[c] || buffer->mAudioDataBytesCapacity > _storedBuffers[c]->mAudioDataBytesCapacity) { - if(_storedBuffers[c]) AudioQueueFreeBuffer(_audioQueue, _storedBuffers[c]); - _storedBuffers[c] = buffer; - [_storedBuffersLock unlock]; - return YES; - } + --_enqueuedBuffers; + + // If that leaves nothing in the queue, re-enqueue whatever just came back in order to keep the + // queue going. AudioQueues seem to stop playing and never restart no matter how much encouragement + // if exhausted. + if(!_enqueuedBuffers) { + AudioQueueEnqueueBuffer(theAudioQueue, buffer, 0, NULL); + ++_enqueuedBuffers; + } else { + AudioQueueFreeBuffer(_audioQueue, buffer); } + [_storedBuffersLock unlock]; - AudioQueueFreeBuffer(_audioQueue, buffer); return YES; } @@ -158,18 +161,12 @@ static void audioOutputCallback( size_t bufferBytes = lengthInSamples * sizeof(int16_t); [_storedBuffersLock lock]; - for(int c = 0; c < NumberOfStoredAudioQueueBuffer; c++) { - if(_storedBuffers[c] && _storedBuffers[c]->mAudioDataBytesCapacity >= bufferBytes) { - memcpy(_storedBuffers[c]->mAudioData, buffer, bufferBytes); - _storedBuffers[c]->mAudioDataByteSize = (UInt32)bufferBytes; - - AudioQueueEnqueueBuffer(_audioQueue, _storedBuffers[c], 0, NULL); - _storedBuffers[c] = NULL; - [_storedBuffersLock unlock]; - return; - } + // Don't enqueue more than 4 buffers ahead of now, to ensure not too much latency accrues. + if(_enqueuedBuffers > 4) { + [_storedBuffersLock unlock]; + return; } - [_storedBuffersLock unlock]; + ++_enqueuedBuffers; AudioQueueBufferRef newBuffer; AudioQueueAllocateBuffer(_audioQueue, (UInt32)bufferBytes * 2, &newBuffer); @@ -177,6 +174,7 @@ static void audioOutputCallback( newBuffer->mAudioDataByteSize = (UInt32)bufferBytes; AudioQueueEnqueueBuffer(_audioQueue, newBuffer, 0, NULL); + [_storedBuffersLock unlock]; } #pragma mark - Sampling Rate getters