1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-30 22:29:56 +00:00

Here, at last, is _some_ audio output, at least.

This commit is contained in:
Thomas Harte 2016-01-14 20:33:22 -05:00
parent afde8dac49
commit 38ffcaa262
12 changed files with 170 additions and 10 deletions

View File

@ -493,7 +493,7 @@ void Machine::set_key_state(Key key, bool isPressed)
}
}
void Machine::Speaker::get_sample_range(uint64_t start_time, int number_of_samples, uint16_t *target)
void Machine::Speaker::get_sample_range(uint64_t start_time, int number_of_samples, int16_t *target)
{
if(!_is_enabled)
{
@ -501,7 +501,7 @@ void Machine::Speaker::get_sample_range(uint64_t start_time, int number_of_sampl
}
else
{
*target = ((start_time / _divider)&1) ? 255 : 0;
*target = ((start_time / (_divider+1))&1) ? 255 : 0;
}
}
@ -513,5 +513,5 @@ void Machine::Speaker::set_divider(uint8_t divider)
void Machine::Speaker::set_is_enabled(bool is_enabled)
{
_is_enabled = false;
_is_enabled = is_enabled;
}

View File

@ -103,7 +103,7 @@ class Machine: public CPU6502::Processor<Machine> {
void set_is_enabled(bool is_enabled);
inline bool get_is_enabled() { return _is_enabled; }
void get_sample_range(uint64_t start_time, int number_of_samples, uint16_t *target);
void get_sample_range(uint64_t start_time, int number_of_samples, int16_t *target);
private:
uint8_t _divider;

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
4B0EBFB81C487F2F00A11F35 /* AudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B0EBFB71C487F2F00A11F35 /* AudioQueue.m */; };
4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; };
4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; };
4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414591B58879D00E04248 /* CPU6502AllRAM.cpp */; };
@ -321,6 +322,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
4B0EBFB61C487F2F00A11F35 /* AudioQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioQueue.h; sourceTree = "<group>"; };
4B0EBFB71C487F2F00A11F35 /* AudioQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioQueue.m; sourceTree = "<group>"; };
4B1414501B58848C00E04248 /* ClockSignal-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ClockSignal-Bridging-Header.h"; sourceTree = "<group>"; };
4B1414571B58879D00E04248 /* CPU6502.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPU6502.cpp; sourceTree = "<group>"; };
4B1414581B58879D00E04248 /* CPU6502.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPU6502.hpp; sourceTree = "<group>"; };
@ -738,6 +741,8 @@
4B55CE521C3B7ABF0093A61B /* CSElectron.h */,
4B55CE531C3B7ABF0093A61B /* CSElectron.mm */,
4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */,
4B0EBFB61C487F2F00A11F35 /* AudioQueue.h */,
4B0EBFB71C487F2F00A11F35 /* AudioQueue.m */,
);
path = Wrappers;
sourceTree = "<group>";
@ -1547,6 +1552,7 @@
4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */,
4B55CE4B1C3B3B0C0093A61B /* CSAtari2600.mm in Sources */,
4B55CE581C3B7D360093A61B /* Atari2600Document.swift in Sources */,
4B0EBFB81C487F2F00A11F35 /* AudioQueue.m in Sources */,
4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */,
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */,
4B55CE4E1C3B3BDA0093A61B /* CSMachine.mm in Sources */,

View File

@ -6,3 +6,4 @@
#import "CSAtari2600.h"
#import "CSElectron.h"
#import "CSCathodeRayView.h"
#import "AudioQueue.h"

View File

@ -27,6 +27,7 @@ class ElectronDocument: MachineDocument {
override func windowControllerDidLoadNib(aController: NSWindowController) {
super.windowControllerDidLoadNib(aController)
electron.view = openGLView
electron.audioQueue = self.audioQueue
openGLView.frameBounds = CGRectMake(0.0225, 0.0625, 0.75, 0.75)
}

View File

@ -7,6 +7,7 @@
//
import Cocoa
import AudioToolbox
class MachineDocument: NSDocument, CSCathodeRayViewDelegate, CSCathodeRayViewResponderDelegate {
@ -17,6 +18,8 @@ class MachineDocument: NSDocument, CSCathodeRayViewDelegate, CSCathodeRayViewRes
}
}
lazy var audioQueue = AudioQueue()
override func windowControllerDidLoadNib(aController: NSWindowController) {
super.windowControllerDidLoadNib(aController)

View File

@ -0,0 +1,15 @@
//
// AudioQueue.h
// Clock Signal
//
// Created by Thomas Harte on 14/01/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface AudioQueue : NSObject
- (void)enqueueAudioBuffer:(const int16_t *)buffer numberOfSamples:(unsigned int)lengthInSamples;
@end

View File

@ -0,0 +1,131 @@
//
// AudioQueue.m
// Clock Signal
//
// Created by Thomas Harte on 14/01/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#import "AudioQueue.h"
@import AudioToolbox;
#define AudioQueueNumAudioBuffers 3
#define AudioQueueStreamLength 2048
#define AudioQueueBufferLength 512
@implementation AudioQueue
{
AudioQueueRef _audioQueue;
AudioQueueBufferRef _audioBuffers[AudioQueueNumAudioBuffers];
unsigned int _audioStreamReadPosition, _audioStreamWritePosition, _queuedAudioStreamSegments;
int16_t _audioStream[AudioQueueStreamLength];
BOOL _isOutputtingAudio;
}
#pragma mark -
#pragma mark AudioQueue callbacks and setup; for pushing audio out
- (void)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer
{
@synchronized(self)
{
if(_queuedAudioStreamSegments > AudioQueueNumAudioBuffers-1) _isOutputtingAudio = YES;
if(_isOutputtingAudio && _queuedAudioStreamSegments)
{
_queuedAudioStreamSegments--;
memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition], buffer->mAudioDataByteSize);
_audioStreamReadPosition = (_audioStreamReadPosition + AudioQueueBufferLength)%AudioQueueStreamLength;
}
else
{
memset(buffer->mAudioData, 0, buffer->mAudioDataByteSize);
_isOutputtingAudio = NO;
}
AudioQueueEnqueueBuffer(theAudioQueue, buffer, 0, NULL);
}
}
static void audioOutputCallback(
void *inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer)
{
[(__bridge AudioQueue *)inUserData audioQueue:inAQ didCallbackWithBuffer:inBuffer];
}
- (instancetype)init
{
self = [super init];
if(self)
{
/*
Describe a mono, 16bit, 44.1Khz audio format
*/
AudioStreamBasicDescription outputDescription;
outputDescription.mSampleRate = 44100;
outputDescription.mFormatID = kAudioFormatLinearPCM;
outputDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
outputDescription.mBytesPerPacket = 2;
outputDescription.mFramesPerPacket = 1;
outputDescription.mBytesPerFrame = 2;
outputDescription.mChannelsPerFrame = 1;
outputDescription.mBitsPerChannel = 16;
outputDescription.mReserved = 0;
// create an audio output queue along those lines
if(!AudioQueueNewOutput(
&outputDescription,
audioOutputCallback,
(__bridge void *)(self),
NULL,
kCFRunLoopCommonModes,
0,
&_audioQueue))
{
_audioStreamWritePosition = AudioQueueBufferLength;
UInt32 bufferBytes = AudioQueueBufferLength * sizeof(int16_t);
int c = AudioQueueNumAudioBuffers;
while(c--)
{
AudioQueueAllocateBuffer(_audioQueue, bufferBytes, &_audioBuffers[c]);
memset(_audioBuffers[c]->mAudioData, 0, bufferBytes);
_audioBuffers[c]->mAudioDataByteSize = bufferBytes;
AudioQueueEnqueueBuffer(_audioQueue, _audioBuffers[c], 0, NULL);
}
AudioQueueStart(_audioQueue, NULL);
}
}
return self;
}
- (void)enqueueAudioBuffer:(const int16_t *)buffer numberOfSamples:(unsigned int)lengthInSamples
{
@synchronized(self)
{
memcpy(&_audioStream[_audioStreamWritePosition], buffer, lengthInSamples * sizeof(int16_t));
_audioStreamWritePosition = (_audioStreamWritePosition + lengthInSamples)%AudioQueueStreamLength;
if(_queuedAudioStreamSegments == (AudioQueueStreamLength/AudioQueueBufferLength))
{
_audioStreamReadPosition = (_audioStreamReadPosition + lengthInSamples)%AudioQueueStreamLength;
}
else
{
_queuedAudioStreamSegments++;
}
}
}
@end

View File

@ -19,6 +19,6 @@
- (void)perform:(dispatch_block_t)action;
- (void)crt:(Outputs::CRT *)crt didEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync;
- (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const uint16_t *)samples length:(int)length;
- (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length;
@end

View File

@ -8,11 +8,13 @@
#import <Foundation/Foundation.h>
#import "CSCathodeRayView.h"
#import "AudioQueue.h"
@interface CSMachine : NSObject
- (void)runForNumberOfCycles:(int)numberOfCycles;
@property (nonatomic, weak) CSCathodeRayView *view;
@property (nonatomic, weak) AudioQueue *audioQueue;
@end

View File

@ -18,7 +18,7 @@ struct CRTDelegate: public Outputs::CRT::Delegate {
struct SpeakerDelegate: public Outputs::Speaker::Delegate {
__weak CSMachine *machine;
void speaker_did_complete_samples(Outputs::Speaker *speaker, const uint16_t *buffer, int buffer_size) {
void speaker_did_complete_samples(Outputs::Speaker *speaker, const int16_t *buffer, int buffer_size) {
[machine speaker:speaker didCompleteSamples:buffer length:buffer_size];
}
};
@ -44,7 +44,8 @@ typedef NS_ENUM(NSInteger, CSAtari2600RunningState) {
if([self.view pushFrame:frame]) crt->return_frame();
}
- (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const uint16_t *)samples length:(int)length {
- (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length {
[self.audioQueue enqueueAudioBuffer:samples numberOfSamples:(unsigned int)length];
}
- (void)runForNumberOfCycles:(int)cycles {

View File

@ -19,7 +19,7 @@ class Speaker {
public:
class Delegate {
public:
virtual void speaker_did_complete_samples(Speaker *speaker, const uint16_t *buffer, int buffer_size) = 0;
virtual void speaker_did_complete_samples(Speaker *speaker, const int16_t *buffer, int buffer_size) = 0;
};
void set_output_rate(int cycles_per_second, int buffer_size)
@ -28,7 +28,7 @@ class Speaker {
if(_buffer_size != buffer_size)
{
delete[] _buffer_in_progress;
_buffer_in_progress = new uint16_t[buffer_size];
_buffer_in_progress = new int16_t[buffer_size];
_buffer_size = buffer_size;
}
set_needs_updated_filter_coefficients();
@ -52,7 +52,7 @@ class Speaker {
}
protected:
uint16_t *_buffer_in_progress;
int16_t *_buffer_in_progress;
int _buffer_size;
int _buffer_in_progress_pointer;
int _number_of_taps;