mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-03 07:33:29 +00:00
Adds mixdown/up capability to Speaker.
To deal with occasions when the host machine just always is either mono or stereo, and the emulated machine must cope.
This commit is contained in:
parent
ea1c8a3b81
commit
90856a0e7a
@ -38,6 +38,7 @@ float MultiSpeaker::get_ideal_clock_rate_in_range(float minimum, float maximum)
|
||||
}
|
||||
|
||||
void MultiSpeaker::set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) {
|
||||
is_stereo_ = stereo;
|
||||
for(const auto &speaker: speakers_) {
|
||||
speaker->set_computed_output_rate(cycles_per_second, buffer_size, stereo);
|
||||
}
|
||||
@ -53,7 +54,7 @@ void MultiSpeaker::speaker_did_complete_samples(Speaker *speaker, const std::vec
|
||||
std::lock_guard<std::mutex> lock_guard(front_speaker_mutex_);
|
||||
if(speaker != front_speaker_) return;
|
||||
}
|
||||
did_complete_samples(this, buffer);
|
||||
did_complete_samples(this, buffer, is_stereo_);
|
||||
}
|
||||
|
||||
void MultiSpeaker::speaker_did_change_input_clock(Speaker *speaker) {
|
||||
|
@ -51,6 +51,8 @@ class MultiSpeaker: public Outputs::Speaker::Speaker, Outputs::Speaker::Speaker:
|
||||
Outputs::Speaker::Speaker *front_speaker_ = nullptr;
|
||||
Outputs::Speaker::Speaker::Delegate *delegate_ = nullptr;
|
||||
std::mutex front_speaker_mutex_;
|
||||
|
||||
bool is_stereo_ = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -58,11 +58,11 @@
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = ""/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Desktop/Soft/Master System/R-Type (NTSC).sms""
|
||||
isEnabled = "NO">
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = ""/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Desktop/Soft/Amstrad CPC/Robocop.dsk""
|
||||
isEnabled = "YES">
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "--speed=5"
|
||||
|
@ -151,7 +151,7 @@ template <typename SampleSource, bool is_stereo> class LowpassSpeaker: public Sp
|
||||
// Announce to delegate if full.
|
||||
if(output_buffer_pointer_ == output_buffer_.size()) {
|
||||
output_buffer_pointer_ = 0;
|
||||
did_complete_samples(this, output_buffer_);
|
||||
did_complete_samples(this, output_buffer_, is_stereo);
|
||||
}
|
||||
|
||||
cycles_remaining -= cycles_to_read;
|
||||
@ -273,7 +273,7 @@ template <typename SampleSource, bool is_stereo> class LowpassSpeaker: public Sp
|
||||
// Announce to delegate if full.
|
||||
if(output_buffer_pointer_ == output_buffer_.size()) {
|
||||
output_buffer_pointer_ = 0;
|
||||
did_complete_samples(this, output_buffer_);
|
||||
did_complete_samples(this, output_buffer_, is_stereo);
|
||||
}
|
||||
|
||||
// If the next loop around is going to reuse some of the samples just collected, use a memmove to
|
||||
|
@ -81,9 +81,32 @@ class Speaker {
|
||||
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<int16_t> &buffer) {
|
||||
void did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer, bool is_stereo) {
|
||||
++completed_sample_sets_;
|
||||
delegate_->speaker_did_complete_samples(this, buffer);
|
||||
|
||||
// Hope for the fast path first: producer and consumer agree about
|
||||
// number of channels.
|
||||
if(is_stereo == stereo_output_) {
|
||||
delegate_->speaker_did_complete_samples(this, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Producer and consumer don't agree, so mix two channels to one, or double out one to two.
|
||||
if(is_stereo) {
|
||||
// Mix down.
|
||||
mix_buffer_.resize(buffer.size() / 2);
|
||||
for(size_t c = 0; c < mix_buffer_.size(); ++c) {
|
||||
mix_buffer_[c] = (buffer[(c << 1) + 0] + buffer[(c << 1) + 1]) >> 1;
|
||||
// TODO: is there an Accelerate framework solution to this?
|
||||
}
|
||||
} else {
|
||||
// Double up.
|
||||
mix_buffer_.resize(buffer.size() * 2);
|
||||
for(size_t c = 0; c < buffer.size(); ++c) {
|
||||
mix_buffer_[(c << 1) + 0] = mix_buffer_[(c << 1) + 1] = buffer[c];
|
||||
}
|
||||
}
|
||||
delegate_->speaker_did_complete_samples(this, mix_buffer_);
|
||||
}
|
||||
Delegate *delegate_ = nullptr;
|
||||
|
||||
@ -99,6 +122,7 @@ class Speaker {
|
||||
float output_cycles_per_second_ = 1.0f;
|
||||
int output_buffer_size_ = 1;
|
||||
bool stereo_output_ = false;
|
||||
std::vector<int16_t> mix_buffer_;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user