From 49b8e771b58b6698b4ccde2023e960c7d62bffe5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 15 Feb 2020 13:40:19 -0500 Subject: [PATCH] Adds the messaging that would allow a Speaker to output stereo, semantically. --- .../Implementation/MultiSpeaker.cpp | 4 +- .../Implementation/MultiSpeaker.hpp | 2 +- .../xcschemes/Clock Signal.xcscheme | 2 +- .../Mac/Clock Signal/Machine/CSMachine.mm | 2 +- OSBindings/SDL/main.cpp | 2 +- .../Speaker/Implementation/LowpassSpeaker.hpp | 7 +++- Outputs/Speaker/Speaker.hpp | 41 +++++++++++++++++-- 7 files changed, 50 insertions(+), 10 deletions(-) diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp index a6f412ca4..8c4680aad 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp @@ -37,9 +37,9 @@ float MultiSpeaker::get_ideal_clock_rate_in_range(float minimum, float maximum) return ideal / static_cast(speakers_.size()); } -void MultiSpeaker::set_computed_output_rate(float cycles_per_second, int buffer_size) { +void MultiSpeaker::set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) { for(const auto &speaker: speakers_) { - speaker->set_computed_output_rate(cycles_per_second, buffer_size); + speaker->set_computed_output_rate(cycles_per_second, buffer_size, stereo); } } diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.hpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.hpp index 1dcf74736..928a6adc9 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.hpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.hpp @@ -39,7 +39,7 @@ class MultiSpeaker: public Outputs::Speaker::Speaker, Outputs::Speaker::Speaker: // Below is the standard Outputs::Speaker::Speaker interface; see there for documentation. float get_ideal_clock_rate_in_range(float minimum, float maximum) override; - void set_computed_output_rate(float cycles_per_second, int buffer_size) override; + void set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) override; void set_delegate(Outputs::Speaker::Speaker::Delegate *delegate) override; private: diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index a99eb0a5d..63be2c037 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -67,7 +67,7 @@ crt_machine()->get_speaker(); if(speaker) { - speaker->set_output_rate(sampleRate, (int)bufferSize); + speaker->set_output_rate(sampleRate, (int)bufferSize, false); speaker->set_delegate(delegate); return YES; } diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index dee03b587..8590db911 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -667,7 +667,7 @@ int main(int argc, char *argv[]) { speaker_delegate.audio_device = SDL_OpenAudioDevice(nullptr, 0, &desired_audio_spec, &obtained_audio_spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); - speaker->set_output_rate(obtained_audio_spec.freq, desired_audio_spec.samples); + speaker->set_output_rate(obtained_audio_spec.freq, desired_audio_spec.samples, false); speaker->set_delegate(&speaker_delegate); SDL_PauseAudioDevice(speaker_delegate.audio_device, 0); } diff --git a/Outputs/Speaker/Implementation/LowpassSpeaker.hpp b/Outputs/Speaker/Implementation/LowpassSpeaker.hpp index da1cc692b..dda9dbabd 100644 --- a/Outputs/Speaker/Implementation/LowpassSpeaker.hpp +++ b/Outputs/Speaker/Implementation/LowpassSpeaker.hpp @@ -58,7 +58,7 @@ template class LowpassSpeaker: public Speaker { } // Implemented as per Speaker. - void set_computed_output_rate(float cycles_per_second, int buffer_size) final { + void set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) final { std::lock_guard lock_guard(filter_parameters_mutex_); if(filter_parameters_.output_cycles_per_second == cycles_per_second && size_t(buffer_size) == output_buffer_.size()) { return; @@ -69,6 +69,11 @@ template class LowpassSpeaker: public Speaker { output_buffer_.resize(std::size_t(buffer_size)); } + // TODO. + bool get_is_stereo() final { + return false; + } + /*! Sets the clock rate of the input audio. */ diff --git a/Outputs/Speaker/Speaker.hpp b/Outputs/Speaker/Speaker.hpp index 941621729..7a3b76e09 100644 --- a/Outputs/Speaker/Speaker.hpp +++ b/Outputs/Speaker/Speaker.hpp @@ -23,28 +23,62 @@ class Speaker { public: virtual ~Speaker() {} + /*! + @returns The best output clock rate for the audio being supplied to this speaker, from the range given. + */ virtual float get_ideal_clock_rate_in_range(float minimum, float maximum) = 0; - void set_output_rate(float cycles_per_second, int buffer_size) { + + /*! + @returns @c true if the device would most ideally output stereo sound; @c false otherwise. + */ + virtual bool get_is_stereo() { return false; }; + + /*! + Sets the actual output rate; packets provided to the delegate will conform to these + specifications regardless of the input. + */ + void set_output_rate(float cycles_per_second, int buffer_size, bool stereo) { output_cycles_per_second_ = cycles_per_second; output_buffer_size_ = buffer_size; + stereo_output_ = stereo; compute_output_rate(); } + + /*! + Speeds a speed multiplier for this machine, e.g. that it is currently being run at 2.0x its normal rate. + This will affect the number of input samples that are combined to produce one output sample. + */ void set_input_rate_multiplier(float multiplier) { input_rate_multiplier_ = multiplier; compute_output_rate(); } + /*! + @returns The number of sample sets so far delivered to the delegate. + */ int completed_sample_sets() const { return completed_sample_sets_; } + /*! + Defines a receiver for audio packets. + */ struct Delegate { + /*! + Indicates that a new audio packet is ready. If the output is stereo, samples will be interleaved with the first + being left, the second being right, etc. + */ virtual void speaker_did_complete_samples(Speaker *speaker, const std::vector &buffer) = 0; + + /*! + Provides the delegate with a hint that the input clock rate has changed, which provides an opportunity to + renegotiate the ideal clock rate, if desired. + */ virtual void speaker_did_change_input_clock(Speaker *speaker) {} }; virtual void set_delegate(Delegate *delegate) { delegate_ = delegate; } - virtual void set_computed_output_rate(float cycles_per_second, int buffer_size) = 0; + virtual void set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) = 0; protected: void did_complete_samples(Speaker *speaker, const std::vector &buffer) { @@ -57,13 +91,14 @@ class Speaker { void compute_output_rate() { // The input rate multiplier is actually used as an output rate divider, // to confirm to the public interface of a generic speaker being output-centric. - set_computed_output_rate(output_cycles_per_second_ / input_rate_multiplier_, output_buffer_size_); + set_computed_output_rate(output_cycles_per_second_ / input_rate_multiplier_, output_buffer_size_, stereo_output_); } int completed_sample_sets_ = 0; float input_rate_multiplier_ = 1.0f; float output_cycles_per_second_ = 1.0f; int output_buffer_size_ = 1; + bool stereo_output_ = false; }; }