241 lines
8.2 KiB
C++

#include "mixer.h"
#include "channel_interface.h"
#include "channel_node.h"
#include "mixer_track.h"
#include "audio/device/audio_device_manager.h"
#include "audio/plugin_host/plugin_host.h"
#include "audio/plugin_host/plugin_host_manager.h"
#include "misc/query_timer.h"
#include "thread_message/thread_message_hubs.h"
IMPL_SINGLETON_INSTANCE(mixer)
void build_effect_channel_interface(mixer_track* track, const channel_interface* in_interface, std::map<mixer_track*, int32_t>& 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;
// 如果这个效果器需要从其他轨道输入,那么目标轨道的深度就是这个轨道的深度+1
for (int i = 1; i < input_channel_nodes.size(); ++i) {
channel_node* node = input_channel_nodes[i];
if (node->type != channel_node_type::mixer)
continue;
const mixer_channel_node* mixer_node = static_cast<mixer_channel_node*>(node);
auto* InputTrack = mixer_node->get_track();
int32_t& target_mixer_current_layer = processed_tracks[InputTrack];
target_mixer_current_layer = std::max(target_mixer_current_layer + 1, track_current_layer + 1);
}
// 如果这个效果器需要输出到其他轨道,那么这个轨道的深度就是目标轨道的深度+1
for (int i = 1; i < output_channel_nodes.size(); ++i) {
auto* node = output_channel_nodes[i];
if (node->type != channel_node_type::mixer)
continue;
const auto* MixerChannelNode = static_cast<mixer_channel_node*>(node);
auto* MixerTrack = MixerChannelNode->get_track();
const int32_t& TargetMixerCurrentLayer = processed_tracks[MixerTrack];
track_current_layer = std::max(track_current_layer, TargetMixerCurrentLayer + 1);
}
}
int32_t build_process_node_internal(mixer_track* track, std::map<mixer_track*, int32_t>& 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) {
mixer_track* ChildTrack = child_link.track;
build_process_node_internal(ChildTrack, processed_tracks, layer + 1);
for (const plugin_host* effect: ChildTrack->effects) {
build_effect_channel_interface(ChildTrack, effect->channel, processed_tracks);
}
}
return ++layer;
}
void build_instrument_process_node(const plugin_host* host, std::map<mixer_track*, int32_t>& processed_tracks) {
for (mixer_track* Track : host->owner_tracks) {
build_effect_channel_interface(Track, host->channel, processed_tracks);
}
}
void mixer::init(singleton_initliazer& initliazer) {
singleton_t<mixer>::init(initliazer);
null_channel_node::init();
executor_.exchange(new tf::Executor(std::thread::hardware_concurrency()));
auto device_manager = initliazer.require<audio_device_manager>();
zero_track = new dummy_track();
zero_track->rename("zero");
zero_track->init();
const auto master = new dummy_track();
master->rename("master");
master->init();
tracks_.push_back(master);
}
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 (const mixer_track* track : tracks_) {
delete track;
}
tracks_.clear();
delete zero_track;
zero_track = nullptr;
}
dummy_track* mixer::create_dummy_track(const std::string& in_name) {
auto* track = new dummy_track();
track->rename(in_name);
track->init();
mixer_track_link link{};
link.track = track;
link.send_level = 1.0f;
get_master()->children.push_back(link);
g_audio_thread_hub.push_message([track, this]() {
thread_register_track(track);
});
return track;
}
instrument_track* mixer::create_instrument_track(plugin_host* in_instrument) {
auto* track = new instrument_track(in_instrument);
track->rename(in_instrument->name);
track->init();
mixer_track_link link{};
link.track = track;
link.send_level = 1.0f;
get_master()->children.push_back(link);
// register track
g_audio_thread_hub.push_message([track, this] {
thread_register_track(track);
});
return track;
}
void mixer::remove_track(mixer_track* track) {
g_audio_thread_hub.push_message([track, this] {
thread_remove_track(track);
});
}
void mixer::process(uint32_t in_frames) {
auto e = executor_.load();
if (!e)
return;
e->run(taskflow_).wait();
post_process(in_frames);
}
void mixer::reset() {
for (const auto track: tracks_) {
track->buffer.clear();
}
}
void mixer::build_process_node() {
if (tracks_.empty())
return;
std::map<mixer_track*, int32_t> processed_tracks;
auto* master = get_master();
build_process_node_internal(master, processed_tracks, 0);
const auto& instruments = g_plugin_host_manager.get_plugin_hosts();
for (const plugin_host* instrument: instruments) {
build_instrument_process_node(instrument, processed_tracks);
}
layer_tracks_.clear();
for (const auto& pair: processed_tracks) {
layer_tracks_[pair.second].push_back(pair.first);
}
layer_order_.clear();
for (const auto& pair: layer_tracks_) {
layer_order_.push_back(pair.first);
}
std::ranges::sort(layer_order_);
}
void mixer::request_build_process_node() {
g_audio_thread_hub.push_message([this] {
build_process_node();
update_taskflow(g_audio_device_manager.get_buffer_size());
});
}
void post_process_internal(mixer_track* track, uint32_t in_frames, std::set<mixer_track*>& processed_tracks) {
if (std::ranges::find(processed_tracks, track) != processed_tracks.end())
return;
for (const auto& link: track->children) {
post_process_internal(link.track, in_frames, processed_tracks);
track->buffer.mix(link.track->buffer, link.send_level);
}
track->post_process(in_frames);
processed_tracks.emplace(track);
}
void mixer::post_process(uint32_t in_frames) const {
const auto master = get_master();
std::set<mixer_track*> processed_tracks;
post_process_internal(master, in_frames, processed_tracks);
}
void mixer::thread_register_track(mixer_track* track) {
tracks_.push_back(track);
build_process_node();
update_taskflow(g_audio_device_manager.get_buffer_size());
on_add_track.broadcast(track);
g_main_thread_hub.push_message([track, this] {
on_add_track_main_thread.broadcast(track);
});
}
void mixer::thread_remove_track(mixer_track* track) {
if (const auto it = std::ranges::find(tracks_, track); it != tracks_.end()) {
tracks_.erase(it);
}
get_master()->remove_child(track);
build_process_node();
update_taskflow(g_audio_device_manager.get_buffer_size());
on_remove_track.broadcast(track);
g_main_thread_hub.push_message([track, this]() {
on_remove_track_main_thread.broadcast(track);
delete track;
});
}
void mixer::update_taskflow(uint32_t in_frames) {
tf::Taskflow taskflow;
std::vector<std::vector<tf::Task>> layer_tasks;
for (int32_t i = layer_order_.size() - 1; i >= 0; --i) {
const auto& order = layer_order_[i];
auto new_layer = std::vector<tf::Task>();
for (const auto& layer = layer_tracks_[order]; const auto& track: layer) {
auto t = taskflow.emplace([track, in_frames] {
track->process(in_frames);
});
new_layer.push_back(t);
}
layer_tasks.push_back(std::move(new_layer));
}
for (int i = layer_tasks.size() - 1; i >= 0; --i) {
tf::Task layer_task = taskflow.emplace([]{});
for (auto& task: layer_tasks[i]) {
task.precede(layer_task);
}
}
taskflow_ = std::move(taskflow);
}
void mixer::begin_release(singleton_release_guard &release_guard) {
singleton::begin_release(release_guard);
auto e = executor_.exchange(nullptr);
e->wait_for_all();
delete e;
}