2018-02-18 20:23:15 +00:00
|
|
|
//
|
|
|
|
// MultiSpeaker.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 18/02/2018.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2018 Thomas Harte. All rights reserved.
|
2018-02-18 20:23:15 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "MultiSpeaker.hpp"
|
|
|
|
|
|
|
|
using namespace Analyser::Dynamic;
|
|
|
|
|
|
|
|
MultiSpeaker *MultiSpeaker::create(const std::vector<std::unique_ptr<::Machine::DynamicMachine>> &machines) {
|
|
|
|
std::vector<Outputs::Speaker::Speaker *> speakers;
|
|
|
|
for(const auto &machine: machines) {
|
2020-04-02 03:19:34 +00:00
|
|
|
Outputs::Speaker::Speaker *speaker = machine->audio_producer()->get_speaker();
|
2018-02-18 20:23:15 +00:00
|
|
|
if(speaker) speakers.push_back(speaker);
|
|
|
|
}
|
|
|
|
if(speakers.empty()) return nullptr;
|
|
|
|
|
|
|
|
return new MultiSpeaker(speakers);
|
|
|
|
}
|
|
|
|
|
|
|
|
MultiSpeaker::MultiSpeaker(const std::vector<Outputs::Speaker::Speaker *> &speakers) :
|
|
|
|
speakers_(speakers), front_speaker_(speakers.front()) {
|
|
|
|
for(const auto &speaker: speakers_) {
|
|
|
|
speaker->set_delegate(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float MultiSpeaker::get_ideal_clock_rate_in_range(float minimum, float maximum) {
|
|
|
|
float ideal = 0.0f;
|
|
|
|
for(const auto &speaker: speakers_) {
|
|
|
|
ideal += speaker->get_ideal_clock_rate_in_range(minimum, maximum);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ideal / static_cast<float>(speakers_.size());
|
|
|
|
}
|
|
|
|
|
2020-02-15 18:40:19 +00:00
|
|
|
void MultiSpeaker::set_computed_output_rate(float cycles_per_second, int buffer_size, bool stereo) {
|
2020-02-16 23:50:34 +00:00
|
|
|
stereo_output_ = stereo;
|
2018-02-18 20:23:15 +00:00
|
|
|
for(const auto &speaker: speakers_) {
|
2020-02-15 18:40:19 +00:00
|
|
|
speaker->set_computed_output_rate(cycles_per_second, buffer_size, stereo);
|
2018-02-18 20:23:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-16 23:50:34 +00:00
|
|
|
bool MultiSpeaker::get_is_stereo() {
|
|
|
|
// Return as stereo if any subspeaker is stereo.
|
|
|
|
for(const auto &speaker: speakers_) {
|
|
|
|
if(speaker->get_is_stereo()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-03-22 02:00:47 +00:00
|
|
|
void MultiSpeaker::set_output_volume(float volume) {
|
|
|
|
for(const auto &speaker: speakers_) {
|
|
|
|
speaker->set_output_volume(volume);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-18 20:23:15 +00:00
|
|
|
void MultiSpeaker::set_delegate(Outputs::Speaker::Speaker::Delegate *delegate) {
|
|
|
|
delegate_ = delegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MultiSpeaker::speaker_did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) {
|
2018-03-22 15:08:07 +00:00
|
|
|
if(!delegate_) return;
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock_guard(front_speaker_mutex_);
|
|
|
|
if(speaker != front_speaker_) return;
|
2018-02-18 20:23:15 +00:00
|
|
|
}
|
2020-02-16 23:50:34 +00:00
|
|
|
did_complete_samples(this, buffer, stereo_output_);
|
2018-02-18 20:23:15 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 13:23:01 +00:00
|
|
|
void MultiSpeaker::speaker_did_change_input_clock(Speaker *speaker) {
|
2018-03-22 15:08:07 +00:00
|
|
|
if(!delegate_) return;
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock_guard(front_speaker_mutex_);
|
|
|
|
if(speaker != front_speaker_) return;
|
2018-03-22 13:23:01 +00:00
|
|
|
}
|
2018-03-22 15:08:07 +00:00
|
|
|
delegate_->speaker_did_change_input_clock(this);
|
2018-03-22 13:23:01 +00:00
|
|
|
}
|
|
|
|
|
2018-02-18 20:23:15 +00:00
|
|
|
void MultiSpeaker::set_new_front_machine(::Machine::DynamicMachine *machine) {
|
2018-03-22 15:08:07 +00:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock_guard(front_speaker_mutex_);
|
2020-04-02 03:19:34 +00:00
|
|
|
front_speaker_ = machine->audio_producer()->get_speaker();
|
2018-03-22 15:08:07 +00:00
|
|
|
}
|
2018-03-22 13:23:01 +00:00
|
|
|
if(delegate_) {
|
|
|
|
delegate_->speaker_did_change_input_clock(this);
|
|
|
|
}
|
2018-02-18 20:23:15 +00:00
|
|
|
}
|