diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index bc478d5fa..1c1d96dba 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -14,6 +14,7 @@ MOS6560::MOS6560() : _crt(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 1)), _horizontal_counter(0), _vertical_counter(0), + _cycles_since_speaker_update(0), _is_odd_frame(false) { _crt->set_composite_sampling_function( @@ -56,6 +57,7 @@ MOS6560::MOS6560() : // show the middle 90% _crt->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); + _speaker.set_input_rate(63920.4375); // assuming NTSC; clock rate / 16 } void MOS6560::set_register(int address, uint8_t value) @@ -88,9 +90,18 @@ void MOS6560::set_register(int address, uint8_t value) _video_matrix_start_address = (uint16_t)((_video_matrix_start_address & 0x0200) | ((value & 0xf0) << 6)); break; + case 0xa: + case 0xb: + case 0xc: + case 0xd: + update_audio(); + _speaker.set_control(address - 0xa, value); + break; + case 0xe: + update_audio(); _auxiliary_colour = _colours[value >> 4]; - // TODO: sound amplitude + _speaker.set_volume(value & 0xf); break; case 0xf: @@ -122,7 +133,6 @@ uint8_t MOS6560::get_register(int address) } } - void MOS6560::output_border(unsigned int number_of_cycles) { uint8_t *colour_pointer = _crt->allocate_write_area(1); @@ -132,6 +142,8 @@ void MOS6560::output_border(unsigned int number_of_cycles) uint16_t MOS6560::get_address() { + _cycles_since_speaker_update++; + _horizontal_counter++; if(_horizontal_counter == 65) { @@ -297,3 +309,37 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) } } } + +void MOS6560::update_audio() +{ +// _speaker.run_for_cycles(_cycles_since_speaker_update >> 4); + _cycles_since_speaker_update &= 15; +} + +#pragma mark - Audio + +MOS6560Speaker::MOS6560Speaker() +{ +} + +void MOS6560Speaker::set_volume(uint8_t volume) +{ +// printf("Volume is %d\n", volume); +} + +void MOS6560Speaker::set_control(int channel, uint8_t volume) +{ + // NTSC: 1022727 +//N: bass switch, R: freq f=Phi2/256/(255-$900a) NTSC: Phi2=14318181/14 Hz +//O: alto switch, S: freq f=Phi2/128/(255-$900b) PAL: Phi2=4433618/4 Hz +//P: soprano switch, T: freq f=Phi2/64/(255-$900c) +//Q: noise switch, U: freq f=Phi2/32/(255-$900d) +} + +void MOS6560Speaker::get_samples(unsigned int number_of_samples, int16_t *target) +{ +} + +void MOS6560Speaker::skip_samples(unsigned int number_of_samples) +{ +} diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 6e9fb6d0b..3c10abca2 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -10,13 +10,26 @@ #define _560_hpp #include "../../Outputs/CRT/CRT.hpp" +#include "../../Outputs/Speaker.hpp" namespace MOS { +class MOS6560Speaker: public ::Outputs::Filter { + public: + MOS6560Speaker(); + + void set_volume(uint8_t volume); + void set_control(int channel, uint8_t volume); + + void get_samples(unsigned int number_of_samples, int16_t *target); + void skip_samples(unsigned int number_of_samples); +}; + class MOS6560 { public: MOS6560(); Outputs::CRT::CRT *get_crt() { return _crt.get(); } + Outputs::Speaker *get_speaker() { return &_speaker; } uint16_t get_address(); void set_graphics_value(uint8_t value, uint8_t colour_value); @@ -26,6 +39,7 @@ class MOS6560 { private: std::unique_ptr _crt; + MOS6560Speaker _speaker; bool _interlaced, _tall_characters; uint8_t _first_column_location, _first_row_location; @@ -54,6 +68,9 @@ class MOS6560 { bool _is_odd_frame; void output_border(unsigned int number_of_cycles); + + unsigned int _cycles_since_speaker_update; + void update_audio(); }; } diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 06f46f0be..3843d392a 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -106,7 +106,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p virtual void setup_output(float aspect_ratio); virtual void close_output() {} virtual Outputs::CRT::CRT *get_crt() { return _mos6560->get_crt(); } - virtual Outputs::Speaker *get_speaker() { return nullptr; } // TODO + virtual Outputs::Speaker *get_speaker() { return _mos6560->get_speaker(); } virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor::run_for_cycles(number_of_cycles); } // to satisfy MOS::MOS6522::Delegate