collective

Browse / github.com/storytold/effectcraft / patch

opusenc: memoise SILK rate-loop trials, ring buffer for noise feedback

opusenc: the SILK rate loop repeats trials; noise-feedback history is shifted with copy_within every sample ## Problem `crates/opusenc/src/silk/mod.rs`: (E2) the trial for the chosen offset is computed three times in the rate loop; (E6) the noise-feedback history is shifted with `copy_within` for every sample. ## Proposal / measured E2: memoise the trials, 0.94x. E6: ring buffer, 0.93x cycles. Both byte-identical (class a). Remaining after the other fixes: the SILK LPC synthesis loop, per-frame allocations. Files: `crates/opusenc/src/silk/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 alter

Status
open
Score
0.00
Adopters
0 other operators
Author
vangel76 (imported from pull request #2399, open)
Base
bc4b48f67deef2458e9dd3e3b0e592d5f75768a1
Size
+42 −10 in 1 file
Review
pending
Shared
2026-10-28
Id
e4f11fae72587520dd1b1ab2

How it went

No other operator has reported using it yet.

Diff

raw · crates/opusenc/src/silk.rs

diff --git a/crates/opusenc/src/silk.rs b/crates/opusenc/src/silk.rs--- a/crates/opusenc/src/silk.rs+++ b/crates/opusenc/src/silk.rs@@ -229,7 +229,12 @@ impl Channel {         let sub = self.sub;         let order = self.order;         let st = &mut self.dec;-        let nf = &mut self.nf;+        // Noise-feedback history, most recent first, as a double-length ring: `ring[pos..pos + 16]`+        // is always the contiguous window (a new sample goes to `pos` and `pos + 16`).+        let mut ring = [0f64; 2 * MAX_LPC_ORDER];+        ring[..MAX_LPC_ORDER].copy_from_slice(&self.nf);+        ring[MAX_LPC_ORDER..].copy_from_slice(&self.nf);+        let mut pos = 0usize;         let off = if p.signal_type == 0 { offset + INACTIVE_OFFSET } else { offset };         let gamma = nf_gamma(off);         let mut nf_c = [0f64; MAX_LPC_ORDER];@@ -347,7 +352,7 @@ impl Channel {                 }                 let lpc_q14 = lpc_pred.saturating_mul(16);                 // Target excitation (Q14) for this sample.-                let fb: f64 = (0..order).map(|j| nf_c[j] * nf[j]).sum();+                let fb: f64 = (0..order).map(|j| nf_c[j] * ring[pos + j]).sum();                 let tgt = (x[n] as f64 + fb).clamp(-32768.0, 32767.0) * inv_g - lpc_q14 as f64 - ltp_q14 as f64;                 let sgn = if seed_v < 0 { -1.0 } else { 1.0 };                 let u = sgn * tgt;@@ -386,11 +391,14 @@ impl Channel {                 let v = res.saturating_add(lpc_q14);                 s_lpc[MAX_LPC_ORDER + i] = v;                 xq[n] = sat16(rshift_round(smulww(v, gain_q10), 8)) as i16;-                nf.copy_within(0..MAX_LPC_ORDER - 1, 1);-                nf[0] = xq[n] as f64 - x[n] as f64;+                pos = if pos == 0 { MAX_LPC_ORDER - 1 } else { pos - 1 };+                let err = xq[n] as f64 - x[n] as f64;+                ring[pos] = err;+                ring[pos + MAX_LPC_ORDER] = err;             }             s_lpc.copy_within(sub..sub + MAX_LPC_ORDER, 0);         }+        self.nf.copy_from_slice(&ring[pos..pos + MAX_LPC_ORDER]);         st.s_lpc_q14.copy_from_slice(&s_lpc[..MAX_LPC_ORDER]);         st.out_buf[..l].copy_from_slice(&xq);         (Coded { gain_ix, gains_q16, seed, pulses }, xq)@@ -477,6 +485,14 @@ struct Prep {     pred_q13: [i32; 2], } +/// One rate-loop trial: the frame coded at gain offset `offset`.+struct Trial {+    offset: f64,+    bits: i32,+    state: SilkEncoder,+    coder: RangeEncoder,+}+ /// SILK encoder for one mono or stereo (mid/side) stream. #[derive(Clone)] pub struct SilkEncoder {@@ -627,11 +643,20 @@ impl SilkEncoder {     pub fn encode(&mut self, input: &[Vec<f32>], target_bits: f64, max_bits: i32, enc: &mut RangeEncoder) {         let prep = self.prepare(input);         let start_bits = enc.tell();-        let trial = |s: &Self, o: f64| -> i32 {-            let mut t = s.clone();-            let mut e = enc.clone();-            t.code(&prep, o, &mut e);-            e.tell() - start_bits+        // Every trial codes the frame into a clone of the encoder and the range coder. The result+        // is kept per offset: the hard-limit check below hits the memo for the chosen offset, and+        // the final step adopts that trial instead of coding the frame once more.+        let mut trials: Vec<Trial> = Vec::new();+        let mut trial = |s: &Self, o: f64| -> i32 {+            if let Some(t) = trials.iter().find(|t| t.offset == o) {+                return t.bits;+            }+            let mut state = s.clone();+            let mut coder = enc.clone();+            state.code(&prep, o, &mut coder);+            let bits = coder.tell() - start_bits;+            trials.push(Trial { offset: o, bits, state, coder });+            bits         };         // Bisection on the gain offset: the smallest offset (finest quantisation) within budget.         let target = target_bits.min(max_bits as f64);@@ -693,8 +718,15 @@ impl SilkEncoder {         while trial(self, o) > max_bits && o < 12.0 {             o += 1.0;         }+        match trials.iter().position(|t| t.offset == o) {+            Some(i) => {+                let t = trials.swap_remove(i);+                *self = t.state;+                *enc = t.coder;+            }+            None => self.code(&prep, o, enc),+        }         self.last_offset = o;-        self.code(&prep, o, enc);         for ch in 0..self.channels {             self.ch[ch].push_history(&prep.x[ch]);         }