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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,4 +418,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename GeneratorT>
|
||||
using PullLowpassSpeakerQueue = SpeakerQueue<Outputs::Speaker::PullLowpass<GeneratorT>, GeneratorT>;
|
||||
|
||||
}
|
||||
|
||||
@@ -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_));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user