243 lines
7.3 KiB
Go
243 lines
7.3 KiB
Go
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
|
|
}
|
|
}
|