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

139 lines
4.0 KiB
Go

package amrnb
// Gain quantization (general modes), ported from opencore-amrnb qua_gain.cpp
// (Qua_gain) and calc_en.cpp (calc_filt_energies). calcFiltEnergies forms the
// five quadratic-form energy coefficients of the gain error from the target,
// the adaptive codebook y1 and the filtered innovation y2; quaGain searches the
// gain VQ table for the (pitch, code) gain pair minimizing that error, returning
// the index and the dequantized gains — the exact encoder counterpart of
// decGain. Bit-exact with the reference.
const (
cVQ_SIZE_HIGHRATES = 128
cVQ_SIZE_LOWRATES = 64
)
// calcFiltEnergies computes the five energy coefficients (frac/exp) of the gain
// MSE. gCoeff[0..3] are the <xn,y1>/<y1,y1> correlations from gPitch. For
// MR795/MR475 it also returns the optimum unconstrained code gain. Mirrors
// calc_filt_energies.
func calcFiltEnergies(mode int, xn, xn2, y1, y2, gCoeff []int16) (fracCoeff, expCoeff [5]int16, codGainFrac, codGainExp int16) {
fracCoeff[0] = gCoeff[0]
expCoeff[0] = gCoeff[1]
fracCoeff[1] = negate(gCoeff[2])
expCoeff[1] = gCoeff[3] + 1
var s1, s2, s3 int32
if mode != dMR795 && mode != dMR475 {
s1, s2, s3 = 1, 1, 1
}
var scaledY2 [cL_SUBFR]int16
for i := 0; i < cL_SUBFR; i++ {
tmp := y2[i] >> 3
scaledY2[i] = tmp
s1 = L_mac(s1, tmp, tmp)
s2 = L_mac(s2, xn[i], tmp)
s3 = L_mac(s3, y1[i], tmp)
}
exp := norm_l(s1)
fracCoeff[2] = int16(L_shl(s1, exp) >> 16)
expCoeff[2] = -3 - exp
exp = norm_l(s2)
fracCoeff[3] = negate(int16(L_shl(s2, exp) >> 16))
expCoeff[3] = 7 - exp
exp = norm_l(s3)
fracCoeff[4] = int16(L_shl(s3, exp) >> 16)
expCoeff[4] = 7 - exp
if mode == dMR795 || mode == dMR475 {
s1 = 0
for i := 0; i < cL_SUBFR; i++ {
s1 += int32(xn2[i]) * int32(scaledY2[i])
}
s1 <<= 1
exp = norm_l(s1)
frac := int16(L_shl(s1, exp) >> 16)
exp = 6 - exp
if frac <= 0 {
codGainFrac = 0
codGainExp = 0
} else {
codGainFrac = div_s(shr(frac, 1), fracCoeff[2])
codGainExp = (exp - expCoeff[2]) - 14
}
}
return
}
// quaGain searches the mode's gain VQ table for the (pitch, code) gain pair
// minimizing the weighted gain MSE, returning the index and dequantized gains
// plus the predictor-update energies. Mirrors Qua_gain.
func quaGain(mode int, expGcode0, fracGcode0 int16, fracCoeff, expCoeff []int16, gpLimit int16) (index, gainPit, gainCod, quaEnerMR122, quaEner int16) {
var tableGain []int16
var tableLen int
if mode == dMR102 || mode == dMR74 || mode == dMR67 {
tableLen = cVQ_SIZE_HIGHRATES
tableGain = table_gain_highrates
} else {
tableLen = cVQ_SIZE_LOWRATES
tableGain = table_gain_lowrates
}
gcode0 := int16(pow2(14, fracGcode0))
expCode := expGcode0 - 11
var expMax [5]int16
expMax[0] = expCoeff[0] - 13
expMax[1] = expCoeff[1] - 14
temp := shl(expCode, 1) + 15
expMax[2] = add(expCoeff[2], temp)
expMax[3] = add(expCoeff[3], expCode)
expMax[4] = add(expCoeff[4], expCode+1)
eMax := expMax[0]
for i := 1; i < 5; i++ {
if expMax[i] > eMax {
eMax = expMax[i]
}
}
eMax++
var coeff, coeffLo [5]int16
for i := 0; i < 5; i++ {
j := eMax - expMax[i]
coeff[i], coeffLo[i] = L_Extract(L_shr(int32(fracCoeff[i])<<16, j))
}
distMin := int32(maxInt32)
for i := 0; i < tableLen; i++ {
p := i << 2
gPitch := tableGain[p]
gCode := tableGain[p+1]
if gPitch <= gpLimit {
gc := mult(gCode, gcode0)
g2Pitch := mult(gPitch, gPitch)
g2Code := mult(gc, gc)
gPitCod := mult(gc, gPitch)
L_tmp := mpy32_16(coeff[0], coeffLo[0], g2Pitch)
L_tmp = L_add(L_tmp, mpy32_16(coeff[1], coeffLo[1], gPitch))
L_tmp = L_add(L_tmp, mpy32_16(coeff[2], coeffLo[2], g2Code))
L_tmp = L_add(L_tmp, mpy32_16(coeff[3], coeffLo[3], gc))
L_tmp = L_add(L_tmp, mpy32_16(coeff[4], coeffLo[4], gPitCod))
if L_tmp < distMin {
distMin = L_tmp
index = int16(i)
}
}
}
p := int(index) << 2
gainPit = tableGain[p]
gCode := tableGain[p+1]
quaEnerMR122 = tableGain[p+2]
quaEner = tableGain[p+3]
L_tmp := L_shr(L_mult(gCode, gcode0), 10-expGcode0)
gainCod = int16(L_tmp >> 16)
return
}