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

158 lines
4.7 KiB
Go

package amrnb
// LSP/LSF conversions and interpolation, ported function-by-function from the
// opencore-amrnb common sources (lsp_az.cpp, lsp_lsf.cpp, int_lpc.cpp). These
// turn the decoded line-spectral representation into the per-subframe LP
// synthesis coefficients A(z) (order 10). Bit-exact with the reference.
// getLspPol finds the coefficients of F1(z) or F2(z) from the (cosine-domain)
// LSPs by expanding the product polynomial. f must have length 6. Mirrors
// Get_lsp_pol (lsp_az.cpp).
func getLspPol(lsp []int16, f []int32) {
fi := 0
li := 0
f[fi] = 0x01000000 // f[0] = 1.0
fi++
f[fi] = (-int32(lsp[li])) << 10 // f[1] = -2.0 * lsp[0]
fi++
li++
li++ // advance lsp pointer
for i := int16(2); i <= 5; i++ {
f[fi] = f[fi-2]
for j := int16(1); j < i; j++ {
hi := int16(f[fi-1] >> 16)
lo := int16((f[fi-1] >> 1) - (int32(hi) << 15))
t0 := int32(hi) * int32(lsp[li])
t0 += (int32(lo) * int32(lsp[li])) >> 15
f[fi] += f[fi-2]
f[fi] -= t0 << 2
fi--
}
f[fi] -= int32(lsp[li]) << 10
li++
fi += int(i)
li++
}
}
// lspAz converts line spectral pairs to order-10 LP coefficients a[0:11].
// Mirrors Lsp_Az (lsp_az.cpp).
func lspAz(lsp []int16, a []int16) {
var f1, f2 [6]int32
getLspPol(lsp[0:], f1[:])
getLspPol(lsp[1:], f2[:])
for i := 5; i > 0; i-- {
f1[i] += f1[i-1]
f2[i] -= f2[i-1]
}
a[0] = 4096
for i, j := 1, 10; i <= 5; i, j = i+1, j-1 {
t0 := f1[i] + f2[i]
t1 := f1[i] - f2[i]
t0 += 1 << 12
t1 += 1 << 12
a[i] = int16(t0 >> 13)
a[j] = int16(t1 >> 13)
}
}
// lsfLsp converts normalized LSFs (Q15, 0..0.5) to LSPs (cosine domain) by
// table lookup and interpolation. Mirrors Lsf_lsp (lsp_lsf.cpp).
func lsfLsp(lsf, lsp []int16, m int16) {
for i := int16(0); i < m; i++ {
ind := lsf[i] >> 8 // b8-b15
offset := lsf[i] & 0x00ff // b0-b7
L_tmp := (int32(lspLsfTable[ind+1]) - int32(lspLsfTable[ind])) * int32(offset) >> 8
lsp[i] = lspLsfTable[ind] + int16(L_tmp)
}
}
// lspLsf converts LSPs (cosine domain) to normalized LSFs (Q15) via the acos
// table and per-segment slope. Mirrors Lsp_lsf (lsp_lsf.cpp).
func lspLsf(lsp, lsf []int16, m int16) {
ind := int16(63)
for i := m - 1; i >= 0; i-- {
temp := lsp[i]
for lspLsfTable[ind] < temp {
ind--
}
L_tmp := (int32(temp) - int32(lspLsfTable[ind])) * int32(lspLsfSlope[ind])
L_tmp = (L_tmp + 0x800) >> 12
lsf[i] = int16(L_tmp) + (ind << 8)
}
}
// intLpc1and3 interpolates LSPs across the four subframes (old/mid/new LSP
// sets) and produces A(z) for each, into Az (length 4*cMP1). Used by modes that
// transmit a mid-frame LSP set. Mirrors Int_lpc_1and3 (int_lpc.cpp).
func intLpc1and3(lspOld, lspMid, lspNew []int16, Az []int16) {
var lsp [cM]int16
for i := 0; i < cM; i++ {
lsp[i] = (lspOld[i] >> 1) + (lspMid[i] >> 1)
}
lspAz(lsp[:], Az[0:]) // subframe 1
lspAz(lspMid, Az[cMP1:]) // subframe 2
for i := 0; i < cM; i++ {
lsp[i] = (lspMid[i] >> 1) + (lspNew[i] >> 1)
}
lspAz(lsp[:], Az[2*cMP1:]) // subframe 3
lspAz(lspNew, Az[3*cMP1:]) // subframe 4
}
// intLpc1to3 interpolates between only the past-frame and present-frame LSP
// sets (no mid set) across the four subframes. Mirrors Int_lpc_1to3.
func intLpc1to3(lspOld, lspNew []int16, Az []int16) {
var lsp [cM]int16
for i := 0; i < cM; i++ {
temp := lspOld[i] - (lspOld[i] >> 2)
lsp[i] = temp + (lspNew[i] >> 2)
}
lspAz(lsp[:], Az[0:]) // subframe 1
for i := 0; i < cM; i++ {
lsp[i] = (lspNew[i] >> 1) + (lspOld[i] >> 1)
}
lspAz(lsp[:], Az[cMP1:]) // subframe 2
for i := 0; i < cM; i++ {
temp := lspNew[i] - (lspNew[i] >> 2)
lsp[i] = temp + (lspOld[i] >> 2)
}
lspAz(lsp[:], Az[2*cMP1:]) // subframe 3
lspAz(lspNew, Az[3*cMP1:]) // subframe 4
}
// intLpc1and3_2 interpolates only subframes 1 and 3 (leaving 2 and 4 as the
// directly-computed A_mid/A_new), used for the unquantized analysis filters.
// Mirrors Int_lpc_1and3_2.
func intLpc1and3_2(lspOld, lspMid, lspNew, az []int16) {
var lsp [cM]int16
for i := 0; i < cM; i++ {
lsp[i] = (lspOld[i] >> 1) + (lspMid[i] >> 1)
}
lspAz(lsp[:], az[0:]) // subframe 1
for i := 0; i < cM; i++ {
lsp[i] = (lspMid[i] >> 1) + (lspNew[i] >> 1)
}
lspAz(lsp[:], az[2*cMP1:]) // subframe 3
}
// intLpc1to3_2 interpolates subframes 1, 2 and 3 (leaving 4 as A_new). Mirrors
// Int_lpc_1to3_2.
func intLpc1to3_2(lspOld, lspNew, az []int16) {
var lsp [cM]int16
for i := 0; i < cM; i++ {
temp := lspOld[i] - (lspOld[i] >> 2)
lsp[i] = temp + (lspNew[i] >> 2)
}
lspAz(lsp[:], az[0:]) // subframe 1
for i := 0; i < cM; i++ {
lsp[i] = (lspNew[i] >> 1) + (lspOld[i] >> 1)
}
lspAz(lsp[:], az[cMP1:]) // subframe 2
for i := 0; i < cM; i++ {
temp := lspNew[i] - (lspNew[i] >> 2)
lsp[i] = temp + (lspOld[i] >> 2)
}
lspAz(lsp[:], az[2*cMP1:]) // subframe 3
}