From f10d489df94ed075c94511fde2b020af9b247c1a Mon Sep 17 00:00:00 2001 From: Daniel Jones Date: Tue, 22 Oct 2024 13:42:42 +0100 Subject: [PATCH] miniaudio: Support for selecting input device --- .../signalflow/node/io/output/miniaudio.h | 4 +- source/src/node/io/input/miniaudio.cpp | 43 ++++++++++++++++++- source/src/node/io/output/miniaudio.cpp | 14 +++--- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/source/include/signalflow/node/io/output/miniaudio.h b/source/include/signalflow/node/io/output/miniaudio.h index 36bfa4ca..c2e03096 100644 --- a/source/include/signalflow/node/io/output/miniaudio.h +++ b/source/include/signalflow/node/io/output/miniaudio.h @@ -29,13 +29,15 @@ class AudioOut : public AudioOut_Abstract static std::list get_input_device_names(std::string backend_name = ""); static std::list get_backend_names(); -private: /*-------------------------------------------------------------------------------- * Initialise a new miniaudio context, using the specified backend name if * present, or the default backend otherwise. + * + * Public because AudioIn also uses this method. *-------------------------------------------------------------------------------*/ static void init_context(ma_context *context, std::string backend_name = ""); +private: std::string backend_name; std::string device_name; ma_context context; diff --git a/source/src/node/io/input/miniaudio.cpp b/source/src/node/io/input/miniaudio.cpp index 29dc5fab..75b62e39 100644 --- a/source/src/node/io/input/miniaudio.cpp +++ b/source/src/node/io/input/miniaudio.cpp @@ -57,6 +57,7 @@ AudioIn::~AudioIn() void AudioIn::init() { + ma_result rv; ma_device_config config = ma_device_config_init(ma_device_type_capture); config.capture.format = ma_format_f32; config.capture.channels = this->num_channels; @@ -64,7 +65,47 @@ void AudioIn::init() config.sampleRate = this->get_graph()->get_sample_rate(); config.dataCallback = read_callback; - ma_result rv = ma_device_init(NULL, &config, &device); + ma_device_info *capture_devices; + ma_uint32 capture_device_count; + + // TODO: Add get_input_backend_name + AudioOut::init_context(&this->context, this->get_graph()->get_config().get_output_backend_name()); + + rv = ma_context_get_devices(&this->context, + NULL, + NULL, + &capture_devices, + &capture_device_count); + int selected_device_index = -1; + std::string device_name = this->get_graph()->get_config().get_input_device_name(); + + if (!device_name.empty()) + { + for (unsigned int i = 0; i < capture_device_count; i++) + { + /*-----------------------------------------------------------------------* + * For ease of use, SignalFlow allows for partial matches so that only + * the first part of the device names needs to be specified. However, + * an errors is thrown if the match is ambiguous. + *-----------------------------------------------------------------------*/ + if (strncmp(capture_devices[i].name, device_name.c_str(), strlen(device_name.c_str())) == 0) + { + if (selected_device_index != -1) + { + throw audio_io_exception("More than one audio device found matching name '" + device_name + "'"); + } + selected_device_index = i; + } + } + if (selected_device_index == -1) + { + throw audio_io_exception("No audio device found matching name '" + device_name + "'"); + } + + config.capture.pDeviceID = &capture_devices[selected_device_index].id; + } + + rv = ma_device_init(NULL, &config, &device); if (rv != MA_SUCCESS) { throw audio_io_exception("miniaudio: Error initialising input device"); diff --git a/source/src/node/io/output/miniaudio.cpp b/source/src/node/io/output/miniaudio.cpp index d69b291b..9b0c257b 100644 --- a/source/src/node/io/output/miniaudio.cpp +++ b/source/src/node/io/output/miniaudio.cpp @@ -98,8 +98,6 @@ void AudioOut::init() ma_device_info *playback_devices; ma_uint32 playback_device_count; - ma_device_info *capture_devices; - ma_uint32 capture_device_count; ma_result rv; AudioOut::init_context(&this->context, this->backend_name); @@ -107,13 +105,18 @@ void AudioOut::init() rv = ma_context_get_devices(&this->context, &playback_devices, &playback_device_count, - &capture_devices, - &capture_device_count); + NULL, + NULL); int selected_device_index = -1; if (!this->device_name.empty()) { for (unsigned int i = 0; i < playback_device_count; i++) { + /*-----------------------------------------------------------------------* + * For ease of use, SignalFlow allows for partial matches so that only + * the first part of the device names needs to be specified. However, + * an errors is thrown if the match is ambiguous. + *-----------------------------------------------------------------------*/ if (strncmp(playback_devices[i].name, device_name.c_str(), strlen(device_name.c_str())) == 0) { if (selected_device_index != -1) @@ -145,9 +148,6 @@ void AudioOut::init() config.sampleRate = this->sample_rate; config.dataCallback = data_callback; - // Buffer blocks into a fixed number of frames - config.noFixedSizedCallback = 1; - // On Core Audio, let the application select a preferred sample rate. config.coreaudio.allowNominalSampleRateChange = 1;