244 lines
8.2 KiB
C++
244 lines
8.2 KiB
C++
#include "mixer.h"
|
|
|
|
#include "channel_interface.h"
|
|
#include "channel_node.h"
|
|
#include "audio/device/audio_device_manager.h"
|
|
#include "audio/misc/audio_buffer_pool.h"
|
|
#include "audio/plugin_host/plugin_host.h"
|
|
#include "audio/plugin_host/plugin_host_manager.h"
|
|
#include "misc/query_timer.h"
|
|
#include "misc/taskflow_singleton.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::unordered_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::unordered_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::unordered_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);
|
|
on_latency_offset_changed.add_raw(this, &mixer::on_mixer_latency_changed);
|
|
initliazer.require<audio_buffer_pool>();
|
|
initliazer.require<audio_device_manager>(); // 依赖音频设备管理器, 用于获取采样率和缓冲区大小
|
|
|
|
null_channel_node::init();
|
|
|
|
zero_track.rename("zero");
|
|
zero_track.init();
|
|
|
|
auto* master = alloc_track<dummy_track>();
|
|
master->rename("master");
|
|
push_track(master);
|
|
}
|
|
|
|
void mixer::begin_release(singleton_release_guard &release_guard) {
|
|
singleton::begin_release(release_guard);
|
|
on_latency_offset_changed.remove_object(this);
|
|
}
|
|
|
|
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 (mixer_track* track : tracks_) {
|
|
free_track(track);
|
|
}
|
|
tracks_.clear();
|
|
}
|
|
|
|
dummy_track* mixer::create_dummy_track(const std::string& in_name) {
|
|
auto* track = alloc_track<dummy_track>();
|
|
track->rename(in_name);
|
|
|
|
g_audio_thread_hub.push_message([track, this]() {
|
|
mixer_track_link link{};
|
|
link.track = track;
|
|
link.send_level = 1.0f;
|
|
get_master()->children.emplace_back(link);
|
|
thread_register_track(track);
|
|
});
|
|
return track;
|
|
}
|
|
|
|
instrument_track* mixer::create_instrument_track(plugin_host* in_instrument) {
|
|
auto* track = alloc_track<instrument_track>(in_instrument);
|
|
|
|
// register track
|
|
g_audio_thread_hub.push_message([track, this] {
|
|
mixer_track_link link;
|
|
link.track = track;
|
|
link.send_level = 1.0f;
|
|
get_master()->children.emplace_back(link);
|
|
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, circular_buffer_vector_type& out_buffer) {
|
|
for (auto& flow: taskflow_) {
|
|
g_executor->run(flow).wait();
|
|
}
|
|
get_master()->compensator_.pop(in_frames, out_buffer);
|
|
}
|
|
|
|
void mixer::reset() {
|
|
if (process_node_dirty_) {
|
|
g_executor->wait_for_all();
|
|
build_process_node();
|
|
update_taskflow(g_audio_device_manager.get_buffer_size());
|
|
process_node_dirty_ = false;
|
|
}
|
|
|
|
for (const auto track : tracks_) {
|
|
track->clear();
|
|
}
|
|
}
|
|
|
|
void mixer::request_build_process_node() {
|
|
g_audio_thread_hub.push_message([this] {
|
|
update_tasks();
|
|
});
|
|
}
|
|
|
|
void mixer::push_track(mixer_track* track) {
|
|
tracks_.push_back(track);
|
|
}
|
|
|
|
void mixer::thread_register_track(mixer_track* track) {
|
|
push_track(track);
|
|
update_tasks();
|
|
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);
|
|
update_tasks();
|
|
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;
|
|
free_track(track);
|
|
});
|
|
}
|
|
|
|
inline std::unordered_map<int32_t, std::vector<mixer_track*>> layer_tracks_;
|
|
inline std::vector<int32_t> layer_order_;
|
|
|
|
void mixer::build_process_node() {
|
|
if (tracks_.empty())
|
|
return;
|
|
std::unordered_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_instrument_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_, std::greater());
|
|
}
|
|
|
|
void mixer::update_taskflow(uint32_t in_frames) {
|
|
taskflow_.clear();
|
|
for (int32_t order : layer_order_) {
|
|
const auto& layer = layer_tracks_[order];
|
|
tf::Taskflow taskflow("mixer_update_layer" + std::to_string(order));
|
|
// 每层的轨道并行处理
|
|
for (mixer_track* track : layer) {
|
|
taskflow.emplace([track, in_frames] {
|
|
track->process(in_frames);
|
|
});
|
|
}
|
|
taskflow_.push_back(std::move(taskflow));
|
|
}
|
|
}
|
|
|
|
void mixer::update_tasks() {
|
|
process_node_dirty_ = true;
|
|
}
|
|
|
|
void mixer::update_tasks_immediate() {
|
|
g_executor->wait_for_all();
|
|
build_process_node();
|
|
update_taskflow(g_audio_device_manager.get_buffer_size());
|
|
}
|
|
|
|
void mixer::on_mixer_latency_changed() {
|
|
int32_t max_latency = 0;
|
|
int32_t min_latency = 0;
|
|
for (mixer_track* track : tracks_) {
|
|
max_latency = std::max<int32_t>(max_latency, track->get_real_latency());
|
|
min_latency = std::min<int32_t>(min_latency, track->get_real_latency());
|
|
}
|
|
int32_t latency = max_latency - min_latency;
|
|
|
|
for (mixer_track* track : tracks_) {
|
|
track->compensator_.update_buffer(min_latency, max_latency);
|
|
}
|
|
}
|