From 33ae24c961665afae5be030f2ed072829f550bfa Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 15 Nov 2025 21:41:34 -0500 Subject: [PATCH] Attempt to shrink repetition even further. --- Machines/Acorn/Electron/Electron.cpp | 21 +++++------- Machines/Atari/2600/Atari2600.cpp | 8 ++--- Machines/Atari/2600/Bus.hpp | 5 +-- Machines/Atari/2600/Cartridges/Cartridge.hpp | 9 ++--- .../Speaker/Implementation/LowpassSpeaker.hpp | 3 ++ Outputs/Speaker/SpeakerQueue.hpp | 34 ++++++++++++++----- 6 files changed, 47 insertions(+), 33 deletions(-) diff --git a/Machines/Acorn/Electron/Electron.cpp b/Machines/Acorn/Electron/Electron.cpp index aa166456e..570e8cd8d 100644 --- a/Machines/Acorn/Electron/Electron.cpp +++ b/Machines/Acorn/Electron/Electron.cpp @@ -27,7 +27,6 @@ #include "ClockReceiver/JustInTime.hpp" #include "Outputs/Speaker/Implementation/LowpassSpeaker.hpp" -#include "Outputs/Speaker/SpeakerQueue.hpp" #include "Interrupts.hpp" #include "Keyboard.hpp" @@ -60,7 +59,11 @@ public: hard_drive_(scsi_bus_, 0), scsi_device_(scsi_bus_.add_device()), video_(ram_), - audio_(SoundGenerator::clock_rate_divider) { + audio_( + 2000000.0 / SoundGenerator::clock_rate_divider, + SoundGenerator::clock_rate_divider, + 6000.0f + ) { memset(key_states_, 0, sizeof(key_states_)); for(int c = 0; c < 16; c++) memset(roms_[c], 0xff, 16384); @@ -68,9 +71,6 @@ public: tape_.set_delegate(this); set_clock_rate(2000000); - audio_.speaker.set_input_rate(2000000 / SoundGenerator::clock_rate_divider); - audio_.speaker.set_high_frequency_cutoff(6000); - ::ROM::Request request = ::ROM::Request(::ROM::Name::AcornBASICII) && ::ROM::Request(::ROM::Name::AcornElectronMOS100); if(target.has_pres_adfs) { request = request && ::ROM::Request(::ROM::Name::PRESADFSSlot1) && ::ROM::Request(::ROM::Name::PRESADFSSlot2); @@ -278,7 +278,7 @@ public: // update speaker mode bool new_speaker_is_enabled = (*value & 6) == 2; if(new_speaker_is_enabled != speaker_is_enabled_) { - audio_.generator.set_is_enabled(new_speaker_is_enabled); + audio_->set_is_enabled(new_speaker_is_enabled); speaker_is_enabled_ = new_speaker_is_enabled; } @@ -339,7 +339,7 @@ public: break; case 0xfe06: if(!is_read(operation)) { - audio_.generator.set_divider(*value); + audio_->set_divider(*value); tape_.set_counter(*value); } break; @@ -529,7 +529,7 @@ public: } Outputs::Speaker::Speaker *get_speaker() final { - return &audio_.speaker; + return &audio_.speaker(); } void run_for(const Cycles cycles) final { @@ -760,10 +760,7 @@ private: // Outputs VideoOutput video_; - Outputs::Speaker::SpeakerQueue< - Outputs::Speaker::PullLowpass, - SoundGenerator - > audio_; + Outputs::Speaker::PullLowpassSpeakerQueue audio_; bool speaker_is_enabled_ = false; diff --git a/Machines/Atari/2600/Atari2600.cpp b/Machines/Atari/2600/Atari2600.cpp index ca1f3c520..9659170e0 100644 --- a/Machines/Atari/2600/Atari2600.cpp +++ b/Machines/Atari/2600/Atari2600.cpp @@ -159,7 +159,7 @@ public: // to satisfy CRTMachine::Machine void set_scan_target(Outputs::Display::ScanTarget *scan_target) final { - bus_->audio_.speaker.set_input_rate(float(get_clock_rate() / double(CPUTicksPerAudioTick))); + bus_->audio_.speaker().set_input_rate(float(get_clock_rate() / double(CPUTicksPerAudioTick))); bus_->tia_.set_crt_delegate(&frequency_mismatch_warner_); bus_->tia_.set_scan_target(scan_target); } @@ -169,7 +169,7 @@ public: } Outputs::Speaker::Speaker *get_speaker() final { - return &bus_->audio_.speaker; + return &bus_->audio_.speaker(); } void run_for(const Cycles cycles) final { @@ -209,8 +209,8 @@ private: void set_is_ntsc(const bool is_ntsc) { bus_->tia_.set_output_mode(is_ntsc ? TIA::OutputMode::NTSC : TIA::OutputMode::PAL); const double clock_rate = is_ntsc ? NTSC_clock_rate : PAL_clock_rate; - bus_->audio_.speaker.set_input_rate(float(clock_rate) / float(CPUTicksPerAudioTick)); - bus_->audio_.speaker.set_high_frequency_cutoff(float(clock_rate) / float(CPUTicksPerAudioTick * 2)); + bus_->audio_.speaker().set_input_rate(float(clock_rate) / float(CPUTicksPerAudioTick)); + bus_->audio_.speaker().set_high_frequency_cutoff(float(clock_rate) / float(CPUTicksPerAudioTick * 2)); set_clock_rate(clock_rate); } }; diff --git a/Machines/Atari/2600/Bus.hpp b/Machines/Atari/2600/Bus.hpp index ec434faa1..86f3780da 100644 --- a/Machines/Atari/2600/Bus.hpp +++ b/Machines/Atari/2600/Bus.hpp @@ -35,10 +35,7 @@ public: // The RIOT, TIA and speaker. PIA mos6532_; TIA tia_; - Outputs::Speaker::SpeakerQueue< - Outputs::Speaker::PullLowpass, - TIASound - > audio_; + Outputs::Speaker::PullLowpassSpeakerQueue audio_; // Joystick state. uint8_t tia_input_value_[2] = {0xff, 0xff}; diff --git a/Machines/Atari/2600/Cartridges/Cartridge.hpp b/Machines/Atari/2600/Cartridges/Cartridge.hpp index 4293fc12d..0f3f1d11f 100644 --- a/Machines/Atari/2600/Cartridges/Cartridge.hpp +++ b/Machines/Atari/2600/Cartridges/Cartridge.hpp @@ -70,8 +70,9 @@ public: // leap to the end of ready only once ready is signalled because on a 6502 ready doesn't take // effect until the next read; therefore it isn't safe to assume that signalling ready immediately // skips to the end of the line. - if(operation == CPU::MOS6502::BusOperation::Ready) + if(operation == CPU::MOS6502::BusOperation::Ready) { cycles_run_for = tia_.get_cycles_until_horizontal_blank(cycles_since_video_update_); + } audio_ += Cycles(cycles_run_for); cycles_since_video_update_ += Cycles(cycles_run_for); @@ -171,11 +172,11 @@ public: case 0x2c: update_video(); tia_.clear_collision_flags(); break; case 0x15: - case 0x16: audio_.generator.set_control(decodedAddress - 0x15, *value); break; + case 0x16: audio_->set_control(decodedAddress - 0x15, *value); break; case 0x17: - case 0x18: audio_.generator.set_divider(decodedAddress - 0x17, *value); break; + case 0x18: audio_->set_divider(decodedAddress - 0x17, *value); break; case 0x19: - case 0x1a: audio_.generator.set_volume(decodedAddress - 0x19, *value); break; + case 0x1a: audio_->set_volume(decodedAddress - 0x19, *value); break; } } } diff --git a/Outputs/Speaker/Implementation/LowpassSpeaker.hpp b/Outputs/Speaker/Implementation/LowpassSpeaker.hpp index cc142cd83..1c37e9064 100644 --- a/Outputs/Speaker/Implementation/LowpassSpeaker.hpp +++ b/Outputs/Speaker/Implementation/LowpassSpeaker.hpp @@ -418,4 +418,7 @@ private: } }; +template +using PullLowpassSpeakerQueue = SpeakerQueue, GeneratorT>; + } diff --git a/Outputs/Speaker/SpeakerQueue.hpp b/Outputs/Speaker/SpeakerQueue.hpp index 5d9504967..80873fe07 100644 --- a/Outputs/Speaker/SpeakerQueue.hpp +++ b/Outputs/Speaker/SpeakerQueue.hpp @@ -16,16 +16,20 @@ using TaskQueue = Concurrency::AsyncTaskQueue; template struct SpeakerQueue: private Concurrency::EnqueueDelegate { -private: - TaskQueue queue_; - -public: - SpeakerQueue(const Cycles divider) : generator(queue_), speaker(generator), divider_(divider) { + constexpr SpeakerQueue(const Cycles divider) noexcept : + generator_(queue_), speaker_(generator_), divider_(divider) + { queue_.set_enqueue_delegate(this); } - GeneratorT generator; - SpeakerT speaker; + constexpr SpeakerQueue(const float input_rate, const Cycles divider, const float high_cutoff = -1.0f) noexcept : + SpeakerQueue(divider) + { + speaker_.set_input_rate(input_rate); + if(high_cutoff >= 0.0) { + speaker_.set_high_frequency_cutoff(high_cutoff); + } + } void operator += (const Cycles &duration) { cycles_since_update_ += duration; @@ -41,12 +45,24 @@ public: queue_.perform(); } + SpeakerT &speaker() { + return speaker_; + } + + GeneratorT *operator ->() { + return &generator_; + } + private: + TaskQueue queue_; + GeneratorT generator_; + SpeakerT speaker_; Cycles divider_; Cycles cycles_since_update_; - std::function prepare_enqueue() { - return speaker.update_for(cycles_since_update_.divide(divider_)); + std::function prepare_enqueue() final { + return speaker_.update_for(cycles_since_update_.divide(divider_)); } }; + }