mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-09 02:31:22 +00:00
Adds the messaging that would allow a Speaker to output stereo, semantically.
This commit is contained in:
parent
dde672701f
commit
49b8e771b5
@ -37,9 +37,9 @@ float MultiSpeaker::get_ideal_clock_rate_in_range(float minimum, float maximum)
|
|||||||
return ideal / static_cast<float>(speakers_.size());
|
return ideal / static_cast<float>(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_) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
// Below is the standard Outputs::Speaker::Speaker interface; see there for documentation.
|
||||||
float get_ideal_clock_rate_in_range(float minimum, float maximum) override;
|
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;
|
void set_delegate(Outputs::Speaker::Speaker::Delegate *delegate) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
</Testables>
|
</Testables>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
enableASanStackUseAfterReturn = "YES"
|
enableASanStackUseAfterReturn = "YES"
|
||||||
|
@ -272,7 +272,7 @@ struct ActivityObserver: public Activity::Observer {
|
|||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
Outputs::Speaker::Speaker *speaker = _machine->crt_machine()->get_speaker();
|
Outputs::Speaker::Speaker *speaker = _machine->crt_machine()->get_speaker();
|
||||||
if(speaker) {
|
if(speaker) {
|
||||||
speaker->set_output_rate(sampleRate, (int)bufferSize);
|
speaker->set_output_rate(sampleRate, (int)bufferSize, false);
|
||||||
speaker->set_delegate(delegate);
|
speaker->set_delegate(delegate);
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
@ -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_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);
|
speaker->set_delegate(&speaker_delegate);
|
||||||
SDL_PauseAudioDevice(speaker_delegate.audio_device, 0);
|
SDL_PauseAudioDevice(speaker_delegate.audio_device, 0);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ template <typename T> class LowpassSpeaker: public Speaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Implemented as per 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<std::mutex> lock_guard(filter_parameters_mutex_);
|
std::lock_guard<std::mutex> lock_guard(filter_parameters_mutex_);
|
||||||
if(filter_parameters_.output_cycles_per_second == cycles_per_second && size_t(buffer_size) == output_buffer_.size()) {
|
if(filter_parameters_.output_cycles_per_second == cycles_per_second && size_t(buffer_size) == output_buffer_.size()) {
|
||||||
return;
|
return;
|
||||||
@ -69,6 +69,11 @@ template <typename T> class LowpassSpeaker: public Speaker {
|
|||||||
output_buffer_.resize(std::size_t(buffer_size));
|
output_buffer_.resize(std::size_t(buffer_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO.
|
||||||
|
bool get_is_stereo() final {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the clock rate of the input audio.
|
Sets the clock rate of the input audio.
|
||||||
*/
|
*/
|
||||||
|
@ -23,28 +23,62 @@ class Speaker {
|
|||||||
public:
|
public:
|
||||||
virtual ~Speaker() {}
|
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;
|
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_cycles_per_second_ = cycles_per_second;
|
||||||
output_buffer_size_ = buffer_size;
|
output_buffer_size_ = buffer_size;
|
||||||
|
stereo_output_ = stereo;
|
||||||
compute_output_rate();
|
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) {
|
void set_input_rate_multiplier(float multiplier) {
|
||||||
input_rate_multiplier_ = multiplier;
|
input_rate_multiplier_ = multiplier;
|
||||||
compute_output_rate();
|
compute_output_rate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@returns The number of sample sets so far delivered to the delegate.
|
||||||
|
*/
|
||||||
int completed_sample_sets() const { return completed_sample_sets_; }
|
int completed_sample_sets() const { return completed_sample_sets_; }
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Defines a receiver for audio packets.
|
||||||
|
*/
|
||||||
struct Delegate {
|
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<int16_t> &buffer) = 0;
|
virtual void speaker_did_complete_samples(Speaker *speaker, const std::vector<int16_t> &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 speaker_did_change_input_clock(Speaker *speaker) {}
|
||||||
};
|
};
|
||||||
virtual void set_delegate(Delegate *delegate) {
|
virtual void set_delegate(Delegate *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:
|
protected:
|
||||||
void did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) {
|
void did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) {
|
||||||
@ -57,13 +91,14 @@ class Speaker {
|
|||||||
void compute_output_rate() {
|
void compute_output_rate() {
|
||||||
// The input rate multiplier is actually used as an output rate divider,
|
// 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.
|
// 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;
|
int completed_sample_sets_ = 0;
|
||||||
float input_rate_multiplier_ = 1.0f;
|
float input_rate_multiplier_ = 1.0f;
|
||||||
float output_cycles_per_second_ = 1.0f;
|
float output_cycles_per_second_ = 1.0f;
|
||||||
int output_buffer_size_ = 1;
|
int output_buffer_size_ = 1;
|
||||||
|
bool stereo_output_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user