Other
- ac4 round 306 — encoder-side aspx_hfgen_iwc_1ch/_2ch writers
- ac4 r299: multi-envelope ASPX body writers (num_env > 1) consuming the r292 packer
- ac4 round 292 — encoder-side TIME-direction ASPX envelope DPCM packing
- ac4 round 285 — real per-band β₃ for the 5_X ASPX_ACPL_3 encoder
- ac4 round 279 — decision-driven SAP-coded ASPX_ACPL_1 residual layer
- ac4 round 271 — SAP-coded alpha_q decision driver (select_alpha_q_for_pair)
- ac4 r263: build_chparam_info_none + select_ms_used_for_pair
- ac4 r260: encoder-side ChparamInfo builders — duals of extract_sap_abcd
- ac4 r257: SAP-aware ASPX_ACPL_1 residual-layer writer
- drop release-plz.toml — use release-plz defaults across the workspace
- ac4 r246: encoder-side Table-181 SAP residual extractor
- ac4 r243: encoder-side chparam_info() / sap_data() builders
- ac4 r240: encoder-side HF QMF energy aggregator (dual of Pseudocodes 90 + 91)
- ac4 r234: encoder-side ASPX envelope extractor (inverse of P82/83 + P80/81 DPCM)
- ac4 r226: write_aspx_data_{1,2}ch_real_envelope() builders
- ac4 r219: ASPX envelope value-emitting helpers (sig/noise F0/DF/DT)
- ac4 r215: real per-band γ₁ / γ₂ / γ₃ / γ₄ extraction in 5_X ASPX_ACPL_3 encoder
- ac4 r208: real per-band γ5 / γ6 extraction in 5_X ASPX_ACPL_3 encoder
- ac4 r202: real per-band α + β extraction in 7.0/7.1 ASPX_ACPL_2 encoder
- ac4 r196: real per-band α1/α2 extraction in 5_X ASPX_ACPL_3 encoder
Added
-
Round 306 — encoder-side
aspx_hfgen_iwc_1ch()/
aspx_hfgen_iwc_2ch()writers (crate::encoder_acpl3). The exact
duals of the decoder'saspx::parse_aspx_hfgen_iwc_1ch/
parse_aspx_hfgen_iwc_2ch(ETSI TS 103 190-1 §4.2.12.6 / §4.2.12.7,
Tables 55 / 56). Until now every encoder body writer emitted this
HF-generation / interleaved-waveform-coding element as the all-zero
compact form (aspx_tna_mode[*] = 0, all three presence bits 0),
even though the decoder fully parses real inverse-filtering modes,
additive harmonics (add_harmonic), frequency-interleaved coding
(fic_used_in_sfb) and time-interleaved coding (tic_used_in_slot).
Newencoder_acpl3::write_aspx_hfgen_iwc_1ch/
write_aspx_hfgen_iwc_2chtake real per-SBGtna_mode(2 b, masked
to0..=3) plus per-SBG / per-timeslot flag vectors via the public
encoder_acpl3::AspxHfgenIwc1ChPayload/
encoder_acpl3::AspxHfgenIwc2ChPayloadpayloads, and auto-derive
every gate from the payload (*_present/*_left/*_rightset
iff the slice has an active flag in range; the 2ch TIC path uses the
compactaspx_tic_copy = 1form when both channels carry the same
active pattern). Underaspx_balance = 1only channel-0tna_mode
is written (decoder mirrors it); short caller slices zero-pad. The
existingwrite_aspx_data_1ch_minimalHFGEN block is refactored to
route through the new 1ch writer with a default payload — output
stays byte-identical. Eight integration tests in
tests/round306_aspx_hfgen_iwc_writers.rspin the bit-exact
round-trip through the decoder parsers (all-zero compact form, real
flags, padding + masking, balance-mirror, distinct-tna, TIC-copy,
TIC-right-only, full multi-field stress). -
Round 292 — encoder-side TIME-direction ASPX envelope DPCM packing
(crate::encoder_acpl3). The dual of thedirection_time == true
branch of the decoder'saspx::delta_decode_sig/
aspx::delta_decode_noise(ETSI TS 103 190-1 §5.7.6.3.4 Pseudocode
80 / 81). The prior round-219/226/234/240 envelope-coding chain only
emitted the FREQ direction (freq_dpcm_encode_qscf); the decoder also
accepts a per-envelope direction flag and walks a TIME branch
reconstructingqscf[sbg][atsg] = prev[sbg] + delta·values[sbg]
(withprevthe previous envelope's row, orqscf_prev_lastfor the
first envelope). Newencoder_acpl3::time_dpcm_encode_qscfinverts it
exactly (values[sbg] = (qscf[sbg] − prev[sbg]) / delta), with
zero-extend-short-prevand±1-step semantics matching the decoder
(delta = 0treated as1for totality). New
encoder_acpl3::dpcm_encode_qscf_envelopespacks a full
qscf[sbg][atsg]matrix into per-envelope
encoder_acpl3::AspxEncodedEnvelope { values, direction_time }rows,
selecting the cheaper direction per envelope by minimising
Σ|values[sbg]|(FREQ wins ties;force_freqreproduces the legacy
single-direction scaffold). Twelve integration tests
(tests/round292_aspx_time_direction_dpcm.rs) pin the bit-exact
round-trip through bothdelta_decode_siganddelta_decode_noise,
step/totality edges, short-prevzero-extension, the min-L1 policy,
force_freqparity withfreq_dpcm_encode_qscf, and empty inputs.
Total tests 941 (was 929). -
Round 285 — real per-parameter-band β₃ extraction for the 5_X
SIMPLE/ASPX_ACPL_3 encoder (crate::encoder_acpl3+
crate::encoder_ims). Closes the round-215 "β₃ stays at the
round-95 zero-delta scaffold" deferral. Per ETSI TS 103 190-1
§5.7.7.6.2 Pseudocode 118 steps 8-10, β₃ is the gain on the third
decorrelator outputy₂; step 10 + step 11 give the centre channel
a wet contributionC_wet = −√2 · 0.5 · β₃ · y₂carrying energy
0.5 · β₃² · E[y₂²].y₂is decoder-side decorrelator state and
unobservable at encode time, but its energy is not: the
decorrelator + ducker chain is energy-preserving in steady state,
soE[y₂²] ≈ E[v₃²]with the third-Transform drive
v₃ = (γ₁+γ₃+γ₅)·x0in + (γ₂+γ₄+γ₆)·x1in(Pseudocode 118 step 2)
fully determined by the carrier spectra and the quantised γ matrix
the encoder is already emitting. New
encoder_acpl3::extract_beta3_q_per_band_centre_residualenergy-
matches that wet contribution against the per-band least-squares
remainder of the round-208 centre dry fit
E_res = Σ (C − K·(γ₅·L + γ₆·R))²(K = 1 + √(1/2), using the
quantised γ₅ / γ₆ the decoder will apply), giving the encoder
decisionβ₃ = √(2 · E_res / E[v₃²])— a non-negative magnitude,
quantised per §5.7.7.7 Table 207 (beta3_q = round(β₃ / beta3_delta)
withbeta3_delta = 0.125Fine /0.25Coarse and the symmetric
±cb_offclamp at±8/±4— half the BETA3 F0 codebook length
per the staged ETSI table file §A.3 Tables A.46 / A.47). New BETA3
value writerswrite_acpl_beta3_f0_value/write_acpl_beta3_df_value
mirror the round-208 γ writers (symbol_index = q + cb_off
addressing); a new fullacpl_data_2ch()emitter
write_acpl_data_2ch_real_alpha_beta_full_gamma_beta3lifts the β₃
entropy layer from zero-delta scaffold to real FREQ-direction DPCM
codewords. New public builder
encoder_acpl3::build_5_x_acpl3_body_from_pcm_spectra_real_alpha_beta_full_gamma_beta3
is a drop-in over the round-215 full-γ builder with an extra
beta3_scaledecision knob, and new caller-facing entry points
encoder_ims::Ac4ImsEncoder::encode_frame_pcm_5_0_acpl3_real_alpha_beta_full_gamma_beta3
/_5_1_accept[L, R, C, Ls, Rs]/[L, R, C, Ls, Rs, LFE]PCM.
beta3_scale = 0.0reproduces the round-215 byte stream exactly
(the all-zero β₃ row emits exactly the zero-delta scaffold
codewords). Four new unit tests pin the Table-207 quant grid +
clamp, the BETA3 F0/DF writer round-trip through
parse_acpl_huff_data+ Pseudocode-121 accumulation, the
zero-residual ⇒ β₃ = 0 / uncaptured-centre ⇒ β₃ > 0 decision
split, and builder byte-equality atbeta3_scale = 0. Six
integration tests (tests/round285_5_x_acpl3_real_beta3.rs) pin
5.0 → 5-channel and 5.1 → 6-channel decoder round-trips, the
decode-side recovery of the exact per-bandbeta3_qrow through
parse_5x_audio_data_outer+differential_decode, IMS
byte-equality with the round-215 entry atbeta3_scale = 0,
wire-liveness of the β₃ layer for an uncaptured centre, and
bit-determinism. Total tests 919 → 929. -
Round 279 — decision-driven SAP-coded ASPX_ACPL_1 residual layer
(crate::encoder_acpl3+crate::encoder_ims). Wires the
round-271select_alpha_q_for_pairdecision driver into the encoder
proper, per ETSI TS 103 190-1 §5.3.4.3.2 / Table 181 + §5.3.2
Pseudocode 59. New
encoder_acpl3::select_acpl1_residual_chparam_pairruns the
least-squaresalpha_qdecision per target(L, Ls)/(R, Rs)
pair over the residual layer's single-window-group
[max_sfb_master]layout — the residual layer's two
chparam_info()payloads drive two independent 2x2 SAP systems
mapping the transmitted(sSMP_A, sSMP_3)/(sSMP_B, sSMP_4)
tracks to the preliminary front/surround pairs — and materialises
the rows via the round-260
build_chparam_info_sap_data_from_alpha_qbuilder, falling back to
the header-onlySapMode::Nonerow when no band raises
sap_coeff_used. The pickedalpha_qis clamped to[-30, +30]so
the pair-major DPCM deltas Pseudocode 59 accumulates stay within the
HCB_SCALEFAC-codable[-60, +60]range on a worst-case sign flip.
Newencoder_acpl3::build_5_x_acpl1_body_from_pcm_spectra_sap_auto
(+ caller-facing
encoder_ims::Ac4ImsEncoder::encode_frame_pcm_5_0_acpl1_sap/
_with_max_sfb) additionally closes the round-257 deferred carrier
side: thetwo_channel_data()payload now carries the Table-181
matrix-input carriers(sSMP_A, sSMP_B)recovered through
invert_sap_table_181— on a SAP-coded band the transmitted pair is
(M, S − g·M)(mid + side prediction residual) rather than the raw
L/R preliminaries the round-257 builder still emitted, so the
decoder'sapply_sap_table_181forward mix reproduces the requested
(L, R, Ls, Rs)preliminaries exactly (up to sf_data quantisation).
Measured: forLs = κ·Lcorrelated surround the optimal projection
g* = (1 − κ) / (1 + κ)collapses the transmitted residual to
near-silence — SAP residual energy < 5 % (unit, synthetic spectra) /
< 10 % (full PCM → MDCT → encode → decode integration) of the
identity path's raw-Lsresidual — while a no-benefit input
(Ls = L⇒ zero side energy ⇒g* = 0) encodes bit-for-bit
identical to the round-103 identity path (strict-superset
invariant). Five new unit tests insrc/encoder_acpl3.rspin the
selector's per-band(1.7, 1, 0.3, −1)extraction forκ = 0.2,
theSapMode::Nonefallback on equal pairs, the ±30 clamp on a
near-anti-correlated pair, the identity byte-equality, and the
bit-stream round trip (decoder walker recoverssap_mode = 3rows;
forward Table-181 mix matches all four preliminaries within 20 %
relative L2; residual energy < 5 % of raw surround energy). Four new
integration tests intests/round279_5_x_acpl1_sap_auto.rscover
the 5-channel AudioFrame shape, the recovered SAP rows + residual
collapse vs the identity encoder on the same tone fixture, the
no-benefit byte-equality through the full encoder entry point, and
sequence-counter advancement. Total lib tests 689 (was 684);
integration suites +4. -
Round 271 —
alpha_qdecision driverselect_alpha_q_for_pair
(crate::asf). The SAP-coded (SapMode::SapData) analogue of the
round-263select_ms_used_for_pair— completes the encoder decision
surface for the third non-reservedchparam_info()arm. Given the
target stereo MDCT spectra(L, R)it picks the per-(group, sfb)
alpha_q[g][sfb]index and the matchingsap_coeff_used[g][sfb]
flag per ETSI TS 103 190-1 §5.3.2 Pseudocode 59 + §5.3.3.2. The
decoder reconstructs the output pair from the transmitted tracks via
the SAP matrix(a, b, c, d) = (1 + g, 1, 1 - g, -1),g = alpha_q · 0.1; inverting (det = -2) gives the tracks the encoder must
transmit:I_0 = M = (L + R) / 2andI_1 = S − g·MwithS = (L − R) / 2. SAP coding is therefore a one-tap prediction of the side
track from the mid; thegthat minimises the transmitted residual
energyΣ (S[k] − g·M[k])²per parameter band is the least-squares
projectiong* = ⟨S, M⟩ / ⟨M, M⟩, quantised byalpha_q = round(10 · g*)and clamped to the HCB_SCALEFAC-codable range[-60, +60]
(the offset of 60 is applied bywrite_sap_data, not the driver).
sap_coeff_usedis raised only when the quantised index is non-zero
(a pure-mid band,⟨S, M⟩ == 0, and a zero-mid-energy band both
clear the flag so no SAP bit is spent where prediction offers no
benefit). The decision is taken on the even (pair-leading) sfb of
each(sfb, sfb+1)pair and copied to the odd partner, matching the
pair-major flag-copy semantics of Pseudocode 59 and
build_chparam_info_sap_data_from_alpha_q. New public type alias
crate::asf::SapAlphaDecisionfor the(alpha_q, sap_coeff_used)
matrix pair. Five new unit tests insrc/asf.rspin: the
least-squares projection (S = M → alpha_q = +10,S = -M → alpha_q = -10, with odd-partner inheritance); pure-mid and
zero-energy bands clear the flag; round-trip through
build_chparam_info_sap_data_from_alpha_q+extract_sap_abcd
reproduces the(2, 1, 0, -1)matrix on picked bands and identity
on cleared bands; saturation toalpha_q = 60forg* ≫ 6;
multi-group independence. The returned matrices plug directly into
the round-260build_chparam_info_sap_data_from_alpha_qbuilder,
closing the encoder path from per-group L/R MDCT spectra to a
fully-populatedSapMode::SapDataChparamInfo. Total lib tests
684 (was 679); integration suites unchanged. -
Round 263 —
build_chparam_info_none+select_ms_used_for_pair
encoder helpers (crate::asf). Completes the
build_chparam_info_*family with the trivial third arm
(SapMode::None, header-only emission whoseextract_sap_abcd
reproduces identity per-sfb across any per-group bound), plus a
per-(group, sfb) M/S-vs-L/R decision driver
(select_ms_used_for_pair) that picksms_used[g][sfb]per band
using the standard joint-stereo concentration criterion:
min(E_M', E_S') < min(E_L, E_R)over the per-band MDCT bins
[sfb_offset[sfb], sfb_offset[sfb+1]). For a correlated pair, M'
carries the signal and S' vanishes (min_ms = 0); for an
uncorrelated or anti-correlated pair, M' and S' both sit near
(E_L + E_R) / 4. Ties (zero-energy bands, no concentration
benefit) resolve tofalseso the encoder doesn't spend a
ms_usedbit when joint coding offers no concentration. The
returnedVec<Vec<bool>>plugs directly into
build_chparam_info_ms_usedand the result round-trips through
extract_sap_abcdto the per-sfb(1, 1, 1, -1)matrix on picked
bands and identity on the rest. Five new unit tests in
src/asf.rscover:SapMode::Nonebuilder extract + bit-stream
round-trip; per-band correlated / anti-correlated / one-sided /
zero-energy decision discrimination; round-trip through
build_chparam_info_ms_used+extract_sap_abcd; respect of the
per-groupmax_sfbbound; multi-group independence. Total lib
tests 679 (was 674); integration suites unchanged. -
Round 260 — encoder-side
ChparamInfobuilders
(crate::asf::build_chparam_info_ms_used+
crate::asf::build_chparam_info_sap_data_from_alpha_q). Encoder-
side duals of [crate::asf::extract_sap_abcd] (§5.3.4.3.2 /
Pseudocode 59) for the two non-trivialSapModearms.build_chparam_info_ms_usedwraps a per-(group, sfb)ms_used
flag matrix into aChparamInfowithsap_mode = 1; feeding
the result intoextract_sap_abcdreproduces the per-sfb
(1, 1, 1, -1)vs identity(1, 0, 0, 1)mix the input
describes, and awrite_chparam_info→parse_chparam_info
round-trip recovers the same row.build_chparam_info_sap_data_from_alpha_qis the real
workhorse: starting from per-(group, sfb)alpha_qindices
(range[-60, +60]— the HCB_SCALEFAC raw-symbol offset of 60
is applied by the writer, not the builder) plus per-pair
sap_coeff_usedflags, it computes the pair-major DPCM
dpcm_alpha_q[g][sfb]deltas Pseudocode 59 accumulates back
intoalpha_q[g][sfb]. Odd sfbs leave the dpcm slot at zero
(decoder inherits from the pair-mate); even sfbs compute
cur - prevwith thecode_deltapolicy mirrored exactly
fromextract_sap_abcd—code_delta == 1wheng > 0,
max_sfb_per_group[g] == max_sfb_per_group[g-1], and the
caller-supplieddelta_code_timeis set, with the reference
beingalpha_q[g-1][sfb]; otherwise the reference is
alpha_q[g][sfb-2]forsfb > 0and zero forsfb == 0. The
fully-uniform "all set" matrix is detected andsap_coeff_all
is raised so the bitstream elides the per-pair flag array.
delta_code_timeis normalised tofalseon single-group
payloads (Table 48 doesn't transmit the bit there).- Round-trip guarantees pinned by five new unit tests in
src/asf.rs:extract_sap_abcdreproduces the original
alpha_qrow on set bands and identity on cleared bands
(build_chparam_info_sap_data_pair_major_round_trip+
..._unused_bands_pass_through); the cross-group
delta_code_timepath delivers the expecteddpcm_alpha_q
deltas (..._delta_code_time_cross_group); single-group
delta_code_time = trueinput is normalised tofalseon
emit (..._single_group_drops_delta_code_time); and
write_chparam_info→parse_chparam_inforecovers the same
SAP body which extracts to the originalalpha_q
(..._round_trips_through_bitstream). - Slots into the round-257 SAP-aware residual-layer writer: an
IMS encoder that runs a psychoacoustic decision per
parameter-band (M/S vs. alpha-driven SAP joint stereo) can now
materialise theChparamInfopair from its decision matrix
instead of hand-crafting the innerSapDatabody — the same
bytes the decoder'sparse_chparam_infowalks back into the
apply_sap_table_181pipeline. Total lib tests 674 (was 667);
integration suites unchanged.
-
Round 257 — SAP-aware ASPX_ACPL_1 residual-layer writer
(write_acpl_1_residual_layer_sap+ body-builder wrapper
build_5_x_acpl1_body_from_pcm_spectra_sap). Pairs the round-246
Table-181 inverse with the existing round-243
[crate::encoder_asf::write_chparam_info] emitter so the IMS
encoder's §4.2.6.6 Table-25case ASPX_ACPL_1:residual layer can
now express any of the three SAP coefficient families produced by
[crate::asf::extract_sap_abcd] — identity (sap_mode = 0), M/S
(sap_mode = 1) and SAP-codedalpha_q(sap_mode = 3) — rather
than being hard-pinned to the identity row by the round-103
[write_acpl_1_residual_layer].- The new private helper
write_acpl_1_residual_layer_saptakes
(coeffs_l, coeffs_r, coeffs_ls, coeffs_rs)preliminary
spectra plus anOption<&[ChparamInfo; 2]>and (1) emits the
chparam_info()pair viawrite_chparam_infowith
max_sfb_per_group = [max_sfb_master], (2) recovers the
joint-MDCT residual(sSMP,3, sSMP,4)via
[crate::asf::invert_sap_table_181] driven by the same chparam
pair, and (3) writes the twosf_data(ASF)bodies for the
recovered residual spectra bounded bymax_sfb_master. When
chparam_pair = None(or both rows carrysap_mode = 0) the
body is bit-for-bit equivalent to
write_acpl_1_residual_layer(... coeffs_ls, coeffs_rs)— the
identity-row inverse reduces tos3 = ls, s4 = rs. The inverse's
surround-silent convention pastmax_sfb_masteris preserved. - The new public body builder
build_5_x_acpl1_body_from_pcm_spectra_sapmirrors the round-103
build_5_x_acpl1_body_from_pcm_spectraAPI with the extra
chparam_pair: Option<&[ChparamInfo; 2]>slot wedged in between
the surround spectra and the ASPX config. The legacy
identity-only builder is unchanged. - Five new tests in
encoder_acpl3::tests:
write_acpl_1_residual_layer_sap_none_matches_legacypins the
bit-equivalence of the SAP-aware path withchparam_pair = None
against the legacy emitter on identical Ls/Rs preliminaries;
write_acpl_1_residual_layer_sap_identity_explicit_matches_default
pins explicit identity rows == defaultNone;
write_acpl_1_residual_layer_sap_ms_row_roundtrips_through_decoder
feeds the body throughparse_chparam_infoand asserts the
decoder recoverssap_mode = 1with the rightms_usedrows
on both chparam slots;build_5_x_acpl1_body_sap_none_matches_legacy
is the body-builder analogue of the bit-equivalence test;
build_5_x_acpl1_body_sap_ms_decoder_recovers_chparamfeeds the
full body throughparse_5x_audio_data_outerand asserts
tools.acpl_1_residual_chparam[0..1]recover the original
chparam pair with allmax_sfb_masterms_used bands present.
Total lib tests 667 (was 662); existing integration suites
remain green. - The downstream decoder pipeline that consumes this is already
wired up: round-30decoder.rs(lines 2661-2705) reads the
persistedtools.acpl_1_residual_chparamand feeds it through
apply_sap_table_181to re-mix the L/R/Ls/Rs preliminary
spectra before IMDCT, so an encoder building a body via the
new SAP-aware path produces a stream that round-trips through
the existing decoder without further changes.
- The new private helper
-
Round 246 — encoder-side Table-181 SAP residual extractor
(invert_sap_table_181, dual ofapply_sap_table_181). An IMS
encoder that wants to populate the §4.2.6.6 ASPX_ACPL_1 residual
layer (Table 25 rowcase ASPX_ACPL_1:, two trailing
sf_data(ASF)bodies carryingsSMP,3/sSMP,4) now has a
closed-form 2x2-per-sfb inverse of the §5.3.4.3.2 / Table 181
first-stage SAP matrix that recovers the joint-MDCT preliminary
spectra(sSMP_A, sSMP_B, sSMP_3, sSMP_4)from a target
(L, R, Ls, Rs)preliminary set and achparam_info()pair.- [
crate::asf::invert_sap_table_181] / new public type alias
[crate::asf::SapTable181EncodeOutput]. Inversion splits the
Table-181 5x5 matrix into the two independent 2x2 sub-systems
(L, Ls)↔(A, s3)driven bychparam_pair[0]and
(R, Rs)↔(B, s4)driven bychparam_pair[1]. Per sfb the
inverse usesdet = a*d - b*cand the closed-form
[[d, -b], [-c, a]] / det. - For the three SAP coefficient families produced by
[crate::asf::extract_sap_abcd] the determinant is always
non-singular: identity row givesdet = 1, M/S row
(1, 1, 1, -1)givesdet = -2, and the SAP-coded row
(1 + g, 1, 1 - g, -1)withg = alpha_q * 0.1also gives
det = -2. The implementation tolerates a hypothetical
det == 0band (e.g. a future spec extension) by emitting
silence for that band instead of panicking, mirroring the
forward path's graceful-degradation convention. - Outside the SAP-coded extent (bins past
sfb_offset[max_sfb_master]) the forward pass leaves the front
pair at(L, R) = (A, B)and zeros the surround pair; the
inverse mirrors this —A = L,B = R,s3 = s4 = 0— so
the round-trip is symmetric at the band boundary. Returns
Nonewhen the transform_length has no entry in
sfb_offset_48, matching the forward path's failure mode. - Five new unit tests in
src/asf.rscover identity-row
inverse, M/S-row inverse, forward-then-inverse round-trip on
both the identity and M/S rows, and the unsupported-tlNone
return. All 5 pass; the existing crate test suite remains
green (662 lib tests pass at this commit).
- [
-
Round 243 — encoder-side
chparam_info()/sap_data()builders
(dual ofparse_chparam_info/parse_sap_data, Table 47 / 48).
Adds a reusable encoder helper covering all foursap_modecodes —
the parser's complement for §4.2.10.1 Table 47 (chparam_info())
and §4.2.10.2 Table 48 (sap_data()). Until this round the
encoder's six chparam-emission sites inencoder_asf.rsopen-coded
bw.write_u32(0, 2)forsap_mode = 0(identity SAP); now there
is a single builder that handlessap_mode = 0(header-only),
sap_mode = 1(header + per-(group, sfb)ms_used[g][sfb]bit
array),sap_mode = 2(reserved; header-only, mirroring the
parser's accept-and-skip behaviour) andsap_mode = 3(full
sap_data()body —sap_coeff_allbit, per-pair flag array when
sap_coeff_all = 0,delta_code_timewhennum_window_groups != 1,
per-pair HCB_SCALEFAC-codeddpcm_alpha_qdeltas).- [
crate::encoder_asf::write_chparam_info] — emits the 2-bit
sap_modeselector and dispatches to the matching payload
branch. Half-builtChparamInfoinputs (rows shorter than
max_sfb_per_group) zero-fill the missing entries so the writer
stays total. Asap_mode = 3input withsap_data = None
emits aSapData::default()body that the parser walks
successfully. - [
crate::encoder_asf::write_sap_data] — emits thesap_coeff_all
bit, the per-pair flag array (skipped whensap_coeff_all = 1),
the conditionaldelta_code_timebit and the per-pair DPCM
deltas. The DPCM map is the samedelta + 60 → HCB_SCALEFAC indexthe round-49 [crate::encoder_asf::write_scalefac_data]
uses, with the same[0, 120]clamp policy. - Round-trip is bit-exact with [
crate::asf::parse_chparam_info]
and [crate::asf::parse_sap_data] acrosssap_mode in {0, 1, 2, 3}, including: single- and multi-groupms_usedpayloads;
sap_coeff_all = 1single-group andsap_coeff_all = 0
partial-pair multi-group bodies withdelta_code_time = 1;
the parser's pair-flag copy semantic (one bit drives both halves
of(sfb, sfb+1)); asymmetric pair-flag input rows; and the
full[-60, +60]DPCM delta range. Out-of-range deltas clamp at
the codebook boundary (±60), matching the existing scale-factor
writer's policy. - Thirteen integration tests in
tests/round243_chparam_info_writer.rspin:sap_mode = 0emits
exactly 2 bits as a header-only element;sap_mode = 2(reserved)
is round-trip stable as a header-only emission;sap_mode = 1
single-groupms_usedrecovers entry-for-entry;sap_mode = 1
multi-group with 3 groups of (3, 4, 1) bands recovers the full
matrix; missingms_usedrows zero-fill on the wire;sap_mode = 3sap_coeff_allbody recovers the DPCM deltas at even-sfb
pair starts;sap_mode = 3partial-pair body with
sap_coeff_all = 0recovers both the flag array and the
selectively-emitted DPCM entries;sap_mode = 3multi-group
body withdelta_code_time = 1recovers across two groups;
sap_mode = 3withsap_data = Noneemits a default body that
parses as asap_coeff_all = 0all-false row; out-of-range DPCM
deltas clamp to ±60; a full sweep of every legal delta in[-60, +60]round-trips exactly;sap_mode = 0drops a populated
ms_used/sap_datapayload on emission; in-memorysap_mode
values with high bits set are masked to the on-wire 2-bit field. - Total tests 883 (was 870). The encoder now has a single reusable
chparam-emission helper covering every legalsap_mode, ready
for the §4.2.10 SAP-mode decisioning work (M/S vs. independent
vs. joint-MDCT) to feed real per-bandms_used[]/ per-pair
DPCM arrays into the existing 5_X / 7_X channel-element walkers
in place of today's hard-coded identity-SAP literals.
- [
-
Round 240 — encoder-side HF QMF energy aggregator (dual of
Pseudocodes 90 + 91). Closes the first half of the round-234
remaining-work note by landing the per-(sbg, atsg)energy
aggregator that converts an HF QMF matrix into the per-sbg
scfvector the round-234 envelope-index extractor consumes —
completing the encoder'sq_high → scf → qscf → DPCM → on-wire byteschain for real ASPX envelope coding.- [
crate::encoder_acpl3::aggregate_qmf_to_sbg_atsg] — aggregate
an HF QMF matrixq_high(shape[absolute_sb][ts]) into a
[sbg][atsg]matrix of average squared magnitudes per
Pseudocode 90's per-subband energy reduction grouped by
Pseudocode 91's SBG borders. Tolerates QMF rows shorter than
tsz(entries past the bounds contribute zero), zero-span ATS
intervals and zero-span band groups (return0.0), and
sbg_borders[i] < sbx(clamps upward tosbxso callers can
pass spec-shaped absolute borders verbatim). - [
crate::encoder_acpl3::extract_aspx_sig_envelope_scf_from_qmf]
/ [crate::encoder_acpl3::extract_aspx_noise_envelope_scf_from_qmf]
— per-side helpers that pick the leading envelope (atsg = 0)
column of the aggregator output, producing a per-sbgVec<f32>
ready to feed the round-234 envelope-index extractor. - New public type
[crate::encoder_acpl3::AspxQmfEnvelopeChannel] —{ q_high: &[Vec<(f32, f32)>], sbg_sig_borders: &[u32], sbg_noise_borders: &[u32] }per-channel bundle consumed by the
QMF-driven envelope builder. - [
crate::encoder_acpl3::build_aspx_real_envelope_channel_from_qmf]
— convenience builder that runs the QMF aggregator + the round-234
extract_aspx_*_envelope_indicesextractors + the round-234
build_aspx_real_envelope_channelbuilder end-to-end and returns
owned(sig, noise) Vec<i32>ready to drop into the round-226
AspxRealEnvelopeChannel { sig: &[i32], noise: &[i32] }slot. - Fourteen integration tests in
tests/round240_aspx_qmf_energy_aggregator.rspin: constant-
energy aggregation matches the per-cell mean; per-ATSG
partitioning recovers a [1.0, 9.0] split; per-SBG partitioning
recovers a [1.0, 16.0] split; sub-sbxborders clamp upward;
empty SBG / ATSG borders return empty matrices; zero-span ATSG
cells return 0.0; the per-side helpers emit per-sbgvectors
mirroring the aggregator; the QMF-driven convenience builder
matches the manual aggregator + extractor + builder chain
entry-for-entry; an integer-quant-grid input (scf = 64and
128for Fine signal) hits the expected[F0 = 0, DF₁ = 2]
DPCM payload; short QMF rows contribute partial energy without
panicking; the QMF-driven builder is deterministic across
repeated invocations; different QMF inputs produce different
DPCM payloads. Total tests 870 (was 856). - Refs ETSI TS 103 190-1 §5.7.6.4.2.1 Pseudocodes 90 + 91.
- [
-
Round 234 — encoder-side ASPX envelope extractor (inverse of
Pseudocodes 80, 81, 82, 83). Closes the round-226 deferral by
landing the per-(sbg, env)envelope-index extractor that inverts
Pseudocode 82'sscf = n_subbands · 2^(qscf/a)reconstruction and
Pseudocode 83'sscf_noise = 2^(6 − qscf_noise)reconstruction so
the round-226write_aspx_data_{1,2}ch_real_envelopebuilders can
be chained with caller-supplied envelope-energy scale factors.- [
crate::encoder_acpl3::quantize_sig_scf] —scf → qscffor one
signal-envelope band per Pseudocode 82.qmode_env = Fine⇒
a = 2(1.5 dB step),Coarse⇒a = 1(3 dB step);
num_qmf_subbandsmirrors the dequantizer's64. Non-positive
scfclamps to a finite quant index instead of producing
-infso the spec'sscf[0] = scf[1]carry-through path and
callers passing 0 for silent bands stay well-defined. - [
crate::encoder_acpl3::quantize_noise_scf] —scf → qscffor
one noise-envelope band per Pseudocode 83 (qscf = round(6 − log2(scf))). - [
crate::encoder_acpl3::freq_dpcm_encode_qscf] — invert the
FREQ-direction DPCM accumulatorqscf[sbg] = sum(values[0..=sbg])
of Pseudocode 80 / 81. Returns[F0, DF₁, DF₂, …]where
F0 = qscf[0],DF[sbg ≥ 1] = qscf[sbg] − qscf[sbg − 1]. Empty
input returns an empty vector. - [
crate::encoder_acpl3::extract_aspx_sig_envelope_indices] /
[crate::encoder_acpl3::extract_aspx_noise_envelope_indices] —
per-channel compositionsscf[] → qscf[] → [F0, DF₁, …]ready
for the round-219 value-emitting helpers + the round-226 builder
pair. - New public type
[crate::encoder_acpl3::AspxEnvelopeScfChannel] —{ sig: &[f32], noise: &[f32] }per-channel envelope-energy payload. - [
crate::encoder_acpl3::build_aspx_real_envelope_channel] —
convenience wrapper that runs both extractors and returns owned
(sig, noise)Vec<i32>pairs callers wire into
AspxRealEnvelopeChannelby slice reference. - Round-trip property: feeding caller
scfslices through the
extractor, then the round-226 builder, then re-parsing the body
throughparse_aspx_ec_data+ the decoder'sdelta_decode_sig/
delta_decode_noise+dequantize_sig_scf/
dequantize_noise_scf, recovers the inputscfvector within
the per-band rounding ofround(a · log2(scf / 64))/
round(6 − log2(scf)). - Fourteen integration tests in
tests/round234_aspx_envelope_extractor.rscover: forward-inverse
identity at integer-quant grid points for both Fine and Coarse
signal step sizes; forward-inverse identity for Pseudocode 83
on the noise side; non-positivescfclamps to a finite quant
index; FREQ-DPCM encoder produces[5, 2, −4, −4, 1]for
qscf = [5, 7, 3, −1, 0]with the decoder's accumulator
recovering the input; empty / single-band inputs pass through;
end-to-end accumulator + Pseudocode-82 / 83 round-trip from
callerscfthrough extractor through Pseudocode-{82, 83};
build_aspx_real_envelope_channelmatches direct calls; full
encoder→decoder loop wiringbuild_aspx_real_envelope_channel
intowrite_aspx_data_2ch_real_enveloperecovers the input
scfvectors through the decoder's full pipeline; determinism
across repeated invocations; different inputs produce materially
different DPCM payloads; empty per-channel slices return empty
vectors. - Total tests 856 (was 842). With this round the encoder now has
the completescf[] → on-wire byteschain for real ASPX
envelope coding; remaining envelope-coding work is the energy
estimator that turns input MDCT spectra into the per-sbg
scfvectors the extractor consumes (the inverse of Pseudocodes
90 + 91), plus driving the new extractor + builder pair from
the existing high-level encode entry points. β₃ extraction in
the 5_X ACPL_3 path and real Table-181 SAP-derived residual
content for the ACPL_1 paths remain deferred.
- [
-
Round 226 —
write_aspx_data_2ch_real_envelope()and
write_aspx_data_1ch_real_envelope()builders. Closes the second
step of the README's "real ASPX envelope coding" deferral. The
round-219 value-emitting ASPX-Huffman primitives
(write_aspx_sig_f0_value/write_aspx_sig_df_value/
write_aspx_noise_f0_value/write_aspx_noise_df_value) are now
driven by per-channel envelope builders that emit a full
ETSI TS 103 190-1 §4.2.12.4 Table 52 (aspx_data_2ch()) or
§4.2.12.3 Table 51 (aspx_data_1ch()) body with caller-supplied
F0 + signed DF quant indices.- New public type
[crate::encoder_acpl3::AspxRealEnvelopeChannel] —{ sig: &[i32], noise: &[i32] }per-channel envelope payload. - [
crate::encoder_acpl3::write_aspx_data_2ch_real_envelope] —
accepts(cfg, ch0, ch1)and writes the Table-52 body with
aspx_xover_subband_offset = 0, FIXFIX framing (num_env = 1,
optionalaspx_freq_res = 0),aspx_balance = 1(shared
channel-0 framing), SIGNAL + NOISE delta-direction bits = FREQ,
aspx_hfgen_iwc_2chall-zero trailer, then fouraspx_ec_data
calls (ch0 SIGNAL LEVEL, ch1 SIGNAL BALANCE, ch0 NOISE LEVEL,
ch1 NOISE BALANCE). qmode is forced Fine on FIXFIX +num_env == 1per Table 52. - [
crate::encoder_acpl3::write_aspx_data_1ch_real_envelope] —
accepts(cfg, ch)and writes the Table-51 body with two
aspx_ec_datacalls (SIGNAL + NOISE, both LEVEL). - The SIGNAL band count keys off
cfg.signals_freq_res(): low-res
when the in-bandaspx_freq_res = 0bit is emitted (Signalled
mode), otherwise the parser'sfreq_res.get(env) .copied().unwrap_or(true)fallback selects high-res (matching
the r181 fix inwrite_aspx_data_2ch_minimal). - Caller slices shorter than the derived SBG count zero-pad the
trailing envelope positions; F0 values outside[0, codebook_length)clamp to the codebook edge; DF values outside
[-cb_off, +cb_off]saturate to the symmetric edge — matching
the round-219 helper semantics. - Eight integration tests in
tests/round226_aspx_real_envelope_writers.rscover:
deterministic 2ch envelope round-trips through
parse_aspx_ec_datarecovering caller inputs per channel;
1ch envelope round-trip with LEVEL-only stereo_mode; short
input slices zero-pad in place; 2ch / 1ch byte determinism;
all-zero inputs decode to all-zero envelopes; different
per-channel inputs produce different bytes; out-of-range DF
saturates at the codebook's+cb_offedge (Fine/Level DF
cb_off = 70). - The minimum-bit-cost
write_aspx_data_2ch_minimal/
write_aspx_data_1ch_minimalwriters stay in place; no
existing call site is touched, so every previous round's
byte-stream expectations remain valid. - Total tests 842 (was 834). The remaining ASPX envelope-coding
work is the per-(sbg, env) envelope-index extractor that
inverts Pseudocode 82'sscf = n_subbands · 2^(qscf/a)
reconstruction so the new builders can be chained with input
MDCT spectra. β3 extraction in the 5_X ACPL_3 path and real
Table-181 SAP-derived residual content for the ACPL_1 paths
remain deferred.
- New public type
-
Round 215 — real per-parameter-band γ₁ / γ₂ / γ₃ / γ₄ extraction
in the 5_X SIMPLE/ASPX_ACPL_3 encoder. Layered on top of the
round-208 real γ₅ / γ₆ (centre) + the round-196 real α₁ / α₂ +
real β₁ / β₂ path: the γ₁..γ₄ entropy layers — previously emitted
as the round-95 zero-delta scaffold codewords — now carry per-band
magnitudes derived from per-band 2×2 least-squares fits of the
(L, Ls) and (R, Rs) output channel pairs onto the (L, R) carrier
pair. In §5.7.7.6.2 Pseudocode 118 step 5 the (L, Ls) pair is
built by the firstACplModule2invocation with(a = α₁, b = β₁, y = y₀), and step 11 scalesLs = √2·z1. Forming
(L + Ls/√2)cancels they₀·β₁decorrelator contribution
exactly, leavingL + Ls/√2 = (γ₁·x0in + γ₂·x1in)which expands
to(1 + √2)·(γ₁·L + γ₂·R)via the step-1 carrier rescaling. By
symmetry with step 6 the same fit shape gives(γ₃, γ₄)from
(R + Rs/√2)/(1 + √2). New
[encoder_acpl3::extract_gamma_1_2_q_per_band_surround_least_squares]
and [extract_gamma_3_4_q_per_band_surround_least_squares]
solve the 2×2 normal equations
[<L,L> <L,R>; <L,R> <R,R>]·[γ; γ'] = [<L,T>; <R,T>]per
parameter band. Bands with a degenerate Gram matrix (no L or R
energy, or perfectly collinear L = ±R within numerical tolerance)
keep γ = γ' = 0. New
[encoder_acpl3::build_5_x_acpl3_body_from_pcm_spectra_real_alpha_beta_full_gamma]
drops all six γ extractors into theacpl_data_2ch()body
alongside the round-208 γ₅ / γ₆ extractor; β₃ stays zero-delta.
Caller-facing
[encoder_ims::Ac4ImsEncoder::encode_frame_pcm_5_0_acpl3_real_alpha_beta_full_gamma]
/encode_frame_pcm_5_1_acpl3_real_alpha_beta_full_gammawrap
the new builder, accepting a 5- / 6-channel
[L, R, C, Ls, Rs (, LFE)]input (vs the round-208 3- / 4-channel
[L, R, C (, LFE)]input that could only drive the centre γ
layer). Nine integration tests in
tests/round215_5_x_acpl3_real_full_gamma.rspin: 5.0 round-trip
to a 5-channelAudioFrame; 5.1 round-trip to a 6-channel
AudioFrame; silent surround (Ls = 0) yields γ₂_q = 0 in every
band when probed directly; silent surround (Rs = 0) yields γ₃_q
= 0 in every band;α/β/γ_scale = 0.0reproduces the round-95
zero-delta scaffold byte-for-byte;γ_scale = 0.0reproduces
the round-196 real-α-β bytes byte-for-byte; loud-surround vs
silent-surround inputs produce materially different bytes (the
round-208 path would emit identical γ₁..γ₄ codewords regardless
of surround input); the encoder is bit-deterministic for matched
inputs and fresh state. Total tests 822 (was 813). β₃ extraction
(requires modelling the unobservable decorrelator outputy₂)
and real ASPX envelope coding remain deferred. -
Round 208 — real per-parameter-band γ5 / γ6 extraction in the
5_X SIMPLE/ASPX_ACPL_3 encoder. Layered on top of the round-196
real α₁ / α₂ + real β₁ / β₂ path: the γ5 / γ6 entropy layers now
carry per-band magnitudes derived from a 2×2 per-band
least-squares fit of the centre channel. In §5.7.7.6.2
Pseudocode 118 step 7 the centre outputz4is built by the
thirdACplModule2invocation with(a = 1, b = 0, y = 0):
z4 = 0.5 · (γ5·x0in + γ6·x1in). Step 11 scalesz4 *= √2
before QMF synthesis; step 1 rescales the carriers
x0in = (1 + √2)·L,x1in = (1 + √2)·R. The centre
reconstruction (β3 = 0, ducker = 1) is therefore
C ≈ K · (γ5·L + γ6·R)withK = √2·(1+√2)/2 = 1+√(1/2). The
round-208 extractor solves the 2×2 normal equations per
parameter band:[ <L,L> <L,R> ] [γ5] [ <L,C>/K ] [ <L,R> <R,R> ] [γ6] = [ <R,C>/K ]for
(γ5, γ6)that minimise the MDCT-bin-wise residual
Σ (C/K − γ5·L − γ6·R)². Bands with a degenerate Gram matrix
(no L or R energy, or perfectly collinear L = ±R within
numerical tolerance) keep γ5 = γ6 = 0. The quantiser uses the
Table-208 lineargamma_q = round(γ / gamma_delta)mapping with
the symmetric±cb_offclamp (cb_off = 20Fine /10Coarse,
table magnitude bound ±2.0). γ1..γ4 + β3 stay at the round-95
scaffold (those parameter sets drive the (L, R, Ls, Rs)
sub-pipeline plus the ACplModule3 cross-residual — neither of
which has a per-side surround reference at encode time for the
5.0 / 5.1 PCM input layouts the real-γ entry point targets).- [
crate::encoder_acpl3::extract_gamma_5_6_q_per_band_centre_least_squares]
— per-parameter-band 2×2 least-squares γ5 / γ6 extractor. - [
crate::encoder_acpl3::build_5_x_acpl3_body_from_pcm_spectra_real_alpha_beta_gamma]
— drop-in replacement for the round-196
build_5_x_acpl3_body_from_pcm_spectra_real_alpha_betawith
additionalcoeffs_c: Option<&[f32]>+gamma_scale: f32
parameters.gamma_scale = 0.0reproduces the round-196 byte
stream exactly;alpha_scale = beta_scale = gamma_scale = 0.0
reproduces the round-95 zero-delta scaffold. - [
crate::encoder_ims::Ac4ImsEncoder::encode_frame_pcm_5_0_acpl3_real_alpha_beta_gamma]..._5_1_...— high-level entry points accepting[L, R, C]
(5.0) or[L, R, C, LFE](5.1) PCM.
tests/round208_5_x_acpl3_real_gamma.rs(8 tests) pins: 5.0
round-trip to 5-channelAudioFrame; 5.1 round-trip to
6-channelAudioFrame; silent-centre input produces
γ5_q = γ6_q = 0 in every band;C = (L + R) / 2produces
non-zero γ_q in ≥1 tonally-active band; loud-centre vs
silent-centre inputs produce materially different bytes (the
round-196 path would emit identical γ codewords regardless of
centre input);α/β/γ_scale = 0.0matches the round-95
scaffold byte-for-byte;γ_scale = 0.0reproduces the
round-196 real-α-β bytes exactly; encoder is bit-deterministic
for matched inputs and fresh state.- Real γ1..γ4 extraction (the (L,R,Ls,Rs) sub-pipeline mix
parameters) requires per-side surround references which the
5.0 / 5.1 PCM input layout does not carry — these stay at the
round-95 zero-delta scaffold pending a 5.1+Ls+Rs PCM input
layout. Real β extraction for the 7_X ACPL_3 paths, real ASPX
envelope coding, and real Table-181 SAP-derived residual
content (for the ACPL_1 paths) remain deferred.
- [
-
Round 202 — real per-parameter-band α + β extraction in the
7.0 / 7.1 SIMPLE/ASPX_ACPL_2 multichannel encoder. The 7_X
(immersive) counterpart to the round-144 5.0 ACPL_2 real-α-β
path and the real-α-β upgrade of the round-107 / 114 zero-delta
7_X ACPL_2 encoder. ACPL_2 does not transmit the Ls/Rs surround
pair on the wire — the decoder reconstructs the surround from
the L/R carriers + the twoacpl_data_1ch()parameter sets per
§5.7.7.5 Pseudocode 116 + §5.7.7.6.1 Pseudocode 117:
z0 = 0.5·(x0·(1+α) + y·β),z1 = 0.5·(x0·(1−α) − y·β).- [
crate::encoder_acpl3::build_7_x_acpl2_body_from_pcm_spectra_real_alpha_beta]
— real-α-β upgrade of
[build_7_x_acpl2_body_from_pcm_spectra]; identical body
schedule (2-bit7_X_codec_mode = 3, optional LFE
mono_data(b_lfe = 1), twotwo_channel_data()pairs, no
joint-MDCT residual layer, trailing centremono_data(0),
aspx_data_2ch + aspx_data_2ch + aspx_data_1chenvelope
trailer) with the two trailingacpl_data_1ch_minimalwriters
replaced bywrite_acpl_data_1ch_real_alpha_beta. D0 module
models (L → Ls); D1 module models (R → Rs).acpl_config_1ch (FULL)carries noqmf_band→start_band = 0so every
parameter band participates. - [
crate::encoder_ims::Ac4ImsEncoder::encode_frame_pcm_7_0_acpl2_real_alpha_beta]_with_max_sfb— accepts[L, R, C, Ls, Rs, Lb, Rb],
forces the 7.0 channel_mode prefix (0b1111000, 7 b — Table
85 channel_mode 5), emits a 7-channel S16 PCM round-trip.
- [
crate::encoder_ims::Ac4ImsEncoder::encode_frame_pcm_7_1_acpl2_real_alpha_beta]_with_max_sfb— accepts[L, R, C, Ls, Rs, Lb, Rb, LFE],
forces the 7.1 channel_mode prefix (0b1111001, 7 b — Table
88 channel_mode 6), emits an 8-channel S16 PCM round-trip
with the LFE element written via the round-80
write_lfe_mono_datashared emitter.
tests/round202_7_x_acpl2_real_alpha_beta.rs(10 tests) pins:
7.0 / 7.1AudioFrameround-trip; decoder resolves
SevenXCodecMode::AspxAcpl2with both
acpl_data_1ch_pair[0/1]populated; loud-surround vs
silence-surround inputs produce materially different bytes;
silence input round-trips with β_q = 0 in every band; encoder
is bit-deterministic for matched inputs and fresh state;
direct body-builder probe diverges from the round-107
zero-delta scaffold byte stream when the caller's Ls/Rs
spectra are non-trivial.- The back pair Lb / Rb is accepted for layout completeness but
not carried by the ASPX_ACPL_2 body (the decoder's 7_X ACPL_2
dispatch populates slots 0..4 + the LFE slot 7 — slots 5/6
stay silent), matching the round-107 documented Table 202
channel mapping plus the round-80 LFE PCM render at decode
time. - Real β extraction for the 7_X ACPL_3 paths, real γ extraction,
real ASPX envelope coding, real Table-181 SAP-derived residual
content (for the ACPL_1 paths), and back-pair Lb/Rb carriage
remain deferred.
- [
-
Round 196 — real per-parameter-band α1 / α2 extraction in the
5_X SIMPLE/ASPX_ACPL_3 encoder. Layered on top of the round-193
real β1 / β2 path: the two ACplModule2 instances in ACPL_3 share
the (L, R) carrier pair as their (x0, x1) input, so without a
per-side surround reference at encode time α₁ / α₂ are driven by
the same L↔R cross-correlation extractor —α[pb] = α_scale · ρ(L, R)[pb]withρ = E[L·R] / √(E[L²]·E[R²])— clamped to the
ALPHA_DQ table magnitude bound (±2.0 Fine / ±2.0 Coarse).- [
crate::encoder_acpl3::extract_alpha_q_per_band_carrier_correlation]
— extracts per-band α_q from the L / R MDCT spectra. The α
parameter modulates the front/back dry-mix balance in
ACplModule2 (Pseudocode 119): higher α → more dry energy on the
front pair, lower α → more on the surround pair. Mono-like
(highly-correlated) bands push α toward +1; decorrelated bands
stay near α = 0. - [
crate::encoder_acpl3::build_5_x_acpl3_body_from_pcm_spectra_real_alpha_beta]
— drop-in replacement for the r193
build_5_x_acpl3_body_from_pcm_spectra_real_betathat lifts
α1 / α2 from the zero-delta scaffold in addition to β1 / β2.
β3 / γ1..γ6 still zero-delta. Withα_scale = β_scale = 0.0the
output is byte-for-byte identical to the round-95
build_5_x_acpl3_body_from_pcm_spectrascaffold. - [
crate::encoder_ims::Ac4ImsEncoder::encode_frame_pcm_5_0_acpl3_real_alpha_beta]
andencode_frame_pcm_5_1_acpl3_real_alpha_beta— caller-facing
entry points wrapping the new builder with the same channel-mode
forcing / MDCT analysis / TOC framing as the existing real-β
paths. tests/round196_5_x_acpl3_real_alpha_beta.rs(4 tests) pins:
round-trip to 5-channelAudioFrame; perfect L = R correlation
(ρ = +1) quantises toα_q = +8(lane 24 = 1.0); perfect
anti-correlation L = -R (ρ = -1) quantises toα_q = -8;
α_scale = β_scale = 0.0is byte-for-byte identical to the
round-95 scaffold.- Total tests 795 (+4 over r193).
- [
-
Round 193 — real per-parameter-band β1 / β2 extraction in the
5_X SIMPLE/ASPX_ACPL_3 encoder. The round-95 ASPX_ACPL_3 path
emits all 11 ACPL parameter sets as zero-delta Huffman codewords:
with α = β = β3 = γ = 0 the §5.7.7.6.2 Pseudocode 118 / 119
synthesis collapses to a trivial mix that produces silent surround
outputs from non-silent carrier inputs (structurally correct but
perceptually inert). This round adds three encoder surface entries
that lift β1 / β2 out of the zero-delta scaffold while keeping
α1 / α2 / β3 / γ1..γ6 at the round-95 minimum-bit-cost defaults.- [
crate::encoder_acpl3::extract_beta_q_per_band_carrier_energy]
— extracts per-parameter-band β_q from a single carrier's MDCT
energy distribution. The β parameter in ACplModule2 is the gain
applied to the decorrelator output; setting it proportional to
√E[x²]keeps the wet/dry balance bounded so the surround
reconstruction tracks the carrier RMS per band. - [
crate::encoder_acpl3::build_5_x_acpl3_body_from_pcm_spectra_real_beta]
— drop-in replacement forbuild_5_x_acpl3_body_from_pcm_spectra
that runs the carrier-energy extractor over the L / R inputs and
emits real β1 / β2 codewords. Mirrors the round-95 wire layout
everywhere else so the decoder walks the same Table 25 body. - [
crate::encoder_ims::Ac4ImsEncoder::encode_frame_pcm_5_0_acpl3_real_beta]
andencode_frame_pcm_5_1_acpl3_real_beta— caller-facing entry
points that wrap the new builder with the same channel-mode
forcing, MDCT analysis and TOC framing the existing
encode_frame_pcm_5_0_acpl3/encode_frame_pcm_5_1_acpl3use. - With α1 = α2 = 0 and β3 = 0 the ACplModule2 synthesis at
parameter bandpbreduces to
z0 = 0.5·(x0·g1 + x1·g2 + y0·β1),
z1 = 0.5·(x0·g1 + x1·g2 − y0·β1),
and analogously(z2, z3)with β2 driving the second
ACplModule2. Non-zero β1 / β2 inject the decorrelator outputy
that gives the Ls / Rs outputs their decorrelated spaciousness. tests/round193_5_x_acpl3_real_beta.rs(7 tests) pins: round-trip
to 5- / 6-channelAudioFramefor 5.0 / 5.1; silent input →
all-zero β_q indices; tonal carrier + non-zerobeta_scale→
at least one non-zero β_q lane;beta_scale = 0.0is
byte-for-byte identical to the round-95 scaffold; silent inputs
at anybeta_scaleare scaffold-identical (carrier-energy
extractor short-circuits to 0); non-silent tonal inputs at
beta_scale > 0diverge from the round-95 scaffold (different
β1 / β2 codeword bit-positions) while keeping the padded
substream length identical.- Total tests 791 (+7 over r190).
- [