diff --git a/Machines/Apple/AppleIIgs/AppleIIgs.cpp b/Machines/Apple/AppleIIgs/AppleIIgs.cpp index c740d4f38..555567ce5 100644 --- a/Machines/Apple/AppleIIgs/AppleIIgs.cpp +++ b/Machines/Apple/AppleIIgs/AppleIIgs.cpp @@ -19,9 +19,12 @@ #include "../../../Components/8530/z8530.hpp" #include "../../../Components/AppleClock/AppleClock.hpp" +#include "../../../Components/AudioToggle/AudioToggle.hpp" #include "../../../Components/DiskII/IWM.hpp" #include "../../../Components/DiskII/MacintoshDoubleDensityDrive.hpp" +#include "../../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp" + #include "../../Utility/MemoryFuzzer.hpp" #include "../../../ClockReceiver/JustInTime.hpp" @@ -42,6 +45,7 @@ class ConcreteMachine: public Apple::IIgs::Machine, public MachineTypes::TimedMachine, public MachineTypes::ScanProducer, + public MachineTypes::AudioProducer, public CPU::MOS6502Esque::BusHandler { public: @@ -51,9 +55,12 @@ class ConcreteMachine: drives_{ {CLOCK_RATE, true}, {CLOCK_RATE, true} - } { + }, + audio_toggle_(audio_queue_), + speaker_(audio_toggle_) { set_clock_rate(double(CLOCK_RATE)); + speaker_.set_input_rate(float(CLOCK_RATE) / float(audio_divider)); using Target = Analyser::Static::AppleIIgs::Target; std::vector rom_descriptions; @@ -118,7 +125,9 @@ class ConcreteMachine: void flush() { video_.flush(); + update_audio(); iwm_.flush(); + audio_queue_.perform(); } void set_scan_target(Outputs::Display::ScanTarget *target) override { @@ -137,6 +146,10 @@ class ConcreteMachine: return video_->get_display_type(); } + Outputs::Speaker::Speaker *get_speaker() final { + return &speaker_; + } + forceinline Cycles perform_bus_operation(const CPU::WDC65816::BusOperation operation, const uint32_t address, uint8_t *const value) { const auto ®ion = MemoryMapRegion(memory_, address); static bool log = false; @@ -440,7 +453,8 @@ class ConcreteMachine: break; case 0xc030: - printf("TODO: audio toggle\n"); + update_audio(); + audio_toggle_.set_output(!audio_toggle_.get_output()); break; // Addresses that seemingly map to nothing; provided as a separate break out for now, @@ -612,6 +626,7 @@ class ConcreteMachine: video_ += duration; iwm_ += duration; + cycles_since_audio_update_ += duration; // Ensure no more than a single line is enqueued for just-in-time video purposes. // TODO: as implemented, check_flush_threshold doesn't actually work. Can it be made to, or is it a bad idea? @@ -648,13 +663,22 @@ class ConcreteMachine: Apple::Clock::ParallelClock clock_; JustInTimeActor video_; // i.e. run video at twice the 1Mhz clock. Apple::IIgs::ADB::GLU adb_glu_; - Apple::IIgs::Sound::GLU sound_glu_; Zilog::SCC::z8530 scc_; JustInTimeActor iwm_; Cycles cycles_since_clock_tick_; - Apple::Macintosh::DoubleDensityDrive drives_[2]; + // The audio parts. + Apple::IIgs::Sound::GLU sound_glu_; + Concurrency::DeferringAsyncTaskQueue audio_queue_; + Audio::Toggle audio_toggle_; + Outputs::Speaker::LowpassSpeaker speaker_; + Cycles cycles_since_audio_update_; + static constexpr int audio_divider = 8; + void update_audio() { + speaker_.run_for(audio_queue_, cycles_since_audio_update_.divide(Cycles(audio_divider))); + } + // MARK: - Cards. // TODO: most of cards.