80%重构mixer计算部分

This commit is contained in:
daiqingshuang 2024-07-05 16:26:49 +08:00
parent d81551255a
commit c4abac61db
10 changed files with 328 additions and 288 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View 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) {
}

View 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;
};

View File

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

View File

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

View File

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