1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-16 05:27:43 +00:00

Merge pull request #444 from TomHarte/AppleAudio

Introduces a low-pass filter for the Apple II
This commit is contained in:
Thomas Harte
2018-05-15 21:33:52 -04:00
committed by GitHub
2 changed files with 23 additions and 20 deletions

View File

@@ -139,6 +139,11 @@ class ConcreteMachine:
// decision to sample it at seven times the CPU clock (plus stretches). // 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)))); 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. // Also, start with randomised memory contents.
Memory::Fuzz(ram_, sizeof(ram_)); Memory::Fuzz(ram_, sizeof(ram_));
} }

View File

@@ -27,9 +27,9 @@ static NSLock *CSAudioQueueDeallocLock;
@implementation CSAudioQueue { @implementation CSAudioQueue {
AudioQueueRef _audioQueue; AudioQueueRef _audioQueue;
AudioQueueBufferRef _storedBuffers[NumberOfStoredAudioQueueBuffer];
NSLock *_storedBuffersLock; NSLock *_storedBuffersLock;
CSWeakAudioQueuePointer *_weakPointer; CSWeakAudioQueuePointer *_weakPointer;
int _enqueuedBuffers;
} }
#pragma mark - AudioQueue callbacks #pragma mark - AudioQueue callbacks
@@ -39,16 +39,19 @@ static NSLock *CSAudioQueueDeallocLock;
*/ */
- (BOOL)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer { - (BOOL)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer {
[_storedBuffersLock lock]; [_storedBuffersLock lock];
for(int c = 0; c < NumberOfStoredAudioQueueBuffer; c++) { --_enqueuedBuffers;
if(!_storedBuffers[c] || buffer->mAudioDataBytesCapacity > _storedBuffers[c]->mAudioDataBytesCapacity) {
if(_storedBuffers[c]) AudioQueueFreeBuffer(_audioQueue, _storedBuffers[c]); // If that leaves nothing in the queue, re-enqueue whatever just came back in order to keep the
_storedBuffers[c] = buffer; // queue going. AudioQueues seem to stop playing and never restart no matter how much encouragement
[_storedBuffersLock unlock]; // if exhausted.
return YES; if(!_enqueuedBuffers) {
} AudioQueueEnqueueBuffer(theAudioQueue, buffer, 0, NULL);
++_enqueuedBuffers;
} else {
AudioQueueFreeBuffer(_audioQueue, buffer);
} }
[_storedBuffersLock unlock]; [_storedBuffersLock unlock];
AudioQueueFreeBuffer(_audioQueue, buffer);
return YES; return YES;
} }
@@ -158,18 +161,12 @@ static void audioOutputCallback(
size_t bufferBytes = lengthInSamples * sizeof(int16_t); size_t bufferBytes = lengthInSamples * sizeof(int16_t);
[_storedBuffersLock lock]; [_storedBuffersLock lock];
for(int c = 0; c < NumberOfStoredAudioQueueBuffer; c++) { // Don't enqueue more than 4 buffers ahead of now, to ensure not too much latency accrues.
if(_storedBuffers[c] && _storedBuffers[c]->mAudioDataBytesCapacity >= bufferBytes) { if(_enqueuedBuffers > 4) {
memcpy(_storedBuffers[c]->mAudioData, buffer, bufferBytes); [_storedBuffersLock unlock];
_storedBuffers[c]->mAudioDataByteSize = (UInt32)bufferBytes; return;
AudioQueueEnqueueBuffer(_audioQueue, _storedBuffers[c], 0, NULL);
_storedBuffers[c] = NULL;
[_storedBuffersLock unlock];
return;
}
} }
[_storedBuffersLock unlock]; ++_enqueuedBuffers;
AudioQueueBufferRef newBuffer; AudioQueueBufferRef newBuffer;
AudioQueueAllocateBuffer(_audioQueue, (UInt32)bufferBytes * 2, &newBuffer); AudioQueueAllocateBuffer(_audioQueue, (UInt32)bufferBytes * 2, &newBuffer);
@@ -177,6 +174,7 @@ static void audioOutputCallback(
newBuffer->mAudioDataByteSize = (UInt32)bufferBytes; newBuffer->mAudioDataByteSize = (UInt32)bufferBytes;
AudioQueueEnqueueBuffer(_audioQueue, newBuffer, 0, NULL); AudioQueueEnqueueBuffer(_audioQueue, newBuffer, 0, NULL);
[_storedBuffersLock unlock];
} }
#pragma mark - Sampling Rate getters #pragma mark - Sampling Rate getters