Files
AskaEth 4a2d276881
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(capability): 转码能力包(vendor 纯 Go AMR-NB 解码器 + 黄金向量逐样本对照 + 8 哨兵 + 注册面)
2026-10-05 13:02:28 +08:00

65 lines
2.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package amrnb
// Per-subframe target-signal and impulse-response setup, ported from
// opencore-amrnb spreproc.cpp (subframePreProc). For each subframe it builds the
// perceptually weighted LP filters A(z/γ1)/A(z/γ2), the weighted synthesis
// impulse response h1, the LP residual (exc/res2), and the target signal xn for
// the pitch search — feeding the closed-loop pitch and codebook searches. Uses
// weightAi/synFilt/residu (all already ported). Bit-exact with the reference.
// perceptual-weighting spectral expansion factors (cod_amr.cpp).
var gamma1 = [cM]int16{30802, 28954, 27217, 25584, 24049, 22606, 21250, 19975, 18777, 17650}
var gamma1_12k2 = [cM]int16{29491, 26542, 23888, 21499, 19349, 17414, 15672, 14105, 12694, 11425}
var gamma2 = [cM]int16{19661, 11797, 7078, 4247, 2548, 1529, 917, 550, 330, 198}
// subframePreProc computes, for one subframe:
// - h1[0:L_SUBFR] the weighted synthesis impulse response,
// - exc/res2 the LP residual,
// - error the synthesis error,
// - xn[0:L_SUBFR] the pitch-search target.
//
// a/aq are the unquantized/quantized LP coefficients for this subframe (M+1
// each). speech is positioned so speech[speechOff-M : speechOff+L_SUBFR] is the
// current subframe with history. memErr and memW0 are the synthesis-error and
// weighting-filter memories (M each), read but not updated here. Mirrors
// subframePreProc.
func subframePreProc(mode int, a, aq, speech []int16, speechOff int, memErr, memW0 []int16, exc, h1, xn, res2, errSig []int16) {
var ap1, ap2 [cMP1]int16
g1 := gamma1[:]
if mode == dMR122 || mode == dMR102 {
g1 = gamma1_12k2[:]
}
weightAi(a, g1, ap1[:])
weightAi(a, gamma2[:], ap2[:])
// h1 = impulse response of A(z/γ1) / (Aq(z)·A(z/γ2))
var aiZero [cL_SUBFR]int16
copy(aiZero[:cMP1], ap1[:cMP1]) // Ap1 then zeros
zero := make([]int16, cM)
synFilt(aq, aiZero[:], h1, cL_SUBFR, zero, false)
for i := range zero {
zero[i] = 0
}
synFilt(ap2[:], h1, h1, cL_SUBFR, zero, false)
// LP residual and synthesis error
residu(aq, speech, speechOff, cL_SUBFR, res2)
copy(exc[:cL_SUBFR], res2[:cL_SUBFR])
// error = synthesis of the residual (with error memory)
memErrCopy := make([]int16, cM)
copy(memErrCopy, memErr[:cM])
synFilt(aq, exc, errSig, cL_SUBFR, memErrCopy, false)
// xn = weighted error (target for pitch search)
// Residu(Ap1, error): error needs M history -> supplied as memErr before it.
var eb [cM + cL_SUBFR]int16
copy(eb[:cM], memErr[:cM])
copy(eb[cM:], errSig[:cL_SUBFR])
residu(ap1[:], eb[:], cM, cL_SUBFR, xn)
memW0Copy := make([]int16, cM)
copy(memW0Copy, memW0[:cM])
synFilt(ap2[:], xn, xn, cL_SUBFR, memW0Copy, false)
}