diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 7cf96d27e..f9229f97c 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -25,7 +25,8 @@ Machine::Machine() : _tiaInputValue{0xff, 0xff}, _upcomingEventsPointer(0), _objectCounterPointer(0), - _stateByTime(_stateByExtendTime[0]) + _stateByTime(_stateByExtendTime[0]), + _cycles_since_speaker_update(0) { memset(_collisions, 0xff, sizeof(_collisions)); set_reset_line(true); @@ -414,6 +415,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } output_pixels(cycles_run_for); + _cycles_since_speaker_update += cycles_run_for; if(operation != CPU6502::BusOperation::Ready) { @@ -449,10 +451,6 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin returnValue &= _ram[address&0x7f]; } else { _ram[address&0x7f] = *value; -// if((address&0x7f) == (0x9a&0x7f)) -// { -// printf("[9a] <- %02x\n", *value); -// } } } @@ -498,6 +496,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin case 0x03: // Reset is delayed by four cycles. _horizontalTimer = horizontalTimerPeriod - 4; + + // TODO: audio will now be out of synchronisation — fix break; case 0x04: @@ -585,6 +585,21 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin _upcomingEvents[(_upcomingEventsPointer + 4)%number_of_upcoming_events].counter = decodedAddress - 0x10; break; + case 0x15: case 0x16: + update_audio(); + _speaker.set_control(decodedAddress - 0x15, *value); + break; + + case 0x17: case 0x18: + update_audio(); + _speaker.set_divider(decodedAddress - 0x17, *value); + break; + + case 0x19: case 0x1a: + update_audio(); + _speaker.set_volume(decodedAddress - 0x19, *value); + break; + case 0x1c: _ballGraphicsEnable[1] = _ballGraphicsEnable[0]; case 0x1b: { @@ -765,3 +780,53 @@ void Machine::set_rom(size_t length, const uint8_t *data) _romPages[2] = &_rom[2048 & romMask]; _romPages[3] = &_rom[3072 & romMask]; } + +#pragma mark - Audio + +void Machine::update_audio() +{ + _speaker.run_for_cycles(_cycles_since_speaker_update / 114); + _cycles_since_speaker_update %= 114; +} + +void Machine::synchronise() +{ + update_audio(); +} + +void Atari2600::Speaker::set_volume(int channel, uint8_t volume) +{ + _volume[channel] = volume & 0xf; +} + +void Atari2600::Speaker::set_divider(int channel, uint8_t divider) +{ + _divider[channel] = divider & 0x1f; +} + +void Atari2600::Speaker::set_control(int channel, uint8_t control) +{ + _control[channel] = control & 0xf; +} + +void Atari2600::Speaker::get_samples(unsigned int number_of_samples, int16_t *target) +{ + for(unsigned int c = 0; c < number_of_samples; c++) + { + target[c] = 0; + for(int channel = 0; channel < 2; channel++) + { + if(!_control[channel]) + { + target[c] += _volume[channel] * 1024; + } + else + { + } + } + } +} + +void Atari2600::Speaker::skip_samples(unsigned int number_of_samples) +{ +} diff --git a/Machines/Atari2600/Atari2600.hpp b/Machines/Atari2600/Atari2600.hpp index d29cb78bc..2965a26c4 100644 --- a/Machines/Atari2600/Atari2600.hpp +++ b/Machines/Atari2600/Atari2600.hpp @@ -48,7 +48,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { // to satisfy CPU6502::Processor unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); - void synchronise() {} + void synchronise(); // to satisfy CRTMachine::Machine virtual void setup_output(float aspect_ratio); @@ -159,10 +159,14 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { uint8_t get_output_pixel(); void update_timers(int mask); - // Outputs + // outputs Outputs::CRT::CRT *_crt; Speaker _speaker; + // speaker backlog accumlation counter + unsigned int _cycles_since_speaker_update; + void update_audio(); + // latched output state unsigned int _lastOutputStateDuration; OutputState _stateByExtendTime[2][57];