修复退出时崩溃

This commit is contained in:
Nanako 2024-08-04 14:55:40 +08:00
parent fba1e94fb8
commit 065448c5a3
16 changed files with 176 additions and 139 deletions

3
.gitmodules vendored
View File

@ -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

View File

@ -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<uint64_t>(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;
}

View File

@ -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_ = {};

View File

@ -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;

View File

@ -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<class T>
auto create_clip() -> T* {

View File

@ -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);
}

View File

@ -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<mixer_channel_node>(this, track, 0);
set_output_channel(0, node_);
}
mixer_channel_interface::~mixer_channel_interface() {
delete node_;
free_pool_obj(node_);
}

View File

@ -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<mixer>::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>();
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<mixer>::release(release_guard);
release_guard.require_release<audio_device_manager>();
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<dummy_track>();
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<instrument_track>(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();
}

View File

@ -14,6 +14,41 @@ class plugin_host;
class channel_interface;
class mixer_track;
using track_pool = inherit_obj_pool<mixer_track, zero_track, dummy_track, instrument_track>;
inline multicast_delegate<mixer_track*> on_add_track;
inline multicast_delegate<mixer_track*> on_add_track_main_thread;
inline multicast_delegate<mixer_track*> on_remove_track;
inline multicast_delegate<mixer_track*> 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<mixer_track*>& {
return tracks_;
}
auto begin() {
return tracks_.begin();
}
auto end() {
return tracks_.end();
}
private:
std::vector<mixer_track*> tracks_;
mixer_processor processor_;
std::atomic<bool> ready_ = false;
std::mutex mutex_;
};
class mixer : public singleton_t<mixer> {
typedef std::pair<int32_t, std::vector<mixer_track*>> 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<mixer_track*>& 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<mixer_track*>& { 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<mixer_track*> on_add_track;
multicast_delegate<mixer_track*> on_add_track_main_thread;
multicast_delegate<mixer_track*> on_remove_track;
multicast_delegate<mixer_track*> 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<mixer_track*> tracks_;
mixer_processor processor_;
std::atomic<bool> ready_ = false;
dummy_track* master_ = nullptr;
zero_track* zero_track_ = nullptr; // 用于没有任何音频输出的通道
std::atomic<bool> need_build_process_node_ = false;
mixer_thread_cache mixer_thread_cache_;
};
DEFINE_SINGLETON_INSTANCE(mixer)

View File

@ -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<mixer_channel_interface>(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) {

View File

@ -3,17 +3,16 @@
#include <utility>
#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<plugin_host*> 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<instrument_track> {
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<dummy_track> {
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:
};

View File

@ -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() {

View File

@ -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();

View File

@ -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>();
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] {

View File

@ -1,9 +1,10 @@
#pragma once
#include <coroutine>
#include "misc/delegates.h"
#include "misc/singleton/singleton.h"
#include "taskflow/taskflow.hpp"
#include "plugin_host.h"
#include "../../misc/mempool.h"
#include <unordered_map>
class mixer_track;

1
third_party/cppzmq vendored

@ -1 +0,0 @@
Subproject commit 6164cf7dbc1df6d1bd8e4c6c5f8e52d7dea63aa7