diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp index 445036baa..26b497f6c 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp @@ -37,6 +37,13 @@ float MultiSpeaker::get_ideal_clock_rate_in_range(float minimum, float maximum) return ideal / float(speakers_.size()); } +//void MultiSpeaker::set_output_rate(float cycles_per_second, int buffer_size, bool stereo) { +// stereo_output_ = stereo; +// for(const auto &speaker: speakers_) { +// speaker->set_output_rate(cycles_per_second, buffer_size, stereo); +// } +//} + void MultiSpeaker::set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) { stereo_output_ = stereo; for(const auto &speaker: speakers_) { diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp index b18b31369..8f96498cc 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp @@ -89,9 +89,28 @@ void MultiMachine::did_run_machines(MultiTimedMachine *) { void MultiMachine::pick_first() { has_picked_ = true; + + // Ensure output rate specifics are properly copied; these may be set only once by the owner, + // but rather than being propagated directly by the MultiSpeaker only the derived computed + // output rate is propagated. So this ensures that if a new derivation is made, it's made correctly. + if(machines_[0]->audio_producer()) { + auto multi_speaker = audio_producer_.get_speaker(); + auto specific_speaker = machines_[0]->audio_producer()->get_speaker(); + + if(specific_speaker && multi_speaker) { + specific_speaker->copy_output_rate(*multi_speaker); + } + } + + // TODO: because it is not invalid for a caller to keep a reference to anything previously returned, + // this erase can be added only once the Multi machines that take static copies of the machines list + // are updated. + // + // Example failing use case otherwise: a caller still has reference to the MultiJoystickMachine, and + // it has dangling references to the various JoystickMachines. + // + // This gets into particularly long grass with the MultiConfigurable and its MultiStruct. // machines_.erase(machines_.begin() + 1, machines_.end()); - // TODO: this isn't quite correct, because it may leak OpenGL/etc resources through failure to - // request a close_output while the context is active. } void *MultiMachine::raw_pointer() { diff --git a/Outputs/Speaker/Speaker.hpp b/Outputs/Speaker/Speaker.hpp index 3319cb08c..875a16032 100644 --- a/Outputs/Speaker/Speaker.hpp +++ b/Outputs/Speaker/Speaker.hpp @@ -45,6 +45,16 @@ class Speaker { compute_output_rate(); } + /*! + Takes a copy of the most recent output rate provided to @c rhs. + */ + void copy_output_rate(const Speaker &rhs) { + output_cycles_per_second_ = rhs.output_cycles_per_second_; + output_buffer_size_ = rhs.output_buffer_size_; + stereo_output_.store(rhs.stereo_output_.load(std::memory_order::memory_order_relaxed), std::memory_order::memory_order_relaxed); + compute_output_rate(); + } + /// Sets the output volume, in the range [0, 1]. virtual void set_output_volume(float) = 0;