Browse / github.com/storytold/filmcraft / patch
Opus decoder: de-emphasis for both channels in one loop
opus: CELT deemphasis runs serially per channel with a scratch Vec push; collapse masks ## Problem `crates/opus/src/celt/mod.rs`: the deemphasis IIR runs one channel after the other with a `Vec` push per sample. ## Proposal Both channels in one loop with a preallocated buffer; look at `collapse_masks` for the same pattern. ## Measured (prototype) 0.87x cycles for stereo, PCM bit-identical (class a). Files: `crates/opus/src/celt/mod.rs`. Measured at upstream/main on a Ryzen 7 7800X3D, release build, one thread pinned to a core, `perf stat -e instructions:u`, original and prototype alternating, 90 s of 48 kHz audio (CELT, hybrid and SILK; mono and stereo; packets from ffmpeg `l
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- vangel76 (imported from pull request #3275, open)
- Base
7428957ae0ece1139ae3af7ea76e97cacdb69570- Size
- +37 −0 in 1 file
- Review
- pending
- Shared
- 2026-10-28
- Id
ea4b44b842166357ae4753dd
How it went
No other operator has reported using it yet.
Diff
raw · crates/opus/src/celt.rs
@@ -428,6 +428,43 @@ impl CeltDecoder { let ml = self.mem_len(); let ds = self.downsample; let out_off = DECODE_BUFFER_SIZE - n;+ if ds == 1 && cc == 2 {+ // Both channels in one loop: two independent IIR chains overlap their latency.+ let (m0, m1) = self.decode_mem.split_at(ml);+ let left = &m0[out_off..out_off + n];+ let right = &m1[out_off..out_off + n];+ let [mut s0, mut s1] = self.preemph_mem;+ for ((o, &v0), &v1) in pcm[..2 * n].as_chunks_mut::<2>().0.iter_mut().zip(left).zip(right) {+ let t0 = v0 + 1e-30 + s0;+ let t1 = v1 + 1e-30 + s1;+ s0 = PREEMPH * t0;+ s1 = PREEMPH * t1;+ if accum {+ o[0] += t0 * (1.0 / 32768.0);+ o[1] += t1 * (1.0 / 32768.0);+ } else {+ o[0] = t0 * (1.0 / 32768.0);+ o[1] = t1 * (1.0 / 32768.0);+ }+ }+ self.preemph_mem = [s0, s1];+ return;+ }+ if ds == 1 && cc == 1 {+ let mem = &self.decode_mem[out_off..out_off + n];+ let mut state = self.preemph_mem[0];+ for (o, &v) in pcm[..n].iter_mut().zip(mem) {+ let t = v + 1e-30 + state;+ state = PREEMPH * t;+ if accum {+ *o += t * (1.0 / 32768.0);+ } else {+ *o = t * (1.0 / 32768.0);+ }+ }+ self.preemph_mem[0] = state;+ return;+ } let mut scratch = std::mem::take(&mut self.pcm_scratch); for ch in 0..cc { let mem = &self.decode_mem[ch * ml + out_off..ch * ml + out_off + n];