From f9f06568bfa7ef02b92c3616b77b337680a1c956 Mon Sep 17 00:00:00 2001 From: Bendik Aagaard Lynghaug Date: Wed, 7 Oct 2026 22:37:17 +0200 Subject: [PATCH] audio: render only the frames PipeWire requests per cycle The process callback filled the whole mapped buffer every cycle. PipeWire sizes that buffer by clock.quantum-limit (8192 frames by default) while the graph drives galdr at the 256-frame quantum we ask for, so each cycle did ~32x the work and everything past the quantum was dropped: choppy output, constant deadline misses in pw-top, and envelopes that sounded 32x faster than their settings. Use Buffer::requested (pipewire feature v0_3_49), clamped to the buffer, with the --latency value as fallback. tui: typing a glyph no longer advances the cursor to the right. Co-Authored-By: Claude Fable 5.1 --- Cargo.toml | 2 +- src/audio.rs | 9 ++++++++- src/tui.rs | 1 - 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bac997f..dcb191e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ codegen-units = 1 [dependencies] anyhow = "1" -pipewire = "0.10" +pipewire = { version = "0.10", features = ["v0_3_49"] } # Buffer::requested midir = "0.10" arc-swap = "1.7" rtrb = "0.3" diff --git a/src/audio.rs b/src/audio.rs index 8a1d45a..334e084 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -75,6 +75,7 @@ fn run( .add_local_listener_with_user_data(()) .process(move |stream, _| { let Some(mut buffer) = stream.dequeue_buffer() else { return }; + let requested = buffer.requested() as usize; let datas = buffer.datas_mut(); let Some(data) = datas.first_mut() else { return }; let stride = ch * 4; @@ -85,9 +86,15 @@ fn run( engine.apply(ev); } + // Render only what the graph asked for this cycle. The mapped + // buffer is sized by clock.quantum-limit (8192 frames by default), + // so filling it whole would do ~32x the work of a 256-frame + // quantum and PipeWire would drop everything past the quantum: + // choppy output and envelopes that race through their stages. + let want = if requested > 0 { requested } else { latency as usize }; let mut n_frames = 0usize; if let Some(slice) = data.data() { - n_frames = slice.len() / stride; + n_frames = want.min(slice.len() / stride); for f in 0..n_frames { let smp = engine.render(&program); let bytes = smp.to_le_bytes(); diff --git a/src/tui.rs b/src/tui.rs index d531bfc..aa761c9 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -169,7 +169,6 @@ pub fn run( KeyCode::Char(c) => { grid.set(cx, cy, if c == ' ' { '.' } else { c }); edited = true; - cx = (cx + 1).min(grid.w - 1); } _ => {} }