1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-01-23 01:16:10 +00:00

Attempt to shrink repetition even further.

This commit is contained in:
Thomas Harte
2025-11-15 21:41:34 -05:00
parent 4247d0ef40
commit 33ae24c961
6 changed files with 47 additions and 33 deletions

View File

@@ -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>,
SoundGenerator
> audio_;
Outputs::Speaker::PullLowpassSpeakerQueue<SoundGenerator> audio_;
bool speaker_is_enabled_ = false;

View File

@@ -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);
}
};

View File

@@ -35,10 +35,7 @@ public:
// The RIOT, TIA and speaker.
PIA mos6532_;
TIA tia_;
Outputs::Speaker::SpeakerQueue<
Outputs::Speaker::PullLowpass<TIASound>,
TIASound
> audio_;
Outputs::Speaker::PullLowpassSpeakerQueue<TIASound> audio_;
// Joystick state.
uint8_t tia_input_value_[2] = {0xff, 0xff};

View File

@@ -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;
}
}
}

View File

@@ -418,4 +418,7 @@ private:
}
};
template <typename GeneratorT>
using PullLowpassSpeakerQueue = SpeakerQueue<Outputs::Speaker::PullLowpass<GeneratorT>, GeneratorT>;
}

View File

@@ -16,16 +16,20 @@ using TaskQueue = Concurrency::AsyncTaskQueue<false, true, true>;
template <typename SpeakerT, typename GeneratorT>
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<void(void)> prepare_enqueue() {
return speaker.update_for(cycles_since_update_.divide(divider_));
std::function<void(void)> prepare_enqueue() final {
return speaker_.update_for(cycles_since_update_.divide(divider_));
}
};
}