Repository navigation
Type your own sound card buffer size, used by the mic too - #35
Conversation
The Sound card buffer setting keeps its presets and gets a box to type any value from 1 to 1000 ms. The devices reopen once the typing or dragging is done, never every frame. The mic input now asks for the same buffer, and the mic queue is capped to a few buffers so its delay can't creep up to a second when the input and output clocks drift. Settings shows the buffer each output actually got (frames and ms), or that the driver refused it. Closes #34 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016m2QHYB4iztqZ2rQPnXw76
There was a problem hiding this comment.
MergeGuard review
Risk: 🟠 35/100 — moderate
Findings: 🟠 1 medium
Open Files changed for 1 inline review thread on the diff.
💡 Use the Fix All MergeGuard Findings checkbox comment on this PR to apply auto-fixes in batch, or reply
@mergeguards fixon any inline finding.
Reviewed by MergeGuard AI
| while s.mic_buf.len() > SR as usize * 2 { | ||
| s.mic_buf.pop_front(); | ||
| // never less than a few of the input's own chunks, whatever size its driver settled on | ||
| let max = s.mic_max.max(samples.len() * 3).min(SR as usize * 2); |
There was a problem hiding this comment.
🛡️ MergeGuard · 🟠 medium · bug
Bitwise AND operation on potentially odd-sized sample buffer. Line 740 uses samples.len() * 3 which may be odd, then .min(SR as usize * 2) which is even (SR=48000, so 96000 samples). The subsequent line 743 applies & !1 to ensure even count, but the intermediate max value could be odd, leading to inconsistent mic_buf length tracking.
💡 Ensure
maxis always even by applying& !1after computing it:let max = (s.mic_max.max(samples.len() * 3).min(SR as usize * 2)) & !1;
Reply with @mergeguards fix to apply an auto-fix on this line.
There was a problem hiding this comment.
I traced this and the queue length stays even, so I'm leaving the line as it is. Here's why:
samplesalways holds interleaved stereo pairs:mic::buildpushes two values for every frame, sosamples.len()is even andsamples.len() * 3is even too.SRis 44 100 here, soSR * 2is even.mic_maxis already rounded down to even inset_mic_latency_ms.
So max is always even. Even if it weren't, drop = (len - max / 2) & !1 is what decides how much gets drained, and it is even whenever len is. mic_buf therefore always gets drained by an even count, and left and right never swap.
Generated by Claude Code
MergeGuard agent actionsFix all findingsAll issues (1)
Apply auto-fixes for the findings above on this branch:
Or reply with |
Requested by epell · project thread
Closes #34
What changed
playing (primary, 144 frames, about 3.0 ms), or that the driver refused the size. Drivers often round or have a floor (WASAPI shared mode is usually about 10 ms), so this shows what you actually got.ASIO (not in this PR)
cpal has an
asiofeature, but turning it on is a bigger job than a setting:CPAL_ASIO_DIR) plus LLVM/clang for bindgen on the Windows CI runner and on any Windows dev machine. The SDK has its own license (Steinberg proprietary or GPLv3), which needs checking against RadioMaster's MIT license before we ship binaries built with it.Remaining limit for very low settings
The mixer renders in fixed 1024-frame blocks (about 23 ms). With a 3 ms buffer the card's own delay goes down, but a sound through the software (the mic, or pressing Play) can still wait up to one block. Smaller mix blocks would need the stream/server taps and monitor channels re-sized (their queues are counted in blocks) and the meter decay rescaled. That is a sensible follow-up, but it was kept out of this change.
Checks
cargo fmt,cargo +1.99.0 clippy --all-targets -- -D warnings,cargo test(new tests for the buffer clamp and frame maths) all passtools/extract_strings.pyregeneratedlang/template.json;tools/check_glyphs.pypassesGenerated by Claude Code