Skip to main content

rusty_opus/silk/
init_decoder.rs

1use crate::silk::decoder_structs::SilkDecoderState;
2use crate::silk::define::*;
3use crate::silk::tables_nlsf::*;
4
5pub fn silk_decoder_set_fs(dec: &mut SilkDecoderState, fs_khz: i32, fs_api_hz: i32) -> i32 {
6    if fs_khz != 8 && fs_khz != 12 && fs_khz != 16 {
7        return -1;
8    }
9
10    let new_subfr_length = (SUB_FRAME_LENGTH_MS as i32) * fs_khz;
11    // libopus keys frame_length AND the pitch-contour table off the CURRENT
12    // nb_subfr (set by the caller before this call): 10 ms frames use nb_subfr=2
13    // with the 10 ms contour CDF, 20 ms use nb_subfr=4. Overwriting nb_subfr to
14    // MAX here forced the 20 ms contour on every 10 ms frame -> wrong bit count
15    // -> range-coder desync on the first 10 ms packet.
16    let new_frame_length = new_subfr_length * dec.nb_subfr;
17    // libopus resets the decoder's sample-history state ONLY when the internal
18    // sampling rate (bandwidth) changes — see decoder_set_fs.c, where the outBuf/
19    // sLPC_Q14_buf memset lives inside `if( psDec->fs_kHz != fs_kHz )`, NOT the
20    // outer `|| frame_length != psDec->frame_length` block. A pure frame-length
21    // switch (e.g. 20 ms -> 10 ms at the same NB/MB/WB rate) must PRESERVE the
22    // LPC/output history; zeroing it there makes the first 10 ms frame synthesize
23    // from silence (~1/4 magnitude, wrong sign) even though the range coder stays
24    // perfectly in sync. Only pitch-contour/frame_length update on a length change.
25    let fs_changed = dec.fs_khz != fs_khz;
26
27    dec.fs_khz = fs_khz;
28    dec.fs_api_hz = fs_api_hz;
29
30    dec.subfr_length = new_subfr_length;
31    dec.frame_length = new_frame_length;
32    dec.ltp_mem_length = (LTP_MEM_LENGTH_MS as i32) * fs_khz;
33    // NB (8k) and MB (12k) use a 10th-order LPC (the NB_MB NLSF codebook);
34    // only WB (16k) is 16th-order. Previously MB got order 16, so it read
35    // order-16 NLSF from the order-10 codebook -> garbage LPC on every MB frame.
36    dec.lpc_order = if fs_khz == 8 || fs_khz == 12 {
37        MIN_LPC_ORDER as i32
38    } else {
39        MAX_LPC_ORDER as i32
40    };
41
42    if fs_khz == 8 {
43        if dec.nb_subfr == MAX_NB_SUBFR as i32 {
44            dec.pitch_contour_icdf = &crate::silk::tables::SILK_PITCH_CONTOUR_NB_ICDF;
45        } else {
46            dec.pitch_contour_icdf = &crate::silk::tables::SILK_PITCH_CONTOUR_10_MS_NB_ICDF;
47        }
48    } else if dec.nb_subfr == MAX_NB_SUBFR as i32 {
49        dec.pitch_contour_icdf = &crate::silk::tables::SILK_PITCH_CONTOUR_ICDF;
50    } else {
51        dec.pitch_contour_icdf = &crate::silk::tables::SILK_PITCH_CONTOUR_10_MS_ICDF;
52    }
53
54    dec.pitch_lag_low_bits_icdf = match fs_khz {
55        8 => &crate::silk::tables::SILK_UNIFORM4_ICDF,
56        12 => &crate::silk::tables::SILK_UNIFORM6_ICDF,
57        16 => &crate::silk::tables::SILK_UNIFORM8_ICDF,
58        _ => &crate::silk::tables::SILK_UNIFORM8_ICDF,
59    };
60
61    dec.ps_nlsf_cb = match fs_khz {
62        8 => Some(&SILK_NLSF_CB_NB_MB),
63        12 => Some(&SILK_NLSF_CB_NB_MB),
64        _ => Some(&SILK_NLSF_CB_WB),
65    };
66
67    if fs_changed {
68        dec.first_frame_after_reset = 1;
69        dec.lag_prev = 100;
70        dec.last_gain_index = 10;
71        dec.prev_signal_type = TYPE_NO_VOICE_ACTIVITY;
72        dec.out_buf.fill(0);
73        dec.s_lpc_q14_buf.fill(0);
74    }
75
76    0
77}
78
79pub fn silk_reset_decoder(ps_dec: &mut SilkDecoderState) -> i32 {
80    ps_dec.prev_gain_q16 = 1 << 16;
81    ps_dec.exc_q14.fill(0);
82    ps_dec.s_lpc_q14_buf.fill(0);
83    ps_dec.out_buf.fill(0);
84    ps_dec.lag_prev = 100;
85    ps_dec.last_gain_index = 10;
86    ps_dec.first_frame_after_reset = 1;
87    ps_dec.ec_prev_signal_type = 0;
88    ps_dec.ec_prev_lag_index = 0;
89    ps_dec.vad_flags.fill(0);
90    ps_dec.lbrr_flag = 0;
91    ps_dec.lbrr_flags.fill(0);
92    ps_dec.prev_nlsf_q15.fill(0);
93    ps_dec.loss_cnt = 0;
94    ps_dec.prev_signal_type = TYPE_NO_VOICE_ACTIVITY;
95    ps_dec.indices = Default::default();
96    // silk_decoder_set_fs relies on nb_subfr already holding a valid value (the
97    // caller sets it per-packet); seed it so the very first set_fs computes the
98    // right frame_length / pitch-contour table.
99    ps_dec.nb_subfr = MAX_NB_SUBFR as i32;
100
101    0
102}
103
104pub fn silk_init_decoder(ps_dec: &mut SilkDecoderState) -> i32 {
105    silk_reset_decoder(ps_dec);
106
107    ps_dec.s_cng = Default::default();
108    crate::silk::cng::silk_cng_reset(ps_dec);
109
110    ps_dec.s_plc = Default::default();
111
112    0
113}
114
115pub fn silk_create_decoder() -> SilkDecoderState {
116    let mut dec = SilkDecoderState::default();
117    silk_init_decoder(&mut dec);
118    dec
119}