Files
LuaCsForBarotraumaEP/Libraries/Concentus/CSharp/Concentus/Celt/Bands.cs
T

1715 lines
64 KiB
C#

/* Copyright (c) 2007-2008 CSIRO
Copyright (c) 2007-2011 Xiph.Org Foundation
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
Timothy B. Terriberry, and the Opus open-source contributors
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.Celt
{
using Concentus.Celt.Enums;
using Concentus.Celt.Structs;
using Concentus.Common;
using Concentus.Common.CPlusPlus;
using System;
using System.Diagnostics;
internal static class Bands
{
internal static int hysteresis_decision(
int val,
int[] thresholds,
int[] hysteresis,
int N,
int prev)
{
int i;
for (i = 0; i < N; i++)
{
if (val < thresholds[i])
break;
}
if (i > prev && val < thresholds[prev] + hysteresis[prev])
{
i = prev;
}
if (i < prev && val > thresholds[prev - 1] - hysteresis[prev - 1])
{
i = prev;
}
return i;
}
internal static uint celt_lcg_rand(uint seed)
{
return unchecked(1664525 * seed + 1013904223);
}
/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness
with this approximation is important because it has an impact on the bit allocation */
internal static int bitexact_cos(int x)
{
int tmp;
int x2;
tmp = (4096 + ((int)(x) * (x))) >> 13;
Inlines.OpusAssert(tmp <= 32767);
x2 = (tmp);
x2 = ((32767 - x2) + Inlines.FRAC_MUL16(x2, (-7651 + Inlines.FRAC_MUL16(x2, (8277 + Inlines.FRAC_MUL16(-626, x2))))));
Inlines.OpusAssert(x2 <= 32766);
return (1 + x2);
}
internal static int bitexact_log2tan(int isin, int icos)
{
int lc = Inlines.EC_ILOG((uint)icos);
int ls = Inlines.EC_ILOG((uint)isin);
icos <<= 15 - lc;
isin <<= 15 - ls;
return (ls - lc) * (1 << 11)
+ Inlines.FRAC_MUL16(isin, Inlines.FRAC_MUL16(isin, -2597) + 7932)
- Inlines.FRAC_MUL16(icos, Inlines.FRAC_MUL16(icos, -2597) + 7932);
}
/* Compute the amplitude (sqrt energy) in each of the bands */
internal static void compute_band_energies(CeltMode m, int[][] X, int[][] bandE, int end, int C, int LM)
{
int i, c, N;
short[] eBands = m.eBands;
N = m.shortMdctSize << LM;
c = 0;
do
{
for (i = 0; i < end; i++)
{
int j;
int maxval = 0;
int sum = 0;
maxval = Inlines.celt_maxabs32(X[c], (eBands[i] << LM), (eBands[i + 1] - eBands[i]) << LM);
if (maxval > 0)
{
int shift = Inlines.celt_ilog2(maxval) - 14 + (((m.logN[i] >> EntropyCoder.BITRES) + LM + 1) >> 1);
j = eBands[i] << LM;
if (shift > 0)
{
do
{
sum = Inlines.MAC16_16(sum, Inlines.EXTRACT16(Inlines.SHR32(X[c][j], shift)),
Inlines.EXTRACT16(Inlines.SHR32(X[c][j], shift)));
} while (++j < eBands[i + 1] << LM);
}
else {
do
{
sum = Inlines.MAC16_16(sum, Inlines.EXTRACT16(Inlines.SHL32(X[c][j], -shift)),
Inlines.EXTRACT16(Inlines.SHL32(X[c][j], -shift)));
} while (++j < eBands[i + 1] << LM);
}
/* We're adding one here to ensure the normalized band isn't larger than unity norm */
bandE[c][i] = CeltConstants.EPSILON + Inlines.VSHR32(Inlines.celt_sqrt(sum), -shift);
}
else {
bandE[c][i] = CeltConstants.EPSILON;
}
/*printf ("%f ", bandE[i+c*m->nbEBands]);*/
}
} while (++c < C);
}
/* Normalise each band such that the energy is one. */
internal static void normalise_bands(CeltMode m, int[][] freq, int[][] X, int[][] bandE, int end, int C, int M)
{
int i, c;
short[] eBands = m.eBands;
c = 0;
do
{
i = 0;
do
{
int g;
int j, shift;
int E;
shift = Inlines.celt_zlog2(bandE[c][i]) - 13;
E = Inlines.VSHR32(bandE[c][i], shift);
g = Inlines.EXTRACT16(Inlines.celt_rcp(Inlines.SHL32(E, 3)));
j = M * eBands[i]; do
{
X[c][j] = Inlines.MULT16_16_Q15(Inlines.VSHR32(freq[c][j], shift - 1), g);
} while (++j < M * eBands[i + 1]);
} while (++i < end);
} while (++c < C);
}
/* De-normalise the energy to produce the synthesis from the unit-energy bands */
internal static void denormalise_bands(CeltMode m, int[] X,
int[] freq, int freq_ptr, int[] bandLogE, int bandLogE_ptr, int start,
int end, int M, int downsample, int silence)
{
int i, N;
int bound;
int f;
int x;
short[] eBands = m.eBands;
N = M * m.shortMdctSize;
bound = M * eBands[end];
if (downsample != 1)
bound = Inlines.IMIN(bound, N / downsample);
if (silence != 0)
{
bound = 0;
start = end = 0;
}
f = freq_ptr;
x = M * eBands[start];
for (i = 0; i < M * eBands[start]; i++)
{
freq[f++] = 0;
}
for (i = start; i < end; i++)
{
int j, band_end;
int g;
int lg;
int shift;
j = M * eBands[i];
band_end = M * eBands[i + 1];
lg = Inlines.ADD16(bandLogE[bandLogE_ptr + i], Inlines.SHL16(Tables.eMeans[i], 6));
/* Handle the integer part of the log energy */
shift = 16 - (lg >> CeltConstants.DB_SHIFT);
if (shift > 31)
{
shift = 0;
g = 0;
}
else {
/* Handle the fractional part. */
g = Inlines.celt_exp2_frac(lg & ((1 << CeltConstants.DB_SHIFT) - 1));
}
/* Handle extreme gains with negative shift. */
if (shift < 0)
{
/* For shift < -2 we'd be likely to overflow, so we're capping
the gain here. This shouldn't happen unless the bitstream is
already corrupted. */
if (shift < -2)
{
g = 32767;
shift = -2;
}
do
{
freq[f] = Inlines.SHR32(Inlines.MULT16_16(X[x], g), -shift);
} while (++j < band_end);
}
else
{
do
{
freq[f++] = Inlines.SHR32(Inlines.MULT16_16(X[x++], g), shift);
} while (++j < band_end);
}
}
Inlines.OpusAssert(start <= end);
Arrays.MemSetWithOffset<int>(freq, 0, freq_ptr + bound, N - bound);
}
/* This prevents energy collapse for transients with multiple short MDCTs */
internal static void anti_collapse(CeltMode m, int[][] X_, byte[] collapse_masks, int LM, int C, int size,
int start, int end, int[] logE, int[] prev1logE,
int[] prev2logE, int[] pulses, uint seed)
{
int c, i, j, k;
for (i = start; i < end; i++)
{
int N0;
int thresh, sqrt_1;
int depth;
int shift;
int thresh32;
N0 = m.eBands[i + 1] - m.eBands[i];
/* depth in 1/8 bits */
Inlines.OpusAssert(pulses[i] >= 0);
depth = Inlines.celt_udiv(1 + pulses[i], (m.eBands[i + 1] - m.eBands[i])) >> LM;
thresh32 = Inlines.SHR32(Inlines.celt_exp2((0 - Inlines.SHL16((depth), 10 - EntropyCoder.BITRES))), 1);
thresh = (Inlines.MULT16_32_Q15(((short)(0.5 + (0.5f) * (((int)1) << (15))))/*Inlines.QCONST16(0.5f, 15)*/, Inlines.MIN32(32767, thresh32)));
{
int t;
t = N0 << LM;
shift = Inlines.celt_ilog2(t) >> 1;
t = Inlines.SHL32(t, (7 - shift) << 1);
sqrt_1 = Inlines.celt_rsqrt_norm(t);
}
c = 0; do
{
int X;
int prev1;
int prev2;
int Ediff;
int r;
int renormalize = 0;
prev1 = prev1logE[c * m.nbEBands + i];
prev2 = prev2logE[c * m.nbEBands + i];
if (C == 1)
{
prev1 = Inlines.MAX16(prev1, prev1logE[m.nbEBands + i]);
prev2 = Inlines.MAX16(prev2, prev2logE[m.nbEBands + i]);
}
Ediff = Inlines.EXTEND32(logE[c * m.nbEBands + i]) - Inlines.EXTEND32(Inlines.MIN16(prev1, prev2));
Ediff = Inlines.MAX32(0, Ediff);
if (Ediff < 16384)
{
int r32 = Inlines.SHR32(Inlines.celt_exp2((short)(0 - Inlines.EXTRACT16(Ediff))), 1);
r = (2 * Inlines.MIN16(16383, (r32)));
}
else {
r = 0;
}
if (LM == 3)
r = Inlines.MULT16_16_Q14(23170, Inlines.MIN32(23169, r)); // opus bug: was MIN32
r = Inlines.SHR16(Inlines.MIN16(thresh, r), 1);
r = (Inlines.SHR32(Inlines.MULT16_16_Q15(sqrt_1, r), shift));
X = m.eBands[i] << LM;
for (k = 0; k < 1 << LM; k++)
{
/* Detect collapse */
if ((collapse_masks[i * C + c] & 1 << k) == 0)
{
/* Fill with noise */
int Xk = X + k;
for (j = 0; j < N0; j++)
{
seed = celt_lcg_rand(seed);
X_[c][Xk + (j << LM)] = ((seed & 0x8000) != 0 ? r : 0 - r);
}
renormalize = 1;
}
}
/* We just added some energy, so we need to renormalise */
if (renormalize != 0)
{
VQ.renormalise_vector(X_[c], X, N0 << LM, CeltConstants.Q15ONE);
}
} while (++c < C);
}
}
internal static void intensity_stereo(CeltMode m, int[] X, int X_ptr, int[] Y, int Y_ptr, int[][] bandE, int bandID, int N)
{
int i = bandID;
int j;
int a1, a2;
int left, right;
int norm;
int shift = Inlines.celt_zlog2(Inlines.MAX32(bandE[0][i], bandE[1][i])) - 13;
left = Inlines.VSHR32(bandE[0][i], shift);
right = Inlines.VSHR32(bandE[1][i], shift);
norm = CeltConstants.EPSILON + Inlines.celt_sqrt(CeltConstants.EPSILON + Inlines.MULT16_16(left, left) + Inlines.MULT16_16(right, right));
a1 = Inlines.DIV32_16(Inlines.SHL32(left, 14), norm);
a2 = Inlines.DIV32_16(Inlines.SHL32(right, 14), norm);
for (j = 0; j < N; j++)
{
int r, l;
l = X[X_ptr + j];
r = Y[Y_ptr + j];
X[X_ptr + j] = Inlines.EXTRACT16(Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(a1, l), a2, r), 14));
/* Side is not encoded, no need to calculate */
}
}
static void stereo_split(int[] X, int X_ptr, int[] Y, int Y_ptr, int N)
{
int j;
for (j = 0; j < N; j++)
{
int r, l;
l = Inlines.MULT16_16(((short)(0.5 + (.70710678f) * (((int)1) << (15))))/*Inlines.QCONST16(.70710678f, 15)*/, X[X_ptr + j]);
r = Inlines.MULT16_16(((short)(0.5 + (.70710678f) * (((int)1) << (15))))/*Inlines.QCONST16(.70710678f, 15)*/, Y[Y_ptr + j]);
X[X_ptr + j] = Inlines.EXTRACT16(Inlines.SHR32(Inlines.ADD32(l, r), 15));
Y[Y_ptr + j] = Inlines.EXTRACT16(Inlines.SHR32(Inlines.SUB32(r, l), 15));
}
}
static void stereo_merge(int[] X, int X_ptr, int[] Y, int Y_ptr, int mid, int N)
{
int j;
int xp, side;
int El, Er;
int mid2;
int kl, kr;
int t, lgain, rgain;
/* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */
#if UNSAFE
unsafe
{
fixed (int* py_base = Y, px_base = X)
{
int* py = py_base + Y_ptr;
int* px = px_base + X_ptr;
Kernels.dual_inner_prod(py, px, py, N, out xp, out side);
}
}
#else
Kernels.dual_inner_prod(Y, Y_ptr, X, X_ptr, Y, Y_ptr, N, out xp, out side);
#endif
/* Compensating for the mid normalization */
xp = Inlines.MULT16_32_Q15(mid, xp);
/* mid and side are in Q15, not Q14 like X and Y */
mid2 = Inlines.SHR16(mid, 1);
El = Inlines.MULT16_16(mid2, mid2) + side - (2 * xp);
Er = Inlines.MULT16_16(mid2, mid2) + side + (2 * xp);
if (Er < ((int)(0.5 + (6e-4f) * (((int)1) << (28))))/*Inlines.QCONST32(6e-4f, 28)*/ || El < ((int)(0.5 + (6e-4f) * (((int)1) << (28))))/*Inlines.QCONST32(6e-4f, 28)*/)
{
Array.Copy(X, X_ptr, Y, Y_ptr, N);
return;
}
kl = Inlines.celt_ilog2(El) >> 1;
kr = Inlines.celt_ilog2(Er) >> 1;
t = Inlines.VSHR32(El, (kl - 7) << 1);
lgain = Inlines.celt_rsqrt_norm(t);
t = Inlines.VSHR32(Er, (kr - 7) << 1);
rgain = Inlines.celt_rsqrt_norm(t);
if (kl < 7)
kl = 7;
if (kr < 7)
kr = 7;
for (j = 0; j < N; j++)
{
int r, l;
/* Apply mid scaling (side is already scaled) */
l = Inlines.MULT16_16_P15(mid, X[X_ptr + j]);
r = Y[Y_ptr + j];
X[X_ptr + j] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(lgain, Inlines.SUB16(l, r)), kl + 1));
Y[Y_ptr + j] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(rgain, Inlines.ADD16(l, r)), kr + 1));
}
}
/* Decide whether we should spread the pulses in the current frame */
internal static int spreading_decision(CeltMode m, int[][] X, ref int average,
int last_decision, ref int hf_average, ref int tapset_decision, int update_hf,
int end, int C, int M)
{
int i, c;
int sum = 0, nbBands = 0;
short[] eBands = m.eBands;
int decision;
int hf_sum = 0;
Inlines.OpusAssert(end > 0);
if (M * (eBands[end] - eBands[end - 1]) <= 8)
{
return Spread.SPREAD_NONE;
}
c = 0;
do
{
for (i = 0; i < end; i++)
{
int j, N, tmp = 0;
int[] tcount = { 0, 0, 0 };
int[] x = X[c];
int x_ptr = M * eBands[i];
N = M * (eBands[i + 1] - eBands[i]);
if (N <= 8)
continue;
/* Compute rough CDF of |x[j]| */
for (j = x_ptr; j < N + x_ptr; j++)
{
int x2N; /* Q13 */
x2N = Inlines.MULT16_16(Inlines.MULT16_16_Q15(x[j], x[j]), N);
if (x2N < ((short)(0.5 + (0.25f) * (((int)1) << (13))))/*Inlines.QCONST16(0.25f, 13)*/)
tcount[0]++;
if (x2N < ((short)(0.5 + (0.0625f) * (((int)1) << (13))))/*Inlines.QCONST16(0.0625f, 13)*/)
tcount[1]++;
if (x2N < ((short)(0.5 + (0.015625f) * (((int)1) << (13))))/*Inlines.QCONST16(0.015625f, 13)*/)
tcount[2]++;
}
/* Only include four last bands (8 kHz and up) */
if (i > m.nbEBands - 4)
{
hf_sum += Inlines.celt_udiv(32 * (tcount[1] + tcount[0]), N);
}
tmp = (2 * tcount[2] >= N ? 1 : 0) + (2 * tcount[1] >= N ? 1 : 0) + (2 * tcount[0] >= N ? 1 : 0);
sum += tmp * 256;
nbBands++;
}
} while (++c < C);
if (update_hf != 0)
{
if (hf_sum != 0)
{
hf_sum = Inlines.celt_udiv(hf_sum, C * (4 - m.nbEBands + end));
}
hf_average = (hf_average + hf_sum) >> 1;
hf_sum = hf_average;
if (tapset_decision == 2)
{
hf_sum += 4;
}
else if (tapset_decision == 0)
{
hf_sum -= 4;
}
if (hf_sum > 22)
{
tapset_decision = 2;
}
else if (hf_sum > 18)
{
tapset_decision = 1;
}
else
{
tapset_decision = 0;
}
}
Inlines.OpusAssert(nbBands > 0); /* end has to be non-zero */
Inlines.OpusAssert(sum >= 0);
sum = Inlines.celt_udiv(sum, nbBands);
/* Recursive averaging */
sum = (sum + average) >> 1;
average = sum;
/* Hysteresis */
sum = (3 * sum + (((3 - last_decision) << 7) + 64) + 2) >> 2;
if (sum < 80)
{
decision = Spread.SPREAD_AGGRESSIVE;
}
else if (sum < 256)
{
decision = Spread.SPREAD_NORMAL;
}
else if (sum < 384)
{
decision = Spread.SPREAD_LIGHT;
}
else {
decision = Spread.SPREAD_NONE;
}
#if FUZZING
decision = new Random().Next() & 0x3;
tapset_decision.Val = new Random().Next() % 3;
#endif
return decision;
}
internal static void deinterleave_hadamard(int[] X, int X_ptr, int N0, int stride, int hadamard)
{
int i, j;
int N;
N = N0 * stride;
int[] tmp = new int[N];
Inlines.OpusAssert(stride > 0);
if (hadamard != 0)
{
int ordery = (stride - 2);
for (i = 0; i < stride; i++)
{
for (j = 0; j < N0; j++)
{
tmp[Tables.ordery_table[ordery + i] * N0 + j] = X[j * stride + i + X_ptr];
}
}
}
else
{
for (i = 0; i < stride; i++)
{
for (j = 0; j < N0; j++)
{
tmp[i * N0 + j] = X[j * stride + i + X_ptr];
}
}
}
Array.Copy(tmp, 0, X, X_ptr, N);
}
internal static void interleave_hadamard(int[] X, int X_ptr, int N0, int stride, int hadamard)
{
int i, j;
int N;
N = N0 * stride;
int[] tmp = new int[N];
if (hadamard != 0)
{
int ordery = (stride - 2);
for (i = 0; i < stride; i++)
{
for (j = 0; j < N0; j++)
{
tmp[j * stride + i] = X[Tables.ordery_table[ordery + i] * N0 + j + X_ptr];
}
}
}
else
{
for (i = 0; i < stride; i++)
{
for (j = 0; j < N0; j++)
{
tmp[j * stride + i] = X[i * N0 + j + X_ptr];
}
}
}
Array.Copy(tmp, 0, X, X_ptr, N);
}
internal static void haar1(int[] X, int X_ptr, int N0, int stride)
{
int i, j;
N0 >>= 1;
for (i = 0; i < stride; i++)
{
for (j = 0; j < N0; j++)
{
int tmpidx = X_ptr + i + (stride * 2 * j);
int tmp1, tmp2;
tmp1 = Inlines.MULT16_16(((short)(0.5 + (.70710678f) * (((int)1) << (15))))/*Inlines.QCONST16(.70710678f, 15)*/, X[tmpidx]);
tmp2 = Inlines.MULT16_16(((short)(0.5 + (.70710678f) * (((int)1) << (15))))/*Inlines.QCONST16(.70710678f, 15)*/, X[tmpidx + stride]);
X[tmpidx] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.ADD32(tmp1, tmp2), 15));
X[tmpidx + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.SUB32(tmp1, tmp2), 15));
}
}
}
internal static void haar1ZeroOffset(int[] X, int N0, int stride)
{
int i, j;
N0 >>= 1;
for (i = 0; i < stride; i++)
{
for (j = 0; j < N0; j++)
{
int tmpidx = i + (stride * 2 * j);
int tmp1, tmp2;
tmp1 = Inlines.MULT16_16(((short)(0.5 + (.70710678f) * (((int)1) << (15))))/*Inlines.QCONST16(.70710678f, 15)*/, X[tmpidx]);
tmp2 = Inlines.MULT16_16(((short)(0.5 + (.70710678f) * (((int)1) << (15))))/*Inlines.QCONST16(.70710678f, 15)*/, X[tmpidx + stride]);
X[tmpidx] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.ADD32(tmp1, tmp2), 15));
X[tmpidx + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.SUB32(tmp1, tmp2), 15));
}
}
}
internal static int compute_qn(int N, int b, int offset, int pulse_cap, int stereo)
{
short[] exp2_table8 =
{16384, 17866, 19483, 21247, 23170, 25267, 27554, 30048};
int qn, qb;
int N2 = 2 * N - 1;
if (stereo != 0 && N == 2)
{
N2--;
}
/* The upper limit ensures that in a stereo split with itheta==16384, we'll
always have enough bits left over to code at least one pulse in the
side; otherwise it would collapse, since it doesn't get folded. */
qb = Inlines.celt_sudiv(b + N2 * offset, N2);
qb = Inlines.IMIN(b - pulse_cap - (4 << EntropyCoder.BITRES), qb);
qb = Inlines.IMIN(8 << EntropyCoder.BITRES, qb);
if (qb < (1 << EntropyCoder.BITRES >> 1))
{
qn = 1;
}
else {
qn = exp2_table8[qb & 0x7] >> (14 - (qb >> EntropyCoder.BITRES));
qn = (qn + 1) >> 1 << 1;
}
Inlines.OpusAssert(qn <= 256);
return qn;
}
public class band_ctx
{
public int encode;
public CeltMode m;
public int i;
public int intensity;
public int spread;
public int tf_change;
public EntropyCoder ec;
public int remaining_bits;
public int[][] bandE;
public uint seed;
};
public class split_ctx
{
public int inv;
public int imid;
public int iside;
public int delta;
public int itheta;
public int qalloc;
};
internal static void compute_theta(band_ctx ctx, split_ctx sctx,
int[] X, int X_ptr, int[] Y, int Y_ptr, int N, ref int b, int B, int B0,
int LM,
int stereo, ref int fill)
{
int qn;
int itheta = 0;
int delta;
int imid, iside;
int qalloc;
int pulse_cap;
int offset;
int tell;
int inv = 0;
int encode;
CeltMode m;
int i;
int intensity;
EntropyCoder ec; // porting note: pointer
int[][] bandE;
encode = ctx.encode;
m = ctx.m;
i = ctx.i;
intensity = ctx.intensity;
ec = ctx.ec;
bandE = ctx.bandE;
/* Decide on the resolution to give to the split parameter theta */
pulse_cap = m.logN[i] + LM * (1 << EntropyCoder.BITRES);
offset = (pulse_cap >> 1) - (stereo != 0 && N == 2 ? CeltConstants.QTHETA_OFFSET_TWOPHASE : CeltConstants.QTHETA_OFFSET);
qn = compute_qn(N, b, offset, pulse_cap, stereo);
if (stereo != 0 && i >= intensity)
{
qn = 1;
}
if (encode != 0)
{
/* theta is the atan() of the ratio between the (normalized)
side and mid. With just that parameter, we can re-scale both
mid and side because we know that 1) they have unit norm and
2) they are orthogonal. */
itheta = VQ.stereo_itheta(X, X_ptr, Y, Y_ptr, stereo, N);
}
tell = (int)ec.tell_frac();
if (qn != 1)
{
if (encode != 0)
{
itheta = (itheta * qn + 8192) >> 14;
}
/* Entropy coding of the angle. We use a uniform pdf for the
time split, a step for stereo, and a triangular one for the rest. */
if (stereo != 0 && N > 2)
{
int p0 = 3;
int x = itheta;
int x0 = qn / 2;
uint ft = (uint)(p0 * (x0 + 1) + x0);
/* Use a probability of p0 up to itheta=8192 and then use 1 after */
if (encode != 0)
{
ec.encode(
(uint)(x <= x0 ?
(p0 * x) :
((x - 1 - x0) + (x0 + 1) * p0)),
(uint)(x <= x0 ?
(p0 * (x + 1)) :
((x - x0) + (x0 + 1) * p0)),
ft);
}
else
{
int fs;
fs = (int)ec.decode(ft);
if (fs < (x0 + 1) * p0)
{
x = fs / p0;
}
else
{
x = x0 + 1 + (fs - (x0 + 1) * p0);
}
ec.dec_update(
(uint)(x <= x0 ?
p0 * x :
(x - 1 - x0) + (x0 + 1) * p0),
(uint)(x <= x0 ?
p0 * (x + 1) :
(x - x0) + (x0 + 1) * p0),
ft);
itheta = x;
}
}
else if (B0 > 1 || stereo != 0)
{
/* Uniform pdf */
if (encode != 0)
{
ec.enc_uint((uint)itheta, (uint)qn + 1);
}
else
{
itheta = (int)ec.dec_uint((uint)qn + 1);
}
}
else
{
int fs = 1, ft;
ft = ((qn >> 1) + 1) * ((qn >> 1) + 1);
if (encode != 0)
{
int fl;
fs = itheta <= (qn >> 1) ? itheta + 1 : qn + 1 - itheta;
fl = itheta <= (qn >> 1) ? itheta * (itheta + 1) >> 1 :
ft - ((qn + 1 - itheta) * (qn + 2 - itheta) >> 1);
ec.encode((uint)fl, (uint)(fl + fs), (uint)ft);
}
else
{
/* Triangular pdf */
int fl = 0;
int fm;
fm = (int)ec.decode((uint)ft);
if (fm < ((qn >> 1) * ((qn >> 1) + 1) >> 1))
{
itheta = (int)(Inlines.isqrt32(8 * (uint)fm + 1) - 1) >> 1;
fs = itheta + 1;
fl = itheta * (itheta + 1) >> 1;
}
else
{
itheta = (int)(2 * (qn + 1) - Inlines.isqrt32(8 * (uint)(ft - fm - 1) + 1)) >> 1;
fs = qn + 1 - itheta;
fl = ft - ((qn + 1 - itheta) * (qn + 2 - itheta) >> 1);
}
ec.dec_update((uint)fl, (uint)(fl + fs), (uint)ft);
}
}
Inlines.OpusAssert(itheta >= 0);
itheta = Inlines.celt_udiv(itheta * 16384, qn);
if (encode != 0 && stereo != 0)
{
if (itheta == 0)
{
intensity_stereo(m, X, X_ptr, Y, Y_ptr, bandE, i, N);
}
else
{
stereo_split(X, X_ptr, Y, Y_ptr, N);
}
}
}
else if (stereo != 0)
{
if (encode != 0)
{
inv = itheta > 8192 ? 1 : 0;
if (inv != 0)
{
int j;
for (j = 0; j < N; j++)
Y[Y_ptr + j] = (0 - Y[Y_ptr + j]);
}
intensity_stereo(m, X, X_ptr, Y, Y_ptr, bandE, i, N);
}
if (b > 2 << EntropyCoder.BITRES && ctx.remaining_bits > 2 << EntropyCoder.BITRES)
{
if (encode != 0)
{
ec.enc_bit_logp(inv, 2);
}
else
{
inv = ec.dec_bit_logp(2);
}
}
else
inv = 0;
itheta = 0;
}
qalloc = (int)ec.tell_frac() - tell;
b -= qalloc;
if (itheta == 0)
{
imid = 32767;
iside = 0;
fill &= (1 << B) - 1;
delta = -16384;
}
else if (itheta == 16384)
{
imid = 0;
iside = 32767;
fill &= ((1 << B) - 1) << B;
delta = 16384;
}
else {
imid = bitexact_cos((short)itheta);
iside = bitexact_cos((short)(16384 - itheta));
/* This is the mid vs side allocation that minimizes squared error
in that band. */
delta = Inlines.FRAC_MUL16((N - 1) << 7, bitexact_log2tan(iside, imid));
}
sctx.inv = inv;
sctx.imid = imid;
sctx.iside = iside;
sctx.delta = delta;
sctx.itheta = itheta;
sctx.qalloc = qalloc;
}
internal static uint quant_band_n1(band_ctx ctx, int[] X, int X_ptr, int[] Y, int Y_ptr, int b,
int[] lowband_out, int lowband_out_ptr)
{
int resynth = ctx.encode == 0 ? 1 : 0;
int c;
int stereo;
int[] x = X;
int x_ptr = X_ptr;
int encode;
EntropyCoder ec; // porting note: pointer
encode = ctx.encode;
ec = ctx.ec;
stereo = (Y != null) ? 1 : 0;
c = 0;
do
{
int sign = 0;
if (ctx.remaining_bits >= 1 << EntropyCoder.BITRES)
{
if (encode != 0)
{
sign = x[x_ptr] < 0 ? 1 : 0;
ec.enc_bits((uint)sign, 1);
}
else
{
sign = (int)ec.dec_bits(1);
}
ctx.remaining_bits -= 1 << EntropyCoder.BITRES;
b -= 1 << EntropyCoder.BITRES;
}
if (resynth != 0)
x[x_ptr] = sign != 0 ? 0 - CeltConstants.NORM_SCALING : CeltConstants.NORM_SCALING;
x = Y;
x_ptr = Y_ptr;
} while (++c < 1 + stereo);
if (lowband_out != null)
{
lowband_out[lowband_out_ptr] = Inlines.SHR16(X[X_ptr], 4);
}
return 1;
}
/* This function is responsible for encoding and decoding a mono partition.
It can split the band in two and transmit the energy difference with
the two half-bands. It can be called recursively so bands can end up being
split in 8 parts. */
internal static uint quant_partition(band_ctx ctx, int[] X, int X_ptr,
int N, int b, int B, int[] lowband, int lowband_ptr,
int LM,
int gain, int fill)
{
int cache_ptr;
int q;
int curr_bits;
int imid = 0, iside = 0;
int B0 = B;
int mid = 0, side = 0;
uint cm = 0;
int resynth = (ctx.encode == 0) ? 1 : 0;
int Y = 0;
int encode;
CeltMode m; //porting note: pointer
int i;
int spread;
EntropyCoder ec; //porting note: pointer
encode = ctx.encode;
m = ctx.m;
i = ctx.i;
spread = ctx.spread;
ec = ctx.ec;
byte[] cache = m.cache.bits;
/* If we need 1.5 more bits than we can produce, split the band in two. */
cache_ptr = m.cache.index[(LM + 1) * m.nbEBands + i];
if (LM != -1 && b > cache[cache_ptr + cache[cache_ptr]] + 12 && N > 2)
{
int mbits, sbits, delta;
int itheta;
int qalloc;
split_ctx sctx = new split_ctx();
int next_lowband2 = 0;
int rebalance;
N >>= 1;
Y = X_ptr + N;
LM -= 1;
if (B == 1)
{
fill = (fill & 1) | (fill << 1);
}
B = (B + 1) >> 1;
compute_theta(ctx, sctx, X, X_ptr, X, Y, N, ref b, B, B0, LM, 0, ref fill);
imid = sctx.imid;
iside = sctx.iside;
delta = sctx.delta;
itheta = sctx.itheta;
qalloc = sctx.qalloc;
mid = (imid);
side = (iside);
/* Give more bits to low-energy MDCTs than they would otherwise deserve */
if (B0 > 1 && ((itheta & 0x3fff) != 0))
{
if (itheta > 8192)
/* Rough approximation for pre-echo masking */
delta -= delta >> (4 - LM);
else
/* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */
delta = Inlines.IMIN(0, delta + (N << EntropyCoder.BITRES >> (5 - LM)));
}
mbits = Inlines.IMAX(0, Inlines.IMIN(b, (b - delta) / 2));
sbits = b - mbits;
ctx.remaining_bits -= qalloc;
if (lowband != null)
{
next_lowband2 = (lowband_ptr + N); /* >32-bit split case */
}
rebalance = ctx.remaining_bits;
if (mbits >= sbits)
{
cm = quant_partition(ctx, X, X_ptr, N, mbits, B,
lowband, lowband_ptr, LM,
Inlines.MULT16_16_P15(gain, mid), fill);
rebalance = mbits - (rebalance - ctx.remaining_bits);
if (rebalance > 3 << EntropyCoder.BITRES && itheta != 0)
sbits += rebalance - (3 << EntropyCoder.BITRES);
cm |= quant_partition(ctx, X, Y, N, sbits, B,
lowband, next_lowband2, LM,
Inlines.MULT16_16_P15(gain, side), fill >> B) << (B0 >> 1);
}
else {
cm = quant_partition(ctx, X, Y, N, sbits, B,
lowband, next_lowband2, LM,
Inlines.MULT16_16_P15(gain, side), fill >> B) << (B0 >> 1);
rebalance = sbits - (rebalance - ctx.remaining_bits);
if (rebalance > 3 << EntropyCoder.BITRES && itheta != 16384)
mbits += rebalance - (3 << EntropyCoder.BITRES);
cm |= quant_partition(ctx, X, X_ptr, N, mbits, B,
lowband, lowband_ptr, LM,
Inlines.MULT16_16_P15(gain, mid), fill);
}
}
else {
/* This is the basic no-split case */
q = Rate.bits2pulses(m, i, LM, b);
curr_bits = Rate.pulses2bits(m, i, LM, q);
ctx.remaining_bits -= curr_bits;
/* Ensures we can never bust the budget */
while (ctx.remaining_bits < 0 && q > 0)
{
ctx.remaining_bits += curr_bits;
q--;
curr_bits = Rate.pulses2bits(m, i, LM, q);
ctx.remaining_bits -= curr_bits;
}
if (q != 0)
{
int K = Rate.get_pulses(q);
/* Finally do the actual quantization */
if (encode != 0)
{
cm = VQ.alg_quant(X, X_ptr, N, K, spread, B, ec);
}
else {
cm = VQ.alg_unquant(X, X_ptr, N, K, spread, B, ec, gain);
}
}
else
{
/* If there's no pulse, fill the band anyway */
int j;
if (resynth != 0)
{
uint cm_mask;
/* B can be as large as 16, so this shift might overflow an int on a
16-bit platform; use a long to get defined behavior.*/
cm_mask = (uint)(1UL << B) - 1;
fill &= (int)cm_mask;
if (fill == 0)
{
Arrays.MemSetWithOffset<int>(X, 0, X_ptr, N);
}
else
{
if (lowband == null)
{
/* Noise */
for (j = 0; j < N; j++)
{
ctx.seed = celt_lcg_rand(ctx.seed);
X[X_ptr + j] = unchecked(unchecked((int)ctx.seed) >> 20);
}
cm = cm_mask;
}
else
{
/* Folded spectrum */
for (j = 0; j < N; j++)
{
int tmp;
ctx.seed = celt_lcg_rand(ctx.seed);
/* About 48 dB below the "normal" folding level */
tmp = ((short)(0.5 + (1.0f / 256) * (((int)1) << (10))))/*Inlines.QCONST16(1.0f / 256, 10)*/;
tmp = (((ctx.seed) & 0x8000) != 0 ? tmp : 0 - tmp);
X[X_ptr + j] = (lowband[lowband_ptr + j] + tmp);
}
cm = (uint)fill;
}
VQ.renormalise_vector(X, X_ptr, N, gain);
}
}
}
}
return cm;
}
private static readonly byte[] bit_interleave_table = { 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3 };
private static readonly byte[] bit_deinterleave_table ={
0x00,0x03,0x0C,0x0F,0x30,0x33,0x3C,0x3F,
0xC0,0xC3,0xCC,0xCF,0xF0,0xF3,0xFC,0xFF
};
/* This function is responsible for encoding and decoding a band for the mono case. */
internal static uint quant_band(band_ctx ctx, int[] X, int X_ptr,
int N, int b, int B, int[] lowband, int lowband_ptr,
int LM, int[] lowband_out, int lowband_out_ptr,
int gain, int[] lowband_scratch, int lowband_scratch_ptr, int fill)
{
int N0 = N;
int N_B = N;
int N_B0;
int B0 = B;
int time_divide = 0;
int recombine = 0;
int longBlocks;
uint cm = 0;
int resynth = ctx.encode == 0 ? 1 : 0;
int k;
int encode;
int tf_change;
encode = ctx.encode;
tf_change = ctx.tf_change;
longBlocks = B0 == 1 ? 1 : 0;
N_B = Inlines.celt_udiv(N_B, B);
/* Special case for one sample */
if (N == 1)
{
return quant_band_n1(ctx, X, X_ptr, null, 0, b, lowband_out, lowband_out_ptr);
}
if (tf_change > 0)
recombine = tf_change;
/* Band recombining to increase frequency resolution */
if (lowband_scratch != null && lowband != null && (recombine != 0 || ((N_B & 1) == 0 && tf_change < 0) || B0 > 1))
{
Array.Copy(lowband, lowband_ptr, lowband_scratch, lowband_scratch_ptr, N);
lowband = lowband_scratch;
lowband_ptr = lowband_scratch_ptr;
}
for (k = 0; k < recombine; k++)
{
if (encode != 0)
haar1(X, X_ptr, N >> k, 1 << k);
if (lowband != null)
haar1(lowband, lowband_ptr, N >> k, 1 << k);
fill = bit_interleave_table[fill & 0xF] | bit_interleave_table[fill >> 4] << 2;
}
B >>= recombine;
N_B <<= recombine;
/* Increasing the time resolution */
while ((N_B & 1) == 0 && tf_change < 0)
{
if (encode != 0)
haar1(X, X_ptr, N_B, B);
if (lowband != null)
haar1(lowband, lowband_ptr, N_B, B);
fill |= fill << B;
B <<= 1;
N_B >>= 1;
time_divide++;
tf_change++;
}
B0 = B;
N_B0 = N_B;
/* Reorganize the samples in time order instead of frequency order */
if (B0 > 1)
{
if (encode != 0)
deinterleave_hadamard(X, X_ptr, N_B >> recombine, B0 << recombine, longBlocks);
if (lowband != null)
deinterleave_hadamard(lowband, lowband_ptr, N_B >> recombine, B0 << recombine, longBlocks);
}
cm = quant_partition(ctx, X, X_ptr, N, b, B, lowband, lowband_ptr, LM, gain, fill);
/* This code is used by the decoder and by the resynthesis-enabled encoder */
if (resynth != 0)
{
/* Undo the sample reorganization going from time order to frequency order */
if (B0 > 1)
interleave_hadamard(X, X_ptr, N_B >> recombine, B0 << recombine, longBlocks);
/* Undo time-freq changes that we did earlier */
N_B = N_B0;
B = B0;
for (k = 0; k < time_divide; k++)
{
B >>= 1;
N_B <<= 1;
cm |= cm >> B;
haar1(X, X_ptr, N_B, B);
}
for (k = 0; k < recombine; k++)
{
cm = bit_deinterleave_table[cm];
haar1(X, X_ptr, N0 >> k, 1 << k);
}
B <<= recombine;
/* Scale output for later folding */
if (lowband_out != null)
{
int j;
int n;
n = (Inlines.celt_sqrt(Inlines.SHL32(N0, 22)));
for (j = 0; j < N0; j++)
lowband_out[lowband_out_ptr + j] = Inlines.MULT16_16_Q15(n, X[X_ptr + j]);
}
cm = cm & (uint)((1 << B) - 1);
}
return cm;
}
/* This function is responsible for encoding and decoding a band for the stereo case. */
internal static uint quant_band_stereo(band_ctx ctx, int[] X, int X_ptr, int[] Y, int Y_ptr,
int N, int b, int B, int[] lowband, int lowband_ptr,
int LM, int[] lowband_out, int lowband_out_ptr,
int[] lowband_scratch, int lowband_scratch_ptr, int fill)
{
int imid = 0, iside = 0;
int inv = 0;
int mid = 0, side = 0;
uint cm = 0;
int resynth = ctx.encode == 0 ? 1 : 0;
int mbits, sbits, delta;
int itheta;
int qalloc;
split_ctx sctx = new split_ctx(); // porting note: stack var
int orig_fill;
int encode;
EntropyCoder ec; //porting note: pointer
encode = ctx.encode;
ec = ctx.ec;
/* Special case for one sample */
if (N == 1)
{
return quant_band_n1(ctx, X, X_ptr, Y, Y_ptr, b, lowband_out, lowband_out_ptr);
}
orig_fill = fill;
compute_theta(ctx, sctx, X, X_ptr, Y, Y_ptr, N, ref b, B, B, LM, 1, ref fill);
inv = sctx.inv;
imid = sctx.imid;
iside = sctx.iside;
delta = sctx.delta;
itheta = sctx.itheta;
qalloc = sctx.qalloc;
mid = (imid);
side = (iside);
/* This is a special case for N=2 that only works for stereo and takes
advantage of the fact that mid and side are orthogonal to encode
the side with just one bit. */
if (N == 2)
{
int c;
int sign = 0;
int[] x2, y2;
int x2_ptr, y2_ptr;
mbits = b;
sbits = 0;
/* Only need one bit for the side. */
if (itheta != 0 && itheta != 16384)
sbits = 1 << EntropyCoder.BITRES;
mbits -= sbits;
c = itheta > 8192 ? 1 : 0;
ctx.remaining_bits -= qalloc + sbits;
if (c != 0)
{
x2 = Y;
x2_ptr = Y_ptr;
y2 = X;
y2_ptr = X_ptr;
}
else
{
x2 = X;
x2_ptr = X_ptr;
y2 = Y;
y2_ptr = Y_ptr;
}
if (sbits != 0)
{
if (encode != 0)
{
/* Here we only need to encode a sign for the side. */
sign = (x2[x2_ptr] * y2[Y_ptr + 1] - x2[x2_ptr + 1] * y2[Y_ptr] < 0) ? 1 : 0;
ec.enc_bits((uint)sign, 1);
}
else
{
sign = (int)ec.dec_bits(1);
}
}
sign = 1 - 2 * sign;
/* We use orig_fill here because we want to fold the side, but if
itheta==16384, we'll have cleared the low bits of fill. */
cm = quant_band(ctx, x2, x2_ptr, N, mbits, B, lowband, lowband_ptr,
LM, lowband_out, lowband_out_ptr, CeltConstants.Q15ONE, lowband_scratch, lowband_scratch_ptr, orig_fill);
/* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse),
and there's no need to worry about mixing with the other channel. */
y2[Y_ptr] = ((0 - sign) * x2[x2_ptr + 1]);
y2[Y_ptr + 1] = (sign * x2[x2_ptr]);
if (resynth != 0)
{
int tmp;
X[X_ptr] = Inlines.MULT16_16_Q15(mid, X[X_ptr]);
X[X_ptr + 1] = Inlines.MULT16_16_Q15(mid, X[X_ptr + 1]);
Y[Y_ptr] = Inlines.MULT16_16_Q15(side, Y[Y_ptr]);
Y[Y_ptr + 1] = Inlines.MULT16_16_Q15(side, Y[Y_ptr + 1]);
tmp = X[X_ptr];
X[X_ptr] = Inlines.SUB16(tmp, Y[Y_ptr]);
Y[Y_ptr] = Inlines.ADD16(tmp, Y[Y_ptr]);
tmp = X[X_ptr + 1];
X[X_ptr + 1] = Inlines.SUB16(tmp, Y[Y_ptr + 1]);
Y[Y_ptr + 1] = Inlines.ADD16(tmp, Y[Y_ptr + 1]);
}
}
else
{
/* "Normal" split code */
int rebalance;
mbits = Inlines.IMAX(0, Inlines.IMIN(b, (b - delta) / 2));
sbits = b - mbits;
ctx.remaining_bits -= qalloc;
rebalance = ctx.remaining_bits;
if (mbits >= sbits)
{
/* In stereo mode, we do not apply a scaling to the mid because we need the normalized
mid for folding later. */
cm = quant_band(ctx, X, X_ptr, N, mbits, B,
lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr,
CeltConstants.Q15ONE, lowband_scratch, lowband_scratch_ptr, fill);
rebalance = mbits - (rebalance - ctx.remaining_bits);
if (rebalance > 3 << EntropyCoder.BITRES && itheta != 0)
sbits += rebalance - (3 << EntropyCoder.BITRES);
/* For a stereo split, the high bits of fill are always zero, so no
folding will be done to the side. */
cm |= quant_band(ctx, Y, Y_ptr, N, sbits, B,
null, 0, LM, null, 0,
side, null, 0, fill >> B);
}
else
{
/* For a stereo split, the high bits of fill are always zero, so no
folding will be done to the side. */
cm = quant_band(ctx, Y, Y_ptr, N, sbits, B,
null, 0, LM, null, 0,
side, null, 0, fill >> B);
rebalance = sbits - (rebalance - ctx.remaining_bits);
if (rebalance > 3 << EntropyCoder.BITRES && itheta != 16384)
mbits += rebalance - (3 << EntropyCoder.BITRES);
/* In stereo mode, we do not apply a scaling to the mid because we need the normalized
mid for folding later. */
cm |= quant_band(ctx, X, X_ptr, N, mbits, B,
lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr,
CeltConstants.Q15ONE, lowband_scratch, lowband_scratch_ptr, fill);
}
}
/* This code is used by the decoder and by the resynthesis-enabled encoder */
if (resynth != 0)
{
if (N != 2)
{
stereo_merge(X, X_ptr, Y, Y_ptr, mid, N);
}
if (inv != 0)
{
int j;
for (j = Y_ptr; j < N + Y_ptr; j++)
Y[j] = (short)(0 - Y[j]);
}
}
return cm;
}
internal static void quant_all_bands(int encode, CeltMode m, int start, int end,
int[] X_, int[] Y_, byte[] collapse_masks,
int[][] bandE, int[] pulses, int shortBlocks, int spread,
int dual_stereo, int intensity, int[] tf_res, int total_bits,
int balance, EntropyCoder ec, int LM, int codedBands,
ref uint seed)
{
int i;
int remaining_bits;
short[] eBands = m.eBands;
int[] norm;
int norm2;
int[] lowband_scratch;
int lowband_scratch_ptr;
int B;
int M;
int lowband_offset;
int update_lowband = 1;
int C = Y_ != null ? 2 : 1;
int norm_offset;
int resynth = encode == 0 ? 1 : 0;
band_ctx ctx = new band_ctx(); // porting note: stack var
M = 1 << LM;
B = (shortBlocks != 0) ? M : 1;
norm_offset = M * eBands[start];
/* No need to allocate norm for the last band because we don't need an
output in that band. */
norm = new int[(C * (M * eBands[m.nbEBands - 1] - norm_offset))];
norm2 = M * eBands[m.nbEBands - 1] - norm_offset;
/* We can use the last band as scratch space because we don't need that
scratch space for the last band. */
lowband_scratch = X_;
lowband_scratch_ptr = M * eBands[m.nbEBands - 1];
lowband_offset = 0;
ctx.bandE = bandE;
ctx.ec = ec;
ctx.encode = encode;
ctx.intensity = intensity;
ctx.m = m;
ctx.seed = seed;
ctx.spread = spread;
for (i = start; i < end; i++)
{
int tell;
int b;
int N;
int curr_balance;
int effective_lowband = -1;
int[] X, Y;
int X_ptr, Y_ptr;
Y_ptr = 0;
int tf_change = 0;
uint x_cm;
uint y_cm;
int last;
ctx.i = i;
last = (i == end - 1) ? 1 : 0;
X = X_;
X_ptr = (M * eBands[i]);
if (Y_ != null)
{
Y = Y_;
Y_ptr = (M * eBands[i]);
}
else
{
Y = null;
}
N = M * eBands[i + 1] - M * eBands[i];
tell = (int)ec.tell_frac();
/* Compute how many bits we want to allocate to this band */
if (i != start)
balance -= tell;
remaining_bits = total_bits - tell - 1;
ctx.remaining_bits = remaining_bits;
if (i <= codedBands - 1)
{
curr_balance = Inlines.celt_sudiv(balance, Inlines.IMIN(3, codedBands - i));
b = Inlines.IMAX(0, Inlines.IMIN(16383, Inlines.IMIN(remaining_bits + 1, pulses[i] + curr_balance)));
}
else
{
b = 0;
}
if (resynth != 0 && M * eBands[i] - N >= M * eBands[start] && (update_lowband != 0 || lowband_offset == 0))
{
lowband_offset = i;
}
tf_change = tf_res[i];
ctx.tf_change = tf_change;
if (i >= m.effEBands)
{
X = norm;
X_ptr = 0;
if (Y_ != null)
{
Y = norm;
Y_ptr = 0;
}
lowband_scratch = null;
}
if (i == end - 1)
{
lowband_scratch = null;
}
/* Get a conservative estimate of the collapse_mask's for the bands we're
going to be folding from. */
if (lowband_offset != 0 && (spread != Spread.SPREAD_AGGRESSIVE || B > 1 || tf_change < 0))
{
int fold_start;
int fold_end;
int fold_i;
/* This ensures we never repeat spectral content within one band */
effective_lowband = Inlines.IMAX(0, M * eBands[lowband_offset] - norm_offset - N);
fold_start = lowband_offset;
while (M * eBands[--fold_start] > effective_lowband + norm_offset) ;
fold_end = lowband_offset - 1;
while (M * eBands[++fold_end] < effective_lowband + norm_offset + N) ;
x_cm = y_cm = 0;
fold_i = fold_start; do
{
x_cm |= collapse_masks[fold_i * C + 0];
y_cm |= collapse_masks[fold_i * C + C - 1];
} while (++fold_i < fold_end);
}
/* Otherwise, we'll be using the LCG to fold, so all blocks will (almost
always) be non-zero. */
else
{
x_cm = y_cm = (uint)((1 << B) - 1);
}
if (dual_stereo != 0 && i == intensity)
{
int j;
/* Switch off dual stereo to do intensity. */
dual_stereo = 0;
if (resynth != 0)
{
for (j = 0; j < M * eBands[i] - norm_offset; j++)
{
norm[j] = (Inlines.HALF32(norm[j] + norm[norm2 + j]));
}
}
}
if (dual_stereo != 0)
{
x_cm = quant_band(ctx,
X,
X_ptr,
N,
b / 2,
B,
effective_lowband != -1 ? norm : null,
effective_lowband,
LM,
last != 0 ? null : norm,
M * eBands[i] - norm_offset,
CeltConstants.Q15ONE,
lowband_scratch,
lowband_scratch_ptr,
(int)x_cm);
y_cm = quant_band(
ctx,
Y,
Y_ptr,
N,
b / 2,
B,
effective_lowband != -1 ? norm : null,
norm2 + effective_lowband,
LM,
last != 0 ? null : norm,
norm2 + (M * eBands[i] - norm_offset),
CeltConstants.Q15ONE,
lowband_scratch,
lowband_scratch_ptr,
(int)y_cm);
}
else
{
if (Y != null)
{
x_cm = quant_band_stereo(
ctx,
X,
X_ptr,
Y,
Y_ptr,
N,
b,
B,
effective_lowband != -1 ? norm : null,
effective_lowband,
LM,
last != 0 ? null : norm,
M * eBands[i] - norm_offset,
lowband_scratch,
lowband_scratch_ptr,
(int)(x_cm | y_cm));
}
else
{
x_cm = quant_band(
ctx,
X,
X_ptr,
N,
b,
B,
effective_lowband != -1 ? norm : null,
effective_lowband,
LM,
last != 0 ? null : norm,
M * eBands[i] - norm_offset,
CeltConstants.Q15ONE,
lowband_scratch,
lowband_scratch_ptr,
(int)(x_cm | y_cm)); // opt: lots of pointers are created here too
}
y_cm = x_cm;
}
collapse_masks[i * C + 0] = (byte)(x_cm & 0xFF);
collapse_masks[i * C + C - 1] = (byte)(y_cm & 0xFF);
balance += pulses[i] + tell;
/* Update the folding position only as long as we have 1 bit/sample depth. */
update_lowband = (b > (N << EntropyCoder.BITRES)) ? 1 : 0;
}
seed = ctx.seed;
}
}
}