use crate::Error;
use crate::fixedvec::FixedVec;
use crate::in_place::{HeapMemory, write_fields, write_zero};
use crate::float2int16;
use crate::range_coder::{RangeCoder, RangeCoderState};
use crate::silk::control_codec::{
SilkBandwidthControl, silk_control_audio_bandwidth, silk_control_encoder, silk_setup_lbrr,
};
use crate::silk::control_fixed::*;
use crate::silk::control_snr::silk_control_snr;
use crate::silk::define::*;
use crate::silk::encode_indices::*;
use crate::silk::encode_pulses::*;
use crate::silk::gain_quant::{silk_gains_dequant, silk_gains_id, silk_gains_quant};
use crate::silk::hp_variable_cutoff::silk_hp_variable_cutoff;
use crate::silk::init_encoder::silk_init_encoder;
use crate::silk::lp_variable_cutoff::*;
use crate::silk::macros::*;
use crate::silk::noise_shape_analysis::*;
use crate::silk::nsq::*;
use crate::silk::nsq_del_dec::*;
use crate::silk::pitch_analysis::*;
use crate::silk::resampler::SilkResampler;
use crate::silk::stereo_lr_to_ms::silk_stereo_lr_to_ms;
use crate::silk::structs::*;
use crate::silk::tuning_parameters::BITRESERVOIR_DECAY_TIME_MS;
use crate::silk::vad::silk_vad_get_sa_q8;
pub fn silk_encode_do_vad(ps_enc: &mut SilkEncoderState, input: &[i16], activity: i32) {
let activity_threshold = SPEECH_ACTIVITY_DTX_THRES_Q8;
let frame_length = ps_enc.s_cmn.frame_length as usize;
silk_vad_get_sa_q8(ps_enc, input, frame_length);
if activity == 0 && ps_enc.s_cmn.speech_activity_q8 >= activity_threshold {
ps_enc.s_cmn.speech_activity_q8 = activity_threshold - 1;
}
if ps_enc.s_cmn.speech_activity_q8 < activity_threshold {
ps_enc.s_cmn.indices.signal_type = TYPE_NO_VOICE_ACTIVITY as i8;
ps_enc.s_cmn.no_speech_counter += 1;
if ps_enc.s_cmn.no_speech_counter <= NB_SPEECH_FRAMES_BEFORE_DTX {
ps_enc.s_cmn.in_dtx = 0;
} else if ps_enc.s_cmn.no_speech_counter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX {
ps_enc.s_cmn.no_speech_counter = NB_SPEECH_FRAMES_BEFORE_DTX;
ps_enc.s_cmn.in_dtx = 0;
}
ps_enc.s_cmn.vad_flags[ps_enc.s_cmn.n_frames_encoded as usize] = 0;
} else {
ps_enc.s_cmn.no_speech_counter = 0;
ps_enc.s_cmn.in_dtx = 0;
ps_enc.s_cmn.indices.signal_type = TYPE_UNVOICED as i8;
ps_enc.s_cmn.vad_flags[ps_enc.s_cmn.n_frames_encoded as usize] = 1;
}
}
fn prefill_geometry(ps_enc: &SilkEncoderState) -> Option<(i32, usize)> {
let fs_khz = ps_enc.s_cmn.fs_khz;
if fs_khz != 8 && fs_khz != 12 && fs_khz != 16 {
return None;
}
Some((fs_khz, fs_khz as usize * 10))
}
pub fn silk_encode_prefill(
mid: &mut SilkEncoderState,
mut side: Option<&mut SilkEncoderState>,
input: [&[i16]; 2],
total_rate_bps: i32,
activity: i32,
) {
let Some((fs_khz, len)) = prefill_geometry(mid) else {
return;
};
let n_channels = 1 + side.is_some() as usize;
if input[..n_channels].iter().any(|frame| frame.len() < len) {
return;
}
let mut x = [[0i16; MAX_FRAME_LENGTH + 2]; 2];
for (buf, frame) in x.iter_mut().zip(&input[..n_channels]) {
buf[2..2 + len].copy_from_slice(&frame[..len]);
}
let [x1, x2] = &mut x;
let mut side_coded = false;
if let Some(side) = side.as_deref_mut() {
enter_stereo(mid, side);
side.s_cmn.s_lp = mid.s_cmn.s_lp;
let (mut ix, mut mid_only, mut rates) = ([[0i8; 3]; 2], 0i8, [0i32; 2]);
let n_bits = packet_target_bits(total_rate_bps, 10);
let target_rate_bps = limit_target_rate(
n_bits * 100 - reservoir_payback_bps(mid.n_bits_exceeded as i64),
total_rate_bps,
);
silk_stereo_lr_to_ms(
&mut mid.stereo,
x1,
x2,
&mut ix,
&mut mid_only,
&mut rates,
target_rate_bps,
0,
false,
fs_khz,
len,
);
mid.stereo.pred_ix[0] = ix;
mid.stereo.mid_only_flags[0] = mid_only;
side.s_cmn.n_frames_encoded = 0;
if mid_only == 0 {
if mid.stereo.prev_decode_only_middle == 1 {
reset_side_for_coding(side);
}
prefill_vad(side, &x2[1..1 + len], activity);
} else {
side.s_cmn.vad_flags[0] = 0;
}
mid.stereo.prev_decode_only_middle = mid_only as i32;
side_coded = rates[1] > 0;
} else {
x1[..2].copy_from_slice(&mid.stereo.s_mid);
mid.stereo.s_mid.copy_from_slice(&x1[len..len + 2]);
mid.stereo.n_channels_internal = 1;
}
mid.s_cmn.n_frames_encoded = 0;
prefill_vad(mid, &x1[1..1 + len], activity);
prefill_frame(mid, x1, len);
if let Some(side) = side
&& side_coded
{
prefill_frame(side, x2, len);
}
mid.stereo.n_prev_channels_internal = n_channels as i32;
}
fn prefill_vad(ps_enc: &mut SilkEncoderState, frame: &[i16], activity: i32) {
let real_frame_length = ps_enc.s_cmn.frame_length;
ps_enc.s_cmn.frame_length = frame.len() as i32;
silk_encode_do_vad(ps_enc, frame, activity);
ps_enc.s_cmn.frame_length = real_frame_length;
}
fn prefill_frame(
ps_enc: &mut SilkEncoderState,
input_buf: &mut [i16; MAX_FRAME_LENGTH + 2],
prefill_frame_length: usize,
) {
ps_enc.s_cmn.indices.seed = (ps_enc.s_cmn.frame_counter & 3) as i8;
ps_enc.s_cmn.frame_counter = ps_enc.s_cmn.frame_counter.wrapping_add(1);
let fs_khz = ps_enc.s_cmn.fs_khz as usize;
let real_frame_length = ps_enc.s_cmn.frame_length as usize;
let real_nb_subfr = ps_enc.s_cmn.nb_subfr;
let real_subfr_length = ps_enc.s_cmn.subfr_length;
ps_enc.s_cmn.frame_length = prefill_frame_length as i32;
ps_enc.s_cmn.nb_subfr = 2;
ps_enc.s_cmn.subfr_length = (prefill_frame_length / 2) as i32;
let ltp_mem_length = ps_enc.s_cmn.ltp_mem_length as usize;
let la_shape_ms_samples = 5 * fs_khz;
silk_lp_variable_cutoff(
&mut ps_enc.s_cmn.s_lp,
&mut input_buf[1..],
prefill_frame_length,
);
let x_frame_idx = ltp_mem_length;
let dst = x_frame_idx + la_shape_ms_samples;
if dst + prefill_frame_length <= ps_enc.s_cmn.x_buf.len() {
ps_enc.s_cmn.x_buf[dst..dst + prefill_frame_length]
.copy_from_slice(&input_buf[1..1 + prefill_frame_length]);
}
let move_len = ltp_mem_length + la_shape_ms_samples;
if prefill_frame_length + move_len <= ps_enc.s_cmn.x_buf.len() {
ps_enc
.s_cmn
.x_buf
.copy_within(prefill_frame_length..prefill_frame_length + move_len, 0);
}
ps_enc.s_cmn.frame_length = real_frame_length as i32;
ps_enc.s_cmn.nb_subfr = real_nb_subfr;
ps_enc.s_cmn.subfr_length = real_subfr_length;
}
pub fn silk_encode_frame(
ps_enc: &mut SilkEncoderState,
input: &[i16],
rc: &mut RangeCoder,
pn_bytes_out: &mut i32,
cond_coding: i32,
max_bits: i32,
use_cbr: i32,
) -> i32 {
let mut s_enc_ctrl = SilkEncoderControl::default();
ps_enc.s_cmn.indices.seed = (ps_enc.s_cmn.frame_counter & 3) as i8;
ps_enc.s_cmn.frame_counter += 1;
let frame_length = ps_enc.s_cmn.frame_length as usize;
let ltp_mem_length = ps_enc.s_cmn.ltp_mem_length as usize;
let la_shape = ps_enc.s_cmn.la_shape as usize;
let x_frame_idx = ltp_mem_length;
let la_shape_max = 5 * ps_enc.s_cmn.fs_khz as usize;
let new_samples_idx = x_frame_idx + la_shape_max;
ps_enc.s_cmn.x_buf[new_samples_idx..new_samples_idx + frame_length]
.copy_from_slice(&input[..frame_length]);
let x_buf_copy = ps_enc.s_cmn.x_buf;
let mut res_pitch = [0i16; LA_PITCH_MAX + MAX_FRAME_LENGTH + LTP_MEM_LENGTH_MS * MAX_FS_KHZ];
let res_pitch_frame_idx = ltp_mem_length;
silk_find_pitch_lags_fix(ps_enc, &mut s_enc_ctrl, &mut res_pitch, &x_buf_copy, 0);
let x_tmp = &x_buf_copy[x_frame_idx - la_shape..];
silk_noise_shape_analysis_fix(
ps_enc,
&mut s_enc_ctrl,
&res_pitch[res_pitch_frame_idx..],
x_tmp,
);
let predict_lpc_order = ps_enc.s_cmn.predict_lpc_order as usize;
let x_tmp_frame = &x_buf_copy[x_frame_idx - predict_lpc_order..];
silk_find_pred_coefs_fix(
ps_enc,
&mut s_enc_ctrl,
&res_pitch,
res_pitch_frame_idx,
x_tmp_frame,
&x_buf_copy,
cond_coding,
);
silk_res_nrg_unscaled_fix(ps_enc, &mut s_enc_ctrl, x_tmp_frame, &x_buf_copy);
silk_process_gains_fix(ps_enc, &mut s_enc_ctrl, cond_coding);
silk_lbrr_encode(ps_enc, &s_enc_ctrl, x_frame_idx, cond_coding);
let max_iter = 6;
let mut gain_mult_q8: i32 = 256;
let mut found_lower = false;
let mut found_upper = false;
#[allow(unused_assignments)]
let mut n_bits: i32 = 0;
let mut n_bits_lower: i32 = 0;
let mut n_bits_upper: i32 = 0;
let mut gain_mult_lower: i32 = 0;
let mut gain_mult_upper: i32 = 0;
let mut gains_id: i32 =
silk_gains_id(&ps_enc.s_cmn.indices.gains_indices, ps_enc.s_cmn.nb_subfr);
let mut gains_id_lower: i32 = -1;
let mut gains_id_upper: i32 = -1;
let bits_margin = if use_cbr != 0 { 5 } else { max_bits / 4 };
let rc_copy = rc.save_state();
let frame_start_offs = rc.offs as usize;
let nsq_copy = ps_enc.s_nsq;
let seed_copy = ps_enc.s_cmn.indices.seed;
let ec_prev_lag_index_copy = ps_enc.s_cmn.ec_prev_lag_index;
let ec_prev_signal_type_copy = ps_enc.s_cmn.ec_prev_signal_type;
let mut rc_copy2: Option<RangeCoderState> = None;
let mut nsq_copy2: Option<SilkNSQState> = None;
let mut ec_buf_copy: FixedVec<u8, { crate::packet::MAX_FRAME_BYTES }> = FixedVec::new();
let mut last_gain_index_copy2: i8 = 0;
let mut gain_lock = [false; MAX_NB_SUBFR];
let mut best_gain_mult = [256i32; MAX_NB_SUBFR];
let mut best_sum = [i32::MAX; MAX_NB_SUBFR];
for iter in 0..=max_iter {
if gains_id == gains_id_lower {
n_bits = n_bits_lower;
} else if gains_id == gains_id_upper {
n_bits = n_bits_upper;
} else {
if iter > 0 {
rc.restore_state(&rc_copy);
ps_enc.s_nsq = nsq_copy;
ps_enc.s_cmn.indices.seed = seed_copy;
ps_enc.s_cmn.ec_prev_lag_index = ec_prev_lag_index_copy;
ps_enc.s_cmn.ec_prev_signal_type = ec_prev_signal_type_copy;
}
let mut pred_coef_q12_flat = [0i16; 2 * MAX_LPC_ORDER];
pred_coef_q12_flat[..MAX_LPC_ORDER].copy_from_slice(&s_enc_ctrl.pred_coef_q12[0]);
pred_coef_q12_flat[MAX_LPC_ORDER..].copy_from_slice(&s_enc_ctrl.pred_coef_q12[1]);
if ps_enc.s_cmn.n_states_delayed_decision > 1 || ps_enc.s_cmn.warping_q16 > 0 {
let winner_seed = silk_nsq_del_dec(
&ps_enc.s_cmn,
&mut ps_enc.s_nsq,
&ps_enc.s_cmn.indices,
&ps_enc.s_cmn.x_buf[x_frame_idx..],
&mut ps_enc.pulses,
&pred_coef_q12_flat,
&s_enc_ctrl.ltp_coef_q14,
&s_enc_ctrl.ar_q13,
&s_enc_ctrl.harm_shape_gain_q14,
&s_enc_ctrl.tilt_q14,
&s_enc_ctrl.lf_shp_q14,
&s_enc_ctrl.gains_q16,
&s_enc_ctrl.pitch_l,
s_enc_ctrl.lambda_q10,
s_enc_ctrl.ltp_scale_q14,
);
ps_enc.s_cmn.indices.seed = winner_seed as i8;
} else {
silk_nsq(
&ps_enc.s_cmn,
&mut ps_enc.s_nsq,
&ps_enc.s_cmn.indices,
&ps_enc.s_cmn.x_buf[x_frame_idx..],
&mut ps_enc.pulses,
&pred_coef_q12_flat,
&s_enc_ctrl.ltp_coef_q14,
&s_enc_ctrl.ar_q13,
&s_enc_ctrl.harm_shape_gain_q14,
&s_enc_ctrl.tilt_q14,
&s_enc_ctrl.lf_shp_q14,
&s_enc_ctrl.gains_q16,
&s_enc_ctrl.pitch_l,
s_enc_ctrl.lambda_q10,
s_enc_ctrl.ltp_scale_q14,
);
}
let rc_before_symbols = rc.save_state();
silk_encode_indices(
ps_enc,
rc,
ps_enc.s_cmn.n_frames_encoded as usize,
false,
cond_coding,
);
silk_encode_pulses(
rc,
ps_enc.s_cmn.indices.signal_type as i32,
ps_enc.s_cmn.indices.quant_offset_type as i32,
&mut ps_enc.pulses,
ps_enc.s_cmn.frame_length as usize,
);
n_bits = rc.tell();
if iter == max_iter && !found_lower && n_bits > max_bits {
rc.restore_state(&rc_before_symbols);
ps_enc.s_shape.last_gain_index = s_enc_ctrl.last_gain_index_prev;
for i in 0..ps_enc.s_cmn.nb_subfr as usize {
ps_enc.s_cmn.indices.gains_indices[i] = 4;
}
if cond_coding != CODE_CONDITIONALLY {
ps_enc.s_cmn.indices.gains_indices[0] = s_enc_ctrl.last_gain_index_prev;
}
ps_enc.s_cmn.ec_prev_lag_index = ec_prev_lag_index_copy;
ps_enc.s_cmn.ec_prev_signal_type = ec_prev_signal_type_copy;
ps_enc.pulses.fill(0);
silk_encode_indices(
ps_enc,
rc,
ps_enc.s_cmn.n_frames_encoded as usize,
false,
cond_coding,
);
silk_encode_pulses(
rc,
ps_enc.s_cmn.indices.signal_type as i32,
ps_enc.s_cmn.indices.quant_offset_type as i32,
&mut ps_enc.pulses,
ps_enc.s_cmn.frame_length as usize,
);
n_bits = rc.tell();
}
if use_cbr == 0 && iter == 0 && n_bits <= max_bits {
break;
}
}
if iter == max_iter {
if found_lower && (gains_id == gains_id_lower || n_bits > max_bits) {
if let Some(rc_c2) = &rc_copy2 {
rc.restore_state(rc_c2);
let offs = rc.offs as usize;
rc.buf[frame_start_offs..offs].copy_from_slice(&ec_buf_copy);
}
if let Some(nsq_c2) = &nsq_copy2 {
ps_enc.s_nsq = *nsq_c2;
}
ps_enc.s_shape.last_gain_index = last_gain_index_copy2;
}
break;
}
if n_bits > max_bits {
if !found_lower && iter >= 2 {
s_enc_ctrl.lambda_q10 =
silk_add_rshift32(s_enc_ctrl.lambda_q10, s_enc_ctrl.lambda_q10, 1);
found_upper = false;
gains_id_upper = -1;
} else {
found_upper = true;
n_bits_upper = n_bits;
gain_mult_upper = gain_mult_q8;
gains_id_upper = gains_id;
}
} else if n_bits < max_bits - bits_margin {
found_lower = true;
n_bits_lower = n_bits;
gain_mult_lower = gain_mult_q8;
if gains_id != gains_id_lower {
gains_id_lower = gains_id;
rc_copy2 = Some(rc.save_state());
ec_buf_copy.clear();
ec_buf_copy.extend_from_slice(&rc.buf[frame_start_offs..rc.offs as usize]);
nsq_copy2 = Some(ps_enc.s_nsq);
last_gain_index_copy2 = ps_enc.s_shape.last_gain_index;
}
} else {
break;
}
if !found_lower && n_bits > max_bits {
let subfr_length = ps_enc.s_cmn.subfr_length as usize;
for i in 0..ps_enc.s_cmn.nb_subfr as usize {
let mut sum: i32 = 0;
for j in (i * subfr_length)..((i + 1) * subfr_length) {
sum += ps_enc.pulses[j].abs() as i32;
}
if iter == 0 || (sum < best_sum[i] && !gain_lock[i]) {
best_sum[i] = sum;
best_gain_mult[i] = gain_mult_q8;
} else {
gain_lock[i] = true;
}
}
}
if !(found_lower && found_upper) {
if n_bits > max_bits {
gain_mult_q8 = silk_min_32(1024, (gain_mult_q8 * 3) / 2);
} else {
gain_mult_q8 = silk_max_32(64, (gain_mult_q8 * 4) / 5);
}
} else {
let delta = gain_mult_upper - gain_mult_lower;
gain_mult_q8 = gain_mult_lower
+ silk_div32_16(
(gain_mult_upper - gain_mult_lower) * (max_bits - n_bits_lower),
n_bits_upper - n_bits_lower,
);
let lower_limit = silk_add_rshift32(gain_mult_lower, delta, 2);
let upper_limit = silk_sub_rshift32(gain_mult_upper, delta, 2);
if gain_mult_q8 > lower_limit {
gain_mult_q8 = lower_limit;
} else if gain_mult_q8 < upper_limit {
gain_mult_q8 = upper_limit;
}
}
for i in 0..ps_enc.s_cmn.nb_subfr as usize {
let tmp = if gain_lock[i] {
best_gain_mult[i]
} else {
gain_mult_q8
};
s_enc_ctrl.gains_q16[i] =
silk_lshift_sat32(silk_smulwb(s_enc_ctrl.gains_unq_q16[i], tmp), 8);
}
ps_enc.s_shape.last_gain_index = s_enc_ctrl.last_gain_index_prev;
silk_gains_quant(
&mut ps_enc.s_cmn.indices.gains_indices,
&mut s_enc_ctrl.gains_q16,
&mut ps_enc.s_shape.last_gain_index,
if cond_coding == CODE_CONDITIONALLY {
1
} else {
0
},
ps_enc.s_cmn.nb_subfr as usize,
);
gains_id = silk_gains_id(&ps_enc.s_cmn.indices.gains_indices, ps_enc.s_cmn.nb_subfr);
}
let move_len = ltp_mem_length + 5 * ps_enc.s_cmn.fs_khz as usize;
ps_enc
.s_cmn
.x_buf
.copy_within(frame_length..frame_length + move_len, 0);
ps_enc.s_cmn.prev_lag = s_enc_ctrl.pitch_l[ps_enc.s_cmn.nb_subfr as usize - 1];
ps_enc.s_cmn.prev_signal_type = ps_enc.s_cmn.indices.signal_type as i32;
ps_enc.s_cmn.first_frame_after_reset = 0;
*pn_bytes_out = (rc.tell() + 7) >> 3;
0
}
fn silk_lbrr_encode(
ps_enc: &mut SilkEncoderState,
s_enc_ctrl: &SilkEncoderControl,
x16_offset: usize,
cond_coding: i32,
) {
if ps_enc.s_cmn.lbrr_enabled == 0
|| ps_enc.s_cmn.speech_activity_q8 <= 77
{
return;
}
let fi = ps_enc.s_cmn.n_frames_encoded as usize;
if fi >= MAX_FRAMES_PER_PACKET {
return;
}
ps_enc.s_cmn.lbrr_flags[fi] = 1;
let mut nsq_lbrr = ps_enc.s_nsq;
let mut indices_lbrr = ps_enc.s_cmn.indices;
if fi == 0 || ps_enc.s_cmn.lbrr_flags[fi - 1] == 0 {
ps_enc.s_cmn.lbrr_prev_last_gain_index = ps_enc.s_shape.last_gain_index;
indices_lbrr.gains_indices[0] = (indices_lbrr.gains_indices[0] as i32
+ ps_enc.s_cmn.lbrr_gain_increases)
.min(N_LEVELS_QGAIN - 1) as i8;
}
let mut gains_lbrr = s_enc_ctrl.gains_q16;
silk_gains_dequant(
&mut gains_lbrr,
&indices_lbrr.gains_indices,
&mut ps_enc.s_cmn.lbrr_prev_last_gain_index,
if cond_coding == CODE_CONDITIONALLY { 1 } else { 0 },
ps_enc.s_cmn.nb_subfr as usize,
);
let mut pred_coef_q12_flat = [0i16; 2 * MAX_LPC_ORDER];
pred_coef_q12_flat[..MAX_LPC_ORDER].copy_from_slice(&s_enc_ctrl.pred_coef_q12[0]);
pred_coef_q12_flat[MAX_LPC_ORDER..].copy_from_slice(&s_enc_ctrl.pred_coef_q12[1]);
let mut pulses_lbrr = [0i8; MAX_FRAME_LENGTH];
if ps_enc.s_cmn.n_states_delayed_decision > 1 || ps_enc.s_cmn.warping_q16 > 0 {
let winner_seed = silk_nsq_del_dec(
&ps_enc.s_cmn,
&mut nsq_lbrr,
&indices_lbrr,
&ps_enc.s_cmn.x_buf[x16_offset..],
&mut pulses_lbrr,
&pred_coef_q12_flat,
&s_enc_ctrl.ltp_coef_q14,
&s_enc_ctrl.ar_q13,
&s_enc_ctrl.harm_shape_gain_q14,
&s_enc_ctrl.tilt_q14,
&s_enc_ctrl.lf_shp_q14,
&gains_lbrr,
&s_enc_ctrl.pitch_l,
s_enc_ctrl.lambda_q10,
s_enc_ctrl.ltp_scale_q14,
);
indices_lbrr.seed = winner_seed as i8;
} else {
silk_nsq(
&ps_enc.s_cmn,
&mut nsq_lbrr,
&indices_lbrr,
&ps_enc.s_cmn.x_buf[x16_offset..],
&mut pulses_lbrr,
&pred_coef_q12_flat,
&s_enc_ctrl.ltp_coef_q14,
&s_enc_ctrl.ar_q13,
&s_enc_ctrl.harm_shape_gain_q14,
&s_enc_ctrl.tilt_q14,
&s_enc_ctrl.lf_shp_q14,
&gains_lbrr,
&s_enc_ctrl.pitch_l,
s_enc_ctrl.lambda_q10,
s_enc_ctrl.ltp_scale_q14,
);
}
ps_enc.s_cmn.indices_lbrr[fi] = indices_lbrr;
ps_enc.s_cmn.pulses_lbrr[fi] = pulses_lbrr;
}
fn silk_frame_max_bits(max_bits: i32, tot_blocks: i32, frame_idx: i32) -> i32 {
let share = |num: i64, den: i64| (max_bits as i64 * num / den) as i32;
match (tot_blocks, frame_idx) {
(2, 0) => share(3, 5),
(3, 0) => share(2, 5),
(3, 1) => share(3, 4),
_ => max_bits,
}
}
fn packet_blocks(packet_length: usize, fs_khz: i32) -> i32 {
let n_blocks_of_10ms = packet_length / (fs_khz.max(1) as usize * 10);
if n_blocks_of_10ms > 1 {
(n_blocks_of_10ms >> 1).min(MAX_FRAMES_PER_PACKET) as i32
} else {
1
}
}
fn silk_frame_target_rate_bps(
ps_enc: &mut SilkEncoderState,
bit_rate: i32,
lbrr_bits: i32,
bits_so_far: i32,
) -> i32 {
let packet_size_ms = ps_enc.s_cmn.packet_size_ms;
ps_enc.n_bits_used_lbrr = if lbrr_bits < 10 {
0
} else if ps_enc.n_bits_used_lbrr < 10 {
lbrr_bits
} else {
(ps_enc.n_bits_used_lbrr + lbrr_bits) / 2
};
let n_bits = (packet_target_bits(bit_rate, packet_size_ms) - ps_enc.n_bits_used_lbrr as i64)
/ ps_enc.s_cmn.n_frames_per_packet as i64;
let mut target = n_bits * if packet_size_ms == 10 { 100 } else { 50 };
target -= reservoir_payback_bps(ps_enc.n_bits_exceeded as i64);
let n_frames_encoded = ps_enc.s_cmn.n_frames_encoded as i64;
if n_frames_encoded > 0 {
let bits_balance =
bits_so_far as i64 - ps_enc.n_bits_used_lbrr as i64 - n_bits * n_frames_encoded;
target -= reservoir_payback_bps(bits_balance);
}
limit_target_rate(target, bit_rate)
}
fn packet_target_bits(bit_rate: i32, packet_size_ms: i32) -> i64 {
bit_rate as i64 * packet_size_ms as i64 / 1000
}
fn reservoir_payback_bps(bits: i64) -> i64 {
bits * 1000 / BITRESERVOIR_DECAY_TIME_MS as i64
}
fn limit_target_rate(target: i64, bit_rate: i32) -> i32 {
target
.clamp(bit_rate.min(5000) as i64, bit_rate.max(5000) as i64)
.clamp(-TARGET_RATE_LIMIT_BPS, TARGET_RATE_LIMIT_BPS) as i32
}
const TARGET_RATE_LIMIT_BPS: i64 = 1 << 24;
fn silk_update_bit_reservoir(ps_enc: &mut SilkEncoderState, bit_rate: i32, n_bytes_out: i32) {
let target_bits = packet_target_bits(bit_rate, ps_enc.s_cmn.packet_size_ms);
ps_enc.n_bits_exceeded =
(ps_enc.n_bits_exceeded as i64 + n_bytes_out as i64 * 8 - target_bits).clamp(0, 10000) as i32;
}
fn lbrr_flags_icdf(n_frames_per_packet: i32) -> &'static [u8] {
match n_frames_per_packet {
3 => &crate::silk::tables::SILK_LBRR_FLAGS_3_ICDF[..],
_ => &crate::silk::tables::SILK_LBRR_FLAGS_2_ICDF[..],
}
}
pub fn silk_encode_packet(
mid: &mut SilkEncoderState,
mut side: Option<&mut SilkEncoderState>,
input: [&[i16]; 2],
rc: &mut RangeCoder,
target_rate_bps: i32,
max_bits: i32,
use_cbr: bool,
activity: i32,
to_mono: bool,
) -> i32 {
let Some((fs_khz, _)) = prefill_geometry(mid) else {
return SILK_ENC_FS_NOT_SUPPORTED;
};
let n_channels = 1 + side.is_some() as usize;
let transition = match side.as_deref_mut() {
Some(side) => enter_stereo(mid, side),
None => {
let transition = mid.stereo.n_channels_internal != 1;
mid.stereo.n_channels_internal = 1;
transition
}
};
let n_frames_per_packet = mid.s_cmn.n_frames_per_packet;
let frame_length = mid.s_cmn.frame_length as usize;
let packet_length = n_frames_per_packet.max(0) as usize * frame_length;
if frame_length == 0
|| frame_length > MAX_FRAME_LENGTH
|| n_frames_per_packet < 1
|| n_frames_per_packet as usize > MAX_FRAMES_PER_PACKET
|| side.as_deref().is_some_and(|side| {
side.s_cmn.fs_khz != fs_khz || side.s_cmn.frame_length as usize != frame_length
})
|| input[..n_channels].iter().any(|x| x.len() < packet_length)
{
return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
}
let tot_blocks = packet_blocks(packet_length, fs_khz);
let max_bits = max_bits.max(0);
let mut lbrr_symbols = [0i32; 2];
for (n, symbol) in lbrr_symbols.iter_mut().enumerate().take(n_channels) {
let ch = channel(mid, &mut side, n);
ch.s_cmn.n_frames_encoded = 0;
ch.s_cmn.in_dtx = ch.s_cmn.use_dtx;
if ch.s_cmn.first_frame_after_reset != 0 || transition {
ch.s_cmn.lbrr_flags = [0; MAX_FRAMES_PER_PACKET];
}
for i in 0..n_frames_per_packet as usize {
*symbol |= ch.s_cmn.lbrr_flags[i] << i;
}
ch.s_cmn.lbrr_flag = (*symbol > 0) as i8;
}
let n_flag_bits = ((n_frames_per_packet + 1) * n_channels as i32) as u32;
let mut lbrr_bits = 0i32;
for frame_idx in 0..n_frames_per_packet {
let fi = frame_idx as usize;
let offset = fi * frame_length;
let mut x = [[0i16; MAX_FRAME_LENGTH + 2]; 2];
for (buf, packet) in x.iter_mut().zip(&input[..n_channels]) {
buf[2..2 + frame_length].copy_from_slice(&packet[offset..offset + frame_length]);
}
if frame_idx == 0 {
let icdf = [(256i32 - (256i32 >> n_flag_bits)) as u8, 0u8];
rc.encode_icdf(0, &icdf, 8);
if lbrr_symbols != [0, 0] {
lbrr_bits =
encode_lbrr_section(rc, mid, side.as_deref_mut(), lbrr_symbols, n_frames_per_packet);
}
mid.s_cmn.lbrr_flags = [0; MAX_FRAMES_PER_PACKET];
if let Some(side) = side.as_deref_mut() {
side.s_cmn.lbrr_flags = [0; MAX_FRAMES_PER_PACKET];
}
}
silk_hp_variable_cutoff(&mut mid.s_cmn);
let frame_rate_bps = silk_frame_target_rate_bps(
mid,
target_rate_bps,
if frame_idx == 0 { lbrr_bits } else { 0 },
rc.tell(),
);
let mut rates = [frame_rate_bps, 0];
let side_after_mid_only = mid.stereo.prev_decode_only_middle == 1;
let [x1, x2] = &mut x;
if let Some(side) = side.as_deref_mut() {
let (mut ix, mut mid_only) = ([[0i8; 3]; 2], 0i8);
silk_stereo_lr_to_ms(
&mut mid.stereo,
x1,
x2,
&mut ix,
&mut mid_only,
&mut rates,
frame_rate_bps,
mid.s_cmn.speech_activity_q8,
to_mono,
fs_khz,
frame_length,
);
mid.stereo.pred_ix[fi] = ix;
mid.stereo.mid_only_flags[fi] = mid_only;
if mid_only == 0 {
if side_after_mid_only {
reset_side_for_coding(side);
}
silk_encode_do_vad(side, &x2[1..1 + frame_length], activity);
} else {
side.s_cmn.vad_flags[fi] = 0;
}
silk_stereo_encode_pred(rc, &ix);
if side.s_cmn.vad_flags[fi] == 0 {
silk_stereo_encode_mid_only(rc, mid_only);
}
} else {
x1[..2].copy_from_slice(&mid.stereo.s_mid);
mid.stereo.s_mid.copy_from_slice(&x1[frame_length..frame_length + 2]);
}
silk_encode_do_vad(mid, &x1[1..1 + frame_length], activity);
for (n, buf) in x.iter_mut().enumerate().take(n_channels) {
let ch = channel(mid, &mut side, n);
let mut channel_max_bits = silk_frame_max_bits(max_bits, tot_blocks, frame_idx);
let mut channel_use_cbr = use_cbr && frame_idx == n_frames_per_packet - 1;
if n == 0 && rates[1] > 0 {
channel_use_cbr = false;
channel_max_bits -= max_bits / (tot_blocks * 2);
}
if rates[n] > 0 {
silk_control_snr(&mut ch.s_cmn, rates[n]);
let cond_coding = if frame_idx == 0 {
CODE_INDEPENDENTLY
} else if n == 1 && side_after_mid_only {
CODE_INDEPENDENTLY_NO_LTP_SCALING
} else {
CODE_CONDITIONALLY
};
silk_lp_variable_cutoff(&mut ch.s_cmn.s_lp, &mut buf[1..], frame_length);
let mut frame_bytes = 0i32;
let ret = silk_encode_frame(
ch,
&buf[1..1 + frame_length],
rc,
&mut frame_bytes,
cond_coding,
channel_max_bits,
channel_use_cbr as i32,
);
if ret != 0 {
return ret;
}
}
ch.s_cmn.n_frames_encoded += 1;
}
mid.stereo.prev_decode_only_middle = mid.stereo.mid_only_flags[fi] as i32;
}
let mut flags = 0u32;
for n in 0..n_channels {
let ch = channel(mid, &mut side, n);
for i in 0..n_frames_per_packet as usize {
flags = (flags << 1) | ch.s_cmn.vad_flags[i] as u32;
}
flags = (flags << 1) | ch.s_cmn.lbrr_flag as u32;
}
rc.patch_initial_bits(flags, n_flag_bits);
let n_bytes_out = if silk_packet_in_dtx(mid, side.as_deref()) {
0
} else {
(rc.tell() + 7) >> 3
};
silk_update_bit_reservoir(mid, target_rate_bps, n_bytes_out);
mid.stereo.n_prev_channels_internal = n_channels as i32;
SILK_NO_ERROR
}
pub fn silk_packet_in_dtx(mid: &SilkEncoderState, side: Option<&SilkEncoderState>) -> bool {
mid.s_cmn.in_dtx != 0 && side.is_none_or(|side| side.s_cmn.in_dtx != 0)
}
fn channel<'a>(
mid: &'a mut SilkEncoderState,
side: &'a mut Option<&mut SilkEncoderState>,
n: usize,
) -> &'a mut SilkEncoderState {
match (n, side) {
(1, Some(side)) => side,
_ => mid,
}
}
pub use crate::silk::control_codec::SILK_ENC_FS_NOT_SUPPORTED;
pub fn silk_downmix_stereo(stereo: &[i16], mono: &mut [i16]) {
let n = mono.len().min(stereo.len() / 2);
for i in 0..n {
mono[i] = silk_rshift_round(stereo[2 * i] as i32 + stereo[2 * i + 1] as i32, 1) as i16;
}
}
pub fn silk_downmix_stereo_float(stereo: &[f32], mono: &mut [i16]) {
for (m, &[left, right]) in mono.iter_mut().zip(stereo.as_chunks::<2>().0) {
*m = silk_rshift_round(float2int16(left + right) as i32, 1) as i16;
}
}
pub fn silk_average_first_mono_frame(
side_resampler: &mut SilkResampler,
mono_frame: &mut [i16],
mono_api: &[i16],
) -> i32 {
let mut other = [0i16; MAX_FRAME_LENGTH];
let n = mono_frame.len().min(MAX_FRAME_LENGTH);
let ret = side_resampler.process(&mut other[..n], mono_api, mono_api.len() as i32);
for (a, &b) in mono_frame.iter_mut().zip(&other[..n]) {
*a = silk_rshift(*a as i32 + b as i32, 1) as i16;
}
ret
}
fn silk_mono_to_stereo(mid: &mut SilkEncoderState, side: &mut SilkEncoderState) -> i32 {
let mut ret = silk_init_encoder(side, 0);
mid.stereo.pred_prev_q13 = [0; 2];
mid.stereo.s_side = [0; 2];
mid.stereo.mid_side_amp_q0 = [0, 1, 0, 1];
mid.stereo.width_prev_q14 = 0;
mid.stereo.smth_width_q14 = 1 << 14;
ret += silk_control_encoder(
side,
mid.s_cmn.fs_khz,
mid.s_cmn.packet_size_ms,
mid.s_cmn.target_rate_bps,
mid.s_cmn.complexity,
);
side.s_cmn.use_cbr = mid.s_cmn.use_cbr;
side.s_cmn.use_dtx = mid.s_cmn.use_dtx;
side.s_cmn.packet_loss_perc = mid.s_cmn.packet_loss_perc;
ret += silk_setup_lbrr(side, mid.s_cmn.lbrr_enabled);
ret
}
fn enter_stereo(mid: &mut SilkEncoderState, side: &mut SilkEncoderState) -> bool {
let transition = mid.stereo.n_channels_internal != 2;
if mid.stereo.n_channels_internal < 2 {
silk_mono_to_stereo(mid, side);
}
mid.stereo.n_channels_internal = 2;
transition
}
fn encode_lbrr_section(
rc: &mut RangeCoder,
mid: &mut SilkEncoderState,
mut side: Option<&mut SilkEncoderState>,
lbrr_symbols: [i32; 2],
n_frames_per_packet: i32,
) -> i32 {
let start_bits = rc.tell();
if n_frames_per_packet > 1 {
for symbol in lbrr_symbols.into_iter().filter(|&s| s > 0) {
rc.encode_icdf(symbol - 1, lbrr_flags_icdf(n_frames_per_packet), 8);
}
}
for i in 0..n_frames_per_packet as usize {
if mid.s_cmn.lbrr_flags[i] != 0 {
if let Some(side) = side.as_deref() {
silk_stereo_encode_pred(rc, &mid.stereo.pred_ix[i]);
if side.s_cmn.lbrr_flags[i] == 0 {
silk_stereo_encode_mid_only(rc, mid.stereo.mid_only_flags[i]);
}
}
encode_lbrr_frame(rc, mid, i);
}
if let Some(side) = side.as_deref_mut()
&& side.s_cmn.lbrr_flags[i] != 0
{
encode_lbrr_frame(rc, side, i);
}
}
rc.tell() - start_bits
}
fn encode_lbrr_frame(rc: &mut RangeCoder, ch: &mut SilkEncoderState, i: usize) {
let cond_coding = if i > 0 && ch.s_cmn.lbrr_flags[i - 1] != 0 {
CODE_CONDITIONALLY
} else {
CODE_INDEPENDENTLY
};
silk_encode_indices(ch, rc, i, true, cond_coding);
silk_encode_pulses(
rc,
ch.s_cmn.indices_lbrr[i].signal_type as i32,
ch.s_cmn.indices_lbrr[i].quant_offset_type as i32,
&mut ch.s_cmn.pulses_lbrr[i],
ch.s_cmn.frame_length as usize,
);
}
fn reset_side_for_coding(side: &mut SilkEncoderState) {
side.s_shape = SilkShapeState::default();
side.s_nsq = SilkNSQState::default();
side.s_cmn.prev_nlsf_q15 = [0; MAX_LPC_ORDER];
side.s_cmn.s_lp.in_lp_state = [0; 2];
side.s_cmn.prev_lag = 100;
side.s_nsq.lag_prev = 100;
side.s_shape.last_gain_index = 10;
side.s_cmn.prev_signal_type = TYPE_NO_VOICE_ACTIVITY;
side.s_nsq.prev_gain_q16 = 65536;
side.s_cmn.first_frame_after_reset = 1;
}
fn silk_carry_history_to_rate(
enc: &mut SilkEncoderState,
resampler: &mut SilkResampler,
api_hz: i32,
new_khz: i32,
) -> Result<(), Error> {
let old_khz = enc.s_cmn.fs_khz;
let buf_length_ms = ((enc.s_cmn.nb_subfr * 5) << 1) + LA_SHAPE_MS as i32;
let old_n = (buf_length_ms * old_khz) as usize;
let new_n = (buf_length_ms * new_khz) as usize;
let api_n = (buf_length_ms * (api_hz / 1000)) as usize;
let mut at_api_rate = [0i16; 45 * 48];
let mut at_new_rate = [0i16; 45 * 16];
if old_n > enc.s_cmn.x_buf.len() || api_n > at_api_rate.len() || new_n > at_new_rate.len() {
return Err(Error::internal("unsupported SILK rate switch"));
}
let mut to_api = SilkResampler::default();
if to_api.init(old_khz * 1000, api_hz) != 0
|| to_api.process(&mut at_api_rate[..api_n], &enc.s_cmn.x_buf[..old_n], old_n as i32) != 0
|| resampler.init_for_enc(api_hz, new_khz * 1000) != 0
|| resampler.process(&mut at_new_rate[..new_n], &at_api_rate[..api_n], api_n as i32) != 0
{
return Err(Error::internal("unsupported SILK rate switch"));
}
enc.s_cmn.x_buf[..new_n].copy_from_slice(&at_new_rate[..new_n]);
Ok(())
}
const MAX_PACKET_SAMPLES: usize = MAX_FRAMES_PER_PACKET * MAX_FRAME_LENGTH;
const MAX_API_SAMPLES: usize = 2880;
#[cfg(all(feature = "heap", not(feature = "std")))]
use alloc::boxed::Box;
#[cfg(feature = "heap")]
type Slot<T> = Box<T>;
#[cfg(not(feature = "heap"))]
type Slot<T> = Inline<T>;
#[cfg(not(feature = "heap"))]
struct Inline<T>(T);
#[cfg(not(feature = "heap"))]
impl<T> core::ops::Deref for Inline<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
#[cfg(not(feature = "heap"))]
impl<T> core::ops::DerefMut for Inline<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
unsafe fn write_slot<T>(this: *mut Slot<T>, memory: HeapMemory, init: impl FnOnce(*mut T)) {
#[cfg(feature = "heap")]
unsafe {
crate::in_place::write_box(this, memory, init)
}
#[cfg(not(feature = "heap"))]
unsafe {
let _ = memory;
init(&raw mut (*this).0)
}
}
#[cfg(feature = "heap")]
type SideSlot = Option<Box<SilkChannel>>;
#[cfg(not(feature = "heap"))]
type SideSlot = InlineSide;
#[cfg(not(feature = "heap"))]
struct InlineSide {
stereo: bool,
ch: SilkChannel,
}
#[cfg(not(feature = "heap"))]
impl InlineSide {
fn is_some(&self) -> bool {
self.stereo
}
fn as_deref(&self) -> Option<&SilkChannel> {
self.stereo.then_some(&self.ch)
}
fn as_deref_mut(&mut self) -> Option<&mut SilkChannel> {
if self.stereo { Some(&mut self.ch) } else { None }
}
}
#[derive(Clone, Copy)]
pub enum SilkInput<'a> {
Int16(&'a [i16]),
Float(&'a [f32]),
}
impl SilkInput<'_> {
fn len(&self) -> usize {
match self {
SilkInput::Int16(x) => x.len(),
SilkInput::Float(x) => x.len(),
}
}
}
#[derive(Clone, Copy)]
pub struct SilkPrefill<'a> {
pub rate_switch: bool,
pub input: Option<SilkInput<'a>>,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct SilkControl {
pub channels_internal: usize,
pub payload_size_ms: i32,
pub min_khz: i32,
pub max_khz: i32,
pub desired_khz: i32,
pub bit_rate: i32,
pub max_bits: i32,
pub use_cbr: bool,
pub complexity: i32,
pub packet_loss_perc: i32,
pub lbrr_coded: bool,
pub activity: i32,
pub use_dtx: bool,
pub to_mono: bool,
pub reduced_dependency: bool,
pub opus_can_switch: bool,
pub fixed_point_res_nrg: bool,
pub allow_bandwidth_switch: bool,
pub internal_khz: i32,
pub switch_ready: bool,
pub in_wb_mode_without_variable_lp: bool,
pub stereo_width_q14: i32,
pub zero_bytes: bool,
}
struct SilkChannel {
state: SilkEncoderState,
resampler: SilkResampler,
x: [i16; MAX_PACKET_SAMPLES],
}
impl SilkChannel {
unsafe fn write_new(this: *mut Self) {
unsafe {
write_fields!(this, {
state = |p: *mut SilkEncoderState| {
p.write(SilkEncoderState::default());
silk_init_encoder(&mut *p, 0);
},
resampler: SilkResampler::default(),
x = |p| write_zero(p),
});
}
}
}
pub struct SilkEncoder {
api_hz: i32,
mid: Slot<SilkChannel>,
side: SideSlot,
api_buf: Slot<[i16; MAX_API_SAMPLES]>,
initialized: bool,
time_since_switch_allowed_ms: i32,
}
impl SilkEncoder {
pub fn new(api_hz: i32, api_channels: usize) -> Self {
let mut enc = core::mem::MaybeUninit::<Self>::uninit();
unsafe {
Self::write_new(enc.as_mut_ptr(), api_hz, api_channels, HeapMemory::Allocate);
enc.assume_init()
}
}
pub(crate) unsafe fn write_new(this: *mut Self, api_hz: i32, api_channels: usize, memory: HeapMemory) {
let stereo = api_channels == 2;
unsafe {
write_fields!(this, {
api_hz: api_hz,
mid = |p| write_slot(p, memory, |q| SilkChannel::write_new(q)),
#[cfg(feature = "heap")]
side = |p: *mut SideSlot| {
if memory == HeapMemory::Reuse {
if let (true, Some(side)) = (stereo, &mut *p) {
return SilkChannel::write_new(&raw mut **side);
}
core::ptr::drop_in_place(p);
}
p.write(stereo.then(|| crate::in_place::boxed(|q| SilkChannel::write_new(q))))
},
#[cfg(not(feature = "heap"))]
side = |p: *mut InlineSide| {
(&raw mut (*p).stereo).write(stereo);
SilkChannel::write_new(&raw mut (*p).ch)
},
api_buf = |p| write_slot(p, memory, |q| write_zero(q)),
initialized: false,
time_since_switch_allowed_ms: 0,
});
}
}
pub fn reset(&mut self) {
for ch in core::iter::once(&mut *self.mid).chain(self.side.as_deref_mut()) {
ch.state = SilkEncoderState::default();
silk_init_encoder(&mut ch.state, 0);
}
self.time_since_switch_allowed_ms = 0;
}
pub fn mid(&self) -> &SilkEncoderState {
&self.mid.state
}
pub fn mid_mut(&mut self) -> &mut SilkEncoderState {
&mut self.mid.state
}
pub fn side(&self) -> Option<&SilkEncoderState> {
self.side.as_deref().map(|ch| &ch.state)
}
pub fn encode(
&mut self,
ctl: &mut SilkControl,
input: SilkInput<'_>,
prefill: Option<SilkPrefill<'_>>,
rc: &mut RangeCoder,
) -> Result<(), Error> {
let sch = if ctl.channels_internal == 2 && self.side.is_some() { 2 } else { 1 };
let restarting = prefill.is_some_and(|p| !p.rate_switch);
let fs_khz = self.control_audio_bandwidth(ctl, sch, restarting);
if let Some(p) = prefill {
let mut lp = self.mid.state.s_cmn.s_lp;
lp.saved_fs_khz = self.mid.state.s_cmn.fs_khz;
for ch in self.coded_channels(sch) {
silk_init_encoder(&mut ch.state, 0);
if p.rate_switch {
ch.state.s_cmn.s_lp = lp;
}
}
self.initialized = false;
}
let new_rate = !self.initialized || self.mid.state.s_cmn.fs_khz != fs_khz;
let running_switch = self.initialized && new_rate;
if running_switch {
let mid = &mut *self.mid;
silk_carry_history_to_rate(&mut mid.state, &mut mid.resampler, self.api_hz, fs_khz)?;
if sch == 2
&& mid.state.stereo.n_channels_internal == 2
&& let Some(side) = self.side.as_deref_mut()
{
silk_carry_history_to_rate(&mut side.state, &mut side.resampler, self.api_hz, fs_khz)?;
}
}
let new_packet_size = self.mid.state.s_cmn.packet_size_ms != ctl.payload_size_ms;
for ch in self.coded_channels(sch) {
let ret = silk_control_encoder(
&mut ch.state,
fs_khz,
ctl.payload_size_ms,
ctl.bit_rate,
ctl.complexity,
);
if ret != 0 {
return Err(Error::internal("SILK cannot code this rate or packet duration"));
}
ch.state.s_cmn.use_cbr = ctl.use_cbr as i32;
ch.state.s_cmn.use_dtx = ctl.use_dtx as i32;
if new_rate || new_packet_size {
ch.state.s_cmn.lbrr_flags = [0; MAX_FRAMES_PER_PACKET];
}
}
if new_rate && !running_switch {
if self.mid.resampler.init_for_enc(self.api_hz, fs_khz * 1000) != 0 {
return Err(Error::internal("unsupported SILK resampling ratio"));
}
if let Some(side) = self.side.as_deref_mut() {
side.resampler = self.mid.resampler.clone();
}
}
self.initialized = true;
if let Some(p) = prefill {
self.setup_fec(ctl, sch);
if let Some(prefill_input) = p.input {
let n = self.resample(prefill_input, sch, usize::MAX)?;
let (mid, side, x) = self.coded_packet(sch, n);
silk_encode_prefill(mid, side, x, ctl.bit_rate, ctl.activity);
}
}
self.setup_fec(ctl, sch);
let first_frame = self.mid.state.s_cmn.frame_length.max(0) as usize;
let n = self.resample(input, sch, first_frame)?;
if ctl.reduced_dependency {
for ch in self.coded_channels(2) {
ch.state.s_cmn.first_frame_after_reset = 1;
}
}
for ch in core::iter::once(&mut *self.mid).chain(self.side.as_deref_mut()) {
ch.state.fixed_point_res_nrg = ctl.fixed_point_res_nrg;
}
let (mid, side, x) = self.coded_packet(sch, n);
let ret = silk_encode_packet(
mid,
side,
x,
rc,
ctl.bit_rate,
ctl.max_bits,
ctl.use_cbr,
ctl.activity,
ctl.to_mono,
);
if ret != 0 {
return Err(Error::internal("SILK encoding failed"));
}
let side = self.side.as_deref().filter(|_| sch == 2).map(|ch| &ch.state);
ctl.zero_bytes = silk_packet_in_dtx(&self.mid.state, side);
let mid = &self.mid.state;
let bar_q8 = silk_smlawb(13, 3188, self.time_since_switch_allowed_ms);
if mid.s_cmn.speech_activity_q8 < bar_q8 {
ctl.allow_bandwidth_switch = true;
self.time_since_switch_allowed_ms = 0;
} else {
ctl.allow_bandwidth_switch = false;
self.time_since_switch_allowed_ms += ctl.payload_size_ms;
}
ctl.in_wb_mode_without_variable_lp = mid.s_cmn.fs_khz == 16 && mid.s_cmn.s_lp.mode == 0;
ctl.internal_khz = fs_khz;
ctl.stereo_width_q14 = if ctl.to_mono { 0 } else { mid.stereo.smth_width_q14 as i32 };
Ok(())
}
fn coded_packet(
&mut self,
sch: usize,
n: usize,
) -> (&mut SilkEncoderState, Option<&mut SilkEncoderState>, [&[i16]; 2]) {
let mid = &mut *self.mid;
match self.side.as_deref_mut().filter(|_| sch == 2) {
Some(side) => (&mut mid.state, Some(&mut side.state), [&mid.x[..n], &side.x[..n]]),
None => (&mut mid.state, None, [&mid.x[..n], &[]]),
}
}
fn coded_channels(&mut self, sch: usize) -> impl Iterator<Item = &mut SilkChannel> {
core::iter::once(&mut *self.mid).chain(self.side.as_deref_mut()).take(sch)
}
fn control_audio_bandwidth(&mut self, ctl: &mut SilkControl, sch: usize, restarting: bool) -> i32 {
ctl.switch_ready = false;
if restarting || !self.initialized {
return ctl.desired_khz.min(self.api_hz / 1000);
}
let mut bw = SilkBandwidthControl {
api_fs_hz: self.api_hz,
max_internal_fs_hz: ctl.max_khz * 1000,
min_internal_fs_hz: ctl.min_khz * 1000,
desired_internal_fs_hz: ctl.desired_khz * 1000,
payload_size_ms: ctl.payload_size_ms,
allow_bandwidth_switch: ctl.allow_bandwidth_switch,
opus_can_switch: ctl.opus_can_switch,
max_bits: ctl.max_bits,
switch_ready: false,
};
let fs_khz = silk_control_audio_bandwidth(&mut self.mid.state.s_cmn, &mut bw);
if sch == 2
&& self.mid.state.stereo.n_channels_internal == 2
&& let Some(side) = self.side.as_deref_mut()
{
silk_control_audio_bandwidth(&mut side.state.s_cmn, &mut bw);
}
ctl.max_bits = bw.max_bits;
ctl.switch_ready = bw.switch_ready;
fs_khz
}
fn setup_fec(&mut self, ctl: &SilkControl, sch: usize) {
for ch in self.coded_channels(sch) {
ch.state.s_cmn.packet_loss_perc = ctl.packet_loss_perc.clamp(0, 100);
silk_setup_lbrr(&mut ch.state, ctl.lbrr_coded as i32);
}
}
fn resample(&mut self, input: SilkInput<'_>, sch: usize, first_frame: usize) -> Result<usize, Error> {
const FAILED: Result<usize, Error> = Err(Error::internal("SILK input resampling failed"));
let api_channels = 1 + self.side.is_some() as usize;
let frames = input.len() / api_channels;
let mid = &mut *self.mid;
let fs_khz = mid.state.s_cmn.fs_khz.max(0) as usize;
let api_khz = (self.api_hz / 1000).max(1) as usize;
let n = frames * fs_khz / api_khz;
if frames > MAX_API_SAMPLES || n > MAX_PACKET_SAMPLES {
return Err(Error::internal("SILK input longer than a packet"));
}
let api = &mut self.api_buf[..frames];
let prev_channels = mid.state.stereo.n_prev_channels_internal;
match (self.side.as_deref_mut(), sch) {
(Some(side), 1) => {
match input {
SilkInput::Int16(x) => silk_downmix_stereo(&x[..2 * frames], api),
SilkInput::Float(x) => silk_downmix_stereo_float(&x[..2 * frames], api),
}
if mid.resampler.process(&mut mid.x[..n], api, frames as i32) != 0 {
return FAILED;
}
if prev_channels == 2 {
let first = first_frame.min(n);
let first_api = first * api_khz / fs_khz.max(1);
let ret = silk_average_first_mono_frame(
&mut side.resampler,
&mut mid.x[..first],
&api[..first_api],
);
if ret != 0 {
return FAILED;
}
}
}
(Some(side), _) => {
if prev_channels == 1 {
side.resampler = mid.resampler.clone();
}
for (c, ch) in [mid, side].into_iter().enumerate() {
match input {
SilkInput::Int16(x) => {
for (dst, pair) in api.iter_mut().zip(x.as_chunks::<2>().0) {
*dst = pair[c];
}
}
SilkInput::Float(x) => {
for (dst, pair) in api.iter_mut().zip(x.as_chunks::<2>().0) {
*dst = float2int16(pair[c]);
}
}
}
if ch.resampler.process(&mut ch.x[..n], api, frames as i32) != 0 {
return FAILED;
}
}
}
(None, _) => {
let samples: &[i16] = match input {
SilkInput::Int16(x) => &x[..frames],
SilkInput::Float(x) => {
for (dst, &src) in api.iter_mut().zip(x) {
*dst = float2int16(src);
}
api
}
};
if mid.resampler.process(&mut mid.x[..n], samples, frames as i32) != 0 {
return FAILED;
}
}
}
Ok(n)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn encoder(packet_size_ms: i32, n_frames: i32, n_frames_encoded: i32) -> SilkEncoderState {
let mut enc = SilkEncoderState::default();
enc.s_cmn.packet_size_ms = packet_size_ms;
enc.s_cmn.n_frames_per_packet = n_frames;
enc.s_cmn.n_frames_encoded = n_frames_encoded;
enc
}
#[test]
fn frame_target_takes_out_the_lbrr_average() {
let mut enc = encoder(20, 1, 0);
assert_eq!(silk_frame_target_rate_bps(&mut enc, 32000, 0, 0), 32000);
assert_eq!(silk_frame_target_rate_bps(&mut enc, 32000, 200, 0), 22000);
assert_eq!(enc.n_bits_used_lbrr, 200);
assert_eq!(silk_frame_target_rate_bps(&mut enc, 32000, 100, 0), 24500);
assert_eq!(enc.n_bits_used_lbrr, 150);
assert_eq!(silk_frame_target_rate_bps(&mut enc, 32000, 9, 0), 32000);
assert_eq!(enc.n_bits_used_lbrr, 0);
}
#[test]
fn frame_target_pays_back_the_reservoir() {
let mut enc = encoder(20, 1, 0);
enc.n_bits_exceeded = 1000;
assert_eq!(silk_frame_target_rate_bps(&mut enc, 32000, 0, 0), 30000);
let mut enc = encoder(10, 1, 0);
enc.n_bits_exceeded = 1000;
assert_eq!(silk_frame_target_rate_bps(&mut enc, 32000, 0, 0), 30000);
}
#[test]
fn later_frames_count_the_lbrr_section_as_overshoot() {
let mut enc = encoder(40, 2, 0);
assert_eq!(
silk_frame_target_rate_bps(&mut enc, 32000, 200, 2 + 200),
27000
);
enc.s_cmn.n_frames_encoded = 1;
assert_eq!(silk_frame_target_rate_bps(&mut enc, 32000, 0, 742), 31796);
assert_eq!(enc.n_bits_used_lbrr, 0);
}
#[test]
fn frame_target_stays_within_5000_and_the_input_rate() {
let mut enc = encoder(20, 1, 0);
assert_eq!(silk_frame_target_rate_bps(&mut enc, 32000, 600, 0), 5000);
let mut enc = encoder(40, 2, 1);
assert_eq!(silk_frame_target_rate_bps(&mut enc, 32000, 0, 100), 32000);
let mut enc = encoder(20, 1, 0);
assert_eq!(silk_frame_target_rate_bps(&mut enc, 4000, 0, 0), 4000);
enc.n_bits_exceeded = 100;
assert_eq!(silk_frame_target_rate_bps(&mut enc, 4000, 0, 0), 4000);
}
#[test]
fn bit_reservoir_keeps_the_overshoot_within_0_and_10000() {
let mut enc = encoder(20, 1, 0);
silk_update_bit_reservoir(&mut enc, 32000, 90);
assert_eq!(enc.n_bits_exceeded, 80);
silk_update_bit_reservoir(&mut enc, 32000, 70);
assert_eq!(enc.n_bits_exceeded, 0);
silk_update_bit_reservoir(&mut enc, 32000, 70);
assert_eq!(enc.n_bits_exceeded, 0, "an undershoot isn't banked");
enc.n_bits_exceeded = 9900;
silk_update_bit_reservoir(&mut enc, 32000, 200);
assert_eq!(enc.n_bits_exceeded, 10000);
}
}