diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index eddc22d6d..b5aa63744 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -139,6 +139,11 @@ class ConcreteMachine: // decision to sample it at seven times the CPU clock (plus stretches). speaker_.set_input_rate(static_cast<float>(master_clock / (2.0 * static_cast<float>(audio_divider)))); + // 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_)); } 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