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

This commit is contained in:
AskaEth committed 2026-10-05 13:02:28 +08:00
1 parent 89715d1813
commit 4a2d276881
100 files changed
+11319

No files matched your search

@@ -0,0 +1,64 @@
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)
}