diff --git a/decoder.go b/decoder.go index 73ad978..24c611b 100644 --- a/decoder.go +++ b/decoder.go @@ -37,6 +37,7 @@ type Decoder struct { resampleBuffer []float32 resampleChannelIn [2][]float32 resampleChannelOut [2][]float32 + resampleChannelOut16 [2][]int16 silkResampler [2]silkresample.Resampler silkResamplerBandwidth Bandwidth silkResamplerChannels int @@ -45,6 +46,7 @@ type Decoder struct { silkRedundancyFades []silkRedundancyFade silkCeltAdditions []silkCeltAddition floatBuffer []float32 + int16Buffer []int16 sampleRate int channels int } @@ -140,6 +142,29 @@ func (d *Decoder) resampleSilk(in, out []float32, channelCount int, bandwidth Ba return nil } +func (d *Decoder) resampleSilkToInt16(in []float32, out []int16, channelCount int, bandwidth Bandwidth) error { + if err := d.initSilkResampler(channelCount, bandwidth); err != nil { + return err + } + + samplesPerChannel := len(in) / channelCount + resampledSamplesPerChannel := samplesPerChannel * d.sampleRate / bandwidth.SampleRate() + for channelIndex := range channelCount { + if err := d.resampleSilkChannelToInt16( + in, + out, + channelIndex, + channelCount, + samplesPerChannel, + resampledSamplesPerChannel, + ); err != nil { + return err + } + } + + return nil +} + func (d *Decoder) initSilkResampler(channelCount int, bandwidth Bandwidth) error { if d.silkResamplerBandwidth != bandwidth { for i := range d.silkResampler { @@ -163,7 +188,6 @@ func (d *Decoder) resampleSilkChannel( channelIndex, channelCount, samplesPerChannel, resampledSamplesPerChannel int, ) error { if channelCount == 1 { - // Mono samples are already contiguous, so skip deinterleave/reinterleave scratch. return d.silkResampler[channelIndex].Resample( in[:samplesPerChannel], out[:resampledSamplesPerChannel], @@ -191,6 +215,39 @@ func (d *Decoder) resampleSilkChannel( return nil } +func (d *Decoder) resampleSilkChannelToInt16( + in []float32, + out []int16, + channelIndex, channelCount, samplesPerChannel, resampledSamplesPerChannel int, +) error { + if channelCount == 1 { + return d.silkResampler[channelIndex].ResampleToInt16( + in[:samplesPerChannel], + out[:resampledSamplesPerChannel], + ) + } + + if cap(d.resampleChannelIn[channelIndex]) < samplesPerChannel { + d.resampleChannelIn[channelIndex] = make([]float32, samplesPerChannel) + } + if cap(d.resampleChannelOut16[channelIndex]) < resampledSamplesPerChannel { + d.resampleChannelOut16[channelIndex] = make([]int16, resampledSamplesPerChannel) + } + channelIn := d.resampleChannelIn[channelIndex][:samplesPerChannel] + channelOut := d.resampleChannelOut16[channelIndex][:resampledSamplesPerChannel] + for i := range samplesPerChannel { + channelIn[i] = in[(i*channelCount)+channelIndex] + } + if err := d.silkResampler[channelIndex].ResampleToInt16(channelIn, channelOut); err != nil { + return err + } + for i := range resampledSamplesPerChannel { + out[(i*channelCount)+channelIndex] = channelOut[i] + } + + return nil +} + // resetModeState applies the decoder resets required by RFC 6716 Section 4.5.2 // before the first frame decoded in a new operating mode. func (d *Decoder) resetModeState(mode configurationMode) { @@ -1185,6 +1242,55 @@ func (d *Decoder) decodeToFloat32( return samplesPerChannel, bandwidth, isStereo, nil } +func (d *Decoder) decodeToInt16( + in []byte, + out []int16, +) (samplesPerChannel int, bandwidth Bandwidth, isStereo bool, err error) { + if d.sampleRate == 0 { + return 0, 0, false, errInvalidSampleRate + } + if d.channels == 0 { + return 0, 0, false, errInvalidChannelCount + } + + bandwidth, decodedSampleRate, isStereo, sampleCount, decodedChannelCount, err := d.decode(in, d.silkBuffer) + if err != nil { + return 0, 0, false, err + } + + samplesPerChannel, handled, err := d.finishDecodeToInt16( + out, + bandwidth, + decodedSampleRate, + sampleCount, + decodedChannelCount, + ) + if err != nil { + return 0, 0, false, err + } + if handled { + return samplesPerChannel, bandwidth, isStereo, nil + } + + if cap(d.floatBuffer) < len(out) { + d.floatBuffer = make([]float32, len(out)) + } + d.floatBuffer = d.floatBuffer[:len(out)] + samplesPerChannel, err = d.finishDecodeToFloat32( + d.floatBuffer, + bandwidth, + decodedSampleRate, + sampleCount, + decodedChannelCount, + ) + if err != nil { + return 0, 0, false, err + } + float32ToInt16(d.floatBuffer, out, samplesPerChannel*d.channels) + + return samplesPerChannel, bandwidth, isStereo, nil +} + func (d *Decoder) finishDecodeToFloat32( out []float32, bandwidth Bandwidth, @@ -1223,13 +1329,53 @@ func (d *Decoder) finishDecodeToFloat32( return samplesPerChannel, nil } +func (d *Decoder) finishDecodeToInt16( + out []int16, + bandwidth Bandwidth, + decodedSampleRate int, + sampleCount int, + decodedChannelCount int, +) (samplesPerChannel int, handled bool, err error) { + defer func() { + if err != nil { + // Redundancy transitions belong to this packet only. + d.clearSilkRedundancyTransitions() + } + }() + + samplesPerChannel = (sampleCount / decodedChannelCount) * d.sampleRate / decodedSampleRate + if len(out) < samplesPerChannel*d.channels { + return 0, false, errOutBufferTooSmall + } + if d.needsResampleBuffer(decodedChannelCount) { + return samplesPerChannel, false, nil + } + + requiredSamples := samplesPerChannel * decodedChannelCount + decodedMode := d.previousMode + switch { + case decodedMode == configurationModeSilkOnly && + decodedSampleRate == bandwidth.SampleRate() && + bandwidth != BandwidthFullband: + err = d.resampleSilkToInt16(d.silkBuffer[:sampleCount], out[:requiredSamples], decodedChannelCount, bandwidth) + case d.sampleRate == decodedSampleRate: + float32ToInt16(d.silkBuffer[:sampleCount], out, sampleCount) + default: + err = d.resampleSilkToInt16(d.silkBuffer[:sampleCount], out[:requiredSamples], decodedChannelCount, bandwidth) + } + if err != nil { + return 0, false, err + } + + return samplesPerChannel, true, nil +} + func (d *Decoder) prepareResampleOutput( out []float32, requiredSamples int, decodedChannelCount int, ) (resampleOut []float32, useResampleBuffer bool) { if !d.needsResampleBuffer(decodedChannelCount) { - // Direct output is safe when no channel remap or redundancy mix runs afterward. return out[:requiredSamples], false } @@ -1365,22 +1511,17 @@ func float32ToInt16(in []float32, out []int16, sampleCount int) { // Decode decodes the Opus bitstream into S16LE PCM. func (d *Decoder) Decode(in, out []byte) (bandwidth Bandwidth, isStereo bool, err error) { - if cap(d.floatBuffer) < len(out)/2 { - d.floatBuffer = make([]float32, len(out)/2) + if cap(d.int16Buffer) < len(out)/2 { + d.int16Buffer = make([]int16, len(out)/2) } - d.floatBuffer = d.floatBuffer[:len(out)/2] + d.int16Buffer = d.int16Buffer[:len(out)/2] - sampleCount, bandwidth, isStereo, err := d.decodeToFloat32(in, d.floatBuffer) + sampleCount, bandwidth, isStereo, err := d.decodeToInt16(in, d.int16Buffer) if err != nil { return } - err = bitdepth.ConvertFloat32LittleEndianToSigned16LittleEndian( - d.floatBuffer[:sampleCount*d.channels], - out, - d.channels, - 1, - ) + err = bitdepth.Signed16ToLittleEndian(d.int16Buffer[:sampleCount*d.channels], out) return } @@ -1394,19 +1535,9 @@ func (d *Decoder) DecodeFloat32(in []byte, out []float32) (bandwidth Bandwidth, // DecodeToInt16 decodes Opus data into signed 16-bit PCM and returns the sample count per channel. func (d *Decoder) DecodeToInt16(in []byte, out []int16) (int, error) { - if cap(d.floatBuffer) < len(out) { - d.floatBuffer = make([]float32, len(out)) - } - d.floatBuffer = d.floatBuffer[:len(out)] - - sampleCount, _, _, err := d.decodeToFloat32(in, d.floatBuffer) - if err != nil { - return 0, err - } + sampleCount, _, _, err := d.decodeToInt16(in, out) - float32ToInt16(d.floatBuffer, out, sampleCount*d.channels) - - return sampleCount, nil + return sampleCount, err } // DecodeToFloat32 decodes Opus data into float32 PCM and returns the sample count per channel. diff --git a/decoder_test.go b/decoder_test.go index ba24411..72ea444 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -13,6 +13,7 @@ import ( "sync" "testing" + "github.com/pion/opus/internal/bitdepth" "github.com/pion/opus/pkg/oggreader" "github.com/stretchr/testify/assert" ) @@ -171,6 +172,18 @@ func TestFinishDecodeToFloat32ClearsSilkRedundancyOnError(t *testing.T) { assert.Empty(t, decoder.silkCeltAdditions) } +func TestFinishDecodeToInt16ClearsSilkRedundancyOnError(t *testing.T) { + decoder := NewDecoder() + decoder.silkRedundancyFades = append(decoder.silkRedundancyFades, silkRedundancyFade{}) + decoder.silkCeltAdditions = append(decoder.silkCeltAdditions, silkCeltAddition{}) + + _, _, err := decoder.finishDecodeToInt16(nil, BandwidthWideband, 16000, 160, 1) + + assert.ErrorIs(t, err, errOutBufferTooSmall) + assert.Empty(t, decoder.silkRedundancyFades) + assert.Empty(t, decoder.silkCeltAdditions) +} + func TestDecodeCeltAtBandwidthSampleRateSkipsSilkResampler(t *testing.T) { decoder, err := NewDecoderWithOutput(8000, 1) assert.NoError(t, err) @@ -205,6 +218,27 @@ func TestDecodeToInt16(t *testing.T) { assert.Equal(t, 80, sampleCount) } +func TestDecodeMatchesDecodeToInt16(t *testing.T) { + packet := []byte{byte(8<<3) | byte(frameCodeOneFrame)} + + byteDecoder, err := NewDecoderWithOutput(48000, 1) + assert.NoError(t, err) + byteOut := make([]byte, 480*2) + _, _, err = byteDecoder.Decode(packet, byteOut) + assert.NoError(t, err) + + int16Decoder, err := NewDecoderWithOutput(48000, 1) + assert.NoError(t, err) + int16Out := make([]int16, 480) + sampleCount, err := int16Decoder.DecodeToInt16(packet, int16Out) + assert.NoError(t, err) + assert.Equal(t, 480, sampleCount) + + expectedByteOut := make([]byte, sampleCount*2) + assert.NoError(t, bitdepth.Signed16ToLittleEndian(int16Out[:sampleCount], expectedByteOut)) + assert.Equal(t, expectedByteOut, byteOut[:len(expectedByteOut)]) +} + func TestDecodeSilkFrameDurations(t *testing.T) { for _, test := range []struct { name string diff --git a/internal/bitdepth/bitdepth.go b/internal/bitdepth/bitdepth.go index 1eec374..4be8145 100644 --- a/internal/bitdepth/bitdepth.go +++ b/internal/bitdepth/bitdepth.go @@ -80,3 +80,20 @@ func ConvertFloat32LittleEndianToSigned16LittleEndian( return nil } + +// Signed16ToLittleEndian converts signed 16-bit PCM to little-endian bytes. +func Signed16ToLittleEndian(in []int16, out []byte) error { + if len(in)*2 > len(out) { + return errOutBufferTooSmall + } + + currIndex := 0 + for _, sample := range in { + out[currIndex] = byte(sample & 0b11111111) + currIndex++ + out[currIndex] = byte(uint16(sample) >> 8) // #nosec G115,G602 -- output length was checked above + currIndex++ + } + + return nil +} diff --git a/internal/bitdepth/bitdepth_test.go b/internal/bitdepth/bitdepth_test.go index f1f2011..8defc7d 100644 --- a/internal/bitdepth/bitdepth_test.go +++ b/internal/bitdepth/bitdepth_test.go @@ -58,3 +58,15 @@ func TestConvertFloat32LittleEndianToSigned16LittleEndianInvalidChannelCount(t * func TestConvertFloat32LittleEndianToSigned16LittleEndianInvalidResampleCount(t *testing.T) { assert.Error(t, ConvertFloat32LittleEndianToSigned16LittleEndian([]float32{0.3}, make([]byte, 2), 1, 0)) } + +func TestSigned16ToLittleEndian(t *testing.T) { + in := []int16{0x2666, 0, 0x4666, 0x5c29, -1638} + out := make([]byte, len(in)*2) + + assert.NoError(t, Signed16ToLittleEndian(in, out)) + assert.Equal(t, []byte{0x66, 0x26, 0x00, 0x00, 0x66, 0x46, 0x29, 0x5c, 0x9a, 0xf9}, out) +} + +func TestSigned16ToLittleEndianOutTooSmall(t *testing.T) { + assert.ErrorIs(t, errOutBufferTooSmall, Signed16ToLittleEndian([]int16{1}, make([]byte, 1))) +} diff --git a/internal/resample/silk/fixed.go b/internal/resample/silk/fixed.go index 1294de2..30ca4bc 100644 --- a/internal/resample/silk/fixed.go +++ b/internal/resample/silk/fixed.go @@ -35,12 +35,13 @@ func silkRShiftRound(a32 int32, shift int) int32 { } func silkSAT16(a32 int32) int16 { - if a32 > math.MaxInt16 { - return math.MaxInt16 - } - if a32 < math.MinInt16 { + if uint32(a32-math.MinInt16) > math.MaxUint16 { //nolint:gosec // G115 + if a32 > math.MaxInt16 { + return math.MaxInt16 + } + return math.MinInt16 } - return int16(a32) + return int16(a32) //nolint:gosec // G115 } diff --git a/internal/resample/silk/iir_fir.go b/internal/resample/silk/iir_fir.go index 200b16b..457c640 100644 --- a/internal/resample/silk/iir_fir.go +++ b/internal/resample/silk/iir_fir.go @@ -4,6 +4,12 @@ package silkresample func (r *Resampler) resamplerPrivateIIRFIR(out, in []int16) { + if r.fsOutKHz == r.fsInKHz*3 { + r.resamplerPrivateIIRFIR3x(out, in) + + return + } + if cap(r.iirFIRBuf) < (2*r.batchSize)+orderFIR12 { r.iirFIRBuf = make([]int16, (2*r.batchSize)+orderFIR12) } @@ -51,3 +57,61 @@ func resamplerPrivateIIRFIRInterpolate(out, buf []int16, maxIndexQ16, indexIncre return outIndex } + +func (r *Resampler) resamplerPrivateIIRFIR3x(out, in []int16) { + phase0 := resamplerFracFIR12[0] + reversePhase0 := resamplerFracFIR12[11] + phase8 := resamplerFracFIR12[8] + reversePhase8 := resamplerFracFIR12[3] + phase4 := resamplerFracFIR12[4] + reversePhase4 := resamplerFracFIR12[7] + + h0 := r.sFIRIIR[0] + h1 := r.sFIRIIR[1] + h2 := r.sFIRIIR[2] + h3 := r.sFIRIIR[3] + h4 := r.sFIRIIR[4] + h5 := r.sFIRIIR[5] + h6 := r.sFIRIIR[6] + h7 := r.sFIRIIR[7] + + outIndex := 0 + for sampleIndex := range in { + resQ15 := silkSMULBB(int32(h0), int32(phase0[0])) + resQ15 = silkSMLABB(resQ15, int32(h1), int32(phase0[1])) + resQ15 = silkSMLABB(resQ15, int32(h2), int32(phase0[2])) + resQ15 = silkSMLABB(resQ15, int32(h3), int32(phase0[3])) + resQ15 = silkSMLABB(resQ15, int32(h4), int32(reversePhase0[3])) + resQ15 = silkSMLABB(resQ15, int32(h5), int32(reversePhase0[2])) + resQ15 = silkSMLABB(resQ15, int32(h6), int32(reversePhase0[1])) + resQ15 = silkSMLABB(resQ15, int32(h7), int32(reversePhase0[0])) + out[outIndex] = silkSAT16(silkRShiftRound(resQ15, 15)) + + resQ15 = silkSMULBB(int32(h0), int32(phase8[0])) + resQ15 = silkSMLABB(resQ15, int32(h1), int32(phase8[1])) + resQ15 = silkSMLABB(resQ15, int32(h2), int32(phase8[2])) + resQ15 = silkSMLABB(resQ15, int32(h3), int32(phase8[3])) + resQ15 = silkSMLABB(resQ15, int32(h4), int32(reversePhase8[3])) + resQ15 = silkSMLABB(resQ15, int32(h5), int32(reversePhase8[2])) + resQ15 = silkSMLABB(resQ15, int32(h6), int32(reversePhase8[1])) + resQ15 = silkSMLABB(resQ15, int32(h7), int32(reversePhase8[0])) + out[outIndex+1] = silkSAT16(silkRShiftRound(resQ15, 15)) + + even, odd := r.resamplerPrivateUp2HQSample(in[sampleIndex]) + resQ15 = silkSMULBB(int32(h1), int32(phase4[0])) + resQ15 = silkSMLABB(resQ15, int32(h2), int32(phase4[1])) + resQ15 = silkSMLABB(resQ15, int32(h3), int32(phase4[2])) + resQ15 = silkSMLABB(resQ15, int32(h4), int32(phase4[3])) + resQ15 = silkSMLABB(resQ15, int32(h5), int32(reversePhase4[3])) + resQ15 = silkSMLABB(resQ15, int32(h6), int32(reversePhase4[2])) + resQ15 = silkSMLABB(resQ15, int32(h7), int32(reversePhase4[1])) + resQ15 = silkSMLABB(resQ15, int32(even), int32(reversePhase4[0])) + out[outIndex+2] = silkSAT16(silkRShiftRound(resQ15, 15)) + + h0, h1, h2, h3 = h2, h3, h4, h5 + h4, h5, h6, h7 = h6, h7, even, odd + outIndex += 3 + } + + r.sFIRIIR = [orderFIR12]int16{h0, h1, h2, h3, h4, h5, h6, h7} +} diff --git a/internal/resample/silk/resampler.go b/internal/resample/silk/resampler.go index df62444..4821703 100644 --- a/internal/resample/silk/resampler.go +++ b/internal/resample/silk/resampler.go @@ -176,21 +176,48 @@ func (r *Resampler) CopyStateFrom(src *Resampler) { // //nolint:cyclop func (r *Resampler) Resample(in, out []float32) error { + out16, outLen, err := r.resampleToSigned16(in) + if err != nil { + return err + } + if len(out) < outLen { + return errOutBufferTooSmall + } + for i := range outLen { + out[i] = float32(out16[i]) / 32768.0 + } + + return nil +} + +// ResampleToInt16 converts one non-interleaved channel directly to signed 16-bit PCM. +func (r *Resampler) ResampleToInt16(in []float32, out []int16) error { + out16, outLen, err := r.resampleToSigned16(in) + if err != nil { + return err + } + if len(out) < outLen { + return errOutBufferTooSmall + } + copy(out, out16[:outLen]) + + return nil +} + +//nolint:cyclop +func (r *Resampler) resampleToSigned16(in []float32) ([]int16, int, error) { if r.fsInKHz == 0 { - return errInvalidInputSampleRate + return nil, 0, errInvalidInputSampleRate } if len(in) < r.fsInKHz { - return errInvalidInputLength + return nil, 0, errInvalidInputLength } outLen := len(in) * r.fsOutKHz if outLen%r.fsInKHz != 0 { - return errNonIntegralInputLength + return nil, 0, errNonIntegralInputLength } outLen /= r.fsInKHz - if len(out) < outLen { - return errOutBufferTooSmall - } if cap(r.in16) < len(in) { r.in16 = make([]int16, len(in)) } @@ -224,11 +251,8 @@ func (r *Resampler) Resample(in, out []float32) error { } copy(r.delayBuf[:], in16[len(in16)-r.inputDelay:]) - for i := range outLen { - out[i] = float32(out16[i]) / 32768.0 - } - return nil + return out16, outLen, nil } func inputRateID(sampleRate int) (int, error) { diff --git a/internal/resample/silk/resampler_test.go b/internal/resample/silk/resampler_test.go index 2dc9637..4781059 100644 --- a/internal/resample/silk/resampler_test.go +++ b/internal/resample/silk/resampler_test.go @@ -275,6 +275,24 @@ func TestResampleChunking(t *testing.T) { } } +func TestResampleToInt16MatchesResample(t *testing.T) { + in := makeTestSignal(16000)[:320] + + var floatResampler Resampler + assert.NoError(t, floatResampler.Init(16000, 48000)) + floatOut := make([]float32, len(in)*3) + assert.NoError(t, floatResampler.Resample(in, floatOut)) + + var int16Resampler Resampler + assert.NoError(t, int16Resampler.Init(16000, 48000)) + int16Out := make([]int16, len(floatOut)) + assert.NoError(t, int16Resampler.ResampleToInt16(in, int16Out)) + + for i := range floatOut { + assert.Equal(t, int16(math.Round(float64(floatOut[i]*32768))), int16Out[i]) + } +} + func TestResampleRoundTripDifference(t *testing.T) { for _, test := range []struct { inputSampleRate int diff --git a/internal/resample/silk/up2_hq.go b/internal/resample/silk/up2_hq.go index df8591a..b85dc78 100644 --- a/internal/resample/silk/up2_hq.go +++ b/internal/resample/silk/up2_hq.go @@ -5,44 +5,50 @@ package silkresample func (r *Resampler) resamplerPrivateUp2HQ(out, in []int16) { for sampleIndex := range in { - in32 := int32(in[sampleIndex]) << 10 - - diff := in32 - r.sIIR[0] - delta := silkSMULWB(diff, int32(resamplerUp2HQ0[0])) - out32 := r.sIIR[0] + delta - r.sIIR[0] = in32 + delta - - out32_1 := out32 - diff = out32_1 - r.sIIR[1] - delta = silkSMULWB(diff, int32(resamplerUp2HQ0[1])) - out32 = r.sIIR[1] + delta - r.sIIR[1] = out32_1 + delta - - out32_2 := out32 - diff = out32_2 - r.sIIR[2] - delta = silkSMLAWB(diff, diff, int32(resamplerUp2HQ0[2])) - out32 = r.sIIR[2] + delta - r.sIIR[2] = out32_2 + delta - - out[2*sampleIndex] = silkSAT16(silkRShiftRound(out32, 10)) - - diff = in32 - r.sIIR[3] - delta = silkSMULWB(diff, int32(resamplerUp2HQ1[0])) - out32 = r.sIIR[3] + delta - r.sIIR[3] = in32 + delta - - out32_1 = out32 - diff = out32_1 - r.sIIR[4] - delta = silkSMULWB(diff, int32(resamplerUp2HQ1[1])) - out32 = r.sIIR[4] + delta - r.sIIR[4] = out32_1 + delta - - out32_2 = out32 - diff = out32_2 - r.sIIR[5] - delta = silkSMLAWB(diff, diff, int32(resamplerUp2HQ1[2])) - out32 = r.sIIR[5] + delta - r.sIIR[5] = out32_2 + delta - - out[(2*sampleIndex)+1] = silkSAT16(silkRShiftRound(out32, 10)) + out[2*sampleIndex], out[(2*sampleIndex)+1] = r.resamplerPrivateUp2HQSample(in[sampleIndex]) } } + +func (r *Resampler) resamplerPrivateUp2HQSample(in int16) (even, odd int16) { + in32 := int32(in) << 10 + + diff := in32 - r.sIIR[0] + delta := silkSMULWB(diff, int32(resamplerUp2HQ0[0])) + out32 := r.sIIR[0] + delta + r.sIIR[0] = in32 + delta + + out32_1 := out32 + diff = out32_1 - r.sIIR[1] + delta = silkSMULWB(diff, int32(resamplerUp2HQ0[1])) + out32 = r.sIIR[1] + delta + r.sIIR[1] = out32_1 + delta + + out32_2 := out32 + diff = out32_2 - r.sIIR[2] + delta = silkSMLAWB(diff, diff, int32(resamplerUp2HQ0[2])) + out32 = r.sIIR[2] + delta + r.sIIR[2] = out32_2 + delta + + even = silkSAT16(silkRShiftRound(out32, 10)) + + diff = in32 - r.sIIR[3] + delta = silkSMULWB(diff, int32(resamplerUp2HQ1[0])) + out32 = r.sIIR[3] + delta + r.sIIR[3] = in32 + delta + + out32_1 = out32 + diff = out32_1 - r.sIIR[4] + delta = silkSMULWB(diff, int32(resamplerUp2HQ1[1])) + out32 = r.sIIR[4] + delta + r.sIIR[4] = out32_1 + delta + + out32_2 = out32 + diff = out32_2 - r.sIIR[5] + delta = silkSMLAWB(diff, diff, int32(resamplerUp2HQ1[2])) + out32 = r.sIIR[5] + delta + r.sIIR[5] = out32_2 + delta + + odd = silkSAT16(silkRShiftRound(out32, 10)) + + return even, odd +}