改为使用rtaudio
This commit is contained in:
parent
c6a8e16393
commit
7f87fc6ba4
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,9 +1,6 @@
|
||||
[submodule "third_party/imgui/imgui"]
|
||||
path = third_party/imgui/imgui
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
[submodule "third_party/portaudio"]
|
||||
path = third_party/portaudio
|
||||
url = https://github.com/PortAudio/portaudio.git
|
||||
[submodule "third_party/spdlog"]
|
||||
path = third_party/spdlog
|
||||
url = https://github.com/gabime/spdlog.git
|
||||
@ -13,3 +10,6 @@
|
||||
[submodule "third_party/taskflow"]
|
||||
path = third_party/taskflow
|
||||
url = https://github.com/taskflow/taskflow.git
|
||||
[submodule "third_party/rtaudio"]
|
||||
path = third_party/rtaudio
|
||||
url = https://github.com/thestk/rtaudio.git
|
||||
|
@ -56,19 +56,14 @@ function(retrieve_files out_files)
|
||||
set(${out_files} ${RESULT} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
set(SHADER_CPP_GENERATED_CMAKE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateShaderCPPFile.cmake" CACHE STRING "" FORCE)
|
||||
|
||||
# setup portaudio
|
||||
set(PA_USE_ASIO ON CACHE BOOL "" FORCE)
|
||||
set(PA_BUILD_SHARED_LIBS ON CACHE BOOL "" FORCE)
|
||||
set(RTAUDIO_API_ASIO ON CACHE BOOL "" FORCE)
|
||||
|
||||
if (WIN32)
|
||||
set(PA_USE_WMME OFF CACHE BOOL "" FORCE)
|
||||
set(PA_USE_WDMKS OFF CACHE BOOL "" FORCE)
|
||||
set(PA_USE_WDMKS_DEVICE_INFO OFF CACHE BOOL "" FORCE)
|
||||
set(PA_USE_DS OFF CACHE BOOL "" FORCE)
|
||||
set(RTAUDIO_API_WASAPI ON CACHE BOOL "" FORCE)
|
||||
set(RTAUDIO_API_DS OFF CACHE BOOL "" FORCE)
|
||||
elseif(APPLE)
|
||||
set(PA_USE_COREAUDIO ON CACHE BOOL "" FORCE)
|
||||
set(RTAUDIO_API_CORE ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
||||
# setup spdlog
|
||||
@ -83,7 +78,7 @@ set(SPDLOG_ENABLE_PCH ON CACHE BOOL "" FORCE)
|
||||
set(SPDLOG_USE_STD_FORMAT OFF CACHE BOOL "" FORCE)
|
||||
|
||||
if (MSVC)
|
||||
link_directories(${CMAKE_BINARY_DIR}/bin/$<CONFIG>)
|
||||
link_directories(${CMAKE_BINARY_DIR}/bin/$<CONFIG>)
|
||||
endif ()
|
||||
|
||||
# setup taskflow
|
||||
@ -91,12 +86,7 @@ set(TF_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||
set(TF_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(third_party/portaudio)
|
||||
add_subdirectory(third_party/rtaudio)
|
||||
add_subdirectory(third_party/spdlog)
|
||||
add_subdirectory(third_party/mempool)
|
||||
add_subdirectory(third_party/taskflow)
|
||||
|
||||
add_definitions(-DGLFW_INCLUDE_NONE)
|
||||
|
||||
# install
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/third_party/imgui/imgui/misc/fonts DESTINATION ${CMAKE_BINARY_DIR}/bin)
|
||||
|
@ -1,25 +0,0 @@
|
||||
function(embed_resource resource_file_name source_file_name variable_name)
|
||||
if(EXISTS "${source_file_name}")
|
||||
if("${source_file_name}" IS_NEWER_THAN "${resource_file_name}")
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
if(EXISTS "${resource_file_name}")
|
||||
file(REMOVE "${source_file_name}")
|
||||
file(READ "${resource_file_name}" hex_content HEX)
|
||||
string(REPEAT "[0-9a-f]" 32 pattern)
|
||||
string(REGEX REPLACE "(${pattern})" "\\1\n" content "${hex_content}")
|
||||
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " content "${content}")
|
||||
string(REGEX REPLACE ", $" "" content "${content}")
|
||||
set(array_definition "static const uint8_t ${variable_name} []=\n{\n${content}\n};")
|
||||
get_filename_component(file_name ${source_file_name} NAME)
|
||||
set(source "#pragma once\n/**\n * @file ${file_name}\n * @brief Auto generated file.\n */\n${array_definition}\n")
|
||||
file(WRITE "${source_file_name}" "${source}")
|
||||
else()
|
||||
message("ERROR: ${resource_file_name} doesn't exist")
|
||||
return()
|
||||
endif()
|
||||
endfunction()
|
||||
if(EXISTS "${PATH}")
|
||||
embed_resource("${PATH}" "${HEADER}" "${GLOBAL}")
|
||||
endif()
|
@ -8,10 +8,10 @@ retrieve_files(ALL_FILES)
|
||||
add_library(${PROJECT_NAME} SHARED ${ALL_FILES})
|
||||
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PortAudio spdlog mempool Taskflow)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} rtaudio spdlog mempool Taskflow)
|
||||
|
||||
target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PortAudio spdlog mempool Taskflow)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC PortAudio spdlog mempool Taskflow)
|
||||
target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} rtaudio spdlog mempool Taskflow)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC rtaudio spdlog mempool Taskflow)
|
||||
|
||||
target_precompile_headers(${PROJECT_NAME} PUBLIC extern.h)
|
||||
add_definitions(-Dcore_EXPORTS)
|
||||
|
@ -1 +0,0 @@
|
||||
#include "audio_device.h"
|
@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
class audio_device {
|
||||
public:
|
||||
virtual ~audio_device() = default;
|
||||
|
||||
virtual bool init() = 0;
|
||||
virtual void destroy() = 0;
|
||||
|
||||
void set_sample_rate(double sample_rate) {
|
||||
if (on_set_sample_rate(sample_rate)) {
|
||||
sample_rate_ = sample_rate;
|
||||
}
|
||||
}
|
||||
void set_buffer_size(uint32_t buffer_size) {
|
||||
if (on_set_buffer_size(buffer_size)) {
|
||||
buffer_size_ = buffer_size;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] double sample_rate() const { return sample_rate_; }
|
||||
[[nodiscard]] uint32_t buffer_size() const { return buffer_size_; }
|
||||
protected:
|
||||
virtual bool on_set_sample_rate(double in_sample_rate) = 0;
|
||||
virtual bool on_set_buffer_size(uint32_t in_buffer_size) = 0;
|
||||
private:
|
||||
double sample_rate_ = 44100;
|
||||
uint32_t buffer_size_ = 2048;
|
||||
};
|
@ -1,46 +1,53 @@
|
||||
#include "audio_device_manager.h"
|
||||
|
||||
#include "dummy_audio_device.h"
|
||||
#include "port_audio_device.h"
|
||||
#include "audio/mixer/mixer.h"
|
||||
#include "audio/mixer/mixer_track.h"
|
||||
#include "audio/plugin_host/midi_sequencer.h"
|
||||
#include "audio/plugin_host/plugin_host_manager.h"
|
||||
#include "thread_message/thread_message_hubs.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void audio_device_manager::init(singleton_initliazer& initliazer) {
|
||||
singleton_t<audio_device_manager>::init(initliazer);
|
||||
|
||||
dummy_audio_device_ = new dummy_audio_device();
|
||||
main_audio_device_ = new port_audio_device();
|
||||
|
||||
main_audio_device_->init();
|
||||
dummy_audio_device_->init();
|
||||
options_.flags = RTAUDIO_NONINTERLEAVED;
|
||||
}
|
||||
|
||||
void audio_device_manager::release(singleton_release_guard& release_guard) {
|
||||
singleton_t<audio_device_manager>::release(release_guard);
|
||||
release_guard.require_release<mixer>();
|
||||
delete dummy_audio_device_;
|
||||
delete main_audio_device_;
|
||||
}
|
||||
|
||||
void audio_device_manager::start() {
|
||||
main_audio_device_->start();
|
||||
RtAudio::StreamParameters* input_params = nullptr;
|
||||
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_);
|
||||
}
|
||||
|
||||
double audio_device_manager::get_sample_rate() const {
|
||||
return main_audio_device_->sample_rate();
|
||||
uint32_t audio_device_manager::get_sample_rate() const {
|
||||
return sample_rate_;
|
||||
}
|
||||
|
||||
void audio_device_manager::set_sample_rate(double sample_rate) {
|
||||
main_audio_device_->set_sample_rate(sample_rate);
|
||||
dummy_audio_device_->set_sample_rate(sample_rate);
|
||||
void audio_device_manager::set_sample_rate(uint32_t sample_rate) {
|
||||
sample_rate_ = sample_rate;
|
||||
}
|
||||
|
||||
uint32_t audio_device_manager::get_buffer_size() const {
|
||||
return main_audio_device_->buffer_size();
|
||||
return options_.numberOfBuffers;
|
||||
}
|
||||
|
||||
void audio_device_manager::set_buffer_size(int buffer_size) {
|
||||
main_audio_device_->set_buffer_size(buffer_size);
|
||||
dummy_audio_device_->set_buffer_size(buffer_size);
|
||||
options_.numberOfBuffers = buffer_size;
|
||||
}
|
||||
|
||||
uint32_t audio_device_manager::get_input_channel_count() const {
|
||||
@ -50,3 +57,52 @@ uint32_t audio_device_manager::get_input_channel_count() const {
|
||||
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)
|
||||
return 0;
|
||||
for (int i = 0; i < output_params_.nChannels; ++i) {
|
||||
render_buffer_.Pop(input[i], frame_count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio_device_manager::start_render_thread() {
|
||||
render_thread_ = std::thread(&audio_device_manager::render_thread, this);
|
||||
render_thread_.detach();
|
||||
}
|
||||
|
||||
void audio_device_manager::stop_render_thread() {
|
||||
if (render_thread_.joinable())
|
||||
render_thread_.join();
|
||||
}
|
||||
|
||||
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);
|
||||
const uint32_t frames = get_buffer_size();
|
||||
const uint32_t rate = get_sample_rate();
|
||||
|
||||
while (audio_.isStreamRunning()) {
|
||||
const uint32_t milliseconds = 1.f / (rate / (frames / 4)) * 1000;
|
||||
|
||||
g_audio_thread_hub.process_messages();
|
||||
if (render_buffer_.Num() >= render_buffer_size_) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
||||
continue;
|
||||
}
|
||||
g_midi_sequencer.process(rate, frames);
|
||||
g_mixer.reset();
|
||||
g_plugin_host_manager.process(frames);
|
||||
g_mixer.process(frames);
|
||||
|
||||
const auto& master_headers = master->buffer.get_headers_vector();
|
||||
for (const auto element: master_headers) {
|
||||
render_buffer_.Push(element, frames);
|
||||
}
|
||||
}
|
||||
spdlog::info("port_audio render thread stopped");
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
#include "misc/singleton/singleton.h"
|
||||
|
||||
class dummy_audio_device;
|
||||
class port_audio_device;
|
||||
#include "audio/misc/circular_audio_buffer.h"
|
||||
#include "RtAudio.h"
|
||||
|
||||
class audio_device_manager : public singleton_t<audio_device_manager> {
|
||||
public:
|
||||
@ -13,15 +13,30 @@ public:
|
||||
|
||||
CORE_API [[nodiscard]] const char* get_name() override { return "audio_device_manager"; }
|
||||
|
||||
CORE_API [[nodiscard]] double get_sample_rate() const;
|
||||
CORE_API void set_sample_rate(double sample_rate);
|
||||
CORE_API [[nodiscard]] uint32_t get_sample_rate() const;
|
||||
CORE_API void set_sample_rate(uint32_t sample_rate);
|
||||
CORE_API [[nodiscard]] uint32_t get_buffer_size() const;
|
||||
CORE_API void set_buffer_size(int buffer_size);
|
||||
CORE_API [[nodiscard]] uint32_t get_input_channel_count() const;
|
||||
CORE_API [[nodiscard]] uint32_t get_output_channel_count() const;
|
||||
|
||||
int stream_callback(float** output, float** input, unsigned long frame_count, double stream_time, RtAudioStreamStatus status);
|
||||
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::atomic_bool render_thread_running_ = false;
|
||||
#pragma endregion
|
||||
private:
|
||||
port_audio_device* main_audio_device_ = nullptr;
|
||||
dummy_audio_device* dummy_audio_device_ = nullptr;
|
||||
RtAudio::StreamParameters input_params_ = {};
|
||||
RtAudio::StreamParameters output_params_ = {};
|
||||
RtAudio::StreamOptions options_ = {};
|
||||
uint32_t sample_rate_ = 44100;
|
||||
RtAudio audio_;
|
||||
};
|
||||
|
||||
DEFINE_SINGLETON_INSTANCE(audio_device_manager)
|
||||
|
@ -1 +0,0 @@
|
||||
#include "dummy_audio_device.h"
|
@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include "audio_device.h"
|
||||
|
||||
class dummy_audio_device : public audio_device {
|
||||
public:
|
||||
bool init() override { return true; }
|
||||
void destroy() override {}
|
||||
|
||||
protected:
|
||||
bool on_set_buffer_size(uint32_t in_buffer_size) override { return true; }
|
||||
bool on_set_sample_rate(double in_sample_rate) override { return true; }
|
||||
};
|
@ -1,144 +0,0 @@
|
||||
#include "port_audio_device.h"
|
||||
|
||||
#include "audio/mixer/mixer.h"
|
||||
#include "audio/mixer/mixer_track.h"
|
||||
#include "audio/plugin_host/midi_sequencer.h"
|
||||
#include "audio/plugin_host/plugin_host_manager.h"
|
||||
#include "thread_message/thread_message_hubs.h"
|
||||
|
||||
int port_audio_callback(const void* Input, void* Output, unsigned long FrameCount, const PaStreamCallbackTimeInfo* TimeInfo, PaStreamCallbackFlags StatusFlags, void* UserData)
|
||||
{
|
||||
auto* API = static_cast<port_audio_device*>(UserData);
|
||||
return API->stream_callback((float**)Input, static_cast<float**>(Output), FrameCount, TimeInfo, StatusFlags);
|
||||
}
|
||||
|
||||
port_audio_device::~port_audio_device() {
|
||||
port_audio_device::destroy();
|
||||
stop();
|
||||
}
|
||||
|
||||
bool port_audio_device::init() {
|
||||
Pa_Initialize();
|
||||
return true;
|
||||
}
|
||||
|
||||
void port_audio_device::destroy() {
|
||||
stop();
|
||||
Pa_Terminate();
|
||||
}
|
||||
|
||||
void port_audio_device::stop() {
|
||||
Pa_StopStream(stream_);
|
||||
Pa_CloseStream(stream_);
|
||||
stream_ = nullptr;
|
||||
stop_render_thread();
|
||||
spdlog::info("port_audio stopped");
|
||||
}
|
||||
|
||||
void port_audio_device::start() {
|
||||
try {
|
||||
auto host_api_info = Pa_GetHostApiInfo(Pa_HostApiTypeIdToHostApiIndex(paASIO));
|
||||
auto device_info = Pa_GetDeviceInfo(host_api_info->defaultOutputDevice);
|
||||
open_stream(-1, host_api_info->defaultOutputDevice, sample_rate(), buffer_size());
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::error("Init failed: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void port_audio_device::open_stream(PaDeviceIndex input_device, PaDeviceIndex output_device, double in_sample_rate, uint32_t in_buffer_size) {
|
||||
const PaStreamParameters* input_params = nullptr;
|
||||
if (input_device >= 0) {
|
||||
input_params_.device = input_device;
|
||||
input_params_.channelCount = 2;
|
||||
input_params_.sampleFormat = paFloat32 | paNonInterleaved;
|
||||
input_params_.suggestedLatency = Pa_GetDeviceInfo(input_device)->defaultLowInputLatency;
|
||||
input_params_.hostApiSpecificStreamInfo = nullptr;
|
||||
input_params = &input_params_;
|
||||
}
|
||||
|
||||
output_params_.device = output_device;
|
||||
output_params_.channelCount = 2;
|
||||
output_params_.sampleFormat = paFloat32 | paNonInterleaved;
|
||||
output_params_.suggestedLatency = Pa_GetDeviceInfo(output_device)->defaultLowOutputLatency;
|
||||
output_params_.hostApiSpecificStreamInfo = nullptr;
|
||||
PaError err = Pa_OpenStream(&stream_, input_params, &output_params_, in_sample_rate, in_buffer_size, paClipOff, port_audio_callback, this);
|
||||
if (err != paNoError) {
|
||||
throw std::runtime_error(Pa_GetErrorText(err));
|
||||
}
|
||||
err = Pa_StartStream(stream_);
|
||||
if (err != paNoError) {
|
||||
throw std::runtime_error(Pa_GetErrorText(err));
|
||||
}
|
||||
start_render_thread();
|
||||
}
|
||||
|
||||
int port_audio_device::stream_callback(float** input, float** output, unsigned long frame_count,
|
||||
const PaStreamCallbackTimeInfo* time_info, PaStreamCallbackFlags status_flags) {
|
||||
if (render_buffer_.Num() < frame_count * output_params_.channelCount)
|
||||
return paContinue;
|
||||
for (int i = 0; i < output_params_.channelCount; ++i) {
|
||||
render_buffer_.Pop(output[i], frame_count);
|
||||
}
|
||||
return paContinue;
|
||||
}
|
||||
|
||||
bool port_audio_device::on_set_buffer_size(uint32_t in_buffer_size) {
|
||||
stop();
|
||||
render_buffer_size_ = in_buffer_size * 4;
|
||||
try {
|
||||
open_stream(input_params_.device, output_params_.device, sample_rate(), in_buffer_size);
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::error("Set buffer size failed: {}", e.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool port_audio_device::on_set_sample_rate(double in_sample_rate) {
|
||||
stop();
|
||||
try {
|
||||
open_stream(input_params_.device, output_params_.device, in_sample_rate, buffer_size());
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::error("Set sample rate failed: {}", e.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void port_audio_device::start_render_thread() {
|
||||
render_thread_ = std::thread(&port_audio_device::render_thread, this);
|
||||
render_thread_.detach();
|
||||
}
|
||||
|
||||
void port_audio_device::stop_render_thread() {
|
||||
if (render_thread_.joinable())
|
||||
render_thread_.join();
|
||||
}
|
||||
|
||||
void port_audio_device::render_thread() {
|
||||
dummy_track* master = g_mixer.get_master();
|
||||
spdlog::info("port_audio render thread started");
|
||||
render_buffer_.SetCapacity(buffer_size() * 4);
|
||||
while (stream_) {
|
||||
const uint32_t frames = buffer_size();
|
||||
const double rate = sample_rate();
|
||||
|
||||
const uint32_t milliseconds = 1.f / (rate / (frames / 4)) * 1000;
|
||||
|
||||
g_audio_thread_hub.process_messages();
|
||||
if (render_buffer_.Num() >= render_buffer_size_) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
||||
continue;
|
||||
}
|
||||
g_midi_sequencer.process(rate, frames);
|
||||
g_mixer.reset();
|
||||
g_plugin_host_manager.process(frames);
|
||||
g_mixer.process(frames);
|
||||
|
||||
const auto& master_headers = master->buffer.get_headers_vector();
|
||||
for (const auto element: master_headers) {
|
||||
render_buffer_.Push(element, frames);
|
||||
}
|
||||
}
|
||||
spdlog::info("port_audio render thread stopped");
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
#include "audio_device.h"
|
||||
|
||||
#include "portaudio.h"
|
||||
#include "audio/misc/circular_audio_buffer.h"
|
||||
|
||||
class port_audio_device : public audio_device {
|
||||
public:
|
||||
~port_audio_device() override;
|
||||
bool init() override;
|
||||
void destroy() override;
|
||||
|
||||
void stop();
|
||||
|
||||
void start();
|
||||
void open_stream(PaDeviceIndex input_device, PaDeviceIndex output_device, double in_sample_rate, uint32_t in_buffer_size);
|
||||
|
||||
int stream_callback(float** input, float** output, unsigned long frame_count, const PaStreamCallbackTimeInfo* time_info, PaStreamCallbackFlags status_flags);
|
||||
protected:
|
||||
bool on_set_buffer_size(uint32_t in_buffer_size) override;
|
||||
bool on_set_sample_rate(double in_sample_rate) override;
|
||||
private:
|
||||
|
||||
#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::atomic_bool render_thread_running_ = false;
|
||||
#pragma endregion
|
||||
|
||||
PaStreamParameters input_params_ = {};
|
||||
PaStreamParameters output_params_ = {};
|
||||
PaStream* stream_ = nullptr;
|
||||
};
|
@ -9,10 +9,10 @@
|
||||
#include "thread_message/thread_message_hubs.h"
|
||||
#include "taskflow/taskflow.hpp"
|
||||
|
||||
void build_effect_channel_interface(mixer_track* track, const channel_interface* interface, std::map<mixer_track*, int32_t>& processed_tracks) {
|
||||
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];
|
||||
auto& input_channel_nodes = interface->input_channel_nodes;
|
||||
auto& output_channel_nodes = interface->output_channel_nodes;
|
||||
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)
|
||||
{
|
||||
|
@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
#ifdef core_EXPORTS
|
||||
#define CORE_API __declspec(dllexport)
|
||||
#else
|
||||
#define CORE_API __declspec(dllimport)
|
||||
#endif
|
||||
#define CORE_API
|
||||
// #ifdef core_EXPORTS
|
||||
// #define CORE_API __declspec(dllexport)
|
||||
// #else
|
||||
// #define CORE_API __declspec(dllimport)
|
||||
// #endif
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
#define checkf(expr, msg, ...) if (!(expr)) { spdlog::error(msg, __VA_ARGS__); throw std::runtime_error(fmt::format(msg, __VA_ARGS__)); }
|
||||
|
1
third_party/portaudio
vendored
1
third_party/portaudio
vendored
@ -1 +0,0 @@
|
||||
Subproject commit daaf637f6f9fce670031221abfd7dfde92e5cce3
|
1
third_party/rtaudio
vendored
Submodule
1
third_party/rtaudio
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit cb03db3c7e474c843444631e842468d5b258d095
|
2
third_party/taskflow
vendored
2
third_party/taskflow
vendored
@ -1 +1 @@
|
||||
Subproject commit a8434d095ff60c53583646e80b6c57c688ee2a4f
|
||||
Subproject commit 10dfa7920d1a786099a92614c4183f6339975728
|
Loading…
x
Reference in New Issue
Block a user