108 const std::vector<unsigned int> device_ids =
stream.getDeviceIds();
109 if (device_ids.empty()) {
110 std::cerr <<
"acmxvk: no audio devices found\n";
114 unsigned int input_device = 0;
116 input_device =
static_cast<unsigned int>(config.
input_device);
118 input_device =
stream.getDefaultInputDevice();
121 const auto selected = std::find(device_ids.begin(), device_ids.end(),
123 if (selected == device_ids.end()) {
124 std::cerr <<
"acmxvk: audio input device " << input_device
125 <<
" was not found\n";
129 const RtAudio::DeviceInfo input_info =
130 stream.getDeviceInfo(input_device);
133 "audio input device name");
134 if (input_info.inputChannels == 0) {
135 std::cerr <<
"acmxvk: audio device " << input_device
136 <<
" has no input channels\n";
141 input_info.inputChannels);
148 std::memory_order_relaxed);
151 unsigned int selected_rate = 44100;
152 if (!input_info.sampleRates.empty() &&
153 std::find(input_info.sampleRates.begin(), input_info.sampleRates.end(),
154 selected_rate) == input_info.sampleRates.end()) {
155 selected_rate = 48000;
156 if (std::find(input_info.sampleRates.begin(),
157 input_info.sampleRates.end(), selected_rate) ==
158 input_info.sampleRates.end()) {
159 selected_rate = input_info.sampleRates.front();
163 RtAudio::StreamParameters input_parameters;
164 input_parameters.deviceId = input_device;
166 input_parameters.firstChannel = 0;
168 RtAudio::StreamParameters output_parameters;
169 RtAudio::StreamParameters *output_parameters_ptr =
nullptr;
170 unsigned int output_device = 0;
171 std::string output_name;
172 std::vector<unsigned int> output_sample_rates;
177 :
stream.getDefaultOutputDevice();
178 const auto output_selected =
179 std::find(device_ids.begin(), device_ids.end(), output_device);
180 if (output_selected == device_ids.end()) {
181 std::cerr <<
"acmxvk: audio output device " << output_device
182 <<
" was not found; live pass-through disabled\n";
185 const RtAudio::DeviceInfo output_info =
186 stream.getDeviceInfo(output_device);
189 "audio output device name");
190 if (output_info.outputChannels == 0) {
191 std::cerr <<
"acmxvk: audio device " << output_device
192 <<
" has no output channels; live "
193 "pass-through disabled\n";
197 std::min(2U, output_info.outputChannels);
198 output_name = output_info.name;
199 output_sample_rates = output_info.sampleRates;
200 output_parameters.deviceId = output_device;
202 output_parameters.firstChannel = 0;
203 output_parameters_ptr = &output_parameters;
208 const auto supports_rate = [](
const std::vector<unsigned int> &rates,
210 return rates.empty() ||
211 std::find(rates.begin(), rates.end(), rate) != rates.end();
214 !supports_rate(output_sample_rates, selected_rate)) {
215 std::vector<unsigned int> candidates{44100, 48000};
216 candidates.insert(candidates.end(), input_info.sampleRates.begin(),
217 input_info.sampleRates.end());
218 candidates.insert(candidates.end(), output_sample_rates.begin(),
219 output_sample_rates.end());
220 const auto common_rate = std::find_if(
221 candidates.begin(), candidates.end(), [&](
unsigned int rate) {
222 return supports_rate(input_info.sampleRates, rate) &&
223 supports_rate(output_sample_rates, rate);
225 if (common_rate == candidates.end()) {
226 std::cerr <<
"acmxvk: input and output devices have no "
227 "common sample rate; live pass-through disabled\n";
230 output_parameters_ptr =
nullptr;
232 selected_rate = *common_rate;
235 sample_rate.store(selected_rate, std::memory_order_relaxed);
237 unsigned int buffer_frames = 512;
238 stream.openStream(output_parameters_ptr, &input_parameters,
239 RTAUDIO_FLOAT32, selected_rate, &buffer_frames,
243 std::cout <<
"acmxvk: audio input " << input_device <<
": "
244 << input_info.name <<
" (" << selected_rate <<
" Hz, "
248 std::cout <<
"acmxvk: live audio pass-through " << output_device
254 return stream.isStreamOpen();
255 }
catch (
const std::exception &error) {
256 std::cerr <<
"acmxvk: audio error: " << error.what() <<
'\n';
281 amplitude.load(std::memory_order_relaxed),
282 frequency.load(std::memory_order_relaxed),
283 peak.load(std::memory_order_relaxed),
284 rms.load(std::memory_order_relaxed),
285 smooth.load(std::memory_order_relaxed),
286 low.load(std::memory_order_relaxed),
287 mid.load(std::memory_order_relaxed),
288 high.load(std::memory_order_relaxed),
292 [[nodiscard]] std::vector<float>
spectrum()
const {
294 std::array<float, AudioEngine::FFT_SIZE * 2> complex{};
299 std::cos(2.0F * PI *
static_cast<float>(index) /
310 for (std::size_t index = 0; index < magnitudes.size(); ++index) {
311 const float real = complex[2 * index];
312 const float imaginary = complex[2 * index + 1];
314 std::sqrt(real * real + imaginary * imaginary) * INVERSE;
320 amplitude.store(0.0F, std::memory_order_relaxed);
321 frequency.store(0.0F, std::memory_order_relaxed);
322 peak.store(0.0F, std::memory_order_relaxed);
323 rms.store(0.0F, std::memory_order_relaxed);
324 smooth.store(0.0F, std::memory_order_relaxed);
325 low.store(0.0F, std::memory_order_relaxed);
326 mid.store(0.0F, std::memory_order_relaxed);
327 high.store(0.0F, std::memory_order_relaxed);
332 for (std::atomic<float> &sample : buffer) {
333 sample.store(0.0F, std::memory_order_relaxed);
373 if (samples ==
nullptr || frame_count == 0 ||
input_channels == 0) {
377 float amplitude_sum = 0.0F;
378 float peak_value = 0.0F;
379 float square_sum = 0.0F;
380 float low_sum = 0.0F;
381 float mid_sum = 0.0F;
382 float high_sum = 0.0F;
383 unsigned int crossings = 0;
384 float previous = samples[0];
385 const int spectrum_back =
387 const float rate =
static_cast<float>(
388 std::max(
sample_rate.load(std::memory_order_relaxed), 1U));
389 const float low_coefficient = 1.0F - std::exp(-2.0F * PI * 300.0F / rate);
390 const float mid_coefficient =
391 1.0F - std::exp(-2.0F * PI * 3000.0F / rate);
393 std::unique_lock<std::mutex> recording_lock;
394 bool capture_recording =
recording.load(std::memory_order_acquire);
395 if (capture_recording) {
398 recording.load(std::memory_order_acquire);
401 for (
unsigned int frame = 0; frame < frame_count; ++frame) {
403 for (
unsigned int channel = 0; channel <
input_channels; ++channel) {
405 amplitude_sum += std::abs(sample);
409 if (capture_recording) {
418 low_sum += low_sample * low_sample;
419 mid_sum += mid_sample * mid_sample;
420 high_sum += high_sample * high_sample;
423 mono, std::memory_order_relaxed);
425 peak_value = std::max(peak_value, std::abs(mono));
426 square_sum += mono * mono;
427 if (frame > 0 && ((previous >= 0.0F && mono < 0.0F) ||
428 (previous < 0.0F && mono >= 0.0F))) {
433 if (capture_recording) {
435 std::memory_order_release);
437 for (std::size_t frame =
441 0.0F, std::memory_order_relaxed);
445 const float amplitude_value =
448 constexpr float SMOOTH_ALPHA = 0.15F;
451 amplitude.store(amplitude_value, std::memory_order_relaxed);
452 peak.store(peak_value, std::memory_order_relaxed);
453 rms.store(std::sqrt(square_sum /
static_cast<float>(frame_count)),
454 std::memory_order_relaxed);
456 low.store(std::sqrt(low_sum /
static_cast<float>(frame_count)),
457 std::memory_order_relaxed);
458 mid.store(std::sqrt(mid_sum /
static_cast<float>(frame_count)),
459 std::memory_order_relaxed);
460 high.store(std::sqrt(high_sum /
static_cast<float>(frame_count)),
461 std::memory_order_relaxed);
463 static_cast<float>(crossings) *
465 (2.0F *
static_cast<float>(frame_count)),
466 std::memory_order_relaxed);