80%重构mixer计算部分
This commit is contained in:
parent
d81551255a
commit
c4abac61db
@ -24,8 +24,8 @@ void audio_device_manager::init(singleton_initliazer& initliazer) {
|
||||
singleton_t<audio_device_manager>::init(initliazer);
|
||||
audio_ = new RtAudio();
|
||||
log_all_devices();
|
||||
// output_params_.deviceId = audio_->getDefaultOutputDevice();
|
||||
output_params_.deviceId = 131;
|
||||
output_params_.deviceId = audio_->getDefaultOutputDevice();
|
||||
// output_params_.deviceId = 131;
|
||||
output_params_.nChannels = get_output_channel_count();
|
||||
output_params_.firstChannel = 0;
|
||||
buffer_size_ = 512;
|
||||
|
@ -18,27 +18,18 @@ latency_compensator::~latency_compensator() {
|
||||
void latency_compensator::init() {
|
||||
const uint32_t channel_count = g_audio_device_manager.get_output_channel_count();
|
||||
internal_buffer.resize(channel_count);
|
||||
ui_buffers.resize(channel_count);
|
||||
|
||||
uint32_t block_size = g_audio_device_manager.get_buffer_size();
|
||||
resize(block_size);
|
||||
for (auto& buffer : ui_buffers) {
|
||||
buffer.set_capacity(block_size * 2);
|
||||
}
|
||||
}
|
||||
|
||||
void latency_compensator::set_latency(int32_t in_latency_offset) {
|
||||
latency_ = in_latency_offset;
|
||||
g_audio_thread_hub.push_message([]() {
|
||||
on_latency_offset_changed.broadcast();
|
||||
});
|
||||
}
|
||||
void latency_compensator::set_latency(uint32_t in_latency) {
|
||||
latency_ = in_latency;
|
||||
|
||||
void latency_compensator::set_user_latency(int32_t in_latency_offset) {
|
||||
user_latency_ = in_latency_offset;
|
||||
g_audio_thread_hub.push_message([]() {
|
||||
on_latency_offset_changed.broadcast();
|
||||
});
|
||||
const uint32_t block_size = g_audio_device_manager.get_buffer_size();
|
||||
const int32_t block_num = in_latency / block_size + 1;
|
||||
resize(block_num * block_size);
|
||||
push_zeros(in_latency);
|
||||
}
|
||||
|
||||
void latency_compensator::push(audio_buffer& in_buffer) {
|
||||
@ -48,39 +39,21 @@ void latency_compensator::push(audio_buffer& in_buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 假设需要延后20个sample(latency_offset = 20), 当前frame_size为512
|
||||
// 2. 那么在第一次pop的时候, 需要在前面补充20个0, 然后再后面补上512-20个sample
|
||||
|
||||
// 1. 如果要提前20个sample(latency_offset = -20), 那么就相当于除去这个混音轨道, 其他的混音轨道都延迟20个sample
|
||||
void latency_compensator::pop(uint64_t delta_sample, circular_buffer_vector_type& out_buffer) {
|
||||
std::vector<sample_t> temp_buffer(delta_sample);
|
||||
|
||||
for (auto buffer : std::views::zip(internal_buffer, ui_buffers, out_buffer)) {
|
||||
auto& [internal, ui_buffer, target_buffer] = buffer;
|
||||
for (auto buffer : std::views::zip(internal_buffer, out_buffer)) {
|
||||
auto& [internal, target_buffer] = buffer;
|
||||
internal.pop(temp_buffer.data(), delta_sample);
|
||||
target_buffer.push(temp_buffer);
|
||||
ui_buffer.push(temp_buffer);
|
||||
|
||||
memset(temp_buffer.data(), 0, delta_sample * sizeof(sample_t));
|
||||
}
|
||||
}
|
||||
|
||||
void latency_compensator::pop(uint64_t delta_smaple, audio_buffer& out_buffer) {
|
||||
for (auto buffer : std::views::zip(internal_buffer, ui_buffers, out_buffer.get_headers_vector())) {
|
||||
auto& [internal, ui_buffer, target_buffer] = buffer;
|
||||
for (auto buffer : std::views::zip(internal_buffer, out_buffer.get_headers_vector())) {
|
||||
auto& [internal, target_buffer] = buffer;
|
||||
internal.pop(target_buffer, delta_smaple);
|
||||
ui_buffer.push(target_buffer, delta_smaple);
|
||||
}
|
||||
}
|
||||
|
||||
void latency_compensator::update_buffer(int32_t min_latency, int32_t max_latency) {
|
||||
// 根据全局最大延迟计算需要的buffer大小
|
||||
const uint32_t block_size = g_audio_device_manager.get_buffer_size();
|
||||
const auto& buffer_size = std::max(0, max_latency - get_real_latency());
|
||||
|
||||
const int32_t block_num = buffer_size / block_size + 1;
|
||||
resize(block_num * block_size);
|
||||
|
||||
const auto& buffer_latency = max_latency - (get_real_latency() - min_latency); // 计算需要的buffer大小
|
||||
push_zeros(buffer_latency);
|
||||
}
|
||||
|
@ -19,22 +19,11 @@ public:
|
||||
void pop(uint64_t delta_sample, circular_buffer_vector_type& out_buffer);
|
||||
void pop(uint64_t delta_smaple, audio_buffer& out_buffer);
|
||||
|
||||
/**
|
||||
* 更新缓冲区, 主要是根据全局最大延迟计算需要的buffer大小
|
||||
* @param global_max_latency 全局最大延迟
|
||||
*/
|
||||
void update_buffer(int32_t min_latency, int32_t max_latency);
|
||||
|
||||
void set_latency(int32_t in_latency_offset);
|
||||
void set_user_latency(int32_t in_latency_offset);
|
||||
|
||||
[[nodiscard]] int32_t get_user_latency() const { return user_latency_; }
|
||||
[[nodiscard]] int32_t get_latency() const { return latency_; }
|
||||
[[nodiscard]] int32_t get_real_latency() const { return latency_ + user_latency_; }
|
||||
void set_latency(uint32_t in_latency);
|
||||
[[nodiscard]] uint32_t get_latency() const { return latency_; }
|
||||
|
||||
[[nodiscard]] circular_buffer_vector_type& get_internal_buffer() { return internal_buffer; }
|
||||
|
||||
circular_buffer_vector_type ui_buffers;
|
||||
protected:
|
||||
void resize(uint32_t block_size) {
|
||||
for (auto& channel : internal_buffer) {
|
||||
@ -52,7 +41,6 @@ protected:
|
||||
private:
|
||||
// 预计完成的sample_pos
|
||||
uint64_t finish_sample_pos_ = 0;
|
||||
int32_t user_latency_ = 0; // 用户期望延迟偏移, 大于0表示延迟, 小于0表示提前
|
||||
int32_t latency_ = 0; // 实际延迟
|
||||
uint32_t latency_ = 0; // 实际延迟
|
||||
circular_buffer_vector_type internal_buffer;
|
||||
};
|
||||
|
@ -12,52 +12,6 @@
|
||||
|
||||
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);
|
||||
@ -69,7 +23,7 @@ void mixer::init(singleton_initliazer& initliazer) {
|
||||
zero_track.rename("zero");
|
||||
zero_track.init();
|
||||
|
||||
auto* master = alloc_track<dummy_track>();
|
||||
auto* master = obj_mempool<dummy_track>::alloc();
|
||||
master->rename("master");
|
||||
push_track(master);
|
||||
}
|
||||
@ -83,35 +37,30 @@ 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);
|
||||
}
|
||||
obj_mempool<dummy_track>::free_all();
|
||||
obj_mempool<instrument_track>::free_all();
|
||||
tracks_.clear();
|
||||
}
|
||||
|
||||
dummy_track* mixer::create_dummy_track(const std::string& in_name) {
|
||||
auto* track = alloc_track<dummy_track>();
|
||||
auto* track = obj_mempool<dummy_track>::alloc();
|
||||
track->init();
|
||||
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);
|
||||
processor_.add_link(track, get_master(), 1.0f);
|
||||
thread_register_track(track);
|
||||
});
|
||||
return track;
|
||||
}
|
||||
|
||||
instrument_track* mixer::create_instrument_track(plugin_host* in_instrument) {
|
||||
auto* track = alloc_track<instrument_track>(in_instrument);
|
||||
auto* track = obj_mempool<instrument_track>::alloc(in_instrument);
|
||||
track->init();
|
||||
|
||||
// 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);
|
||||
processor_.add_link(track, get_master(), 1.0f);
|
||||
thread_register_track(track);
|
||||
});
|
||||
return track;
|
||||
@ -119,22 +68,38 @@ instrument_track* mixer::create_instrument_track(plugin_host* in_instrument) {
|
||||
|
||||
void mixer::remove_track(mixer_track* track) {
|
||||
g_audio_thread_hub.push_message([track, this] {
|
||||
thread_remove_track(track);
|
||||
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;
|
||||
switch (track->get_type()) {
|
||||
case mixer_track_type::unknown:
|
||||
break;
|
||||
case mixer_track_type::dummy:
|
||||
obj_mempool<dummy_track>::free(dynamic_cast<dummy_track*>(track));
|
||||
break;
|
||||
case mixer_track_type::instrument:
|
||||
obj_mempool<instrument_track>::free(dynamic_cast<instrument_track*>(track));
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
processor_.process(in_frames);
|
||||
processor_.pop_master(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());
|
||||
processor_.update_all();
|
||||
process_node_dirty_ = false;
|
||||
}
|
||||
|
||||
@ -145,7 +110,7 @@ void mixer::reset() {
|
||||
|
||||
void mixer::request_build_process_node() {
|
||||
g_audio_thread_hub.push_message([this] {
|
||||
update_tasks();
|
||||
processor_.update_all();
|
||||
});
|
||||
}
|
||||
|
||||
@ -155,89 +120,13 @@ void mixer::push_track(mixer_track* track) {
|
||||
|
||||
void mixer::thread_register_track(mixer_track* track) {
|
||||
push_track(track);
|
||||
update_tasks();
|
||||
processor_.update_all();
|
||||
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());
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < tracks_.size(); i++) {
|
||||
mixer_track* track = tracks_[i];
|
||||
track->compensator_.update_buffer(min_latency, max_latency);
|
||||
}
|
||||
processor_.update_latency();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include "mempool.h"
|
||||
#include "mixer_processor.h"
|
||||
#include "mixer_track.h"
|
||||
#include "taskflow/taskflow.hpp"
|
||||
|
||||
@ -24,7 +25,7 @@ public:
|
||||
dummy_track* create_dummy_track(const std::string& in_name);
|
||||
instrument_track* create_instrument_track(plugin_host* in_instrument);
|
||||
void remove_track(mixer_track* track);
|
||||
const std::vector<mixer_track*>& get_tracks() const { return tracks_; }
|
||||
[[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();
|
||||
@ -43,35 +44,12 @@ public:
|
||||
private:
|
||||
void push_track(mixer_track* track);
|
||||
|
||||
template<typename T>
|
||||
auto alloc_track() -> T* {
|
||||
auto* track = track_pool_[T::type].template alloc<T>();
|
||||
track->init();
|
||||
return track;
|
||||
}
|
||||
template<typename T, typename ...Args>
|
||||
auto alloc_track(Args&&... args) -> T* {
|
||||
auto* track = track_pool_[T::type].template alloc<T>(std::forward<Args>(args)...);
|
||||
track->init();
|
||||
return track;
|
||||
}
|
||||
void free_track(mixer_track* track) {
|
||||
track_pool_[track->get_type()].free(track);
|
||||
}
|
||||
|
||||
void thread_register_track(mixer_track* track);
|
||||
void thread_remove_track(mixer_track* track);
|
||||
|
||||
void build_process_node();
|
||||
void update_taskflow(uint32_t in_frames);
|
||||
void update_tasks();
|
||||
void update_tasks_immediate();
|
||||
|
||||
void on_mixer_latency_changed();
|
||||
|
||||
std::vector<mixer_track*> tracks_;
|
||||
std::unordered_map<mixer_track_type, mempool<>> track_pool_;
|
||||
std::vector<tf::Taskflow> taskflow_;
|
||||
mixer_processor processor_;
|
||||
bool process_node_dirty_ = false;
|
||||
};
|
||||
|
||||
|
175
core/audio/mixer/mixer_processor.cpp
Normal file
175
core/audio/mixer/mixer_processor.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
#include "mixer_processor.h"
|
||||
|
||||
#include "channel_interface.h"
|
||||
#include "channel_node.h"
|
||||
#include "mempool.h"
|
||||
#include "mixer.h"
|
||||
#include "mixer_track.h"
|
||||
#include "audio/plugin_host/plugin_host.h"
|
||||
#include "audio/plugin_host/plugin_host_manager.h"
|
||||
#include "misc/taskflow_singleton.h"
|
||||
|
||||
struct build_process_node {
|
||||
explicit build_process_node(std::unordered_map<mixer_track *, std::vector<mixer_track *>> &track_map)
|
||||
: track_map(track_map) {
|
||||
}
|
||||
|
||||
void run() {
|
||||
build(g_mixer.get_master());
|
||||
build_instruments(g_plugin_host_manager.get_instrument_hosts());
|
||||
|
||||
for (const auto& pair : processed_tracks_) {
|
||||
layer_tracks[pair.second].push_back(pair.first);
|
||||
}
|
||||
for (const auto& pair : layer_tracks) {
|
||||
layer_order.push_back(pair.first);
|
||||
}
|
||||
std::ranges::sort(layer_order, std::greater());
|
||||
}
|
||||
|
||||
std::unordered_map<int32_t, std::vector<mixer_track*>> layer_tracks;
|
||||
std::vector<int32_t> layer_order;
|
||||
|
||||
std::unordered_map<mixer_track*, std::vector<mixer_track*>>& track_map;
|
||||
private:
|
||||
int32_t layer = 0;
|
||||
std::unordered_map<mixer_track*, int32_t> processed_tracks_;
|
||||
|
||||
void build(mixer_track* current_track) {
|
||||
int32_t& track_current_layer = processed_tracks_[current_track];
|
||||
track_current_layer = std::max(track_current_layer, layer);
|
||||
const std::vector<mixer_track*>& children = track_map[current_track];
|
||||
for (mixer_track* child : children) {
|
||||
build(child);
|
||||
for (const plugin_host* effect : child->effects) {
|
||||
build_effect_channel_interface(child, effect->channel, processed_tracks_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 = dynamic_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 = dynamic_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);
|
||||
}
|
||||
}
|
||||
|
||||
void build_instruments(const std::vector<plugin_host*>& instruments) {
|
||||
for (auto instrument: instruments) {
|
||||
build_instrument_process_node(instrument, processed_tracks_);
|
||||
}
|
||||
}
|
||||
|
||||
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_processor::process(uint32_t in_frames) {
|
||||
task_frame_ = in_frames;
|
||||
for (auto& flow: taskflow_) {
|
||||
g_executor->run(flow).wait();
|
||||
}
|
||||
}
|
||||
|
||||
void mixer_processor::pop_master(uint32_t in_frames, circular_buffer_vector_type &out_buffer) {
|
||||
g_mixer.get_master();
|
||||
g_mixer.compensator_.pop(in_frames, out_buffer);
|
||||
}
|
||||
|
||||
void mixer_processor::update_taskflow() {
|
||||
build_process_node build_node(layer_tracks_);
|
||||
build_node.run();
|
||||
auto& layer_order = build_node.layer_order;
|
||||
auto& layer_tracks = build_node.layer_tracks;
|
||||
|
||||
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, this] {
|
||||
auto& track_buffer_header = track;
|
||||
// 从children中获取buffer
|
||||
for (const auto &link: children) {
|
||||
link.track->compensator_.pop(in_frames, temp_mix_buffer_);
|
||||
// audio_buffer& child_buffer = link.track->buffer;
|
||||
buffer_.add(temp_mix_buffer_, link.send_level);
|
||||
}
|
||||
track->process(task_frame_);
|
||||
});
|
||||
}
|
||||
taskflow_.push_back(std::move(taskflow));
|
||||
}
|
||||
}
|
||||
|
||||
void mixer_processor::update_latency() {
|
||||
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());
|
||||
// }
|
||||
//
|
||||
// for (size_t i = 1; i < tracks_.size(); i++) {
|
||||
// mixer_track* track = tracks_[i];
|
||||
// track->compensator_.update_buffer(min_latency, max_latency);
|
||||
// }
|
||||
}
|
||||
|
||||
void mixer_processor::add_link(mixer_track* from, mixer_track* to, float in_send_level) {
|
||||
mixer_track_link* new_link = obj_mempool<mixer_track_link>::alloc(from, to, in_send_level);
|
||||
links_.push_back(new_link);
|
||||
|
||||
// 将连接的轨道加入到层次结构中
|
||||
layer_tracks_[from].push_back(to);
|
||||
|
||||
update_all();
|
||||
}
|
||||
|
||||
void mixer_processor::remove_link(mixer_track* from, mixer_track* to) {
|
||||
const auto it = std::ranges::find_if(links_, [from, to](const auto& link) {
|
||||
return link->from == from && link->send_to == to;
|
||||
});
|
||||
if (it != links_.end()) {
|
||||
obj_mempool<mixer_track_link>::free(*it);
|
||||
links_.erase(it);
|
||||
|
||||
// 更新层次结构
|
||||
std::ranges::remove(layer_tracks_[from], to);
|
||||
if (layer_tracks_[from].empty()) {
|
||||
layer_tracks_.erase(from);
|
||||
}
|
||||
|
||||
update_all();
|
||||
}
|
||||
}
|
||||
|
||||
void mixer_processor::remove_track(mixer_track *track) {
|
||||
|
||||
}
|
39
core/audio/mixer/mixer_processor.h
Normal file
39
core/audio/mixer/mixer_processor.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "latency_compensator.h"
|
||||
#include "taskflow/taskflow.hpp"
|
||||
|
||||
class mixer_track;
|
||||
|
||||
struct mixer_track_link {
|
||||
mixer_track_link() = default;
|
||||
mixer_track_link(mixer_track* from_track, mixer_track* to, float in_send_level) : from(from_track), send_to(to), send_level(in_send_level) {
|
||||
}
|
||||
mixer_track* from = nullptr;
|
||||
mixer_track* send_to = nullptr;
|
||||
float send_level = 1.0f;
|
||||
latency_compensator compensator;
|
||||
};
|
||||
|
||||
class mixer_processor {
|
||||
public:
|
||||
void process(uint32_t in_frames);
|
||||
void pop_master(uint32_t in_frames, circular_buffer_vector_type& out_buffer);
|
||||
|
||||
void update_all() {
|
||||
update_taskflow();
|
||||
update_latency();
|
||||
}
|
||||
|
||||
void update_taskflow();
|
||||
void update_latency();
|
||||
|
||||
void add_link(mixer_track* from, mixer_track* to, float in_send_level);
|
||||
void remove_link(mixer_track* from, mixer_track* to);
|
||||
void remove_track(mixer_track* track);
|
||||
private:
|
||||
std::vector<tf::Taskflow> taskflow_;
|
||||
std::vector<mixer_track_link*> links_;
|
||||
std::unordered_map<mixer_track*, std::vector<mixer_track*>> layer_tracks_;
|
||||
|
||||
std::atomic<uint32_t> task_frame_ = 0;
|
||||
};
|
@ -16,16 +16,18 @@ mixer_track::~mixer_track() {
|
||||
|
||||
void mixer_track::init() {
|
||||
const uint32_t channel_count = g_audio_device_manager.get_output_channel_count();
|
||||
buffer_.resize(channel_count, g_audio_device_manager.get_buffer_size());
|
||||
temp_mix_buffer_.resize(buffer_.get_num_channels(), g_audio_device_manager.get_buffer_size());
|
||||
uint32_t block_size = g_audio_device_manager.get_buffer_size();
|
||||
buffer_.resize(channel_count, block_size);
|
||||
|
||||
ui_buffers.resize(channel_count);
|
||||
for (auto& buffer : ui_buffers) {
|
||||
buffer.set_capacity(block_size * 2);
|
||||
}
|
||||
|
||||
channel_interface_ = new mixer_channel_interface(this);
|
||||
compensator_.init();
|
||||
}
|
||||
|
||||
void mixer_track::add_effect(plugin_host* in_effect) {
|
||||
in_effect->on_latency_changed.add_raw(this, &mixer_track::on_latency_changed);
|
||||
|
||||
g_audio_thread_hub.push_message([in_effect, this] {
|
||||
in_effect->owner_tracks.push_back(this);
|
||||
in_effect->channel->set_input_channel(channel_interface_->output_channel_nodes);
|
||||
@ -36,7 +38,6 @@ void mixer_track::add_effect(plugin_host* in_effect) {
|
||||
|
||||
void mixer_track::remove_effect(plugin_host* in_effect) {
|
||||
g_audio_thread_hub.push_message([in_effect, this] {
|
||||
on_latency_changed(0);
|
||||
auto remove_effect_track = std::remove(in_effect->owner_tracks.begin(), in_effect->owner_tracks.end(), this);
|
||||
in_effect->owner_tracks.erase(remove_effect_track, in_effect->owner_tracks.end());
|
||||
|
||||
@ -45,44 +46,21 @@ void mixer_track::remove_effect(plugin_host* in_effect) {
|
||||
});
|
||||
}
|
||||
|
||||
void mixer_track::add_child(mixer_track* in_child, float in_send_level) {
|
||||
children.push_back({in_child, in_send_level});
|
||||
}
|
||||
|
||||
void mixer_track::remove_child(mixer_track* in_child) {
|
||||
const auto new_end = std::remove_if(children.begin(), children.end(), [in_child](const mixer_track_link& link) {
|
||||
return link.track == in_child;
|
||||
});
|
||||
children.erase(new_end, children.end());
|
||||
}
|
||||
|
||||
void mixer_track::process(uint32_t in_frames) {
|
||||
// 从children中获取buffer
|
||||
for (const auto& link : children) {
|
||||
link.track->compensator_.pop(in_frames, temp_mix_buffer_);
|
||||
// audio_buffer& child_buffer = link.track->buffer;
|
||||
buffer_.add(temp_mix_buffer_, link.send_level);
|
||||
}
|
||||
for (auto effect : effects)
|
||||
effect->process(in_frames);
|
||||
post_process(in_frames);
|
||||
compensator_.push(buffer_);
|
||||
}
|
||||
|
||||
void mixer_track::post_process(uint32_t in_frames) {
|
||||
buffer_.multiple(get_volume());
|
||||
}
|
||||
|
||||
void mixer_track::on_latency_changed(int32_t in_latency) {
|
||||
int32_t latency = 0;
|
||||
for (const auto effect: effects) {
|
||||
int32_t mixer_track::get_latency() const {
|
||||
uint32_t latency = 0;
|
||||
for (const auto effect : effects) {
|
||||
latency += effect->get_latency();
|
||||
}
|
||||
compensator_.set_latency(latency);
|
||||
return latency;
|
||||
}
|
||||
|
||||
instrument_track::instrument_track(plugin_host* in_instrument): mixer_track(mixer_track_type::instrument), instrument_(in_instrument) {
|
||||
in_instrument->on_latency_changed.add_raw(this, &instrument_track::on_latency_changed);
|
||||
}
|
||||
|
||||
void instrument_track::rename(const std::string& in_name) {
|
||||
@ -93,12 +71,8 @@ std::string instrument_track::get_name() const {
|
||||
return instrument_->name;
|
||||
}
|
||||
|
||||
void instrument_track::on_latency_changed(int32_t in_latency) {
|
||||
int32_t latency = 0;
|
||||
for (const auto effect: effects) {
|
||||
latency += effect->get_latency();
|
||||
}
|
||||
compensator_.set_latency(latency);
|
||||
int32_t instrument_track::get_latency() const {
|
||||
return mixer_track::get_latency() + instrument_->get_latency();
|
||||
}
|
||||
|
||||
void delete_effect(mixer_track* track, plugin_host* host) {
|
||||
|
@ -16,15 +16,6 @@ enum class mixer_track_type {
|
||||
instrument,
|
||||
};
|
||||
|
||||
struct mixer_track_link {
|
||||
mixer_track_link() = default;
|
||||
mixer_track_link(mixer_track* in_track, float in_send_level) : track(in_track), send_level(in_send_level) {
|
||||
}
|
||||
mixer_track* track = nullptr;
|
||||
float send_level = 1.0f;
|
||||
};
|
||||
|
||||
|
||||
class CORE_API mixer_track {
|
||||
friend class mixer;
|
||||
public:
|
||||
@ -35,11 +26,8 @@ public:
|
||||
void init();
|
||||
void add_effect(plugin_host* in_effect);
|
||||
void remove_effect(plugin_host* in_effect);
|
||||
void add_child(mixer_track* in_child, float in_send_level);
|
||||
void remove_child(mixer_track* in_child);
|
||||
|
||||
void process(uint32_t in_frames);
|
||||
void post_process(uint32_t in_frames);
|
||||
|
||||
virtual void rename(const std::string& in_name) = 0;
|
||||
[[nodiscard]] virtual std::string get_name() const = 0;
|
||||
@ -55,24 +43,17 @@ public:
|
||||
void set_volume(float in_volume) { volume_ = in_volume; }
|
||||
[[nodiscard]] float get_volume() const { return volume_; }
|
||||
|
||||
[[nodiscard]] int32_t get_latency() const { return compensator_.get_latency(); }
|
||||
[[nodiscard]] int32_t get_user_latency() const { return compensator_.get_user_latency(); }
|
||||
[[nodiscard]] int32_t get_real_latency() const { return compensator_.get_real_latency(); }
|
||||
void set_user_latency(int32_t in_latency) { compensator_.set_latency(in_latency); }
|
||||
[[nodiscard]] circular_buffer_vector_type& get_ui_buffers() { return compensator_.ui_buffers; }
|
||||
[[nodiscard]] virtual int32_t get_latency() const;
|
||||
|
||||
[[nodiscard]] std::string get_imgui_id() const {
|
||||
return get_name() + "##" + std::to_string(id_);
|
||||
}
|
||||
|
||||
std::vector<plugin_host*> effects{};
|
||||
std::vector<mixer_track_link> children{};
|
||||
protected:
|
||||
virtual void on_latency_changed(int32_t in_latency);
|
||||
latency_compensator compensator_;
|
||||
|
||||
circular_buffer_vector_type ui_buffers;
|
||||
private:
|
||||
audio_buffer buffer_;
|
||||
audio_buffer temp_mix_buffer_;
|
||||
const mixer_track_type type_;
|
||||
float volume_ = 1.0f;
|
||||
channel_interface* channel_interface_ = nullptr;
|
||||
@ -88,8 +69,9 @@ public:
|
||||
[[nodiscard]] std::string get_name() const override;
|
||||
|
||||
[[nodiscard]] plugin_host* get_instrument() const { return instrument_; }
|
||||
|
||||
[[nodiscard]] int32_t get_latency() const override;
|
||||
private:
|
||||
void on_latency_changed(int32_t in_latency) override;
|
||||
plugin_host* instrument_;
|
||||
};
|
||||
|
||||
|
42
third_party/mempool/mempool.h
vendored
42
third_party/mempool/mempool.h
vendored
@ -52,3 +52,45 @@ public:
|
||||
private:
|
||||
ncx_slab_pool_t* mem_pool_ = nullptr;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class obj_mempool {
|
||||
public:
|
||||
template<typename ...Args>
|
||||
static T* alloc(Args&&... args) {
|
||||
auto obj = pool_.template alloc<T>(std::forward<Args>(args)...);
|
||||
objs_.push_back(obj);
|
||||
return obj;
|
||||
}
|
||||
static T* alloc() {
|
||||
auto obj = pool_.template alloc<T>();
|
||||
objs_.push_back(obj);
|
||||
return obj;
|
||||
}
|
||||
static void free(T* p) {
|
||||
pool_.template free<T>(p);
|
||||
objs_.erase(std::remove(objs_.begin(), objs_.end(), p), objs_.end());
|
||||
}
|
||||
static void free_all() {
|
||||
for (auto obj : objs_) {
|
||||
pool_.template free<T>(obj);
|
||||
}
|
||||
objs_.clear();
|
||||
}
|
||||
static const std::vector<T*>& objs() {
|
||||
return objs_;
|
||||
}
|
||||
static bool has_obj(T* p) {
|
||||
return std::find(objs_.begin(), objs_.end(), p) != objs_.end();
|
||||
}
|
||||
static bool safe_free(T* p) {
|
||||
if (has_obj(p)) {
|
||||
free(p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
static mempool<alignof(T)> pool_;
|
||||
static std::vector<T*> objs_;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user