diff --git a/.gitmodules b/.gitmodules index c50a5c7..7fb3998 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,6 +10,3 @@ [submodule "third_party/glfw"] path = third_party/glfw url = https://github.com/glfw/glfw.git -[submodule "third_party/cppzmq"] - path = third_party/cppzmq - url = https://github.com/zeromq/cppzmq.git diff --git a/core/audio/device/audio_device_manager.cpp b/core/audio/device/audio_device_manager.cpp index eabc074..6c0c067 100644 --- a/core/audio/device/audio_device_manager.cpp +++ b/core/audio/device/audio_device_manager.cpp @@ -136,18 +136,15 @@ void audio_device_manager::start_render_thread() { void audio_device_manager::stop_render_thread() { render_thread_should_stop_ = true; - if (render_thread_.joinable()) - render_thread_.join(); + // if (render_thread_.joinable()) + // render_thread_.join(); // wait for render thread to stop - while (render_thread_running_) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + std::scoped_lock lock(render_thread_mutex_); spdlog::info("port_audio render thread stopped"); } void audio_device_manager::render_thread() { set_thread_name("audio_render"); - render_thread_running_ = true; g_audio_thread_id = std::this_thread::get_id(); dummy_track* master = g_mixer.get_master(); @@ -162,6 +159,7 @@ void audio_device_manager::render_thread() { const float milliseconds = frames / rate * 1000; // 512 / 48000 while (!render_thread_should_stop_) { + std::scoped_lock lock(render_thread_mutex_); g_audio_thread_hub.process_messages(); if (render_buffers_[0].remainder() < frames) { // std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(milliseconds))); @@ -173,5 +171,4 @@ void audio_device_manager::render_thread() { g_plugin_host_manager.process(frames); g_mixer.process(frames, render_buffers_); } - render_thread_running_ = false; } diff --git a/core/audio/device/audio_device_manager.h b/core/audio/device/audio_device_manager.h index f35acad..66c1788 100644 --- a/core/audio/device/audio_device_manager.h +++ b/core/audio/device/audio_device_manager.h @@ -33,8 +33,8 @@ protected: void render_thread(); std::thread render_thread_; circular_buffer_vector_type render_buffers_; - std::atomic_bool render_thread_running_ = false; std::atomic_bool render_thread_should_stop_ = false; + std::mutex render_thread_mutex_; #pragma endregion private: RtAudio::StreamParameters input_params_ = {}; diff --git a/core/audio/midi_sequencer/midi_sequencer.cpp b/core/audio/midi_sequencer/midi_sequencer.cpp index 91ab892..c1d5778 100644 --- a/core/audio/midi_sequencer/midi_sequencer.cpp +++ b/core/audio/midi_sequencer/midi_sequencer.cpp @@ -11,12 +11,13 @@ IMPL_SINGLETON_INSTANCE(midi_sequencer) +smf::MidiFile midifile; void midi_sequencer::test() { - const char* path = R"(F:\VST\VST64\Serum_x64.dll)"; + const char* path = R"(F:\VST\VST64\Addictive Keys.dll)"; // host->try_open_editor(); - smf::MidiFile midifile("E:/Projects/AronaStudio/Arona/resources/1.mid"); + midifile.read("E:/Projects/AronaStudio/Arona/resources/1.mid"); if (!midifile.status()) spdlog::critical("Error reading MIDI file"); midifile.doTimeAnalysis(); @@ -71,6 +72,7 @@ auto midi_sequencer::toggle_play() -> bool { } auto midi_sequencer::create_clip_instance(clip* clip) -> clip_instance* { + check(IS_AUDIO_THREAD()); auto instance = new clip_instance(clip); clip_instances_.push_back(instance); return instance; diff --git a/core/audio/midi_sequencer/midi_sequencer.h b/core/audio/midi_sequencer/midi_sequencer.h index 9f06355..54ff49b 100644 --- a/core/audio/midi_sequencer/midi_sequencer.h +++ b/core/audio/midi_sequencer/midi_sequencer.h @@ -15,7 +15,7 @@ public: void init(singleton_initliazer& initliazer) override; void process(double sample_rate, uint32_t delta_frames); - auto toggle_play() -> bool ; + auto toggle_play() -> bool; template auto create_clip() -> T* { diff --git a/core/audio/misc/audio_buffer_pool.cpp b/core/audio/misc/audio_buffer_pool.cpp index eb22c0e..0162506 100644 --- a/core/audio/misc/audio_buffer_pool.cpp +++ b/core/audio/misc/audio_buffer_pool.cpp @@ -12,6 +12,7 @@ void audio_buffer_pool::release(singleton_release_guard& release_guard) { for (auto& pool : pool_map_) { delete pool.second; } + pool_map_.clear(); } sample_t* audio_buffer_pool::alloc(uint32_t block_size) { @@ -22,5 +23,6 @@ sample_t* audio_buffer_pool::alloc(uint32_t block_size) { } void audio_buffer_pool::free(sample_t* block, uint32_t block_size) { - pool_map_[block_size]->deallocate(block); + if (const auto pool = pool_map_[block_size]) + pool->deallocate(block); } diff --git a/core/audio/mixer/channel_interface.cpp b/core/audio/mixer/channel_interface.cpp index dd5fbfd..ace6ae6 100644 --- a/core/audio/mixer/channel_interface.cpp +++ b/core/audio/mixer/channel_interface.cpp @@ -134,11 +134,11 @@ void channel_interface::remove_track(mixer_track* track) { } mixer_channel_interface::mixer_channel_interface(mixer_track* track) : channel_interface(0, 2), track_(track) { - node_ = new mixer_channel_node(this, track, 0); + node_ = get_pool_obj(this, track, 0); set_output_channel(0, node_); } mixer_channel_interface::~mixer_channel_interface() { - delete node_; + free_pool_obj(node_); } diff --git a/core/audio/mixer/mixer.cpp b/core/audio/mixer/mixer.cpp index 21c9a9b..7ba882b 100644 --- a/core/audio/mixer/mixer.cpp +++ b/core/audio/mixer/mixer.cpp @@ -9,6 +9,60 @@ IMPL_SINGLETON_INSTANCE(mixer) +void mixer_thread_cache::add_track(mixer_track* track) { + std::lock_guard lock(mutex_); + tracks_.push_back(track); +} + +void mixer_thread_cache::remove_track(mixer_track* track) { + std::lock_guard lock(mutex_); + + if (const auto it = std::ranges::find(tracks_, track); it != tracks_.end()) { + tracks_.erase(it); + } + processor_.remove_track(track); + on_remove_track.broadcast(track); + + g_main_thread_hub.push_message([track, this]() { + on_remove_track_main_thread.broadcast(track); + track_pool::free(track); + }); +} + +void mixer_thread_cache::process(uint32_t in_frames, circular_buffer_vector_type& out_buffer) { + std::lock_guard lock(mutex_); + processor_.process(in_frames); + processor_.pop_master(in_frames, out_buffer); + ready_ = true; +} + +void mixer_thread_cache::reset() { + std::lock_guard lock(mutex_); + for (const auto track : tracks_) { + track->clear(); + } +} + +void mixer_thread_cache::add_link(mixer_track* in_source, mixer_track* in_target, float in_gain) { + std::lock_guard lock(mutex_); + processor_.add_link(in_source, in_target, in_gain); +} + +void mixer_thread_cache::remove_link(mixer_track* in_source, mixer_track* in_target) { + std::lock_guard lock(mutex_); + processor_.remove_link(in_source, in_target); +} + +void mixer_thread_cache::build_process_node() { + std::lock_guard lock(mutex_); + processor_.update_all(); +} + +void mixer_thread_cache::update_latency() { + std::lock_guard lock(mutex_); + processor_.update_latency(); +} + void mixer::init(singleton_initliazer& initliazer) { singleton_t::init(initliazer); on_latency_offset_changed.add_raw(this, &mixer::on_mixer_latency_changed); @@ -17,17 +71,12 @@ void mixer::init(singleton_initliazer& initliazer) { null_channel_node::init(); - zero_track_ = new dummy_track(); - zero_track_->rename("zero"); + zero_track_ = track_pool::construct(); zero_track_->init(); - - master_ = new dummy_track(); - master_->rename("master"); - master_->init(); - push_track(master_); + master_ = create_dummy_track("master"); } -void mixer::begin_release(singleton_release_guard &release_guard) { +void mixer::begin_release(singleton_release_guard& release_guard) { singleton::begin_release(release_guard); on_latency_offset_changed.remove_object(this); } @@ -36,90 +85,37 @@ void mixer::release(singleton_release_guard& release_guard) { singleton_t::release(release_guard); release_guard.require_release(); null_channel_node::destroy(); - for (auto track : tracks_) { - delete track; - } - delete zero_track_; - tracks_.clear(); + track_pool::free_all(); } -dummy_track* mixer::create_dummy_track(const std::string& in_name) { - ready_dirty(); - auto* track = new dummy_track(); +dummy_track* mixer::create_dummy_track(const std::string& in_name, bool register_to_manager) { + auto* track = track_pool::construct(); track->init(); track->rename(in_name); - g_audio_thread_hub.push_message([track, this]() { - processor_.add_link(track, get_master(), 1.0f); - thread_register_track(track); - }); + if (register_to_manager) { + mixer_thread_cache_.add_track(track); + mixer_thread_cache_.add_link(track, get_master(), 1.0f); + } return track; } -instrument_track* mixer::create_instrument_track(plugin_host* in_instrument) { - ready_dirty(); - auto* track = new instrument_track(in_instrument); +instrument_track* mixer::create_instrument_track(plugin_host* in_instrument, bool register_to_manager) { + auto* track = track_pool::construct(in_instrument); track->init(); - // register track - g_audio_thread_hub.push_message([track, this] { - processor_.add_link(track, get_master(), 1.0f); - thread_register_track(track); - }); + if (register_to_manager) { + mixer_thread_cache_.add_track(track); + mixer_thread_cache_.add_link(track, get_master(), 1.0f); + } return track; } void mixer::remove_track(mixer_track* track) { - g_audio_thread_hub.push_message([track, this] { - if (const auto it = std::ranges::find(tracks_, track); it != tracks_.end()) { - tracks_.erase(it); - } - processor_.remove_track(track); - on_remove_track.broadcast(track); - - g_main_thread_hub.push_message([track, this]() { - on_remove_track_main_thread.broadcast(track); - if (track == selected_track) - selected_track = nullptr; - delete track; - }); - }); -} - -void mixer::process(uint32_t in_frames, circular_buffer_vector_type& out_buffer) { - processor_.process(in_frames); - processor_.pop_master(in_frames, out_buffer); - ready_ = true; -} - -void mixer::reset() { - for (const auto track : tracks_) { - track->clear(); - } -} - -void mixer::request_build_process_node() { - g_audio_thread_hub.push_message([this] { - processor_.update_all(); - }); -} - -void mixer::push_track(mixer_track* track) { - tracks_.push_back(track); -} - -void mixer::thread_register_track(mixer_track* track) { - push_track(track); - processor_.update_all(); - on_add_track.broadcast(track); - g_main_thread_hub.push_message([track, this] { - on_add_track_main_thread.broadcast(track); - }); + mixer_thread_cache_.remove_track(track); + if (track == selected_track) selected_track = nullptr; } void mixer::on_mixer_latency_changed() { - ready_dirty(); - g_audio_thread_hub.push_message([this] { - processor_.update_latency(); - }); + mixer_thread_cache_.update_latency(); } diff --git a/core/audio/mixer/mixer.h b/core/audio/mixer/mixer.h index b4c2a53..9ce39a5 100644 --- a/core/audio/mixer/mixer.h +++ b/core/audio/mixer/mixer.h @@ -14,6 +14,41 @@ class plugin_host; class channel_interface; class mixer_track; +using track_pool = inherit_obj_pool; +inline multicast_delegate on_add_track; +inline multicast_delegate on_add_track_main_thread; +inline multicast_delegate on_remove_track; +inline multicast_delegate on_remove_track_main_thread; + +class mixer_thread_cache { +public: + void add_track(mixer_track* track); + void remove_track(mixer_track* track); + void process(uint32_t in_frames, circular_buffer_vector_type& out_buffer); + void reset(); + + void add_link(mixer_track* in_source, mixer_track* in_target, float in_gain); + void remove_link(mixer_track* in_source, mixer_track* in_target); + + void build_process_node(); + void update_latency(); + + auto get_tracks() -> const std::vector& { + return tracks_; + } + auto begin() { + return tracks_.begin(); + } + auto end() { + return tracks_.end(); + } +private: + std::vector tracks_; + mixer_processor processor_; + std::atomic ready_ = false; + std::mutex mutex_; +}; + class mixer : public singleton_t { typedef std::pair> layer_type; public: @@ -22,38 +57,32 @@ public: void release(singleton_release_guard& release_guard) override; const char* get_name() override { return "mixer"; } - dummy_track* create_dummy_track(const std::string& in_name); - instrument_track* create_instrument_track(plugin_host* in_instrument); + dummy_track* create_dummy_track(const std::string& in_name, bool register_to_manager = true); + instrument_track* create_instrument_track(plugin_host* in_instrument, bool register_to_manager = true); void remove_track(mixer_track* track); - [[nodiscard]] const std::vector& get_tracks() const { return tracks_; } - void process(uint32_t in_frames, circular_buffer_vector_type& out_buffer); - void reset(); + void process(uint32_t in_frames, circular_buffer_vector_type& out_buffer) { + if (need_build_process_node_) { + mixer_thread_cache_.build_process_node(); + need_build_process_node_ = false; + } + mixer_thread_cache_.process(in_frames, out_buffer); + } + void reset() { mixer_thread_cache_.reset(); } + void request_build_process_node() { need_build_process_node_ = true; } + auto get_tracks() -> const std::vector& { return mixer_thread_cache_.get_tracks(); } [[nodiscard]] auto get_master() const -> dummy_track* { return master_; } - [[nodiscard]] auto get_zero_track() const -> dummy_track* { return zero_track_; } - void request_build_process_node(); - bool is_ready() const { return ready_; } - void ready_dirty() { ready_ = false; } - - multicast_delegate on_add_track; - multicast_delegate on_add_track_main_thread; - multicast_delegate on_remove_track; - multicast_delegate on_remove_track_main_thread; + [[nodiscard]] auto get_zero_track() const -> zero_track* { return zero_track_; } mixer_track* selected_track = nullptr; private: - void push_track(mixer_track* track); - - void thread_register_track(mixer_track* track); - void on_mixer_latency_changed(); - dummy_track* master_; - dummy_track* zero_track_; // 用于没有任何音频输出的通道 - std::vector tracks_; - mixer_processor processor_; - std::atomic ready_ = false; + dummy_track* master_ = nullptr; + zero_track* zero_track_ = nullptr; // 用于没有任何音频输出的通道 + std::atomic need_build_process_node_ = false; + mixer_thread_cache mixer_thread_cache_; }; DEFINE_SINGLETON_INSTANCE(mixer) diff --git a/core/audio/mixer/mixer_track.cpp b/core/audio/mixer/mixer_track.cpp index 0ce7fef..3442317 100644 --- a/core/audio/mixer/mixer_track.cpp +++ b/core/audio/mixer/mixer_track.cpp @@ -7,8 +7,7 @@ #include "thread_message/thread_message_hubs.h" mixer_track::~mixer_track() { - delete channel_interface_; - channel_interface_ = nullptr; + free_pool_obj(channel_interface_); for (auto e : effects_) { // e->on_latency_changed.remove_all(this); get_plugin_host_manager()->remove_effect_plugin_host(e); @@ -25,7 +24,7 @@ void mixer_track::init() { buffer.set_capacity(block_size * 2); } - channel_interface_ = new mixer_channel_interface(this); + channel_interface_ = get_pool_obj(this); } void mixer_track::add_effect(plugin_host* in_effect) { @@ -67,7 +66,7 @@ void mixer_track::push_ui_buffer(const audio_buffer& in_buffer) { } } -instrument_track::instrument_track(plugin_host* in_instrument): mixer_track(mixer_track_type::instrument) +instrument_track::instrument_track(plugin_host* in_instrument): mixer_track(type) , instrument_(in_instrument) {} void instrument_track::rename(const std::string& in_name) { diff --git a/core/audio/mixer/mixer_track.h b/core/audio/mixer/mixer_track.h index f86c44e..780a3fc 100644 --- a/core/audio/mixer/mixer_track.h +++ b/core/audio/mixer/mixer_track.h @@ -3,17 +3,16 @@ #include #include "latency_compensator.h" -#include "../../misc/mempool.h" #include "audio/misc/audio_buffer.h" #include "audio/misc/circular_audio_buffer.h" -#include "misc/delegates.h" -class channel_interface; +class mixer_channel_interface; class mixer_track; class plugin_host; enum class mixer_track_type { unknown, + zero, dummy, instrument, }; @@ -48,7 +47,7 @@ public: [[nodiscard]] auto get_type() const -> mixer_track_type { return type_; } - [[nodiscard]] auto get_channel_interface() const -> channel_interface* { return channel_interface_; } + [[nodiscard]] auto get_channel_interface() const -> mixer_channel_interface* { return channel_interface_; } void set_volume(float in_volume) { volume_ = in_volume; } [[nodiscard]] auto get_volume() const -> float { return volume_; } @@ -69,12 +68,12 @@ private: circular_buffer_vector_type ui_buffers_; std::vector effects_{}; audio_buffer buffer_; - channel_interface* channel_interface_ = nullptr; + mixer_channel_interface* channel_interface_ = nullptr; const uint64_t id_ = 0; float volume_ = 1.0f; }; -class instrument_track : public mixer_track, public pool_obj { +class instrument_track : public mixer_track { public: static constexpr auto type = mixer_track_type::instrument; @@ -92,10 +91,10 @@ private: plugin_host* instrument_; }; -class dummy_track : public mixer_track, public pool_obj { +class dummy_track : public mixer_track { public: static constexpr auto type = mixer_track_type::dummy; - dummy_track() : mixer_track(mixer_track_type::dummy) {} + dummy_track() : mixer_track(type) {} void rename(const std::string& in_name) override { name_ = in_name; } [[nodiscard]] auto get_name() const -> std::string override { return name_; } @@ -103,3 +102,14 @@ public: private: std::string name_; }; + +class zero_track : public mixer_track { +public: + static constexpr auto type = mixer_track_type::zero; + zero_track() : mixer_track(type) {} + + [[nodiscard]] auto get_name() const -> std::string override { return "zero"; } + void rename(const std::string& in_name) override {} +private: + +}; diff --git a/core/audio/plugin_host/plugin_host.cpp b/core/audio/plugin_host/plugin_host.cpp index 9259955..e27b7f2 100644 --- a/core/audio/plugin_host/plugin_host.cpp +++ b/core/audio/plugin_host/plugin_host.cpp @@ -24,9 +24,11 @@ void plugin_host::on_update_buffer_size(int buffer_size) } } -void plugin_host::push_stop_all_notes(uint32_t frame_delta) { - smf::MidiEvent event(0xB0, 0x7B, 0x00); - push_midi(event, frame_delta); +void plugin_host::push_stop_all_notes(uint8_t channel) { + for (uint8_t i = 0; i < 127; ++i) { + smf::MidiEvent event(0x80 | channel, i, 0x00); + push_midi(event, 0); + } } void plugin_host::try_open_editor() { diff --git a/core/audio/plugin_host/plugin_host.h b/core/audio/plugin_host/plugin_host.h index 6aff088..21262e2 100644 --- a/core/audio/plugin_host/plugin_host.h +++ b/core/audio/plugin_host/plugin_host.h @@ -59,7 +59,7 @@ public: virtual void process(uint32_t frame_num) = 0; virtual void push_midi(const smf::MidiEvent& event, uint32_t frame_delta) = 0; - void push_stop_all_notes(uint32_t frame_delta = 0); + void push_stop_all_notes(uint8_t channel = 0); void try_open_editor(); diff --git a/core/audio/plugin_host/plugin_host_manager.cpp b/core/audio/plugin_host/plugin_host_manager.cpp index 686b801..92e0b90 100644 --- a/core/audio/plugin_host/plugin_host_manager.cpp +++ b/core/audio/plugin_host/plugin_host_manager.cpp @@ -16,8 +16,7 @@ IMPL_SINGLETON_INSTANCE(plugin_host_manager) void plugin_host_manager::init(singleton_initliazer& initliazer) { singleton_t::init(initliazer); - auto* mixer_ptr = initliazer.require(); - mixer_ptr->on_remove_track.add_raw(this, &plugin_host_manager::on_mixer_track_removed); + on_remove_track.add_raw(this, &plugin_host_manager::on_mixer_track_removed); } void plugin_host_manager::release(singleton_release_guard& release_guard) { @@ -77,7 +76,7 @@ void plugin_host_manager::remove_instrument_plugin_host(plugin_host* host) { plugin_host* plugin_host_manager::load_plugin(const char* path) { auto host = new vst2_plugin_host(); try { - host->load_plugin(path); + host->load(path); } catch (std::exception& e) { spdlog::error("Failed to load plugin: {}", e.what()); delete host; @@ -91,14 +90,15 @@ plugin_host* plugin_host_manager::load_plugin(const char* path) { } void plugin_host_manager::register_instrument_plugin(plugin_host* host) { - instrument_plugins_.push_back(host); g_audio_thread_hub.push_message([this, host]() { + instrument_plugins_.push_back(host); instrument_track* instrument_track = g_mixer.create_instrument_track(host); host->channel->set_input_channel(instrument_track->get_channel_interface()->input_channel_nodes); host->channel->set_output_channel(instrument_track->get_channel_interface()->output_channel_nodes); host->owner_tracks.push_back(instrument_track); host->update_channel_node_name(); update_taskflow(g_audio_device_manager.get_buffer_size()); + g_main_thread_hub.push_message([host, this]() { on_instrument_added.broadcast(host); }); @@ -106,16 +106,19 @@ void plugin_host_manager::register_instrument_plugin(plugin_host* host) { } void plugin_host_manager::process(uint32_t in_frames) { + check(IS_AUDIO_THREAD()); g_executor->run(taskflow_).wait(); } void plugin_host_manager::on_mixer_track_removed(mixer_track* track) { + check(IS_AUDIO_THREAD()); for (auto host : plugin_hosts_) { host->channel->remove_track(track); } } void plugin_host_manager::update_taskflow(uint32_t in_frames) { + check(IS_AUDIO_THREAD()); tf::Taskflow taskflow; for (auto host : instrument_plugins_) { taskflow.emplace([host, in_frames] { diff --git a/core/audio/plugin_host/plugin_host_manager.h b/core/audio/plugin_host/plugin_host_manager.h index b81facd..0f4b92f 100644 --- a/core/audio/plugin_host/plugin_host_manager.h +++ b/core/audio/plugin_host/plugin_host_manager.h @@ -1,9 +1,10 @@ #pragma once +#include + #include "misc/delegates.h" #include "misc/singleton/singleton.h" #include "taskflow/taskflow.hpp" #include "plugin_host.h" -#include "../../misc/mempool.h" #include class mixer_track; diff --git a/third_party/cppzmq b/third_party/cppzmq deleted file mode 160000 index 6164cf7..0000000 --- a/third_party/cppzmq +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6164cf7dbc1df6d1bd8e4c6c5f8e52d7dea63aa7