#include #include #include #include #include #include #include #include #include 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, 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(config, std::move(*engine)); }