use crate::bitstream::{self, FIELDS, Params};
use crate::codebook;
use crate::convolve::filter;
use crate::excitation::{cap_gain, carry_gain, excite, interpolation_gains, update_memories};
use crate::fixed::acc;
use crate::frontend::Frontend;
use crate::gain::{GainState, MEASURES as GAIN_MEASURES, align, search as gain_search};
use crate::lpc::{ANALYSIS, autocorrelate, lag_window, levinson, line_spectrum, split_polynomials};
use crate::lsf_weight::{quantise, weights};
use crate::lsp::{self, LsfIndices, LsfState, Quantiser};
use crate::mode::Mode;
use crate::pitch;
use crate::pitch_search::{
MAX_CLOSED_LOOP_DISTANCE, SEARCH_SPAN, Scaled, adaptive_gain, best_closed_lag, cross,
first as first_window, interpolate, lag_correlations_into, measures, open_loop_lag, periodic,
prescale, search_range, track_peak,
};
use crate::postfilter::inverse_filter;
use crate::pulses;
use crate::shaping::HOP;
use crate::synth::synthesis;
use crate::weight_lpc::{Sharpness, expand, midpoint};
use crate::weighting::{Highpass, Smooth, Tilt};
use crate::{FRAME, HALF, LPC_ORDER as ORDER};
const REACH: usize = ANALYSIS - 2 * HALF;
const HISTORY: usize = CARRY + HOP;
const CARRY: usize = SUB;
const WINDOW: usize = 40;
use crate::SUBFRAME as SUB;
const FLAT: [i16; ORDER] = [
31441, 27568, 21460, 13612, 4663, -4663, -13612, -21460, -27568, -31441,
];
#[derive(Default)]
struct Shaping {
highpass: Highpass,
smooth: Smooth,
tilt: Tilt,
}
impl Shaping {
fn run(&mut self, block: &mut [i16]) {
self.highpass.run(block);
self.smooth.run(block);
self.tilt.run(block);
}
}
pub struct Encoder {
frontend: Frontend,
shaping: Shaping,
tail: [i16; REACH],
lsf: LsfState,
interpolating: bool,
previous: [i16; ORDER],
interpolated: [i16; ORDER],
last_half: [i16; ORDER],
subframe_lsp: [[[i16; ORDER]; 2]; 2],
subframe_lsf: [[[i16; ORDER]; 2]; 2],
reflection: [i16; 2],
sharpness: Sharpness,
factors: [([i16; 2], [i16; 2]); 2],
weighting: [[([i16; ORDER + 1], [i16; ORDER + 1]); 2]; 2],
history: [i16; HISTORY],
weighting_memory: [i16; ORDER],
search: [i16; SEARCH_SPAN],
impulse: [[[i16; SUB]; 2]; 2],
decoded_lpc: [i16; ORDER + 1],
decoded_previous: [i16; ORDER],
decoded_last_half: [i16; ORDER],
synthesis_lpc: [[[i16; ORDER + 1]; 2]; 2],
open_loop: [i16; 2],
bracket: [(i16, i16); 2],
second_lpc: [i16; ORDER + 1],
excitation: [i16; EXCITATION],
error_memory: [i16; ORDER],
residual_memory: [i16; ORDER],
speech_memory: [i16; ORDER],
subframe_target: [[[i16; SUB]; 2]; 2],
peaks: [i64; PEAKS],
first_lag: i16,
adaptive_correlations: [i16; SUB],
extension: (i16, i16),
carried_gain: i16,
previous_lag: i16,
half_lag: i16,
mode: Mode,
quantiser: Quantiser,
gain_state: GainState,
weighting_lpc: [[[i16; ORDER + 1]; 2]; 2],
field: [i16; FIELDS],
}
const PEAKS: usize = 4;
const LAGS_OVER: usize = 9;
const MAX_CLOSED_LOOP_LAGS: usize = MAX_CLOSED_LOOP_DISTANCE + LAGS_OVER;
const LAG_MARGIN: usize = 4;
const REACH_TAPS: usize = 40;
const COARSE_LAG: i16 = 84;
fn lag_correlation_window(sub: usize, low: i16, high: i16) -> (usize, usize) {
let lags = (high - low) as usize + LAGS_OVER;
let at = HISTORY_EXC + sub * SUB;
let start = at + LAG_MARGIN - low as usize;
(start, lags)
}
struct ClosedLoopCorrelations {
values: [i16; MAX_CLOSED_LOOP_LAGS],
len: usize,
}
impl ClosedLoopCorrelations {
fn as_slice(&self) -> &[i16] {
&self.values[..self.len]
}
}
fn filter_weighting_span(
numerator: &[i16; ORDER + 1],
denominator: &[i16; ORDER + 1],
signal: &[i16],
len: usize,
memory: [i16; ORDER],
) -> ([i16; SUB], [i16; ORDER]) {
let mut through = [0i16; SUB];
inverse_filter(numerator, signal, &mut through[..len]);
let mut out = [0i16; SUB];
let mut carried = memory;
synthesis(denominator, &through[..len], &mut out[..len], &mut carried);
(out, carried)
}
const EXCITATION: usize = HISTORY_EXC + HOP;
const HISTORY_EXC: usize = crate::EXCITATION_HISTORY;
struct SubframeSignals {
start: usize,
synthesis_filter: [i16; ORDER + 1],
target: [i16; SUB],
}
struct AdaptiveSearch {
lag: pitch::Lag,
filtered: [i16; SUB],
energy: Scaled,
correlation: Scaled,
coding: i16,
weights: usize,
}
struct AdaptiveCandidate {
filtered: [i16; SUB],
energy: Scaled,
correlation: Scaled,
gain: i16,
}
struct FixedSearch {
innovation: [i16; SUB],
filtered: [i16; SUB],
pitch_gain: i16,
code_gain: i16,
}
fn decode_innovation(index: i16, lag: &pitch::Lag, extension: (i16, i16)) -> [i16; SUB] {
let decoded = codebook::decode(index as u16);
let mut innovation = decoded.code;
if lag.integer < SUB as i16 {
let sharpen = if decoded.class == 5 || (1..3).contains(&decoded.class) {
extension.1
} else {
extension.0
};
pitch::sharpen(&mut innovation, lag, sharpen);
}
innovation
}
fn aligned_gain_measures(
adaptive: &AdaptiveSearch,
fixed: &[Scaled; 3],
gain_exponent: i16,
) -> ([i16; GAIN_MEASURES], [i16; GAIN_MEASURES]) {
let mut mantissa = [
adaptive.energy.mantissa,
adaptive.correlation.mantissa,
fixed[0].mantissa,
fixed[1].mantissa,
fixed[2].mantissa,
];
let exponent = [
adaptive.energy.exponent,
adaptive.correlation.exponent,
fixed[0].exponent,
fixed[1].exponent,
fixed[2].exponent,
];
let shifts = align(&mut mantissa, &exponent, gain_exponent);
(mantissa, shifts)
}
struct FrameAnalysis {
lsp: [i16; ORDER],
lpc: [i16; ORDER + 1],
fields: [i16; 2],
}
impl Default for Encoder {
fn default() -> Self {
Encoder {
frontend: Frontend::default(),
shaping: Shaping::default(),
tail: [0; REACH],
lsf: LsfState::default(),
interpolating: false,
previous: FLAT,
interpolated: [0; ORDER],
last_half: FLAT,
subframe_lsp: [[[0; ORDER]; 2]; 2],
subframe_lsf: [[[0; ORDER]; 2]; 2],
reflection: [0; 2],
sharpness: Sharpness::default(),
factors: [([0; 2], [0; 2]); 2],
weighting: [[([0; ORDER + 1], [0; ORDER + 1]); 2]; 2],
history: [0; HISTORY],
weighting_memory: [0; ORDER],
search: [0; SEARCH_SPAN],
impulse: [[[0; SUB]; 2]; 2],
decoded_lpc: [0; ORDER + 1],
decoded_previous: FLAT,
decoded_last_half: FLAT,
synthesis_lpc: [[[0; ORDER + 1]; 2]; 2],
open_loop: [0; 2],
bracket: [(0, 0); 2],
second_lpc: [0; ORDER + 1],
excitation: [0; EXCITATION],
error_memory: [0; ORDER],
residual_memory: [0; ORDER],
speech_memory: [0; ORDER],
subframe_target: [[[0; SUB]; 2]; 2],
peaks: [0; PEAKS],
first_lag: 0,
adaptive_correlations: [0; SUB],
extension: (0, 0),
carried_gain: 0,
previous_lag: 0,
half_lag: 0,
mode: Mode::default(),
quantiser: Quantiser::default(),
gain_state: GainState::default(),
weighting_lpc: [[[0; ORDER + 1]; 2]; 2],
field: [0; FIELDS],
}
}
}
impl Encoder {
pub fn new() -> Self {
Self::default()
}
#[doc(hidden)]
pub fn synthesis_lpc(&self) -> &[[[i16; ORDER + 1]; 2]; 2] {
&self.synthesis_lpc
}
#[doc(hidden)]
pub fn impulse(&self) -> &[[[i16; SUB]; 2]; 2] {
&self.impulse
}
#[doc(hidden)]
pub fn weighting(&self) -> &[[([i16; ORDER + 1], [i16; ORDER + 1]); 2]; 2] {
&self.weighting
}
fn shape(&mut self, frame: &[u8; FRAME]) -> [[i16; HOP]; 2] {
let linear = self.frontend.condition(frame);
let mut out = [[0i16; HOP]; 2];
for (half, signal) in out.iter_mut().enumerate() {
let mut block = [0i16; HALF];
block.copy_from_slice(&linear[half * HALF..(half + 1) * HALF]);
*signal = self.frontend.process(&block);
self.shaping.run(signal);
}
out
}
fn line_spectrum(&mut self, shaped: &[[i16; HOP]; 2]) -> ([i16; ORDER], [i16; ORDER + 1]) {
let mut window = [0i16; ANALYSIS];
window[..REACH].copy_from_slice(&self.tail);
for (half, signal) in shaped.iter().enumerate() {
let at = REACH + half * HOP;
window[at..at + HOP].copy_from_slice(signal);
}
self.tail.copy_from_slice(&shaped[1][HOP - REACH..]);
let mut correlation = autocorrelate(&window);
lag_window(&mut correlation);
let (a, k) = levinson(&correlation);
self.reflection = [k[0], k[1]];
let (sum, difference) = split_polynomials(&a);
(line_spectrum(&sum, &difference), a)
}
fn quantised_spectrum(&mut self, lsf: &[i16; ORDER]) -> ([i16; 2], [i16; ORDER], bool, bool) {
let chosen = quantise(lsf, &weights(lsf), &self.lsf.history);
let fields = chosen.fields();
let rebuilt = lsp::decode(&mut self.lsf, LsfIndices::unpack(fields.0, fields.1));
let decoded = lsp::lsf_to_lsp(&rebuilt);
self.decoded_lpc = lsp::lsp_to_lpc(&decoded);
let reflection = lsp::reflection_coefficients(&self.decoded_lpc);
let (interpolating, take_current) =
lsp::interpolation_control(&reflection, self.interpolating);
([fields.0, fields.1], decoded, interpolating, take_current)
}
fn update_analysis_spectrum(
&mut self,
lsp: [i16; ORDER],
lpc: [i16; ORDER + 1],
take_current: bool,
) {
self.interpolated = if take_current {
lsp
} else {
midpoint(&self.previous, &lsp)
};
self.second_lpc = if take_current {
lpc
} else {
lsp::lsp_to_lpc(&self.interpolated)
};
self.previous = lsp;
}
fn update_synthesis_spectrum(&mut self, decoded: [i16; ORDER], take_current: bool) {
let decoded_interpolated = if take_current {
decoded
} else {
midpoint(&self.decoded_previous, &decoded)
};
self.decoded_previous = decoded;
for (half, ¤t) in [decoded_interpolated, decoded].iter().enumerate() {
let first = midpoint(&self.decoded_last_half, ¤t);
self.synthesis_lpc[half] = [lsp::lsp_to_lpc(&first), lsp::lsp_to_lpc(¤t)];
self.decoded_last_half = current;
}
}
fn analyse_frame_spectrum(&mut self, shaped: &[[i16; HOP]; 2]) -> FrameAnalysis {
let (lsp, lpc) = self.line_spectrum(shaped);
let lsf = lsp::lsp_to_lsf(&lsp);
let (fields, decoded, interpolating, take_current) = self.quantised_spectrum(&lsf);
self.update_analysis_spectrum(lsp, lpc, take_current);
self.interpolating = interpolating;
self.update_synthesis_spectrum(decoded, take_current);
FrameAnalysis { lsp, lpc, fields }
}
fn configure_half_spectra(&mut self, half: usize, current: &[i16; ORDER]) {
let first = midpoint(&self.last_half, current);
self.subframe_lsp[half] = [first, *current];
self.subframe_lsf[half] = [lsp::lsp_to_lsf(&first), lsp::lsp_to_lsf(current)];
self.last_half = *current;
self.factors[half] = self.sharpness.choose(
&self.reflection,
&[&self.subframe_lsf[half][0], &self.subframe_lsf[half][1]],
);
}
fn weighting_source_lpc(
&self,
half: usize,
sub: usize,
analysis_lpc: &[i16; ORDER + 1],
) -> [i16; ORDER + 1] {
match (sub, half) {
(0, _) => lsp::lsp_to_lpc(&self.subframe_lsp[half][0]),
(_, 0) => self.second_lpc,
(_, _) => *analysis_lpc,
}
}
fn configure_half_filters(
&mut self,
half: usize,
current: &[i16; ORDER],
analysis_lpc: &[i16; ORDER + 1],
) {
self.configure_half_spectra(half, current);
let (numerator, denominator) = self.factors[half];
for sub in 0..2 {
let lpc = self.weighting_source_lpc(half, sub, analysis_lpc);
self.weighting[half][sub] =
(expand(&lpc, numerator[sub]), expand(&lpc, denominator[sub]));
self.weighting_lpc[half][sub] = lpc;
}
}
fn update_weighting_history(&mut self, shaped: &[i16; HOP]) {
self.history.copy_within(HISTORY - CARRY.., 0);
self.history[CARRY..].copy_from_slice(shaped);
}
fn weight_signal_pass(
&mut self,
half: usize,
pass: usize,
start: usize,
len: usize,
memory: &mut [i16; ORDER],
) {
let sub = usize::from(pass > 0);
let (numerator, denominator) = self.weighting[half][sub];
let (out, carried) = filter_weighting_span(
&numerator,
&denominator,
&self.history[start - ORDER..start + len],
len,
*memory,
);
if pass < 2 {
*memory = carried;
}
let at = SEARCH_SPAN - 2 * SUB - SUB / 2 + pass * SUB;
let room = (SEARCH_SPAN - at).min(len);
self.search[at..at + room].copy_from_slice(&out[..room]);
}
fn weight_half_signal(&mut self, half: usize, shaped: &[i16; HOP]) {
self.update_weighting_history(shaped);
let mut memory = self.weighting_memory;
for (pass, &(start, len)) in [
(CARRY - WINDOW, SUB),
(CARRY + WINDOW, SUB),
(CARRY + WINDOW + SUB, SUB / 2),
]
.iter()
.enumerate()
{
self.weight_signal_pass(half, pass, start, len, &mut memory);
}
self.weighting_memory = memory;
self.open_loop[half] = open_loop_lag(&self.search);
self.bracket[half] = search_range(self.open_loop[half]);
self.search.copy_within(HOP.., 0);
}
fn encode_half(
&mut self,
half: usize,
current_lsp: &[i16; ORDER],
analysis_lpc: &[i16; ORDER + 1],
shaped: &[i16; HOP],
) {
self.configure_half_filters(half, current_lsp, analysis_lpc);
self.weight_half_signal(half, shaped);
for sub in 0..2 {
self.subframe(half, sub);
}
self.previous_lag = self.half_lag;
self.excitation.copy_within(HOP.., 0);
}
#[doc(hidden)]
pub fn subframe_target(&self) -> &[[[i16; SUB]; 2]; 2] {
&self.subframe_target
}
fn subframe(&mut self, half: usize, sub: usize) {
let signals = self.prepare_subframe_signals(half, sub);
let adaptive = self.search_adaptive_codebook(half, sub, &signals);
let fixed = self.search_fixed_codebook(half, sub, &signals.target, &adaptive);
self.finish_subframe(sub, &signals, &adaptive, &fixed);
}
fn resynthesise_residual(
&self,
residual: &[i16; SUB],
synthesis_filter: &[i16; ORDER + 1],
) -> [i16; SUB] {
let mut resynthesised = [0i16; SUB];
let mut memory = self.error_memory;
synthesis(synthesis_filter, residual, &mut resynthesised, &mut memory);
resynthesised
}
fn weight_subframe_target(
&self,
half: usize,
sub: usize,
resynthesised: &[i16; SUB],
) -> [i16; SUB] {
let (numerator, denominator) = self.weighting[half][sub];
let mut window = [0i16; ORDER + SUB];
window[..ORDER].copy_from_slice(&self.error_memory);
window[ORDER..].copy_from_slice(resynthesised);
let mut weighted = [0i16; SUB];
inverse_filter(&numerator, &window, &mut weighted);
let mut target = [0i16; SUB];
let mut memory = self.residual_memory;
synthesis(&denominator, &weighted, &mut target, &mut memory);
target
}
fn build_subframe_target(
&mut self,
half: usize,
sub: usize,
start: usize,
synthesis_filter: &[i16; ORDER + 1],
) -> [i16; SUB] {
let mut residual = [0i16; SUB];
inverse_filter(
synthesis_filter,
&self.history[start - ORDER..start + SUB],
&mut residual,
);
let offset = sub * SUB;
self.excitation[HISTORY_EXC + offset..HISTORY_EXC + offset + SUB]
.copy_from_slice(&residual);
let resynthesised = self.resynthesise_residual(&residual, synthesis_filter);
self.weight_subframe_target(half, sub, &resynthesised)
}
fn build_subframe_impulse(
&self,
half: usize,
sub: usize,
synthesis_filter: &[i16; ORDER + 1],
) -> [i16; SUB] {
let (numerator, denominator) = self.weighting[half][sub];
let mut fed = [0i16; SUB];
fed[..ORDER + 1].copy_from_slice(&numerator);
let mut once = [0i16; SUB];
let mut rest = [0i16; ORDER];
synthesis(synthesis_filter, &fed, &mut once, &mut rest);
let mut twice = [0i16; SUB];
let mut rest = [0i16; ORDER];
synthesis(&denominator, &once, &mut twice, &mut rest);
twice
}
fn prepare_subframe_signals(&mut self, half: usize, sub: usize) -> SubframeSignals {
let offset = sub * SUB;
let start = CARRY - WINDOW + offset;
let synthesis_filter = self.synthesis_lpc[half][sub];
let target = self.build_subframe_target(half, sub, start, &synthesis_filter);
self.subframe_target[half][sub] = target;
self.impulse[half][sub] = self.build_subframe_impulse(half, sub, &synthesis_filter);
SubframeSignals {
start,
synthesis_filter,
target,
}
}
fn record_adaptive_lag(&mut self, half: usize, sub: usize, lag: &pitch::Lag) {
let field = Params::subframe_base(half, sub);
self.field[field + bitstream::LAG] = if sub == 0 {
pitch::encode_absolute(lag)
} else {
pitch::encode_relative(lag, self.first_lag)
};
if sub == 0 {
self.first_lag = lag.integer;
}
}
fn measure_adaptive_candidate(
&mut self,
half: usize,
sub: usize,
target: &[i16; SUB],
lag: &pitch::Lag,
) -> AdaptiveCandidate {
let offset = sub * SUB;
let at = HISTORY_EXC + offset;
pitch::predict(&mut self.excitation, at, lag);
let adaptive = &self.excitation[at..at + SUB];
let filtered = filter(adaptive, &self.impulse[half][sub]);
let (rounded, correlation, against) = cross(target, &filtered);
let (mut gain, energy) = adaptive_gain(&filtered, rounded, against);
cap_gain(
i16::from(periodic(lag.integer, lag.frac, &self.peaks)),
&mut gain,
);
AdaptiveCandidate {
filtered,
energy,
correlation,
gain,
}
}
fn configure_adaptive_modes(
&mut self,
half: usize,
sub: usize,
signals: &SubframeSignals,
lag: &pitch::Lag,
candidate: &AdaptiveCandidate,
) -> (i16, usize) {
let reflection = lsp::reflection_coefficients(&signals.synthesis_filter)[0];
self.extension = interpolation_gains(
reflection,
self.carried_gain,
lag.integer,
self.previous_lag,
);
let coding = self
.mode
.choose(&signals.target, &candidate.filtered, candidate.gain);
let weights = self.quantiser.choose(
&self.weighting_lpc[half][sub],
&signals.target,
&self.subframe_lsf[half][sub],
);
(coding, weights as usize)
}
fn search_adaptive_codebook(
&mut self,
half: usize,
sub: usize,
signals: &SubframeSignals,
) -> AdaptiveSearch {
let lag = self.closed_loop_lag(half, sub, &signals.target);
self.record_adaptive_lag(half, sub, &lag);
let candidate = self.measure_adaptive_candidate(half, sub, &signals.target, &lag);
let (coding, weights) = self.configure_adaptive_modes(half, sub, signals, &lag, &candidate);
AdaptiveSearch {
lag,
filtered: candidate.filtered,
energy: candidate.energy,
correlation: candidate.correlation,
coding,
weights,
}
}
fn fixed_innovation_index(
&mut self,
half: usize,
sub: usize,
target: &[i16; SUB],
adaptive: &AdaptiveSearch,
) -> i16 {
let field = Params::subframe_base(half, sub);
let chosen = pulses::search(
&pulses::Search {
target,
contribution: &adaptive.filtered,
impulse: &self.impulse[half][sub],
lag: adaptive.lag.integer,
fraction: adaptive.lag.frac,
extension: self.extension,
coding: adaptive.coding,
weights: adaptive.weights,
},
&mut self.adaptive_correlations,
);
self.field[field + bitstream::CODE] = chosen.index;
chosen.index
}
fn select_fixed_innovation(
&mut self,
half: usize,
sub: usize,
target: &[i16; SUB],
adaptive: &AdaptiveSearch,
) -> ([i16; SUB], [i16; SUB]) {
let index = self.fixed_innovation_index(half, sub, target, adaptive);
let innovation = decode_innovation(index, &adaptive.lag, self.extension);
let shaped = filter(&innovation, &self.impulse[half][sub]);
(innovation, shaped)
}
fn search_joint_gains(
&mut self,
half: usize,
sub: usize,
target: &[i16; SUB],
adaptive: &AdaptiveSearch,
innovation: &[i16; SUB],
shaped: &[i16; SUB],
) -> (i16, i16) {
let field = Params::subframe_base(half, sub);
let taken = measures(shaped, target, &adaptive.filtered);
let (scale, gain_exponent) = crate::gain::predict_code_gain(&self.gain_state, innovation);
let (mantissa, shifts) = aligned_gain_measures(adaptive, &taken, gain_exponent);
let (entry, pitch_gain, code_gain) = gain_search(scale, &mantissa, &shifts, gain_exponent);
self.field[field + bitstream::GAIN] = entry as i16;
crate::gain::decode(&mut self.gain_state, entry as i16, innovation);
self.carried_gain = carry_gain(pitch_gain);
(pitch_gain, code_gain)
}
fn search_fixed_codebook(
&mut self,
half: usize,
sub: usize,
target: &[i16; SUB],
adaptive: &AdaptiveSearch,
) -> FixedSearch {
let (innovation, shaped) = self.select_fixed_innovation(half, sub, target, adaptive);
let (pitch_gain, code_gain) =
self.search_joint_gains(half, sub, target, adaptive, &innovation, &shaped);
FixedSearch {
innovation,
filtered: shaped,
pitch_gain,
code_gain,
}
}
fn reconstruct_subframe(
&mut self,
sub: usize,
signals: &SubframeSignals,
fixed: &FixedSearch,
) -> [i16; SUB] {
let offset = sub * SUB;
let at = HISTORY_EXC + offset;
excite(
&mut self.excitation[at..at + SUB],
&fixed.innovation,
fixed.pitch_gain,
fixed.code_gain,
);
let mut reconstructed = [0i16; SUB];
synthesis(
&signals.synthesis_filter,
&self.excitation[at..at + SUB],
&mut reconstructed,
&mut self.speech_memory,
);
reconstructed
}
fn carry_subframe_memories(
&mut self,
signals: &SubframeSignals,
adaptive: &AdaptiveSearch,
fixed: &FixedSearch,
reconstructed: &[i16; SUB],
) {
let tail = SUB - ORDER;
let (error, residue) = update_memories(
&self.history[signals.start + tail..signals.start + SUB],
&reconstructed[tail..],
&signals.target[tail..],
&adaptive.filtered[tail..],
&fixed.filtered[tail..],
(fixed.pitch_gain, fixed.code_gain),
);
self.error_memory = error;
self.residual_memory = residue;
}
fn finish_subframe(
&mut self,
sub: usize,
signals: &SubframeSignals,
adaptive: &AdaptiveSearch,
fixed: &FixedSearch,
) {
let reconstructed = self.reconstruct_subframe(sub, signals, fixed);
track_peak(&mut self.peaks, adaptive.lag.integer, fixed.pitch_gain);
self.carry_subframe_memories(signals, adaptive, fixed, &reconstructed);
self.half_lag = adaptive.lag.integer;
}
fn closed_loop_bounds(&self, half: usize, sub: usize) -> (i16, i16) {
if sub == 0 {
self.bracket[half]
} else {
let window = first_window(self.first_lag, 0);
(window.low, window.high)
}
}
fn closed_loop_correlations(
&self,
half: usize,
sub: usize,
target: &[i16; SUB],
low: i16,
high: i16,
) -> ClosedLoopCorrelations {
let (start, lags) = lag_correlation_window(sub, low, high);
assert!(lags <= MAX_CLOSED_LOOP_LAGS);
let mut filtered = filter(
&self.impulse[half][sub][..REACH_TAPS],
&self.excitation[start..start + SUB],
);
let down = prescale(&mut filtered);
let mut past = [0i16; MAX_CLOSED_LOOP_LAGS];
for (offset, value) in past.iter_mut().enumerate().take(lags.saturating_sub(1)) {
*value = self.excitation[start - 1 - offset];
}
let mut correlations = ClosedLoopCorrelations {
values: [0; MAX_CLOSED_LOOP_LAGS],
len: lags,
};
lag_correlations_into(
target,
&mut filtered,
&past[..lags.saturating_sub(1)],
&self.impulse[half][sub],
down,
&mut correlations.values[..lags],
);
correlations
}
fn refine_fractional_lag(correlations: &[i16], low: i16, integer: i16) -> pitch::Lag {
let centre = LAG_MARGIN + (integer - low) as usize;
let mut best = interpolate(correlations, centre, -2);
let mut fraction = -2;
for candidate in -1..=2 {
let here = interpolate(correlations, centre, candidate);
if acc(here - best) >= 0 {
best = here;
fraction = candidate;
}
}
match fraction {
-2 => pitch::Lag {
integer: integer - 1,
frac: 1,
},
2 => pitch::Lag {
integer: integer + 1,
frac: -1,
},
_ => pitch::Lag {
integer,
frac: fraction,
},
}
}
fn closed_loop_lag(&mut self, half: usize, sub: usize, target: &[i16; SUB]) -> pitch::Lag {
let (low, high) = self.closed_loop_bounds(half, sub);
let correlations = self.closed_loop_correlations(half, sub, target, low, high);
let correlations = correlations.as_slice();
let integer = best_closed_lag(&correlations[LAG_MARGIN..], low, high);
if sub == 0 && integer > COARSE_LAG {
return pitch::Lag { integer, frac: 0 };
}
Self::refine_fractional_lag(correlations, low, integer)
}
pub fn encode(&mut self, frame: &[u8; FRAME]) -> [u8; bitstream::FRAME_BYTES] {
bitstream::to_bytes(&bitstream::pack(&self.frame(frame)))
}
pub fn frame(&mut self, frame: &[u8; FRAME]) -> Params {
let shaped = self.shape(frame);
let analysis = self.analyse_frame_spectrum(&shaped);
let half_lsp = [self.interpolated, analysis.lsp];
for (half, current_lsp) in half_lsp.iter().enumerate() {
self.encode_half(half, current_lsp, &analysis.lpc, &shaped[half]);
}
self.field[..2].copy_from_slice(&analysis.fields);
Params {
field: self.field,
suppress: false,
}
}
}