fix(vsti): crackle fix P1-P3 — SHM 8-slot ring + drain-delta pump + AudioWorklet sink

- SharedMemoryIPC.h/main.cpp: render into ring slot (idx & ringMask), 8 slots
- shm.rs: ring fields + read_ring_audio; lib.rs pump drains FULL delta, not just latest
- bridgeAudioNode.js: AudioWorklet primary (bridge-audio-sink), ScriptProcessor fallback
- bridgeAudioWorklet.js: ring 64 blocks, underrun fade, overrun drop + crossfade
- layout tests: sizeof 27560 (8-align via u64)
This commit is contained in:
2026-08-16 20:43:50 +07:00
parent ed26e1706d
commit cead8c8c71
8 changed files with 235 additions and 29 deletions
+22 -1
View File
@@ -67,6 +67,13 @@ pub struct SharedAudioBufferIPC {
// independent of the audio loop. Watchdog liveness keys on this.
// Append-only field: offsets above are unchanged.
pub heartbeat: u32,
// VSTi crackle fix: multi-slot audio ring (appended after heartbeat —
// offsets above are unchanged). Bridge renders block N into slot
// (bridge_write_index & ring_mask), then increments bridge_write_index.
// Pump drains EVERY slot between its last index and write_index, in order.
pub ring_mask: u32,
pub ring_left: [[f32; AUDIO_BLOCK_SIZE]; 8],
pub ring_right: [[f32; AUDIO_BLOCK_SIZE]; 8],
}
pub struct Shm {
@@ -159,6 +166,17 @@ impl Shm {
(ipc.master_left, ipc.master_right)
}
/// Read ring slot for block index `idx` (slot = idx & ring_mask).
pub fn read_ring_audio(&self, idx: u32) -> ([f32; AUDIO_BLOCK_SIZE], [f32; AUDIO_BLOCK_SIZE]) {
let ipc = self.ipc();
let slot = (idx & ipc.ring_mask) as usize;
(ipc.ring_left[slot], ipc.ring_right[slot])
}
pub fn ring_mask(&self) -> u32 {
self.ipc().ring_mask
}
pub fn write_index(&self) -> u32 {
self.ipc().bridge_write_index
}
@@ -196,6 +214,9 @@ mod tests {
// native_bridge/tests/shm_selfcheck.cpp asserts the same sizes.
assert_eq!(std::mem::size_of::<MidiEventIPC>(), 12);
assert_eq!(std::mem::size_of::<ControlEventIPC>(), 1040);
assert_eq!(std::mem::size_of::<SharedAudioBufferIPC>(), 11168);
// 11168 + ring_mask(4) + ring_left(8*256*4) + ring_right(8*256*4)
// = 27556, rounded up to 8-byte struct alignment (u64 block_timestamp)
// => 27560. Matches MSVC sizeof (verified against the C header).
assert_eq!(std::mem::size_of::<SharedAudioBufferIPC>(), 27560);
}
}