Feat: audio input channel selection
This commit is contained in:
@@ -454,6 +454,36 @@ pub(super) const WORDS: &[Word] = &[
|
||||
compile: Param,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "eqlofreq",
|
||||
aliases: &[],
|
||||
category: "Filter",
|
||||
stack: "(v.. --)",
|
||||
desc: "Set low shelf frequency (Hz)",
|
||||
example: "400 eqlofreq",
|
||||
compile: Param,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "eqmidfreq",
|
||||
aliases: &[],
|
||||
category: "Filter",
|
||||
stack: "(v.. --)",
|
||||
desc: "Set mid peak frequency (Hz)",
|
||||
example: "2000 eqmidfreq",
|
||||
compile: Param,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "eqhifreq",
|
||||
aliases: &[],
|
||||
category: "Filter",
|
||||
stack: "(v.. --)",
|
||||
desc: "Set high shelf frequency (Hz)",
|
||||
example: "8000 eqhifreq",
|
||||
compile: Param,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "tilt",
|
||||
aliases: &[],
|
||||
|
||||
@@ -246,6 +246,16 @@ pub(super) const WORDS: &[Word] = &[
|
||||
compile: Param,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "inchan",
|
||||
aliases: &[],
|
||||
category: "Sample",
|
||||
stack: "(v.. --)",
|
||||
desc: "Select input channel for live input (0-indexed)",
|
||||
example: "0 inchan",
|
||||
compile: Param,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "cut",
|
||||
aliases: &[],
|
||||
|
||||
@@ -355,9 +355,6 @@ pub fn build_stream(
|
||||
|
||||
let registry = Arc::clone(&engine.sample_registry);
|
||||
|
||||
const INPUT_BUFFER_SIZE: usize = 8192;
|
||||
let (input_producer, input_consumer) = HeapRb::<f32>::new(INPUT_BUFFER_SIZE).split();
|
||||
|
||||
let input_device = config
|
||||
.input_device
|
||||
.as_ref()
|
||||
@@ -374,6 +371,12 @@ pub fn build_stream(
|
||||
.and_then(|dev| dev.default_input_config().ok())
|
||||
.map_or(0, |cfg| cfg.channels() as usize);
|
||||
|
||||
engine.input_channels = input_channels;
|
||||
|
||||
const INPUT_BUFFER_BASE: usize = 8192;
|
||||
let input_buffer_size = INPUT_BUFFER_BASE * (input_channels.max(2) / 2);
|
||||
let (input_producer, input_consumer) = HeapRb::<f32>::new(input_buffer_size).split();
|
||||
|
||||
let input_stream = input_device.and_then(|dev| {
|
||||
let input_cfg = match dev.default_input_config() {
|
||||
Ok(cfg) => cfg,
|
||||
@@ -476,47 +479,16 @@ pub fn build_stream(
|
||||
}
|
||||
}
|
||||
|
||||
// doux expects stereo interleaved live_input (CHANNELS=2)
|
||||
let stereo_len = buffer_samples * 2;
|
||||
if live_scratch.len() < stereo_len {
|
||||
live_scratch.resize(stereo_len, 0.0);
|
||||
}
|
||||
match input_channels {
|
||||
0 => {
|
||||
live_scratch[..stereo_len].fill(0.0);
|
||||
}
|
||||
1 => {
|
||||
for i in 0..buffer_samples {
|
||||
let s = input_consumer.try_pop().unwrap_or(0.0);
|
||||
live_scratch[i * 2] = s;
|
||||
live_scratch[i * 2 + 1] = s;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
for sample in &mut live_scratch[..stereo_len] {
|
||||
*sample = input_consumer.try_pop().unwrap_or(0.0);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
for i in 0..buffer_samples {
|
||||
let l = input_consumer.try_pop().unwrap_or(0.0);
|
||||
let r = input_consumer.try_pop().unwrap_or(0.0);
|
||||
for _ in 2..input_channels {
|
||||
input_consumer.try_pop();
|
||||
}
|
||||
live_scratch[i * 2] = l;
|
||||
live_scratch[i * 2 + 1] = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Discard excess if input produced more than we consumed
|
||||
let excess = input_consumer.occupied_len().saturating_sub(INPUT_BUFFER_SIZE / 2);
|
||||
for _ in 0..excess {
|
||||
input_consumer.try_pop();
|
||||
let nch_in = input_channels.max(1);
|
||||
let raw_len = buffer_samples * nch_in;
|
||||
if live_scratch.len() < raw_len {
|
||||
live_scratch.resize(raw_len, 0.0);
|
||||
}
|
||||
live_scratch[..raw_len].fill(0.0);
|
||||
input_consumer.pop_slice(&mut live_scratch[..raw_len]);
|
||||
|
||||
engine.metrics.load.set_buffer_time(buffer_time_ns);
|
||||
engine.process_block(data, &[], &live_scratch[..stereo_len]);
|
||||
engine.process_block(data, &[], &live_scratch[..raw_len]);
|
||||
scope_buffer.write(data);
|
||||
|
||||
// Feed mono mix to analysis thread via ring buffer (non-blocking)
|
||||
|
||||
Reference in New Issue
Block a user