rvsttd: single faded audio stream feeds both Moonshine and debug WAV

This commit is contained in:
2026-08-17 06:51:27 +00:00
parent 411f1c0952
commit cc9fc95519
+25 -21
View File
@@ -113,6 +113,14 @@ impl DebugRecorder {
self.audio.extend_from_slice(samples); self.audio.extend_from_slice(samples);
} }
fn audio_len(&self) -> usize {
self.audio.len()
}
fn truncate_audio(&mut self, len: usize) {
self.audio.truncate(len);
}
fn save(self) { fn save(self) {
// Write log // Write log
let log_path = self.dir.join("session.log"); let log_path = self.dir.join("session.log");
@@ -325,48 +333,44 @@ fn transcriber_loop(
// Fixed 100ms window — cpal delivers every ~50ms (800 samples @ 16kHz), // Fixed 100ms window — cpal delivers every ~50ms (800 samples @ 16kHz),
// so this captures 1-2 more callbacks worth of trailing audio. // so this captures 1-2 more callbacks worth of trailing audio.
let drain_deadline = std::time::Instant::now() + Duration::from_millis(100); let drain_deadline = std::time::Instant::now() + Duration::from_millis(100);
let mut last_chunk: Option<Vec<f32>> = None; let mut drained: Vec<f32> = Vec::new();
while std::time::Instant::now() < drain_deadline { while std::time::Instant::now() < drain_deadline {
match rx.recv_timeout(drain_deadline - std::time::Instant::now()) { match rx.recv_timeout(drain_deadline - std::time::Instant::now()) {
Ok(chunk) => { Ok(chunk) => {
// Record raw audio for debug WAV
if let Some(ref mut r) = recorder { if let Some(ref mut r) = recorder {
r.add_audio(&chunk); r.add_audio(&chunk);
} }
drained.extend_from_slice(&chunk);
// Feed previous chunk to Moonshine, hold the latest for fade
if let Some(prev) = last_chunk.take() {
unsafe {
moonshine_transcribe_add_audio_to_stream(
handle, stream_handle,
prev.as_ptr(), prev.len() as u64,
SAMPLE_RATE, 0,
);
}
}
last_chunk = Some(chunk);
} }
Err(mpsc::RecvTimeoutError::Timeout) => break, Err(mpsc::RecvTimeoutError::Timeout) => break,
Err(mpsc::RecvTimeoutError::Disconnected) => break, Err(mpsc::RecvTimeoutError::Disconnected) => break,
} }
} }
// Apply 5ms fade-out to the last chunk before feeding to Moonshine. // Apply 5ms fade-out to the trailing edge of the drained audio.
// The recorder already captured the unmodified audio for the debug WAV. // Both the debug WAV and Moonshine receive the same faded audio.
if let Some(mut chunk) = last_chunk.take() {
let fade_samples = (SAMPLE_RATE as usize * 5) / 1000; let fade_samples = (SAMPLE_RATE as usize * 5) / 1000;
if chunk.len() > fade_samples { if drained.len() > fade_samples {
let start = chunk.len() - fade_samples; let start = drained.len() - fade_samples;
for i in 0..fade_samples { for i in 0..fade_samples {
let t = 1.0 - (i as f32 / fade_samples as f32); let t = 1.0 - (i as f32 / fade_samples as f32);
chunk[start + i] *= t; drained[start + i] *= t;
} }
} }
// Update recorder with the faded audio (replaces the raw versions added above)
if let Some(ref mut r) = recorder {
// Remove the raw drained samples and re-add the faded ones
let raw_drained_len = r.audio_len();
r.truncate_audio(raw_drained_len.saturating_sub(drained.len()));
r.add_audio(&drained);
}
if !drained.is_empty() {
unsafe { unsafe {
moonshine_transcribe_add_audio_to_stream( moonshine_transcribe_add_audio_to_stream(
handle, stream_handle, handle, stream_handle,
chunk.as_ptr(), chunk.len() as u64, drained.as_ptr(), drained.len() as u64,
SAMPLE_RATE, 0, SAMPLE_RATE, 0,
); );
} }