feat(capability): 转码能力包(vendor 纯 Go AMR-NB 解码器 + 黄金向量逐样本对照 + 8 哨兵 + 注册面)
This commit is contained in:
1 parent
89715d1813
commit
4a2d276881
100 files changed
+11319
No files matched your search
@@ -0,0 +1,108 @@
|
||||
package amrnb
|
||||
|
||||
// Adaptive formant post-filter, ported from opencore-amrnb pstfilt.cpp. For each
|
||||
// subframe it builds the weighted LP filters A(z/γ3) and A(z/γ4), forms the
|
||||
// residual through A(z/γ3), derives a spectral-tilt compensation coefficient
|
||||
// from the truncated impulse response, applies it via preemphasis, synthesizes
|
||||
// through 1/A(z/γ4), and finally matches the energy back to the synthesis with
|
||||
// AGC. Uses the building blocks weightAi/residu/synFilt/preemphasis/agc; this is
|
||||
// the orchestration that chains them. Bit-exact with the reference.
|
||||
|
||||
const (
|
||||
cL_H = 22 // truncated impulse-response length
|
||||
cMU = 26214 // tilt compensation factor (0.8)
|
||||
)
|
||||
|
||||
// γ bandwidth-expansion factors (pstfilt.cpp).
|
||||
var gamma3MR122 = [cM]int16{22938, 16057, 11240, 7868, 5508, 3856, 2699, 1889, 1322, 925}
|
||||
var gamma3 = [cM]int16{18022, 9912, 5451, 2998, 1649, 907, 499, 274, 151, 83}
|
||||
var gamma4MR122 = [cM]int16{24576, 18432, 13824, 10368, 7776, 5832, 4374, 3281, 2461, 1846}
|
||||
var gamma4 = [cM]int16{22938, 16057, 11240, 7868, 5508, 3856, 2699, 1889, 1322, 925}
|
||||
|
||||
// postFilterState holds the formant post-filter memory across frames.
|
||||
type postFilterState struct {
|
||||
res2 [cL_SUBFR]int16
|
||||
memSynPst [cM]int16
|
||||
preemph int16
|
||||
agc agcState
|
||||
synthBuf [cM + cL_FRAME]int16 // M history + current frame
|
||||
}
|
||||
|
||||
func (st *postFilterState) reset() {
|
||||
*st = postFilterState{}
|
||||
}
|
||||
|
||||
// postFilter post-filters one 160-sample synthesis frame in place. az4 holds the
|
||||
// four per-subframe LP coefficient sets (4*cMP1). Mirrors Post_Filter.
|
||||
func (st *postFilterState) postFilter(mode int, syn []int16, az4 []int16) {
|
||||
var ap3, ap4 [cMP1]int16
|
||||
var h [cL_H]int16
|
||||
|
||||
synWork := st.synthBuf[cM:] // syn_work[i] == synthBuf[M+i]
|
||||
copy(synWork[:cL_FRAME], syn[:cL_FRAME])
|
||||
|
||||
azOff := 0
|
||||
for iSubfr := 0; iSubfr < cL_FRAME; iSubfr += cL_SUBFR {
|
||||
az := az4[azOff:]
|
||||
if mode == dMR122 || mode == dMR102 {
|
||||
weightAi(az, gamma3MR122[:], ap3[:])
|
||||
weightAi(az, gamma4MR122[:], ap4[:])
|
||||
} else {
|
||||
weightAi(az, gamma3[:], ap3[:])
|
||||
weightAi(az, gamma4[:], ap4[:])
|
||||
}
|
||||
|
||||
// Residual through A(z/γ3); syn_work[iSubfr] == synthBuf[M+iSubfr].
|
||||
residu(ap3[:], st.synthBuf[:], cM+iSubfr, cL_SUBFR, st.res2[:])
|
||||
|
||||
// Truncated impulse response of A(z/γ3)/A(z/γ4).
|
||||
copy(h[:cMP1], ap3[:cMP1])
|
||||
for i := cMP1; i < cL_H; i++ {
|
||||
h[i] = 0
|
||||
}
|
||||
synFilt(ap4[:], h[:], h[:], cL_H, h[cMP1:], false)
|
||||
|
||||
// Tilt compensation coefficient from the impulse-response autocorr.
|
||||
var lTmp int32
|
||||
for i := cL_H - 1; i >= 0; i-- {
|
||||
t2 := int32(h[i]) * int32(h[i])
|
||||
if t2 == 0x40000000 {
|
||||
break // reference sets overflow and stops without adding
|
||||
}
|
||||
lTmp = L_add(lTmp, t2<<1)
|
||||
}
|
||||
temp1 := int16(lTmp >> 16)
|
||||
|
||||
lTmp = 0
|
||||
for i := cL_H - 2; i >= 0; i-- {
|
||||
t2 := int32(h[i]) * int32(h[i+1])
|
||||
if t2 == 0x40000000 {
|
||||
break
|
||||
}
|
||||
lTmp = L_add(lTmp, t2<<1)
|
||||
}
|
||||
temp2 := int16(lTmp >> 16)
|
||||
|
||||
if temp2 <= 0 {
|
||||
temp2 = 0
|
||||
} else {
|
||||
lt := (int32(temp2) * cMU) >> 15
|
||||
if lt&0x00010000 != 0 {
|
||||
lt |= int32(-0x10000)
|
||||
}
|
||||
temp2 = int16(lt)
|
||||
temp2 = div_s(temp2, temp1)
|
||||
}
|
||||
|
||||
preemphasis(&st.preemph, st.res2[:], temp2, cL_SUBFR)
|
||||
|
||||
synFilt(ap4[:], st.res2[:], syn[iSubfr:], cL_SUBFR, st.memSynPst[:], true)
|
||||
|
||||
st.agc.agc(synWork[iSubfr:], syn[iSubfr:], cAGC_FAC, cL_SUBFR)
|
||||
|
||||
azOff += cMP1
|
||||
}
|
||||
|
||||
// Carry the last M samples as history for the next frame.
|
||||
copy(st.synthBuf[:cM], synWork[cL_FRAME-cM:cL_FRAME])
|
||||
}
|
||||
Reference in new issue
Block a user