(caf7e6a2e) Replaced Concentus NuGet package with csproj (ensures correct System.Runtime references)
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
|
||||
internal static class ApplySineWindow
|
||||
{
|
||||
/* Apply sine window to signal vector. */
|
||||
/* Window types: */
|
||||
/* 1 . sine window from 0 to pi/2 */
|
||||
/* 2 . sine window from pi/2 to pi */
|
||||
/* Every other sample is linearly interpolated, for speed. */
|
||||
/* Window length must be between 16 and 120 (incl) and a multiple of 4. */
|
||||
|
||||
/* Matlab code for table:
|
||||
for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end
|
||||
*/
|
||||
private static readonly short[] freq_table_Q16 = {
|
||||
12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202,
|
||||
3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422,
|
||||
2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702,
|
||||
};
|
||||
|
||||
internal static void silk_apply_sine_window(
|
||||
short[] px_win, /* O Pointer to windowed signal */
|
||||
int px_win_ptr,
|
||||
short[] px, /* I Pointer to input signal */
|
||||
int px_ptr,
|
||||
int win_type, /* I Selects a window type */
|
||||
int length /* I Window length, multiple of 4 */
|
||||
)
|
||||
{
|
||||
int k, f_Q16, c_Q16;
|
||||
int S0_Q16, S1_Q16;
|
||||
|
||||
Inlines.OpusAssert(win_type == 1 || win_type == 2);
|
||||
|
||||
/* Length must be in a range from 16 to 120 and a multiple of 4 */
|
||||
Inlines.OpusAssert(length >= 16 && length <= 120);
|
||||
Inlines.OpusAssert((length & 3) == 0);
|
||||
|
||||
/* Frequency */
|
||||
k = (length >> 2) - 4;
|
||||
Inlines.OpusAssert(k >= 0 && k <= 26);
|
||||
f_Q16 = (int)freq_table_Q16[k];
|
||||
|
||||
/* Factor used for cosine approximation */
|
||||
c_Q16 = Inlines.silk_SMULWB((int)f_Q16, -f_Q16);
|
||||
Inlines.OpusAssert(c_Q16 >= -32768);
|
||||
|
||||
/* initialize state */
|
||||
if (win_type == 1)
|
||||
{
|
||||
/* start from 0 */
|
||||
S0_Q16 = 0;
|
||||
/* approximation of sin(f) */
|
||||
S1_Q16 = f_Q16 + Inlines.silk_RSHIFT(length, 3);
|
||||
}
|
||||
else {
|
||||
/* start from 1 */
|
||||
S0_Q16 = ((int)1 << 16);
|
||||
/* approximation of cos(f) */
|
||||
S1_Q16 = ((int)1 << 16) + Inlines.silk_RSHIFT(c_Q16, 1) + Inlines.silk_RSHIFT(length, 4);
|
||||
}
|
||||
|
||||
/* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */
|
||||
/* 4 samples at a time */
|
||||
for (k = 0; k < length; k += 4)
|
||||
{
|
||||
int pxwk = px_win_ptr + k;
|
||||
int pxk = px_ptr + k;
|
||||
px_win[pxwk] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(S0_Q16 + S1_Q16, 1), px[pxk]);
|
||||
px_win[pxwk + 1] = (short)Inlines.silk_SMULWB(S1_Q16, px[pxk + 1]);
|
||||
S0_Q16 = Inlines.silk_SMULWB(S1_Q16, c_Q16) + Inlines.silk_LSHIFT(S1_Q16, 1) - S0_Q16 + 1;
|
||||
S0_Q16 = Inlines.silk_min(S0_Q16, ((int)1 << 16));
|
||||
|
||||
px_win[pxwk + 2] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(S0_Q16 + S1_Q16, 1), px[pxk + 2]);
|
||||
px_win[pxwk + 3] = (short)Inlines.silk_SMULWB(S0_Q16, px[pxk + 3]);
|
||||
S1_Q16 = Inlines.silk_SMULWB(S0_Q16, c_Q16) + Inlines.silk_LSHIFT(S0_Q16, 1) - S1_Q16;
|
||||
S1_Q16 = Inlines.silk_min(S1_Q16, ((int)1 << 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class BWExpander
|
||||
{
|
||||
/// <summary>
|
||||
/// Chirp (bw expand) LP AR filter (Fixed point implementation)
|
||||
/// </summary>
|
||||
/// <param name="ar">I/O AR filter to be expanded (without leading 1)</param>
|
||||
/// <param name="d">I length of ar</param>
|
||||
/// <param name="chirp_Q16">I chirp factor (typically in range (0..1) )</param>
|
||||
internal static void silk_bwexpander_32(
|
||||
int[] ar, /* I/O AR filter to be expanded (without leading 1) */
|
||||
int d, /* I Length of ar */
|
||||
int chirp_Q16 /* I Chirp factor in Q16 */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int chirp_minus_one_Q16 = chirp_Q16 - 65536;
|
||||
|
||||
for (i = 0; i < d - 1; i++)
|
||||
{
|
||||
ar[i] = Inlines.silk_SMULWW(chirp_Q16, ar[i]);
|
||||
chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, chirp_minus_one_Q16), 16);
|
||||
}
|
||||
ar[d - 1] = Inlines.silk_SMULWW(chirp_Q16, ar[d - 1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chirp (bw expand) LP AR filter (Fixed point implementation)
|
||||
/// </summary>
|
||||
/// <param name="ar">I/O AR filter to be expanded (without leading 1)</param>
|
||||
/// <param name="d">I length of ar</param>
|
||||
/// <param name="chirp_Q16">I chirp factor (typically in range (0..1) )</param>
|
||||
internal static void silk_bwexpander(
|
||||
short[] ar,
|
||||
int d,
|
||||
int chirp_Q16)
|
||||
{
|
||||
int i;
|
||||
int chirp_minus_one_Q16 = chirp_Q16 - 65536;
|
||||
|
||||
/* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */
|
||||
/* Bias in silk_SMULWB can lead to unstable filters */
|
||||
for (i = 0; i < d - 1; i++)
|
||||
{
|
||||
ar[i] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[i]), 16);
|
||||
chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, chirp_minus_one_Q16), 16);
|
||||
}
|
||||
ar[d - 1] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[d - 1]), 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !UNSAFE
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Celt;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class BurgModified
|
||||
{
|
||||
/* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
|
||||
private const int MAX_FRAME_SIZE = 384;
|
||||
private const int QA = 25;
|
||||
private const int N_BITS_HEAD_ROOM = 2;
|
||||
private const int MIN_RSHIFTS = -16;
|
||||
private const int MAX_RSHIFTS = (32 - QA);
|
||||
|
||||
/* Compute reflection coefficients from input signal */
|
||||
internal static void silk_burg_modified(
|
||||
BoxedValueInt res_nrg, /* O Residual energy */
|
||||
BoxedValueInt res_nrg_Q, /* O Residual energy Q value */
|
||||
int[] A_Q16, /* O Prediction coefficients (length order) */
|
||||
short[] x, /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
|
||||
int x_ptr,
|
||||
int minInvGain_Q30, /* I Inverse of max prediction gain */
|
||||
int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
|
||||
int nb_subfr, /* I Number of subframes stacked in x */
|
||||
int D /* I Order */
|
||||
)
|
||||
{
|
||||
int k, n, s, lz, rshifts, reached_max_gain;
|
||||
int C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
|
||||
int x_offset;
|
||||
int[] C_first_row = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] C_last_row = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] Af_QA = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] CAf = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1];
|
||||
int[] CAb = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1];
|
||||
int[] xcorr = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
long C0_64;
|
||||
|
||||
Inlines.OpusAssert(subfr_length * nb_subfr <= MAX_FRAME_SIZE);
|
||||
|
||||
/* Compute autocorrelations, added over subframes */
|
||||
C0_64 = Inlines.silk_inner_prod16_aligned_64(x, x_ptr, x, x_ptr, subfr_length * nb_subfr);
|
||||
lz = Inlines.silk_CLZ64(C0_64);
|
||||
rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz;
|
||||
if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS;
|
||||
if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS;
|
||||
|
||||
if (rshifts > 0)
|
||||
{
|
||||
C0 = (int)Inlines.silk_RSHIFT64(C0_64, rshifts);
|
||||
}
|
||||
else {
|
||||
C0 = Inlines.silk_LSHIFT32((int)C0_64, -rshifts);
|
||||
}
|
||||
|
||||
CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */
|
||||
Arrays.MemSetInt(C_first_row, 0, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
if (rshifts > 0)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
C_first_row[n - 1] += (int)Inlines.silk_RSHIFT64(
|
||||
Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset + n, subfr_length - n), rshifts);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
int i;
|
||||
int d;
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
CeltPitchXCorr.pitch_xcorr(x, x_offset, x, x_offset + 1, xcorr, subfr_length - D, D);
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
for (i = n + subfr_length - D, d = 0; i < subfr_length; i++)
|
||||
d = Inlines.MAC16_16(d, x[x_offset + i], x[x_offset + i - n]);
|
||||
xcorr[n - 1] += d;
|
||||
}
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
C_first_row[n - 1] += Inlines.silk_LSHIFT32(xcorr[n - 1], -rshifts);
|
||||
}
|
||||
}
|
||||
}
|
||||
Array.Copy(C_first_row, C_last_row, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
|
||||
/* Initialize */
|
||||
CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */
|
||||
|
||||
invGain_Q30 = (int)1 << 30;
|
||||
reached_max_gain = 0;
|
||||
for (n = 0; n < D; n++)
|
||||
{
|
||||
/* Update first row of correlation matrix (without first element) */
|
||||
/* Update last row of correlation matrix (without last element, stored in reversed order) */
|
||||
/* Update C * Af */
|
||||
/* Update C * flipud(Af) (stored in reversed order) */
|
||||
if (rshifts > -2)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
x1 = -Inlines.silk_LSHIFT32((int)x[x_offset + n], 16 - rshifts); /* Q(16-rshifts) */
|
||||
x2 = -Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], 16 - rshifts); /* Q(16-rshifts) */
|
||||
tmp1 = Inlines.silk_LSHIFT32((int)x[x_offset + n], QA - 16); /* Q(QA-16) */
|
||||
tmp2 = Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], QA - 16); /* Q(QA-16) */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
C_first_row[k] = Inlines.silk_SMLAWB(C_first_row[k], x1, x[x_offset + n - k - 1]); /* Q( -rshifts ) */
|
||||
C_last_row[k] = Inlines.silk_SMLAWB(C_last_row[k], x2, x[x_offset + subfr_length - n + k]); /* Q( -rshifts ) */
|
||||
Atmp_QA = Af_QA[k];
|
||||
tmp1 = Inlines.silk_SMLAWB(tmp1, Atmp_QA, x[x_offset + n - k - 1]); /* Q(QA-16) */
|
||||
tmp2 = Inlines.silk_SMLAWB(tmp2, Atmp_QA, x[x_offset + subfr_length - n + k]); /* Q(QA-16) */
|
||||
}
|
||||
tmp1 = Inlines.silk_LSHIFT32(-tmp1, 32 - QA - rshifts); /* Q(16-rshifts) */
|
||||
tmp2 = Inlines.silk_LSHIFT32(-tmp2, 32 - QA - rshifts); /* Q(16-rshifts) */
|
||||
for (k = 0; k <= n; k++)
|
||||
{
|
||||
CAf[k] = Inlines.silk_SMLAWB(CAf[k], tmp1, x[x_offset + n - k]); /* Q( -rshift ) */
|
||||
CAb[k] = Inlines.silk_SMLAWB(CAb[k], tmp2, x[x_offset + subfr_length - n + k - 1]); /* Q( -rshift ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
x1 = -Inlines.silk_LSHIFT32((int)x[x_offset + n], -rshifts); /* Q( -rshifts ) */
|
||||
x2 = -Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], -rshifts); /* Q( -rshifts ) */
|
||||
tmp1 = Inlines.silk_LSHIFT32((int)x[x_offset + n], 17); /* Q17 */
|
||||
tmp2 = Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], 17); /* Q17 */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
C_first_row[k] = Inlines.silk_MLA(C_first_row[k], x1, x[x_offset + n - k - 1]); /* Q( -rshifts ) */
|
||||
C_last_row[k] = Inlines.silk_MLA(C_last_row[k], x2, x[x_offset + subfr_length - n + k]); /* Q( -rshifts ) */
|
||||
Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 17); /* Q17 */
|
||||
tmp1 = Inlines.silk_MLA(tmp1, x[x_offset + n - k - 1], Atmp1); /* Q17 */
|
||||
tmp2 = Inlines.silk_MLA(tmp2, x[x_offset + subfr_length - n + k], Atmp1); /* Q17 */
|
||||
}
|
||||
tmp1 = -tmp1; /* Q17 */
|
||||
tmp2 = -tmp2; /* Q17 */
|
||||
for (k = 0; k <= n; k++)
|
||||
{
|
||||
CAf[k] = Inlines.silk_SMLAWW(CAf[k], tmp1,
|
||||
Inlines.silk_LSHIFT32((int)x[x_offset + n - k], -rshifts - 1)); /* Q( -rshift ) */
|
||||
CAb[k] = Inlines.silk_SMLAWW(CAb[k], tmp2,
|
||||
Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n + k - 1], -rshifts - 1)); /* Q( -rshift ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
|
||||
tmp1 = C_first_row[n]; /* Q( -rshifts ) */
|
||||
tmp2 = C_last_row[n]; /* Q( -rshifts ) */
|
||||
num = 0; /* Q( -rshifts ) */
|
||||
nrg = Inlines.silk_ADD32(CAb[0], CAf[0]); /* Q( 1-rshifts ) */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
Atmp_QA = Af_QA[k];
|
||||
lz = Inlines.silk_CLZ32(Inlines.silk_abs(Atmp_QA)) - 1;
|
||||
lz = Inlines.silk_min(32 - QA, lz);
|
||||
Atmp1 = Inlines.silk_LSHIFT32(Atmp_QA, lz); /* Q( QA + lz ) */
|
||||
|
||||
tmp1 = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(C_last_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
tmp2 = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(C_first_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
num = Inlines.silk_ADD_LSHIFT32(num, Inlines.silk_SMMUL(CAb[n - k], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
nrg = Inlines.silk_ADD_LSHIFT32(nrg, Inlines.silk_SMMUL(Inlines.silk_ADD32(CAb[k + 1], CAf[k + 1]),
|
||||
Atmp1), 32 - QA - lz); /* Q( 1-rshifts ) */
|
||||
}
|
||||
CAf[n + 1] = tmp1; /* Q( -rshifts ) */
|
||||
CAb[n + 1] = tmp2; /* Q( -rshifts ) */
|
||||
num = Inlines.silk_ADD32(num, tmp2); /* Q( -rshifts ) */
|
||||
num = Inlines.silk_LSHIFT32(-num, 1); /* Q( 1-rshifts ) */
|
||||
|
||||
/* Calculate the next order reflection (parcor) coefficient */
|
||||
if (Inlines.silk_abs(num) < nrg)
|
||||
{
|
||||
rc_Q31 = Inlines.silk_DIV32_varQ(num, nrg, 31);
|
||||
}
|
||||
else {
|
||||
rc_Q31 = (num > 0) ? int.MaxValue : int.MinValue;
|
||||
}
|
||||
|
||||
/* Update inverse prediction gain */
|
||||
tmp1 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
tmp1 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, tmp1), 2);
|
||||
if (tmp1 <= minInvGain_Q30)
|
||||
{
|
||||
/* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
|
||||
tmp2 = ((int)1 << 30) - Inlines.silk_DIV32_varQ(minInvGain_Q30, invGain_Q30, 30); /* Q30 */
|
||||
rc_Q31 = Inlines.silk_SQRT_APPROX(tmp2); /* Q15 */
|
||||
/* Newton-Raphson iteration */
|
||||
rc_Q31 = Inlines.silk_RSHIFT32(rc_Q31 + Inlines.silk_DIV32(tmp2, rc_Q31), 1); /* Q15 */
|
||||
rc_Q31 = Inlines.silk_LSHIFT32(rc_Q31, 16); /* Q31 */
|
||||
if (num < 0)
|
||||
{
|
||||
/* Ensure adjusted reflection coefficients has the original sign */
|
||||
rc_Q31 = -rc_Q31;
|
||||
}
|
||||
invGain_Q30 = minInvGain_Q30;
|
||||
reached_max_gain = 1;
|
||||
}
|
||||
else {
|
||||
invGain_Q30 = tmp1;
|
||||
}
|
||||
|
||||
/* Update the AR coefficients */
|
||||
for (k = 0; k < (n + 1) >> 1; k++)
|
||||
{
|
||||
tmp1 = Af_QA[k]; /* QA */
|
||||
tmp2 = Af_QA[n - k - 1]; /* QA */
|
||||
Af_QA[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* QA */
|
||||
Af_QA[n - k - 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* QA */
|
||||
}
|
||||
Af_QA[n] = Inlines.silk_RSHIFT32(rc_Q31, 31 - QA); /* QA */
|
||||
|
||||
if (reached_max_gain != 0)
|
||||
{
|
||||
/* Reached max prediction gain; set remaining coefficients to zero and exit loop */
|
||||
for (k = n + 1; k < D; k++)
|
||||
{
|
||||
Af_QA[k] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update C * Af and C * Ab */
|
||||
for (k = 0; k <= n + 1; k++)
|
||||
{
|
||||
tmp1 = CAf[k]; /* Q( -rshifts ) */
|
||||
tmp2 = CAb[n - k + 1]; /* Q( -rshifts ) */
|
||||
CAf[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* Q( -rshifts ) */
|
||||
CAb[n - k + 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* Q( -rshifts ) */
|
||||
}
|
||||
}
|
||||
|
||||
if (reached_max_gain != 0)
|
||||
{
|
||||
for (k = 0; k < D; k++)
|
||||
{
|
||||
/* Scale coefficients */
|
||||
A_Q16[k] = -Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16);
|
||||
}
|
||||
/* Subtract energy of preceding samples from C0 */
|
||||
if (rshifts > 0)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
C0 -= (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset, D), rshifts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
C0 -= Inlines.silk_LSHIFT32(Inlines.silk_inner_prod_self(x, x_offset, D), -rshifts);
|
||||
}
|
||||
}
|
||||
/* Approximate residual energy */
|
||||
res_nrg.Val = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, C0), 2);
|
||||
res_nrg_Q.Val = 0 - rshifts;
|
||||
}
|
||||
else {
|
||||
/* Return residual energy */
|
||||
nrg = CAf[0]; /* Q( -rshifts ) */
|
||||
tmp1 = (int)1 << 16; /* Q16 */
|
||||
for (k = 0; k < D; k++)
|
||||
{
|
||||
Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16); /* Q16 */
|
||||
nrg = Inlines.silk_SMLAWW(nrg, CAf[k + 1], Atmp1); /* Q( -rshifts ) */
|
||||
tmp1 = Inlines.silk_SMLAWW(tmp1, Atmp1, Atmp1); /* Q16 */
|
||||
A_Q16[k] = -Atmp1;
|
||||
}
|
||||
res_nrg.Val = Inlines.silk_SMLAWW(nrg, Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0), -tmp1);/* Q( -rshifts ) */
|
||||
res_nrg_Q.Val = -rshifts;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,336 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if UNSAFE
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Celt;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class BurgModified
|
||||
{
|
||||
/* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
|
||||
private const int MAX_FRAME_SIZE = 384;
|
||||
private const int QA = 25;
|
||||
private const int N_BITS_HEAD_ROOM = 2;
|
||||
private const int MIN_RSHIFTS = -16;
|
||||
private const int MAX_RSHIFTS = (32 - QA);
|
||||
|
||||
/* Compute reflection coefficients from input signal */
|
||||
internal static unsafe void silk_burg_modified(
|
||||
BoxedValueInt res_nrg, /* O Residual energy */
|
||||
BoxedValueInt res_nrg_Q, /* O Residual energy Q value */
|
||||
int[] A_Q16, /* O Prediction coefficients (length order) */
|
||||
short[] x, /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
|
||||
int x_ptr,
|
||||
int minInvGain_Q30, /* I Inverse of max prediction gain */
|
||||
int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
|
||||
int nb_subfr, /* I Number of subframes stacked in x */
|
||||
int D /* I Order */
|
||||
)
|
||||
{
|
||||
int k, n, s, lz, rshifts, reached_max_gain;
|
||||
int C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
|
||||
int x_offset;
|
||||
int[] C_first_row = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] C_last_row = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] Af_QA = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] CAf = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1];
|
||||
int[] CAb = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1];
|
||||
int[] xcorr = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
long C0_64;
|
||||
|
||||
Inlines.OpusAssert(subfr_length * nb_subfr <= MAX_FRAME_SIZE);
|
||||
|
||||
fixed (short* px_base = x)
|
||||
{
|
||||
short* px = px_base + x_ptr;
|
||||
/* Compute autocorrelations, added over subframes */
|
||||
C0_64 = Inlines.silk_inner_prod16_aligned_64(x, x_ptr, x, x_ptr, subfr_length * nb_subfr);
|
||||
lz = Inlines.silk_CLZ64(C0_64);
|
||||
rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz;
|
||||
if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS;
|
||||
if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS;
|
||||
|
||||
if (rshifts > 0)
|
||||
{
|
||||
C0 = (int)Inlines.silk_RSHIFT64(C0_64, rshifts);
|
||||
}
|
||||
else
|
||||
{
|
||||
C0 = Inlines.silk_LSHIFT32((int)C0_64, -rshifts);
|
||||
}
|
||||
|
||||
CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */
|
||||
Arrays.MemSetInt(C_first_row, 0, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
if (rshifts > 0)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
short* px2 = px + s * subfr_length;
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
C_first_row[n - 1] += (int)Inlines.silk_RSHIFT64(
|
||||
Inlines.silk_inner_prod16_aligned_64(px2, px2 + n, subfr_length - n), rshifts);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
int i;
|
||||
int d;
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
CeltPitchXCorr.pitch_xcorr(x, x_offset, x, x_offset + 1, xcorr, subfr_length - D, D);
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
for (i = n + subfr_length - D, d = 0; i < subfr_length; i++)
|
||||
d = Inlines.MAC16_16(d, x[x_offset + i], x[x_offset + i - n]);
|
||||
xcorr[n - 1] += d;
|
||||
}
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
C_first_row[n - 1] += Inlines.silk_LSHIFT32(xcorr[n - 1], -rshifts);
|
||||
}
|
||||
}
|
||||
}
|
||||
Array.Copy(C_first_row, C_last_row, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
|
||||
/* Initialize */
|
||||
CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */
|
||||
|
||||
invGain_Q30 = (int)1 << 30;
|
||||
reached_max_gain = 0;
|
||||
for (n = 0; n < D; n++)
|
||||
{
|
||||
/* Update first row of correlation matrix (without first element) */
|
||||
/* Update last row of correlation matrix (without last element, stored in reversed order) */
|
||||
/* Update C * Af */
|
||||
/* Update C * flipud(Af) (stored in reversed order) */
|
||||
if (rshifts > -2)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
short* px2 = px + s * subfr_length;
|
||||
x1 = -Inlines.silk_LSHIFT32((int)px2[n], 16 - rshifts); /* Q(16-rshifts) */
|
||||
x2 = -Inlines.silk_LSHIFT32((int)px2[subfr_length - n - 1], 16 - rshifts); /* Q(16-rshifts) */
|
||||
tmp1 = Inlines.silk_LSHIFT32((int)px2[n], QA - 16); /* Q(QA-16) */
|
||||
tmp2 = Inlines.silk_LSHIFT32((int)px2[subfr_length - n - 1], QA - 16); /* Q(QA-16) */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
C_first_row[k] = Inlines.silk_SMLAWB(C_first_row[k], x1, px2[n - k - 1]); /* Q( -rshifts ) */
|
||||
C_last_row[k] = Inlines.silk_SMLAWB(C_last_row[k], x2, px2[subfr_length - n + k]); /* Q( -rshifts ) */
|
||||
Atmp_QA = Af_QA[k];
|
||||
tmp1 = Inlines.silk_SMLAWB(tmp1, Atmp_QA, px2[n - k - 1]); /* Q(QA-16) */
|
||||
tmp2 = Inlines.silk_SMLAWB(tmp2, Atmp_QA, px2[subfr_length - n + k]); /* Q(QA-16) */
|
||||
}
|
||||
tmp1 = Inlines.silk_LSHIFT32(-tmp1, 32 - QA - rshifts); /* Q(16-rshifts) */
|
||||
tmp2 = Inlines.silk_LSHIFT32(-tmp2, 32 - QA - rshifts); /* Q(16-rshifts) */
|
||||
for (k = 0; k <= n; k++)
|
||||
{
|
||||
CAf[k] = Inlines.silk_SMLAWB(CAf[k], tmp1, px2[n - k]); /* Q( -rshift ) */
|
||||
CAb[k] = Inlines.silk_SMLAWB(CAb[k], tmp2, px2[subfr_length - n + k - 1]); /* Q( -rshift ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
short* px2 = px + s * subfr_length;
|
||||
x1 = -Inlines.silk_LSHIFT32((int)px2[n], -rshifts); /* Q( -rshifts ) */
|
||||
x2 = -Inlines.silk_LSHIFT32((int)px2[subfr_length - n - 1], -rshifts); /* Q( -rshifts ) */
|
||||
tmp1 = Inlines.silk_LSHIFT32((int)px2[n], 17); /* Q17 */
|
||||
tmp2 = Inlines.silk_LSHIFT32((int)px2[subfr_length - n - 1], 17); /* Q17 */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
C_first_row[k] = Inlines.silk_MLA(C_first_row[k], x1, px2[n - k - 1]); /* Q( -rshifts ) */
|
||||
C_last_row[k] = Inlines.silk_MLA(C_last_row[k], x2, px2[subfr_length - n + k]); /* Q( -rshifts ) */
|
||||
Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 17); /* Q17 */
|
||||
tmp1 = Inlines.silk_MLA(tmp1, px2[n - k - 1], Atmp1); /* Q17 */
|
||||
tmp2 = Inlines.silk_MLA(tmp2, px2[subfr_length - n + k], Atmp1); /* Q17 */
|
||||
}
|
||||
tmp1 = -tmp1; /* Q17 */
|
||||
tmp2 = -tmp2; /* Q17 */
|
||||
for (k = 0; k <= n; k++)
|
||||
{
|
||||
CAf[k] = Inlines.silk_SMLAWW(CAf[k], tmp1,
|
||||
Inlines.silk_LSHIFT32((int)px2[n - k], -rshifts - 1)); /* Q( -rshift ) */
|
||||
CAb[k] = Inlines.silk_SMLAWW(CAb[k], tmp2,
|
||||
Inlines.silk_LSHIFT32((int)px2[subfr_length - n + k - 1], -rshifts - 1)); /* Q( -rshift ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
|
||||
tmp1 = C_first_row[n]; /* Q( -rshifts ) */
|
||||
tmp2 = C_last_row[n]; /* Q( -rshifts ) */
|
||||
num = 0; /* Q( -rshifts ) */
|
||||
nrg = Inlines.silk_ADD32(CAb[0], CAf[0]); /* Q( 1-rshifts ) */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
Atmp_QA = Af_QA[k];
|
||||
lz = Inlines.silk_CLZ32(Inlines.silk_abs(Atmp_QA)) - 1;
|
||||
lz = Inlines.silk_min(32 - QA, lz);
|
||||
Atmp1 = Inlines.silk_LSHIFT32(Atmp_QA, lz); /* Q( QA + lz ) */
|
||||
|
||||
tmp1 = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(C_last_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
tmp2 = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(C_first_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
num = Inlines.silk_ADD_LSHIFT32(num, Inlines.silk_SMMUL(CAb[n - k], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
nrg = Inlines.silk_ADD_LSHIFT32(nrg, Inlines.silk_SMMUL(Inlines.silk_ADD32(CAb[k + 1], CAf[k + 1]),
|
||||
Atmp1), 32 - QA - lz); /* Q( 1-rshifts ) */
|
||||
}
|
||||
CAf[n + 1] = tmp1; /* Q( -rshifts ) */
|
||||
CAb[n + 1] = tmp2; /* Q( -rshifts ) */
|
||||
num = Inlines.silk_ADD32(num, tmp2); /* Q( -rshifts ) */
|
||||
num = Inlines.silk_LSHIFT32(-num, 1); /* Q( 1-rshifts ) */
|
||||
|
||||
/* Calculate the next order reflection (parcor) coefficient */
|
||||
if (Inlines.silk_abs(num) < nrg)
|
||||
{
|
||||
rc_Q31 = Inlines.silk_DIV32_varQ(num, nrg, 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc_Q31 = (num > 0) ? int.MaxValue : int.MinValue;
|
||||
}
|
||||
|
||||
/* Update inverse prediction gain */
|
||||
tmp1 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
tmp1 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, tmp1), 2);
|
||||
if (tmp1 <= minInvGain_Q30)
|
||||
{
|
||||
/* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
|
||||
tmp2 = ((int)1 << 30) - Inlines.silk_DIV32_varQ(minInvGain_Q30, invGain_Q30, 30); /* Q30 */
|
||||
rc_Q31 = Inlines.silk_SQRT_APPROX(tmp2); /* Q15 */
|
||||
/* Newton-Raphson iteration */
|
||||
rc_Q31 = Inlines.silk_RSHIFT32(rc_Q31 + Inlines.silk_DIV32(tmp2, rc_Q31), 1); /* Q15 */
|
||||
rc_Q31 = Inlines.silk_LSHIFT32(rc_Q31, 16); /* Q31 */
|
||||
if (num < 0)
|
||||
{
|
||||
/* Ensure adjusted reflection coefficients has the original sign */
|
||||
rc_Q31 = -rc_Q31;
|
||||
}
|
||||
invGain_Q30 = minInvGain_Q30;
|
||||
reached_max_gain = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
invGain_Q30 = tmp1;
|
||||
}
|
||||
|
||||
/* Update the AR coefficients */
|
||||
for (k = 0; k < (n + 1) >> 1; k++)
|
||||
{
|
||||
tmp1 = Af_QA[k]; /* QA */
|
||||
tmp2 = Af_QA[n - k - 1]; /* QA */
|
||||
Af_QA[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* QA */
|
||||
Af_QA[n - k - 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* QA */
|
||||
}
|
||||
Af_QA[n] = Inlines.silk_RSHIFT32(rc_Q31, 31 - QA); /* QA */
|
||||
|
||||
if (reached_max_gain != 0)
|
||||
{
|
||||
/* Reached max prediction gain; set remaining coefficients to zero and exit loop */
|
||||
for (k = n + 1; k < D; k++)
|
||||
{
|
||||
Af_QA[k] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update C * Af and C * Ab */
|
||||
for (k = 0; k <= n + 1; k++)
|
||||
{
|
||||
tmp1 = CAf[k]; /* Q( -rshifts ) */
|
||||
tmp2 = CAb[n - k + 1]; /* Q( -rshifts ) */
|
||||
CAf[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* Q( -rshifts ) */
|
||||
CAb[n - k + 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* Q( -rshifts ) */
|
||||
}
|
||||
}
|
||||
|
||||
if (reached_max_gain != 0)
|
||||
{
|
||||
for (k = 0; k < D; k++)
|
||||
{
|
||||
/* Scale coefficients */
|
||||
A_Q16[k] = -Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16);
|
||||
}
|
||||
/* Subtract energy of preceding samples from C0 */
|
||||
if (rshifts > 0)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
C0 -= (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset, D), rshifts);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
C0 -= Inlines.silk_LSHIFT32(Inlines.silk_inner_prod_self(x, x_offset, D), -rshifts);
|
||||
}
|
||||
}
|
||||
/* Approximate residual energy */
|
||||
res_nrg.Val = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, C0), 2);
|
||||
res_nrg_Q.Val = 0 - rshifts;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return residual energy */
|
||||
nrg = CAf[0]; /* Q( -rshifts ) */
|
||||
tmp1 = (int)1 << 16; /* Q16 */
|
||||
for (k = 0; k < D; k++)
|
||||
{
|
||||
Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16); /* Q16 */
|
||||
nrg = Inlines.silk_SMLAWW(nrg, CAf[k + 1], Atmp1); /* Q( -rshifts ) */
|
||||
tmp1 = Inlines.silk_SMLAWW(tmp1, Atmp1, Atmp1); /* Q16 */
|
||||
A_Q16[k] = -Atmp1;
|
||||
}
|
||||
res_nrg.Val = Inlines.silk_SMLAWW(nrg, Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0), -tmp1);/* Q( -rshifts ) */
|
||||
res_nrg_Q.Val = -rshifts;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,232 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
/// <summary>
|
||||
/// Comfort noise generation and estimation
|
||||
/// </summary>
|
||||
internal static class CNG
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates excitation for CNG LPC synthesis
|
||||
/// </summary>
|
||||
/// <param name="exc_Q10">O CNG excitation signal Q10</param>
|
||||
/// <param name="exc_buf_Q14">I Random samples buffer Q10</param>
|
||||
/// <param name="Gain_Q16">I Gain to apply</param>
|
||||
/// <param name="length">I Length</param>
|
||||
/// <param name="rand_seed">I/O Seed to random index generator</param>
|
||||
internal static void silk_CNG_exc(
|
||||
int[] exc_Q10,
|
||||
int exc_Q10_ptr,
|
||||
int[] exc_buf_Q14,
|
||||
int Gain_Q16,
|
||||
int length,
|
||||
ref int rand_seed)
|
||||
{
|
||||
int seed;
|
||||
int i, idx, exc_mask;
|
||||
|
||||
exc_mask = SilkConstants.CNG_BUF_MASK_MAX;
|
||||
|
||||
while (exc_mask > length)
|
||||
{
|
||||
exc_mask = Inlines.silk_RSHIFT(exc_mask, 1);
|
||||
}
|
||||
|
||||
seed = rand_seed;
|
||||
for (i = exc_Q10_ptr; i < exc_Q10_ptr + length; i++)
|
||||
{
|
||||
seed = Inlines.silk_RAND(seed);
|
||||
idx = (int)(Inlines.silk_RSHIFT(seed, 24) & exc_mask);
|
||||
Inlines.OpusAssert(idx >= 0);
|
||||
Inlines.OpusAssert(idx <= SilkConstants.CNG_BUF_MASK_MAX);
|
||||
exc_Q10[i] = (short)Inlines.silk_SAT16(Inlines.silk_SMULWW(exc_buf_Q14[idx], Gain_Q16 >> 4));
|
||||
}
|
||||
|
||||
rand_seed = seed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets CNG state
|
||||
/// </summary>
|
||||
/// <param name="psDec">I/O Decoder state</param>
|
||||
internal static void silk_CNG_Reset(SilkChannelDecoder psDec)
|
||||
{
|
||||
int i, NLSF_step_Q15, NLSF_acc_Q15;
|
||||
|
||||
NLSF_step_Q15 = Inlines.silk_DIV32_16(short.MaxValue, (short)(psDec.LPC_order + 1));
|
||||
NLSF_acc_Q15 = 0;
|
||||
for (i = 0; i < psDec.LPC_order; i++)
|
||||
{
|
||||
NLSF_acc_Q15 += NLSF_step_Q15;
|
||||
psDec.sCNG.CNG_smth_NLSF_Q15[i] = (short)(NLSF_acc_Q15);
|
||||
}
|
||||
psDec.sCNG.CNG_smth_Gain_Q16 = 0;
|
||||
psDec.sCNG.rand_seed = 3176576;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates CNG estimate, and applies the CNG when packet was lost
|
||||
/// </summary>
|
||||
/// <param name="psDec">I/O Decoder state</param>
|
||||
/// <param name="psDecCtrl">I/O Decoder control</param>
|
||||
/// <param name="frame">I/O Signal</param>
|
||||
/// <param name="length">I Length of residual</param>
|
||||
internal static void silk_CNG(
|
||||
SilkChannelDecoder psDec,
|
||||
SilkDecoderControl psDecCtrl,
|
||||
short[] frame,
|
||||
int frame_ptr,
|
||||
int length)
|
||||
{
|
||||
int i, subfr;
|
||||
int sum_Q6, max_Gain_Q16, gain_Q16;
|
||||
short[] A_Q12 = new short[psDec.LPC_order];
|
||||
CNGState psCNG = psDec.sCNG;
|
||||
|
||||
if (psDec.fs_kHz != psCNG.fs_kHz)
|
||||
{
|
||||
/* Reset state */
|
||||
silk_CNG_Reset(psDec);
|
||||
|
||||
psCNG.fs_kHz = psDec.fs_kHz;
|
||||
}
|
||||
|
||||
if (psDec.lossCnt == 0 && psDec.prevSignalType == SilkConstants.TYPE_NO_VOICE_ACTIVITY)
|
||||
{
|
||||
/* Update CNG parameters */
|
||||
|
||||
/* Smoothing of LSF's */
|
||||
for (i = 0; i < psDec.LPC_order; i++)
|
||||
{
|
||||
psCNG.CNG_smth_NLSF_Q15[i] += (short)(Inlines.silk_SMULWB((int)psDec.prevNLSF_Q15[i] - (int)psCNG.CNG_smth_NLSF_Q15[i], SilkConstants.CNG_NLSF_SMTH_Q16));
|
||||
}
|
||||
|
||||
/* Find the subframe with the highest gain */
|
||||
max_Gain_Q16 = 0;
|
||||
subfr = 0;
|
||||
for (i = 0; i < psDec.nb_subfr; i++)
|
||||
{
|
||||
if (psDecCtrl.Gains_Q16[i] > max_Gain_Q16)
|
||||
{
|
||||
max_Gain_Q16 = psDecCtrl.Gains_Q16[i];
|
||||
subfr = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update CNG excitation buffer with excitation from this subframe */
|
||||
Arrays.MemMoveInt(psCNG.CNG_exc_buf_Q14, 0, psDec.subfr_length, (psDec.nb_subfr - 1) * psDec.subfr_length);
|
||||
|
||||
/* Smooth gains */
|
||||
for (i = 0; i < psDec.nb_subfr; i++)
|
||||
{
|
||||
psCNG.CNG_smth_Gain_Q16 += Inlines.silk_SMULWB(psDecCtrl.Gains_Q16[i] - psCNG.CNG_smth_Gain_Q16, SilkConstants.CNG_GAIN_SMTH_Q16);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add CNG when packet is lost or during DTX */
|
||||
if (psDec.lossCnt != 0)
|
||||
{
|
||||
int[] CNG_sig_Q10 = new int[length + SilkConstants.MAX_LPC_ORDER];
|
||||
|
||||
/* Generate CNG excitation */
|
||||
gain_Q16 = Inlines.silk_SMULWW(psDec.sPLC.randScale_Q14, psDec.sPLC.prevGain_Q16[1]);
|
||||
if (gain_Q16 >= (1 << 21) || psCNG.CNG_smth_Gain_Q16 > (1 << 23))
|
||||
{
|
||||
gain_Q16 = Inlines.silk_SMULTT(gain_Q16, gain_Q16);
|
||||
gain_Q16 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULTT(psCNG.CNG_smth_Gain_Q16, psCNG.CNG_smth_Gain_Q16), gain_Q16, 5);
|
||||
gain_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(gain_Q16), 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
gain_Q16 = Inlines.silk_SMULWW(gain_Q16, gain_Q16);
|
||||
gain_Q16 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULWW(psCNG.CNG_smth_Gain_Q16, psCNG.CNG_smth_Gain_Q16), gain_Q16, 5);
|
||||
gain_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(gain_Q16), 8);
|
||||
}
|
||||
silk_CNG_exc(CNG_sig_Q10, SilkConstants.MAX_LPC_ORDER, psCNG.CNG_exc_buf_Q14, gain_Q16, length, ref psCNG.rand_seed);
|
||||
|
||||
/* Convert CNG NLSF to filter representation */
|
||||
NLSF.silk_NLSF2A(A_Q12, psCNG.CNG_smth_NLSF_Q15, psDec.LPC_order);
|
||||
|
||||
/* Generate CNG signal, by synthesis filtering */
|
||||
Array.Copy(psCNG.CNG_synth_state, CNG_sig_Q10, SilkConstants.MAX_LPC_ORDER);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
int lpci = SilkConstants.MAX_LPC_ORDER + i;
|
||||
Inlines.OpusAssert(psDec.LPC_order == 10 || psDec.LPC_order == 16);
|
||||
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
|
||||
sum_Q6 = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 1], A_Q12[0]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 2], A_Q12[1]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 3], A_Q12[2]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 4], A_Q12[3]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 5], A_Q12[4]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 6], A_Q12[5]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 7], A_Q12[6]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 8], A_Q12[7]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 9], A_Q12[8]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 10], A_Q12[9]);
|
||||
|
||||
if (psDec.LPC_order == 16)
|
||||
{
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 11], A_Q12[10]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 12], A_Q12[11]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 13], A_Q12[12]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 14], A_Q12[13]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 15], A_Q12[14]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 16], A_Q12[15]);
|
||||
}
|
||||
|
||||
/* Update states */
|
||||
CNG_sig_Q10[lpci] = Inlines.silk_ADD_LSHIFT(CNG_sig_Q10[lpci], sum_Q6, 4);
|
||||
|
||||
frame[frame_ptr + i] = Inlines.silk_ADD_SAT16(frame[frame_ptr + i], (short)(Inlines.silk_RSHIFT_ROUND(CNG_sig_Q10[lpci], 10)));
|
||||
}
|
||||
|
||||
Array.Copy(CNG_sig_Q10, length, psCNG.CNG_synth_state, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrays.MemSetInt(psCNG.CNG_synth_state, 0, psDec.LPC_order);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class CodeSigns
|
||||
{
|
||||
private static int silk_enc_map(int a)
|
||||
{
|
||||
return (Inlines.silk_RSHIFT((a), 15) + 1);
|
||||
}
|
||||
|
||||
private static int silk_dec_map(int a)
|
||||
{
|
||||
return (Inlines.silk_LSHIFT((a), 1) - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes signs of excitation
|
||||
/// </summary>
|
||||
/// <param name="psRangeEnc">I/O Compressor data structure</param>
|
||||
/// <param name="pulses">I pulse signal</param>
|
||||
/// <param name="length">I length of input</param>
|
||||
/// <param name="signalType">I Signal type</param>
|
||||
/// <param name="quantOffsetType">I Quantization offset type</param>
|
||||
/// <param name="sum_pulses">I Sum of absolute pulses per block [MAX_NB_SHELL_BLOCKS]</param>
|
||||
internal static void silk_encode_signs(
|
||||
EntropyCoder psRangeEnc,
|
||||
sbyte[] pulses,
|
||||
int length,
|
||||
int signalType,
|
||||
int quantOffsetType,
|
||||
int[] sum_pulses)
|
||||
{
|
||||
int i, j, p;
|
||||
byte[] icdf = new byte[2];
|
||||
int q_ptr;
|
||||
byte[] sign_icdf = Tables.silk_sign_iCDF;
|
||||
int icdf_ptr;
|
||||
|
||||
icdf[1] = 0;
|
||||
q_ptr = 0;
|
||||
i = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1));
|
||||
icdf_ptr = i;
|
||||
length = Inlines.silk_RSHIFT(length + (SilkConstants.SHELL_CODEC_FRAME_LENGTH / 2), SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH);
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
p = sum_pulses[i];
|
||||
if (p > 0)
|
||||
{
|
||||
icdf[0] = sign_icdf[icdf_ptr + Inlines.silk_min(p & 0x1F, 6)];
|
||||
for (j = q_ptr; j < q_ptr + SilkConstants.SHELL_CODEC_FRAME_LENGTH; j++)
|
||||
{
|
||||
if (pulses[j] != 0)
|
||||
{
|
||||
psRangeEnc.enc_icdf( silk_enc_map(pulses[j]), icdf, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
q_ptr += SilkConstants.SHELL_CODEC_FRAME_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes signs of excitation
|
||||
/// </summary>
|
||||
/// <param name="psRangeDec">I/O Compressor data structure</param>
|
||||
/// <param name="pulses">I/O pulse signal</param>
|
||||
/// <param name="length">I length of input</param>
|
||||
/// <param name="signalType">I Signal type</param>
|
||||
/// <param name="quantOffsetType">I Quantization offset type</param>
|
||||
/// <param name="sum_pulses">I Sum of absolute pulses per block [MAX_NB_SHELL_BLOCKS]</param>
|
||||
internal static void silk_decode_signs(
|
||||
EntropyCoder psRangeDec,
|
||||
short[] pulses,
|
||||
int length,
|
||||
int signalType,
|
||||
int quantOffsetType,
|
||||
int[] sum_pulses)
|
||||
{
|
||||
int i, j, p;
|
||||
byte[] icdf = new byte[2];
|
||||
int q_ptr;
|
||||
byte[] icdf_table = Tables.silk_sign_iCDF;
|
||||
int icdf_ptr;
|
||||
|
||||
icdf[1] = 0;
|
||||
q_ptr = 0;
|
||||
i = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1));
|
||||
icdf_ptr = i;
|
||||
length = Inlines.silk_RSHIFT(length + SilkConstants.SHELL_CODEC_FRAME_LENGTH / 2, SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
p = sum_pulses[i];
|
||||
|
||||
if (p > 0)
|
||||
{
|
||||
icdf[0] = icdf_table[icdf_ptr + Inlines.silk_min(p & 0x1F, 6)];
|
||||
for (j = 0; j < SilkConstants.SHELL_CODEC_FRAME_LENGTH; j++)
|
||||
{
|
||||
if (pulses[q_ptr + j] > 0)
|
||||
{
|
||||
/* attach sign */
|
||||
pulses[q_ptr + j] *= (short)(silk_dec_map(psRangeDec.dec_icdf(icdf, 8)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
q_ptr += SilkConstants.SHELL_CODEC_FRAME_LENGTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
/**********************************************************************
|
||||
* Correlation Matrix Computations for LS estimate.
|
||||
**********************************************************************/
|
||||
internal static class CorrelateMatrix
|
||||
{
|
||||
/* Calculates correlation vector X'*t */
|
||||
internal static void silk_corrVector(
|
||||
short[] x, /* I x vector [L + order - 1] used to form data matrix X */
|
||||
int x_ptr,
|
||||
short[] t, /* I Target vector [L] */
|
||||
int t_ptr,
|
||||
int L, /* I Length of vectors */
|
||||
int order, /* I Max lag for correlation */
|
||||
int[] Xt, /* O Pointer to X'*t correlation vector [order] */
|
||||
int rshifts /* I Right shifts of correlations */
|
||||
)
|
||||
{
|
||||
int lag, i;
|
||||
int ptr1;
|
||||
int ptr2;
|
||||
int inner_prod;
|
||||
|
||||
ptr1 = x_ptr + order - 1; /* Points to first sample of column 0 of X: X[:,0] */
|
||||
ptr2 = t_ptr;
|
||||
/* Calculate X'*t */
|
||||
if (rshifts > 0)
|
||||
{
|
||||
/* Right shifting used */
|
||||
for (lag = 0; lag < order; lag++)
|
||||
{
|
||||
inner_prod = 0;
|
||||
for (i = 0; i < L; i++)
|
||||
{
|
||||
inner_prod += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + i], t[ptr2 + i]), rshifts);
|
||||
}
|
||||
Xt[lag] = inner_prod; /* X[:,lag]'*t */
|
||||
ptr1--; /* Go to next column of X */
|
||||
}
|
||||
}
|
||||
else {
|
||||
Inlines.OpusAssert(rshifts == 0);
|
||||
for (lag = 0; lag < order; lag++)
|
||||
{
|
||||
Xt[lag] = Inlines.silk_inner_prod(x, ptr1, t, ptr2, L); /* X[:,lag]'*t */
|
||||
ptr1--; /* Go to next column of X */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates correlation matrix X'*X */
|
||||
internal static void silk_corrMatrix(
|
||||
short[] x, /* I x vector [L + order - 1] used to form data matrix X */
|
||||
int x_ptr,
|
||||
int L, /* I Length of vectors */
|
||||
int order, /* I Max lag for correlation */
|
||||
int head_room, /* I Desired headroom */
|
||||
int[] XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
|
||||
int XX_ptr,
|
||||
BoxedValueInt rshifts /* I/O Right shifts of correlations */
|
||||
)
|
||||
{
|
||||
int i, j, lag, head_room_rshifts;
|
||||
int energy, rshifts_local;
|
||||
int ptr1, ptr2;
|
||||
|
||||
/* Calculate energy to find shift used to fit in 32 bits */
|
||||
SumSqrShift.silk_sum_sqr_shift(out energy, out rshifts_local, x, x_ptr, L + order - 1);
|
||||
/* Add shifts to get the desired head room */
|
||||
head_room_rshifts = Inlines.silk_max(head_room - Inlines.silk_CLZ32(energy), 0);
|
||||
|
||||
energy = Inlines.silk_RSHIFT32(energy, head_room_rshifts);
|
||||
rshifts_local += head_room_rshifts;
|
||||
|
||||
/* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */
|
||||
/* Remove contribution of first order - 1 samples */
|
||||
for (i = x_ptr; i < x_ptr + order - 1; i++)
|
||||
{
|
||||
energy -= Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[i], x[i]), rshifts_local);
|
||||
}
|
||||
if (rshifts_local < rshifts.Val)
|
||||
{
|
||||
/* Adjust energy */
|
||||
energy = Inlines.silk_RSHIFT32(energy, rshifts.Val - rshifts_local);
|
||||
rshifts_local = rshifts.Val;
|
||||
}
|
||||
|
||||
/* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */
|
||||
/* Fill out the diagonal of the correlation matrix */
|
||||
Inlines.MatrixSet(XX, XX_ptr, 0, 0, order, energy);
|
||||
ptr1 = x_ptr + order - 1; /* First sample of column 0 of X */
|
||||
for (j = 1; j < order; j++)
|
||||
{
|
||||
energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + L - j], x[ptr1 + L - j]), rshifts_local));
|
||||
energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 - j], x[ptr1 - j]), rshifts_local));
|
||||
Inlines.MatrixSet(XX, XX_ptr, j, j, order, energy);
|
||||
}
|
||||
|
||||
ptr2 = x_ptr + order - 2; /* First sample of column 1 of X */
|
||||
/* Calculate the remaining elements of the correlation matrix */
|
||||
if (rshifts_local > 0)
|
||||
{
|
||||
/* Right shifting used */
|
||||
for (lag = 1; lag < order; lag++)
|
||||
{
|
||||
/* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
|
||||
energy = 0;
|
||||
for (i = 0; i < L; i++)
|
||||
{
|
||||
energy += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + i], x[ptr2 + i]), rshifts_local);
|
||||
}
|
||||
/* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
|
||||
Inlines.MatrixSet(XX, XX_ptr, lag, 0, order, energy);
|
||||
Inlines.MatrixSet(XX, XX_ptr, 0, lag, order, energy);
|
||||
for (j = 1; j < (order - lag); j++)
|
||||
{
|
||||
energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + L - j], x[ptr2 + L - j]), rshifts_local));
|
||||
energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 - j], x[ptr2 - j]), rshifts_local));
|
||||
Inlines.MatrixSet(XX, XX_ptr, lag + j, j, order, energy);
|
||||
Inlines.MatrixSet(XX, XX_ptr, j, lag + j, order, energy);
|
||||
}
|
||||
ptr2--; /* Update pointer to first sample of next column (lag) in X */
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (lag = 1; lag < order; lag++)
|
||||
{
|
||||
/* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
|
||||
energy = Inlines.silk_inner_prod(x, ptr1, x, ptr2, L);
|
||||
Inlines.MatrixSet(XX, XX_ptr, lag, 0, order,energy);
|
||||
Inlines.MatrixSet(XX, XX_ptr, 0, lag, order, energy);
|
||||
/* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
|
||||
for (j = 1; j < (order - lag); j++)
|
||||
{
|
||||
energy = Inlines.silk_SUB32(energy, Inlines.silk_SMULBB(x[ptr1 + L - j], x[ptr2 + L - j]));
|
||||
energy = Inlines.silk_SMLABB(energy, x[ptr1 - j], x[ptr2 - j]);
|
||||
Inlines.MatrixSet(XX, XX_ptr, lag + j, j, order, energy);
|
||||
Inlines.MatrixSet(XX, XX_ptr, j, lag + j, order, energy);
|
||||
}
|
||||
ptr2--;/* Update pointer to first sample of next column (lag) in X */
|
||||
}
|
||||
}
|
||||
rshifts.Val = rshifts_local;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,461 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodeAPI
|
||||
{
|
||||
/// <summary>
|
||||
/// Reset decoder state
|
||||
/// </summary>
|
||||
/// <param name="decState">I/O Stat</param>
|
||||
/// <returns>Returns error code</returns>
|
||||
internal static int silk_InitDecoder(SilkDecoder decState)
|
||||
{
|
||||
/* Reset decoder */
|
||||
decState.Reset();
|
||||
|
||||
int n, ret = SilkError.SILK_NO_ERROR;
|
||||
SilkChannelDecoder[] channel_states = decState.channel_state;
|
||||
|
||||
for (n = 0; n < SilkConstants.DECODER_NUM_CHANNELS; n++)
|
||||
{
|
||||
ret = channel_states[n].silk_init_decoder();
|
||||
}
|
||||
|
||||
decState.sStereo.Reset();
|
||||
|
||||
/* Not strictly needed, but it's cleaner that way */
|
||||
decState.prev_decode_only_middle = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Decode a frame */
|
||||
internal static int silk_Decode( /* O Returns error code */
|
||||
SilkDecoder psDec, /* I/O State */
|
||||
DecControlState decControl, /* I/O Control Structure */
|
||||
int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
|
||||
int newPacketFlag, /* I Indicates first decoder call for this packet */
|
||||
EntropyCoder psRangeDec, /* I/O Compressor data structure */
|
||||
short[] samplesOut, /* O Decoded output speech vector */
|
||||
int samplesOut_ptr,
|
||||
out int nSamplesOut /* O Number of samples decoded */
|
||||
)
|
||||
{
|
||||
int i, n, decode_only_middle = 0, ret = SilkError.SILK_NO_ERROR;
|
||||
int LBRR_symbol;
|
||||
BoxedValueInt nSamplesOutDec = new BoxedValueInt();
|
||||
short[] samplesOut_tmp;
|
||||
int[] samplesOut_tmp_ptrs = new int[2];
|
||||
short[] samplesOut1_tmp_storage1;
|
||||
short[] samplesOut1_tmp_storage2;
|
||||
short[] samplesOut2_tmp;
|
||||
int[] MS_pred_Q13 = new int[] { 0, 0 };
|
||||
short[] resample_out;
|
||||
int resample_out_ptr;
|
||||
SilkChannelDecoder[] channel_state = psDec.channel_state;
|
||||
int has_side;
|
||||
int stereo_to_mono;
|
||||
int delay_stack_alloc;
|
||||
nSamplesOut = 0;
|
||||
|
||||
Inlines.OpusAssert(decControl.nChannelsInternal == 1 || decControl.nChannelsInternal == 2);
|
||||
|
||||
/**********************************/
|
||||
/* Test if first frame in payload */
|
||||
/**********************************/
|
||||
if (newPacketFlag != 0)
|
||||
{
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
channel_state[n].nFramesDecoded = 0; /* Used to count frames in packet */
|
||||
}
|
||||
}
|
||||
|
||||
/* If Mono . Stereo transition in bitstream: init state of second channel */
|
||||
if (decControl.nChannelsInternal > psDec.nChannelsInternal)
|
||||
{
|
||||
ret += channel_state[1].silk_init_decoder();
|
||||
}
|
||||
|
||||
stereo_to_mono = (decControl.nChannelsInternal == 1 && psDec.nChannelsInternal == 2 &&
|
||||
(decControl.internalSampleRate == 1000 * channel_state[0].fs_kHz)) ? 1 : 0;
|
||||
|
||||
if (channel_state[0].nFramesDecoded == 0)
|
||||
{
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
int fs_kHz_dec;
|
||||
if (decControl.payloadSize_ms == 0)
|
||||
{
|
||||
/* Assuming packet loss, use 10 ms */
|
||||
channel_state[n].nFramesPerPacket = 1;
|
||||
channel_state[n].nb_subfr = 2;
|
||||
}
|
||||
else if (decControl.payloadSize_ms == 10)
|
||||
{
|
||||
channel_state[n].nFramesPerPacket = 1;
|
||||
channel_state[n].nb_subfr = 2;
|
||||
}
|
||||
else if (decControl.payloadSize_ms == 20)
|
||||
{
|
||||
channel_state[n].nFramesPerPacket = 1;
|
||||
channel_state[n].nb_subfr = 4;
|
||||
}
|
||||
else if (decControl.payloadSize_ms == 40)
|
||||
{
|
||||
channel_state[n].nFramesPerPacket = 2;
|
||||
channel_state[n].nb_subfr = 4;
|
||||
}
|
||||
else if (decControl.payloadSize_ms == 60)
|
||||
{
|
||||
channel_state[n].nFramesPerPacket = 3;
|
||||
channel_state[n].nb_subfr = 4;
|
||||
}
|
||||
else {
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_DEC_INVALID_FRAME_SIZE;
|
||||
}
|
||||
fs_kHz_dec = (decControl.internalSampleRate >> 10) + 1;
|
||||
if (fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY;
|
||||
}
|
||||
ret += channel_state[n].silk_decoder_set_fs(fs_kHz_dec, decControl.API_sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2 && (psDec.nChannelsAPI == 1 || psDec.nChannelsInternal == 1))
|
||||
{
|
||||
Arrays.MemSetShort(psDec.sStereo.pred_prev_Q13, 0, 2);
|
||||
Arrays.MemSetShort(psDec.sStereo.sSide, 0, 2);
|
||||
channel_state[1].resampler_state.Assign(channel_state[0].resampler_state);
|
||||
}
|
||||
psDec.nChannelsAPI = decControl.nChannelsAPI;
|
||||
psDec.nChannelsInternal = decControl.nChannelsInternal;
|
||||
|
||||
if (decControl.API_sampleRate > (int)SilkConstants.MAX_API_FS_KHZ * 1000 || decControl.API_sampleRate < 8000)
|
||||
{
|
||||
ret = SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (lostFlag != DecoderAPIFlag.FLAG_PACKET_LOST && channel_state[0].nFramesDecoded == 0)
|
||||
{
|
||||
/* First decoder call for this payload */
|
||||
/* Decode VAD flags and LBRR flag */
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
for (i = 0; i < channel_state[n].nFramesPerPacket; i++)
|
||||
{
|
||||
channel_state[n].VAD_flags[i] = psRangeDec.dec_bit_logp(1);
|
||||
}
|
||||
channel_state[n].LBRR_flag = psRangeDec.dec_bit_logp(1);
|
||||
}
|
||||
/* Decode LBRR flags */
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
Arrays.MemSetInt(channel_state[n].LBRR_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
|
||||
if (channel_state[n].LBRR_flag != 0)
|
||||
{
|
||||
if (channel_state[n].nFramesPerPacket == 1)
|
||||
{
|
||||
channel_state[n].LBRR_flags[0] = 1;
|
||||
}
|
||||
else {
|
||||
LBRR_symbol = psRangeDec.dec_icdf(Tables.silk_LBRR_flags_iCDF_ptr[channel_state[n].nFramesPerPacket - 2], 8) + 1;
|
||||
for (i = 0; i < channel_state[n].nFramesPerPacket; i++)
|
||||
{
|
||||
channel_state[n].LBRR_flags[i] = Inlines.silk_RSHIFT(LBRR_symbol, i) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lostFlag == DecoderAPIFlag.FLAG_DECODE_NORMAL)
|
||||
{
|
||||
/* Regular decoding: skip all LBRR data */
|
||||
for (i = 0; i < channel_state[0].nFramesPerPacket; i++)
|
||||
{
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
if (channel_state[n].LBRR_flags[i] != 0)
|
||||
{
|
||||
short[] pulses = new short[SilkConstants.MAX_FRAME_LENGTH];
|
||||
int condCoding;
|
||||
|
||||
if (decControl.nChannelsInternal == 2 && n == 0)
|
||||
{
|
||||
Stereo.silk_stereo_decode_pred(psRangeDec, MS_pred_Q13);
|
||||
if (channel_state[1].LBRR_flags[i] == 0)
|
||||
{
|
||||
BoxedValueInt decodeOnlyMiddleBoxed = new BoxedValueInt(decode_only_middle);
|
||||
Stereo.silk_stereo_decode_mid_only(psRangeDec, decodeOnlyMiddleBoxed);
|
||||
decode_only_middle = decodeOnlyMiddleBoxed.Val;
|
||||
}
|
||||
}
|
||||
/* Use conditional coding if previous frame available */
|
||||
if (i > 0 && (channel_state[n].LBRR_flags[i - 1] != 0))
|
||||
{
|
||||
condCoding = SilkConstants.CODE_CONDITIONALLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
DecodeIndices.silk_decode_indices(channel_state[n], psRangeDec, i, 1, condCoding);
|
||||
DecodePulses.silk_decode_pulses(psRangeDec, pulses, channel_state[n].indices.signalType,
|
||||
channel_state[n].indices.quantOffsetType, channel_state[n].frame_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get MS predictor index */
|
||||
if (decControl.nChannelsInternal == 2)
|
||||
{
|
||||
if (lostFlag == DecoderAPIFlag.FLAG_DECODE_NORMAL ||
|
||||
(lostFlag == DecoderAPIFlag.FLAG_DECODE_LBRR && channel_state[0].LBRR_flags[channel_state[0].nFramesDecoded] == 1))
|
||||
{
|
||||
Stereo.silk_stereo_decode_pred(psRangeDec, MS_pred_Q13);
|
||||
/* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */
|
||||
if ((lostFlag == DecoderAPIFlag.FLAG_DECODE_NORMAL && channel_state[1].VAD_flags[channel_state[0].nFramesDecoded] == 0) ||
|
||||
(lostFlag == DecoderAPIFlag.FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[channel_state[0].nFramesDecoded] == 0))
|
||||
{
|
||||
BoxedValueInt decodeOnlyMiddleBoxed = new BoxedValueInt(decode_only_middle);
|
||||
Stereo.silk_stereo_decode_mid_only(psRangeDec, decodeOnlyMiddleBoxed);
|
||||
decode_only_middle = decodeOnlyMiddleBoxed.Val;
|
||||
}
|
||||
else
|
||||
{
|
||||
decode_only_middle = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (n = 0; n < 2; n++)
|
||||
{
|
||||
MS_pred_Q13[n] = psDec.sStereo.pred_prev_Q13[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset side channel decoder prediction memory for first frame with side coding */
|
||||
if (decControl.nChannelsInternal == 2 && decode_only_middle == 0 && psDec.prev_decode_only_middle == 1)
|
||||
{
|
||||
Arrays.MemSetShort(psDec.channel_state[1].outBuf, 0, SilkConstants.MAX_FRAME_LENGTH + 2 * SilkConstants.MAX_SUB_FRAME_LENGTH);
|
||||
Arrays.MemSetInt(psDec.channel_state[1].sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
psDec.channel_state[1].lagPrev = 100;
|
||||
psDec.channel_state[1].LastGainIndex = 10;
|
||||
psDec.channel_state[1].prevSignalType = SilkConstants.TYPE_NO_VOICE_ACTIVITY;
|
||||
psDec.channel_state[1].first_frame_after_reset = 1;
|
||||
}
|
||||
|
||||
/* Check if the temp buffer fits into the output PCM buffer. If it fits,
|
||||
we can delay allocating the temp buffer until after the SILK peak stack
|
||||
usage. We need to use a < and not a <= because of the two extra samples. */
|
||||
delay_stack_alloc = (decControl.internalSampleRate * decControl.nChannelsInternal
|
||||
< decControl.API_sampleRate * decControl.nChannelsAPI) ? 1 : 0;
|
||||
|
||||
if (delay_stack_alloc != 0)
|
||||
{
|
||||
samplesOut_tmp = samplesOut;
|
||||
samplesOut_tmp_ptrs[0] = samplesOut_ptr;
|
||||
samplesOut_tmp_ptrs[1] = samplesOut_ptr + channel_state[0].frame_length + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
samplesOut1_tmp_storage1 = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)];
|
||||
samplesOut_tmp = samplesOut1_tmp_storage1;
|
||||
samplesOut_tmp_ptrs[0] = 0;
|
||||
samplesOut_tmp_ptrs[1] = channel_state[0].frame_length + 2;
|
||||
}
|
||||
|
||||
if (lostFlag == DecoderAPIFlag.FLAG_DECODE_NORMAL)
|
||||
{
|
||||
has_side = (decode_only_middle == 0) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
has_side = (psDec.prev_decode_only_middle == 0
|
||||
|| (decControl.nChannelsInternal == 2 &&
|
||||
lostFlag == DecoderAPIFlag.FLAG_DECODE_LBRR &&
|
||||
channel_state[1].LBRR_flags[channel_state[1].nFramesDecoded] == 1)) ? 1 : 0;
|
||||
}
|
||||
/* Call decoder for one frame */
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
if (n == 0 || (has_side != 0))
|
||||
{
|
||||
int FrameIndex;
|
||||
int condCoding;
|
||||
|
||||
FrameIndex = channel_state[0].nFramesDecoded - n;
|
||||
/* Use independent coding if no previous frame available */
|
||||
if (FrameIndex <= 0)
|
||||
{
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
else if (lostFlag == DecoderAPIFlag.FLAG_DECODE_LBRR)
|
||||
{
|
||||
condCoding = (channel_state[n].LBRR_flags[FrameIndex - 1] != 0) ? SilkConstants.CODE_CONDITIONALLY : SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
else if (n > 0 && (psDec.prev_decode_only_middle != 0))
|
||||
{
|
||||
/* If we skipped a side frame in this packet, we don't
|
||||
need LTP scaling; the LTP state is well-defined. */
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY_NO_LTP_SCALING;
|
||||
}
|
||||
else
|
||||
{
|
||||
condCoding = SilkConstants.CODE_CONDITIONALLY;
|
||||
}
|
||||
ret += channel_state[n].silk_decode_frame(psRangeDec, samplesOut_tmp, samplesOut_tmp_ptrs[n] + 2, nSamplesOutDec, lostFlag, condCoding);
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrays.MemSetWithOffset<short>(samplesOut_tmp, 0, samplesOut_tmp_ptrs[n] + 2, nSamplesOutDec.Val);
|
||||
}
|
||||
channel_state[n].nFramesDecoded++;
|
||||
}
|
||||
|
||||
if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2)
|
||||
{
|
||||
/* Convert Mid/Side to Left/Right */
|
||||
Stereo.silk_stereo_MS_to_LR(psDec.sStereo, samplesOut_tmp, samplesOut_tmp_ptrs[0], samplesOut_tmp, samplesOut_tmp_ptrs[1], MS_pred_Q13, channel_state[0].fs_kHz, nSamplesOutDec.Val);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Buffering */
|
||||
Array.Copy(psDec.sStereo.sMid, 0, samplesOut_tmp, samplesOut_tmp_ptrs[0], 2);
|
||||
Array.Copy(samplesOut_tmp, samplesOut_tmp_ptrs[0] + nSamplesOutDec.Val, psDec.sStereo.sMid, 0, 2);
|
||||
}
|
||||
|
||||
/* Number of output samples */
|
||||
nSamplesOut = Inlines.silk_DIV32(nSamplesOutDec.Val * decControl.API_sampleRate, Inlines.silk_SMULBB(channel_state[0].fs_kHz, 1000));
|
||||
|
||||
/* Set up pointers to temp buffers */
|
||||
if (decControl.nChannelsAPI == 2)
|
||||
{
|
||||
samplesOut2_tmp = new short[nSamplesOut];
|
||||
resample_out = samplesOut2_tmp;
|
||||
resample_out_ptr = 0;
|
||||
}
|
||||
else {
|
||||
resample_out = samplesOut;
|
||||
resample_out_ptr = samplesOut_ptr;
|
||||
}
|
||||
|
||||
if (delay_stack_alloc != 0)
|
||||
{
|
||||
samplesOut1_tmp_storage2 = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)];
|
||||
Array.Copy(samplesOut, samplesOut_ptr, samplesOut1_tmp_storage2, 0, decControl.nChannelsInternal * (channel_state[0].frame_length + 2));
|
||||
samplesOut_tmp = samplesOut1_tmp_storage2;
|
||||
samplesOut_tmp_ptrs[0] = 0;
|
||||
samplesOut_tmp_ptrs[1] = channel_state[0].frame_length + 2;
|
||||
}
|
||||
for (n = 0; n < Inlines.silk_min(decControl.nChannelsAPI, decControl.nChannelsInternal); n++)
|
||||
{
|
||||
|
||||
/* Resample decoded signal to API_sampleRate */
|
||||
ret += Resampler.silk_resampler(channel_state[n].resampler_state, resample_out, resample_out_ptr, samplesOut_tmp, samplesOut_tmp_ptrs[n] + 1, nSamplesOutDec.Val);
|
||||
|
||||
/* Interleave if stereo output and stereo stream */
|
||||
if (decControl.nChannelsAPI == 2)
|
||||
{
|
||||
int nptr = samplesOut_ptr + n;
|
||||
for (i = 0; i < nSamplesOut; i++)
|
||||
{
|
||||
samplesOut[nptr + 2 * i] = resample_out[resample_out_ptr + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create two channel output from mono stream */
|
||||
if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 1)
|
||||
{
|
||||
if (stereo_to_mono != 0)
|
||||
{
|
||||
/* Resample right channel for newly collapsed stereo just in case
|
||||
we weren't doing collapsing when switching to mono */
|
||||
ret += Resampler.silk_resampler(channel_state[1].resampler_state, resample_out, resample_out_ptr, samplesOut_tmp, samplesOut_tmp_ptrs[0] + 1, nSamplesOutDec.Val);
|
||||
|
||||
for (i = 0; i < nSamplesOut; i++)
|
||||
{
|
||||
samplesOut[samplesOut_ptr + 1 + 2 * i] = resample_out[resample_out_ptr + i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < nSamplesOut; i++)
|
||||
{
|
||||
samplesOut[samplesOut_ptr + 1 + 2 * i] = samplesOut[samplesOut_ptr + 2 * i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Export pitch lag, measured at 48 kHz sampling rate */
|
||||
if (channel_state[0].prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
int[] mult_tab = { 6, 4, 3 };
|
||||
decControl.prevPitchLag = channel_state[0].lagPrev * mult_tab[(channel_state[0].fs_kHz - 8) >> 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
decControl.prevPitchLag = 0;
|
||||
}
|
||||
|
||||
if (lostFlag == DecoderAPIFlag.FLAG_PACKET_LOST)
|
||||
{
|
||||
/* On packet loss, remove the gain clamping to prevent having the energy "bounce back"
|
||||
if we lose packets when the energy is going down */
|
||||
for (i = 0; i < psDec.nChannelsInternal; i++)
|
||||
psDec.channel_state[i].LastGainIndex = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
psDec.prev_decode_only_middle = decode_only_middle;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodeCore
|
||||
{
|
||||
/**********************************************************/
|
||||
/* Core decoder. Performs inverse NSQ operation LTP + LPC */
|
||||
/**********************************************************/
|
||||
internal static void silk_decode_core(
|
||||
SilkChannelDecoder psDec, /* I/O Decoder state */
|
||||
SilkDecoderControl psDecCtrl, /* I Decoder control */
|
||||
short[] xq, /* O Decoded speech */
|
||||
int xq_ptr,
|
||||
short[] pulses /* I Pulse signal [MAX_FRAME_LENGTH] */
|
||||
)
|
||||
{
|
||||
int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType;
|
||||
short[] A_Q12;
|
||||
short[] B_Q14 = psDecCtrl.LTPCoef_Q14;
|
||||
int B_Q14_ptr;
|
||||
int pxq;
|
||||
short[] sLTP;
|
||||
int[] sLTP_Q15;
|
||||
int LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10;
|
||||
int pred_lag_ptr;
|
||||
int pexc_Q14;
|
||||
int[] pres_Q14;
|
||||
int pres_Q14_ptr;
|
||||
int[] res_Q14;
|
||||
int[] sLPC_Q14;
|
||||
|
||||
Inlines.OpusAssert(psDec.prev_gain_Q16 != 0);
|
||||
|
||||
sLTP= new short[psDec.ltp_mem_length];
|
||||
sLTP_Q15 = new int[psDec.ltp_mem_length + psDec.frame_length];
|
||||
res_Q14 = new int[psDec.subfr_length];
|
||||
sLPC_Q14 = new int[psDec.subfr_length + SilkConstants.MAX_LPC_ORDER];
|
||||
|
||||
offset_Q10 = Tables.silk_Quantization_Offsets_Q10[psDec.indices.signalType >> 1][psDec.indices.quantOffsetType];
|
||||
|
||||
if (psDec.indices.NLSFInterpCoef_Q2 < 1 << 2)
|
||||
{
|
||||
NLSF_interpolation_flag = 1;
|
||||
}
|
||||
else {
|
||||
NLSF_interpolation_flag = 0;
|
||||
}
|
||||
|
||||
/* Decode excitation */
|
||||
rand_seed = psDec.indices.Seed;
|
||||
for (i = 0; i < psDec.frame_length; i++)
|
||||
{
|
||||
rand_seed = Inlines.silk_RAND(rand_seed);
|
||||
psDec.exc_Q14[i] = Inlines.silk_LSHIFT((int)pulses[i], 14);
|
||||
if (psDec.exc_Q14[i] > 0)
|
||||
{
|
||||
psDec.exc_Q14[i] -= SilkConstants.QUANT_LEVEL_ADJUST_Q10 << 4;
|
||||
}
|
||||
else
|
||||
if (psDec.exc_Q14[i] < 0)
|
||||
{
|
||||
psDec.exc_Q14[i] += SilkConstants.QUANT_LEVEL_ADJUST_Q10 << 4;
|
||||
}
|
||||
psDec.exc_Q14[i] += offset_Q10 << 4;
|
||||
if (rand_seed < 0)
|
||||
{
|
||||
psDec.exc_Q14[i] = -psDec.exc_Q14[i];
|
||||
}
|
||||
|
||||
rand_seed = Inlines.silk_ADD32_ovflw(rand_seed, pulses[i]);
|
||||
}
|
||||
|
||||
/* Copy LPC state */
|
||||
Array.Copy(psDec.sLPC_Q14_buf, sLPC_Q14, SilkConstants.MAX_LPC_ORDER);
|
||||
|
||||
pexc_Q14 = 0;
|
||||
pxq = xq_ptr;
|
||||
sLTP_buf_idx = psDec.ltp_mem_length;
|
||||
/* Loop over subframes */
|
||||
for (k = 0; k < psDec.nb_subfr; k++)
|
||||
{
|
||||
pres_Q14 = res_Q14;
|
||||
pres_Q14_ptr = 0;
|
||||
A_Q12 = psDecCtrl.PredCoef_Q12[k >> 1];
|
||||
B_Q14_ptr = k * SilkConstants.LTP_ORDER;
|
||||
signalType = psDec.indices.signalType;
|
||||
|
||||
Gain_Q10 = Inlines.silk_RSHIFT(psDecCtrl.Gains_Q16[k], 6);
|
||||
inv_gain_Q31 = Inlines.silk_INVERSE32_varQ(psDecCtrl.Gains_Q16[k], 47);
|
||||
|
||||
/* Calculate gain adjustment factor */
|
||||
if (psDecCtrl.Gains_Q16[k] != psDec.prev_gain_Q16)
|
||||
{
|
||||
gain_adj_Q16 = Inlines.silk_DIV32_varQ(psDec.prev_gain_Q16, psDecCtrl.Gains_Q16[k], 16);
|
||||
|
||||
/* Scale short term state */
|
||||
for (i = 0; i < SilkConstants.MAX_LPC_ORDER; i++)
|
||||
{
|
||||
sLPC_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, sLPC_Q14[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gain_adj_Q16 = (int)1 << 16;
|
||||
}
|
||||
|
||||
/* Save inv_gain */
|
||||
Inlines.OpusAssert(inv_gain_Q31 != 0);
|
||||
psDec.prev_gain_Q16 = psDecCtrl.Gains_Q16[k];
|
||||
|
||||
/* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */
|
||||
if (psDec.lossCnt != 0 && psDec.prevSignalType == SilkConstants.TYPE_VOICED &&
|
||||
psDec.indices.signalType != SilkConstants.TYPE_VOICED && k < SilkConstants.MAX_NB_SUBFR / 2)
|
||||
{
|
||||
|
||||
Arrays.MemSetWithOffset<short>(B_Q14, 0, B_Q14_ptr, SilkConstants.LTP_ORDER);
|
||||
B_Q14[B_Q14_ptr + (SilkConstants.LTP_ORDER / 2)] = (short)(((int)((0.25f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(0.25f, 14)*/);
|
||||
|
||||
signalType = SilkConstants.TYPE_VOICED;
|
||||
psDecCtrl.pitchL[k] = psDec.lagPrev;
|
||||
}
|
||||
|
||||
if (signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Voiced */
|
||||
lag = psDecCtrl.pitchL[k];
|
||||
|
||||
/* Re-whitening */
|
||||
if (k == 0 || (k == 2 && (NLSF_interpolation_flag != 0)))
|
||||
{
|
||||
/* Rewhiten with new A coefs */
|
||||
start_idx = psDec.ltp_mem_length - lag - psDec.LPC_order - SilkConstants.LTP_ORDER / 2;
|
||||
Inlines.OpusAssert(start_idx > 0);
|
||||
|
||||
if (k == 2)
|
||||
{
|
||||
Array.Copy(xq, xq_ptr, psDec.outBuf, psDec.ltp_mem_length, 2 * psDec.subfr_length);
|
||||
}
|
||||
|
||||
Filters.silk_LPC_analysis_filter(sLTP, start_idx, psDec.outBuf, (start_idx + k * psDec.subfr_length),
|
||||
A_Q12, 0, psDec.ltp_mem_length - start_idx, psDec.LPC_order);
|
||||
|
||||
/* After rewhitening the LTP state is unscaled */
|
||||
if (k == 0)
|
||||
{
|
||||
/* Do LTP downscaling to reduce inter-packet dependency */
|
||||
inv_gain_Q31 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(inv_gain_Q31, psDecCtrl.LTP_scale_Q14), 2);
|
||||
}
|
||||
for (i = 0; i < lag + SilkConstants.LTP_ORDER / 2; i++)
|
||||
{
|
||||
sLTP_Q15[sLTP_buf_idx - i - 1] = Inlines.silk_SMULWB(inv_gain_Q31, sLTP[psDec.ltp_mem_length - i - 1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Update LTP state when Gain changes */
|
||||
if (gain_adj_Q16 != (int)1 << 16)
|
||||
{
|
||||
for (i = 0; i < lag + SilkConstants.LTP_ORDER / 2; i++)
|
||||
{
|
||||
sLTP_Q15[sLTP_buf_idx - i - 1] = Inlines.silk_SMULWW(gain_adj_Q16, sLTP_Q15[sLTP_buf_idx - i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Long-term prediction */
|
||||
if (signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Set up pointer */
|
||||
pred_lag_ptr = sLTP_buf_idx - lag + SilkConstants.LTP_ORDER / 2;
|
||||
for (i = 0; i < psDec.subfr_length; i++)
|
||||
{
|
||||
/* Unrolled loop */
|
||||
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
|
||||
LTP_pred_Q13 = 2;
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr], B_Q14[B_Q14_ptr]);
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 1], B_Q14[B_Q14_ptr + 1]);
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 2], B_Q14[B_Q14_ptr + 2]);
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 3], B_Q14[B_Q14_ptr + 3]);
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 4], B_Q14[B_Q14_ptr + 4]);
|
||||
pred_lag_ptr += 1;
|
||||
|
||||
/* Generate LPC excitation */
|
||||
pres_Q14[pres_Q14_ptr + i] = Inlines.silk_ADD_LSHIFT32(psDec.exc_Q14[pexc_Q14 + i], LTP_pred_Q13, 1);
|
||||
|
||||
/* Update states */
|
||||
sLTP_Q15[sLTP_buf_idx] = Inlines.silk_LSHIFT(pres_Q14[pres_Q14_ptr + i], 1);
|
||||
sLTP_buf_idx++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pres_Q14 = psDec.exc_Q14;
|
||||
pres_Q14_ptr = pexc_Q14;
|
||||
}
|
||||
|
||||
for (i = 0; i < psDec.subfr_length; i++)
|
||||
{
|
||||
/* Short-term prediction */
|
||||
Inlines.OpusAssert(psDec.LPC_order == 10 || psDec.LPC_order == 16);
|
||||
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
|
||||
LPC_pred_Q10 = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 1], A_Q12[0]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 2], A_Q12[1]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 3], A_Q12[2]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 4], A_Q12[3]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 5], A_Q12[4]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 6], A_Q12[5]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 7], A_Q12[6]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 8], A_Q12[7]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 9], A_Q12[8]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 10], A_Q12[9]);
|
||||
if (psDec.LPC_order == 16)
|
||||
{
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 11], A_Q12[10]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 12], A_Q12[11]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 13], A_Q12[12]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 14], A_Q12[13]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 15], A_Q12[14]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 16], A_Q12[15]);
|
||||
}
|
||||
|
||||
/* Add prediction to LPC excitation */
|
||||
sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i] = Inlines.silk_ADD_LSHIFT32(pres_Q14[pres_Q14_ptr + i], LPC_pred_Q10, 4);
|
||||
|
||||
/* Scale with gain */
|
||||
xq[pxq + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i], Gain_Q10), 8));
|
||||
}
|
||||
|
||||
/* DEBUG_STORE_DATA( dec.pcm, pxq, psDec.subfr_length * sizeof( short ) ) */
|
||||
|
||||
/* Update LPC filter state */
|
||||
Array.Copy(sLPC_Q14, psDec.subfr_length, sLPC_Q14, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
pexc_Q14 += psDec.subfr_length;
|
||||
pxq += psDec.subfr_length;
|
||||
}
|
||||
|
||||
/* Save LPC state */
|
||||
Array.Copy(sLPC_Q14, 0, psDec.sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodeIndices
|
||||
{
|
||||
/* Decode side-information parameters from payload */
|
||||
internal static void silk_decode_indices(
|
||||
SilkChannelDecoder psDec, /* I/O State */
|
||||
EntropyCoder psRangeDec, /* I/O Compressor data structure */
|
||||
int FrameIndex, /* I Frame number */
|
||||
int decode_LBRR, /* I Flag indicating LBRR data is being decoded */
|
||||
int condCoding /* I The type of conditional coding to use */
|
||||
)
|
||||
{
|
||||
int i, k, Ix;
|
||||
int decode_absolute_lagIndex, delta_lagIndex;
|
||||
short[] ec_ix = new short[psDec.LPC_order];
|
||||
byte[] pred_Q8 = new byte[psDec.LPC_order];
|
||||
|
||||
/*******************************************/
|
||||
/* Decode signal type and quantizer offset */
|
||||
/*******************************************/
|
||||
if (decode_LBRR != 0 || psDec.VAD_flags[FrameIndex] != 0)
|
||||
{
|
||||
Ix = psRangeDec.dec_icdf(Tables.silk_type_offset_VAD_iCDF, 8) + 2;
|
||||
}
|
||||
else {
|
||||
Ix = psRangeDec.dec_icdf(Tables.silk_type_offset_no_VAD_iCDF, 8);
|
||||
}
|
||||
psDec.indices.signalType = (sbyte)Inlines.silk_RSHIFT(Ix, 1);
|
||||
psDec.indices.quantOffsetType = (sbyte)(Ix & 1);
|
||||
|
||||
/****************/
|
||||
/* Decode gains */
|
||||
/****************/
|
||||
/* First subframe */
|
||||
if (condCoding == SilkConstants.CODE_CONDITIONALLY)
|
||||
{
|
||||
/* Conditional coding */
|
||||
psDec.indices.GainsIndices[0] = (sbyte)psRangeDec.dec_icdf(Tables.silk_delta_gain_iCDF, 8);
|
||||
}
|
||||
else {
|
||||
/* Independent coding, in two stages: MSB bits followed by 3 LSBs */
|
||||
psDec.indices.GainsIndices[0] = (sbyte)Inlines.silk_LSHIFT(psRangeDec.dec_icdf(Tables.silk_gain_iCDF[psDec.indices.signalType], 8), 3);
|
||||
psDec.indices.GainsIndices[0] += (sbyte)psRangeDec.dec_icdf(Tables.silk_uniform8_iCDF, 8);
|
||||
}
|
||||
|
||||
/* Remaining subframes */
|
||||
for (i = 1; i < psDec.nb_subfr; i++)
|
||||
{
|
||||
psDec.indices.GainsIndices[i] = (sbyte)psRangeDec.dec_icdf(Tables.silk_delta_gain_iCDF, 8);
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Decode LSF Indices */
|
||||
/**********************/
|
||||
psDec.indices.NLSFIndices[0] = (sbyte)psRangeDec.dec_icdf(psDec.psNLSF_CB.CB1_iCDF, (psDec.indices.signalType >> 1) * psDec.psNLSF_CB.nVectors, 8);
|
||||
NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psDec.psNLSF_CB, psDec.indices.NLSFIndices[0]);
|
||||
Inlines.OpusAssert(psDec.psNLSF_CB.order == psDec.LPC_order);
|
||||
for (i = 0; i < psDec.psNLSF_CB.order; i++)
|
||||
{
|
||||
Ix = psRangeDec.dec_icdf(psDec.psNLSF_CB.ec_iCDF, (ec_ix[i]), 8);
|
||||
if (Ix == 0)
|
||||
{
|
||||
Ix -= psRangeDec.dec_icdf(Tables.silk_NLSF_EXT_iCDF, 8);
|
||||
}
|
||||
else if (Ix == 2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE)
|
||||
{
|
||||
Ix += psRangeDec.dec_icdf(Tables.silk_NLSF_EXT_iCDF, 8);
|
||||
}
|
||||
psDec.indices.NLSFIndices[i + 1] = (sbyte)(Ix - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE);
|
||||
}
|
||||
|
||||
/* Decode LSF interpolation factor */
|
||||
if (psDec.nb_subfr == SilkConstants.MAX_NB_SUBFR)
|
||||
{
|
||||
psDec.indices.NLSFInterpCoef_Q2 = (sbyte)psRangeDec.dec_icdf(Tables.silk_NLSF_interpolation_factor_iCDF, 8);
|
||||
}
|
||||
else {
|
||||
psDec.indices.NLSFInterpCoef_Q2 = 4;
|
||||
}
|
||||
|
||||
if (psDec.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/*********************/
|
||||
/* Decode pitch lags */
|
||||
/*********************/
|
||||
/* Get lag index */
|
||||
decode_absolute_lagIndex = 1;
|
||||
if (condCoding == SilkConstants.CODE_CONDITIONALLY && psDec.ec_prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Decode Delta index */
|
||||
delta_lagIndex = (short)psRangeDec.dec_icdf(Tables.silk_pitch_delta_iCDF, 8);
|
||||
if (delta_lagIndex > 0)
|
||||
{
|
||||
delta_lagIndex = delta_lagIndex - 9;
|
||||
psDec.indices.lagIndex = (short)(psDec.ec_prevLagIndex + delta_lagIndex);
|
||||
decode_absolute_lagIndex = 0;
|
||||
}
|
||||
}
|
||||
if (decode_absolute_lagIndex != 0)
|
||||
{
|
||||
/* Absolute decoding */
|
||||
psDec.indices.lagIndex = (short)(psRangeDec.dec_icdf(Tables.silk_pitch_lag_iCDF, 8) * Inlines.silk_RSHIFT(psDec.fs_kHz, 1));
|
||||
psDec.indices.lagIndex += (short)psRangeDec.dec_icdf(psDec.pitch_lag_low_bits_iCDF, 8);
|
||||
}
|
||||
psDec.ec_prevLagIndex = psDec.indices.lagIndex;
|
||||
|
||||
/* Get countour index */
|
||||
psDec.indices.contourIndex = (sbyte)psRangeDec.dec_icdf(psDec.pitch_contour_iCDF, 8);
|
||||
|
||||
/********************/
|
||||
/* Decode LTP gains */
|
||||
/********************/
|
||||
/* Decode PERIndex value */
|
||||
psDec.indices.PERIndex = (sbyte)psRangeDec.dec_icdf(Tables.silk_LTP_per_index_iCDF, 8);
|
||||
|
||||
for (k = 0; k < psDec.nb_subfr; k++)
|
||||
{
|
||||
psDec.indices.LTPIndex[k] = (sbyte)psRangeDec.dec_icdf(Tables.silk_LTP_gain_iCDF_ptrs[psDec.indices.PERIndex], 8);
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Decode LTP scaling */
|
||||
/**********************/
|
||||
if (condCoding == SilkConstants.CODE_INDEPENDENTLY)
|
||||
{
|
||||
psDec.indices.LTP_scaleIndex = (sbyte)psRangeDec.dec_icdf(Tables.silk_LTPscale_iCDF, 8);
|
||||
}
|
||||
else {
|
||||
psDec.indices.LTP_scaleIndex = 0;
|
||||
}
|
||||
}
|
||||
psDec.ec_prevSignalType = psDec.indices.signalType;
|
||||
|
||||
/***************/
|
||||
/* Decode seed */
|
||||
/***************/
|
||||
psDec.indices.Seed = (sbyte)psRangeDec.dec_icdf(Tables.silk_uniform4_iCDF, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal class DecodeParameters
|
||||
{
|
||||
/* Decode parameters from payload */
|
||||
internal static void silk_decode_parameters(
|
||||
SilkChannelDecoder psDec, /* I/O State */
|
||||
SilkDecoderControl psDecCtrl, /* I/O Decoder control */
|
||||
int condCoding /* I The type of conditional coding to use */
|
||||
)
|
||||
{
|
||||
int i, k, Ix;
|
||||
short[] pNLSF_Q15 = new short[psDec.LPC_order];
|
||||
short[] pNLSF0_Q15 = new short[psDec.LPC_order];
|
||||
sbyte[][] cbk_ptr_Q7;
|
||||
|
||||
/* Dequant Gains */
|
||||
BoxedValueSbyte boxedLastGainIndex = new BoxedValueSbyte(psDec.LastGainIndex);
|
||||
GainQuantization.silk_gains_dequant(psDecCtrl.Gains_Q16, psDec.indices.GainsIndices,
|
||||
boxedLastGainIndex, condCoding == SilkConstants.CODE_CONDITIONALLY ? 1 : 0, psDec.nb_subfr);
|
||||
psDec.LastGainIndex = boxedLastGainIndex.Val;
|
||||
|
||||
/****************/
|
||||
/* Decode NLSFs */
|
||||
/****************/
|
||||
NLSF.silk_NLSF_decode(pNLSF_Q15, psDec.indices.NLSFIndices, psDec.psNLSF_CB);
|
||||
|
||||
/* Convert NLSF parameters to AR prediction filter coefficients */
|
||||
NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[1], pNLSF_Q15, psDec.LPC_order);
|
||||
|
||||
/* If just reset, e.g., because internal Fs changed, do not allow interpolation */
|
||||
/* improves the case of packet loss in the first frame after a switch */
|
||||
if (psDec.first_frame_after_reset == 1)
|
||||
{
|
||||
psDec.indices.NLSFInterpCoef_Q2 = 4;
|
||||
}
|
||||
|
||||
if (psDec.indices.NLSFInterpCoef_Q2 < 4)
|
||||
{
|
||||
/* Calculation of the interpolated NLSF0 vector from the interpolation factor, */
|
||||
/* the previous NLSF1, and the current NLSF1 */
|
||||
for (i = 0; i < psDec.LPC_order; i++)
|
||||
{
|
||||
pNLSF0_Q15[i] = (short)(psDec.prevNLSF_Q15[i] + Inlines.silk_RSHIFT(Inlines.silk_MUL(psDec.indices.NLSFInterpCoef_Q2,
|
||||
pNLSF_Q15[i] - psDec.prevNLSF_Q15[i]), 2));
|
||||
}
|
||||
|
||||
/* Convert NLSF parameters to AR prediction filter coefficients */
|
||||
NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[0], pNLSF0_Q15, psDec.LPC_order);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy LPC coefficients for first half from second half */
|
||||
Array.Copy(psDecCtrl.PredCoef_Q12[1], psDecCtrl.PredCoef_Q12[0], psDec.LPC_order);
|
||||
}
|
||||
|
||||
Array.Copy(pNLSF_Q15, psDec.prevNLSF_Q15, psDec.LPC_order);
|
||||
|
||||
/* After a packet loss do BWE of LPC coefs */
|
||||
if (psDec.lossCnt != 0)
|
||||
{
|
||||
BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[0], psDec.LPC_order, SilkConstants.BWE_AFTER_LOSS_Q16);
|
||||
BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[1], psDec.LPC_order, SilkConstants.BWE_AFTER_LOSS_Q16);
|
||||
}
|
||||
|
||||
if (psDec.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/*********************/
|
||||
/* Decode pitch lags */
|
||||
/*********************/
|
||||
|
||||
/* Decode pitch values */
|
||||
DecodePitch.silk_decode_pitch(psDec.indices.lagIndex, psDec.indices.contourIndex, psDecCtrl.pitchL, psDec.fs_kHz, psDec.nb_subfr);
|
||||
|
||||
/* Decode Codebook Index */
|
||||
cbk_ptr_Q7 = Tables.silk_LTP_vq_ptrs_Q7[psDec.indices.PERIndex]; /* set pointer to start of codebook */
|
||||
|
||||
for (k = 0; k < psDec.nb_subfr; k++)
|
||||
{
|
||||
Ix = psDec.indices.LTPIndex[k];
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
psDecCtrl.LTPCoef_Q14[k * SilkConstants.LTP_ORDER + i] = (short)(Inlines.silk_LSHIFT(cbk_ptr_Q7[Ix][i], 7));
|
||||
}
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Decode LTP scaling */
|
||||
/**********************/
|
||||
Ix = psDec.indices.LTP_scaleIndex;
|
||||
psDecCtrl.LTP_scale_Q14 = Tables.silk_LTPScales_table_Q14[Ix];
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrays.MemSetInt(psDecCtrl.pitchL, 0, psDec.nb_subfr);
|
||||
Arrays.MemSetShort(psDecCtrl.LTPCoef_Q14, 0, SilkConstants.LTP_ORDER * psDec.nb_subfr);
|
||||
psDec.indices.PERIndex = 0;
|
||||
psDecCtrl.LTP_scale_Q14 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodePitch
|
||||
{
|
||||
internal static void silk_decode_pitch(
|
||||
short lagIndex, /* I */
|
||||
sbyte contourIndex, /* O */
|
||||
int[] pitch_lags, /* O 4 pitch values */
|
||||
int Fs_kHz, /* I sampling frequency (kHz) */
|
||||
int nb_subfr /* I number of sub frames */
|
||||
)
|
||||
{
|
||||
int lag, k, min_lag, max_lag;
|
||||
sbyte[][] Lag_CB_ptr;
|
||||
|
||||
if (Fs_kHz == 8)
|
||||
{
|
||||
if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR)
|
||||
{
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage2_10_ms;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR)
|
||||
{
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3;
|
||||
}
|
||||
else
|
||||
{
|
||||
Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3_10_ms;
|
||||
}
|
||||
}
|
||||
|
||||
min_lag = Inlines.silk_SMULBB(SilkConstants.PE_MIN_LAG_MS, Fs_kHz);
|
||||
max_lag = Inlines.silk_SMULBB(SilkConstants.PE_MAX_LAG_MS, Fs_kHz);
|
||||
lag = min_lag + lagIndex;
|
||||
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
pitch_lags[k] = lag + Lag_CB_ptr[k][contourIndex];
|
||||
pitch_lags[k] = Inlines.silk_LIMIT(pitch_lags[k], min_lag, max_lag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodePulses
|
||||
{
|
||||
/*********************************************/
|
||||
/* Decode quantization indices of excitation */
|
||||
/*********************************************/
|
||||
internal static void silk_decode_pulses(
|
||||
EntropyCoder psRangeDec, /* I/O Compressor data structure */
|
||||
short[] pulses, /* O Excitation signal */
|
||||
int signalType, /* I Sigtype */
|
||||
int quantOffsetType, /* I quantOffsetType */
|
||||
int frame_length /* I Frame length */
|
||||
)
|
||||
{
|
||||
int i, j, k, iter, abs_q, nLS, RateLevelIndex;
|
||||
int[] sum_pulses = new int[SilkConstants.MAX_NB_SHELL_BLOCKS];
|
||||
int[] nLshifts = new int[SilkConstants.MAX_NB_SHELL_BLOCKS];
|
||||
int pulses_ptr;
|
||||
|
||||
/*********************/
|
||||
/* Decode rate level */
|
||||
/*********************/
|
||||
RateLevelIndex = psRangeDec.dec_icdf(Tables.silk_rate_levels_iCDF[signalType >> 1], 8);
|
||||
|
||||
/* Calculate number of shell blocks */
|
||||
Inlines.OpusAssert(1 << SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH == SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
iter = Inlines.silk_RSHIFT(frame_length, SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH);
|
||||
if (iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH < frame_length)
|
||||
{
|
||||
Inlines.OpusAssert(frame_length == 12 * 10); /* Make sure only happens for 10 ms @ 12 kHz */
|
||||
iter++;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/* Sum-Weighted-Pulses Decoding */
|
||||
/***************************************************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
nLshifts[i] = 0;
|
||||
sum_pulses[i] = psRangeDec.dec_icdf(Tables.silk_pulses_per_block_iCDF[RateLevelIndex], 8);
|
||||
|
||||
/* LSB indication */
|
||||
while (sum_pulses[i] == SilkConstants.SILK_MAX_PULSES + 1)
|
||||
{
|
||||
nLshifts[i]++;
|
||||
/* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */
|
||||
sum_pulses[i] = psRangeDec.dec_icdf(
|
||||
Tables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], (nLshifts[i] == 10 ? 1 : 0), 8);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/* Shell decoding */
|
||||
/***************************************************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (sum_pulses[i] > 0)
|
||||
{
|
||||
ShellCoder.silk_shell_decoder(pulses, Inlines.silk_SMULBB(i, SilkConstants.SHELL_CODEC_FRAME_LENGTH), psRangeDec, sum_pulses[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrays.MemSetWithOffset<short>(pulses, 0, Inlines.silk_SMULBB(i, SilkConstants.SHELL_CODEC_FRAME_LENGTH), SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/* LSB Decoding */
|
||||
/***************************************************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (nLshifts[i] > 0)
|
||||
{
|
||||
nLS = nLshifts[i];
|
||||
pulses_ptr = Inlines.silk_SMULBB(i, SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
for (k = 0; k < SilkConstants.SHELL_CODEC_FRAME_LENGTH; k++)
|
||||
{
|
||||
abs_q = pulses[pulses_ptr + k];
|
||||
for (j = 0; j < nLS; j++)
|
||||
{
|
||||
abs_q = Inlines.silk_LSHIFT(abs_q, 1);
|
||||
abs_q += psRangeDec.dec_icdf(Tables.silk_lsb_iCDF, 8);
|
||||
}
|
||||
pulses[pulses_ptr + k] = (short)(abs_q);
|
||||
}
|
||||
/* Mark the number of pulses non-zero for sign decoding. */
|
||||
sum_pulses[i] |= nLS << 5;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
/* Decode and add signs to pulse signal */
|
||||
/****************************************/
|
||||
CodeSigns.silk_decode_signs(psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,740 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class EncodeAPI
|
||||
{
|
||||
/// <summary>
|
||||
/// Init or Reset encoder
|
||||
/// </summary>
|
||||
/// <param name="encState">I/O State</param>
|
||||
/// <param name="encStatus">O Encoder Status</param>
|
||||
/// <returns>O Returns error code</returns>
|
||||
internal static int silk_InitEncoder(SilkEncoder encState, EncControlState encStatus)
|
||||
{
|
||||
int ret = SilkError.SILK_NO_ERROR;
|
||||
|
||||
/* Reset encoder */
|
||||
encState.Reset();
|
||||
|
||||
for (int n = 0; n < SilkConstants.ENCODER_NUM_CHANNELS; n++)
|
||||
{
|
||||
ret += SilkEncoder.silk_init_encoder(encState.state_Fxx[n]);
|
||||
Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR);
|
||||
}
|
||||
|
||||
encState.nChannelsAPI = 1;
|
||||
encState.nChannelsInternal = 1;
|
||||
|
||||
/* Read control structure */
|
||||
ret += silk_QueryEncoder(encState, encStatus);
|
||||
Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read control structure from encode
|
||||
/// </summary>
|
||||
/// <param name="encState">I State</param>
|
||||
/// <param name="encStatus">O Encoder Status</param>
|
||||
/// <returns>Returns error code</returns>
|
||||
internal static int silk_QueryEncoder(SilkEncoder encState, EncControlState encStatus)
|
||||
{
|
||||
int ret = SilkError.SILK_NO_ERROR;
|
||||
SilkChannelEncoder state_Fxx = encState.state_Fxx[0];
|
||||
|
||||
encStatus.Reset();
|
||||
|
||||
encStatus.nChannelsAPI = encState.nChannelsAPI;
|
||||
encStatus.nChannelsInternal = encState.nChannelsInternal;
|
||||
encStatus.API_sampleRate = state_Fxx.API_fs_Hz;
|
||||
encStatus.maxInternalSampleRate = state_Fxx.maxInternal_fs_Hz;
|
||||
encStatus.minInternalSampleRate = state_Fxx.minInternal_fs_Hz;
|
||||
encStatus.desiredInternalSampleRate = state_Fxx.desiredInternal_fs_Hz;
|
||||
encStatus.payloadSize_ms = state_Fxx.PacketSize_ms;
|
||||
encStatus.bitRate = state_Fxx.TargetRate_bps;
|
||||
encStatus.packetLossPercentage = state_Fxx.PacketLoss_perc;
|
||||
encStatus.complexity = state_Fxx.Complexity;
|
||||
encStatus.useInBandFEC = state_Fxx.useInBandFEC;
|
||||
encStatus.useDTX = state_Fxx.useDTX;
|
||||
encStatus.useCBR = state_Fxx.useCBR;
|
||||
encStatus.internalSampleRate = Inlines.silk_SMULBB(state_Fxx.fs_kHz, 1000);
|
||||
encStatus.allowBandwidthSwitch = state_Fxx.allow_bandwidth_switch;
|
||||
encStatus.inWBmodeWithoutVariableLP = (state_Fxx.fs_kHz == 16 && state_Fxx.sLP.mode == 0) ? 1 : 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode frame with Silk
|
||||
/// Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what
|
||||
/// encControl.payloadSize_ms is set to
|
||||
/// </summary>
|
||||
/// <param name="psEnc">I/O State</param>
|
||||
/// <param name="encControl">I Control status</param>
|
||||
/// <param name="samplesIn">I Speech sample input vector</param>
|
||||
/// <param name="nSamplesIn">I Number of samples in input vector</param>
|
||||
/// <param name="psRangeEnc">I/O Compressor data structure</param>
|
||||
/// <param name="nBytesOut">I/O Number of bytes in payload (input: Max bytes)</param>
|
||||
/// <param name="prefillFlag">I Flag to indicate prefilling buffers no coding</param>
|
||||
/// <returns>error code</returns>
|
||||
internal static int silk_Encode(
|
||||
SilkEncoder psEnc,
|
||||
EncControlState encControl,
|
||||
short[] samplesIn,
|
||||
int nSamplesIn,
|
||||
EntropyCoder psRangeEnc,
|
||||
BoxedValueInt nBytesOut,
|
||||
int prefillFlag)
|
||||
{
|
||||
int ret = SilkError.SILK_NO_ERROR;
|
||||
int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0;
|
||||
int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms;
|
||||
int nSamplesFromInput = 0, nSamplesFromInputMax;
|
||||
int speech_act_thr_for_switch_Q8;
|
||||
int TargetRate_bps, channelRate_bps, LBRR_symbol, sum;
|
||||
int[] MStargetRates_bps = new int[2];
|
||||
short[] buf;
|
||||
int transition, curr_block, tot_blocks;
|
||||
nBytesOut.Val = 0;
|
||||
|
||||
if (encControl.reducedDependency != 0)
|
||||
{
|
||||
psEnc.state_Fxx[0].first_frame_after_reset = 1;
|
||||
psEnc.state_Fxx[1].first_frame_after_reset = 1;
|
||||
}
|
||||
psEnc.state_Fxx[0].nFramesEncoded = psEnc.state_Fxx[1].nFramesEncoded = 0;
|
||||
|
||||
/* Check values in encoder control structure */
|
||||
ret += encControl.check_control_input();
|
||||
if (ret != SilkError.SILK_NO_ERROR)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
encControl.switchReady = 0;
|
||||
|
||||
if (encControl.nChannelsInternal > psEnc.nChannelsInternal)
|
||||
{
|
||||
/* Mono . Stereo transition: init state of second channel and stereo state */
|
||||
ret += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[1]);
|
||||
|
||||
Arrays.MemSetShort(psEnc.sStereo.pred_prev_Q13, 0, 2);
|
||||
Arrays.MemSetShort(psEnc.sStereo.sSide, 0, 2);
|
||||
psEnc.sStereo.mid_side_amp_Q0[0] = 0;
|
||||
psEnc.sStereo.mid_side_amp_Q0[1] = 1;
|
||||
psEnc.sStereo.mid_side_amp_Q0[2] = 0;
|
||||
psEnc.sStereo.mid_side_amp_Q0[3] = 1;
|
||||
psEnc.sStereo.width_prev_Q14 = 0;
|
||||
psEnc.sStereo.smth_width_Q14 = (short)(((int)((1.0f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1.0f, 14)*/);
|
||||
if (psEnc.nChannelsAPI == 2)
|
||||
{
|
||||
psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state);
|
||||
Array.Copy(psEnc.state_Fxx[0].In_HP_State, psEnc.state_Fxx[1].In_HP_State, 2);
|
||||
}
|
||||
}
|
||||
|
||||
transition = ((encControl.payloadSize_ms != psEnc.state_Fxx[0].PacketSize_ms) || (psEnc.nChannelsInternal != encControl.nChannelsInternal)) ? 1 : 0;
|
||||
|
||||
psEnc.nChannelsAPI = encControl.nChannelsAPI;
|
||||
psEnc.nChannelsInternal = encControl.nChannelsInternal;
|
||||
|
||||
nBlocksOf10ms = Inlines.silk_DIV32(100 * nSamplesIn, encControl.API_sampleRate);
|
||||
tot_blocks = (nBlocksOf10ms > 1) ? nBlocksOf10ms >> 1 : 1;
|
||||
curr_block = 0;
|
||||
if (prefillFlag != 0)
|
||||
{
|
||||
/* Only accept input length of 10 ms */
|
||||
if (nBlocksOf10ms != 1)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
|
||||
}
|
||||
/* Reset Encoder */
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
ret += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[n]);
|
||||
Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR);
|
||||
}
|
||||
tmp_payloadSize_ms = encControl.payloadSize_ms;
|
||||
encControl.payloadSize_ms = 10;
|
||||
tmp_complexity = encControl.complexity;
|
||||
encControl.complexity = 0;
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
psEnc.state_Fxx[n].controlled_since_last_payload = 0;
|
||||
psEnc.state_Fxx[n].prefillFlag = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Only accept input lengths that are a multiple of 10 ms */
|
||||
if (nBlocksOf10ms * encControl.API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
|
||||
}
|
||||
/* Make sure no more than one packet can be produced */
|
||||
if (1000 * (int)nSamplesIn > encControl.payloadSize_ms * encControl.API_sampleRate)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
|
||||
}
|
||||
}
|
||||
|
||||
TargetRate_bps = Inlines.silk_RSHIFT32(encControl.bitRate, encControl.nChannelsInternal - 1);
|
||||
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
/* Force the side channel to the same rate as the mid */
|
||||
int force_fs_kHz = (n == 1) ? psEnc.state_Fxx[0].fs_kHz : 0;
|
||||
ret += psEnc.state_Fxx[n].silk_control_encoder(encControl, TargetRate_bps, psEnc.allowBandwidthSwitch, n, force_fs_kHz);
|
||||
|
||||
if (ret != SilkError.SILK_NO_ERROR)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (psEnc.state_Fxx[n].first_frame_after_reset != 0 || transition != 0)
|
||||
{
|
||||
for (i = 0; i < psEnc.state_Fxx[0].nFramesPerPacket; i++)
|
||||
{
|
||||
psEnc.state_Fxx[n].LBRR_flags[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[n].inDTX = psEnc.state_Fxx[n].useDTX;
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(encControl.nChannelsInternal == 1 || psEnc.state_Fxx[0].fs_kHz == psEnc.state_Fxx[1].fs_kHz);
|
||||
|
||||
/* Input buffering/resampling and encoding */
|
||||
nSamplesToBufferMax = 10 * nBlocksOf10ms * psEnc.state_Fxx[0].fs_kHz;
|
||||
nSamplesFromInputMax =
|
||||
Inlines.silk_DIV32_16(nSamplesToBufferMax *
|
||||
psEnc.state_Fxx[0].API_fs_Hz,
|
||||
(short)(psEnc.state_Fxx[0].fs_kHz * 1000));
|
||||
|
||||
buf = new short[nSamplesFromInputMax];
|
||||
|
||||
int samplesIn_ptr = 0;
|
||||
while (true)
|
||||
{
|
||||
nSamplesToBuffer = psEnc.state_Fxx[0].frame_length - psEnc.state_Fxx[0].inputBufIx;
|
||||
nSamplesToBuffer = Inlines.silk_min(nSamplesToBuffer, nSamplesToBufferMax);
|
||||
nSamplesFromInput = Inlines.silk_DIV32_16(nSamplesToBuffer * psEnc.state_Fxx[0].API_fs_Hz, psEnc.state_Fxx[0].fs_kHz * 1000);
|
||||
|
||||
/* Resample and write to buffer */
|
||||
if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 2)
|
||||
{
|
||||
int id = psEnc.state_Fxx[0].nFramesEncoded;
|
||||
for (n = 0; n < nSamplesFromInput; n++)
|
||||
{
|
||||
buf[n] = samplesIn[samplesIn_ptr + (2 * n)];
|
||||
}
|
||||
|
||||
/* Making sure to start both resamplers from the same state when switching from mono to stereo */
|
||||
if (psEnc.nPrevChannelsInternal == 1 && id == 0)
|
||||
{
|
||||
//silk_memcpy(&psEnc.state_Fxx[1].resampler_state, &psEnc.state_Fxx[0].resampler_state, sizeof(psEnc.state_Fxx[1].resampler_state));
|
||||
psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state);
|
||||
}
|
||||
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[0].resampler_state,
|
||||
psEnc.state_Fxx[0].inputBuf,
|
||||
psEnc.state_Fxx[0].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer;
|
||||
|
||||
nSamplesToBuffer = psEnc.state_Fxx[1].frame_length - psEnc.state_Fxx[1].inputBufIx;
|
||||
nSamplesToBuffer = Inlines.silk_min(nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc.state_Fxx[1].fs_kHz);
|
||||
for (n = 0; n < nSamplesFromInput; n++)
|
||||
{
|
||||
buf[n] = samplesIn[samplesIn_ptr + (2 * n) + 1];
|
||||
}
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[1].resampler_state,
|
||||
psEnc.state_Fxx[1].inputBuf,
|
||||
psEnc.state_Fxx[1].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
psEnc.state_Fxx[1].inputBufIx += nSamplesToBuffer;
|
||||
}
|
||||
else if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 1)
|
||||
{
|
||||
/* Combine left and right channels before resampling */
|
||||
for (n = 0; n < nSamplesFromInput; n++)
|
||||
{
|
||||
sum = samplesIn[samplesIn_ptr + (2 * n)] + samplesIn[samplesIn_ptr + (2 * n) + 1];
|
||||
buf[n] = (short)Inlines.silk_RSHIFT_ROUND(sum, 1);
|
||||
}
|
||||
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[0].resampler_state,
|
||||
psEnc.state_Fxx[0].inputBuf,
|
||||
psEnc.state_Fxx[0].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
/* On the first mono frame, average the results for the two resampler states */
|
||||
if (psEnc.nPrevChannelsInternal == 2 && psEnc.state_Fxx[0].nFramesEncoded == 0)
|
||||
{
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[1].resampler_state,
|
||||
psEnc.state_Fxx[1].inputBuf,
|
||||
psEnc.state_Fxx[1].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
for (n = 0; n < psEnc.state_Fxx[0].frame_length; n++)
|
||||
{
|
||||
psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + n + 2] =
|
||||
(short)(Inlines.silk_RSHIFT(psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + n + 2]
|
||||
+ psEnc.state_Fxx[1].inputBuf[psEnc.state_Fxx[1].inputBufIx + n + 2], 1));
|
||||
}
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
Inlines.OpusAssert(encControl.nChannelsAPI == 1 && encControl.nChannelsInternal == 1);
|
||||
Array.Copy(samplesIn, samplesIn_ptr, buf, 0, nSamplesFromInput);
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[0].resampler_state,
|
||||
psEnc.state_Fxx[0].inputBuf,
|
||||
psEnc.state_Fxx[0].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer;
|
||||
}
|
||||
|
||||
samplesIn_ptr += (nSamplesFromInput * encControl.nChannelsAPI);
|
||||
nSamplesIn -= nSamplesFromInput;
|
||||
|
||||
/* Default */
|
||||
psEnc.allowBandwidthSwitch = 0;
|
||||
|
||||
/* Silk encoder */
|
||||
if (psEnc.state_Fxx[0].inputBufIx >= psEnc.state_Fxx[0].frame_length)
|
||||
{
|
||||
/* Enough data in input buffer, so encode */
|
||||
Inlines.OpusAssert(psEnc.state_Fxx[0].inputBufIx == psEnc.state_Fxx[0].frame_length);
|
||||
Inlines.OpusAssert(encControl.nChannelsInternal == 1 || psEnc.state_Fxx[1].inputBufIx == psEnc.state_Fxx[1].frame_length);
|
||||
|
||||
/* Deal with LBRR data */
|
||||
if (psEnc.state_Fxx[0].nFramesEncoded == 0 && prefillFlag == 0)
|
||||
{
|
||||
/* Create space at start of payload for VAD and FEC flags */
|
||||
byte[] iCDF = { 0, 0 };
|
||||
iCDF[0] = (byte)(256 - Inlines.silk_RSHIFT(256, (psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal));
|
||||
psRangeEnc.enc_icdf(0, iCDF, 8);
|
||||
|
||||
/* Encode any LBRR data from previous packet */
|
||||
/* Encode LBRR flags */
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
LBRR_symbol = 0;
|
||||
for (i = 0; i < psEnc.state_Fxx[n].nFramesPerPacket; i++)
|
||||
{
|
||||
LBRR_symbol |= Inlines.silk_LSHIFT(psEnc.state_Fxx[n].LBRR_flags[i], i);
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[n].LBRR_flag = (sbyte)(LBRR_symbol > 0 ? 1 : 0);
|
||||
if (LBRR_symbol != 0 && psEnc.state_Fxx[n].nFramesPerPacket > 1)
|
||||
{
|
||||
psRangeEnc.enc_icdf( LBRR_symbol - 1, Tables.silk_LBRR_flags_iCDF_ptr[psEnc.state_Fxx[n].nFramesPerPacket - 2], 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Code LBRR indices and excitation signals */
|
||||
for (i = 0; i < psEnc.state_Fxx[0].nFramesPerPacket; i++)
|
||||
{
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
if (psEnc.state_Fxx[n].LBRR_flags[i] != 0)
|
||||
{
|
||||
int condCoding;
|
||||
|
||||
if (encControl.nChannelsInternal == 2 && n == 0)
|
||||
{
|
||||
Stereo.silk_stereo_encode_pred(psRangeEnc, psEnc.sStereo.predIx[i]);
|
||||
/* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */
|
||||
if (psEnc.state_Fxx[1].LBRR_flags[i] == 0)
|
||||
{
|
||||
Stereo.silk_stereo_encode_mid_only(psRangeEnc, psEnc.sStereo.mid_only_flags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Use conditional coding if previous frame available */
|
||||
if (i > 0 && psEnc.state_Fxx[n].LBRR_flags[i - 1] != 0)
|
||||
{
|
||||
condCoding = SilkConstants.CODE_CONDITIONALLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
|
||||
EncodeIndices.silk_encode_indices(psEnc.state_Fxx[n], psRangeEnc, i, 1, condCoding);
|
||||
EncodePulses.silk_encode_pulses(psRangeEnc, psEnc.state_Fxx[n].indices_LBRR[i].signalType, psEnc.state_Fxx[n].indices_LBRR[i].quantOffsetType,
|
||||
psEnc.state_Fxx[n].pulses_LBRR[i], psEnc.state_Fxx[n].frame_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset LBRR flags */
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
Arrays.MemSetInt(psEnc.state_Fxx[n].LBRR_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
|
||||
}
|
||||
|
||||
psEnc.nBitsUsedLBRR = psRangeEnc.tell();
|
||||
}
|
||||
|
||||
HPVariableCutoff.silk_HP_variable_cutoff(psEnc.state_Fxx);
|
||||
|
||||
/* Total target bits for packet */
|
||||
nBits = Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000);
|
||||
|
||||
/* Subtract bits used for LBRR */
|
||||
if (prefillFlag == 0)
|
||||
{
|
||||
nBits -= psEnc.nBitsUsedLBRR;
|
||||
}
|
||||
|
||||
/* Divide by number of uncoded frames left in packet */
|
||||
nBits = Inlines.silk_DIV32_16(nBits, psEnc.state_Fxx[0].nFramesPerPacket);
|
||||
|
||||
/* Convert to bits/second */
|
||||
if (encControl.payloadSize_ms == 10)
|
||||
{
|
||||
TargetRate_bps = Inlines.silk_SMULBB(nBits, 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetRate_bps = Inlines.silk_SMULBB(nBits, 50);
|
||||
}
|
||||
|
||||
/* Subtract fraction of bits in excess of target in previous frames and packets */
|
||||
TargetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(psEnc.nBitsExceeded, 1000), TuningParameters.BITRESERVOIR_DECAY_TIME_MS);
|
||||
|
||||
if (prefillFlag == 0 && psEnc.state_Fxx[0].nFramesEncoded > 0)
|
||||
{
|
||||
/* Compare actual vs target bits so far in this packet */
|
||||
int bitsBalance = psRangeEnc.tell() - psEnc.nBitsUsedLBRR - nBits * psEnc.state_Fxx[0].nFramesEncoded;
|
||||
TargetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(bitsBalance, 1000), TuningParameters.BITRESERVOIR_DECAY_TIME_MS);
|
||||
}
|
||||
|
||||
/* Never exceed input bitrate */
|
||||
TargetRate_bps = Inlines.silk_LIMIT(TargetRate_bps, encControl.bitRate, 5000);
|
||||
|
||||
/* Convert Left/Right to Mid/Side */
|
||||
if (encControl.nChannelsInternal == 2)
|
||||
{
|
||||
BoxedValueSbyte midOnlyFlagBoxed = new BoxedValueSbyte(psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]);
|
||||
Stereo.silk_stereo_LR_to_MS(psEnc.sStereo,
|
||||
psEnc.state_Fxx[0].inputBuf,
|
||||
2,
|
||||
psEnc.state_Fxx[1].inputBuf,
|
||||
2,
|
||||
psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded],
|
||||
midOnlyFlagBoxed,
|
||||
MStargetRates_bps,
|
||||
TargetRate_bps,
|
||||
psEnc.state_Fxx[0].speech_activity_Q8,
|
||||
encControl.toMono,
|
||||
psEnc.state_Fxx[0].fs_kHz,
|
||||
psEnc.state_Fxx[0].frame_length);
|
||||
|
||||
psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded] = midOnlyFlagBoxed.Val;
|
||||
|
||||
if (midOnlyFlagBoxed.Val == 0)
|
||||
{
|
||||
/* Reset side channel encoder memory for first frame with side coding */
|
||||
if (psEnc.prev_decode_only_middle == 1)
|
||||
{
|
||||
psEnc.state_Fxx[1].sShape.Reset();
|
||||
psEnc.state_Fxx[1].sPrefilt.Reset();
|
||||
psEnc.state_Fxx[1].sNSQ.Reset();
|
||||
Arrays.MemSetShort(psEnc.state_Fxx[1].prev_NLSFq_Q15, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
Arrays.MemSetInt(psEnc.state_Fxx[1].sLP.In_LP_State, 0, 2);
|
||||
|
||||
psEnc.state_Fxx[1].prevLag = 100;
|
||||
psEnc.state_Fxx[1].sNSQ.lagPrev = 100;
|
||||
psEnc.state_Fxx[1].sShape.LastGainIndex = 10;
|
||||
psEnc.state_Fxx[1].prevSignalType = SilkConstants.TYPE_NO_VOICE_ACTIVITY;
|
||||
psEnc.state_Fxx[1].sNSQ.prev_gain_Q16 = 65536;
|
||||
psEnc.state_Fxx[1].first_frame_after_reset = 1;
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[1].silk_encode_do_VAD();
|
||||
}
|
||||
else
|
||||
{
|
||||
psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] = 0;
|
||||
}
|
||||
|
||||
if (prefillFlag == 0)
|
||||
{
|
||||
Stereo.silk_stereo_encode_pred(psRangeEnc, psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded]);
|
||||
if (psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] == 0)
|
||||
{
|
||||
Stereo.silk_stereo_encode_mid_only(psRangeEnc, psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Buffering */
|
||||
Array.Copy(psEnc.sStereo.sMid, psEnc.state_Fxx[0].inputBuf, 2);
|
||||
Array.Copy(psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].frame_length, psEnc.sStereo.sMid, 0, 2);
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[0].silk_encode_do_VAD();
|
||||
|
||||
/* Encode */
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
int maxBits, useCBR;
|
||||
|
||||
/* Handling rate constraints */
|
||||
maxBits = encControl.maxBits;
|
||||
if (tot_blocks == 2 && curr_block == 0)
|
||||
{
|
||||
maxBits = maxBits * 3 / 5;
|
||||
}
|
||||
|
||||
else if (tot_blocks == 3)
|
||||
{
|
||||
if (curr_block == 0)
|
||||
{
|
||||
maxBits = maxBits * 2 / 5;
|
||||
}
|
||||
else if (curr_block == 1)
|
||||
{
|
||||
maxBits = maxBits * 3 / 4;
|
||||
}
|
||||
}
|
||||
|
||||
useCBR = (encControl.useCBR != 0 && curr_block == tot_blocks - 1) ? 1 : 0;
|
||||
|
||||
if (encControl.nChannelsInternal == 1)
|
||||
{
|
||||
channelRate_bps = TargetRate_bps;
|
||||
}
|
||||
else
|
||||
{
|
||||
channelRate_bps = MStargetRates_bps[n];
|
||||
if (n == 0 && MStargetRates_bps[1] > 0)
|
||||
{
|
||||
useCBR = 0;
|
||||
/* Give mid up to 1/2 of the max bits for that frame */
|
||||
maxBits -= encControl.maxBits / (tot_blocks * 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (channelRate_bps > 0)
|
||||
{
|
||||
int condCoding;
|
||||
|
||||
psEnc.state_Fxx[n].silk_control_SNR(channelRate_bps);
|
||||
|
||||
/* Use independent coding if no previous frame available */
|
||||
if (psEnc.state_Fxx[0].nFramesEncoded - n <= 0)
|
||||
{
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
else if (n > 0 && psEnc.prev_decode_only_middle != 0)
|
||||
{
|
||||
/* If we skipped a side frame in this packet, we don't
|
||||
need LTP scaling; the LTP state is well-defined. */
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY_NO_LTP_SCALING;
|
||||
}
|
||||
else
|
||||
{
|
||||
condCoding = SilkConstants.CODE_CONDITIONALLY;
|
||||
}
|
||||
|
||||
ret += psEnc.state_Fxx[n].silk_encode_frame(nBytesOut, psRangeEnc, condCoding, maxBits, useCBR);
|
||||
Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR);
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[n].controlled_since_last_payload = 0;
|
||||
psEnc.state_Fxx[n].inputBufIx = 0;
|
||||
psEnc.state_Fxx[n].nFramesEncoded++;
|
||||
}
|
||||
|
||||
psEnc.prev_decode_only_middle = psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded - 1];
|
||||
|
||||
/* Insert VAD and FEC flags at beginning of bitstream */
|
||||
if (nBytesOut.Val > 0 && psEnc.state_Fxx[0].nFramesEncoded == psEnc.state_Fxx[0].nFramesPerPacket)
|
||||
{
|
||||
flags = 0;
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
for (i = 0; i < psEnc.state_Fxx[n].nFramesPerPacket; i++)
|
||||
{
|
||||
flags = Inlines.silk_LSHIFT(flags, 1);
|
||||
flags |= (int)psEnc.state_Fxx[n].VAD_flags[i];
|
||||
}
|
||||
flags = Inlines.silk_LSHIFT(flags, 1);
|
||||
flags |= (int)psEnc.state_Fxx[n].LBRR_flag;
|
||||
}
|
||||
|
||||
if (prefillFlag == 0)
|
||||
{
|
||||
psRangeEnc.enc_patch_initial_bits((uint)flags, (uint)((psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal));
|
||||
}
|
||||
|
||||
/* Return zero bytes if all channels DTXed */
|
||||
if (psEnc.state_Fxx[0].inDTX != 0 && (encControl.nChannelsInternal == 1 || psEnc.state_Fxx[1].inDTX != 0))
|
||||
{
|
||||
nBytesOut.Val = 0;
|
||||
}
|
||||
|
||||
psEnc.nBitsExceeded += nBytesOut.Val * 8;
|
||||
psEnc.nBitsExceeded -= Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000);
|
||||
psEnc.nBitsExceeded = Inlines.silk_LIMIT(psEnc.nBitsExceeded, 0, 10000);
|
||||
|
||||
/* Update flag indicating if bandwidth switching is allowed */
|
||||
speech_act_thr_for_switch_Q8 = Inlines.silk_SMLAWB(((int)((TuningParameters.SPEECH_ACTIVITY_DTX_THRES) * ((long)1 << (8)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.SPEECH_ACTIVITY_DTX_THRES, 8)*/,
|
||||
((int)(((1 - TuningParameters.SPEECH_ACTIVITY_DTX_THRES) / TuningParameters.MAX_BANDWIDTH_SWITCH_DELAY_MS) * ((long)1 << (16 + 8)) + 0.5))/*Inlines.SILK_CONST((1 - TuningParameters.SPEECH_ACTIVITY_DTX_THRES) / TuningParameters.MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8)*/,
|
||||
psEnc.timeSinceSwitchAllowed_ms);
|
||||
if (psEnc.state_Fxx[0].speech_activity_Q8 < speech_act_thr_for_switch_Q8)
|
||||
{
|
||||
psEnc.allowBandwidthSwitch = 1;
|
||||
psEnc.timeSinceSwitchAllowed_ms = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
psEnc.allowBandwidthSwitch = 0;
|
||||
psEnc.timeSinceSwitchAllowed_ms += encControl.payloadSize_ms;
|
||||
}
|
||||
}
|
||||
|
||||
if (nSamplesIn == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
curr_block++;
|
||||
}
|
||||
|
||||
psEnc.nPrevChannelsInternal = encControl.nChannelsInternal;
|
||||
|
||||
encControl.allowBandwidthSwitch = psEnc.allowBandwidthSwitch;
|
||||
encControl.inWBmodeWithoutVariableLP = (psEnc.state_Fxx[0].fs_kHz == 16 && psEnc.state_Fxx[0].sLP.mode == 0) ? 1 : 0;
|
||||
encControl.internalSampleRate = Inlines.silk_SMULBB(psEnc.state_Fxx[0].fs_kHz, 1000);
|
||||
encControl.stereoWidth_Q14 = encControl.toMono != 0 ? 0 : psEnc.sStereo.smth_width_Q14;
|
||||
|
||||
if (prefillFlag != 0)
|
||||
{
|
||||
encControl.payloadSize_ms = tmp_payloadSize_ms;
|
||||
encControl.complexity = tmp_complexity;
|
||||
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
psEnc.state_Fxx[n].controlled_since_last_payload = 0;
|
||||
psEnc.state_Fxx[n].prefillFlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//────────────────────▄▄▄▄▄▄▄▄▄▄────────────────────
|
||||
//─────────────▄▄▄▄████▓▓▓▓▓▓▓▓▓██▄▄────────────────
|
||||
//─────────▄▄██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒░▀▀▄─────────────
|
||||
//────────▀▀▀▀▀█████▓▓▓▓▒▒▒▒▒▒▒▒▒▒░░░░░▀▄───────────
|
||||
//────────────▄▄█▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░▀▄─────────
|
||||
//─────▄▀▀▄─▄█▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░█▄▀▀▄─────
|
||||
//────█░░░▄█▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░█░░░░░█────
|
||||
//───█░░░█▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░▄▀░░░▄░░█───
|
||||
//──█░░░█▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░█░░░░░█░░█──
|
||||
//──█░░█▓▒▒▄▄▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░██░░░░░░█░█──
|
||||
//─█░░█▓▄▄▀█▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░▄▄▀█░░░░▄▀█░░░░░░█░░█─
|
||||
//─█░██▀░▄▀▒▒▒▒▒▒▒▒▒▒▒▒▄▄▄▄▀▀▀░▄▀░░░▄▀░░░░░░░░░█░░█─
|
||||
//─██▀░░█▒▒▒▒▒▒▒▒▒▄▄▀▀▀░░░░░░▄▀░░▄▄▀░░░░░░░░░░░░░░█─
|
||||
//──█░░█▒▒▒▒▒▒▒▄▀▀░░░░░░░░░░▀▀▀▀▀░░░░░░░░░░▄▄░░░░░█─
|
||||
//───██▒▒▒▒▒▒▄▀██▄▄░░░░░█░░░░░░░░░░░░░▄▄▄█▀░░░░░░█──
|
||||
//────█▒▒▒▒▒█─▓██████▄▄█░░░█░░░░▄▄▄████▓─█▀▀░░░░█───
|
||||
//───█▒▒▒▒▄█─▓█──████▓─█░░░░████████──█▓─█▄░░░▄▀────
|
||||
//───█▒▒▄▀█──▓█▒▓████▓─█░░░░█─▓█████▓▒█▓─█░░█▀──────
|
||||
//──█▒▄▀█░█──▓███─███▓─█░░░░█─▓████─██▓──█░█────────
|
||||
//──█▀──█░█──▓▓██████▓─█░░░░█─▓██████▓▓──█░█────────
|
||||
//──────█░░█──▓▓████▓─█░░░░░░█─▓████▓▓──█░░█────────
|
||||
//──────█░░▀▄───▓▓▓▓──█░░░░░░█──▓▓▓▓───▄▀░░█────────
|
||||
//───────█░░▀▄───────█░░░░░░░░█───────▄▀░░█─────────
|
||||
//───────█░░░░▀▄▄▄▄▄▀░░▄▀▀▀▀▄░░▀▄▄▄▄▄▀░░░░█─────────
|
||||
//────────█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█──────────
|
||||
//─────────█░░░░░░░░░░▀▄░░░░▄▀░░░░░░░░░░█───────────
|
||||
//──────────▀▄░░░░░░░░░░░░░░░░░░░░░░░░▄▀────────────
|
||||
//────────────▀▄░░░░░░▀▄░░░░▄▀░░░░░░▄▀──────────────
|
||||
//──────────────▀▄▄░░░░░▀▀▀▀░░░░░▄▄▀────────────────
|
||||
//─────────────────▀▀▄▄▄▄▄▄▄▄▄▄▀▀───────────────────
|
||||
//──────────────────────────────────────────────────
|
||||
//───────█───█───█─████──███──███──█───█─████─█─────
|
||||
//──────█─█──█───█─█────█────█───█─██─██─█────█─────
|
||||
//─────█▄▄▄█─█─█─█─██────██──█───█─█─█─█─██───█─────
|
||||
//─────█───█──█─█──█───────█─█───█─█───█─█──────────
|
||||
//─────█───█──█─█──████─███───███──█───█─████─█─────
|
||||
//──────────────────────────────────────────────────
|
||||
//──────────────────────────────────────────────────
|
||||
@@ -0,0 +1,223 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class EncodeIndices
|
||||
{
|
||||
/// <summary>
|
||||
/// Encode side-information parameters to payload
|
||||
/// </summary>
|
||||
/// <param name="psEncC">I/O Encoder state</param>
|
||||
/// <param name="psRangeEnc">I/O Compressor data structure</param>
|
||||
/// <param name="FrameIndex">I Frame number</param>
|
||||
/// <param name="encode_LBRR">I Flag indicating LBRR data is being encoded</param>
|
||||
/// <param name="condCoding">I The type of conditional coding to use</param>
|
||||
internal static void silk_encode_indices(
|
||||
SilkChannelEncoder psEncC,
|
||||
EntropyCoder psRangeEnc,
|
||||
int FrameIndex,
|
||||
int encode_LBRR,
|
||||
int condCoding)
|
||||
{
|
||||
int i, k, typeOffset;
|
||||
int encode_absolute_lagIndex, delta_lagIndex;
|
||||
short[] ec_ix = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
byte[] pred_Q8 = new byte[SilkConstants.MAX_LPC_ORDER];
|
||||
SideInfoIndices psIndices;
|
||||
|
||||
if (encode_LBRR != 0)
|
||||
{
|
||||
psIndices = psEncC.indices_LBRR[FrameIndex];
|
||||
}
|
||||
else {
|
||||
psIndices = psEncC.indices;
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
/* Encode signal type and quantizer offset */
|
||||
/*******************************************/
|
||||
typeOffset = 2 * psIndices.signalType + psIndices.quantOffsetType;
|
||||
Inlines.OpusAssert(typeOffset >= 0 && typeOffset < 6);
|
||||
Inlines.OpusAssert(encode_LBRR == 0 || typeOffset >= 2);
|
||||
if (encode_LBRR != 0 || typeOffset >= 2)
|
||||
{
|
||||
psRangeEnc.enc_icdf( typeOffset - 2, Tables.silk_type_offset_VAD_iCDF, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
psRangeEnc.enc_icdf( typeOffset, Tables.silk_type_offset_no_VAD_iCDF, 8);
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Encode gains */
|
||||
/****************/
|
||||
/* first subframe */
|
||||
if (condCoding == SilkConstants.CODE_CONDITIONALLY)
|
||||
{
|
||||
/* conditional coding */
|
||||
Inlines.OpusAssert(psIndices.GainsIndices[0] >= 0 && psIndices.GainsIndices[0] < SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.MIN_DELTA_GAIN_QUANT + 1);
|
||||
psRangeEnc.enc_icdf( psIndices.GainsIndices[0], Tables.silk_delta_gain_iCDF, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* independent coding, in two stages: MSB bits followed by 3 LSBs */
|
||||
Inlines.OpusAssert(psIndices.GainsIndices[0] >= 0 && psIndices.GainsIndices[0] < SilkConstants.N_LEVELS_QGAIN);
|
||||
psRangeEnc.enc_icdf( Inlines.silk_RSHIFT(psIndices.GainsIndices[0], 3), Tables.silk_gain_iCDF[psIndices.signalType], 8);
|
||||
psRangeEnc.enc_icdf( psIndices.GainsIndices[0] & 7, Tables.silk_uniform8_iCDF, 8);
|
||||
}
|
||||
|
||||
/* remaining subframes */
|
||||
for (i = 1; i < psEncC.nb_subfr; i++)
|
||||
{
|
||||
Inlines.OpusAssert(psIndices.GainsIndices[i] >= 0 && psIndices.GainsIndices[i] < SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.MIN_DELTA_GAIN_QUANT + 1);
|
||||
psRangeEnc.enc_icdf( psIndices.GainsIndices[i], Tables.silk_delta_gain_iCDF, 8);
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Encode NLSFs */
|
||||
/****************/
|
||||
psRangeEnc.enc_icdf( psIndices.NLSFIndices[0], psEncC.psNLSF_CB.CB1_iCDF, ((psIndices.signalType >> 1) * psEncC.psNLSF_CB.nVectors), 8);
|
||||
NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psEncC.psNLSF_CB, psIndices.NLSFIndices[0]);
|
||||
Inlines.OpusAssert(psEncC.psNLSF_CB.order == psEncC.predictLPCOrder);
|
||||
|
||||
for (i = 0; i < psEncC.psNLSF_CB.order; i++)
|
||||
{
|
||||
if (psIndices.NLSFIndices[i + 1] >= SilkConstants.NLSF_QUANT_MAX_AMPLITUDE)
|
||||
{
|
||||
psRangeEnc.enc_icdf( 2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, psEncC.psNLSF_CB.ec_iCDF, (ec_ix[i]), 8);
|
||||
psRangeEnc.enc_icdf( psIndices.NLSFIndices[i + 1] - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, Tables.silk_NLSF_EXT_iCDF, 8);
|
||||
}
|
||||
else if (psIndices.NLSFIndices[i + 1] <= 0 - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE)
|
||||
{
|
||||
psRangeEnc.enc_icdf( 0, psEncC.psNLSF_CB.ec_iCDF, ec_ix[i], 8);
|
||||
psRangeEnc.enc_icdf( -psIndices.NLSFIndices[i + 1] - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, Tables.silk_NLSF_EXT_iCDF, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
psRangeEnc.enc_icdf( psIndices.NLSFIndices[i + 1] + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, psEncC.psNLSF_CB.ec_iCDF, ec_ix[i], 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Encode NLSF interpolation factor */
|
||||
if (psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR)
|
||||
{
|
||||
Inlines.OpusAssert(psIndices.NLSFInterpCoef_Q2 >= 0 && psIndices.NLSFInterpCoef_Q2 < 5);
|
||||
psRangeEnc.enc_icdf( psIndices.NLSFInterpCoef_Q2, Tables.silk_NLSF_interpolation_factor_iCDF, 8);
|
||||
}
|
||||
|
||||
if (psIndices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/*********************/
|
||||
/* Encode pitch lags */
|
||||
/*********************/
|
||||
/* lag index */
|
||||
encode_absolute_lagIndex = 1;
|
||||
if (condCoding == SilkConstants.CODE_CONDITIONALLY && psEncC.ec_prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Delta Encoding */
|
||||
delta_lagIndex = psIndices.lagIndex - psEncC.ec_prevLagIndex;
|
||||
|
||||
if (delta_lagIndex < -8 || delta_lagIndex > 11)
|
||||
{
|
||||
delta_lagIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta_lagIndex = delta_lagIndex + 9;
|
||||
encode_absolute_lagIndex = 0; /* Only use delta */
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(delta_lagIndex >= 0 && delta_lagIndex < 21);
|
||||
psRangeEnc.enc_icdf( delta_lagIndex, Tables.silk_pitch_delta_iCDF, 8);
|
||||
}
|
||||
|
||||
if (encode_absolute_lagIndex != 0)
|
||||
{
|
||||
/* Absolute encoding */
|
||||
int pitch_high_bits, pitch_low_bits;
|
||||
pitch_high_bits = Inlines.silk_DIV32_16(psIndices.lagIndex, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1));
|
||||
pitch_low_bits = psIndices.lagIndex - Inlines.silk_SMULBB(pitch_high_bits, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1));
|
||||
Inlines.OpusAssert(pitch_low_bits < psEncC.fs_kHz / 2);
|
||||
Inlines.OpusAssert(pitch_high_bits < 32);
|
||||
psRangeEnc.enc_icdf( pitch_high_bits, Tables.silk_pitch_lag_iCDF, 8);
|
||||
psRangeEnc.enc_icdf( pitch_low_bits, psEncC.pitch_lag_low_bits_iCDF, 8);
|
||||
}
|
||||
psEncC.ec_prevLagIndex = psIndices.lagIndex;
|
||||
|
||||
/* Countour index */
|
||||
Inlines.OpusAssert(psIndices.contourIndex >= 0);
|
||||
Inlines.OpusAssert((psIndices.contourIndex < 34 && psEncC.fs_kHz > 8 && psEncC.nb_subfr == 4) || (psIndices.contourIndex < 11 && psEncC.fs_kHz == 8 && psEncC.nb_subfr == 4) || (psIndices.contourIndex < 12 && psEncC.fs_kHz > 8 && psEncC.nb_subfr == 2) || (psIndices.contourIndex < 3 && psEncC.fs_kHz == 8 && psEncC.nb_subfr == 2));
|
||||
psRangeEnc.enc_icdf( psIndices.contourIndex, psEncC.pitch_contour_iCDF, 8);
|
||||
|
||||
/********************/
|
||||
/* Encode LTP gains */
|
||||
/********************/
|
||||
/* PERIndex value */
|
||||
Inlines.OpusAssert(psIndices.PERIndex >= 0 && psIndices.PERIndex < 3);
|
||||
psRangeEnc.enc_icdf( psIndices.PERIndex, Tables.silk_LTP_per_index_iCDF, 8);
|
||||
|
||||
/* Codebook Indices */
|
||||
for (k = 0; k < psEncC.nb_subfr; k++)
|
||||
{
|
||||
Inlines.OpusAssert(psIndices.LTPIndex[k] >= 0 && psIndices.LTPIndex[k] < (8 << psIndices.PERIndex));
|
||||
psRangeEnc.enc_icdf( psIndices.LTPIndex[k], Tables.silk_LTP_gain_iCDF_ptrs[psIndices.PERIndex], 8);
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Encode LTP scaling */
|
||||
/**********************/
|
||||
if (condCoding == SilkConstants.CODE_INDEPENDENTLY)
|
||||
{
|
||||
Inlines.OpusAssert(psIndices.LTP_scaleIndex >= 0 && psIndices.LTP_scaleIndex < 3);
|
||||
psRangeEnc.enc_icdf( psIndices.LTP_scaleIndex, Tables.silk_LTPscale_iCDF, 8);
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(condCoding == 0 || psIndices.LTP_scaleIndex == 0);
|
||||
}
|
||||
|
||||
psEncC.ec_prevSignalType = psIndices.signalType;
|
||||
|
||||
/***************/
|
||||
/* Encode seed */
|
||||
/***************/
|
||||
Inlines.OpusAssert(psIndices.Seed >= 0 && psIndices.Seed < 4);
|
||||
psRangeEnc.enc_icdf( psIndices.Seed, Tables.silk_uniform4_iCDF, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class EncodePulses
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pulses_comb">(O)</param>
|
||||
/// <param name="pulses_in">(I)</param>
|
||||
/// <param name="max_pulses"> I max value for sum of pulses</param>
|
||||
/// <param name="len">I number of output values</param>
|
||||
/// <returns>return ok</returns>
|
||||
internal static int combine_and_check(
|
||||
int[] pulses_comb,
|
||||
int pulses_comb_ptr,
|
||||
int[] pulses_in,
|
||||
int pulses_in_ptr,
|
||||
int max_pulses,
|
||||
int len)
|
||||
{
|
||||
for (int k = 0; k < len; k++)
|
||||
{
|
||||
int k2p = 2 * k + pulses_in_ptr;
|
||||
int sum = pulses_in[k2p] + pulses_in[k2p + 1];
|
||||
if (sum > max_pulses)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
pulses_comb[pulses_comb_ptr + k] = sum;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pulses_comb">(O)</param>
|
||||
/// <param name="pulses_in">(I)</param>
|
||||
/// <param name="max_pulses"> I max value for sum of pulses</param>
|
||||
/// <param name="len">I number of output values</param>
|
||||
/// <returns>return ok</returns>
|
||||
internal static int combine_and_check(
|
||||
int[] pulses_comb,
|
||||
int[] pulses_in,
|
||||
int max_pulses,
|
||||
int len)
|
||||
{
|
||||
for (int k = 0; k < len; k++)
|
||||
{
|
||||
int sum = pulses_in[2 * k] + pulses_in[2 * k + 1];
|
||||
if (sum > max_pulses)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
pulses_comb[k] = sum;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode quantization indices of excitation
|
||||
/// </summary>
|
||||
/// <param name="psRangeEnc">I/O compressor data structure</param>
|
||||
/// <param name="signalType">I Signal type</param>
|
||||
/// <param name="quantOffsetType">I quantOffsetType</param>
|
||||
/// <param name="pulses">I quantization indices</param>
|
||||
/// <param name="frame_length">I Frame length</param>
|
||||
internal static void silk_encode_pulses(
|
||||
EntropyCoder psRangeEnc,
|
||||
int signalType,
|
||||
int quantOffsetType,
|
||||
sbyte[] pulses,
|
||||
int frame_length)
|
||||
{
|
||||
int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0;
|
||||
int abs_q, minSumBits_Q5, sumBits_Q5;
|
||||
int[] abs_pulses;
|
||||
int[] sum_pulses;
|
||||
int[] nRshifts;
|
||||
int[] pulses_comb = new int[8];
|
||||
int abs_pulses_ptr;
|
||||
int pulses_ptr;
|
||||
byte[] nBits_ptr;
|
||||
|
||||
Arrays.MemSetInt(pulses_comb, 0, 8);
|
||||
|
||||
/****************************/
|
||||
/* Prepare for shell coding */
|
||||
/****************************/
|
||||
/* Calculate number of shell blocks */
|
||||
Inlines.OpusAssert(1 << SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH == SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
iter = Inlines.silk_RSHIFT(frame_length, SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH);
|
||||
if (iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH < frame_length)
|
||||
{
|
||||
Inlines.OpusAssert(frame_length == 12 * 10); /* Make sure only happens for 10 ms @ 12 kHz */
|
||||
iter++;
|
||||
Arrays.MemSetWithOffset<sbyte>(pulses, 0, frame_length, SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
}
|
||||
|
||||
/* Take the absolute value of the pulses */
|
||||
abs_pulses = new int[iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH];
|
||||
Inlines.OpusAssert((SilkConstants.SHELL_CODEC_FRAME_LENGTH & 3) == 0);
|
||||
|
||||
// unrolled loop
|
||||
for (i = 0; i < iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH; i += 4)
|
||||
{
|
||||
abs_pulses[i + 0] = (int)Inlines.silk_abs(pulses[i + 0]);
|
||||
abs_pulses[i + 1] = (int)Inlines.silk_abs(pulses[i + 1]);
|
||||
abs_pulses[i + 2] = (int)Inlines.silk_abs(pulses[i + 2]);
|
||||
abs_pulses[i + 3] = (int)Inlines.silk_abs(pulses[i + 3]);
|
||||
}
|
||||
|
||||
/* Calc sum pulses per shell code frame */
|
||||
sum_pulses = new int[iter];
|
||||
nRshifts = new int[iter];
|
||||
abs_pulses_ptr = 0;
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
nRshifts[i] = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* 1+1 . 2 */
|
||||
scale_down = combine_and_check(pulses_comb, 0, abs_pulses, abs_pulses_ptr, Tables.silk_max_pulses_table[0], 8);
|
||||
/* 2+2 . 4 */
|
||||
scale_down += combine_and_check(pulses_comb, pulses_comb, Tables.silk_max_pulses_table[1], 4);
|
||||
/* 4+4 . 8 */
|
||||
scale_down += combine_and_check(pulses_comb, pulses_comb, Tables.silk_max_pulses_table[2], 2);
|
||||
/* 8+8 . 16 */
|
||||
scale_down += combine_and_check(sum_pulses, i, pulses_comb, 0, Tables.silk_max_pulses_table[3], 1);
|
||||
|
||||
if (scale_down != 0)
|
||||
{
|
||||
/* We need to downscale the quantization signal */
|
||||
nRshifts[i]++;
|
||||
for (k = abs_pulses_ptr; k < abs_pulses_ptr + SilkConstants.SHELL_CODEC_FRAME_LENGTH; k++)
|
||||
{
|
||||
abs_pulses[k] = Inlines.silk_RSHIFT(abs_pulses[k], 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Jump out of while(1) loop and go to next shell coding frame */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
abs_pulses_ptr += SilkConstants.SHELL_CODEC_FRAME_LENGTH;
|
||||
}
|
||||
|
||||
/**************/
|
||||
/* Rate level */
|
||||
/**************/
|
||||
/* find rate level that leads to fewest bits for coding of pulses per block info */
|
||||
minSumBits_Q5 = int.MaxValue;
|
||||
for (k = 0; k < SilkConstants.N_RATE_LEVELS - 1; k++)
|
||||
{
|
||||
nBits_ptr = Tables.silk_pulses_per_block_BITS_Q5[k];
|
||||
sumBits_Q5 = Tables.silk_rate_levels_BITS_Q5[signalType >> 1][k];
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (nRshifts[i] > 0)
|
||||
{
|
||||
sumBits_Q5 += nBits_ptr[SilkConstants.SILK_MAX_PULSES + 1];
|
||||
}
|
||||
else {
|
||||
sumBits_Q5 += nBits_ptr[sum_pulses[i]];
|
||||
}
|
||||
}
|
||||
if (sumBits_Q5 < minSumBits_Q5)
|
||||
{
|
||||
minSumBits_Q5 = sumBits_Q5;
|
||||
RateLevelIndex = k;
|
||||
}
|
||||
}
|
||||
|
||||
psRangeEnc.enc_icdf( RateLevelIndex, Tables.silk_rate_levels_iCDF[signalType >> 1], 8);
|
||||
|
||||
/***************************************************/
|
||||
/* Sum-Weighted-Pulses Encoding */
|
||||
/***************************************************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (nRshifts[i] == 0)
|
||||
{
|
||||
psRangeEnc.enc_icdf( sum_pulses[i], Tables.silk_pulses_per_block_iCDF[RateLevelIndex], 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
psRangeEnc.enc_icdf( SilkConstants.SILK_MAX_PULSES + 1, Tables.silk_pulses_per_block_iCDF[RateLevelIndex], 8);
|
||||
for (k = 0; k < nRshifts[i] - 1; k++)
|
||||
{
|
||||
psRangeEnc.enc_icdf( SilkConstants.SILK_MAX_PULSES + 1, Tables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], 8);
|
||||
}
|
||||
|
||||
psRangeEnc.enc_icdf( sum_pulses[i], Tables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], 8);
|
||||
}
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* Shell Encoding */
|
||||
/******************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (sum_pulses[i] > 0)
|
||||
{
|
||||
ShellCoder.silk_shell_encoder(psRangeEnc, abs_pulses, i * SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* LSB Encoding */
|
||||
/****************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (nRshifts[i] > 0)
|
||||
{
|
||||
pulses_ptr = i * SilkConstants.SHELL_CODEC_FRAME_LENGTH;
|
||||
nLS = nRshifts[i] - 1;
|
||||
for (k = 0; k < SilkConstants.SHELL_CODEC_FRAME_LENGTH; k++)
|
||||
{
|
||||
abs_q = (sbyte)Inlines.silk_abs(pulses[pulses_ptr + k]);
|
||||
for (j = nLS; j > 0; j--)
|
||||
{
|
||||
bit = Inlines.silk_RSHIFT(abs_q, j) & 1;
|
||||
psRangeEnc.enc_icdf( bit, Tables.silk_lsb_iCDF, 8);
|
||||
}
|
||||
bit = abs_q & 1;
|
||||
psRangeEnc.enc_icdf( bit, Tables.silk_lsb_iCDF, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Encode signs */
|
||||
/****************/
|
||||
CodeSigns.silk_encode_signs(psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Enums
|
||||
{
|
||||
internal static class DecoderAPIFlag
|
||||
{
|
||||
public const int FLAG_DECODE_NORMAL = 0;
|
||||
public const int FLAG_PACKET_LOST = 1;
|
||||
public const int FLAG_DECODE_LBRR = 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents error messages from a silk encoder/decoder
|
||||
/// </summary>
|
||||
internal static class SilkError
|
||||
{
|
||||
internal static int SILK_NO_ERROR = 0;
|
||||
|
||||
// Encoder error messages
|
||||
|
||||
/* Input length is not a multiple of 10 ms, or length is longer than the packet length */
|
||||
internal static int SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES = -101;
|
||||
|
||||
/* Sampling frequency not 8000, 12000 or 16000 Hertz */
|
||||
internal static int SILK_ENC_FS_NOT_SUPPORTED = -102;
|
||||
|
||||
/* Packet size not 10, 20, 40, or 60 ms */
|
||||
internal static int SILK_ENC_PACKET_SIZE_NOT_SUPPORTED = -103;
|
||||
|
||||
/* Allocated payload buffer too short */
|
||||
internal static int SILK_ENC_PAYLOAD_BUF_TOO_SHORT = -104;
|
||||
|
||||
/* Loss rate not between 0 and 100 percent */
|
||||
internal static int SILK_ENC_INVALID_LOSS_RATE = -105;
|
||||
|
||||
/* Complexity setting not valid, use 0...10 */
|
||||
internal static int SILK_ENC_INVALID_COMPLEXITY_SETTING = -106;
|
||||
|
||||
/* Inband FEC setting not valid, use 0 or 1 */
|
||||
internal static int SILK_ENC_INVALID_INBAND_FEC_SETTING = -107;
|
||||
|
||||
/* DTX setting not valid, use 0 or 1 */
|
||||
internal static int SILK_ENC_INVALID_DTX_SETTING = -108;
|
||||
|
||||
/* CBR setting not valid, use 0 or 1 */
|
||||
internal static int SILK_ENC_INVALID_CBR_SETTING = -109;
|
||||
|
||||
/* Internal encoder error */
|
||||
internal static int SILK_ENC_INTERNAL_ERROR = -110;
|
||||
|
||||
/* Internal encoder error */
|
||||
internal static int SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR = -111;
|
||||
|
||||
// Decoder error messages
|
||||
|
||||
/* Output sampling frequency lower than internal decoded sampling frequency */
|
||||
internal static int SILK_DEC_INVALID_SAMPLING_FREQUENCY = -200;
|
||||
|
||||
/* Payload size exceeded the maximum allowed 1024 bytes */
|
||||
internal static int SILK_DEC_PAYLOAD_TOO_LARGE = -201;
|
||||
|
||||
/* Payload has bit errors */
|
||||
internal static int SILK_DEC_PAYLOAD_ERROR = -202;
|
||||
|
||||
/* Payload has bit errors */
|
||||
internal static int SILK_DEC_INVALID_FRAME_SIZE = -203;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,714 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Celt;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class Filters
|
||||
{
|
||||
internal static void silk_warped_LPC_analysis_filter(
|
||||
int[] state, /* I/O State [order + 1] */
|
||||
int[] res_Q2, /* O Residual signal [length] */
|
||||
short[] coef_Q13, /* I Coefficients [order] */
|
||||
int coef_Q13_ptr,
|
||||
short[] input, /* I Input signal [length] */
|
||||
int input_ptr,
|
||||
short lambda_Q16, /* I Warping factor */
|
||||
int length, /* I Length of input signal */
|
||||
int order /* I Filter order (even) */
|
||||
)
|
||||
{
|
||||
int n, i;
|
||||
int acc_Q11, tmp1, tmp2;
|
||||
|
||||
/* Order must be even */
|
||||
Inlines.OpusAssert((order & 1) == 0);
|
||||
|
||||
for (n = 0; n < length; n++)
|
||||
{
|
||||
/* Output of lowpass section */
|
||||
tmp2 = Inlines.silk_SMLAWB(state[0], state[1], lambda_Q16);
|
||||
state[0] = Inlines.silk_LSHIFT(input[input_ptr + n], 14);
|
||||
/* Output of allpass section */
|
||||
tmp1 = Inlines.silk_SMLAWB(state[1], state[2] - tmp2, lambda_Q16);
|
||||
state[1] = tmp2;
|
||||
acc_Q11 = Inlines.silk_RSHIFT(order, 1);
|
||||
acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp2, coef_Q13[coef_Q13_ptr]);
|
||||
/* Loop over allpass sections */
|
||||
for (i = 2; i < order; i += 2)
|
||||
{
|
||||
/* Output of allpass section */
|
||||
tmp2 = Inlines.silk_SMLAWB(state[i], state[i + 1] - tmp1, lambda_Q16);
|
||||
state[i] = tmp1;
|
||||
acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp1, coef_Q13[coef_Q13_ptr + i - 1]);
|
||||
/* Output of allpass section */
|
||||
tmp1 = Inlines.silk_SMLAWB(state[i + 1], state[i + 2] - tmp2, lambda_Q16);
|
||||
state[i + 1] = tmp2;
|
||||
acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp2, coef_Q13[coef_Q13_ptr + i]);
|
||||
}
|
||||
state[order] = tmp1;
|
||||
acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp1, coef_Q13[coef_Q13_ptr + order - 1]);
|
||||
res_Q2[n] = Inlines.silk_LSHIFT((int)input[input_ptr + n], 2) - Inlines.silk_RSHIFT_ROUND(acc_Q11, 9);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void silk_prefilter(
|
||||
SilkChannelEncoder psEnc, /* I/O Encoder state */
|
||||
SilkEncoderControl psEncCtrl, /* I Encoder control */
|
||||
int[] xw_Q3, /* O Weighted signal */
|
||||
short[] x, /* I Speech signal */
|
||||
int x_ptr
|
||||
)
|
||||
{
|
||||
SilkPrefilterState P = psEnc.sPrefilt;
|
||||
int j, k, lag;
|
||||
int tmp_32;
|
||||
int AR1_shp_Q13;
|
||||
int px;
|
||||
int pxw_Q3;
|
||||
int HarmShapeGain_Q12, Tilt_Q14;
|
||||
int HarmShapeFIRPacked_Q12, LF_shp_Q14;
|
||||
int[] x_filt_Q12;
|
||||
int[] st_res_Q2;
|
||||
short[] B_Q10 = new short[2];
|
||||
|
||||
/* Set up pointers */
|
||||
px = x_ptr;
|
||||
pxw_Q3 = 0;
|
||||
lag = P.lagPrev;
|
||||
x_filt_Q12 = new int[psEnc.subfr_length];
|
||||
st_res_Q2 = new int[psEnc.subfr_length];
|
||||
for (k = 0; k < psEnc.nb_subfr; k++)
|
||||
{
|
||||
/* Update Variables that change per sub frame */
|
||||
if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
lag = psEncCtrl.pitchL[k];
|
||||
}
|
||||
|
||||
/* Noise shape parameters */
|
||||
HarmShapeGain_Q12 = Inlines.silk_SMULWB((int)psEncCtrl.HarmShapeGain_Q14[k], 16384 - psEncCtrl.HarmBoost_Q14[k]);
|
||||
Inlines.OpusAssert(HarmShapeGain_Q12 >= 0);
|
||||
HarmShapeFIRPacked_Q12 = Inlines.silk_RSHIFT(HarmShapeGain_Q12, 2);
|
||||
HarmShapeFIRPacked_Q12 |= Inlines.silk_LSHIFT((int)Inlines.silk_RSHIFT(HarmShapeGain_Q12, 1), 16);
|
||||
Tilt_Q14 = psEncCtrl.Tilt_Q14[k];
|
||||
LF_shp_Q14 = psEncCtrl.LF_shp_Q14[k];
|
||||
AR1_shp_Q13 = k * SilkConstants.MAX_SHAPE_LPC_ORDER;
|
||||
|
||||
/* Short term FIR filtering*/
|
||||
silk_warped_LPC_analysis_filter(P.sAR_shp, st_res_Q2, psEncCtrl.AR1_Q13, AR1_shp_Q13, x, px,
|
||||
(short)(psEnc.warping_Q16), psEnc.subfr_length, psEnc.shapingLPCOrder);
|
||||
|
||||
/* Reduce (mainly) low frequencies during harmonic emphasis */
|
||||
B_Q10[0] = (short)(Inlines.silk_RSHIFT_ROUND(psEncCtrl.GainsPre_Q14[k], 4));
|
||||
tmp_32 = Inlines.silk_SMLABB(((int)((TuningParameters.INPUT_TILT) * ((long)1 << (26)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.INPUT_TILT, 26)*/, psEncCtrl.HarmBoost_Q14[k], HarmShapeGain_Q12); /* Q26 */
|
||||
tmp_32 = Inlines.silk_SMLABB(tmp_32, psEncCtrl.coding_quality_Q14, ((int)((TuningParameters.HIGH_RATE_INPUT_TILT) * ((long)1 << (12)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HIGH_RATE_INPUT_TILT, 12)*/); /* Q26 */
|
||||
tmp_32 = Inlines.silk_SMULWB(tmp_32, -psEncCtrl.GainsPre_Q14[k]); /* Q24 */
|
||||
tmp_32 = Inlines.silk_RSHIFT_ROUND(tmp_32, 14); /* Q10 */
|
||||
B_Q10[1] = (short)(Inlines.silk_SAT16(tmp_32));
|
||||
x_filt_Q12[0] = Inlines.silk_MLA(Inlines.silk_MUL(st_res_Q2[0], B_Q10[0]), P.sHarmHP_Q2, B_Q10[1]);
|
||||
for (j = 1; j < psEnc.subfr_length; j++)
|
||||
{
|
||||
x_filt_Q12[j] = Inlines.silk_MLA(Inlines.silk_MUL(st_res_Q2[j], B_Q10[0]), st_res_Q2[j - 1], B_Q10[1]);
|
||||
}
|
||||
P.sHarmHP_Q2 = st_res_Q2[psEnc.subfr_length - 1];
|
||||
|
||||
silk_prefilt(P, x_filt_Q12, xw_Q3, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc.subfr_length);
|
||||
|
||||
px += psEnc.subfr_length;
|
||||
pxw_Q3 += psEnc.subfr_length;
|
||||
}
|
||||
|
||||
P.lagPrev = psEncCtrl.pitchL[psEnc.nb_subfr - 1];
|
||||
|
||||
}
|
||||
|
||||
/* Prefilter for finding Quantizer input signal */
|
||||
static void silk_prefilt(
|
||||
SilkPrefilterState P, /* I/O state */
|
||||
int[] st_res_Q12, /* I short term residual signal */
|
||||
int[] xw_Q3, /* O prefiltered signal */
|
||||
int xw_Q3_ptr,
|
||||
int HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */
|
||||
int Tilt_Q14, /* I Tilt shaping coeficient */
|
||||
int LF_shp_Q14, /* I Low-frequancy shaping coeficients */
|
||||
int lag, /* I Lag for harmonic shaping */
|
||||
int length /* I Length of signals */
|
||||
)
|
||||
{
|
||||
int i, idx, LTP_shp_buf_idx;
|
||||
int n_LTP_Q12, n_Tilt_Q10, n_LF_Q10;
|
||||
int sLF_MA_shp_Q12, sLF_AR_shp_Q12;
|
||||
short[] LTP_shp_buf;
|
||||
|
||||
/* To speed up use temp variables instead of using the struct */
|
||||
LTP_shp_buf = P.sLTP_shp;
|
||||
LTP_shp_buf_idx = P.sLTP_shp_buf_idx;
|
||||
sLF_AR_shp_Q12 = P.sLF_AR_shp_Q12;
|
||||
sLF_MA_shp_Q12 = P.sLF_MA_shp_Q12;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
if (lag > 0)
|
||||
{
|
||||
/* unrolled loop */
|
||||
Inlines.OpusAssert(SilkConstants.HARM_SHAPE_FIR_TAPS == 3);
|
||||
idx = lag + LTP_shp_buf_idx;
|
||||
n_LTP_Q12 = Inlines.silk_SMULBB(LTP_shp_buf[(idx - SilkConstants.HARM_SHAPE_FIR_TAPS / 2 - 1) & SilkConstants.LTP_MASK], HarmShapeFIRPacked_Q12);
|
||||
n_LTP_Q12 = Inlines.silk_SMLABT(n_LTP_Q12, LTP_shp_buf[(idx - SilkConstants.HARM_SHAPE_FIR_TAPS / 2) & SilkConstants.LTP_MASK], HarmShapeFIRPacked_Q12);
|
||||
n_LTP_Q12 = Inlines.silk_SMLABB(n_LTP_Q12, LTP_shp_buf[(idx - SilkConstants.HARM_SHAPE_FIR_TAPS / 2 + 1) & SilkConstants.LTP_MASK], HarmShapeFIRPacked_Q12);
|
||||
}
|
||||
else {
|
||||
n_LTP_Q12 = 0;
|
||||
}
|
||||
|
||||
n_Tilt_Q10 = Inlines.silk_SMULWB(sLF_AR_shp_Q12, Tilt_Q14);
|
||||
n_LF_Q10 = Inlines.silk_SMLAWB(Inlines.silk_SMULWT(sLF_AR_shp_Q12, LF_shp_Q14), sLF_MA_shp_Q12, LF_shp_Q14);
|
||||
|
||||
sLF_AR_shp_Q12 = Inlines.silk_SUB32(st_res_Q12[i], Inlines.silk_LSHIFT(n_Tilt_Q10, 2));
|
||||
sLF_MA_shp_Q12 = Inlines.silk_SUB32(sLF_AR_shp_Q12, Inlines.silk_LSHIFT(n_LF_Q10, 2));
|
||||
|
||||
LTP_shp_buf_idx = (LTP_shp_buf_idx - 1) & SilkConstants.LTP_MASK;
|
||||
LTP_shp_buf[LTP_shp_buf_idx] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sLF_MA_shp_Q12, 12));
|
||||
|
||||
xw_Q3[xw_Q3_ptr + i] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SUB32(sLF_MA_shp_Q12, n_LTP_Q12), 9);
|
||||
}
|
||||
|
||||
/* Copy temp variable back to state */
|
||||
P.sLF_AR_shp_Q12 = sLF_AR_shp_Q12;
|
||||
P.sLF_MA_shp_Q12 = sLF_MA_shp_Q12;
|
||||
P.sLTP_shp_buf_idx = LTP_shp_buf_idx;
|
||||
}
|
||||
|
||||
#if !UNSAFE
|
||||
|
||||
/// <summary>
|
||||
/// Second order ARMA filter, alternative implementation
|
||||
/// </summary>
|
||||
/// <param name="input">I input signal</param>
|
||||
/// <param name="B_Q28">I MA coefficients [3]</param>
|
||||
/// <param name="A_Q28">I AR coefficients [2]</param>
|
||||
/// <param name="S">I/O State vector [2]</param>
|
||||
/// <param name="output">O output signal</param>
|
||||
/// <param name="len">I signal length (must be even)</param>
|
||||
/// <param name="stride">I Operate on interleaved signal if > 1</param>
|
||||
internal static void silk_biquad_alt(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int[] S,
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
int len,
|
||||
int stride)
|
||||
{
|
||||
/* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
|
||||
int k;
|
||||
int inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
|
||||
|
||||
/* Negate A_Q28 values and split in two parts */
|
||||
A0_L_Q28 = (-A_Q28[0]) & 0x00003FFF; /* lower part */
|
||||
A0_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[0], 14); /* upper part */
|
||||
A1_L_Q28 = (-A_Q28[1]) & 0x00003FFF; /* lower part */
|
||||
A1_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[1], 14); /* upper part */
|
||||
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
/* S[ 0 ], S[ 1 ]: Q12 */
|
||||
inval = input[input_ptr + k * stride];
|
||||
out32_Q14 = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(S[0], B_Q28[0], inval), 2);
|
||||
|
||||
S[0] = S[1] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A0_L_Q28), 14);
|
||||
S[0] = Inlines.silk_SMLAWB(S[0], out32_Q14, A0_U_Q28);
|
||||
S[0] = Inlines.silk_SMLAWB(S[0], B_Q28[1], inval);
|
||||
|
||||
S[1] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A1_L_Q28), 14);
|
||||
S[1] = Inlines.silk_SMLAWB(S[1], out32_Q14, A1_U_Q28);
|
||||
S[1] = Inlines.silk_SMLAWB(S[1], B_Q28[2], inval);
|
||||
|
||||
/* Scale back to Q0 and saturate */
|
||||
output[output_ptr + k * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(out32_Q14 + (1 << 14) - 1, 14));
|
||||
}
|
||||
}
|
||||
|
||||
internal static void silk_biquad_alt(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int[] S,
|
||||
int S_ptr,
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
int len,
|
||||
int stride)
|
||||
{
|
||||
/* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
|
||||
int k;
|
||||
int inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
|
||||
|
||||
/* Negate A_Q28 values and split in two parts */
|
||||
A0_L_Q28 = (-A_Q28[0]) & 0x00003FFF; /* lower part */
|
||||
A0_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[0], 14); /* upper part */
|
||||
A1_L_Q28 = (-A_Q28[1]) & 0x00003FFF; /* lower part */
|
||||
A1_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[1], 14); /* upper part */
|
||||
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
int s1 = S_ptr + 1;
|
||||
/* S[ 0 ], S[ 1 ]: Q12 */
|
||||
inval = input[input_ptr + k * stride];
|
||||
out32_Q14 = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(S[S_ptr], B_Q28[0], inval), 2);
|
||||
|
||||
S[S_ptr] = S[s1] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A0_L_Q28), 14);
|
||||
S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr], out32_Q14, A0_U_Q28);
|
||||
S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr], B_Q28[1], inval);
|
||||
|
||||
S[s1] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A1_L_Q28), 14);
|
||||
S[s1] = Inlines.silk_SMLAWB(S[s1], out32_Q14, A1_U_Q28);
|
||||
S[s1] = Inlines.silk_SMLAWB(S[s1], B_Q28[2], inval);
|
||||
|
||||
/* Scale back to Q0 and saturate */
|
||||
output[output_ptr + k * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(out32_Q14 + (1 << 14) - 1, 14));
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
/// <summary>
|
||||
/// Second order ARMA filter, alternative implementation
|
||||
/// </summary>
|
||||
/// <param name="input">I input signal</param>
|
||||
/// <param name="B_Q28">I MA coefficients [3]</param>
|
||||
/// <param name="A_Q28">I AR coefficients [2]</param>
|
||||
/// <param name="S">I/O State vector [2]</param>
|
||||
/// <param name="output">O output signal</param>
|
||||
/// <param name="len">I signal length (must be even)</param>
|
||||
/// <param name="stride">I Operate on interleaved signal if > 1</param>
|
||||
internal static unsafe void silk_biquad_alt(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int[] S,
|
||||
int S_ptr,
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
int len,
|
||||
int stride)
|
||||
{
|
||||
/* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
|
||||
int k;
|
||||
int inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
|
||||
|
||||
/* Negate A_Q28 values and split in two parts */
|
||||
A0_L_Q28 = (-A_Q28[0]) & 0x00003FFF; /* lower part */
|
||||
A0_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[0], 14); /* upper part */
|
||||
A1_L_Q28 = (-A_Q28[1]) & 0x00003FFF; /* lower part */
|
||||
A1_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[1], 14); /* upper part */
|
||||
|
||||
fixed (short* pinput_base = input, poutput_base = output)
|
||||
{
|
||||
fixed (int* pS_base = S, pBQ28 = B_Q28)
|
||||
{
|
||||
int* pS = pS_base + S_ptr;
|
||||
short* pinput = pinput_base + input_ptr;
|
||||
short* poutput = poutput_base + output_ptr;
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
/* S[ 0 ], S[ 1 ]: Q12 */
|
||||
inval = pinput[k * stride];
|
||||
out32_Q14 = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(pS[0], pBQ28[0], inval), 2);
|
||||
|
||||
pS[0] = pS[1] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A0_L_Q28), 14);
|
||||
pS[0] = Inlines.silk_SMLAWB(pS[0], out32_Q14, A0_U_Q28);
|
||||
pS[0] = Inlines.silk_SMLAWB(pS[0], pBQ28[1], inval);
|
||||
|
||||
pS[1] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A1_L_Q28), 14);
|
||||
pS[1] = Inlines.silk_SMLAWB(pS[1], out32_Q14, A1_U_Q28);
|
||||
pS[1] = Inlines.silk_SMLAWB(pS[1], pBQ28[2], inval);
|
||||
|
||||
/* Scale back to Q0 and saturate */
|
||||
poutput[k * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(out32_Q14 + (1 << 14) - 1, 14));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void silk_biquad_alt(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int[] S,
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
int len,
|
||||
int stride)
|
||||
{
|
||||
silk_biquad_alt(input, input_ptr, B_Q28, A_Q28, S, 0, output, output_ptr, len, stride);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Coefficients for 2-band filter bank based on first-order allpass filters */
|
||||
private readonly static short A_fb1_20 = 5394 << 1;
|
||||
private readonly static short A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */
|
||||
|
||||
/// <summary>
|
||||
/// Split signal into two decimated bands using first-order allpass filters
|
||||
/// </summary>
|
||||
/// <param name="input">I Input signal [N]</param>
|
||||
/// <param name="S">I/O State vector [2]</param>
|
||||
/// <param name="outL">O Low band [N/2]</param>
|
||||
/// <param name="outH">O High band [N/2]</param>
|
||||
/// <param name="N">I Number of input samples</param>
|
||||
internal static void silk_ana_filt_bank_1(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] S,
|
||||
short[] outL,
|
||||
short[] outH,
|
||||
int outH_ptr,
|
||||
int N)
|
||||
{
|
||||
int k, N2 = Inlines.silk_RSHIFT(N, 1);
|
||||
int in32, X, Y, out_1, out_2;
|
||||
|
||||
/* Internal variables and state are in Q10 format */
|
||||
for (k = 0; k < N2; k++)
|
||||
{
|
||||
/* Convert to Q10 */
|
||||
in32 = Inlines.silk_LSHIFT((int)input[input_ptr + 2 * k], 10);
|
||||
|
||||
/* All-pass section for even input sample */
|
||||
Y = Inlines.silk_SUB32(in32, S[0]);
|
||||
X = Inlines.silk_SMLAWB(Y, Y, A_fb1_21);
|
||||
out_1 = Inlines.silk_ADD32(S[0], X);
|
||||
S[0] = Inlines.silk_ADD32(in32, X);
|
||||
|
||||
/* Convert to Q10 */
|
||||
in32 = Inlines.silk_LSHIFT((int)input[input_ptr + 2 * k + 1], 10);
|
||||
|
||||
/* All-pass section for odd input sample, and add to output of previous section */
|
||||
Y = Inlines.silk_SUB32(in32, S[1]);
|
||||
X = Inlines.silk_SMULWB(Y, A_fb1_20);
|
||||
out_2 = Inlines.silk_ADD32(S[1], X);
|
||||
S[1] = Inlines.silk_ADD32(in32, X);
|
||||
|
||||
/* Add/subtract, convert back to int16 and store to output */
|
||||
outL[k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD32(out_2, out_1), 11));
|
||||
outH[outH_ptr + k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SUB32(out_2, out_1), 11));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chirp (bandwidth expand) LP AR filter
|
||||
/// </summary>
|
||||
/// <param name="ar">I/O AR filter to be expanded (without leading 1)</param>
|
||||
/// <param name="d">I Length of ar</param>
|
||||
/// <param name="chirp_Q16">I Chirp factor in Q16</param>
|
||||
internal static void silk_bwexpander_32(int[] ar, int d, int chirp_Q16)
|
||||
{
|
||||
int i;
|
||||
int chirp_minus_one_Q16 = chirp_Q16 - 65536;
|
||||
|
||||
for (i = 0; i < d - 1; i++)
|
||||
{
|
||||
ar[i] = Inlines.silk_SMULWW(chirp_Q16, ar[i]);
|
||||
chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, chirp_minus_one_Q16), 16);
|
||||
}
|
||||
|
||||
ar[d - 1] = Inlines.silk_SMULWW(chirp_Q16, ar[d - 1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elliptic/Cauer filters designed with 0.1 dB passband ripple,
|
||||
/// 80 dB minimum stopband attenuation, and
|
||||
/// [0.95 : 0.15 : 0.35] normalized cut off frequencies.
|
||||
/// Helper function, interpolates the filter taps
|
||||
/// </summary>
|
||||
/// <param name="B_Q28">order [TRANSITION_NB]</param>
|
||||
/// <param name="A_Q28">order [TRANSITION_NA]</param>
|
||||
/// <param name="ind"></param>
|
||||
/// <param name="fac_Q16"></param>
|
||||
internal static void silk_LP_interpolate_filter_taps(
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int ind,
|
||||
int fac_Q16)
|
||||
{
|
||||
int nb, na;
|
||||
|
||||
if (ind < SilkConstants.TRANSITION_INT_NUM - 1)
|
||||
{
|
||||
if (fac_Q16 > 0)
|
||||
{
|
||||
if (fac_Q16 < 32768)
|
||||
{
|
||||
/* fac_Q16 is in range of a 16-bit int */
|
||||
/* Piece-wise linear interpolation of B and A */
|
||||
for (nb = 0; nb < SilkConstants.TRANSITION_NB; nb++)
|
||||
{
|
||||
B_Q28[nb] = Inlines.silk_SMLAWB(
|
||||
Tables.silk_Transition_LP_B_Q28[ind][nb],
|
||||
Tables.silk_Transition_LP_B_Q28[ind + 1][nb] -
|
||||
Tables.silk_Transition_LP_B_Q28[ind][nb],
|
||||
fac_Q16);
|
||||
}
|
||||
|
||||
for (na = 0; na < SilkConstants.TRANSITION_NA; na++)
|
||||
{
|
||||
A_Q28[na] = Inlines.silk_SMLAWB(
|
||||
Tables.silk_Transition_LP_A_Q28[ind][na],
|
||||
Tables.silk_Transition_LP_A_Q28[ind + 1][na] -
|
||||
Tables.silk_Transition_LP_A_Q28[ind][na],
|
||||
fac_Q16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */
|
||||
Inlines.OpusAssert(fac_Q16 - (1 << 16) == Inlines.silk_SAT16(fac_Q16 - (1 << 16)));
|
||||
|
||||
/* Piece-wise linear interpolation of B and A */
|
||||
|
||||
for (nb = 0; nb < SilkConstants.TRANSITION_NB; nb++)
|
||||
{
|
||||
B_Q28[nb] = Inlines.silk_SMLAWB(
|
||||
Tables.silk_Transition_LP_B_Q28[ind + 1][nb],
|
||||
Tables.silk_Transition_LP_B_Q28[ind + 1][nb] -
|
||||
Tables.silk_Transition_LP_B_Q28[ind][nb],
|
||||
fac_Q16 - ((int)1 << 16));
|
||||
}
|
||||
|
||||
for (na = 0; na < SilkConstants.TRANSITION_NA; na++)
|
||||
{
|
||||
A_Q28[na] = Inlines.silk_SMLAWB(
|
||||
Tables.silk_Transition_LP_A_Q28[ind + 1][na],
|
||||
Tables.silk_Transition_LP_A_Q28[ind + 1][na] -
|
||||
Tables.silk_Transition_LP_A_Q28[ind][na],
|
||||
fac_Q16 - ((int)1 << 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(Tables.silk_Transition_LP_B_Q28[ind], 0, B_Q28, 0, SilkConstants.TRANSITION_NB);
|
||||
Array.Copy(Tables.silk_Transition_LP_A_Q28[ind], 0, A_Q28, 0, SilkConstants.TRANSITION_NA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(Tables.silk_Transition_LP_B_Q28[SilkConstants.TRANSITION_INT_NUM - 1], 0, B_Q28, 0, SilkConstants.TRANSITION_NB);
|
||||
Array.Copy(Tables.silk_Transition_LP_A_Q28[SilkConstants.TRANSITION_INT_NUM - 1], 0, A_Q28, 0, SilkConstants.TRANSITION_NA);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LPC analysis filter
|
||||
/// NB! State is kept internally and the
|
||||
/// filter always starts with zero state
|
||||
/// first d output samples are set to zero
|
||||
/// </summary>
|
||||
/// <param name="output">O Output signal</param>
|
||||
/// <param name="input">I Input signal</param>
|
||||
/// <param name="B">I MA prediction coefficients, Q12 [order]</param>
|
||||
/// <param name="len">I Signal length</param>
|
||||
/// <param name="d">I Filter order</param>
|
||||
internal static void silk_LPC_analysis_filter(
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
short[] B,
|
||||
int B_ptr,
|
||||
int len,
|
||||
int d)
|
||||
{
|
||||
int j;
|
||||
|
||||
short[] mem = new short[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
short[] num = new short[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
|
||||
Inlines.OpusAssert(d >= 6);
|
||||
Inlines.OpusAssert((d & 1) == 0);
|
||||
Inlines.OpusAssert(d <= len);
|
||||
|
||||
Inlines.OpusAssert(d <= SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
for (j = 0; j < d; j++)
|
||||
{
|
||||
num[j] = (short)(0 - B[B_ptr + j]);
|
||||
}
|
||||
for (j = 0; j < d; j++)
|
||||
{
|
||||
mem[j] = input[input_ptr + d - j - 1];
|
||||
}
|
||||
#if UNSAFE
|
||||
unsafe
|
||||
{
|
||||
fixed (short* pinput_base = input, poutput_base = output)
|
||||
{
|
||||
short* pinput = pinput_base + input_ptr + d;
|
||||
short* poutput = poutput_base + output_ptr + d;
|
||||
Kernels.celt_fir(pinput, num, poutput, len - d, d, mem);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Kernels.celt_fir(input, input_ptr + d, num, output, output_ptr + d, len - d, d, mem);
|
||||
#endif
|
||||
for (j = output_ptr; j < output_ptr + d; j++)
|
||||
{
|
||||
output[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private const int QA = 24;
|
||||
private static readonly int A_LIMIT = ((int)((0.99975f) * ((long)1 << (QA)) + 0.5))/*Inlines.SILK_CONST(0.99975f, QA)*/;
|
||||
|
||||
/// <summary>
|
||||
/// Compute inverse of LPC prediction gain, and
|
||||
/// test if LPC coefficients are stable (all poles within unit circle)
|
||||
/// </summary>
|
||||
/// <param name="A_QA">Prediction coefficients, order [2][SILK_MAX_ORDER_LPC]</param>
|
||||
/// <param name="order">Prediction order</param>
|
||||
/// <returns>inverse prediction gain in energy domain, Q30</returns>
|
||||
internal static int LPC_inverse_pred_gain_QA(
|
||||
int[][] A_QA,
|
||||
int order)
|
||||
{
|
||||
int k, n, mult2Q;
|
||||
int invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
|
||||
int[] Aold_QA, Anew_QA;
|
||||
|
||||
Anew_QA = A_QA[order & 1];
|
||||
|
||||
invGain_Q30 = (int)1 << 30;
|
||||
for (k = order - 1; k > 0; k--)
|
||||
{
|
||||
/* Check for stability */
|
||||
if ((Anew_QA[k] > A_LIMIT) || (Anew_QA[k] < -A_LIMIT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set RC equal to negated AR coef */
|
||||
rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[k], 31 - QA);
|
||||
|
||||
/* rc_mult1_Q30 range: [ 1 : 2^30 ] */
|
||||
rc_mult1_Q30 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
Inlines.OpusAssert(rc_mult1_Q30 > (1 << 15)); /* reduce A_LIMIT if fails */
|
||||
Inlines.OpusAssert(rc_mult1_Q30 <= (1 << 30));
|
||||
|
||||
/* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
|
||||
mult2Q = 32 - Inlines.silk_CLZ32(Inlines.silk_abs(rc_mult1_Q30));
|
||||
rc_mult2 = Inlines.silk_INVERSE32_varQ(rc_mult1_Q30, mult2Q + 30);
|
||||
|
||||
/* Update inverse gain */
|
||||
/* invGain_Q30 range: [ 0 : 2^30 ] */
|
||||
invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2);
|
||||
Inlines.OpusAssert(invGain_Q30 >= 0);
|
||||
Inlines.OpusAssert(invGain_Q30 <= (1 << 30));
|
||||
|
||||
/* Swap pointers */
|
||||
Aold_QA = Anew_QA;
|
||||
Anew_QA = A_QA[k & 1];
|
||||
|
||||
/* Update AR coefficient */
|
||||
for (n = 0; n < k; n++)
|
||||
{
|
||||
tmp_QA = Aold_QA[n] - Inlines.MUL32_FRAC_Q(Aold_QA[k - n - 1], rc_Q31, 31);
|
||||
Anew_QA[n] = Inlines.MUL32_FRAC_Q(tmp_QA, rc_mult2, mult2Q);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for stability */
|
||||
if ((Anew_QA[0] > A_LIMIT) || (Anew_QA[0] < -A_LIMIT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set RC equal to negated AR coef */
|
||||
rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[0], 31 - QA);
|
||||
|
||||
/* Range: [ 1 : 2^30 ] */
|
||||
rc_mult1_Q30 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
|
||||
/* Update inverse gain */
|
||||
/* Range: [ 0 : 2^30 ] */
|
||||
invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2);
|
||||
Inlines.OpusAssert(invGain_Q30 >= 0);
|
||||
Inlines.OpusAssert(invGain_Q30 <= 1 << 30);
|
||||
|
||||
return invGain_Q30;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For input in Q12 domain
|
||||
/// </summary>
|
||||
/// <param name="A_Q12">Prediction coefficients, Q12 [order]</param>
|
||||
/// <param name="order">I Prediction order</param>
|
||||
/// <returns>inverse prediction gain in energy domain, Q30</returns>
|
||||
internal static int silk_LPC_inverse_pred_gain(short[] A_Q12, int order)
|
||||
{
|
||||
int k;
|
||||
int[][] Atmp_QA = new int[2][];
|
||||
Atmp_QA[0] = new int[order];
|
||||
Atmp_QA[1] = new int[order];
|
||||
int[] Anew_QA;
|
||||
int DC_resp = 0;
|
||||
|
||||
Anew_QA = Atmp_QA[order & 1];
|
||||
|
||||
/* Increase Q domain of the AR coefficients */
|
||||
for (k = 0; k < order; k++)
|
||||
{
|
||||
DC_resp += (int)A_Q12[k];
|
||||
Anew_QA[k] = Inlines.silk_LSHIFT32((int)A_Q12[k], QA - 12);
|
||||
}
|
||||
|
||||
/* If the DC is unstable, we don't even need to do the full calculations */
|
||||
if (DC_resp >= 4096)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return LPC_inverse_pred_gain_QA(Atmp_QA, order);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class FindLPC
|
||||
{
|
||||
/* Finds LPC vector from correlations, and converts to NLSF */
|
||||
internal static void silk_find_LPC(
|
||||
SilkChannelEncoder psEncC, /* I/O Encoder state */
|
||||
short[] NLSF_Q15, /* O NLSFs */
|
||||
short[] x, /* I Input signal */
|
||||
int minInvGain_Q30 /* I Inverse of max prediction gain */
|
||||
)
|
||||
{
|
||||
int k, subfr_length;
|
||||
int[] a_Q16 = new int[SilkConstants.MAX_LPC_ORDER];
|
||||
int isInterpLower, shift;
|
||||
int res_nrg0, res_nrg1;
|
||||
int rshift0, rshift1;
|
||||
BoxedValueInt scratch_box1 = new BoxedValueInt();
|
||||
BoxedValueInt scratch_box2 = new BoxedValueInt();
|
||||
|
||||
/* Used only for LSF interpolation */
|
||||
int[] a_tmp_Q16 = new int[SilkConstants.MAX_LPC_ORDER];
|
||||
int res_nrg_interp, res_nrg, res_tmp_nrg;
|
||||
int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q;
|
||||
short[] a_tmp_Q12 = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
short[] NLSF0_Q15 = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
|
||||
subfr_length = psEncC.subfr_length + psEncC.predictLPCOrder;
|
||||
|
||||
/* Default: no interpolation */
|
||||
psEncC.indices.NLSFInterpCoef_Q2 = 4;
|
||||
|
||||
/* Burg AR analysis for the full frame */
|
||||
BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_Q16, x, 0, minInvGain_Q30, subfr_length, psEncC.nb_subfr, psEncC.predictLPCOrder);
|
||||
res_nrg = scratch_box1.Val;
|
||||
res_nrg_Q = scratch_box2.Val;
|
||||
|
||||
if (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR)
|
||||
{
|
||||
short[] LPC_res;
|
||||
|
||||
/* Optimal solution for last 10 ms */
|
||||
BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_tmp_Q16, x, (2 * subfr_length), minInvGain_Q30, subfr_length, 2, psEncC.predictLPCOrder);
|
||||
res_tmp_nrg = scratch_box1.Val;
|
||||
res_tmp_nrg_Q = scratch_box2.Val;
|
||||
|
||||
/* subtract residual energy here, as that's easier than adding it to the */
|
||||
/* residual energy of the first 10 ms in each iteration of the search below */
|
||||
shift = res_tmp_nrg_Q - res_nrg_Q;
|
||||
if (shift >= 0)
|
||||
{
|
||||
if (shift < 32)
|
||||
{
|
||||
res_nrg = res_nrg - Inlines.silk_RSHIFT(res_tmp_nrg, shift);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Inlines.OpusAssert(shift > -32);
|
||||
res_nrg = Inlines.silk_RSHIFT(res_nrg, -shift) - res_tmp_nrg;
|
||||
res_nrg_Q = res_tmp_nrg_Q;
|
||||
}
|
||||
|
||||
/* Convert to NLSFs */
|
||||
NLSF.silk_A2NLSF(NLSF_Q15, a_tmp_Q16, psEncC.predictLPCOrder);
|
||||
|
||||
LPC_res = new short[2 * subfr_length];
|
||||
|
||||
/* Search over interpolation indices to find the one with lowest residual energy */
|
||||
for (k = 3; k >= 0; k--)
|
||||
{
|
||||
/* Interpolate NLSFs for first half */
|
||||
Inlines.silk_interpolate(NLSF0_Q15, psEncC.prev_NLSFq_Q15, NLSF_Q15, k, psEncC.predictLPCOrder);
|
||||
|
||||
/* Convert to LPC for residual energy evaluation */
|
||||
NLSF.silk_NLSF2A(a_tmp_Q12, NLSF0_Q15, psEncC.predictLPCOrder);
|
||||
|
||||
/* Calculate residual energy with NLSF interpolation */
|
||||
Filters.silk_LPC_analysis_filter(LPC_res, 0, x, 0, a_tmp_Q12, 0, 2 * subfr_length, psEncC.predictLPCOrder);
|
||||
|
||||
SumSqrShift.silk_sum_sqr_shift(out res_nrg0, out rshift0, LPC_res, psEncC.predictLPCOrder, subfr_length - psEncC.predictLPCOrder);
|
||||
|
||||
SumSqrShift.silk_sum_sqr_shift(out res_nrg1, out rshift1, LPC_res, psEncC.predictLPCOrder + subfr_length, subfr_length - psEncC.predictLPCOrder);
|
||||
|
||||
/* Add subframe energies from first half frame */
|
||||
shift = rshift0 - rshift1;
|
||||
if (shift >= 0)
|
||||
{
|
||||
res_nrg1 = Inlines.silk_RSHIFT(res_nrg1, shift);
|
||||
res_nrg_interp_Q = -rshift0;
|
||||
}
|
||||
else {
|
||||
res_nrg0 = Inlines.silk_RSHIFT(res_nrg0, -shift);
|
||||
res_nrg_interp_Q = -rshift1;
|
||||
}
|
||||
res_nrg_interp = Inlines.silk_ADD32(res_nrg0, res_nrg1);
|
||||
|
||||
/* Compare with first half energy without NLSF interpolation, or best interpolated value so far */
|
||||
shift = res_nrg_interp_Q - res_nrg_Q;
|
||||
if (shift >= 0)
|
||||
{
|
||||
if (Inlines.silk_RSHIFT(res_nrg_interp, shift) < res_nrg)
|
||||
{
|
||||
isInterpLower = (true ? 1 : 0);
|
||||
}
|
||||
else {
|
||||
isInterpLower = (false ? 1 : 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (-shift < 32)
|
||||
{
|
||||
if (res_nrg_interp < Inlines.silk_RSHIFT(res_nrg, -shift))
|
||||
{
|
||||
isInterpLower = (true ? 1 : 0);
|
||||
}
|
||||
else {
|
||||
isInterpLower = (false ? 1 : 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
isInterpLower = (false ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine whether current interpolated NLSFs are best so far */
|
||||
if (isInterpLower == (true ? 1 : 0))
|
||||
{
|
||||
/* Interpolation has lower residual energy */
|
||||
res_nrg = res_nrg_interp;
|
||||
res_nrg_Q = res_nrg_interp_Q;
|
||||
psEncC.indices.NLSFInterpCoef_Q2 = (sbyte)k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (psEncC.indices.NLSFInterpCoef_Q2 == 4)
|
||||
{
|
||||
/* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
|
||||
NLSF.silk_A2NLSF(NLSF_Q15, a_Q16, psEncC.predictLPCOrder);
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(psEncC.indices.NLSFInterpCoef_Q2 == 4 || (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class FindLTP
|
||||
{
|
||||
/* Head room for correlations */
|
||||
private const int LTP_CORRS_HEAD_ROOM = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Finds linear prediction coeffecients and weights
|
||||
/// </summary>
|
||||
/// <param name="b_Q14"></param>
|
||||
/// <param name="WLTP"></param>
|
||||
/// <param name="LTPredCodGain_Q7"></param>
|
||||
/// <param name="r_lpc"></param>
|
||||
/// <param name="lag"></param>
|
||||
/// <param name="Wght_Q15"></param>
|
||||
/// <param name="subfr_length"></param>
|
||||
/// <param name="nb_subfr"></param>
|
||||
/// <param name="mem_offset"></param>
|
||||
/// <param name="corr_rshifts"></param>
|
||||
internal static void silk_find_LTP(
|
||||
short[] b_Q14, /* O LTP coefs [SilkConstants.MAX_NB_SUBFR * SilkConstants.LTP_ORDER] */
|
||||
int[] WLTP, /* O Weight for LTP quantization [SilkConstants.MAX_NB_SUBFR * SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER] */
|
||||
BoxedValueInt LTPredCodGain_Q7, /* O LTP coding gain */
|
||||
short[] r_lpc, /* I residual signal after LPC signal + state for first 10 ms */
|
||||
int[] lag, /* I LTP lags [SilkConstants.MAX_NB_SUBFR] */
|
||||
int[] Wght_Q15, /* I weights [SilkConstants.MAX_NB_SUBFR] */
|
||||
int subfr_length, /* I subframe length */
|
||||
int nb_subfr, /* I number of subframes */
|
||||
int mem_offset, /* I number of samples in LTP memory */
|
||||
int[] corr_rshifts /* O right shifts applied to correlations [SilkConstants.MAX_NB_SUBFR] */
|
||||
)
|
||||
{
|
||||
int i, k, lshift;
|
||||
int r_ptr;
|
||||
int lag_ptr;
|
||||
int b_Q14_ptr;
|
||||
|
||||
int regu;
|
||||
int WLTP_ptr;
|
||||
int[] b_Q16 = new int[SilkConstants.LTP_ORDER];
|
||||
int[] delta_b_Q14 = new int[SilkConstants.LTP_ORDER];
|
||||
int[] d_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int[] nrg = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int g_Q26;
|
||||
int[] w = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int WLTP_max, max_abs_d_Q14, max_w_bits;
|
||||
|
||||
int temp32, denom32;
|
||||
int extra_shifts;
|
||||
int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs;
|
||||
int LPC_res_nrg, LPC_LTP_res_nrg, div_Q16;
|
||||
int[] Rr = new int[SilkConstants.LTP_ORDER];
|
||||
int[] rr = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int wd, m_Q12;
|
||||
|
||||
b_Q14_ptr = 0;
|
||||
WLTP_ptr = 0;
|
||||
r_ptr = mem_offset;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
lag_ptr = r_ptr - (lag[k] + SilkConstants.LTP_ORDER / 2);
|
||||
|
||||
SumSqrShift.silk_sum_sqr_shift(out rr[k], out rr_shifts, r_lpc, r_ptr, subfr_length); /* rr[ k ] in Q( -rr_shifts ) */
|
||||
|
||||
/* Assure headroom */
|
||||
LZs = Inlines.silk_CLZ32(rr[k]);
|
||||
if (LZs < LTP_CORRS_HEAD_ROOM)
|
||||
{
|
||||
rr[k] = Inlines.silk_RSHIFT_ROUND(rr[k], LTP_CORRS_HEAD_ROOM - LZs);
|
||||
rr_shifts += (LTP_CORRS_HEAD_ROOM - LZs);
|
||||
}
|
||||
corr_rshifts[k] = rr_shifts;
|
||||
BoxedValueInt boxed_shifts = new BoxedValueInt(corr_rshifts[k]);
|
||||
CorrelateMatrix.silk_corrMatrix(r_lpc, lag_ptr, subfr_length, SilkConstants.LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP, WLTP_ptr, boxed_shifts); /* WLTP_ptr in Q( -corr_rshifts[ k ] ) */
|
||||
corr_rshifts[k] = boxed_shifts.Val;
|
||||
|
||||
/* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */
|
||||
CorrelateMatrix.silk_corrVector(r_lpc, lag_ptr, r_lpc, r_ptr, subfr_length, SilkConstants.LTP_ORDER, Rr, corr_rshifts[k]); /* Rr_ptr in Q( -corr_rshifts[ k ] ) */
|
||||
if (corr_rshifts[k] > rr_shifts)
|
||||
{
|
||||
rr[k] = Inlines.silk_RSHIFT(rr[k], corr_rshifts[k] - rr_shifts); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */
|
||||
}
|
||||
Inlines.OpusAssert(rr[k] >= 0);
|
||||
|
||||
regu = 1;
|
||||
regu = Inlines.silk_SMLAWB(regu, rr[k], ((int)((TuningParameters.LTP_DAMPING / 3) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_DAMPING / 3, 16)*/);
|
||||
regu = Inlines.silk_SMLAWB(regu, Inlines.MatrixGet(WLTP, WLTP_ptr, 0, 0, SilkConstants.LTP_ORDER), ((int)((TuningParameters.LTP_DAMPING / 3) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_DAMPING / 3, 16)*/);
|
||||
regu = Inlines.silk_SMLAWB(regu, Inlines.MatrixGet(WLTP, WLTP_ptr, SilkConstants.LTP_ORDER - 1, SilkConstants.LTP_ORDER - 1, SilkConstants.LTP_ORDER), ((int)((TuningParameters.LTP_DAMPING / 3) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_DAMPING / 3, 16)*/);
|
||||
RegularizeCorrelations.silk_regularize_correlations(WLTP, WLTP_ptr, rr, k, regu, SilkConstants.LTP_ORDER);
|
||||
|
||||
LinearAlgebra.silk_solve_LDL(WLTP, WLTP_ptr, SilkConstants.LTP_ORDER, Rr, b_Q16); /* WLTP_ptr and Rr_ptr both in Q(-corr_rshifts[k]) */
|
||||
|
||||
/* Limit and store in Q14 */
|
||||
silk_fit_LTP(b_Q16, b_Q14, b_Q14_ptr);
|
||||
|
||||
/* Calculate residual energy */
|
||||
nrg[k] = ResidualEnergy.silk_residual_energy16_covar(b_Q14, b_Q14_ptr, WLTP, WLTP_ptr, Rr, rr[k], SilkConstants.LTP_ORDER, 14); /* nrg in Q( -corr_rshifts[ k ] ) */
|
||||
|
||||
/* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */
|
||||
extra_shifts = Inlines.silk_min_int(corr_rshifts[k], LTP_CORRS_HEAD_ROOM);
|
||||
denom32 = Inlines.silk_LSHIFT_SAT32(Inlines.silk_SMULWB(nrg[k], Wght_Q15[k]), 1 + extra_shifts) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */
|
||||
Inlines.silk_RSHIFT(Inlines.silk_SMULWB((int)subfr_length, 655), corr_rshifts[k] - extra_shifts); /* Q( -corr_rshifts[ k ] + extra_shifts ) */
|
||||
denom32 = Inlines.silk_max(denom32, 1);
|
||||
Inlines.OpusAssert(((long)Wght_Q15[k] << 16) < int.MaxValue); /* Wght always < 0.5 in Q0 */
|
||||
temp32 = Inlines.silk_DIV32(Inlines.silk_LSHIFT((int)Wght_Q15[k], 16), denom32); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */
|
||||
temp32 = Inlines.silk_RSHIFT(temp32, 31 + corr_rshifts[k] - extra_shifts - 26); /* Q26 */
|
||||
|
||||
/* Limit temp such that the below scaling never wraps around */
|
||||
WLTP_max = 0;
|
||||
for (i = WLTP_ptr; i < WLTP_ptr + (SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER); i++)
|
||||
{
|
||||
WLTP_max = Inlines.silk_max(WLTP[i], WLTP_max);
|
||||
}
|
||||
lshift = Inlines.silk_CLZ32(WLTP_max) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor */
|
||||
Inlines.OpusAssert(26 - 18 + lshift >= 0);
|
||||
if (26 - 18 + lshift < 31)
|
||||
{
|
||||
temp32 = Inlines.silk_min_32(temp32, Inlines.silk_LSHIFT((int)1, 26 - 18 + lshift));
|
||||
}
|
||||
|
||||
Inlines.silk_scale_vector32_Q26_lshift_18(WLTP, WLTP_ptr, temp32, SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */
|
||||
|
||||
w[k] = Inlines.MatrixGet(WLTP, WLTP_ptr, SilkConstants.LTP_ORDER / 2, SilkConstants.LTP_ORDER / 2, SilkConstants.LTP_ORDER); /* w in Q( 18 - corr_rshifts[ k ] ) */
|
||||
Inlines.OpusAssert(w[k] >= 0);
|
||||
|
||||
r_ptr += subfr_length;
|
||||
b_Q14_ptr += SilkConstants.LTP_ORDER;
|
||||
WLTP_ptr += (SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER);
|
||||
}
|
||||
|
||||
maxRshifts = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
maxRshifts = Inlines.silk_max_int(corr_rshifts[k], maxRshifts);
|
||||
}
|
||||
|
||||
/* Compute LTP coding gain */
|
||||
if (LTPredCodGain_Q7 != null)
|
||||
{
|
||||
LPC_LTP_res_nrg = 0;
|
||||
LPC_res_nrg = 0;
|
||||
Inlines.OpusAssert(LTP_CORRS_HEAD_ROOM >= 2); /* Check that no overflow will happen when adding */
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
LPC_res_nrg = Inlines.silk_ADD32(LPC_res_nrg, Inlines.silk_RSHIFT(Inlines.silk_ADD32(Inlines.silk_SMULWB(rr[k], Wght_Q15[k]), 1), 1 + (maxRshifts - corr_rshifts[k]))); /* Q( -maxRshifts ) */
|
||||
LPC_LTP_res_nrg = Inlines.silk_ADD32(LPC_LTP_res_nrg, Inlines.silk_RSHIFT(Inlines.silk_ADD32(Inlines.silk_SMULWB(nrg[k], Wght_Q15[k]), 1), 1 + (maxRshifts - corr_rshifts[k]))); /* Q( -maxRshifts ) */
|
||||
}
|
||||
LPC_LTP_res_nrg = Inlines.silk_max(LPC_LTP_res_nrg, 1); /* avoid division by zero */
|
||||
|
||||
div_Q16 = Inlines.silk_DIV32_varQ(LPC_res_nrg, LPC_LTP_res_nrg, 16);
|
||||
LTPredCodGain_Q7.Val = (int)Inlines.silk_SMULBB(3, Inlines.silk_lin2log(div_Q16) - (16 << 7));
|
||||
|
||||
Inlines.OpusAssert(LTPredCodGain_Q7.Val == (int)Inlines.silk_SAT16(Inlines.silk_MUL(3, Inlines.silk_lin2log(div_Q16) - (16 << 7))));
|
||||
}
|
||||
|
||||
/* smoothing */
|
||||
/* d = sum( B, 1 ); */
|
||||
b_Q14_ptr = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
d_Q14[k] = 0;
|
||||
for (i = b_Q14_ptr; i < b_Q14_ptr + SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
d_Q14[k] += b_Q14[i];
|
||||
}
|
||||
b_Q14_ptr += SilkConstants.LTP_ORDER;
|
||||
}
|
||||
|
||||
/* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */
|
||||
|
||||
/* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */
|
||||
max_abs_d_Q14 = 0;
|
||||
max_w_bits = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
max_abs_d_Q14 = Inlines.silk_max_32(max_abs_d_Q14, Inlines.silk_abs(d_Q14[k]));
|
||||
/* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */
|
||||
/* Find bits needed in Q( 18 - maxRshifts ) */
|
||||
max_w_bits = Inlines.silk_max_32(max_w_bits, 32 - Inlines.silk_CLZ32(w[k]) + corr_rshifts[k] - maxRshifts);
|
||||
}
|
||||
|
||||
/* max_abs_d_Q14 = (5 << 15); worst case, i.e. SilkConstants.LTP_ORDER * -silk_int16_MIN */
|
||||
Inlines.OpusAssert(max_abs_d_Q14 <= (5 << 15));
|
||||
|
||||
/* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */
|
||||
extra_shifts = max_w_bits + 32 - Inlines.silk_CLZ32(max_abs_d_Q14) - 14;
|
||||
|
||||
/* Subtract what we got available; bits in output var plus maxRshifts */
|
||||
extra_shifts -= (32 - 1 - 2 + maxRshifts); /* Keep sign bit free as well as 2 bits for accumulation */
|
||||
extra_shifts = Inlines.silk_max_int(extra_shifts, 0);
|
||||
|
||||
maxRshifts_wxtra = maxRshifts + extra_shifts;
|
||||
|
||||
temp32 = Inlines.silk_RSHIFT(262, maxRshifts + extra_shifts) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */
|
||||
wd = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
/* w has at least 2 bits of headroom so no overflow should happen */
|
||||
temp32 = Inlines.silk_ADD32(temp32, Inlines.silk_RSHIFT(w[k], maxRshifts_wxtra - corr_rshifts[k])); /* Q( 18 - maxRshifts_wxtra ) */
|
||||
wd = Inlines.silk_ADD32(wd, Inlines.silk_LSHIFT(Inlines.silk_SMULWW(Inlines.silk_RSHIFT(w[k], maxRshifts_wxtra - corr_rshifts[k]), d_Q14[k]), 2)); /* Q( 18 - maxRshifts_wxtra ) */
|
||||
}
|
||||
m_Q12 = Inlines.silk_DIV32_varQ(wd, temp32, 12);
|
||||
|
||||
b_Q14_ptr = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
/* w[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */
|
||||
if (2 - corr_rshifts[k] > 0)
|
||||
{
|
||||
temp32 = Inlines.silk_RSHIFT(w[k], 2 - corr_rshifts[k]);
|
||||
}
|
||||
else {
|
||||
temp32 = Inlines.silk_LSHIFT_SAT32(w[k], corr_rshifts[k] - 2);
|
||||
}
|
||||
|
||||
g_Q26 = Inlines.silk_MUL(
|
||||
Inlines.silk_DIV32(
|
||||
((int)((TuningParameters.LTP_SMOOTHING) * ((long)1 << (26)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_SMOOTHING, 26)*/,
|
||||
Inlines.silk_RSHIFT(((int)((TuningParameters.LTP_SMOOTHING) * ((long)1 << (26)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_SMOOTHING, 26)*/, 10) + temp32), /* Q10 */
|
||||
Inlines.silk_LSHIFT_SAT32(Inlines.silk_SUB_SAT32((int)m_Q12, Inlines.silk_RSHIFT(d_Q14[k], 2)), 4)); /* Q16 */
|
||||
|
||||
temp32 = 0;
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
delta_b_Q14[i] = Inlines.silk_max_16(b_Q14[b_Q14_ptr + i], 1638); /* 1638_Q14 = 0.1_Q0 */
|
||||
temp32 += delta_b_Q14[i]; /* Q14 */
|
||||
}
|
||||
temp32 = Inlines.silk_DIV32(g_Q26, temp32); /* Q14 . Q12 */
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
b_Q14[b_Q14_ptr + i] = (short)(Inlines.silk_LIMIT_32((int)b_Q14[b_Q14_ptr + i] + Inlines.silk_SMULWB(Inlines.silk_LSHIFT_SAT32(temp32, 4), delta_b_Q14[i]), -16000, 28000));
|
||||
}
|
||||
b_Q14_ptr += SilkConstants.LTP_ORDER;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="LTP_coefs_Q16">[SilkConstants.LTP_ORDER]</param>
|
||||
/// <param name="LTP_coefs_Q14">[SilkConstants.LTP_ORDER]</param>
|
||||
/// <param name="LTP_coefs_Q14_ptr"></param>
|
||||
internal static void silk_fit_LTP(
|
||||
int[] LTP_coefs_Q16,
|
||||
short[] LTP_coefs_Q14,
|
||||
int LTP_coefs_Q14_ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
LTP_coefs_Q14[LTP_coefs_Q14_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(LTP_coefs_Q16[i], 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class FindPitchLags
|
||||
{
|
||||
/* Find pitch lags */
|
||||
internal static void silk_find_pitch_lags(
|
||||
SilkChannelEncoder psEnc, /* I/O encoder state */
|
||||
SilkEncoderControl psEncCtrl, /* I/O encoder control */
|
||||
short[] res, /* O residual */
|
||||
short[] x, /* I Speech signal */
|
||||
int x_ptr
|
||||
)
|
||||
{
|
||||
int buf_len, i, scale;
|
||||
int thrhld_Q13, res_nrg;
|
||||
int x_buf, x_buf_ptr;
|
||||
short[] Wsig;
|
||||
int Wsig_ptr;
|
||||
int[] auto_corr = new int[SilkConstants.MAX_FIND_PITCH_LPC_ORDER + 1];
|
||||
short[] rc_Q15 = new short[SilkConstants.MAX_FIND_PITCH_LPC_ORDER];
|
||||
int[] A_Q24 = new int[SilkConstants.MAX_FIND_PITCH_LPC_ORDER];
|
||||
short[] A_Q12 = new short[SilkConstants.MAX_FIND_PITCH_LPC_ORDER];
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* Set up buffer lengths etc based on Fs */
|
||||
/******************************************/
|
||||
buf_len = psEnc.la_pitch + psEnc.frame_length + psEnc.ltp_mem_length;
|
||||
|
||||
/* Safety check */
|
||||
Inlines.OpusAssert(buf_len >= psEnc.pitch_LPC_win_length);
|
||||
|
||||
x_buf = x_ptr - psEnc.ltp_mem_length;
|
||||
|
||||
/*************************************/
|
||||
/* Estimate LPC AR coefficients */
|
||||
/*************************************/
|
||||
|
||||
/* Calculate windowed signal */
|
||||
|
||||
Wsig = new short[psEnc.pitch_LPC_win_length];
|
||||
|
||||
/* First LA_LTP samples */
|
||||
x_buf_ptr = x_buf + buf_len - psEnc.pitch_LPC_win_length;
|
||||
Wsig_ptr = 0;
|
||||
ApplySineWindow.silk_apply_sine_window(Wsig, Wsig_ptr, x, x_buf_ptr, 1, psEnc.la_pitch);
|
||||
|
||||
/* Middle un - windowed samples */
|
||||
Wsig_ptr += psEnc.la_pitch;
|
||||
x_buf_ptr += psEnc.la_pitch;
|
||||
Array.Copy(x, x_buf_ptr, Wsig, Wsig_ptr, (psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1)));
|
||||
|
||||
/* Last LA_LTP samples */
|
||||
Wsig_ptr += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1);
|
||||
x_buf_ptr += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1);
|
||||
ApplySineWindow.silk_apply_sine_window(Wsig, Wsig_ptr, x, x_buf_ptr, 2, psEnc.la_pitch);
|
||||
|
||||
/* Calculate autocorrelation sequence */
|
||||
BoxedValueInt boxed_scale = new BoxedValueInt();
|
||||
Autocorrelation.silk_autocorr(auto_corr, boxed_scale, Wsig, psEnc.pitch_LPC_win_length, psEnc.pitchEstimationLPCOrder + 1);
|
||||
scale = boxed_scale.Val;
|
||||
|
||||
/* Add white noise, as fraction of energy */
|
||||
auto_corr[0] = Inlines.silk_SMLAWB(auto_corr[0], auto_corr[0], ((int)((TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION, 16)*/) + 1;
|
||||
|
||||
/* Calculate the reflection coefficients using schur */
|
||||
res_nrg = Schur.silk_schur(rc_Q15, auto_corr, psEnc.pitchEstimationLPCOrder);
|
||||
|
||||
/* Prediction gain */
|
||||
psEncCtrl.predGain_Q16 = Inlines.silk_DIV32_varQ(auto_corr[0], Inlines.silk_max_int(res_nrg, 1), 16);
|
||||
|
||||
/* Convert reflection coefficients to prediction coefficients */
|
||||
K2A.silk_k2a(A_Q24, rc_Q15, psEnc.pitchEstimationLPCOrder);
|
||||
|
||||
/* Convert From 32 bit Q24 to 16 bit Q12 coefs */
|
||||
for (i = 0; i < psEnc.pitchEstimationLPCOrder; i++)
|
||||
{
|
||||
A_Q12[i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(A_Q24[i], 12));
|
||||
}
|
||||
|
||||
/* Do BWE */
|
||||
BWExpander.silk_bwexpander(A_Q12, psEnc.pitchEstimationLPCOrder, ((int)((TuningParameters.FIND_PITCH_BANDWIDTH_EXPANSION) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_PITCH_BANDWIDTH_EXPANSION, 16)*/);
|
||||
|
||||
/*****************************************/
|
||||
/* LPC analysis filtering */
|
||||
/*****************************************/
|
||||
Filters.silk_LPC_analysis_filter(res, 0, x, x_buf, A_Q12, 0, buf_len, psEnc.pitchEstimationLPCOrder);
|
||||
|
||||
if (psEnc.indices.signalType != SilkConstants.TYPE_NO_VOICE_ACTIVITY && psEnc.first_frame_after_reset == 0)
|
||||
{
|
||||
/* Threshold for pitch estimator */
|
||||
thrhld_Q13 = ((int)((0.6f) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(0.6f, 13)*/;
|
||||
thrhld_Q13 = Inlines.silk_SMLABB(thrhld_Q13, ((int)((-0.004f) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(-0.004f, 13)*/, psEnc.pitchEstimationLPCOrder);
|
||||
thrhld_Q13 = Inlines.silk_SMLAWB(thrhld_Q13, ((int)((-0.1f) * ((long)1 << (21)) + 0.5))/*Inlines.SILK_CONST(-0.1f, 21)*/, psEnc.speech_activity_Q8);
|
||||
thrhld_Q13 = Inlines.silk_SMLABB(thrhld_Q13, ((int)((-0.15f) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(-0.15f, 13)*/, Inlines.silk_RSHIFT(psEnc.prevSignalType, 1));
|
||||
thrhld_Q13 = Inlines.silk_SMLAWB(thrhld_Q13, ((int)((-0.1f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(-0.1f, 14)*/, psEnc.input_tilt_Q15);
|
||||
thrhld_Q13 = Inlines.silk_SAT16(thrhld_Q13);
|
||||
|
||||
/*****************************************/
|
||||
/* Call pitch estimator */
|
||||
/*****************************************/
|
||||
BoxedValueShort boxed_lagIndex = new BoxedValueShort(psEnc.indices.lagIndex);
|
||||
BoxedValueSbyte boxed_contourIndex = new BoxedValueSbyte(psEnc.indices.contourIndex);
|
||||
BoxedValueInt boxed_LTPcorr = new BoxedValueInt(psEnc.LTPCorr_Q15);
|
||||
if (PitchAnalysisCore.silk_pitch_analysis_core(res, psEncCtrl.pitchL, boxed_lagIndex, boxed_contourIndex,
|
||||
boxed_LTPcorr, psEnc.prevLag, psEnc.pitchEstimationThreshold_Q16,
|
||||
(int)thrhld_Q13, psEnc.fs_kHz, psEnc.pitchEstimationComplexity, psEnc.nb_subfr) == 0)
|
||||
{
|
||||
psEnc.indices.signalType = SilkConstants.TYPE_VOICED;
|
||||
}
|
||||
else {
|
||||
psEnc.indices.signalType = SilkConstants.TYPE_UNVOICED;
|
||||
}
|
||||
|
||||
psEnc.indices.lagIndex = boxed_lagIndex.Val;
|
||||
psEnc.indices.contourIndex = boxed_contourIndex.Val;
|
||||
psEnc.LTPCorr_Q15 = boxed_LTPcorr.Val;
|
||||
}
|
||||
else {
|
||||
Arrays.MemSetInt(psEncCtrl.pitchL, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
psEnc.indices.lagIndex = 0;
|
||||
psEnc.indices.contourIndex = 0;
|
||||
psEnc.LTPCorr_Q15 = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class FindPredCoefs
|
||||
{
|
||||
internal static void silk_find_pred_coefs(
|
||||
SilkChannelEncoder psEnc, /* I/O encoder state */
|
||||
SilkEncoderControl psEncCtrl, /* I/O encoder control */
|
||||
short[] res_pitch, /* I Residual from pitch analysis */
|
||||
short[] x, /* I Speech signal */
|
||||
int x_ptr,
|
||||
int condCoding /* I The type of conditional coding to use */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int[] invGains_Q16 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int[] local_gains = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int[] Wght_Q15 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
short[] NLSF_Q15 = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
int x_ptr2;
|
||||
int x_pre_ptr;
|
||||
short[] LPC_in_pre;
|
||||
int tmp, min_gain_Q16, minInvGain_Q30;
|
||||
int[] LTP_corrs_rshift = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
|
||||
/* weighting for weighted least squares */
|
||||
min_gain_Q16 = int.MaxValue >> 6;
|
||||
for (i = 0; i < psEnc.nb_subfr; i++)
|
||||
{
|
||||
min_gain_Q16 = Inlines.silk_min(min_gain_Q16, psEncCtrl.Gains_Q16[i]);
|
||||
}
|
||||
for (i = 0; i < psEnc.nb_subfr; i++)
|
||||
{
|
||||
/* Divide to Q16 */
|
||||
Inlines.OpusAssert(psEncCtrl.Gains_Q16[i] > 0);
|
||||
/* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */
|
||||
invGains_Q16[i] = Inlines.silk_DIV32_varQ(min_gain_Q16, psEncCtrl.Gains_Q16[i], 16 - 2);
|
||||
|
||||
/* Ensure Wght_Q15 a minimum value 1 */
|
||||
invGains_Q16[i] = Inlines.silk_max(invGains_Q16[i], 363);
|
||||
|
||||
/* Square the inverted gains */
|
||||
Inlines.OpusAssert(invGains_Q16[i] == Inlines.silk_SAT16(invGains_Q16[i]));
|
||||
tmp = Inlines.silk_SMULWB(invGains_Q16[i], invGains_Q16[i]);
|
||||
Wght_Q15[i] = Inlines.silk_RSHIFT(tmp, 1);
|
||||
|
||||
/* Invert the inverted and normalized gains */
|
||||
local_gains[i] = Inlines.silk_DIV32(((int)1 << 16), invGains_Q16[i]);
|
||||
}
|
||||
|
||||
LPC_in_pre = new short[psEnc.nb_subfr * psEnc.predictLPCOrder + psEnc.frame_length];
|
||||
if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
int[] WLTP;
|
||||
|
||||
/**********/
|
||||
/* VOICED */
|
||||
/**********/
|
||||
Inlines.OpusAssert(psEnc.ltp_mem_length - psEnc.predictLPCOrder >= psEncCtrl.pitchL[0] + SilkConstants.LTP_ORDER / 2);
|
||||
|
||||
WLTP = new int[psEnc.nb_subfr * SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER];
|
||||
|
||||
/* LTP analysis */
|
||||
BoxedValueInt boxed_codgain = new BoxedValueInt(psEncCtrl.LTPredCodGain_Q7);
|
||||
FindLTP.silk_find_LTP(psEncCtrl.LTPCoef_Q14, WLTP, boxed_codgain,
|
||||
res_pitch, psEncCtrl.pitchL, Wght_Q15, psEnc.subfr_length,
|
||||
psEnc.nb_subfr, psEnc.ltp_mem_length, LTP_corrs_rshift);
|
||||
psEncCtrl.LTPredCodGain_Q7 = boxed_codgain.Val;
|
||||
|
||||
/* Quantize LTP gain parameters */
|
||||
BoxedValueSbyte boxed_periodicity = new BoxedValueSbyte(psEnc.indices.PERIndex);
|
||||
BoxedValueInt boxed_gain = new BoxedValueInt(psEnc.sum_log_gain_Q7);
|
||||
QuantizeLTPGains.silk_quant_LTP_gains(psEncCtrl.LTPCoef_Q14, psEnc.indices.LTPIndex, boxed_periodicity,
|
||||
boxed_gain, WLTP, psEnc.mu_LTP_Q9, psEnc.LTPQuantLowComplexity, psEnc.nb_subfr
|
||||
);
|
||||
psEnc.indices.PERIndex = boxed_periodicity.Val;
|
||||
psEnc.sum_log_gain_Q7 = boxed_gain.Val;
|
||||
|
||||
/* Control LTP scaling */
|
||||
LTPScaleControl.silk_LTP_scale_ctrl(psEnc, psEncCtrl, condCoding);
|
||||
|
||||
/* Create LTP residual */
|
||||
LTPAnalysisFilter.silk_LTP_analysis_filter(LPC_in_pre, x, x_ptr - psEnc.predictLPCOrder, psEncCtrl.LTPCoef_Q14,
|
||||
psEncCtrl.pitchL, invGains_Q16, psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder);
|
||||
|
||||
}
|
||||
else {
|
||||
/************/
|
||||
/* UNVOICED */
|
||||
/************/
|
||||
/* Create signal with prepended subframes, scaled by inverse gains */
|
||||
x_ptr2 = x_ptr - psEnc.predictLPCOrder;
|
||||
x_pre_ptr = 0;
|
||||
for (i = 0; i < psEnc.nb_subfr; i++)
|
||||
{
|
||||
Inlines.silk_scale_copy_vector16(LPC_in_pre, x_pre_ptr, x, x_ptr2, invGains_Q16[i],
|
||||
psEnc.subfr_length + psEnc.predictLPCOrder);
|
||||
x_pre_ptr += psEnc.subfr_length + psEnc.predictLPCOrder;
|
||||
x_ptr2 += psEnc.subfr_length;
|
||||
}
|
||||
|
||||
Arrays.MemSetShort(psEncCtrl.LTPCoef_Q14, 0, psEnc.nb_subfr * SilkConstants.LTP_ORDER);
|
||||
psEncCtrl.LTPredCodGain_Q7 = 0;
|
||||
psEnc.sum_log_gain_Q7 = 0;
|
||||
}
|
||||
|
||||
/* Limit on total predictive coding gain */
|
||||
if (psEnc.first_frame_after_reset != 0)
|
||||
{
|
||||
minInvGain_Q30 = ((int)((1.0f / SilkConstants.MAX_PREDICTION_POWER_GAIN_AFTER_RESET) * ((long)1 << (30)) + 0.5))/*Inlines.SILK_CONST(1.0f / SilkConstants.MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30)*/;
|
||||
}
|
||||
else {
|
||||
minInvGain_Q30 = Inlines.silk_log2lin(Inlines.silk_SMLAWB(16 << 7, (int)psEncCtrl.LTPredCodGain_Q7, ((int)((1.0f / 3f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f / 3f, 16)*/)); /* Q16 */
|
||||
minInvGain_Q30 = Inlines.silk_DIV32_varQ(minInvGain_Q30,
|
||||
Inlines.silk_SMULWW(((int)((SilkConstants.MAX_PREDICTION_POWER_GAIN) * ((long)1 << (0)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.MAX_PREDICTION_POWER_GAIN, 0)*/,
|
||||
Inlines.silk_SMLAWB(((int)((0.25f) * ((long)1 << (18)) + 0.5))/*Inlines.SILK_CONST(0.25f, 18)*/, ((int)((0.75f) * ((long)1 << (18)) + 0.5))/*Inlines.SILK_CONST(0.75f, 18)*/, psEncCtrl.coding_quality_Q14)), 14);
|
||||
}
|
||||
|
||||
/* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
|
||||
FindLPC.silk_find_LPC(psEnc, NLSF_Q15, LPC_in_pre, minInvGain_Q30);
|
||||
|
||||
/* Quantize LSFs */
|
||||
NLSF.silk_process_NLSFs(psEnc, psEncCtrl.PredCoef_Q12, NLSF_Q15, psEnc.prev_NLSFq_Q15);
|
||||
|
||||
/* Calculate residual energy using quantized LPC coefficients */
|
||||
ResidualEnergy.silk_residual_energy(psEncCtrl.ResNrg, psEncCtrl.ResNrgQ, LPC_in_pre, psEncCtrl.PredCoef_Q12, local_gains,
|
||||
psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder);
|
||||
|
||||
/* Copy to prediction struct for use in next frame for interpolation */
|
||||
Array.Copy(NLSF_Q15, psEnc.prev_NLSFq_Q15, SilkConstants.MAX_LPC_ORDER);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class GainQuantization
|
||||
{
|
||||
private static readonly int OFFSET = ((SilkConstants.MIN_QGAIN_DB * 128) / 6 + 16 * 128);
|
||||
private static readonly int SCALE_Q16 = ((65536 * (SilkConstants.N_LEVELS_QGAIN - 1)) / (((SilkConstants.MAX_QGAIN_DB - SilkConstants.MIN_QGAIN_DB) * 128) / 6));
|
||||
private static readonly int INV_SCALE_Q16 = ((65536 * (((SilkConstants.MAX_QGAIN_DB - SilkConstants.MIN_QGAIN_DB) * 128) / 6)) / (SilkConstants.N_LEVELS_QGAIN - 1));
|
||||
|
||||
/// <summary>
|
||||
/// Gain scalar quantization with hysteresis, uniform on log scale
|
||||
/// </summary>
|
||||
/// <param name="ind">O gain indices [MAX_NB_SUBFR]</param>
|
||||
/// <param name="gain_Q16">I/O gains (quantized out) [MAX_NB_SUBFR]</param>
|
||||
/// <param name="prev_ind">I/O last index in previous frame. [Porting note] original implementation passed this as an int8*</param>
|
||||
/// <param name="conditional">I first gain is delta coded if 1</param>
|
||||
/// <param name="nb_subfr">I number of subframes</param>
|
||||
internal static void silk_gains_quant(
|
||||
sbyte[] ind,
|
||||
int[] gain_Q16,
|
||||
BoxedValueSbyte prev_ind,
|
||||
int conditional,
|
||||
int nb_subfr)
|
||||
{
|
||||
int k, double_step_size_threshold;
|
||||
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
// Debug.WriteLine("2a 0x{0:x}", (uint)gain_Q16[k]);
|
||||
/* Convert to log scale, scale, floor() */
|
||||
ind[k] = (sbyte)(Inlines.silk_SMULWB(SCALE_Q16, Inlines.silk_lin2log(gain_Q16[k]) - OFFSET));
|
||||
|
||||
/* Round towards previous quantized gain (hysteresis) */
|
||||
if (ind[k] < prev_ind.Val)
|
||||
{
|
||||
ind[k]++;
|
||||
}
|
||||
|
||||
ind[k] = (sbyte)(Inlines.silk_LIMIT_int(ind[k], 0, SilkConstants.N_LEVELS_QGAIN - 1));
|
||||
|
||||
/* Compute delta indices and limit */
|
||||
if (k == 0 && conditional == 0)
|
||||
{
|
||||
/* Full index */
|
||||
ind[k] = (sbyte)(Inlines.silk_LIMIT_int(ind[k], prev_ind.Val + SilkConstants.MIN_DELTA_GAIN_QUANT, SilkConstants.N_LEVELS_QGAIN - 1));
|
||||
prev_ind.Val = ind[k];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Delta index */
|
||||
ind[k] = (sbyte)(ind[k] - prev_ind.Val);
|
||||
|
||||
/* Double the quantization step size for large gain increases, so that the max gain level can be reached */
|
||||
double_step_size_threshold = 2 * SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.N_LEVELS_QGAIN + prev_ind.Val;
|
||||
if (ind[k] > double_step_size_threshold)
|
||||
{
|
||||
ind[k] = (sbyte)(double_step_size_threshold + Inlines.silk_RSHIFT(ind[k] - double_step_size_threshold + 1, 1));
|
||||
}
|
||||
|
||||
ind[k] = (sbyte)(Inlines.silk_LIMIT_int(ind[k], SilkConstants.MIN_DELTA_GAIN_QUANT, SilkConstants.MAX_DELTA_GAIN_QUANT));
|
||||
|
||||
/* Accumulate deltas */
|
||||
if (ind[k] > double_step_size_threshold)
|
||||
{
|
||||
prev_ind.Val += (sbyte)(Inlines.silk_LSHIFT(ind[k], 1) - double_step_size_threshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_ind.Val += ind[k];
|
||||
}
|
||||
|
||||
/* Shift to make non-negative */
|
||||
ind[k] -= SilkConstants.MIN_DELTA_GAIN_QUANT;
|
||||
// Debug.WriteLine("2b 0x{0:x}", (uint)ind[k]);
|
||||
}
|
||||
|
||||
/* Scale and convert to linear scale */
|
||||
gain_Q16[k] = Inlines.silk_log2lin(Inlines.silk_min_32(Inlines.silk_SMULWB(INV_SCALE_Q16, prev_ind.Val) + OFFSET, 3967)); /* 3967 = 31 in Q7 */
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gains scalar dequantization, uniform on log scale
|
||||
/// </summary>
|
||||
/// <param name="gain_Q16">O quantized gains [MAX_NB_SUBFR]</param>
|
||||
/// <param name="ind">I gain indices [MAX_NB_SUBFR]</param>
|
||||
/// <param name="prev_ind">I/O last index in previous frame [Porting note] original implementation passed this as an int8*</param>
|
||||
/// <param name="conditional">I first gain is delta coded if 1</param>
|
||||
/// <param name="nb_subfr">I number of subframes</param>
|
||||
internal static void silk_gains_dequant(
|
||||
int[] gain_Q16,
|
||||
sbyte[] ind,
|
||||
BoxedValueSbyte prev_ind,
|
||||
int conditional,
|
||||
int nb_subfr)
|
||||
{
|
||||
int k, ind_tmp, double_step_size_threshold;
|
||||
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
if (k == 0 && conditional == 0)
|
||||
{
|
||||
/* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */
|
||||
prev_ind.Val = (sbyte)(Inlines.silk_max_int(ind[k], prev_ind.Val - 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Delta index */
|
||||
ind_tmp = ind[k] + SilkConstants.MIN_DELTA_GAIN_QUANT;
|
||||
|
||||
/* Accumulate deltas */
|
||||
double_step_size_threshold = 2 * SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.N_LEVELS_QGAIN + prev_ind.Val;
|
||||
if (ind_tmp > double_step_size_threshold)
|
||||
{
|
||||
prev_ind.Val += (sbyte)(Inlines.silk_LSHIFT(ind_tmp, 1) - double_step_size_threshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_ind.Val += (sbyte)(ind_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
prev_ind.Val = (sbyte)(Inlines.silk_LIMIT_int(prev_ind.Val, 0, SilkConstants.N_LEVELS_QGAIN - 1));
|
||||
|
||||
/* Scale and convert to linear scale */
|
||||
gain_Q16[k] = Inlines.silk_log2lin(Inlines.silk_min_32(Inlines.silk_SMULWB(INV_SCALE_Q16, prev_ind.Val) + OFFSET, 3967)); /* 3967 = 31 in Q7 */
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute unique identifier of gain indices vector
|
||||
/// </summary>
|
||||
/// <param name="ind">I gain indices [MAX_NB_SUBFR]</param>
|
||||
/// <param name="nb_subfr">I number of subframes</param>
|
||||
/// <returns>unique identifier of gains</returns>
|
||||
internal static int silk_gains_ID(sbyte[] ind, int nb_subfr)
|
||||
{
|
||||
int k;
|
||||
int gainsID;
|
||||
|
||||
gainsID = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
gainsID = Inlines.silk_ADD_LSHIFT32(ind[k], gainsID, 8);
|
||||
}
|
||||
|
||||
return gainsID;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class HPVariableCutoff
|
||||
{
|
||||
/// <summary>
|
||||
/// High-pass filter with cutoff frequency adaptation based on pitch lag statistics
|
||||
/// </summary>
|
||||
/// <param name="state_Fxx">I/O Encoder states</param>
|
||||
internal static void silk_HP_variable_cutoff(SilkChannelEncoder[] state_Fxx)
|
||||
{
|
||||
int quality_Q15;
|
||||
int pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7;
|
||||
SilkChannelEncoder psEncC1 = state_Fxx[0];
|
||||
|
||||
/* Adaptive cutoff frequency: estimate low end of pitch frequency range */
|
||||
if (psEncC1.prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* difference, in log domain */
|
||||
pitch_freq_Hz_Q16 = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(Inlines.silk_MUL(psEncC1.fs_kHz, 1000), 16), psEncC1.prevLag);
|
||||
pitch_freq_log_Q7 = Inlines.silk_lin2log(pitch_freq_Hz_Q16) - (16 << 7);
|
||||
|
||||
/* adjustment based on quality */
|
||||
quality_Q15 = psEncC1.input_quality_bands_Q15[0];
|
||||
pitch_freq_log_Q7 = Inlines.silk_SMLAWB(pitch_freq_log_Q7, Inlines.silk_SMULWB(Inlines.silk_LSHIFT(-quality_Q15, 2), quality_Q15),
|
||||
pitch_freq_log_Q7 - (Inlines.silk_lin2log(((int)((TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ, 16)*/) - (16 << 7)));
|
||||
|
||||
/* delta_freq = pitch_freq_log - psEnc.variable_HP_smth1; */
|
||||
delta_freq_Q7 = pitch_freq_log_Q7 - Inlines.silk_RSHIFT(psEncC1.variable_HP_smth1_Q15, 8);
|
||||
if (delta_freq_Q7 < 0)
|
||||
{
|
||||
/* less smoothing for decreasing pitch frequency, to track something close to the minimum */
|
||||
delta_freq_Q7 = Inlines.silk_MUL(delta_freq_Q7, 3);
|
||||
}
|
||||
|
||||
/* limit delta, to reduce impact of outliers in pitch estimation */
|
||||
delta_freq_Q7 = Inlines.silk_LIMIT_32(
|
||||
delta_freq_Q7,
|
||||
0 - ((int)((TuningParameters.VARIABLE_HP_MAX_DELTA_FREQ) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_MAX_DELTA_FREQ, 7)*/,
|
||||
((int)((TuningParameters.VARIABLE_HP_MAX_DELTA_FREQ) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_MAX_DELTA_FREQ, 7)*/);
|
||||
|
||||
/* update smoother */
|
||||
psEncC1.variable_HP_smth1_Q15 = Inlines.silk_SMLAWB(psEncC1.variable_HP_smth1_Q15,
|
||||
Inlines.silk_SMULBB(psEncC1.speech_activity_Q8, delta_freq_Q7), ((int)((TuningParameters.VARIABLE_HP_SMTH_COEF1) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_SMTH_COEF1, 16)*/);
|
||||
|
||||
/* limit frequency range */
|
||||
psEncC1.variable_HP_smth1_Q15 = Inlines.silk_LIMIT_32(psEncC1.variable_HP_smth1_Q15,
|
||||
Inlines.silk_LSHIFT(Inlines.silk_lin2log(TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ), 8),
|
||||
Inlines.silk_LSHIFT(Inlines.silk_lin2log(TuningParameters.VARIABLE_HP_MAX_CUTOFF_HZ), 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class K2A
|
||||
{
|
||||
/* Step up function, converts reflection coefficients to prediction coefficients */
|
||||
internal static void silk_k2a(
|
||||
int[] A_Q24, /* O Prediction coefficients [order] Q24 */
|
||||
short[] rc_Q15, /* I Reflection coefficients [order] Q15 */
|
||||
int order /* I Prediction order */
|
||||
)
|
||||
{
|
||||
int k, n;
|
||||
int[] Atmp = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
|
||||
for (k = 0; k < order; k++)
|
||||
{
|
||||
for (n = 0; n < k; n++)
|
||||
{
|
||||
Atmp[n] = A_Q24[n];
|
||||
}
|
||||
for (n = 0; n < k; n++)
|
||||
{
|
||||
A_Q24[n] = Inlines.silk_SMLAWB(A_Q24[n], Inlines.silk_LSHIFT(Atmp[k - n - 1], 1), rc_Q15[k]);
|
||||
}
|
||||
A_Q24[k] = 0 - Inlines.silk_LSHIFT((int)rc_Q15[k], 9);
|
||||
}
|
||||
}
|
||||
|
||||
/* Step up function, converts reflection coefficients to prediction coefficients */
|
||||
internal static void silk_k2a_Q16(
|
||||
int[] A_Q24, /* O Prediction coefficients [order] Q24 */
|
||||
int[] rc_Q16, /* I Reflection coefficients [order] Q16 */
|
||||
int order /* I Prediction order */
|
||||
)
|
||||
{
|
||||
int k, n;
|
||||
int[] Atmp = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
|
||||
for (k = 0; k < order; k++)
|
||||
{
|
||||
for (n = 0; n < k; n++)
|
||||
{
|
||||
Atmp[n] = A_Q24[n];
|
||||
}
|
||||
for (n = 0; n < k; n++)
|
||||
{
|
||||
A_Q24[n] = Inlines.silk_SMLAWW(A_Q24[n], Atmp[k - n - 1], rc_Q16[k]);
|
||||
}
|
||||
A_Q24[k] = 0 - Inlines.silk_LSHIFT(rc_Q16[k], 8);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class LPCInversePredGain
|
||||
{
|
||||
private const float RC_THRESHOLD = 0.9999f;
|
||||
|
||||
private const int QA = 24;
|
||||
private static readonly int A_LIMIT = ((int)((0.99975f) * ((long)1 << (QA)) + 0.5))/*Inlines.SILK_CONST(0.99975f, QA)*/;
|
||||
|
||||
/* Compute inverse of LPC prediction gain, and */
|
||||
/* test if LPC coefficients are stable (all poles within unit circle) */
|
||||
internal static int LPC_inverse_pred_gain_QA( /* O Returns inverse prediction gain in energy domain, Q30 */
|
||||
int[][] A_QA, /* I Prediction coefficients [ 2 ][SILK_MAX_ORDER_LPC] */
|
||||
int order /* I Prediction order */
|
||||
)
|
||||
{
|
||||
int k, n, mult2Q;
|
||||
int invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
|
||||
int[] Aold_QA;
|
||||
int[] Anew_QA;
|
||||
|
||||
Anew_QA = A_QA[order & 1];
|
||||
|
||||
invGain_Q30 = (int)1 << 30;
|
||||
for (k = order - 1; k > 0; k--)
|
||||
{
|
||||
/* Check for stability */
|
||||
if ((Anew_QA[k] > A_LIMIT) || (Anew_QA[k] < -A_LIMIT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set RC equal to negated AR coef */
|
||||
rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[k], 31 - QA);
|
||||
|
||||
/* rc_mult1_Q30 range: [ 1 : 2^30 ] */
|
||||
rc_mult1_Q30 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
Inlines.OpusAssert(rc_mult1_Q30 > (1 << 15)); /* reduce A_LIMIT if fails */
|
||||
Inlines.OpusAssert(rc_mult1_Q30 <= (1 << 30));
|
||||
|
||||
/* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
|
||||
mult2Q = 32 - Inlines.silk_CLZ32(Inlines.silk_abs(rc_mult1_Q30));
|
||||
rc_mult2 = Inlines.silk_INVERSE32_varQ(rc_mult1_Q30, mult2Q + 30);
|
||||
|
||||
/* Update inverse gain */
|
||||
/* invGain_Q30 range: [ 0 : 2^30 ] */
|
||||
invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2);
|
||||
Inlines.OpusAssert(invGain_Q30 >= 0);
|
||||
Inlines.OpusAssert(invGain_Q30 <= (1 << 30));
|
||||
|
||||
/* Swap pointers */
|
||||
Aold_QA = Anew_QA;
|
||||
Anew_QA = A_QA[k & 1];
|
||||
|
||||
/* Update AR coefficient */
|
||||
for (n = 0; n < k; n++)
|
||||
{
|
||||
tmp_QA = Aold_QA[n] - Inlines.MUL32_FRAC_Q(Aold_QA[k - n - 1], rc_Q31, 31);
|
||||
Anew_QA[n] = Inlines.MUL32_FRAC_Q(tmp_QA, rc_mult2, mult2Q);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for stability */
|
||||
if ((Anew_QA[0] > A_LIMIT) || (Anew_QA[0] < -A_LIMIT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set RC equal to negated AR coef */
|
||||
rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[0], 31 - QA);
|
||||
|
||||
/* Range: [ 1 : 2^30 ] */
|
||||
rc_mult1_Q30 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
|
||||
/* Update inverse gain */
|
||||
/* Range: [ 0 : 2^30 ] */
|
||||
invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2);
|
||||
Inlines.OpusAssert(invGain_Q30 >= 0);
|
||||
Inlines.OpusAssert(invGain_Q30 <= 1 << 30);
|
||||
|
||||
return invGain_Q30;
|
||||
}
|
||||
|
||||
/* For input in Q12 domain */
|
||||
internal static int silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */
|
||||
short[] A_Q12, /* I Prediction coefficients, Q12 [order] */
|
||||
int order /* I Prediction order */
|
||||
)
|
||||
{
|
||||
int k;
|
||||
int[][] Atmp_QA = Arrays.InitTwoDimensionalArray<int>(2, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
int[] Anew_QA;
|
||||
int DC_resp = 0;
|
||||
|
||||
Anew_QA = Atmp_QA[order & 1];
|
||||
|
||||
/* Increase Q domain of the AR coefficients */
|
||||
for (k = 0; k < order; k++)
|
||||
{
|
||||
DC_resp += (int)A_Q12[k];
|
||||
Anew_QA[k] = Inlines.silk_LSHIFT32((int)A_Q12[k], QA - 12);
|
||||
}
|
||||
/* If the DC is unstable, we don't even need to do the full calculations */
|
||||
if (DC_resp >= 4096)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return LPC_inverse_pred_gain_QA(Atmp_QA, order);
|
||||
}
|
||||
|
||||
internal static int silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */
|
||||
int[] A_Q24, /* I Prediction coefficients [order] */
|
||||
int order /* I Prediction order */
|
||||
)
|
||||
{
|
||||
int k;
|
||||
int[][] Atmp_QA = Arrays.InitTwoDimensionalArray<int>(2, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
int[] Anew_QA;
|
||||
|
||||
Anew_QA = Atmp_QA[order & 1];
|
||||
|
||||
/* Increase Q domain of the AR coefficients */
|
||||
for (k = 0; k < order; k++)
|
||||
{
|
||||
Anew_QA[k] = Inlines.silk_RSHIFT32(A_Q24[k], 24 - QA);
|
||||
}
|
||||
|
||||
return LPC_inverse_pred_gain_QA(Atmp_QA, order);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class LTPAnalysisFilter
|
||||
{
|
||||
internal static void silk_LTP_analysis_filter(
|
||||
short[] LTP_res, /* O LTP residual signal of length SilkConstants.MAX_NB_SUBFR * ( pre_length + subfr_length ) */
|
||||
short[] x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */
|
||||
int x_ptr,
|
||||
short[] LTPCoef_Q14,/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe [SilkConstants.LTP_ORDER * SilkConstants.MAX_NB_SUBFR] */
|
||||
int[] pitchL, /* I Pitch lag, one for each subframe [SilkConstants.MAX_NB_SUBFR] */
|
||||
int[] invGains_Q16, /* I Inverse quantization gains, one for each subframe [SilkConstants.MAX_NB_SUBFR] */
|
||||
int subfr_length, /* I Length of each subframe */
|
||||
int nb_subfr, /* I Number of subframes */
|
||||
int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */
|
||||
)
|
||||
{
|
||||
int x_ptr2, x_lag_ptr;
|
||||
short[] Btmp_Q14 = new short[SilkConstants.LTP_ORDER];
|
||||
int LTP_res_ptr;
|
||||
int k, i;
|
||||
int LTP_est;
|
||||
|
||||
x_ptr2 = x_ptr;
|
||||
LTP_res_ptr = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
x_lag_ptr = x_ptr2 - pitchL[k];
|
||||
|
||||
Btmp_Q14[0] = LTPCoef_Q14[k * SilkConstants.LTP_ORDER];
|
||||
Btmp_Q14[1] = LTPCoef_Q14[k * SilkConstants.LTP_ORDER + 1];
|
||||
Btmp_Q14[2] = LTPCoef_Q14[k * SilkConstants.LTP_ORDER + 2];
|
||||
Btmp_Q14[3] = LTPCoef_Q14[k * SilkConstants.LTP_ORDER + 3];
|
||||
Btmp_Q14[4] = LTPCoef_Q14[k * SilkConstants.LTP_ORDER + 4];
|
||||
|
||||
/* LTP analysis FIR filter */
|
||||
for (i = 0; i < subfr_length + pre_length; i++)
|
||||
{
|
||||
int LTP_res_ptri = LTP_res_ptr + i;
|
||||
LTP_res[LTP_res_ptri] = x[x_ptr2 + i];
|
||||
|
||||
/* Long-term prediction */
|
||||
LTP_est = Inlines.silk_SMULBB(x[x_lag_ptr + SilkConstants.LTP_ORDER / 2], Btmp_Q14[0]);
|
||||
LTP_est = Inlines.silk_SMLABB_ovflw(LTP_est, x[x_lag_ptr + 1], Btmp_Q14[1]);
|
||||
LTP_est = Inlines.silk_SMLABB_ovflw(LTP_est, x[x_lag_ptr], Btmp_Q14[2]);
|
||||
LTP_est = Inlines.silk_SMLABB_ovflw(LTP_est, x[x_lag_ptr - 1], Btmp_Q14[3]);
|
||||
LTP_est = Inlines.silk_SMLABB_ovflw(LTP_est, x[x_lag_ptr - 2], Btmp_Q14[4]);
|
||||
|
||||
LTP_est = Inlines.silk_RSHIFT_ROUND(LTP_est, 14); /* round and . Q0*/
|
||||
|
||||
/* Subtract long-term prediction */
|
||||
LTP_res[LTP_res_ptri] = (short)Inlines.silk_SAT16((int)x[x_ptr2 + i] - LTP_est);
|
||||
|
||||
/* Scale residual */
|
||||
LTP_res[LTP_res_ptri] = (short)(Inlines.silk_SMULWB(invGains_Q16[k], LTP_res[LTP_res_ptri]));
|
||||
|
||||
x_lag_ptr++;
|
||||
}
|
||||
|
||||
/* Update pointers */
|
||||
LTP_res_ptr += subfr_length + pre_length;
|
||||
x_ptr2 += subfr_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class LTPScaleControl
|
||||
{
|
||||
/* Calculation of LTP state scaling */
|
||||
internal static void silk_LTP_scale_ctrl(
|
||||
SilkChannelEncoder psEnc, /* I/O encoder state */
|
||||
SilkEncoderControl psEncCtrl, /* I/O encoder control */
|
||||
int condCoding /* I The type of conditional coding to use */
|
||||
)
|
||||
{
|
||||
int round_loss;
|
||||
|
||||
if (condCoding == SilkConstants.CODE_INDEPENDENTLY)
|
||||
{
|
||||
/* Only scale if first frame in packet */
|
||||
round_loss = psEnc.PacketLoss_perc + psEnc.nFramesPerPacket;
|
||||
psEnc.indices.LTP_scaleIndex = (sbyte)Inlines.silk_LIMIT(
|
||||
Inlines.silk_SMULWB(Inlines.silk_SMULBB(round_loss, psEncCtrl.LTPredCodGain_Q7), ((int)((0.1f) * ((long)1 << (9)) + 0.5))/*Inlines.SILK_CONST(0.1f, 9)*/), 0, 2);
|
||||
}
|
||||
else {
|
||||
/* Default is minimum scaling */
|
||||
psEnc.indices.LTP_scaleIndex = 0;
|
||||
}
|
||||
psEncCtrl.LTP_scale_Q14 = Tables.silk_LTPScales_table_Q14[psEnc.indices.LTP_scaleIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class LinearAlgebra
|
||||
{
|
||||
/* Solves Ax = b, assuming A is symmetric */
|
||||
internal static void silk_solve_LDL(
|
||||
int[] A, /* I Pointer to symetric square matrix A */
|
||||
int A_ptr,
|
||||
int M, /* I Size of matrix */
|
||||
int[] b, /* I Pointer to b vector */
|
||||
int[] x_Q16 /* O Pointer to x solution vector */
|
||||
)
|
||||
{
|
||||
Inlines.OpusAssert(M <= SilkConstants.MAX_MATRIX_SIZE);
|
||||
int[] L_Q16 = new int[M * M];
|
||||
int[] Y = new int[SilkConstants.MAX_MATRIX_SIZE];
|
||||
|
||||
// [Porting note] This is an interleaved array. Formerly it was an array of data structures laid out thus:
|
||||
//private struct inv_D_t
|
||||
//{
|
||||
// int Q36_part;
|
||||
// int Q48_part;
|
||||
//}
|
||||
int[] inv_D = new int[SilkConstants.MAX_MATRIX_SIZE * 2];
|
||||
|
||||
/***************************************************
|
||||
Factorize A by LDL such that A = L*D*L',
|
||||
where L is lower triangular with ones on diagonal
|
||||
****************************************************/
|
||||
silk_LDL_factorize(A, A_ptr, M, L_Q16, inv_D);
|
||||
|
||||
/****************************************************
|
||||
* substitute D*L'*x = Y. ie:
|
||||
L*D*L'*x = b => L*Y = b <=> Y = inv(L)*b
|
||||
******************************************************/
|
||||
silk_LS_SolveFirst(L_Q16, M, b, Y);
|
||||
|
||||
/****************************************************
|
||||
D*L'*x = Y <=> L'*x = inv(D)*Y, because D is
|
||||
diagonal just multiply with 1/d_i
|
||||
****************************************************/
|
||||
silk_LS_divide_Q16(Y, inv_D, M);
|
||||
|
||||
/****************************************************
|
||||
x = inv(L') * inv(D) * Y
|
||||
*****************************************************/
|
||||
silk_LS_SolveLast(L_Q16, M, Y, x_Q16);
|
||||
|
||||
}
|
||||
|
||||
/* Factorize square matrix A into LDL form */
|
||||
private static void silk_LDL_factorize(
|
||||
int[] A, /* I/O Pointer to Symetric Square Matrix */
|
||||
int A_ptr,
|
||||
int M, /* I Size of Matrix */
|
||||
int[] L_Q16, /* I/O Pointer to Square Upper triangular Matrix */
|
||||
int[] inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */
|
||||
)
|
||||
{
|
||||
int i, j, k, status, loop_count;
|
||||
int[] scratch1;
|
||||
int scratch1_ptr;
|
||||
int[] scratch2;
|
||||
int scratch2_ptr;
|
||||
int diag_min_value, tmp_32, err;
|
||||
int[] v_Q0 = new int[M]; /*SilkConstants.MAX_MATRIX_SIZE*/
|
||||
int[] D_Q0 = new int[M]; /*SilkConstants.MAX_MATRIX_SIZE*/
|
||||
int one_div_diag_Q36, one_div_diag_Q40, one_div_diag_Q48;
|
||||
|
||||
Inlines.OpusAssert(M <= SilkConstants.MAX_MATRIX_SIZE);
|
||||
|
||||
status = 1;
|
||||
diag_min_value = Inlines.silk_max_32(Inlines.silk_SMMUL(Inlines.silk_ADD_SAT32(A[A_ptr], A[A_ptr + Inlines.silk_SMULBB(M, M) - 1]), ((int)((TuningParameters.FIND_LTP_COND_FAC) * ((long)1 << (31)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LTP_COND_FAC, 31)*/), 1 << 9);
|
||||
for (loop_count = 0; loop_count < M && status == 1; loop_count++)
|
||||
{
|
||||
status = 0;
|
||||
for (j = 0; j < M; j++)
|
||||
{
|
||||
scratch1 = L_Q16;
|
||||
scratch1_ptr = Inlines.MatrixGetPointer(j, 0, M);
|
||||
tmp_32 = 0;
|
||||
for (i = 0; i < j; i++)
|
||||
{
|
||||
v_Q0[i] = Inlines.silk_SMULWW(D_Q0[i], scratch1[scratch1_ptr + i]); /* Q0 */
|
||||
tmp_32 = Inlines.silk_SMLAWW(tmp_32, v_Q0[i], scratch1[scratch1_ptr + i]); /* Q0 */
|
||||
}
|
||||
tmp_32 = Inlines.silk_SUB32(Inlines.MatrixGet(A, A_ptr, j, j, M), tmp_32);
|
||||
|
||||
if (tmp_32 < diag_min_value)
|
||||
{
|
||||
tmp_32 = Inlines.silk_SUB32(Inlines.silk_SMULBB(loop_count + 1, diag_min_value), tmp_32);
|
||||
/* Matrix not positive semi-definite, or ill conditioned */
|
||||
for (i = 0; i < M; i++)
|
||||
{
|
||||
Inlines.MatrixSet(A, A_ptr, i, i, M, Inlines.silk_ADD32(Inlines.MatrixGet(A, A_ptr, i, i, M), tmp_32));
|
||||
}
|
||||
status = 1;
|
||||
break;
|
||||
}
|
||||
D_Q0[j] = tmp_32; /* always < max(Correlation) */
|
||||
|
||||
/* two-step division */
|
||||
one_div_diag_Q36 = Inlines.silk_INVERSE32_varQ(tmp_32, 36); /* Q36 */
|
||||
one_div_diag_Q40 = Inlines.silk_LSHIFT(one_div_diag_Q36, 4); /* Q40 */
|
||||
err = Inlines.silk_SUB32((int)1 << 24, Inlines.silk_SMULWW(tmp_32, one_div_diag_Q40)); /* Q24 */
|
||||
one_div_diag_Q48 = Inlines.silk_SMULWW(err, one_div_diag_Q40); /* Q48 */
|
||||
|
||||
/* Save 1/Ds */
|
||||
inv_D[(j * 2) + 0] = one_div_diag_Q36;
|
||||
inv_D[(j * 2) + 1] = one_div_diag_Q48;
|
||||
|
||||
Inlines.MatrixSet(L_Q16, j, j, M, 65536); /* 1.0 in Q16 */
|
||||
scratch1 = A;
|
||||
scratch1_ptr = Inlines.MatrixGetPointer(j, 0, M) + A_ptr;
|
||||
scratch2 = L_Q16;
|
||||
scratch2_ptr = Inlines.MatrixGetPointer(j + 1, 0, M);
|
||||
for (i = j + 1; i < M; i++)
|
||||
{
|
||||
tmp_32 = 0;
|
||||
for (k = 0; k < j; k++)
|
||||
{
|
||||
tmp_32 = Inlines.silk_SMLAWW(tmp_32, v_Q0[k], scratch2[scratch2_ptr + k]); /* Q0 */
|
||||
}
|
||||
tmp_32 = Inlines.silk_SUB32(scratch1[scratch1_ptr + i], tmp_32); /* always < max(Correlation) */
|
||||
|
||||
/* tmp_32 / D_Q0[j] : Divide to Q16 */
|
||||
Inlines.MatrixSet(L_Q16, i, j, M, Inlines.silk_ADD32(Inlines.silk_SMMUL(tmp_32, one_div_diag_Q48),
|
||||
Inlines.silk_RSHIFT(Inlines.silk_SMULWW(tmp_32, one_div_diag_Q36), 4)));
|
||||
|
||||
/* go to next column */
|
||||
scratch2_ptr += M;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(status == 0);
|
||||
}
|
||||
|
||||
private static void silk_LS_divide_Q16(
|
||||
int[] T, /* I/O Numenator vector */
|
||||
int[] inv_D, /* I 1 / D vector */
|
||||
int M /* I dimension */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int tmp_32;
|
||||
int one_div_diag_Q36, one_div_diag_Q48;
|
||||
|
||||
for (i = 0; i < M; i++)
|
||||
{
|
||||
one_div_diag_Q36 = inv_D[(i * 2) + 0];
|
||||
one_div_diag_Q48 = inv_D[(i * 2) + 1];
|
||||
|
||||
tmp_32 = T[i];
|
||||
T[i] = Inlines.silk_ADD32(Inlines.silk_SMMUL(tmp_32, one_div_diag_Q48), Inlines.silk_RSHIFT(Inlines.silk_SMULWW(tmp_32, one_div_diag_Q36), 4));
|
||||
}
|
||||
}
|
||||
|
||||
/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */
|
||||
private static void silk_LS_SolveFirst(
|
||||
int[] L_Q16, /* I Pointer to Lower Triangular Matrix */
|
||||
int M, /* I Dim of Matrix equation */
|
||||
int[] b, /* I b Vector */
|
||||
int[] x_Q16 /* O x Vector */
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
int ptr32;
|
||||
int tmp_32;
|
||||
|
||||
for (i = 0; i < M; i++)
|
||||
{
|
||||
ptr32 = Inlines.MatrixGetPointer(i, 0, M);
|
||||
tmp_32 = 0;
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
tmp_32 = Inlines.silk_SMLAWW(tmp_32, L_Q16[ptr32 + j], x_Q16[j]);
|
||||
}
|
||||
x_Q16[i] = Inlines.silk_SUB32(b[i], tmp_32);
|
||||
}
|
||||
}
|
||||
|
||||
/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */
|
||||
private static void silk_LS_SolveLast(
|
||||
int[] L_Q16, /* I Pointer to Lower Triangular Matrix */
|
||||
int M, /* I Dim of Matrix equation */
|
||||
int[] b, /* I b Vector */
|
||||
int[] x_Q16 /* O x Vector */
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
int ptr32;
|
||||
int tmp_32;
|
||||
|
||||
for (i = M - 1; i >= 0; i--)
|
||||
{
|
||||
ptr32 = Inlines.MatrixGetPointer(0, i, M);
|
||||
tmp_32 = 0;
|
||||
for (j = M - 1; j > i; j--)
|
||||
{
|
||||
tmp_32 = Inlines.silk_SMLAWW(tmp_32, L_Q16[ptr32 + Inlines.silk_SMULBB(j, M)], x_Q16[j]);
|
||||
}
|
||||
x_Q16[i] = Inlines.silk_SUB32(b[i], tmp_32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,498 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class NoiseShapeAnalysis
|
||||
{
|
||||
/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */
|
||||
/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
|
||||
/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
|
||||
/* coefficient in an array of coefficients, for monic filters. */
|
||||
internal static int warped_gain( /* gain in Q16*/
|
||||
int[] coefs_Q24,
|
||||
int lambda_Q16,
|
||||
int order
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int gain_Q24;
|
||||
|
||||
lambda_Q16 = -lambda_Q16;
|
||||
gain_Q24 = coefs_Q24[order - 1];
|
||||
for (i = order - 2; i >= 0; i--)
|
||||
{
|
||||
gain_Q24 = Inlines.silk_SMLAWB(coefs_Q24[i], gain_Q24, lambda_Q16);
|
||||
}
|
||||
gain_Q24 = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (24)) + 0.5))/*Inlines.SILK_CONST(1.0f, 24)*/, gain_Q24, -lambda_Q16);
|
||||
return Inlines.silk_INVERSE32_varQ(gain_Q24, 40);
|
||||
}
|
||||
|
||||
/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */
|
||||
/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
|
||||
internal static void limit_warped_coefs(
|
||||
int[] coefs_syn_Q24,
|
||||
int[] coefs_ana_Q24,
|
||||
int lambda_Q16,
|
||||
int limit_Q24,
|
||||
int order
|
||||
)
|
||||
{
|
||||
int i, iter, ind = 0;
|
||||
int tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16;
|
||||
int nom_Q16, den_Q24;
|
||||
|
||||
/* Convert to monic coefficients */
|
||||
lambda_Q16 = -lambda_Q16;
|
||||
for (i = order - 1; i > 0; i--)
|
||||
{
|
||||
coefs_syn_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16);
|
||||
coefs_ana_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16);
|
||||
}
|
||||
lambda_Q16 = -lambda_Q16;
|
||||
nom_Q16 = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f, 16)*/, -(int)lambda_Q16, lambda_Q16);
|
||||
den_Q24 = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (24)) + 0.5))/*Inlines.SILK_CONST(1.0f, 24)*/, coefs_syn_Q24[0], lambda_Q16);
|
||||
gain_syn_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
|
||||
den_Q24 = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (24)) + 0.5))/*Inlines.SILK_CONST(1.0f, 24)*/, coefs_ana_Q24[0], lambda_Q16);
|
||||
gain_ana_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
|
||||
for (i = 0; i < order; i++)
|
||||
{
|
||||
coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]);
|
||||
coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]);
|
||||
}
|
||||
|
||||
for (iter = 0; iter < 10; iter++)
|
||||
{
|
||||
/* Find maximum absolute value */
|
||||
maxabs_Q24 = -1;
|
||||
for (i = 0; i < order; i++)
|
||||
{
|
||||
tmp = Inlines.silk_max(Inlines.silk_abs_int32(coefs_syn_Q24[i]), Inlines.silk_abs_int32(coefs_ana_Q24[i]));
|
||||
if (tmp > maxabs_Q24)
|
||||
{
|
||||
maxabs_Q24 = tmp;
|
||||
ind = i;
|
||||
}
|
||||
}
|
||||
if (maxabs_Q24 <= limit_Q24)
|
||||
{
|
||||
/* Coefficients are within range - done */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert back to true warped coefficients */
|
||||
for (i = 1; i < order; i++)
|
||||
{
|
||||
coefs_syn_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16);
|
||||
coefs_ana_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16);
|
||||
}
|
||||
gain_syn_Q16 = Inlines.silk_INVERSE32_varQ(gain_syn_Q16, 32);
|
||||
gain_ana_Q16 = Inlines.silk_INVERSE32_varQ(gain_ana_Q16, 32);
|
||||
for (i = 0; i < order; i++)
|
||||
{
|
||||
coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]);
|
||||
coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]);
|
||||
}
|
||||
|
||||
/* Apply bandwidth expansion */
|
||||
chirp_Q16 = ((int)((0.99f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.99f, 16)*/ - Inlines.silk_DIV32_varQ(
|
||||
Inlines.silk_SMULWB(maxabs_Q24 - limit_Q24, Inlines.silk_SMLABB(((int)((0.8f) * ((long)1 << (10)) + 0.5))/*Inlines.SILK_CONST(0.8f, 10)*/, ((int)((0.1f) * ((long)1 << (10)) + 0.5))/*Inlines.SILK_CONST(0.1f, 10)*/, iter)),
|
||||
Inlines.silk_MUL(maxabs_Q24, ind + 1), 22);
|
||||
BWExpander.silk_bwexpander_32(coefs_syn_Q24, order, chirp_Q16);
|
||||
BWExpander.silk_bwexpander_32(coefs_ana_Q24, order, chirp_Q16);
|
||||
|
||||
/* Convert to monic warped coefficients */
|
||||
lambda_Q16 = -lambda_Q16;
|
||||
for (i = order - 1; i > 0; i--)
|
||||
{
|
||||
coefs_syn_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16);
|
||||
coefs_ana_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16);
|
||||
}
|
||||
lambda_Q16 = -lambda_Q16;
|
||||
nom_Q16 = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f, 16)*/, -(int)lambda_Q16, lambda_Q16);
|
||||
den_Q24 = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (24)) + 0.5))/*Inlines.SILK_CONST(1.0f, 24)*/, coefs_syn_Q24[0], lambda_Q16);
|
||||
gain_syn_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
|
||||
den_Q24 = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (24)) + 0.5))/*Inlines.SILK_CONST(1.0f, 24)*/, coefs_ana_Q24[0], lambda_Q16);
|
||||
gain_ana_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
|
||||
for (i = 0; i < order; i++)
|
||||
{
|
||||
coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]);
|
||||
coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]);
|
||||
}
|
||||
}
|
||||
Inlines.OpusAssert(false);
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
/* Compute noise shaping coefficients and initial gain values */
|
||||
/**************************************************************/
|
||||
internal static void silk_noise_shape_analysis(
|
||||
SilkChannelEncoder psEnc, /* I/O Encoder state FIX */
|
||||
SilkEncoderControl psEncCtrl, /* I/O Encoder control FIX */
|
||||
short[] pitch_res, /* I LPC residual from pitch analysis */
|
||||
int pitch_res_ptr,
|
||||
short[] x, /* I Input signal [ frame_length + la_shape ] */
|
||||
int x_ptr
|
||||
)
|
||||
{
|
||||
SilkShapeState psShapeSt = psEnc.sShape;
|
||||
int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0;
|
||||
int SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32;
|
||||
int nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
|
||||
int delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;
|
||||
int[] auto_corr = new int[SilkConstants.MAX_SHAPE_LPC_ORDER + 1];
|
||||
int[] refl_coef_Q16 = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
|
||||
int[] AR1_Q24 = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
|
||||
int[] AR2_Q24 = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
|
||||
short[] x_windowed;
|
||||
int pitch_res_ptr2;
|
||||
int x_ptr2;
|
||||
|
||||
/* Point to start of first LPC analysis block */
|
||||
x_ptr2 = x_ptr - psEnc.la_shape;
|
||||
|
||||
/****************/
|
||||
/* GAIN CONTROL */
|
||||
/****************/
|
||||
SNR_adj_dB_Q7 = psEnc.SNR_dB_Q7;
|
||||
|
||||
/* Input quality is the average of the quality in the lowest two VAD bands */
|
||||
psEncCtrl.input_quality_Q14 = (int)Inlines.silk_RSHIFT((int)psEnc.input_quality_bands_Q15[0]
|
||||
+ psEnc.input_quality_bands_Q15[1], 2);
|
||||
|
||||
/* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
|
||||
psEncCtrl.coding_quality_Q14 = Inlines.silk_RSHIFT(Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT_ROUND(SNR_adj_dB_Q7 -
|
||||
((int)((20.0f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(20.0f, 7)*/, 4)), 1);
|
||||
|
||||
/* Reduce coding SNR during low speech activity */
|
||||
if (psEnc.useCBR == 0)
|
||||
{
|
||||
b_Q8 = ((int)((1.0f) * ((long)1 << (8)) + 0.5))/*Inlines.SILK_CONST(1.0f, 8)*/ - psEnc.speech_activity_Q8;
|
||||
b_Q8 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(b_Q8, 8), b_Q8);
|
||||
SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7,
|
||||
Inlines.silk_SMULBB(((int)((0 - TuningParameters.BG_SNR_DECR_dB) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(0 - TuningParameters.BG_SNR_DECR_dB, 7)*/ >> (4 + 1), b_Q8), /* Q11*/
|
||||
Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1.0f, 14)*/ + psEncCtrl.input_quality_Q14, psEncCtrl.coding_quality_Q14)); /* Q12*/
|
||||
}
|
||||
|
||||
if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Reduce gains for periodic signals */
|
||||
SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7, ((int)((TuningParameters.HARM_SNR_INCR_dB) * ((long)1 << (8)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HARM_SNR_INCR_dB, 8)*/, psEnc.LTPCorr_Q15);
|
||||
}
|
||||
else {
|
||||
/* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
|
||||
SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7,
|
||||
Inlines.silk_SMLAWB(((int)((6.0f) * ((long)1 << (9)) + 0.5))/*Inlines.SILK_CONST(6.0f, 9)*/, -((int)((0.4f) * ((long)1 << (18)) + 0.5))/*Inlines.SILK_CONST(0.4f, 18)*/, psEnc.SNR_dB_Q7),
|
||||
((int)((1.0f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1.0f, 14)*/ - psEncCtrl.input_quality_Q14);
|
||||
}
|
||||
|
||||
/*************************/
|
||||
/* SPARSENESS PROCESSING */
|
||||
/*************************/
|
||||
/* Set quantizer offset */
|
||||
if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Initially set to 0; may be overruled in process_gains(..) */
|
||||
psEnc.indices.quantOffsetType = 0;
|
||||
psEncCtrl.sparseness_Q8 = 0;
|
||||
}
|
||||
else {
|
||||
/* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
|
||||
nSamples = Inlines.silk_LSHIFT(psEnc.fs_kHz, 1);
|
||||
energy_variation_Q7 = 0;
|
||||
log_energy_prev_Q7 = 0;
|
||||
pitch_res_ptr2 = pitch_res_ptr;
|
||||
for (k = 0; k < Inlines.silk_SMULBB(SilkConstants.SUB_FRAME_LENGTH_MS, psEnc.nb_subfr) / 2; k++)
|
||||
{
|
||||
SumSqrShift.silk_sum_sqr_shift(out nrg, out scale, pitch_res, pitch_res_ptr2, nSamples);
|
||||
nrg += Inlines.silk_RSHIFT(nSamples, scale); /* Q(-scale)*/
|
||||
|
||||
log_energy_Q7 = Inlines.silk_lin2log(nrg);
|
||||
if (k > 0)
|
||||
{
|
||||
energy_variation_Q7 += Inlines.silk_abs(log_energy_Q7 - log_energy_prev_Q7);
|
||||
}
|
||||
log_energy_prev_Q7 = log_energy_Q7;
|
||||
pitch_res_ptr2 += nSamples;
|
||||
}
|
||||
|
||||
psEncCtrl.sparseness_Q8 = Inlines.silk_RSHIFT(Sigmoid.silk_sigm_Q15(Inlines.silk_SMULWB(energy_variation_Q7 -
|
||||
((int)((5.0f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(5.0f, 7)*/, ((int)((0.1f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.1f, 16)*/)), 7);
|
||||
|
||||
/* Set quantization offset depending on sparseness measure */
|
||||
if (psEncCtrl.sparseness_Q8 > ((int)((TuningParameters.SPARSENESS_THRESHOLD_QNT_OFFSET) * ((long)1 << (8)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.SPARSENESS_THRESHOLD_QNT_OFFSET, 8)*/)
|
||||
{
|
||||
psEnc.indices.quantOffsetType = 0;
|
||||
}
|
||||
else {
|
||||
psEnc.indices.quantOffsetType = 1;
|
||||
}
|
||||
|
||||
/* Increase coding SNR for sparse signals */
|
||||
SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7, ((int)((TuningParameters.SPARSE_SNR_INCR_dB) * ((long)1 << (15)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.SPARSE_SNR_INCR_dB, 15)*/, psEncCtrl.sparseness_Q8 - ((int)((0.5f) * ((long)1 << (8)) + 0.5))/*Inlines.SILK_CONST(0.5f, 8)*/);
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
/* Control bandwidth expansion */
|
||||
/*******************************/
|
||||
/* More BWE for signals with high prediction gain */
|
||||
strength_Q16 = Inlines.silk_SMULWB(psEncCtrl.predGain_Q16, ((int)((TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION, 16)*/);
|
||||
BWExp1_Q16 = BWExp2_Q16 = Inlines.silk_DIV32_varQ(((int)((TuningParameters.BANDWIDTH_EXPANSION) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.BANDWIDTH_EXPANSION, 16)*/,
|
||||
Inlines.silk_SMLAWW(((int)((1.0f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f, 16)*/, strength_Q16, strength_Q16), 16);
|
||||
delta_Q16 = Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f, 16)*/ - Inlines.silk_SMULBB(3, psEncCtrl.coding_quality_Q14),
|
||||
((int)((TuningParameters.LOW_RATE_BANDWIDTH_EXPANSION_DELTA) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16)*/);
|
||||
BWExp1_Q16 = Inlines.silk_SUB32(BWExp1_Q16, delta_Q16);
|
||||
BWExp2_Q16 = Inlines.silk_ADD32(BWExp2_Q16, delta_Q16);
|
||||
/* BWExp1 will be applied after BWExp2, so make it relative */
|
||||
BWExp1_Q16 = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(BWExp1_Q16, 14), Inlines.silk_RSHIFT(BWExp2_Q16, 2));
|
||||
|
||||
if (psEnc.warping_Q16 > 0)
|
||||
{
|
||||
/* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
|
||||
warping_Q16 = Inlines.silk_SMLAWB(psEnc.warping_Q16, (int)psEncCtrl.coding_quality_Q14, ((int)((0.01f) * ((long)1 << (18)) + 0.5))/*Inlines.SILK_CONST(0.01f, 18)*/);
|
||||
}
|
||||
else {
|
||||
warping_Q16 = 0;
|
||||
}
|
||||
|
||||
/********************************************/
|
||||
/* Compute noise shaping AR coefs and gains */
|
||||
/********************************************/
|
||||
x_windowed = new short[psEnc.shapeWinLength];
|
||||
for (k = 0; k < psEnc.nb_subfr; k++)
|
||||
{
|
||||
/* Apply window: sine slope followed by flat part followed by cosine slope */
|
||||
int shift, slope_part, flat_part;
|
||||
flat_part = psEnc.fs_kHz * 3;
|
||||
slope_part = Inlines.silk_RSHIFT(psEnc.shapeWinLength - flat_part, 1);
|
||||
|
||||
ApplySineWindow.silk_apply_sine_window(x_windowed, 0, x, x_ptr2, 1, slope_part);
|
||||
shift = slope_part;
|
||||
Array.Copy(x, x_ptr2 + shift, x_windowed, shift, flat_part);
|
||||
shift += flat_part;
|
||||
ApplySineWindow.silk_apply_sine_window(x_windowed, shift, x, x_ptr2 + shift, 2, slope_part);
|
||||
|
||||
/* Update pointer: next LPC analysis block */
|
||||
x_ptr2 += psEnc.subfr_length;
|
||||
BoxedValueInt scale_boxed = new BoxedValueInt(scale);
|
||||
if (psEnc.warping_Q16 > 0)
|
||||
{
|
||||
/* Calculate warped auto correlation */
|
||||
Autocorrelation.silk_warped_autocorrelation(auto_corr, scale_boxed, x_windowed, warping_Q16, psEnc.shapeWinLength, psEnc.shapingLPCOrder);
|
||||
}
|
||||
else {
|
||||
/* Calculate regular auto correlation */
|
||||
Autocorrelation.silk_autocorr(auto_corr, scale_boxed, x_windowed, psEnc.shapeWinLength, psEnc.shapingLPCOrder + 1);
|
||||
}
|
||||
scale = scale_boxed.Val;
|
||||
|
||||
/* Add white noise, as a fraction of energy */
|
||||
auto_corr[0] = Inlines.silk_ADD32(auto_corr[0], Inlines.silk_max_32(Inlines.silk_SMULWB(Inlines.silk_RSHIFT(auto_corr[0], 4),
|
||||
((int)((TuningParameters.SHAPE_WHITE_NOISE_FRACTION) * ((long)1 << (20)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.SHAPE_WHITE_NOISE_FRACTION, 20)*/), 1));
|
||||
|
||||
/* Calculate the reflection coefficients using schur */
|
||||
nrg = Schur.silk_schur64(refl_coef_Q16, auto_corr, psEnc.shapingLPCOrder);
|
||||
Inlines.OpusAssert(nrg >= 0);
|
||||
|
||||
/* Convert reflection coefficients to prediction coefficients */
|
||||
K2A.silk_k2a_Q16(AR2_Q24, refl_coef_Q16, psEnc.shapingLPCOrder);
|
||||
|
||||
Qnrg = -scale; /* range: -12...30*/
|
||||
Inlines.OpusAssert(Qnrg >= -12);
|
||||
Inlines.OpusAssert(Qnrg <= 30);
|
||||
|
||||
/* Make sure that Qnrg is an even number */
|
||||
if ((Qnrg & 1) != 0)
|
||||
{
|
||||
Qnrg -= 1;
|
||||
nrg >>= 1;
|
||||
}
|
||||
|
||||
tmp32 = Inlines.silk_SQRT_APPROX(nrg);
|
||||
Qnrg >>= 1; /* range: -6...15*/
|
||||
|
||||
psEncCtrl.Gains_Q16[k] = Inlines.silk_LSHIFT_SAT32(tmp32, 16 - Qnrg);
|
||||
|
||||
if (psEnc.warping_Q16 > 0)
|
||||
{
|
||||
/* Adjust gain for warping */
|
||||
gain_mult_Q16 = warped_gain(AR2_Q24, warping_Q16, psEnc.shapingLPCOrder);
|
||||
Inlines.OpusAssert(psEncCtrl.Gains_Q16[k] >= 0);
|
||||
if (Inlines.silk_SMULWW(Inlines.silk_RSHIFT_ROUND(psEncCtrl.Gains_Q16[k], 1), gain_mult_Q16) >= (int.MaxValue >> 1))
|
||||
{
|
||||
psEncCtrl.Gains_Q16[k] = int.MaxValue;
|
||||
}
|
||||
else {
|
||||
psEncCtrl.Gains_Q16[k] = Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[k], gain_mult_Q16);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bandwidth expansion for synthesis filter shaping */
|
||||
BWExpander.silk_bwexpander_32(AR2_Q24, psEnc.shapingLPCOrder, BWExp2_Q16);
|
||||
|
||||
/* Compute noise shaping filter coefficients */
|
||||
Array.Copy(AR2_Q24, AR1_Q24, psEnc.shapingLPCOrder);
|
||||
|
||||
/* Bandwidth expansion for analysis filter shaping */
|
||||
Inlines.OpusAssert(BWExp1_Q16 <= ((int)((1.0f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f, 16)*/);
|
||||
BWExpander.silk_bwexpander_32(AR1_Q24, psEnc.shapingLPCOrder, BWExp1_Q16);
|
||||
|
||||
/* Ratio of prediction gains, in energy domain */
|
||||
pre_nrg_Q30 = LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(AR2_Q24, psEnc.shapingLPCOrder);
|
||||
nrg = LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(AR1_Q24, psEnc.shapingLPCOrder);
|
||||
|
||||
/*psEncCtrl.GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/
|
||||
pre_nrg_Q30 = Inlines.silk_LSHIFT32(Inlines.silk_SMULWB(pre_nrg_Q30, ((int)((0.7f) * ((long)1 << (15)) + 0.5))/*Inlines.SILK_CONST(0.7f, 15)*/), 1);
|
||||
psEncCtrl.GainsPre_Q14[k] = (int)((int)((0.3f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(0.3f, 14)*/ + Inlines.silk_DIV32_varQ(pre_nrg_Q30, nrg, 14);
|
||||
|
||||
/* Convert to monic warped prediction coefficients and limit absolute values */
|
||||
limit_warped_coefs(AR2_Q24, AR1_Q24, warping_Q16, ((int)((3.999f) * ((long)1 << (24)) + 0.5))/*Inlines.SILK_CONST(3.999f, 24)*/, psEnc.shapingLPCOrder);
|
||||
|
||||
/* Convert from Q24 to Q13 and store in int16 */
|
||||
for (i = 0; i < psEnc.shapingLPCOrder; i++)
|
||||
{
|
||||
psEncCtrl.AR1_Q13[k * SilkConstants.MAX_SHAPE_LPC_ORDER + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(AR1_Q24[i], 11));
|
||||
psEncCtrl.AR2_Q13[k * SilkConstants.MAX_SHAPE_LPC_ORDER + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(AR2_Q24[i], 11));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/* Gain tweaking */
|
||||
/*****************/
|
||||
/* Increase gains during low speech activity and put lower limit on gains */
|
||||
gain_mult_Q16 = Inlines.silk_log2lin(-Inlines.silk_SMLAWB(-((int)((16.0f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(16.0f, 7)*/, SNR_adj_dB_Q7, ((int)((0.16f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.16f, 16)*/));
|
||||
gain_add_Q16 = Inlines.silk_log2lin(Inlines.silk_SMLAWB(((int)((16.0f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(16.0f, 7)*/, ((int)((SilkConstants.MIN_QGAIN_DB) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.MIN_QGAIN_DB, 7)*/, ((int)((0.16f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.16f, 16)*/));
|
||||
Inlines.OpusAssert(gain_mult_Q16 > 0);
|
||||
for (k = 0; k < psEnc.nb_subfr; k++)
|
||||
{
|
||||
psEncCtrl.Gains_Q16[k] = Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[k], gain_mult_Q16);
|
||||
Inlines.OpusAssert(psEncCtrl.Gains_Q16[k] >= 0);
|
||||
psEncCtrl.Gains_Q16[k] = Inlines.silk_ADD_POS_SAT32(psEncCtrl.Gains_Q16[k], gain_add_Q16);
|
||||
}
|
||||
|
||||
gain_mult_Q16 = ((int)((1.0f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f, 16)*/ + Inlines.silk_RSHIFT_ROUND(Inlines.silk_MLA(((int)((TuningParameters.INPUT_TILT) * ((long)1 << (26)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.INPUT_TILT, 26)*/,
|
||||
psEncCtrl.coding_quality_Q14, ((int)((TuningParameters.HIGH_RATE_INPUT_TILT) * ((long)1 << (12)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HIGH_RATE_INPUT_TILT, 12)*/), 10);
|
||||
for (k = 0; k < psEnc.nb_subfr; k++)
|
||||
{
|
||||
psEncCtrl.GainsPre_Q14[k] = Inlines.silk_SMULWB(gain_mult_Q16, psEncCtrl.GainsPre_Q14[k]);
|
||||
}
|
||||
|
||||
/************************************************/
|
||||
/* Control low-frequency shaping and noise tilt */
|
||||
/************************************************/
|
||||
/* Less low frequency shaping for noisy inputs */
|
||||
strength_Q16 = Inlines.silk_MUL(((int)((TuningParameters.LOW_FREQ_SHAPING) * ((long)1 << (4)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LOW_FREQ_SHAPING, 4)*/, Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (12)) + 0.5))/*Inlines.SILK_CONST(1.0f, 12)*/,
|
||||
((int)((TuningParameters.LOW_QUALITY_LOW_FREQ_SHAPING_DECR) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13)*/, psEnc.input_quality_bands_Q15[0] - ((int)((1.0f) * ((long)1 << (15)) + 0.5))/*Inlines.SILK_CONST(1.0f, 15)*/));
|
||||
strength_Q16 = Inlines.silk_RSHIFT(Inlines.silk_MUL(strength_Q16, psEnc.speech_activity_Q8), 8);
|
||||
if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
|
||||
/*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
|
||||
int fs_kHz_inv = Inlines.silk_DIV32_16(((int)((0.2f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(0.2f, 14)*/, psEnc.fs_kHz);
|
||||
for (k = 0; k < psEnc.nb_subfr; k++)
|
||||
{
|
||||
b_Q14 = fs_kHz_inv + Inlines.silk_DIV32_16(((int)((3.0f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(3.0f, 14)*/, psEncCtrl.pitchL[k]);
|
||||
/* Pack two coefficients in one int32 */
|
||||
psEncCtrl.LF_shp_Q14[k] = Inlines.silk_LSHIFT(((int)((1.0f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1.0f, 14)*/ - b_Q14 - Inlines.silk_SMULWB(strength_Q16, b_Q14), 16);
|
||||
psEncCtrl.LF_shp_Q14[k] |= (b_Q14 - ((int)((1.0f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1.0f, 14)*/) & 0xFFFF; // opus bug: again, cast to ushort was done here where bitwise masking was intended
|
||||
}
|
||||
Inlines.OpusAssert(((int)((TuningParameters.HARM_HP_NOISE_COEF) * ((long)1 << (24)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HARM_HP_NOISE_COEF, 24)*/ < ((int)((0.5f) * ((long)1 << (24)) + 0.5))/*Inlines.SILK_CONST(0.5f, 24)*/); /* Guarantees that second argument to SMULWB() is within range of an short*/
|
||||
Tilt_Q16 = -((int)((TuningParameters.HP_NOISE_COEF) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HP_NOISE_COEF, 16)*/ -
|
||||
Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f, 16)*/ - ((int)((TuningParameters.HP_NOISE_COEF) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HP_NOISE_COEF, 16)*/,
|
||||
Inlines.silk_SMULWB(((int)((TuningParameters.HARM_HP_NOISE_COEF) * ((long)1 << (24)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HARM_HP_NOISE_COEF, 24)*/, psEnc.speech_activity_Q8));
|
||||
}
|
||||
else {
|
||||
b_Q14 = Inlines.silk_DIV32_16(21299, psEnc.fs_kHz); /* 1.3_Q0 = 21299_Q14*/
|
||||
/* Pack two coefficients in one int32 */
|
||||
psEncCtrl.LF_shp_Q14[0] = Inlines.silk_LSHIFT(((int)((1.0f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1.0f, 14)*/ - b_Q14 -
|
||||
Inlines.silk_SMULWB(strength_Q16, Inlines.silk_SMULWB(((int)((0.6f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.6f, 16)*/, b_Q14)), 16);
|
||||
psEncCtrl.LF_shp_Q14[0] |= (b_Q14 - ((int)((1.0f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1.0f, 14)*/) & 0xFFFF; // opus bug: cast to ushort is better expressed as a bitwise operator, otherwise runtime analysis might flag it as an overflow error
|
||||
for (k = 1; k < psEnc.nb_subfr; k++)
|
||||
{
|
||||
psEncCtrl.LF_shp_Q14[k] = psEncCtrl.LF_shp_Q14[0];
|
||||
}
|
||||
Tilt_Q16 = -((int)((TuningParameters.HP_NOISE_COEF) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HP_NOISE_COEF, 16)*/;
|
||||
}
|
||||
|
||||
/****************************/
|
||||
/* HARMONIC SHAPING CONTROL */
|
||||
/****************************/
|
||||
/* Control boosting of harmonic frequencies */
|
||||
HarmBoost_Q16 = Inlines.silk_SMULWB(Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (17)) + 0.5))/*Inlines.SILK_CONST(1.0f, 17)*/ - Inlines.silk_LSHIFT(psEncCtrl.coding_quality_Q14, 3),
|
||||
psEnc.LTPCorr_Q15), ((int)((TuningParameters.LOW_RATE_HARMONIC_BOOST) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LOW_RATE_HARMONIC_BOOST, 16)*/);
|
||||
|
||||
/* More harmonic boost for noisy input signals */
|
||||
HarmBoost_Q16 = Inlines.silk_SMLAWB(HarmBoost_Q16,
|
||||
((int)((1.0f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f, 16)*/ - Inlines.silk_LSHIFT(psEncCtrl.input_quality_Q14, 2), ((int)((TuningParameters.LOW_INPUT_QUALITY_HARMONIC_BOOST) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LOW_INPUT_QUALITY_HARMONIC_BOOST, 16)*/);
|
||||
|
||||
if (SilkConstants.USE_HARM_SHAPING != 0 && psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* More harmonic noise shaping for high bitrates or noisy input */
|
||||
HarmShapeGain_Q16 = Inlines.silk_SMLAWB(((int)((TuningParameters.HARMONIC_SHAPING) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HARMONIC_SHAPING, 16)*/,
|
||||
((int)((1.0f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f, 16)*/ - Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (18)) + 0.5))/*Inlines.SILK_CONST(1.0f, 18)*/ - Inlines.silk_LSHIFT(psEncCtrl.coding_quality_Q14, 4),
|
||||
psEncCtrl.input_quality_Q14), ((int)((TuningParameters.HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16)*/);
|
||||
|
||||
/* Less harmonic noise shaping for less periodic signals */
|
||||
HarmShapeGain_Q16 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(HarmShapeGain_Q16, 1),
|
||||
Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT(psEnc.LTPCorr_Q15, 15)));
|
||||
}
|
||||
else {
|
||||
HarmShapeGain_Q16 = 0;
|
||||
}
|
||||
|
||||
/*************************/
|
||||
/* Smooth over subframes */
|
||||
/*************************/
|
||||
for (k = 0; k < SilkConstants.MAX_NB_SUBFR; k++)
|
||||
{
|
||||
psShapeSt.HarmBoost_smth_Q16 =
|
||||
Inlines.silk_SMLAWB(psShapeSt.HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt.HarmBoost_smth_Q16, ((int)((TuningParameters.SUBFR_SMTH_COEF) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.SUBFR_SMTH_COEF, 16)*/);
|
||||
psShapeSt.HarmShapeGain_smth_Q16 =
|
||||
Inlines.silk_SMLAWB(psShapeSt.HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt.HarmShapeGain_smth_Q16, ((int)((TuningParameters.SUBFR_SMTH_COEF) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.SUBFR_SMTH_COEF, 16)*/);
|
||||
psShapeSt.Tilt_smth_Q16 =
|
||||
Inlines.silk_SMLAWB(psShapeSt.Tilt_smth_Q16, Tilt_Q16 - psShapeSt.Tilt_smth_Q16, ((int)((TuningParameters.SUBFR_SMTH_COEF) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.SUBFR_SMTH_COEF, 16)*/);
|
||||
|
||||
psEncCtrl.HarmBoost_Q14[k] = (int)Inlines.silk_RSHIFT_ROUND(psShapeSt.HarmBoost_smth_Q16, 2);
|
||||
psEncCtrl.HarmShapeGain_Q14[k] = (int)Inlines.silk_RSHIFT_ROUND(psShapeSt.HarmShapeGain_smth_Q16, 2);
|
||||
psEncCtrl.Tilt_Q14[k] = (int)Inlines.silk_RSHIFT_ROUND(psShapeSt.Tilt_smth_Q16, 2);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
/// <summary>
|
||||
/// Routines for managing packet loss concealment
|
||||
/// </summary>
|
||||
internal static class PLC
|
||||
{
|
||||
private const int NB_ATT = 2;
|
||||
private static readonly short[] HARM_ATT_Q15 = { 32440, 31130 }; /* 0.99, 0.95 */
|
||||
private static readonly short[] PLC_RAND_ATTENUATE_V_Q15 = { 31130, 26214 }; /* 0.95, 0.8 */
|
||||
private static readonly short[] PLC_RAND_ATTENUATE_UV_Q15 = { 32440, 29491 }; /* 0.99, 0.9 */
|
||||
|
||||
internal static void silk_PLC_Reset(
|
||||
SilkChannelDecoder psDec /* I/O Decoder state */
|
||||
)
|
||||
{
|
||||
psDec.sPLC.pitchL_Q8 = Inlines.silk_LSHIFT(psDec.frame_length, 8 - 1);
|
||||
psDec.sPLC.prevGain_Q16[0] = ((int)((1) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1, 16)*/;
|
||||
psDec.sPLC.prevGain_Q16[1] = ((int)((1) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1, 16)*/;
|
||||
psDec.sPLC.subfr_length = 20;
|
||||
psDec.sPLC.nb_subfr = 2;
|
||||
}
|
||||
|
||||
internal static void silk_PLC(
|
||||
SilkChannelDecoder psDec, /* I/O Decoder state */
|
||||
SilkDecoderControl psDecCtrl, /* I/O Decoder control */
|
||||
short[] frame, /* I/O signal */
|
||||
int frame_ptr,
|
||||
int lost /* I Loss flag */
|
||||
)
|
||||
{
|
||||
/* PLC control function */
|
||||
if (psDec.fs_kHz != psDec.sPLC.fs_kHz)
|
||||
{
|
||||
silk_PLC_Reset(psDec);
|
||||
psDec.sPLC.fs_kHz = psDec.fs_kHz;
|
||||
}
|
||||
|
||||
if (lost != 0)
|
||||
{
|
||||
/****************************/
|
||||
/* Generate Signal */
|
||||
/****************************/
|
||||
silk_PLC_conceal(psDec, psDecCtrl, frame, frame_ptr);
|
||||
|
||||
psDec.lossCnt++;
|
||||
}
|
||||
else {
|
||||
/****************************/
|
||||
/* Update state */
|
||||
/****************************/
|
||||
silk_PLC_update(psDec, psDecCtrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* Update state of PLC */
|
||||
/**************************************************/
|
||||
internal static void silk_PLC_update(
|
||||
SilkChannelDecoder psDec, /* I/O Decoder state */
|
||||
SilkDecoderControl psDecCtrl /* I/O Decoder control */
|
||||
)
|
||||
{
|
||||
int LTP_Gain_Q14, temp_LTP_Gain_Q14;
|
||||
int i, j;
|
||||
PLCStruct psPLC = psDec.sPLC; // [porting note] pointer on the stack
|
||||
|
||||
/* Update parameters used in case of packet loss */
|
||||
psDec.prevSignalType = psDec.indices.signalType;
|
||||
LTP_Gain_Q14 = 0;
|
||||
if (psDec.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Find the parameters for the last subframe which contains a pitch pulse */
|
||||
for (j = 0; j * psDec.subfr_length < psDecCtrl.pitchL[psDec.nb_subfr - 1]; j++)
|
||||
{
|
||||
if (j == psDec.nb_subfr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
temp_LTP_Gain_Q14 = 0;
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
temp_LTP_Gain_Q14 += psDecCtrl.LTPCoef_Q14[(psDec.nb_subfr - 1 - j) * SilkConstants.LTP_ORDER + i];
|
||||
}
|
||||
if (temp_LTP_Gain_Q14 > LTP_Gain_Q14)
|
||||
{
|
||||
LTP_Gain_Q14 = temp_LTP_Gain_Q14;
|
||||
|
||||
Array.Copy(psDecCtrl.LTPCoef_Q14, Inlines.silk_SMULBB(psDec.nb_subfr - 1 - j, SilkConstants.LTP_ORDER), psPLC.LTPCoef_Q14, 0, SilkConstants.LTP_ORDER);
|
||||
|
||||
psPLC.pitchL_Q8 = Inlines.silk_LSHIFT(psDecCtrl.pitchL[psDec.nb_subfr - 1 - j], 8);
|
||||
}
|
||||
}
|
||||
|
||||
Arrays.MemSetShort(psPLC.LTPCoef_Q14, 0, SilkConstants.LTP_ORDER);
|
||||
psPLC.LTPCoef_Q14[SilkConstants.LTP_ORDER / 2] = (short)(LTP_Gain_Q14);
|
||||
|
||||
/* Limit LT coefs */
|
||||
if (LTP_Gain_Q14 < SilkConstants.V_PITCH_GAIN_START_MIN_Q14)
|
||||
{
|
||||
int scale_Q10;
|
||||
int tmp;
|
||||
|
||||
tmp = Inlines.silk_LSHIFT(SilkConstants.V_PITCH_GAIN_START_MIN_Q14, 10);
|
||||
scale_Q10 = Inlines.silk_DIV32(tmp, Inlines.silk_max(LTP_Gain_Q14, 1));
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
psPLC.LTPCoef_Q14[i] = (short)(Inlines.silk_RSHIFT(Inlines.silk_SMULBB(psPLC.LTPCoef_Q14[i], scale_Q10), 10));
|
||||
}
|
||||
}
|
||||
else if (LTP_Gain_Q14 > SilkConstants.V_PITCH_GAIN_START_MAX_Q14)
|
||||
{
|
||||
int scale_Q14;
|
||||
int tmp;
|
||||
|
||||
tmp = Inlines.silk_LSHIFT(SilkConstants.V_PITCH_GAIN_START_MAX_Q14, 14);
|
||||
scale_Q14 = Inlines.silk_DIV32(tmp, Inlines.silk_max(LTP_Gain_Q14, 1));
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
psPLC.LTPCoef_Q14[i] = (short)(Inlines.silk_RSHIFT(Inlines.silk_SMULBB(psPLC.LTPCoef_Q14[i], scale_Q14), 14));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
psPLC.pitchL_Q8 = Inlines.silk_LSHIFT(Inlines.silk_SMULBB(psDec.fs_kHz, 18), 8);
|
||||
Arrays.MemSetShort(psPLC.LTPCoef_Q14, 0, SilkConstants.LTP_ORDER);
|
||||
}
|
||||
|
||||
/* Save LPC coeficients */
|
||||
Array.Copy(psDecCtrl.PredCoef_Q12[1], psPLC.prevLPC_Q12, psDec.LPC_order);
|
||||
psPLC.prevLTP_scale_Q14 = (short)(psDecCtrl.LTP_scale_Q14);
|
||||
|
||||
/* Save last two gains */
|
||||
Array.Copy(psDecCtrl.Gains_Q16, psDec.nb_subfr - 2, psPLC.prevGain_Q16, 0, 2);
|
||||
|
||||
psPLC.subfr_length = psDec.subfr_length;
|
||||
psPLC.nb_subfr = psDec.nb_subfr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="energy1">O</param>
|
||||
/// <param name="shift1">O</param>
|
||||
/// <param name="energy2">O</param>
|
||||
/// <param name="shift2">O</param>
|
||||
/// <param name="exc_Q14">I</param>
|
||||
/// <param name="prevGain_Q10">I</param>
|
||||
/// <param name="subfr_length">I</param>
|
||||
/// <param name="nb_subfr">I</param>
|
||||
internal static void silk_PLC_energy(
|
||||
out int energy1,
|
||||
out int shift1,
|
||||
out int energy2,
|
||||
out int shift2,
|
||||
int[] exc_Q14,
|
||||
int[] prevGain_Q10,
|
||||
int subfr_length,
|
||||
int nb_subfr)
|
||||
{
|
||||
int i, k;
|
||||
int exc_buf_ptr = 0;
|
||||
short[] exc_buf = new short[2 * subfr_length];
|
||||
|
||||
/* Find random noise component */
|
||||
/* Scale previous excitation signal */
|
||||
for (k = 0; k < 2; k++)
|
||||
{
|
||||
for (i = 0; i < subfr_length; i++)
|
||||
{
|
||||
exc_buf[exc_buf_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(
|
||||
Inlines.silk_SMULWW(exc_Q14[i + (k + nb_subfr - 2) * subfr_length], prevGain_Q10[k]), 8));
|
||||
}
|
||||
exc_buf_ptr += subfr_length;
|
||||
}
|
||||
|
||||
/* Find the subframe with lowest energy of the last two and use that as random noise generator */
|
||||
SumSqrShift.silk_sum_sqr_shift(out energy1, out shift1, exc_buf, subfr_length);
|
||||
SumSqrShift.silk_sum_sqr_shift(out energy2, out shift2, exc_buf, subfr_length, subfr_length);
|
||||
}
|
||||
|
||||
internal static void silk_PLC_conceal(
|
||||
SilkChannelDecoder psDec, /* I/O Decoder state */
|
||||
SilkDecoderControl psDecCtrl, /* I/O Decoder control */
|
||||
short[] frame, /* O LPC residual signal */
|
||||
int frame_ptr
|
||||
)
|
||||
{
|
||||
int i, j, k;
|
||||
int lag, idx, sLTP_buf_idx;
|
||||
int rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30;
|
||||
int energy1, energy2, shift1, shift2;
|
||||
int rand_ptr;
|
||||
int pred_lag_ptr;
|
||||
int LPC_pred_Q10, LTP_pred_Q12;
|
||||
short rand_scale_Q14;
|
||||
short[] B_Q14;
|
||||
int sLPC_Q14_ptr;
|
||||
short[] sLTP = new short[psDec.ltp_mem_length];
|
||||
int[] sLTP_Q14 = new int[psDec.ltp_mem_length + psDec.frame_length];
|
||||
PLCStruct psPLC = psDec.sPLC;
|
||||
int[] prevGain_Q10 = new int[2];
|
||||
|
||||
prevGain_Q10[0] = Inlines.silk_RSHIFT(psPLC.prevGain_Q16[0], 6);
|
||||
prevGain_Q10[1] = Inlines.silk_RSHIFT(psPLC.prevGain_Q16[1], 6);
|
||||
|
||||
if (psDec.first_frame_after_reset != 0)
|
||||
{
|
||||
Arrays.MemSetShort(psPLC.prevLPC_Q12, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
}
|
||||
|
||||
silk_PLC_energy(out energy1, out shift1, out energy2, out shift2, psDec.exc_Q14, prevGain_Q10, psDec.subfr_length, psDec.nb_subfr);
|
||||
|
||||
if (Inlines.silk_RSHIFT(energy1, shift2) < Inlines.silk_RSHIFT(energy2, shift1))
|
||||
{
|
||||
/* First sub-frame has lowest energy */
|
||||
rand_ptr = Inlines.silk_max_int(0, (psPLC.nb_subfr - 1) * psPLC.subfr_length - SilkConstants.RAND_BUF_SIZE);
|
||||
}
|
||||
else {
|
||||
/* Second sub-frame has lowest energy */
|
||||
rand_ptr = Inlines.silk_max_int(0, psPLC.nb_subfr * psPLC.subfr_length - SilkConstants.RAND_BUF_SIZE);
|
||||
}
|
||||
|
||||
/* Set up Gain to random noise component */
|
||||
B_Q14 = psPLC.LTPCoef_Q14;
|
||||
rand_scale_Q14 = psPLC.randScale_Q14;
|
||||
|
||||
/* Set up attenuation gains */
|
||||
harm_Gain_Q15 = HARM_ATT_Q15[Inlines.silk_min_int(NB_ATT - 1, psDec.lossCnt)];
|
||||
if (psDec.prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[Inlines.silk_min_int(NB_ATT - 1, psDec.lossCnt)];
|
||||
}
|
||||
else {
|
||||
rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[Inlines.silk_min_int(NB_ATT - 1, psDec.lossCnt)];
|
||||
}
|
||||
|
||||
/* LPC concealment. Apply BWE to previous LPC */
|
||||
BWExpander.silk_bwexpander(psPLC.prevLPC_Q12, psDec.LPC_order, ((int)((SilkConstants.BWE_COEF) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.BWE_COEF, 16)*/);
|
||||
|
||||
/* First Lost frame */
|
||||
if (psDec.lossCnt == 0)
|
||||
{
|
||||
rand_scale_Q14 = 1 << 14;
|
||||
|
||||
/* Reduce random noise Gain for voiced frames */
|
||||
if (psDec.prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
rand_scale_Q14 -= B_Q14[i];
|
||||
}
|
||||
rand_scale_Q14 = Inlines.silk_max_16(3277, rand_scale_Q14); /* 0.2 */
|
||||
rand_scale_Q14 = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(rand_scale_Q14, psPLC.prevLTP_scale_Q14), 14);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reduce random noise for unvoiced frames with high LPC gain */
|
||||
int invGain_Q30, down_scale_Q30;
|
||||
|
||||
invGain_Q30 = LPCInversePredGain.silk_LPC_inverse_pred_gain(psPLC.prevLPC_Q12, psDec.LPC_order);
|
||||
|
||||
down_scale_Q30 = Inlines.silk_min_32(Inlines.silk_RSHIFT((int)1 << 30, SilkConstants.LOG2_INV_LPC_GAIN_HIGH_THRES), invGain_Q30);
|
||||
down_scale_Q30 = Inlines.silk_max_32(Inlines.silk_RSHIFT((int)1 << 30, SilkConstants.LOG2_INV_LPC_GAIN_LOW_THRES), down_scale_Q30);
|
||||
down_scale_Q30 = Inlines.silk_LSHIFT(down_scale_Q30, SilkConstants.LOG2_INV_LPC_GAIN_HIGH_THRES);
|
||||
|
||||
rand_Gain_Q15 = Inlines.silk_RSHIFT(Inlines.silk_SMULWB(down_scale_Q30, rand_Gain_Q15), 14);
|
||||
}
|
||||
}
|
||||
|
||||
rand_seed = psPLC.rand_seed;
|
||||
lag = Inlines.silk_RSHIFT_ROUND(psPLC.pitchL_Q8, 8);
|
||||
sLTP_buf_idx = psDec.ltp_mem_length;
|
||||
|
||||
/* Rewhiten LTP state */
|
||||
idx = psDec.ltp_mem_length - lag - psDec.LPC_order - SilkConstants.LTP_ORDER / 2;
|
||||
Inlines.OpusAssert(idx > 0);
|
||||
Filters.silk_LPC_analysis_filter(sLTP, idx, psDec.outBuf, idx, psPLC.prevLPC_Q12, 0, psDec.ltp_mem_length - idx, psDec.LPC_order);
|
||||
/* Scale LTP state */
|
||||
inv_gain_Q30 = Inlines.silk_INVERSE32_varQ(psPLC.prevGain_Q16[1], 46);
|
||||
inv_gain_Q30 = Inlines.silk_min(inv_gain_Q30, int.MaxValue >> 1);
|
||||
for (i = idx + psDec.LPC_order; i < psDec.ltp_mem_length; i++)
|
||||
{
|
||||
sLTP_Q14[i] = Inlines.silk_SMULWB(inv_gain_Q30, sLTP[i]);
|
||||
}
|
||||
|
||||
/***************************/
|
||||
/* LTP synthesis filtering */
|
||||
/***************************/
|
||||
for (k = 0; k < psDec.nb_subfr; k++)
|
||||
{
|
||||
/* Set up pointer */
|
||||
pred_lag_ptr = sLTP_buf_idx - lag + SilkConstants.LTP_ORDER / 2;
|
||||
for (i = 0; i < psDec.subfr_length; i++)
|
||||
{
|
||||
/* Unrolled loop */
|
||||
/* Avoids introducing a bias because Inlines.silk_SMLAWB() always rounds to -inf */
|
||||
LTP_pred_Q12 = 2;
|
||||
LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr], B_Q14[0]);
|
||||
LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 1], B_Q14[1]);
|
||||
LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 2], B_Q14[2]);
|
||||
LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 3], B_Q14[3]);
|
||||
LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 4], B_Q14[4]);
|
||||
pred_lag_ptr++;
|
||||
|
||||
/* Generate LPC excitation */
|
||||
rand_seed = Inlines.silk_RAND(rand_seed);
|
||||
idx = Inlines.silk_RSHIFT(rand_seed, 25) & SilkConstants.RAND_BUF_MASK;
|
||||
sLTP_Q14[sLTP_buf_idx] = Inlines.silk_LSHIFT32(Inlines.silk_SMLAWB(LTP_pred_Q12, psDec.exc_Q14[rand_ptr + idx], rand_scale_Q14), 2);
|
||||
sLTP_buf_idx++;
|
||||
}
|
||||
|
||||
/* Gradually reduce LTP gain */
|
||||
for (j = 0; j < SilkConstants.LTP_ORDER; j++)
|
||||
{
|
||||
B_Q14[j] = (short)(Inlines.silk_RSHIFT(Inlines.silk_SMULBB(harm_Gain_Q15, B_Q14[j]), 15));
|
||||
}
|
||||
/* Gradually reduce excitation gain */
|
||||
rand_scale_Q14 = (short)(Inlines.silk_RSHIFT(Inlines.silk_SMULBB(rand_scale_Q14, rand_Gain_Q15), 15));
|
||||
|
||||
/* Slowly increase pitch lag */
|
||||
psPLC.pitchL_Q8 = Inlines.silk_SMLAWB(psPLC.pitchL_Q8, psPLC.pitchL_Q8, SilkConstants.PITCH_DRIFT_FAC_Q16);
|
||||
psPLC.pitchL_Q8 = Inlines.silk_min_32(psPLC.pitchL_Q8, Inlines.silk_LSHIFT(Inlines.silk_SMULBB(SilkConstants.MAX_PITCH_LAG_MS, psDec.fs_kHz), 8));
|
||||
lag = Inlines.silk_RSHIFT_ROUND(psPLC.pitchL_Q8, 8);
|
||||
}
|
||||
|
||||
/***************************/
|
||||
/* LPC synthesis filtering */
|
||||
/***************************/
|
||||
sLPC_Q14_ptr = psDec.ltp_mem_length - SilkConstants.MAX_LPC_ORDER;
|
||||
|
||||
/* Copy LPC state */
|
||||
Array.Copy(psDec.sLPC_Q14_buf, 0, sLTP_Q14, sLPC_Q14_ptr, SilkConstants.MAX_LPC_ORDER);
|
||||
|
||||
Inlines.OpusAssert(psDec.LPC_order >= 10); /* check that unrolling works */
|
||||
for (i = 0; i < psDec.frame_length; i++)
|
||||
{
|
||||
/* partly unrolled */
|
||||
int sLPCmaxi = sLPC_Q14_ptr + SilkConstants.MAX_LPC_ORDER + i;
|
||||
/* Avoids introducing a bias because Inlines.silk_SMLAWB() always rounds to -inf */
|
||||
LPC_pred_Q10 = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 1], psPLC.prevLPC_Q12[0]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 2], psPLC.prevLPC_Q12[1]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 3], psPLC.prevLPC_Q12[2]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 4], psPLC.prevLPC_Q12[3]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 5], psPLC.prevLPC_Q12[4]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 6], psPLC.prevLPC_Q12[5]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 7], psPLC.prevLPC_Q12[6]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 8], psPLC.prevLPC_Q12[7]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 9], psPLC.prevLPC_Q12[8]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 10], psPLC.prevLPC_Q12[9]);
|
||||
for (j = 10; j < psDec.LPC_order; j++)
|
||||
{
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - j - 1], psPLC.prevLPC_Q12[j]);
|
||||
}
|
||||
|
||||
/* Add prediction to LPC excitation */
|
||||
sLTP_Q14[sLPCmaxi] = Inlines.silk_ADD_LSHIFT32(sLTP_Q14[sLPCmaxi], LPC_pred_Q10, 4);
|
||||
|
||||
/* Scale with Gain */
|
||||
frame[frame_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(sLTP_Q14[sLPCmaxi], prevGain_Q10[1]), 8)));
|
||||
}
|
||||
|
||||
/* Save LPC state */
|
||||
Array.Copy(sLTP_Q14, sLPC_Q14_ptr + psDec.frame_length, psDec.sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
|
||||
/**************************************/
|
||||
/* Update states */
|
||||
/**************************************/
|
||||
psPLC.rand_seed = rand_seed;
|
||||
psPLC.randScale_Q14 = rand_scale_Q14;
|
||||
for (i = 0; i < SilkConstants.MAX_NB_SUBFR; i++)
|
||||
{
|
||||
psDecCtrl.pitchL[i] = lag;
|
||||
}
|
||||
}
|
||||
|
||||
/* Glues concealed frames with new good received frames */
|
||||
internal static void silk_PLC_glue_frames(
|
||||
SilkChannelDecoder psDec, /* I/O decoder state */
|
||||
short[] frame, /* I/O signal */
|
||||
int frame_ptr,
|
||||
int length /* I length of signal */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int energy_shift, energy;
|
||||
PLCStruct psPLC = psDec.sPLC;
|
||||
|
||||
if (psDec.lossCnt != 0)
|
||||
{
|
||||
/* Calculate energy in concealed residual */
|
||||
SumSqrShift.silk_sum_sqr_shift(out psPLC.conc_energy, out psPLC.conc_energy_shift, frame, frame_ptr, length);
|
||||
|
||||
psPLC.last_frame_lost = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (psDec.sPLC.last_frame_lost != 0)
|
||||
{
|
||||
/* Calculate residual in decoded signal if last frame was lost */
|
||||
SumSqrShift.silk_sum_sqr_shift(out energy, out energy_shift, frame, frame_ptr, length);
|
||||
|
||||
/* Normalize energies */
|
||||
if (energy_shift > psPLC.conc_energy_shift)
|
||||
{
|
||||
psPLC.conc_energy = Inlines.silk_RSHIFT(psPLC.conc_energy, energy_shift - psPLC.conc_energy_shift);
|
||||
}
|
||||
else if (energy_shift < psPLC.conc_energy_shift)
|
||||
{
|
||||
energy = Inlines.silk_RSHIFT(energy, psPLC.conc_energy_shift - energy_shift);
|
||||
}
|
||||
|
||||
/* Fade in the energy difference */
|
||||
if (energy > psPLC.conc_energy)
|
||||
{
|
||||
int frac_Q24, LZ;
|
||||
int gain_Q16, slope_Q16;
|
||||
|
||||
LZ = Inlines.silk_CLZ32(psPLC.conc_energy);
|
||||
LZ = LZ - 1;
|
||||
psPLC.conc_energy = Inlines.silk_LSHIFT(psPLC.conc_energy, LZ);
|
||||
energy = Inlines.silk_RSHIFT(energy, Inlines.silk_max_32(24 - LZ, 0));
|
||||
|
||||
frac_Q24 = Inlines.silk_DIV32(psPLC.conc_energy, Inlines.silk_max(energy, 1));
|
||||
|
||||
gain_Q16 = Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(frac_Q24), 4);
|
||||
slope_Q16 = Inlines.silk_DIV32_16(((int)1 << 16) - gain_Q16, length);
|
||||
/* Make slope 4x steeper to avoid missing onsets after DTX */
|
||||
slope_Q16 = Inlines.silk_LSHIFT(slope_Q16, 2);
|
||||
|
||||
for (i = frame_ptr; i < frame_ptr + length; i++)
|
||||
{
|
||||
frame[i] = (short)(Inlines.silk_SMULWB(gain_Q16, frame[i]));
|
||||
gain_Q16 += slope_Q16;
|
||||
if (gain_Q16 > (int)1 << 16)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
psPLC.last_frame_lost = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,792 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Celt;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class PitchAnalysisCore
|
||||
{
|
||||
private const int SCRATCH_SIZE = 22;
|
||||
private const int SF_LENGTH_4KHZ = (SilkConstants.PE_SUBFR_LENGTH_MS * 4);
|
||||
private const int SF_LENGTH_8KHZ = (SilkConstants.PE_SUBFR_LENGTH_MS * 8);
|
||||
private const int MIN_LAG_4KHZ = (SilkConstants.PE_MIN_LAG_MS * 4);
|
||||
private const int MIN_LAG_8KHZ = (SilkConstants.PE_MIN_LAG_MS * 8);
|
||||
private const int MAX_LAG_4KHZ = (SilkConstants.PE_MAX_LAG_MS * 4);
|
||||
private const int MAX_LAG_8KHZ = (SilkConstants.PE_MAX_LAG_MS * 8 - 1);
|
||||
private const int CSTRIDE_4KHZ = (MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ);
|
||||
private const int CSTRIDE_8KHZ = (MAX_LAG_8KHZ + 3 - (MIN_LAG_8KHZ - 2));
|
||||
private const int D_COMP_MIN = (MIN_LAG_8KHZ - 3);
|
||||
private const int D_COMP_MAX = (MAX_LAG_8KHZ + 4);
|
||||
private const int D_COMP_STRIDE = (D_COMP_MAX - D_COMP_MIN);
|
||||
|
||||
// typedef int silk_pe_stage3_vals[SilkConstants.PE_NB_STAGE3_LAGS];
|
||||
// fixme can I linearize this?
|
||||
private class silk_pe_stage3_vals
|
||||
{
|
||||
public readonly int[] Values = new int[SilkConstants.PE_NB_STAGE3_LAGS];
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */
|
||||
/*************************************************************/
|
||||
internal static int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */
|
||||
short[] frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
|
||||
int[] pitch_out, /* O 4 pitch lag values */
|
||||
BoxedValueShort lagIndex, /* O Lag Index */
|
||||
BoxedValueSbyte contourIndex, /* O Pitch contour Index */
|
||||
BoxedValueInt LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */
|
||||
int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
|
||||
int search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */
|
||||
int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */
|
||||
int Fs_kHz, /* I Sample frequency (kHz) */
|
||||
int complexity, /* I Complexity setting, 0-2, where 2 is highest */
|
||||
int nb_subfr /* I number of 5 ms subframes */
|
||||
)
|
||||
{
|
||||
short[] frame_8kHz;
|
||||
short[] frame_4kHz;
|
||||
int[] filt_state = new int[6];
|
||||
short[] input_frame_ptr;
|
||||
int i, k, d, j;
|
||||
short[] C;
|
||||
int[] xcorr32;
|
||||
short[] basis;
|
||||
int basis_ptr;
|
||||
short[] target;
|
||||
int target_ptr;
|
||||
int cross_corr, normalizer, energy, shift, energy_basis, energy_target;
|
||||
int Cmax, length_d_srch, length_d_comp;
|
||||
int[] d_srch = new int[SilkConstants.PE_D_SRCH_LENGTH];
|
||||
short[] d_comp;
|
||||
int sum, threshold, lag_counter;
|
||||
int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new;
|
||||
int CCmax, CCmax_b, CCmax_new_b, CCmax_new;
|
||||
int[] CC = new int[SilkConstants.PE_NB_CBKS_STAGE2_EXT];
|
||||
silk_pe_stage3_vals[] energies_st3;
|
||||
silk_pe_stage3_vals[] cross_corr_st3;
|
||||
int frame_length, frame_length_8kHz, frame_length_4kHz;
|
||||
int sf_length;
|
||||
int min_lag;
|
||||
int max_lag;
|
||||
int contour_bias_Q15, diff;
|
||||
int nb_cbk_search;
|
||||
int delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13;
|
||||
sbyte[][] Lag_CB_ptr;
|
||||
|
||||
/* Check for valid sampling frequency */
|
||||
Inlines.OpusAssert(Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16);
|
||||
|
||||
/* Check for valid complexity setting */
|
||||
Inlines.OpusAssert(complexity >= SilkConstants.SILK_PE_MIN_COMPLEX);
|
||||
Inlines.OpusAssert(complexity <= SilkConstants.SILK_PE_MAX_COMPLEX);
|
||||
|
||||
Inlines.OpusAssert(search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1 << 16));
|
||||
Inlines.OpusAssert(search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1 << 13));
|
||||
|
||||
/* Set up frame lengths max / min lag for the sampling frequency */
|
||||
frame_length = (SilkConstants.PE_LTP_MEM_LENGTH_MS + nb_subfr * SilkConstants.PE_SUBFR_LENGTH_MS) * Fs_kHz;
|
||||
frame_length_4kHz = (SilkConstants.PE_LTP_MEM_LENGTH_MS + nb_subfr * SilkConstants.PE_SUBFR_LENGTH_MS) * 4;
|
||||
frame_length_8kHz = (SilkConstants.PE_LTP_MEM_LENGTH_MS + nb_subfr * SilkConstants.PE_SUBFR_LENGTH_MS) * 8;
|
||||
sf_length = SilkConstants.PE_SUBFR_LENGTH_MS * Fs_kHz;
|
||||
min_lag = SilkConstants.PE_MIN_LAG_MS * Fs_kHz;
|
||||
max_lag = SilkConstants.PE_MAX_LAG_MS * Fs_kHz - 1;
|
||||
|
||||
/* Resample from input sampled at Fs_kHz to 8 kHz */
|
||||
frame_8kHz = new short[frame_length_8kHz];
|
||||
if (Fs_kHz == 16)
|
||||
{
|
||||
Arrays.MemSetInt(filt_state, 0, 2);
|
||||
Resampler.silk_resampler_down2(filt_state, frame_8kHz, frame, frame_length);
|
||||
}
|
||||
else if (Fs_kHz == 12)
|
||||
{
|
||||
Arrays.MemSetInt(filt_state, 0, 6);
|
||||
Resampler.silk_resampler_down2_3(filt_state, frame_8kHz, frame, frame_length);
|
||||
}
|
||||
else {
|
||||
Inlines.OpusAssert(Fs_kHz == 8);
|
||||
Array.Copy(frame, frame_8kHz, frame_length_8kHz);
|
||||
}
|
||||
|
||||
/* Decimate again to 4 kHz */
|
||||
Arrays.MemSetInt(filt_state, 0, 2); /* Set state to zero */
|
||||
frame_4kHz = new short[frame_length_4kHz];
|
||||
Resampler.silk_resampler_down2(filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz);
|
||||
|
||||
/* Low-pass filter */
|
||||
for (i = frame_length_4kHz - 1; i > 0; i--)
|
||||
{
|
||||
frame_4kHz[i] = Inlines.silk_ADD_SAT16(frame_4kHz[i], frame_4kHz[i - 1]);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Scale 4 kHz signal down to prevent correlations measures from overflowing
|
||||
** find scaling as max scaling for each 8kHz(?) subframe
|
||||
*******************************************************************************/
|
||||
|
||||
/* Inner product is calculated with different lengths, so scale for the worst case */
|
||||
SumSqrShift.silk_sum_sqr_shift(out energy, out shift, frame_4kHz, frame_length_4kHz);
|
||||
if (shift > 0)
|
||||
{
|
||||
shift = Inlines.silk_RSHIFT(shift, 1);
|
||||
for (i = 0; i < frame_length_4kHz; i++)
|
||||
{
|
||||
frame_4kHz[i] = Inlines.silk_RSHIFT16(frame_4kHz[i], shift);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FIRST STAGE, operating in 4 khz
|
||||
******************************************************************************/
|
||||
C = new short[nb_subfr * CSTRIDE_8KHZ];
|
||||
xcorr32 = new int[MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1];
|
||||
Arrays.MemSetShort(C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ);
|
||||
target = frame_4kHz;
|
||||
target_ptr = Inlines.silk_LSHIFT(SF_LENGTH_4KHZ, 2);
|
||||
for (k = 0; k < nb_subfr >> 1; k++)
|
||||
{
|
||||
basis = target;
|
||||
basis_ptr = target_ptr - MIN_LAG_4KHZ;
|
||||
|
||||
CeltPitchXCorr.pitch_xcorr(target, target_ptr, target, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1);
|
||||
|
||||
/* Calculate first vector products before loop */
|
||||
cross_corr = xcorr32[MAX_LAG_4KHZ - MIN_LAG_4KHZ];
|
||||
normalizer = Inlines.silk_inner_prod_self(target, target_ptr, SF_LENGTH_8KHZ);
|
||||
normalizer = Inlines.silk_ADD32(normalizer, Inlines.silk_inner_prod_self(basis, basis_ptr, SF_LENGTH_8KHZ));
|
||||
normalizer = Inlines.silk_ADD32(normalizer, Inlines.silk_SMULBB(SF_LENGTH_8KHZ, 4000));
|
||||
|
||||
Inlines.MatrixSet(C, k, 0, CSTRIDE_4KHZ,
|
||||
(short)Inlines.silk_DIV32_varQ(cross_corr, normalizer, 13 + 1)); /* Q13 */
|
||||
|
||||
/* From now on normalizer is computed recursively */
|
||||
for (d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++)
|
||||
{
|
||||
basis_ptr--;
|
||||
|
||||
cross_corr = xcorr32[MAX_LAG_4KHZ - d];
|
||||
|
||||
/* Add contribution of new sample and remove contribution from oldest sample */
|
||||
normalizer = Inlines.silk_ADD32(normalizer,
|
||||
Inlines.silk_SMULBB(basis[basis_ptr], basis[basis_ptr]) -
|
||||
Inlines.silk_SMULBB(basis[basis_ptr + SF_LENGTH_8KHZ], basis[basis_ptr + SF_LENGTH_8KHZ]));
|
||||
|
||||
Inlines.MatrixSet(C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ,
|
||||
(short)Inlines.silk_DIV32_varQ(cross_corr, normalizer, 13 + 1)); /* Q13 */
|
||||
}
|
||||
/* Update target pointer */
|
||||
target_ptr += SF_LENGTH_8KHZ;
|
||||
}
|
||||
|
||||
/* Combine two subframes into single correlation measure and apply short-lag bias */
|
||||
if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR)
|
||||
{
|
||||
for (i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i--)
|
||||
{
|
||||
sum = (int)Inlines.MatrixGet(C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ)
|
||||
+ (int)Inlines.MatrixGet(C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ); /* Q14 */
|
||||
sum = Inlines.silk_SMLAWB(sum, sum, Inlines.silk_LSHIFT(-i, 4)); /* Q14 */
|
||||
C[i - MIN_LAG_4KHZ] = (short)sum; /* Q14 */
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Only short-lag bias */
|
||||
for (i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i--)
|
||||
{
|
||||
sum = Inlines.silk_LSHIFT((int)C[i - MIN_LAG_4KHZ], 1); /* Q14 */
|
||||
sum = Inlines.silk_SMLAWB(sum, sum, Inlines.silk_LSHIFT(-i, 4)); /* Q14 */
|
||||
C[i - MIN_LAG_4KHZ] = (short)sum; /* Q14 */
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort */
|
||||
length_d_srch = Inlines.silk_ADD_LSHIFT32(4, complexity, 1);
|
||||
Inlines.OpusAssert(3 * length_d_srch <= SilkConstants.PE_D_SRCH_LENGTH);
|
||||
Sort.silk_insertion_sort_decreasing_int16(C, d_srch, CSTRIDE_4KHZ, length_d_srch);
|
||||
|
||||
/* Escape if correlation is very low already here */
|
||||
Cmax = (int)C[0]; /* Q14 */
|
||||
if (Cmax < ((int)((0.2f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(0.2f, 14)*/)
|
||||
{
|
||||
Arrays.MemSetInt(pitch_out, 0, nb_subfr);
|
||||
LTPCorr_Q15.Val = 0;
|
||||
lagIndex.Val = 0;
|
||||
contourIndex.Val = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
threshold = Inlines.silk_SMULWB(search_thres1_Q16, Cmax);
|
||||
for (i = 0; i < length_d_srch; i++)
|
||||
{
|
||||
/* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
|
||||
if (C[i] > threshold)
|
||||
{
|
||||
d_srch[i] = Inlines.silk_LSHIFT(d_srch[i] + MIN_LAG_4KHZ, 1);
|
||||
}
|
||||
else {
|
||||
length_d_srch = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Inlines.OpusAssert(length_d_srch > 0);
|
||||
|
||||
d_comp = new short[D_COMP_STRIDE];
|
||||
for (i = D_COMP_MIN; i < D_COMP_MAX; i++)
|
||||
{
|
||||
d_comp[i - D_COMP_MIN] = 0;
|
||||
}
|
||||
for (i = 0; i < length_d_srch; i++)
|
||||
{
|
||||
d_comp[d_srch[i] - D_COMP_MIN] = 1;
|
||||
}
|
||||
|
||||
/* Convolution */
|
||||
for (i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i--)
|
||||
{
|
||||
d_comp[i - D_COMP_MIN] += (short)(d_comp[i - 1 - D_COMP_MIN] + d_comp[i - 2 - D_COMP_MIN]);
|
||||
}
|
||||
|
||||
length_d_srch = 0;
|
||||
for (i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++)
|
||||
{
|
||||
if (d_comp[i + 1 - D_COMP_MIN] > 0)
|
||||
{
|
||||
d_srch[length_d_srch] = i;
|
||||
length_d_srch++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convolution */
|
||||
for (i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i--)
|
||||
{
|
||||
d_comp[i - D_COMP_MIN] += (short)(d_comp[i - 1 - D_COMP_MIN] + d_comp[i - 2 - D_COMP_MIN] + d_comp[i - 3 - D_COMP_MIN]);
|
||||
}
|
||||
|
||||
length_d_comp = 0;
|
||||
for (i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++)
|
||||
{
|
||||
if (d_comp[i - D_COMP_MIN] > 0)
|
||||
{
|
||||
d_comp[length_d_comp] = (short)(i - 2);
|
||||
length_d_comp++;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************************
|
||||
** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
|
||||
*************************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
** Scale signal down to avoid correlations measures from overflowing
|
||||
*******************************************************************************/
|
||||
/* find scaling as max scaling for each subframe */
|
||||
SumSqrShift.silk_sum_sqr_shift(out energy, out shift, frame_8kHz, frame_length_8kHz);
|
||||
if (shift > 0)
|
||||
{
|
||||
shift = Inlines.silk_RSHIFT(shift, 1);
|
||||
for (i = 0; i < frame_length_8kHz; i++)
|
||||
{
|
||||
frame_8kHz[i] = Inlines.silk_RSHIFT16(frame_8kHz[i], shift);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
* Find energy of each subframe projected onto its history, for a range of delays
|
||||
*********************************************************************************/
|
||||
Arrays.MemSetShort(C, 0, nb_subfr * CSTRIDE_8KHZ );
|
||||
|
||||
target = frame_8kHz;
|
||||
target_ptr = SilkConstants.PE_LTP_MEM_LENGTH_MS * 8;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
|
||||
energy_target = Inlines.silk_ADD32(Inlines.silk_inner_prod(target, target_ptr, target, target_ptr, SF_LENGTH_8KHZ), 1);
|
||||
for (j = 0; j < length_d_comp; j++)
|
||||
{
|
||||
d = d_comp[j];
|
||||
basis = target;
|
||||
basis_ptr = target_ptr - d;
|
||||
|
||||
cross_corr = Inlines.silk_inner_prod(target, target_ptr, basis, basis_ptr, SF_LENGTH_8KHZ);
|
||||
if (cross_corr > 0)
|
||||
{
|
||||
energy_basis = Inlines.silk_inner_prod_self(basis, basis_ptr, SF_LENGTH_8KHZ);
|
||||
Inlines.MatrixSet(C, k, d - (MIN_LAG_8KHZ - 2), CSTRIDE_8KHZ,
|
||||
(short)Inlines.silk_DIV32_varQ(cross_corr,
|
||||
Inlines.silk_ADD32(energy_target,
|
||||
energy_basis),
|
||||
13 + 1)); /* Q13 */
|
||||
}
|
||||
else {
|
||||
Inlines.MatrixSet<short>(C, k, d - (MIN_LAG_8KHZ - 2), CSTRIDE_8KHZ, 0);
|
||||
}
|
||||
}
|
||||
target_ptr += SF_LENGTH_8KHZ;
|
||||
}
|
||||
|
||||
/* search over lag range and lags codebook */
|
||||
/* scale factor for lag codebook, as a function of center lag */
|
||||
|
||||
CCmax = int.MinValue;
|
||||
CCmax_b = int.MinValue;
|
||||
|
||||
CBimax = 0; /* To avoid returning undefined lag values */
|
||||
lag = -1; /* To check if lag with strong enough correlation has been found */
|
||||
|
||||
if (prevLag > 0)
|
||||
{
|
||||
if (Fs_kHz == 12)
|
||||
{
|
||||
prevLag = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(prevLag, 1), 3);
|
||||
}
|
||||
else if (Fs_kHz == 16)
|
||||
{
|
||||
prevLag = Inlines.silk_RSHIFT(prevLag, 1);
|
||||
}
|
||||
prevLag_log2_Q7 = Inlines.silk_lin2log((int)prevLag);
|
||||
}
|
||||
else {
|
||||
prevLag_log2_Q7 = 0;
|
||||
}
|
||||
Inlines.OpusAssert(search_thres2_Q13 == Inlines.silk_SAT16(search_thres2_Q13));
|
||||
/* Set up stage 2 codebook based on number of subframes */
|
||||
if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR)
|
||||
{
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage2;
|
||||
if (Fs_kHz == 8 && complexity > SilkConstants.SILK_PE_MIN_COMPLEX)
|
||||
{
|
||||
/* If input is 8 khz use a larger codebook here because it is last stage */
|
||||
nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE2_EXT;
|
||||
}
|
||||
else {
|
||||
nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage2_10_ms;
|
||||
nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE2_10MS;
|
||||
}
|
||||
|
||||
for (k = 0; k < length_d_srch; k++)
|
||||
{
|
||||
d = d_srch[k];
|
||||
for (j = 0; j < nb_cbk_search; j++)
|
||||
{
|
||||
CC[j] = 0;
|
||||
for (i = 0; i < nb_subfr; i++)
|
||||
{
|
||||
int d_subfr;
|
||||
/* Try all codebooks */
|
||||
d_subfr = d + Lag_CB_ptr[i][j];
|
||||
CC[j] = CC[j]
|
||||
+ (int)Inlines.MatrixGet(C, i,
|
||||
d_subfr - (MIN_LAG_8KHZ - 2),
|
||||
CSTRIDE_8KHZ);
|
||||
}
|
||||
}
|
||||
/* Find best codebook */
|
||||
CCmax_new = int.MinValue;
|
||||
CBimax_new = 0;
|
||||
for (i = 0; i < nb_cbk_search; i++)
|
||||
{
|
||||
if (CC[i] > CCmax_new)
|
||||
{
|
||||
CCmax_new = CC[i];
|
||||
CBimax_new = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bias towards shorter lags */
|
||||
lag_log2_Q7 = Inlines.silk_lin2log(d); /* Q7 */
|
||||
Inlines.OpusAssert(lag_log2_Q7 == Inlines.silk_SAT16(lag_log2_Q7));
|
||||
Inlines.OpusAssert(nb_subfr * ((int)((SilkConstants.PE_SHORTLAG_BIAS) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.PE_SHORTLAG_BIAS, 13)*/ == Inlines.silk_SAT16(nb_subfr * ((int)((SilkConstants.PE_SHORTLAG_BIAS) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.PE_SHORTLAG_BIAS, 13)*/));
|
||||
CCmax_new_b = CCmax_new - Inlines.silk_RSHIFT(Inlines.silk_SMULBB(nb_subfr * ((int)((SilkConstants.PE_SHORTLAG_BIAS) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.PE_SHORTLAG_BIAS, 13)*/, lag_log2_Q7), 7); /* Q13 */
|
||||
|
||||
/* Bias towards previous lag */
|
||||
Inlines.OpusAssert(nb_subfr * ((int)((SilkConstants.PE_PREVLAG_BIAS) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.PE_PREVLAG_BIAS, 13)*/ == Inlines.silk_SAT16(nb_subfr * ((int)((SilkConstants.PE_PREVLAG_BIAS) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.PE_PREVLAG_BIAS, 13)*/));
|
||||
if (prevLag > 0)
|
||||
{
|
||||
delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7;
|
||||
Inlines.OpusAssert(delta_lag_log2_sqr_Q7 == Inlines.silk_SAT16(delta_lag_log2_sqr_Q7));
|
||||
delta_lag_log2_sqr_Q7 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7), 7);
|
||||
prev_lag_bias_Q13 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(nb_subfr * ((int)((SilkConstants.PE_PREVLAG_BIAS) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.PE_PREVLAG_BIAS, 13)*/, LTPCorr_Q15.Val), 15); /* Q13 */
|
||||
prev_lag_bias_Q13 = Inlines.silk_DIV32(Inlines.silk_MUL(prev_lag_bias_Q13, delta_lag_log2_sqr_Q7), delta_lag_log2_sqr_Q7 + ((int)((0.5f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(0.5f, 7)*/);
|
||||
CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */
|
||||
}
|
||||
|
||||
if (CCmax_new_b > CCmax_b && /* Find maximum biased correlation */
|
||||
CCmax_new > Inlines.silk_SMULBB(nb_subfr, search_thres2_Q13) && /* Correlation needs to be high enough to be voiced */
|
||||
Tables.silk_CB_lags_stage2[0][CBimax_new] <= MIN_LAG_8KHZ /* Lag must be in range */
|
||||
)
|
||||
{
|
||||
CCmax_b = CCmax_new_b;
|
||||
CCmax = CCmax_new;
|
||||
lag = d;
|
||||
CBimax = CBimax_new;
|
||||
}
|
||||
}
|
||||
|
||||
if (lag == -1)
|
||||
{
|
||||
/* No suitable candidate found */
|
||||
Arrays.MemSetInt(pitch_out, 0, nb_subfr);
|
||||
LTPCorr_Q15.Val = 0;
|
||||
lagIndex.Val = 0;
|
||||
contourIndex.Val = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Output normalized correlation */
|
||||
LTPCorr_Q15.Val = (int)Inlines.silk_LSHIFT(Inlines.silk_DIV32_16(CCmax, nb_subfr), 2);
|
||||
Inlines.OpusAssert(LTPCorr_Q15.Val >= 0);
|
||||
|
||||
if (Fs_kHz > 8)
|
||||
{
|
||||
short[] scratch_mem;
|
||||
/***************************************************************************/
|
||||
/* Scale input signal down to avoid correlations measures from overflowing */
|
||||
/***************************************************************************/
|
||||
/* find scaling as max scaling for each subframe */
|
||||
SumSqrShift.silk_sum_sqr_shift(out energy, out shift, frame, frame_length);
|
||||
if (shift > 0)
|
||||
{
|
||||
scratch_mem = new short[frame_length];
|
||||
/* Move signal to scratch mem because the input signal should be unchanged */
|
||||
shift = Inlines.silk_RSHIFT(shift, 1);
|
||||
for (i = 0; i < frame_length; i++)
|
||||
{
|
||||
scratch_mem[i] = Inlines.silk_RSHIFT16(frame[i], shift);
|
||||
}
|
||||
input_frame_ptr = scratch_mem;
|
||||
}
|
||||
else {
|
||||
input_frame_ptr = frame;
|
||||
}
|
||||
|
||||
/* Search in original signal */
|
||||
CBimax_old = CBimax;
|
||||
/* Compensate for decimation */
|
||||
Inlines.OpusAssert(lag == Inlines.silk_SAT16(lag));
|
||||
if (Fs_kHz == 12)
|
||||
{
|
||||
lag = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(lag, 3), 1);
|
||||
}
|
||||
else if (Fs_kHz == 16)
|
||||
{
|
||||
lag = Inlines.silk_LSHIFT(lag, 1);
|
||||
}
|
||||
else {
|
||||
lag = Inlines.silk_SMULBB(lag, 3);
|
||||
}
|
||||
|
||||
lag = Inlines.silk_LIMIT_int(lag, min_lag, max_lag);
|
||||
start_lag = Inlines.silk_max_int(lag - 2, min_lag);
|
||||
end_lag = Inlines.silk_min_int(lag + 2, max_lag);
|
||||
lag_new = lag; /* to avoid undefined lag */
|
||||
CBimax = 0; /* to avoid undefined lag */
|
||||
|
||||
CCmax = int.MinValue;
|
||||
/* pitch lags according to second stage */
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
pitch_out[k] = lag + 2 * Tables.silk_CB_lags_stage2[k][CBimax_old];
|
||||
}
|
||||
|
||||
/* Set up codebook parameters according to complexity setting and frame length */
|
||||
if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR)
|
||||
{
|
||||
nb_cbk_search = (int)Tables.silk_nb_cbk_searchs_stage3[complexity];
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3;
|
||||
}
|
||||
else {
|
||||
nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE3_10MS;
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3_10_ms;
|
||||
}
|
||||
|
||||
/* Calculate the correlations and energies needed in stage 3 */
|
||||
energies_st3 = new silk_pe_stage3_vals[nb_subfr * nb_cbk_search];
|
||||
cross_corr_st3 = new silk_pe_stage3_vals[nb_subfr * nb_cbk_search];
|
||||
for (int c = 0; c < nb_subfr * nb_cbk_search; c++)
|
||||
{
|
||||
energies_st3[c] = new silk_pe_stage3_vals(); // fixme: these can be replaced with a linearized array probably, or at least a struct
|
||||
cross_corr_st3[c] = new silk_pe_stage3_vals();
|
||||
}
|
||||
silk_P_Ana_calc_corr_st3(cross_corr_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity);
|
||||
silk_P_Ana_calc_energy_st3(energies_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity);
|
||||
|
||||
lag_counter = 0;
|
||||
Inlines.OpusAssert(lag == Inlines.silk_SAT16(lag));
|
||||
contour_bias_Q15 = Inlines.silk_DIV32_16(((int)((SilkConstants.PE_FLATCONTOUR_BIAS) * ((long)1 << (15)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.PE_FLATCONTOUR_BIAS, 15)*/, lag);
|
||||
|
||||
target = input_frame_ptr;
|
||||
target_ptr = SilkConstants.PE_LTP_MEM_LENGTH_MS * Fs_kHz;
|
||||
energy_target = Inlines.silk_ADD32(Inlines.silk_inner_prod_self(target, target_ptr, nb_subfr * sf_length), 1);
|
||||
for (d = start_lag; d <= end_lag; d++)
|
||||
{
|
||||
for (j = 0; j < nb_cbk_search; j++)
|
||||
{
|
||||
cross_corr = 0;
|
||||
energy = energy_target;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
cross_corr = Inlines.silk_ADD32(cross_corr,
|
||||
Inlines.MatrixGet(cross_corr_st3, k, j,
|
||||
nb_cbk_search).Values[lag_counter]);
|
||||
energy = Inlines.silk_ADD32(energy,
|
||||
Inlines.MatrixGet(energies_st3, k, j,
|
||||
nb_cbk_search).Values[lag_counter]);
|
||||
Inlines.OpusAssert(energy >= 0);
|
||||
}
|
||||
if (cross_corr > 0)
|
||||
{
|
||||
CCmax_new = Inlines.silk_DIV32_varQ(cross_corr, energy, 13 + 1); /* Q13 */
|
||||
/* Reduce depending on flatness of contour */
|
||||
diff = short.MaxValue - Inlines.silk_MUL(contour_bias_Q15, j); /* Q15 */
|
||||
Inlines.OpusAssert(diff == Inlines.silk_SAT16(diff));
|
||||
CCmax_new = Inlines.silk_SMULWB(CCmax_new, diff); /* Q14 */
|
||||
}
|
||||
else {
|
||||
CCmax_new = 0;
|
||||
}
|
||||
|
||||
if (CCmax_new > CCmax && (d + Tables.silk_CB_lags_stage3[0][j]) <= max_lag)
|
||||
{
|
||||
CCmax = CCmax_new;
|
||||
lag_new = d;
|
||||
CBimax = j;
|
||||
}
|
||||
}
|
||||
lag_counter++;
|
||||
}
|
||||
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
pitch_out[k] = lag_new + Lag_CB_ptr[k][CBimax];
|
||||
pitch_out[k] = Inlines.silk_LIMIT(pitch_out[k], min_lag, SilkConstants.PE_MAX_LAG_MS * Fs_kHz);
|
||||
}
|
||||
lagIndex.Val = (short)(lag_new - min_lag);
|
||||
contourIndex.Val = (sbyte)CBimax;
|
||||
}
|
||||
else { /* Fs_kHz == 8 */
|
||||
/* Save Lags */
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
pitch_out[k] = lag + Lag_CB_ptr[k][CBimax];
|
||||
pitch_out[k] = Inlines.silk_LIMIT(pitch_out[k], MIN_LAG_8KHZ, SilkConstants.PE_MAX_LAG_MS * 8);
|
||||
}
|
||||
lagIndex.Val = (short)(lag - MIN_LAG_8KHZ);
|
||||
contourIndex.Val = (sbyte)CBimax;
|
||||
}
|
||||
Inlines.OpusAssert(lagIndex.Val >= 0);
|
||||
/* return as voiced */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Calculates the correlations used in stage 3 search. In order to cover
|
||||
* the whole lag codebook for all the searched offset lags (lag +- 2),
|
||||
* the following correlations are needed in each sub frame:
|
||||
*
|
||||
* sf1: lag range [-8,...,7] total 16 correlations
|
||||
* sf2: lag range [-4,...,4] total 9 correlations
|
||||
* sf3: lag range [-3,....4] total 8 correltions
|
||||
* sf4: lag range [-6,....8] total 15 correlations
|
||||
*
|
||||
* In total 48 correlations. The direct implementation computed in worst
|
||||
* case 4*12*5 = 240 correlations, but more likely around 120.
|
||||
***********************************************************************/
|
||||
private static void silk_P_Ana_calc_corr_st3(
|
||||
silk_pe_stage3_vals[] cross_corr_st3, /* O 3 DIM correlation array */
|
||||
short[] frame, /* I vector to correlate */
|
||||
int start_lag, /* I lag offset to search around */
|
||||
int sf_length, /* I length of a 5 ms subframe */
|
||||
int nb_subfr, /* I number of subframes */
|
||||
int complexity /* I Complexity setting */
|
||||
)
|
||||
{
|
||||
int target_ptr;
|
||||
int i, j, k, lag_counter, lag_low, lag_high;
|
||||
int nb_cbk_search, delta, idx;
|
||||
int[] scratch_mem;
|
||||
int[] xcorr32;
|
||||
sbyte[][] Lag_range_ptr;
|
||||
sbyte[][] Lag_CB_ptr;
|
||||
|
||||
Inlines.OpusAssert(complexity >= SilkConstants.SILK_PE_MIN_COMPLEX);
|
||||
Inlines.OpusAssert(complexity <= SilkConstants.SILK_PE_MAX_COMPLEX);
|
||||
|
||||
if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR)
|
||||
{
|
||||
Lag_range_ptr = Tables.silk_Lag_range_stage3[complexity];
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3;
|
||||
nb_cbk_search = Tables.silk_nb_cbk_searchs_stage3[complexity];
|
||||
}
|
||||
else {
|
||||
Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
|
||||
Lag_range_ptr = Tables.silk_Lag_range_stage3_10_ms;
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3_10_ms;
|
||||
nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE3_10MS;
|
||||
}
|
||||
scratch_mem = new int[SCRATCH_SIZE];
|
||||
xcorr32 = new int[SCRATCH_SIZE];
|
||||
|
||||
target_ptr = Inlines.silk_LSHIFT(sf_length, 2); /* Pointer to middle of frame */
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
lag_counter = 0;
|
||||
|
||||
/* Calculate the correlations for each subframe */
|
||||
lag_low = Lag_range_ptr[k][0];
|
||||
lag_high = Lag_range_ptr[k][1];
|
||||
Inlines.OpusAssert(lag_high - lag_low + 1 <= SCRATCH_SIZE);
|
||||
CeltPitchXCorr.pitch_xcorr(frame, target_ptr, frame, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1);
|
||||
for (j = lag_low; j <= lag_high; j++)
|
||||
{
|
||||
Inlines.OpusAssert(lag_counter < SCRATCH_SIZE);
|
||||
scratch_mem[lag_counter] = xcorr32[lag_high - j];
|
||||
lag_counter++;
|
||||
}
|
||||
|
||||
delta = Lag_range_ptr[k][0];
|
||||
for (i = 0; i < nb_cbk_search; i++)
|
||||
{
|
||||
/* Fill out the 3 dim array that stores the correlations for */
|
||||
/* each code_book vector for each start lag */
|
||||
idx = Lag_CB_ptr[k][i] - delta;
|
||||
for (j = 0; j < SilkConstants.PE_NB_STAGE3_LAGS; j++)
|
||||
{
|
||||
Inlines.OpusAssert(idx + j < SCRATCH_SIZE);
|
||||
Inlines.OpusAssert(idx + j < lag_counter);
|
||||
Inlines.MatrixGet(cross_corr_st3, k, i, nb_cbk_search).Values[j] =
|
||||
scratch_mem[idx + j];
|
||||
}
|
||||
}
|
||||
target_ptr += sf_length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/* Calculate the energies for first two subframes. The energies are */
|
||||
/* calculated recursively. */
|
||||
/********************************************************************/
|
||||
static void silk_P_Ana_calc_energy_st3(
|
||||
silk_pe_stage3_vals[] energies_st3, /* O 3 DIM energy array */
|
||||
short[] frame, /* I vector to calc energy in */
|
||||
int start_lag, /* I lag offset to search around */
|
||||
int sf_length, /* I length of one 5 ms subframe */
|
||||
int nb_subfr, /* I number of subframes */
|
||||
int complexity /* I Complexity setting */
|
||||
)
|
||||
{
|
||||
int target_ptr, basis_ptr;
|
||||
int energy;
|
||||
int k, i, j, lag_counter;
|
||||
int nb_cbk_search, delta, idx, lag_diff;
|
||||
int[] scratch_mem;
|
||||
sbyte[][] Lag_range_ptr;
|
||||
sbyte[][] Lag_CB_ptr;
|
||||
|
||||
|
||||
Inlines.OpusAssert(complexity >= SilkConstants.SILK_PE_MIN_COMPLEX);
|
||||
Inlines.OpusAssert(complexity <= SilkConstants.SILK_PE_MAX_COMPLEX);
|
||||
|
||||
if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR)
|
||||
{
|
||||
Lag_range_ptr = Tables.silk_Lag_range_stage3[complexity];
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3;
|
||||
nb_cbk_search = Tables.silk_nb_cbk_searchs_stage3[complexity];
|
||||
}
|
||||
else {
|
||||
Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
|
||||
Lag_range_ptr = Tables.silk_Lag_range_stage3_10_ms;
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3_10_ms;
|
||||
nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE3_10MS;
|
||||
}
|
||||
scratch_mem = new int[SCRATCH_SIZE];
|
||||
|
||||
target_ptr = Inlines.silk_LSHIFT(sf_length, 2);
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
lag_counter = 0;
|
||||
|
||||
/* Calculate the energy for first lag */
|
||||
basis_ptr = target_ptr - (start_lag + Lag_range_ptr[k][0]);
|
||||
energy = Inlines.silk_inner_prod_self(frame, basis_ptr, sf_length);
|
||||
Inlines.OpusAssert(energy >= 0);
|
||||
scratch_mem[lag_counter] = energy;
|
||||
lag_counter++;
|
||||
|
||||
lag_diff = (Lag_range_ptr[k][1] - Lag_range_ptr[k][0] + 1);
|
||||
for (i = 1; i < lag_diff; i++)
|
||||
{
|
||||
/* remove part outside new window */
|
||||
energy -= Inlines.silk_SMULBB(frame[basis_ptr + sf_length - i], frame[basis_ptr + sf_length - i]);
|
||||
Inlines.OpusAssert(energy >= 0);
|
||||
|
||||
/* add part that comes into window */
|
||||
energy = Inlines.silk_ADD_SAT32(energy, Inlines.silk_SMULBB(frame[basis_ptr - i], frame[basis_ptr - i]));
|
||||
Inlines.OpusAssert(energy >= 0);
|
||||
Inlines.OpusAssert(lag_counter < SCRATCH_SIZE);
|
||||
scratch_mem[lag_counter] = energy;
|
||||
lag_counter++;
|
||||
}
|
||||
|
||||
delta = Lag_range_ptr[k][0];
|
||||
for (i = 0; i < nb_cbk_search; i++)
|
||||
{
|
||||
/* Fill out the 3 dim array that stores the correlations for */
|
||||
/* each code_book vector for each start lag */
|
||||
idx = Lag_CB_ptr[k][i] - delta;
|
||||
for (j = 0; j < SilkConstants.PE_NB_STAGE3_LAGS; j++)
|
||||
{
|
||||
Inlines.OpusAssert(idx + j < SCRATCH_SIZE);
|
||||
Inlines.OpusAssert(idx + j < lag_counter);
|
||||
Inlines.MatrixGet(energies_st3, k, i, nb_cbk_search).Values[j] = scratch_mem[idx + j];
|
||||
Inlines.OpusAssert(Inlines.MatrixGet(energies_st3, k, i, nb_cbk_search).Values[j] >= 0);
|
||||
}
|
||||
}
|
||||
target_ptr += sf_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class ProcessGains
|
||||
{
|
||||
/* Processing of gains */
|
||||
internal static void silk_process_gains(
|
||||
SilkChannelEncoder psEnc, /* I/O Encoder state */
|
||||
SilkEncoderControl psEncCtrl, /* I/O Encoder control */
|
||||
int condCoding /* I The type of conditional coding to use */
|
||||
)
|
||||
{
|
||||
SilkShapeState psShapeSt = psEnc.sShape;
|
||||
int k;
|
||||
int s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10;
|
||||
|
||||
/* Gain reduction when LTP coding gain is high */
|
||||
if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl.LTPredCodGain - 12.0f ) ); */
|
||||
s_Q16 = 0 - Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT_ROUND(psEncCtrl.LTPredCodGain_Q7 - ((int)((12.0f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(12.0f, 7)*/, 4));
|
||||
for (k = 0; k < psEnc.nb_subfr; k++)
|
||||
{
|
||||
psEncCtrl.Gains_Q16[k] = Inlines.silk_SMLAWB(psEncCtrl.Gains_Q16[k], psEncCtrl.Gains_Q16[k], s_Q16);
|
||||
}
|
||||
}
|
||||
|
||||
/* Limit the quantized signal */
|
||||
/* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */
|
||||
InvMaxSqrVal_Q16 = Inlines.silk_DIV32_16(Inlines.silk_log2lin(
|
||||
Inlines.silk_SMULWB(((int)((21 + 16 / 0.33f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(21 + 16 / 0.33f, 7)*/ - psEnc.SNR_dB_Q7, ((int)((0.33f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.33f, 16)*/)), psEnc.subfr_length);
|
||||
|
||||
for (k = 0; k < psEnc.nb_subfr; k++)
|
||||
{
|
||||
/* Soft limit on ratio residual energy and squared gains */
|
||||
ResNrg = psEncCtrl.ResNrg[k];
|
||||
ResNrgPart = Inlines.silk_SMULWW(ResNrg, InvMaxSqrVal_Q16);
|
||||
if (psEncCtrl.ResNrgQ[k] > 0)
|
||||
{
|
||||
ResNrgPart = Inlines.silk_RSHIFT_ROUND(ResNrgPart, psEncCtrl.ResNrgQ[k]);
|
||||
}
|
||||
else {
|
||||
if (ResNrgPart >= Inlines.silk_RSHIFT(int.MaxValue, -psEncCtrl.ResNrgQ[k]))
|
||||
{
|
||||
ResNrgPart = int.MaxValue;
|
||||
}
|
||||
else {
|
||||
ResNrgPart = Inlines.silk_LSHIFT(ResNrgPart, -psEncCtrl.ResNrgQ[k]);
|
||||
}
|
||||
}
|
||||
gain = psEncCtrl.Gains_Q16[k];
|
||||
gain_squared = Inlines.silk_ADD_SAT32(ResNrgPart, Inlines.silk_SMMUL(gain, gain));
|
||||
if (gain_squared < short.MaxValue)
|
||||
{
|
||||
/* recalculate with higher precision */
|
||||
gain_squared = Inlines.silk_SMLAWW(Inlines.silk_LSHIFT(ResNrgPart, 16), gain, gain);
|
||||
Inlines.OpusAssert(gain_squared > 0);
|
||||
gain = Inlines.silk_SQRT_APPROX(gain_squared); /* Q8 */
|
||||
gain = Inlines.silk_min(gain, int.MaxValue >> 8);
|
||||
psEncCtrl.Gains_Q16[k] = Inlines.silk_LSHIFT_SAT32(gain, 8); /* Q16 */
|
||||
}
|
||||
else {
|
||||
gain = Inlines.silk_SQRT_APPROX(gain_squared); /* Q0 */
|
||||
gain = Inlines.silk_min(gain, int.MaxValue >> 16);
|
||||
psEncCtrl.Gains_Q16[k] = Inlines.silk_LSHIFT_SAT32(gain, 16); /* Q16 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Save unquantized gains and gain Index */
|
||||
Array.Copy(psEncCtrl.Gains_Q16, psEncCtrl.GainsUnq_Q16, psEnc.nb_subfr);
|
||||
psEncCtrl.lastGainIndexPrev = psShapeSt.LastGainIndex;
|
||||
|
||||
/* Quantize gains */
|
||||
BoxedValueSbyte boxed_lastGainIndex = new BoxedValueSbyte(psShapeSt.LastGainIndex);
|
||||
GainQuantization.silk_gains_quant(psEnc.indices.GainsIndices, psEncCtrl.Gains_Q16,
|
||||
boxed_lastGainIndex, condCoding == SilkConstants.CODE_CONDITIONALLY ? 1 : 0, psEnc.nb_subfr);
|
||||
psShapeSt.LastGainIndex = boxed_lastGainIndex.Val;
|
||||
|
||||
/* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
|
||||
if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
if (psEncCtrl.LTPredCodGain_Q7 + Inlines.silk_RSHIFT(psEnc.input_tilt_Q15, 8) > ((int)((1.0f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(1.0f, 7)*/)
|
||||
{
|
||||
psEnc.indices.quantOffsetType = 0;
|
||||
}
|
||||
else {
|
||||
psEnc.indices.quantOffsetType = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Quantizer boundary adjustment */
|
||||
quant_offset_Q10 = Tables.silk_Quantization_Offsets_Q10[psEnc.indices.signalType >> 1][psEnc.indices.quantOffsetType];
|
||||
psEncCtrl.Lambda_Q10 = ((int)((TuningParameters.LAMBDA_OFFSET) * ((long)1 << (10)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LAMBDA_OFFSET, 10)*/
|
||||
+ Inlines.silk_SMULBB(((int)((TuningParameters.LAMBDA_DELAYED_DECISIONS) * ((long)1 << (10)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LAMBDA_DELAYED_DECISIONS, 10)*/, psEnc.nStatesDelayedDecision)
|
||||
+ Inlines.silk_SMULWB(((int)((TuningParameters.LAMBDA_SPEECH_ACT) * ((long)1 << (18)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LAMBDA_SPEECH_ACT, 18)*/, psEnc.speech_activity_Q8)
|
||||
+ Inlines.silk_SMULWB(((int)((TuningParameters.LAMBDA_INPUT_QUALITY) * ((long)1 << (12)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LAMBDA_INPUT_QUALITY, 12)*/, psEncCtrl.input_quality_Q14)
|
||||
+ Inlines.silk_SMULWB(((int)((TuningParameters.LAMBDA_CODING_QUALITY) * ((long)1 << (12)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LAMBDA_CODING_QUALITY, 12)*/, psEncCtrl.coding_quality_Q14)
|
||||
+ Inlines.silk_SMULWB(((int)((TuningParameters.LAMBDA_QUANT_OFFSET) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LAMBDA_QUANT_OFFSET, 16)*/, quant_offset_Q10);
|
||||
|
||||
Inlines.OpusAssert(psEncCtrl.Lambda_Q10 > 0);
|
||||
Inlines.OpusAssert(psEncCtrl.Lambda_Q10 < ((int)((2) * ((long)1 << (10)) + 0.5))/*Inlines.SILK_CONST(2, 10)*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class QuantizeLTPGains
|
||||
{
|
||||
internal static void silk_quant_LTP_gains(
|
||||
short[] B_Q14, /* I/O (un)quantized LTP gains [MAX_NB_SUBFR * LTP_ORDER] */
|
||||
sbyte[] cbk_index, /* O Codebook Index [MAX_NB_SUBFR] */
|
||||
BoxedValueSbyte periodicity_index, /* O Periodicity Index */
|
||||
BoxedValueInt sum_log_gain_Q7, /* I/O Cumulative max prediction gain */
|
||||
int[] W_Q18, /* I Error Weights in Q18 [MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER] */
|
||||
int mu_Q9, /* I Mu value (R/D tradeoff) */
|
||||
int lowComplexity, /* I Flag for low complexity */
|
||||
int nb_subfr /* I number of subframes */
|
||||
)
|
||||
{
|
||||
int j, k, cbk_size;
|
||||
sbyte[] temp_idx = new sbyte[SilkConstants.MAX_NB_SUBFR];
|
||||
byte[] cl_ptr_Q5;
|
||||
sbyte[][] cbk_ptr_Q7;
|
||||
byte[] cbk_gain_ptr_Q7;
|
||||
int b_Q14_ptr;
|
||||
int W_Q18_ptr;
|
||||
int rate_dist_Q14_subfr, rate_dist_Q14, min_rate_dist_Q14;
|
||||
int sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7, gain_Q7;
|
||||
|
||||
/***************************************************/
|
||||
/* iterate over different codebooks with different */
|
||||
/* rates/distortions, and choose best */
|
||||
/***************************************************/
|
||||
min_rate_dist_Q14 = int.MaxValue;
|
||||
best_sum_log_gain_Q7 = 0;
|
||||
for (k = 0; k < 3; k++)
|
||||
{
|
||||
/* Safety margin for pitch gain control, to take into account factors
|
||||
such as state rescaling/rewhitening. */
|
||||
int gain_safety = ((int)((0.4f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(0.4f, 7)*/;
|
||||
|
||||
cl_ptr_Q5 = Tables.silk_LTP_gain_BITS_Q5_ptrs[k];
|
||||
cbk_ptr_Q7 = Tables.silk_LTP_vq_ptrs_Q7[k];
|
||||
cbk_gain_ptr_Q7 = Tables.silk_LTP_vq_gain_ptrs_Q7[k];
|
||||
cbk_size = Tables.silk_LTP_vq_sizes[k];
|
||||
|
||||
/* Set up pointer to first subframe */
|
||||
W_Q18_ptr = 0;
|
||||
b_Q14_ptr = 0;
|
||||
|
||||
rate_dist_Q14 = 0;
|
||||
sum_log_gain_tmp_Q7 = sum_log_gain_Q7.Val;
|
||||
for (j = 0; j < nb_subfr; j++)
|
||||
{
|
||||
max_gain_Q7 = Inlines.silk_log2lin((((int)((TuningParameters.MAX_SUM_LOG_GAIN_DB / 6.0f) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.MAX_SUM_LOG_GAIN_DB / 6.0f, 7)*/ - sum_log_gain_tmp_Q7)
|
||||
+ ((int)((7) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(7, 7)*/) - gain_safety;
|
||||
|
||||
BoxedValueSbyte temp_idx_box = new BoxedValueSbyte(temp_idx[j]);
|
||||
BoxedValueInt rate_dist_Q14_subfr_box = new BoxedValueInt();
|
||||
BoxedValueInt gain_Q7_box = new BoxedValueInt();
|
||||
VQ_WMat_EC.silk_VQ_WMat_EC(
|
||||
temp_idx_box, /* O index of best codebook vector */
|
||||
rate_dist_Q14_subfr_box, /* O best weighted quantization error + mu * rate */
|
||||
gain_Q7_box, /* O sum of absolute LTP coefficients */
|
||||
B_Q14,
|
||||
b_Q14_ptr, /* I input vector to be quantized */
|
||||
W_Q18,
|
||||
W_Q18_ptr, /* I weighting matrix */
|
||||
cbk_ptr_Q7, /* I codebook */
|
||||
cbk_gain_ptr_Q7, /* I codebook effective gains */
|
||||
cl_ptr_Q5, /* I code length for each codebook vector */
|
||||
mu_Q9, /* I tradeoff between weighted error and rate */
|
||||
max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
|
||||
cbk_size /* I number of vectors in codebook */
|
||||
);
|
||||
rate_dist_Q14_subfr = rate_dist_Q14_subfr_box.Val;
|
||||
gain_Q7 = gain_Q7_box.Val;
|
||||
temp_idx[j] = temp_idx_box.Val;
|
||||
|
||||
rate_dist_Q14 = Inlines.silk_ADD_POS_SAT32(rate_dist_Q14, rate_dist_Q14_subfr);
|
||||
sum_log_gain_tmp_Q7 = Inlines.silk_max(0, sum_log_gain_tmp_Q7
|
||||
+ Inlines.silk_lin2log(gain_safety + gain_Q7) - ((int)((7) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(7, 7)*/);
|
||||
|
||||
b_Q14_ptr += SilkConstants.LTP_ORDER;
|
||||
W_Q18_ptr += SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER;
|
||||
}
|
||||
|
||||
/* Avoid never finding a codebook */
|
||||
rate_dist_Q14 = Inlines.silk_min(int.MaxValue - 1, rate_dist_Q14);
|
||||
|
||||
if (rate_dist_Q14 < min_rate_dist_Q14)
|
||||
{
|
||||
min_rate_dist_Q14 = rate_dist_Q14;
|
||||
periodicity_index.Val = (sbyte)k;
|
||||
Array.Copy(temp_idx, 0, cbk_index, 0, nb_subfr);
|
||||
best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7;
|
||||
}
|
||||
|
||||
/* Break early in low-complexity mode if rate distortion is below threshold */
|
||||
if (lowComplexity != 0 && (rate_dist_Q14 < Tables.silk_LTP_gain_middle_avg_RD_Q14))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cbk_ptr_Q7 = Tables.silk_LTP_vq_ptrs_Q7[periodicity_index.Val];
|
||||
for (j = 0; j < nb_subfr; j++)
|
||||
{
|
||||
for (k = 0; k < SilkConstants.LTP_ORDER; k++)
|
||||
{
|
||||
B_Q14[j * SilkConstants.LTP_ORDER + k] = (short)(Inlines.silk_LSHIFT(cbk_ptr_Q7[cbk_index[j]][k], 7));
|
||||
}
|
||||
}
|
||||
|
||||
sum_log_gain_Q7.Val = best_sum_log_gain_Q7;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class RegularizeCorrelations
|
||||
{
|
||||
/* Add noise to matrix diagonal */
|
||||
internal static void silk_regularize_correlations(
|
||||
int[] XX, /* I/O Correlation matrices */
|
||||
int XX_ptr,
|
||||
int[] xx, /* I/O Correlation values */
|
||||
int xx_ptr,
|
||||
int noise, /* I Noise to add */
|
||||
int D /* I Dimension of XX */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < D; i++)
|
||||
{
|
||||
Inlines.MatrixSet(XX, XX_ptr, i, i, D, Inlines.silk_ADD32(Inlines.MatrixGet(XX, XX_ptr, i, i, D), noise));
|
||||
}
|
||||
xx[xx_ptr] += noise;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,744 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
// fixme: merge with resampler state
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
/*
|
||||
* Matrix of resampling methods used:
|
||||
* Fs_out (kHz)
|
||||
* 8 12 16 24 48
|
||||
*
|
||||
* 8 C UF U UF UF
|
||||
* 12 AF C UF U UF
|
||||
* Fs_in (kHz) 16 D AF C UF UF
|
||||
* 24 AF D AF C U
|
||||
* 48 AF AF AF D C
|
||||
*
|
||||
* C . Copy (no resampling)
|
||||
* D . Allpass-based 2x downsampling
|
||||
* U . Allpass-based 2x upsampling
|
||||
* UF . Allpass-based 2x upsampling followed by FIR interpolation
|
||||
* AF . AR2 filter followed by FIR interpolation
|
||||
*/
|
||||
|
||||
internal static class Resampler
|
||||
{
|
||||
private const int USE_silk_resampler_copy = 0;
|
||||
private const int USE_silk_resampler_private_up2_HQ_wrapper = 1;
|
||||
private const int USE_silk_resampler_private_IIR_FIR = 2;
|
||||
private const int USE_silk_resampler_private_down_FIR = 3;
|
||||
|
||||
private const int ORDER_FIR = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4]
|
||||
/// </summary>
|
||||
/// <param name="R"></param>
|
||||
/// <returns></returns>
|
||||
private static int rateID(int R)
|
||||
{
|
||||
return (((((R) >> 12) - ((R > 16000) ? 1 : 0)) >> ((R > 24000) ? 1 : 0)) - 1);
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
/// <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="input">I Input signal</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>
|
||||
/// Downsample by a factor 2
|
||||
/// </summary>
|
||||
/// <param name="S">I/O State vector [ 2 ]</param>
|
||||
/// <param name="output">O Output signal [ floor(len/2) ]</param>
|
||||
/// <param name="input">I Input signal [ len ]</param>
|
||||
/// <param name="inLen">I Number of input samples</param>
|
||||
internal static void silk_resampler_down2(
|
||||
int[] S,
|
||||
short[] output,
|
||||
short[] input,
|
||||
int inLen)
|
||||
{
|
||||
int k, len2 = Inlines.silk_RSHIFT32(inLen, 1);
|
||||
int in32, out32, Y, X;
|
||||
|
||||
Inlines.OpusAssert(Tables.silk_resampler_down2_0 > 0);
|
||||
Inlines.OpusAssert(Tables.silk_resampler_down2_1 < 0);
|
||||
|
||||
/* Internal variables and state are in Q10 format */
|
||||
for (k = 0; k < len2; k++)
|
||||
{
|
||||
/* Convert to Q10 */
|
||||
in32 = Inlines.silk_LSHIFT((int)input[2 * k], 10);
|
||||
|
||||
/* All-pass section for even input sample */
|
||||
Y = Inlines.silk_SUB32(in32, S[0]);
|
||||
X = Inlines.silk_SMLAWB(Y, Y, Tables.silk_resampler_down2_1);
|
||||
out32 = Inlines.silk_ADD32(S[0], X);
|
||||
S[0] = Inlines.silk_ADD32(in32, X);
|
||||
|
||||
/* Convert to Q10 */
|
||||
in32 = Inlines.silk_LSHIFT((int)input[2 * k + 1], 10);
|
||||
|
||||
/* All-pass section for odd input sample, and add to output of previous section */
|
||||
Y = Inlines.silk_SUB32(in32, S[1]);
|
||||
X = Inlines.silk_SMULWB(Y, Tables.silk_resampler_down2_0);
|
||||
out32 = Inlines.silk_ADD32(out32, S[1]);
|
||||
out32 = Inlines.silk_ADD32(out32, X);
|
||||
S[1] = Inlines.silk_ADD32(in32, X);
|
||||
|
||||
/* Add, convert back to int16 and store to output */
|
||||
output[k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(out32, 11));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downsample by a factor 2/3, low quality
|
||||
/// </summary>
|
||||
/// <param name="S">I/O State vector [ 6 ]</param>
|
||||
/// <param name="output">O Output signal [ floor(2*inLen/3) ]</param>
|
||||
/// <param name="input">I Input signal [ inLen ]</param>
|
||||
/// <param name="inLen">I Number of input samples</param>
|
||||
internal static void silk_resampler_down2_3(
|
||||
int[] S,
|
||||
short[] output,
|
||||
short[] input,
|
||||
int inLen)
|
||||
{
|
||||
int nSamplesIn, counter, res_Q6;
|
||||
int[] buf = new int[SilkConstants.RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR];
|
||||
int buf_ptr;
|
||||
int input_ptr = 0;
|
||||
int output_ptr = 0;
|
||||
|
||||
/* Copy buffered samples to start of buffer */
|
||||
Array.Copy(S, 0, buf, 0, ORDER_FIR);
|
||||
|
||||
/* Iterate over blocks of frameSizeIn input samples */
|
||||
while (true)
|
||||
{
|
||||
nSamplesIn = Inlines.silk_min(inLen, SilkConstants.RESAMPLER_MAX_BATCH_SIZE_IN);
|
||||
|
||||
/* Second-order AR filter (output in Q8) */
|
||||
silk_resampler_private_AR2(S, ORDER_FIR, buf, ORDER_FIR, input, input_ptr,
|
||||
Tables.silk_Resampler_2_3_COEFS_LQ, nSamplesIn);
|
||||
|
||||
/* Interpolate filtered signal */
|
||||
buf_ptr = 0;
|
||||
counter = nSamplesIn;
|
||||
while (counter > 2)
|
||||
{
|
||||
/* Inner product */
|
||||
res_Q6 = Inlines.silk_SMULWB(buf[buf_ptr], Tables.silk_Resampler_2_3_COEFS_LQ[2]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 1], Tables.silk_Resampler_2_3_COEFS_LQ[3]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 2], Tables.silk_Resampler_2_3_COEFS_LQ[5]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 3], Tables.silk_Resampler_2_3_COEFS_LQ[4]);
|
||||
|
||||
/* Scale down, saturate and store in output array */
|
||||
output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6));
|
||||
|
||||
res_Q6 = Inlines.silk_SMULWB(buf[buf_ptr + 1], Tables.silk_Resampler_2_3_COEFS_LQ[4]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 2], Tables.silk_Resampler_2_3_COEFS_LQ[5]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 3], Tables.silk_Resampler_2_3_COEFS_LQ[3]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 4], Tables.silk_Resampler_2_3_COEFS_LQ[2]);
|
||||
|
||||
/* Scale down, saturate and store in output array */
|
||||
output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6));
|
||||
|
||||
buf_ptr += 3;
|
||||
counter -= 3;
|
||||
}
|
||||
|
||||
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, buf, 0, ORDER_FIR);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy last part of filtered signal to the state for the next call */
|
||||
Array.Copy(buf, nSamplesIn, S, 0, ORDER_FIR);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Second order AR filter with single delay elements
|
||||
/// </summary>
|
||||
/// <param name="S">I/O State vector [ 2 ]</param>
|
||||
/// <param name="out_Q8">O Output signal</param>
|
||||
/// <param name="input">I Input signal</param>
|
||||
/// <param name="A_Q14">I AR coefficients, Q14</param>
|
||||
/// <param name="len">I Signal length</param>
|
||||
internal static void silk_resampler_private_AR2(
|
||||
int[] S,
|
||||
int S_ptr,
|
||||
int[] out_Q8,
|
||||
int out_Q8_ptr,
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
short[] A_Q14,
|
||||
int len)
|
||||
{
|
||||
int k, out32;
|
||||
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
out32 = Inlines.silk_ADD_LSHIFT32(S[S_ptr], (int)input[input_ptr + k], 8);
|
||||
out_Q8[out_Q8_ptr + k] = out32;
|
||||
out32 = Inlines.silk_LSHIFT(out32, 2);
|
||||
S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr + 1], out32, A_Q14[0]);
|
||||
S[S_ptr + 1] = Inlines.silk_SMULWB(out32, A_Q14[1]);
|
||||
}
|
||||
}
|
||||
|
||||
internal static int silk_resampler_private_down_FIR_INTERPOL(
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
int[] buf,
|
||||
short[] FIR_Coefs,
|
||||
int FIR_Coefs_ptr,
|
||||
int FIR_Order,
|
||||
int FIR_Fracs,
|
||||
int max_index_Q16,
|
||||
int index_increment_Q16)
|
||||
{
|
||||
int index_Q16, res_Q6;
|
||||
int buf_ptr;
|
||||
int interpol_ind;
|
||||
int interpol_ptr;
|
||||
|
||||
switch (FIR_Order)
|
||||
{
|
||||
case SilkConstants.RESAMPLER_DOWN_ORDER_FIR0:
|
||||
for (index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16)
|
||||
{
|
||||
/* Integer part gives pointer to buffered input */
|
||||
buf_ptr = Inlines.silk_RSHIFT(index_Q16, 16);
|
||||
|
||||
/* Fractional part gives interpolation coefficients */
|
||||
interpol_ind = Inlines.silk_SMULWB(index_Q16 & 0xFFFF, FIR_Fracs);
|
||||
|
||||
/* Inner product */
|
||||
interpol_ptr = FIR_Coefs_ptr + (SilkConstants.RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind);
|
||||
res_Q6 = Inlines.silk_SMULWB(buf[buf_ptr + 0], FIR_Coefs[interpol_ptr + 0]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 1], FIR_Coefs[interpol_ptr + 1]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 2], FIR_Coefs[interpol_ptr + 2]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 3], FIR_Coefs[interpol_ptr + 3]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 4], FIR_Coefs[interpol_ptr + 4]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 5], FIR_Coefs[interpol_ptr + 5]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 6], FIR_Coefs[interpol_ptr + 6]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 7], FIR_Coefs[interpol_ptr + 7]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 8], FIR_Coefs[interpol_ptr + 8]);
|
||||
interpol_ptr = FIR_Coefs_ptr + (SilkConstants.RESAMPLER_DOWN_ORDER_FIR0 / 2 * (FIR_Fracs - 1 - interpol_ind));
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 17], FIR_Coefs[interpol_ptr + 0]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 16], FIR_Coefs[interpol_ptr + 1]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 15], FIR_Coefs[interpol_ptr + 2]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 14], FIR_Coefs[interpol_ptr + 3]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 13], FIR_Coefs[interpol_ptr + 4]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 12], FIR_Coefs[interpol_ptr + 5]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 11], FIR_Coefs[interpol_ptr + 6]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 10], FIR_Coefs[interpol_ptr + 7]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 9], FIR_Coefs[interpol_ptr + 8]);
|
||||
|
||||
/* Scale down, saturate and store in output array */
|
||||
output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6));
|
||||
}
|
||||
break;
|
||||
case SilkConstants.RESAMPLER_DOWN_ORDER_FIR1:
|
||||
for (index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16)
|
||||
{
|
||||
/* Integer part gives pointer to buffered input */
|
||||
buf_ptr = Inlines.silk_RSHIFT(index_Q16, 16);
|
||||
|
||||
/* Inner product */
|
||||
res_Q6 = Inlines.silk_SMULWB(Inlines.silk_ADD32(buf[buf_ptr + 0], buf[buf_ptr + 23]), FIR_Coefs[FIR_Coefs_ptr + 0]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 1], buf[buf_ptr + 22]), FIR_Coefs[FIR_Coefs_ptr + 1]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 2], buf[buf_ptr + 21]), FIR_Coefs[FIR_Coefs_ptr + 2]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 3], buf[buf_ptr + 20]), FIR_Coefs[FIR_Coefs_ptr + 3]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 4], buf[buf_ptr + 19]), FIR_Coefs[FIR_Coefs_ptr + 4]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 5], buf[buf_ptr + 18]), FIR_Coefs[FIR_Coefs_ptr + 5]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 6], buf[buf_ptr + 17]), FIR_Coefs[FIR_Coefs_ptr + 6]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 7], buf[buf_ptr + 16]), FIR_Coefs[FIR_Coefs_ptr + 7]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 8], buf[buf_ptr + 15]), FIR_Coefs[FIR_Coefs_ptr + 8]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 9], buf[buf_ptr + 14]), FIR_Coefs[FIR_Coefs_ptr + 9]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 10], buf[buf_ptr + 13]), FIR_Coefs[FIR_Coefs_ptr + 10]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 11], buf[buf_ptr + 12]), FIR_Coefs[FIR_Coefs_ptr + 11]);
|
||||
|
||||
/* Scale down, saturate and store in output array */
|
||||
output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6));
|
||||
}
|
||||
break;
|
||||
case SilkConstants.RESAMPLER_DOWN_ORDER_FIR2:
|
||||
for (index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16)
|
||||
{
|
||||
/* Integer part gives pointer to buffered input */
|
||||
buf_ptr = Inlines.silk_RSHIFT(index_Q16, 16);
|
||||
|
||||
/* Inner product */
|
||||
res_Q6 = Inlines.silk_SMULWB(Inlines.silk_ADD32(buf[buf_ptr + 0], buf[buf_ptr + 35]), FIR_Coefs[FIR_Coefs_ptr + 0]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 1], buf[buf_ptr + 34]), FIR_Coefs[FIR_Coefs_ptr + 1]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 2], buf[buf_ptr + 33]), FIR_Coefs[FIR_Coefs_ptr + 2]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 3], buf[buf_ptr + 32]), FIR_Coefs[FIR_Coefs_ptr + 3]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 4], buf[buf_ptr + 31]), FIR_Coefs[FIR_Coefs_ptr + 4]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 5], buf[buf_ptr + 30]), FIR_Coefs[FIR_Coefs_ptr + 5]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 6], buf[buf_ptr + 29]), FIR_Coefs[FIR_Coefs_ptr + 6]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 7], buf[buf_ptr + 28]), FIR_Coefs[FIR_Coefs_ptr + 7]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 8], buf[buf_ptr + 27]), FIR_Coefs[FIR_Coefs_ptr + 8]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 9], buf[buf_ptr + 26]), FIR_Coefs[FIR_Coefs_ptr + 9]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 10], buf[buf_ptr + 25]), FIR_Coefs[FIR_Coefs_ptr + 10]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 11], buf[buf_ptr + 24]), FIR_Coefs[FIR_Coefs_ptr + 11]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 12], buf[buf_ptr + 23]), FIR_Coefs[FIR_Coefs_ptr + 12]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 13], buf[buf_ptr + 22]), FIR_Coefs[FIR_Coefs_ptr + 13]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 14], buf[buf_ptr + 21]), FIR_Coefs[FIR_Coefs_ptr + 14]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 15], buf[buf_ptr + 20]), FIR_Coefs[FIR_Coefs_ptr + 15]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 16], buf[buf_ptr + 19]), FIR_Coefs[FIR_Coefs_ptr + 16]);
|
||||
res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 17], buf[buf_ptr + 18]), FIR_Coefs[FIR_Coefs_ptr + 17]);
|
||||
|
||||
/* Scale down, saturate and store in output array */
|
||||
output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Inlines.OpusAssert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return output_ptr;
|
||||
}
|
||||
|
||||
/// <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="input">I Input signal</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);
|
||||
}
|
||||
|
||||
internal static int silk_resampler_private_IIR_FIR_INTERPOL(
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
short[] buf,
|
||||
int max_index_Q16,
|
||||
int index_increment_Q16)
|
||||
{
|
||||
int index_Q16, res_Q15;
|
||||
int buf_ptr;
|
||||
int table_index;
|
||||
|
||||
/* Interpolate upsampled signal and store in output array */
|
||||
for (index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16)
|
||||
{
|
||||
table_index = Inlines.silk_SMULWB(index_Q16 & 0xFFFF, 12);
|
||||
buf_ptr = index_Q16 >> 16;
|
||||
|
||||
res_Q15 = Inlines.silk_SMULBB(buf[buf_ptr], Tables.silk_resampler_frac_FIR_12[table_index, 0]);
|
||||
res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 1], Tables.silk_resampler_frac_FIR_12[table_index, 1]);
|
||||
res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 2], Tables.silk_resampler_frac_FIR_12[table_index, 2]);
|
||||
res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 3], Tables.silk_resampler_frac_FIR_12[table_index, 3]);
|
||||
res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 4], Tables.silk_resampler_frac_FIR_12[11 - table_index, 3]);
|
||||
res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 5], Tables.silk_resampler_frac_FIR_12[11 - table_index, 2]);
|
||||
res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 6], Tables.silk_resampler_frac_FIR_12[11 - table_index, 1]);
|
||||
res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 7], Tables.silk_resampler_frac_FIR_12[11 - table_index, 0]);
|
||||
output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q15, 15));
|
||||
}
|
||||
return output_ptr;
|
||||
}
|
||||
|
||||
/// <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="input">I Input signal</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>
|
||||
/// Upsample by a factor 2, high quality
|
||||
/// Uses 2nd order allpass filters for the 2x upsampling, followed by a
|
||||
/// notch filter just above Nyquist.
|
||||
/// </summary>
|
||||
/// <param name="S">I/O Resampler state [ 6 ]</param>
|
||||
/// <param name="output">O Output signal [ 2 * len ]</param>
|
||||
/// <param name="input">I Input signal [ len ]</param>
|
||||
/// <param name="len">I Number of input samples</param>
|
||||
internal static void silk_resampler_private_up2_HQ(
|
||||
int[] S,
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int len)
|
||||
{
|
||||
int k;
|
||||
int in32, out32_1, out32_2, Y, X;
|
||||
|
||||
Inlines.OpusAssert(Tables.silk_resampler_up2_hq_0[0] > 0);
|
||||
Inlines.OpusAssert(Tables.silk_resampler_up2_hq_0[1] > 0);
|
||||
Inlines.OpusAssert(Tables.silk_resampler_up2_hq_0[2] < 0);
|
||||
Inlines.OpusAssert(Tables.silk_resampler_up2_hq_1[0] > 0);
|
||||
Inlines.OpusAssert(Tables.silk_resampler_up2_hq_1[1] > 0);
|
||||
Inlines.OpusAssert(Tables.silk_resampler_up2_hq_1[2] < 0);
|
||||
|
||||
/* Internal variables and state are in Q10 format */
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
/* Convert to Q10 */
|
||||
in32 = Inlines.silk_LSHIFT((int)input[input_ptr + k], 10);
|
||||
|
||||
/* First all-pass section for even output sample */
|
||||
Y = Inlines.silk_SUB32(in32, S[0]);
|
||||
X = Inlines.silk_SMULWB(Y, Tables.silk_resampler_up2_hq_0[0]);
|
||||
out32_1 = Inlines.silk_ADD32(S[0], X);
|
||||
S[0] = Inlines.silk_ADD32(in32, X);
|
||||
|
||||
/* Second all-pass section for even output sample */
|
||||
Y = Inlines.silk_SUB32(out32_1, S[1]);
|
||||
X = Inlines.silk_SMULWB(Y, Tables.silk_resampler_up2_hq_0[1]);
|
||||
out32_2 = Inlines.silk_ADD32(S[1], X);
|
||||
S[1] = Inlines.silk_ADD32(out32_1, X);
|
||||
|
||||
/* Third all-pass section for even output sample */
|
||||
Y = Inlines.silk_SUB32(out32_2, S[2]);
|
||||
X = Inlines.silk_SMLAWB(Y, Y, Tables.silk_resampler_up2_hq_0[2]);
|
||||
out32_1 = Inlines.silk_ADD32(S[2], X);
|
||||
S[2] = Inlines.silk_ADD32(out32_2, X);
|
||||
|
||||
/* Apply gain in Q15, convert back to int16 and store to output */
|
||||
output[output_ptr + (2 * k)] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(out32_1, 10));
|
||||
|
||||
/* First all-pass section for odd output sample */
|
||||
Y = Inlines.silk_SUB32(in32, S[3]);
|
||||
X = Inlines.silk_SMULWB(Y, Tables.silk_resampler_up2_hq_1[0]);
|
||||
out32_1 = Inlines.silk_ADD32(S[3], X);
|
||||
S[3] = Inlines.silk_ADD32(in32, X);
|
||||
|
||||
/* Second all-pass section for odd output sample */
|
||||
Y = Inlines.silk_SUB32(out32_1, S[4]);
|
||||
X = Inlines.silk_SMULWB(Y, Tables.silk_resampler_up2_hq_1[1]);
|
||||
out32_2 = Inlines.silk_ADD32(S[4], X);
|
||||
S[4] = Inlines.silk_ADD32(out32_1, X);
|
||||
|
||||
/* Third all-pass section for odd output sample */
|
||||
Y = Inlines.silk_SUB32(out32_2, S[5]);
|
||||
X = Inlines.silk_SMLAWB(Y, Y, Tables.silk_resampler_up2_hq_1[2]);
|
||||
out32_1 = Inlines.silk_ADD32(S[5], X);
|
||||
S[5] = Inlines.silk_ADD32(out32_2, X);
|
||||
|
||||
/* Apply gain in Q15, convert back to int16 and store to output */
|
||||
output[output_ptr + (2 * k) + 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(out32_1, 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class ResidualEnergy
|
||||
{
|
||||
/* Calculates residual energies of input subframes where all subframes have LPC_order */
|
||||
/* of preceding samples */
|
||||
internal static void silk_residual_energy(
|
||||
int[] nrgs, /* O Residual energy per subframe [MAX_NB_SUBFR] */
|
||||
int[] nrgsQ, /* O Q value per subframe [MAX_NB_SUBFR] */
|
||||
short[] x, /* I Input signal */
|
||||
short[][] a_Q12, /* I AR coefs for each frame half [2][MAX_LPC_ORDER] */
|
||||
int[] gains, /* I Quantization gains [SilkConstants.MAX_NB_SUBFR] */
|
||||
int subfr_length, /* I Subframe length */
|
||||
int nb_subfr, /* I Number of subframes */
|
||||
int LPC_order /* I LPC order */
|
||||
)
|
||||
{
|
||||
int offset, i, j, lz1, lz2;
|
||||
int rshift, energy;
|
||||
int LPC_res_ptr;
|
||||
short[] LPC_res;
|
||||
int x_ptr;
|
||||
int tmp32;
|
||||
|
||||
x_ptr = 0;
|
||||
offset = LPC_order + subfr_length;
|
||||
|
||||
/* Filter input to create the LPC residual for each frame half, and measure subframe energies */
|
||||
LPC_res = new short[(SilkConstants.MAX_NB_SUBFR >> 1) * offset];
|
||||
Inlines.OpusAssert((nb_subfr >> 1) * (SilkConstants.MAX_NB_SUBFR >> 1) == nb_subfr);
|
||||
for (i = 0; i < nb_subfr >> 1; i++)
|
||||
{
|
||||
/* Calculate half frame LPC residual signal including preceding samples */
|
||||
Filters.silk_LPC_analysis_filter(LPC_res, 0, x, x_ptr, a_Q12[i], 0, (SilkConstants.MAX_NB_SUBFR >> 1) * offset, LPC_order);
|
||||
|
||||
/* Point to first subframe of the just calculated LPC residual signal */
|
||||
LPC_res_ptr = LPC_order;
|
||||
for (j = 0; j < (SilkConstants.MAX_NB_SUBFR >> 1); j++)
|
||||
{
|
||||
/* Measure subframe energy */
|
||||
SumSqrShift.silk_sum_sqr_shift(out energy, out rshift, LPC_res, LPC_res_ptr, subfr_length);
|
||||
nrgs[i * (SilkConstants.MAX_NB_SUBFR >> 1) + j] = energy;
|
||||
|
||||
/* Set Q values for the measured energy */
|
||||
nrgsQ[i * (SilkConstants.MAX_NB_SUBFR >> 1) + j] = 0 - rshift;
|
||||
|
||||
/* Move to next subframe */
|
||||
LPC_res_ptr += offset;
|
||||
}
|
||||
/* Move to next frame half */
|
||||
x_ptr += (SilkConstants.MAX_NB_SUBFR >> 1) * offset;
|
||||
}
|
||||
|
||||
/* Apply the squared subframe gains */
|
||||
for (i = 0; i < nb_subfr; i++)
|
||||
{
|
||||
/* Fully upscale gains and energies */
|
||||
lz1 = Inlines.silk_CLZ32(nrgs[i]) - 1;
|
||||
lz2 = Inlines.silk_CLZ32(gains[i]) - 1;
|
||||
|
||||
tmp32 = Inlines.silk_LSHIFT32(gains[i], lz2);
|
||||
|
||||
/* Find squared gains */
|
||||
tmp32 = Inlines.silk_SMMUL(tmp32, tmp32); /* Q( 2 * lz2 - 32 )*/
|
||||
|
||||
/* Scale energies */
|
||||
nrgs[i] = Inlines.silk_SMMUL(tmp32, Inlines.silk_LSHIFT32(nrgs[i], lz1)); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/
|
||||
nrgsQ[i] += lz1 + 2 * lz2 - 32 - 32;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
|
||||
internal static int silk_residual_energy16_covar(
|
||||
short[] c, /* I Prediction vector */
|
||||
int c_ptr,
|
||||
int[] wXX, /* I Correlation matrix */
|
||||
int wXX_ptr,
|
||||
int[] wXx, /* I Correlation vector */
|
||||
int wxx, /* I Signal energy */
|
||||
int D, /* I Dimension */
|
||||
int cQ /* I Q value for c vector 0 - 15 */
|
||||
)
|
||||
{
|
||||
int i, j, lshifts, Qxtra;
|
||||
int c_max, w_max, tmp, tmp2, nrg;
|
||||
int[] cn = new int[D]; //SilkConstants.MAX_MATRIX_SIZE
|
||||
int pRow;
|
||||
|
||||
/* Safety checks */
|
||||
Inlines.OpusAssert(D >= 0);
|
||||
Inlines.OpusAssert(D <= 16);
|
||||
Inlines.OpusAssert(cQ > 0);
|
||||
Inlines.OpusAssert(cQ < 16);
|
||||
|
||||
lshifts = 16 - cQ;
|
||||
Qxtra = lshifts;
|
||||
|
||||
c_max = 0;
|
||||
for (i = c_ptr; i < c_ptr + D; i++)
|
||||
{
|
||||
c_max = Inlines.silk_max_32(c_max, Inlines.silk_abs((int)c[i]));
|
||||
}
|
||||
Qxtra = Inlines.silk_min_int(Qxtra, Inlines.silk_CLZ32(c_max) - 17);
|
||||
|
||||
w_max = Inlines.silk_max_32(wXX[wXX_ptr], wXX[wXX_ptr + (D * D) - 1]);
|
||||
Qxtra = Inlines.silk_min_int(Qxtra, Inlines.silk_CLZ32(Inlines.silk_MUL(D, Inlines.silk_RSHIFT(Inlines.silk_SMULWB(w_max, c_max), 4))) - 5);
|
||||
Qxtra = Inlines.silk_max_int(Qxtra, 0);
|
||||
for (i = 0; i < D; i++)
|
||||
{
|
||||
cn[i] = Inlines.silk_LSHIFT((int)c[c_ptr + i], Qxtra);
|
||||
Inlines.OpusAssert(Inlines.silk_abs(cn[i]) <= (short.MaxValue + 1)); /* Check that Inlines.silk_SMLAWB can be used */
|
||||
}
|
||||
lshifts -= Qxtra;
|
||||
|
||||
/* Compute wxx - 2 * wXx * c */
|
||||
tmp = 0;
|
||||
for (i = 0; i < D; i++)
|
||||
{
|
||||
tmp = Inlines.silk_SMLAWB(tmp, wXx[i], cn[i]);
|
||||
}
|
||||
nrg = Inlines.silk_RSHIFT(wxx, 1 + lshifts) - tmp; /* Q: -lshifts - 1 */
|
||||
|
||||
/* Add c' * wXX * c, assuming wXX is symmetric */
|
||||
tmp2 = 0;
|
||||
for (i = 0; i < D; i++)
|
||||
{
|
||||
tmp = 0;
|
||||
pRow = wXX_ptr + (i * D);
|
||||
for (j = i + 1; j < D; j++)
|
||||
{
|
||||
tmp = Inlines.silk_SMLAWB(tmp, wXX[pRow + j], cn[j]);
|
||||
}
|
||||
tmp = Inlines.silk_SMLAWB(tmp, Inlines.silk_RSHIFT(wXX[pRow + i], 1), cn[i]);
|
||||
tmp2 = Inlines.silk_SMLAWB(tmp2, tmp, cn[i]);
|
||||
}
|
||||
nrg = Inlines.silk_ADD_LSHIFT32(nrg, tmp2, lshifts); /* Q: -lshifts - 1 */
|
||||
|
||||
/* Keep one bit free always, because we add them for LSF interpolation */
|
||||
if (nrg < 1)
|
||||
{
|
||||
nrg = 1;
|
||||
}
|
||||
else if (nrg > Inlines.silk_RSHIFT(int.MaxValue, lshifts + 2))
|
||||
{
|
||||
nrg = int.MaxValue >> 1;
|
||||
}
|
||||
else {
|
||||
nrg = Inlines.silk_LSHIFT(nrg, lshifts + 1); /* Q0 */
|
||||
}
|
||||
return nrg;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class Schur
|
||||
{
|
||||
/* Faster than schur64(), but much less accurate. */
|
||||
/* uses SMLAWB(), requiring armv5E and higher. */
|
||||
internal static int silk_schur( /* O Returns residual energy */
|
||||
short[] rc_Q15, /* O reflection coefficients [order] Q15 */
|
||||
int[] c, /* I correlations [order+1] */
|
||||
int order /* I prediction order */
|
||||
)
|
||||
{
|
||||
int k, n, lz;
|
||||
int[][] C = Arrays.InitTwoDimensionalArray<int>(SilkConstants.SILK_MAX_ORDER_LPC + 1, 2);
|
||||
int Ctmp1, Ctmp2, rc_tmp_Q15;
|
||||
|
||||
Inlines.OpusAssert(order == 6 || order == 8 || order == 10 || order == 12 || order == 14 || order == 16);
|
||||
|
||||
/* Get number of leading zeros */
|
||||
lz = Inlines.silk_CLZ32(c[0]);
|
||||
|
||||
/* Copy correlations and adjust level to Q30 */
|
||||
if (lz < 2)
|
||||
{
|
||||
/* lz must be 1, so shift one to the right */
|
||||
for (k = 0; k < order + 1; k++)
|
||||
{
|
||||
C[k][0] = C[k][1] = Inlines.silk_RSHIFT(c[k], 1);
|
||||
}
|
||||
}
|
||||
else if (lz > 2)
|
||||
{
|
||||
/* Shift to the left */
|
||||
lz -= 2;
|
||||
for (k = 0; k < order + 1; k++)
|
||||
{
|
||||
C[k][0] = C[k][1] = Inlines.silk_LSHIFT(c[k], lz);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* No need to shift */
|
||||
for (k = 0; k < order + 1; k++)
|
||||
{
|
||||
C[k][0] = C[k][1] = c[k];
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 0; k < order; k++)
|
||||
{
|
||||
/* Check that we won't be getting an unstable rc, otherwise stop here. */
|
||||
if (Inlines.silk_abs_int32(C[k + 1][0]) >= C[0][1])
|
||||
{
|
||||
if (C[k + 1][0] > 0)
|
||||
{
|
||||
rc_Q15[k] = (short)(0 - ((int)((.99f) * ((long)1 << (15)) + 0.5))/*Inlines.SILK_CONST(.99f, 15)*/);
|
||||
}
|
||||
else {
|
||||
rc_Q15[k] = (short)(((int)((.99f) * ((long)1 << (15)) + 0.5))/*Inlines.SILK_CONST(.99f, 15)*/);
|
||||
}
|
||||
k++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get reflection coefficient */
|
||||
rc_tmp_Q15 = 0 - Inlines.silk_DIV32_16(C[k + 1][0], Inlines.silk_max_32(Inlines.silk_RSHIFT(C[0][1], 15), 1));
|
||||
|
||||
/* Clip (shouldn't happen for properly conditioned inputs) */
|
||||
rc_tmp_Q15 = Inlines.silk_SAT16(rc_tmp_Q15);
|
||||
|
||||
/* Store */
|
||||
rc_Q15[k] = (short)rc_tmp_Q15;
|
||||
|
||||
/* Update correlations */
|
||||
for (n = 0; n < order - k; n++)
|
||||
{
|
||||
Ctmp1 = C[n + k + 1][0];
|
||||
Ctmp2 = C[n][1];
|
||||
C[n + k + 1][0] = Inlines.silk_SMLAWB(Ctmp1, Inlines.silk_LSHIFT(Ctmp2, 1), rc_tmp_Q15);
|
||||
C[n][1] = Inlines.silk_SMLAWB(Ctmp2, Inlines.silk_LSHIFT(Ctmp1, 1), rc_tmp_Q15);
|
||||
}
|
||||
}
|
||||
|
||||
for (; k < order; k++)
|
||||
{
|
||||
rc_Q15[k] = 0;
|
||||
}
|
||||
|
||||
/* return residual energy */
|
||||
return Inlines.silk_max_32(1, C[0][1]);
|
||||
}
|
||||
|
||||
/* Slower than schur(), but more accurate. */
|
||||
/* Uses SMULL(), available on armv4 */
|
||||
internal static int silk_schur64( /* O returns residual energy */
|
||||
int[] rc_Q16, /* O Reflection coefficients [order] Q16 */
|
||||
int[] c, /* I Correlations [order+1] */
|
||||
int order /* I Prediction order */
|
||||
)
|
||||
{
|
||||
int k, n;
|
||||
int[][] C = Arrays.InitTwoDimensionalArray<int>(SilkConstants.SILK_MAX_ORDER_LPC + 1, 2);
|
||||
int Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31;
|
||||
|
||||
Inlines.OpusAssert(order == 6 || order == 8 || order == 10 || order == 12 || order == 14 || order == 16);
|
||||
|
||||
/* Check for invalid input */
|
||||
if (c[0] <= 0)
|
||||
{
|
||||
Arrays.MemSetInt(rc_Q16, 0, order);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (k = 0; k < order + 1; k++)
|
||||
{
|
||||
C[k][0] = C[k][1] = c[k];
|
||||
}
|
||||
|
||||
for (k = 0; k < order; k++)
|
||||
{
|
||||
/* Check that we won't be getting an unstable rc, otherwise stop here. */
|
||||
if (Inlines.silk_abs_int32(C[k + 1][0]) >= C[0][1])
|
||||
{
|
||||
if (C[k + 1][0] > 0)
|
||||
{
|
||||
rc_Q16[k] = -((int)((.99f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(.99f, 16)*/;
|
||||
}
|
||||
else {
|
||||
rc_Q16[k] = ((int)((.99f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(.99f, 16)*/;
|
||||
}
|
||||
k++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get reflection coefficient: divide two Q30 values and get result in Q31 */
|
||||
rc_tmp_Q31 = Inlines.silk_DIV32_varQ(-C[k + 1][0], C[0][1], 31);
|
||||
|
||||
/* Save the output */
|
||||
rc_Q16[k] = Inlines.silk_RSHIFT_ROUND(rc_tmp_Q31, 15);
|
||||
|
||||
/* Update correlations */
|
||||
for (n = 0; n < order - k; n++)
|
||||
{
|
||||
Ctmp1_Q30 = C[n + k + 1][0];
|
||||
Ctmp2_Q30 = C[n][1];
|
||||
|
||||
/* Multiply and add the highest int32 */
|
||||
C[n + k + 1][0] = Ctmp1_Q30 + Inlines.silk_SMMUL(Inlines.silk_LSHIFT(Ctmp2_Q30, 1), rc_tmp_Q31);
|
||||
C[n][1] = Ctmp2_Q30 + Inlines.silk_SMMUL(Inlines.silk_LSHIFT(Ctmp1_Q30, 1), rc_tmp_Q31);
|
||||
}
|
||||
}
|
||||
|
||||
for (; k < order; k++)
|
||||
{
|
||||
rc_Q16[k] = 0;
|
||||
}
|
||||
|
||||
return Inlines.silk_max_32(1, C[0][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
/// <summary>
|
||||
/// shell coder; pulse-subframe length is hardcoded
|
||||
/// </summary>
|
||||
internal static class ShellCoder
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="output">O combined pulses vector [len]</param>
|
||||
/// <param name="input">I input vector [2 * len]</param>
|
||||
/// <param name="len">I number of OUTPUT samples</param>
|
||||
internal static void combine_pulses(
|
||||
int[] output,
|
||||
int[] input,
|
||||
int input_ptr,
|
||||
int len)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
output[k] = input[input_ptr + (2 * k)] + input[input_ptr + (2 * k) + 1];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="output">O combined pulses vector [len]</param>
|
||||
/// <param name="input">I input vector [2 * len]</param>
|
||||
/// <param name="len">I number of OUTPUT samples</param>
|
||||
internal static void combine_pulses(
|
||||
int[] output,
|
||||
int[] input,
|
||||
int len)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
output[k] = input[2 * k] + input[2 * k + 1];
|
||||
}
|
||||
}
|
||||
|
||||
internal static void encode_split(
|
||||
EntropyCoder psRangeEnc, /* I/O compressor data structure */
|
||||
int p_child1, /* I pulse amplitude of first child subframe */
|
||||
int p, /* I pulse amplitude of current subframe */
|
||||
byte[] shell_table /* I table of shell cdfs */
|
||||
)
|
||||
{
|
||||
if (p > 0)
|
||||
{
|
||||
psRangeEnc.enc_icdf( p_child1, shell_table, Tables.silk_shell_code_table_offsets[p], 8);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="p_child1">O pulse amplitude of first child subframe</param>
|
||||
/// <param name="p_child2">O pulse amplitude of second child subframe</param>
|
||||
/// <param name="psRangeDec">I/O Compressor data structure</param>
|
||||
/// <param name="p">I pulse amplitude of current subframe</param>
|
||||
/// <param name="shell_table">I table of shell cdfs</param>
|
||||
internal static void decode_split(
|
||||
short[] p_child1,
|
||||
int child1_ptr,
|
||||
short[] p_child2,
|
||||
int p_child2_ptr,
|
||||
EntropyCoder psRangeDec,
|
||||
int p,
|
||||
byte[] shell_table)
|
||||
{
|
||||
if (p > 0)
|
||||
{
|
||||
p_child1[child1_ptr] = (short)(psRangeDec.dec_icdf(shell_table, (Tables.silk_shell_code_table_offsets[p]), 8));
|
||||
p_child2[p_child2_ptr] = (short)(p - p_child1[child1_ptr]);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_child1[child1_ptr] = 0;
|
||||
p_child2[p_child2_ptr] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shell encoder, operates on one shell code frame of 16 pulses
|
||||
/// </summary>
|
||||
/// <param name="psRangeEnc">I/O compressor data structure</param>
|
||||
/// <param name="pulses0">I data: nonnegative pulse amplitudes</param>
|
||||
internal static void silk_shell_encoder(EntropyCoder psRangeEnc, int[] pulses0, int pulses0_ptr)
|
||||
{
|
||||
int[] pulses1 = new int[8];
|
||||
int[] pulses2 = new int[4];
|
||||
int[] pulses3 = new int[2];
|
||||
int[] pulses4 = new int[1];
|
||||
|
||||
/* this function operates on one shell code frame of 16 pulses */
|
||||
Inlines.OpusAssert(SilkConstants.SHELL_CODEC_FRAME_LENGTH == 16);
|
||||
|
||||
/* tree representation per pulse-subframe */
|
||||
combine_pulses(pulses1, pulses0, pulses0_ptr, 8);
|
||||
combine_pulses(pulses2, pulses1, 4);
|
||||
combine_pulses(pulses3, pulses2, 2);
|
||||
combine_pulses(pulses4, pulses3, 1);
|
||||
|
||||
encode_split(psRangeEnc, pulses3[0], pulses4[0], Tables.silk_shell_code_table3);
|
||||
|
||||
encode_split(psRangeEnc, pulses2[0], pulses3[0], Tables.silk_shell_code_table2);
|
||||
|
||||
encode_split(psRangeEnc, pulses1[0], pulses2[0], Tables.silk_shell_code_table1);
|
||||
encode_split(psRangeEnc, pulses0[pulses0_ptr], pulses1[0], Tables.silk_shell_code_table0);
|
||||
encode_split(psRangeEnc, pulses0[pulses0_ptr + 2], pulses1[1], Tables.silk_shell_code_table0);
|
||||
|
||||
encode_split(psRangeEnc, pulses1[2], pulses2[1], Tables.silk_shell_code_table1);
|
||||
encode_split(psRangeEnc, pulses0[pulses0_ptr + 4], pulses1[2], Tables.silk_shell_code_table0);
|
||||
encode_split(psRangeEnc, pulses0[pulses0_ptr + 6], pulses1[3], Tables.silk_shell_code_table0);
|
||||
|
||||
encode_split(psRangeEnc, pulses2[2], pulses3[1], Tables.silk_shell_code_table2);
|
||||
|
||||
encode_split(psRangeEnc, pulses1[4], pulses2[2], Tables.silk_shell_code_table1);
|
||||
encode_split(psRangeEnc, pulses0[pulses0_ptr + 8], pulses1[4], Tables.silk_shell_code_table0);
|
||||
encode_split(psRangeEnc, pulses0[pulses0_ptr + 10], pulses1[5], Tables.silk_shell_code_table0);
|
||||
|
||||
encode_split(psRangeEnc, pulses1[6], pulses2[3], Tables.silk_shell_code_table1);
|
||||
encode_split(psRangeEnc, pulses0[pulses0_ptr + 12], pulses1[6], Tables.silk_shell_code_table0);
|
||||
encode_split(psRangeEnc, pulses0[pulses0_ptr + 14], pulses1[7], Tables.silk_shell_code_table0);
|
||||
}
|
||||
|
||||
|
||||
/* Shell decoder, operates on one shell code frame of 16 pulses */
|
||||
internal static void silk_shell_decoder(
|
||||
short[] pulses0, /* O data: nonnegative pulse amplitudes */
|
||||
int pulses0_ptr,
|
||||
EntropyCoder psRangeDec, /* I/O Compressor data structure */
|
||||
int pulses4 /* I number of pulses per pulse-subframe */
|
||||
)
|
||||
{
|
||||
short[] pulses1 = new short[8];
|
||||
short[] pulses2 = new short[4];
|
||||
short[] pulses3 = new short[2];
|
||||
|
||||
/* this function operates on one shell code frame of 16 pulses */
|
||||
Inlines.OpusAssert(SilkConstants.SHELL_CODEC_FRAME_LENGTH == 16);
|
||||
|
||||
decode_split(pulses3, 0, pulses3, 1, psRangeDec, pulses4, Tables.silk_shell_code_table3);
|
||||
|
||||
decode_split(pulses2, 0, pulses2, 1, psRangeDec, pulses3[0], Tables.silk_shell_code_table2);
|
||||
|
||||
decode_split(pulses1, 0, pulses1 ,1, psRangeDec, pulses2[0], Tables.silk_shell_code_table1);
|
||||
decode_split(pulses0, pulses0_ptr, pulses0, pulses0_ptr + 1, psRangeDec, pulses1[0], Tables.silk_shell_code_table0);
|
||||
decode_split(pulses0, pulses0_ptr + 2, pulses0, pulses0_ptr + 3, psRangeDec, pulses1[1], Tables.silk_shell_code_table0);
|
||||
|
||||
decode_split(pulses1, 2, pulses1, 3, psRangeDec, pulses2[1], Tables.silk_shell_code_table1);
|
||||
decode_split(pulses0, pulses0_ptr + 4, pulses0, pulses0_ptr + 5, psRangeDec, pulses1[2], Tables.silk_shell_code_table0);
|
||||
decode_split(pulses0, pulses0_ptr + 6, pulses0, pulses0_ptr + 7, psRangeDec, pulses1[3], Tables.silk_shell_code_table0);
|
||||
|
||||
decode_split(pulses2, 2, pulses2, 3, psRangeDec, pulses3[1], Tables.silk_shell_code_table2);
|
||||
|
||||
decode_split(pulses1, 4, pulses1 ,5, psRangeDec, pulses2[2], Tables.silk_shell_code_table1);
|
||||
decode_split(pulses0, pulses0_ptr + 8, pulses0, pulses0_ptr + 9, psRangeDec, pulses1[4], Tables.silk_shell_code_table0);
|
||||
decode_split(pulses0, pulses0_ptr + 10, pulses0, pulses0_ptr + 11, psRangeDec, pulses1[5], Tables.silk_shell_code_table0);
|
||||
|
||||
decode_split(pulses1, 6, pulses1, 7, psRangeDec, pulses2[3], Tables.silk_shell_code_table1);
|
||||
decode_split(pulses0, pulses0_ptr + 12, pulses0, pulses0_ptr + 13, psRangeDec, pulses1[6], Tables.silk_shell_code_table0);
|
||||
decode_split(pulses0, pulses0_ptr + 14, pulses0, pulses0_ptr + 15, psRangeDec, pulses1[7], Tables.silk_shell_code_table0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
/// <summary>
|
||||
/// Approximate sigmoid function
|
||||
/// </summary>
|
||||
internal static class Sigmoid
|
||||
{
|
||||
private static readonly int[] sigm_LUT_slope_Q10 = {
|
||||
237, 153, 73, 30, 12, 7
|
||||
};
|
||||
|
||||
private static readonly int[] sigm_LUT_pos_Q15 = {
|
||||
16384, 23955, 28861, 31213, 32178, 32548
|
||||
};
|
||||
|
||||
private static readonly int[] sigm_LUT_neg_Q15 = {
|
||||
16384, 8812, 3906, 1554, 589, 219
|
||||
};
|
||||
|
||||
internal static int silk_sigm_Q15(int in_Q5)
|
||||
{
|
||||
int ind;
|
||||
|
||||
if (in_Q5 < 0)
|
||||
{
|
||||
/* Negative input */
|
||||
in_Q5 = -in_Q5;
|
||||
if (in_Q5 >= 6 * 32)
|
||||
{
|
||||
return 0; /* Clip */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Linear interpolation of look up table */
|
||||
ind = Inlines.silk_RSHIFT(in_Q5, 5);
|
||||
return (sigm_LUT_neg_Q15[ind] - Inlines.silk_SMULBB(sigm_LUT_slope_Q10[ind], in_Q5 & 0x1F));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Positive input */
|
||||
if (in_Q5 >= 6 * 32)
|
||||
{
|
||||
return 32767; /* clip */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Linear interpolation of look up table */
|
||||
ind = Inlines.silk_RSHIFT(in_Q5, 5);
|
||||
return (sigm_LUT_pos_Q15[ind] + Inlines.silk_SMULBB(sigm_LUT_slope_Q10[ind], in_Q5 & 0x1F));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class SilkConstants
|
||||
{
|
||||
/* Max number of encoder channels (1/2) */
|
||||
public const int ENCODER_NUM_CHANNELS = 2;
|
||||
/* Number of decoder channels (1/2) */
|
||||
public const int DECODER_NUM_CHANNELS = 2;
|
||||
|
||||
public const int MAX_FRAMES_PER_PACKET = 3;
|
||||
|
||||
/* Limits on bitrate */
|
||||
public const int MIN_TARGET_RATE_BPS = 5000;
|
||||
public const int MAX_TARGET_RATE_BPS = 80000;
|
||||
public const int TARGET_RATE_TAB_SZ = 8;
|
||||
|
||||
/* LBRR thresholds */
|
||||
public const int LBRR_NB_MIN_RATE_BPS = 12000;
|
||||
public const int LBRR_MB_MIN_RATE_BPS = 14000;
|
||||
public const int LBRR_WB_MIN_RATE_BPS = 16000;
|
||||
|
||||
/* DTX settings */
|
||||
public const int NB_SPEECH_FRAMES_BEFORE_DTX = 10; /* eq 200 ms */
|
||||
public const int MAX_CONSECUTIVE_DTX = 20; /* eq 400 ms */
|
||||
|
||||
/* Maximum sampling frequency */
|
||||
public const int MAX_FS_KHZ = 16;
|
||||
public const int MAX_API_FS_KHZ = 48;
|
||||
|
||||
// FIXME can use enums here
|
||||
/* Signal types */
|
||||
public const int TYPE_NO_VOICE_ACTIVITY = 0;
|
||||
public const int TYPE_UNVOICED = 1;
|
||||
public const int TYPE_VOICED = 2;
|
||||
|
||||
/* Conditional coding types */
|
||||
public const int CODE_INDEPENDENTLY = 0;
|
||||
public const int CODE_INDEPENDENTLY_NO_LTP_SCALING = 1;
|
||||
public const int CODE_CONDITIONALLY = 2;
|
||||
|
||||
/* Settings for stereo processing */
|
||||
public const int STEREO_QUANT_TAB_SIZE = 16;
|
||||
public const int STEREO_QUANT_SUB_STEPS = 5;
|
||||
public const int STEREO_INTERP_LEN_MS = 8; /* must be even */
|
||||
public const float STEREO_RATIO_SMOOTH_COEF = 0.01f; /* smoothing coef for signal norms and stereo width */
|
||||
|
||||
/* Range of pitch lag estimates */
|
||||
public const int PITCH_EST_MIN_LAG_MS = 2; /* 2 ms . 500 Hz */
|
||||
public const int PITCH_EST_MAX_LAG_MS = 18; /* 18 ms . 56 Hz */
|
||||
|
||||
/* Maximum number of subframes */
|
||||
public const int MAX_NB_SUBFR = 4;
|
||||
|
||||
/* Number of samples per frame */
|
||||
public const int LTP_MEM_LENGTH_MS = 20;
|
||||
public const int SUB_FRAME_LENGTH_MS = 5;
|
||||
public const int MAX_SUB_FRAME_LENGTH = (SUB_FRAME_LENGTH_MS * MAX_FS_KHZ);
|
||||
public const int MAX_FRAME_LENGTH_MS = (SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR);
|
||||
public const int MAX_FRAME_LENGTH = (MAX_FRAME_LENGTH_MS * MAX_FS_KHZ);
|
||||
|
||||
/* Milliseconds of lookahead for pitch analysis */
|
||||
public const int LA_PITCH_MS = 2;
|
||||
public const int LA_PITCH_MAX = (LA_PITCH_MS * MAX_FS_KHZ);
|
||||
|
||||
/* Order of LPC used in find pitch */
|
||||
public const int MAX_FIND_PITCH_LPC_ORDER = 16;
|
||||
|
||||
/* Length of LPC window used in find pitch */
|
||||
public const int FIND_PITCH_LPC_WIN_MS = (20 + (LA_PITCH_MS << 1));
|
||||
public const int FIND_PITCH_LPC_WIN_MS_2_SF = (10 + (LA_PITCH_MS << 1));
|
||||
public const int FIND_PITCH_LPC_WIN_MAX = (FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ);
|
||||
|
||||
/* Milliseconds of lookahead for noise shape analysis */
|
||||
public const int LA_SHAPE_MS = 5;
|
||||
public const int LA_SHAPE_MAX = (LA_SHAPE_MS * MAX_FS_KHZ);
|
||||
|
||||
/* Maximum length of LPC window used in noise shape analysis */
|
||||
public const int SHAPE_LPC_WIN_MAX = (15 * MAX_FS_KHZ);
|
||||
|
||||
/* dB level of lowest gain quantization level */
|
||||
public const int MIN_QGAIN_DB = 2;
|
||||
/* dB level of highest gain quantization level */
|
||||
public const int MAX_QGAIN_DB = 88;
|
||||
/* Number of gain quantization levels */
|
||||
public const int N_LEVELS_QGAIN = 64;
|
||||
/* Max increase in gain quantization index */
|
||||
public const int MAX_DELTA_GAIN_QUANT = 36;
|
||||
/* Max decrease in gain quantization index */
|
||||
public const int MIN_DELTA_GAIN_QUANT = -4;
|
||||
|
||||
/* Quantization offsets (multiples of 4) */
|
||||
public const short OFFSET_VL_Q10 = 32;
|
||||
public const short OFFSET_VH_Q10 = 100;
|
||||
public const short OFFSET_UVL_Q10 = 100;
|
||||
public const short OFFSET_UVH_Q10 = 240;
|
||||
|
||||
public const int QUANT_LEVEL_ADJUST_Q10 = 80;
|
||||
|
||||
/* Maximum numbers of iterations used to stabilize an LPC vector */
|
||||
public const int MAX_LPC_STABILIZE_ITERATIONS = 16;
|
||||
public const float MAX_PREDICTION_POWER_GAIN = 1e4f;
|
||||
public const float MAX_PREDICTION_POWER_GAIN_AFTER_RESET = 1e2f;
|
||||
|
||||
public const int SILK_MAX_ORDER_LPC = 16;
|
||||
public const int MAX_LPC_ORDER = 16;
|
||||
public const int MIN_LPC_ORDER = 10;
|
||||
|
||||
/* Find Pred Coef defines */
|
||||
public const int LTP_ORDER = 5;
|
||||
|
||||
/* LTP quantization settings */
|
||||
public const int NB_LTP_CBKS = 3;
|
||||
|
||||
/* Flag to use harmonic noise shaping */
|
||||
public const int USE_HARM_SHAPING = 1;
|
||||
|
||||
/* Max LPC order of noise shaping filters */
|
||||
public const int MAX_SHAPE_LPC_ORDER = 16;
|
||||
|
||||
public const int HARM_SHAPE_FIR_TAPS = 3;
|
||||
|
||||
/* Maximum number of delayed decision states */
|
||||
public const int MAX_DEL_DEC_STATES = 4;
|
||||
|
||||
public const int LTP_BUF_LENGTH = 512;
|
||||
public const int LTP_MASK = (LTP_BUF_LENGTH - 1);
|
||||
|
||||
public const int DECISION_DELAY = 32;
|
||||
public const int DECISION_DELAY_MASK = (DECISION_DELAY - 1);
|
||||
|
||||
/* Number of subframes for excitation entropy coding */
|
||||
public const int SHELL_CODEC_FRAME_LENGTH = 16;
|
||||
public const int LOG2_SHELL_CODEC_FRAME_LENGTH = 4;
|
||||
public const int MAX_NB_SHELL_BLOCKS = (MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH);
|
||||
|
||||
/* Number of rate levels, for entropy coding of excitation */
|
||||
public const int N_RATE_LEVELS = 10;
|
||||
|
||||
/* Maximum sum of pulses per shell coding frame */
|
||||
public const int SILK_MAX_PULSES = 16;
|
||||
|
||||
public const int MAX_MATRIX_SIZE = MAX_LPC_ORDER; /* Max of LPC Order and LTP order */
|
||||
|
||||
internal static readonly int NSQ_LPC_BUF_LENGTH = Math.Max(MAX_LPC_ORDER, DECISION_DELAY);
|
||||
|
||||
/***************************/
|
||||
/* Voice activity detector */
|
||||
/***************************/
|
||||
public const int VAD_N_BANDS = 4;
|
||||
|
||||
public const int VAD_INTERNAL_SUBFRAMES_LOG2 = 2;
|
||||
public const int VAD_INTERNAL_SUBFRAMES = (1 << VAD_INTERNAL_SUBFRAMES_LOG2);
|
||||
|
||||
public const int VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 = 1024; /* Must be < 4096 */
|
||||
public const int VAD_NOISE_LEVELS_BIAS = 50;
|
||||
|
||||
/* Sigmoid settings */
|
||||
public const int VAD_NEGATIVE_OFFSET_Q5 = 128; /* sigmoid is 0 at -128 */
|
||||
public const int VAD_SNR_FACTOR_Q16 = 45000;
|
||||
|
||||
/* smoothing for SNR measurement */
|
||||
public const int VAD_SNR_SMOOTH_COEF_Q18 = 4096;
|
||||
|
||||
/* Size of the piecewise linear cosine approximation table for the LSFs */
|
||||
public const int LSF_COS_TAB_SZ = 128;
|
||||
|
||||
/******************/
|
||||
/* NLSF quantizer */
|
||||
/******************/
|
||||
public const int NLSF_W_Q = 2;
|
||||
public const int NLSF_VQ_MAX_VECTORS = 32;
|
||||
public const int NLSF_VQ_MAX_SURVIVORS = 32;
|
||||
public const int NLSF_QUANT_MAX_AMPLITUDE = 4;
|
||||
public const int NLSF_QUANT_MAX_AMPLITUDE_EXT = 10;
|
||||
public const float NLSF_QUANT_LEVEL_ADJ = 0.1f;
|
||||
public const int NLSF_QUANT_DEL_DEC_STATES_LOG2 = 2;
|
||||
public const int NLSF_QUANT_DEL_DEC_STATES = (1 << NLSF_QUANT_DEL_DEC_STATES_LOG2);
|
||||
|
||||
/* Transition filtering for mode switching */
|
||||
public const int TRANSITION_TIME_MS = 5120; /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/
|
||||
public const int TRANSITION_NB = 3; /* Hardcoded in tables */
|
||||
public const int TRANSITION_NA = 2; /* Hardcoded in tables */
|
||||
public const int TRANSITION_INT_NUM = 5; /* Hardcoded in tables */
|
||||
public const int TRANSITION_FRAMES = (TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS);
|
||||
public const int TRANSITION_INT_STEPS = (TRANSITION_FRAMES / (TRANSITION_INT_NUM - 1));
|
||||
|
||||
/* BWE factors to apply after packet loss */
|
||||
public const int BWE_AFTER_LOSS_Q16 = 63570;
|
||||
|
||||
/* Defines for CN generation */
|
||||
public const int CNG_BUF_MASK_MAX = 255; /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */
|
||||
public const int CNG_GAIN_SMTH_Q16 = 4634; /* 0.25^(1/4) */
|
||||
public const int CNG_NLSF_SMTH_Q16 = 16348; /* 0.25 */
|
||||
|
||||
/********************************************************/
|
||||
/* Definitions for pitch estimator (from pitch_est_defines.h) */
|
||||
/********************************************************/
|
||||
|
||||
public const int PE_MAX_FS_KHZ = 16; /* Maximum sampling frequency used */
|
||||
|
||||
public const int PE_MAX_NB_SUBFR = 4;
|
||||
public const int PE_SUBFR_LENGTH_MS = 5; /* 5 ms */
|
||||
|
||||
public const int PE_LTP_MEM_LENGTH_MS = (4 * PE_SUBFR_LENGTH_MS);
|
||||
|
||||
public const int PE_MAX_FRAME_LENGTH_MS = (PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS);
|
||||
public const int PE_MAX_FRAME_LENGTH = (PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ );
|
||||
public const int PE_MAX_FRAME_LENGTH_ST_1 = (PE_MAX_FRAME_LENGTH >> 2);
|
||||
public const int PE_MAX_FRAME_LENGTH_ST_2 = (PE_MAX_FRAME_LENGTH >> 1);
|
||||
|
||||
public const int PE_MAX_LAG_MS = 18; /* 18 ms . 56 Hz */
|
||||
public const int PE_MIN_LAG_MS = 2; /* 2 ms . 500 Hz */
|
||||
public const int PE_MAX_LAG = (PE_MAX_LAG_MS * PE_MAX_FS_KHZ);
|
||||
public const int PE_MIN_LAG = (PE_MIN_LAG_MS * PE_MAX_FS_KHZ);
|
||||
|
||||
public const int PE_D_SRCH_LENGTH = 24;
|
||||
|
||||
public const int PE_NB_STAGE3_LAGS = 5;
|
||||
|
||||
public const int PE_NB_CBKS_STAGE2 = 3;
|
||||
public const int PE_NB_CBKS_STAGE2_EXT = 11;
|
||||
|
||||
public const int PE_NB_CBKS_STAGE3_MAX = 34;
|
||||
public const int PE_NB_CBKS_STAGE3_MID = 24;
|
||||
public const int PE_NB_CBKS_STAGE3_MIN = 16;
|
||||
|
||||
public const int PE_NB_CBKS_STAGE3_10MS = 12;
|
||||
public const int PE_NB_CBKS_STAGE2_10MS = 3;
|
||||
|
||||
public const float PE_SHORTLAG_BIAS = 0.2f; /* for logarithmic weighting */
|
||||
public const float PE_PREVLAG_BIAS = 0.2f; /* for logarithmic weighting */
|
||||
public const float PE_FLATCONTOUR_BIAS = 0.05f;
|
||||
|
||||
public const int SILK_PE_MIN_COMPLEX = 0;
|
||||
public const int SILK_PE_MID_COMPLEX = 1;
|
||||
public const int SILK_PE_MAX_COMPLEX = 2;
|
||||
|
||||
// Definitions for PLC (from plc.h)
|
||||
|
||||
public const float BWE_COEF = 0.99f;
|
||||
public const int V_PITCH_GAIN_START_MIN_Q14 = 11469; /* 0.7 in Q14 */
|
||||
public const int V_PITCH_GAIN_START_MAX_Q14 = 15565; /* 0.95 in Q14 */
|
||||
public const int MAX_PITCH_LAG_MS = 18;
|
||||
public const int RAND_BUF_SIZE = 128;
|
||||
public const int RAND_BUF_MASK = (RAND_BUF_SIZE - 1);
|
||||
public const int LOG2_INV_LPC_GAIN_HIGH_THRES = 3; /* 2^3 = 8 dB LPC gain */
|
||||
public const int LOG2_INV_LPC_GAIN_LOW_THRES = 8; /* 2^8 = 24 dB LPC gain */
|
||||
public const int PITCH_DRIFT_FAC_Q16 = 655; /* 0.01 in Q16 */
|
||||
|
||||
// Definitions for resampler (from resampler_structs.h)
|
||||
|
||||
public const int SILK_RESAMPLER_MAX_FIR_ORDER = 36;
|
||||
public const int SILK_RESAMPLER_MAX_IIR_ORDER = 6;
|
||||
|
||||
// from resampler_rom.h
|
||||
public const int RESAMPLER_DOWN_ORDER_FIR0 = 18;
|
||||
public const int RESAMPLER_DOWN_ORDER_FIR1 = 24;
|
||||
public const int RESAMPLER_DOWN_ORDER_FIR2 = 36;
|
||||
public const int RESAMPLER_ORDER_FIR_12 = 8;
|
||||
|
||||
// from resampler_private.h
|
||||
|
||||
/* Number of input samples to process in the inner loop */
|
||||
public const int RESAMPLER_MAX_BATCH_SIZE_MS = 10;
|
||||
public const int RESAMPLER_MAX_FS_KHZ = 48;
|
||||
public const int RESAMPLER_MAX_BATCH_SIZE_IN = (RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ);
|
||||
|
||||
// from api.h
|
||||
|
||||
public const int SILK_MAX_FRAMES_PER_PACKET = 3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class Sort
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="a">(I/O) Unsorted / Sorted vector</param>
|
||||
/// <param name="idx">(O) Index vector for the sorted elements</param>
|
||||
/// <param name="L">(I) Vector length</param>
|
||||
/// <param name="K">(I) Number of correctly sorted positions</param>
|
||||
internal static void silk_insertion_sort_increasing(int[] a, int[] idx, int L, int K)
|
||||
{
|
||||
int value;
|
||||
int i, j;
|
||||
|
||||
// Safety checks
|
||||
Inlines.OpusAssert(K > 0);
|
||||
Inlines.OpusAssert(L > 0);
|
||||
Inlines.OpusAssert(L >= K);
|
||||
|
||||
// Write start indices in index vector
|
||||
for (i = 0; i < K; i++)
|
||||
{
|
||||
idx[i] = i;
|
||||
}
|
||||
|
||||
// Sort vector elements by value, increasing order
|
||||
for (i = 1; i < K; i++)
|
||||
{
|
||||
value = a[i];
|
||||
|
||||
for (j = i - 1; (j >= 0) && (value < a[j]); j--)
|
||||
{
|
||||
a[j + 1] = a[j]; /* Shift value */
|
||||
idx[j + 1] = idx[j]; /* Shift index */
|
||||
}
|
||||
|
||||
a[j + 1] = value; /* Write value */
|
||||
idx[j + 1] = i; /* Write index */
|
||||
}
|
||||
|
||||
// If less than L values are asked for, check the remaining values,
|
||||
// but only spend CPU to ensure that the K first values are correct
|
||||
for (i = K; i < L; i++)
|
||||
{
|
||||
value = a[i];
|
||||
|
||||
if (value < a[K - 1])
|
||||
{
|
||||
for (j = K - 2; (j >= 0) && (value < a[j]); j--)
|
||||
{
|
||||
a[j + 1] = a[j]; /* Shift value */
|
||||
idx[j + 1] = idx[j]; /* Shift index */
|
||||
}
|
||||
|
||||
a[j + 1] = value; /* Write value */
|
||||
idx[j + 1] = i; /* Write index */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insertion sort (fast for already almost sorted arrays):
|
||||
/// Best case: O(n) for an already sorted array
|
||||
/// Worst case: O(n^2) for an inversely sorted array
|
||||
/// </summary>
|
||||
/// <param name="a">(I/O) Unsorted / Sorted vector</param>
|
||||
/// <param name="L">(I) Vector length</param>
|
||||
internal static void silk_insertion_sort_increasing_all_values_int16(short[] a, int L)
|
||||
{
|
||||
// FIXME: Could just use Array.Sort(a.Array, a.Offset, L);
|
||||
|
||||
short value;
|
||||
int i, j;
|
||||
|
||||
// Safety checks
|
||||
Inlines.OpusAssert(L > 0);
|
||||
|
||||
// Sort vector elements by value, increasing order
|
||||
for (i = 1; i < L; i++)
|
||||
{
|
||||
value = a[i];
|
||||
for (j = i - 1; (j >= 0) && (value < a[j]); j--)
|
||||
{
|
||||
a[j + 1] = a[j]; // Shift value
|
||||
}
|
||||
|
||||
a[j + 1] = value; // Write value
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is only used by the fixed-point build */
|
||||
internal static void silk_insertion_sort_decreasing_int16(
|
||||
short[] a, /* I/O Unsorted / Sorted vector */
|
||||
int[] idx, /* O Index vector for the sorted elements */
|
||||
int L, /* I Vector length */
|
||||
int K /* I Number of correctly sorted positions */
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
short value;
|
||||
|
||||
/* Safety checks */
|
||||
Inlines.OpusAssert(K > 0);
|
||||
Inlines.OpusAssert(L > 0);
|
||||
Inlines.OpusAssert(L >= K);
|
||||
|
||||
/* Write start indices in index vector */
|
||||
for (i = 0; i < K; i++)
|
||||
{
|
||||
idx[i] = i;
|
||||
}
|
||||
|
||||
/* Sort vector elements by value, decreasing order */
|
||||
for (i = 1; i < K; i++)
|
||||
{
|
||||
value = a[i];
|
||||
for (j = i - 1; (j >= 0) && (value > a[j]); j--)
|
||||
{
|
||||
a[j + 1] = a[j]; /* Shift value */
|
||||
idx[j + 1] = idx[j]; /* Shift index */
|
||||
}
|
||||
a[j + 1] = value; /* Write value */
|
||||
idx[j + 1] = i; /* Write index */
|
||||
}
|
||||
|
||||
/* If less than L values are asked for, check the remaining values, */
|
||||
/* but only spend CPU to ensure that the K first values are correct */
|
||||
for (i = K; i < L; i++)
|
||||
{
|
||||
value = a[i];
|
||||
if (value > a[K - 1])
|
||||
{
|
||||
for (j = K - 2; (j >= 0) && (value > a[j]); j--)
|
||||
{
|
||||
a[j + 1] = a[j]; /* Shift value */
|
||||
idx[j + 1] = idx[j]; /* Shift index */
|
||||
}
|
||||
a[j + 1] = value; /* Write value */
|
||||
idx[j + 1] = i; /* Write index */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,543 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class Stereo
|
||||
{
|
||||
/// <summary>
|
||||
/// Decode mid/side predictors
|
||||
/// </summary>
|
||||
/// <param name="psRangeDec">I/O Compressor data structure</param>
|
||||
/// <param name="pred_Q13">O Predictors</param>
|
||||
internal static void silk_stereo_decode_pred(
|
||||
EntropyCoder psRangeDec,
|
||||
int[] pred_Q13)
|
||||
{
|
||||
int n;
|
||||
int[][] ix = Arrays.InitTwoDimensionalArray<int>(2, 3);
|
||||
int low_Q13, step_Q13;
|
||||
|
||||
// Entropy decoding
|
||||
n = psRangeDec.dec_icdf(Tables.silk_stereo_pred_joint_iCDF, 8);
|
||||
ix[0][2] = Inlines.silk_DIV32_16(n, 5);
|
||||
ix[1][2] = n - 5 * ix[0][2];
|
||||
for (n = 0; n < 2; n++)
|
||||
{
|
||||
ix[n][0] = psRangeDec.dec_icdf(Tables.silk_uniform3_iCDF, 8);
|
||||
ix[n][1] = psRangeDec.dec_icdf(Tables.silk_uniform5_iCDF, 8);
|
||||
}
|
||||
|
||||
// Dequantize
|
||||
for (n = 0; n < 2; n++)
|
||||
{
|
||||
ix[n][0] += 3 * ix[n][2];
|
||||
low_Q13 = Tables.silk_stereo_pred_quant_Q13[ix[n][0]];
|
||||
step_Q13 = Inlines.silk_SMULWB(Tables.silk_stereo_pred_quant_Q13[ix[n][0] + 1] - low_Q13,
|
||||
((int)((0.5f / SilkConstants.STEREO_QUANT_SUB_STEPS) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.5f / SilkConstants.STEREO_QUANT_SUB_STEPS, 16)*/);
|
||||
pred_Q13[n] = Inlines.silk_SMLABB(low_Q13, step_Q13, 2 * ix[n][1] + 1);
|
||||
}
|
||||
|
||||
/* Subtract second from first predictor (helps when actually applying these) */
|
||||
pred_Q13[0] -= pred_Q13[1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode mid-only flag
|
||||
/// </summary>
|
||||
/// <param name="psRangeDec">I/O Compressor data structure</param>
|
||||
/// <param name="decode_only_mid">O Flag that only mid channel has been coded</param>
|
||||
internal static void silk_stereo_decode_mid_only(
|
||||
EntropyCoder psRangeDec,
|
||||
BoxedValueInt decode_only_mid
|
||||
)
|
||||
{
|
||||
/* Decode flag that only mid channel is coded */
|
||||
decode_only_mid.Val = psRangeDec.dec_icdf(Tables.silk_stereo_only_code_mid_iCDF, 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entropy code the mid/side quantization indices
|
||||
/// </summary>
|
||||
/// <param name="psRangeEnc">I/O Compressor data structure</param>
|
||||
/// <param name="ix">I Quantization indices [ 2 ][ 3 ]</param>
|
||||
internal static void silk_stereo_encode_pred(EntropyCoder psRangeEnc, sbyte[][] ix)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* Entropy coding */
|
||||
n = 5 * ix[0][2] + ix[1][2];
|
||||
Inlines.OpusAssert(n < 25);
|
||||
psRangeEnc.enc_icdf( n, Tables.silk_stereo_pred_joint_iCDF, 8);
|
||||
for (n = 0; n < 2; n++)
|
||||
{
|
||||
Inlines.OpusAssert(ix[n][0] < 3);
|
||||
Inlines.OpusAssert(ix[n][1] < SilkConstants.STEREO_QUANT_SUB_STEPS);
|
||||
psRangeEnc.enc_icdf( ix[n][0], Tables.silk_uniform3_iCDF, 8);
|
||||
psRangeEnc.enc_icdf( ix[n][1], Tables.silk_uniform5_iCDF, 8);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entropy code the mid-only flag
|
||||
/// </summary>
|
||||
/// <param name="psRangeEnc">I/O Compressor data structure</param>
|
||||
/// <param name="mid_only_flag"></param>
|
||||
internal static void silk_stereo_encode_mid_only(EntropyCoder psRangeEnc, sbyte mid_only_flag)
|
||||
{
|
||||
/* Encode flag that only mid channel is coded */
|
||||
psRangeEnc.enc_icdf( mid_only_flag, Tables.silk_stereo_only_code_mid_iCDF, 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find least-squares prediction gain for one signal based on another and quantize it
|
||||
/// </summary>
|
||||
/// <param name="ratio_Q14">O Ratio of residual and mid energies</param>
|
||||
/// <param name="x">I Basis signal</param>
|
||||
/// <param name="y">I Target signal</param>
|
||||
/// <param name="mid_res_amp_Q0">I/O Smoothed mid, residual norms</param>
|
||||
/// <param name="length">I Number of samples</param>
|
||||
/// <param name="smooth_coef_Q16">I Smoothing coefficient</param>
|
||||
/// <returns>O Returns predictor in Q13</returns>
|
||||
internal static int silk_stereo_find_predictor(
|
||||
BoxedValueInt ratio_Q14,
|
||||
short[] x,
|
||||
short[] y,
|
||||
int[] mid_res_amp_Q0,
|
||||
int mid_res_amp_Q0_ptr,
|
||||
int length,
|
||||
int smooth_coef_Q16)
|
||||
{
|
||||
int scale;
|
||||
int nrgx, nrgy, scale1, scale2;
|
||||
int corr, pred_Q13, pred2_Q10;
|
||||
|
||||
/* Find predictor */
|
||||
SumSqrShift.silk_sum_sqr_shift(out nrgx, out scale1, x, length);
|
||||
SumSqrShift.silk_sum_sqr_shift(out nrgy, out scale2, y, length);
|
||||
scale = Inlines.silk_max_int(scale1, scale2);
|
||||
scale = scale + (scale & 1); /* make even */
|
||||
nrgy = Inlines.silk_RSHIFT32(nrgy, scale - scale2);
|
||||
nrgx = Inlines.silk_RSHIFT32(nrgx, scale - scale1);
|
||||
nrgx = Inlines.silk_max_int(nrgx, 1);
|
||||
corr = Inlines.silk_inner_prod_aligned_scale(x, y, scale, length);
|
||||
pred_Q13 = Inlines.silk_DIV32_varQ(corr, nrgx, 13);
|
||||
pred_Q13 = Inlines.silk_LIMIT(pred_Q13, -(1 << 14), 1 << 14);
|
||||
pred2_Q10 = Inlines.silk_SMULWB(pred_Q13, pred_Q13);
|
||||
|
||||
/* Faster update for signals with large prediction parameters */
|
||||
smooth_coef_Q16 = (int)Inlines.silk_max_int(smooth_coef_Q16, Inlines.silk_abs(pred2_Q10));
|
||||
|
||||
/* Smoothed mid and residual norms */
|
||||
Inlines.OpusAssert(smooth_coef_Q16 < 32768);
|
||||
scale = Inlines.silk_RSHIFT(scale, 1);
|
||||
mid_res_amp_Q0[mid_res_amp_Q0_ptr] = Inlines.silk_SMLAWB(mid_res_amp_Q0[mid_res_amp_Q0_ptr],
|
||||
Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(nrgx), scale) - mid_res_amp_Q0[mid_res_amp_Q0_ptr], smooth_coef_Q16);
|
||||
/* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */
|
||||
nrgy = Inlines.silk_SUB_LSHIFT32(nrgy, Inlines.silk_SMULWB(corr, pred_Q13), 3 + 1);
|
||||
nrgy = Inlines.silk_ADD_LSHIFT32(nrgy, Inlines.silk_SMULWB(nrgx, pred2_Q10), 6);
|
||||
mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1] = Inlines.silk_SMLAWB(mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1],
|
||||
Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(nrgy), scale) - mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1], smooth_coef_Q16);
|
||||
|
||||
/* Ratio of smoothed residual and mid norms */
|
||||
ratio_Q14.Val = Inlines.silk_DIV32_varQ(mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1], Inlines.silk_max(mid_res_amp_Q0[mid_res_amp_Q0_ptr], 1), 14);
|
||||
ratio_Q14.Val = Inlines.silk_LIMIT(ratio_Q14.Val, 0, 32767);
|
||||
|
||||
return pred_Q13;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert Left/Right stereo signal to adaptive Mid/Side representation
|
||||
/// </summary>
|
||||
/// <param name="state">I/O State</param>
|
||||
/// <param name="x1">I/O Left input signal, becomes mid signal</param>
|
||||
/// <param name="x2">I/O Right input signal, becomes side signal</param>
|
||||
/// <param name="ix">O Quantization indices [ 2 ][ 3 ]</param>
|
||||
/// <param name="mid_only_flag">O Flag: only mid signal coded</param>
|
||||
/// <param name="mid_side_rates_bps">O Bitrates for mid and side signals</param>
|
||||
/// <param name="total_rate_bps">I Total bitrate</param>
|
||||
/// <param name="prev_speech_act_Q8">I Speech activity level in previous frame</param>
|
||||
/// <param name="toMono">I Last frame before a stereo.mono transition</param>
|
||||
/// <param name="fs_kHz">I Sample rate (kHz)</param>
|
||||
/// <param name="frame_length">I Number of samples</param>
|
||||
internal static void silk_stereo_LR_to_MS(
|
||||
StereoEncodeState state,
|
||||
short[] x1,
|
||||
int x1_ptr,
|
||||
short[] x2,
|
||||
int x2_ptr,
|
||||
sbyte[][] ix,
|
||||
BoxedValueSbyte mid_only_flag,
|
||||
int[] mid_side_rates_bps,
|
||||
int total_rate_bps,
|
||||
int prev_speech_act_Q8,
|
||||
int toMono,
|
||||
int fs_kHz,
|
||||
int frame_length)
|
||||
{
|
||||
int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13;
|
||||
int sum, diff, smooth_coef_Q16, pred0_Q13, pred1_Q13;
|
||||
int[] pred_Q13 = new int[2];
|
||||
int frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24;
|
||||
BoxedValueInt LP_ratio_Q14 = new BoxedValueInt();
|
||||
BoxedValueInt HP_ratio_Q14 = new BoxedValueInt();
|
||||
short[] side;
|
||||
short[] LP_mid;
|
||||
short[] HP_mid;
|
||||
short[] LP_side;
|
||||
short[] HP_side;
|
||||
int mid = x1_ptr - 2;
|
||||
|
||||
side = new short[frame_length + 2];
|
||||
|
||||
/* Convert to basic mid/side signals */
|
||||
for (n = 0; n < frame_length + 2; n++)
|
||||
{
|
||||
sum = x1[x1_ptr + n - 2] + (int)x2[x2_ptr + n - 2];
|
||||
diff = x1[x1_ptr + n - 2] - (int)x2[x2_ptr + n - 2];
|
||||
x1[mid + n] = (short)Inlines.silk_RSHIFT_ROUND(sum, 1);
|
||||
side[n] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(diff, 1));
|
||||
}
|
||||
|
||||
/* Buffering */
|
||||
Array.Copy(state.sMid, 0, x1, mid, 2);
|
||||
Array.Copy(state.sSide, side, 2);
|
||||
Array.Copy(x1, mid + frame_length, state.sMid, 0, 2);
|
||||
Array.Copy(side, frame_length, state.sSide, 0, 2);
|
||||
|
||||
/* LP and HP filter mid signal */
|
||||
LP_mid = new short[frame_length];
|
||||
HP_mid = new short[frame_length];
|
||||
for (n = 0; n < frame_length; n++)
|
||||
{
|
||||
sum = Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD_LSHIFT32(x1[mid + n] + x1[mid + n + 2], x1[mid + n + 1], 1), 2);
|
||||
LP_mid[n] = (short)(sum);
|
||||
HP_mid[n] = (short)(x1[mid + n + 1] - sum);
|
||||
}
|
||||
|
||||
/* LP and HP filter side signal */
|
||||
LP_side = new short[frame_length];
|
||||
HP_side = new short[frame_length];
|
||||
for (n = 0; n < frame_length; n++)
|
||||
{
|
||||
sum = Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD_LSHIFT32(side[n] + side[n + 2], side[n + 1], 1), 2);
|
||||
LP_side[n] = (short)(sum);
|
||||
HP_side[n] = (short)(side[n + 1] - sum);
|
||||
}
|
||||
|
||||
/* Find energies and predictors */
|
||||
is10msFrame = (frame_length == 10 * fs_kHz ? 1 : 0);
|
||||
smooth_coef_Q16 = is10msFrame != 0 ?
|
||||
((int)((SilkConstants.STEREO_RATIO_SMOOTH_COEF / 2) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.STEREO_RATIO_SMOOTH_COEF / 2, 16)*/ :
|
||||
((int)((SilkConstants.STEREO_RATIO_SMOOTH_COEF) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.STEREO_RATIO_SMOOTH_COEF, 16)*/;
|
||||
smooth_coef_Q16 = Inlines.silk_SMULWB(Inlines.silk_SMULBB(prev_speech_act_Q8, prev_speech_act_Q8), smooth_coef_Q16);
|
||||
|
||||
pred_Q13[0] = silk_stereo_find_predictor(LP_ratio_Q14, LP_mid, LP_side, state.mid_side_amp_Q0, 0, frame_length, smooth_coef_Q16);
|
||||
pred_Q13[1] = silk_stereo_find_predictor(HP_ratio_Q14, HP_mid, HP_side, state.mid_side_amp_Q0, 2, frame_length, smooth_coef_Q16);
|
||||
|
||||
/* Ratio of the norms of residual and mid signals */
|
||||
frac_Q16 = Inlines.silk_SMLABB(HP_ratio_Q14.Val, LP_ratio_Q14.Val, 3);
|
||||
frac_Q16 = Inlines.silk_min(frac_Q16, ((int)((1) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1, 16)*/);
|
||||
|
||||
/* Determine bitrate distribution between mid and side, and possibly reduce stereo width */
|
||||
total_rate_bps -= is10msFrame != 0 ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */
|
||||
if (total_rate_bps < 1)
|
||||
{
|
||||
total_rate_bps = 1;
|
||||
}
|
||||
min_mid_rate_bps = Inlines.silk_SMLABB(2000, fs_kHz, 900);
|
||||
Inlines.OpusAssert(min_mid_rate_bps < 32767);
|
||||
/* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */
|
||||
frac_3_Q16 = Inlines.silk_MUL(3, frac_Q16);
|
||||
mid_side_rates_bps[0] = Inlines.silk_DIV32_varQ(total_rate_bps, ((int)((8 + 5) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(8 + 5, 16)*/ + frac_3_Q16, 16 + 3);
|
||||
/* If Mid bitrate below minimum, reduce stereo width */
|
||||
if (mid_side_rates_bps[0] < min_mid_rate_bps)
|
||||
{
|
||||
mid_side_rates_bps[0] = min_mid_rate_bps;
|
||||
mid_side_rates_bps[1] = total_rate_bps - mid_side_rates_bps[0];
|
||||
/* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */
|
||||
width_Q14 = Inlines.silk_DIV32_varQ(Inlines.silk_LSHIFT(mid_side_rates_bps[1], 1) - min_mid_rate_bps,
|
||||
Inlines.silk_SMULWB(((int)((1) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1, 16)*/ + frac_3_Q16, min_mid_rate_bps), 14 + 2);
|
||||
width_Q14 = Inlines.silk_LIMIT(width_Q14, 0, ((int)((1) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1, 14)*/);
|
||||
}
|
||||
else {
|
||||
mid_side_rates_bps[1] = total_rate_bps - mid_side_rates_bps[0];
|
||||
width_Q14 = ((int)((1) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1, 14)*/;
|
||||
}
|
||||
|
||||
/* Smoother */
|
||||
state.smth_width_Q14 = (short)Inlines.silk_SMLAWB(state.smth_width_Q14, width_Q14 - state.smth_width_Q14, smooth_coef_Q16);
|
||||
|
||||
/* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */
|
||||
mid_only_flag.Val = 0;
|
||||
if (toMono != 0)
|
||||
{
|
||||
/* Last frame before stereo.mono transition; collapse stereo width */
|
||||
width_Q14 = 0;
|
||||
pred_Q13[0] = 0;
|
||||
pred_Q13[1] = 0;
|
||||
silk_stereo_quant_pred(pred_Q13, ix);
|
||||
}
|
||||
else if (state.width_prev_Q14 == 0 &&
|
||||
(8 * total_rate_bps < 13 * min_mid_rate_bps || Inlines.silk_SMULWB(frac_Q16, state.smth_width_Q14) < ((int)((0.05f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(0.05f, 14)*/))
|
||||
{
|
||||
/* Code as panned-mono; previous frame already had zero width */
|
||||
/* Scale down and quantize predictors */
|
||||
pred_Q13[0] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[0]), 14);
|
||||
pred_Q13[1] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[1]), 14);
|
||||
silk_stereo_quant_pred(pred_Q13, ix);
|
||||
/* Collapse stereo width */
|
||||
width_Q14 = 0;
|
||||
pred_Q13[0] = 0;
|
||||
pred_Q13[1] = 0;
|
||||
mid_side_rates_bps[0] = total_rate_bps;
|
||||
mid_side_rates_bps[1] = 0;
|
||||
mid_only_flag.Val = 1;
|
||||
}
|
||||
else if (state.width_prev_Q14 != 0 &&
|
||||
(8 * total_rate_bps < 11 * min_mid_rate_bps || Inlines.silk_SMULWB(frac_Q16, state.smth_width_Q14) < ((int)((0.02f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(0.02f, 14)*/))
|
||||
{
|
||||
/* Transition to zero-width stereo */
|
||||
/* Scale down and quantize predictors */
|
||||
pred_Q13[0] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[0]), 14);
|
||||
pred_Q13[1] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[1]), 14);
|
||||
silk_stereo_quant_pred(pred_Q13, ix);
|
||||
/* Collapse stereo width */
|
||||
width_Q14 = 0;
|
||||
pred_Q13[0] = 0;
|
||||
pred_Q13[1] = 0;
|
||||
}
|
||||
else if (state.smth_width_Q14 > ((int)((0.95f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(0.95f, 14)*/)
|
||||
{
|
||||
/* Full-width stereo coding */
|
||||
silk_stereo_quant_pred(pred_Q13, ix);
|
||||
width_Q14 = ((int)((1) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1, 14)*/;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reduced-width stereo coding; scale down and quantize predictors */
|
||||
pred_Q13[0] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[0]), 14);
|
||||
pred_Q13[1] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[1]), 14);
|
||||
silk_stereo_quant_pred(pred_Q13, ix);
|
||||
width_Q14 = state.smth_width_Q14;
|
||||
}
|
||||
|
||||
/* Make sure to keep on encoding until the tapered output has been transmitted */
|
||||
if (mid_only_flag.Val == 1)
|
||||
{
|
||||
state.silent_side_len += (short)(frame_length - SilkConstants.STEREO_INTERP_LEN_MS * fs_kHz);
|
||||
if (state.silent_side_len < SilkConstants.LA_SHAPE_MS * fs_kHz)
|
||||
{
|
||||
mid_only_flag.Val = 0;
|
||||
}
|
||||
else {
|
||||
/* Limit to avoid wrapping around */
|
||||
state.silent_side_len = 10000;
|
||||
}
|
||||
}
|
||||
else {
|
||||
state.silent_side_len = 0;
|
||||
}
|
||||
|
||||
if (mid_only_flag.Val == 0 && mid_side_rates_bps[1] < 1)
|
||||
{
|
||||
mid_side_rates_bps[1] = 1;
|
||||
mid_side_rates_bps[0] = Inlines.silk_max_int(1, total_rate_bps - mid_side_rates_bps[1]);
|
||||
}
|
||||
|
||||
/* Interpolate predictors and subtract prediction from side channel */
|
||||
pred0_Q13 = -state.pred_prev_Q13[0];
|
||||
pred1_Q13 = -state.pred_prev_Q13[1];
|
||||
w_Q24 = Inlines.silk_LSHIFT(state.width_prev_Q14, 10);
|
||||
denom_Q16 = Inlines.silk_DIV32_16((int)1 << 16, SilkConstants.STEREO_INTERP_LEN_MS * fs_kHz);
|
||||
delta0_Q13 = 0 - Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[0] - state.pred_prev_Q13[0], denom_Q16), 16);
|
||||
delta1_Q13 = 0 - Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[1] - state.pred_prev_Q13[1], denom_Q16), 16);
|
||||
deltaw_Q24 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(width_Q14 - state.width_prev_Q14, denom_Q16), 10);
|
||||
for (n = 0; n < SilkConstants.STEREO_INTERP_LEN_MS * fs_kHz; n++)
|
||||
{
|
||||
pred0_Q13 += delta0_Q13;
|
||||
pred1_Q13 += delta1_Q13;
|
||||
w_Q24 += deltaw_Q24;
|
||||
sum = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[mid + n] + x1[mid + n + 2], x1[mid + n + 1], 1), 9); /* Q11 */
|
||||
sum = Inlines.silk_SMLAWB(Inlines.silk_SMULWB(w_Q24, side[n + 1]), sum, pred0_Q13); /* Q8 */
|
||||
sum = Inlines.silk_SMLAWB(sum, Inlines.silk_LSHIFT((int)x1[mid + n + 1], 11), pred1_Q13); /* Q8 */
|
||||
x2[x2_ptr + n - 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sum, 8));
|
||||
}
|
||||
|
||||
pred0_Q13 = 0 - pred_Q13[0];
|
||||
pred1_Q13 = 0 - pred_Q13[1];
|
||||
w_Q24 = Inlines.silk_LSHIFT(width_Q14, 10);
|
||||
for (n = SilkConstants.STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++)
|
||||
{
|
||||
sum = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[mid + n] + x1[mid + n + 2], x1[mid + n + 1], 1), 9); /* Q11 */
|
||||
sum = Inlines.silk_SMLAWB(Inlines.silk_SMULWB(w_Q24, side[n + 1]), sum, pred0_Q13); /* Q8 */
|
||||
sum = Inlines.silk_SMLAWB(sum, Inlines.silk_LSHIFT((int)x1[mid + n + 1], 11), pred1_Q13); /* Q8 */
|
||||
x2[x2_ptr + n - 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sum, 8));
|
||||
}
|
||||
state.pred_prev_Q13[0] = (short)pred_Q13[0];
|
||||
state.pred_prev_Q13[1] = (short)pred_Q13[1];
|
||||
state.width_prev_Q14 = (short)width_Q14;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert adaptive Mid/Side representation to Left/Right stereo signal
|
||||
/// </summary>
|
||||
/// <param name="state">I/O State</param>
|
||||
/// <param name="x1">I/O Left input signal, becomes mid signal</param>
|
||||
/// <param name="x2">I/O Right input signal, becomes side signal</param>
|
||||
/// <param name="pred_Q13">I Predictors</param>
|
||||
/// <param name="fs_kHz">I Samples rate (kHz)</param>
|
||||
/// <param name="frame_length">I Number of samples</param>
|
||||
internal static void silk_stereo_MS_to_LR(
|
||||
StereoDecodeState state,
|
||||
short[] x1,
|
||||
int x1_ptr,
|
||||
short[] x2,
|
||||
int x2_ptr,
|
||||
int[] pred_Q13,
|
||||
int fs_kHz,
|
||||
int frame_length)
|
||||
{
|
||||
int n, denom_Q16, delta0_Q13, delta1_Q13;
|
||||
int sum, diff, pred0_Q13, pred1_Q13;
|
||||
|
||||
/* Buffering */
|
||||
Array.Copy(state.sMid, 0, x1, x1_ptr, 2);
|
||||
Array.Copy(state.sSide, 0, x2, x2_ptr, 2);
|
||||
Array.Copy(x1, x1_ptr + frame_length, state.sMid, 0, 2);
|
||||
Array.Copy(x2, x2_ptr + frame_length, state.sSide, 0, 2);
|
||||
|
||||
/* Interpolate predictors and add prediction to side channel */
|
||||
pred0_Q13 = state.pred_prev_Q13[0];
|
||||
pred1_Q13 = state.pred_prev_Q13[1];
|
||||
denom_Q16 = Inlines.silk_DIV32_16((int)1 << 16, SilkConstants.STEREO_INTERP_LEN_MS * fs_kHz);
|
||||
delta0_Q13 = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[0] - state.pred_prev_Q13[0], denom_Q16), 16);
|
||||
delta1_Q13 = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[1] - state.pred_prev_Q13[1], denom_Q16), 16);
|
||||
for (n = 0; n < SilkConstants.STEREO_INTERP_LEN_MS * fs_kHz; n++)
|
||||
{
|
||||
pred0_Q13 += delta0_Q13;
|
||||
pred1_Q13 += delta1_Q13;
|
||||
sum = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[x1_ptr + n] + x1[x1_ptr + n + 2], x1[x1_ptr + n + 1], 1), 9); /* Q11 */
|
||||
sum = Inlines.silk_SMLAWB(Inlines.silk_LSHIFT((int)x2[x2_ptr + n + 1], 8), sum, pred0_Q13); /* Q8 */
|
||||
sum = Inlines.silk_SMLAWB(sum, Inlines.silk_LSHIFT((int)x1[x1_ptr + n + 1], 11), pred1_Q13); /* Q8 */
|
||||
x2[x2_ptr + n + 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sum, 8));
|
||||
}
|
||||
pred0_Q13 = pred_Q13[0];
|
||||
pred1_Q13 = pred_Q13[1];
|
||||
for (n = SilkConstants.STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++)
|
||||
{
|
||||
sum = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[x1_ptr + n] + x1[x1_ptr + n + 2], x1[x1_ptr + n + 1], 1), 9); /* Q11 */
|
||||
sum = Inlines.silk_SMLAWB(Inlines.silk_LSHIFT((int)x2[x2_ptr + n + 1], 8), sum, pred0_Q13); /* Q8 */
|
||||
sum = Inlines.silk_SMLAWB(sum, Inlines.silk_LSHIFT((int)x1[x1_ptr + n + 1], 11), pred1_Q13); /* Q8 */
|
||||
x2[x2_ptr + n + 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sum, 8));
|
||||
}
|
||||
state.pred_prev_Q13[0] = (short)(pred_Q13[0]);
|
||||
state.pred_prev_Q13[1] = (short)(pred_Q13[1]);
|
||||
|
||||
/* Convert to left/right signals */
|
||||
for (n = 0; n < frame_length; n++)
|
||||
{
|
||||
sum = x1[x1_ptr + n + 1] + (int)x2[x2_ptr + n + 1];
|
||||
diff = x1[x1_ptr + n + 1] - (int)x2[x2_ptr + n + 1];
|
||||
x1[x1_ptr + n + 1] = (short)Inlines.silk_SAT16(sum);
|
||||
x2[x2_ptr + n + 1] = (short)Inlines.silk_SAT16(diff);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Quantize mid/side predictors
|
||||
/// </summary>
|
||||
/// <param name="pred_Q13">I/O Predictors (out: quantized)</param>
|
||||
/// <param name="ix">O Quantization indices [ 2 ][ 3 ]</param>
|
||||
internal static void silk_stereo_quant_pred(
|
||||
int[] pred_Q13,
|
||||
sbyte[][] ix)
|
||||
{
|
||||
sbyte i, j; // [porting note] these were originally ints
|
||||
int n;
|
||||
int low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0;
|
||||
|
||||
// FIXME: ix was formerly an out parameter that was newly allocated here
|
||||
// but now it relies on the caller to initialize it
|
||||
// clear ix
|
||||
Arrays.MemSetSbyte(ix[0], 0, 3);
|
||||
Arrays.MemSetSbyte(ix[1], 0, 3);
|
||||
|
||||
/* Quantize */
|
||||
for (n = 0; n < 2; n++)
|
||||
{
|
||||
/* Brute-force search over quantization levels */
|
||||
err_min_Q13 = int.MaxValue;
|
||||
for (i = 0; i < SilkConstants.STEREO_QUANT_TAB_SIZE - 1; i++)
|
||||
{
|
||||
low_Q13 = Tables.silk_stereo_pred_quant_Q13[i];
|
||||
step_Q13 = Inlines.silk_SMULWB(Tables.silk_stereo_pred_quant_Q13[i + 1] - low_Q13,
|
||||
((int)((0.5f / SilkConstants.STEREO_QUANT_SUB_STEPS) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.5f / SilkConstants.STEREO_QUANT_SUB_STEPS, 16)*/);
|
||||
|
||||
for (j = 0; j < SilkConstants.STEREO_QUANT_SUB_STEPS; j++)
|
||||
{
|
||||
lvl_Q13 = Inlines.silk_SMLABB(low_Q13, step_Q13, 2 * j + 1);
|
||||
err_Q13 = Inlines.silk_abs(pred_Q13[n] - lvl_Q13);
|
||||
if (err_Q13 < err_min_Q13)
|
||||
{
|
||||
err_min_Q13 = err_Q13;
|
||||
quant_pred_Q13 = lvl_Q13;
|
||||
ix[n][0] = i;
|
||||
ix[n][1] = j;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error increasing, so we're past the optimum */
|
||||
// FIXME: get this crap out of here
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ix[n][2] = (sbyte)(Inlines.silk_DIV32_16(ix[n][0], 3));
|
||||
ix[n][0] = (sbyte)(ix[n][0] - (sbyte)(ix[n][2] * 3));
|
||||
pred_Q13[n] = quant_pred_Q13;
|
||||
}
|
||||
|
||||
/* Subtract second from first predictor (helps when actually applying these) */
|
||||
pred_Q13[0] -= pred_Q13[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common.CPlusPlus;
|
||||
|
||||
/// <summary>
|
||||
/// Struct for CNG
|
||||
/// </summary>
|
||||
internal class CNGState
|
||||
{
|
||||
internal readonly int[] CNG_exc_buf_Q14 = new int[SilkConstants.MAX_FRAME_LENGTH];
|
||||
internal readonly short[] CNG_smth_NLSF_Q15 = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
internal readonly int[] CNG_synth_state = new int[SilkConstants.MAX_LPC_ORDER];
|
||||
internal int CNG_smth_Gain_Q16 = 0;
|
||||
internal int rand_seed = 0;
|
||||
internal int fs_kHz = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetInt(CNG_exc_buf_Q14, 0, SilkConstants.MAX_FRAME_LENGTH);
|
||||
Arrays.MemSetShort(CNG_smth_NLSF_Q15, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
Arrays.MemSetInt(CNG_synth_state, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
CNG_smth_Gain_Q16 = 0;
|
||||
rand_seed = 0;
|
||||
fs_kHz = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Structure for controlling decoder operation and reading decoder status
|
||||
/// </summary>
|
||||
internal class DecControlState
|
||||
{
|
||||
/* I: Number of channels; 1/2 */
|
||||
internal int nChannelsAPI = 0;
|
||||
|
||||
/* I: Number of channels; 1/2 */
|
||||
internal int nChannelsInternal = 0;
|
||||
|
||||
/* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */
|
||||
internal int API_sampleRate = 0;
|
||||
|
||||
/* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */
|
||||
internal int internalSampleRate = 0;
|
||||
|
||||
/* I: Number of samples per packet in milliseconds; 10/20/40/60 */
|
||||
internal int payloadSize_ms = 0;
|
||||
|
||||
/* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */
|
||||
internal int prevPitchLag = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
nChannelsAPI = 0;
|
||||
nChannelsInternal = 0;
|
||||
API_sampleRate = 0;
|
||||
internalSampleRate = 0;
|
||||
payloadSize_ms = 0;
|
||||
prevPitchLag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Structure for controlling encoder operation
|
||||
/// </summary>
|
||||
internal class EncControlState
|
||||
{
|
||||
/* I: Number of channels; 1/2 */
|
||||
internal int nChannelsAPI = 0;
|
||||
|
||||
/* I: Number of channels; 1/2 */
|
||||
internal int nChannelsInternal = 0;
|
||||
|
||||
/* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */
|
||||
internal int API_sampleRate = 0;
|
||||
|
||||
/* I: Maximum internal sampling rate in Hertz; 8000/12000/16000 */
|
||||
internal int maxInternalSampleRate = 0;
|
||||
|
||||
/* I: Minimum internal sampling rate in Hertz; 8000/12000/16000 */
|
||||
internal int minInternalSampleRate = 0;
|
||||
|
||||
/* I: Soft request for internal sampling rate in Hertz; 8000/12000/16000 */
|
||||
internal int desiredInternalSampleRate = 0;
|
||||
|
||||
/* I: Number of samples per packet in milliseconds; 10/20/40/60 */
|
||||
internal int payloadSize_ms = 0;
|
||||
|
||||
/* I: Bitrate during active speech in bits/second; internally limited */
|
||||
internal int bitRate = 0;
|
||||
|
||||
/* I: Uplink packet loss in percent (0-100) */
|
||||
internal int packetLossPercentage = 0;
|
||||
|
||||
/* I: Complexity mode; 0 is lowest, 10 is highest complexity */
|
||||
internal int complexity = 0;
|
||||
|
||||
/* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */
|
||||
internal int useInBandFEC = 0;
|
||||
|
||||
/* I: Flag to enable discontinuous transmission (DTX); 0/1 */
|
||||
internal int useDTX = 0;
|
||||
|
||||
/* I: Flag to use constant bitrate */
|
||||
internal int useCBR = 0;
|
||||
|
||||
/* I: Maximum number of bits allowed for the frame */
|
||||
internal int maxBits = 0;
|
||||
|
||||
/* I: Causes a smooth downmix to mono */
|
||||
internal int toMono = 0;
|
||||
|
||||
/* I: Opus encoder is allowing us to switch bandwidth */
|
||||
internal int opusCanSwitch = 0;
|
||||
|
||||
/* I: Make frames as independent as possible (but still use LPC) */
|
||||
internal int reducedDependency = 0;
|
||||
|
||||
/* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */
|
||||
internal int internalSampleRate = 0;
|
||||
|
||||
/* O: Flag that bandwidth switching is allowed (because low voice activity) */
|
||||
internal int allowBandwidthSwitch = 0;
|
||||
|
||||
/* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */
|
||||
internal int inWBmodeWithoutVariableLP = 0;
|
||||
|
||||
/* O: Stereo width */
|
||||
internal int stereoWidth_Q14 = 0;
|
||||
|
||||
/* O: Tells the Opus encoder we're ready to switch */
|
||||
internal int switchReady = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
nChannelsAPI = 0;
|
||||
nChannelsInternal = 0;
|
||||
API_sampleRate = 0;
|
||||
maxInternalSampleRate = 0;
|
||||
minInternalSampleRate = 0;
|
||||
desiredInternalSampleRate = 0;
|
||||
payloadSize_ms = 0;
|
||||
bitRate = 0;
|
||||
packetLossPercentage = 0;
|
||||
complexity = 0;
|
||||
useInBandFEC = 0;
|
||||
useDTX = 0;
|
||||
useCBR = 0;
|
||||
maxBits = 0;
|
||||
toMono = 0;
|
||||
opusCanSwitch = 0;
|
||||
reducedDependency = 0;
|
||||
internalSampleRate = 0;
|
||||
allowBandwidthSwitch = 0;
|
||||
inWBmodeWithoutVariableLP = 0;
|
||||
stereoWidth_Q14 = 0;
|
||||
switchReady = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks this encoder control struct and returns error code, if any
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal int check_control_input()
|
||||
{
|
||||
if (((API_sampleRate != 8000) &&
|
||||
(API_sampleRate != 12000) &&
|
||||
(API_sampleRate != 16000) &&
|
||||
(API_sampleRate != 24000) &&
|
||||
(API_sampleRate != 32000) &&
|
||||
(API_sampleRate != 44100) &&
|
||||
(API_sampleRate != 48000)) ||
|
||||
((desiredInternalSampleRate != 8000) &&
|
||||
(desiredInternalSampleRate != 12000) &&
|
||||
(desiredInternalSampleRate != 16000)) ||
|
||||
((maxInternalSampleRate != 8000) &&
|
||||
(maxInternalSampleRate != 12000) &&
|
||||
(maxInternalSampleRate != 16000)) ||
|
||||
((minInternalSampleRate != 8000) &&
|
||||
(minInternalSampleRate != 12000) &&
|
||||
(minInternalSampleRate != 16000)) ||
|
||||
(minInternalSampleRate > desiredInternalSampleRate) ||
|
||||
(maxInternalSampleRate < desiredInternalSampleRate) ||
|
||||
(minInternalSampleRate > maxInternalSampleRate))
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_FS_NOT_SUPPORTED;
|
||||
}
|
||||
if (payloadSize_ms != 10 &&
|
||||
payloadSize_ms != 20 &&
|
||||
payloadSize_ms != 40 &&
|
||||
payloadSize_ms != 60)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
|
||||
}
|
||||
if (packetLossPercentage < 0 || packetLossPercentage > 100)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INVALID_LOSS_RATE;
|
||||
}
|
||||
if (useDTX < 0 || useDTX > 1)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INVALID_DTX_SETTING;
|
||||
}
|
||||
if (useCBR < 0 || useCBR > 1)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INVALID_CBR_SETTING;
|
||||
}
|
||||
if (useInBandFEC < 0 || useInBandFEC > 1)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INVALID_INBAND_FEC_SETTING;
|
||||
}
|
||||
if (nChannelsAPI < 1 || nChannelsAPI > SilkConstants.ENCODER_NUM_CHANNELS)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
|
||||
}
|
||||
if (nChannelsInternal < 1 || nChannelsInternal > SilkConstants.ENCODER_NUM_CHANNELS)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
|
||||
}
|
||||
if (nChannelsInternal > nChannelsAPI)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
|
||||
}
|
||||
if (complexity < 0 || complexity > 10)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INVALID_COMPLEXITY_SETTING;
|
||||
}
|
||||
|
||||
return SilkError.SILK_NO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Structure containing NLSF codebook
|
||||
/// </summary>
|
||||
internal class NLSFCodebook
|
||||
{
|
||||
internal short nVectors = 0;
|
||||
|
||||
internal short order = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Quantization step size
|
||||
/// </summary>
|
||||
internal short quantStepSize_Q16 = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Inverse quantization step size
|
||||
/// </summary>
|
||||
internal short invQuantStepSize_Q6 = 0;
|
||||
|
||||
/// <summary>
|
||||
/// POINTER
|
||||
/// </summary>
|
||||
internal byte[] CB1_NLSF_Q8 = null;
|
||||
|
||||
/// <summary>
|
||||
/// POINTER
|
||||
/// </summary>
|
||||
internal byte[] CB1_iCDF = null;
|
||||
|
||||
/// <summary>
|
||||
/// POINTER to Backward predictor coefs [ order ]
|
||||
/// </summary>
|
||||
internal byte[] pred_Q8 = null;
|
||||
|
||||
/// <summary>
|
||||
/// POINTER to Indices to entropy coding tables [ order ]
|
||||
/// </summary>
|
||||
internal byte[] ec_sel = null;
|
||||
|
||||
/// <summary>
|
||||
/// POINTER
|
||||
/// </summary>
|
||||
internal byte[] ec_iCDF = null;
|
||||
|
||||
/// <summary>
|
||||
/// POINTER
|
||||
/// </summary>
|
||||
internal byte[] ec_Rates_Q5 = null;
|
||||
|
||||
/// <summary>
|
||||
/// POINTER
|
||||
/// </summary>
|
||||
internal short[] deltaMin_Q15 = null;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
nVectors = 0;
|
||||
order = 0;
|
||||
quantStepSize_Q16 = 0;
|
||||
invQuantStepSize_Q6 = 0;
|
||||
CB1_NLSF_Q8 = null;
|
||||
CB1_iCDF = null;
|
||||
pred_Q8 = null;
|
||||
ec_sel = null;
|
||||
ec_iCDF = null;
|
||||
ec_Rates_Q5 = null;
|
||||
deltaMin_Q15 = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Struct for Packet Loss Concealment
|
||||
/// </summary>
|
||||
internal class PLCStruct
|
||||
{
|
||||
internal int pitchL_Q8 = 0; /* Pitch lag to use for voiced concealment */
|
||||
internal readonly short[] LTPCoef_Q14 = new short[SilkConstants.LTP_ORDER]; /* LTP coeficients to use for voiced concealment */
|
||||
internal readonly short[] prevLPC_Q12 = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
internal int last_frame_lost = 0; /* Was previous frame lost */
|
||||
internal int rand_seed = 0; /* Seed for unvoiced signal generation */
|
||||
internal short randScale_Q14 = 0; /* Scaling of unvoiced random signal */
|
||||
internal int conc_energy = 0;
|
||||
internal int conc_energy_shift = 0;
|
||||
internal short prevLTP_scale_Q14 = 0;
|
||||
internal readonly int[] prevGain_Q16 = new int[2];
|
||||
internal int fs_kHz = 0;
|
||||
internal int nb_subfr = 0;
|
||||
internal int subfr_length = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
pitchL_Q8 = 0;
|
||||
Arrays.MemSetShort(LTPCoef_Q14, 0, SilkConstants.LTP_ORDER);
|
||||
Arrays.MemSetShort(prevLPC_Q12, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
last_frame_lost = 0;
|
||||
rand_seed = 0;
|
||||
randScale_Q14 = 0;
|
||||
conc_energy = 0;
|
||||
conc_energy_shift = 0;
|
||||
prevLTP_scale_Q14 = 0;
|
||||
Arrays.MemSetInt(prevGain_Q16, 0, 2);
|
||||
fs_kHz = 0;
|
||||
nb_subfr = 0;
|
||||
subfr_length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using System;
|
||||
|
||||
internal class SideInfoIndices
|
||||
{
|
||||
internal readonly sbyte[] GainsIndices = new sbyte[SilkConstants.MAX_NB_SUBFR];
|
||||
internal readonly sbyte[] LTPIndex = new sbyte[SilkConstants.MAX_NB_SUBFR];
|
||||
internal readonly sbyte[] NLSFIndices = new sbyte[SilkConstants.MAX_LPC_ORDER + 1];
|
||||
internal short lagIndex = 0;
|
||||
internal sbyte contourIndex = 0;
|
||||
internal sbyte signalType = 0;
|
||||
internal sbyte quantOffsetType = 0;
|
||||
internal sbyte NLSFInterpCoef_Q2 = 0;
|
||||
internal sbyte PERIndex = 0;
|
||||
internal sbyte LTP_scaleIndex = 0;
|
||||
internal sbyte Seed = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetSbyte(GainsIndices, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetSbyte(LTPIndex, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetSbyte(NLSFIndices, 0, SilkConstants.MAX_LPC_ORDER + 1);
|
||||
lagIndex = 0;
|
||||
contourIndex = 0;
|
||||
signalType = 0;
|
||||
quantOffsetType = 0;
|
||||
NLSFInterpCoef_Q2 = 0;
|
||||
PERIndex = 0;
|
||||
LTP_scaleIndex = 0;
|
||||
Seed = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overwrites this struct with values from another one. Equivalent to C struct assignment this = other
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
internal void Assign(SideInfoIndices other)
|
||||
{
|
||||
Array.Copy(other.GainsIndices, this.GainsIndices, SilkConstants.MAX_NB_SUBFR);
|
||||
Array.Copy(other.LTPIndex, this.LTPIndex, SilkConstants.MAX_NB_SUBFR);
|
||||
Array.Copy(other.NLSFIndices, this.NLSFIndices, SilkConstants.MAX_LPC_ORDER + 1);
|
||||
this.lagIndex = other.lagIndex;
|
||||
this.contourIndex = other.contourIndex;
|
||||
this.signalType = other.signalType;
|
||||
this.quantOffsetType = other.quantOffsetType;
|
||||
this.NLSFInterpCoef_Q2 = other.NLSFInterpCoef_Q2;
|
||||
this.PERIndex = other.PERIndex;
|
||||
this.LTP_scaleIndex = other.LTP_scaleIndex;
|
||||
this.Seed = other.Seed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using System;
|
||||
/// <summary>
|
||||
/// Decoder state
|
||||
/// </summary>
|
||||
internal class SilkChannelDecoder
|
||||
{
|
||||
internal int prev_gain_Q16 = 0;
|
||||
internal readonly int[] exc_Q14 = new int[SilkConstants.MAX_FRAME_LENGTH];
|
||||
internal readonly int[] sLPC_Q14_buf = new int[SilkConstants.MAX_LPC_ORDER];
|
||||
internal readonly short[] outBuf = new short[SilkConstants.MAX_FRAME_LENGTH + 2 * SilkConstants.MAX_SUB_FRAME_LENGTH]; /* Buffer for output signal */
|
||||
internal int lagPrev = 0; /* Previous Lag */
|
||||
internal sbyte LastGainIndex = 0; /* Previous gain index */
|
||||
internal int fs_kHz = 0; /* Sampling frequency in kHz */
|
||||
internal int fs_API_hz = 0; /* API sample frequency (Hz) */
|
||||
internal int nb_subfr = 0; /* Number of 5 ms subframes in a frame */
|
||||
internal int frame_length = 0; /* Frame length (samples) */
|
||||
internal int subfr_length = 0; /* Subframe length (samples) */
|
||||
internal int ltp_mem_length = 0; /* Length of LTP memory */
|
||||
internal int LPC_order = 0; /* LPC order */
|
||||
internal readonly short[] prevNLSF_Q15 = new short[SilkConstants.MAX_LPC_ORDER]; /* Used to interpolate LSFs */
|
||||
internal int first_frame_after_reset = 0; /* Flag for deactivating NLSF interpolation */
|
||||
internal byte[] pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */
|
||||
internal byte[] pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */
|
||||
|
||||
/* For buffering payload in case of more frames per packet */
|
||||
internal int nFramesDecoded = 0;
|
||||
internal int nFramesPerPacket = 0;
|
||||
|
||||
/* Specifically for entropy coding */
|
||||
internal int ec_prevSignalType = 0;
|
||||
internal short ec_prevLagIndex = 0;
|
||||
|
||||
internal readonly int[] VAD_flags = new int[SilkConstants.MAX_FRAMES_PER_PACKET];
|
||||
internal int LBRR_flag = 0;
|
||||
internal readonly int[] LBRR_flags = new int[SilkConstants.MAX_FRAMES_PER_PACKET];
|
||||
|
||||
internal readonly SilkResamplerState resampler_state = new SilkResamplerState();
|
||||
|
||||
internal NLSFCodebook psNLSF_CB = null; /* Pointer to NLSF codebook */
|
||||
|
||||
/* Quantization indices */
|
||||
internal readonly SideInfoIndices indices = new SideInfoIndices();
|
||||
|
||||
/* CNG state */
|
||||
internal readonly CNGState sCNG = new CNGState();
|
||||
|
||||
/* Stuff used for PLC */
|
||||
internal int lossCnt = 0;
|
||||
internal int prevSignalType = 0;
|
||||
|
||||
internal readonly PLCStruct sPLC = new PLCStruct();
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
prev_gain_Q16 = 0;
|
||||
Arrays.MemSetInt(exc_Q14, 0, SilkConstants.MAX_FRAME_LENGTH);
|
||||
Arrays.MemSetInt(sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
Arrays.MemSetShort(outBuf, 0, SilkConstants.MAX_FRAME_LENGTH + 2 * SilkConstants.MAX_SUB_FRAME_LENGTH);
|
||||
lagPrev = 0;
|
||||
LastGainIndex = 0;
|
||||
fs_kHz = 0;
|
||||
fs_API_hz = 0;
|
||||
nb_subfr = 0;
|
||||
frame_length = 0;
|
||||
subfr_length = 0;
|
||||
ltp_mem_length = 0;
|
||||
LPC_order = 0;
|
||||
Arrays.MemSetShort(prevNLSF_Q15, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
first_frame_after_reset = 0;
|
||||
pitch_lag_low_bits_iCDF = null;
|
||||
pitch_contour_iCDF = null;
|
||||
nFramesDecoded = 0;
|
||||
nFramesPerPacket = 0;
|
||||
ec_prevSignalType = 0;
|
||||
ec_prevLagIndex = 0;
|
||||
Arrays.MemSetInt(VAD_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
|
||||
LBRR_flag = 0;
|
||||
Arrays.MemSetInt(LBRR_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
|
||||
resampler_state.Reset();
|
||||
psNLSF_CB = null;
|
||||
indices.Reset();
|
||||
sCNG.Reset();
|
||||
lossCnt = 0;
|
||||
prevSignalType = 0;
|
||||
sPLC.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init Decoder State
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal int silk_init_decoder()
|
||||
{
|
||||
/* Clear the entire encoder state, except anything copied */
|
||||
this.Reset();
|
||||
|
||||
/* Used to deactivate LSF interpolation */
|
||||
this.first_frame_after_reset = 1;
|
||||
this.prev_gain_Q16 = 65536;
|
||||
|
||||
/* Reset CNG state */
|
||||
silk_CNG_Reset();
|
||||
|
||||
/* Reset PLC state */
|
||||
silk_PLC_Reset();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets CNG state
|
||||
/// </summary>
|
||||
private void silk_CNG_Reset()
|
||||
{
|
||||
int i, NLSF_step_Q15, NLSF_acc_Q15;
|
||||
|
||||
NLSF_step_Q15 = Inlines.silk_DIV32_16(short.MaxValue, this.LPC_order + 1);
|
||||
NLSF_acc_Q15 = 0;
|
||||
for (i = 0; i < this.LPC_order; i++)
|
||||
{
|
||||
NLSF_acc_Q15 += NLSF_step_Q15;
|
||||
this.sCNG.CNG_smth_NLSF_Q15[i] = (short)(NLSF_acc_Q15);
|
||||
}
|
||||
this.sCNG.CNG_smth_Gain_Q16 = 0;
|
||||
this.sCNG.rand_seed = 3176576;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets PLC state
|
||||
/// </summary>
|
||||
private void silk_PLC_Reset()
|
||||
{
|
||||
this.sPLC.pitchL_Q8 = Inlines.silk_LSHIFT(this.frame_length, 8 - 1);
|
||||
this.sPLC.prevGain_Q16[0] = ((int)((1) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1, 16)*/;
|
||||
this.sPLC.prevGain_Q16[1] = ((int)((1) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1, 16)*/;
|
||||
this.sPLC.subfr_length = 20;
|
||||
this.sPLC.nb_subfr = 2;
|
||||
}
|
||||
|
||||
/* Set decoder sampling rate */
|
||||
internal int silk_decoder_set_fs(
|
||||
int fs_kHz, /* I Sampling frequency (kHz) */
|
||||
int fs_API_Hz /* I API Sampling frequency (Hz) */
|
||||
)
|
||||
{
|
||||
int frame_length, ret = 0;
|
||||
|
||||
Inlines.OpusAssert(fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16);
|
||||
Inlines.OpusAssert(this.nb_subfr == SilkConstants.MAX_NB_SUBFR || this.nb_subfr == SilkConstants.MAX_NB_SUBFR / 2);
|
||||
|
||||
/* New (sub)frame length */
|
||||
this.subfr_length = Inlines.silk_SMULBB(SilkConstants.SUB_FRAME_LENGTH_MS, fs_kHz);
|
||||
frame_length = Inlines.silk_SMULBB(this.nb_subfr, this.subfr_length);
|
||||
|
||||
/* Initialize resampler when switching internal or external sampling frequency */
|
||||
if (this.fs_kHz != fs_kHz || this.fs_API_hz != fs_API_Hz)
|
||||
{
|
||||
/* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */
|
||||
ret += Resampler.silk_resampler_init(this.resampler_state, Inlines.silk_SMULBB(fs_kHz, 1000), fs_API_Hz, 0);
|
||||
|
||||
this.fs_API_hz = fs_API_Hz;
|
||||
}
|
||||
|
||||
if (this.fs_kHz != fs_kHz || frame_length != this.frame_length)
|
||||
{
|
||||
if (fs_kHz == 8)
|
||||
{
|
||||
if (this.nb_subfr == SilkConstants.MAX_NB_SUBFR)
|
||||
{
|
||||
this.pitch_contour_iCDF = Tables.silk_pitch_contour_NB_iCDF;
|
||||
}
|
||||
else {
|
||||
this.pitch_contour_iCDF = Tables.silk_pitch_contour_10_ms_NB_iCDF;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.nb_subfr == SilkConstants.MAX_NB_SUBFR)
|
||||
{
|
||||
this.pitch_contour_iCDF = Tables.silk_pitch_contour_iCDF;
|
||||
}
|
||||
else {
|
||||
this.pitch_contour_iCDF = Tables.silk_pitch_contour_10_ms_iCDF;
|
||||
}
|
||||
}
|
||||
if (this.fs_kHz != fs_kHz)
|
||||
{
|
||||
this.ltp_mem_length = Inlines.silk_SMULBB(SilkConstants.LTP_MEM_LENGTH_MS, fs_kHz);
|
||||
if (fs_kHz == 8 || fs_kHz == 12)
|
||||
{
|
||||
this.LPC_order = SilkConstants.MIN_LPC_ORDER;
|
||||
this.psNLSF_CB = Tables.silk_NLSF_CB_NB_MB;
|
||||
}
|
||||
else {
|
||||
this.LPC_order = SilkConstants.MAX_LPC_ORDER;
|
||||
this.psNLSF_CB = Tables.silk_NLSF_CB_WB;
|
||||
}
|
||||
if (fs_kHz == 16)
|
||||
{
|
||||
this.pitch_lag_low_bits_iCDF = Tables.silk_uniform8_iCDF;
|
||||
}
|
||||
else if (fs_kHz == 12)
|
||||
{
|
||||
this.pitch_lag_low_bits_iCDF = Tables.silk_uniform6_iCDF;
|
||||
}
|
||||
else if (fs_kHz == 8)
|
||||
{
|
||||
this.pitch_lag_low_bits_iCDF = Tables.silk_uniform4_iCDF;
|
||||
}
|
||||
else {
|
||||
/* unsupported sampling rate */
|
||||
Inlines.OpusAssert(false);
|
||||
}
|
||||
this.first_frame_after_reset = 1;
|
||||
this.lagPrev = 100;
|
||||
this.LastGainIndex = 10;
|
||||
this.prevSignalType = SilkConstants.TYPE_NO_VOICE_ACTIVITY;
|
||||
Arrays.MemSetShort(this.outBuf, 0, SilkConstants.MAX_FRAME_LENGTH + 2 * SilkConstants.MAX_SUB_FRAME_LENGTH);
|
||||
Arrays.MemSetInt(this.sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
}
|
||||
|
||||
this.fs_kHz = fs_kHz;
|
||||
this.frame_length = frame_length;
|
||||
}
|
||||
|
||||
/* Check that settings are valid */
|
||||
Inlines.OpusAssert(this.frame_length > 0 && this.frame_length <= SilkConstants.MAX_FRAME_LENGTH);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Decode frame */
|
||||
/****************/
|
||||
internal int silk_decode_frame(
|
||||
EntropyCoder psRangeDec, /* I/O Compressor data structure */
|
||||
short[] pOut, /* O Pointer to output speech frame */
|
||||
int pOut_ptr,
|
||||
BoxedValueInt pN, /* O Pointer to size of output frame */
|
||||
int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
|
||||
int condCoding /* I The type of conditional coding to use */
|
||||
)
|
||||
{
|
||||
SilkDecoderControl thisCtrl = new SilkDecoderControl();
|
||||
int L, mv_len, ret = 0;
|
||||
|
||||
L = this.frame_length;
|
||||
thisCtrl.LTP_scale_Q14 = 0;
|
||||
|
||||
/* Safety checks */
|
||||
Inlines.OpusAssert(L > 0 && L <= SilkConstants.MAX_FRAME_LENGTH);
|
||||
|
||||
if (lostFlag == DecoderAPIFlag.FLAG_DECODE_NORMAL ||
|
||||
(lostFlag == DecoderAPIFlag.FLAG_DECODE_LBRR && this.LBRR_flags[this.nFramesDecoded] == 1))
|
||||
{
|
||||
short[] pulses = new short[(L + SilkConstants.SHELL_CODEC_FRAME_LENGTH - 1) & ~(SilkConstants.SHELL_CODEC_FRAME_LENGTH - 1)];
|
||||
/*********************************************/
|
||||
/* Decode quantization indices of side info */
|
||||
/*********************************************/
|
||||
DecodeIndices.silk_decode_indices(this, psRangeDec, this.nFramesDecoded, lostFlag, condCoding);
|
||||
|
||||
/*********************************************/
|
||||
/* Decode quantization indices of excitation */
|
||||
/*********************************************/
|
||||
DecodePulses.silk_decode_pulses(psRangeDec, pulses, this.indices.signalType,
|
||||
this.indices.quantOffsetType, this.frame_length);
|
||||
|
||||
/********************************************/
|
||||
/* Decode parameters and pulse signal */
|
||||
/********************************************/
|
||||
DecodeParameters.silk_decode_parameters(this, thisCtrl, condCoding);
|
||||
|
||||
/********************************************************/
|
||||
/* Run inverse NSQ */
|
||||
/********************************************************/
|
||||
DecodeCore.silk_decode_core(this, thisCtrl, pOut, pOut_ptr, pulses);
|
||||
|
||||
/********************************************************/
|
||||
/* Update PLC state */
|
||||
/********************************************************/
|
||||
PLC.silk_PLC(this, thisCtrl, pOut, pOut_ptr, 0);
|
||||
|
||||
this.lossCnt = 0;
|
||||
this.prevSignalType = this.indices.signalType;
|
||||
Inlines.OpusAssert(this.prevSignalType >= 0 && this.prevSignalType <= 2);
|
||||
|
||||
/* A frame has been decoded without errors */
|
||||
this.first_frame_after_reset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle packet loss by extrapolation */
|
||||
PLC.silk_PLC(this, thisCtrl, pOut, pOut_ptr, 1);
|
||||
}
|
||||
|
||||
/*************************/
|
||||
/* Update output buffer. */
|
||||
/*************************/
|
||||
Inlines.OpusAssert(this.ltp_mem_length >= this.frame_length);
|
||||
mv_len = this.ltp_mem_length - this.frame_length;
|
||||
Arrays.MemMoveShort(this.outBuf, this.frame_length, 0, mv_len);
|
||||
Array.Copy(pOut, pOut_ptr, this.outBuf, mv_len, this.frame_length);
|
||||
|
||||
/************************************************/
|
||||
/* Comfort noise generation / estimation */
|
||||
/************************************************/
|
||||
CNG.silk_CNG(this, thisCtrl, pOut, pOut_ptr, L);
|
||||
|
||||
/****************************************************************/
|
||||
/* Ensure smooth connection of extrapolated and good frames */
|
||||
/****************************************************************/
|
||||
PLC.silk_PLC_glue_frames(this, pOut, pOut_ptr, L);
|
||||
|
||||
/* Update some decoder state variables */
|
||||
this.lagPrev = thisCtrl.pitchL[this.nb_subfr - 1];
|
||||
|
||||
/* Set output frame length */
|
||||
pN.Val = L;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Decoder super struct
|
||||
/// </summary>
|
||||
internal class SilkDecoder
|
||||
{
|
||||
internal readonly SilkChannelDecoder[] channel_state = new SilkChannelDecoder[SilkConstants.DECODER_NUM_CHANNELS];
|
||||
internal readonly StereoDecodeState sStereo = new StereoDecodeState();
|
||||
internal int nChannelsAPI = 0;
|
||||
internal int nChannelsInternal = 0;
|
||||
internal int prev_decode_only_middle = 0;
|
||||
|
||||
internal SilkDecoder()
|
||||
{
|
||||
for (int c = 0; c < SilkConstants.DECODER_NUM_CHANNELS; c++)
|
||||
{
|
||||
channel_state[c] = new SilkChannelDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
for (int c = 0; c < SilkConstants.DECODER_NUM_CHANNELS; c++)
|
||||
{
|
||||
channel_state[c].Reset();
|
||||
}
|
||||
sStereo.Reset();
|
||||
nChannelsAPI = 0;
|
||||
nChannelsInternal = 0;
|
||||
prev_decode_only_middle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Decoder control
|
||||
/// </summary>
|
||||
internal class SilkDecoderControl
|
||||
{
|
||||
/* Prediction and coding parameters */
|
||||
internal readonly int[] pitchL = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
internal readonly int[] Gains_Q16 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
|
||||
/* Holds interpolated and final coefficients */
|
||||
internal readonly short[][] PredCoef_Q12 = Arrays.InitTwoDimensionalArray<short>(2, SilkConstants.MAX_LPC_ORDER);
|
||||
internal readonly short[] LTPCoef_Q14 = new short[SilkConstants.LTP_ORDER * SilkConstants.MAX_NB_SUBFR];
|
||||
internal int LTP_scale_Q14 = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetInt(pitchL, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetInt(Gains_Q16, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetShort(PredCoef_Q12[0], 0, SilkConstants.MAX_LPC_ORDER);
|
||||
Arrays.MemSetShort(PredCoef_Q12[1], 0, SilkConstants.MAX_LPC_ORDER);
|
||||
Arrays.MemSetShort(LTPCoef_Q14, 0, SilkConstants.LTP_ORDER * SilkConstants.MAX_NB_SUBFR);
|
||||
LTP_scale_Q14 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Encoder Super Struct
|
||||
/// </summary>
|
||||
internal class SilkEncoder
|
||||
{
|
||||
internal readonly SilkChannelEncoder[] state_Fxx = new SilkChannelEncoder[SilkConstants.ENCODER_NUM_CHANNELS];
|
||||
internal readonly StereoEncodeState sStereo = new StereoEncodeState();
|
||||
internal int nBitsUsedLBRR = 0;
|
||||
internal int nBitsExceeded = 0;
|
||||
internal int nChannelsAPI = 0;
|
||||
internal int nChannelsInternal = 0;
|
||||
internal int nPrevChannelsInternal = 0;
|
||||
internal int timeSinceSwitchAllowed_ms = 0;
|
||||
internal int allowBandwidthSwitch = 0;
|
||||
internal int prev_decode_only_middle = 0;
|
||||
|
||||
internal SilkEncoder()
|
||||
{
|
||||
for (int c = 0; c < SilkConstants.ENCODER_NUM_CHANNELS; c++)
|
||||
{
|
||||
state_Fxx[c] = new SilkChannelEncoder();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
for (int c = 0; c < SilkConstants.ENCODER_NUM_CHANNELS; c++)
|
||||
{
|
||||
state_Fxx[c].Reset();
|
||||
}
|
||||
|
||||
sStereo.Reset();
|
||||
nBitsUsedLBRR = 0;
|
||||
nBitsExceeded = 0;
|
||||
nChannelsAPI = 0;
|
||||
nChannelsInternal = 0;
|
||||
nPrevChannelsInternal = 0;
|
||||
timeSinceSwitchAllowed_ms = 0;
|
||||
allowBandwidthSwitch = 0;
|
||||
prev_decode_only_middle = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize Silk Encoder state
|
||||
/// </summary>
|
||||
/// <param name="psEnc">I/O Pointer to Silk FIX encoder state</param>
|
||||
/// <returns></returns>
|
||||
internal static int silk_init_encoder(SilkChannelEncoder psEnc)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
// Clear the entire encoder state
|
||||
psEnc.Reset();
|
||||
|
||||
psEnc.variable_HP_smth1_Q15 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(((int)((TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ, 16)*/) - (16 << 7), 8);
|
||||
psEnc.variable_HP_smth2_Q15 = psEnc.variable_HP_smth1_Q15;
|
||||
|
||||
// Used to deactivate LSF interpolation, pitch prediction
|
||||
psEnc.first_frame_after_reset = 1;
|
||||
|
||||
// Initialize Silk VAD
|
||||
ret += VoiceActivityDetection.silk_VAD_Init(psEnc.sVAD);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/************************/
|
||||
/* Encoder control FIX */
|
||||
/************************/
|
||||
internal class SilkEncoderControl
|
||||
{
|
||||
/* Prediction and coding parameters */
|
||||
internal readonly int[] Gains_Q16 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
internal readonly short[][] PredCoef_Q12 = Arrays.InitTwoDimensionalArray<short>(2, SilkConstants.MAX_LPC_ORDER); /* holds interpolated and final coefficients */
|
||||
internal readonly short[] LTPCoef_Q14 = new short[SilkConstants.LTP_ORDER * SilkConstants.MAX_NB_SUBFR];
|
||||
internal int LTP_scale_Q14 = 0;
|
||||
internal readonly int[] pitchL = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
|
||||
/* Noise shaping parameters */
|
||||
internal readonly short[] AR1_Q13 = new short[SilkConstants.MAX_NB_SUBFR * SilkConstants.MAX_SHAPE_LPC_ORDER];
|
||||
internal readonly short[] AR2_Q13 = new short[SilkConstants.MAX_NB_SUBFR * SilkConstants.MAX_SHAPE_LPC_ORDER];
|
||||
internal readonly int[] LF_shp_Q14 = new int[SilkConstants.MAX_NB_SUBFR]; /* Packs two int16 coefficients per int32 value */
|
||||
internal readonly int[] GainsPre_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
internal readonly int[] HarmBoost_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
internal readonly int[] Tilt_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
internal readonly int[] HarmShapeGain_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
internal int Lambda_Q10 = 0;
|
||||
internal int input_quality_Q14 = 0;
|
||||
internal int coding_quality_Q14 = 0;
|
||||
|
||||
/* Measures */
|
||||
internal int sparseness_Q8 = 0;
|
||||
internal int predGain_Q16 = 0;
|
||||
internal int LTPredCodGain_Q7 = 0;
|
||||
|
||||
/* Residual energy per subframe */
|
||||
internal readonly int[] ResNrg = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
|
||||
/* Q domain for the residual energy > 0 */
|
||||
internal readonly int[] ResNrgQ = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
|
||||
/* Parameters for CBR mode */
|
||||
internal readonly int[] GainsUnq_Q16 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
internal sbyte lastGainIndexPrev = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetInt(Gains_Q16, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetShort(PredCoef_Q12[0], 0, SilkConstants.MAX_LPC_ORDER);
|
||||
Arrays.MemSetShort(PredCoef_Q12[1], 0, SilkConstants.MAX_LPC_ORDER);
|
||||
Arrays.MemSetShort(LTPCoef_Q14, 0, SilkConstants.LTP_ORDER * SilkConstants.MAX_NB_SUBFR);
|
||||
LTP_scale_Q14 = 0;
|
||||
Arrays.MemSetInt(pitchL, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetShort(AR1_Q13, 0, SilkConstants.MAX_NB_SUBFR * SilkConstants.MAX_SHAPE_LPC_ORDER);
|
||||
Arrays.MemSetShort(AR2_Q13, 0, SilkConstants.MAX_NB_SUBFR * SilkConstants.MAX_SHAPE_LPC_ORDER);
|
||||
Arrays.MemSetInt(LF_shp_Q14, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetInt(GainsPre_Q14, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetInt(HarmBoost_Q14, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetInt(Tilt_Q14, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetInt(HarmShapeGain_Q14, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Lambda_Q10 = 0;
|
||||
input_quality_Q14 = 0;
|
||||
coding_quality_Q14 = 0;
|
||||
sparseness_Q8 = 0;
|
||||
predGain_Q16 = 0;
|
||||
LTPredCodGain_Q7 = 0;
|
||||
Arrays.MemSetInt(ResNrg, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetInt(ResNrgQ, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
Arrays.MemSetInt(GainsUnq_Q16, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
lastGainIndexPrev = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Variable cut-off low-pass filter state
|
||||
/// </summary>
|
||||
internal class SilkLPState
|
||||
{
|
||||
/// <summary>
|
||||
/// Low pass filter state
|
||||
/// </summary>
|
||||
internal readonly int[] In_LP_State = new int[2];
|
||||
|
||||
/// <summary>
|
||||
/// Counter which is mapped to a cut-off frequency
|
||||
/// </summary>
|
||||
internal int transition_frame_no = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Operating mode, <0: switch down, >0: switch up; 0: do nothing
|
||||
/// </summary>
|
||||
internal int mode = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
In_LP_State[0] = 0;
|
||||
In_LP_State[1] = 0;
|
||||
transition_frame_no = 0;
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
/* Low-pass filter with variable cutoff frequency based on */
|
||||
/* piece-wise linear interpolation between elliptic filters */
|
||||
/* Start by setting psEncC.mode <> 0; */
|
||||
/* Deactivate by setting psEncC.mode = 0; */
|
||||
internal void silk_LP_variable_cutoff(
|
||||
short[] frame, /* I/O Low-pass filtered output signal */
|
||||
int frame_ptr,
|
||||
int frame_length /* I Frame length */
|
||||
)
|
||||
{
|
||||
int[] B_Q28 = new int[SilkConstants.TRANSITION_NB];
|
||||
int[] A_Q28 = new int[SilkConstants.TRANSITION_NA];
|
||||
int fac_Q16 = 0;
|
||||
int ind = 0;
|
||||
|
||||
Inlines.OpusAssert(this.transition_frame_no >= 0 && this.transition_frame_no <= SilkConstants.TRANSITION_FRAMES);
|
||||
|
||||
/* Run filter if needed */
|
||||
if (this.mode != 0)
|
||||
{
|
||||
/* Calculate index and interpolation factor for interpolation */
|
||||
fac_Q16 = Inlines.silk_LSHIFT(SilkConstants.TRANSITION_FRAMES - this.transition_frame_no, 16 - 6);
|
||||
|
||||
ind = Inlines.silk_RSHIFT(fac_Q16, 16);
|
||||
fac_Q16 -= Inlines.silk_LSHIFT(ind, 16);
|
||||
|
||||
Inlines.OpusAssert(ind >= 0);
|
||||
Inlines.OpusAssert(ind < SilkConstants.TRANSITION_INT_NUM);
|
||||
|
||||
/* Interpolate filter coefficients */
|
||||
Filters.silk_LP_interpolate_filter_taps(B_Q28, A_Q28, ind, fac_Q16);
|
||||
|
||||
/* Update transition frame number for next frame */
|
||||
this.transition_frame_no = Inlines.silk_LIMIT(this.transition_frame_no + this.mode, 0, SilkConstants.TRANSITION_FRAMES);
|
||||
|
||||
/* ARMA low-pass filtering */
|
||||
Inlines.OpusAssert(SilkConstants.TRANSITION_NB == 3 && SilkConstants.TRANSITION_NA == 2);
|
||||
Filters.silk_biquad_alt(frame, frame_ptr, B_Q28, A_Q28, this.In_LP_State, frame, frame_ptr, frame_length, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Prefilter state
|
||||
/// </summary>
|
||||
internal class SilkPrefilterState
|
||||
{
|
||||
internal readonly short[] sLTP_shp = new short[SilkConstants.LTP_BUF_LENGTH];
|
||||
internal readonly int[] sAR_shp = new int[SilkConstants.MAX_SHAPE_LPC_ORDER + 1];
|
||||
internal int sLTP_shp_buf_idx = 0;
|
||||
internal int sLF_AR_shp_Q12 = 0;
|
||||
internal int sLF_MA_shp_Q12 = 0;
|
||||
internal int sHarmHP_Q2 = 0;
|
||||
internal int rand_seed = 0;
|
||||
internal int lagPrev = 0;
|
||||
|
||||
internal SilkPrefilterState()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetShort(sLTP_shp, 0, SilkConstants.LTP_BUF_LENGTH);
|
||||
Arrays.MemSetInt(sAR_shp, 0, SilkConstants.MAX_SHAPE_LPC_ORDER + 1);
|
||||
sLTP_shp_buf_idx = 0;
|
||||
sLF_AR_shp_Q12 = 0;
|
||||
sLF_MA_shp_Q12 = 0;
|
||||
sHarmHP_Q2 = 0;
|
||||
rand_seed = 0;
|
||||
lagPrev = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using System;
|
||||
internal class SilkResamplerState
|
||||
{
|
||||
internal readonly int[] sIIR = new int[SilkConstants.SILK_RESAMPLER_MAX_IIR_ORDER]; /* this must be the first element of this struct FIXME why? */
|
||||
internal readonly int[] sFIR_i32 = new int[SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER]; // porting note: these two fields were originally a union, so that means only 1 will ever be used at a time.
|
||||
internal readonly short[] sFIR_i16 = new short[SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER];
|
||||
|
||||
internal readonly short[] delayBuf = new short[48];
|
||||
internal int resampler_function = 0;
|
||||
internal int batchSize = 0;
|
||||
internal int invRatio_Q16 = 0;
|
||||
internal int FIR_Order = 0;
|
||||
internal int FIR_Fracs = 0;
|
||||
internal int Fs_in_kHz = 0;
|
||||
internal int Fs_out_kHz = 0;
|
||||
internal int inputDelay = 0;
|
||||
|
||||
/// <summary>
|
||||
/// POINTER
|
||||
/// </summary>
|
||||
internal short[] Coefs = null;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetInt(sIIR, 0, SilkConstants.SILK_RESAMPLER_MAX_IIR_ORDER);
|
||||
Arrays.MemSetInt(sFIR_i32, 0, SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER);
|
||||
Arrays.MemSetShort(sFIR_i16, 0, SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER);
|
||||
Arrays.MemSetShort(delayBuf, 0, 48);
|
||||
resampler_function = 0;
|
||||
batchSize = 0;
|
||||
invRatio_Q16 = 0;
|
||||
FIR_Order = 0;
|
||||
FIR_Fracs = 0;
|
||||
Fs_in_kHz = 0;
|
||||
Fs_out_kHz = 0;
|
||||
inputDelay = 0;
|
||||
Coefs = null;
|
||||
}
|
||||
|
||||
internal void Assign(SilkResamplerState other)
|
||||
{
|
||||
resampler_function = other.resampler_function;
|
||||
batchSize = other.batchSize;
|
||||
invRatio_Q16 = other.invRatio_Q16;
|
||||
FIR_Order = other.FIR_Order;
|
||||
FIR_Fracs = other.FIR_Fracs;
|
||||
Fs_in_kHz = other.Fs_in_kHz;
|
||||
Fs_out_kHz = other.Fs_out_kHz;
|
||||
inputDelay = other.inputDelay;
|
||||
Coefs = other.Coefs;
|
||||
Array.Copy(other.sIIR, this.sIIR, SilkConstants.SILK_RESAMPLER_MAX_IIR_ORDER);
|
||||
Array.Copy(other.sFIR_i32, this.sFIR_i32, SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER);
|
||||
Array.Copy(other.sFIR_i16, this.sFIR_i16, SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER);
|
||||
Array.Copy(other.delayBuf, this.delayBuf, 48);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Noise shaping analysis state
|
||||
/// </summary>
|
||||
internal class SilkShapeState
|
||||
{
|
||||
internal sbyte LastGainIndex = 0;
|
||||
internal int HarmBoost_smth_Q16 = 0;
|
||||
internal int HarmShapeGain_smth_Q16 = 0;
|
||||
internal int Tilt_smth_Q16 = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
LastGainIndex = 0;
|
||||
HarmBoost_smth_Q16 = 0;
|
||||
HarmShapeGain_smth_Q16 = 0;
|
||||
Tilt_smth_Q16 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// VAD state
|
||||
/// </summary>
|
||||
internal class SilkVADState
|
||||
{
|
||||
/// <summary>
|
||||
/// Analysis filterbank state: 0-8 kHz
|
||||
/// </summary>
|
||||
internal readonly int[] AnaState = new int[2];
|
||||
|
||||
/// <summary>
|
||||
/// Analysis filterbank state: 0-4 kHz
|
||||
/// </summary>
|
||||
internal readonly int[] AnaState1 = new int[2];
|
||||
|
||||
/// <summary>
|
||||
/// Analysis filterbank state: 0-2 kHz
|
||||
/// </summary>
|
||||
internal readonly int[] AnaState2 = new int[2];
|
||||
|
||||
/// <summary>
|
||||
/// Subframe energies
|
||||
/// </summary>
|
||||
internal readonly int[] XnrgSubfr = new int[SilkConstants.VAD_N_BANDS];
|
||||
|
||||
/// <summary>
|
||||
/// Smoothed energy level in each band
|
||||
/// </summary>
|
||||
internal readonly int[] NrgRatioSmth_Q8 = new int[SilkConstants.VAD_N_BANDS];
|
||||
|
||||
/// <summary>
|
||||
/// State of differentiator in the lowest band
|
||||
/// </summary>
|
||||
internal short HPstate = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Noise energy level in each band
|
||||
/// </summary>
|
||||
internal readonly int[] NL = new int[SilkConstants.VAD_N_BANDS];
|
||||
|
||||
/// <summary>
|
||||
/// Inverse noise energy level in each band
|
||||
/// </summary>
|
||||
internal readonly int[] inv_NL = new int[SilkConstants.VAD_N_BANDS];
|
||||
|
||||
/// <summary>
|
||||
/// Noise level estimator bias/offset
|
||||
/// </summary>
|
||||
internal readonly int[] NoiseLevelBias = new int[SilkConstants.VAD_N_BANDS];
|
||||
|
||||
/// <summary>
|
||||
/// Frame counter used in the initial phase
|
||||
/// </summary>
|
||||
internal int counter = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetInt(AnaState, 0, 2);
|
||||
Arrays.MemSetInt(AnaState1, 0, 2);
|
||||
Arrays.MemSetInt(AnaState2, 0, 2);
|
||||
Arrays.MemSetInt(XnrgSubfr, 0, SilkConstants.VAD_N_BANDS);
|
||||
Arrays.MemSetInt(NrgRatioSmth_Q8, 0, SilkConstants.VAD_N_BANDS);
|
||||
HPstate = 0;
|
||||
Arrays.MemSetInt(NL, 0, SilkConstants.VAD_N_BANDS);
|
||||
Arrays.MemSetInt(inv_NL, 0, SilkConstants.VAD_N_BANDS);
|
||||
Arrays.MemSetInt(NoiseLevelBias, 0, SilkConstants.VAD_N_BANDS);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
internal class StereoDecodeState
|
||||
{
|
||||
internal readonly short[] pred_prev_Q13 = new short[2];
|
||||
internal readonly short[] sMid = new short[2];
|
||||
internal readonly short[] sSide = new short[2];
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetShort(pred_prev_Q13, 0, 2);
|
||||
Arrays.MemSetShort(sMid, 0, 2);
|
||||
Arrays.MemSetShort(sSide, 0, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
internal class StereoEncodeState
|
||||
{
|
||||
internal readonly short[] pred_prev_Q13 = new short[2];
|
||||
internal readonly short[] sMid = new short[2];
|
||||
internal readonly short[] sSide = new short[2];
|
||||
internal readonly int[] mid_side_amp_Q0 = new int[4];
|
||||
internal short smth_width_Q14 = 0;
|
||||
internal short width_prev_Q14 = 0;
|
||||
internal short silent_side_len = 0;
|
||||
internal readonly sbyte[][][] predIx = Arrays.InitThreeDimensionalArray<sbyte>(SilkConstants.MAX_FRAMES_PER_PACKET, 2, 3);
|
||||
internal readonly sbyte[] mid_only_flags = new sbyte[SilkConstants.MAX_FRAMES_PER_PACKET];
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetShort(pred_prev_Q13, 0, 2);
|
||||
Arrays.MemSetShort(sMid, 0, 2);
|
||||
Arrays.MemSetShort(sSide, 0, 2);
|
||||
Arrays.MemSetInt(mid_side_amp_Q0, 0, 4);
|
||||
smth_width_Q14 = 0;
|
||||
width_prev_Q14 = 0;
|
||||
silent_side_len = 0;
|
||||
for (int x = 0; x < SilkConstants.MAX_FRAMES_PER_PACKET; x++)
|
||||
{
|
||||
for (int y= 0; y < 2; y++)
|
||||
{
|
||||
Arrays.MemSetSbyte(predIx[x][y], 0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
Arrays.MemSetSbyte(mid_only_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Structs
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Struct for TOC (Table of Contents)
|
||||
/// </summary>
|
||||
internal class TOCStruct
|
||||
{
|
||||
/// <summary>
|
||||
/// Voice activity for packet
|
||||
/// </summary>
|
||||
internal int VADFlag = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Voice activity for each frame in packet
|
||||
/// </summary>
|
||||
internal readonly int[] VADFlags = new int[SilkConstants.SILK_MAX_FRAMES_PER_PACKET];
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating if packet contains in-band FEC
|
||||
/// </summary>
|
||||
internal int inbandFECFlag = 0;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
VADFlag = 0;
|
||||
Arrays.MemSetInt(VADFlags, 0, SilkConstants.SILK_MAX_FRAMES_PER_PACKET);
|
||||
inbandFECFlag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class SumSqrShift
|
||||
{
|
||||
/// <summary>
|
||||
/// Compute number of bits to right shift the sum of squares of a vector
|
||||
/// of int16s to make it fit in an int32
|
||||
/// </summary>
|
||||
/// <param name="energy">O Energy of x, after shifting to the right</param>
|
||||
/// <param name="shift">O Number of bits right shift applied to energy</param>
|
||||
/// <param name="x">I Input vector</param>
|
||||
/// <param name="len">I Length of input vector</param>
|
||||
internal static void silk_sum_sqr_shift(
|
||||
out int energy,
|
||||
out int shift,
|
||||
short[] x,
|
||||
int x_ptr,
|
||||
int len)
|
||||
{
|
||||
int i, shft;
|
||||
int nrg_tmp, nrg;
|
||||
|
||||
nrg = 0;
|
||||
shft = 0;
|
||||
len--;
|
||||
|
||||
for (i = 0; i < len; i += 2)
|
||||
{
|
||||
nrg = Inlines.silk_SMLABB_ovflw(nrg, x[x_ptr + i], x[x_ptr + i]);
|
||||
nrg = Inlines.silk_SMLABB_ovflw(nrg, x[x_ptr + i + 1], x[x_ptr + i + 1]);
|
||||
if (nrg < 0)
|
||||
{
|
||||
/* Scale down */
|
||||
nrg = unchecked((int)Inlines.silk_RSHIFT_uint(unchecked((uint)nrg), 2));
|
||||
shft = 2;
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < len; i += 2)
|
||||
{
|
||||
nrg_tmp = Inlines.silk_SMULBB(x[x_ptr + i], x[x_ptr + i]);
|
||||
nrg_tmp = Inlines.silk_SMLABB_ovflw(nrg_tmp, x[x_ptr + i + 1], x[x_ptr + i + 1]);
|
||||
nrg = unchecked((int)Inlines.silk_ADD_RSHIFT_uint(unchecked((uint)nrg), unchecked((uint)nrg_tmp), shft));
|
||||
if (nrg < 0)
|
||||
{
|
||||
/* Scale down */
|
||||
nrg = unchecked((int)Inlines.silk_RSHIFT_uint(unchecked((uint)nrg), 2));
|
||||
shft += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == len)
|
||||
{
|
||||
/* One sample left to process */
|
||||
nrg_tmp = Inlines.silk_SMULBB(x[x_ptr + i], x[x_ptr + i]);
|
||||
nrg = unchecked((int)Inlines.silk_ADD_RSHIFT_uint(unchecked((uint)nrg), unchecked((uint)nrg_tmp), shft));
|
||||
}
|
||||
|
||||
/* Make sure to have at least one extra leading zero (two leading zeros in total) */
|
||||
if ((nrg & 0xC0000000) != 0)
|
||||
{
|
||||
nrg = unchecked((int)Inlines.silk_RSHIFT_uint(unchecked((uint)nrg), 2));
|
||||
shft += 2;
|
||||
}
|
||||
|
||||
/* Output arguments */
|
||||
shift = shft;
|
||||
energy = nrg;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zero-index variant
|
||||
/// Compute number of bits to right shift the sum of squares of a vector
|
||||
/// of int16s to make it fit in an int32
|
||||
/// </summary>
|
||||
/// <param name="energy">O Energy of x, after shifting to the right</param>
|
||||
/// <param name="shift">O Number of bits right shift applied to energy</param>
|
||||
/// <param name="x">I Input vector</param>
|
||||
/// <param name="len">I Length of input vector</param>
|
||||
internal static void silk_sum_sqr_shift(
|
||||
out int energy,
|
||||
out int shift,
|
||||
short[] x,
|
||||
int len)
|
||||
{
|
||||
int i, shft;
|
||||
int nrg_tmp, nrg;
|
||||
|
||||
nrg = 0;
|
||||
shft = 0;
|
||||
len--;
|
||||
|
||||
for (i = 0; i < len; i += 2)
|
||||
{
|
||||
nrg = Inlines.silk_SMLABB_ovflw(nrg, x[i], x[i]);
|
||||
nrg = Inlines.silk_SMLABB_ovflw(nrg, x[i + 1], x[i + 1]);
|
||||
if (nrg < 0)
|
||||
{
|
||||
/* Scale down */
|
||||
nrg = unchecked((int)Inlines.silk_RSHIFT_uint(unchecked((uint)nrg), 2));
|
||||
shft = 2;
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < len; i += 2)
|
||||
{
|
||||
nrg_tmp = Inlines.silk_SMULBB(x[i], x[i]);
|
||||
nrg_tmp = Inlines.silk_SMLABB_ovflw(nrg_tmp, x[i + 1], x[i + 1]);
|
||||
nrg = unchecked((int)Inlines.silk_ADD_RSHIFT_uint(unchecked((uint)nrg), unchecked((uint)nrg_tmp), shft));
|
||||
if (nrg < 0)
|
||||
{
|
||||
/* Scale down */
|
||||
nrg = unchecked((int)Inlines.silk_RSHIFT_uint(unchecked((uint)nrg), 2));
|
||||
shft += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == len)
|
||||
{
|
||||
/* One sample left to process */
|
||||
nrg_tmp = Inlines.silk_SMULBB(x[i], x[i]);
|
||||
nrg = unchecked((int)Inlines.silk_ADD_RSHIFT_uint(unchecked((uint)nrg), unchecked((uint)nrg_tmp), shft));
|
||||
}
|
||||
|
||||
/* Make sure to have at least one extra leading zero (two leading zeros in total) */
|
||||
if ((nrg & 0xC0000000) != 0)
|
||||
{
|
||||
nrg = unchecked((int)Inlines.silk_RSHIFT_uint(unchecked((uint)nrg), 2));
|
||||
shft += 2;
|
||||
}
|
||||
|
||||
/* Output arguments */
|
||||
shift = shft;
|
||||
energy = nrg;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,174 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal class TuningParameters
|
||||
{
|
||||
/* Decay time for EntropyCoder.BITREServoir */
|
||||
internal const int BITRESERVOIR_DECAY_TIME_MS = 500;
|
||||
|
||||
/*******************/
|
||||
/* Pitch estimator */
|
||||
/*******************/
|
||||
|
||||
/* Level of noise floor for whitening filter LPC analysis in pitch analysis */
|
||||
internal const float FIND_PITCH_WHITE_NOISE_FRACTION = 1e-3f;
|
||||
|
||||
/* Bandwidth expansion for whitening filter in pitch analysis */
|
||||
internal const float FIND_PITCH_BANDWIDTH_EXPANSION = 0.99f;
|
||||
|
||||
/*********************/
|
||||
/* Linear prediction */
|
||||
/*********************/
|
||||
|
||||
/* LPC analysis regularization */
|
||||
internal const float FIND_LPC_COND_FAC = 1e-5f;
|
||||
|
||||
/* LTP analysis defines */
|
||||
internal const float FIND_LTP_COND_FAC = 1e-5f;
|
||||
internal const float LTP_DAMPING = 0.05f;
|
||||
internal const float LTP_SMOOTHING = 0.1f;
|
||||
|
||||
/* LTP quantization settings */
|
||||
internal const float MU_LTP_QUANT_NB = 0.03f;
|
||||
internal const float MU_LTP_QUANT_MB = 0.025f;
|
||||
internal const float MU_LTP_QUANT_WB = 0.02f;
|
||||
|
||||
/* Max cumulative LTP gain */
|
||||
internal const float MAX_SUM_LOG_GAIN_DB = 250.0f;
|
||||
|
||||
/***********************/
|
||||
/* High pass filtering */
|
||||
/***********************/
|
||||
|
||||
/* Smoothing parameters for low end of pitch frequency range estimation */
|
||||
internal const float VARIABLE_HP_SMTH_COEF1 = 0.1f;
|
||||
internal const float VARIABLE_HP_SMTH_COEF2 = 0.015f;
|
||||
internal const float VARIABLE_HP_MAX_DELTA_FREQ = 0.4f;
|
||||
|
||||
/* Min and max cut-off frequency values (-3 dB points) */
|
||||
internal const int VARIABLE_HP_MIN_CUTOFF_HZ = 60;
|
||||
internal const int VARIABLE_HP_MAX_CUTOFF_HZ = 100;
|
||||
|
||||
/***********/
|
||||
/* Various */
|
||||
/***********/
|
||||
|
||||
/* VAD threshold */
|
||||
internal const float SPEECH_ACTIVITY_DTX_THRES = 0.05f;
|
||||
|
||||
/* Speech Activity LBRR enable threshold */
|
||||
internal const float LBRR_SPEECH_ACTIVITY_THRES = 0.3f;
|
||||
|
||||
/*************************/
|
||||
/* Perceptual parameters */
|
||||
/*************************/
|
||||
|
||||
/* reduction in coding SNR during low speech activity */
|
||||
internal const float BG_SNR_DECR_dB = 2.0f;
|
||||
|
||||
/* factor for reducing quantization noise during voiced speech */
|
||||
internal const float HARM_SNR_INCR_dB = 2.0f;
|
||||
|
||||
/* factor for reducing quantization noise for unvoiced sparse signals */
|
||||
internal const float SPARSE_SNR_INCR_dB = 2.0f;
|
||||
|
||||
/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */
|
||||
internal const float SPARSENESS_THRESHOLD_QNT_OFFSET = 0.75f;
|
||||
|
||||
/* warping control */
|
||||
internal const float WARPING_MULTIPLIER = 0.015f;
|
||||
|
||||
/* fraction added to first autocorrelation value */
|
||||
internal const float SHAPE_WHITE_NOISE_FRACTION = 5e-5f;
|
||||
|
||||
/* noise shaping filter chirp factor */
|
||||
internal const float BANDWIDTH_EXPANSION = 0.95f;
|
||||
|
||||
/* difference between chirp factors for analysis and synthesis noise shaping filters at low bitrates */
|
||||
internal const float LOW_RATE_BANDWIDTH_EXPANSION_DELTA = 0.01f;
|
||||
|
||||
/* extra harmonic boosting (signal shaping) at low bitrates */
|
||||
internal const float LOW_RATE_HARMONIC_BOOST = 0.1f;
|
||||
|
||||
/* extra harmonic boosting (signal shaping) for noisy input signals */
|
||||
internal const float LOW_INPUT_QUALITY_HARMONIC_BOOST = 0.1f;
|
||||
|
||||
/* harmonic noise shaping */
|
||||
internal const float HARMONIC_SHAPING = 0.3f;
|
||||
|
||||
/* extra harmonic noise shaping for high bitrates or noisy input */
|
||||
internal const float HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING = 0.2f;
|
||||
|
||||
/* parameter for shaping noise towards higher frequencies */
|
||||
internal const float HP_NOISE_COEF = 0.25f;
|
||||
|
||||
/* parameter for shaping noise even more towards higher frequencies during voiced speech */
|
||||
internal const float HARM_HP_NOISE_COEF = 0.35f;
|
||||
|
||||
/* parameter for applying a high-pass tilt to the input signal */
|
||||
internal const float INPUT_TILT = 0.05f;
|
||||
|
||||
/* parameter for extra high-pass tilt to the input signal at high rates */
|
||||
internal const float HIGH_RATE_INPUT_TILT = 0.1f;
|
||||
|
||||
/* parameter for reducing noise at the very low frequencies */
|
||||
internal const float LOW_FREQ_SHAPING = 4.0f;
|
||||
|
||||
/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */
|
||||
internal const float LOW_QUALITY_LOW_FREQ_SHAPING_DECR = 0.5f;
|
||||
|
||||
/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower . more smoothing) */
|
||||
internal const float SUBFR_SMTH_COEF = 0.4f;
|
||||
|
||||
/* parameters defining the R/D tradeoff in the residual quantizer */
|
||||
internal const float LAMBDA_OFFSET = 1.2f;
|
||||
internal const float LAMBDA_SPEECH_ACT = -0.2f;
|
||||
internal const float LAMBDA_DELAYED_DECISIONS = -0.05f;
|
||||
internal const float LAMBDA_INPUT_QUALITY = -0.1f;
|
||||
internal const float LAMBDA_CODING_QUALITY = -0.2f;
|
||||
internal const float LAMBDA_QUANT_OFFSET = 0.8f;
|
||||
|
||||
/* Compensation in bitrate calculations for 10 ms modes */
|
||||
internal const int REDUCE_BITRATE_10_MS_BPS = 2200;
|
||||
|
||||
/* Maximum time before allowing a bandwidth transition */
|
||||
internal const int MAX_BANDWIDTH_SWITCH_DELAY_MS = 5000;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class VQ_WMat_EC
|
||||
{
|
||||
/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
|
||||
internal static void silk_VQ_WMat_EC(
|
||||
BoxedValueSbyte ind, /* O index of best codebook vector */
|
||||
BoxedValueInt rate_dist_Q14, /* O best weighted quant error + mu * rate */
|
||||
BoxedValueInt gain_Q7, /* O sum of absolute LTP coefficients */
|
||||
short[] in_Q14, /* I input vector to be quantized */
|
||||
int in_Q14_ptr,
|
||||
int[] W_Q18, /* I weighting matrix */
|
||||
int W_Q18_ptr,
|
||||
sbyte[][] cb_Q7, /* I codebook */
|
||||
byte[] cb_gain_Q7, /* I codebook effective gain */
|
||||
byte[] cl_Q5, /* I code length for each codebook vector */
|
||||
int mu_Q9, /* I tradeoff betw. weighted error and rate */
|
||||
int max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
|
||||
int L /* I number of vectors in codebook */
|
||||
)
|
||||
{
|
||||
int k, gain_tmp_Q7;
|
||||
sbyte[] cb_row_Q7;
|
||||
int cb_row_Q7_ptr = 0;
|
||||
short[] diff_Q14 = new short[5];
|
||||
int sum1_Q14, sum2_Q16;
|
||||
|
||||
/* Loop over codebook */
|
||||
rate_dist_Q14.Val = int.MaxValue;
|
||||
for (k = 0; k < L; k++)
|
||||
{
|
||||
/* Go to next cbk vector */
|
||||
cb_row_Q7 = cb_Q7[cb_row_Q7_ptr++];
|
||||
gain_tmp_Q7 = cb_gain_Q7[k];
|
||||
|
||||
diff_Q14[0] = (short)(in_Q14[in_Q14_ptr] - Inlines.silk_LSHIFT(cb_row_Q7[0], 7));
|
||||
diff_Q14[1] = (short)(in_Q14[in_Q14_ptr + 1] - Inlines.silk_LSHIFT(cb_row_Q7[1], 7));
|
||||
diff_Q14[2] = (short)(in_Q14[in_Q14_ptr + 2] - Inlines.silk_LSHIFT(cb_row_Q7[2], 7));
|
||||
diff_Q14[3] = (short)(in_Q14[in_Q14_ptr + 3] - Inlines.silk_LSHIFT(cb_row_Q7[3], 7));
|
||||
diff_Q14[4] = (short)(in_Q14[in_Q14_ptr + 4] - Inlines.silk_LSHIFT(cb_row_Q7[4], 7));
|
||||
|
||||
/* Weighted rate */
|
||||
sum1_Q14 = Inlines.silk_SMULBB(mu_Q9, cl_Q5[k]);
|
||||
|
||||
/* Penalty for too large gain */
|
||||
sum1_Q14 = Inlines.silk_ADD_LSHIFT32(sum1_Q14, Inlines.silk_max(Inlines.silk_SUB32(gain_tmp_Q7, max_gain_Q7), 0), 10);
|
||||
|
||||
Inlines.OpusAssert(sum1_Q14 >= 0);
|
||||
|
||||
/* first row of W_Q18 */
|
||||
sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 1], diff_Q14[1]);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 2], diff_Q14[2]);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 3], diff_Q14[3]);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 4], diff_Q14[4]);
|
||||
sum2_Q16 = Inlines.silk_LSHIFT(sum2_Q16, 1);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr], diff_Q14[0]);
|
||||
sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[0]);
|
||||
|
||||
/* second row of W_Q18 */
|
||||
sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 7], diff_Q14[2]);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 8], diff_Q14[3]);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 9], diff_Q14[4]);
|
||||
sum2_Q16 = Inlines.silk_LSHIFT(sum2_Q16, 1);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 6], diff_Q14[1]);
|
||||
sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[1]);
|
||||
|
||||
/* third row of W_Q18 */
|
||||
sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 13], diff_Q14[3]);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 14], diff_Q14[4]);
|
||||
sum2_Q16 = Inlines.silk_LSHIFT(sum2_Q16, 1);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 12], diff_Q14[2]);
|
||||
sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[2]);
|
||||
|
||||
/* fourth row of W_Q18 */
|
||||
sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 19], diff_Q14[4]);
|
||||
sum2_Q16 = Inlines.silk_LSHIFT(sum2_Q16, 1);
|
||||
sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 18], diff_Q14[3]);
|
||||
sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[3]);
|
||||
|
||||
/* last row of W_Q18 */
|
||||
sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 24], diff_Q14[4]);
|
||||
sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[4]);
|
||||
|
||||
Inlines.OpusAssert(sum1_Q14 >= 0);
|
||||
|
||||
/* find best */
|
||||
if (sum1_Q14 < rate_dist_Q14.Val)
|
||||
{
|
||||
rate_dist_Q14.Val = sum1_Q14;
|
||||
ind.Val = (sbyte)k;
|
||||
gain_Q7.Val = gain_tmp_Q7;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
/// <summary>
|
||||
/// Voice Activity Detection module for silk codec
|
||||
/// </summary>
|
||||
internal static class VoiceActivityDetection
|
||||
{
|
||||
/// <summary>
|
||||
/// Weighting factors for tilt measure
|
||||
/// </summary>
|
||||
private static readonly int[] tiltWeights = { 30000, 6000, -12000, -12000 };
|
||||
|
||||
/// <summary>
|
||||
/// Initialization of the Silk VAD
|
||||
/// </summary>
|
||||
/// <param name="psSilk_VAD">O Pointer to Silk VAD state. Cannot be nullptr</param>
|
||||
/// <returns>0 if success</returns>
|
||||
internal static int silk_VAD_Init(SilkVADState psSilk_VAD)
|
||||
{
|
||||
int b, ret = 0;
|
||||
|
||||
/* reset state memory */
|
||||
psSilk_VAD.Reset();
|
||||
|
||||
/* init noise levels */
|
||||
/* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */
|
||||
for (b = 0; b < SilkConstants.VAD_N_BANDS; b++)
|
||||
{
|
||||
psSilk_VAD.NoiseLevelBias[b] = Inlines.silk_max_32(Inlines.silk_DIV32_16(SilkConstants.VAD_NOISE_LEVELS_BIAS, (short)(b + 1)), 1);
|
||||
}
|
||||
|
||||
/* Initialize state */
|
||||
for (b = 0; b < SilkConstants.VAD_N_BANDS; b++)
|
||||
{
|
||||
psSilk_VAD.NL[b] = Inlines.silk_MUL(100, psSilk_VAD.NoiseLevelBias[b]);
|
||||
psSilk_VAD.inv_NL[b] = Inlines.silk_DIV32(int.MaxValue, psSilk_VAD.NL[b]);
|
||||
}
|
||||
|
||||
psSilk_VAD.counter = 15;
|
||||
|
||||
/* init smoothed energy-to-noise ratio*/
|
||||
for (b = 0; b < SilkConstants.VAD_N_BANDS; b++)
|
||||
{
|
||||
psSilk_VAD.NrgRatioSmth_Q8[b] = 100 * 256; /* 100 * 256 -. 20 dB SNR */
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the speech activity level in Q8
|
||||
/// </summary>
|
||||
/// <param name="psEncC">I/O Encoder state</param>
|
||||
/// <param name="pIn">I PCM input</param>
|
||||
/// <returns>0 if success</returns>
|
||||
internal static int silk_VAD_GetSA_Q8(
|
||||
SilkChannelEncoder psEncC,
|
||||
short[] pIn,
|
||||
int pIn_ptr)
|
||||
{
|
||||
int SA_Q15, pSNR_dB_Q7, input_tilt;
|
||||
int decimated_framelength1, decimated_framelength2;
|
||||
int decimated_framelength;
|
||||
int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s;
|
||||
int sumSquared = 0, smooth_coef_Q16;
|
||||
short HPstateTmp;
|
||||
short[] X;
|
||||
int[] Xnrg = new int[SilkConstants.VAD_N_BANDS];
|
||||
int[] NrgToNoiseRatio_Q8 = new int[SilkConstants.VAD_N_BANDS];
|
||||
int speech_nrg, x_tmp;
|
||||
int[] X_offset = new int[SilkConstants.VAD_N_BANDS];
|
||||
int ret = 0;
|
||||
SilkVADState psSilk_VAD = psEncC.sVAD;
|
||||
|
||||
/* Safety checks */
|
||||
Inlines.OpusAssert(SilkConstants.VAD_N_BANDS == 4);
|
||||
Inlines.OpusAssert(SilkConstants.MAX_FRAME_LENGTH >= psEncC.frame_length);
|
||||
Inlines.OpusAssert(psEncC.frame_length <= 512);
|
||||
Inlines.OpusAssert(psEncC.frame_length == 8 * Inlines.silk_RSHIFT(psEncC.frame_length, 3));
|
||||
|
||||
/***********************/
|
||||
/* Filter and Decimate */
|
||||
/***********************/
|
||||
decimated_framelength1 = Inlines.silk_RSHIFT(psEncC.frame_length, 1);
|
||||
decimated_framelength2 = Inlines.silk_RSHIFT(psEncC.frame_length, 2);
|
||||
decimated_framelength = Inlines.silk_RSHIFT(psEncC.frame_length, 3);
|
||||
|
||||
/* Decimate into 4 bands:
|
||||
0 L 3L L 3L 5L
|
||||
- -- - -- --
|
||||
8 8 2 4 4
|
||||
|
||||
[0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz |
|
||||
|
||||
They're arranged to allow the minimal ( frame_length / 4 ) extra
|
||||
scratch space during the downsampling process */
|
||||
X_offset[0] = 0;
|
||||
X_offset[1] = decimated_framelength + decimated_framelength2;
|
||||
X_offset[2] = X_offset[1] + decimated_framelength;
|
||||
X_offset[3] = X_offset[2] + decimated_framelength2;
|
||||
X = new short[X_offset[3] + decimated_framelength1];
|
||||
|
||||
/* 0-8 kHz to 0-4 kHz and 4-8 kHz */
|
||||
Filters.silk_ana_filt_bank_1(pIn, pIn_ptr, psSilk_VAD.AnaState,
|
||||
X, X, X_offset[3], psEncC.frame_length);
|
||||
|
||||
/* 0-4 kHz to 0-2 kHz and 2-4 kHz */
|
||||
Filters.silk_ana_filt_bank_1(X, 0, psSilk_VAD.AnaState1,
|
||||
X, X, X_offset[2], decimated_framelength1);
|
||||
|
||||
/* 0-2 kHz to 0-1 kHz and 1-2 kHz */
|
||||
Filters.silk_ana_filt_bank_1(X, 0, psSilk_VAD.AnaState2,
|
||||
X, X, X_offset[1], decimated_framelength2);
|
||||
|
||||
/*********************************************/
|
||||
/* HP filter on lowest band (differentiator) */
|
||||
/*********************************************/
|
||||
X[decimated_framelength - 1] = (short)(Inlines.silk_RSHIFT(X[decimated_framelength - 1], 1));
|
||||
HPstateTmp = X[decimated_framelength - 1];
|
||||
|
||||
for (i = decimated_framelength - 1; i > 0; i--)
|
||||
{
|
||||
X[i - 1] = (short)(Inlines.silk_RSHIFT(X[i - 1], 1));
|
||||
X[i] -= X[i - 1];
|
||||
}
|
||||
|
||||
X[0] -= psSilk_VAD.HPstate;
|
||||
psSilk_VAD.HPstate = HPstateTmp;
|
||||
|
||||
/*************************************/
|
||||
/* Calculate the energy in each band */
|
||||
/*************************************/
|
||||
for (b = 0; b < SilkConstants.VAD_N_BANDS; b++)
|
||||
{
|
||||
/* Find the decimated framelength in the non-uniformly divided bands */
|
||||
decimated_framelength = Inlines.silk_RSHIFT(psEncC.frame_length, Inlines.silk_min_int(SilkConstants.VAD_N_BANDS - b, SilkConstants.VAD_N_BANDS - 1));
|
||||
|
||||
/* Split length into subframe lengths */
|
||||
dec_subframe_length = Inlines.silk_RSHIFT(decimated_framelength, SilkConstants.VAD_INTERNAL_SUBFRAMES_LOG2);
|
||||
dec_subframe_offset = 0;
|
||||
|
||||
/* Compute energy per sub-frame */
|
||||
/* initialize with summed energy of last subframe */
|
||||
Xnrg[b] = psSilk_VAD.XnrgSubfr[b];
|
||||
for (s = 0; s < SilkConstants.VAD_INTERNAL_SUBFRAMES; s++)
|
||||
{
|
||||
sumSquared = 0;
|
||||
|
||||
for (i = 0; i < dec_subframe_length; i++)
|
||||
{
|
||||
/* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */
|
||||
/* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */
|
||||
x_tmp = Inlines.silk_RSHIFT(
|
||||
X[X_offset[b] + i + dec_subframe_offset], 3);
|
||||
sumSquared = Inlines.silk_SMLABB(sumSquared, x_tmp, x_tmp);
|
||||
/* Safety check */
|
||||
Inlines.OpusAssert(sumSquared >= 0);
|
||||
}
|
||||
|
||||
/* Add/saturate summed energy of current subframe */
|
||||
if (s < SilkConstants.VAD_INTERNAL_SUBFRAMES - 1)
|
||||
{
|
||||
Xnrg[b] = Inlines.silk_ADD_POS_SAT32(Xnrg[b], sumSquared);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Look-ahead subframe */
|
||||
Xnrg[b] = Inlines.silk_ADD_POS_SAT32(Xnrg[b], Inlines.silk_RSHIFT(sumSquared, 1));
|
||||
}
|
||||
|
||||
dec_subframe_offset += dec_subframe_length;
|
||||
}
|
||||
|
||||
psSilk_VAD.XnrgSubfr[b] = sumSquared;
|
||||
}
|
||||
|
||||
/********************/
|
||||
/* Noise estimation */
|
||||
/********************/
|
||||
silk_VAD_GetNoiseLevels(Xnrg, psSilk_VAD);
|
||||
|
||||
/***********************************************/
|
||||
/* Signal-plus-noise to noise ratio estimation */
|
||||
/***********************************************/
|
||||
sumSquared = 0;
|
||||
input_tilt = 0;
|
||||
for (b = 0; b < SilkConstants.VAD_N_BANDS; b++)
|
||||
{
|
||||
speech_nrg = Xnrg[b] - psSilk_VAD.NL[b];
|
||||
if (speech_nrg > 0)
|
||||
{
|
||||
/* Divide, with sufficient resolution */
|
||||
if ((Xnrg[b] & 0xFF800000) == 0)
|
||||
{
|
||||
NrgToNoiseRatio_Q8[b] = Inlines.silk_DIV32(Inlines.silk_LSHIFT(Xnrg[b], 8), psSilk_VAD.NL[b] + 1);
|
||||
}
|
||||
else {
|
||||
NrgToNoiseRatio_Q8[b] = Inlines.silk_DIV32(Xnrg[b], Inlines.silk_RSHIFT(psSilk_VAD.NL[b], 8) + 1);
|
||||
}
|
||||
|
||||
/* Convert to log domain */
|
||||
SNR_Q7 = Inlines.silk_lin2log(NrgToNoiseRatio_Q8[b]) - 8 * 128;
|
||||
|
||||
/* Sum-of-squares */
|
||||
sumSquared = Inlines.silk_SMLABB(sumSquared, SNR_Q7, SNR_Q7); /* Q14 */
|
||||
|
||||
/* Tilt measure */
|
||||
if (speech_nrg < ((int)1 << 20))
|
||||
{
|
||||
/* Scale down SNR value for small subband speech energies */
|
||||
SNR_Q7 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(speech_nrg), 6), SNR_Q7);
|
||||
}
|
||||
input_tilt = Inlines.silk_SMLAWB(input_tilt, tiltWeights[b], SNR_Q7);
|
||||
}
|
||||
else
|
||||
{
|
||||
NrgToNoiseRatio_Q8[b] = 256;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mean-of-squares */
|
||||
sumSquared = Inlines.silk_DIV32_16(sumSquared, SilkConstants.VAD_N_BANDS); /* Q14 */
|
||||
|
||||
/* Root-mean-square approximation, scale to dBs, and write to output pointer */
|
||||
pSNR_dB_Q7 = (short)(3 * Inlines.silk_SQRT_APPROX(sumSquared)); /* Q7 */
|
||||
|
||||
/*********************************/
|
||||
/* Speech Probability Estimation */
|
||||
/*********************************/
|
||||
SA_Q15 = Sigmoid.silk_sigm_Q15(Inlines.silk_SMULWB(SilkConstants.VAD_SNR_FACTOR_Q16, pSNR_dB_Q7) - SilkConstants.VAD_NEGATIVE_OFFSET_Q5);
|
||||
|
||||
/**************************/
|
||||
/* Frequency Tilt Measure */
|
||||
/**************************/
|
||||
psEncC.input_tilt_Q15 = Inlines.silk_LSHIFT(Sigmoid.silk_sigm_Q15(input_tilt) - 16384, 1);
|
||||
|
||||
/**************************************************/
|
||||
/* Scale the sigmoid output based on power levels */
|
||||
/**************************************************/
|
||||
speech_nrg = 0;
|
||||
for (b = 0; b < SilkConstants.VAD_N_BANDS; b++)
|
||||
{
|
||||
/* Accumulate signal-without-noise energies, higher frequency bands have more weight */
|
||||
speech_nrg += (b + 1) * Inlines.silk_RSHIFT(Xnrg[b] - psSilk_VAD.NL[b], 4);
|
||||
}
|
||||
|
||||
/* Power scaling */
|
||||
if (speech_nrg <= 0)
|
||||
{
|
||||
SA_Q15 = Inlines.silk_RSHIFT(SA_Q15, 1);
|
||||
}
|
||||
else if (speech_nrg < 32768)
|
||||
{
|
||||
if (psEncC.frame_length == 10 * psEncC.fs_kHz)
|
||||
{
|
||||
speech_nrg = Inlines.silk_LSHIFT_SAT32(speech_nrg, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
speech_nrg = Inlines.silk_LSHIFT_SAT32(speech_nrg, 15);
|
||||
}
|
||||
|
||||
/* square-root */
|
||||
speech_nrg = Inlines.silk_SQRT_APPROX(speech_nrg);
|
||||
SA_Q15 = Inlines.silk_SMULWB(32768 + speech_nrg, SA_Q15);
|
||||
}
|
||||
|
||||
/* Copy the resulting speech activity in Q8 */
|
||||
psEncC.speech_activity_Q8 = Inlines.silk_min_int(Inlines.silk_RSHIFT(SA_Q15, 7), byte.MaxValue);
|
||||
|
||||
/***********************************/
|
||||
/* Energy Level and SNR estimation */
|
||||
/***********************************/
|
||||
/* Smoothing coefficient */
|
||||
smooth_coef_Q16 = Inlines.silk_SMULWB(SilkConstants.VAD_SNR_SMOOTH_COEF_Q18, Inlines.silk_SMULWB((int)SA_Q15, SA_Q15));
|
||||
|
||||
if (psEncC.frame_length == 10 * psEncC.fs_kHz)
|
||||
{
|
||||
smooth_coef_Q16 >>= 1;
|
||||
}
|
||||
|
||||
for (b = 0; b < SilkConstants.VAD_N_BANDS; b++)
|
||||
{
|
||||
/* compute smoothed energy-to-noise ratio per band */
|
||||
psSilk_VAD.NrgRatioSmth_Q8[b] = Inlines.silk_SMLAWB(psSilk_VAD.NrgRatioSmth_Q8[b],
|
||||
NrgToNoiseRatio_Q8[b] - psSilk_VAD.NrgRatioSmth_Q8[b], smooth_coef_Q16);
|
||||
/* signal to noise ratio in dB per band */
|
||||
SNR_Q7 = 3 * (Inlines.silk_lin2log(psSilk_VAD.NrgRatioSmth_Q8[b]) - 8 * 128);
|
||||
/* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */
|
||||
psEncC.input_quality_bands_Q15[b] = Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT(SNR_Q7 - 16 * 128, 4));
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Noise level estimation
|
||||
/// </summary>
|
||||
/// <param name="pX">I subband energies [VAD_N_BANDS]</param>
|
||||
/// <param name="psSilk_VAD">I/O Pointer to Silk VAD state</param>
|
||||
internal static void silk_VAD_GetNoiseLevels(
|
||||
int[] pX,
|
||||
SilkVADState psSilk_VAD)
|
||||
{
|
||||
int k;
|
||||
int nl, nrg, inv_nrg;
|
||||
int coef, min_coef;
|
||||
|
||||
/* Initially faster smoothing */
|
||||
if (psSilk_VAD.counter < 1000)
|
||||
{ /* 1000 = 20 sec */
|
||||
min_coef = Inlines.silk_DIV32_16(short.MaxValue, (short)(Inlines.silk_RSHIFT(psSilk_VAD.counter, 4) + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
min_coef = 0;
|
||||
}
|
||||
|
||||
for (k = 0; k < SilkConstants.VAD_N_BANDS; k++)
|
||||
{
|
||||
/* Get old noise level estimate for current band */
|
||||
nl = psSilk_VAD.NL[k];
|
||||
Inlines.OpusAssert(nl >= 0);
|
||||
|
||||
/* Add bias */
|
||||
nrg = Inlines.silk_ADD_POS_SAT32(pX[k], psSilk_VAD.NoiseLevelBias[k]);
|
||||
Inlines.OpusAssert(nrg > 0);
|
||||
|
||||
/* Invert energies */
|
||||
inv_nrg = Inlines.silk_DIV32(int.MaxValue, nrg);
|
||||
Inlines.OpusAssert(inv_nrg >= 0);
|
||||
|
||||
/* Less update when subband energy is high */
|
||||
if (nrg > Inlines.silk_LSHIFT(nl, 3))
|
||||
{
|
||||
coef = SilkConstants.VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3;
|
||||
}
|
||||
else if (nrg < nl)
|
||||
{
|
||||
coef = SilkConstants.VAD_NOISE_LEVEL_SMOOTH_COEF_Q16;
|
||||
}
|
||||
else
|
||||
{
|
||||
coef = Inlines.silk_SMULWB(Inlines.silk_SMULWW(inv_nrg, nl), SilkConstants.VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1);
|
||||
}
|
||||
|
||||
/* Initially faster smoothing */
|
||||
coef = Inlines.silk_max_int(coef, min_coef);
|
||||
|
||||
/* Smooth inverse energies */
|
||||
psSilk_VAD.inv_NL[k] = Inlines.silk_SMLAWB(psSilk_VAD.inv_NL[k], inv_nrg - psSilk_VAD.inv_NL[k], coef);
|
||||
Inlines.OpusAssert(psSilk_VAD.inv_NL[k] >= 0);
|
||||
|
||||
/* Compute noise level by inverting again */
|
||||
nl = Inlines.silk_DIV32(int.MaxValue, psSilk_VAD.inv_NL[k]);
|
||||
Inlines.OpusAssert(nl >= 0);
|
||||
|
||||
/* Limit noise levels (guarantee 7 bits of head room) */
|
||||
nl = Inlines.silk_min(nl, 0x00FFFFFF);
|
||||
|
||||
/* Store as part of state */
|
||||
psSilk_VAD.NL[k] = nl;
|
||||
}
|
||||
|
||||
/* Increment frame counter */
|
||||
psSilk_VAD.counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user