Files
Cyrene_v2/internal/capability/transcode/amrnb/dsp_postproc.go
T
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

68 lines
2.2 KiB
Go
Raw 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
// Output post-processing building blocks, ported from opencore-amrnb
// weight_a.cpp (Weight_Ai), preemph.cpp (preemphasis) and post_pro.cpp
// (Post_Process). weightAi applies gamma bandwidth expansion to an LP filter;
// preemphasis is the 1st-order y[n]=x[n]-g·x[n-1]; postProcess is the decoder's
// output high-pass biquad with the ×2 output scaling. Bit-exact with the
// reference.
// weightAi computes the bandwidth-expanded coefficients a_exp[i] = a[i]·fac[i-1]
// (with a_exp[0]=a[0]). Mirrors Weight_Ai.
func weightAi(a []int16, fac []int16, aExp []int16) {
aExp[0] = a[0]
for i := 1; i <= cM; i++ {
aExp[i] = int16((int32(a[i])*int32(fac[i-1]) + 0x4000) >> 15)
}
}
// preemphasis applies y[n] = x[n] - g·x[n-1] in place over L samples, carrying
// one sample of memory. Mirrors preemphasis (preemph.cpp).
func preemphasis(memPre *int16, signal []int16, g int16, L int) {
temp := signal[L-1]
for i := L - 1; i >= 1; i-- {
signal[i] = sub(signal[i], mult(g, signal[i-1]))
}
signal[0] = sub(signal[0], mult(g, *memPre))
*memPre = temp
}
// post-process output high-pass biquad coefficients (post_pro.cpp).
var postB = [3]int16{7699, -15398, 7699}
var postA = [3]int16{8192, 15836, -7667}
// postProcessState holds the biquad's double-precision input/output memory.
type postProcessState struct {
x0, x1 int16
y1hi, y1lo, y2hi, y2lo int16
}
// process applies the output high-pass filter (with ×2 gain) in place over lg
// samples. The feedback memory is kept as (hi,lo) double precision. Mirrors
// Post_Process.
func (st *postProcessState) process(signal []int16, lg int) {
a1, a2 := int32(postA[1]), int32(postA[2])
b0, b1, b2 := int32(postB[0]), int32(postB[1]), int32(postB[2])
for i := 0; i < lg; i++ {
x2 := st.x1
st.x1 = st.x0
st.x0 = signal[i]
L := int32(st.y1hi) * a1
L += (int32(st.y1lo) * a1) >> 15
L += int32(st.y2hi) * a2
L += (int32(st.y2lo) * a2) >> 15
L += int32(st.x0) * b0
L += int32(st.x1) * b1
L += int32(x2) * b2
L = L_shl(L, 3)
signal[i] = round_(L_shl(L, 1))
st.y2hi = st.y1hi
st.y2lo = st.y1lo
st.y1hi = int16(L >> 16)
st.y1lo = int16((L >> 1) - (int32(st.y1hi) << 15))
}
}