diff --git a/core/application/command_line.h b/core/application/command_line.h index 6b17ddf..4f11591 100644 --- a/core/application/command_line.h +++ b/core/application/command_line.h @@ -1,6 +1,6 @@ #pragma once -#include #include +#include class command_line { public: @@ -20,6 +20,6 @@ public: void get_arg(const std::string& key, bool& out) const; private: - std::map args_; // key-value pairs + std::unordered_map args_; // key-value pairs command_line() = default; }; diff --git a/core/audio/device/audio_device_manager.cpp b/core/audio/device/audio_device_manager.cpp index 40e6aa2..394e10d 100644 --- a/core/audio/device/audio_device_manager.cpp +++ b/core/audio/device/audio_device_manager.cpp @@ -38,7 +38,8 @@ void audio_device_manager::release(singleton_release_guard& release_guard) { singleton_t::release(release_guard); stop_render_thread(); release_guard.require_release(); - audio_->stopStream(); + if (audio_) + audio_->stopStream(); delete audio_; } @@ -76,6 +77,7 @@ uint32_t audio_device_manager::get_sample_rate() const { void audio_device_manager::set_sample_rate(uint32_t sample_rate) { sample_rate_ = sample_rate; + on_sample_rate_changed.broadcast(sample_rate_); } uint32_t audio_device_manager::get_buffer_size() const { @@ -164,7 +166,7 @@ void audio_device_manager::render_thread() { // std::this_thread::yield(); continue; } - g_midi_sequencer.process(rate, frames); + g_midi_sequencer.process(get_sample_rate(), frames); g_mixer.reset(); g_plugin_host_manager.process(frames); g_mixer.process(frames); diff --git a/core/audio/device/audio_device_manager.h b/core/audio/device/audio_device_manager.h index 8399b18..f35acad 100644 --- a/core/audio/device/audio_device_manager.h +++ b/core/audio/device/audio_device_manager.h @@ -3,6 +3,7 @@ #include "audio/misc/circular_audio_buffer.h" #include "RtAudio.h" +#include "misc/delegates.h" class audio_device_manager : public singleton_t { public: @@ -23,6 +24,8 @@ public: int stream_callback(sample_t* output, sample_t* input, unsigned long frame_count, double stream_time, RtAudioStreamStatus status); void log_all_devices(); void log_current_device_info(); + + multicast_delegate on_sample_rate_changed; protected: #pragma region render_thread void start_render_thread(); diff --git a/core/audio/mixer/channel_interface.cpp b/core/audio/mixer/channel_interface.cpp index ef0a2a6..0152a57 100644 --- a/core/audio/mixer/channel_interface.cpp +++ b/core/audio/mixer/channel_interface.cpp @@ -92,22 +92,22 @@ void channel_interface::set_output_channel_node_name(uint32_t node_index, uint32 output_channel_names_[node_index][channel_index] = name; } -std::map channel_interface::get_input_channel_node_name(uint32_t node_index) { +std::unordered_map channel_interface::get_input_channel_node_name(uint32_t node_index) { return input_channel_names_[node_index]; } -std::map channel_interface::get_input_channel_node_name(channel_node* node) { +std::unordered_map channel_interface::get_input_channel_node_name(channel_node* node) { uint32_t index = get_input_node_index(node); if (index == -1) return {}; return get_input_channel_node_name(index); } -std::map channel_interface::get_output_channel_node_name(uint32_t node_index) { +std::unordered_map channel_interface::get_output_channel_node_name(uint32_t node_index) { return output_channel_names_[node_index]; } -std::map channel_interface::get_output_channel_node_name(channel_node* node) { +std::unordered_map channel_interface::get_output_channel_node_name(channel_node* node) { uint32_t index = get_output_node_index(node); if (index == -1) return {}; diff --git a/core/audio/mixer/channel_interface.h b/core/audio/mixer/channel_interface.h index 788f690..e536b39 100644 --- a/core/audio/mixer/channel_interface.h +++ b/core/audio/mixer/channel_interface.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include @@ -27,18 +27,18 @@ public: void set_input_channel_node_name(uint32_t node_index, uint32_t channel_index, const std::string& name); void set_output_channel_node_name(uint32_t node_index, uint32_t channel_index, const std::string& name); - std::map get_input_channel_node_name(uint32_t node_index); - std::map get_input_channel_node_name(channel_node* node); - std::map get_output_channel_node_name(uint32_t node_index); - std::map get_output_channel_node_name(channel_node* node); + std::unordered_map get_input_channel_node_name(uint32_t node_index); + std::unordered_map get_input_channel_node_name(channel_node* node); + std::unordered_map get_output_channel_node_name(uint32_t node_index); + std::unordered_map get_output_channel_node_name(channel_node* node); void remove_track(mixer_track* track); std::vector input_channel_nodes; std::vector output_channel_nodes; private: - std::map> input_channel_names_; - std::map> output_channel_names_; + std::unordered_map> input_channel_names_; + std::unordered_map> output_channel_names_; std::vector input_headers_; std::vector output_headers_; }; diff --git a/core/audio/mixer/mixer.cpp b/core/audio/mixer/mixer.cpp index ae8269c..87569f9 100644 --- a/core/audio/mixer/mixer.cpp +++ b/core/audio/mixer/mixer.cpp @@ -11,7 +11,7 @@ IMPL_SINGLETON_INSTANCE(mixer) -void build_effect_channel_interface(mixer_track* track, const channel_interface* in_interface, std::map& processed_tracks) { +void build_effect_channel_interface(mixer_track* track, const channel_interface* in_interface, std::unordered_map& processed_tracks) { int32_t& track_current_layer = processed_tracks[track]; auto& input_channel_nodes = in_interface->input_channel_nodes; auto& output_channel_nodes = in_interface->output_channel_nodes; @@ -38,7 +38,7 @@ void build_effect_channel_interface(mixer_track* track, const channel_interface* } } -int32_t build_process_node_internal(mixer_track* track, std::map& processed_tracks, int32_t layer) { +int32_t build_process_node_internal(mixer_track* track, std::unordered_map& processed_tracks, int32_t layer) { int32_t& track_current_layer = processed_tracks[track]; track_current_layer = std::max(track_current_layer, layer); for (const mixer_track_link& child_link: track->children) { @@ -51,7 +51,7 @@ int32_t build_process_node_internal(mixer_track* track, std::map& processed_tracks) { +void build_instrument_process_node(const plugin_host* host, std::unordered_map& processed_tracks) { for (mixer_track* Track : host->owner_tracks) { build_effect_channel_interface(Track, host->channel, processed_tracks); } @@ -140,7 +140,7 @@ void mixer::reset() { void mixer::build_process_node() { if (tracks_.empty()) return; - std::map processed_tracks; + std::unordered_map processed_tracks; auto* master = get_master(); build_process_node_internal(master, processed_tracks, 0); const auto& instruments = g_plugin_host_manager.get_plugin_hosts(); @@ -235,6 +235,7 @@ void mixer::update_taskflow(uint32_t in_frames) { void mixer::begin_release(singleton_release_guard &release_guard) { singleton::begin_release(release_guard); auto e = executor_.exchange(nullptr); - e->wait_for_all(); + if (e) + e->wait_for_all(); delete e; } diff --git a/core/audio/mixer/mixer.h b/core/audio/mixer/mixer.h index d4c12ad..efcc439 100644 --- a/core/audio/mixer/mixer.h +++ b/core/audio/mixer/mixer.h @@ -47,7 +47,7 @@ private: void update_taskflow(uint32_t in_frames); std::vector tracks_; - std::map> layer_tracks_; + std::unordered_map> layer_tracks_; std::vector layer_order_; std::atomic executor_; tf::Taskflow taskflow_; diff --git a/core/audio/plugin_host/midi_sequencer.cpp b/core/audio/plugin_host/midi_sequencer.cpp index 5d2cae5..01aa625 100644 --- a/core/audio/plugin_host/midi_sequencer.cpp +++ b/core/audio/plugin_host/midi_sequencer.cpp @@ -1,15 +1,44 @@ #include "midi_sequencer.h" +#include "audio/device/audio_device_manager.h" +#include "misc/tick.h" #include "vst2/vst2_plugin_host.h" IMPL_SINGLETON_INSTANCE(midi_sequencer) + void midi_sequencer::init(singleton_initliazer& initliazer) { singleton_t::init(initliazer); - - vst2_plugin_host::vst_time_info.tempo = 128.0; - + auto adm = initliazer.require(); + adm->on_sample_rate_changed.add_raw(this, &midi_sequencer::on_sample_rate_changed); + set_bpm(140.0); + set_tpq(960); } -void midi_sequencer::process(double sample_rate, uint32_t in_frames) { +void midi_sequencer::process(double sample_rate, uint32_t delta_frames) { + update_time(sample_rate, delta_frames); + update_vst2_time_info(); } + +void midi_sequencer::set_bpm(double in_bpm) { + bpm_ = std::max(in_bpm, 1.0); + vst2_time.tempo = bpm_; +} + +void midi_sequencer::set_tpq(int32_t in_tpq) { + tpq_ = in_tpq; +} + +void midi_sequencer::on_sample_rate_changed(uint32_t sample_rate) { + vst2_time.sampleRate = sample_rate; +} + +void midi_sequencer::update_time(double sample_rate, uint32_t delta_frames) { + audio_frame frame(delta_frames); +} + +void midi_sequencer::update_vst2_time_info() { + vst2_time.nanoSeconds = 0; + vst2_time.ppqPos = tpq_pos_; +} + diff --git a/core/audio/plugin_host/midi_sequencer.h b/core/audio/plugin_host/midi_sequencer.h index 6e6f391..85e3593 100644 --- a/core/audio/plugin_host/midi_sequencer.h +++ b/core/audio/plugin_host/midi_sequencer.h @@ -1,14 +1,35 @@ #pragma once #include +#include "misc/tick.h" #include "misc/singleton/singleton.h" class midi_sequencer : public singleton_t { public: + void init(singleton_initliazer& initliazer) override; - void process(double sample_rate, uint32_t in_frames); + void process(double sample_rate, uint32_t delta_frames); const char* get_name() override { return "midi_sequencer"; } + void set_bpm(double in_bpm); + void set_tpq(int32_t in_tpq); + [[nodiscard]] double get_bpm() const { + return bpm_; + } + [[nodiscard]] int32_t get_tpq() const { + return tpq_; + } +protected: + void on_sample_rate_changed(uint32_t sample_rate); + void update_time(double sample_rate, uint32_t delta_frames); +private: + void update_vst2_time_info(); + + double bpm_ = 0; + int32_t tpq_ = 0; + audio_frame sample_pos_ = 0; + int32_t tpq_pos_ = 0; + double nano_seconds_ = 0; }; DEFINE_SINGLETON_INSTANCE(midi_sequencer) diff --git a/core/audio/plugin_host/plugin_host_manager.cpp b/core/audio/plugin_host/plugin_host_manager.cpp index 35ca39b..580f7a6 100644 --- a/core/audio/plugin_host/plugin_host_manager.cpp +++ b/core/audio/plugin_host/plugin_host_manager.cpp @@ -116,6 +116,7 @@ void plugin_host_manager::update_taskflow(uint32_t in_frames) { void plugin_host_manager::begin_release(singleton_release_guard& release_guard) { auto executor = executor_.exchange(nullptr); - executor->wait_for_all(); + if (executor) + executor->wait_for_all(); delete executor; } diff --git a/core/audio/plugin_host/vst2/vst2_plugin_host.cpp b/core/audio/plugin_host/vst2/vst2_plugin_host.cpp index 198d045..7c45521 100644 --- a/core/audio/plugin_host/vst2/vst2_plugin_host.cpp +++ b/core/audio/plugin_host/vst2/vst2_plugin_host.cpp @@ -4,10 +4,10 @@ #include "audio/mixer/channel_interface.h" #include "window/window_manager.h" -std::map> vst2_library_map; +std::unordered_map> vst2_library_map; VstTimeInfo vst2_plugin_host::vst_time_info{}; -std::map can_do_map = +std::unordered_map can_do_map = { {"sendVstEvents", true}, {"sendVstMidiEvent", true}, @@ -73,7 +73,7 @@ VstIntPtr vst_master_callback(AEffect* effect, VstInt32 opcode, VstInt32 index, return 1; } case audioMasterGetTime: - return (VstIntPtr)&vst2_plugin_host::vst_time_info; + return (VstIntPtr)&vst2_time; case audioMasterIdle: // UE_LOG(LogTemp, Log, TEXT("Plugin Idle")); return 1; diff --git a/core/audio/plugin_host/vst2/vst2_plugin_host.h b/core/audio/plugin_host/vst2/vst2_plugin_host.h index 5725e20..89b1184 100644 --- a/core/audio/plugin_host/vst2/vst2_plugin_host.h +++ b/core/audio/plugin_host/vst2/vst2_plugin_host.h @@ -43,3 +43,5 @@ private: std::shared_ptr library_; bool enabled_ = false; }; + +#define vst2_time vst2_plugin_host::vst_time_info diff --git a/core/misc/singleton/singleton.h b/core/misc/singleton/singleton.h index c7ca432..ab70213 100644 --- a/core/misc/singleton/singleton.h +++ b/core/misc/singleton/singleton.h @@ -46,7 +46,7 @@ public: #define DEFINE_SINGLETON_INSTANCE(T) \ inline T g_##T; \ extern "C" CORE_API T* get_##T(); - #else +#else #define DEFINE_SINGLETON_INSTANCE(T) \ extern "C" CORE_API T* get_##T(); #endif diff --git a/core/misc/tick.cpp b/core/misc/tick.cpp new file mode 100644 index 0000000..6ad56f7 --- /dev/null +++ b/core/misc/tick.cpp @@ -0,0 +1,29 @@ +#include "tick.h" +#include "audio/device/audio_device_manager.h" +#include "audio/plugin_host/midi_sequencer.h" + +midi_tick::midi_tick(const audio_frame& in_frame) { + auto bpm = g_midi_sequencer.get_bpm(); + auto tpq = g_midi_sequencer.get_tpq(); + auto sample_rate = g_audio_device_manager.get_sample_rate(); + + double time_in_seconds = (double)in_frame.get_frames() / sample_rate; + ticks = time_in_seconds * bpm * tpq / 60.0; +} + +audio_frame midi_tick::to_audio_frame() const { + return audio_frame(*this); +} + +audio_frame::audio_frame(const midi_tick& in_tick) { + auto bpm = g_midi_sequencer.get_bpm(); + auto tpq = g_midi_sequencer.get_tpq(); + auto sample_rate = g_audio_device_manager.get_sample_rate(); + double tick_duration = 60.0 / (bpm * tpq); + double tick_in_seconds = in_tick.get_ticks() * tick_duration; + frames = tick_in_seconds * sample_rate; +} + +midi_tick audio_frame::to_midi_tick() const { + return midi_tick(*this); +} diff --git a/core/misc/tick.h b/core/misc/tick.h new file mode 100644 index 0000000..950d35f --- /dev/null +++ b/core/misc/tick.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +class audio_frame; + +class midi_tick { +public: + midi_tick(int64_t in_ticks) : ticks(in_ticks) { + + } + explicit midi_tick(const audio_frame& in_frame); + + [[nodiscard]] audio_frame to_audio_frame() const; + [[nodiscard]] int64_t get_ticks() const { + return ticks; + } + operator int64_t() const { + return ticks; + } +private: + int64_t ticks; +}; + +class audio_frame { +public: + audio_frame(int64_t in_frames) : frames(in_frames) { + + } + explicit audio_frame(const midi_tick& in_tick); + + [[nodiscard]] midi_tick to_midi_tick() const; + [[nodiscard]] int64_t get_frames() const { + return frames; + } + operator int64_t() const { + return frames; + } + auto operator<=>(const audio_frame&) const = default; +private: + int64_t frames; +}; \ No newline at end of file diff --git a/core/window/window_manager.h b/core/window/window_manager.h index a470152..ba7a3ca 100644 --- a/core/window/window_manager.h +++ b/core/window/window_manager.h @@ -1,7 +1,7 @@ #pragma once #include "GLFW/glfw3.h" #include "misc/singleton/singleton.h" -#include +#include #include #include @@ -27,7 +27,7 @@ private: std::shared_ptr window; }; void on_host_window_close(GLFWwindow* window); - std::map host_infos_; + std::unordered_map host_infos_; }; DEFINE_SINGLETON_INSTANCE(window_manager) \ No newline at end of file