105 lines
3.1 KiB
C++
105 lines
3.1 KiB
C++
#include <expected>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include <modulus.hpp>
|
|
#include <sonus.hpp>
|
|
|
|
#include <vamp_zero/audio.hpp>
|
|
#include <vamp_zero/navigation.hpp>
|
|
|
|
|
|
namespace {
|
|
|
|
auto score_active(vamp_zero::app_state const &state) -> std::bool_t {
|
|
if (state.mode == vamp_zero::app_mode::PERFORMANCE_SCORE) {
|
|
return vamp_zero::active_part(state) != nullptr;
|
|
}
|
|
if (state.mode == vamp_zero::app_mode::PRACTICE_SCORE) {
|
|
auto const *exercise = vamp_zero::active_practice(state);
|
|
return exercise != nullptr && vamp_zero::selected_practice_variant(state, *exercise) != nullptr;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
auto log_audio_error(std::string const &action, modulus::error const &error) -> void {
|
|
modulus::log_error(action + ": " + error.describe());
|
|
}
|
|
|
|
}
|
|
|
|
vamp_zero::audio_controller::audio_controller(vamp_zero::audio_config config, sonus::engine engine)
|
|
: config_{config}, engine_{std::move(engine)} {}
|
|
|
|
vamp_zero::audio_controller::~audio_controller() {
|
|
auto lock = std::scoped_lock{mutex_};
|
|
engine_.stop_metronome();
|
|
engine_.stop_all();
|
|
engine_.stop();
|
|
}
|
|
|
|
auto vamp_zero::audio_controller::make_metronome_config(vamp_zero::app_state const &state) const -> sonus::metronome_config {
|
|
auto result = sonus::metronome_config{};
|
|
result.bpm = state.audio.metronome_bpm;
|
|
result.beats_per_bar = config_.beats_per_bar;
|
|
result.volume = config_.metronome_volume;
|
|
return result;
|
|
}
|
|
|
|
auto vamp_zero::audio_controller::sync(vamp_zero::app_state const &state) -> void {
|
|
auto lock = std::scoped_lock{mutex_};
|
|
auto const should_run_metronome = state.audio.metronome_enabled && score_active(state);
|
|
if (!should_run_metronome) {
|
|
if (metronome_running_) {
|
|
engine_.stop_metronome();
|
|
metronome_running_ = false;
|
|
}
|
|
return;
|
|
}
|
|
auto metronome = make_metronome_config(state);
|
|
if (!metronome_running_) {
|
|
auto started = engine_.start_metronome(metronome);
|
|
if (!started) {
|
|
log_audio_error("failed to start metronome", started.error());
|
|
engine_.stop_metronome();
|
|
metronome_running_ = false;
|
|
return;
|
|
}
|
|
metronome_running_ = true;
|
|
last_metronome_bpm_ = metronome.bpm;
|
|
return;
|
|
}
|
|
if (last_metronome_bpm_ != metronome.bpm) {
|
|
auto updated = engine_.update_metronome(metronome);
|
|
if (!updated) {
|
|
log_audio_error("failed to update metronome", updated.error());
|
|
engine_.stop_metronome();
|
|
metronome_running_ = false;
|
|
return;
|
|
}
|
|
last_metronome_bpm_ = metronome.bpm;
|
|
}
|
|
}
|
|
|
|
auto vamp_zero::create_audio_controller(vamp_zero::audio_config const &config)
|
|
-> std::expected<std::unique_ptr<vamp_zero::audio_controller>, modulus::error> {
|
|
if (!config.enabled) {
|
|
return nullptr;
|
|
}
|
|
auto sonus_config = sonus::audio_config{};
|
|
sonus_config.sample_rate = 48000;
|
|
sonus_config.channels = 2;
|
|
sonus_config.master_volume = config.master_volume;
|
|
auto engine = sonus::engine::create(sonus_config);
|
|
if (!engine) {
|
|
return std::unexpected(engine.error());
|
|
}
|
|
auto started = engine->start();
|
|
if (!started) {
|
|
return std::unexpected(started.error());
|
|
}
|
|
return std::make_unique<vamp_zero::audio_controller>(config, std::move(*engine));
|
|
}
|