Build AsminVoicechat / prepare-release (push) Successful in 14s
Build AsminVoicechat / build-and-test (17) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (18) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (19) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (20) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (21) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (22) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (23) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (24) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (25) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (26) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (27-ea) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (16) (push) Canceled after 38s
844 lines
36 KiB
Java
844 lines
36 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*/
|
|
package de.maxhenkel.voicechat.concentus;
|
|
|
|
import de.maxhenkel.voicechat.concentus.AnalysisInfo;
|
|
import de.maxhenkel.voicechat.concentus.Arrays;
|
|
import de.maxhenkel.voicechat.concentus.Bands;
|
|
import de.maxhenkel.voicechat.concentus.BoxedValueInt;
|
|
import de.maxhenkel.voicechat.concentus.CeltMode;
|
|
import de.maxhenkel.voicechat.concentus.CeltTables;
|
|
import de.maxhenkel.voicechat.concentus.EntropyCoder;
|
|
import de.maxhenkel.voicechat.concentus.Inlines;
|
|
import de.maxhenkel.voicechat.concentus.Kernels;
|
|
import de.maxhenkel.voicechat.concentus.MDCT;
|
|
import de.maxhenkel.voicechat.concentus.OpusFramesize;
|
|
import de.maxhenkel.voicechat.concentus.Pitch;
|
|
|
|
class CeltCommon {
|
|
private static final short[] inv_table = new short[]{255, 255, 156, 110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25, 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2};
|
|
private static final short[][] gains = new short[][]{{10048, 7112, 4248}, {15200, 8784, 0}, {26208, 3280, 0}};
|
|
private static final byte[][] tf_select_table = new byte[][]{{0, -1, 0, -1, 0, -1, 0, -1}, {0, -1, 0, -2, 1, 0, 1, -1}, {0, -2, 0, -3, 2, 0, 1, -1}, {0, -2, 0, -3, 3, 0, 1, -1}};
|
|
|
|
CeltCommon() {
|
|
}
|
|
|
|
static int compute_vbr(CeltMode mode, AnalysisInfo analysis, int base_target, int LM, int bitrate, int lastCodedBands, int C, int intensity, int constrained_vbr, int stereo_saving, int tot_boost, int tf_estimate, int pitch_change, int maxDepth, OpusFramesize variable_duration, int lfe, int has_surround_mask, int surround_masking, int temporal_vbr) {
|
|
int nbEBands = mode.nbEBands;
|
|
short[] eBands = mode.eBands;
|
|
int coded_bands = lastCodedBands != 0 ? lastCodedBands : nbEBands;
|
|
int coded_bins = eBands[coded_bands] << LM;
|
|
if (C == 2) {
|
|
coded_bins += eBands[Inlines.IMIN(intensity, coded_bands)] << LM;
|
|
}
|
|
int target = base_target;
|
|
if (analysis.enabled && analysis.valid != 0 && (double)analysis.activity < 0.4) {
|
|
target -= (int)((float)(coded_bins << 3) * (0.4f - analysis.activity));
|
|
}
|
|
if (C == 2) {
|
|
int coded_stereo_bands = Inlines.IMIN(intensity, coded_bands);
|
|
int coded_stereo_dof = (eBands[coded_stereo_bands] << LM) - coded_stereo_bands;
|
|
int max_frac = Inlines.DIV32_16(Inlines.MULT16_16(26214, coded_stereo_dof), coded_bins);
|
|
stereo_saving = Inlines.MIN16(stereo_saving, 256);
|
|
target -= Inlines.MIN32(Inlines.MULT16_32_Q15(max_frac, target), Inlines.SHR32(Inlines.MULT16_16(stereo_saving - 26, coded_stereo_dof << 3), 8));
|
|
}
|
|
target += tot_boost - (16 << LM);
|
|
int tf_calibration = variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE ? 328 : 655;
|
|
target += Inlines.SHL32(Inlines.MULT16_32_Q15(tf_estimate - tf_calibration, target), 1);
|
|
if (analysis.enabled && analysis.valid != 0 && lfe == 0) {
|
|
float tonal = Inlines.MAX16(0.0f, analysis.tonality - 0.15f) - 0.09f;
|
|
int tonal_target = target + (int)((float)(coded_bins << 3) * 1.2f * tonal);
|
|
if (pitch_change != 0) {
|
|
tonal_target += (int)((float)(coded_bins << 3) * 0.8f);
|
|
}
|
|
target = tonal_target;
|
|
}
|
|
if (has_surround_mask != 0 && lfe == 0) {
|
|
int surround_target = target + Inlines.SHR32(Inlines.MULT16_16(surround_masking, coded_bins << 3), 10);
|
|
target = Inlines.IMAX(target / 4, surround_target);
|
|
}
|
|
int bins = eBands[nbEBands - 2] << LM;
|
|
int floor_depth = Inlines.SHR32(Inlines.MULT16_16(C * bins << 3, maxDepth), 10);
|
|
floor_depth = Inlines.IMAX(floor_depth, target >> 2);
|
|
target = Inlines.IMIN(target, floor_depth);
|
|
if (!(has_surround_mask != 0 && lfe == 0 || constrained_vbr == 0 && bitrate >= 64000)) {
|
|
int rate_factor = Inlines.MAX16(0, bitrate - 32000);
|
|
if (constrained_vbr != 0) {
|
|
rate_factor = Inlines.MIN16(rate_factor, 21955);
|
|
}
|
|
target = base_target + Inlines.MULT16_32_Q15(rate_factor, target - base_target);
|
|
}
|
|
if (has_surround_mask == 0 && tf_estimate < 3277) {
|
|
int amount = Inlines.MULT16_16_Q15(3329, Inlines.IMAX(0, Inlines.IMIN(32000, 96000 - bitrate)));
|
|
int tvbr_factor = Inlines.SHR32(Inlines.MULT16_16(temporal_vbr, amount), 10);
|
|
target += Inlines.MULT16_32_Q15(tvbr_factor, target);
|
|
}
|
|
target = Inlines.IMIN(2 * base_target, target);
|
|
return target;
|
|
}
|
|
|
|
static int transient_analysis(int[][] input, int len, int C, BoxedValueInt tf_estimate, BoxedValueInt tf_chan) {
|
|
int is_transient = 0;
|
|
int mask_metric = 0;
|
|
tf_chan.Val = 0;
|
|
int[] tmp = new int[len];
|
|
int len2 = len / 2;
|
|
for (int c = 0; c < C; ++c) {
|
|
int i;
|
|
int unmask = 0;
|
|
int mem0 = 0;
|
|
int mem1 = 0;
|
|
for (i = 0; i < len; ++i) {
|
|
int x = Inlines.SHR32(input[c][i], 12);
|
|
int y = Inlines.ADD32(mem0, x);
|
|
mem0 = mem1 + y - Inlines.SHL32(x, 1);
|
|
mem1 = x - Inlines.SHR32(y, 1);
|
|
tmp[i] = Inlines.EXTRACT16(Inlines.SHR32(y, 2));
|
|
}
|
|
Arrays.MemSet(tmp, 0, 12);
|
|
int shift = 0;
|
|
shift = 14 - Inlines.celt_ilog2(1 + Inlines.celt_maxabs32(tmp, 0, len));
|
|
if (shift != 0) {
|
|
for (i = 0; i < len; ++i) {
|
|
tmp[i] = Inlines.SHL16(tmp[i], shift);
|
|
}
|
|
}
|
|
int mean = 0;
|
|
mem0 = 0;
|
|
for (i = 0; i < len2; ++i) {
|
|
int x2 = Inlines.PSHR32(Inlines.MULT16_16(tmp[2 * i], tmp[2 * i]) + Inlines.MULT16_16(tmp[2 * i + 1], tmp[2 * i + 1]), 16);
|
|
mean += x2;
|
|
tmp[i] = mem0 + Inlines.PSHR32(x2 - mem0, 4);
|
|
mem0 = tmp[i];
|
|
}
|
|
mem0 = 0;
|
|
int maxE = 0;
|
|
for (i = len2 - 1; i >= 0; --i) {
|
|
tmp[i] = mem0 + Inlines.PSHR32(tmp[i] - mem0, 3);
|
|
mem0 = tmp[i];
|
|
maxE = Inlines.MAX16(maxE, mem0);
|
|
}
|
|
mean = Inlines.MULT16_16(Inlines.celt_sqrt(mean), Inlines.celt_sqrt(Inlines.MULT16_16(maxE, len2 >> 1)));
|
|
int norm = Inlines.SHL32(len2, 20) / Inlines.ADD32(1, Inlines.SHR32(mean, 1));
|
|
unmask = 0;
|
|
for (i = 12; i < len2 - 5; i += 4) {
|
|
int id = Inlines.MAX32(0, Inlines.MIN32(127, Inlines.MULT16_32_Q15(tmp[i] + 1, norm)));
|
|
unmask += inv_table[id];
|
|
}
|
|
if ((unmask = 64 * unmask * 4 / (6 * (len2 - 17))) <= mask_metric) continue;
|
|
tf_chan.Val = c;
|
|
mask_metric = unmask;
|
|
}
|
|
is_transient = mask_metric > 200 ? 1 : 0;
|
|
int tf_max = Inlines.MAX16(0, Inlines.celt_sqrt(27 * mask_metric) - 42);
|
|
tf_estimate.Val = Inlines.celt_sqrt(Inlines.MAX32(0, Inlines.SHL32(Inlines.MULT16_16(113, Inlines.MIN16(163, tf_max)), 14) - 37312528));
|
|
return is_transient;
|
|
}
|
|
|
|
static int patch_transient_decision(int[][] newE, int[][] oldE, int nbEBands, int start, int end, int C) {
|
|
int i;
|
|
int mean_diff = 0;
|
|
int[] spread_old = new int[26];
|
|
if (C == 1) {
|
|
spread_old[start] = oldE[0][start];
|
|
for (i = start + 1; i < end; ++i) {
|
|
spread_old[i] = Inlines.MAX16(spread_old[i - 1] - 1024, oldE[0][i]);
|
|
}
|
|
} else {
|
|
spread_old[start] = Inlines.MAX16(oldE[0][start], oldE[1][start]);
|
|
for (i = start + 1; i < end; ++i) {
|
|
spread_old[i] = Inlines.MAX16(spread_old[i - 1] - 1024, Inlines.MAX16(oldE[0][i], oldE[1][i]));
|
|
}
|
|
}
|
|
for (i = end - 2; i >= start; --i) {
|
|
spread_old[i] = Inlines.MAX16(spread_old[i], spread_old[i + 1] - 1024);
|
|
}
|
|
int c = 0;
|
|
do {
|
|
for (i = Inlines.IMAX(2, start); i < end - 1; ++i) {
|
|
int x1 = Inlines.MAX16(0, newE[c][i]);
|
|
int x2 = Inlines.MAX16(0, spread_old[i]);
|
|
mean_diff = Inlines.ADD32(mean_diff, Inlines.MAX16(0, Inlines.SUB16(x1, x2)));
|
|
}
|
|
} while (++c < C);
|
|
return (mean_diff = Inlines.DIV32(mean_diff, C * (end - 1 - Inlines.IMAX(2, start)))) > 1024 ? 1 : 0;
|
|
}
|
|
|
|
static void compute_mdcts(CeltMode mode, int shortBlocks, int[][] input, int[][] output, int C, int CC, int LM, int upsample) {
|
|
int i;
|
|
int shift;
|
|
int N;
|
|
int B;
|
|
int overlap = mode.overlap;
|
|
if (shortBlocks != 0) {
|
|
B = shortBlocks;
|
|
N = mode.shortMdctSize;
|
|
shift = mode.maxLM;
|
|
} else {
|
|
B = 1;
|
|
N = mode.shortMdctSize << LM;
|
|
shift = mode.maxLM - LM;
|
|
}
|
|
int c = 0;
|
|
do {
|
|
for (int b = 0; b < B; ++b) {
|
|
MDCT.clt_mdct_forward(mode.mdct, input[c], b * N, output[c], b, mode.window, overlap, shift, B);
|
|
}
|
|
} while (++c < CC);
|
|
if (CC == 2 && C == 1) {
|
|
for (i = 0; i < B * N; ++i) {
|
|
output[0][i] = Inlines.ADD32(Inlines.HALF32(output[0][i]), Inlines.HALF32(output[1][i]));
|
|
}
|
|
}
|
|
if (upsample != 1) {
|
|
c = 0;
|
|
do {
|
|
int bound = B * N / upsample;
|
|
i = 0;
|
|
while (i < bound) {
|
|
int[] nArray = output[c];
|
|
int n = i++;
|
|
nArray[n] = nArray[n] * upsample;
|
|
}
|
|
Arrays.MemSetWithOffset(output[c], 0, bound, B * N - bound);
|
|
} while (++c < C);
|
|
}
|
|
}
|
|
|
|
static void celt_preemphasis(short[] pcmp, int pcmp_ptr, int[] inp, int inp_ptr, int N, int CC, int upsample, int[] coef, BoxedValueInt mem, int clip) {
|
|
int i;
|
|
int coef0 = coef[0];
|
|
int m = mem.Val;
|
|
if (coef[1] == 0 && upsample == 1 && clip == 0) {
|
|
for (int i2 = 0; i2 < N; ++i2) {
|
|
short x = pcmp[pcmp_ptr + CC * i2];
|
|
inp[inp_ptr + i2] = Inlines.SHL32(x, 12) - m;
|
|
m = Inlines.SHR32(Inlines.MULT16_16(coef0, (int)x), 3);
|
|
}
|
|
mem.Val = m;
|
|
return;
|
|
}
|
|
int Nu = N / upsample;
|
|
if (upsample != 1) {
|
|
Arrays.MemSetWithOffset(inp, 0, inp_ptr, N);
|
|
}
|
|
for (i = 0; i < Nu; ++i) {
|
|
inp[inp_ptr + i * upsample] = pcmp[pcmp_ptr + CC * i];
|
|
}
|
|
for (i = 0; i < N; ++i) {
|
|
int x = inp[inp_ptr + i];
|
|
inp[inp_ptr + i] = Inlines.SHL32(x, 12) - m;
|
|
m = Inlines.SHR32(Inlines.MULT16_16(coef0, x), 3);
|
|
}
|
|
mem.Val = m;
|
|
}
|
|
|
|
static void celt_preemphasis(short[] pcmp, int[] inp, int inp_ptr, int N, int CC, int upsample, int[] coef, BoxedValueInt mem, int clip) {
|
|
int i;
|
|
int coef0 = coef[0];
|
|
int m = mem.Val;
|
|
if (coef[1] == 0 && upsample == 1 && clip == 0) {
|
|
for (int i2 = 0; i2 < N; ++i2) {
|
|
short x = pcmp[CC * i2];
|
|
inp[inp_ptr + i2] = Inlines.SHL32(x, 12) - m;
|
|
m = Inlines.SHR32(Inlines.MULT16_16(coef0, (int)x), 3);
|
|
}
|
|
mem.Val = m;
|
|
return;
|
|
}
|
|
int Nu = N / upsample;
|
|
if (upsample != 1) {
|
|
Arrays.MemSetWithOffset(inp, 0, inp_ptr, N);
|
|
}
|
|
for (i = 0; i < Nu; ++i) {
|
|
inp[inp_ptr + i * upsample] = pcmp[CC * i];
|
|
}
|
|
for (i = 0; i < N; ++i) {
|
|
int x = inp[inp_ptr + i];
|
|
inp[inp_ptr + i] = Inlines.SHL32(x, 12) - m;
|
|
m = Inlines.SHR32(Inlines.MULT16_16(coef0, x), 3);
|
|
}
|
|
mem.Val = m;
|
|
}
|
|
|
|
static int l1_metric(int[] tmp, int N, int LM, int bias) {
|
|
int L1 = 0;
|
|
for (int i = 0; i < N; ++i) {
|
|
L1 += Inlines.EXTEND32(Inlines.ABS32(tmp[i]));
|
|
}
|
|
L1 = Inlines.MAC16_32_Q15(L1, LM * bias, L1);
|
|
return L1;
|
|
}
|
|
|
|
static int tf_analysis(CeltMode m, int len, int isTransient, int[] tf_res, int lambda, int[][] X, int N0, int LM, BoxedValueInt tf_sum, int tf_estimate, int tf_chan) {
|
|
int curr1;
|
|
int curr0;
|
|
int cost1;
|
|
int cost0;
|
|
int i;
|
|
int[] selcost = new int[2];
|
|
int tf_select = 0;
|
|
int bias = Inlines.MULT16_16_Q14(1311, Inlines.MAX16(-4096, 8192 - tf_estimate));
|
|
int[] metric = new int[len];
|
|
int[] tmp = new int[m.eBands[len] - m.eBands[len - 1] << LM];
|
|
int[] tmp_1 = new int[m.eBands[len] - m.eBands[len - 1] << LM];
|
|
int[] path0 = new int[len];
|
|
int[] path1 = new int[len];
|
|
tf_sum.Val = 0;
|
|
for (i = 0; i < len; ++i) {
|
|
int L1;
|
|
int best_level = 0;
|
|
int N = m.eBands[i + 1] - m.eBands[i] << LM;
|
|
boolean narrow = m.eBands[i + 1] - m.eBands[i] == 1;
|
|
System.arraycopy(X[tf_chan], m.eBands[i] << LM, tmp, 0, N);
|
|
int best_L1 = L1 = CeltCommon.l1_metric(tmp, N, isTransient != 0 ? LM : 0, bias);
|
|
if (isTransient != 0 && !narrow) {
|
|
System.arraycopy(tmp, 0, tmp_1, 0, N);
|
|
Bands.haar1ZeroOffset(tmp_1, N >> LM, 1 << LM);
|
|
L1 = CeltCommon.l1_metric(tmp_1, N, LM + 1, bias);
|
|
if (L1 < best_L1) {
|
|
best_L1 = L1;
|
|
best_level = -1;
|
|
}
|
|
}
|
|
for (int k = 0; k < LM + (isTransient == 0 && !narrow ? 1 : 0); ++k) {
|
|
int B = isTransient != 0 ? LM - k - 1 : k + 1;
|
|
Bands.haar1ZeroOffset(tmp, N >> k, 1 << k);
|
|
L1 = CeltCommon.l1_metric(tmp, N, B, bias);
|
|
if (L1 >= best_L1) continue;
|
|
best_L1 = L1;
|
|
best_level = k + 1;
|
|
}
|
|
metric[i] = isTransient != 0 ? 2 * best_level : -2 * best_level;
|
|
tf_sum.Val = tf_sum.Val + ((isTransient != 0 ? LM : 0) - metric[i] / 2);
|
|
if (!narrow || metric[i] != 0 && metric[i] != -2 * LM) continue;
|
|
int n = i;
|
|
metric[n] = metric[n] - 1;
|
|
}
|
|
tf_select = 0;
|
|
for (int sel = 0; sel < 2; ++sel) {
|
|
cost0 = 0;
|
|
cost1 = isTransient != 0 ? 0 : lambda;
|
|
for (i = 1; i < len; ++i) {
|
|
curr0 = Inlines.IMIN(cost0, cost1 + lambda);
|
|
curr1 = Inlines.IMIN(cost0 + lambda, cost1);
|
|
cost0 = curr0 + Inlines.abs(metric[i] - 2 * CeltTables.tf_select_table[LM][4 * isTransient + 2 * sel + 0]);
|
|
cost1 = curr1 + Inlines.abs(metric[i] - 2 * CeltTables.tf_select_table[LM][4 * isTransient + 2 * sel + 1]);
|
|
}
|
|
selcost[sel] = cost0 = Inlines.IMIN(cost0, cost1);
|
|
}
|
|
if (selcost[1] < selcost[0] && isTransient != 0) {
|
|
tf_select = 1;
|
|
}
|
|
cost0 = 0;
|
|
cost1 = isTransient != 0 ? 0 : lambda;
|
|
for (i = 1; i < len; ++i) {
|
|
int from0 = cost0;
|
|
int from1 = cost1 + lambda;
|
|
if (from0 < from1) {
|
|
curr0 = from0;
|
|
path0[i] = 0;
|
|
} else {
|
|
curr0 = from1;
|
|
path0[i] = 1;
|
|
}
|
|
from0 = cost0 + lambda;
|
|
from1 = cost1;
|
|
if (from0 < from1) {
|
|
curr1 = from0;
|
|
path1[i] = 0;
|
|
} else {
|
|
curr1 = from1;
|
|
path1[i] = 1;
|
|
}
|
|
cost0 = curr0 + Inlines.abs(metric[i] - 2 * CeltTables.tf_select_table[LM][4 * isTransient + 2 * tf_select + 0]);
|
|
cost1 = curr1 + Inlines.abs(metric[i] - 2 * CeltTables.tf_select_table[LM][4 * isTransient + 2 * tf_select + 1]);
|
|
}
|
|
tf_res[len - 1] = cost0 < cost1 ? 0 : 1;
|
|
for (i = len - 2; i >= 0; --i) {
|
|
tf_res[i] = tf_res[i + 1] == 1 ? path1[i + 1] : path0[i + 1];
|
|
}
|
|
return tf_select;
|
|
}
|
|
|
|
static void tf_encode(int start, int end, int isTransient, int[] tf_res, int LM, int tf_select, EntropyCoder enc) {
|
|
int i;
|
|
int budget = enc.storage * 8;
|
|
int tell = enc.tell();
|
|
int logp = isTransient != 0 ? 2 : 4;
|
|
int tf_select_rsv = LM > 0 && tell + logp + 1 <= budget ? 1 : 0;
|
|
budget -= tf_select_rsv;
|
|
int tf_changed = 0;
|
|
int curr = 0;
|
|
for (i = start; i < end; ++i) {
|
|
if (tell + logp <= budget) {
|
|
enc.enc_bit_logp(tf_res[i] ^ curr, logp);
|
|
tell = enc.tell();
|
|
curr = tf_res[i];
|
|
tf_changed |= curr;
|
|
} else {
|
|
tf_res[i] = curr;
|
|
}
|
|
logp = isTransient != 0 ? 4 : 5;
|
|
}
|
|
if (tf_select_rsv != 0 && CeltTables.tf_select_table[LM][4 * isTransient + 0 + tf_changed] != CeltTables.tf_select_table[LM][4 * isTransient + 2 + tf_changed]) {
|
|
enc.enc_bit_logp(tf_select, 1);
|
|
} else {
|
|
tf_select = 0;
|
|
}
|
|
for (i = start; i < end; ++i) {
|
|
tf_res[i] = CeltTables.tf_select_table[LM][4 * isTransient + 2 * tf_select + tf_res[i]];
|
|
}
|
|
}
|
|
|
|
static int alloc_trim_analysis(CeltMode m, int[][] X, int[][] bandLogE, int end, int LM, int C, AnalysisInfo analysis, BoxedValueInt stereo_saving, int tf_estimate, int intensity, int surround_trim) {
|
|
int i;
|
|
int diff = 0;
|
|
int trim = 1280;
|
|
if (C == 2) {
|
|
int partial;
|
|
int sum = 0;
|
|
for (i = 0; i < 8; ++i) {
|
|
partial = Kernels.celt_inner_prod(X[0], m.eBands[i] << LM, X[1], m.eBands[i] << LM, m.eBands[i + 1] - m.eBands[i] << LM);
|
|
sum = Inlines.ADD16(sum, (int)Inlines.EXTRACT16(Inlines.SHR32(partial, 18)));
|
|
}
|
|
sum = Inlines.MULT16_16_Q15(4096, sum);
|
|
int minXC = sum = Inlines.MIN16(1024, Inlines.ABS32(sum));
|
|
for (i = 8; i < intensity; ++i) {
|
|
partial = Kernels.celt_inner_prod(X[0], m.eBands[i] << LM, X[1], m.eBands[i] << LM, m.eBands[i + 1] - m.eBands[i] << LM);
|
|
minXC = Inlines.MIN16(minXC, (int)Inlines.ABS16(Inlines.EXTRACT16(Inlines.SHR32(partial, 18))));
|
|
}
|
|
minXC = Inlines.MIN16(1024, Inlines.ABS32(minXC));
|
|
int logXC = Inlines.celt_log2(1049625 - Inlines.MULT16_16(sum, sum));
|
|
int logXC2 = Inlines.MAX16(Inlines.HALF16(logXC), Inlines.celt_log2(1049625 - Inlines.MULT16_16(minXC, minXC)));
|
|
logXC = Inlines.PSHR32(logXC - 6144, 2);
|
|
logXC2 = Inlines.PSHR32(logXC2 - 6144, 2);
|
|
trim += Inlines.MAX16(-1024, Inlines.MULT16_16_Q15(24576, logXC));
|
|
stereo_saving.Val = Inlines.MIN16(stereo_saving.Val + 64, 0 - Inlines.HALF16(logXC2));
|
|
}
|
|
int c = 0;
|
|
do {
|
|
for (i = 0; i < end - 1; ++i) {
|
|
diff += bandLogE[c][i] * (2 + 2 * i - end);
|
|
}
|
|
} while (++c < C);
|
|
trim -= Inlines.MAX16((int)Inlines.NEG16((short)512), Inlines.MIN16(512, Inlines.SHR16((diff /= C * (end - 1)) + 1024, 2) / 6));
|
|
trim -= Inlines.SHR16(surround_trim, 2);
|
|
trim -= 2 * Inlines.SHR16(tf_estimate, 6);
|
|
if (analysis.enabled && analysis.valid != 0) {
|
|
trim -= Inlines.MAX16(-512, Inlines.MIN16(512, (int)(512.0f * (analysis.tonality_slope + 0.05f))));
|
|
}
|
|
int trim_index = Inlines.PSHR32(trim, 8);
|
|
trim_index = Inlines.IMAX(0, Inlines.IMIN(10, trim_index));
|
|
return trim_index;
|
|
}
|
|
|
|
static int stereo_analysis(CeltMode m, int[][] X, int LM) {
|
|
int sumLR = 1;
|
|
int sumMS = 1;
|
|
for (int i = 0; i < 13; ++i) {
|
|
for (int j = m.eBands[i] << LM; j < m.eBands[i + 1] << LM; ++j) {
|
|
int L = Inlines.EXTEND32(X[0][j]);
|
|
int R = Inlines.EXTEND32(X[1][j]);
|
|
int M = Inlines.ADD32(L, R);
|
|
int S = Inlines.SUB32(L, R);
|
|
sumLR = Inlines.ADD32(sumLR, Inlines.ADD32(Inlines.ABS32(L), Inlines.ABS32(R)));
|
|
sumMS = Inlines.ADD32(sumMS, Inlines.ADD32(Inlines.ABS32(M), Inlines.ABS32(S)));
|
|
}
|
|
}
|
|
sumMS = Inlines.MULT16_32_Q15((short)23170, sumMS);
|
|
int thetas = 13;
|
|
if (LM <= 1) {
|
|
thetas -= 8;
|
|
}
|
|
return Inlines.MULT16_32_Q15((m.eBands[13] << LM + 1) + thetas, sumMS) > Inlines.MULT16_32_Q15(m.eBands[13] << LM + 1, sumLR) ? 1 : 0;
|
|
}
|
|
|
|
static int median_of_5(int[] x, int x_ptr) {
|
|
int t4;
|
|
int t3;
|
|
int t1;
|
|
int t0;
|
|
int t2 = x[x_ptr + 2];
|
|
if (x[x_ptr] > x[x_ptr + 1]) {
|
|
t0 = x[x_ptr + 1];
|
|
t1 = x[x_ptr];
|
|
} else {
|
|
t0 = x[x_ptr];
|
|
t1 = x[x_ptr + 1];
|
|
}
|
|
if (x[x_ptr + 3] > x[x_ptr + 4]) {
|
|
t3 = x[x_ptr + 4];
|
|
t4 = x[x_ptr + 3];
|
|
} else {
|
|
t3 = x[x_ptr + 3];
|
|
t4 = x[x_ptr + 4];
|
|
}
|
|
if (t0 > t3) {
|
|
int tmp = t3;
|
|
t3 = t0;
|
|
t0 = tmp;
|
|
tmp = t4;
|
|
t4 = t1;
|
|
t1 = tmp;
|
|
}
|
|
if (t2 > t1) {
|
|
if (t1 < t3) {
|
|
return Inlines.MIN16(t2, t3);
|
|
}
|
|
return Inlines.MIN16(t4, t1);
|
|
}
|
|
if (t2 < t3) {
|
|
return Inlines.MIN16(t1, t3);
|
|
}
|
|
return Inlines.MIN16(t2, t4);
|
|
}
|
|
|
|
static int median_of_3(int[] x, int x_ptr) {
|
|
int t1;
|
|
int t0;
|
|
if (x[x_ptr] > x[x_ptr + 1]) {
|
|
t0 = x[x_ptr + 1];
|
|
t1 = x[x_ptr];
|
|
} else {
|
|
t0 = x[x_ptr];
|
|
t1 = x[x_ptr + 1];
|
|
}
|
|
int t2 = x[x_ptr + 2];
|
|
if (t1 < t2) {
|
|
return t1;
|
|
}
|
|
if (t0 < t2) {
|
|
return t2;
|
|
}
|
|
return t0;
|
|
}
|
|
|
|
static int dynalloc_analysis(int[][] bandLogE, int[][] bandLogE2, int nbEBands, int start, int end, int C, int[] offsets, int lsb_depth, short[] logN, int isTransient, int vbr, int constrained_vbr, short[] eBands, int LM, int effectiveBytes, BoxedValueInt tot_boost_, int lfe, int[] surround_dynalloc) {
|
|
int i;
|
|
int tot_boost = 0;
|
|
int[][] follower = Arrays.InitTwoDimensionalArrayInt(2, nbEBands);
|
|
int[] noise_floor = new int[C * nbEBands];
|
|
Arrays.MemSet(offsets, 0, nbEBands);
|
|
int maxDepth = -32666;
|
|
for (i = 0; i < end; ++i) {
|
|
noise_floor[i] = Inlines.MULT16_16((short)64, logN[i]) + 512 + Inlines.SHL16(9 - lsb_depth, 10) - Inlines.SHL16(CeltTables.eMeans[i], 6) + Inlines.MULT16_16(6, (i + 5) * (i + 5));
|
|
}
|
|
int c = 0;
|
|
do {
|
|
for (i = 0; i < end; ++i) {
|
|
maxDepth = Inlines.MAX16(maxDepth, bandLogE[c][i] - noise_floor[i]);
|
|
}
|
|
} while (++c < C);
|
|
if (effectiveBytes > 50 && LM >= 1 && lfe == 0) {
|
|
int last = 0;
|
|
c = 0;
|
|
do {
|
|
int[] f = follower[c];
|
|
f[0] = bandLogE2[c][0];
|
|
for (i = 1; i < end; ++i) {
|
|
if (bandLogE2[c][i] > bandLogE2[c][i - 1] + 512) {
|
|
last = i;
|
|
}
|
|
f[i] = Inlines.MIN16(f[i - 1] + 1536, bandLogE2[c][i]);
|
|
}
|
|
for (i = last - 1; i >= 0; --i) {
|
|
f[i] = Inlines.MIN16(f[i], Inlines.MIN16(f[i + 1] + 2048, bandLogE2[c][i]));
|
|
}
|
|
int offset = 1024;
|
|
for (i = 2; i < end - 2; ++i) {
|
|
f[i] = Inlines.MAX16(f[i], CeltCommon.median_of_5(bandLogE2[c], i - 2) - offset);
|
|
}
|
|
int tmp = CeltCommon.median_of_3(bandLogE2[c], 0) - offset;
|
|
f[0] = Inlines.MAX16(f[0], tmp);
|
|
f[1] = Inlines.MAX16(f[1], tmp);
|
|
tmp = CeltCommon.median_of_3(bandLogE2[c], end - 3) - offset;
|
|
f[end - 2] = Inlines.MAX16(f[end - 2], tmp);
|
|
f[end - 1] = Inlines.MAX16(f[end - 1], tmp);
|
|
for (i = 0; i < end; ++i) {
|
|
f[i] = Inlines.MAX16(f[i], noise_floor[i]);
|
|
}
|
|
} while (++c < C);
|
|
if (C == 2) {
|
|
for (i = start; i < end; ++i) {
|
|
follower[1][i] = Inlines.MAX16(follower[1][i], follower[0][i] - 4096);
|
|
follower[0][i] = Inlines.MAX16(follower[0][i], follower[1][i] - 4096);
|
|
follower[0][i] = Inlines.HALF16(Inlines.MAX16(0, bandLogE[0][i] - follower[0][i]) + Inlines.MAX16(0, bandLogE[1][i] - follower[1][i]));
|
|
}
|
|
} else {
|
|
for (i = start; i < end; ++i) {
|
|
follower[0][i] = Inlines.MAX16(0, bandLogE[0][i] - follower[0][i]);
|
|
}
|
|
}
|
|
for (i = start; i < end; ++i) {
|
|
follower[0][i] = Inlines.MAX16(follower[0][i], surround_dynalloc[i]);
|
|
}
|
|
if ((vbr == 0 || constrained_vbr != 0) && isTransient == 0) {
|
|
for (i = start; i < end; ++i) {
|
|
follower[0][i] = Inlines.HALF16(follower[0][i]);
|
|
}
|
|
}
|
|
for (i = start; i < end; ++i) {
|
|
int boost_bits;
|
|
int boost;
|
|
if (i < 8) {
|
|
int[] nArray = follower[0];
|
|
int n = i;
|
|
nArray[n] = nArray[n] * 2;
|
|
}
|
|
if (i >= 12) {
|
|
follower[0][i] = Inlines.HALF16(follower[0][i]);
|
|
}
|
|
follower[0][i] = Inlines.MIN16(follower[0][i], 4096);
|
|
int width = C * (eBands[i + 1] - eBands[i]) << LM;
|
|
if (width < 6) {
|
|
boost = Inlines.SHR32(follower[0][i], 10);
|
|
boost_bits = boost * width << 3;
|
|
} else if (width > 48) {
|
|
boost = Inlines.SHR32(follower[0][i] * 8, 10);
|
|
boost_bits = (boost * width << 3) / 8;
|
|
} else {
|
|
boost = Inlines.SHR32(follower[0][i] * width / 6, 10);
|
|
boost_bits = boost * 6 << 3;
|
|
}
|
|
if ((vbr == 0 || constrained_vbr != 0 && isTransient == 0) && tot_boost + boost_bits >> 3 >> 3 > effectiveBytes / 4) {
|
|
int cap = effectiveBytes / 4 << 3 << 3;
|
|
offsets[i] = cap - tot_boost;
|
|
tot_boost = cap;
|
|
break;
|
|
}
|
|
offsets[i] = boost;
|
|
tot_boost += boost_bits;
|
|
}
|
|
}
|
|
tot_boost_.Val = tot_boost;
|
|
return maxDepth;
|
|
}
|
|
|
|
static void deemphasis(int[][] input, int[] input_ptrs, short[] pcm, int pcm_ptr, int N, int C, int downsample, int[] coef, int[] mem, int accum) {
|
|
boolean apply_downsampling = false;
|
|
int[] scratch = new int[N];
|
|
int coef0 = coef[0];
|
|
int Nd = N / downsample;
|
|
int c = 0;
|
|
do {
|
|
int tmp;
|
|
int j;
|
|
int m = mem[c];
|
|
int[] x = input[c];
|
|
int x_ptr = input_ptrs[c];
|
|
int y = pcm_ptr + c;
|
|
if (downsample > 1) {
|
|
for (j = 0; j < N; ++j) {
|
|
tmp = x[x_ptr + j] + m + 0;
|
|
m = Inlines.MULT16_32_Q15(coef0, tmp);
|
|
scratch[j] = tmp;
|
|
}
|
|
apply_downsampling = true;
|
|
} else if (accum != 0) {
|
|
for (j = 0; j < N; ++j) {
|
|
tmp = x[x_ptr + j] + m + 0;
|
|
m = Inlines.MULT16_32_Q15(coef0, tmp);
|
|
pcm[y + j * C] = Inlines.SAT16(Inlines.ADD32(pcm[y + j * C], Inlines.SIG2WORD16(tmp)));
|
|
}
|
|
} else {
|
|
for (j = 0; j < N; ++j) {
|
|
tmp = x[x_ptr + j] + m + 0;
|
|
if (x[x_ptr + j] > 0 && m > 0 && tmp < 0) {
|
|
tmp = Integer.MAX_VALUE;
|
|
m = Integer.MAX_VALUE;
|
|
} else {
|
|
m = Inlines.MULT16_32_Q15(coef0, tmp);
|
|
}
|
|
pcm[y + j * C] = Inlines.SIG2WORD16(tmp);
|
|
}
|
|
}
|
|
mem[c] = m;
|
|
if (!apply_downsampling) continue;
|
|
for (j = 0; j < Nd; ++j) {
|
|
pcm[y + j * C] = Inlines.SIG2WORD16(scratch[j * downsample]);
|
|
}
|
|
} while (++c < C);
|
|
}
|
|
|
|
static void celt_synthesis(CeltMode mode, int[][] X, int[][] out_syn, int[] out_syn_ptrs, int[] oldBandE, int start, int effEnd, int C, int CC, int isTransient, int LM, int downsample, int silence) {
|
|
int shift;
|
|
int NB;
|
|
int B;
|
|
int overlap = mode.overlap;
|
|
int nbEBands = mode.nbEBands;
|
|
int N = mode.shortMdctSize << LM;
|
|
int[] freq = new int[N];
|
|
int M = 1 << LM;
|
|
if (isTransient != 0) {
|
|
B = M;
|
|
NB = mode.shortMdctSize;
|
|
shift = mode.maxLM;
|
|
} else {
|
|
B = 1;
|
|
NB = mode.shortMdctSize << LM;
|
|
shift = mode.maxLM - LM;
|
|
}
|
|
if (CC == 2 && C == 1) {
|
|
int b;
|
|
Bands.denormalise_bands(mode, X[0], freq, 0, oldBandE, 0, start, effEnd, M, downsample, silence);
|
|
int freq2 = out_syn_ptrs[1] + overlap / 2;
|
|
System.arraycopy(freq, 0, out_syn[1], freq2, N);
|
|
for (b = 0; b < B; ++b) {
|
|
MDCT.clt_mdct_backward(mode.mdct, out_syn[1], freq2 + b, out_syn[0], out_syn_ptrs[0] + NB * b, mode.window, overlap, shift, B);
|
|
}
|
|
for (b = 0; b < B; ++b) {
|
|
MDCT.clt_mdct_backward(mode.mdct, freq, b, out_syn[1], out_syn_ptrs[1] + NB * b, mode.window, overlap, shift, B);
|
|
}
|
|
} else if (CC == 1 && C == 2) {
|
|
int freq2 = out_syn_ptrs[0] + overlap / 2;
|
|
Bands.denormalise_bands(mode, X[0], freq, 0, oldBandE, 0, start, effEnd, M, downsample, silence);
|
|
Bands.denormalise_bands(mode, X[1], out_syn[0], freq2, oldBandE, nbEBands, start, effEnd, M, downsample, silence);
|
|
for (int i = 0; i < N; ++i) {
|
|
freq[i] = Inlines.HALF32(Inlines.ADD32(freq[i], out_syn[0][freq2 + i]));
|
|
}
|
|
for (int b = 0; b < B; ++b) {
|
|
MDCT.clt_mdct_backward(mode.mdct, freq, b, out_syn[0], out_syn_ptrs[0] + NB * b, mode.window, overlap, shift, B);
|
|
}
|
|
} else {
|
|
int c = 0;
|
|
do {
|
|
Bands.denormalise_bands(mode, X[c], freq, 0, oldBandE, c * nbEBands, start, effEnd, M, downsample, silence);
|
|
for (int b = 0; b < B; ++b) {
|
|
MDCT.clt_mdct_backward(mode.mdct, freq, b, out_syn[c], out_syn_ptrs[c] + NB * b, mode.window, overlap, shift, B);
|
|
}
|
|
} while (++c < CC);
|
|
}
|
|
}
|
|
|
|
static void tf_decode(int start, int end, int isTransient, int[] tf_res, int LM, EntropyCoder dec) {
|
|
int i;
|
|
int budget = dec.storage * 8;
|
|
int tell = dec.tell();
|
|
int logp = isTransient != 0 ? 2 : 4;
|
|
int tf_select_rsv = LM > 0 && tell + logp + 1 <= budget ? 1 : 0;
|
|
budget -= tf_select_rsv;
|
|
int curr = 0;
|
|
int tf_changed = 0;
|
|
for (i = start; i < end; ++i) {
|
|
if (tell + logp <= budget) {
|
|
tell = dec.tell();
|
|
tf_changed |= (curr ^= dec.dec_bit_logp(logp));
|
|
}
|
|
tf_res[i] = curr;
|
|
logp = isTransient != 0 ? 4 : 5;
|
|
}
|
|
int tf_select = 0;
|
|
if (tf_select_rsv != 0 && CeltTables.tf_select_table[LM][4 * isTransient + 0 + tf_changed] != CeltTables.tf_select_table[LM][4 * isTransient + 2 + tf_changed]) {
|
|
tf_select = dec.dec_bit_logp(1L);
|
|
}
|
|
for (i = start; i < end; ++i) {
|
|
tf_res[i] = CeltTables.tf_select_table[LM][4 * isTransient + 2 * tf_select + tf_res[i]];
|
|
}
|
|
}
|
|
|
|
static int celt_plc_pitch_search(int[][] decode_mem, int C) {
|
|
BoxedValueInt pitch_index = new BoxedValueInt(0);
|
|
int[] lp_pitch_buf = new int[1024];
|
|
Pitch.pitch_downsample(decode_mem, lp_pitch_buf, 2048, C);
|
|
Pitch.pitch_search(lp_pitch_buf, 360, lp_pitch_buf, 1328, 620, pitch_index);
|
|
pitch_index.Val = 720 - pitch_index.Val;
|
|
return pitch_index.Val;
|
|
}
|
|
|
|
static int resampling_factor(int rate) {
|
|
int ret;
|
|
switch (rate) {
|
|
case 48000: {
|
|
ret = 1;
|
|
break;
|
|
}
|
|
case 24000: {
|
|
ret = 2;
|
|
break;
|
|
}
|
|
case 16000: {
|
|
ret = 3;
|
|
break;
|
|
}
|
|
case 12000: {
|
|
ret = 4;
|
|
break;
|
|
}
|
|
case 8000: {
|
|
ret = 6;
|
|
break;
|
|
}
|
|
default: {
|
|
Inlines.OpusAssert(false);
|
|
ret = 0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void comb_filter_const(int[] y, int y_ptr, int[] x, int x_ptr, int T, int N, int g10, int g11, int g12) {
|
|
int xpt = x_ptr - T;
|
|
int x4 = x[xpt - 2];
|
|
int x3 = x[xpt - 1];
|
|
int x2 = x[xpt];
|
|
int x1 = x[xpt + 1];
|
|
for (int i = 0; i < N; ++i) {
|
|
int x0 = x[xpt + i + 2];
|
|
y[y_ptr + i] = x[x_ptr + i] + Inlines.MULT16_32_Q15(g10, x2) + Inlines.MULT16_32_Q15(g11, Inlines.ADD32(x1, x3)) + Inlines.MULT16_32_Q15(g12, Inlines.ADD32(x0, x4));
|
|
x4 = x3;
|
|
x3 = x2;
|
|
x2 = x1;
|
|
x1 = x0;
|
|
}
|
|
}
|
|
|
|
static void comb_filter(int[] y, int y_ptr, int[] x, int x_ptr, int T0, int T1, int N, int g0, int g1, int tapset0, int tapset1, int[] window, int overlap) {
|
|
int i;
|
|
if (g0 == 0 && g1 == 0) {
|
|
if (x_ptr != y_ptr) {
|
|
// empty if block
|
|
}
|
|
return;
|
|
}
|
|
int g00 = Inlines.MULT16_16_P15(g0, (int)gains[tapset0][0]);
|
|
int g01 = Inlines.MULT16_16_P15(g0, (int)gains[tapset0][1]);
|
|
int g02 = Inlines.MULT16_16_P15(g0, (int)gains[tapset0][2]);
|
|
int g10 = Inlines.MULT16_16_P15(g1, (int)gains[tapset1][0]);
|
|
int g11 = Inlines.MULT16_16_P15(g1, (int)gains[tapset1][1]);
|
|
int g12 = Inlines.MULT16_16_P15(g1, (int)gains[tapset1][2]);
|
|
int x1 = x[x_ptr - T1 + 1];
|
|
int x2 = x[x_ptr - T1];
|
|
int x3 = x[x_ptr - T1 - 1];
|
|
int x4 = x[x_ptr - T1 - 2];
|
|
if (g0 == g1 && T0 == T1 && tapset0 == tapset1) {
|
|
overlap = 0;
|
|
}
|
|
for (i = 0; i < overlap; ++i) {
|
|
int x0 = x[x_ptr + i - T1 + 2];
|
|
int f = Inlines.MULT16_16_Q15(window[i], window[i]);
|
|
y[y_ptr + i] = x[x_ptr + i] + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((int)((short)(Short.MAX_VALUE - f)), g00), x[x_ptr + i - T0]) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((int)((short)(Short.MAX_VALUE - f)), g01), Inlines.ADD32(x[x_ptr + i - T0 + 1], x[x_ptr + i - T0 - 1])) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((int)((short)(Short.MAX_VALUE - f)), g02), Inlines.ADD32(x[x_ptr + i - T0 + 2], x[x_ptr + i - T0 - 2])) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(f, g10), x2) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(f, g11), Inlines.ADD32(x1, x3)) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(f, g12), Inlines.ADD32(x0, x4));
|
|
x4 = x3;
|
|
x3 = x2;
|
|
x2 = x1;
|
|
x1 = x0;
|
|
}
|
|
if (g1 == 0) {
|
|
if (x_ptr != y_ptr) {
|
|
// empty if block
|
|
}
|
|
return;
|
|
}
|
|
CeltCommon.comb_filter_const(y, y_ptr + i, x, x_ptr + i, T1, N - i, g10, g11, g12);
|
|
}
|
|
|
|
static void init_caps(CeltMode m, int[] cap, int LM, int C) {
|
|
for (int i = 0; i < m.nbEBands; ++i) {
|
|
int N = m.eBands[i + 1] - m.eBands[i] << LM;
|
|
cap[i] = (m.cache.caps[m.nbEBands * (2 * LM + C - 1) + i] + 64) * C * N >> 2;
|
|
}
|
|
}
|
|
}
|
|
|