158 lines
4.7 KiB
Go
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
|
|
}
|