1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-25 02:29:08 +00:00

Made a first attempt to implement the full top-to-bottom change of clock rates, giving the Atari the ability to change rate when it switches to PAL mode, as it should always have been.

This commit is contained in:
Thomas Harte 2016-06-20 21:47:27 -04:00
parent 3591479571
commit 31b26b8118
4 changed files with 48 additions and 8 deletions

View File

@ -24,7 +24,8 @@ Machine::Machine() :
_upcomingEventsPointer(0), _upcomingEventsPointer(0),
_objectCounterPointer(0), _objectCounterPointer(0),
_stateByTime(_stateByExtendTime[0]), _stateByTime(_stateByExtendTime[0]),
_cycles_since_speaker_update(0) _cycles_since_speaker_update(0),
_is_pal_region(false)
{ {
memset(_collisions, 0xff, sizeof(_collisions)); memset(_collisions, 0xff, sizeof(_collisions));
set_reset_line(true); set_reset_line(true);
@ -71,7 +72,7 @@ void Machine::setup_output(float aspect_ratio)
"}"); "}");
_crt->set_output_device(Outputs::CRT::Television); _crt->set_output_device(Outputs::CRT::Television);
_speaker.set_input_rate(1194720 / 38); _speaker.set_input_rate((float)(get_clock_rate() / 38.0));
} }
void Machine::switch_region() void Machine::switch_region()
@ -90,8 +91,9 @@ void Machine::switch_region()
"return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);" "return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);"
"}"); "}");
_crt->set_new_timing(228, 312, Outputs::CRT::ColourSpace::YUV, 228, 1); _crt->set_new_timing(228, 312, Outputs::CRT::ColourSpace::YUV, 228, 1);
_is_pal_region = true;
// _speaker.set_input_rate(2 * 312 * 50); if(delegate) delegate->machine_did_change_clock_rate(this);
_speaker.set_input_rate((float)(get_clock_rate() / 38.0));
} }
void Machine::close_output() void Machine::close_output()
@ -106,6 +108,11 @@ Machine::~Machine()
close_output(); close_output();
} }
double Machine::get_clock_rate()
{
return _is_pal_region ? 1182298 : 1194720;
}
void Machine::update_timers(int mask) void Machine::update_timers(int mask)
{ {
unsigned int upcomingPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events; unsigned int upcomingPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events;
@ -733,7 +740,6 @@ void Machine::set_switch_is_enabled(Atari2600Switch input, bool state)
} }
} }
void Machine::set_rom(size_t length, const uint8_t *data) void Machine::set_rom(size_t length, const uint8_t *data)
{ {
_rom_size = 1024; _rom_size = 1024;
@ -816,7 +822,6 @@ void Atari2600::Speaker::set_control(int channel, uint8_t control)
#define advance_poly5(c) _poly5_counter[channel] = (_poly5_counter[channel] >> 1) | (((_poly5_counter[channel] << 4) ^ (_poly5_counter[channel] << 2))&0x010) #define advance_poly5(c) _poly5_counter[channel] = (_poly5_counter[channel] >> 1) | (((_poly5_counter[channel] << 4) ^ (_poly5_counter[channel] << 2))&0x010)
#define advance_poly9(c) _poly9_counter[channel] = (_poly9_counter[channel] >> 1) | (((_poly9_counter[channel] << 4) ^ (_poly9_counter[channel] << 8))&0x100) #define advance_poly9(c) _poly9_counter[channel] = (_poly9_counter[channel] >> 1) | (((_poly9_counter[channel] << 4) ^ (_poly9_counter[channel] << 8))&0x100)
void Atari2600::Speaker::get_samples(unsigned int number_of_samples, int16_t *target) void Atari2600::Speaker::get_samples(unsigned int number_of_samples, int16_t *target)
{ {
for(unsigned int c = 0; c < number_of_samples; c++) for(unsigned int c = 0; c < number_of_samples; c++)

View File

@ -95,7 +95,7 @@ class Machine: public CPU6502::Processor<Machine>, public CRTMachine::Machine {
virtual Outputs::CRT::CRT *get_crt() { return _crt; } virtual Outputs::CRT::CRT *get_crt() { return _crt; }
virtual Outputs::Speaker *get_speaker() { return &_speaker; } virtual Outputs::Speaker *get_speaker() { return &_speaker; }
virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); } virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
virtual double get_clock_rate() { return 1194720; } virtual double get_clock_rate();
// TODO: different rate for PAL // TODO: different rate for PAL
private: private:
@ -200,6 +200,9 @@ class Machine: public CPU6502::Processor<Machine>, public CRTMachine::Machine {
Outputs::CRT::CRT *_crt; Outputs::CRT::CRT *_crt;
Speaker _speaker; Speaker _speaker;
// current mode
bool _is_pal_region;
// speaker backlog accumlation counter // speaker backlog accumlation counter
unsigned int _cycles_since_speaker_update; unsigned int _cycles_since_speaker_update;
void update_audio(); void update_audio();

View File

@ -12,6 +12,7 @@ import AudioToolbox
class MachineDocument: class MachineDocument:
NSDocument, NSDocument,
NSWindowDelegate, NSWindowDelegate,
CSMachineDelegate,
CSOpenGLViewDelegate, CSOpenGLViewDelegate,
CSOpenGLViewResponderDelegate, CSOpenGLViewResponderDelegate,
CSBestEffortUpdaterDelegate, CSBestEffortUpdaterDelegate,
@ -56,6 +57,14 @@ class MachineDocument:
self.machine().setView(self.openGLView, aspectRatio: Float(displayAspectRatio.width / displayAspectRatio.height)) self.machine().setView(self.openGLView, aspectRatio: Float(displayAspectRatio.width / displayAspectRatio.height))
}) })
setupClockRate()
}
func machineDidChangeClockRate(machine: CSMachine!) {
setupClockRate()
}
private func setupClockRate() {
// establish and provide the audio queue, taking advice as to an appropriate sampling rate // establish and provide the audio queue, taking advice as to an appropriate sampling rate
let maximumSamplingRate = CSAudioQueue.preferredSamplingRate() let maximumSamplingRate = CSAudioQueue.preferredSamplingRate()
let selectedSamplingRate = self.machine().idealSamplingRateFromRange(NSRange(location: 0, length: NSInteger(maximumSamplingRate))) let selectedSamplingRate = self.machine().idealSamplingRateFromRange(NSRange(location: 0, length: NSInteger(maximumSamplingRate)))

View File

@ -12,6 +12,7 @@
@interface CSMachine() @interface CSMachine()
- (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length; - (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length;
- (void)machineDidChangeClockRate;
@end @end
struct SpeakerDelegate: public Outputs::Speaker::Delegate { struct SpeakerDelegate: public Outputs::Speaker::Delegate {
@ -21,14 +22,37 @@ struct SpeakerDelegate: public Outputs::Speaker::Delegate {
} }
}; };
struct MachineDelegate: CRTMachine::Machine::Delegate {
__weak CSMachine *machine;
void machine_did_change_clock_rate(CRTMachine::Machine *sender) {
[machine machineDidChangeClockRate];
}
};
@implementation CSMachine { @implementation CSMachine {
SpeakerDelegate _speakerDelegate; SpeakerDelegate _speakerDelegate;
MachineDelegate _machineDelegate;
}
- (instancetype)init {
self = [super init];
if(self)
{
_machineDelegate.machine = self;
self.machine->set_delegate(&_machineDelegate);
_speakerDelegate.machine = self;
}
return self;
} }
- (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_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]; [self.audioQueue enqueueAudioBuffer:samples numberOfSamples:(unsigned int)length];
} }
- (void)machineDidChangeClockRate {
[self.delegate machineDidChangeClockRate:self];
}
- (void)dealloc { - (void)dealloc {
[_view performWithGLContext:^{ [_view performWithGLContext:^{
@synchronized(self) { @synchronized(self) {
@ -50,7 +74,6 @@ struct SpeakerDelegate: public Outputs::Speaker::Delegate {
- (void)setAudioSamplingRate:(float)samplingRate bufferSize:(NSUInteger)bufferSize { - (void)setAudioSamplingRate:(float)samplingRate bufferSize:(NSUInteger)bufferSize {
@synchronized(self) { @synchronized(self) {
_speakerDelegate.machine = self;
[self setSpeakerDelegate:&_speakerDelegate sampleRate:samplingRate bufferSize:bufferSize]; [self setSpeakerDelegate:&_speakerDelegate sampleRate:samplingRate bufferSize:bufferSize];
} }
} }