/// <summary> /// Resampler: convert from one sampling rate to another /// Input and output sampling rate are at most 48000 Hz /// </summary> /// <param name="S">I/O Resampler state</param> /// <param name="output">O Output signal</param> /// <param name="output_ptr"></param> /// <param name="input">I Input signal</param> /// <param name="input_ptr"></param> /// <param name="inLen">I Number of input samples</param> /// <returns></returns> internal static int silk_resampler( SilkResamplerState S, short[] output, int output_ptr, short[] input, int input_ptr, int inLen) { int nSamples; /* Need at least 1 ms of input data */ Inlines.OpusAssert(inLen >= S.Fs_in_kHz); /* Delay can't exceed the 1 ms of buffering */ Inlines.OpusAssert(S.inputDelay <= S.Fs_in_kHz); nSamples = S.Fs_in_kHz - S.inputDelay; short[] delayBufPtr = S.delayBuf; /* Copy to delay buffer */ Array.Copy(input, input_ptr, delayBufPtr, S.inputDelay, nSamples); switch (S.resampler_function) { case USE_silk_resampler_private_up2_HQ_wrapper: silk_resampler_private_up2_HQ(S.sIIR, output, output_ptr, delayBufPtr, 0, S.Fs_in_kHz); silk_resampler_private_up2_HQ(S.sIIR, output, output_ptr + S.Fs_out_kHz, input, input_ptr + nSamples, inLen - S.Fs_in_kHz); break; case USE_silk_resampler_private_IIR_FIR: silk_resampler_private_IIR_FIR(S, output, output_ptr, delayBufPtr, 0, S.Fs_in_kHz); silk_resampler_private_IIR_FIR(S, output, output_ptr + S.Fs_out_kHz, input, input_ptr + nSamples, inLen - S.Fs_in_kHz); break; case USE_silk_resampler_private_down_FIR: silk_resampler_private_down_FIR(S, output, output_ptr, delayBufPtr, 0, S.Fs_in_kHz); silk_resampler_private_down_FIR(S, output, output_ptr + S.Fs_out_kHz, input, input_ptr + nSamples, inLen - S.Fs_in_kHz); break; default: Array.Copy(delayBufPtr, 0, output, output_ptr, S.Fs_in_kHz); Array.Copy(input, input_ptr + nSamples, output, output_ptr + S.Fs_out_kHz, inLen - S.Fs_in_kHz); break; } /* Copy to delay buffer */ Array.Copy(input, input_ptr + inLen - S.inputDelay, delayBufPtr, 0, S.inputDelay); return(SilkError.SILK_NO_ERROR); }
/// <summary> /// Resample with a 2nd order AR filter followed by FIR interpolation /// </summary> /// <param name="S">I/O Resampler state</param> /// <param name="output">O Output signal</param> /// <param name="output_ptr"></param> /// <param name="input">I Input signal</param> /// <param name="input_ptr"></param> /// <param name="inLen">I Number of input samples</param> internal static void silk_resampler_private_down_FIR( SilkResamplerState S, short[] output, int output_ptr, short[] input, int input_ptr, int inLen) { int nSamplesIn; int max_index_Q16, index_increment_Q16; int[] buf = new int[S.batchSize + S.FIR_Order]; /* Copy buffered samples to start of buffer */ Array.Copy(S.sFIR_i32, buf, S.FIR_Order); /* Iterate over blocks of frameSizeIn input samples */ index_increment_Q16 = S.invRatio_Q16; while (true) { nSamplesIn = Inlines.silk_min(inLen, S.batchSize); /* Second-order AR filter (output in Q8) */ silk_resampler_private_AR2(S.sIIR, 0, buf, S.FIR_Order, input, input_ptr, S.Coefs, nSamplesIn); max_index_Q16 = Inlines.silk_LSHIFT32(nSamplesIn, 16); /* Interpolate filtered signal */ output_ptr = silk_resampler_private_down_FIR_INTERPOL(output, output_ptr, buf, S.Coefs, 2, S.FIR_Order, S.FIR_Fracs, max_index_Q16, index_increment_Q16); input_ptr += nSamplesIn; inLen -= nSamplesIn; if (inLen > 1) { /* More iterations to do; copy last part of filtered signal to beginning of buffer */ Array.Copy(buf, nSamplesIn, buf, 0, S.FIR_Order); } else { break; } } /* Copy last part of filtered signal to the state for the next call */ Array.Copy(buf, nSamplesIn, S.sFIR_i32, 0, S.FIR_Order); }
/// <summary> /// Upsample using a combination of allpass-based 2x upsampling and FIR interpolation /// </summary> /// <param name="S">I/O Resampler state</param> /// <param name="output">O Output signal</param> /// <param name="output_ptr"></param> /// <param name="input">I Input signal</param> /// <param name="input_ptr"></param> /// <param name="inLen">I Number of input samples</param> internal static void silk_resampler_private_IIR_FIR( SilkResamplerState S, short[] output, int output_ptr, short[] input, int input_ptr, int inLen) { int nSamplesIn; int max_index_Q16, index_increment_Q16; short[] buf = new short[2 * S.batchSize + SilkConstants.RESAMPLER_ORDER_FIR_12]; /* Copy buffered samples to start of buffer */ Array.Copy(S.sFIR_i16, 0, buf, 0, SilkConstants.RESAMPLER_ORDER_FIR_12); /* Iterate over blocks of frameSizeIn input samples */ index_increment_Q16 = S.invRatio_Q16; while (true) { nSamplesIn = Inlines.silk_min(inLen, S.batchSize); /* Upsample 2x */ silk_resampler_private_up2_HQ(S.sIIR, buf, SilkConstants.RESAMPLER_ORDER_FIR_12, input, input_ptr, nSamplesIn); max_index_Q16 = Inlines.silk_LSHIFT32(nSamplesIn, 16 + 1); /* + 1 because 2x upsampling */ output_ptr = silk_resampler_private_IIR_FIR_INTERPOL(output, output_ptr, buf, max_index_Q16, index_increment_Q16); input_ptr += nSamplesIn; inLen -= nSamplesIn; if (inLen > 0) { /* More iterations to do; copy last part of filtered signal to beginning of buffer */ Array.Copy(buf, nSamplesIn << 1, buf, 0, SilkConstants.RESAMPLER_ORDER_FIR_12); } else { break; } } /* Copy last part of filtered signal to the state for the next call */ Array.Copy(buf, nSamplesIn << 1, S.sFIR_i16, 0, SilkConstants.RESAMPLER_ORDER_FIR_12); }
/// <summary> /// Initialize/reset the resampler state for a given pair of input/output sampling rates /// </summary> /// <param name="S">I/O Resampler state</param> /// <param name="Fs_Hz_in">I Input sampling rate (Hz)</param> /// <param name="Fs_Hz_out">I Output sampling rate (Hz)</param> /// <param name="forEnc">I If 1: encoder; if 0: decoder</param> /// <returns></returns> internal static int silk_resampler_init( SilkResamplerState S, int Fs_Hz_in, int Fs_Hz_out, int forEnc) { int up2x; /* Clear state */ S.Reset(); /* Input checking */ if (forEnc != 0) { if ((Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000) || (Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000)) { Inlines.OpusAssert(false); return(-1); } S.inputDelay = Tables.delay_matrix_enc[rateID(Fs_Hz_in), rateID(Fs_Hz_out)]; } else { if ((Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000) || (Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000)) { Inlines.OpusAssert(false); return(-1); } S.inputDelay = Tables.delay_matrix_dec[rateID(Fs_Hz_in), rateID(Fs_Hz_out)]; } S.Fs_in_kHz = Inlines.silk_DIV32_16(Fs_Hz_in, 1000); S.Fs_out_kHz = Inlines.silk_DIV32_16(Fs_Hz_out, 1000); /* Number of samples processed per batch */ S.batchSize = S.Fs_in_kHz * SilkConstants.RESAMPLER_MAX_BATCH_SIZE_MS; /* Find resampler with the right sampling ratio */ up2x = 0; if (Fs_Hz_out > Fs_Hz_in) { /* Upsample */ if (Fs_Hz_out == Inlines.silk_MUL(Fs_Hz_in, 2)) { /* Fs_out : Fs_in = 2 : 1 */ /* Special case: directly use 2x upsampler */ S.resampler_function = USE_silk_resampler_private_up2_HQ_wrapper; } else { /* Default resampler */ S.resampler_function = USE_silk_resampler_private_IIR_FIR; up2x = 1; } } else if (Fs_Hz_out < Fs_Hz_in) { /* Downsample */ S.resampler_function = USE_silk_resampler_private_down_FIR; if (Inlines.silk_MUL(Fs_Hz_out, 4) == Inlines.silk_MUL(Fs_Hz_in, 3)) { /* Fs_out : Fs_in = 3 : 4 */ S.FIR_Fracs = 3; S.FIR_Order = SilkConstants.RESAMPLER_DOWN_ORDER_FIR0; S.Coefs = Tables.silk_Resampler_3_4_COEFS; } else if (Inlines.silk_MUL(Fs_Hz_out, 3) == Inlines.silk_MUL(Fs_Hz_in, 2)) { /* Fs_out : Fs_in = 2 : 3 */ S.FIR_Fracs = 2; S.FIR_Order = SilkConstants.RESAMPLER_DOWN_ORDER_FIR0; S.Coefs = Tables.silk_Resampler_2_3_COEFS; } else if (Inlines.silk_MUL(Fs_Hz_out, 2) == Fs_Hz_in) { /* Fs_out : Fs_in = 1 : 2 */ S.FIR_Fracs = 1; S.FIR_Order = SilkConstants.RESAMPLER_DOWN_ORDER_FIR1; S.Coefs = Tables.silk_Resampler_1_2_COEFS; } else if (Inlines.silk_MUL(Fs_Hz_out, 3) == Fs_Hz_in) { /* Fs_out : Fs_in = 1 : 3 */ S.FIR_Fracs = 1; S.FIR_Order = SilkConstants.RESAMPLER_DOWN_ORDER_FIR2; S.Coefs = Tables.silk_Resampler_1_3_COEFS; } else if (Inlines.silk_MUL(Fs_Hz_out, 4) == Fs_Hz_in) { /* Fs_out : Fs_in = 1 : 4 */ S.FIR_Fracs = 1; S.FIR_Order = SilkConstants.RESAMPLER_DOWN_ORDER_FIR2; S.Coefs = Tables.silk_Resampler_1_4_COEFS; } else if (Inlines.silk_MUL(Fs_Hz_out, 6) == Fs_Hz_in) { /* Fs_out : Fs_in = 1 : 6 */ S.FIR_Fracs = 1; S.FIR_Order = SilkConstants.RESAMPLER_DOWN_ORDER_FIR2; S.Coefs = Tables.silk_Resampler_1_6_COEFS; } else { /* None available */ Inlines.OpusAssert(false); return(-1); } } else { /* Input and output sampling rates are equal: copy */ S.resampler_function = USE_silk_resampler_copy; } /* Ratio of input/output samples */ S.invRatio_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_DIV32(Inlines.silk_LSHIFT32(Fs_Hz_in, 14 + up2x), Fs_Hz_out), 2); /* Make sure the ratio is rounded up */ while (Inlines.silk_SMULWW(S.invRatio_Q16, Fs_Hz_out) < Inlines.silk_LSHIFT32(Fs_Hz_in, up2x)) { S.invRatio_Q16++; } return(0); }