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,242 @@
|
||||
package amrnb
|
||||
|
||||
// AMR-NB decoder frame driver, ported from opencore-amrnb dec_amr.cpp
|
||||
// (Decoder_amr) and sp_dec.cpp (GSMFrameDecode). It orchestrates the
|
||||
// already-ported building blocks for one 20 ms frame: LSF dequantization and
|
||||
// LSP interpolation, then four subframes of pitch-lag decode, adaptive
|
||||
// codebook, fixed codebook with pitch sharpening, gain decode, excitation
|
||||
// assembly and LP synthesis; finally the formant post-filter and output
|
||||
// high-pass.
|
||||
//
|
||||
// This implements the active-speech (good-frame) path. Error concealment
|
||||
// (bad-frame / DTX), background-noise adaptation, the gain-averaging
|
||||
// (Cb_gain_average) and adaptive phase dispersion are not yet ported, so the
|
||||
// excitation is synthesized directly from the total excitation (equivalent to
|
||||
// phase dispersion disabled) and the code gain is used unmixed.
|
||||
|
||||
const (
|
||||
cSHARPMAX = 13017 // max pitch sharpening
|
||||
cExcOff = cPIT_MAX + cL_INTERPOL // 154: excitation history length
|
||||
cPIT_MIN_MR122 = 18
|
||||
)
|
||||
|
||||
// decoderStateDSP holds the persistent decoder synthesis state across frames.
|
||||
type decoderStateDSP struct {
|
||||
oldExc [cL_SUBFR + cPIT_MAX + cL_INTERPOL]int16 // excitation w/ history
|
||||
lspOld [cM]int16 // previous-frame LSPs
|
||||
memSyn [cM]int16 // synthesis filter memory
|
||||
sharp int16 // pitch sharpening (prev gain_pit)
|
||||
oldT0 int16 // previous integer pitch lag
|
||||
lsf dPlsfState // LSF predictor state
|
||||
pred gcPredState // gain predictor state
|
||||
pst postFilterState // formant post-filter state
|
||||
post postProcessState // output HP filter state
|
||||
}
|
||||
|
||||
func (st *decoderStateDSP) reset() {
|
||||
for i := range st.oldExc {
|
||||
st.oldExc[i] = 0
|
||||
}
|
||||
copy(st.lspOld[:], lsp_init_data[:cM])
|
||||
for i := range st.memSyn {
|
||||
st.memSyn[i] = 0
|
||||
}
|
||||
st.sharp = 0
|
||||
st.oldT0 = 40
|
||||
st.lsf.reset()
|
||||
st.pred.reset()
|
||||
st.pst.reset()
|
||||
st.post = postProcessState{}
|
||||
}
|
||||
|
||||
// sharpenCode applies pitch sharpening to the innovation: code[i] += pitSharp ·
|
||||
// code[i-T0] for i in [T0, L_SUBFR).
|
||||
func sharpenCode(code []int16, T0 int, pitSharp int16) {
|
||||
for i := T0; i < cL_SUBFR; i++ {
|
||||
code[i] = add(code[i], mult(code[i-T0], pitSharp))
|
||||
}
|
||||
}
|
||||
|
||||
// decodeAmr decodes one frame's parameters into 160 raw synthesis samples and
|
||||
// returns the four per-subframe LP coefficient sets for the post-filter.
|
||||
func (st *decoderStateDSP) decodeAmr(mode int, params []int16, synth []int16) []int16 {
|
||||
var lspMid, lspNew [cM]int16
|
||||
at := make([]int16, cNB_SUBFR*cMP1)
|
||||
|
||||
pi := 0
|
||||
if mode == dMR122 {
|
||||
st.lsf.dPlsf5(0, params[pi:pi+5], lspMid[:], lspNew[:])
|
||||
pi += 5
|
||||
intLpc1and3(st.lspOld[:], lspMid[:], lspNew[:], at)
|
||||
} else {
|
||||
st.lsf.dPlsf3(mode, 0, params[pi:pi+3], lspNew[:])
|
||||
pi += 3
|
||||
intLpc1to3(st.lspOld[:], lspNew[:], at)
|
||||
}
|
||||
copy(st.lspOld[:], lspNew[:])
|
||||
|
||||
var code [cL_SUBFR]int16
|
||||
exc := st.oldExc[cExcOff:] // current-subframe excitation window (40 samples)
|
||||
|
||||
azOff := 0
|
||||
subfrNr := -1
|
||||
evenSubfr := int16(0)
|
||||
var indexMR475 int16 // carried across the MR475 subframe pair
|
||||
|
||||
for iSubfr := 0; iSubfr < cL_FRAME; iSubfr += cL_SUBFR {
|
||||
subfrNr++
|
||||
evenSubfr = 1 - evenSubfr
|
||||
az := at[azOff:]
|
||||
|
||||
pitFlag := int16(iSubfr)
|
||||
if iSubfr == cL_FRAME_BY2 && mode != dMR475 && mode != dMR515 {
|
||||
pitFlag = 0
|
||||
}
|
||||
|
||||
// ---- pitch lag + adaptive codebook ----
|
||||
index := params[pi]
|
||||
pi++
|
||||
var T0, T0frac int16
|
||||
if mode != dMR122 {
|
||||
flag4 := int16(0)
|
||||
if mode == dMR475 || mode == dMR515 || mode == dMR59 || mode == dMR67 {
|
||||
flag4 = 1
|
||||
}
|
||||
deltaLow, deltaRange := int16(5), int16(9)
|
||||
if mode == dMR795 {
|
||||
deltaLow, deltaRange = 10, 19
|
||||
}
|
||||
t0min := sub(st.oldT0, deltaLow)
|
||||
if t0min < cPIT_MIN {
|
||||
t0min = cPIT_MIN
|
||||
}
|
||||
t0max := add(t0min, deltaRange)
|
||||
if t0max > cPIT_MAX {
|
||||
t0max = cPIT_MAX
|
||||
t0min = sub(t0max, deltaRange)
|
||||
}
|
||||
T0, T0frac = decLag3(index, t0min, t0max, pitFlag, st.oldT0, flag4)
|
||||
predLt(st.oldExc[:], cExcOff, T0, T0frac, cL_SUBFR, 1)
|
||||
} else {
|
||||
T0, T0frac = decLag6(index, cPIT_MIN_MR122, cPIT_MAX, pitFlag, st.oldT0)
|
||||
predLt(st.oldExc[:], cExcOff, T0, T0frac, cL_SUBFR, 0)
|
||||
}
|
||||
|
||||
// ---- fixed codebook + pitch sharpening ----
|
||||
var gainPit, gainCode int16
|
||||
switch mode {
|
||||
case dMR475, dMR515:
|
||||
posIdx := params[pi]
|
||||
pi++
|
||||
signs := params[pi]
|
||||
pi++
|
||||
decode2i40_9bits(int16(subfrNr), signs, posIdx, code[:])
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR59:
|
||||
posIdx := params[pi]
|
||||
pi++
|
||||
signs := params[pi]
|
||||
pi++
|
||||
decode2i40_11bits(signs, posIdx, code[:])
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR67:
|
||||
posIdx := params[pi]
|
||||
pi++
|
||||
signs := params[pi]
|
||||
pi++
|
||||
decode3i40_14bits(signs, posIdx, code[:])
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR74, dMR795:
|
||||
posIdx := params[pi]
|
||||
pi++
|
||||
signs := params[pi]
|
||||
pi++
|
||||
decode4i40_17bits(signs, posIdx, code[:])
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR102:
|
||||
dec8i40_31bits(params[pi:pi+7], code[:])
|
||||
pi += 7
|
||||
sharpenCode(code[:], int(T0), shl(st.sharp, 1))
|
||||
case dMR122:
|
||||
gpIdx := params[pi]
|
||||
pi++
|
||||
gainPit = dGainPitch(mode, gpIdx)
|
||||
dec10i40_35bits(params[pi:pi+10], code[:])
|
||||
pi += 10
|
||||
sharpenCode(code[:], int(T0), shl(gainPit, 1))
|
||||
}
|
||||
|
||||
// ---- gain decode ----
|
||||
switch mode {
|
||||
case dMR475:
|
||||
if evenSubfr != 0 {
|
||||
indexMR475 = params[pi]
|
||||
pi++
|
||||
}
|
||||
gainPit, gainCode = st.pred.decGain(mode, indexMR475, code[:], evenSubfr)
|
||||
case dMR515, dMR59, dMR67, dMR74, dMR102:
|
||||
idx := params[pi]
|
||||
pi++
|
||||
gainPit, gainCode = st.pred.decGain(mode, idx, code[:], evenSubfr)
|
||||
case dMR795:
|
||||
gpIdx := params[pi]
|
||||
pi++
|
||||
gainPit = dGainPitch(mode, gpIdx)
|
||||
gcIdx := params[pi]
|
||||
pi++
|
||||
gainCode = st.pred.dGainCode(mode, gcIdx, code[:])
|
||||
case dMR122:
|
||||
gcIdx := params[pi]
|
||||
pi++
|
||||
gainCode = st.pred.dGainCode(mode, gcIdx, code[:])
|
||||
}
|
||||
|
||||
// store pitch sharpening for next subframe (not in MR475 even subframe)
|
||||
if mode != dMR475 || evenSubfr == 0 {
|
||||
st.sharp = gainPit
|
||||
if st.sharp > cSHARPMAX {
|
||||
st.sharp = cSHARPMAX
|
||||
}
|
||||
}
|
||||
|
||||
// ---- total excitation: gain_pit·adaptive + gain_code·code ----
|
||||
var pitchFac, tmpShift int16
|
||||
if mode <= dMR102 {
|
||||
pitchFac = gainPit
|
||||
tmpShift = 1
|
||||
} else {
|
||||
pitchFac = shr(gainPit, 1)
|
||||
tmpShift = 2
|
||||
}
|
||||
for i := 0; i < cL_SUBFR; i++ {
|
||||
L := L_mult(exc[i], pitchFac)
|
||||
L = L_mac(L, code[i], gainCode)
|
||||
L = L_shl(L, tmpShift)
|
||||
exc[i] = round_(L)
|
||||
}
|
||||
|
||||
// ---- LP synthesis ----
|
||||
synFilt(az, exc[:cL_SUBFR], synth[iSubfr:iSubfr+cL_SUBFR], cL_SUBFR, st.memSyn[:], false)
|
||||
copy(st.memSyn[:], synth[iSubfr+cL_SUBFR-cM:iSubfr+cL_SUBFR])
|
||||
|
||||
// slide the excitation buffer left by one subframe
|
||||
copy(st.oldExc[:cExcOff], st.oldExc[cL_SUBFR:cL_SUBFR+cExcOff])
|
||||
|
||||
st.oldT0 = T0
|
||||
azOff += cMP1
|
||||
}
|
||||
|
||||
return at
|
||||
}
|
||||
|
||||
// decodeSpeechFrame decodes one good speech frame end-to-end into 160 PCM
|
||||
// samples: parameter decode, post-filter, output high-pass, and the 13-bit
|
||||
// output truncation. Mirrors GSMFrameDecode for the speech path.
|
||||
func (st *decoderStateDSP) decodeSpeechFrame(mode int, params []int16, synth []int16) {
|
||||
az := st.decodeAmr(mode, params, synth)
|
||||
st.pst.postFilter(mode, synth, az)
|
||||
st.post.process(synth, cL_FRAME)
|
||||
for i := 0; i < cL_FRAME; i++ {
|
||||
synth[i] &^= 7 // truncate to 13 bits
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user