// The encoder: 160 input samples in, the nine fields of one frame out, two frames behind the input. // // Each input frame is high-passed, analysed (two windowed spectra, the per-pitch harmonic fit and YIN costs, the // pitch network) and pushed into the pitch tracker. The frame two frames back is then decided: pitch from the // tracker, the noise gate, voicing from the harmonic fit, harmonic amplitudes from the amplitude spectrum, and the // quantiser chooses gain and shape fields against the decoder's own prediction, which it tracks with a // dequantiser state of its own. #pragma once #include #include #include "dequant.h" #include "frame.h" #include "analysis.h" #include "history.h" #include "options.h" #include "pitch.h" #include "shape_quantizer.h" namespace halfrate::enc { constexpr int kEncoderDelay = 2; // Input high-pass: a second-order section (coefficients for the corner the options name). struct HighPass { float b0 = 0.0f, b1 = 0.0f, b2 = 0.0f, a1 = 0.0f, a2 = 0.0f; float x1 = 0.0f, x2 = 0.0f, y1 = 0.0f, y2 = 0.0f; float designed_hz = -1.0f; // corner the coefficients are for }; // What the band-energy rescoring of the shape candidates compares against: per harmonic its band (of the 18 // rescoring bands) and weight, and the reference energy per band. struct RescoreInput { int32_t enabled = 0; std::array band{}; std::array weight{}; std::array band_energy{}; }; struct Encoder { EncoderOptions options; bool transitions_dirty = true; // the tracker's transition costs depend on options // pitch grid (the codebook's pitch indices) std::array inverse_fundamental{}; // samples per period std::array log2_fundamental{}; std::array log2_ratio_to_lowest{}; // log2 f[0] - log2 f[i]: octaves below index 0 std::array octave_below{}; // index one octave lower (-1: none within 0.06) std::array transition{}; // tracker cost [from * 120 + to] AnalysisWindow long_window; // 256 points: pitch AnalysisWindow short_window; // 160 points: amplitudes ShapeBasis shape_basis; SignalHistory history; PitchTracker tracker; // gate float noise_floor_db = 0.0f; int32_t gate_hang = 0; // the decoder's predictor state, and what the gain choice looks ahead to core::DequantState predictor; std::array lookahead_gain{}; // expected gain targets of the next two frames int32_t lookahead_count = 0; // how many of them are set (0 or 2) // previous frame std::array previous_amplitudes{}; float previous_fundamental = 0.0f; int32_t previous_harmonic_count = 0; int32_t have_previous = 0; // previous_amplitudes hold a speech frame int32_t previous_voicing = -1; // its voicing index for the hysteresis, -1: none int32_t after_silence = 0; // the previous frame was silent int32_t low_band = 0; // the frame being voiced has a weak low band int32_t previous_unvoiced = 1; // the previous frame was unvoiced or gated HighPass highpass; // pitch network input: the last six frames' features (frame n in features[n % 6]) std::array, kNetFrames> features{}; std::array net_input{}; std::array net_output{}; // per grid pitch, this frame std::array fit_cost{}; std::array yin_cost{}; std::array pitch_cost{}; }; // Builds the tables and resets the state (the options keep their values). void encoder_init(Encoder& e); void encoder_reset(Encoder& e); // Encodes 160 samples; fields gets the frame of the input two frames back. void encode_frame(Encoder& e, const int16_t* pcm, core::FrameFields& fields); } // namespace halfrate::enc