collective

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

diff --git a/crates/opus/src/celt.rs b/crates/opus/src/celt.rs--- a/crates/opus/src/celt.rs+++ b/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];