From b493dc1e0fdfaea8fd77def7b4d1b90c84ff1cf0 Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Tue, 21 May 2024 01:36:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Equery=5Ftimer=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E6=9F=A5=E7=9C=8B=E5=87=BD=E6=95=B0=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E9=97=B4=20=E4=BF=AE=E5=A4=8Dcircular=5Faudio=5Fbuffe?= =?UTF-8?q?r=E7=BC=96=E8=AF=91=E9=94=99=E8=AF=AF=20=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E5=B0=86taskflow=E7=A7=BB=E9=99=A4=EF=BC=8C=E5=9B=A0=E4=B8=BA?= =?UTF-8?q?=E5=9C=A8=E6=89=A7=E8=A1=8C=E4=BB=BB=E5=8A=A1=E6=97=B6=E7=AD=89?= =?UTF-8?q?=E5=BE=85=E6=97=B6=E9=97=B4=E5=BE=88=E9=95=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/application/application.cpp | 4 ++ core/audio/device/audio_device_manager.cpp | 71 ++++++++++++++----- core/audio/device/audio_device_manager.h | 9 +-- core/audio/misc/circular_audio_buffer.h | 4 +- core/audio/mixer/mixer.cpp | 37 +++++----- core/audio/mixer/mixer.h | 1 + .../audio/plugin_host/plugin_host_manager.cpp | 12 ++-- core/misc/query_timer.h | 23 ++++++ core/window/window_manager.cpp | 2 +- 9 files changed, 117 insertions(+), 46 deletions(-) create mode 100644 core/misc/query_timer.h diff --git a/core/application/application.cpp b/core/application/application.cpp index 82c022e..55a8edc 100644 --- a/core/application/application.cpp +++ b/core/application/application.cpp @@ -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() { diff --git a/core/audio/device/audio_device_manager.cpp b/core/audio/device/audio_device_manager.cpp index 893dc52..debc14a 100644 --- a/core/audio/device/audio_device_manager.cpp +++ b/core/audio/device/audio_device_manager.cpp @@ -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(user_data); - return API->stream_callback((float**)output_buffer, static_cast(input_buffer), frames_nums, stream_time, status); + return API->stream_callback(static_cast(output_buffer), static_cast(input_buffer), frames_nums, stream_time, status); } void audio_device_manager::init(singleton_initliazer& initliazer) { singleton_t::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::release(release_guard); release_guard.require_release(); + 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(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"); diff --git a/core/audio/device/audio_device_manager.h b/core/audio/device/audio_device_manager.h index 41c5690..143a046 100644 --- a/core/audio/device/audio_device_manager.h +++ b/core/audio/device/audio_device_manager.h @@ -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 render_buffer_; - uint32_t render_buffer_size_ = 512; + std::vector> 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; }; diff --git a/core/audio/misc/circular_audio_buffer.h b/core/audio/misc/circular_audio_buffer.h index 212ea78..6b360aa 100644 --- a/core/audio/misc/circular_audio_buffer.h +++ b/core/audio/misc/circular_audio_buffer.h @@ -122,8 +122,8 @@ public: int32_t NumToZeroEnd = std::min(NumSamplesOfZeros, Remainder()); const int32_t NumToZeroBegin = std::min(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; diff --git a/core/audio/mixer/mixer.cpp b/core/audio/mixer/mixer.cpp index e84fef1..55c2f94 100644 --- a/core/audio/mixer/mixer.cpp +++ b/core/audio/mixer/mixer.cpp @@ -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& 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(); } diff --git a/core/audio/mixer/mixer.h b/core/audio/mixer/mixer.h index 8d4de91..9adc637 100644 --- a/core/audio/mixer/mixer.h +++ b/core/audio/mixer/mixer.h @@ -4,6 +4,7 @@ #include #include +#include "taskflow/taskflow.hpp" class plugin_host; class channel_interface; diff --git a/core/audio/plugin_host/plugin_host_manager.cpp b/core/audio/plugin_host/plugin_host_manager.cpp index 55ed9b2..9cfbbfc 100644 --- a/core/audio/plugin_host/plugin_host_manager.cpp +++ b/core/audio/plugin_host/plugin_host_manager.cpp @@ -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) { diff --git a/core/misc/query_timer.h b/core/misc/query_timer.h new file mode 100644 index 0000000..7d4767d --- /dev/null +++ b/core/misc/query_timer.h @@ -0,0 +1,23 @@ +#pragma once +#include + +#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(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_; +}; diff --git a/core/window/window_manager.cpp b/core/window/window_manager.cpp index 475ec6f..6d0d5ad 100644 --- a/core/window/window_manager.cpp +++ b/core/window/window_manager.cpp @@ -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;