use crate::silk::define::*;
use crate::silk::macros::{silk_fix_const, silk_smulwb};
use crate::silk::structs::*;
use crate::silk::tables_nlsf::*;
pub const FIND_PITCH_LPC_WIN_MS: i32 = 20 + (LA_PITCH_MS as i32 * 2);
pub const FIND_PITCH_LPC_WIN_MS_2_SF: i32 = 10 + (LA_PITCH_MS as i32 * 2);
pub const MAX_DEL_DEC_STATES: i32 = 4;
pub const LA_SHAPE_MAX: i32 = LA_SHAPE_MS as i32 * MAX_FS_KHZ as i32;
pub const SHAPE_LPC_WIN_MAX: i32 = 15 * MAX_FS_KHZ as i32;
pub const WARPING_MULTIPLIER_Q16: i32 = 983;
pub fn silk_setup_fs(ps_enc: &mut SilkEncoderState, fs_khz: i32, packet_size_ms: i32) -> i32 {
if fs_khz != 8 && fs_khz != 12 && fs_khz != 16 {
return SILK_ENC_FS_NOT_SUPPORTED;
}
if !matches!(packet_size_ms, 10 | 20 | 40 | 60) {
return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
}
let cmn = &mut ps_enc.s_cmn;
if packet_size_ms <= 10 {
cmn.n_frames_per_packet = 1;
cmn.nb_subfr = if packet_size_ms == 10 { 2 } else { 1 };
cmn.frame_length = packet_size_ms * fs_khz;
cmn.pitch_lpc_win_length = FIND_PITCH_LPC_WIN_MS_2_SF * fs_khz;
} else {
cmn.n_frames_per_packet = packet_size_ms / MAX_FRAME_LENGTH_MS as i32;
cmn.nb_subfr = MAX_NB_SUBFR as i32;
cmn.frame_length = 20 * fs_khz;
cmn.pitch_lpc_win_length = FIND_PITCH_LPC_WIN_MS * fs_khz;
}
cmn.packet_size_ms = packet_size_ms;
if cmn.fs_khz != fs_khz {
ps_enc.s_shape = SilkShapeState::default();
ps_enc.s_nsq = SilkNSQState::default();
cmn.prev_nlsf_q15 = [0; MAX_LPC_ORDER];
cmn.s_lp.in_lp_state = [0; 2];
cmn.n_frames_encoded = 0;
cmn.target_rate_bps = 0;
cmn.prev_lag = 100;
cmn.first_frame_after_reset = 1;
ps_enc.s_shape.last_gain_index = 10;
ps_enc.s_nsq.lag_prev = 100;
ps_enc.s_nsq.prev_gain_q16 = 65536;
cmn.prev_signal_type = TYPE_NO_VOICE_ACTIVITY;
cmn.fs_khz = fs_khz;
if fs_khz == 8 || fs_khz == 12 {
cmn.predict_lpc_order = MIN_LPC_ORDER as i32;
ps_enc.ps_nlsf_cb = Some(&SILK_NLSF_CB_NB_MB);
} else {
cmn.predict_lpc_order = MAX_LPC_ORDER as i32;
ps_enc.ps_nlsf_cb = Some(&SILK_NLSF_CB_WB);
}
cmn.subfr_length = SUB_FRAME_LENGTH_MS as i32 * fs_khz;
cmn.frame_length = cmn.subfr_length * cmn.nb_subfr;
cmn.ltp_mem_length = LTP_MEM_LENGTH_MS as i32 * fs_khz;
cmn.la_pitch = LA_PITCH_MS as i32 * fs_khz;
if cmn.nb_subfr == MAX_NB_SUBFR as i32 {
cmn.pitch_lpc_win_length = FIND_PITCH_LPC_WIN_MS * fs_khz;
} else {
cmn.pitch_lpc_win_length = FIND_PITCH_LPC_WIN_MS_2_SF * fs_khz;
}
}
SILK_NO_ERROR
}
pub fn silk_setup_complexity(ps_enc: &mut SilkEncoderState, complexity: i32) -> i32 {
let cmn = &mut ps_enc.s_cmn;
if complexity < 1 {
cmn.pitch_estimation_complexity = SILK_PE_MIN_COMPLEX as i32;
cmn.pitch_estimation_threshold_q16 = silk_fix_const(0.8, 16);
ps_enc.pitch_estimation_lpc_order = 6;
cmn.shaping_lpc_order = 12;
cmn.la_shape = 3 * cmn.fs_khz;
cmn.n_states_delayed_decision = 1;
cmn.use_interpolated_nlsfs = 0;
cmn.n_nlsf_survivors = 2;
cmn.warping_q16 = 0;
} else if complexity < 2 {
cmn.pitch_estimation_complexity = SILK_PE_MID_COMPLEX as i32;
cmn.pitch_estimation_threshold_q16 = silk_fix_const(0.76, 16);
ps_enc.pitch_estimation_lpc_order = 8;
cmn.shaping_lpc_order = 14;
cmn.la_shape = 5 * cmn.fs_khz;
cmn.n_states_delayed_decision = 1;
cmn.use_interpolated_nlsfs = 0;
cmn.n_nlsf_survivors = 3;
cmn.warping_q16 = 0;
} else if complexity < 3 {
cmn.pitch_estimation_complexity = SILK_PE_MIN_COMPLEX as i32;
cmn.pitch_estimation_threshold_q16 = silk_fix_const(0.8, 16);
ps_enc.pitch_estimation_lpc_order = 6;
cmn.shaping_lpc_order = 12;
cmn.la_shape = 3 * cmn.fs_khz;
cmn.n_states_delayed_decision = 2;
cmn.use_interpolated_nlsfs = 0;
cmn.n_nlsf_survivors = 2;
cmn.warping_q16 = 0;
} else if complexity < 4 {
cmn.pitch_estimation_complexity = SILK_PE_MID_COMPLEX as i32;
cmn.pitch_estimation_threshold_q16 = silk_fix_const(0.76, 16);
ps_enc.pitch_estimation_lpc_order = 8;
cmn.shaping_lpc_order = 14;
cmn.la_shape = 5 * cmn.fs_khz;
cmn.n_states_delayed_decision = 2;
cmn.use_interpolated_nlsfs = 0;
cmn.n_nlsf_survivors = 4;
cmn.warping_q16 = 0;
} else if complexity < 6 {
cmn.pitch_estimation_complexity = SILK_PE_MID_COMPLEX as i32;
cmn.pitch_estimation_threshold_q16 = silk_fix_const(0.74, 16);
ps_enc.pitch_estimation_lpc_order = 10;
cmn.shaping_lpc_order = 16;
cmn.la_shape = 5 * cmn.fs_khz;
cmn.n_states_delayed_decision = 2;
cmn.use_interpolated_nlsfs = 1;
cmn.n_nlsf_survivors = 6;
cmn.warping_q16 = cmn.fs_khz * WARPING_MULTIPLIER_Q16;
} else if complexity < 8 {
cmn.pitch_estimation_complexity = SILK_PE_MID_COMPLEX as i32;
cmn.pitch_estimation_threshold_q16 = silk_fix_const(0.72, 16);
ps_enc.pitch_estimation_lpc_order = 12;
cmn.shaping_lpc_order = 20;
cmn.la_shape = 5 * cmn.fs_khz;
cmn.n_states_delayed_decision = 3;
cmn.use_interpolated_nlsfs = 1;
cmn.n_nlsf_survivors = 8;
cmn.warping_q16 = cmn.fs_khz * WARPING_MULTIPLIER_Q16;
} else {
cmn.pitch_estimation_complexity = SILK_PE_MAX_COMPLEX as i32;
cmn.pitch_estimation_threshold_q16 = silk_fix_const(0.7, 16);
ps_enc.pitch_estimation_lpc_order = 16;
cmn.shaping_lpc_order = 24;
cmn.la_shape = 5 * cmn.fs_khz;
cmn.n_states_delayed_decision = MAX_DEL_DEC_STATES;
cmn.use_interpolated_nlsfs = 1;
cmn.n_nlsf_survivors = 16;
cmn.warping_q16 = cmn.fs_khz * WARPING_MULTIPLIER_Q16;
}
ps_enc.pitch_estimation_lpc_order =
ps_enc.pitch_estimation_lpc_order.min(cmn.predict_lpc_order);
cmn.shape_win_length = SUB_FRAME_LENGTH_MS as i32 * cmn.fs_khz + 2 * cmn.la_shape;
cmn.complexity = complexity;
SILK_NO_ERROR
}
pub fn silk_control_encoder(
ps_enc: &mut SilkEncoderState,
fs_khz: i32,
packet_size_ms: i32,
target_rate_bps: i32,
complexity: i32,
) -> i32 {
let mut ret = silk_setup_fs(ps_enc, fs_khz, packet_size_ms);
if ret != SILK_NO_ERROR {
return ret;
}
ret += silk_setup_complexity(ps_enc, complexity);
ps_enc.s_cmn.target_rate_bps = target_rate_bps;
ret
}
pub fn silk_setup_lbrr(ps_enc: &mut SilkEncoderState, lbrr_coded: i32) -> i32 {
let lbrr_in_previous_packet = ps_enc.s_cmn.lbrr_enabled;
ps_enc.s_cmn.lbrr_enabled = lbrr_coded;
if ps_enc.s_cmn.lbrr_enabled != 0 {
if lbrr_in_previous_packet == 0 {
ps_enc.s_cmn.lbrr_gain_increases = 7;
} else {
ps_enc.s_cmn.lbrr_gain_increases =
(7 - silk_smulwb(ps_enc.s_cmn.packet_loss_perc, silk_fix_const(0.2, 16))).max(3);
}
}
SILK_NO_ERROR
}
pub const SILK_ENC_FS_NOT_SUPPORTED: i32 = -102;
pub const SILK_ENC_PACKET_SIZE_NOT_SUPPORTED: i32 = -103;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SilkBandwidthControl {
pub api_fs_hz: i32,
pub max_internal_fs_hz: i32,
pub min_internal_fs_hz: i32,
pub desired_internal_fs_hz: i32,
pub payload_size_ms: i32,
pub allow_bandwidth_switch: bool,
pub opus_can_switch: bool,
pub max_bits: i32,
pub switch_ready: bool,
}
fn make_room_for_redundancy(ctl: &mut SilkBandwidthControl) {
if ctl.payload_size_ms >= 0 {
let share = ctl.max_bits as i64 * 5 / (ctl.payload_size_ms as i64 + 5);
ctl.max_bits -= share as i32;
}
}
pub fn silk_control_audio_bandwidth(
ps_enc_c: &mut SilkEncoderStateCommon,
ctl: &mut SilkBandwidthControl,
) -> i32 {
let mut orig_khz = ps_enc_c.fs_khz;
if orig_khz == 0 {
orig_khz = ps_enc_c.s_lp.saved_fs_khz;
}
let mut fs_khz = orig_khz;
let mut fs_hz = fs_khz.saturating_mul(1000);
let orig_hz = fs_hz;
let lp = &mut ps_enc_c.s_lp;
if fs_hz == 0 {
fs_hz = ctl.desired_internal_fs_hz.min(ctl.api_fs_hz);
fs_khz = fs_hz / 1000;
} else if fs_hz > ctl.api_fs_hz
|| fs_hz > ctl.max_internal_fs_hz
|| fs_hz < ctl.min_internal_fs_hz
{
fs_hz = ctl.api_fs_hz;
fs_hz = fs_hz.min(ctl.max_internal_fs_hz);
fs_hz = fs_hz.max(ctl.min_internal_fs_hz);
fs_khz = fs_hz / 1000;
} else {
if lp.transition_frame_no >= TRANSITION_FRAMES {
lp.mode = 0;
}
if ctl.allow_bandwidth_switch || ctl.opus_can_switch {
if orig_hz > ctl.desired_internal_fs_hz {
if lp.mode == 0 {
lp.transition_frame_no = TRANSITION_FRAMES;
lp.in_lp_state = [0; 2];
}
if ctl.opus_can_switch {
lp.mode = 0;
fs_khz = if orig_khz == 16 { 12 } else { 8 };
} else if lp.transition_frame_no <= 0 {
ctl.switch_ready = true;
make_room_for_redundancy(ctl);
} else {
lp.mode = -2;
}
} else if orig_hz < ctl.desired_internal_fs_hz {
if ctl.opus_can_switch {
fs_khz = if orig_khz == 8 { 12 } else { 16 };
lp.transition_frame_no = 0;
lp.in_lp_state = [0; 2];
lp.mode = 1;
} else if lp.mode == 0 {
ctl.switch_ready = true;
make_room_for_redundancy(ctl);
} else {
lp.mode = 1;
}
} else if lp.mode < 0 {
lp.mode = 1;
}
}
}
fs_khz
}