From c12aaea7474e90c88fbdfd5675eb3bd9da3efaa7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 30 Jan 2018 22:23:06 -0500 Subject: [PATCH] Attempts to get as far as running the MultiMachine. In doing so, fixes the long-standing bug that machines that output audio but don't have a listener produce a divide by zero. --- .../Implementation/MultiCRTMachine.cpp | 70 +++++++++++++++++++ .../Implementation/MultiCRTMachine.hpp | 45 ++++++++++++ .../Dynamic/MultiMachine/MultiMachine.cpp | 5 +- .../Dynamic/MultiMachine/MultiMachine.hpp | 2 + Machines/CRTMachine.hpp | 6 +- .../Clock Signal.xcodeproj/project.pbxproj | 8 +++ .../Speaker/Implementation/LowpassSpeaker.hpp | 10 ++- 7 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 Analyser/Dynamic/MultiMachine/Implementation/MultiCRTMachine.cpp create mode 100644 Analyser/Dynamic/MultiMachine/Implementation/MultiCRTMachine.hpp diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiCRTMachine.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiCRTMachine.cpp new file mode 100644 index 000000000..3aeabe886 --- /dev/null +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiCRTMachine.cpp @@ -0,0 +1,70 @@ +// +// MultiCRTMachine.cpp +// Clock Signal +// +// Created by Thomas Harte on 29/01/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#include "MultiCRTMachine.hpp" + +using namespace Analyser::Dynamic; + +MultiCRTMachine::MultiCRTMachine(const std::vector> &machines) : + machines_(machines) {} + +void MultiCRTMachine::setup_output(float aspect_ratio) { + for(const auto &machine: machines_) { + CRTMachine::Machine *crt_machine = machine->crt_machine(); + if(crt_machine) crt_machine->setup_output(aspect_ratio); + } +} + +void MultiCRTMachine::close_output() { + for(const auto &machine: machines_) { + CRTMachine::Machine *crt_machine = machine->crt_machine(); + if(crt_machine) crt_machine->close_output(); + } +} + +Outputs::CRT::CRT *MultiCRTMachine::get_crt() { + CRTMachine::Machine *crt_machine = machines_.front()->crt_machine(); + return crt_machine ? crt_machine->get_crt() : nullptr; +} + +Outputs::Speaker::Speaker *MultiCRTMachine::get_speaker() { + CRTMachine::Machine *crt_machine = machines_.front()->crt_machine(); + return crt_machine ? crt_machine->get_speaker() : nullptr; +} + +void MultiCRTMachine::run_for(const Cycles cycles) { + for(const auto &machine: machines_) { + CRTMachine::Machine *crt_machine = machine->crt_machine(); + if(crt_machine) crt_machine->run_for(cycles); + } + + // TODO: announce an opportunity potentially to reorder the list of machines. +} + +double MultiCRTMachine::get_clock_rate() { + // TODO: something smarter than this? Not all clock rates will necessarily be the same. + CRTMachine::Machine *crt_machine = machines_.front()->crt_machine(); + return crt_machine ? crt_machine->get_clock_rate() : 0.0; +} + +bool MultiCRTMachine::get_clock_is_unlimited() { + CRTMachine::Machine *crt_machine = machines_.front()->crt_machine(); + return crt_machine ? crt_machine->get_clock_is_unlimited() : false; +} + +void MultiCRTMachine::set_delegate(::CRTMachine::Machine::Delegate *delegate) { + // TODO +} + +void MultiCRTMachine::machine_did_change_clock_rate(Machine *machine) { + // TODO +} + +void MultiCRTMachine::machine_did_change_clock_is_unlimited(Machine *machine) { + // TODO +} diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiCRTMachine.hpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiCRTMachine.hpp new file mode 100644 index 000000000..662db277c --- /dev/null +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiCRTMachine.hpp @@ -0,0 +1,45 @@ +// +// MultiCRTMachine.hpp +// Clock Signal +// +// Created by Thomas Harte on 29/01/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#ifndef MultiCRTMachine_hpp +#define MultiCRTMachine_hpp + +#include "../../../../Machines/CRTMachine.hpp" +#include "../../../../Machines/DynamicMachine.hpp" + +#include +#include + +namespace Analyser { +namespace Dynamic { + +struct MultiCRTMachine: public ::CRTMachine::Machine, public ::CRTMachine::Machine::Delegate { + public: + MultiCRTMachine(const std::vector> &machines); + + void setup_output(float aspect_ratio) override; + void close_output() override; + Outputs::CRT::CRT *get_crt() override; + Outputs::Speaker::Speaker *get_speaker() override; + void run_for(const Cycles cycles) override; + double get_clock_rate() override; + bool get_clock_is_unlimited() override; + void set_delegate(::CRTMachine::Machine::Delegate *delegate) override; + + void machine_did_change_clock_rate(Machine *machine) override; + void machine_did_change_clock_is_unlimited(Machine *machine) override; + + private: + const std::vector> &machines_; +}; + +} +} + + +#endif /* MultiCRTMachine_hpp */ diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp index 32a30a9a9..d668c66a9 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp @@ -12,14 +12,15 @@ using namespace Analyser::Dynamic; MultiMachine::MultiMachine(std::vector> &&machines) : machines_(std::move(machines)), - configuration_target_(machines_) {} + configuration_target_(machines_), + crt_machine_(machines_) {} ConfigurationTarget::Machine *MultiMachine::configuration_target() { return &configuration_target_; } CRTMachine::Machine *MultiMachine::crt_machine() { - return nullptr; + return &crt_machine_; } JoystickMachine::Machine *MultiMachine::joystick_machine() { diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp index e255bb7b1..759e9452a 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp @@ -12,6 +12,7 @@ #include "../../../Machines/DynamicMachine.hpp" #include "Implementation/MultiConfigurationTarget.hpp" +#include "Implementation/MultiCRTMachine.hpp" #include #include @@ -46,6 +47,7 @@ class MultiMachine: public ::Machine::DynamicMachine { std::vector> machines_; MultiConfigurationTarget configuration_target_; + MultiCRTMachine crt_machine_; }; } diff --git a/Machines/CRTMachine.hpp b/Machines/CRTMachine.hpp index 06c796e36..538bb29cd 100644 --- a/Machines/CRTMachine.hpp +++ b/Machines/CRTMachine.hpp @@ -45,10 +45,10 @@ class Machine: public ROMMachine::Machine { virtual void run_for(const Cycles cycles) = 0; // TODO: sever the clock-rate stuff. - double get_clock_rate() { + virtual double get_clock_rate() { return clock_rate_; } - bool get_clock_is_unlimited() { + virtual bool get_clock_is_unlimited() { return clock_is_unlimited_; } class Delegate { @@ -56,7 +56,7 @@ class Machine: public ROMMachine::Machine { virtual void machine_did_change_clock_rate(Machine *machine) = 0; virtual void machine_did_change_clock_is_unlimited(Machine *machine) = 0; }; - void set_delegate(Delegate *delegate) { delegate_ = delegate; } + virtual void set_delegate(Delegate *delegate) { delegate_ = delegate; } protected: void set_clock_rate(double clock_rate) { diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 4c1c3ebb5..c28a5e7a9 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -570,6 +570,8 @@ 4BBB14311CD2CECE00BDB55C /* IntermediateShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB142F1CD2CECE00BDB55C /* IntermediateShader.cpp */; }; 4BBB70A4202011C2002FE009 /* MultiConfigurationTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB70A3202011C2002FE009 /* MultiConfigurationTarget.cpp */; }; 4BBB70A5202011C2002FE009 /* MultiConfigurationTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB70A3202011C2002FE009 /* MultiConfigurationTarget.cpp */; }; + 4BBB70A8202014E2002FE009 /* MultiCRTMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB70A6202014E2002FE009 /* MultiCRTMachine.cpp */; }; + 4BBB70A9202014E2002FE009 /* MultiCRTMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB70A6202014E2002FE009 /* MultiCRTMachine.cpp */; }; 4BBC951E1F368D83008F4C34 /* i8272.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBC951C1F368D83008F4C34 /* i8272.cpp */; }; 4BBF49AF1ED2880200AB3669 /* FUSETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF49AE1ED2880200AB3669 /* FUSETests.swift */; }; 4BBF99141C8FBA6F0075DAFB /* TextureBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99081C8FBA6F0075DAFB /* TextureBuilder.cpp */; }; @@ -1253,6 +1255,8 @@ 4BBB709C2020109C002FE009 /* DynamicMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DynamicMachine.hpp; sourceTree = ""; }; 4BBB70A2202011C2002FE009 /* MultiConfigurationTarget.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MultiConfigurationTarget.hpp; sourceTree = ""; }; 4BBB70A3202011C2002FE009 /* MultiConfigurationTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MultiConfigurationTarget.cpp; sourceTree = ""; }; + 4BBB70A6202014E2002FE009 /* MultiCRTMachine.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiCRTMachine.cpp; sourceTree = ""; }; + 4BBB70A7202014E2002FE009 /* MultiCRTMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiCRTMachine.hpp; sourceTree = ""; }; 4BBC34241D2208B100FFC9DF /* CSFastLoading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSFastLoading.h; sourceTree = ""; }; 4BBC951C1F368D83008F4C34 /* i8272.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = i8272.cpp; path = 8272/i8272.cpp; sourceTree = ""; }; 4BBC951D1F368D83008F4C34 /* i8272.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = i8272.hpp; path = 8272/i8272.hpp; sourceTree = ""; }; @@ -2659,6 +2663,8 @@ children = ( 4BBB70A2202011C2002FE009 /* MultiConfigurationTarget.hpp */, 4BBB70A3202011C2002FE009 /* MultiConfigurationTarget.cpp */, + 4BBB70A6202014E2002FE009 /* MultiCRTMachine.cpp */, + 4BBB70A7202014E2002FE009 /* MultiCRTMachine.hpp */, ); path = Implementation; sourceTree = ""; @@ -3368,6 +3374,7 @@ 4B055AEA1FAE9B990060FFFF /* 6502Storage.cpp in Sources */, 4B055AA71FAE85EF0060FFFF /* SegmentParser.cpp in Sources */, 4B055AC11FAE98DC0060FFFF /* MachineForTarget.cpp in Sources */, + 4BBB70A9202014E2002FE009 /* MultiCRTMachine.cpp in Sources */, 4B055AD81FAE9B180060FFFF /* Video.cpp in Sources */, 4B89452F201967B4007DE474 /* StaticAnalyser.cpp in Sources */, 4B894531201967B4007DE474 /* StaticAnalyser.cpp in Sources */, @@ -3533,6 +3540,7 @@ 4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.mm in Sources */, 4B894532201967B4007DE474 /* 6502.cpp in Sources */, 4B4518811F75E91A00926311 /* PCMPatchedTrack.cpp in Sources */, + 4BBB70A8202014E2002FE009 /* MultiCRTMachine.cpp in Sources */, 4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */, 4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */, 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */, diff --git a/Outputs/Speaker/Implementation/LowpassSpeaker.hpp b/Outputs/Speaker/Implementation/LowpassSpeaker.hpp index 406f8fe10..3ca42e477 100644 --- a/Outputs/Speaker/Implementation/LowpassSpeaker.hpp +++ b/Outputs/Speaker/Implementation/LowpassSpeaker.hpp @@ -82,6 +82,8 @@ template class LowpassSpeaker: public Speaker { at construction, filtering it and passing it on to the speaker's delegate if there is one. */ void run_for(const Cycles cycles) { + if(!delegate_) return; + std::size_t cycles_remaining = static_cast(cycles.as_int()); if(!cycles_remaining) return; if(filter_parameters_.parameters_are_dirty) update_filter_coefficients(); @@ -99,9 +101,7 @@ template class LowpassSpeaker: public Speaker { // announce to delegate if full if(output_buffer_pointer_ == output_buffer_.size()) { output_buffer_pointer_ = 0; - if(delegate_) { - delegate_->speaker_did_complete_samples(this, output_buffer_); - } + delegate_->speaker_did_complete_samples(this, output_buffer_); } cycles_remaining -= cycles_to_read; @@ -126,9 +126,7 @@ template class LowpassSpeaker: public Speaker { // Announce to delegate if full. if(output_buffer_pointer_ == output_buffer_.size()) { output_buffer_pointer_ = 0; - if(delegate_) { - delegate_->speaker_did_complete_samples(this, output_buffer_); - } + delegate_->speaker_did_complete_samples(this, output_buffer_); } // If the next loop around is going to reuse some of the samples just collected, use a memmove to