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

102 lines
3.0 KiB
Go

package amrnb
// Gain dequantization, ported from opencore-amrnb d_gain_p.cpp, d_gain_c.cpp and
// dec_gain.cpp. These turn the received gain indices into the per-subframe pitch
// gain and fixed-codebook gain, driving the gc_pred energy predictor. dGainPitch
// and dGainCode handle MR795/MR122; decGain handles the joint/scalar-VQ modes
// (MR475 joint, MR515/MR59 low-rate, MR67/MR74/MR102 high-rate). Bit-exact with
// the reference.
const cMR475_VQ_SIZE = 256
// dGainPitch returns the quantized pitch gain (Q14) for the given index.
// Mirrors d_gain_pitch.
func dGainPitch(mode int, index int16) int16 {
gain := qua_gain_pitch[index]
if mode == dMR122 {
gain &^= 3 // clear 2 LSBits
}
return gain
}
// dGainCode decodes the fixed-codebook gain for MR795/MR122 from the predicted
// gain (gc_pred) and the quantized correction factor, then updates the
// predictor. Mirrors d_gain_code.
func (pred *gcPredState) dGainCode(mode int, index int16, code []int16) (gainCode int16) {
r := pred.gcPred(mode, code)
exp, frac := r.expGcode0, r.fracGcode0
index &= 31 // index < 32, avoid buffer overflow
tblTmp := index + (index << 1)
p := qua_gain_code[tblTmp:]
if mode == dMR122 {
gcode0 := int16(pow2(exp, frac))
gcode0 = shl(gcode0, 4)
gainCode = shl(mult(gcode0, p[0]), 1)
} else {
gcode0 := int16(pow2(14, frac))
lTmp := L_mult(p[0], gcode0)
lTmp = L_shr(lTmp, sub(9, exp))
gainCode = int16(lTmp >> 16) // Q1
}
quaEnerMR122 := p[1]
quaEner := p[2]
pred.update(quaEnerMR122, quaEner)
return gainCode
}
// decGain decodes both the pitch gain and fixed-codebook gain for the
// scalar/joint-VQ modes (all except MR795/MR122), updating the predictor.
// evenSubfr selects the MR475 joint-gain half. Mirrors Dec_gain.
func (pred *gcPredState) decGain(mode int, index int16, code []int16, evenSubfr int16) (gainPit, gainCod int16) {
index = shl(index, 2)
var gCode, quaEnerMR122, quaEner int16
switch {
case mode == dMR102 || mode == dMR74 || mode == dMR67:
p := table_gain_highrates[index:]
gainPit = p[0]
gCode = p[1]
quaEnerMR122 = p[2]
quaEner = p[3]
case mode == dMR475:
index += (1 ^ evenSubfr) << 1 // evenSubfr is 0 or 1
if index > int16(cMR475_VQ_SIZE*4-2) {
index = int16(cMR475_VQ_SIZE*4 - 2)
}
p := table_gain_MR475[index:]
gainPit = p[0]
gCode = p[1]
// Predictor update values are recomputed (not stored in the 4.75 table):
// qua_ener_MR122 = log2(g), qua_ener = 20*log10(g)
e, f := log2(int32(gCode)) // Log2(x Q12) = log2(x) + 12
e -= 12
t1 := shr_r(f, 5)
t2 := shl(e, 10)
quaEnerMR122 = add(t1, t2)
lTmp := mpy32_16(e, f, 24660) // 24660 Q12 ~= 20*log10(2)
lTmp = L_shl(lTmp, 13)
quaEner = round_(lTmp)
default: // MR515, MR59
p := table_gain_lowrates[index:]
gainPit = p[0]
gCode = p[1]
quaEnerMR122 = p[2]
quaEner = p[3]
}
r := pred.gcPred(mode, code)
exp, frac := r.expGcode0, r.fracGcode0
gcode0 := int16(pow2(14, frac))
lTmp := L_mult(gCode, gcode0)
lTmp = L_shr(lTmp, 10-exp)
gainCod = int16(lTmp >> 16)
pred.update(quaEnerMR122, quaEner)
return gainPit, gainCod
}