Skip to content

Commit 60ccbd5

Browse files
committed
fix(nodes/audio): audio input outputs partial buffers
1 parent 582ae37 commit 60ccbd5

4 files changed

Lines changed: 34 additions & 23 deletions

File tree

‎crates/runtime/pipeline/nodes/audio/src/input.rs‎

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
66

77
use mizer_node::*;
88

9-
use crate::AudioContext;
9+
use crate::{AudioContext, CHANNEL_COUNT, INPUT_BUFFER_SIZE};
1010

1111
const AUDIO_OUTPUT: &str = "Stereo";
1212

@@ -41,9 +41,9 @@ impl ProcessingNode for AudioInputNode {
4141
*state = AudioInputNodeState::new(context).context("Creating audio input state")?;
4242
}
4343
if let Some(state) = state {
44-
let buffer = state.read(context)?;
45-
46-
context.write_port(AUDIO_OUTPUT, buffer);
44+
if let Some(buffer) = state.read(context)? {
45+
context.write_port(AUDIO_OUTPUT, buffer);
46+
}
4747
}
4848

4949
Ok(())
@@ -64,11 +64,12 @@ impl AudioInputNodeState {
6464
fn new(audio_context: &impl AudioContext) -> anyhow::Result<Option<Self>> {
6565
tracing::trace!("Opening audio input device");
6666
if let Some(device) = cpal::default_host().default_input_device() {
67-
let buffer = SpscRb::new(audio_context.transfer_size() * 2);
67+
let buffer = SpscRb::new(audio_context.transfer_size_per_channel() * CHANNEL_COUNT * INPUT_BUFFER_SIZE);
6868

6969
let config = device.supported_input_configs()?;
7070
let configs = config.collect::<Vec<_>>();
7171
tracing::trace!("Supported Input Configs: {configs:?}");
72+
// TODO: find device with lowest buffer size
7273
if let Some(config) = configs.into_iter().find(|c| {
7374
c.channels() == 2
7475
&& c.sample_format() == SampleFormat::F32
@@ -112,14 +113,17 @@ impl AudioInputNodeState {
112113
}
113114
}
114115

115-
fn read(&mut self, audio_context: &impl AudioContext) -> anyhow::Result<Vec<f64>> {
116-
let mut buffer = vec![0.; audio_context.transfer_size()];
117-
let count = self
118-
.buffer
119-
.consumer()
120-
.read(&mut buffer)
121-
.map_err(|err| anyhow::anyhow!("Unable to read from Ringbuffer: {err:?}"))?;
116+
fn read(&mut self, audio_context: &impl AudioContext) -> anyhow::Result<Option<Vec<f64>>> {
117+
let mut buffer = vec![0.; audio_context.transfer_size_per_channel() * CHANNEL_COUNT];
118+
let consumer = self.buffer.consumer();
119+
let count = consumer.get(&mut buffer).unwrap_or(0);
120+
if count < buffer.len() {
121+
return Ok(None);
122+
}
123+
124+
consumer.skip(count)
125+
.map_err(|err| anyhow::anyhow!("Unable to skip from Ringbuffer: {err:?}"))?;
122126

123-
Ok(buffer[0..count].iter().map(|f| *f as f64).collect())
127+
Ok(Some(buffer.into_iter().map(|f| f as f64).collect()))
124128
}
125129
}

‎crates/runtime/pipeline/nodes/audio/src/lib.rs‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::vec::IntoIter;
22

33
use dasp::frame::Stereo;
44
use dasp::signal::{from_interleaved_samples_iter, FromInterleavedSamplesIterator};
5-
use dasp::Signal;
5+
pub use dasp::Signal;
66

77
pub use file::*;
88
pub use input::*;
@@ -12,7 +12,13 @@ use mizer_node::{NodeContext, PortId};
1212
pub use output::*;
1313
pub use volume::*;
1414

15+
pub(crate) const CHANNEL_COUNT: usize = 2;
1516
pub(crate) const SAMPLE_RATE: u32 = 44_100;
17+
const BUFFER_SIZE: usize = 4;
18+
19+
// TODO: decrease buffer size if possible
20+
pub(crate) const INPUT_BUFFER_SIZE: usize = BUFFER_SIZE;
21+
pub(crate) const OUTPUT_BUFFER_SIZE: usize = BUFFER_SIZE;
1622

1723
mod file;
1824
mod input;
@@ -21,10 +27,10 @@ mod mix;
2127
mod output;
2228
mod volume;
2329

24-
trait AudioContext {
30+
pub trait AudioContext {
2531
type InputSignal: Signal<Frame = Stereo<f64>>;
2632

27-
fn transfer_size(&self) -> usize;
33+
fn transfer_size_per_channel(&self) -> usize;
2834
fn sample_rate(&self) -> u32 {
2935
SAMPLE_RATE
3036
}
@@ -40,7 +46,7 @@ trait AudioContext {
4046
impl<T: NodeContext> AudioContext for T {
4147
type InputSignal = FromInterleavedSamplesIterator<IntoIter<f64>, Stereo<f64>>;
4248

43-
fn transfer_size(&self) -> usize {
49+
fn transfer_size_per_channel(&self) -> usize {
4450
(self.sample_rate() / self.fps().round() as u32) as usize
4551
}
4652

@@ -58,7 +64,7 @@ impl<T: NodeContext> AudioContext for T {
5864
let buffer: Vec<f64> = signal
5965
.into_interleaved_samples()
6066
.into_iter()
61-
.take(self.transfer_size() * 2) // Stereo Signal so take twice the sample count
67+
.take(self.transfer_size_per_channel() * CHANNEL_COUNT) // Stereo Signal so take twice the sample count
6268
.collect();
6369
self.write_port(name, buffer);
6470
}

‎crates/runtime/pipeline/nodes/audio/src/meter.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use crate::AudioContext;
99

1010
const AUDIO_INPUT: &str = "Stereo";
1111
const VOLUME_OUTPUT: &str = "Volume";
12-
const VOLUME_L_OUTPUT: &str = "Volume (L)";
13-
const VOLUME_R_OUTPUT: &str = "Volume (R)";
12+
const VOLUME_L_OUTPUT: &str = "Volume L";
13+
const VOLUME_R_OUTPUT: &str = "Volume R";
1414

1515
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq)]
1616
pub struct AudioMeterNode;
@@ -45,7 +45,7 @@ impl ProcessingNode for AudioMeterNode {
4545

4646
fn process(&self, context: &impl NodeContext, _state: &mut Self::State) -> anyhow::Result<()> {
4747
if let Some(signal) = context.input_signal(AUDIO_INPUT) {
48-
let buffer = Fixed::from(vec![[0.0; 2]; context.transfer_size()]);
48+
let buffer = Fixed::from(vec![[0.0; 2]; context.transfer_size_per_channel()]);
4949
let rms = signal.rms(buffer).until_exhausted().last().unwrap();
5050
let stereo_rms = rms.into_iter().sum::<f64>() / 2.0;
5151
context.write_port(VOLUME_OUTPUT, stereo_rms);

‎crates/runtime/pipeline/nodes/audio/src/output.rs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
66

77
use mizer_node::*;
88

9-
use crate::AudioContext;
9+
use crate::{AudioContext, CHANNEL_COUNT, OUTPUT_BUFFER_SIZE};
1010

1111
const AUDIO_INPUT: &str = "Stereo";
1212

@@ -87,7 +87,7 @@ impl AudioOutputNodeState {
8787
fn new(audio_context: &impl AudioContext) -> anyhow::Result<Option<Self>> {
8888
tracing::trace!("Opening audio output device");
8989
if let Some(device) = cpal::default_host().default_output_device() {
90-
let buffer = SpscRb::new(audio_context.transfer_size() * 8);
90+
let buffer = SpscRb::new(audio_context.transfer_size_per_channel() * CHANNEL_COUNT * OUTPUT_BUFFER_SIZE);
9191

9292
let config = device.supported_output_configs()?;
9393
let configs = config.collect::<Vec<_>>();
@@ -137,6 +137,7 @@ impl AudioOutputNodeState {
137137

138138
fn write(&self, buffer: Vec<f64>) -> anyhow::Result<()> {
139139
tracing::trace!("Received {} frames", buffer.len());
140+
// TODO: count dropped frames
140141
self.buffer
141142
.producer()
142143
.write(

0 commit comments

Comments
 (0)