新增query_timer用于查看函数执行时间
修复circular_audio_buffer编译错误 临时将taskflow移除,因为在执行任务时等待时间很长
This commit is contained in:
parent
cc44f2bbae
commit
b493dc1e0f
@ -1,5 +1,6 @@
|
||||
#include "application.h"
|
||||
|
||||
#include "audio/device/audio_device_manager.h"
|
||||
#include "misc/singleton/singleton_manager.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/sinks/daily_file_sink.h"
|
||||
@ -31,6 +32,9 @@ void application::init() {
|
||||
spdlog::set_default_logger(logger);
|
||||
|
||||
singleton_manager::get()->init();
|
||||
|
||||
|
||||
get_audio_device_manager()->start();
|
||||
}
|
||||
|
||||
void application::shutdown() {
|
||||
|
@ -7,30 +7,32 @@
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "thread_message/thread_message_hubs.h"
|
||||
|
||||
int rt_audio_callback(void *output_buffer, void *input_buffer,
|
||||
int rt_audio_callback(void* output_buffer, void *input_buffer,
|
||||
unsigned int frames_nums,
|
||||
double stream_time,
|
||||
RtAudioStreamStatus status,
|
||||
void* user_data)
|
||||
{
|
||||
auto* API = static_cast<audio_device_manager*>(user_data);
|
||||
return API->stream_callback((float**)output_buffer, static_cast<float**>(input_buffer), frames_nums, stream_time, status);
|
||||
return API->stream_callback(static_cast<float*>(output_buffer), static_cast<float*>(input_buffer), frames_nums, stream_time, status);
|
||||
}
|
||||
|
||||
void audio_device_manager::init(singleton_initliazer& initliazer) {
|
||||
singleton_t<audio_device_manager>::init(initliazer);
|
||||
options_.flags = RTAUDIO_NONINTERLEAVED;
|
||||
audio_ = new RtAudio();
|
||||
log_all_devices();
|
||||
output_params_.deviceId = audio_->getDefaultOutputDevice();
|
||||
// output_params_.deviceId = audio_->getDefaultOutputDevice();
|
||||
output_params_.deviceId = 131;
|
||||
output_params_.nChannels = get_output_channel_count();
|
||||
spdlog::info("using output device id: {}", output_params_.deviceId);
|
||||
output_params_.firstChannel = 0;
|
||||
buffer_size_ = 512;
|
||||
}
|
||||
|
||||
void audio_device_manager::release(singleton_release_guard& release_guard) {
|
||||
singleton_t<audio_device_manager>::release(release_guard);
|
||||
release_guard.require_release<mixer>();
|
||||
audio_->stopStream();
|
||||
stop_render_thread();
|
||||
delete audio_;
|
||||
}
|
||||
|
||||
@ -39,7 +41,22 @@ void audio_device_manager::start() {
|
||||
if (input_params_.deviceId != 0) {
|
||||
input_params = &input_params_;
|
||||
}
|
||||
audio_->openStream(&output_params_, input_params, RTAUDIO_FLOAT32, get_sample_rate(), &options_.numberOfBuffers, &rt_audio_callback, this, &options_);
|
||||
log_current_device_info();
|
||||
|
||||
options_.flags = RTAUDIO_NONINTERLEAVED;
|
||||
auto err = audio_->openStream(&output_params_, input_params, RTAUDIO_FLOAT32, get_sample_rate(), &buffer_size_, &rt_audio_callback, this, &options_);
|
||||
if (err != RTAUDIO_NO_ERROR) {
|
||||
spdlog::error("failed to open audio stream: {}", audio_->getErrorText());
|
||||
return;
|
||||
}
|
||||
|
||||
err = audio_->startStream();
|
||||
if (err != RTAUDIO_NO_ERROR) {
|
||||
spdlog::error("failed to start audio stream: {}", audio_->getErrorText());
|
||||
return;
|
||||
}
|
||||
spdlog::info("audio stream opened");
|
||||
start_render_thread();
|
||||
}
|
||||
|
||||
uint32_t audio_device_manager::get_sample_rate() const {
|
||||
@ -51,11 +68,11 @@ void audio_device_manager::set_sample_rate(uint32_t sample_rate) {
|
||||
}
|
||||
|
||||
uint32_t audio_device_manager::get_buffer_size() const {
|
||||
return options_.numberOfBuffers;
|
||||
return buffer_size_;
|
||||
}
|
||||
|
||||
void audio_device_manager::set_buffer_size(int buffer_size) {
|
||||
options_.numberOfBuffers = buffer_size;
|
||||
buffer_size_ = buffer_size;
|
||||
}
|
||||
|
||||
uint32_t audio_device_manager::get_input_channel_count() const {
|
||||
@ -66,12 +83,14 @@ uint32_t audio_device_manager::get_output_channel_count() const {
|
||||
return 2; // 现在是固定值, 以后可能会改
|
||||
}
|
||||
|
||||
int audio_device_manager::stream_callback(float** output, float** input, unsigned long frame_count, double stream_time,
|
||||
RtAudioStreamStatus status) {
|
||||
if (render_buffer_.Num() < frame_count * output_params_.nChannels)
|
||||
int audio_device_manager::stream_callback(float* output, float* input, unsigned long frame_count, double stream_time, RtAudioStreamStatus status) {
|
||||
if (render_buffers_[0].Num() < frame_count) {
|
||||
// spdlog::warn("render buffer underflow: {}", render_buffers_[0].Num());
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < output_params_.nChannels; ++i) {
|
||||
render_buffer_.Pop(input[i], frame_count);
|
||||
render_buffers_[i].Pop(output, frame_count);
|
||||
output += frame_count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -84,6 +103,16 @@ void audio_device_manager::log_all_devices() {
|
||||
}
|
||||
}
|
||||
|
||||
void audio_device_manager::log_current_device_info() {
|
||||
spdlog::info("using output device: {}", audio_->getDeviceInfo(output_params_.deviceId).name);
|
||||
spdlog::info("using input device: {}",
|
||||
input_params_.deviceId == 0 ? "none" : audio_->getDeviceInfo(input_params_.deviceId).name);
|
||||
spdlog::info("using sample rate: {}", get_sample_rate());
|
||||
spdlog::info("using buffer size: {}", get_buffer_size());
|
||||
spdlog::info("using output channel count: {}", get_output_channel_count());
|
||||
spdlog::info("using input channel count: {}", get_input_channel_count());
|
||||
}
|
||||
|
||||
void audio_device_manager::start_render_thread() {
|
||||
render_thread_ = std::thread(&audio_device_manager::render_thread, this);
|
||||
render_thread_.detach();
|
||||
@ -98,16 +127,21 @@ void audio_device_manager::render_thread() {
|
||||
dummy_track* master = g_mixer.get_master();
|
||||
spdlog::info("port_audio render thread started");
|
||||
|
||||
render_buffer_.SetCapacity(get_buffer_size() * 4);
|
||||
render_buffers_.resize(get_output_channel_count());
|
||||
|
||||
const uint32_t frames = get_buffer_size();
|
||||
const uint32_t rate = get_sample_rate();
|
||||
|
||||
for (auto& render_buffer : render_buffers_)
|
||||
render_buffer.SetCapacity(frames * 3);
|
||||
|
||||
while (audio_->isStreamRunning()) {
|
||||
const uint32_t milliseconds = 1.f / (rate / (frames / 4)) * 1000;
|
||||
// const float milliseconds = 1.f / (rate / (frames / 4)) * 1e4;
|
||||
|
||||
g_audio_thread_hub.process_messages();
|
||||
if (render_buffer_.Num() >= render_buffer_size_) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
||||
if (render_buffers_[0].Remainder() < frames) {
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<uint64_t>(milliseconds)));
|
||||
std::this_thread::yield();
|
||||
continue;
|
||||
}
|
||||
g_midi_sequencer.process(rate, frames);
|
||||
@ -116,8 +150,9 @@ void audio_device_manager::render_thread() {
|
||||
g_mixer.process(frames);
|
||||
|
||||
const auto& master_headers = master->buffer.get_headers_vector();
|
||||
for (const auto element: master_headers) {
|
||||
render_buffer_.Push(element, frames);
|
||||
for (int i = 0; i < master_headers.size(); ++i) {
|
||||
const auto element = master_headers[i];
|
||||
render_buffers_[i].Push(element, frames);
|
||||
}
|
||||
}
|
||||
spdlog::info("port_audio render thread stopped");
|
||||
|
@ -20,23 +20,24 @@ public:
|
||||
[[nodiscard]] CORE_API uint32_t get_input_channel_count() const;
|
||||
[[nodiscard]] CORE_API uint32_t get_output_channel_count() const;
|
||||
|
||||
int stream_callback(float** output, float** input, unsigned long frame_count, double stream_time, RtAudioStreamStatus status);
|
||||
int stream_callback(float* output, float* input, unsigned long frame_count, double stream_time, RtAudioStreamStatus status);
|
||||
void log_all_devices();
|
||||
void log_current_device_info();
|
||||
protected:
|
||||
#pragma region render_thread
|
||||
void start_render_thread();
|
||||
void stop_render_thread();
|
||||
void render_thread();
|
||||
std::thread render_thread_;
|
||||
circular_audio_buffer<float> render_buffer_;
|
||||
uint32_t render_buffer_size_ = 512;
|
||||
std::vector<circular_audio_buffer<float>> render_buffers_;
|
||||
std::atomic_bool render_thread_running_ = false;
|
||||
#pragma endregion
|
||||
private:
|
||||
RtAudio::StreamParameters input_params_ = {};
|
||||
RtAudio::StreamParameters output_params_ = {};
|
||||
RtAudio::StreamOptions options_ = {};
|
||||
uint32_t sample_rate_ = 44100;
|
||||
uint32_t sample_rate_ = 48000;
|
||||
uint32_t buffer_size_ = 2048;
|
||||
RtAudio* audio_ = nullptr;
|
||||
};
|
||||
|
||||
|
@ -122,8 +122,8 @@ public:
|
||||
int32_t NumToZeroEnd = std::min<int32_t>(NumSamplesOfZeros, Remainder());
|
||||
const int32_t NumToZeroBegin = std::min<int32_t>(NumToZeroEnd, Capacity - WriteIndex);
|
||||
|
||||
memzero(&DestBuffer[WriteIndex], NumToZeroBegin * sizeof(SampleType));
|
||||
memzero(&DestBuffer[0], (NumToZeroEnd - NumToZeroBegin) * sizeof(SampleType));
|
||||
memset(&DestBuffer[WriteIndex], 0, NumToZeroBegin * sizeof(SampleType));
|
||||
memset(&DestBuffer[0], 0, (NumToZeroEnd - NumToZeroBegin) * sizeof(SampleType));
|
||||
|
||||
WriteCounter = (WriteIndex + NumToZeroEnd) % Capacity;
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
#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"
|
||||
#include "taskflow/taskflow.hpp"
|
||||
|
||||
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];
|
||||
@ -68,8 +68,6 @@ void mixer::init(singleton_initliazer& initliazer) {
|
||||
master->rename("master");
|
||||
master->init();
|
||||
tracks_.push_back(master);
|
||||
|
||||
device_manager->start();
|
||||
}
|
||||
|
||||
void mixer::release(singleton_release_guard& release_guard) {
|
||||
@ -121,27 +119,34 @@ void mixer::remove_track(mixer_track* track) {
|
||||
}
|
||||
|
||||
void mixer::process(uint32_t in_frames) {
|
||||
tf::Executor executor;
|
||||
tf::Taskflow taskflow;
|
||||
{
|
||||
query_timer timer("mixer process");
|
||||
// tf::Executor executor;
|
||||
// tf::Taskflow taskflow;
|
||||
|
||||
tf::Task previous_task = taskflow.emplace([] {});
|
||||
for (const auto& order: layer_order_) {
|
||||
for (const auto& layer = layer_tracks_[order]; const auto& track: layer) {
|
||||
taskflow.emplace([track, in_frames] {
|
||||
track->process(in_frames);
|
||||
}).succeed(previous_task);
|
||||
// tf::Task previous_task = taskflow.emplace([] {});
|
||||
for (const auto& order: layer_order_) {
|
||||
for (const auto& layer = layer_tracks_[order]; const auto& track: layer) {
|
||||
// taskflow.emplace([track, in_frames] {
|
||||
track->process(in_frames);
|
||||
// }).succeed(previous_task);
|
||||
}
|
||||
// tf::Task new_layer = taskflow.emplace([] {});
|
||||
// new_layer.succeed(previous_task);
|
||||
// previous_task = new_layer;
|
||||
}
|
||||
tf::Task new_layer = taskflow.emplace([] {});
|
||||
new_layer.succeed(previous_task);
|
||||
previous_task = new_layer;
|
||||
// executor.run(taskflow).wait();
|
||||
}
|
||||
{
|
||||
query_timer timer("mixer post process");
|
||||
post_process(in_frames);
|
||||
}
|
||||
executor.run(taskflow).wait();
|
||||
post_process(in_frames);
|
||||
dummy_track* master = get_master();
|
||||
master->buffer.multiple(master->volume);
|
||||
}
|
||||
|
||||
void mixer::reset() {
|
||||
query_timer timer("mixer reset");
|
||||
for (const auto track: tracks_) {
|
||||
track->buffer.clear();
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "taskflow/taskflow.hpp"
|
||||
|
||||
class plugin_host;
|
||||
class channel_interface;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "audio/mixer/channel_interface.h"
|
||||
#include "audio/mixer/mixer.h"
|
||||
#include "audio/mixer/mixer_track.h"
|
||||
#include "misc/query_timer.h"
|
||||
#include "misc/singleton/singleton_manager.h"
|
||||
#include "thread_message/thread_message_hubs.h"
|
||||
#include "vst2/vst2_plugin_host.h"
|
||||
@ -81,14 +82,15 @@ void plugin_host_manager::register_instrument_plugin(plugin_host* host) {
|
||||
}
|
||||
|
||||
void plugin_host_manager::process(uint32_t in_frames) const {
|
||||
tf::Executor executor;
|
||||
tf::Taskflow taskflow;
|
||||
query_timer timer("host process");
|
||||
// tf::Executor executor;
|
||||
// tf::Taskflow taskflow;
|
||||
for (auto host : plugin_hosts_) {
|
||||
taskflow.emplace([host, in_frames] {
|
||||
// taskflow.emplace([host, in_frames] {
|
||||
host->process(in_frames);
|
||||
});
|
||||
// });
|
||||
}
|
||||
executor.run(taskflow).wait();
|
||||
// executor.run(taskflow).wait();
|
||||
}
|
||||
|
||||
void plugin_host_manager::on_mixer_track_removed(mixer_track* track) {
|
||||
|
23
core/misc/query_timer.h
Normal file
23
core/misc/query_timer.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include <chrono>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
class query_timer {
|
||||
public:
|
||||
query_timer(std::string name) : name_(std::move(name)) {
|
||||
start();
|
||||
}
|
||||
~query_timer() {
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
const auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start_);
|
||||
spdlog::info("{}: {} ms", name_, duration.count() / 1000.f);
|
||||
}
|
||||
|
||||
private:
|
||||
void start() {
|
||||
start_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
std::chrono::high_resolution_clock::time_point start_;
|
||||
std::string name_;
|
||||
};
|
@ -72,7 +72,7 @@ void window_manager::destroy_plugin_window(plugin_host* host) {
|
||||
}
|
||||
|
||||
void window_manager::update() {
|
||||
glfwPollEvents();
|
||||
// glfwPollEvents();
|
||||
for (auto& info : host_infos_) {
|
||||
if (!info.second.window) {
|
||||
continue;
|
||||
|
Loading…
x
Reference in New Issue
Block a user