diff --git a/README.md b/README.md
index 3dca82efd8..7cc7c98227 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,7 @@ vendor's servers.
* Files in app/src/main/java/net/osmand/ and app/src/main/aidl/net/osmand/ are taken from the [OsmAnd](https://osmand.net/) project, licensed under the GPLv3 by OsmAnd BV
* Files in app/src/main/java/org/bouncycastle are taken from the [Bouncy Castle](https://www.bouncycastle.org/java.html) project, licensed under the MIT license by The Legion of the Bouncy Castle Inc.
* Files in app/src/main/java/com/android/nQuant are taken from the [nQuant.android](https://github.com/mcychan/nQuant.android/) project, licensed under the Apache license by Miller Cy Chan
+* Files in app/src/main/java/org/concentus are taken from the [Concentus](https://github.com/lostromb/concentus) project, licensed under the BSD-3 license by various holding parties
## Download
diff --git a/app/src/main/assets/licenses/concentus.txt b/app/src/main/assets/licenses/concentus.txt
new file mode 100644
index 0000000000..9250838b70
--- /dev/null
+++ b/app/src/main/assets/licenses/concentus.txt
@@ -0,0 +1,37 @@
+Copyright (c) by various holding parties, including (but not limited to):
+Skype Limited, Xiph.Org Foundation, CSIRO, Microsoft Corporation,
+Jean-Marc Valin, Gregory Maxwell, Mark Borgerding, Timothy B. Terriberry,
+Logan Stromberg. All rights are reserved by their respective holders.
+
+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 HOLDER 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.
+
+
+This repository and its redistributable packages contain independently compiled
+versions of the Opus C reference library, which is maintained by Xiph.org and the
+Opus open-source contributors. The source code for these libraries is freely available
+at https://gitlab.xiph.org/xiph/opus/-/tags/v1.5.2, and all binaries are being
+redistributed to you under the same terms of the general Opus license dictated above.
diff --git a/app/src/main/assets/licenses/licenses.json b/app/src/main/assets/licenses/licenses.json
index 3f54ac235d..b466a06e6c 100644
--- a/app/src/main/assets/licenses/licenses.json
+++ b/app/src/main/assets/licenses/licenses.json
@@ -132,6 +132,13 @@
"url": "https://github.com/cketti/ckChangeLog",
"path": "licenses/ckchangelog.txt"
},
+ {
+ "name": "Concentus",
+ "owner": "Logan Stromberg, various holding parties",
+ "type": "BSD-3",
+ "url": "https://github.com/lostromb/concentus",
+ "path": "licenses/concentus.txt"
+ },
{
"name": "solarpositioning",
"owner": "Klaus A. Brunner",
diff --git a/app/src/main/java/org/concentus/Analysis.java b/app/src/main/java/org/concentus/Analysis.java
new file mode 100644
index 0000000000..18795e52e3
--- /dev/null
+++ b/app/src/main/java/org/concentus/Analysis.java
@@ -0,0 +1,575 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class Analysis {
+
+ private static final double M_PI = 3.141592653;
+ private static final float cA = 0.43157974f;
+ private static final float cB = 0.67848403f;
+ private static final float cC = 0.08595542f;
+ private static final float cE = ((float) M_PI / 2);
+
+ private static final int NB_TONAL_SKIP_BANDS = 9;
+
+ static float fast_atan2f(float y, float x) {
+ float x2, y2;
+ /* Should avoid underflow on the values we'll get */
+ if (Inlines.ABS16(x) + Inlines.ABS16(y) < 1e-9f) {
+ x *= 1e12f;
+ y *= 1e12f;
+ }
+ x2 = x * x;
+ y2 = y * y;
+ if (x2 < y2) {
+ float den = (y2 + cB * x2) * (y2 + cC * x2);
+ if (den != 0) {
+ return -x * y * (y2 + cA * x2) / den + (y < 0 ? -cE : cE);
+ } else {
+ return (y < 0 ? -cE : cE);
+ }
+ } else {
+ float den = (x2 + cB * y2) * (x2 + cC * y2);
+ if (den != 0) {
+ return x * y * (x2 + cA * y2) / den + (y < 0 ? -cE : cE) - (x * y < 0 ? -cE : cE);
+ } else {
+ return (y < 0 ? -cE : cE) - (x * y < 0 ? -cE : cE);
+ }
+ }
+ }
+
+ static void tonality_analysis_init(TonalityAnalysisState tonal) {
+ tonal.Reset();
+ }
+
+ static void tonality_get_info(TonalityAnalysisState tonal, AnalysisInfo info_out, int len) {
+ int pos;
+ int curr_lookahead;
+ float psum;
+ int i;
+
+ pos = tonal.read_pos;
+ curr_lookahead = tonal.write_pos - tonal.read_pos;
+ if (curr_lookahead < 0) {
+ curr_lookahead += OpusConstants.DETECT_SIZE;
+ }
+
+ if (len > 480 && pos != tonal.write_pos) {
+ pos++;
+ if (pos == OpusConstants.DETECT_SIZE) {
+ pos = 0;
+ }
+ }
+ if (pos == tonal.write_pos) {
+ pos--;
+ }
+ if (pos < 0) {
+ pos = OpusConstants.DETECT_SIZE - 1;
+ }
+
+ info_out.Assign(tonal.info[pos]);
+ tonal.read_subframe += len / 120;
+ while (tonal.read_subframe >= 4) {
+ tonal.read_subframe -= 4;
+ tonal.read_pos++;
+ }
+ if (tonal.read_pos >= OpusConstants.DETECT_SIZE) {
+ tonal.read_pos -= OpusConstants.DETECT_SIZE;
+ }
+
+ /* Compensate for the delay in the features themselves.
+ FIXME: Need a better estimate the 10 I just made up */
+ curr_lookahead = Inlines.IMAX(curr_lookahead - 10, 0);
+
+ psum = 0;
+ /* Summing the probability of transition patterns that involve music at
+ time (DETECT_SIZE-curr_lookahead-1) */
+ for (i = 0; i < OpusConstants.DETECT_SIZE - curr_lookahead; i++) {
+ psum += tonal.pmusic[i];
+ }
+ for (; i < OpusConstants.DETECT_SIZE; i++) {
+ psum += tonal.pspeech[i];
+ }
+ psum = psum * tonal.music_confidence + (1 - psum) * tonal.speech_confidence;
+ /*printf("%f %f %f\n", psum, info_out.music_prob, info_out.tonality);*/
+
+ info_out.music_prob = psum;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ static void tonality_analysis(TonalityAnalysisState tonal, CeltMode celt_mode, short[] x, int x_ptr, int len, int offset, int c1, int c2, int C, int lsb_depth) {
+ int i, b;
+ FFTState kfft;
+ int[] input;
+ int[] output;
+ int N = 480, N2 = 240;
+ float[] A = tonal.angle;
+ float[] dA = tonal.d_angle;
+ float[] d2A = tonal.d2_angle;
+ float[] tonality;
+ float[] noisiness;
+ float[] band_tonality = new float[OpusConstants.NB_TBANDS];
+ float[] logE = new float[OpusConstants.NB_TBANDS];
+ float[] BFCC = new float[8];
+ float[] features = new float[25];
+ float frame_tonality;
+ float max_frame_tonality;
+ /*float tw_sum=0;*/
+ float frame_noisiness;
+ float pi4 = (float) (M_PI * M_PI * M_PI * M_PI);
+ float slope = 0;
+ float frame_stationarity;
+ float relativeE;
+ float[] frame_probs = new float[2];
+ float alpha, alphaE, alphaE2;
+ float frame_loudness;
+ float bandwidth_mask;
+ int bandwidth = 0;
+ float maxE = 0;
+ float noise_floor;
+ int remaining;
+ AnalysisInfo info; //[porting note] pointer
+
+ tonal.last_transition++;
+ alpha = 1.0f / Inlines.IMIN(20, 1 + tonal.count);
+ alphaE = 1.0f / Inlines.IMIN(50, 1 + tonal.count);
+ alphaE2 = 1.0f / Inlines.IMIN(1000, 1 + tonal.count);
+
+ if (tonal.count < 4) {
+ tonal.music_prob = 0.5f;
+ }
+ kfft = celt_mode.mdct.kfft[0];
+ if (tonal.count == 0) {
+ tonal.mem_fill = 240;
+ }
+
+ Downmix.downmix_int(x, x_ptr, tonal.inmem, tonal.mem_fill, Inlines.IMIN(len, OpusConstants.ANALYSIS_BUF_SIZE - tonal.mem_fill), offset, c1, c2, C);
+
+ if (tonal.mem_fill + len < OpusConstants.ANALYSIS_BUF_SIZE) {
+ tonal.mem_fill += len;
+ /* Don't have enough to update the analysis */
+ return;
+ }
+
+ info = tonal.info[tonal.write_pos++];
+ if (tonal.write_pos >= OpusConstants.DETECT_SIZE) {
+ tonal.write_pos -= OpusConstants.DETECT_SIZE;
+ }
+
+ input = new int[960];
+ output = new int[960];
+ tonality = new float[240];
+ noisiness = new float[240];
+ for (i = 0; i < N2; i++) {
+ float w = OpusTables.analysis_window[i];
+ input[2 * i] = (int) (w * tonal.inmem[i]);
+ input[2 * i + 1] = (int) (w * tonal.inmem[N2 + i]);
+ input[(2 * (N - i - 1))] = (int) (w * tonal.inmem[N - i - 1]);
+ input[(2 * (N - i - 1)) + 1] = (int) (w * tonal.inmem[N + N2 - i - 1]);
+ }
+ Arrays.MemMove(tonal.inmem, OpusConstants.ANALYSIS_BUF_SIZE - 240, 0, 240);
+
+ remaining = len - (OpusConstants.ANALYSIS_BUF_SIZE - tonal.mem_fill);
+ Downmix.downmix_int(x, x_ptr, tonal.inmem, 240, remaining, offset + OpusConstants.ANALYSIS_BUF_SIZE - tonal.mem_fill, c1, c2, C);
+ tonal.mem_fill = 240 + remaining;
+
+ KissFFT.opus_fft(kfft, input, output);
+
+ for (i = 1; i < N2; i++) {
+ float X1r, X2r, X1i, X2i;
+ float angle, d_angle, d2_angle;
+ float angle2, d_angle2, d2_angle2;
+ float mod1, mod2, avg_mod;
+ X1r = (float) output[2 * i] + output[2 * (N - i)];
+ X1i = (float) output[(2 * i) + 1] - output[2 * (N - i) + 1];
+ X2r = (float) output[(2 * i) + 1] + output[2 * (N - i) + 1];
+ X2i = (float) output[2 * (N - i)] - output[2 * i];
+
+ angle = (float) (.5f / M_PI) * fast_atan2f(X1i, X1r);
+ d_angle = angle - A[i];
+ d2_angle = d_angle - dA[i];
+
+ angle2 = (float) (.5f / M_PI) * fast_atan2f(X2i, X2r);
+ d_angle2 = angle2 - angle;
+ d2_angle2 = d_angle2 - d_angle;
+
+ mod1 = d2_angle - (float) Math.floor(0.5f + d2_angle);
+ noisiness[i] = Inlines.ABS16(mod1);
+ mod1 *= mod1;
+ mod1 *= mod1;
+
+ mod2 = d2_angle2 - (float) Math.floor(0.5f + d2_angle2);
+ noisiness[i] += Inlines.ABS16(mod2);
+ mod2 *= mod2;
+ mod2 *= mod2;
+
+ avg_mod = .25f * (d2A[i] + 2.0f * mod1 + mod2);
+ tonality[i] = 1.0f / (1.0f + 40.0f * 16.0f * pi4 * avg_mod) - .015f;
+
+ A[i] = angle2;
+ dA[i] = d_angle2;
+ d2A[i] = mod2;
+ }
+
+ frame_tonality = 0;
+ max_frame_tonality = 0;
+ /*tw_sum = 0;*/
+ info.activity = 0;
+ frame_noisiness = 0;
+ frame_stationarity = 0;
+ if (tonal.count == 0) {
+ for (b = 0; b < OpusConstants.NB_TBANDS; b++) {
+ tonal.lowE[b] = 1e10f;
+ tonal.highE[b] = -1e10f;
+ }
+ }
+ relativeE = 0;
+ frame_loudness = 0;
+ for (b = 0; b < OpusConstants.NB_TBANDS; b++) {
+ float E = 0, tE = 0, nE = 0;
+ float L1, L2;
+ float stationarity;
+ for (i = OpusTables.tbands[b]; i < OpusTables.tbands[b + 1]; i++) {
+ float binE = output[2 * i] * (float) output[2 * i] + output[2 * (N - i)] * (float) output[2 * (N - i)]
+ + output[2 * i + 1] * (float) output[2 * i + 1] + output[2 * (N - i) + 1] * (float) output[2 * (N - i) + 1];
+ /* FIXME: It's probably best to change the BFCC filter initial state instead */
+ binE *= 5.55e-17f;
+ E += binE;
+ tE += binE * tonality[i];
+ nE += binE * 2.0f * (.5f - noisiness[i]);
+ }
+
+ tonal.E[tonal.E_count][b] = E;
+ frame_noisiness += nE / (1e-15f + E);
+
+ frame_loudness += (float) Math.sqrt(E + 1e-10f);
+ logE[b] = (float) Math.log(E + 1e-10f);
+ tonal.lowE[b] = Inlines.MIN32(logE[b], tonal.lowE[b] + 0.01f);
+ tonal.highE[b] = Inlines.MAX32(logE[b], tonal.highE[b] - 0.1f);
+ if (tonal.highE[b] < tonal.lowE[b] + 1.0f) {
+ tonal.highE[b] += 0.5f;
+ tonal.lowE[b] -= 0.5f;
+ }
+ relativeE += (logE[b] - tonal.lowE[b]) / (1e-15f + tonal.highE[b] - tonal.lowE[b]);
+
+ L1 = L2 = 0;
+ for (i = 0; i < OpusConstants.NB_FRAMES; i++) {
+ L1 += (float) Math.sqrt(tonal.E[i][b]);
+ L2 += tonal.E[i][b];
+ }
+
+ stationarity = Inlines.MIN16(0.99f, L1 / (float) Math.sqrt(1e-15 + OpusConstants.NB_FRAMES * L2));
+ stationarity *= stationarity;
+ stationarity *= stationarity;
+ frame_stationarity += stationarity;
+ /*band_tonality[b] = tE/(1e-15+E)*/
+ band_tonality[b] = Inlines.MAX16(tE / (1e-15f + E), stationarity * tonal.prev_band_tonality[b]);
+ frame_tonality += band_tonality[b];
+ if (b >= OpusConstants.NB_TBANDS - OpusConstants.NB_TONAL_SKIP_BANDS) {
+ frame_tonality -= band_tonality[b - OpusConstants.NB_TBANDS + OpusConstants.NB_TONAL_SKIP_BANDS];
+ }
+ max_frame_tonality = Inlines.MAX16(max_frame_tonality, (1.0f + .03f * (b - OpusConstants.NB_TBANDS)) * frame_tonality);
+ slope += band_tonality[b] * (b - 8);
+ tonal.prev_band_tonality[b] = band_tonality[b];
+ }
+
+ bandwidth_mask = 0;
+ bandwidth = 0;
+ maxE = 0;
+ noise_floor = 5.7e-4f / (1 << (Inlines.IMAX(0, lsb_depth - 8)));
+ noise_floor *= 1 << (15 + CeltConstants.SIG_SHIFT);
+ noise_floor *= noise_floor;
+ for (b = 0; b < OpusConstants.NB_TOT_BANDS; b++) {
+ float E = 0;
+ int band_start, band_end;
+ /* Keep a margin of 300 Hz for aliasing */
+ band_start = OpusTables.extra_bands[b];
+ band_end = OpusTables.extra_bands[b + 1];
+ for (i = band_start; i < band_end; i++) {
+ float binE = output[2 * i] * (float) output[2 * i] + output[2 * (N - i)] * (float) output[2 * (N - i)]
+ + output[2 * i + 1] * (float) output[2 * i + 1] + output[2 * (N - i) + 1] * (float) output[2 * (N - i) + 1];
+ E += binE;
+ }
+ maxE = Inlines.MAX32(maxE, E);
+ tonal.meanE[b] = Inlines.MAX32((1 - alphaE2) * tonal.meanE[b], E);
+ E = Inlines.MAX32(E, tonal.meanE[b]);
+ /* Use a simple follower with 13 dB/Bark slope for spreading function */
+ bandwidth_mask = Inlines.MAX32(.05f * bandwidth_mask, E);
+ /* Consider the band "active" only if all these conditions are met:
+ 1) less than 10 dB below the simple follower
+ 2) less than 90 dB below the peak band (maximal masking possible considering
+ both the ATH and the loudness-dependent slope of the spreading function)
+ 3) above the PCM quantization noise floor
+ */
+ if (E > .1 * bandwidth_mask && E * 1e9f > maxE && E > noise_floor * (band_end - band_start)) {
+ bandwidth = b;
+ }
+ }
+ if (tonal.count <= 2) {
+ bandwidth = 20;
+ }
+ frame_loudness = 20 * (float) Math.log10(frame_loudness);
+ tonal.Etracker = Inlines.MAX32(tonal.Etracker - .03f, frame_loudness);
+ tonal.lowECount *= (1 - alphaE);
+ if (frame_loudness < tonal.Etracker - 30) {
+ tonal.lowECount += alphaE;
+ }
+
+ for (i = 0; i < 8; i++) {
+ float sum = 0;
+ for (b = 0; b < 16; b++) {
+ sum += OpusTables.dct_table[i * 16 + b] * logE[b];
+ }
+ BFCC[i] = sum;
+ }
+
+ frame_stationarity /= OpusConstants.NB_TBANDS;
+ relativeE /= OpusConstants.NB_TBANDS;
+ if (tonal.count < 10) {
+ relativeE = 0.5f;
+ }
+ frame_noisiness /= OpusConstants.NB_TBANDS;
+ info.activity = frame_noisiness + (1 - frame_noisiness) * relativeE;
+ frame_tonality = (max_frame_tonality / (OpusConstants.NB_TBANDS - OpusConstants.NB_TONAL_SKIP_BANDS));
+ frame_tonality = Inlines.MAX16(frame_tonality, tonal.prev_tonality * .8f);
+ tonal.prev_tonality = frame_tonality;
+
+ slope /= 8 * 8;
+ info.tonality_slope = slope;
+
+ tonal.E_count = (tonal.E_count + 1) % OpusConstants.NB_FRAMES;
+ tonal.count++;
+ info.tonality = frame_tonality;
+
+ for (i = 0; i < 4; i++) {
+ features[i] = -0.12299f * (BFCC[i] + tonal.mem[i + 24]) + 0.49195f * (tonal.mem[i] + tonal.mem[i + 16]) + 0.69693f * tonal.mem[i + 8] - 1.4349f * tonal.cmean[i];
+ }
+
+ for (i = 0; i < 4; i++) {
+ tonal.cmean[i] = (1 - alpha) * tonal.cmean[i] + alpha * BFCC[i];
+ }
+
+ for (i = 0; i < 4; i++) {
+ features[4 + i] = 0.63246f * (BFCC[i] - tonal.mem[i + 24]) + 0.31623f * (tonal.mem[i] - tonal.mem[i + 16]);
+ }
+ for (i = 0; i < 3; i++) {
+ features[8 + i] = 0.53452f * (BFCC[i] + tonal.mem[i + 24]) - 0.26726f * (tonal.mem[i] + tonal.mem[i + 16]) - 0.53452f * tonal.mem[i + 8];
+ }
+
+ if (tonal.count > 5) {
+ for (i = 0; i < 9; i++) {
+ tonal.std[i] = (1 - alpha) * tonal.std[i] + alpha * features[i] * features[i];
+ }
+ }
+
+ for (i = 0; i < 8; i++) {
+ tonal.mem[i + 24] = tonal.mem[i + 16];
+ tonal.mem[i + 16] = tonal.mem[i + 8];
+ tonal.mem[i + 8] = tonal.mem[i];
+ tonal.mem[i] = BFCC[i];
+ }
+ for (i = 0; i < 9; i++) {
+ features[11 + i] = (float) Math.sqrt(tonal.std[i]);
+ }
+ features[20] = info.tonality;
+ features[21] = info.activity;
+ features[22] = frame_stationarity;
+ features[23] = info.tonality_slope;
+ features[24] = tonal.lowECount;
+
+ if (info.enabled) {
+ MultiLayerPerceptron.mlp_process(OpusTables.net, features, frame_probs);
+ frame_probs[0] = .5f * (frame_probs[0] + 1);
+ /* Curve fitting between the MLP probability and the actual probability */
+ frame_probs[0] = .01f + 1.21f * frame_probs[0] * frame_probs[0] - .23f * (float) Math.pow(frame_probs[0], 10);
+ /* Probability of active audio (as opposed to silence) */
+ frame_probs[1] = .5f * frame_probs[1] + .5f;
+ /* Consider that silence has a 50-50 probability. */
+ frame_probs[0] = frame_probs[1] * frame_probs[0] + (1 - frame_probs[1]) * .5f;
+
+ /*printf("%f %f ", frame_probs[0], frame_probs[1]);*/
+ {
+ /* Probability of state transition */
+ float tau;
+ /* Represents independence of the MLP probabilities, where
+ beta=1 means fully independent. */
+ float beta;
+ /* Denormalized probability of speech (p0) and music (p1) after update */
+ float p0, p1;
+ /* Probabilities for "all speech" and "all music" */
+ float s0, m0;
+ /* Probability sum for renormalisation */
+ float psum;
+ /* Instantaneous probability of speech and music, with beta pre-applied. */
+ float speech0;
+ float music0;
+
+ /* One transition every 3 minutes of active audio */
+ tau = .00005f * frame_probs[1];
+ beta = .05f;
+ //if (1)
+ {
+ /* Adapt beta based on how "unexpected" the new prob is */
+ float p, q;
+ p = Inlines.MAX16(.05f, Inlines.MIN16(.95f, frame_probs[0]));
+ q = Inlines.MAX16(.05f, Inlines.MIN16(.95f, tonal.music_prob));
+ beta = .01f + .05f * Inlines.ABS16(p - q) / (p * (1 - q) + q * (1 - p));
+ }
+ /* p0 and p1 are the probabilities of speech and music at this frame
+ using only information from previous frame and applying the
+ state transition model */
+ p0 = (1 - tonal.music_prob) * (1 - tau) + tonal.music_prob * tau;
+ p1 = tonal.music_prob * (1 - tau) + (1 - tonal.music_prob) * tau;
+ /* We apply the current probability with exponent beta to work around
+ the fact that the probability estimates aren't independent. */
+ p0 *= (float) Math.pow(1 - frame_probs[0], beta);
+ p1 *= (float) Math.pow(frame_probs[0], beta);
+ /* Normalise the probabilities to get the Marokv probability of music. */
+ tonal.music_prob = p1 / (p0 + p1);
+ info.music_prob = tonal.music_prob;
+
+ /* This chunk of code deals with delayed decision. */
+ psum = 1e-20f;
+ /* Instantaneous probability of speech and music, with beta pre-applied. */
+ speech0 = (float) Math.pow(1 - frame_probs[0], beta);
+ music0 = (float) Math.pow(frame_probs[0], beta);
+ if (tonal.count == 1) {
+ tonal.pspeech[0] = 0.5f;
+ tonal.pmusic[0] = 0.5f;
+ }
+ /* Updated probability of having only speech (s0) or only music (m0),
+ before considering the new observation. */
+ s0 = tonal.pspeech[0] + tonal.pspeech[1];
+ m0 = tonal.pmusic[0] + tonal.pmusic[1];
+ /* Updates s0 and m0 with instantaneous probability. */
+ tonal.pspeech[0] = s0 * (1 - tau) * speech0;
+ tonal.pmusic[0] = m0 * (1 - tau) * music0;
+ /* Propagate the transition probabilities */
+ for (i = 1; i < OpusConstants.DETECT_SIZE - 1; i++) {
+ tonal.pspeech[i] = tonal.pspeech[i + 1] * speech0;
+ tonal.pmusic[i] = tonal.pmusic[i + 1] * music0;
+ }
+ /* Probability that the latest frame is speech, when all the previous ones were music. */
+ tonal.pspeech[OpusConstants.DETECT_SIZE - 1] = m0 * tau * speech0;
+ /* Probability that the latest frame is music, when all the previous ones were speech. */
+ tonal.pmusic[OpusConstants.DETECT_SIZE - 1] = s0 * tau * music0;
+
+ /* Renormalise probabilities to 1 */
+ for (i = 0; i < OpusConstants.DETECT_SIZE; i++) {
+ psum += tonal.pspeech[i] + tonal.pmusic[i];
+ }
+ psum = 1.0f / psum;
+ for (i = 0; i < OpusConstants.DETECT_SIZE; i++) {
+ tonal.pspeech[i] *= psum;
+ tonal.pmusic[i] *= psum;
+ }
+ psum = tonal.pmusic[0];
+ for (i = 1; i < OpusConstants.DETECT_SIZE; i++) {
+ psum += tonal.pspeech[i];
+ }
+
+ /* Estimate our confidence in the speech/music decisions */
+ if (frame_probs[1] > .75) {
+ if (tonal.music_prob > .9) {
+ float adapt;
+ adapt = 1.0f / (++tonal.music_confidence_count);
+ tonal.music_confidence_count = Inlines.IMIN(tonal.music_confidence_count, 500);
+ tonal.music_confidence += adapt * Inlines.MAX16(-.2f, frame_probs[0] - tonal.music_confidence);
+ }
+ if (tonal.music_prob < .1) {
+ float adapt;
+ adapt = 1.0f / (++tonal.speech_confidence_count);
+ tonal.speech_confidence_count = Inlines.IMIN(tonal.speech_confidence_count, 500);
+ tonal.speech_confidence += adapt * Inlines.MIN16(.2f, frame_probs[0] - tonal.speech_confidence);
+ }
+ } else {
+ if (tonal.music_confidence_count == 0) {
+ tonal.music_confidence = .9f;
+ }
+ if (tonal.speech_confidence_count == 0) {
+ tonal.speech_confidence = .1f;
+ }
+ }
+ }
+ if (tonal.last_music != ((tonal.music_prob > .5f) ? 1 : 0)) {
+ tonal.last_transition = 0;
+ }
+ tonal.last_music = (tonal.music_prob > .5f) ? 1 : 0;
+ } else {
+ info.music_prob = 0;
+ }
+
+ info.bandwidth = bandwidth;
+ info.noisiness = frame_noisiness;
+ info.valid = 1;
+ }
+
+ static void run_analysis(TonalityAnalysisState analysis, CeltMode celt_mode, short[] analysis_pcm, int analysis_pcm_ptr,
+ int analysis_frame_size, int frame_size, int c1, int c2, int C, int Fs,
+ int lsb_depth, AnalysisInfo analysis_info) {
+ int offset;
+ int pcm_len;
+
+ if (analysis_pcm != null) {
+ /* Avoid overflow/wrap-around of the analysis buffer */
+ analysis_frame_size = Inlines.IMIN((OpusConstants.DETECT_SIZE - 5) * Fs / 100, analysis_frame_size);
+
+ pcm_len = analysis_frame_size - analysis.analysis_offset;
+ offset = analysis.analysis_offset;
+ do {
+ tonality_analysis(analysis, celt_mode, analysis_pcm, analysis_pcm_ptr, Inlines.IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth);
+ offset += 480;
+ pcm_len -= 480;
+ } while (pcm_len > 0);
+ analysis.analysis_offset = analysis_frame_size;
+
+ analysis.analysis_offset -= frame_size;
+ }
+
+ analysis_info.valid = 0;
+ tonality_get_info(analysis, analysis_info, frame_size);
+ }
+}
diff --git a/app/src/main/java/org/concentus/AnalysisInfo.java b/app/src/main/java/org/concentus/AnalysisInfo.java
new file mode 100644
index 0000000000..aeb0e7378c
--- /dev/null
+++ b/app/src/main/java/org/concentus/AnalysisInfo.java
@@ -0,0 +1,70 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class AnalysisInfo {
+
+ boolean enabled = false;
+ int valid = 0;
+ float tonality = 0;
+ float tonality_slope = 0;
+ float noisiness = 0;
+ float activity = 0;
+ float music_prob = 0;
+ int bandwidth = 0;
+
+ AnalysisInfo() {
+ }
+
+ void Assign(AnalysisInfo other) {
+ this.valid = other.valid;
+ this.tonality = other.tonality;
+ this.tonality_slope = other.tonality_slope;
+ this.noisiness = other.noisiness;
+ this.activity = other.activity;
+ this.music_prob = other.music_prob;
+ this.bandwidth = other.bandwidth;
+ }
+
+ void Reset() {
+ valid = 0;
+ tonality = 0;
+ tonality_slope = 0;
+ noisiness = 0;
+ activity = 0;
+ music_prob = 0;
+ bandwidth = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/ApplySineWindow.java b/app/src/main/java/org/concentus/ApplySineWindow.java
new file mode 100644
index 0000000000..409b3f604b
--- /dev/null
+++ b/app/src/main/java/org/concentus/ApplySineWindow.java
@@ -0,0 +1,106 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+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 final 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,};
+
+ 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));
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/Arrays.java b/app/src/main/java/org/concentus/Arrays.java
new file mode 100644
index 0000000000..6879b90918
--- /dev/null
+++ b/app/src/main/java/org/concentus/Arrays.java
@@ -0,0 +1,111 @@
+/* Copyright (c) 2016 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.
+ */
+package org.concentus;
+
+class Arrays {
+
+ static int[][] InitTwoDimensionalArrayInt(int x, int y) {
+ return new int[x][y];
+ }
+
+ static float[][] InitTwoDimensionalArrayFloat(int x, int y) {
+ return new float[x][y];
+ }
+
+ static short[][] InitTwoDimensionalArrayShort(int x, int y) {
+ return new short[x][y];
+ }
+
+ static byte[][] InitTwoDimensionalArrayByte(int x, int y) {
+ return new byte[x][y];
+ }
+
+ static byte[][][] InitThreeDimensionalArrayByte(int x, int y, int z) {
+ return new byte[x][y][z];
+ }
+
+ static void MemSet(byte[] array, byte value) {
+ java.util.Arrays.fill(array, value);
+ }
+
+ static void MemSet(short[] array, short value) {
+ java.util.Arrays.fill(array, value);
+ }
+
+ static void MemSet(int[] array, int value) {
+ java.util.Arrays.fill(array, value);
+ }
+
+ static void MemSet(float[] array, float value) {
+ java.util.Arrays.fill(array, value);
+ }
+
+ static void MemSet(byte[] array, byte value, int length) {
+ java.util.Arrays.fill(array, 0, length, value);
+ }
+
+ static void MemSet(short[] array, short value, int length) {
+ java.util.Arrays.fill(array, 0, length, value);
+ }
+
+ static void MemSet(int[] array, int value, int length) {
+ java.util.Arrays.fill(array, 0, length, value);
+ }
+
+ static void MemSet(float[] array, float value, int length) {
+ java.util.Arrays.fill(array, 0, length, value);
+ }
+
+ static void MemSetWithOffset(byte[] array, byte value, int offset, int length) {
+ java.util.Arrays.fill(array, offset, offset + length, value);
+ }
+
+ static void MemSetWithOffset(short[] array, short value, int offset, int length) {
+ java.util.Arrays.fill(array, offset, offset + length, value);
+ }
+
+ static void MemSetWithOffset(int[] array, int value, int offset, int length) {
+ java.util.Arrays.fill(array, offset, offset + length, value);
+ }
+
+ static void MemMove(byte[] array, int src_idx, int dst_idx, int length) {
+ System.arraycopy(array, src_idx, array, dst_idx, length);
+ }
+
+ static void MemMove(short[] array, int src_idx, int dst_idx, int length) {
+ System.arraycopy(array, src_idx, array, dst_idx, length);
+ }
+
+ static void MemMove(int[] array, int src_idx, int dst_idx, int length) {
+ System.arraycopy(array, src_idx, array, dst_idx, length);
+ }
+
+}
diff --git a/app/src/main/java/org/concentus/Autocorrelation.java b/app/src/main/java/org/concentus/Autocorrelation.java
new file mode 100644
index 0000000000..b920493ff4
--- /dev/null
+++ b/app/src/main/java/org/concentus/Autocorrelation.java
@@ -0,0 +1,257 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class Autocorrelation {
+
+ /* Compute autocorrelation */
+ static void silk_autocorr(
+ int[] results, /* O Result (length correlationCount) */
+ BoxedValueInt scale, /* O Scaling of the correlation vector */
+ short[] inputData, /* I Input data to correlate */
+ int inputDataSize, /* I Length of input */
+ int correlationCount /* I Number of correlation taps to compute */
+ ) {
+ int corrCount = Inlines.silk_min_int(inputDataSize, correlationCount);
+ scale.Val = Autocorrelation._celt_autocorr(inputData, results, corrCount - 1, inputDataSize);
+ }
+
+ static int _celt_autocorr(
+ short[] x, /* in: [0...n-1] samples x */
+ int[] ac, /* out: [0...lag-1] ac values */
+ int lag,
+ int n
+ ) {
+ int d;
+ int i, k;
+ int fastN = n - lag;
+ int shift;
+ short[] xptr;
+ short[] xx = new short[n];
+ Inlines.OpusAssert(n > 0);
+ xptr = x;
+
+ shift = 0;
+ {
+ int ac0;
+ ac0 = 1 + (n << 7);
+ if ((n & 1) != 0) {
+ ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[0], xptr[0]), 9);
+ }
+ for (i = (n & 1); i < n; i += 2) {
+ ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i], xptr[i]), 9);
+ ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i + 1], xptr[i + 1]), 9);
+ }
+ shift = Inlines.celt_ilog2(ac0) - 30 + 10;
+ shift = (shift) / 2;
+ if (shift > 0) {
+ for (i = 0; i < n; i++) {
+ xx[i] = (short) (Inlines.PSHR32(xptr[i], shift));
+ }
+ xptr = xx;
+ } else {
+ shift = 0;
+ }
+ }
+ CeltPitchXCorr.pitch_xcorr(xptr, xptr, ac, fastN, lag + 1);
+ for (k = 0; k <= lag; k++) {
+ for (i = k + fastN, d = 0; i < n; i++) {
+ d = Inlines.MAC16_16(d, xptr[i], xptr[i - k]);
+ }
+ ac[k] += d;
+ }
+ shift = 2 * shift;
+ if (shift <= 0) {
+ ac[0] += Inlines.SHL32((int) 1, -shift);
+ }
+ if (ac[0] < 268435456) {
+ int shift2 = 29 - Inlines.EC_ILOG(ac[0]);
+ for (i = 0; i <= lag; i++) {
+ ac[i] = Inlines.SHL32(ac[i], shift2);
+ }
+ shift -= shift2;
+ } else if (ac[0] >= 536870912) {
+ int shift2 = 1;
+ if (ac[0] >= 1073741824) {
+ shift2++;
+ }
+ for (i = 0; i <= lag; i++) {
+ ac[i] = Inlines.SHR32(ac[i], shift2);
+ }
+ shift += shift2;
+ }
+
+ return shift;
+ }
+
+ static int _celt_autocorr(
+ int[] x, /* in: [0...n-1] samples x */
+ int[] ac, /* out: [0...lag-1] ac values */
+ int[] window,
+ int overlap,
+ int lag,
+ int n) {
+ int d;
+ int i, k;
+ int fastN = n - lag;
+ int shift;
+ int[] xptr;
+ int[] xx = new int[n];
+
+ Inlines.OpusAssert(n > 0);
+ Inlines.OpusAssert(overlap >= 0);
+
+ if (overlap == 0) {
+ xptr = x;
+ } else {
+ for (i = 0; i < n; i++) {
+ xx[i] = x[i];
+ }
+ for (i = 0; i < overlap; i++) {
+ xx[i] = Inlines.MULT16_16_Q15(x[i], window[i]);
+ xx[n - i - 1] = Inlines.MULT16_16_Q15(x[n - i - 1], window[i]);
+ }
+ xptr = xx;
+ }
+
+ shift = 0;
+
+ int ac0;
+ ac0 = 1 + (n << 7);
+ if ((n & 1) != 0) {
+ ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[0], xptr[0]), 9);
+ }
+
+ for (i = (n & 1); i < n; i += 2) {
+ ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i], xptr[i]), 9);
+ ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i + 1], xptr[i + 1]), 9);
+ }
+
+ shift = Inlines.celt_ilog2(ac0) - 30 + 10;
+ shift = (shift) / 2;
+ if (shift > 0) {
+ for (i = 0; i < n; i++) {
+ xx[i] = (Inlines.PSHR32(xptr[i], shift));
+ }
+ xptr = xx;
+ } else {
+ shift = 0;
+ }
+
+ CeltPitchXCorr.pitch_xcorr(xptr, xptr, ac, fastN, lag + 1);
+ for (k = 0; k <= lag; k++) {
+ for (i = k + fastN, d = 0; i < n; i++) {
+ d = Inlines.MAC16_16(d, xptr[i], xptr[i - k]);
+ }
+ ac[k] += d;
+ }
+
+ shift = 2 * shift;
+ if (shift <= 0) {
+ ac[0] += Inlines.SHL32((int) 1, -shift);
+ }
+ if (ac[0] < 268435456) {
+ int shift2 = 29 - Inlines.EC_ILOG(ac[0]);
+ for (i = 0; i <= lag; i++) {
+ ac[i] = Inlines.SHL32(ac[i], shift2);
+ }
+ shift -= shift2;
+ } else if (ac[0] >= 536870912) {
+ int shift2 = 1;
+ if (ac[0] >= 1073741824) {
+ shift2++;
+ }
+ for (i = 0; i <= lag; i++) {
+ ac[i] = Inlines.SHR32(ac[i], shift2);
+ }
+ shift += shift2;
+ }
+
+ return shift;
+ }
+
+ private static final int QC = 10;
+ private static final int QS = 14;
+
+ /* Autocorrelations for a warped frequency axis */
+ static void silk_warped_autocorrelation(
+ int[] corr, /* O Result [order + 1] */
+ BoxedValueInt scale, /* O Scaling of the correlation vector */
+ short[] input, /* I Input data to correlate */
+ int warping_Q16, /* I Warping coefficient */
+ int length, /* I Length of input */
+ int order /* I Correlation order (even) */
+ ) {
+ int n, i, lsh;
+ int tmp1_QS, tmp2_QS;
+ int[] state_QS = new int[SilkConstants.MAX_SHAPE_LPC_ORDER + 1];// = { 0 };
+ long[] corr_QC = new long[SilkConstants.MAX_SHAPE_LPC_ORDER + 1];// = { 0 };
+
+ /* Order must be even */
+ Inlines.OpusAssert((order & 1) == 0);
+ Inlines.OpusAssert(2 * QS - QC >= 0);
+
+ /* Loop over samples */
+ for (n = 0; n < length; n++) {
+ tmp1_QS = Inlines.silk_LSHIFT32((int) input[n], QS);
+ /* Loop over allpass sections */
+ for (i = 0; i < order; i += 2) {
+ /* Output of allpass section */
+ tmp2_QS = Inlines.silk_SMLAWB(state_QS[i], state_QS[i + 1] - tmp1_QS, warping_Q16);
+ state_QS[i] = tmp1_QS;
+ corr_QC[i] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp1_QS, state_QS[0]), 2 * QS - QC);
+ /* Output of allpass section */
+ tmp1_QS = Inlines.silk_SMLAWB(state_QS[i + 1], state_QS[i + 2] - tmp2_QS, warping_Q16);
+ state_QS[i + 1] = tmp2_QS;
+ corr_QC[i + 1] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp2_QS, state_QS[0]), 2 * QS - QC);
+ }
+ state_QS[order] = tmp1_QS;
+ corr_QC[order] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp1_QS, state_QS[0]), 2 * QS - QC);
+ }
+
+ lsh = Inlines.silk_CLZ64(corr_QC[0]) - 35;
+ lsh = Inlines.silk_LIMIT(lsh, -12 - QC, 30 - QC);
+ scale.Val = -(QC + lsh);
+ Inlines.OpusAssert(scale.Val >= -30 && scale.Val <= 12);
+ if (lsh >= 0) {
+ for (i = 0; i < order + 1; i++) {
+ corr[i] = (int) (Inlines.silk_LSHIFT64(corr_QC[i], lsh));
+ }
+ } else {
+ for (i = 0; i < order + 1; i++) {
+ corr[i] = (int) (Inlines.silk_RSHIFT64(corr_QC[i], -lsh));
+ }
+ }
+ Inlines.OpusAssert(corr_QC[0] >= 0);
+ /* If breaking, decrease QC*/
+ }
+}
diff --git a/app/src/main/java/org/concentus/BWExpander.java b/app/src/main/java/org/concentus/BWExpander.java
new file mode 100644
index 0000000000..ca28a3a65a
--- /dev/null
+++ b/app/src/main/java/org/concentus/BWExpander.java
@@ -0,0 +1,78 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class BWExpander {
+
+ ///
+ /// Chirp (bw expand) LP AR filter (Fixed point implementation)
+ ///
+ /// I/O AR filter to be expanded (without leading 1)
+ /// I length of ar
+ /// I chirp factor (typically in range (0..1) )
+ 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]);
+ }
+
+ ///
+ /// Chirp (bw expand) LP AR filter (Fixed point implementation)
+ ///
+ /// I/O AR filter to be expanded (without leading 1)
+ /// I length of ar
+ /// I chirp factor (typically in range (0..1) )
+ 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);
+ }
+}
diff --git a/app/src/main/java/org/concentus/Bands.java b/app/src/main/java/org/concentus/Bands.java
new file mode 100644
index 0000000000..5b4da12388
--- /dev/null
+++ b/app/src/main/java/org/concentus/Bands.java
@@ -0,0 +1,1512 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class Bands {
+
+ 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;
+ }
+
+ static int celt_lcg_rand(int seed) {
+ return (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 */
+ 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);
+ }
+
+ static int bitexact_log2tan(int isin, int icos) {
+ int lc = Inlines.EC_ILOG((long) icos);
+ int ls = Inlines.EC_ILOG((long) 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 */
+ 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. */
+ 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 */
+ 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(CeltTables.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(freq, 0, freq_ptr + bound, N - bound);
+ }
+
+ /* This prevents energy collapse for transients with multiple short MDCTs */
+ static void anti_collapse(CeltMode m, int[][] X_, short[] collapse_masks, int LM, int C, int size,
+ int start, int end, int[] logE, int[] prev1logE,
+ int[] prev2logE, int[] pulses, int 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);
+ }
+ }
+
+ 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;
+ BoxedValueInt xp = new BoxedValueInt(0);
+ BoxedValueInt side = new BoxedValueInt(0);
+ 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) */
+ Kernels.dual_inner_prod(Y, Y_ptr, X, X_ptr, Y, Y_ptr, N, xp, side);
+ /* Compensating for the mid normalization */
+ xp.Val = Inlines.MULT16_32_Q15(mid, xp.Val);
+ /* mid and side are in Q15, not Q14 like X and Y */
+ mid2 = Inlines.SHR16(mid, 1);
+ El = Inlines.MULT16_16(mid2, mid2) + side.Val - (2 * xp.Val);
+ Er = Inlines.MULT16_16(mid2, mid2) + side.Val + (2 * xp.Val);
+ 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)*/) {
+ System.arraycopy(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 */
+ static int spreading_decision(CeltMode m, int[][] X, BoxedValueInt average,
+ int last_decision, BoxedValueInt hf_average, BoxedValueInt 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.Val = (hf_average.Val + hf_sum) >> 1;
+ hf_sum = hf_average.Val;
+
+ if (tapset_decision.Val == 2) {
+ hf_sum += 4;
+ } else if (tapset_decision.Val == 0) {
+ hf_sum -= 4;
+ }
+ if (hf_sum > 22) {
+ tapset_decision.Val = 2;
+ } else if (hf_sum > 18) {
+ tapset_decision.Val = 1;
+ } else {
+ tapset_decision.Val = 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.Val) >> 1;
+ average.Val = 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;
+ }
+ return decision;
+ }
+
+ 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[CeltTables.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];
+ }
+ }
+ }
+
+ System.arraycopy(tmp, 0, X, X_ptr, N);
+ }
+
+ 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[CeltTables.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];
+ }
+ }
+ }
+
+ System.arraycopy(tmp, 0, X, X_ptr, N);
+ }
+
+ 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));
+ }
+ }
+ }
+
+ 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));
+ }
+ }
+ }
+
+ 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 static 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 int seed;
+ };
+
+ public static class split_ctx {
+
+ public int inv;
+ public int imid;
+ public int iside;
+ public int delta;
+ public int itheta;
+ public int qalloc;
+ };
+
+ static void compute_theta(band_ctx ctx, split_ctx sctx,
+ int[] X, int X_ptr, int[] Y, int Y_ptr, int N, BoxedValueInt b, int B, int B0,
+ int LM,
+ int stereo, BoxedValueInt 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.Val, 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;
+ long ft = Inlines.CapToUInt32(p0 * (x0 + 1) + x0);
+ /* Use a probability of p0 up to itheta=8192 and then use 1 after */
+ if (encode != 0) {
+ ec.encode(
+ (x <= x0
+ ? (p0 * x)
+ : ((x - 1 - x0) + (x0 + 1) * p0)),
+ (x <= x0
+ ? (p0 * (x + 1))
+ : ((x - x0) + (x0 + 1) * p0)),
+ ft);
+ } else {
+ int fs = (int) ec.decode(ft);
+ if (fs < (x0 + 1) * p0) {
+ x = fs / p0;
+ } else {
+ x = x0 + 1 + (fs - (x0 + 1) * p0);
+ }
+
+ ec.dec_update(
+ (x <= x0
+ ? p0 * x
+ : (x - 1 - x0) + (x0 + 1) * p0),
+ (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(itheta, (qn + 1));
+ } else {
+ itheta = (int) ec.dec_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(fl, (fl + fs), ft);
+ } else {
+ /* Triangular pdf */
+ int fl = 0;
+ int fm;
+ fm = (int) ec.decode(ft);
+
+ if (fm < ((qn >> 1) * ((qn >> 1) + 1) >> 1)) {
+ itheta = (Inlines.isqrt32(8 * fm + 1) - 1) >> 1;
+ fs = itheta + 1;
+ fl = itheta * (itheta + 1) >> 1;
+ } else {
+ itheta = (2 * (qn + 1) - Inlines.isqrt32(8 * (ft - fm - 1) + 1)) >> 1;
+ fs = qn + 1 - itheta;
+ fl = ft - ((qn + 1 - itheta) * (qn + 2 - itheta) >> 1);
+ }
+
+ ec.dec_update(fl, (fl + fs), 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.Val > 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.Val -= qalloc;
+
+ if (itheta == 0) {
+ imid = 32767;
+ iside = 0;
+ fill.Val &= (1 << B) - 1;
+ delta = -16384;
+ } else if (itheta == 16384) {
+ imid = 0;
+ iside = 32767;
+ fill.Val &= ((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;
+ }
+
+ static int 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(sign, 1);
+ } else {
+ sign = 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. */
+ static int 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;
+ int 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;
+ short[] 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;
+
+ BoxedValueInt boxed_b = new BoxedValueInt(b);
+ BoxedValueInt boxed_fill = new BoxedValueInt(fill);
+ compute_theta(ctx, sctx, X, X_ptr, X, Y, N, boxed_b, B, B0, LM, 0, boxed_fill);
+ b = boxed_b.Val;
+ fill = boxed_fill.Val;
+
+ 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) {
+ int 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 = (1 << B) - 1;
+ fill = fill & cm_mask;
+
+ if (fill == 0) {
+ Arrays.MemSetWithOffset(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] = (((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 = fill;
+ }
+
+ VQ.renormalise_vector(X, X_ptr, N, gain);
+ }
+ }
+ }
+ }
+
+ return cm;
+ }
+
+ private static final byte[] bit_interleave_table = {0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3};
+
+ private static final short[] 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. */
+ static int 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;
+ int 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)) {
+ System.arraycopy(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);
+ }
+ int idx1 = fill & 0xF;
+ int idx2 = fill >> 4;
+ if (idx1 < 0) {
+ System.out.println("e");
+ }
+ if (idx2 < 0) {
+ System.out.println("e");
+ }
+ 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 & ((1 << B) - 1);
+ }
+ return cm;
+ }
+
+ /* This function is responsible for encoding and decoding a band for the stereo case. */
+ static int 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;
+ int 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;
+
+ BoxedValueInt boxed_b = new BoxedValueInt(b);
+ BoxedValueInt boxed_fill = new BoxedValueInt(fill);
+ compute_theta(ctx, sctx, X, X_ptr, Y, Y_ptr, N, boxed_b, B, B, LM, 1, boxed_fill);
+ b = boxed_b.Val;
+ fill = boxed_fill.Val;
+
+ 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(sign, 1);
+ } else {
+ sign = 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;
+ }
+
+ static void quant_all_bands(int encode, CeltMode m, int start, int end,
+ int[] X_, int[] Y_, short[] 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,
+ BoxedValueInt 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.Val;
+ 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;
+ long x_cm;
+ long 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 = ((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] = (short) (x_cm & 0xFF);
+ collapse_masks[i * C + C - 1] = (short) (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.Val = ctx.seed;
+ }
+}
diff --git a/app/src/main/java/org/concentus/BoxedValue.java b/app/src/main/java/org/concentus/BoxedValue.java
new file mode 100644
index 0000000000..f039bc17c5
--- /dev/null
+++ b/app/src/main/java/org/concentus/BoxedValue.java
@@ -0,0 +1,58 @@
+/* Copyright (c) 2016 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.
+ */
+package org.concentus;
+
+class BoxedValueByte {
+
+ public byte Val;
+
+ public BoxedValueByte(byte v) {
+ Val = v;
+ }
+}
+
+class BoxedValueShort {
+
+ public short Val;
+
+ public BoxedValueShort(short v) {
+ Val = v;
+ }
+}
+
+class BoxedValueInt {
+
+ public int Val;
+
+ public BoxedValueInt(int v) {
+ Val = v;
+ }
+}
diff --git a/app/src/main/java/org/concentus/BurgModified.java b/app/src/main/java/org/concentus/BurgModified.java
new file mode 100644
index 0000000000..1d1e6726a5
--- /dev/null
+++ b/app/src/main/java/org/concentus/BurgModified.java
@@ -0,0 +1,337 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class BurgModified {
+
+ /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
+ private static final int MAX_FRAME_SIZE = 384;
+ private static final int QA = 25;
+ private static final int N_BITS_HEAD_ROOM = 2;
+ private static final int MIN_RSHIFTS = -16;
+ private static final int MAX_RSHIFTS = (32 - QA);
+
+ /* Compute reflection coefficients from input signal */
+ 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.MemSet(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);
+ }
+ }
+ }
+ System.arraycopy(C_first_row, 0, C_last_row, 0, 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) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
+ }
+
+ /* 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;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/CNG.java b/app/src/main/java/org/concentus/CNG.java
new file mode 100644
index 0000000000..d08f9237dc
--- /dev/null
+++ b/app/src/main/java/org/concentus/CNG.java
@@ -0,0 +1,206 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Comfort noise generation and estimation
+///
+class CNG {
+
+ ///
+ /// Generates excitation for CNG LPC synthesis
+ ///
+ /// O CNG excitation signal Q10
+ /// I Random samples buffer Q10
+ /// I Gain to apply
+ /// I Length
+ /// I/O Seed to random index generator
+ static void silk_CNG_exc(
+ int[] exc_Q10,
+ int exc_Q10_ptr,
+ int[] exc_buf_Q14,
+ int Gain_Q16,
+ int length,
+ BoxedValueInt 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.Val;
+ 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.Val = seed;
+ }
+
+ ///
+ /// Resets CNG state
+ ///
+ /// I/O Decoder state
+ static void silk_CNG_Reset(SilkChannelDecoder psDec) {
+ int i, NLSF_step_Q15, NLSF_acc_Q15;
+
+ NLSF_step_Q15 = Inlines.silk_DIV32_16(Short.MAX_VALUE, (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;
+ }
+
+ ///
+ /// Updates CNG estimate, and applies the CNG when packet was lost
+ ///
+ /// I/O Decoder state
+ /// I/O Decoder control
+ /// I/O Signal
+ /// I Length of residual
+ 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.MemMove(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);
+ }
+
+ BoxedValueInt boxed_rand_seed = new BoxedValueInt(psCNG.rand_seed);
+ silk_CNG_exc(CNG_sig_Q10, SilkConstants.MAX_LPC_ORDER, psCNG.CNG_exc_buf_Q14, gain_Q16, length, boxed_rand_seed);
+ psCNG.rand_seed = boxed_rand_seed.Val;
+
+ /* 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 */
+ System.arraycopy(psCNG.CNG_synth_state, 0, CNG_sig_Q10, 0, 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)));
+ }
+
+ System.arraycopy(CNG_sig_Q10, length, psCNG.CNG_synth_state, 0, SilkConstants.MAX_LPC_ORDER);
+ } else {
+ Arrays.MemSet(psCNG.CNG_synth_state, 0, psDec.LPC_order);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/CNGState.java b/app/src/main/java/org/concentus/CNGState.java
new file mode 100644
index 0000000000..9f4d6cb8af
--- /dev/null
+++ b/app/src/main/java/org/concentus/CNGState.java
@@ -0,0 +1,54 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Struct for CNG
+///
+class CNGState {
+
+ final int[] CNG_exc_buf_Q14 = new int[SilkConstants.MAX_FRAME_LENGTH];
+ final short[] CNG_smth_NLSF_Q15 = new short[SilkConstants.MAX_LPC_ORDER];
+ final int[] CNG_synth_state = new int[SilkConstants.MAX_LPC_ORDER];
+ int CNG_smth_Gain_Q16 = 0;
+ int rand_seed = 0;
+ int fs_kHz = 0;
+
+ void Reset() {
+ Arrays.MemSet(CNG_exc_buf_Q14, 0, SilkConstants.MAX_FRAME_LENGTH);
+ Arrays.MemSet(CNG_smth_NLSF_Q15, (short) 0, SilkConstants.MAX_LPC_ORDER);
+ Arrays.MemSet(CNG_synth_state, 0, SilkConstants.MAX_LPC_ORDER);
+ CNG_smth_Gain_Q16 = 0;
+ rand_seed = 0;
+ fs_kHz = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/CWRS.java b/app/src/main/java/org/concentus/CWRS.java
new file mode 100644
index 0000000000..3568ef9a5c
--- /dev/null
+++ b/app/src/main/java/org/concentus/CWRS.java
@@ -0,0 +1,290 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class CWRS {
+
+ /*Although derived separately, the pulse vector coding scheme is equivalent to
+a Pyramid Vector Quantizer \cite{Fis86}.
+Some additional notes about an early version appear at
+http://people.xiph.org/~tterribe/notes/cwrs.html, but the codebook ordering
+and the definitions of some terms have evolved since that was written.
+
+The conversion from a pulse vector to an integer index (encoding) and back
+(decoding) is governed by two related functions, V(N,K) and U(N,K).
+
+V(N,K) = the number of combinations, with replacement, of N items, taken K
+at a time, when a sign bit is added to each item taken at least once (i.e.,
+the number of N-dimensional unit pulse vectors with K pulses).
+One way to compute this is via
+V(N,K) = K>0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1,
+where choose() is the binomial function.
+A table of values for N<10 and K<10 looks like:
+V[10][10] = {
+{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{1, 2, 2, 2, 2, 2, 2, 2, 2, 2},
+{1, 4, 8, 12, 16, 20, 24, 28, 32, 36},
+{1, 6, 18, 38, 66, 102, 146, 198, 258, 326},
+{1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992},
+{1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290},
+{1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436},
+{1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598},
+{1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688},
+{1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146}
+};
+
+U(N,K) = the number of such combinations wherein N-1 objects are taken at
+most K-1 at a time.
+This is given by
+U(N,K) = sum(k=0...K-1,V(N-1,k))
+ = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0.
+The latter expression also makes clear that U(N,K) is half the number of such
+combinations wherein the first object is taken at least once.
+Although it may not be clear from either of these definitions, U(N,K) is the
+natural function to work with when enumerating the pulse vector codebooks,
+not V(N,K).
+U(N,K) is not well-defined for N=0, but with the extension
+U(0,K) = K>0 ? 0 : 1,
+the function becomes symmetric: U(N,K) = U(K,N), with a similar table:
+U[10][10] = {
+{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+{0, 1, 3, 5, 7, 9, 11, 13, 15, 17},
+{0, 1, 5, 13, 25, 41, 61, 85, 113, 145},
+{0, 1, 7, 25, 63, 129, 231, 377, 575, 833},
+{0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649},
+{0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073},
+{0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081},
+{0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545},
+{0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729}
+};
+
+With this extension, V(N,K) may be written in terms of U(N,K):
+V(N,K) = U(N,K) + U(N,K+1)
+for all N>=0, K>=0.
+Thus U(N,K+1) represents the number of combinations where the first element
+is positive or zero, and U(N,K) represents the number of combinations where
+it is negative.
+With a large enough table of U(N,K) values, we could write O(N) encoding
+and O(min(N*log(K),N+K)) decoding routines, but such a table would be
+prohibitively large for small embedded devices (K may be as large as 32767
+for small N, and N may be as large as 200).
+
+Both functions obey the same recurrence relation:
+V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1),
+U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1),
+for all N>0, K>0, with different initial conditions at N=0 or K=0.
+This allows us to construct a row of one of the tables above given the
+previous row or the next row.
+Thus we can derive O(NK) encoding and decoding routines with O(K) memory
+using only addition and subtraction.
+
+When encoding, we build up from the U(2,K) row and work our way forwards.
+When decoding, we need to start at the U(N,K) row and work our way backwards,
+which requires a means of computing U(N,K).
+U(N,K) may be computed from two previous values with the same N:
+U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2)
+for all N>1, and since U(N,K) is symmetric, a similar relation holds for two
+previous values with the same K:
+U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K)
+for all K>1.
+This allows us to construct an arbitrary row of the U(N,K) table by starting
+with the first two values, which are constants.
+This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K)
+multiplications.
+Similar relations can be derived for V(N,K), but are not used here.
+
+For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree
+polynomial for fixed N.
+The first few are
+U(1,K) = 1,
+U(2,K) = 2*K-1,
+U(3,K) = (2*K-2)*K+1,
+U(4,K) = (((4*K-6)*K+8)*K-3)/3,
+U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3,
+and
+V(1,K) = 2,
+V(2,K) = 4*K,
+V(3,K) = 4*K*K+2,
+V(4,K) = 8*(K*K+2)*K/3,
+V(5,K) = ((4*K*K+20)*K*K+6)/3,
+for all K>0.
+This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for
+small N (and indeed decoding is also O(N) for N<3).
+
+@ARTICLE{Fis86,
+author="Thomas R. Fischer",
+title="A Pyramid Vector Quantizer",
+journal="IEEE Transactions on Information Theory",
+volume="IT-32",
+number=4,
+pages="568--583",
+month=Jul,
+year=1986
+}*/
+
+ static final int[] CELT_PVQ_U_ROW
+ = {
+ 0, 176, 351, 525, 698, 870, 1041, 1131, 1178, 1207, 1226, 1240, 1248, 1254, 1257
+ };
+
+ /*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/
+ private static long CELT_PVQ_U(int _n, int _k) {
+ return CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[Inlines.IMIN(_n, _k)] + Inlines.IMAX(_n, _k)];
+ }
+
+
+ /*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N
+ with K pulses allocated to it.*/
+ private static long CELT_PVQ_V(int _n, int _k) {
+ return (CELT_PVQ_U(_n, _k) + CELT_PVQ_U(_n, (_k) + 1));
+ }
+
+ static long icwrs(int _n, int[] _y) {
+ long i;
+ int j;
+ int k;
+ Inlines.OpusAssert(_n >= 2);
+ j = _n - 1;
+ i = (_y[j] < 0) ? 1 : 0;
+ k = Inlines.abs(_y[j]);
+ do {
+ j--;
+ i += CELT_PVQ_U(_n - j, k);
+ k += Inlines.abs(_y[j]);
+ if (_y[j] < 0) {
+ i += CELT_PVQ_U(_n - j, k + 1);
+ }
+ } while (j > 0);
+ return i;
+ }
+
+ static void encode_pulses(int[] _y, int _n, int _k, EntropyCoder _enc) {
+ Inlines.OpusAssert(_k > 0);
+ _enc.enc_uint(icwrs(_n, _y), CELT_PVQ_V(_n, _k));
+ }
+
+ static int cwrsi(int _n, int _k, long _i, int[] _y) {
+ long p;
+ int s;
+ int k0;
+ short val;
+ int yy = 0;
+ int y_ptr = 0;
+ Inlines.OpusAssert(_k > 0);
+ Inlines.OpusAssert(_n > 1);
+
+ while (_n > 2) {
+ long q;
+ /*Lots of pulses case:*/
+ if (_k >= _n) {
+ int row;
+ row = CELT_PVQ_U_ROW[_n];
+ /*Are the pulses in this dimension negative?*/
+ p = CeltTables.CELT_PVQ_U_DATA[row + _k + 1];
+ s = 0 - (_i >= p ? 1 : 0);
+ _i = _i - Inlines.CapToUInt32(p & s);
+ /*Count how many pulses were placed in this dimension.*/
+ k0 = _k;
+ q = CeltTables.CELT_PVQ_U_DATA[row + _n];
+
+ if (q > _i) {
+ Inlines.OpusAssert(p > q);
+ _k = _n;
+
+ do {
+ p = CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[--_k] + _n];
+ } while (p > _i);
+ } else {
+ for (p = CeltTables.CELT_PVQ_U_DATA[row + _k]; p > _i; p = CeltTables.CELT_PVQ_U_DATA[row + _k]) {
+ _k--;
+ }
+ }
+
+ _i -= p;
+ val = (short) ((k0 - _k + s) ^ s);
+ _y[y_ptr++] = val;
+ yy = Inlines.MAC16_16(yy, val, val);
+ } /*Lots of dimensions case:*/ else {
+ /*Are there any pulses in this dimension at all?*/
+ p = CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[_k] + _n];
+ q = CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[_k + 1] + _n];
+ if (p <= _i && _i < q) {
+ _i -= p;
+ _y[y_ptr++] = 0;
+ } else {
+ /*Are the pulses in this dimension negative?*/
+ s = 0 - (_i >= q ? 1 : 0);
+ _i = _i - Inlines.CapToUInt32(q & s);
+ /*Count how many pulses were placed in this dimension.*/
+ k0 = _k;
+ do {
+ p = CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[--_k] + _n];
+ } while (p > _i);
+
+ _i -= p;
+ val = (short) ((k0 - _k + s) ^ s);
+ _y[y_ptr++] = val;
+ yy = Inlines.MAC16_16(yy, val, val);
+ }
+ }
+ _n--;
+ }
+
+ /*_n==2*/
+ p = (2L * _k + 1);
+ s = 0 - (_i >= p ? 1 : 0);
+ _i = _i - Inlines.CapToUInt32(p & s);
+ k0 = _k;
+ _k = (int) ((_i + 1) >> 1);
+ if (_k != 0) {
+ _i -= (2L * _k - 1);
+ }
+
+ val = (short) ((k0 - _k + s) ^ s);
+ _y[y_ptr++] = val;
+ yy = Inlines.MAC16_16(yy, val, val);
+ /*_n==1*/
+ s = -(int) _i;
+ val = (short) ((_k + s) ^ s);
+ _y[y_ptr] = val;
+ yy = Inlines.MAC16_16(yy, val, val);
+ return yy;
+ }
+
+ static int decode_pulses(int[] _y, int _n, int _k, EntropyCoder _dec) {
+ return cwrsi(_n, _k, _dec.dec_uint(CELT_PVQ_V(_n, _k)), _y);
+ }
+}
diff --git a/app/src/main/java/org/concentus/CeltCommon.java b/app/src/main/java/org/concentus/CeltCommon.java
new file mode 100644
index 0000000000..45426e7d4c
--- /dev/null
+++ b/app/src/main/java/org/concentus/CeltCommon.java
@@ -0,0 +1,1231 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class CeltCommon {
+
+ /* Table of 6*64/x, trained on real data to minimize the average error */
+ private static final short[] inv_table = {
+ 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,};
+
+ 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) {
+ /* The target rate in 8th bits per frame */
+ int target;
+ int coded_bins;
+ int coded_bands;
+ int tf_calibration;
+ int nbEBands;
+ short[] eBands;
+
+ nbEBands = mode.nbEBands;
+ eBands = mode.eBands;
+
+ coded_bands = lastCodedBands != 0 ? lastCodedBands : nbEBands;
+ coded_bins = eBands[coded_bands] << LM;
+ if (C == 2) {
+ coded_bins += eBands[Inlines.IMIN(intensity, coded_bands)] << LM;
+ }
+
+ target = base_target;
+ if (analysis.enabled && analysis.valid != 0 && analysis.activity < .4) {
+ target -= (int) ((coded_bins << EntropyCoder.BITRES) * (.4f - analysis.activity));
+ }
+
+ /* Stereo savings */
+ if (C == 2) {
+ int coded_stereo_bands;
+ int coded_stereo_dof;
+ int max_frac;
+ coded_stereo_bands = Inlines.IMIN(intensity, coded_bands);
+ coded_stereo_dof = (eBands[coded_stereo_bands] << LM) - coded_stereo_bands;
+ /* Maximum fraction of the bits we can save if the signal is mono. */
+ max_frac = Inlines.DIV32_16(Inlines.MULT16_16(((short) (0.5 + (0.8f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.8f, 15)*/, coded_stereo_dof), coded_bins);
+ stereo_saving = Inlines.MIN16(stereo_saving, ((short) (0.5 + (1.0f) * (((int) 1) << (8))))/*Inlines.QCONST16(1.0f, 8)*/);
+ /*printf("%d %d %d ", coded_stereo_dof, coded_bins, tot_boost);*/
+ target -= (int) Inlines.MIN32(Inlines.MULT16_32_Q15(max_frac, target),
+ Inlines.SHR32(Inlines.MULT16_16(stereo_saving - ((short) (0.5 + (0.1f) * (((int) 1) << (8))))/*Inlines.QCONST16(0.1f, 8)*/, (coded_stereo_dof << EntropyCoder.BITRES)), 8));
+ }
+ /* Boost the rate according to dynalloc (minus the dynalloc average for calibration). */
+ target += tot_boost - (16 << LM);
+ /* Apply transient boost, compensating for average boost. */
+ tf_calibration = variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE
+ ? ((short) (0.5 + (0.02f) * (((int) 1) << (14))))/*Inlines.QCONST16(0.02f, 14)*/ : ((short) (0.5 + (0.04f) * (((int) 1) << (14))))/*Inlines.QCONST16(0.04f, 14)*/;
+ target += (int) Inlines.SHL32(Inlines.MULT16_32_Q15(tf_estimate - tf_calibration, target), 1);
+
+ /* Apply tonality boost */
+ if (analysis.enabled && analysis.valid != 0 && lfe == 0) {
+ int tonal_target;
+ float tonal;
+
+ /* Tonality boost (compensating for the average). */
+ tonal = Inlines.MAX16(0, analysis.tonality - .15f) - 0.09f;
+ tonal_target = target + (int) ((coded_bins << EntropyCoder.BITRES) * 1.2f * tonal);
+ if (pitch_change != 0) {
+ tonal_target += (int) ((coded_bins << EntropyCoder.BITRES) * .8f);
+ }
+ target = tonal_target;
+ }
+
+ if (has_surround_mask != 0 && lfe == 0) {
+ int surround_target = target + (int) Inlines.SHR32(Inlines.MULT16_16(surround_masking, coded_bins << EntropyCoder.BITRES), CeltConstants.DB_SHIFT);
+ /*printf("%f %d %d %d %d %d %d ", surround_masking, coded_bins, st.end, st.intensity, surround_target, target, st.bitrate);*/
+ target = Inlines.IMAX(target / 4, surround_target);
+ }
+
+ {
+ int floor_depth;
+ int bins;
+ bins = eBands[nbEBands - 2] << LM;
+ /*floor_depth = Inlines.SHR32(Inlines.MULT16_16((C*bins<> 2);
+ target = Inlines.IMIN(target, floor_depth);
+ /*printf("%f %d\n", maxDepth, floor_depth);*/
+ }
+
+ if ((has_surround_mask == 0 || lfe != 0) && (constrained_vbr != 0 || bitrate < 64000)) {
+ int rate_factor;
+ rate_factor = Inlines.MAX16(0, (bitrate - 32000));
+ if (constrained_vbr != 0) {
+ rate_factor = Inlines.MIN16(rate_factor, ((short) (0.5 + (0.67f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.67f, 15)*/);
+ }
+ target = base_target + (int) Inlines.MULT16_32_Q15(rate_factor, target - base_target);
+ }
+
+ if (has_surround_mask == 0 && tf_estimate < ((short) (0.5 + (.2f) * (((int) 1) << (14))))/*Inlines.QCONST16(.2f, 14)*/) {
+ int amount;
+ int tvbr_factor;
+ amount = Inlines.MULT16_16_Q15(((short) (0.5 + (.0000031f) * (((int) 1) << (30))))/*Inlines.QCONST16(.0000031f, 30)*/, Inlines.IMAX(0, Inlines.IMIN(32000, 96000 - bitrate)));
+ tvbr_factor = Inlines.SHR32(Inlines.MULT16_16(temporal_vbr, amount), CeltConstants.DB_SHIFT);
+ target += (int) Inlines.MULT16_32_Q15(tvbr_factor, target);
+ }
+
+ /* Don't allow more than doubling the rate */
+ 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 i;
+ int[] tmp;
+ int mem0, mem1;
+ int is_transient = 0;
+ int mask_metric = 0;
+ int c;
+ int tf_max;
+ int len2;
+ tf_chan.Val = 0;
+ tmp = new int[len];
+
+ len2 = len / 2;
+ for (c = 0; c < C; c++) {
+ int mean;
+ int unmask = 0;
+ int norm;
+ int maxE;
+ mem0 = 0;
+ mem1 = 0;
+ /* High-pass filter: (1 - 2*z^-1 + z^-2) / (1 - z^-1 + .5*z^-2) */
+ for (i = 0; i < len; i++) {
+ int x, y;
+ x = Inlines.SHR32(input[c][i], CeltConstants.SIG_SHIFT);
+ 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));
+ /*printf("%f ", tmp[i]);*/
+ }
+ /*printf("\n");*/
+ /* First few samples are bad because we don't propagate the memory */
+ Arrays.MemSet(tmp, 0, 12);
+
+ /* Normalize tmp to max range */
+ {
+ 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);
+ }
+ }
+ }
+
+ mean = 0;
+ mem0 = 0;
+ /* Grouping by two to reduce complexity */
+ /* Forward pass to compute the post-echo threshold*/
+ 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;
+ maxE = 0;
+ /* Backward pass to compute the pre-echo threshold */
+ for (i = len2 - 1; i >= 0; i--) {
+ tmp[i] = (mem0 + Inlines.PSHR32(tmp[i] - mem0, 3));
+ mem0 = tmp[i];
+ maxE = Inlines.MAX16(maxE, (mem0));
+ }
+ /*for (i=0;i> 1)));
+ /* Inverse of the mean energy in Q15+6 */
+ norm = Inlines.SHL32((len2), 6 + 14) / Inlines.ADD32(CeltConstants.EPSILON, Inlines.SHR32(mean, 1));
+ /* Compute harmonic mean discarding the unreliable boundaries
+ The data is smooth, so we only take 1/4th of the samples */
+ unmask = 0;
+ for (i = 12; i < len2 - 5; i += 4) {
+ int id;
+ id = Inlines.MAX32(0, Inlines.MIN32(127, Inlines.MULT16_32_Q15((tmp[i] + CeltConstants.EPSILON), norm)));
+ /* Do not round to nearest */
+ unmask += inv_table[id];
+ }
+ /*printf("%d\n", unmask);*/
+ /* Normalize, compensate for the 1/4th of the sample and the factor of 6 in the inverse table */
+ unmask = 64 * unmask * 4 / (6 * (len2 - 17));
+ if (unmask > mask_metric) {
+ tf_chan.Val = c;
+ mask_metric = unmask;
+ }
+ }
+ is_transient = mask_metric > 200 ? 1 : 0;
+
+ /* Arbitrary metric for VBR boost */
+ tf_max = Inlines.MAX16(0, (Inlines.celt_sqrt(27 * mask_metric) - 42));
+ /* *tf_estimate = 1 + Inlines.MIN16(1, sqrt(Inlines.MAX16(0, tf_max-30))/20); */
+ tf_estimate.Val = (Inlines.celt_sqrt(Inlines.MAX32(0, Inlines.SHL32(Inlines.MULT16_16(((short) (0.5 + (0.0069f) * (((int) 1) << (14))))/*Inlines.QCONST16(0.0069f, 14)*/, Inlines.MIN16(163, tf_max)), 14) - ((int) (0.5 + (0.139f) * (((int) 1) << (28))))/*Inlines.QCONST32(0.139f, 28)*/)));
+ /*printf("%d %f\n", tf_max, mask_metric);*/
+
+ /*printf("%d %f %d\n", is_transient, (float)*tf_estimate, tf_max);*/
+ return is_transient;
+ }
+
+ /* Looks for sudden increases of energy to decide whether we need to patch
+ the transient decision */
+ static int patch_transient_decision(int[][] newE, int[][] oldE, int nbEBands,
+ int start, int end, int C) {
+ int i, c;
+ int mean_diff = 0;
+ int[] spread_old = new int[26];
+ /* Apply an aggressive (-6 dB/Bark) spreading function to the old frame to
+ avoid false detection caused by irrelevant bands */
+ 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] - ((short) (0.5 + (1.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/), 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] - ((short) (0.5 + (1.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/),
+ 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] - ((short) (0.5 + (1.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/));
+ }
+ /* Compute mean increase */
+ c = 0;
+ do {
+ for (i = Inlines.IMAX(2, start); i < end - 1; i++) {
+ int x1, x2;
+ x1 = Inlines.MAX16(0, newE[c][i]);
+ x2 = Inlines.MAX16(0, spread_old[i]);
+ mean_diff = Inlines.ADD32(mean_diff, (Inlines.MAX16(0, Inlines.SUB16(x1, x2))));
+ }
+ } while (++c < C);
+ mean_diff = Inlines.DIV32(mean_diff, C * (end - 1 - Inlines.IMAX(2, start)));
+ /*printf("%f %f %d\n", mean_diff, max_diff, count);*/
+ return (mean_diff > ((short) (0.5 + (1.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/) ? 1 : 0;
+ }
+
+ /**
+ * Apply window and compute the MDCT for all sub-frames and all channels in
+ * a frame
+ */
+ static void compute_mdcts(CeltMode mode, int shortBlocks, int[][] input,
+ int[][] output, int C, int CC, int LM, int upsample) {
+ int overlap = mode.overlap;
+ int N;
+ int B;
+ int shift;
+ int i, b, c;
+ if (shortBlocks != 0) {
+ B = shortBlocks;
+ N = mode.shortMdctSize;
+ shift = mode.maxLM;
+ } else {
+ B = 1;
+ N = mode.shortMdctSize << LM;
+ shift = mode.maxLM - LM;
+ }
+ c = 0;
+ do {
+ for (b = 0; b < B; b++) {
+ /* Interleaving the sub-frames while doing the MDCTs */
+ 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;
+ for (i = 0; i < bound; i++) {
+ output[c][i] *= 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;
+ int m;
+ int Nu;
+
+ coef0 = coef[0];
+ m = mem.Val;
+
+ /* Fast path for the normal 48kHz case and no clipping */
+ if (coef[1] == 0 && upsample == 1 && clip == 0) {
+ for (i = 0; i < N; i++) {
+ int x = pcmp[pcmp_ptr + (CC * i)];
+ /* Apply pre-emphasis */
+ inp[inp_ptr + i] = Inlines.SHL32(x, CeltConstants.SIG_SHIFT) - m;
+ m = Inlines.SHR32(Inlines.MULT16_16(coef0, x), 15 - CeltConstants.SIG_SHIFT);
+ }
+ mem.Val = m;
+ return;
+ }
+
+ 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;
+ x = (inp[inp_ptr + i]);
+ /* Apply pre-emphasis */
+ inp[inp_ptr + i] = Inlines.SHL32(x, CeltConstants.SIG_SHIFT) - m;
+ m = Inlines.SHR32(Inlines.MULT16_16(coef0, x), 15 - CeltConstants.SIG_SHIFT);
+ }
+
+ 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;
+ int m;
+ int Nu;
+
+ coef0 = coef[0];
+ m = mem.Val;
+
+ /* Fast path for the normal 48kHz case and no clipping */
+ if (coef[1] == 0 && upsample == 1 && clip == 0) {
+ for (i = 0; i < N; i++) {
+ int x;
+ x = pcmp[CC * i];
+ /* Apply pre-emphasis */
+ inp[inp_ptr + i] = Inlines.SHL32(x, CeltConstants.SIG_SHIFT) - m;
+ m = Inlines.SHR32(Inlines.MULT16_16(coef0, x), 15 - CeltConstants.SIG_SHIFT);
+ }
+ mem.Val = m;
+ return;
+ }
+
+ 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;
+ x = (inp[inp_ptr + i]);
+ /* Apply pre-emphasis */
+ inp[inp_ptr + i] = Inlines.SHL32(x, CeltConstants.SIG_SHIFT) - m;
+ m = Inlines.SHR32(Inlines.MULT16_16(coef0, x), 15 - CeltConstants.SIG_SHIFT);
+ }
+
+ mem.Val = m;
+ }
+
+ static int l1_metric(int[] tmp, int N, int LM, int bias) {
+ int i;
+ int L1;
+ L1 = 0;
+ for (i = 0; i < N; i++) {
+ L1 += Inlines.EXTEND32(Inlines.ABS32(tmp[i]));
+ }
+
+ /* When in doubt, prefer good freq resolution */
+ 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 i;
+ int[] metric;
+ int cost0;
+ int cost1;
+ int[] path0;
+ int[] path1;
+ int[] tmp;
+ int[] tmp_1;
+ int sel;
+ int[] selcost = new int[2];
+ int tf_select = 0;
+ int bias;
+
+ bias = Inlines.MULT16_16_Q14(((short) (0.5 + (.04f) * (((int) 1) << (15))))/*Inlines.QCONST16(.04f, 15)*/, Inlines.MAX16((short) (0 - ((short) (0.5 + (.25f) * (((int) 1) << (14))))/*Inlines.QCONST16(.25f, 14)*/), (((short) (0.5 + (.5f) * (((int) 1) << (14))))/*Inlines.QCONST16(.5f, 14)*/ - tf_estimate)));
+ /*printf("%f ", bias);*/
+
+ metric = new int[len];
+ tmp = new int[(m.eBands[len] - m.eBands[len - 1]) << LM];
+ tmp_1 = new int[(m.eBands[len] - m.eBands[len - 1]) << LM];
+ path0 = new int[len];
+ path1 = new int[len];
+
+ tf_sum.Val = 0;
+ for (i = 0; i < len; i++) {
+ int k, N;
+ int narrow;
+ int L1, best_L1;
+ int best_level = 0;
+ N = (m.eBands[i + 1] - m.eBands[i]) << LM;
+ /* band is too narrow to be split down to LM=-1 */
+ narrow = ((m.eBands[i + 1] - m.eBands[i]) == 1) ? 1 : 0;
+ System.arraycopy(X[tf_chan], (m.eBands[i] << LM), tmp, 0, N);
+ /* Just add the right channel if we're in stereo */
+ /*if (C==2)
+ for (j=0;j> LM, 1 << LM);
+ L1 = l1_metric(tmp_1, N, LM + 1, bias);
+ if (L1 < best_L1) {
+ best_L1 = L1;
+ best_level = -1;
+ }
+ }
+ /*printf ("%f ", L1);*/
+ for (k = 0; k < LM + (!(isTransient != 0 || narrow != 0) ? 1 : 0); k++) {
+ int B;
+
+ if (isTransient != 0) {
+ B = (LM - k - 1);
+ } else {
+ B = k + 1;
+ }
+
+ Bands.haar1ZeroOffset(tmp, N >> k, 1 << k);
+
+ L1 = l1_metric(tmp, N, B, bias);
+
+ if (L1 < best_L1) {
+ best_L1 = L1;
+ best_level = k + 1;
+ }
+ }
+ /*printf ("%d ", isTransient ? LM-best_level : best_level);*/
+ /* metric is in Q1 to be able to select the mid-point (-0.5) for narrower bands */
+ if (isTransient != 0) {
+ metric[i] = 2 * best_level;
+ } else {
+ metric[i] = -2 * best_level;
+ }
+ tf_sum.Val += (isTransient != 0 ? LM : 0) - metric[i] / 2;
+ /* For bands that can't be split to -1, set the metric to the half-way point to avoid
+ biasing the decision */
+ if (narrow != 0 && (metric[i] == 0 || metric[i] == -2 * LM)) {
+ metric[i] -= 1;
+ }
+ /*printf("%d ", metric[i]);*/
+ }
+ /*printf("\n");*/
+ /* Search for the optimal tf resolution, including tf_select */
+ tf_select = 0;
+ for (sel = 0; sel < 2; sel++) {
+ cost0 = 0;
+ cost1 = isTransient != 0 ? 0 : lambda;
+ for (i = 1; i < len; i++) {
+ int curr0, curr1;
+ 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]);
+ }
+ cost0 = Inlines.IMIN(cost0, cost1);
+ selcost[sel] = cost0;
+ }
+ /* For now, we're conservative and only allow tf_select=1 for transients.
+ * If tests confirm it's useful for non-transients, we could allow it. */
+ if (selcost[1] < selcost[0] && isTransient != 0) {
+ tf_select = 1;
+ }
+ cost0 = 0;
+ cost1 = isTransient != 0 ? 0 : lambda;
+ /* Viterbi forward pass */
+ for (i = 1; i < len; i++) {
+ int curr0, curr1;
+ int from0, from1;
+
+ from0 = cost0;
+ 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;
+ /* Viterbi backward pass to check the decisions */
+ for (i = len - 2; i >= 0; i--) {
+ if (tf_res[i + 1] == 1) {
+ tf_res[i] = path1[i + 1];
+ } else {
+ tf_res[i] = path0[i + 1];
+ }
+ }
+ /*printf("%d %f\n", *tf_sum, tf_estimate);*/
+
+ return tf_select;
+ }
+
+ static void tf_encode(int start, int end, int isTransient, int[] tf_res, int LM, int tf_select, EntropyCoder enc) {
+ int curr, i;
+ int tf_select_rsv;
+ int tf_changed;
+ int logp;
+ int budget;
+ int tell;
+ budget = enc.storage * 8;
+ tell = enc.tell();
+ logp = isTransient != 0 ? 2 : 4;
+ /* Reserve space to code the tf_select decision. */
+ tf_select_rsv = (LM > 0 && tell + logp + 1 <= budget) ? 1 : 0;
+ budget -= tf_select_rsv;
+ curr = tf_changed = 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;
+ }
+ /* Only code tf_select if it would actually make a difference. */
+ 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]];
+ }
+ /*for(i=0;i Inlines.MULT16_32_Q15((m.eBands[13] << (LM + 1)), sumLR)) ? 1 : 0;
+ }
+
+ static int median_of_5(int[] x, int x_ptr) {
+ int t0, t1, t2, t3, t4;
+ 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) {
+ // swap the pairs
+ int tmp = t3;
+ t3 = t0;
+ t0 = tmp;
+ tmp = t4;
+ t4 = t1;
+ t1 = tmp;
+ }
+ if (t2 > t1) {
+ if (t1 < t3) {
+ return Inlines.MIN16(t2, t3);
+ } else {
+ return Inlines.MIN16(t4, t1);
+ }
+ } else if (t2 < t3) {
+ return Inlines.MIN16(t1, t3);
+ } else {
+ return Inlines.MIN16(t2, t4);
+ }
+ }
+
+ static int median_of_3(int[] x, int x_ptr) {
+ int t0, t1, t2;
+ 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];
+ }
+ t2 = x[x_ptr + 2];
+ if (t1 < t2) {
+ return t1;
+ } else if (t0 < t2) {
+ return t2;
+ } else {
+ 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, c;
+ int tot_boost = 0;
+ int maxDepth;
+ int[][] follower = Arrays.InitTwoDimensionalArrayInt(2, nbEBands);
+ int[] noise_floor = new int[C * nbEBands]; // opt: partitioned array
+
+ Arrays.MemSet(offsets, 0, nbEBands);
+ /* Dynamic allocation code */
+ maxDepth = (0 - ((short) (0.5 + (31.9f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(31.9f, CeltConstants.DB_SHIFT)*/);
+ for (i = 0; i < end; i++) {
+ /* Noise floor must take into account eMeans, the depth, the width of the bands
+ and the preemphasis filter (approx. square of bark band ID) */
+ noise_floor[i] = (Inlines.MULT16_16(((short) (0.5 + (0.0625f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.0625f, CeltConstants.DB_SHIFT)*/, logN[i])
+ + ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/ + Inlines.SHL16((9 - lsb_depth), CeltConstants.DB_SHIFT) - Inlines.SHL16(CeltTables.eMeans[i], 6)
+ + Inlines.MULT16_16(((short) (0.5 + (0.0062f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.0062f, CeltConstants.DB_SHIFT)*/, (i + 5) * (i + 5)));
+ }
+ c = 0;
+ do {
+ for (i = 0; i < end; i++) {
+ maxDepth = Inlines.MAX16(maxDepth, (bandLogE[c][i] - noise_floor[i]));
+ }
+ } while (++c < C);
+ /* Make sure that dynamic allocation can't make us bust the budget */
+ if (effectiveBytes > 50 && LM >= 1 && lfe == 0) {
+ int last = 0;
+ c = 0;
+ do {
+ int offset;
+ int tmp;
+ int[] f = follower[c];
+ f[0] = bandLogE2[c][0];
+ for (i = 1; i < end; i++) {
+ /* The last band to be at least 3 dB higher than the previous one
+ is the last we'll consider. Otherwise, we run into problems on
+ bandlimited signals. */
+ if (bandLogE2[c][i] > bandLogE2[c][i - 1] + ((short) (0.5 + (0.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.5f, CeltConstants.DB_SHIFT)*/) {
+ last = i;
+ }
+ f[i] = Inlines.MIN16((f[i - 1] + ((short) (0.5 + (1.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.5f, CeltConstants.DB_SHIFT)*/), bandLogE2[c][i]);
+ }
+ for (i = last - 1; i >= 0; i--) {
+ f[i] = Inlines.MIN16(f[i], Inlines.MIN16((f[i + 1] + ((short) (0.5 + (2.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(2.0f, CeltConstants.DB_SHIFT)*/), bandLogE2[c][i]));
+ }
+
+ /* Combine with a median filter to avoid dynalloc triggering unnecessarily.
+ The "offset" value controls how conservative we are -- a higher offset
+ reduces the impact of the median filter and makes dynalloc use more bits. */
+ offset = ((short) (0.5 + (1.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/;
+ for (i = 2; i < end - 2; i++) {
+ f[i] = Inlines.MAX16(f[i], median_of_5(bandLogE2[c], i - 2) - offset);
+ }
+ tmp = median_of_3(bandLogE2[c], 0) - offset;
+ f[0] = Inlines.MAX16(f[0], tmp);
+ f[1] = Inlines.MAX16(f[1], tmp);
+ tmp = 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++) {
+ /* Consider 24 dB "cross-talk" */
+ follower[1][i] = Inlines.MAX16(follower[1][i], follower[0][i] - ((short) (0.5 + (4.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(4.0f, CeltConstants.DB_SHIFT)*/);
+ follower[0][i] = Inlines.MAX16(follower[0][i], follower[1][i] - ((short) (0.5 + (4.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(4.0f, CeltConstants.DB_SHIFT)*/);
+ 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]);
+ }
+ /* For non-transient CBR/CVBR frames, halve the dynalloc contribution */
+ 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 width;
+ int boost;
+ int boost_bits;
+
+ if (i < 8) {
+ follower[0][i] *= 2;
+ }
+ if (i >= 12) {
+ follower[0][i] = Inlines.HALF16(follower[0][i]);
+ }
+ follower[0][i] = Inlines.MIN16(follower[0][i], ((short) (0.5 + (4) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(4, CeltConstants.DB_SHIFT)*/);
+
+ width = C * (eBands[i + 1] - eBands[i]) << LM;
+ if (width < 6) {
+ boost = (int) Inlines.SHR32((follower[0][i]), CeltConstants.DB_SHIFT);
+ boost_bits = boost * width << EntropyCoder.BITRES;
+ } else if (width > 48) {
+ boost = (int) Inlines.SHR32((follower[0][i]) * 8, CeltConstants.DB_SHIFT);
+ boost_bits = (boost * width << EntropyCoder.BITRES) / 8;
+ } else {
+ boost = (int) Inlines.SHR32((follower[0][i]) * width / 6, CeltConstants.DB_SHIFT);
+ boost_bits = boost * 6 << EntropyCoder.BITRES;
+ }
+ /* For CBR and non-transient CVBR frames, limit dynalloc to 1/4 of the bits */
+ if ((vbr == 0 || (constrained_vbr != 0 && isTransient == 0))
+ && (tot_boost + boost_bits) >> EntropyCoder.BITRES >> 3 > effectiveBytes / 4) {
+ int cap = ((effectiveBytes / 4) << EntropyCoder.BITRES << 3);
+ offsets[i] = cap - tot_boost;
+ tot_boost = cap;
+ break;
+ } else {
+ 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) {
+ int c;
+ int Nd;
+ int apply_downsampling = 0;
+ int coef0;
+ int[] scratch = new int[N];
+ coef0 = coef[0];
+ Nd = N / downsample;
+ c = 0;
+ do {
+ int j;
+ int x_ptr;
+ int y;
+ int m = mem[c];
+ int[] x = input[c];
+ x_ptr = input_ptrs[c];
+ y = pcm_ptr + c;
+ if (downsample > 1) {
+ /* Shortcut for the standard (non-custom modes) case */
+ for (j = 0; j < N; j++) {
+ int tmp = x[x_ptr + j] + m + CeltConstants.VERY_SMALL;
+ m = Inlines.MULT16_32_Q15(coef0, tmp);
+ scratch[j] = tmp;
+ }
+ apply_downsampling = 1;
+ } else /* Shortcut for the standard (non-custom modes) case */ if (accum != 0) // should never hit this branch?
+ {
+ for (j = 0; j < N; j++) {
+ int tmp = x[x_ptr + j] + m + CeltConstants.VERY_SMALL;
+ 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++) {
+ int tmp = (x[x_ptr + j] + m + CeltConstants.VERY_SMALL); // Opus bug: This can overflow.
+ if (x[x_ptr + j] > 0 && m > 0 && tmp < 0) // This is a hack to saturate to INT_MAXVALUE
+ {
+ 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 != 0) {
+ /* Perform down-sampling */
+ {
+ 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 c, i;
+ int M;
+ int b;
+ int B;
+ int N, NB;
+ int shift;
+ int nbEBands;
+ int overlap;
+ int[] freq;
+
+ overlap = mode.overlap;
+ nbEBands = mode.nbEBands;
+ N = mode.shortMdctSize << LM;
+ freq = new int[N];
+ /**
+ * < Interleaved signal MDCTs
+ */
+ 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) {
+ /* Copying a mono streams to two channels */
+ int freq2;
+ Bands.denormalise_bands(mode, X[0], freq, 0, oldBandE, 0, start, effEnd, M,
+ downsample, silence);
+ /* Store a temporary copy in the output buffer because the IMDCT destroys its input. */
+ 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) {
+ /* Downmixing a stereo stream to mono */
+ int freq2 = out_syn_ptrs[0] + (overlap / 2);
+ Bands.denormalise_bands(mode, X[0], freq, 0, oldBandE, 0, start, effEnd, M,
+ downsample, silence);
+ /* Use the output buffer as temp array before downmixing. */
+ Bands.denormalise_bands(mode, X[1], out_syn[0], freq2, oldBandE, nbEBands, start, effEnd, M,
+ downsample, silence);
+ for (i = 0; i < N; i++) {
+ freq[i] = Inlines.HALF32(Inlines.ADD32(freq[i], out_syn[0][freq2 + i]));
+ }
+ for (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 {
+ /* Normal case (mono or stereo) */
+ c = 0;
+ do {
+ Bands.denormalise_bands(mode, X[c], freq, 0, oldBandE, c * nbEBands, start, effEnd, M,
+ downsample, silence);
+ for (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, curr, tf_select;
+ int tf_select_rsv;
+ int tf_changed;
+ int logp;
+ int budget;
+ int tell;
+
+ budget = dec.storage * 8;
+ tell = dec.tell();
+ logp = isTransient != 0 ? 2 : 4;
+ tf_select_rsv = (LM > 0 && tell + logp + 1 <= budget) ? 1 : 0;
+ budget -= tf_select_rsv;
+ tf_changed = curr = 0;
+ for (i = start; i < end; i++) {
+ if (tell + logp <= budget) {
+ curr ^= dec.dec_bit_logp(logp);
+ tell = dec.tell();
+ tf_changed |= curr;
+ }
+ tf_res[i] = curr;
+ logp = isTransient != 0 ? 4 : 5;
+ }
+ 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(1);
+ }
+ 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[CeltConstants.DECODE_BUFFER_SIZE >> 1];
+ Pitch.pitch_downsample(decode_mem, lp_pitch_buf,
+ CeltConstants.DECODE_BUFFER_SIZE, C);
+ Pitch.pitch_search(lp_pitch_buf, CeltConstants.PLC_PITCH_LAG_MAX >> 1, lp_pitch_buf,
+ CeltConstants.DECODE_BUFFER_SIZE - CeltConstants.PLC_PITCH_LAG_MAX,
+ CeltConstants.PLC_PITCH_LAG_MAX - CeltConstants.PLC_PITCH_LAG_MIN, pitch_index);
+ pitch_index.Val = CeltConstants.PLC_PITCH_LAG_MAX - 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;
+ break;
+ }
+ 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 x0, x1, x2, x3, x4;
+ int i;
+ int xpt = x_ptr - T;
+ x4 = x[xpt - 2];
+ x3 = x[xpt - 1];
+ x2 = x[xpt];
+ x1 = x[xpt + 1];
+ for (i = 0; i < N; i++) {
+ 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;
+ }
+ }
+
+ private static final short[][] gains = {
+ new short[]{((short) (0.5 + (0.3066406250f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.3066406250f, 15)*/, ((short) (0.5 + (0.2170410156f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.2170410156f, 15)*/, ((short) (0.5 + (0.1296386719f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.1296386719f, 15)*/},
+ new short[]{((short) (0.5 + (0.4638671875f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.4638671875f, 15)*/, ((short) (0.5 + (0.2680664062f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.2680664062f, 15)*/, ((short) (0.5 + (0.0f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.0f, 15)*/},
+ new short[]{((short) (0.5 + (0.7998046875f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.7998046875f, 15)*/, ((short) (0.5 + (0.1000976562f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.1000976562f, 15)*/, ((short) (0.5 + (0.0f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.0f, 15)*/}
+ };
+
+ 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;
+ /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */
+ int g00, g01, g02, g10, g11, g12;
+ int x0, x1, x2, x3, x4;
+
+ if (g0 == 0 && g1 == 0) {
+ /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+ if (x_ptr != y_ptr) {
+ //x.MemMoveTo(y, N);
+ }
+
+ return;
+ }
+ g00 = Inlines.MULT16_16_P15(g0, gains[tapset0][0]);
+ g01 = Inlines.MULT16_16_P15(g0, gains[tapset0][1]);
+ g02 = Inlines.MULT16_16_P15(g0, gains[tapset0][2]);
+ g10 = Inlines.MULT16_16_P15(g1, gains[tapset1][0]);
+ g11 = Inlines.MULT16_16_P15(g1, gains[tapset1][1]);
+ g12 = Inlines.MULT16_16_P15(g1, gains[tapset1][2]);
+ x1 = x[x_ptr - T1 + 1];
+ x2 = x[x_ptr - T1];
+ x3 = x[x_ptr - T1 - 1];
+ x4 = x[x_ptr - T1 - 2];
+ /* If the filter didn't change, we don't need the overlap */
+ if (g0 == g1 && T0 == T1 && tapset0 == tapset1) {
+ overlap = 0;
+ }
+ for (i = 0; i < overlap; i++) {
+ int f;
+ x0 = x[x_ptr + i - T1 + 2];
+ 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((short) (CeltConstants.Q15ONE - f), g00), x[x_ptr + i - T0])
+ + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((short) (CeltConstants.Q15ONE - f), g01), Inlines.ADD32(x[x_ptr + i - T0 + 1], x[x_ptr + i - T0 - 1]))
+ + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((short) (CeltConstants.Q15ONE - 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) {
+ /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+ if (x_ptr != y_ptr) {
+ //x.Point(overlap).MemMoveTo(y.Point(overlap), N - overlap);
+ }
+ return;
+ }
+
+ /* Compute the part with the constant filter. */
+ comb_filter_const(y, y_ptr + i, x, x_ptr + i, T1, N - i, g10, g11, g12);
+ }
+
+ private static final byte[][] tf_select_table = {
+ new byte[]{0, -1, 0, -1, 0, -1, 0, -1},
+ new byte[]{0, -1, 0, -2, 1, 0, 1, -1},
+ new byte[]{0, -2, 0, -3, 2, 0, 1, -1},
+ new byte[]{0, -2, 0, -3, 3, 0, 1, -1},};
+
+ static void init_caps(CeltMode m, int[] cap, int LM, int C) {
+ int i;
+ for (i = 0; i < m.nbEBands; i++) {
+ int N;
+ 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;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/CeltConstants.java b/app/src/main/java/org/concentus/CeltConstants.java
new file mode 100644
index 0000000000..38b3022d67
--- /dev/null
+++ b/app/src/main/java/org/concentus/CeltConstants.java
@@ -0,0 +1,90 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class CeltConstants {
+
+ public static final int Q15ONE = 32767;
+
+ public static final float CELT_SIG_SCALE = 32768.0f;
+
+ public static final int SIG_SHIFT = 12;
+
+ public static final int NORM_SCALING = 16384;
+
+ public static final int DB_SHIFT = 10;
+
+ public static final int EPSILON = 1;
+ public static final int VERY_SMALL = 0;
+ public static final short VERY_LARGE16 = ((short) 32767);
+ public static final short Q15_ONE = ((short) 32767);
+
+ public static final int COMBFILTER_MAXPERIOD = 1024;
+ public static final int COMBFILTER_MINPERIOD = 15;
+
+ // from opus_decode.c
+ public static final int DECODE_BUFFER_SIZE = 2048;
+
+ // from modes.c
+ /* Alternate tuning (partially derived from Vorbis) */
+ public static final int BITALLOC_SIZE = 11;
+ public static final int MAX_PERIOD = 1024;
+
+ // from static_modes_float.h
+ public static final int TOTAL_MODES = 1;
+
+ // from rate.h
+ public static final int MAX_PSEUDO = 40;
+ public static final int LOG_MAX_PSEUDO = 6;
+
+ public static final int CELT_MAX_PULSES = 128;
+
+ public static final int MAX_FINE_BITS = 8;
+
+ public static final int FINE_OFFSET = 21;
+ public static final int QTHETA_OFFSET = 4;
+ public static final int QTHETA_OFFSET_TWOPHASE = 16;
+
+ /* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save
+CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The
+current value corresponds to a pitch of 66.67 Hz. */
+ public static final int PLC_PITCH_LAG_MAX = 720;
+
+ /* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a
+ pitch of 480 Hz. */
+ public static final int PLC_PITCH_LAG_MIN = 100;
+
+ public static final int LPC_ORDER = 24;
+}
diff --git a/app/src/main/java/org/concentus/CeltDecoder.java b/app/src/main/java/org/concentus/CeltDecoder.java
new file mode 100644
index 0000000000..e6dad5f7f3
--- /dev/null
+++ b/app/src/main/java/org/concentus/CeltDecoder.java
@@ -0,0 +1,830 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+///
+/// Decoder state
+///
+class CeltDecoder {
+
+ CeltMode mode = null;
+ int overlap = 0;
+ int channels = 0;
+ int stream_channels = 0;
+
+ int downsample = 0;
+ int start = 0;
+ int end = 0;
+ int signalling = 0;
+
+ /* Everything beyond this point gets cleared on a reset */
+ int rng = 0;
+ int error = 0;
+ int last_pitch_index = 0;
+ int loss_count = 0;
+ int postfilter_period = 0;
+ int postfilter_period_old = 0;
+ int postfilter_gain = 0;
+ int postfilter_gain_old = 0;
+ int postfilter_tapset = 0;
+ int postfilter_tapset_old = 0;
+
+ final int[] preemph_memD = new int[2];
+
+ ///
+ /// Scratch space used by the decoder. It is actually a variable-sized
+ /// field that resulted in a variable-sized struct. There are 6 distinct regions inside.
+ /// I have laid them out into separate variables here,
+ /// but these were the original definitions:
+ /// val32 decode_mem[], Size = channels*(DECODE_BUFFER_SIZE+mode.overlap)
+ /// val16 lpc[], Size = channels*LPC_ORDER
+ /// val16 oldEBands[], Size = 2*mode.nbEBands
+ /// val16 oldLogE[], Size = 2*mode.nbEBands
+ /// val16 oldLogE2[], Size = 2*mode.nbEBands
+ /// val16 backgroundLogE[], Size = 2*mode.nbEBands
+ ///
+ int[][] decode_mem = null;
+ int[][] lpc = null; // Porting note: Split two-part array into separate arrays (one per channel)
+ int[] oldEBands = null;
+ int[] oldLogE = null;
+ int[] oldLogE2 = null;
+ int[] backgroundLogE = null;
+
+ private void Reset() {
+ mode = null;
+ overlap = 0;
+ channels = 0;
+ stream_channels = 0;
+ downsample = 0;
+ start = 0;
+ end = 0;
+ signalling = 0;
+ PartialReset();
+ }
+
+ private void PartialReset() {
+ rng = 0;
+ error = 0;
+ last_pitch_index = 0;
+ loss_count = 0;
+ postfilter_period = 0;
+ postfilter_period_old = 0;
+ postfilter_gain = 0;
+ postfilter_gain_old = 0;
+ postfilter_tapset = 0;
+ postfilter_tapset_old = 0;
+ Arrays.MemSet(preemph_memD, 0, 2);
+ decode_mem = null;
+ lpc = null;
+ oldEBands = null;
+ oldLogE = null;
+ oldLogE2 = null;
+ backgroundLogE = null;
+ }
+
+ void ResetState() {
+ int i;
+
+ this.PartialReset();
+
+ // We have to reconstitute the dynamic buffers here. fixme: this could be better implemented
+ this.decode_mem = new int[this.channels][];
+ this.lpc = new int[this.channels][];
+ for (int c = 0; c < this.channels; c++) {
+ this.decode_mem[c] = new int[CeltConstants.DECODE_BUFFER_SIZE + this.mode.overlap];
+ this.lpc[c] = new int[CeltConstants.LPC_ORDER];
+ }
+ this.oldEBands = new int[2 * this.mode.nbEBands];
+ this.oldLogE = new int[2 * this.mode.nbEBands];
+ this.oldLogE2 = new int[2 * this.mode.nbEBands];
+ this.backgroundLogE = new int[2 * this.mode.nbEBands];
+
+ for (i = 0; i < 2 * this.mode.nbEBands; i++) {
+ this.oldLogE[i] = this.oldLogE2[i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ }
+
+ int celt_decoder_init(int sampling_rate, int channels) {
+ int ret;
+ ret = this.opus_custom_decoder_init(CeltMode.mode48000_960_120, channels);
+ if (ret != OpusError.OPUS_OK) {
+ return ret;
+ }
+ this.downsample = CeltCommon.resampling_factor(sampling_rate);
+ if (this.downsample == 0) {
+ return OpusError.OPUS_BAD_ARG;
+ } else {
+ return OpusError.OPUS_OK;
+ }
+ }
+
+ private int opus_custom_decoder_init(CeltMode mode, int channels) {
+ if (channels < 0 || channels > 2) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ if (this == null) {
+ return OpusError.OPUS_ALLOC_FAIL;
+ }
+
+ this.Reset();
+
+ this.mode = mode;
+ this.overlap = mode.overlap;
+ this.stream_channels = this.channels = channels;
+
+ this.downsample = 1;
+ this.start = 0;
+ this.end = this.mode.effEBands;
+ this.signalling = 1;
+
+ this.loss_count = 0;
+
+ //this.decode_mem = new int[channels * (CeltConstants.DECODE_BUFFER_SIZE + mode.overlap));
+ //this.lpc = new int[channels * CeltConstants.LPC_ORDER);
+ //this.oldEBands = new int[2 * mode.nbEBands);
+ //this.oldLogE = new int[2 * mode.nbEBands);
+ //this.oldLogE2 = new int[2 * mode.nbEBands);
+ //this.backgroundLogE = new int[2 * mode.nbEBands);
+ this.ResetState();
+
+ return OpusError.OPUS_OK;
+ }
+
+ void celt_decode_lost(int N, int LM) {
+ int c;
+ int i;
+ int C = this.channels;
+ int[][] out_syn = new int[2][];
+ int[] out_syn_ptrs = new int[2];
+ CeltMode mode;
+ int nbEBands;
+ int overlap;
+ int noise_based;
+ short[] eBands;
+
+ mode = this.mode;
+ nbEBands = mode.nbEBands;
+ overlap = mode.overlap;
+ eBands = mode.eBands;
+
+ c = 0;
+ do {
+ out_syn[c] = this.decode_mem[c];
+ out_syn_ptrs[c] = CeltConstants.DECODE_BUFFER_SIZE - N;
+ } while (++c < C);
+
+ noise_based = (loss_count >= 5 || start != 0) ? 1 : 0;
+ if (noise_based != 0) {
+ /* Noise-based PLC/CNG */
+ int[][] X;
+ int seed;
+ int end;
+ int effEnd;
+ int decay;
+ end = this.end;
+ effEnd = Inlines.IMAX(start, Inlines.IMIN(end, mode.effEBands));
+
+ X = Arrays.InitTwoDimensionalArrayInt(C, N);
+ /**
+ * < Interleaved normalised MDCTs
+ */
+
+ /* Energy decay */
+ decay = loss_count == 0 ? ((short) (0.5 + (1.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.5f, CeltConstants.DB_SHIFT)*/ : ((short) (0.5 + (0.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.5f, CeltConstants.DB_SHIFT)*/;
+ c = 0;
+ do {
+ for (i = start; i < end; i++) {
+ this.oldEBands[c * nbEBands + i] = Inlines.MAX16(backgroundLogE[c * nbEBands + i], this.oldEBands[c * nbEBands + i] - decay);
+ }
+ } while (++c < C);
+ seed = this.rng;
+ for (c = 0; c < C; c++) {
+ for (i = start; i < effEnd; i++) {
+ int j;
+ int boffs;
+ int blen;
+ boffs = (eBands[i] << LM);
+ blen = (eBands[i + 1] - eBands[i]) << LM;
+ for (j = 0; j < blen; j++) {
+ seed = Bands.celt_lcg_rand(seed);
+ X[c][boffs + j] = (((int) seed) >> 20);
+ }
+
+ VQ.renormalise_vector(X[c], 0, blen, CeltConstants.Q15ONE);
+ }
+ }
+ this.rng = seed;
+
+ c = 0;
+ do {
+ Arrays.MemMove(this.decode_mem[c], N, 0, CeltConstants.DECODE_BUFFER_SIZE - N + (overlap >> 1));
+ } while (++c < C);
+
+ CeltCommon.celt_synthesis(mode, X, out_syn, out_syn_ptrs, this.oldEBands, start, effEnd, C, C, 0, LM, this.downsample, 0);
+ } else {
+ /* Pitch-based PLC */
+ int[] window;
+ int fade = CeltConstants.Q15ONE;
+ int pitch_index;
+ int[] etmp;
+ int[] exc;
+
+ if (loss_count == 0) {
+ this.last_pitch_index = pitch_index = CeltCommon.celt_plc_pitch_search(this.decode_mem, C);
+ } else {
+ pitch_index = this.last_pitch_index;
+ fade = ((short) (0.5 + (.8f) * (((int) 1) << (15))))/*Inlines.QCONST16(.8f, 15)*/;
+ }
+
+ etmp = new int[overlap];
+ exc = new int[CeltConstants.MAX_PERIOD];
+ window = mode.window;
+ c = 0;
+ do {
+ int decay;
+ int attenuation;
+ int S1 = 0;
+ int[] buf;
+ int extrapolation_offset;
+ int extrapolation_len;
+ int exc_length;
+ int j;
+
+ buf = this.decode_mem[c];
+ for (i = 0; i < CeltConstants.MAX_PERIOD; i++) {
+ exc[i] = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - CeltConstants.MAX_PERIOD + i], CeltConstants.SIG_SHIFT);
+ }
+
+ if (loss_count == 0) {
+ int[] ac = new int[CeltConstants.LPC_ORDER + 1];
+ /* Compute LPC coefficients for the last MAX_PERIOD samples before
+ the first loss so we can work in the excitation-filter domain. */
+ Autocorrelation._celt_autocorr(exc, ac, window, overlap,
+ CeltConstants.LPC_ORDER, CeltConstants.MAX_PERIOD);
+ /* Add a noise floor of -40 dB. */
+ ac[0] += Inlines.SHR32(ac[0], 13);
+ /* Use lag windowing to stabilize the Levinson-Durbin recursion. */
+ for (i = 1; i <= CeltConstants.LPC_ORDER; i++) {
+ /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+ ac[i] -= Inlines.MULT16_32_Q15(2 * i * i, ac[i]);
+ }
+ CeltLPC.celt_lpc(this.lpc[c], ac, CeltConstants.LPC_ORDER);
+ }
+ /* We want the excitation for 2 pitch periods in order to look for a
+ decaying signal, but we can't get more than MAX_PERIOD. */
+ exc_length = Inlines.IMIN(2 * pitch_index, CeltConstants.MAX_PERIOD);
+ /* Initialize the LPC history with the samples just before the start
+ of the region for which we're computing the excitation. */
+ {
+ int[] lpc_mem = new int[CeltConstants.LPC_ORDER];
+ for (i = 0; i < CeltConstants.LPC_ORDER; i++) {
+ lpc_mem[i]
+ = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - exc_length - 1 - i], CeltConstants.SIG_SHIFT);
+ }
+
+ /* Compute the excitation for exc_length samples before the loss. */
+ Kernels.celt_fir(exc, (CeltConstants.MAX_PERIOD - exc_length), this.lpc[c], 0,
+ exc, (CeltConstants.MAX_PERIOD - exc_length), exc_length, CeltConstants.LPC_ORDER, lpc_mem);
+ }
+
+ /* Check if the waveform is decaying, and if so how fast.
+ We do this to avoid adding energy when concealing in a segment
+ with decaying energy. */
+ {
+ int E1 = 1, E2 = 1;
+ int decay_length;
+ int shift = Inlines.IMAX(0, 2 * Inlines.celt_zlog2(Inlines.celt_maxabs16(exc, (CeltConstants.MAX_PERIOD - exc_length), exc_length)) - 20);
+ decay_length = exc_length >> 1;
+ for (i = 0; i < decay_length; i++) {
+ int e;
+ e = exc[CeltConstants.MAX_PERIOD - decay_length + i];
+ E1 += Inlines.SHR32(Inlines.MULT16_16(e, e), shift);
+ e = exc[CeltConstants.MAX_PERIOD - 2 * decay_length + i];
+ E2 += Inlines.SHR32(Inlines.MULT16_16(e, e), shift);
+ }
+ E1 = Inlines.MIN32(E1, E2);
+ decay = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(E1, 1), E2));
+ }
+
+ /* Move the decoder memory one frame to the left to give us room to
+ add the data for the new frame. We ignore the overlap that extends
+ past the end of the buffer, because we aren't going to use it. */
+ Arrays.MemMove(buf, N, 0, CeltConstants.DECODE_BUFFER_SIZE - N);
+
+ /* Extrapolate from the end of the excitation with a period of
+ "pitch_index", scaling down each period by an additional factor of
+ "decay". */
+ extrapolation_offset = CeltConstants.MAX_PERIOD - pitch_index;
+ /* We need to extrapolate enough samples to cover a complete MDCT
+ window (including overlap/2 samples on both sides). */
+ extrapolation_len = N + overlap;
+ /* We also apply fading if this is not the first loss. */
+ attenuation = Inlines.MULT16_16_Q15(fade, decay);
+ for (i = j = 0; i < extrapolation_len; i++, j++) {
+ int tmp;
+ if (j >= pitch_index) {
+ j -= pitch_index;
+ attenuation = Inlines.MULT16_16_Q15(attenuation, decay);
+ }
+ buf[CeltConstants.DECODE_BUFFER_SIZE - N + i]
+ = Inlines.SHL32((Inlines.MULT16_16_Q15(attenuation,
+ exc[extrapolation_offset + j])), CeltConstants.SIG_SHIFT);
+ /* Compute the energy of the previously decoded signal whose
+ excitation we're copying. */
+ tmp = Inlines.ROUND16(
+ buf[CeltConstants.DECODE_BUFFER_SIZE - CeltConstants.MAX_PERIOD - N + extrapolation_offset + j],
+ CeltConstants.SIG_SHIFT);
+ S1 += Inlines.SHR32(Inlines.MULT16_16(tmp, tmp), 8);
+ }
+
+ {
+ int[] lpc_mem = new int[CeltConstants.LPC_ORDER];
+ /* Copy the last decoded samples (prior to the overlap region) to
+ synthesis filter memory so we can have a continuous signal. */
+ for (i = 0; i < CeltConstants.LPC_ORDER; i++) {
+ lpc_mem[i] = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - N - 1 - i], CeltConstants.SIG_SHIFT);
+ }
+ /* Apply the synthesis filter to convert the excitation back into
+ the signal domain. */
+ CeltLPC.celt_iir(buf, CeltConstants.DECODE_BUFFER_SIZE - N, this.lpc[c],
+ buf, CeltConstants.DECODE_BUFFER_SIZE - N, extrapolation_len, CeltConstants.LPC_ORDER,
+ lpc_mem);
+ }
+
+ /* Check if the synthesis energy is higher than expected, which can
+ happen with the signal changes during our window. If so,
+ attenuate. */
+ {
+ int S2 = 0;
+ for (i = 0; i < extrapolation_len; i++) {
+ int tmp = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - N + i], CeltConstants.SIG_SHIFT);
+ S2 += Inlines.SHR32(Inlines.MULT16_16(tmp, tmp), 8);
+ }
+ /* This checks for an "explosion" in the synthesis. */
+ if (!(S1 > Inlines.SHR32(S2, 2))) {
+ for (i = 0; i < extrapolation_len; i++) {
+ buf[CeltConstants.DECODE_BUFFER_SIZE - N + i] = 0;
+ }
+ } else if (S1 < S2) {
+ int ratio = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(S1, 1) + 1, S2 + 1));
+ for (i = 0; i < overlap; i++) {
+ int tmp_g = CeltConstants.Q15ONE
+ - Inlines.MULT16_16_Q15(window[i], CeltConstants.Q15ONE - ratio);
+ buf[CeltConstants.DECODE_BUFFER_SIZE - N + i]
+ = Inlines.MULT16_32_Q15(tmp_g, buf[CeltConstants.DECODE_BUFFER_SIZE - N + i]);
+ }
+ for (i = overlap; i < extrapolation_len; i++) {
+ buf[CeltConstants.DECODE_BUFFER_SIZE - N + i]
+ = Inlines.MULT16_32_Q15(ratio, buf[CeltConstants.DECODE_BUFFER_SIZE - N + i]);
+ }
+ }
+ }
+
+ /* Apply the pre-filter to the MDCT overlap for the next frame because
+ the post-filter will be re-applied in the decoder after the MDCT
+ overlap. */
+ CeltCommon.comb_filter(etmp, 0, buf, CeltConstants.DECODE_BUFFER_SIZE,
+ this.postfilter_period, this.postfilter_period, overlap,
+ -this.postfilter_gain, -this.postfilter_gain,
+ this.postfilter_tapset, this.postfilter_tapset, null, 0);
+
+ /* Simulate TDAC on the concealed audio so that it blends with the
+ MDCT of the next frame. */
+ for (i = 0; i < overlap / 2; i++) {
+ buf[CeltConstants.DECODE_BUFFER_SIZE + i]
+ = Inlines.MULT16_32_Q15(window[i], etmp[overlap - 1 - i])
+ + Inlines.MULT16_32_Q15(window[overlap - i - 1], etmp[i]);
+ }
+ } while (++c < C);
+ }
+
+ this.loss_count = loss_count + 1;
+ }
+
+ int celt_decode_with_ec(byte[] data, int data_ptr,
+ int len, short[] pcm, int pcm_ptr, int frame_size, EntropyCoder dec, int accum) {
+ int c, i, N;
+ int spread_decision;
+ int bits;
+ int[][] X;
+ int[] fine_quant;
+ int[] pulses;
+ int[] cap;
+ int[] offsets;
+ int[] fine_priority;
+ int[] tf_res;
+ short[] collapse_masks;
+ int[][] out_syn = new int[2][];
+ int[] out_syn_ptrs = new int[2];
+ int[] oldBandE, oldLogE, oldLogE2, backgroundLogE;
+
+ int shortBlocks;
+ int isTransient;
+ int intra_ener;
+ int CC = this.channels;
+ int LM, M;
+ int start;
+ int end;
+ int effEnd;
+ int codedBands;
+ int alloc_trim;
+ int postfilter_pitch;
+ int postfilter_gain;
+ int intensity = 0;
+ int dual_stereo = 0;
+ int total_bits;
+ int balance;
+ int tell;
+ int dynalloc_logp;
+ int postfilter_tapset;
+ int anti_collapse_rsv;
+ int anti_collapse_on = 0;
+ int silence;
+ int C = this.stream_channels;
+ CeltMode mode; // porting note: pointer
+ int nbEBands;
+ int overlap;
+ short[] eBands;
+
+ mode = this.mode;
+ nbEBands = mode.nbEBands;
+ overlap = mode.overlap;
+ eBands = mode.eBands;
+ start = this.start;
+ end = this.end;
+ frame_size *= this.downsample;
+
+ oldBandE = this.oldEBands;
+ oldLogE = this.oldLogE;
+ oldLogE2 = this.oldLogE2;
+ backgroundLogE = this.backgroundLogE;
+
+ {
+ for (LM = 0; LM <= mode.maxLM; LM++) {
+ if (mode.shortMdctSize << LM == frame_size) {
+ break;
+ }
+ }
+ if (LM > mode.maxLM) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ }
+ M = 1 << LM;
+
+ if (len < 0 || len > 1275 || pcm == null) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ N = M * mode.shortMdctSize;
+ c = 0;
+ do {
+ out_syn[c] = this.decode_mem[c];
+ out_syn_ptrs[c] = CeltConstants.DECODE_BUFFER_SIZE - N;
+ } while (++c < CC);
+
+ effEnd = end;
+ if (effEnd > mode.effEBands) {
+ effEnd = mode.effEBands;
+ }
+
+ if (data == null || len <= 1) {
+ this.celt_decode_lost(N, LM);
+ CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum);
+
+ return frame_size / this.downsample;
+ }
+
+ if (dec == null) {
+ // If no entropy decoder was passed into this function, we need to create
+ // a new one here for local use only. It only exists in this function scope.
+ dec = new EntropyCoder();
+ dec.dec_init(data, data_ptr, len);
+ }
+
+ if (C == 1) {
+ for (i = 0; i < nbEBands; i++) {
+ oldBandE[i] = Inlines.MAX16(oldBandE[i], oldBandE[nbEBands + i]);
+ }
+ }
+
+ total_bits = len * 8;
+ tell = dec.tell();
+
+ if (tell >= total_bits) {
+ silence = 1;
+ } else if (tell == 1) {
+ silence = dec.dec_bit_logp(15);
+ } else {
+ silence = 0;
+ }
+
+ if (silence != 0) {
+ /* Pretend we've read all the remaining bits */
+ tell = len * 8;
+ dec.nbits_total += tell - dec.tell();
+ }
+
+ postfilter_gain = 0;
+ postfilter_pitch = 0;
+ postfilter_tapset = 0;
+ if (start == 0 && tell + 16 <= total_bits) {
+ if (dec.dec_bit_logp(1) != 0) {
+ int qg, octave;
+ octave = (int) dec.dec_uint(6);
+ postfilter_pitch = (16 << octave) + dec.dec_bits(4 + octave) - 1;
+ qg = dec.dec_bits(3);
+ if (dec.tell() + 2 <= total_bits) {
+ postfilter_tapset = dec.dec_icdf(CeltTables.tapset_icdf, 2);
+ }
+ postfilter_gain = ((short) (0.5 + (.09375f) * ((1) << (15))))/*Inlines.QCONST16(.09375f, 15)*/ * (qg + 1);
+ }
+ tell = dec.tell();
+ }
+
+ if (LM > 0 && tell + 3 <= total_bits) {
+ isTransient = dec.dec_bit_logp(3);
+ tell = dec.tell();
+ } else {
+ isTransient = 0;
+ }
+
+ if (isTransient != 0) {
+ shortBlocks = M;
+ } else {
+ shortBlocks = 0;
+ }
+
+ /* Decode the global flags (first symbols in the stream) */
+ intra_ener = tell + 3 <= total_bits ? dec.dec_bit_logp(3) : 0;
+ /* Get band energies */
+ QuantizeBands.unquant_coarse_energy(mode, start, end, oldBandE,
+ intra_ener, dec, C, LM);
+
+ tf_res = new int[nbEBands];
+ CeltCommon.tf_decode(start, end, isTransient, tf_res, LM, dec);
+
+ tell = dec.tell();
+ spread_decision = Spread.SPREAD_NORMAL;
+ if (tell + 4 <= total_bits) {
+ spread_decision = dec.dec_icdf(CeltTables.spread_icdf, 5);
+ }
+
+ cap = new int[nbEBands];
+
+ CeltCommon.init_caps(mode, cap, LM, C);
+
+ offsets = new int[nbEBands];
+
+ dynalloc_logp = 6;
+ total_bits <<= EntropyCoder.BITRES;
+ tell = dec.tell_frac();
+ for (i = start; i < end; i++) {
+ int width, quanta;
+ int dynalloc_loop_logp;
+ int boost;
+ width = C * (eBands[i + 1] - eBands[i]) << LM;
+ /* quanta is 6 bits, but no more than 1 bit/sample
+ and no less than 1/8 bit/sample */
+ quanta = Inlines.IMIN(width << EntropyCoder.BITRES, Inlines.IMAX(6 << EntropyCoder.BITRES, width));
+ dynalloc_loop_logp = dynalloc_logp;
+ boost = 0;
+ while (tell + (dynalloc_loop_logp << EntropyCoder.BITRES) < total_bits && boost < cap[i]) {
+ int flag;
+ flag = dec.dec_bit_logp(dynalloc_loop_logp);
+ tell = dec.tell_frac();
+ if (flag == 0) {
+ break;
+ }
+ boost += quanta;
+ total_bits -= quanta;
+ dynalloc_loop_logp = 1;
+ }
+ offsets[i] = boost;
+ /* Making dynalloc more likely */
+ if (boost > 0) {
+ dynalloc_logp = Inlines.IMAX(2, dynalloc_logp - 1);
+ }
+ }
+
+ fine_quant = new int[nbEBands];
+ alloc_trim = tell + (6 << EntropyCoder.BITRES) <= total_bits
+ ? dec.dec_icdf(CeltTables.trim_icdf, 7) : 5;
+
+ bits = ((len * 8) << EntropyCoder.BITRES) - dec.tell_frac() - 1;
+ anti_collapse_rsv = isTransient != 0 && LM >= 2 && bits >= ((LM + 2) << EntropyCoder.BITRES) ? (1 << EntropyCoder.BITRES) : 0;
+ bits -= anti_collapse_rsv;
+
+ pulses = new int[nbEBands];
+ fine_priority = new int[nbEBands];
+
+ BoxedValueInt boxed_intensity = new BoxedValueInt(intensity);
+ BoxedValueInt boxed_dual_stereo = new BoxedValueInt(dual_stereo);
+ BoxedValueInt boxed_balance = new BoxedValueInt(0);
+ codedBands = Rate.compute_allocation(mode, start, end, offsets, cap,
+ alloc_trim, boxed_intensity, boxed_dual_stereo, bits, boxed_balance, pulses,
+ fine_quant, fine_priority, C, LM, dec, 0, 0, 0);
+ intensity = boxed_intensity.Val;
+ dual_stereo = boxed_dual_stereo.Val;
+ balance = boxed_balance.Val;
+
+ QuantizeBands.unquant_fine_energy(mode, start, end, oldBandE, fine_quant, dec, C);
+
+ c = 0;
+ do {
+ Arrays.MemMove(decode_mem[c], N, 0, CeltConstants.DECODE_BUFFER_SIZE - N + overlap / 2);
+ } while (++c < CC);
+
+ /* Decode fixed codebook */
+ collapse_masks = new short[C * nbEBands];
+
+ X = Arrays.InitTwoDimensionalArrayInt(C, N);
+ /**
+ * < Interleaved normalised MDCTs
+ */
+
+ BoxedValueInt boxed_rng = new BoxedValueInt(this.rng);
+ Bands.quant_all_bands(0, mode, start, end, X[0], C == 2 ? X[1] : null, collapse_masks,
+ null, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res,
+ len * (8 << EntropyCoder.BITRES) - anti_collapse_rsv, balance, dec, LM, codedBands, boxed_rng);
+ this.rng = boxed_rng.Val;
+
+ if (anti_collapse_rsv > 0) {
+ anti_collapse_on = dec.dec_bits(1);
+ }
+
+ QuantizeBands.unquant_energy_finalise(mode, start, end, oldBandE,
+ fine_quant, fine_priority, len * 8 - dec.tell(), dec, C);
+
+ if (anti_collapse_on != 0) {
+ Bands.anti_collapse(mode, X, collapse_masks, LM, C, N,
+ start, end, oldBandE, oldLogE, oldLogE2, pulses, this.rng);
+ }
+
+ if (silence != 0) {
+ for (i = 0; i < C * nbEBands; i++) {
+ oldBandE[i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ }
+
+ CeltCommon.celt_synthesis(mode, X, out_syn, out_syn_ptrs, oldBandE, start, effEnd,
+ C, CC, isTransient, LM, this.downsample, silence);
+
+ c = 0;
+ do {
+ this.postfilter_period = Inlines.IMAX(this.postfilter_period, CeltConstants.COMBFILTER_MINPERIOD);
+ this.postfilter_period_old = Inlines.IMAX(this.postfilter_period_old, CeltConstants.COMBFILTER_MINPERIOD);
+ CeltCommon.comb_filter(out_syn[c], out_syn_ptrs[c], out_syn[c], out_syn_ptrs[c], this.postfilter_period_old, this.postfilter_period, mode.shortMdctSize,
+ this.postfilter_gain_old, this.postfilter_gain, this.postfilter_tapset_old, this.postfilter_tapset,
+ mode.window, overlap);
+ if (LM != 0) {
+ CeltCommon.comb_filter(
+ out_syn[c], out_syn_ptrs[c] + (mode.shortMdctSize),
+ out_syn[c], out_syn_ptrs[c] + (mode.shortMdctSize),
+ this.postfilter_period, postfilter_pitch, N - mode.shortMdctSize,
+ this.postfilter_gain, postfilter_gain, this.postfilter_tapset, postfilter_tapset,
+ mode.window, overlap);
+ }
+
+ } while (++c < CC);
+ this.postfilter_period_old = this.postfilter_period;
+ this.postfilter_gain_old = this.postfilter_gain;
+ this.postfilter_tapset_old = this.postfilter_tapset;
+ this.postfilter_period = postfilter_pitch;
+ this.postfilter_gain = postfilter_gain;
+ this.postfilter_tapset = postfilter_tapset;
+ if (LM != 0) {
+ this.postfilter_period_old = this.postfilter_period;
+ this.postfilter_gain_old = this.postfilter_gain;
+ this.postfilter_tapset_old = this.postfilter_tapset;
+ }
+
+ if (C == 1) {
+ System.arraycopy(oldBandE, 0, oldBandE, nbEBands, nbEBands);
+ }
+
+ /* In case start or end were to change */
+ if (isTransient == 0) {
+ int max_background_increase;
+ System.arraycopy(oldLogE, 0, oldLogE2, 0, 2 * nbEBands);
+ System.arraycopy(oldBandE, 0, oldLogE, 0, 2 * nbEBands);
+ /* In normal circumstances, we only allow the noise floor to increase by
+ up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB
+ increase for each update.*/
+ if (this.loss_count < 10) {
+ max_background_increase = M * ((short) (0.5 + (0.001f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.001f, CeltConstants.DB_SHIFT)*/;
+ } else {
+ max_background_increase = ((short) (0.5 + (1.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ for (i = 0; i < 2 * nbEBands; i++) {
+ backgroundLogE[i] = Inlines.MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]);
+ }
+ } else {
+ for (i = 0; i < 2 * nbEBands; i++) {
+ oldLogE[i] = Inlines.MIN16(oldLogE[i], oldBandE[i]);
+ }
+ }
+ c = 0;
+ do {
+ for (i = 0; i < start; i++) {
+ oldBandE[c * nbEBands + i] = 0;
+ oldLogE[c * nbEBands + i] = oldLogE2[c * nbEBands + i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ for (i = end; i < nbEBands; i++) {
+ oldBandE[c * nbEBands + i] = 0;
+ oldLogE[c * nbEBands + i] = oldLogE2[c * nbEBands + i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ } while (++c < 2);
+ this.rng = (int) dec.rng;
+
+ CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum);
+ this.loss_count = 0;
+
+ if (dec.tell() > 8 * len) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ if (dec.get_error() != 0) {
+ this.error = 1;
+ }
+ return frame_size / this.downsample;
+ }
+
+ void SetStartBand(int value) {
+ if (value < 0 || value >= this.mode.nbEBands) {
+ throw new IllegalArgumentException("Start band above max number of ebands (or negative)");
+ }
+ this.start = value;
+ }
+
+ void SetEndBand(int value) {
+ if (value < 1 || value > this.mode.nbEBands) {
+ throw new IllegalArgumentException("End band above max number of ebands (or less than 1)");
+ }
+ this.end = value;
+ }
+
+ void SetChannels(int value) {
+ if (value < 1 || value > 2) {
+ throw new IllegalArgumentException("Channel count must be 1 or 2");
+ }
+ this.stream_channels = value;
+ }
+
+ int GetAndClearError() {
+ int returnVal = this.error;
+ this.error = 0;
+ return returnVal;
+ }
+
+ public int GetLookahead() {
+ return this.overlap / this.downsample;
+ }
+
+ public int GetPitch() {
+ return this.postfilter_period;
+ }
+
+ public CeltMode GetMode() {
+ return this.mode;
+ }
+
+ public void SetSignalling(int value) {
+ this.signalling = value;
+ }
+
+ public int GetFinalRange() {
+ return this.rng;
+ }
+}
diff --git a/app/src/main/java/org/concentus/CeltEncoder.java b/app/src/main/java/org/concentus/CeltEncoder.java
new file mode 100644
index 0000000000..5c06419081
--- /dev/null
+++ b/app/src/main/java/org/concentus/CeltEncoder.java
@@ -0,0 +1,1254 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class CeltEncoder {
+
+ CeltMode mode = null;
+ /**
+ * < Mode used by the encoder. Without custom modes, this always refers to
+ * the same predefined struct
+ */
+ int channels = 0;
+ int stream_channels = 0;
+
+ int force_intra = 0;
+ int clip = 0;
+ int disable_pf = 0;
+ int complexity = 0;
+ int upsample = 0;
+ int start = 0;
+ int end = 0;
+
+ int bitrate = 0;
+ int vbr = 0;
+ int signalling = 0;
+
+ /* If zero, VBR can do whatever it likes with the rate */
+ int constrained_vbr = 0;
+ int loss_rate = 0;
+ int lsb_depth = 0;
+ OpusFramesize variable_duration = OpusFramesize.OPUS_FRAMESIZE_UNKNOWN;
+ int lfe = 0;
+
+ /* Everything beyond this point gets cleared on a reset */
+ int rng = 0;
+ int spread_decision = 0;
+ int delayedIntra = 0;
+ int tonal_average = 0;
+ int lastCodedBands = 0;
+ int hf_average = 0;
+ int tapset_decision = 0;
+
+ int prefilter_period = 0;
+ int prefilter_gain = 0;
+ int prefilter_tapset = 0;
+ int consec_transient = 0;
+ AnalysisInfo analysis = new AnalysisInfo();
+
+ final int[] preemph_memE = new int[2];
+ final int[] preemph_memD = new int[2];
+
+ /* VBR-related parameters */
+ int vbr_reservoir = 0;
+ int vbr_drift = 0;
+ int vbr_offset = 0;
+ int vbr_count = 0;
+ int overlap_max = 0;
+ int stereo_saving = 0;
+ int intensity = 0;
+ int[] energy_mask = null;
+ int spec_avg = 0;
+
+ ///
+ /// The original C++ defined in_mem as a single float[1] which was the "caboose"
+ /// to the overall encoder struct, containing 5 separate variable-sized buffer
+ /// spaces of heterogeneous datatypes. I have laid them out into separate variables here,
+ /// but these were the original definitions:
+ /// val32 in_mem[], Size = channels*mode.overlap
+ /// val32 prefilter_mem[], Size = channels*COMBFILTER_MAXPERIOD
+ /// val16 oldBandE[], Size = channels*mode.nbEBands
+ /// val16 oldLogE[], Size = channels*mode.nbEBands
+ /// val16 oldLogE2[], Size = channels*mode.nbEBands
+ ///
+ int[][] in_mem = null;
+ int[][] prefilter_mem = null;
+ int[][] oldBandE = null;
+ int[][] oldLogE = null;
+ int[][] oldLogE2 = null;
+
+ private void Reset() {
+ mode = null;
+ channels = 0;
+ stream_channels = 0;
+ force_intra = 0;
+ clip = 0;
+ disable_pf = 0;
+ complexity = 0;
+ upsample = 0;
+ start = 0;
+ end = 0;
+ bitrate = 0;
+ vbr = 0;
+ signalling = 0;
+ constrained_vbr = 0;
+ loss_rate = 0;
+ lsb_depth = 0;
+ variable_duration = OpusFramesize.OPUS_FRAMESIZE_UNKNOWN;
+ lfe = 0;
+ PartialReset();
+ }
+
+ private void PartialReset() {
+ rng = 0;
+ spread_decision = 0;
+ delayedIntra = 0;
+ tonal_average = 0;
+ lastCodedBands = 0;
+ hf_average = 0;
+ tapset_decision = 0;
+ prefilter_period = 0;
+ prefilter_gain = 0;
+ prefilter_tapset = 0;
+ consec_transient = 0;
+ analysis.Reset();
+ preemph_memE[0] = 0;
+ preemph_memE[1] = 0;
+ preemph_memD[0] = 0;
+ preemph_memD[1] = 0;
+ vbr_reservoir = 0;
+ vbr_drift = 0;
+ vbr_offset = 0;
+ vbr_count = 0;
+ overlap_max = 0;
+ stereo_saving = 0;
+ intensity = 0;
+ energy_mask = null;
+ spec_avg = 0;
+ in_mem = null;
+ prefilter_mem = null;
+ oldBandE = null;
+ oldLogE = null;
+ oldLogE2 = null;
+ }
+
+ void ResetState() {
+ int i;
+
+ this.PartialReset();
+
+ // We have to reconstitute the dynamic buffers here.
+ this.in_mem = Arrays.InitTwoDimensionalArrayInt(this.channels, this.mode.overlap);
+ this.prefilter_mem = Arrays.InitTwoDimensionalArrayInt(this.channels, CeltConstants.COMBFILTER_MAXPERIOD);
+ this.oldBandE = Arrays.InitTwoDimensionalArrayInt(this.channels, this.mode.nbEBands);
+ this.oldLogE = Arrays.InitTwoDimensionalArrayInt(this.channels, this.mode.nbEBands);
+ this.oldLogE2 = Arrays.InitTwoDimensionalArrayInt(this.channels, this.mode.nbEBands);
+
+ for (i = 0; i < this.mode.nbEBands; i++) {
+ this.oldLogE[0][i] = this.oldLogE2[0][i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ if (this.channels == 2) {
+ for (i = 0; i < this.mode.nbEBands; i++) {
+ this.oldLogE[1][i] = this.oldLogE2[1][i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ }
+ this.vbr_offset = 0;
+ this.delayedIntra = 1;
+ this.spread_decision = Spread.SPREAD_NORMAL;
+ this.tonal_average = 256;
+ this.hf_average = 0;
+ this.tapset_decision = 0;
+ }
+
+ int opus_custom_encoder_init_arch(CeltMode mode,
+ int channels) {
+ if (channels < 0 || channels > 2) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ if (this == null || mode == null) {
+ return OpusError.OPUS_ALLOC_FAIL;
+ }
+
+ this.Reset();
+
+ this.mode = mode;
+ this.stream_channels = this.channels = channels;
+
+ this.upsample = 1;
+ this.start = 0;
+ this.end = this.mode.effEBands;
+ this.signalling = 1;
+
+ this.constrained_vbr = 1;
+ this.clip = 1;
+
+ this.bitrate = OpusConstants.OPUS_BITRATE_MAX;
+ this.vbr = 0;
+ this.force_intra = 0;
+ this.complexity = 5;
+ this.lsb_depth = 24;
+
+ //this.in_mem = new int[channels * mode.overlap);
+ //this.prefilter_mem = new int[channels * CeltConstants.COMBFILTER_MAXPERIOD);
+ //this.oldBandE = new int[channels * mode.nbEBands);
+ //this.oldLogE = new int[channels * mode.nbEBands);
+ //this.oldLogE2 = new int[channels * mode.nbEBands);
+ this.ResetState();
+
+ return OpusError.OPUS_OK;
+ }
+
+ int celt_encoder_init(int sampling_rate, int channels) {
+ int ret;
+ ret = this.opus_custom_encoder_init_arch(CeltMode.mode48000_960_120, channels);
+ if (ret != OpusError.OPUS_OK) {
+ return ret;
+ }
+ this.upsample = CeltCommon.resampling_factor(sampling_rate);
+ return OpusError.OPUS_OK;
+ }
+
+ int run_prefilter(int[][] input, int[][] prefilter_mem, int CC, int N,
+ int prefilter_tapset, BoxedValueInt pitch, BoxedValueInt gain, BoxedValueInt qgain, int enabled, int nbAvailableBytes) {
+ int c;
+ int[][] pre = new int[CC][];
+ CeltMode mode; // [porting note] pointer
+ BoxedValueInt pitch_index = new BoxedValueInt(0);
+ int gain1;
+ int pf_threshold;
+ int pf_on;
+ int qg;
+ int overlap;
+
+ mode = this.mode;
+ overlap = mode.overlap;
+ for (int z = 0; z < CC; z++) {
+ pre[z] = new int[N + CeltConstants.COMBFILTER_MAXPERIOD];
+ }
+
+ c = 0;
+ do {
+ System.arraycopy(prefilter_mem[c], 0, pre[c], 0, CeltConstants.COMBFILTER_MAXPERIOD);
+ System.arraycopy(input[c], overlap, pre[c], CeltConstants.COMBFILTER_MAXPERIOD, N);
+ } while (++c < CC);
+
+ if (enabled != 0) {
+ int[] pitch_buf = new int[(CeltConstants.COMBFILTER_MAXPERIOD + N) >> 1];
+
+ Pitch.pitch_downsample(pre, pitch_buf, CeltConstants.COMBFILTER_MAXPERIOD + N, CC);
+ /* Don't search for the fir last 1.5 octave of the range because
+ there's too many false-positives due to short-term correlation */
+ Pitch.pitch_search(pitch_buf, CeltConstants.COMBFILTER_MAXPERIOD >> 1, pitch_buf, N,
+ CeltConstants.COMBFILTER_MAXPERIOD - 3 * CeltConstants.COMBFILTER_MINPERIOD, pitch_index);
+ pitch_index.Val = CeltConstants.COMBFILTER_MAXPERIOD - pitch_index.Val;
+ gain1 = Pitch.remove_doubling(pitch_buf, CeltConstants.COMBFILTER_MAXPERIOD, CeltConstants.COMBFILTER_MINPERIOD,
+ N, pitch_index, this.prefilter_period, this.prefilter_gain);
+ if (pitch_index.Val > CeltConstants.COMBFILTER_MAXPERIOD - 2) {
+ pitch_index.Val = CeltConstants.COMBFILTER_MAXPERIOD - 2;
+ }
+ gain1 = Inlines.MULT16_16_Q15(((short) (0.5 + (.7f) * (((int) 1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, gain1);
+ /*printf("%d %d %f %f\n", pitch_change, pitch_index, gain1, st.analysis.tonality);*/
+ if (this.loss_rate > 2) {
+ gain1 = Inlines.HALF32(gain1);
+ }
+ if (this.loss_rate > 4) {
+ gain1 = Inlines.HALF32(gain1);
+ }
+ if (this.loss_rate > 8) {
+ gain1 = 0;
+ }
+ } else {
+ gain1 = 0;
+ pitch_index.Val = CeltConstants.COMBFILTER_MINPERIOD;
+ }
+
+ /* Gain threshold for enabling the prefilter/postfilter */
+ pf_threshold = ((short) (0.5 + (.2f) * (((int) 1) << (15))))/*Inlines.QCONST16(.2f, 15)*/;
+
+ /* Adjusting the threshold based on rate and continuity */
+ if (Inlines.abs(pitch_index.Val - this.prefilter_period) * 10 > pitch_index.Val) {
+ pf_threshold += ((short) (0.5 + (.2f) * (((int) 1) << (15))))/*Inlines.QCONST16(.2f, 15)*/;
+ }
+ if (nbAvailableBytes < 25) {
+ pf_threshold += ((short) (0.5 + (.1f) * (((int) 1) << (15))))/*Inlines.QCONST16(.1f, 15)*/;
+ }
+ if (nbAvailableBytes < 35) {
+ pf_threshold += ((short) (0.5 + (.1f) * (((int) 1) << (15))))/*Inlines.QCONST16(.1f, 15)*/;
+ }
+ if (this.prefilter_gain > ((short) (0.5 + (.4f) * (((int) 1) << (15))))/*Inlines.QCONST16(.4f, 15)*/) {
+ pf_threshold -= ((short) (0.5 + (.1f) * (((int) 1) << (15))))/*Inlines.QCONST16(.1f, 15)*/;
+ }
+ if (this.prefilter_gain > ((short) (0.5 + (.55f) * (((int) 1) << (15))))/*Inlines.QCONST16(.55f, 15)*/) {
+ pf_threshold -= ((short) (0.5 + (.1f) * (((int) 1) << (15))))/*Inlines.QCONST16(.1f, 15)*/;
+ }
+
+ /* Hard threshold at 0.2 */
+ pf_threshold = Inlines.MAX16(pf_threshold, ((short) (0.5 + (.2f) * (((int) 1) << (15))))/*Inlines.QCONST16(.2f, 15)*/);
+
+ if (gain1 < pf_threshold) {
+ gain1 = 0;
+ pf_on = 0;
+ qg = 0;
+ } else {
+ /*This block is not gated by a total bits check only because
+ of the nbAvailableBytes check above.*/
+ if (Inlines.ABS32(gain1 - this.prefilter_gain) < ((short) (0.5 + (.1f) * (((int) 1) << (15))))/*Inlines.QCONST16(.1f, 15)*/) {
+ gain1 = this.prefilter_gain;
+ }
+
+ qg = ((gain1 + 1536) >> 10) / 3 - 1;
+ qg = Inlines.IMAX(0, Inlines.IMIN(7, qg));
+ gain1 = ((short) (0.5 + (0.09375f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.09375f, 15)*/ * (qg + 1);
+ pf_on = 1;
+ }
+ /*printf("%d %f\n", pitch_index, gain1);*/
+
+ c = 0;
+ do {
+ int offset = mode.shortMdctSize - overlap;
+ this.prefilter_period = Inlines.IMAX(this.prefilter_period, CeltConstants.COMBFILTER_MINPERIOD);
+ System.arraycopy(this.in_mem[c], 0, input[c], 0, overlap);
+ if (offset != 0) {
+ CeltCommon.comb_filter(input[c], (overlap), pre[c], (CeltConstants.COMBFILTER_MAXPERIOD),
+ this.prefilter_period, this.prefilter_period, offset, -this.prefilter_gain, -this.prefilter_gain,
+ this.prefilter_tapset, this.prefilter_tapset, null, 0); // opt: lots of pointer allocations here
+ }
+
+ CeltCommon.comb_filter(input[c], (overlap + offset), pre[c], (CeltConstants.COMBFILTER_MAXPERIOD + offset),
+ this.prefilter_period, pitch_index.Val, N - offset, -this.prefilter_gain, -gain1,
+ this.prefilter_tapset, prefilter_tapset, mode.window, overlap);
+ System.arraycopy(input[c], N, this.in_mem[c], 0, overlap);
+
+ if (N > CeltConstants.COMBFILTER_MAXPERIOD) {
+ System.arraycopy(pre[c], N, prefilter_mem[c], 0, CeltConstants.COMBFILTER_MAXPERIOD);
+ } else {
+ Arrays.MemMove(prefilter_mem[c], N, 0, CeltConstants.COMBFILTER_MAXPERIOD - N);
+ System.arraycopy(pre[c], CeltConstants.COMBFILTER_MAXPERIOD, prefilter_mem[c], CeltConstants.COMBFILTER_MAXPERIOD - N, N);
+ }
+ } while (++c < CC);
+
+ gain.Val = gain1;
+ pitch.Val = pitch_index.Val;
+ qgain.Val = qg;
+ return pf_on;
+ }
+
+ int celt_encode_with_ec(short[] pcm, int pcm_ptr, int frame_size, byte[] compressed, int compressed_ptr, int nbCompressedBytes, EntropyCoder enc) {
+ int i, c, N;
+ int bits;
+ int[][] input;
+ int[][] freq;
+ int[][] X;
+ int[][] bandE;
+ int[][] bandLogE;
+ int[][] bandLogE2;
+ int[] fine_quant;
+ int[][] error;
+ int[] pulses;
+ int[] cap;
+ int[] offsets;
+ int[] fine_priority;
+ int[] tf_res;
+ short[] collapse_masks;
+ int shortBlocks = 0;
+ int isTransient = 0;
+ int CC = this.channels;
+ int C = this.stream_channels;
+ int LM, M;
+ int tf_select;
+ int nbFilledBytes, nbAvailableBytes;
+ int start;
+ int end;
+ int effEnd;
+ int codedBands;
+ int tf_sum;
+ int alloc_trim;
+ int pitch_index = CeltConstants.COMBFILTER_MINPERIOD;
+ int gain1 = 0;
+ int dual_stereo = 0;
+ int effectiveBytes;
+ int dynalloc_logp;
+ int vbr_rate;
+ int total_bits;
+ int total_boost;
+ int balance;
+ int tell;
+ int prefilter_tapset = 0;
+ int pf_on;
+ int anti_collapse_rsv;
+ int anti_collapse_on = 0;
+ int silence = 0;
+ int tf_chan = 0;
+ int tf_estimate;
+ int pitch_change = 0;
+ int tot_boost;
+ int sample_max;
+ int maxDepth;
+ CeltMode mode;
+ int nbEBands;
+ int overlap;
+ short[] eBands;
+ int secondMdct;
+ int signalBandwidth;
+ int transient_got_disabled = 0;
+ int surround_masking = 0;
+ int temporal_vbr = 0;
+ int surround_trim = 0;
+ int equiv_rate = 510000;
+ int[] surround_dynalloc;
+
+ mode = this.mode;
+ nbEBands = mode.nbEBands;
+ overlap = mode.overlap;
+ eBands = mode.eBands;
+ start = this.start;
+ end = this.end;
+ tf_estimate = 0;
+ if (nbCompressedBytes < 2 || pcm == null) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ frame_size *= this.upsample;
+ for (LM = 0; LM <= mode.maxLM; LM++) {
+ if (mode.shortMdctSize << LM == frame_size) {
+ break;
+ }
+ }
+ if (LM > mode.maxLM) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ M = 1 << LM;
+ N = M * mode.shortMdctSize;
+
+ if (enc == null) {
+ tell = 1;
+ nbFilledBytes = 0;
+ } else {
+ tell = enc.tell();
+ nbFilledBytes = (tell + 4) >> 3;
+ }
+
+ Inlines.OpusAssert(this.signalling == 0);
+
+ /* Can't produce more than 1275 output bytes */
+ nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, 1275);
+ nbAvailableBytes = nbCompressedBytes - nbFilledBytes;
+
+ if (this.vbr != 0 && this.bitrate != OpusConstants.OPUS_BITRATE_MAX) {
+ int den = mode.Fs >> EntropyCoder.BITRES;
+ vbr_rate = (this.bitrate * frame_size + (den >> 1)) / den;
+ effectiveBytes = vbr_rate >> (3 + EntropyCoder.BITRES);
+ } else {
+ int tmp;
+ vbr_rate = 0;
+ tmp = this.bitrate * frame_size;
+ if (tell > 1) {
+ tmp += tell;
+ }
+ if (this.bitrate != OpusConstants.OPUS_BITRATE_MAX) {
+ nbCompressedBytes = Inlines.IMAX(2, Inlines.IMIN(nbCompressedBytes,
+ (tmp + 4 * mode.Fs) / (8 * mode.Fs) - (this.signalling != 0 ? 1 : 0)));
+ }
+ effectiveBytes = nbCompressedBytes;
+ }
+ if (this.bitrate != OpusConstants.OPUS_BITRATE_MAX) {
+ equiv_rate = this.bitrate - (40 * C + 20) * ((400 >> LM) - 50);
+ }
+
+ if (enc == null) {
+ enc = new EntropyCoder();
+ enc.enc_init(compressed, compressed_ptr, nbCompressedBytes);
+ }
+
+ if (vbr_rate > 0) {
+ /* Computes the max bit-rate allowed in VBR mode to avoid violating the
+ target rate and buffering.
+ We must do this up front so that bust-prevention logic triggers
+ correctly if we don't have enough bits. */
+ if (this.constrained_vbr != 0) {
+ int vbr_bound;
+ int max_allowed;
+ /* We could use any multiple of vbr_rate as bound (depending on the
+ delay).
+ This is clamped to ensure we use at least two bytes if the encoder
+ was entirely empty, but to allow 0 in hybrid mode. */
+ vbr_bound = vbr_rate;
+ max_allowed = Inlines.IMIN(Inlines.IMAX(tell == 1 ? 2 : 0,
+ (vbr_rate + vbr_bound - this.vbr_reservoir) >> (EntropyCoder.BITRES + 3)),
+ nbAvailableBytes);
+ if (max_allowed < nbAvailableBytes) {
+ nbCompressedBytes = nbFilledBytes + max_allowed;
+ nbAvailableBytes = max_allowed;
+ enc.enc_shrink(nbCompressedBytes);
+ }
+ }
+ }
+ total_bits = nbCompressedBytes * 8;
+
+ effEnd = end;
+ if (effEnd > mode.effEBands) {
+ effEnd = mode.effEBands;
+ }
+
+ input = Arrays.InitTwoDimensionalArrayInt(CC, N + overlap);
+
+ sample_max = Inlines.MAX32(this.overlap_max, Inlines.celt_maxabs32(pcm, pcm_ptr, C * (N - overlap) / this.upsample));
+ this.overlap_max = Inlines.celt_maxabs32(pcm, pcm_ptr + (C * (N - overlap) / this.upsample), C * overlap / this.upsample);
+ sample_max = Inlines.MAX32(sample_max, this.overlap_max);
+ silence = (sample_max == 0) ? 1 : 0;
+ if (tell == 1) {
+ enc.enc_bit_logp(silence, 15);
+ } else {
+ silence = 0;
+ }
+ if (silence != 0) {
+ /*In VBR mode there is no need to send more than the minimum. */
+ if (vbr_rate > 0) {
+ effectiveBytes = nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, nbFilledBytes + 2);
+ total_bits = nbCompressedBytes * 8;
+ nbAvailableBytes = 2;
+ enc.enc_shrink(nbCompressedBytes);
+ }
+ /* Pretend we've filled all the remaining bits with zeros
+ (that's what the initialiser did anyway) */
+ tell = nbCompressedBytes * 8;
+ enc.nbits_total += tell - enc.tell();
+ }
+ c = 0;
+ BoxedValueInt boxed_memE = new BoxedValueInt(0);
+ do {
+ int need_clip = 0;
+ boxed_memE.Val = this.preemph_memE[c];
+ CeltCommon.celt_preemphasis(pcm, pcm_ptr + c, input[c], overlap, N, CC, this.upsample,
+ mode.preemph, boxed_memE, need_clip);
+ this.preemph_memE[c] = boxed_memE.Val;
+ } while (++c < CC);
+
+ /* Find pitch period and gain */
+ {
+ int enabled;
+ int qg;
+ enabled = (((this.lfe != 0 && nbAvailableBytes > 3) || nbAvailableBytes > 12 * C) && start == 0 && silence == 0 && this.disable_pf == 0
+ && this.complexity >= 5 && !(this.consec_transient != 0 && LM != 3 && this.variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE)) ? 1 : 0;
+
+ prefilter_tapset = this.tapset_decision;
+ BoxedValueInt boxed_pitch_index = new BoxedValueInt(0);
+ BoxedValueInt boxed_gain1 = new BoxedValueInt(0);
+ BoxedValueInt boxed_qg = new BoxedValueInt(0);
+ pf_on = this.run_prefilter(input, this.prefilter_mem, CC, N, prefilter_tapset, boxed_pitch_index, boxed_gain1, boxed_qg, enabled, nbAvailableBytes);
+ pitch_index = boxed_pitch_index.Val;
+ gain1 = boxed_gain1.Val;
+ qg = boxed_qg.Val;
+
+ if ((gain1 > ((short) (0.5 + (.4f) * (((int) 1) << (15))))/*Inlines.QCONST16(.4f, 15)*/ || this.prefilter_gain > ((short) (0.5 + (.4f) * (((int) 1) << (15))))/*Inlines.QCONST16(.4f, 15)*/) && (this.analysis.valid == 0 || this.analysis.tonality > .3)
+ && (pitch_index > 1.26 * this.prefilter_period || pitch_index < .79 * this.prefilter_period)) {
+ pitch_change = 1;
+ }
+ if (pf_on == 0) {
+ if (start == 0 && tell + 16 <= total_bits) {
+ enc.enc_bit_logp(0, 1);
+ }
+ } else {
+ /*This block is not gated by a total bits check only because
+ of the nbAvailableBytes check above.*/
+ int octave;
+ enc.enc_bit_logp(1, 1);
+ pitch_index += 1;
+ octave = Inlines.EC_ILOG(pitch_index) - 5;
+ enc.enc_uint(octave, 6);
+ enc.enc_bits((pitch_index - (16 << octave)), 4 + octave);
+ pitch_index -= 1;
+ enc.enc_bits(qg, 3);
+ enc.enc_icdf(prefilter_tapset, CeltTables.tapset_icdf, 2);
+ }
+ }
+
+ isTransient = 0;
+ shortBlocks = 0;
+ if (this.complexity >= 1 && this.lfe == 0) {
+ BoxedValueInt boxed_tf_estimate = new BoxedValueInt(0);
+ BoxedValueInt boxed_tf_chan = new BoxedValueInt(0);
+ isTransient = CeltCommon.transient_analysis(input, N + overlap, CC,
+ boxed_tf_estimate, boxed_tf_chan);
+ tf_estimate = boxed_tf_estimate.Val;
+ tf_chan = boxed_tf_chan.Val;
+ }
+
+ if (LM > 0 && enc.tell() + 3 <= total_bits) {
+ if (isTransient != 0) {
+ shortBlocks = M;
+ }
+ } else {
+ isTransient = 0;
+ transient_got_disabled = 1;
+ }
+
+ freq = Arrays.InitTwoDimensionalArrayInt(CC, N);
+ /**
+ * < Interleaved signal MDCTs
+ */
+ bandE = Arrays.InitTwoDimensionalArrayInt(CC, nbEBands);
+ bandLogE = Arrays.InitTwoDimensionalArrayInt(CC, nbEBands);
+
+ secondMdct = (shortBlocks != 0 && this.complexity >= 8) ? 1 : 0;
+ bandLogE2 = Arrays.InitTwoDimensionalArrayInt(CC, nbEBands);
+ //Arrays.MemSet(bandLogE2, 0, C * nbEBands); // not explicitly needed
+ if (secondMdct != 0) {
+ CeltCommon.compute_mdcts(mode, 0, input, freq, C, CC, LM, this.upsample);
+ Bands.compute_band_energies(mode, freq, bandE, effEnd, C, LM);
+ QuantizeBands.amp2Log2(mode, effEnd, end, bandE, bandLogE2, C);
+ for (i = 0; i < nbEBands; i++) {
+ bandLogE2[0][i] += Inlines.HALF16(Inlines.SHL16(LM, CeltConstants.DB_SHIFT));
+ }
+ if (C == 2) {
+ for (i = 0; i < nbEBands; i++) {
+ bandLogE2[1][i] += Inlines.HALF16(Inlines.SHL16(LM, CeltConstants.DB_SHIFT));
+ }
+ }
+ }
+
+ CeltCommon.compute_mdcts(mode, shortBlocks, input, freq, C, CC, LM, this.upsample);
+ if (CC == 2 && C == 1) {
+ tf_chan = 0;
+ }
+ Bands.compute_band_energies(mode, freq, bandE, effEnd, C, LM);
+
+ if (this.lfe != 0) {
+ for (i = 2; i < end; i++) {
+ bandE[0][i] = Inlines.IMIN(bandE[0][i], Inlines.MULT16_32_Q15(((short) (0.5 + (1e-4f) * (((int) 1) << (15))))/*Inlines.QCONST16(1e-4f, 15)*/, bandE[0][0]));
+ bandE[0][i] = Inlines.MAX32(bandE[0][i], CeltConstants.EPSILON);
+ }
+ }
+
+ QuantizeBands.amp2Log2(mode, effEnd, end, bandE, bandLogE, C);
+
+ surround_dynalloc = new int[C * nbEBands];
+ //Arrays.MemSet(surround_dynalloc, 0, end); // not strictly needed
+ /* This computes how much masking takes place between surround channels */
+ if (start == 0 && this.energy_mask != null && this.lfe == 0) {
+ int mask_end;
+ int midband;
+ int count_dynalloc;
+ int mask_avg = 0;
+ int diff = 0;
+ int count = 0;
+ mask_end = Inlines.IMAX(2, this.lastCodedBands);
+ for (c = 0; c < C; c++) {
+ for (i = 0; i < mask_end; i++) {
+ int mask;
+ mask = Inlines.MAX16(Inlines.MIN16(this.energy_mask[nbEBands * c + i],
+ ((short) (0.5 + (.25f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.25f, CeltConstants.DB_SHIFT)*/), -((short) (0.5 + (2.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(2.0f, CeltConstants.DB_SHIFT)*/);
+ if (mask > 0) {
+ mask = Inlines.HALF16(mask);
+ }
+ mask_avg += Inlines.MULT16_16(mask, eBands[i + 1] - eBands[i]);
+ count += eBands[i + 1] - eBands[i];
+ diff += Inlines.MULT16_16(mask, 1 + 2 * i - mask_end);
+ }
+ }
+ Inlines.OpusAssert(count > 0);
+ mask_avg = Inlines.DIV32_16(mask_avg, count);
+ mask_avg += ((short) (0.5 + (.2f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.2f, CeltConstants.DB_SHIFT)*/;
+ diff = diff * 6 / (C * (mask_end - 1) * (mask_end + 1) * mask_end);
+ /* Again, being conservative */
+ diff = Inlines.HALF32(diff);
+ diff = Inlines.MAX32(Inlines.MIN32(diff, ((int) (0.5 + (.031f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST32(.031f, CeltConstants.DB_SHIFT)*/), 0 - ((int) (0.5 + (.031f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST32(.031f, CeltConstants.DB_SHIFT)*/);
+ /* Find the band that's in the middle of the coded spectrum */
+ for (midband = 0; eBands[midband + 1] < eBands[mask_end] / 2; midband++) ;
+ count_dynalloc = 0;
+ for (i = 0; i < mask_end; i++) {
+ int lin;
+ int unmask;
+ lin = mask_avg + diff * (i - midband);
+ if (C == 2) {
+ unmask = Inlines.MAX16(this.energy_mask[i], this.energy_mask[nbEBands + i]);
+ } else {
+ unmask = this.energy_mask[i];
+ }
+ unmask = Inlines.MIN16(unmask, ((short) (0.5 + (.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.0f, CeltConstants.DB_SHIFT)*/);
+ unmask -= lin;
+ if (unmask > ((short) (0.5 + (.25f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.25f, CeltConstants.DB_SHIFT)*/) {
+ surround_dynalloc[i] = unmask - ((short) (0.5 + (.25f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.25f, CeltConstants.DB_SHIFT)*/;
+ count_dynalloc++;
+ }
+ }
+ if (count_dynalloc >= 3) {
+ /* If we need dynalloc in many bands, it's probably because our
+ initial masking rate was too low. */
+ mask_avg += ((short) (0.5 + (.25f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.25f, CeltConstants.DB_SHIFT)*/;
+ if (mask_avg > 0) {
+ /* Something went really wrong in the original calculations,
+ disabling masking. */
+ mask_avg = 0;
+ diff = 0;
+ Arrays.MemSet(surround_dynalloc, 0, mask_end);
+ } else {
+ for (i = 0; i < mask_end; i++) {
+ surround_dynalloc[i] = Inlines.MAX16(0, surround_dynalloc[i] - ((short) (0.5 + (.25f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.25f, CeltConstants.DB_SHIFT)*/);
+ }
+ }
+ }
+ mask_avg += ((short) (0.5 + (.2f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.2f, CeltConstants.DB_SHIFT)*/;
+ /* Convert to 1/64th units used for the trim */
+ surround_trim = 64 * diff;
+ /*printf("%d %d ", mask_avg, surround_trim);*/
+ surround_masking = mask_avg;
+ }
+ /* Temporal VBR (but not for LFE) */
+ if (this.lfe == 0) {
+ int follow = -((short) (0.5 + (10.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(10.0f, CeltConstants.DB_SHIFT)*/;
+ int frame_avg = 0;
+ int offset = shortBlocks != 0 ? Inlines.HALF16(Inlines.SHL16(LM, CeltConstants.DB_SHIFT)) : 0;
+ for (i = start; i < end; i++) {
+ follow = Inlines.MAX16(follow - ((short) (0.5 + (1.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/, bandLogE[0][i] - offset);
+ if (C == 2) {
+ follow = Inlines.MAX16(follow, bandLogE[1][i] - offset);
+ }
+ frame_avg += follow;
+ }
+ frame_avg /= (end - start);
+ temporal_vbr = Inlines.SUB16(frame_avg, this.spec_avg);
+ temporal_vbr = Inlines.MIN16(((short) (0.5 + (3.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(3.0f, CeltConstants.DB_SHIFT)*/, Inlines.MAX16(-((short) (0.5 + (1.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.5f, CeltConstants.DB_SHIFT)*/, temporal_vbr));
+ this.spec_avg += (short) (Inlines.MULT16_16_Q15(((short) (0.5 + (.02f) * (((int) 1) << (15))))/*Inlines.QCONST16(.02f, 15)*/, temporal_vbr));
+ }
+ /*for (i=0;i<21;i++)
+ printf("%f ", bandLogE[i]);
+ printf("\n");*/
+
+ if (secondMdct == 0) {
+ System.arraycopy(bandLogE[0], 0, bandLogE2[0], 0, nbEBands);
+ if (C == 2) {
+ System.arraycopy(bandLogE[1], 0, bandLogE2[1], 0, nbEBands);
+ }
+ }
+
+ /* Last chance to catch any transient we might have missed in the
+ time-domain analysis */
+ if (LM > 0 && enc.tell() + 3 <= total_bits && isTransient == 0 && this.complexity >= 5 && this.lfe == 0) {
+ if (CeltCommon.patch_transient_decision(bandLogE, this.oldBandE, nbEBands, start, end, C) != 0) {
+ isTransient = 1;
+ shortBlocks = M;
+ CeltCommon.compute_mdcts(mode, shortBlocks, input, freq, C, CC, LM, this.upsample);
+ Bands.compute_band_energies(mode, freq, bandE, effEnd, C, LM);
+ QuantizeBands.amp2Log2(mode, effEnd, end, bandE, bandLogE, C);
+ /* Compensate for the scaling of short vs long mdcts */
+ for (i = 0; i < nbEBands; i++) {
+ bandLogE2[0][i] += Inlines.HALF16(Inlines.SHL16(LM, CeltConstants.DB_SHIFT));
+ }
+ if (C == 2) {
+ for (i = 0; i < nbEBands; i++) {
+ bandLogE2[1][i] += Inlines.HALF16(Inlines.SHL16(LM, CeltConstants.DB_SHIFT));
+ }
+ }
+ tf_estimate = ((short) (0.5 + (.2f) * (((int) 1) << (14))))/*Inlines.QCONST16(.2f, 14)*/;
+ }
+ }
+
+ if (LM > 0 && enc.tell() + 3 <= total_bits) {
+ enc.enc_bit_logp(isTransient, 3);
+ }
+
+ X = Arrays.InitTwoDimensionalArrayInt(C, N);
+ /**
+ * < Interleaved normalised MDCTs
+ */
+
+ /* Band normalisation */
+ Bands.normalise_bands(mode, freq, X, bandE, effEnd, C, M);
+
+ tf_res = new int[nbEBands];
+ /* Disable variable tf resolution for hybrid and at very low bitrate */
+ if (effectiveBytes >= 15 * C && start == 0 && this.complexity >= 2 && this.lfe == 0) {
+ int lambda;
+ if (effectiveBytes < 40) {
+ lambda = 12;
+ } else if (effectiveBytes < 60) {
+ lambda = 6;
+ } else if (effectiveBytes < 100) {
+ lambda = 4;
+ } else {
+ lambda = 3;
+ }
+ lambda *= 2;
+ BoxedValueInt boxed_tf_sum = new BoxedValueInt(0);
+ tf_select = CeltCommon.tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, boxed_tf_sum, tf_estimate, tf_chan);
+ tf_sum = boxed_tf_sum.Val;
+
+ for (i = effEnd; i < end; i++) {
+ tf_res[i] = tf_res[effEnd - 1];
+ }
+ } else {
+ tf_sum = 0;
+ for (i = 0; i < end; i++) {
+ tf_res[i] = isTransient;
+ }
+ tf_select = 0;
+ }
+
+ error = Arrays.InitTwoDimensionalArrayInt(C, nbEBands);
+ BoxedValueInt boxed_delayedintra = new BoxedValueInt(this.delayedIntra);
+ QuantizeBands.quant_coarse_energy(mode, start, end, effEnd, bandLogE,
+ this.oldBandE, total_bits, error, enc,
+ C, LM, nbAvailableBytes, this.force_intra,
+ boxed_delayedintra, this.complexity >= 4 ? 1 : 0, this.loss_rate, this.lfe);
+ this.delayedIntra = boxed_delayedintra.Val;
+
+ CeltCommon.tf_encode(start, end, isTransient, tf_res, LM, tf_select, enc);
+
+ if (enc.tell() + 4 <= total_bits) {
+ if (this.lfe != 0) {
+ this.tapset_decision = 0;
+ this.spread_decision = Spread.SPREAD_NORMAL;
+ } else if (shortBlocks != 0 || this.complexity < 3 || nbAvailableBytes < 10 * C || start != 0) {
+ if (this.complexity == 0) {
+ this.spread_decision = Spread.SPREAD_NONE;
+ } else {
+ this.spread_decision = Spread.SPREAD_NORMAL;
+ }
+ } else {
+ BoxedValueInt boxed_tonal_average = new BoxedValueInt(this.tonal_average);
+ BoxedValueInt boxed_tapset_decision = new BoxedValueInt(this.tapset_decision);
+ BoxedValueInt boxed_hf_average = new BoxedValueInt(this.hf_average);
+ this.spread_decision = Bands.spreading_decision(mode, X,
+ boxed_tonal_average, this.spread_decision, boxed_hf_average,
+ boxed_tapset_decision, (pf_on != 0 && shortBlocks == 0) ? 1 : 0, effEnd, C, M);
+ this.tonal_average = boxed_tonal_average.Val;
+ this.tapset_decision = boxed_tapset_decision.Val;
+ this.hf_average = boxed_hf_average.Val;
+
+ /*printf("%d %d\n", st.tapset_decision, st.spread_decision);*/
+ /*printf("%f %d %f %d\n\n", st.analysis.tonality, st.spread_decision, st.analysis.tonality_slope, st.tapset_decision);*/
+ }
+ enc.enc_icdf(this.spread_decision, CeltTables.spread_icdf, 5);
+ }
+
+ offsets = new int[nbEBands];
+
+ BoxedValueInt boxed_tot_boost = new BoxedValueInt(0);
+ maxDepth = CeltCommon.dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets,
+ this.lsb_depth, mode.logN, isTransient, this.vbr, this.constrained_vbr,
+ eBands, LM, effectiveBytes, boxed_tot_boost, this.lfe, surround_dynalloc);
+ tot_boost = boxed_tot_boost.Val;
+
+ /* For LFE, everything interesting is in the first band */
+ if (this.lfe != 0) {
+ offsets[0] = Inlines.IMIN(8, effectiveBytes / 3);
+ }
+ cap = new int[nbEBands];
+ CeltCommon.init_caps(mode, cap, LM, C);
+
+ dynalloc_logp = 6;
+ total_bits <<= EntropyCoder.BITRES;
+ total_boost = 0;
+ tell = (int) enc.tell_frac();
+ for (i = start; i < end; i++) {
+ int width, quanta;
+ int dynalloc_loop_logp;
+ int boost;
+ int j;
+ width = C * (eBands[i + 1] - eBands[i]) << LM;
+ /* quanta is 6 bits, but no more than 1 bit/sample
+ and no less than 1/8 bit/sample */
+ quanta = Inlines.IMIN(width << EntropyCoder.BITRES, Inlines.IMAX(6 << EntropyCoder.BITRES, width));
+ dynalloc_loop_logp = dynalloc_logp;
+ boost = 0;
+ for (j = 0; tell + (dynalloc_loop_logp << EntropyCoder.BITRES) < total_bits - total_boost
+ && boost < cap[i]; j++) {
+ int flag;
+ flag = j < offsets[i] ? 1 : 0;
+ enc.enc_bit_logp(flag, dynalloc_loop_logp);
+ tell = (int) enc.tell_frac();
+ if (flag == 0) {
+ break;
+ }
+ boost += quanta;
+ total_boost += quanta;
+ dynalloc_loop_logp = 1;
+ }
+ /* Making dynalloc more likely */
+ if (j != 0) {
+ dynalloc_logp = Inlines.IMAX(2, dynalloc_logp - 1);
+ }
+ offsets[i] = boost;
+ }
+
+ if (C == 2) {
+ /* Always use MS for 2.5 ms frames until we can do a better analysis */
+ if (LM != 0) {
+ dual_stereo = CeltCommon.stereo_analysis(mode, X, LM);
+ }
+
+ this.intensity = Bands.hysteresis_decision((int) (equiv_rate / 1000),
+ CeltTables.intensity_thresholds, CeltTables.intensity_histeresis, 21, this.intensity);
+ this.intensity = Inlines.IMIN(end, Inlines.IMAX(start, this.intensity));
+ }
+
+ alloc_trim = 5;
+ if (tell + (6 << EntropyCoder.BITRES) <= total_bits - total_boost) {
+ if (this.lfe != 0) {
+ alloc_trim = 5;
+ } else {
+ BoxedValueInt boxed_stereo_saving = new BoxedValueInt(this.stereo_saving);
+ alloc_trim = CeltCommon.alloc_trim_analysis(mode, X, bandLogE,
+ end, LM, C, this.analysis, boxed_stereo_saving, tf_estimate,
+ this.intensity, surround_trim);
+ this.stereo_saving = boxed_stereo_saving.Val;
+ }
+ enc.enc_icdf(alloc_trim, CeltTables.trim_icdf, 7);
+ tell = (int) enc.tell_frac();
+ }
+
+ /* Variable bitrate */
+ if (vbr_rate > 0) {
+ int alpha;
+ int delta;
+ /* The target rate in 8th bits per frame */
+ int target, base_target;
+ int min_allowed;
+ int lm_diff = mode.maxLM - LM;
+
+ /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms.
+ The CELT allocator will just not be able to use more than that anyway. */
+ nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, 1275 >> (3 - LM));
+ base_target = vbr_rate - ((40 * C + 20) << EntropyCoder.BITRES);
+
+ if (this.constrained_vbr != 0) {
+ base_target += (this.vbr_offset >> lm_diff);
+ }
+
+ target = CeltCommon.compute_vbr(mode, this.analysis, base_target, LM, equiv_rate,
+ this.lastCodedBands, C, this.intensity, this.constrained_vbr,
+ this.stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth,
+ this.variable_duration, this.lfe, this.energy_mask != null ? 1 : 0, surround_masking,
+ temporal_vbr);
+
+ /* The current offset is removed from the target and the space used
+ so far is added*/
+ target = target + tell;
+ /* In VBR mode the frame size must not be reduced so much that it would
+ result in the encoder running out of bits.
+ The margin of 2 bytes ensures that none of the bust-prevention logic
+ in the decoder will have triggered so far. */
+ min_allowed = ((tell + total_boost + (1 << (EntropyCoder.BITRES + 3)) - 1) >> (EntropyCoder.BITRES + 3)) + 2 - nbFilledBytes;
+
+ nbAvailableBytes = (target + (1 << (EntropyCoder.BITRES + 2))) >> (EntropyCoder.BITRES + 3);
+ nbAvailableBytes = Inlines.IMAX(min_allowed, nbAvailableBytes);
+ nbAvailableBytes = Inlines.IMIN(nbCompressedBytes, nbAvailableBytes + nbFilledBytes) - nbFilledBytes;
+
+ /* By how much did we "miss" the target on that frame */
+ delta = target - vbr_rate;
+
+ target = nbAvailableBytes << (EntropyCoder.BITRES + 3);
+
+ /*If the frame is silent we don't adjust our drift, otherwise
+ the encoder will shoot to very high rates after hitting a
+ span of silence, but we do allow the EntropyCoder.BITRES to refill.
+ This means that we'll undershoot our target in CVBR/VBR modes
+ on files with lots of silence. */
+ if (silence != 0) {
+ nbAvailableBytes = 2;
+ target = 2 * 8 << EntropyCoder.BITRES;
+ delta = 0;
+ }
+
+ if (this.vbr_count < 970) {
+ this.vbr_count++;
+ alpha = Inlines.celt_rcp(Inlines.SHL32((this.vbr_count + 20), 16));
+ } else {
+ alpha = ((short) (0.5 + (.001f) * (((int) 1) << (15))))/*Inlines.QCONST16(.001f, 15)*/;
+ }
+ /* How many bits have we used in excess of what we're allowed */
+ if (this.constrained_vbr != 0) {
+ this.vbr_reservoir += target - vbr_rate;
+ }
+ /*printf ("%d\n", st.vbr_reservoir);*/
+
+ /* Compute the offset we need to apply in order to reach the target */
+ if (this.constrained_vbr != 0) {
+ this.vbr_drift += (int) Inlines.MULT16_32_Q15(alpha, (delta * (1 << lm_diff)) - this.vbr_offset - this.vbr_drift);
+ this.vbr_offset = -this.vbr_drift;
+ }
+ /*printf ("%d\n", st.vbr_drift);*/
+
+ if (this.constrained_vbr != 0 && this.vbr_reservoir < 0) {
+ /* We're under the min value -- increase rate */
+ int adjust = (-this.vbr_reservoir) / (8 << EntropyCoder.BITRES);
+ /* Unless we're just coding silence */
+ nbAvailableBytes += silence != 0 ? 0 : adjust;
+ this.vbr_reservoir = 0;
+ /*printf ("+%d\n", adjust);*/
+ }
+ nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, nbAvailableBytes + nbFilledBytes);
+ /*printf("%d\n", nbCompressedBytes*50*8);*/
+ /* This moves the raw bits to take into account the new compressed size */
+ enc.enc_shrink(nbCompressedBytes);
+ }
+
+ /* Bit allocation */
+ fine_quant = new int[nbEBands];
+ pulses = new int[nbEBands];
+ fine_priority = new int[nbEBands];
+
+ /* bits = packet size - where we are - safety*/
+ bits = (((int) nbCompressedBytes * 8) << EntropyCoder.BITRES) - (int) enc.tell_frac() - 1;
+ anti_collapse_rsv = isTransient != 0 && LM >= 2 && bits >= ((LM + 2) << EntropyCoder.BITRES) ? (1 << EntropyCoder.BITRES) : 0;
+ bits -= anti_collapse_rsv;
+ signalBandwidth = end - 1;
+
+ if (this.analysis.enabled && this.analysis.valid != 0) {
+ int min_bandwidth;
+ if (equiv_rate < (int) 32000 * C) {
+ min_bandwidth = 13;
+ } else if (equiv_rate < (int) 48000 * C) {
+ min_bandwidth = 16;
+ } else if (equiv_rate < (int) 60000 * C) {
+ min_bandwidth = 18;
+ } else if (equiv_rate < (int) 80000 * C) {
+ min_bandwidth = 19;
+ } else {
+ min_bandwidth = 20;
+ }
+ signalBandwidth = Inlines.IMAX(this.analysis.bandwidth, min_bandwidth);
+ }
+
+ if (this.lfe != 0) {
+ signalBandwidth = 1;
+ }
+
+ BoxedValueInt boxed_intensity = new BoxedValueInt(this.intensity);
+ BoxedValueInt boxed_balance = new BoxedValueInt(0);
+ BoxedValueInt boxed_dual_stereo = new BoxedValueInt(dual_stereo);
+ codedBands = Rate.compute_allocation(mode, start, end, offsets, cap,
+ alloc_trim, boxed_intensity, boxed_dual_stereo, bits, boxed_balance, pulses,
+ fine_quant, fine_priority, C, LM, enc, 1, this.lastCodedBands, signalBandwidth);
+ this.intensity = boxed_intensity.Val;
+ balance = boxed_balance.Val;
+ dual_stereo = boxed_dual_stereo.Val;
+
+ if (this.lastCodedBands != 0) {
+ this.lastCodedBands = Inlines.IMIN(this.lastCodedBands + 1, Inlines.IMAX(this.lastCodedBands - 1, codedBands));
+ } else {
+ this.lastCodedBands = codedBands;
+ }
+
+ QuantizeBands.quant_fine_energy(mode, start, end, this.oldBandE, error, fine_quant, enc, C);
+
+ /* Residual quantisation */
+ collapse_masks = new short[C * nbEBands];
+ BoxedValueInt boxed_rng = new BoxedValueInt(this.rng);
+ Bands.quant_all_bands(1, mode, start, end, X[0], C == 2 ? X[1] : null, collapse_masks,
+ bandE, pulses, shortBlocks, this.spread_decision,
+ dual_stereo, this.intensity, tf_res, nbCompressedBytes * (8 << EntropyCoder.BITRES) - anti_collapse_rsv,
+ balance, enc, LM, codedBands, boxed_rng);
+ this.rng = boxed_rng.Val;
+
+ if (anti_collapse_rsv > 0) {
+ anti_collapse_on = (this.consec_transient < 2) ? 1 : 0;
+ enc.enc_bits(anti_collapse_on, 1);
+ }
+
+ QuantizeBands.quant_energy_finalise(mode, start, end, this.oldBandE, error, fine_quant, fine_priority, nbCompressedBytes * 8 - (int) enc.tell(), enc, C);
+
+ if (silence != 0) {
+ for (i = 0; i < nbEBands; i++) {
+ this.oldBandE[0][i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ if (C == 2) {
+ for (i = 0; i < nbEBands; i++) {
+ this.oldBandE[1][i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ }
+ }
+
+ this.prefilter_period = pitch_index;
+ this.prefilter_gain = gain1;
+ this.prefilter_tapset = prefilter_tapset;
+
+ if (CC == 2 && C == 1) {
+ System.arraycopy(oldBandE[0], 0, oldBandE[1], 0, nbEBands);
+ }
+
+ if (isTransient == 0) {
+ System.arraycopy(oldLogE[0], 0, oldLogE2[0], 0, nbEBands);
+ System.arraycopy(oldBandE[0], 0, oldLogE[0], 0, nbEBands);
+ if (CC == 2) {
+ System.arraycopy(oldLogE[1], 0, oldLogE2[1], 0, nbEBands);
+ System.arraycopy(oldBandE[1], 0, oldLogE[1], 0, nbEBands);
+ }
+ } else {
+ for (i = 0; i < nbEBands; i++) {
+ oldLogE[0][i] = Inlines.MIN16(oldLogE[0][i], oldBandE[0][i]);
+ }
+ if (CC == 2) {
+ for (i = 0; i < nbEBands; i++) {
+ oldLogE[1][i] = Inlines.MIN16(oldLogE[1][i], oldBandE[1][i]);
+ }
+ }
+ }
+
+ /* In case start or end were to change */
+ c = 0;
+ do {
+ for (i = 0; i < start; i++) {
+ oldBandE[c][i] = 0;
+ oldLogE[c][i] = oldLogE2[c][i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ for (i = end; i < nbEBands; i++) {
+ oldBandE[c][i] = 0;
+ oldLogE[c][i] = oldLogE2[c][i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ } while (++c < CC);
+
+ if (isTransient != 0 || transient_got_disabled != 0) {
+ this.consec_transient++;
+ } else {
+ this.consec_transient = 0;
+ }
+ this.rng = (int) enc.rng;
+
+ /* If there's any room left (can only happen for very high rates),
+ it's already filled with zeros */
+ enc.enc_done();
+
+ if (enc.get_error() != 0) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ } else {
+ return nbCompressedBytes;
+ }
+ }
+
+ void SetComplexity(int value) {
+ if (value < 0 || value > 10) {
+ throw new IllegalArgumentException("Complexity must be between 0 and 10 inclusive");
+ }
+ this.complexity = value;
+ }
+
+ void SetStartBand(int value) {
+ if (value < 0 || value >= this.mode.nbEBands) {
+ throw new IllegalArgumentException("Start band above max number of ebands (or negative)");
+ }
+ this.start = value;
+ }
+
+ void SetEndBand(int value) {
+ if (value < 1 || value > this.mode.nbEBands) {
+ throw new IllegalArgumentException("End band above max number of ebands (or less than 1)");
+ }
+ this.end = value;
+ }
+
+ void SetPacketLossPercent(int value) {
+ if (value < 0 || value > 100) {
+ throw new IllegalArgumentException("Packet loss must be between 0 and 100");
+ }
+ this.loss_rate = value;
+ }
+
+ void SetPrediction(int value) {
+ if (value < 0 || value > 2) {
+ throw new IllegalArgumentException("CELT prediction mode must be 0, 1, or 2");
+ }
+ this.disable_pf = (value <= 1) ? 1 : 0;
+ this.force_intra = (value == 0) ? 1 : 0;
+ }
+
+ void SetVBRConstraint(boolean value) {
+ this.constrained_vbr = value ? 1 : 0;
+ }
+
+ void SetVBR(boolean value) {
+ this.vbr = value ? 1 : 0;
+ }
+
+ void SetBitrate(int value) {
+ if (value <= 500 && value != OpusConstants.OPUS_BITRATE_MAX) {
+ throw new IllegalArgumentException("Bitrate out of range");
+ }
+ value = Inlines.IMIN(value, 260000 * this.channels);
+ this.bitrate = value;
+ }
+
+ void SetChannels(int value) {
+ if (value < 1 || value > 2) {
+ throw new IllegalArgumentException("Channel count must be 1 or 2");
+ }
+ this.stream_channels = value;
+ }
+
+ void SetLSBDepth(int value) {
+ if (value < 8 || value > 24) {
+ throw new IllegalArgumentException("Bit depth must be between 8 and 24");
+ }
+ this.lsb_depth = value;
+ }
+
+ int GetLSBDepth() {
+ return this.lsb_depth;
+ }
+
+ void SetExpertFrameDuration(OpusFramesize value) {
+ this.variable_duration = value;
+ }
+
+ void SetSignalling(int value) {
+ this.signalling = value;
+ }
+
+ void SetAnalysis(AnalysisInfo value) {
+ if (value == null) {
+ throw new IllegalArgumentException("AnalysisInfo");
+ }
+ this.analysis.Assign(value);
+ }
+
+ CeltMode GetMode() {
+ return this.mode;
+ }
+
+ int GetFinalRange() {
+ return this.rng;
+ }
+
+ void SetLFE(int value) {
+ this.lfe = value;
+ }
+
+ void SetEnergyMask(int[] value) {
+ this.energy_mask = value;
+ }
+
+}
diff --git a/app/src/main/java/org/concentus/CeltLPC.java b/app/src/main/java/org/concentus/CeltLPC.java
new file mode 100644
index 0000000000..a3aa0c876b
--- /dev/null
+++ b/app/src/main/java/org/concentus/CeltLPC.java
@@ -0,0 +1,153 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class CeltLPC {
+
+ static void celt_lpc(
+ int[] _lpc, /* out: [0...p-1] LPC coefficients */
+ int[] ac, /* in: [0...p] autocorrelation values */
+ int p) {
+ int i, j;
+ int r;
+ int error = ac[0];
+ int[] lpc = new int[p];
+
+ //Arrays.MemSet(lpc, 0, p); strictly, this is not necessary since the runtime zeroes memory for us
+ if (ac[0] != 0) {
+ for (i = 0; i < p; i++) {
+ /* Sum up this iteration's reflection coefficient */
+ int rr = 0;
+ for (j = 0; j < i; j++) {
+ rr += Inlines.MULT32_32_Q31(lpc[j], ac[i - j]);
+ }
+ rr += Inlines.SHR32(ac[i + 1], 3);
+ r = 0 - Inlines.frac_div32(Inlines.SHL32(rr, 3), error);
+ /* Update LPC coefficients and total error */
+ lpc[i] = Inlines.SHR32(r, 3);
+
+ for (j = 0; j < (i + 1) >> 1; j++) {
+ int tmp1, tmp2;
+ tmp1 = lpc[j];
+ tmp2 = lpc[i - 1 - j];
+ lpc[j] = tmp1 + Inlines.MULT32_32_Q31(r, tmp2);
+ lpc[i - 1 - j] = tmp2 + Inlines.MULT32_32_Q31(r, tmp1);
+ }
+
+ error = error - Inlines.MULT32_32_Q31(Inlines.MULT32_32_Q31(r, r), error);
+
+ /* Bail out once we get 30 dB gain */
+ if (error < Inlines.SHR32(ac[0], 10)) {
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < p; i++) {
+ _lpc[i] = Inlines.ROUND16((lpc[i]), 16);
+ }
+ }
+
+ static void celt_iir(
+ int[] _x,
+ int _x_ptr,
+ int[] den,
+ int[] _y,
+ int _y_ptr,
+ int N,
+ int ord,
+ int[] mem) {
+ int i, j;
+ int[] rden = new int[ord];
+ int[] y = new int[N + ord];
+ Inlines.OpusAssert((ord & 3) == 0);
+
+ BoxedValueInt _sum0 = new BoxedValueInt(0);
+ BoxedValueInt _sum1 = new BoxedValueInt(0);
+ BoxedValueInt _sum2 = new BoxedValueInt(0);
+ BoxedValueInt _sum3 = new BoxedValueInt(0);
+ int sum0, sum1, sum2, sum3;
+
+ for (i = 0; i < ord; i++) {
+ rden[i] = den[ord - i - 1];
+ }
+ for (i = 0; i < ord; i++) {
+ y[i] = (0 - mem[ord - i - 1]);
+ }
+ for (; i < N + ord; i++) {
+ y[i] = 0;
+ }
+ for (i = 0; i < N - 3; i += 4) {
+ /* Unroll by 4 as if it were an FIR filter */
+ _sum0.Val = _x[_x_ptr + i];
+ _sum1.Val = _x[_x_ptr + i + 1];
+ _sum2.Val = _x[_x_ptr + i + 2];
+ _sum3.Val = _x[_x_ptr + i + 3];
+ Kernels.xcorr_kernel(rden, y, i, _sum0, _sum1, _sum2, _sum3, ord);
+ sum0 = _sum0.Val;
+ sum1 = _sum1.Val;
+ sum2 = _sum2.Val;
+ sum3 = _sum3.Val;
+
+ /* Patch up the result to compensate for the fact that this is an IIR */
+ y[i + ord] = (0 - Inlines.ROUND16((sum0), CeltConstants.SIG_SHIFT));
+ _y[_y_ptr + i] = sum0;
+ sum1 = Inlines.MAC16_16(sum1, y[i + ord], den[0]);
+ y[i + ord + 1] = (0 - Inlines.ROUND16((sum1), CeltConstants.SIG_SHIFT));
+ _y[_y_ptr + i + 1] = sum1;
+ sum2 = Inlines.MAC16_16(sum2, y[i + ord + 1], den[0]);
+ sum2 = Inlines.MAC16_16(sum2, y[i + ord], den[1]);
+ y[i + ord + 2] = (0 - Inlines.ROUND16((sum2), CeltConstants.SIG_SHIFT));
+ _y[_y_ptr + i + 2] = sum2;
+
+ sum3 = Inlines.MAC16_16(sum3, y[i + ord + 2], den[0]);
+ sum3 = Inlines.MAC16_16(sum3, y[i + ord + 1], den[1]);
+ sum3 = Inlines.MAC16_16(sum3, y[i + ord], den[2]);
+ y[i + ord + 3] = (0 - Inlines.ROUND16((sum3), CeltConstants.SIG_SHIFT));
+ _y[_y_ptr + i + 3] = sum3;
+ }
+ for (; i < N; i++) {
+ int sum = _x[_x_ptr + i];
+ for (j = 0; j < ord; j++) {
+ sum -= Inlines.MULT16_16(rden[j], y[i + j]);
+ }
+ y[i + ord] = Inlines.ROUND16((sum), CeltConstants.SIG_SHIFT);
+ _y[_y_ptr + i] = sum;
+ }
+ for (i = 0; i < ord; i++) {
+ mem[i] = (_y[_y_ptr + N - i - 1]);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/CeltMode.java b/app/src/main/java/org/concentus/CeltMode.java
new file mode 100644
index 0000000000..921e3b7007
--- /dev/null
+++ b/app/src/main/java/org/concentus/CeltMode.java
@@ -0,0 +1,107 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class CeltMode {
+
+ int Fs = 0;
+ int overlap = 0;
+
+ int nbEBands = 0;
+ int effEBands = 0;
+ int[] preemph = {0, 0, 0, 0};
+
+ ///
+ /// Definition for each "pseudo-critical band"
+ ///
+ short[] eBands = null;
+
+ int maxLM = 0;
+ int nbShortMdcts = 0;
+ int shortMdctSize = 0;
+
+ ///
+ /// Number of lines in allocVectors
+ ///
+ int nbAllocVectors = 0;
+
+ ///
+ /// Number of bits in each band for several rates
+ ///
+ short[] allocVectors = null;
+ short[] logN = null;
+
+ int[] window = null;
+ MDCTLookup mdct = new MDCTLookup();
+ PulseCache cache = new PulseCache();
+
+ private CeltMode() {
+ }
+
+ static final CeltMode mode48000_960_120 = new CeltMode();
+
+ static {
+ mode48000_960_120.Fs = 48000;
+ mode48000_960_120.overlap = 120;
+ mode48000_960_120.nbEBands = 21;
+ mode48000_960_120.effEBands = 21;
+ mode48000_960_120.preemph = new int[]{27853, 0, 4096, 8192};
+ mode48000_960_120.eBands = CeltTables.eband5ms;
+ mode48000_960_120.maxLM = 3;
+ mode48000_960_120.nbShortMdcts = 8;
+ mode48000_960_120.shortMdctSize = 120;
+ mode48000_960_120.nbAllocVectors = 11;
+ mode48000_960_120.allocVectors = CeltTables.band_allocation;
+ mode48000_960_120.logN = CeltTables.logN400;
+ mode48000_960_120.window = CeltTables.window120;
+ mode48000_960_120.mdct = new MDCTLookup();
+
+ mode48000_960_120.mdct.n = 1920;
+ mode48000_960_120.mdct.maxshift = 3;
+ mode48000_960_120.mdct.kfft = new FFTState[]{
+ CeltTables.fft_state48000_960_0,
+ CeltTables.fft_state48000_960_1,
+ CeltTables.fft_state48000_960_2,
+ CeltTables.fft_state48000_960_3,};
+
+ mode48000_960_120.mdct.trig = CeltTables.mdct_twiddles960;
+ mode48000_960_120.cache = new PulseCache();
+ mode48000_960_120.cache.size = 392;
+ mode48000_960_120.cache.index = CeltTables.cache_index50;
+ mode48000_960_120.cache.bits = CeltTables.cache_bits50;
+ mode48000_960_120.cache.caps = CeltTables.cache_caps50;
+ }
+;
+}
diff --git a/app/src/main/java/org/concentus/CeltPitchXCorr.java b/app/src/main/java/org/concentus/CeltPitchXCorr.java
new file mode 100644
index 0000000000..a39672512f
--- /dev/null
+++ b/app/src/main/java/org/concentus/CeltPitchXCorr.java
@@ -0,0 +1,153 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class CeltPitchXCorr {
+
+ static int pitch_xcorr(
+ int[] _x,
+ int[] _y,
+ int[] xcorr,
+ int len,
+ int max_pitch) {
+ int i;
+ int maxcorr = 1;
+ Inlines.OpusAssert(max_pitch > 0);
+ BoxedValueInt sum0 = new BoxedValueInt(0);
+ BoxedValueInt sum1 = new BoxedValueInt(0);
+ BoxedValueInt sum2 = new BoxedValueInt(0);
+ BoxedValueInt sum3 = new BoxedValueInt(0);
+ for (i = 0; i < max_pitch - 3; i += 4) {
+ sum0.Val = 0;
+ sum1.Val = 0;
+ sum2.Val = 0;
+ sum3.Val = 0;
+ Kernels.xcorr_kernel(_x, _y, i, sum0, sum1, sum2, sum3, len);
+ xcorr[i] = sum0.Val;
+ xcorr[i + 1] = sum1.Val;
+ xcorr[i + 2] = sum2.Val;
+ xcorr[i + 3] = sum3.Val;
+ sum0.Val = Inlines.MAX32(sum0.Val, sum1.Val);
+ sum2.Val = Inlines.MAX32(sum2.Val, sum3.Val);
+ sum0.Val = Inlines.MAX32(sum0.Val, sum2.Val);
+ maxcorr = Inlines.MAX32(maxcorr, sum0.Val);
+ }
+ /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
+ for (; i < max_pitch; i++) {
+ int inner_sum = Kernels.celt_inner_prod(_x, 0, _y, i, len);
+ xcorr[i] = inner_sum;
+ maxcorr = Inlines.MAX32(maxcorr, inner_sum);
+ }
+ return maxcorr;
+ }
+
+ static int pitch_xcorr(
+ short[] _x,
+ int _x_ptr,
+ short[] _y,
+ int _y_ptr,
+ int[] xcorr,
+ int len,
+ int max_pitch) {
+ int i;
+ int maxcorr = 1;
+ Inlines.OpusAssert(max_pitch > 0);
+ BoxedValueInt sum0 = new BoxedValueInt(0);
+ BoxedValueInt sum1 = new BoxedValueInt(0);
+ BoxedValueInt sum2 = new BoxedValueInt(0);
+ BoxedValueInt sum3 = new BoxedValueInt(0);
+ for (i = 0; i < max_pitch - 3; i += 4) {
+ sum0.Val = 0;
+ sum1.Val = 0;
+ sum2.Val = 0;
+ sum3.Val = 0;
+ Kernels.xcorr_kernel(_x, _x_ptr, _y, _y_ptr + i, sum0, sum1, sum2, sum3, len);
+
+ xcorr[i] = sum0.Val;
+ xcorr[i + 1] = sum1.Val;
+ xcorr[i + 2] = sum2.Val;
+ xcorr[i + 3] = sum3.Val;
+ sum0.Val = Inlines.MAX32(sum0.Val, sum1.Val);
+ sum2.Val = Inlines.MAX32(sum2.Val, sum3.Val);
+ sum0.Val = Inlines.MAX32(sum0.Val, sum2.Val);
+ maxcorr = Inlines.MAX32(maxcorr, sum0.Val);
+ }
+ /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
+ for (; i < max_pitch; i++) {
+ int inner_sum = Kernels.celt_inner_prod(_x, _x_ptr, _y, _y_ptr + i, len);
+ xcorr[i] = inner_sum;
+ maxcorr = Inlines.MAX32(maxcorr, inner_sum);
+ }
+ return maxcorr;
+ }
+
+ static int pitch_xcorr(
+ short[] _x,
+ short[] _y,
+ int[] xcorr,
+ int len,
+ int max_pitch) {
+ int i;
+ int maxcorr = 1;
+ Inlines.OpusAssert(max_pitch > 0);
+ BoxedValueInt sum0 = new BoxedValueInt(0);
+ BoxedValueInt sum1 = new BoxedValueInt(0);
+ BoxedValueInt sum2 = new BoxedValueInt(0);
+ BoxedValueInt sum3 = new BoxedValueInt(0);
+ for (i = 0; i < max_pitch - 3; i += 4) {
+ sum0.Val = 0;
+ sum1.Val = 0;
+ sum2.Val = 0;
+ sum3.Val = 0;
+ Kernels.xcorr_kernel(_x, 0, _y, i, sum0, sum1, sum2, sum3, len);
+
+ xcorr[i] = sum0.Val;
+ xcorr[i + 1] = sum1.Val;
+ xcorr[i + 2] = sum2.Val;
+ xcorr[i + 3] = sum3.Val;
+ sum0.Val = Inlines.MAX32(sum0.Val, sum1.Val);
+ sum2.Val = Inlines.MAX32(sum2.Val, sum3.Val);
+ sum0.Val = Inlines.MAX32(sum0.Val, sum2.Val);
+ maxcorr = Inlines.MAX32(maxcorr, sum0.Val);
+ }
+ /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
+ for (; i < max_pitch; i++) {
+ int inner_sum = Kernels.celt_inner_prod(_x, _y, i, len);
+ xcorr[i] = inner_sum;
+ maxcorr = Inlines.MAX32(maxcorr, inner_sum);
+ }
+ return maxcorr;
+ }
+}
diff --git a/app/src/main/java/org/concentus/CeltTables.java b/app/src/main/java/org/concentus/CeltTables.java
new file mode 100644
index 0000000000..90c8500f12
--- /dev/null
+++ b/app/src/main/java/org/concentus/CeltTables.java
@@ -0,0 +1,1116 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class CeltTables {
+
+ /* Mean energy in each band quantized in Q4 */
+ static final byte[] eMeans/*[25]*/ = {
+ 103, 100, 92, 85, 81,
+ 77, 72, 70, 78, 75,
+ 73, 71, 78, 74, 69,
+ 72, 70, 74, 76, 71,
+ 60, 60, 60, 60, 60
+ };
+
+ /* Indexing table for converting from natural Hadamard to ordery Hadamard
+ This is essentially a bit-reversed Gray, on top of which we've added
+ an inversion of the order because we want the DC at the end rather than
+ the beginning. The lines are for N=2, 4, 8, 16 */
+ static final int[] ordery_table = {
+ 1, 0,
+ 3, 0, 2, 1,
+ 7, 0, 4, 3, 6, 1, 5, 2,
+ 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5,};
+
+ static final short[] eband5ms = {
+ /*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100
+ };
+
+ /*Parameters of the Laplace-like probability models used for the coarse energy.
+ There is one pair of parameters for each frame size, prediction type
+ (inter/intra), and band number.
+ The first number of each pair is the probability of 0, and the second is the
+ decay rate, both in Q8 precision.*/
+ static final short[][][] e_prob_model = {
+ /*120 sample frames.*/
+ new short[][]{
+ /*Inter*/
+ new short[]{
+ 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128,
+ 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40,
+ 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11
+ },
+ /*Intra*/
+ new short[]{
+ 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132,
+ 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66,
+ 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50
+ }
+ },
+ /*240 sample frames.*/
+ new short[][]{
+ /*Inter*/
+ new short[]{
+ 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74,
+ 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18,
+ 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9
+ },
+ /*Intra*/
+ new short[]{
+ 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91,
+ 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60,
+ 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45
+ }
+ },
+ /*480 sample frames.*/
+ new short[][]{
+ /*Inter*/
+ new short[]{
+ 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38,
+ 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16,
+ 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10
+ },
+ /*Intra*/
+ new short[]{
+ 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73,
+ 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55,
+ 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42
+ }
+ },
+ /*960 sample frames.*/
+ new short[][]{
+ /*Inter*/
+ new short[]{
+ 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36,
+ 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25,
+ 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15
+ },
+ /*Intra*/
+ new short[]{
+ 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72,
+ 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52,
+ 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40
+ }
+ }
+ };
+
+ static final byte[][] tf_select_table = {
+ new byte[]{0, -1, 0, -1, 0, -1, 0, -1},
+ new byte[]{0, -1, 0, -2, 1, 0, 1, -1},
+ new byte[]{0, -2, 0, -3, 2, 0, 1, -1},
+ new byte[]{0, -2, 0, -3, 3, 0, 1, -1},};
+
+ static final short[] trim_icdf = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0};
+ /* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */
+ static final short[] spread_icdf = {25, 23, 2, 0};
+
+ static final short[] tapset_icdf = {2, 1, 0};
+
+ /* Bit allocation table in units of 1/32 bit/sample (0.1875 dB SNR) */
+ static final short[] band_allocation = {
+ /*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0,
+ 110, 100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0,
+ 118, 110, 103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0,
+ 126, 119, 112, 104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0,
+ 134, 127, 120, 114, 103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1,
+ 144, 137, 130, 124, 113, 107, 101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1,
+ 152, 145, 138, 132, 123, 117, 111, 105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1,
+ 162, 155, 148, 142, 133, 127, 121, 115, 108, 102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1,
+ 172, 165, 158, 152, 143, 137, 131, 125, 118, 112, 106, 100, 94, 87, 81, 75, 69, 63, 56, 45, 20,
+ 200, 200, 200, 200, 200, 200, 200, 200, 198, 193, 188, 183, 178, 173, 168, 163, 158, 153, 148, 129, 104,};
+
+ /*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)).
+ Thus, the number of entries in row I is the larger of the maximum number of
+ pulses we will ever allocate for a given N=I (K=128, or however many fit in
+ 32 bits, whichever is smaller), plus one, and the maximum N for which
+ K=I-1 pulses fit in 32 bits.
+ The largest band size in an Opus Custom mode is 208.
+ Otherwise, we can limit things to the set of N which can be achieved by
+ splitting a band from a standard Opus mode: 176, 144, 96, 88, 72, 64, 48,
+ 44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/
+ static final long[] CELT_PVQ_U_DATA = {
+ /*N=0, K=0...176:*/
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /*N=1, K=1...176:*/
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /*N=2, K=2...176:*/
+ 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41,
+ 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79,
+ 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113,
+ 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143,
+ 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
+ 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203,
+ 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233,
+ 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263,
+ 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293,
+ 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323,
+ 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351,
+ /*N=3, K=3...176:*/
+ 13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613,
+ 685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861,
+ 1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785,
+ 3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385,
+ 6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661,
+ 9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961,
+ 13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745,
+ 17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013,
+ 21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765,
+ 26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001,
+ 31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721,
+ 37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925,
+ 43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613,
+ 50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785,
+ 57461, 58141, 58825, 59513, 60205, 60901, 61601,
+ /*N=4, K=4...176:*/
+ 63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017,
+ 7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775,
+ 30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153,
+ 82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193,
+ 161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575,
+ 267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217,
+ 410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951,
+ 597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609,
+ 833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023,
+ 1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407,
+ 1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759,
+ 1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175,
+ 2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751,
+ 2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583,
+ 3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767,
+ 3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399,
+ 4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575,
+ 5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391,
+ 6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943,
+ 7085049, 7207551,
+ /*N=5, K=5...176:*/
+ 321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041,
+ 50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401,
+ 330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241,
+ 1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241,
+ 2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801,
+ 4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849,
+ 8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849,
+ 13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809,
+ 20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881,
+ 29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641,
+ 40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081,
+ 55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609,
+ 73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049,
+ 95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641,
+ 122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041,
+ 155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321,
+ 193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969,
+ 238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889,
+ 290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401,
+ 351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241,
+ 420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561,
+ 500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929,
+ 590359041, 604167209, 618216201, 632508801,
+ /*N=6, K=6...96:*/
+ 1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047,
+ 335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409,
+ 2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793,
+ 11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455,
+ 29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189,
+ 64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651,
+ 128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185,
+ 235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647,
+ 402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229,
+ 655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283,
+ 1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135,
+ 1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187,
+ 2011371957, 2120032959,
+ /*N=7, K=7...54*/
+ 8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777,
+ 1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233,
+ 19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013,
+ 88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805,
+ 292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433,
+ 793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821,
+ 1667010073, 1870535785, 2094367717,
+ /*N=8, K=8...37*/
+ 48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767,
+ 9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017,
+ 104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351,
+ 638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615,
+ 2229491905L,
+ /*N=9, K=9...28:*/
+ 265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777,
+ 39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145,
+ 628496897L, 872893441L, 1196924561L, 1621925137L, 2173806145L,
+ /*N=10, K=10...24:*/
+ 1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073,
+ 254831667L, 413442773L, 654862247L, 1014889769L, 1541911931L, 2300409629L,
+ 3375210671L,
+ /*N=11, K=11...19:*/
+ 8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585,
+ 948062325, 1616336765,
+ /*N=12, K=12...18:*/
+ 45046719, 103274625, 224298231, 464387817, 921406335, 1759885185,
+ 3248227095L,
+ /*N=13, K=13...16:*/
+ 251595969L, 579168825L, 1267854873L, 2653649025L,
+ /*N=14, K=14:*/
+ 1409933619
+ };
+
+ static final int[] window120 = {
+ 2, 20, 55, 108, 178,
+ 266, 372, 494, 635, 792,
+ 966, 1157, 1365, 1590, 1831,
+ 2089, 2362, 2651, 2956, 3276,
+ 3611, 3961, 4325, 4703, 5094,
+ 5499, 5916, 6346, 6788, 7241,
+ 7705, 8179, 8663, 9156, 9657,
+ 10167, 10684, 11207, 11736, 12271,
+ 12810, 13353, 13899, 14447, 14997,
+ 15547, 16098, 16648, 17197, 17744,
+ 18287, 18827, 19363, 19893, 20418,
+ 20936, 21447, 21950, 22445, 22931,
+ 23407, 23874, 24330, 24774, 25208,
+ 25629, 26039, 26435, 26819, 27190,
+ 27548, 27893, 28224, 28541, 28845,
+ 29135, 29411, 29674, 29924, 30160,
+ 30384, 30594, 30792, 30977, 31151,
+ 31313, 31463, 31602, 31731, 31849,
+ 31958, 32057, 32148, 32229, 32303,
+ 32370, 32429, 32481, 32528, 32568,
+ 32604, 32634, 32661, 32683, 32701,
+ 32717, 32729, 32740, 32748, 32754,
+ 32758, 32762, 32764, 32766, 32767,
+ 32767, 32767, 32767, 32767, 32767,};
+
+ static final short[] logN400
+ = {0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36,};
+
+ static final short[] cache_index50 = {
+ -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41,
+ 82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41,
+ 41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41,
+ 41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305,
+ 318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240,
+ 305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240,
+ 240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387,};
+
+ static final short[] cache_bits50 = {
+ 40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28,
+ 31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50,
+ 51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65,
+ 66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61,
+ 64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92,
+ 94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123,
+ 124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94,
+ 97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139,
+ 142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35,
+ 28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149,
+ 153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225,
+ 229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157,
+ 166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63,
+ 86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250,
+ 25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180,
+ 185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89,
+ 110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41,
+ 74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138,
+ 163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214,
+ 228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49,
+ 90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47,
+ 87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57,
+ 106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187,
+ 224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127,
+ 182, 234,};
+
+ static final short[] cache_caps50 = {
+ 224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185,
+ 178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
+ 240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160,
+ 160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172,
+ 138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207,
+ 204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185,
+ 185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39,
+ 207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201,
+ 188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+ 193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204,
+ 204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175,
+ 140, 66, 40,};
+
+ static final short[] fft_twiddles48000_960
+ = new short[]{
+ 32767, 0, 32766, -429,
+ 32757, -858, 32743, -1287,
+ 32724, -1715, 32698, -2143,
+ 32667, -2570, 32631, -2998,
+ 32588, -3425, 32541, -3851,
+ 32488, -4277, 32429, -4701,
+ 32364, -5125, 32295, -5548,
+ 32219, -5971, 32138, -6393,
+ 32051, -6813, 31960, -7231,
+ 31863, -7650, 31760, -8067,
+ 31652, -8481, 31539, -8895,
+ 31419, -9306, 31294, -9716,
+ 31165, -10126, 31030, -10532,
+ 30889, -10937, 30743, -11340,
+ 30592, -11741, 30436, -12141,
+ 30274, -12540, 30107, -12935,
+ 29936, -13328, 29758, -13718,
+ 29577, -14107, 29390, -14493,
+ 29197, -14875, 29000, -15257,
+ 28797, -15635, 28590, -16010,
+ 28379, -16384, 28162, -16753,
+ 27940, -17119, 27714, -17484,
+ 27482, -17845, 27246, -18205,
+ 27006, -18560, 26760, -18911,
+ 26510, -19260, 26257, -19606,
+ 25997, -19947, 25734, -20286,
+ 25466, -20621, 25194, -20952,
+ 24918, -21281, 24637, -21605,
+ 24353, -21926, 24063, -22242,
+ 23770, -22555, 23473, -22865,
+ 23171, -23171, 22866, -23472,
+ 22557, -23769, 22244, -24063,
+ 21927, -24352, 21606, -24636,
+ 21282, -24917, 20954, -25194,
+ 20622, -25465, 20288, -25733,
+ 19949, -25997, 19607, -26255,
+ 19261, -26509, 18914, -26760,
+ 18561, -27004, 18205, -27246,
+ 17846, -27481, 17485, -27713,
+ 17122, -27940, 16755, -28162,
+ 16385, -28378, 16012, -28590,
+ 15636, -28797, 15258, -28999,
+ 14878, -29197, 14494, -29389,
+ 14108, -29576, 13720, -29757,
+ 13329, -29934, 12937, -30107,
+ 12540, -30274, 12142, -30435,
+ 11744, -30592, 11342, -30743,
+ 10939, -30889, 10534, -31030,
+ 10127, -31164, 9718, -31294,
+ 9307, -31418, 8895, -31537,
+ 8482, -31652, 8067, -31759,
+ 7650, -31862, 7233, -31960,
+ 6815, -32051, 6393, -32138,
+ 5973, -32219, 5549, -32294,
+ 5127, -32364, 4703, -32429,
+ 4278, -32487, 3852, -32541,
+ 3426, -32588, 2999, -32630,
+ 2572, -32667, 2144, -32698,
+ 1716, -32724, 1287, -32742,
+ 860, -32757, 430, -32766,
+ 0, -32767, -429, -32766,
+ -858, -32757, -1287, -32743,
+ -1715, -32724, -2143, -32698,
+ -2570, -32667, -2998, -32631,
+ -3425, -32588, -3851, -32541,
+ -4277, -32488, -4701, -32429,
+ -5125, -32364, -5548, -32295,
+ -5971, -32219, -6393, -32138,
+ -6813, -32051, -7231, -31960,
+ -7650, -31863, -8067, -31760,
+ -8481, -31652, -8895, -31539,
+ -9306, -31419, -9716, -31294,
+ -10126, -31165, -10532, -31030,
+ -10937, -30889, -11340, -30743,
+ -11741, -30592, -12141, -30436,
+ -12540, -30274, -12935, -30107,
+ -13328, -29936, -13718, -29758,
+ -14107, -29577, -14493, -29390,
+ -14875, -29197, -15257, -29000,
+ -15635, -28797, -16010, -28590,
+ -16384, -28379, -16753, -28162,
+ -17119, -27940, -17484, -27714,
+ -17845, -27482, -18205, -27246,
+ -18560, -27006, -18911, -26760,
+ -19260, -26510, -19606, -26257,
+ -19947, -25997, -20286, -25734,
+ -20621, -25466, -20952, -25194,
+ -21281, -24918, -21605, -24637,
+ -21926, -24353, -22242, -24063,
+ -22555, -23770, -22865, -23473,
+ -23171, -23171, -23472, -22866,
+ -23769, -22557, -24063, -22244,
+ -24352, -21927, -24636, -21606,
+ -24917, -21282, -25194, -20954,
+ -25465, -20622, -25733, -20288,
+ -25997, -19949, -26255, -19607,
+ -26509, -19261, -26760, -18914,
+ -27004, -18561, -27246, -18205,
+ -27481, -17846, -27713, -17485,
+ -27940, -17122, -28162, -16755,
+ -28378, -16385, -28590, -16012,
+ -28797, -15636, -28999, -15258,
+ -29197, -14878, -29389, -14494,
+ -29576, -14108, -29757, -13720,
+ -29934, -13329, -30107, -12937,
+ -30274, -12540, -30435, -12142,
+ -30592, -11744, -30743, -11342,
+ -30889, -10939, -31030, -10534,
+ -31164, -10127, -31294, -9718,
+ -31418, -9307, -31537, -8895,
+ -31652, -8482, -31759, -8067,
+ -31862, -7650, -31960, -7233,
+ -32051, -6815, -32138, -6393,
+ -32219, -5973, -32294, -5549,
+ -32364, -5127, -32429, -4703,
+ -32487, -4278, -32541, -3852,
+ -32588, -3426, -32630, -2999,
+ -32667, -2572, -32698, -2144,
+ -32724, -1716, -32742, -1287,
+ -32757, -860, -32766, -430,
+ -32767, 0, -32766, 429,
+ -32757, 858, -32743, 1287,
+ -32724, 1715, -32698, 2143,
+ -32667, 2570, -32631, 2998,
+ -32588, 3425, -32541, 3851,
+ -32488, 4277, -32429, 4701,
+ -32364, 5125, -32295, 5548,
+ -32219, 5971, -32138, 6393,
+ -32051, 6813, -31960, 7231,
+ -31863, 7650, -31760, 8067,
+ -31652, 8481, -31539, 8895,
+ -31419, 9306, -31294, 9716,
+ -31165, 10126, -31030, 10532,
+ -30889, 10937, -30743, 11340,
+ -30592, 11741, -30436, 12141,
+ -30274, 12540, -30107, 12935,
+ -29936, 13328, -29758, 13718,
+ -29577, 14107, -29390, 14493,
+ -29197, 14875, -29000, 15257,
+ -28797, 15635, -28590, 16010,
+ -28379, 16384, -28162, 16753,
+ -27940, 17119, -27714, 17484,
+ -27482, 17845, -27246, 18205,
+ -27006, 18560, -26760, 18911,
+ -26510, 19260, -26257, 19606,
+ -25997, 19947, -25734, 20286,
+ -25466, 20621, -25194, 20952,
+ -24918, 21281, -24637, 21605,
+ -24353, 21926, -24063, 22242,
+ -23770, 22555, -23473, 22865,
+ -23171, 23171, -22866, 23472,
+ -22557, 23769, -22244, 24063,
+ -21927, 24352, -21606, 24636,
+ -21282, 24917, -20954, 25194,
+ -20622, 25465, -20288, 25733,
+ -19949, 25997, -19607, 26255,
+ -19261, 26509, -18914, 26760,
+ -18561, 27004, -18205, 27246,
+ -17846, 27481, -17485, 27713,
+ -17122, 27940, -16755, 28162,
+ -16385, 28378, -16012, 28590,
+ -15636, 28797, -15258, 28999,
+ -14878, 29197, -14494, 29389,
+ -14108, 29576, -13720, 29757,
+ -13329, 29934, -12937, 30107,
+ -12540, 30274, -12142, 30435,
+ -11744, 30592, -11342, 30743,
+ -10939, 30889, -10534, 31030,
+ -10127, 31164, -9718, 31294,
+ -9307, 31418, -8895, 31537,
+ -8482, 31652, -8067, 31759,
+ -7650, 31862, -7233, 31960,
+ -6815, 32051, -6393, 32138,
+ -5973, 32219, -5549, 32294,
+ -5127, 32364, -4703, 32429,
+ -4278, 32487, -3852, 32541,
+ -3426, 32588, -2999, 32630,
+ -2572, 32667, -2144, 32698,
+ -1716, 32724, -1287, 32742,
+ -860, 32757, -430, 32766,
+ 0, 32767, 429, 32766,
+ 858, 32757, 1287, 32743,
+ 1715, 32724, 2143, 32698,
+ 2570, 32667, 2998, 32631,
+ 3425, 32588, 3851, 32541,
+ 4277, 32488, 4701, 32429,
+ 5125, 32364, 5548, 32295,
+ 5971, 32219, 6393, 32138,
+ 6813, 32051, 7231, 31960,
+ 7650, 31863, 8067, 31760,
+ 8481, 31652, 8895, 31539,
+ 9306, 31419, 9716, 31294,
+ 10126, 31165, 10532, 31030,
+ 10937, 30889, 11340, 30743,
+ 11741, 30592, 12141, 30436,
+ 12540, 30274, 12935, 30107,
+ 13328, 29936, 13718, 29758,
+ 14107, 29577, 14493, 29390,
+ 14875, 29197, 15257, 29000,
+ 15635, 28797, 16010, 28590,
+ 16384, 28379, 16753, 28162,
+ 17119, 27940, 17484, 27714,
+ 17845, 27482, 18205, 27246,
+ 18560, 27006, 18911, 26760,
+ 19260, 26510, 19606, 26257,
+ 19947, 25997, 20286, 25734,
+ 20621, 25466, 20952, 25194,
+ 21281, 24918, 21605, 24637,
+ 21926, 24353, 22242, 24063,
+ 22555, 23770, 22865, 23473,
+ 23171, 23171, 23472, 22866,
+ 23769, 22557, 24063, 22244,
+ 24352, 21927, 24636, 21606,
+ 24917, 21282, 25194, 20954,
+ 25465, 20622, 25733, 20288,
+ 25997, 19949, 26255, 19607,
+ 26509, 19261, 26760, 18914,
+ 27004, 18561, 27246, 18205,
+ 27481, 17846, 27713, 17485,
+ 27940, 17122, 28162, 16755,
+ 28378, 16385, 28590, 16012,
+ 28797, 15636, 28999, 15258,
+ 29197, 14878, 29389, 14494,
+ 29576, 14108, 29757, 13720,
+ 29934, 13329, 30107, 12937,
+ 30274, 12540, 30435, 12142,
+ 30592, 11744, 30743, 11342,
+ 30889, 10939, 31030, 10534,
+ 31164, 10127, 31294, 9718,
+ 31418, 9307, 31537, 8895,
+ 31652, 8482, 31759, 8067,
+ 31862, 7650, 31960, 7233,
+ 32051, 6815, 32138, 6393,
+ 32219, 5973, 32294, 5549,
+ 32364, 5127, 32429, 4703,
+ 32487, 4278, 32541, 3852,
+ 32588, 3426, 32630, 2999,
+ 32667, 2572, 32698, 2144,
+ 32724, 1716, 32742, 1287,
+ 32757, 860, 32766, 430
+ };
+
+ static final short[] fft_bitrev480 = {
+ 0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448,
+ 8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456,
+ 16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464,
+ 24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472,
+ 4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452,
+ 12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460,
+ 20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468,
+ 28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476,
+ 1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449,
+ 9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457,
+ 17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465,
+ 25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473,
+ 5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453,
+ 13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461,
+ 21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469,
+ 29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477,
+ 2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450,
+ 10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458,
+ 18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466,
+ 26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474,
+ 6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454,
+ 14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462,
+ 22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470,
+ 30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478,
+ 3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451,
+ 11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459,
+ 19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467,
+ 27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475,
+ 7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455,
+ 15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463,
+ 23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471,
+ 31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479,};
+
+ static final short[] fft_bitrev240 = {
+ 0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224,
+ 4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228,
+ 8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232,
+ 12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236,
+ 1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225,
+ 5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229,
+ 9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233,
+ 13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237,
+ 2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226,
+ 6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230,
+ 10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234,
+ 14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238,
+ 3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227,
+ 7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231,
+ 11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235,
+ 15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239,};
+
+ static final short[] fft_bitrev120 = {
+ 0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112,
+ 4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116,
+ 1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113,
+ 5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117,
+ 2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114,
+ 6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118,
+ 3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115,
+ 7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119,};
+
+ static final short[] fft_bitrev60 = {
+ 0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56,
+ 1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57,
+ 2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58,
+ 3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59,};
+
+ static final FFTState fft_state48000_960_0 = new FFTState();
+
+ static {
+ fft_state48000_960_0.nfft = 480;
+ fft_state48000_960_0.scale = 17476;
+ fft_state48000_960_0.scale_shift = 8;
+ fft_state48000_960_0.shift = -1;
+ fft_state48000_960_0.factors = new short[]{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0,};
+ fft_state48000_960_0.bitrev = fft_bitrev480;
+ fft_state48000_960_0.twiddles = fft_twiddles48000_960;
+ }
+ ;
+
+ static final FFTState fft_state48000_960_1 = new FFTState();
+
+ static {
+ fft_state48000_960_1.nfft = 240;
+ fft_state48000_960_1.scale = 17476;
+ fft_state48000_960_1.scale_shift = 7;
+ fft_state48000_960_1.shift = 1;
+ fft_state48000_960_1.factors = new short[]{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0,};
+ fft_state48000_960_1.bitrev = fft_bitrev240;
+ fft_state48000_960_1.twiddles = fft_twiddles48000_960;
+ }
+ ;
+
+ static final FFTState fft_state48000_960_2 = new FFTState();
+
+ static {
+ fft_state48000_960_2.nfft = 120;
+ fft_state48000_960_2.scale = 17476;
+ fft_state48000_960_2.scale_shift = 6;
+ fft_state48000_960_2.shift = 2;
+ fft_state48000_960_2.factors = new short[]{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0,};
+ fft_state48000_960_2.bitrev = fft_bitrev120;
+ fft_state48000_960_2.twiddles = fft_twiddles48000_960;
+ }
+ ;
+
+ static final FFTState fft_state48000_960_3 = new FFTState();
+
+ static {
+ fft_state48000_960_3.nfft = 60;
+ fft_state48000_960_3.scale = 17476;
+ fft_state48000_960_3.scale_shift = 5;
+ fft_state48000_960_3.shift = 3;
+ fft_state48000_960_3.factors = new short[]{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
+ fft_state48000_960_3.bitrev = fft_bitrev60;
+ fft_state48000_960_3.twiddles = fft_twiddles48000_960;
+ }
+ ;
+
+ static final short[] mdct_twiddles960 /*1800*/ = {
+ 32767, 32767, 32767, 32766, 32765,
+ 32763, 32761, 32759, 32756, 32753,
+ 32750, 32746, 32742, 32738, 32733,
+ 32728, 32722, 32717, 32710, 32704,
+ 32697, 32690, 32682, 32674, 32666,
+ 32657, 32648, 32639, 32629, 32619,
+ 32609, 32598, 32587, 32576, 32564,
+ 32552, 32539, 32526, 32513, 32500,
+ 32486, 32472, 32457, 32442, 32427,
+ 32411, 32395, 32379, 32362, 32345,
+ 32328, 32310, 32292, 32274, 32255,
+ 32236, 32217, 32197, 32177, 32157,
+ 32136, 32115, 32093, 32071, 32049,
+ 32027, 32004, 31981, 31957, 31933,
+ 31909, 31884, 31859, 31834, 31809,
+ 31783, 31756, 31730, 31703, 31676,
+ 31648, 31620, 31592, 31563, 31534,
+ 31505, 31475, 31445, 31415, 31384,
+ 31353, 31322, 31290, 31258, 31226,
+ 31193, 31160, 31127, 31093, 31059,
+ 31025, 30990, 30955, 30920, 30884,
+ 30848, 30812, 30775, 30738, 30701,
+ 30663, 30625, 30587, 30548, 30509,
+ 30470, 30430, 30390, 30350, 30309,
+ 30269, 30227, 30186, 30144, 30102,
+ 30059, 30016, 29973, 29930, 29886,
+ 29842, 29797, 29752, 29707, 29662,
+ 29616, 29570, 29524, 29477, 29430,
+ 29383, 29335, 29287, 29239, 29190,
+ 29142, 29092, 29043, 28993, 28943,
+ 28892, 28842, 28791, 28739, 28688,
+ 28636, 28583, 28531, 28478, 28425,
+ 28371, 28317, 28263, 28209, 28154,
+ 28099, 28044, 27988, 27932, 27876,
+ 27820, 27763, 27706, 27648, 27591,
+ 27533, 27474, 27416, 27357, 27298,
+ 27238, 27178, 27118, 27058, 26997,
+ 26936, 26875, 26814, 26752, 26690,
+ 26628, 26565, 26502, 26439, 26375,
+ 26312, 26247, 26183, 26119, 26054,
+ 25988, 25923, 25857, 25791, 25725,
+ 25658, 25592, 25524, 25457, 25389,
+ 25322, 25253, 25185, 25116, 25047,
+ 24978, 24908, 24838, 24768, 24698,
+ 24627, 24557, 24485, 24414, 24342,
+ 24270, 24198, 24126, 24053, 23980,
+ 23907, 23834, 23760, 23686, 23612,
+ 23537, 23462, 23387, 23312, 23237,
+ 23161, 23085, 23009, 22932, 22856,
+ 22779, 22701, 22624, 22546, 22468,
+ 22390, 22312, 22233, 22154, 22075,
+ 21996, 21916, 21836, 21756, 21676,
+ 21595, 21515, 21434, 21352, 21271,
+ 21189, 21107, 21025, 20943, 20860,
+ 20777, 20694, 20611, 20528, 20444,
+ 20360, 20276, 20192, 20107, 20022,
+ 19937, 19852, 19767, 19681, 19595,
+ 19509, 19423, 19336, 19250, 19163,
+ 19076, 18988, 18901, 18813, 18725,
+ 18637, 18549, 18460, 18372, 18283,
+ 18194, 18104, 18015, 17925, 17835,
+ 17745, 17655, 17565, 17474, 17383,
+ 17292, 17201, 17110, 17018, 16927,
+ 16835, 16743, 16650, 16558, 16465,
+ 16372, 16279, 16186, 16093, 15999,
+ 15906, 15812, 15718, 15624, 15529,
+ 15435, 15340, 15245, 15150, 15055,
+ 14960, 14864, 14769, 14673, 14577,
+ 14481, 14385, 14288, 14192, 14095,
+ 13998, 13901, 13804, 13706, 13609,
+ 13511, 13414, 13316, 13218, 13119,
+ 13021, 12923, 12824, 12725, 12626,
+ 12527, 12428, 12329, 12230, 12130,
+ 12030, 11930, 11831, 11730, 11630,
+ 11530, 11430, 11329, 11228, 11128,
+ 11027, 10926, 10824, 10723, 10622,
+ 10520, 10419, 10317, 10215, 10113,
+ 10011, 9909, 9807, 9704, 9602,
+ 9499, 9397, 9294, 9191, 9088,
+ 8985, 8882, 8778, 8675, 8572,
+ 8468, 8364, 8261, 8157, 8053,
+ 7949, 7845, 7741, 7637, 7532,
+ 7428, 7323, 7219, 7114, 7009,
+ 6905, 6800, 6695, 6590, 6485,
+ 6380, 6274, 6169, 6064, 5958,
+ 5853, 5747, 5642, 5536, 5430,
+ 5325, 5219, 5113, 5007, 4901,
+ 4795, 4689, 4583, 4476, 4370,
+ 4264, 4157, 4051, 3945, 3838,
+ 3732, 3625, 3518, 3412, 3305,
+ 3198, 3092, 2985, 2878, 2771,
+ 2664, 2558, 2451, 2344, 2237,
+ 2130, 2023, 1916, 1809, 1702,
+ 1594, 1487, 1380, 1273, 1166,
+ 1059, 952, 844, 737, 630,
+ 523, 416, 308, 201, 94,
+ -13, -121, -228, -335, -442,
+ -550, -657, -764, -871, -978,
+ -1086, -1193, -1300, -1407, -1514,
+ -1621, -1728, -1835, -1942, -2049,
+ -2157, -2263, -2370, -2477, -2584,
+ -2691, -2798, -2905, -3012, -3118,
+ -3225, -3332, -3439, -3545, -3652,
+ -3758, -3865, -3971, -4078, -4184,
+ -4290, -4397, -4503, -4609, -4715,
+ -4821, -4927, -5033, -5139, -5245,
+ -5351, -5457, -5562, -5668, -5774,
+ -5879, -5985, -6090, -6195, -6301,
+ -6406, -6511, -6616, -6721, -6826,
+ -6931, -7036, -7140, -7245, -7349,
+ -7454, -7558, -7663, -7767, -7871,
+ -7975, -8079, -8183, -8287, -8390,
+ -8494, -8597, -8701, -8804, -8907,
+ -9011, -9114, -9217, -9319, -9422,
+ -9525, -9627, -9730, -9832, -9934,
+ -10037, -10139, -10241, -10342, -10444,
+ -10546, -10647, -10748, -10850, -10951,
+ -11052, -11153, -11253, -11354, -11455,
+ -11555, -11655, -11756, -11856, -11955,
+ -12055, -12155, -12254, -12354, -12453,
+ -12552, -12651, -12750, -12849, -12947,
+ -13046, -13144, -13242, -13340, -13438,
+ -13536, -13633, -13731, -13828, -13925,
+ -14022, -14119, -14216, -14312, -14409,
+ -14505, -14601, -14697, -14793, -14888,
+ -14984, -15079, -15174, -15269, -15364,
+ -15459, -15553, -15647, -15741, -15835,
+ -15929, -16023, -16116, -16210, -16303,
+ -16396, -16488, -16581, -16673, -16766,
+ -16858, -16949, -17041, -17133, -17224,
+ -17315, -17406, -17497, -17587, -17678,
+ -17768, -17858, -17948, -18037, -18127,
+ -18216, -18305, -18394, -18483, -18571,
+ -18659, -18747, -18835, -18923, -19010,
+ -19098, -19185, -19271, -19358, -19444,
+ -19531, -19617, -19702, -19788, -19873,
+ -19959, -20043, -20128, -20213, -20297,
+ -20381, -20465, -20549, -20632, -20715,
+ -20798, -20881, -20963, -21046, -21128,
+ -21210, -21291, -21373, -21454, -21535,
+ -21616, -21696, -21776, -21856, -21936,
+ -22016, -22095, -22174, -22253, -22331,
+ -22410, -22488, -22566, -22643, -22721,
+ -22798, -22875, -22951, -23028, -23104,
+ -23180, -23256, -23331, -23406, -23481,
+ -23556, -23630, -23704, -23778, -23852,
+ -23925, -23998, -24071, -24144, -24216,
+ -24288, -24360, -24432, -24503, -24574,
+ -24645, -24716, -24786, -24856, -24926,
+ -24995, -25064, -25133, -25202, -25270,
+ -25339, -25406, -25474, -25541, -25608,
+ -25675, -25742, -25808, -25874, -25939,
+ -26005, -26070, -26135, -26199, -26264,
+ -26327, -26391, -26455, -26518, -26581,
+ -26643, -26705, -26767, -26829, -26891,
+ -26952, -27013, -27073, -27133, -27193,
+ -27253, -27312, -27372, -27430, -27489,
+ -27547, -27605, -27663, -27720, -27777,
+ -27834, -27890, -27946, -28002, -28058,
+ -28113, -28168, -28223, -28277, -28331,
+ -28385, -28438, -28491, -28544, -28596,
+ -28649, -28701, -28752, -28803, -28854,
+ -28905, -28955, -29006, -29055, -29105,
+ -29154, -29203, -29251, -29299, -29347,
+ -29395, -29442, -29489, -29535, -29582,
+ -29628, -29673, -29719, -29764, -29808,
+ -29853, -29897, -29941, -29984, -30027,
+ -30070, -30112, -30154, -30196, -30238,
+ -30279, -30320, -30360, -30400, -30440,
+ -30480, -30519, -30558, -30596, -30635,
+ -30672, -30710, -30747, -30784, -30821,
+ -30857, -30893, -30929, -30964, -30999,
+ -31033, -31068, -31102, -31135, -31168,
+ -31201, -31234, -31266, -31298, -31330,
+ -31361, -31392, -31422, -31453, -31483,
+ -31512, -31541, -31570, -31599, -31627,
+ -31655, -31682, -31710, -31737, -31763,
+ -31789, -31815, -31841, -31866, -31891,
+ -31915, -31939, -31963, -31986, -32010,
+ -32032, -32055, -32077, -32099, -32120,
+ -32141, -32162, -32182, -32202, -32222,
+ -32241, -32260, -32279, -32297, -32315,
+ -32333, -32350, -32367, -32383, -32399,
+ -32415, -32431, -32446, -32461, -32475,
+ -32489, -32503, -32517, -32530, -32542,
+ -32555, -32567, -32579, -32590, -32601,
+ -32612, -32622, -32632, -32641, -32651,
+ -32659, -32668, -32676, -32684, -32692,
+ -32699, -32706, -32712, -32718, -32724,
+ -32729, -32734, -32739, -32743, -32747,
+ -32751, -32754, -32757, -32760, -32762,
+ -32764, -32765, -32767, -32767, -32767,
+ 32767, 32767, 32765, 32761, 32756,
+ 32750, 32742, 32732, 32722, 32710,
+ 32696, 32681, 32665, 32647, 32628,
+ 32608, 32586, 32562, 32538, 32512,
+ 32484, 32455, 32425, 32393, 32360,
+ 32326, 32290, 32253, 32214, 32174,
+ 32133, 32090, 32046, 32001, 31954,
+ 31906, 31856, 31805, 31753, 31700,
+ 31645, 31588, 31530, 31471, 31411,
+ 31349, 31286, 31222, 31156, 31089,
+ 31020, 30951, 30880, 30807, 30733,
+ 30658, 30582, 30504, 30425, 30345,
+ 30263, 30181, 30096, 30011, 29924,
+ 29836, 29747, 29656, 29564, 29471,
+ 29377, 29281, 29184, 29086, 28987,
+ 28886, 28784, 28681, 28577, 28471,
+ 28365, 28257, 28147, 28037, 27925,
+ 27812, 27698, 27583, 27467, 27349,
+ 27231, 27111, 26990, 26868, 26744,
+ 26620, 26494, 26367, 26239, 26110,
+ 25980, 25849, 25717, 25583, 25449,
+ 25313, 25176, 25038, 24900, 24760,
+ 24619, 24477, 24333, 24189, 24044,
+ 23898, 23751, 23602, 23453, 23303,
+ 23152, 22999, 22846, 22692, 22537,
+ 22380, 22223, 22065, 21906, 21746,
+ 21585, 21423, 21261, 21097, 20933,
+ 20767, 20601, 20434, 20265, 20096,
+ 19927, 19756, 19584, 19412, 19239,
+ 19065, 18890, 18714, 18538, 18361,
+ 18183, 18004, 17824, 17644, 17463,
+ 17281, 17098, 16915, 16731, 16546,
+ 16361, 16175, 15988, 15800, 15612,
+ 15423, 15234, 15043, 14852, 14661,
+ 14469, 14276, 14083, 13889, 13694,
+ 13499, 13303, 13107, 12910, 12713,
+ 12515, 12317, 12118, 11918, 11718,
+ 11517, 11316, 11115, 10913, 10710,
+ 10508, 10304, 10100, 9896, 9691,
+ 9486, 9281, 9075, 8869, 8662,
+ 8455, 8248, 8040, 7832, 7623,
+ 7415, 7206, 6996, 6787, 6577,
+ 6366, 6156, 5945, 5734, 5523,
+ 5311, 5100, 4888, 4675, 4463,
+ 4251, 4038, 3825, 3612, 3399,
+ 3185, 2972, 2758, 2544, 2330,
+ 2116, 1902, 1688, 1474, 1260,
+ 1045, 831, 617, 402, 188,
+ -27, -241, -456, -670, -885,
+ -1099, -1313, -1528, -1742, -1956,
+ -2170, -2384, -2598, -2811, -3025,
+ -3239, -3452, -3665, -3878, -4091,
+ -4304, -4516, -4728, -4941, -5153,
+ -5364, -5576, -5787, -5998, -6209,
+ -6419, -6629, -6839, -7049, -7258,
+ -7467, -7676, -7884, -8092, -8300,
+ -8507, -8714, -8920, -9127, -9332,
+ -9538, -9743, -9947, -10151, -10355,
+ -10558, -10761, -10963, -11165, -11367,
+ -11568, -11768, -11968, -12167, -12366,
+ -12565, -12762, -12960, -13156, -13352,
+ -13548, -13743, -13937, -14131, -14324,
+ -14517, -14709, -14900, -15091, -15281,
+ -15470, -15659, -15847, -16035, -16221,
+ -16407, -16593, -16777, -16961, -17144,
+ -17326, -17508, -17689, -17869, -18049,
+ -18227, -18405, -18582, -18758, -18934,
+ -19108, -19282, -19455, -19627, -19799,
+ -19969, -20139, -20308, -20475, -20642,
+ -20809, -20974, -21138, -21301, -21464,
+ -21626, -21786, -21946, -22105, -22263,
+ -22420, -22575, -22730, -22884, -23037,
+ -23189, -23340, -23490, -23640, -23788,
+ -23935, -24080, -24225, -24369, -24512,
+ -24654, -24795, -24934, -25073, -25211,
+ -25347, -25482, -25617, -25750, -25882,
+ -26013, -26143, -26272, -26399, -26526,
+ -26651, -26775, -26898, -27020, -27141,
+ -27260, -27379, -27496, -27612, -27727,
+ -27841, -27953, -28065, -28175, -28284,
+ -28391, -28498, -28603, -28707, -28810,
+ -28911, -29012, -29111, -29209, -29305,
+ -29401, -29495, -29587, -29679, -29769,
+ -29858, -29946, -30032, -30118, -30201,
+ -30284, -30365, -30445, -30524, -30601,
+ -30677, -30752, -30825, -30897, -30968,
+ -31038, -31106, -31172, -31238, -31302,
+ -31365, -31426, -31486, -31545, -31602,
+ -31658, -31713, -31766, -31818, -31869,
+ -31918, -31966, -32012, -32058, -32101,
+ -32144, -32185, -32224, -32262, -32299,
+ -32335, -32369, -32401, -32433, -32463,
+ -32491, -32518, -32544, -32568, -32591,
+ -32613, -32633, -32652, -32669, -32685,
+ -32700, -32713, -32724, -32735, -32744,
+ -32751, -32757, -32762, -32766, -32767,
+ 32767, 32764, 32755, 32741, 32720,
+ 32694, 32663, 32626, 32583, 32535,
+ 32481, 32421, 32356, 32286, 32209,
+ 32128, 32041, 31948, 31850, 31747,
+ 31638, 31523, 31403, 31278, 31148,
+ 31012, 30871, 30724, 30572, 30415,
+ 30253, 30086, 29913, 29736, 29553,
+ 29365, 29172, 28974, 28771, 28564,
+ 28351, 28134, 27911, 27684, 27452,
+ 27216, 26975, 26729, 26478, 26223,
+ 25964, 25700, 25432, 25159, 24882,
+ 24601, 24315, 24026, 23732, 23434,
+ 23133, 22827, 22517, 22204, 21886,
+ 21565, 21240, 20912, 20580, 20244,
+ 19905, 19563, 19217, 18868, 18516,
+ 18160, 17802, 17440, 17075, 16708,
+ 16338, 15964, 15588, 15210, 14829,
+ 14445, 14059, 13670, 13279, 12886,
+ 12490, 12093, 11693, 11291, 10888,
+ 10482, 10075, 9666, 9255, 8843,
+ 8429, 8014, 7597, 7180, 6760,
+ 6340, 5919, 5496, 5073, 4649,
+ 4224, 3798, 3372, 2945, 2517,
+ 2090, 1661, 1233, 804, 375,
+ -54, -483, -911, -1340, -1768,
+ -2197, -2624, -3052, -3479, -3905,
+ -4330, -4755, -5179, -5602, -6024,
+ -6445, -6865, -7284, -7702, -8118,
+ -8533, -8946, -9358, -9768, -10177,
+ -10584, -10989, -11392, -11793, -12192,
+ -12589, -12984, -13377, -13767, -14155,
+ -14541, -14924, -15305, -15683, -16058,
+ -16430, -16800, -17167, -17531, -17892,
+ -18249, -18604, -18956, -19304, -19649,
+ -19990, -20329, -20663, -20994, -21322,
+ -21646, -21966, -22282, -22595, -22904,
+ -23208, -23509, -23806, -24099, -24387,
+ -24672, -24952, -25228, -25499, -25766,
+ -26029, -26288, -26541, -26791, -27035,
+ -27275, -27511, -27741, -27967, -28188,
+ -28405, -28616, -28823, -29024, -29221,
+ -29412, -29599, -29780, -29957, -30128,
+ -30294, -30455, -30611, -30761, -30906,
+ -31046, -31181, -31310, -31434, -31552,
+ -31665, -31773, -31875, -31972, -32063,
+ -32149, -32229, -32304, -32373, -32437,
+ -32495, -32547, -32594, -32635, -32671,
+ -32701, -32726, -32745, -32758, -32766,
+ 32767, 32754, 32717, 32658, 32577,
+ 32473, 32348, 32200, 32029, 31837,
+ 31624, 31388, 31131, 30853, 30553,
+ 30232, 29891, 29530, 29148, 28746,
+ 28324, 27883, 27423, 26944, 26447,
+ 25931, 25398, 24847, 24279, 23695,
+ 23095, 22478, 21846, 21199, 20538,
+ 19863, 19174, 18472, 17757, 17030,
+ 16291, 15541, 14781, 14010, 13230,
+ 12441, 11643, 10837, 10024, 9204,
+ 8377, 7545, 6708, 5866, 5020,
+ 4171, 3319, 2464, 1608, 751,
+ -107, -965, -1822, -2678, -3532,
+ -4383, -5232, -6077, -6918, -7754,
+ -8585, -9409, -10228, -11039, -11843,
+ -12639, -13426, -14204, -14972, -15730,
+ -16477, -17213, -17937, -18648, -19347,
+ -20033, -20705, -21363, -22006, -22634,
+ -23246, -23843, -24423, -24986, -25533,
+ -26062, -26573, -27066, -27540, -27995,
+ -28431, -28848, -29245, -29622, -29979,
+ -30315, -30630, -30924, -31197, -31449,
+ -31679, -31887, -32074, -32239, -32381,
+ -32501, -32600, -32675, -32729, -32759,};
+
+ static final int[] intensity_thresholds
+ = /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 off*/ {1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 36, 44, 50, 56, 62, 67, 72, 79, 88, 106, 134};
+ static final int[] intensity_histeresis
+ = {1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 6, 8, 8};
+}
diff --git a/app/src/main/java/org/concentus/ChannelLayout.java b/app/src/main/java/org/concentus/ChannelLayout.java
new file mode 100644
index 0000000000..f7b580aa9c
--- /dev/null
+++ b/app/src/main/java/org/concentus/ChannelLayout.java
@@ -0,0 +1,50 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class ChannelLayout {
+
+ int nb_channels;
+ int nb_streams;
+ int nb_coupled_streams;
+ final short[] mapping = new short[256];
+
+ void Reset() {
+ nb_channels = 0;
+ nb_streams = 0;
+ nb_coupled_streams = 0;
+ Arrays.MemSet(mapping, (short) 0);
+ }
+}
diff --git a/app/src/main/java/org/concentus/CodeSigns.java b/app/src/main/java/org/concentus/CodeSigns.java
new file mode 100644
index 0000000000..0cc94005b2
--- /dev/null
+++ b/app/src/main/java/org/concentus/CodeSigns.java
@@ -0,0 +1,130 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+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);
+ }
+
+ ///
+ /// Encodes signs of excitation
+ ///
+ /// I/O Compressor data structure
+ /// I pulse signal
+ /// I length of input
+ /// I Signal type
+ /// I Quantization offset type
+ /// I Sum of absolute pulses per block [MAX_NB_SHELL_BLOCKS]
+ static void silk_encode_signs(
+ EntropyCoder psRangeEnc,
+ byte[] pulses,
+ int length,
+ int signalType,
+ int quantOffsetType,
+ int[] sum_pulses) {
+ int i, j, p;
+ short[] icdf = new short[2];
+ int q_ptr;
+ short[] sign_icdf = SilkTables.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;
+ }
+ }
+
+ ///
+ /// Decodes signs of excitation
+ ///
+ /// I/O Compressor data structure
+ /// I/O pulse signal
+ /// I length of input
+ /// I Signal type
+ /// I Quantization offset type
+ /// I Sum of absolute pulses per block [MAX_NB_SHELL_BLOCKS]
+ static void silk_decode_signs(
+ EntropyCoder psRangeDec,
+ short[] pulses,
+ int length,
+ int signalType,
+ int quantOffsetType,
+ int[] sum_pulses) {
+ int i, j, p;
+ short[] icdf = new short[2];
+ int q_ptr;
+ short[] icdf_table = SilkTables.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;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/CodecHelpers.java b/app/src/main/java/org/concentus/CodecHelpers.java
new file mode 100644
index 0000000000..84d4846ffe
--- /dev/null
+++ b/app/src/main/java/org/concentus/CodecHelpers.java
@@ -0,0 +1,631 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public class CodecHelpers {
+
+ static byte gen_toc(OpusMode mode, int framerate, OpusBandwidth bandwidth, int channels) {
+ int period;
+ short toc;
+ period = 0;
+ while (framerate < 400) {
+ framerate <<= 1;
+ period++;
+ }
+ if (mode == OpusMode.MODE_SILK_ONLY) {
+ toc = (short) ((OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND)) << 5);
+ toc |= (short) ((period - 2) << 3);
+ } else if (mode == OpusMode.MODE_CELT_ONLY) {
+ int tmp = OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND);
+ if (tmp < 0) {
+ tmp = 0;
+ }
+ toc = 0x80;
+ toc |= (short) (tmp << 5);
+ toc |= (short) (period << 3);
+ } else /* Hybrid */ {
+ toc = 0x60;
+ toc |= (short) ((OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND)) << 4);
+ toc |= (short) ((period - 2) << 3);
+ }
+ toc |= (short) ((channels == 2 ? 1 : 0) << 2);
+ return (byte) (0xFF & toc);
+ }
+
+ static void hp_cutoff(short[] input, int input_ptr, int cutoff_Hz, short[] output, int output_ptr, int[] hp_mem, int len, int channels, int Fs) {
+ int[] B_Q28 = new int[3];
+ int[] A_Q28 = new int[2];
+ int Fc_Q19, r_Q28, r_Q22;
+
+ Inlines.OpusAssert(cutoff_Hz <= Integer.MAX_VALUE / ((int) ((1.5f * 3.14159f / 1000) * ((long) 1 << (19)) + 0.5))/*Inlines.SILK_CONST(1.5f * 3.14159f / 1000, 19)*/);
+ Fc_Q19 = Inlines.silk_DIV32_16(Inlines.silk_SMULBB(((int) ((1.5f * 3.14159f / 1000) * ((long) 1 << (19)) + 0.5))/*Inlines.SILK_CONST(1.5f * 3.14159f / 1000, 19)*/, cutoff_Hz), Fs / 1000);
+ Inlines.OpusAssert(Fc_Q19 > 0 && Fc_Q19 < 32768);
+
+ r_Q28 = ((int) ((1.0f) * ((long) 1 << (28)) + 0.5))/*Inlines.SILK_CONST(1.0f, 28)*/ - Inlines.silk_MUL(((int) ((0.92f) * ((long) 1 << (9)) + 0.5))/*Inlines.SILK_CONST(0.92f, 9)*/, Fc_Q19);
+
+ /* b = r * [ 1; -2; 1 ]; */
+ /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */
+ B_Q28[0] = r_Q28;
+ B_Q28[1] = Inlines.silk_LSHIFT(-r_Q28, 1);
+ B_Q28[2] = r_Q28;
+
+ /* -r * ( 2 - Fc * Fc ); */
+ r_Q22 = Inlines.silk_RSHIFT(r_Q28, 6);
+ A_Q28[0] = Inlines.silk_SMULWW(r_Q22, Inlines.silk_SMULWW(Fc_Q19, Fc_Q19) - ((int) ((2.0f) * ((long) 1 << (22)) + 0.5))/*Inlines.SILK_CONST(2.0f, 22)*/);
+ A_Q28[1] = Inlines.silk_SMULWW(r_Q22, r_Q22);
+
+ Filters.silk_biquad_alt(input, input_ptr, B_Q28, A_Q28, hp_mem, 0, output, output_ptr, len, channels);
+ if (channels == 2) {
+ Filters.silk_biquad_alt(input, input_ptr + 1, B_Q28, A_Q28, hp_mem, 2, output, output_ptr + 1, len, channels);
+ }
+ }
+
+ static void dc_reject(short[] input, int input_ptr, int cutoff_Hz, short[] output, int output_ptr, int[] hp_mem, int len, int channels, int Fs) {
+ int c, i;
+ int shift;
+
+ /* Approximates -round(log2(4.*cutoff_Hz/Fs)) */
+ shift = Inlines.celt_ilog2(Fs / (cutoff_Hz * 3));
+ for (c = 0; c < channels; c++) {
+ for (i = 0; i < len; i++) {
+ int x, tmp, y;
+ x = Inlines.SHL32(Inlines.EXTEND32(input[channels * i + c + input_ptr]), 15);
+ /* First stage */
+ tmp = x - hp_mem[2 * c];
+ hp_mem[2 * c] = hp_mem[2 * c] + Inlines.PSHR32(x - hp_mem[2 * c], shift);
+ /* Second stage */
+ y = tmp - hp_mem[2 * c + 1];
+ hp_mem[2 * c + 1] = hp_mem[2 * c + 1] + Inlines.PSHR32(tmp - hp_mem[2 * c + 1], shift);
+ output[channels * i + c + output_ptr] = Inlines.EXTRACT16(Inlines.SATURATE(Inlines.PSHR32(y, 15), 32767));
+ }
+ }
+ }
+
+ static void stereo_fade(
+ short[] pcm_buf,
+ int g1,
+ int g2,
+ int overlap48,
+ int frame_size,
+ int channels,
+ int[] window,
+ int Fs) {
+ int i;
+ int overlap;
+ int inc;
+ inc = 48000 / Fs;
+ overlap = overlap48 / inc;
+ g1 = CeltConstants.Q15ONE - g1;
+ g2 = CeltConstants.Q15ONE - g2;
+ for (i = 0; i < overlap; i++) {
+ int diff;
+ int g, w;
+ w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]);
+ g = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, g2),
+ CeltConstants.Q15ONE - w, g1), 15);
+ diff = Inlines.EXTRACT16(Inlines.HALF32((int) pcm_buf[i * channels] - (int) pcm_buf[i * channels + 1]));
+ diff = Inlines.MULT16_16_Q15(g, diff);
+ pcm_buf[i * channels] = (short) (pcm_buf[i * channels] - diff);
+ pcm_buf[i * channels + 1] = (short) (pcm_buf[i * channels + 1] + diff);
+ }
+ for (; i < frame_size; i++) {
+ int diff;
+ diff = Inlines.EXTRACT16(Inlines.HALF32((int) pcm_buf[i * channels] - (int) pcm_buf[i * channels + 1]));
+ diff = Inlines.MULT16_16_Q15(g2, diff);
+ pcm_buf[i * channels] = (short) (pcm_buf[i * channels] - diff);
+ pcm_buf[i * channels + 1] = (short) (pcm_buf[i * channels + 1] + diff);
+ }
+ }
+
+ static void gain_fade(short[] buffer, int buf_ptr, int g1, int g2,
+ int overlap48, int frame_size, int channels, int[] window, int Fs) {
+ int i;
+ int inc;
+ int overlap;
+ int c;
+ inc = 48000 / Fs;
+ overlap = overlap48 / inc;
+ if (channels == 1) {
+ for (i = 0; i < overlap; i++) {
+ int g, w;
+ w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]);
+ g = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, g2),
+ CeltConstants.Q15ONE - w, g1), 15);
+ buffer[buf_ptr + i] = (short) Inlines.MULT16_16_Q15(g, buffer[buf_ptr + i]);
+ }
+ } else {
+ for (i = 0; i < overlap; i++) {
+ int g, w;
+ w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]);
+ g = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, g2),
+ CeltConstants.Q15ONE - w, g1), 15);
+ buffer[buf_ptr + i * 2] = (short) Inlines.MULT16_16_Q15(g, buffer[buf_ptr + i * 2]);
+ buffer[buf_ptr + i * 2 + 1] = (short) Inlines.MULT16_16_Q15(g, buffer[buf_ptr + i * 2 + 1]);
+ }
+ }
+ c = 0;
+ do {
+ for (i = overlap; i < frame_size; i++) {
+ buffer[buf_ptr + i * channels + c] = (short) Inlines.MULT16_16_Q15(g2, buffer[buf_ptr + i * channels + c]);
+ }
+ } while (++c < channels);
+ }
+
+ /* Don't use more than 60 ms for the frame size analysis */
+ private final static int MAX_DYNAMIC_FRAMESIZE = 24;
+
+ /* Estimates how much the bitrate will be boosted based on the sub-frame energy */
+ static float transient_boost(float[] E, int E_ptr, float[] E_1, int LM, int maxM) {
+ int i;
+ int M;
+ float sumE = 0, sumE_1 = 0;
+ float metric;
+
+ M = Inlines.IMIN(maxM, (1 << LM) + 1);
+ for (i = E_ptr; i < M + E_ptr; i++) {
+ sumE += E[i];
+ sumE_1 += E_1[i];
+ }
+ metric = sumE * sumE_1 / (M * M);
+ /*if (LM==3)
+ printf("%f\n", metric);*/
+ /*return metric>10 ? 1 : 0;*/
+ /*return Inlines.MAX16(0,1-exp(-.25*(metric-2.)));*/
+ return Inlines.MIN16(1, (float) Math.sqrt(Inlines.MAX16(0, .05f * (metric - 2))));
+ }
+
+ /* Viterbi decoding trying to find the best frame size combination using look-ahead
+
+ State numbering:
+ 0: unused
+ 1: 2.5 ms
+ 2: 5 ms (#1)
+ 3: 5 ms (#2)
+ 4: 10 ms (#1)
+ 5: 10 ms (#2)
+ 6: 10 ms (#3)
+ 7: 10 ms (#4)
+ 8: 20 ms (#1)
+ 9: 20 ms (#2)
+ 10: 20 ms (#3)
+ 11: 20 ms (#4)
+ 12: 20 ms (#5)
+ 13: 20 ms (#6)
+ 14: 20 ms (#7)
+ 15: 20 ms (#8)
+ */
+ static int transient_viterbi(float[] E, float[] E_1, int N, int frame_cost, int rate) {
+ int i;
+ float[][] cost = Arrays.InitTwoDimensionalArrayFloat(MAX_DYNAMIC_FRAMESIZE, 16);
+ int[][] states = Arrays.InitTwoDimensionalArrayInt(MAX_DYNAMIC_FRAMESIZE, 16);
+ float best_cost;
+ int best_state;
+ float factor;
+ /* Take into account that we damp VBR in the 32 kb/s to 64 kb/s range. */
+ if (rate < 80) {
+ factor = 0;
+ } else if (rate > 160) {
+ factor = 1;
+ } else {
+ factor = (rate - 80.0f) / 80.0f;
+ }
+ /* Makes variable framesize less aggressive at lower bitrates, but I can't
+ find any valid theoretical justification for this (other than it seems
+ to help) */
+ for (i = 0; i < 16; i++) {
+ /* Impossible state */
+ states[0][i] = -1;
+ cost[0][i] = 1e10f;
+ }
+ for (i = 0; i < 4; i++) {
+ cost[0][1 << i] = (frame_cost + rate * (1 << i)) * (1 + factor * transient_boost(E, 0, E_1, i, N + 1));
+ states[0][1 << i] = i;
+ }
+ for (i = 1; i < N; i++) {
+ int j;
+
+ /* Follow continuations */
+ for (j = 2; j < 16; j++) {
+ cost[i][j] = cost[i - 1][j - 1];
+ states[i][j] = j - 1;
+ }
+
+ /* New frames */
+ for (j = 0; j < 4; j++) {
+ int k;
+ float min_cost;
+ float curr_cost;
+ states[i][1 << j] = 1;
+ min_cost = cost[i - 1][1];
+ for (k = 1; k < 4; k++) {
+ float tmp = cost[i - 1][(1 << (k + 1)) - 1];
+ if (tmp < min_cost) {
+ states[i][1 << j] = (1 << (k + 1)) - 1;
+ min_cost = tmp;
+ }
+ }
+ curr_cost = (frame_cost + rate * (1 << j)) * (1 + factor * transient_boost(E, i, E_1, j, N - i + 1));
+ cost[i][1 << j] = min_cost;
+ /* If part of the frame is outside the analysis window, only count part of the cost */
+ if (N - i < (1 << j)) {
+ cost[i][1 << j] += curr_cost * (float) (N - i) / (1 << j);
+ } else {
+ cost[i][1 << j] += curr_cost;
+ }
+ }
+ }
+
+ best_state = 1;
+ best_cost = cost[N - 1][1];
+ /* Find best end state (doesn't force a frame to end at N-1) */
+ for (i = 2; i < 16; i++) {
+ if (cost[N - 1][i] < best_cost) {
+ best_cost = cost[N - 1][i];
+ best_state = i;
+ }
+ }
+
+ /* Follow transitions back */
+ for (i = N - 1; i >= 0; i--) {
+ /*printf("%d ", best_state);*/
+ best_state = states[i][best_state];
+ }
+ /*printf("%d\n", best_state);*/
+ return best_state;
+ }
+
+ static int optimize_framesize(short[] x, int x_ptr, int len, int C, int Fs,
+ int bitrate, int tonality, float[] mem, int buffering) {
+ int N;
+ int i;
+ float[] e = new float[MAX_DYNAMIC_FRAMESIZE + 4];
+ float[] e_1 = new float[MAX_DYNAMIC_FRAMESIZE + 3];
+ int memx;
+ int bestLM = 0;
+ int subframe;
+ int pos;
+ int offset;
+ int[] sub;
+
+ subframe = Fs / 400;
+ sub = new int[subframe];
+ e[0] = mem[0];
+ e_1[0] = 1.0f / (CeltConstants.EPSILON + mem[0]);
+ if (buffering != 0) {
+ /* Consider the CELT delay when not in restricted-lowdelay */
+ /* We assume the buffering is between 2.5 and 5 ms */
+ offset = 2 * subframe - buffering;
+ Inlines.OpusAssert(offset >= 0 && offset <= subframe);
+ len -= offset;
+ e[1] = mem[1];
+ e_1[1] = 1.0f / (CeltConstants.EPSILON + mem[1]);
+ e[2] = mem[2];
+ e_1[2] = 1.0f / (CeltConstants.EPSILON + mem[2]);
+ pos = 3;
+ } else {
+ pos = 1;
+ offset = 0;
+ }
+ N = Inlines.IMIN(len / subframe, MAX_DYNAMIC_FRAMESIZE);
+ /* Just silencing a warning, it's really initialized later */
+ memx = 0;
+ for (i = 0; i < N; i++) {
+ float tmp;
+ int tmpx;
+ int j;
+ tmp = CeltConstants.EPSILON;
+
+ Downmix.downmix_int(x, x_ptr, sub, 0, subframe, i * subframe + offset, 0, -2, C);
+ if (i == 0) {
+ memx = sub[0];
+ }
+ for (j = 0; j < subframe; j++) {
+ tmpx = sub[j];
+ tmp += (tmpx - memx) * (float) (tmpx - memx);
+ memx = tmpx;
+ }
+ e[i + pos] = tmp;
+ e_1[i + pos] = 1.0f / tmp;
+ }
+ /* Hack to get 20 ms working with APPLICATION_AUDIO
+ The real problem is that the corresponding memory needs to use 1.5 ms
+ from this frame and 1 ms from the next frame */
+ e[i + pos] = e[i + pos - 1];
+ if (buffering != 0) {
+ N = Inlines.IMIN(MAX_DYNAMIC_FRAMESIZE, N + 2);
+ }
+ bestLM = transient_viterbi(e, e_1, N, (int) ((1.0f + .5f * tonality) * (60 * C + 40)), bitrate / 400);
+ mem[0] = e[1 << bestLM];
+ if (buffering != 0) {
+ mem[1] = e[(1 << bestLM) + 1];
+ mem[2] = e[(1 << bestLM) + 2];
+ }
+ return bestLM;
+ }
+
+ static int frame_size_select(int frame_size, OpusFramesize variable_duration, int Fs) {
+ int new_size;
+ if (frame_size < Fs / 400) {
+ return -1;
+ }
+ if (variable_duration == OpusFramesize.OPUS_FRAMESIZE_ARG) {
+ new_size = frame_size;
+ } else if (variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE) {
+ new_size = Fs / 50;
+ } else if (OpusFramesizeHelpers.GetOrdinal(variable_duration) >= OpusFramesizeHelpers.GetOrdinal(OpusFramesize.OPUS_FRAMESIZE_2_5_MS)
+ && OpusFramesizeHelpers.GetOrdinal(variable_duration) <= OpusFramesizeHelpers.GetOrdinal(OpusFramesize.OPUS_FRAMESIZE_60_MS)) {
+ new_size = Inlines.IMIN(3 * Fs / 50, (Fs / 400) << (OpusFramesizeHelpers.GetOrdinal(variable_duration) - OpusFramesizeHelpers.GetOrdinal(OpusFramesize.OPUS_FRAMESIZE_2_5_MS)));
+ } else {
+ return -1;
+ }
+ if (new_size > frame_size) {
+ return -1;
+ }
+ if (400 * new_size != Fs && 200 * new_size != Fs && 100 * new_size != Fs
+ && 50 * new_size != Fs && 25 * new_size != Fs && 50 * new_size != 3 * Fs) {
+ return -1;
+ }
+ return new_size;
+ }
+
+ static int compute_frame_size(short[] analysis_pcm, int analysis_pcm_ptr, int frame_size,
+ OpusFramesize variable_duration, int C, int Fs, int bitrate_bps,
+ int delay_compensation, float[] subframe_mem, boolean analysis_enabled
+ ) {
+
+ if (analysis_enabled && variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs / 200) {
+ int LM = 3;
+ LM = optimize_framesize(analysis_pcm, analysis_pcm_ptr, frame_size, C, Fs, bitrate_bps,
+ 0, subframe_mem, delay_compensation);
+ while ((Fs / 400 << LM) > frame_size) {
+ LM--;
+ }
+ frame_size = (Fs / 400 << LM);
+ } else {
+ frame_size = frame_size_select(frame_size, variable_duration, Fs);
+ }
+
+ if (frame_size < 0) {
+ return -1;
+ }
+ return frame_size;
+ }
+
+ static int compute_stereo_width(short[] pcm, int pcm_ptr, int frame_size, int Fs, StereoWidthState mem) {
+ int corr;
+ int ldiff;
+ int width;
+ int xx, xy, yy;
+ int sqrt_xx, sqrt_yy;
+ int qrrt_xx, qrrt_yy;
+ int frame_rate;
+ int i;
+ int short_alpha;
+
+ frame_rate = Fs / frame_size;
+ short_alpha = CeltConstants.Q15ONE - (25 * CeltConstants.Q15ONE / Inlines.IMAX(50, frame_rate));
+ xx = xy = yy = 0;
+ for (i = 0; i < frame_size - 3; i += 4) {
+ int pxx = 0;
+ int pxy = 0;
+ int pyy = 0;
+ int x, y;
+ int p2i = pcm_ptr + (2 * i);
+ x = pcm[p2i];
+ y = pcm[p2i + 1];
+ pxx = Inlines.SHR32(Inlines.MULT16_16(x, x), 2);
+ pxy = Inlines.SHR32(Inlines.MULT16_16(x, y), 2);
+ pyy = Inlines.SHR32(Inlines.MULT16_16(y, y), 2);
+ x = pcm[p2i + 2];
+ y = pcm[p2i + 3];
+ pxx += Inlines.SHR32(Inlines.MULT16_16(x, x), 2);
+ pxy += Inlines.SHR32(Inlines.MULT16_16(x, y), 2);
+ pyy += Inlines.SHR32(Inlines.MULT16_16(y, y), 2);
+ x = pcm[p2i + 4];
+ y = pcm[p2i + 5];
+ pxx += Inlines.SHR32(Inlines.MULT16_16(x, x), 2);
+ pxy += Inlines.SHR32(Inlines.MULT16_16(x, y), 2);
+ pyy += Inlines.SHR32(Inlines.MULT16_16(y, y), 2);
+ x = pcm[p2i + 6];
+ y = pcm[p2i + 7];
+ pxx += Inlines.SHR32(Inlines.MULT16_16(x, x), 2);
+ pxy += Inlines.SHR32(Inlines.MULT16_16(x, y), 2);
+ pyy += Inlines.SHR32(Inlines.MULT16_16(y, y), 2);
+
+ xx += Inlines.SHR32(pxx, 10);
+ xy += Inlines.SHR32(pxy, 10);
+ yy += Inlines.SHR32(pyy, 10);
+ }
+
+ mem.XX += Inlines.MULT16_32_Q15(short_alpha, xx - mem.XX);
+ mem.XY += Inlines.MULT16_32_Q15(short_alpha, xy - mem.XY);
+ mem.YY += Inlines.MULT16_32_Q15(short_alpha, yy - mem.YY);
+ mem.XX = Inlines.MAX32(0, mem.XX);
+ mem.XY = Inlines.MAX32(0, mem.XY);
+ mem.YY = Inlines.MAX32(0, mem.YY);
+ if (Inlines.MAX32(mem.XX, mem.YY) > ((short) (0.5 + (8e-4f) * (((int) 1) << (18))))/*Inlines.QCONST16(8e-4f, 18)*/) {
+ sqrt_xx = Inlines.celt_sqrt(mem.XX);
+ sqrt_yy = Inlines.celt_sqrt(mem.YY);
+ qrrt_xx = Inlines.celt_sqrt(sqrt_xx);
+ qrrt_yy = Inlines.celt_sqrt(sqrt_yy);
+ /* Inter-channel correlation */
+ mem.XY = Inlines.MIN32(mem.XY, sqrt_xx * sqrt_yy);
+ corr = Inlines.SHR32(Inlines.frac_div32(mem.XY, CeltConstants.EPSILON + Inlines.MULT16_16(sqrt_xx, sqrt_yy)), 16);
+ /* Approximate loudness difference */
+ ldiff = CeltConstants.Q15ONE * Inlines.ABS16(qrrt_xx - qrrt_yy) / (CeltConstants.EPSILON + qrrt_xx + qrrt_yy);
+ width = Inlines.MULT16_16_Q15(Inlines.celt_sqrt(((int) (0.5 + (1.0f) * (((int) 1) << (30))))/*Inlines.QCONST32(1.0f, 30)*/ - Inlines.MULT16_16(corr, corr)), ldiff);
+ /* Smoothing over one second */
+ mem.smoothed_width += (width - mem.smoothed_width) / frame_rate;
+ /* Peak follower */
+ mem.max_follower = Inlines.MAX16(mem.max_follower - ((short) (0.5 + (.02f) * (((int) 1) << (15))))/*Inlines.QCONST16(.02f, 15)*/ / frame_rate, mem.smoothed_width);
+ } else {
+ width = 0;
+ corr = CeltConstants.Q15ONE;
+ ldiff = 0;
+ }
+ /*printf("%f %f %f %f %f ", corr/(float)1.0f, ldiff/(float)1.0f, width/(float)1.0f, mem.smoothed_width/(float)1.0f, mem.max_follower/(float)1.0f);*/
+ return Inlines.EXTRACT16(Inlines.MIN32(CeltConstants.Q15ONE, 20 * mem.max_follower));
+ }
+
+ static void smooth_fade(short[] in1, int in1_ptr, short[] in2, int in2_ptr,
+ short[] output, int output_ptr, int overlap, int channels,
+ int[] window, int Fs) {
+ int i, c;
+ int inc = 48000 / Fs;
+ for (c = 0; c < channels; c++) {
+ for (i = 0; i < overlap; i++) {
+ int w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]);
+ output[output_ptr + (i * channels) + c] = (short) (Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, in2[in2_ptr + (i * channels) + c]),
+ CeltConstants.Q15ONE - w, in1[in1_ptr + (i * channels) + c]), 15));
+ }
+ }
+ }
+
+ //static void opus_pcm_soft_clip(Pointer _x, int N, int C, Pointer declip_mem)
+ //{
+ // int c;
+ // int i;
+ // Pointer x;
+ // if (C < 1 || N < 1 || _x == null || declip_mem == null) return;
+ // /* First thing: saturate everything to +/- 2 which is the highest level our
+ // non-linearity can handle. At the point where the signal reaches +/-2,
+ // the derivative will be zero anyway, so this doesn't introduce any
+ // discontinuity in the derivative. */
+ // for (i = 0; i < N * C; i++)
+ // _x[i] = Inlines.MAX16(-2.0f, Inlines.MIN16(2.0f, _x[i]));
+ // for (c = 0; c < C; c++)
+ // {
+ // float a;
+ // float x0;
+ // int curr;
+ // x = _x.Point(c);
+ // a = declip_mem[c];
+ // /* Continue applying the non-linearity from the previous frame to avoid
+ // any discontinuity. */
+ // for (i = 0; i < N; i++)
+ // {
+ // if (x[i * C] * a >= 0)
+ // break;
+ // x[i * C] = x[i * C] + a * x[i * C] * x[i * C];
+ // }
+ // curr = 0;
+ // x0 = x[0];
+ // while (true)
+ // {
+ // int start, end;
+ // float maxval;
+ // int special = 0;
+ // int peak_pos;
+ // for (i = curr; i < N; i++)
+ // {
+ // if (x[i * C] > 1 || x[i * C] < -1)
+ // break;
+ // }
+ // if (i == N)
+ // {
+ // a = 0;
+ // break;
+ // }
+ // peak_pos = i;
+ // start = end = i;
+ // maxval = Inlines.ABS16(x[i * C]);
+ // /* Look for first zero crossing before clipping */
+ // while (start > 0 && x[i * C] * x[(start - 1) * C] >= 0)
+ // start--;
+ // /* Look for first zero crossing after clipping */
+ // while (end < N && x[i * C] * x[end * C] >= 0)
+ // {
+ // /* Look for other peaks until the next zero-crossing. */
+ // if (Inlines.ABS16(x[end * C]) > maxval)
+ // {
+ // maxval = Inlines.ABS16(x[end * C]);
+ // peak_pos = end;
+ // }
+ // end++;
+ // }
+ // /* Detect the special case where we clip before the first zero crossing */
+ // special = (start == 0 && x[i * C] * x[0] >= 0) ? 1 : 0;
+ // /* Compute a such that maxval + a*maxval^2 = 1 */
+ // a = (maxval - 1) / (maxval * maxval);
+ // if (x[i * C] > 0)
+ // a = -a;
+ // /* Apply soft clipping */
+ // for (i = start; i < end; i++)
+ // x[i * C] = x[i * C] + a * x[i * C] * x[i * C];
+ // if (special != 0 && peak_pos >= 2)
+ // {
+ // /* Add a linear ramp from the first sample to the signal peak.
+ // This avoids a discontinuity at the beginning of the frame. */
+ // float delta;
+ // float offset = x0 - x[0];
+ // delta = offset / peak_pos;
+ // for (i = curr; i < peak_pos; i++)
+ // {
+ // offset -= delta;
+ // x[i * C] += offset;
+ // x[i * C] = Inlines.MAX16(-1.0f, Inlines.MIN16(1.0f, x[i * C]));
+ // }
+ // }
+ // curr = end;
+ // if (curr == N)
+ // {
+ // break;
+ // }
+ // }
+ // declip_mem[c] = a;
+ // }
+ //}
+ public static String opus_strerror(int error) {
+ String[] error_strings = {
+ "success",
+ "invalid argument",
+ "buffer too small",
+ "error",
+ "corrupted stream",
+ "request not implemented",
+ "invalid state",
+ "memory allocation failed"
+ };
+ if (error > 0 || error < -7) {
+ return "unknown error";
+ } else {
+ return error_strings[-error];
+ }
+ }
+
+ public static String GetVersionString() {
+ return "concentus 1.0a-java-fixed";
+ }
+}
diff --git a/app/src/main/java/org/concentus/CorrelateMatrix.java b/app/src/main/java/org/concentus/CorrelateMatrix.java
new file mode 100644
index 0000000000..425cf63ea7
--- /dev/null
+++ b/app/src/main/java/org/concentus/CorrelateMatrix.java
@@ -0,0 +1,175 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+/**
+ * ********************************************************************
+ * Correlation Matrix Computations for LS estimate.
+ *********************************************************************
+ */
+class CorrelateMatrix {
+
+ /* Calculates correlation vector X'*t */
+ 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 */
+ 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 */
+ BoxedValueInt boxed_energy = new BoxedValueInt(0);
+ BoxedValueInt boxed_rshifts_local = new BoxedValueInt(0);
+ SumSqrShift.silk_sum_sqr_shift(boxed_energy, boxed_rshifts_local, x, x_ptr, L + order - 1);
+ energy = boxed_energy.Val;
+ rshifts_local = boxed_rshifts_local.Val;
+
+ /* 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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/DecControlState.java b/app/src/main/java/org/concentus/DecControlState.java
new file mode 100644
index 0000000000..3419e81a96
--- /dev/null
+++ b/app/src/main/java/org/concentus/DecControlState.java
@@ -0,0 +1,65 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Structure for controlling decoder operation and reading decoder status
+///
+class DecControlState {
+
+ /* I: Number of channels; 1/2 */
+ int nChannelsAPI = 0;
+
+ /* I: Number of channels; 1/2 */
+ int nChannelsInternal = 0;
+
+ /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */
+ int API_sampleRate = 0;
+
+ /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */
+ int internalSampleRate = 0;
+
+ /* I: Number of samples per packet in milliseconds; 10/20/40/60 */
+ int payloadSize_ms = 0;
+
+ /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */
+ int prevPitchLag = 0;
+
+ void Reset() {
+ nChannelsAPI = 0;
+ nChannelsInternal = 0;
+ API_sampleRate = 0;
+ internalSampleRate = 0;
+ payloadSize_ms = 0;
+ prevPitchLag = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/DecodeAPI.java b/app/src/main/java/org/concentus/DecodeAPI.java
new file mode 100644
index 0000000000..89acade7c2
--- /dev/null
+++ b/app/src/main/java/org/concentus/DecodeAPI.java
@@ -0,0 +1,374 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class DecodeAPI {
+
+ ///
+ /// Reset decoder state
+ ///
+ /// I/O Stat
+ /// Returns error code
+ 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 */
+ 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,
+ BoxedValueInt 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(0);
+ 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.Val = 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.MemSet(psDec.sStereo.pred_prev_Q13, (short) 0, 2);
+ Arrays.MemSet(psDec.sStereo.sSide, (short) 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.MemSet(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(SilkTables.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.MemSet(psDec.channel_state[1].outBuf, (short) 0, SilkConstants.MAX_FRAME_LENGTH + 2 * SilkConstants.MAX_SUB_FRAME_LENGTH);
+ Arrays.MemSet(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(samplesOut_tmp, (short) 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 */
+ System.arraycopy(psDec.sStereo.sMid, 0, samplesOut_tmp, samplesOut_tmp_ptrs[0], 2);
+ System.arraycopy(samplesOut_tmp, samplesOut_tmp_ptrs[0] + nSamplesOutDec.Val, psDec.sStereo.sMid, 0, 2);
+ }
+
+ /* Number of output samples */
+ nSamplesOut.Val = 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.Val];
+ 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)];
+ System.arraycopy(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.Val; 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.Val; i++) {
+ samplesOut[samplesOut_ptr + 1 + 2 * i] = resample_out[resample_out_ptr + i];
+ }
+ } else {
+ for (i = 0; i < nSamplesOut.Val; 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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/DecodeCore.java b/app/src/main/java/org/concentus/DecodeCore.java
new file mode 100644
index 0000000000..0b26a41c9e
--- /dev/null
+++ b/app/src/main/java/org/concentus/DecodeCore.java
@@ -0,0 +1,245 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class DecodeCore {
+
+ /**
+ * *******************************************************
+ */
+ /* Core decoder. Performs inverse NSQ operation LTP + LPC */
+ /**
+ * *******************************************************
+ */
+ 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 = SilkTables.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 */
+ System.arraycopy(psDec.sLPC_Q14_buf, 0, sLPC_Q14, 0, 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(B_Q14, (short) 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) {
+ System.arraycopy(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 */
+ System.arraycopy(sLPC_Q14, psDec.subfr_length, sLPC_Q14, 0, SilkConstants.MAX_LPC_ORDER);
+ pexc_Q14 += psDec.subfr_length;
+ pxq += psDec.subfr_length;
+ }
+
+ /* Save LPC state */
+ System.arraycopy(sLPC_Q14, 0, psDec.sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
+ }
+}
diff --git a/app/src/main/java/org/concentus/DecodeIndices.java b/app/src/main/java/org/concentus/DecodeIndices.java
new file mode 100644
index 0000000000..e35ffa0cc0
--- /dev/null
+++ b/app/src/main/java/org/concentus/DecodeIndices.java
@@ -0,0 +1,180 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class DecodeIndices {
+
+ /* Decode side-information parameters from payload */
+ 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];
+ short[] pred_Q8 = new short[psDec.LPC_order];
+
+ /**
+ * ****************************************
+ */
+ /* Decode signal type and quantizer offset */
+ /**
+ * ****************************************
+ */
+ if (decode_LBRR != 0 || psDec.VAD_flags[FrameIndex] != 0) {
+ Ix = psRangeDec.dec_icdf(SilkTables.silk_type_offset_VAD_iCDF, 8) + 2;
+ } else {
+ Ix = psRangeDec.dec_icdf(SilkTables.silk_type_offset_no_VAD_iCDF, 8);
+ }
+ psDec.indices.signalType = (byte) Inlines.silk_RSHIFT(Ix, 1);
+ psDec.indices.quantOffsetType = (byte) (Ix & 1);
+
+ /**
+ * *************
+ */
+ /* Decode gains */
+ /**
+ * *************
+ */
+ /* First subframe */
+ if (condCoding == SilkConstants.CODE_CONDITIONALLY) {
+ /* Conditional coding */
+ psDec.indices.GainsIndices[0] = (byte) psRangeDec.dec_icdf(SilkTables.silk_delta_gain_iCDF, 8);
+ } else {
+ /* Independent coding, in two stages: MSB bits followed by 3 LSBs */
+ psDec.indices.GainsIndices[0] = (byte) Inlines.silk_LSHIFT(psRangeDec.dec_icdf(SilkTables.silk_gain_iCDF[psDec.indices.signalType], 8), 3);
+ psDec.indices.GainsIndices[0] += (byte) psRangeDec.dec_icdf(SilkTables.silk_uniform8_iCDF, 8);
+ }
+
+ /* Remaining subframes */
+ for (i = 1; i < psDec.nb_subfr; i++) {
+ psDec.indices.GainsIndices[i] = (byte) psRangeDec.dec_icdf(SilkTables.silk_delta_gain_iCDF, 8);
+ }
+
+ /**
+ * *******************
+ */
+ /* Decode LSF Indices */
+ /**
+ * *******************
+ */
+ psDec.indices.NLSFIndices[0] = (byte) 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(SilkTables.silk_NLSF_EXT_iCDF, 8);
+ } else if (Ix == 2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE) {
+ Ix += psRangeDec.dec_icdf(SilkTables.silk_NLSF_EXT_iCDF, 8);
+ }
+ psDec.indices.NLSFIndices[i + 1] = (byte) (Ix - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE);
+ }
+
+ /* Decode LSF interpolation factor */
+ if (psDec.nb_subfr == SilkConstants.MAX_NB_SUBFR) {
+ psDec.indices.NLSFInterpCoef_Q2 = (byte) psRangeDec.dec_icdf(SilkTables.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(SilkTables.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(SilkTables.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 = (byte) psRangeDec.dec_icdf(psDec.pitch_contour_iCDF, 8);
+
+ /**
+ * *****************
+ */
+ /* Decode LTP gains */
+ /**
+ * *****************
+ */
+ /* Decode PERIndex value */
+ psDec.indices.PERIndex = (byte) psRangeDec.dec_icdf(SilkTables.silk_LTP_per_index_iCDF, 8);
+
+ for (k = 0; k < psDec.nb_subfr; k++) {
+ psDec.indices.LTPIndex[k] = (byte) psRangeDec.dec_icdf(SilkTables.silk_LTP_gain_iCDF_ptrs[psDec.indices.PERIndex], 8);
+ }
+
+ /**
+ * *******************
+ */
+ /* Decode LTP scaling */
+ /**
+ * *******************
+ */
+ if (condCoding == SilkConstants.CODE_INDEPENDENTLY) {
+ psDec.indices.LTP_scaleIndex = (byte) psRangeDec.dec_icdf(SilkTables.silk_LTPscale_iCDF, 8);
+ } else {
+ psDec.indices.LTP_scaleIndex = 0;
+ }
+ }
+ psDec.ec_prevSignalType = psDec.indices.signalType;
+
+ /**
+ * ************
+ */
+ /* Decode seed */
+ /**
+ * ************
+ */
+ psDec.indices.Seed = (byte) psRangeDec.dec_icdf(SilkTables.silk_uniform4_iCDF, 8);
+ }
+}
diff --git a/app/src/main/java/org/concentus/DecodeParameters.java b/app/src/main/java/org/concentus/DecodeParameters.java
new file mode 100644
index 0000000000..cbc6c8a190
--- /dev/null
+++ b/app/src/main/java/org/concentus/DecodeParameters.java
@@ -0,0 +1,133 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class DecodeParameters {
+
+ /* Decode parameters from payload */
+ 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];
+ byte[][] cbk_ptr_Q7;
+
+ /* Dequant Gains */
+ BoxedValueByte boxedLastGainIndex = new BoxedValueByte(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 */
+ System.arraycopy(psDecCtrl.PredCoef_Q12[1], 0, psDecCtrl.PredCoef_Q12[0], 0, psDec.LPC_order);
+ }
+
+ System.arraycopy(pNLSF_Q15, 0, psDec.prevNLSF_Q15, 0, 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 = SilkTables.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 = SilkTables.silk_LTPScales_table_Q14[Ix];
+ } else {
+ Arrays.MemSet(psDecCtrl.pitchL, 0, psDec.nb_subfr);
+ Arrays.MemSet(psDecCtrl.LTPCoef_Q14, (short) 0, SilkConstants.LTP_ORDER * psDec.nb_subfr);
+ psDec.indices.PERIndex = 0;
+ psDecCtrl.LTP_scale_Q14 = 0;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/DecodePitch.java b/app/src/main/java/org/concentus/DecodePitch.java
new file mode 100644
index 0000000000..c68ff7c1d5
--- /dev/null
+++ b/app/src/main/java/org/concentus/DecodePitch.java
@@ -0,0 +1,69 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class DecodePitch {
+
+ static void silk_decode_pitch(
+ short lagIndex, /* I */
+ byte 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;
+ byte[][] Lag_CB_ptr;
+
+ if (Fs_kHz == 8) {
+ if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR) {
+ Lag_CB_ptr = SilkTables.silk_CB_lags_stage2;
+ } else {
+ Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
+ Lag_CB_ptr = SilkTables.silk_CB_lags_stage2_10_ms;
+ }
+ } else if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR) {
+ Lag_CB_ptr = SilkTables.silk_CB_lags_stage3;
+ } else {
+ Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
+ Lag_CB_ptr = SilkTables.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);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/DecodePulses.java b/app/src/main/java/org/concentus/DecodePulses.java
new file mode 100644
index 0000000000..9be3b0a8c4
--- /dev/null
+++ b/app/src/main/java/org/concentus/DecodePulses.java
@@ -0,0 +1,141 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class DecodePulses {
+
+ /**
+ * ******************************************
+ */
+ /* Decode quantization indices of excitation */
+ /**
+ * ******************************************
+ */
+ 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(SilkTables.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(SilkTables.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(
+ SilkTables.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(pulses, (byte) 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(SilkTables.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);
+ }
+}
diff --git a/app/src/main/java/org/concentus/DecoderAPIFlag.java b/app/src/main/java/org/concentus/DecoderAPIFlag.java
new file mode 100644
index 0000000000..ad33a3d0a1
--- /dev/null
+++ b/app/src/main/java/org/concentus/DecoderAPIFlag.java
@@ -0,0 +1,39 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class DecoderAPIFlag {
+
+ public static final int FLAG_DECODE_NORMAL = 0;
+ public static final int FLAG_PACKET_LOST = 1;
+ public static final int FLAG_DECODE_LBRR = 2;
+}
diff --git a/app/src/main/java/org/concentus/Downmix.java b/app/src/main/java/org/concentus/Downmix.java
new file mode 100644
index 0000000000..c95bcc6a12
--- /dev/null
+++ b/app/src/main/java/org/concentus/Downmix.java
@@ -0,0 +1,78 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class Downmix {
+
+ ///
+ ///
+ ///
+ /// The type of signal being handled (either short or float)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ static void downmix_int(short[] x, int x_ptr, int[] sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C) {
+ int scale;
+ int j;
+ for (j = 0; j < subframe; j++) {
+ sub[j + sub_ptr] = x[(j + offset) * C + c1];
+ }
+ if (c2 > -1) {
+ for (j = 0; j < subframe; j++) {
+ sub[j + sub_ptr] += x[(j + offset) * C + c2];
+ }
+ } else if (c2 == -2) {
+ int c;
+ for (c = 1; c < C; c++) {
+ for (j = 0; j < subframe; j++) {
+ sub[j + sub_ptr] += x[(j + offset) * C + c];
+ }
+ }
+ }
+ scale = (1 << CeltConstants.SIG_SHIFT);
+ if (C == -2) {
+ scale /= C;
+ } else {
+ scale /= 2;
+ }
+ for (j = 0; j < subframe; j++) {
+ sub[j + sub_ptr] *= scale;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/EncControlState.java b/app/src/main/java/org/concentus/EncControlState.java
new file mode 100644
index 0000000000..5da1308350
--- /dev/null
+++ b/app/src/main/java/org/concentus/EncControlState.java
@@ -0,0 +1,199 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Structure for controlling encoder operation
+///
+class EncControlState {
+
+ /* I: Number of channels; 1/2 */
+ int nChannelsAPI = 0;
+
+ /* I: Number of channels; 1/2 */
+ int nChannelsInternal = 0;
+
+ /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */
+ int API_sampleRate = 0;
+
+ /* I: Maximum sampling rate in Hertz; 8000/12000/16000 */
+ int maxInternalSampleRate = 0;
+
+ /* I: Minimum sampling rate in Hertz; 8000/12000/16000 */
+ int minInternalSampleRate = 0;
+
+ /* I: Soft request for sampling rate in Hertz; 8000/12000/16000 */
+ int desiredInternalSampleRate = 0;
+
+ /* I: Number of samples per packet in milliseconds; 10/20/40/60 */
+ int payloadSize_ms = 0;
+
+ /* I: Bitrate during active speech in bits/second; internally limited */
+ int bitRate = 0;
+
+ /* I: Uplink packet loss in percent (0-100) */
+ int packetLossPercentage = 0;
+
+ /* I: Complexity mode; 0 is lowest, 10 is highest complexity */
+ int complexity = 0;
+
+ /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */
+ int useInBandFEC = 0;
+
+ /* I: Flag to enable discontinuous transmission (DTX); 0/1 */
+ int useDTX = 0;
+
+ /* I: Flag to use constant bitrate */
+ int useCBR = 0;
+
+ /* I: Maximum number of bits allowed for the frame */
+ int maxBits = 0;
+
+ /* I: Causes a smooth downmix to mono */
+ int toMono = 0;
+
+ /* I: Opus encoder is allowing us to switch bandwidth */
+ int opusCanSwitch = 0;
+
+ /* I: Make frames as independent as possible (but still use LPC) */
+ int reducedDependency = 0;
+
+ /* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */
+ int internalSampleRate = 0;
+
+ /* O: Flag that bandwidth switching is allowed (because low voice activity) */
+ int allowBandwidthSwitch = 0;
+
+ /* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */
+ int inWBmodeWithoutVariableLP = 0;
+
+ /* O: Stereo width */
+ int stereoWidth_Q14 = 0;
+
+ /* O: Tells the Opus encoder we're ready to switch */
+ int switchReady = 0;
+
+ 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;
+ }
+
+ ///
+ /// Checks this encoder control struct and returns error code, if any
+ ///
+ ///
+ 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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/EncodeAPI.java b/app/src/main/java/org/concentus/EncodeAPI.java
new file mode 100644
index 0000000000..7d3ab4ef8e
--- /dev/null
+++ b/app/src/main/java/org/concentus/EncodeAPI.java
@@ -0,0 +1,641 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class EncodeAPI {
+
+ ///
+ /// Init or Reset encoder
+ ///
+ /// I/O State
+ /// I Run-time architecture
+ /// O Encoder Status
+ /// O Returns error code
+ 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;
+ }
+
+ ///
+ /// Read control structure from encode
+ ///
+ /// I State
+ /// O Encoder Status
+ /// Returns error code
+ 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;
+ }
+
+ ///
+ /// 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
+ ///
+ /// I/O State
+ /// I Control status
+ /// I Speech sample input vector
+ /// I Number of samples in input vector
+ /// I/O Compressor data structure
+ /// I/O Number of bytes in payload (input: Max bytes)
+ /// I Flag to indicate prefilling buffers no coding
+ /// error code
+ 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.MemSet(psEnc.sStereo.pred_prev_Q13, (short) 0, 2);
+ Arrays.MemSet(psEnc.sStereo.sSide, (short) 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);
+ System.arraycopy(psEnc.state_Fxx[0].In_HP_State, 0, psEnc.state_Fxx[1].In_HP_State, 0, 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);
+ System.arraycopy(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 */
+ short[] iCDF = {0, 0};
+ iCDF[0] = (short) (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 = (byte) (LBRR_symbol > 0 ? 1 : 0);
+ if (LBRR_symbol != 0 && psEnc.state_Fxx[n].nFramesPerPacket > 1) {
+ psRangeEnc.enc_icdf(LBRR_symbol - 1, SilkTables.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.MemSet(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) {
+ BoxedValueByte midOnlyFlagBoxed = new BoxedValueByte(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.MemSet(psEnc.state_Fxx[1].prev_NLSFq_Q15, (short) 0, SilkConstants.MAX_LPC_ORDER);
+ Arrays.MemSet(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 */
+ System.arraycopy(psEnc.sStereo.sMid, 0, psEnc.state_Fxx[0].inputBuf, 0, 2);
+ System.arraycopy(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(flags, ((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;
+ }
+}
+
+//────────────────────▄▄▄▄▄▄▄▄▄▄────────────────────
+//─────────────▄▄▄▄████▓▓▓▓▓▓▓▓▓██▄▄────────────────
+//─────────▄▄██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒░▀▀▄─────────────
+//────────▀▀▀▀▀█████▓▓▓▓▒▒▒▒▒▒▒▒▒▒░░░░░▀▄───────────
+//────────────▄▄█▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░▀▄─────────
+//─────▄▀▀▄─▄█▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░█▄▀▀▄─────
+//────█░░░▄█▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░█░░░░░█────
+//───█░░░█▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░▄▀░░░▄░░█───
+//──█░░░█▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░█░░░░░█░░█──
+//──█░░█▓▒▒▄▄▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░██░░░░░░█░█──
+//─█░░█▓▄▄▀█▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░▄▄▀█░░░░▄▀█░░░░░░█░░█─
+//─█░██▀░▄▀▒▒▒▒▒▒▒▒▒▒▒▒▄▄▄▄▀▀▀░▄▀░░░▄▀░░░░░░░░░█░░█─
+//─██▀░░█▒▒▒▒▒▒▒▒▒▄▄▀▀▀░░░░░░▄▀░░▄▄▀░░░░░░░░░░░░░░█─
+//──█░░█▒▒▒▒▒▒▒▄▀▀░░░░░░░░░░▀▀▀▀▀░░░░░░░░░░▄▄░░░░░█─
+//───██▒▒▒▒▒▒▄▀██▄▄░░░░░█░░░░░░░░░░░░░▄▄▄█▀░░░░░░█──
+//────█▒▒▒▒▒█─▓██████▄▄█░░░█░░░░▄▄▄████▓─█▀▀░░░░█───
+//───█▒▒▒▒▄█─▓█──████▓─█░░░░████████──█▓─█▄░░░▄▀────
+//───█▒▒▄▀█──▓█▒▓████▓─█░░░░█─▓█████▓▒█▓─█░░█▀──────
+//──█▒▄▀█░█──▓███─███▓─█░░░░█─▓████─██▓──█░█────────
+//──█▀──█░█──▓▓██████▓─█░░░░█─▓██████▓▓──█░█────────
+//──────█░░█──▓▓████▓─█░░░░░░█─▓████▓▓──█░░█────────
+//──────█░░▀▄───▓▓▓▓──█░░░░░░█──▓▓▓▓───▄▀░░█────────
+//───────█░░▀▄───────█░░░░░░░░█───────▄▀░░█─────────
+//───────█░░░░▀▄▄▄▄▄▀░░▄▀▀▀▀▄░░▀▄▄▄▄▄▀░░░░█─────────
+//────────█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█──────────
+//─────────█░░░░░░░░░░▀▄░░░░▄▀░░░░░░░░░░█───────────
+//──────────▀▄░░░░░░░░░░░░░░░░░░░░░░░░▄▀────────────
+//────────────▀▄░░░░░░▀▄░░░░▄▀░░░░░░▄▀──────────────
+//──────────────▀▄▄░░░░░▀▀▀▀░░░░░▄▄▀────────────────
+//─────────────────▀▀▄▄▄▄▄▄▄▄▄▄▀▀───────────────────
+//──────────────────────────────────────────────────
+//───────█───█───█─████──███──███──█───█─████─█─────
+//──────█─█──█───█─█────█────█───█─██─██─█────█─────
+//─────█▄▄▄█─█─█─█─██────██──█───█─█─█─█─██───█─────
+//─────█───█──█─█──█───────█─█───█─█───█─█──────────
+//─────█───█──█─█──████─███───███──█───█─████─█─────
+//──────────────────────────────────────────────────
+//──────────────────────────────────────────────────
diff --git a/app/src/main/java/org/concentus/EncodeIndices.java b/app/src/main/java/org/concentus/EncodeIndices.java
new file mode 100644
index 0000000000..719ca835ba
--- /dev/null
+++ b/app/src/main/java/org/concentus/EncodeIndices.java
@@ -0,0 +1,219 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class EncodeIndices {
+
+ ///
+ /// Encode side-information parameters to payload
+ ///
+ /// I/O Encoder state
+ /// I/O Compressor data structure
+ /// I Frame number
+ /// I Flag indicating LBRR data is being encoded
+ /// I The type of conditional coding to use
+ 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];
+ short[] pred_Q8 = new short[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, SilkTables.silk_type_offset_VAD_iCDF, 8);
+ } else {
+ psRangeEnc.enc_icdf(typeOffset, SilkTables.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], SilkTables.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), SilkTables.silk_gain_iCDF[psIndices.signalType], 8);
+ psRangeEnc.enc_icdf(psIndices.GainsIndices[0] & 7, SilkTables.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], SilkTables.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, SilkTables.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, SilkTables.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, SilkTables.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, SilkTables.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, SilkTables.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, SilkTables.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], SilkTables.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, SilkTables.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, SilkTables.silk_uniform4_iCDF, 8);
+ }
+}
diff --git a/app/src/main/java/org/concentus/EncodePulses.java b/app/src/main/java/org/concentus/EncodePulses.java
new file mode 100644
index 0000000000..b4e77f2360
--- /dev/null
+++ b/app/src/main/java/org/concentus/EncodePulses.java
@@ -0,0 +1,264 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class EncodePulses {
+
+ ///
+ ///
+ ///
+ /// (O)
+ /// (I)
+ /// I max value for sum of pulses
+ /// I number of output values
+ /// return ok
+ 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;
+ }
+
+ ///
+ ///
+ ///
+ /// (O)
+ /// (I)
+ /// I max value for sum of pulses
+ /// I number of output values
+ /// return ok
+ 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;
+ }
+
+ ///
+ /// Encode quantization indices of excitation
+ ///
+ /// I/O compressor data structure
+ /// I Signal type
+ /// I quantOffsetType
+ /// I quantization indices
+ /// I Frame length
+ static void silk_encode_pulses(
+ EntropyCoder psRangeEnc,
+ int signalType,
+ int quantOffsetType,
+ byte[] 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;
+ short[] nBits_ptr;
+
+ Arrays.MemSet(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(pulses, (byte) 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, SilkTables.silk_max_pulses_table[0], 8);
+ /* 2+2 . 4 */
+ scale_down += combine_and_check(pulses_comb, pulses_comb, SilkTables.silk_max_pulses_table[1], 4);
+ /* 4+4 . 8 */
+ scale_down += combine_and_check(pulses_comb, pulses_comb, SilkTables.silk_max_pulses_table[2], 2);
+ /* 8+8 . 16 */
+ scale_down += combine_and_check(sum_pulses, i, pulses_comb, 0, SilkTables.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 = Integer.MAX_VALUE;
+ for (k = 0; k < SilkConstants.N_RATE_LEVELS - 1; k++) {
+ nBits_ptr = SilkTables.silk_pulses_per_block_BITS_Q5[k];
+ sumBits_Q5 = SilkTables.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, SilkTables.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], SilkTables.silk_pulses_per_block_iCDF[RateLevelIndex], 8);
+ } else {
+ psRangeEnc.enc_icdf(SilkConstants.SILK_MAX_PULSES + 1, SilkTables.silk_pulses_per_block_iCDF[RateLevelIndex], 8);
+ for (k = 0; k < nRshifts[i] - 1; k++) {
+ psRangeEnc.enc_icdf(SilkConstants.SILK_MAX_PULSES + 1, SilkTables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], 8);
+ }
+
+ psRangeEnc.enc_icdf(sum_pulses[i], SilkTables.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 = (byte) 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, SilkTables.silk_lsb_iCDF, 8);
+ }
+ bit = abs_q & 1;
+ psRangeEnc.enc_icdf(bit, SilkTables.silk_lsb_iCDF, 8);
+ }
+ }
+ }
+
+ /**
+ * *************
+ */
+ /* Encode signs */
+ /**
+ * *************
+ */
+ CodeSigns.silk_encode_signs(psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses);
+ }
+}
diff --git a/app/src/main/java/org/concentus/EntropyCoder.java b/app/src/main/java/org/concentus/EntropyCoder.java
new file mode 100644
index 0000000000..49fa3ac747
--- /dev/null
+++ b/app/src/main/java/org/concentus/EntropyCoder.java
@@ -0,0 +1,720 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Ported to Java 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.
+ */
+package org.concentus;
+
+/*A range decoder.
+This is an entropy decoder based upon \cite{Mar79}, which is itself a
+rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}.
+It is very similar to arithmetic encoding, except that encoding is done with
+digits in any base, instead of with bits, and so it is faster when using
+larger bases (i.e.: a byte).
+The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$
+is the base, longer than the theoretical optimum, but to my knowledge there
+is no published justification for this claim.
+This only seems true when using near-infinite precision arithmetic so that
+the process is carried out with no rounding errors.
+
+An excellent description of implementation details is available at
+http://www.arturocampos.com/ac_range.html
+A recent work \cite{MNW98} which proposes several changes to arithmetic
+encoding for efficiency actually re-discovers many of the principles
+behind range encoding, and presents a good theoretical analysis of them.
+
+End of stream is handled by writing out the smallest number of bits that
+ensures that the stream will be correctly decoded regardless of the value of
+any subsequent bits.
+ec_tell() can be used to determine how many bits were needed to decode
+all the symbols thus far; other data can be packed in the remaining bits of
+the input buffer.
+@PHDTHESIS{Pas76,
+author="Richard Clark Pasco",
+title="Source coding algorithms for fast data compression",
+school="Dept. of Electrical Engineering, Stanford University",
+address="Stanford, CA",
+month=May,
+year=1976
+}
+@INPROCEEDINGS{Mar79,
+author="Martin, G.N.N.",
+title="Range encoding: an algorithm for removing redundancy from a digitised
+message",
+booktitle="Video & Data Recording Conference",
+year=1979,
+address="Southampton",
+month=Jul
+}
+@ARTICLE{MNW98,
+author="Alistair Moffat and Radford Neal and Ian H. Witten",
+title="Arithmetic Coding Revisited",
+journal="{ACM} Transactions on Information Systems",
+year=1998,
+volume=16,
+number=3,
+pages="256--294",
+month=Jul,
+URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf"
+}*/
+class EntropyCoder {
+
+ private final int EC_WINDOW_SIZE = 32;
+
+ ///*The number of bits to use for the range-coded part of uint integers.*/
+ private final int EC_UINT_BITS = 8;
+
+ ///*The resolution of fractional-precision bit usage measurements, i.e.,
+ // 3 => 1/8th bits.*/
+ static final int BITRES = 3;
+
+ /*The number of bits to output at a time.*/
+ private final int EC_SYM_BITS = 8;
+
+ /*The total number of bits in each of the state registers.*/
+ private final int EC_CODE_BITS = 32;
+
+ /*The maximum symbol value.*/
+ private final long EC_SYM_MAX = 0x000000FF;
+
+ /*Bits to shift by to move a symbol into the high-order position.*/
+ private final int EC_CODE_SHIFT = 0x00000017;
+
+ /*Carry bit of the high-order range symbol.*/
+ private final long EC_CODE_TOP = 0x80000000L;
+
+ /*Low-order bit of the high-order range symbol.*/
+ private final long EC_CODE_BOT = 0x00800000;
+
+ /*The number of bits available for the last, partial symbol in the code field.*/
+ private final int EC_CODE_EXTRA = 0x00000007;
+
+ //////////////// Coder State ////////////////////
+
+ /*POINTER to Buffered input/output.*/
+ private byte[] buf;
+ private int buf_ptr;
+
+ /*The size of the buffer.*/
+ int storage;
+
+ /*The offset at which the last byte containing raw bits was read/written.*/
+ int end_offs;
+
+ /*Bits that will be read from/written at the end.*/
+ long end_window;
+
+ /*Number of valid bits in end_window.*/
+ int nend_bits;
+
+ /*The total number of whole bits read/written.
+ This does not include partial bits currently in the range coder.*/
+ int nbits_total;
+
+ /*The offset at which the next range coder byte will be read/written.*/
+ int offs;
+
+ /*The number of values in the current range.*/
+ long rng;
+
+ /*In the decoder: the difference between the top of the current range and
+ the input value, minus one.
+ In the encoder: the low end of the current range.*/
+ long val;
+
+ /*In the decoder: the saved normalization factor from ec_decode().
+ In the encoder: the number of oustanding carry propagating symbols.*/
+ long ext;
+
+ /*A buffered input/output symbol, awaiting carry propagation.*/
+ int rem;
+
+ /*Nonzero if an error occurred.*/
+ int error;
+
+ EntropyCoder() {
+ Reset();
+ }
+
+ void Reset() {
+ buf = null;
+ buf_ptr = 0;
+ storage = 0;
+ end_offs = 0;
+ end_window = 0;
+ nend_bits = 0;
+ offs = 0;
+ rng = 0;
+ val = 0;
+ ext = 0;
+ rem = 0;
+ error = 0;
+ }
+
+ void Assign(EntropyCoder other) {
+ this.buf = other.buf;
+ this.buf_ptr = other.buf_ptr;
+ this.storage = other.storage;
+ this.end_offs = other.end_offs;
+ this.end_window = other.end_window;
+ this.nend_bits = other.nend_bits;
+ this.nbits_total = other.nbits_total;
+ this.offs = other.offs;
+ this.rng = other.rng;
+ this.val = other.val;
+ this.ext = other.ext;
+ this.rem = other.rem;
+ this.error = other.error;
+ }
+
+ byte[] get_buffer() {
+ byte[] convertedBuf = new byte[this.storage];
+ System.arraycopy(this.buf, this.buf_ptr, convertedBuf, 0, this.storage);
+ return convertedBuf;
+ }
+
+ void write_buffer(byte[] data, int data_ptr, int target_offset, int size) {
+ System.arraycopy(data, data_ptr, this.buf, this.buf_ptr + target_offset, size);
+ }
+
+ int read_byte() {
+ return this.offs < this.storage ? Inlines.SignedByteToUnsignedInt(this.buf[buf_ptr + this.offs++]) : 0;
+ }
+
+ int read_byte_from_end() {
+ return this.end_offs < this.storage
+ ? Inlines.SignedByteToUnsignedInt(this.buf[buf_ptr + (this.storage - ++(this.end_offs))]) : 0;
+ }
+
+ int write_byte(long _value) {
+ if (this.offs + this.end_offs >= this.storage) {
+ return -1;
+ }
+ this.buf[buf_ptr + this.offs++] = (byte) (_value & 0xFF);
+ return 0;
+ }
+
+ int write_byte_at_end(long _value) {
+ if (this.offs + this.end_offs >= this.storage) {
+ return -1;
+ }
+
+ this.buf[buf_ptr + (this.storage - ++(this.end_offs))] = (byte) (_value & 0xFF);
+ return 0;
+ }
+
+ ///
+ /// Normalizes the contents of val and rng so that rng lies entirely in the high-order symbol.
+ ///
+ ///
+ void dec_normalize() {
+ /*If the range is too small, rescale it and input some bits.*/
+ while (this.rng <= EC_CODE_BOT) {
+ int sym;
+ this.nbits_total += EC_SYM_BITS;
+ this.rng = Inlines.CapToUInt32(this.rng << EC_SYM_BITS);
+
+ /*Use up the remaining bits from our last symbol.*/
+ sym = this.rem;
+
+ /*Read the next value from the input.*/
+ this.rem = read_byte();
+
+ /*Take the rest of the bits we need from this new symbol.*/
+ sym = (sym << EC_SYM_BITS | this.rem) >> (EC_SYM_BITS - EC_CODE_EXTRA);
+
+ /*And subtract them from val, capped to be less than EC_CODE_TOP.*/
+ this.val = Inlines.CapToUInt32((((long) this.val << EC_SYM_BITS) + (EC_SYM_MAX & ~sym))
+ & (EC_CODE_TOP - 1));
+ }
+ }
+
+ void dec_init(byte[] _buf, int _buf_ptr, int _storage) {
+ this.buf = _buf;
+ this.buf_ptr = _buf_ptr;
+ this.storage = _storage;
+ this.end_offs = 0;
+ this.end_window = 0;
+ this.nend_bits = 0;
+ /*This is the offset from which ec_tell() will subtract partial bits.
+ The final value after the ec_dec_normalize() call will be the same as in
+ the encoder, but we have to compensate for the bits that are added there.*/
+ this.nbits_total = EC_CODE_BITS + 1
+ - ((EC_CODE_BITS - EC_CODE_EXTRA) / EC_SYM_BITS) * EC_SYM_BITS;
+ this.offs = 0;
+ this.rng = 1 << EC_CODE_EXTRA;
+ this.rem = read_byte();
+ this.val = Inlines.CapToUInt32(this.rng - 1 - (this.rem >> (EC_SYM_BITS - EC_CODE_EXTRA)));
+ this.error = 0;
+ /*Normalize the interval.*/
+ dec_normalize();
+ }
+
+ long decode(long _ft) {
+ _ft = Inlines.CapToUInt32(_ft);
+ this.ext = Inlines.CapToUInt32(this.rng / _ft);
+ long s = Inlines.CapToUInt32(this.val / this.ext);
+ return Inlines.CapToUInt32(_ft - Inlines.EC_MINI(Inlines.CapToUInt32(s + 1), _ft));
+ }
+
+ long decode_bin(int _bits) {
+ this.ext = this.rng >> _bits;
+ long s = Inlines.CapToUInt32(this.val / this.ext);
+ return Inlines.CapToUInt32(Inlines.CapToUInt32(1L << _bits) - Inlines.EC_MINI(Inlines.CapToUInt32(s + 1), 1L << _bits));
+ }
+
+ void dec_update(long _fl, long _fh, long _ft) {
+ _fl = Inlines.CapToUInt32(_fl);
+ _fh = Inlines.CapToUInt32(_fh);
+ _ft = Inlines.CapToUInt32(_ft);
+ long s = Inlines.CapToUInt32(this.ext * (_ft - _fh));
+ this.val = this.val - s;
+ this.rng = _fl > 0 ? Inlines.CapToUInt32(this.ext * (_fh - _fl)) : this.rng - s;
+ dec_normalize();
+ }
+
+ ///
+ /// The probability of having a "one" is 1/(1<<_logp).
+ ///
+ ///
+ ///
+ ///
+ int dec_bit_logp(long _logp) {
+ long r;
+ long d;
+ long s;
+ int ret;
+ r = this.rng;
+ d = this.val;
+ s = r >> (int) _logp;
+ ret = d < s ? 1 : 0;
+ if (ret == 0) {
+ this.val = Inlines.CapToUInt32(d - s);
+ }
+ this.rng = ret != 0 ? s : r - s;
+ dec_normalize();
+ return ret;
+ }
+
+ int dec_icdf(short[] _icdf, int _ftb) {
+ long t;
+ long s = this.rng;
+ long d = this.val;
+ long r = s >> _ftb;
+ int ret = -1;
+ do {
+ t = s;
+ s = Inlines.CapToUInt32(r * _icdf[++ret]);
+ } while (d < s);
+ this.val = Inlines.CapToUInt32(d - s);
+ this.rng = Inlines.CapToUInt32(t - s);
+ dec_normalize();
+ return ret;
+ }
+
+ int dec_icdf(short[] _icdf, int _icdf_offset, int _ftb) {
+ long t;
+ long s = this.rng;
+ long d = this.val;
+ long r = s >> _ftb;
+ int ret = _icdf_offset - 1;
+ do {
+ t = s;
+ s = Inlines.CapToUInt32(r * _icdf[++ret]);
+ } while (d < s);
+ this.val = Inlines.CapToUInt32(d - s);
+ this.rng = Inlines.CapToUInt32(t - s);
+ dec_normalize();
+ return ret - _icdf_offset;
+ }
+
+ long dec_uint(long _ft) {
+ _ft = Inlines.CapToUInt32(_ft);
+ long ft;
+ long s;
+ int ftb;
+ /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
+ Inlines.OpusAssert(_ft > 1);
+ _ft--;
+ ftb = Inlines.EC_ILOG(_ft);
+ if (ftb > EC_UINT_BITS) {
+ long t;
+ ftb -= EC_UINT_BITS;
+ ft = Inlines.CapToUInt32((_ft >> ftb) + 1);
+ s = Inlines.CapToUInt32(decode(ft));
+ dec_update(s, (s + 1), ft);
+ t = Inlines.CapToUInt32((s << ftb | dec_bits(ftb)));
+ if (t <= _ft) {
+ return t;
+ }
+ this.error = 1;
+ return _ft;
+ } else {
+ _ft++;
+ s = Inlines.CapToUInt32(decode(_ft));
+ dec_update(s, s + 1, _ft);
+ return s;
+ }
+ }
+
+ int dec_bits(int _bits) {
+ long window;
+ int available;
+ int ret;
+ window = this.end_window;
+ available = this.nend_bits;
+ if (available < _bits) {
+ do {
+ window = Inlines.CapToUInt32(window | (read_byte_from_end() << available));
+ available += EC_SYM_BITS;
+ } while (available <= EC_WINDOW_SIZE - EC_SYM_BITS);
+ }
+ ret = (int) (0xFFFFFFFF & (window & ((1 << _bits) - 1)));
+ window = window >> _bits;
+ available = available - _bits;
+ this.end_window = Inlines.CapToUInt32(window);
+ this.nend_bits = available;
+ this.nbits_total = this.nbits_total + _bits;
+ return ret;
+ }
+
+ ///
+ /// Outputs a symbol, with a carry bit.
+ /// If there is a potential to propagate a carry over several symbols, they are
+ /// buffered until it can be determined whether or not an actual carry will
+ /// occur.
+ /// If the counter for the buffered symbols overflows, then the stream becomes
+ /// undecodable.
+ /// This gives a theoretical limit of a few billion symbols in a single packet on
+ /// 32-bit systems.
+ /// The alternative is to truncate the range in order to force a carry, but
+ /// requires similar carry tracking in the decoder, needlessly slowing it down.
+ ///
+ ///
+ ///
+ void enc_carry_out(int _c) {
+ if (_c != EC_SYM_MAX) {
+ /*No further carry propagation possible, flush buffer.*/
+ int carry;
+ carry = _c >> EC_SYM_BITS;
+
+ /*Don't output a byte on the first write.
+ This compare should be taken care of by branch-prediction thereafter.*/
+ if (this.rem >= 0) {
+ this.error |= write_byte(Inlines.CapToUInt32(this.rem + carry));
+ }
+
+ if (this.ext > 0) {
+ long sym;
+ sym = (EC_SYM_MAX + carry) & EC_SYM_MAX;
+ do {
+ this.error |= write_byte(sym);
+ } while (--(this.ext) > 0);
+ }
+
+ this.rem = (int) (_c & EC_SYM_MAX);
+ } else {
+ this.ext++;
+ }
+ }
+
+ void enc_normalize() {
+ /*If the range is too small, output some bits and rescale it.*/
+ while (this.rng <= EC_CODE_BOT) {
+ enc_carry_out((int) (this.val >> EC_CODE_SHIFT));
+ /*Move the next-to-high-order symbol into the high-order position.*/
+ this.val = Inlines.CapToUInt32((this.val << EC_SYM_BITS) & (EC_CODE_TOP - 1));
+ this.rng = Inlines.CapToUInt32(this.rng << EC_SYM_BITS);
+ this.nbits_total += EC_SYM_BITS;
+ }
+ }
+
+ void enc_init(byte[] _buf, int buf_ptr, int _size) {
+ this.buf = _buf;
+ this.buf_ptr = buf_ptr;
+ this.end_offs = 0;
+ this.end_window = 0;
+ this.nend_bits = 0;
+ /*This is the offset from which ec_tell() will subtract partial bits.*/
+ this.nbits_total = EC_CODE_BITS + 1;
+ this.offs = 0;
+ this.rng = Inlines.CapToUInt32(EC_CODE_TOP);
+ this.rem = -1;
+ this.val = 0;
+ this.ext = 0;
+ this.storage = _size;
+ this.error = 0;
+ }
+
+ void encode(long _fl, long _fh, long _ft) {
+ _fl = Inlines.CapToUInt32(_fl);
+ _fh = Inlines.CapToUInt32(_fh);
+ _ft = Inlines.CapToUInt32(_ft);
+ long r = Inlines.CapToUInt32(this.rng / _ft);
+ if (_fl > 0) {
+ this.val += Inlines.CapToUInt32(this.rng - (r * (_ft - _fl)));
+ this.rng = Inlines.CapToUInt32(r * (_fh - _fl));
+ } else {
+ this.rng = Inlines.CapToUInt32(this.rng - (r * (_ft - _fh)));
+ }
+
+ enc_normalize();
+ }
+
+ void encode_bin(long _fl, long _fh, int _bits) {
+ _fl = Inlines.CapToUInt32(_fl);
+ _fh = Inlines.CapToUInt32(_fh);
+ long r = Inlines.CapToUInt32(this.rng >> (int) _bits);
+ if (_fl > 0) {
+ this.val = Inlines.CapToUInt32(this.val + Inlines.CapToUInt32(this.rng - (r * ((1 << (int) _bits) - _fl))));
+ this.rng = Inlines.CapToUInt32(r * (_fh - _fl));
+ } else {
+ this.rng = Inlines.CapToUInt32(this.rng - (r * ((1 << (int) _bits) - _fh)));
+ }
+
+ enc_normalize();
+ }
+
+ /*The probability of having a "one" is 1/(1<<_logp).*/
+ void enc_bit_logp(int _val, int _logp) {
+ long r = this.rng;
+ long l = this.val;
+ long s = r >> _logp;
+ r -= s;
+ if (_val != 0) {
+ this.val = Inlines.CapToUInt32(l + r);
+ }
+
+ this.rng = _val != 0 ? s : r;
+ enc_normalize();
+ }
+
+ void enc_icdf(int _s, short[] _icdf, int _ftb) {
+ long r = Inlines.CapToUInt32(this.rng >> _ftb);
+ if (_s > 0) {
+ this.val = this.val + Inlines.CapToUInt32(this.rng - Inlines.CapToUInt32(r * _icdf[_s - 1]));
+ this.rng = (r * Inlines.CapToUInt32(_icdf[_s - 1] - _icdf[_s]));
+ } else {
+ this.rng = Inlines.CapToUInt32(this.rng - (r * _icdf[_s]));
+ }
+ enc_normalize();
+ }
+
+ void enc_icdf(int _s, short[] _icdf, int icdf_ptr, int _ftb) {
+ long r = Inlines.CapToUInt32(this.rng >> _ftb);
+ if (_s > 0) {
+ this.val = this.val + Inlines.CapToUInt32(this.rng - Inlines.CapToUInt32(r * _icdf[icdf_ptr + _s - 1]));
+ this.rng = Inlines.CapToUInt32(r * Inlines.CapToUInt32(_icdf[icdf_ptr + _s - 1] - _icdf[icdf_ptr + _s]));
+ } else {
+ this.rng = Inlines.CapToUInt32(this.rng - (r * _icdf[icdf_ptr + _s]));
+ }
+ enc_normalize();
+ }
+
+ void enc_uint(long _fl, long _ft) {
+ _fl = Inlines.CapToUInt32(_fl);
+ _ft = Inlines.CapToUInt32(_ft);
+
+ long ft;
+ long fl;
+ int ftb;
+ /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
+ Inlines.OpusAssert(_ft > 1);
+ _ft--;
+ ftb = Inlines.EC_ILOG(_ft);
+ if (ftb > EC_UINT_BITS) {
+ ftb -= EC_UINT_BITS;
+ ft = Inlines.CapToUInt32((_ft >> ftb) + 1);
+ fl = Inlines.CapToUInt32(_fl >> ftb);
+ encode(fl, fl + 1, ft);
+ enc_bits(_fl & Inlines.CapToUInt32((1 << ftb) - 1), ftb);
+ } else {
+ encode(_fl, _fl + 1, _ft + 1);
+ }
+ }
+
+ void enc_bits(long _fl, int _bits) {
+ _fl = Inlines.CapToUInt32(_fl);
+ long window;
+ int used;
+ window = this.end_window;
+ used = this.nend_bits;
+ Inlines.OpusAssert(_bits > 0);
+
+ if (used + _bits > EC_WINDOW_SIZE) {
+ do {
+ this.error = this.error | write_byte_at_end(window & EC_SYM_MAX);
+ window >>= EC_SYM_BITS;
+ used -= EC_SYM_BITS;
+ } while (used >= EC_SYM_BITS);
+ }
+
+ window = window | Inlines.CapToUInt32(_fl << used);
+ used += _bits;
+ this.end_window = window;
+ this.nend_bits = used;
+ this.nbits_total += _bits;
+ }
+
+ void enc_patch_initial_bits(long _val, int _nbits) {
+ int shift;
+ long mask;
+ Inlines.OpusAssert(_nbits <= EC_SYM_BITS);
+ shift = EC_SYM_BITS - _nbits;
+ mask = ((1 << _nbits) - 1) << shift;
+
+ if (this.offs > 0) {
+ /*The first byte has been finalized.*/
+ this.buf[buf_ptr] = (byte) ((this.buf[buf_ptr] & ~mask) | Inlines.CapToUInt32(_val << shift));
+ } else if (this.rem >= 0) {
+ /*The first byte is still awaiting carry propagation.*/
+ this.rem = (int) Inlines.CapToUInt32((Inlines.CapToUInt32((this.rem & ~mask) | _val)) << shift);
+ } else if (this.rng <= (EC_CODE_TOP >> (int) _nbits)) {
+ /*The renormalization loop has never been run.*/
+ this.val = Inlines.CapToUInt32((this.val & ~(mask << EC_CODE_SHIFT))
+ | Inlines.CapToUInt32(Inlines.CapToUInt32(_val) << (EC_CODE_SHIFT + shift)));
+ } else {
+ /*The encoder hasn't even encoded _nbits of data yet.*/
+ this.error = -1;
+ }
+ }
+
+ void enc_shrink(int _size) {
+ Inlines.OpusAssert(this.offs + this.end_offs <= _size);
+ Arrays.MemMove(this.buf, buf_ptr + (int) _size - (int) this.end_offs, buf_ptr + (int) this.storage - (int) this.end_offs, (int) this.end_offs);
+ this.storage = _size;
+ }
+
+ int range_bytes() {
+ return this.offs;
+ }
+
+ int get_error() {
+ return this.error;
+ }
+
+ ///
+ /// Returns the number of bits "used" by the encoded or decoded symbols so far.
+ /// This same number can be computed in either the encoder or the decoder, and is
+ /// suitable for making coding decisions.
+ /// This will always be slightly larger than the exact value (e.g., all
+ /// rounding error is in the positive direction).
+ ///
+ ///
+ /// The number of bits.
+ int tell() {
+ int returnVal = this.nbits_total - Inlines.EC_ILOG(this.rng);
+ return returnVal;
+ }
+
+ private static final int[] correction = {35733, 38967, 42495, 46340, 50535, 55109, 60097, 65535};
+
+ ///
+ /// This is a faster version of ec_tell_frac() that takes advantage
+ /// of the low(1/8 bit) resolution to use just a linear function
+ /// followed by a lookup to determine the exact transition thresholds.
+ ///
+ ///
+ ///
+ int tell_frac() {
+ int nbits;
+ int r;
+ int l;
+ long b;
+ nbits = this.nbits_total << BITRES;
+ l = Inlines.EC_ILOG(this.rng);
+ r = (int) (this.rng >> (l - 16));
+ b = Inlines.CapToUInt32((r >> 12) - 8);
+ b = Inlines.CapToUInt32(b + (r > correction[(int) b] ? 1 : 0));
+ l = (int) ((l << 3) + b);
+ return nbits - l;
+ }
+
+ void enc_done() {
+ long window;
+ int used;
+ long msk;
+ long end;
+ int l;
+ /*We output the minimum number of bits that ensures that the symbols encoded
+ thus far will be decoded correctly regardless of the bits that follow.*/
+ l = EC_CODE_BITS - Inlines.EC_ILOG(this.rng);
+ msk = Inlines.CapToUInt32((EC_CODE_TOP - 1) >>> l);
+ end = Inlines.CapToUInt32((Inlines.CapToUInt32(this.val + msk)) & ~msk);
+
+ if ((end | msk) >= this.val + this.rng) {
+ l++;
+ msk >>= 1;
+ end = Inlines.CapToUInt32((Inlines.CapToUInt32(this.val + msk)) & ~msk);
+ }
+
+ while (l > 0) {
+ enc_carry_out((int) (end >> EC_CODE_SHIFT));
+ end = Inlines.CapToUInt32((end << EC_SYM_BITS) & (EC_CODE_TOP - 1));
+ l -= EC_SYM_BITS;
+ }
+
+ /*If we have a buffered byte flush it into the output buffer.*/
+ if (this.rem >= 0 || this.ext > 0) {
+ enc_carry_out(0);
+ }
+
+ /*If we have buffered extra bits, flush them as well.*/
+ window = this.end_window;
+ used = this.nend_bits;
+
+ while (used >= EC_SYM_BITS) {
+ this.error |= write_byte_at_end(window & EC_SYM_MAX);
+ window = window >> EC_SYM_BITS;
+ used -= EC_SYM_BITS;
+ }
+
+ /*Clear any excess space and add any remaining extra bits to the last byte.*/
+ if (this.error == 0) {
+ Arrays.MemSetWithOffset(this.buf, (byte) 0, buf_ptr + (int) this.offs, (int) this.storage - (int) this.offs - (int) this.end_offs);
+ if (used > 0) {
+ /*If there's no range coder data at all, give up.*/
+ if (this.end_offs >= this.storage) {
+ this.error = -1;
+ } else {
+ l = -l;
+ /*If we've busted, don't add too many extra bits to the last byte; it
+ would corrupt the range coder data, and that's more important.*/
+ if (this.offs + this.end_offs >= this.storage && l < used) {
+ window = Inlines.CapToUInt32(window & ((1 << l) - 1));
+ this.error = -1;
+ }
+
+ int z = buf_ptr + this.storage - this.end_offs - 1;
+ this.buf[z] = (byte) (this.buf[z] | (byte) (window & 0xFF));
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/FFTState.java b/app/src/main/java/org/concentus/FFTState.java
new file mode 100644
index 0000000000..2b9a18b825
--- /dev/null
+++ b/app/src/main/java/org/concentus/FFTState.java
@@ -0,0 +1,46 @@
+/* Copyright (c) 2003-2004, Mark Borgerding
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2011 Xiph.Org Foundation
+ Modified from KISS-FFT by Jean-Marc Valin
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class FFTState {
+
+ int nfft = 0;
+ short scale = 0;
+ int scale_shift = 0;
+ int shift = 0;
+ short[] factors = new short[2 * KissFFT.MAXFACTORS];
+ short[] bitrev = null;
+ short[] twiddles = null;
+}
diff --git a/app/src/main/java/org/concentus/Filters.java b/app/src/main/java/org/concentus/Filters.java
new file mode 100644
index 0000000000..1f0dad42bb
--- /dev/null
+++ b/app/src/main/java/org/concentus/Filters.java
@@ -0,0 +1,584 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class Filters {
+
+ 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);
+ }
+ }
+
+ 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;
+ }
+
+ ///
+ /// Second order ARMA filter, alternative implementation
+ ///
+ /// I input signal
+ /// I MA coefficients [3]
+ /// I AR coefficients [2]
+ /// I/O State vector [2]
+ /// O output signal
+ /// I signal length (must be even)
+ /// I Operate on interleaved signal if > 1
+ 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));
+ }
+ }
+
+ 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));
+ }
+ }
+
+ /* Coefficients for 2-band filter bank based on first-order allpass filters */
+ private final static short A_fb1_20 = 5394 << 1;
+ private final static short A_fb1_21 = -24290;
+
+ /* (opus_int16)(20623 << 1) */
+
+ ///
+ /// Split signal into two decimated bands using first-order allpass filters
+ ///
+ /// I Input signal [N]
+ /// I/O State vector [2]
+ /// O Low band [N/2]
+ /// O High band [N/2]
+ /// I Number of input samples
+ 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));
+ }
+ }
+
+ ///
+ /// Chirp (bandwidth expand) LP AR filter
+ ///
+ /// I/O AR filter to be expanded (without leading 1)
+ /// I Length of ar
+ /// I Chirp factor in Q16
+ 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]);
+ }
+
+ ///
+ /// 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
+ ///
+ /// order [TRANSITION_NB]
+ /// order [TRANSITION_NA]
+ ///
+ ///
+ 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(
+ SilkTables.silk_Transition_LP_B_Q28[ind][nb],
+ SilkTables.silk_Transition_LP_B_Q28[ind + 1][nb]
+ - SilkTables.silk_Transition_LP_B_Q28[ind][nb],
+ fac_Q16);
+ }
+
+ for (na = 0; na < SilkConstants.TRANSITION_NA; na++) {
+ A_Q28[na] = Inlines.silk_SMLAWB(
+ SilkTables.silk_Transition_LP_A_Q28[ind][na],
+ SilkTables.silk_Transition_LP_A_Q28[ind + 1][na]
+ - SilkTables.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(
+ SilkTables.silk_Transition_LP_B_Q28[ind + 1][nb],
+ SilkTables.silk_Transition_LP_B_Q28[ind + 1][nb]
+ - SilkTables.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(
+ SilkTables.silk_Transition_LP_A_Q28[ind + 1][na],
+ SilkTables.silk_Transition_LP_A_Q28[ind + 1][na]
+ - SilkTables.silk_Transition_LP_A_Q28[ind][na],
+ fac_Q16 - ((int) 1 << 16));
+ }
+ }
+ } else {
+ System.arraycopy(SilkTables.silk_Transition_LP_B_Q28[ind], 0, B_Q28, 0, SilkConstants.TRANSITION_NB);
+ System.arraycopy(SilkTables.silk_Transition_LP_A_Q28[ind], 0, A_Q28, 0, SilkConstants.TRANSITION_NA);
+ }
+ } else {
+ System.arraycopy(SilkTables.silk_Transition_LP_B_Q28[SilkConstants.TRANSITION_INT_NUM - 1], 0, B_Q28, 0, SilkConstants.TRANSITION_NB);
+ System.arraycopy(SilkTables.silk_Transition_LP_A_Q28[SilkConstants.TRANSITION_INT_NUM - 1], 0, A_Q28, 0, SilkConstants.TRANSITION_NA);
+ }
+ }
+
+ ///
+ /// LPC analysis filter
+ /// NB! State is kept internally and the
+ /// filter always starts with zero state
+ /// first d output samples are set to zero
+ ///
+ /// O Output signal
+ /// I Input signal
+ /// I MA prediction coefficients, Q12 [order]
+ /// I Signal length
+ /// I Filter order
+ /// I Run-time architecture
+ 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];
+ }
+ Kernels.celt_fir(input, input_ptr + d, num, output, output_ptr + d, len - d, d, mem);
+ for (j = output_ptr; j < output_ptr + d; j++) {
+ output[j] = 0;
+ }
+ }
+
+ private static final int QA = 24;
+ private static final 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)
+ ///
+ /// Prediction coefficients, order [2][SILK_MAX_ORDER_LPC]
+ /// Prediction order
+ /// inverse prediction gain in energy domain, Q30
+ 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;
+ }
+
+ ///
+ /// For input in Q12 domain
+ ///
+ /// Prediction coefficients, Q12 [order]
+ /// I Prediction order
+ /// inverse prediction gain in energy domain, Q30
+ 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);
+ }
+}
diff --git a/app/src/main/java/org/concentus/FindLPC.java b/app/src/main/java/org/concentus/FindLPC.java
new file mode 100644
index 0000000000..5f8c17f6d8
--- /dev/null
+++ b/app/src/main/java/org/concentus/FindLPC.java
@@ -0,0 +1,158 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class FindLPC {
+
+ /* Finds LPC vector from correlations, and converts to NLSF */
+ 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;
+ BoxedValueInt res_nrg0 = new BoxedValueInt(0);
+ BoxedValueInt res_nrg1 = new BoxedValueInt(0);
+ BoxedValueInt rshift0 = new BoxedValueInt(0);
+ BoxedValueInt rshift1 = new BoxedValueInt(0);
+ BoxedValueInt scratch_box1 = new BoxedValueInt(0);
+ BoxedValueInt scratch_box2 = new BoxedValueInt(0);
+
+ /* 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(res_nrg0, rshift0, LPC_res, psEncC.predictLPCOrder, subfr_length - psEncC.predictLPCOrder);
+
+ SumSqrShift.silk_sum_sqr_shift(res_nrg1, rshift1, LPC_res, psEncC.predictLPCOrder + subfr_length, subfr_length - psEncC.predictLPCOrder);
+
+ /* Add subframe energies from first half frame */
+ shift = rshift0.Val - rshift1.Val;
+ if (shift >= 0) {
+ res_nrg1.Val = Inlines.silk_RSHIFT(res_nrg1.Val, shift);
+ res_nrg_interp_Q = 0 - rshift0.Val;
+ } else {
+ res_nrg0.Val = Inlines.silk_RSHIFT(res_nrg0.Val, 0 - shift);
+ res_nrg_interp_Q = 0 - rshift1.Val;
+ }
+ res_nrg_interp = Inlines.silk_ADD32(res_nrg0.Val, res_nrg1.Val);
+
+ /* 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 = (byte) 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));
+
+ }
+}
diff --git a/app/src/main/java/org/concentus/FindLTP.java b/app/src/main/java/org/concentus/FindLTP.java
new file mode 100644
index 0000000000..9ee550d508
--- /dev/null
+++ b/app/src/main/java/org/concentus/FindLTP.java
@@ -0,0 +1,296 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class FindLTP {
+
+ /* Head room for correlations */
+ private static final int LTP_CORRS_HEAD_ROOM = 2;
+
+ ///
+ /// Finds linear prediction coeffecients and weights
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ 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);
+ BoxedValueInt boxed_rr = new BoxedValueInt(0);
+ BoxedValueInt boxed_rr_shift = new BoxedValueInt(0);
+ SumSqrShift.silk_sum_sqr_shift(boxed_rr, boxed_rr_shift, r_lpc, r_ptr, subfr_length);
+ /* rr[ k ] in Q( -rr_shifts ) */
+ rr[k] = boxed_rr.Val;
+ rr_shifts = boxed_rr_shift.Val;
+
+ /* 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) < Integer.MAX_VALUE);
+ /* 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], (short) 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;
+ }
+ }
+
+ ///
+ ///
+ ///
+ /// [SilkConstants.LTP_ORDER]
+ /// [SilkConstants.LTP_ORDER]
+ ///
+ 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));
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/FindPitchLags.java b/app/src/main/java/org/concentus/FindPitchLags.java
new file mode 100644
index 0000000000..02dcb3bf4b
--- /dev/null
+++ b/app/src/main/java/org/concentus/FindPitchLags.java
@@ -0,0 +1,165 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class FindPitchLags {
+
+ /* Find pitch lags */
+ 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;
+ System.arraycopy(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(0);
+ 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);
+ BoxedValueByte boxed_contourIndex = new BoxedValueByte(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.MemSet(psEncCtrl.pitchL, 0, SilkConstants.MAX_NB_SUBFR);
+ psEnc.indices.lagIndex = 0;
+ psEnc.indices.contourIndex = 0;
+ psEnc.LTPCorr_Q15 = 0;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/FindPredCoefs.java b/app/src/main/java/org/concentus/FindPredCoefs.java
new file mode 100644
index 0000000000..053bac986a
--- /dev/null
+++ b/app/src/main/java/org/concentus/FindPredCoefs.java
@@ -0,0 +1,163 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class FindPredCoefs {
+
+ 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 = Integer.MAX_VALUE >> 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 */
+ BoxedValueByte boxed_periodicity = new BoxedValueByte(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.MemSet(psEncCtrl.LTPCoef_Q14, (short) 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 */
+ System.arraycopy(NLSF_Q15, 0, psEnc.prev_NLSFq_Q15, 0, SilkConstants.MAX_LPC_ORDER);
+ }
+}
diff --git a/app/src/main/java/org/concentus/GainQuantization.java b/app/src/main/java/org/concentus/GainQuantization.java
new file mode 100644
index 0000000000..c81f5e0c84
--- /dev/null
+++ b/app/src/main/java/org/concentus/GainQuantization.java
@@ -0,0 +1,161 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class GainQuantization {
+
+ private static final int OFFSET = ((SilkConstants.MIN_QGAIN_DB * 128) / 6 + 16 * 128);
+ private static final int SCALE_Q16 = ((65536 * (SilkConstants.N_LEVELS_QGAIN - 1)) / (((SilkConstants.MAX_QGAIN_DB - SilkConstants.MIN_QGAIN_DB) * 128) / 6));
+ private static final int INV_SCALE_Q16 = ((65536 * (((SilkConstants.MAX_QGAIN_DB - SilkConstants.MIN_QGAIN_DB) * 128) / 6)) / (SilkConstants.N_LEVELS_QGAIN - 1));
+
+ ///
+ /// Gain scalar quantization with hysteresis, uniform on log scale
+ ///
+ /// O gain indices [MAX_NB_SUBFR]
+ /// I/O gains (quantized out) [MAX_NB_SUBFR]
+ /// I/O last index in previous frame. [Porting note] original implementation passed this as an int8*
+ /// I first gain is delta coded if 1
+ /// I number of subframes
+ static void silk_gains_quant(
+ byte[] ind,
+ int[] gain_Q16,
+ BoxedValueByte 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] = (byte) (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] = (byte) (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] = (byte) (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] = (byte) (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] = (byte) (double_step_size_threshold + Inlines.silk_RSHIFT(ind[k] - double_step_size_threshold + 1, 1));
+ }
+
+ ind[k] = (byte) (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 = (byte) (prev_ind.Val + (byte) (Inlines.silk_LSHIFT(ind[k], 1) - double_step_size_threshold));
+ } else {
+ prev_ind.Val = (byte) (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 */
+ }
+ }
+
+ ///
+ /// Gains scalar dequantization, uniform on log scale
+ ///
+ /// O quantized gains [MAX_NB_SUBFR]
+ /// I gain indices [MAX_NB_SUBFR]
+ /// I/O last index in previous frame [Porting note] original implementation passed this as an int8*
+ /// I first gain is delta coded if 1
+ /// I number of subframes
+ static void silk_gains_dequant(
+ int[] gain_Q16,
+ byte[] ind,
+ BoxedValueByte 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 = (byte) (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 = (byte) (prev_ind.Val + (byte) (Inlines.silk_LSHIFT(ind_tmp, 1) - double_step_size_threshold));
+ } else {
+ prev_ind.Val = (byte) (prev_ind.Val + (byte) (ind_tmp));
+ }
+ }
+
+ prev_ind.Val = (byte) (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 */
+ }
+ }
+
+ ///
+ /// Compute unique identifier of gain indices vector
+ ///
+ /// I gain indices [MAX_NB_SUBFR]
+ /// I number of subframes
+ /// unique identifier of gains
+ static int silk_gains_ID(byte[] 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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/HPVariableCutoff.java b/app/src/main/java/org/concentus/HPVariableCutoff.java
new file mode 100644
index 0000000000..240a49f114
--- /dev/null
+++ b/app/src/main/java/org/concentus/HPVariableCutoff.java
@@ -0,0 +1,79 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class HPVariableCutoff {
+
+ ///
+ /// High-pass filter with cutoff frequency adaptation based on pitch lag statistics
+ ///
+ /// I/O Encoder states
+ 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));
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/Inlines.java b/app/src/main/java/org/concentus/Inlines.java
new file mode 100644
index 0000000000..559dd818a9
--- /dev/null
+++ b/app/src/main/java/org/concentus/Inlines.java
@@ -0,0 +1,1781 @@
+/* Copyright (c) 2006-2011 Skype Limited.
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2011 Xiph.Org Foundation
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class Inlines {
+
+ static void OpusAssert(boolean condition) {
+ if (!condition) {
+ throw new AssertionError();
+ }
+ //Debug.Assert(condition);
+ }
+
+ static void OpusAssert(boolean condition, String message) {
+ if (!condition) {
+ throw new AssertionError(message);
+ }
+ //Debug.Assert(condition, message);
+ }
+
+ static long CapToUInt32(long val) {
+ return (0xFFFFFFFFL & (int) val);
+ }
+
+ static long CapToUInt32(int val) {
+ return val;
+ }
+
+ // CELT-SPECIFIC INLINES
+ // /** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */
+ //#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
+ static int MULT16_16SU(int a, int b) {
+ return ((int) (short) (a) * (int) (b & 0xFFFF));
+ }
+
+ // /** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+ //#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
+ static int MULT16_32_Q16(short a, int b) {
+ return ADD32(MULT16_16((a), SHR((b), 16)), SHR(MULT16_16SU((a), ((b) & 0x0000ffff)), 16));
+ }
+
+ static int MULT16_32_Q16(int a, int b) {
+ return ADD32(MULT16_16((a), SHR((b), 16)), SHR(MULT16_16SU((a), ((b) & 0x0000ffff)), 16));
+ }
+
+ // /** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */
+ //#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
+ static int MULT16_32_P16(short a, int b) {
+ return ADD32(MULT16_16((a), SHR((b), 16)), PSHR(MULT16_16SU((a), ((b) & 0x0000ffff)), 16));
+ }
+
+ static int MULT16_32_P16(int a, int b) {
+ return ADD32(MULT16_16((a), SHR((b), 16)), PSHR(MULT16_16SU((a), ((b) & 0x0000ffff)), 16));
+ }
+
+ // /** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+ static int MULT16_32_Q15(short a, int b) {
+ return ((a * (b >> 16)) << 1) + ((a * (b & 0xFFFF)) >> 15);
+ //return ADD32(SHL(MULT16_16((a), SHR((b), 16)), 1), SHR(MULT16_16SU((a), (ushort)((b) & 0x0000ffff)), 15));
+ }
+
+ static int MULT16_32_Q15(int a, int b) {
+ return ((a * (b >> 16)) << 1) + ((a * (b & 0xFFFF)) >> 15);
+ //return ADD32(SHL(MULT16_16((a), SHR((b), 16)), 1), SHR(MULT16_16SU((a), (uint)((b) & 0x0000ffff)), 15));
+ }
+
+ // /** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */
+ //#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15))
+ static int MULT32_32_Q31(int a, int b) {
+ return ADD32(ADD32(SHL(MULT16_16(SHR((a), 16), SHR((b), 16)), 1), SHR(MULT16_16SU(SHR((a), 16), ((b) & 0x0000ffff)), 15)), SHR(MULT16_16SU(SHR((b), 16), ((a) & 0x0000ffff)), 15));
+ }
+
+ // "Compile-time" (not really) conversion of float constant to 16-bit value
+ static short QCONST16(float x, int bits) {
+ return ((short) (0.5 + (x) * (((int) 1) << (bits))));
+ }
+
+ // "Compile-time" (not really) conversion of float constant to 32-bit value
+ static int QCONST32(float x, int bits) {
+ return ((int) (0.5 + (x) * (((int) 1) << (bits))));
+ }
+
+ // /** Negate a 16-bit value */
+ static short NEG16(short x) {
+ return (short) (0 - x);
+ }
+
+ static int NEG16(int x) {
+ return 0 - x;
+ }
+
+ // /** Negate a 32-bit value */
+ static int NEG32(int x) {
+ return 0 - x;
+ }
+
+ // /** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */
+ static short EXTRACT16(int x) {
+ return ((short) x);
+ }
+
+ // /** Change a 16-bit value into a 32-bit value */
+ static int EXTEND32(short x) {
+ return (int) x;
+ }
+
+ static int EXTEND32(int x) {
+ return x;
+ }
+
+ // /** Arithmetic shift-right of a 16-bit value */
+ static short SHR16(short a, int shift) {
+ return (short) ((a) >> (shift));
+ }
+
+ static int SHR16(int a, int shift) {
+ return ((a) >> (shift));
+ }
+
+ // /** Arithmetic shift-left of a 16-bit value */
+ static short SHL16(short a, int shift) {
+ return ((short) ((a & 0xFFFF) << shift));
+ }
+
+ static int SHL16(int a, int shift) {
+ return (int) (0xFFFFFFFF & ((long) a << shift));
+ }
+
+ // /** Arithmetic shift-right of a 32-bit value */
+ static int SHR32(int a, int shift) {
+ return a >> shift;
+ }
+
+ // /** Arithmetic shift-left of a 32-bit value */
+ static int SHL32(int a, int shift) {
+ return (int) (0xFFFFFFFF & ((long) a << shift));
+ }
+
+ // /** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */
+ static int PSHR32(int a, int shift) {
+ return (SHR32((a) + ((EXTEND32(1) << ((shift)) >> 1)), shift));
+ }
+
+ static short PSHR16(short a, int shift) {
+ return SHR16((short) (a + (1 << (shift) >> 1)), shift);
+ }
+
+ static int PSHR16(int a, int shift) {
+ return SHR32((a + (1 << (shift) >> 1)), shift);
+ }
+
+ // /** 32-bit arithmetic shift right where the argument can be negative */
+ static int VSHR32(int a, int shift) {
+ return (((shift) > 0) ? SHR32(a, shift) : SHL32(a, -(shift)));
+ }
+
+ // /** "RAW" macros, should not be used outside of this header file */
+ private static int SHR(int a, int shift) {
+ return ((a) >> (shift));
+ }
+
+ private static int SHL(int a, int shift) {
+ return SHL32(a, shift);
+ }
+
+ private static int SHR(short a, int shift) {
+ return ((a) >> (shift));
+ }
+
+ private static int SHL(short a, int shift) {
+ return SHL32(a, shift);
+ }
+
+ private static int PSHR(int a, int shift) {
+ return (SHR((a) + ((EXTEND32(1) << ((shift)) >> 1)), shift));
+ }
+
+ static int SATURATE(int x, int a) {
+ return (((x) > (a) ? (a) : (x) < -(a) ? -(a) : (x)));
+ }
+
+ static short SATURATE16(int x) {
+ return (EXTRACT16((x) > 32767 ? 32767 : (x) < -32768 ? -32768 : (x)));
+ }
+
+ // /** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */
+ static short ROUND16(short x, short a) {
+ return (EXTRACT16(PSHR32((x), (a))));
+ }
+
+ static int ROUND16(int x, int a) {
+ return PSHR32((x), (a));
+ }
+
+ static int PDIV32(int a, int b) {
+ return a / b;
+ }
+
+ // /** Divide by two */
+ // fixme: can this be optimized?
+ static short HALF16(short x) {
+ return (SHR16(x, 1));
+ }
+
+ static int HALF16(int x) {
+ return (SHR32(x, 1));
+ }
+
+ static int HALF32(int x) {
+ return (SHR32(x, 1));
+ }
+
+ // /** Add two 16-bit values */
+ static short ADD16(short a, short b) {
+ return ((short) ((short) (a) + (short) (b)));
+ }
+
+ static int ADD16(int a, int b) {
+ return (a + b);
+ }
+
+ // /** Subtract two 16-bit values */
+ static short SUB16(short a, short b) {
+ return ((short) ((short) (a) - (short) (b)));
+ }
+
+ static int SUB16(int a, int b) {
+ return (a - b);
+ }
+
+ // /** Add two 32-bit values */
+ static int ADD32(int a, int b) {
+ return ((int) (a) + (int) (b));
+ }
+
+ // /** Subtract two 32-bit values */
+ static int SUB32(int a, int b) {
+ return ((int) (a) - (int) (b));
+ }
+
+ // /** 16x16 multiplication where the result fits in 16 bits */
+ //#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b))))
+ static short MULT16_16_16(short a, short b) {
+ return (short) (((((short) (a)) * ((short) (b)))));
+ }
+
+ static int MULT16_16_16(int a, int b) {
+ return (a * b);
+ }
+
+ // /* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */
+ // /** 16x16 multiplication where the result fits in 32 bits */
+ //#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b)))
+ static int MULT16_16(int a, int b) {
+ return a * b;
+ }
+
+ static int MULT16_16(short a, short b) {
+ return a * b;
+ }
+
+ // /** 16x16 multiply-add where the result fits in 32 bits */
+ //#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
+ static int MAC16_16(short c, short a, short b) {
+ return c + (a * b);
+ }
+
+ static int MAC16_16(int c, short a, short b) {
+ return c + (a * b);
+ }
+
+ static int MAC16_16(int c, int a, int b) {
+ return c + (a * b);
+ }
+
+ // /** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+ // b must fit in 31 bits.
+ // Result fits in 32 bits. */
+ //#define MAC16_32_Q15(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
+ static int MAC16_32_Q15(int c, short a, short b) {
+ return ADD32((c), ADD32(MULT16_16((a), SHR((b), 15)), SHR(MULT16_16((a), ((b) & 0x00007fff)), 15)));
+ }
+
+ static int MAC16_32_Q15(int c, int a, int b) {
+ return ADD32((c), ADD32(MULT16_16((a), SHR((b), 15)), SHR(MULT16_16((a), ((b) & 0x00007fff)), 15)));
+ }
+
+ // /** 16x32 multiplication, followed by a 16-bit shift right and 32-bit add.
+ // Results fits in 32 bits */
+ //#define MAC16_32_Q16(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)))
+ static int MAC16_32_Q16(int c, short a, short b) {
+ return ADD32((c), ADD32(MULT16_16((a), SHR((b), 16)), SHR(MULT16_16SU((a), ((b) & 0x0000ffff)), 16)));
+ }
+
+ static int MAC16_32_Q16(int c, int a, int b) {
+ return ADD32((c), ADD32(MULT16_16((a), SHR((b), 16)), SHR(MULT16_16SU((a), ((b) & 0x0000ffff)), 16)));
+ }
+
+ //#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
+ static int MULT16_16_Q11_32(short a, short b) {
+ return (SHR(MULT16_16((a), (b)), 11));
+ }
+
+ static int MULT16_16_Q11_32(int a, int b) {
+ return (SHR(MULT16_16((a), (b)), 11));
+ }
+
+ //#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11))
+ static short MULT16_16_Q11(short a, short b) {
+ return (short) ((SHR(MULT16_16((a), (b)), 11)));
+ }
+
+ static int MULT16_16_Q11(int a, int b) {
+ return (SHR(MULT16_16((a), (b)), 11));
+ }
+
+ //#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
+ static short MULT16_16_Q13(short a, short b) {
+ return (short) ((SHR(MULT16_16((a), (b)), 13)));
+ }
+
+ static int MULT16_16_Q13(int a, int b) {
+ return (SHR(MULT16_16((a), (b)), 13));
+ }
+
+ //#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
+ static short MULT16_16_Q14(short a, short b) {
+ return (short) ((SHR(MULT16_16((a), (b)), 14)));
+ }
+
+ static int MULT16_16_Q14(int a, int b) {
+ return (SHR(MULT16_16((a), (b)), 14));
+ }
+
+ //#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
+ static short MULT16_16_Q15(short a, short b) {
+ return (short) ((SHR(MULT16_16((a), (b)), 15)));
+ }
+
+ static int MULT16_16_Q15(int a, int b) {
+ return (SHR(MULT16_16((a), (b)), 15));
+ }
+
+ //#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
+ static short MULT16_16_P13(short a, short b) {
+ return (short) ((SHR(ADD32(4096, MULT16_16((a), (b))), 13)));
+ }
+
+ static int MULT16_16_P13(int a, int b) {
+ return (SHR(ADD32(4096, MULT16_16((a), (b))), 13));
+ }
+
+ //#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
+ static short MULT16_16_P14(short a, short b) {
+ return (short) ((SHR(ADD32(8192, MULT16_16((a), (b))), 14)));
+ }
+
+ static int MULT16_16_P14(int a, int b) {
+ return (SHR(ADD32(8192, MULT16_16((a), (b))), 14));
+ }
+
+ //#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
+ static short MULT16_16_P15(short a, short b) {
+ return (short) ((SHR(ADD32(16384, MULT16_16((a), (b))), 15)));
+ }
+
+ static int MULT16_16_P15(int a, int b) {
+ return (SHR(ADD32(16384, MULT16_16((a), (b))), 15));
+ }
+
+ // /** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */
+ //#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b))))
+ static short DIV32_16(int a, short b) {
+ return (short) (((short) (((int) (a)) / ((short) (b)))));
+ }
+
+ static int DIV32_16(int a, int b) {
+ return a / b;
+ }
+
+ // /** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */
+ //#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b)))
+ static int DIV32(int a, int b) {
+ return a / b;
+ }
+
+ // identical to silk_SAT16 - saturate operation
+ static short SAT16(int x) {
+ return (short) (x > 32767 ? 32767 : x < -32768 ? -32768 : (short) x);
+ }
+
+ static short SIG2WORD16(int x) {
+ x = PSHR32(x, 12);
+ x = MAX32(x, -32768);
+ x = MIN32(x, 32767);
+ return EXTRACT16(x);
+ }
+
+ static short MIN(short a, short b) {
+ return ((a) < (b) ? (a) : (b));
+ }
+
+ static short MAX(short a, short b) {
+ return ((a) > (b) ? (a) : (b));
+ }
+
+ static short MIN16(short a, short b) {
+ return ((a) < (b) ? (a) : (b));
+ }
+
+ static short MAX16(short a, short b) {
+ return ((a) > (b) ? (a) : (b));
+ }
+
+ static int MIN16(int a, int b) {
+ return ((a) < (b) ? (a) : (b));
+ }
+
+ static int MAX16(int a, int b) {
+ return ((a) > (b) ? (a) : (b));
+ }
+
+ static float MIN16(float a, float b) {
+ return ((a) < (b) ? (a) : (b));
+ }
+
+ static float MAX16(float a, float b) {
+ return ((a) > (b) ? (a) : (b));
+ }
+
+ static int MIN(int a, int b) {
+ return ((a) < (b) ? (a) : (b));
+ }
+
+ static int MAX(int a, int b) {
+ return ((a) > (b) ? (a) : (b));
+ }
+
+ static int IMIN(int a, int b) {
+ return ((a) < (b) ? (a) : (b));
+ }
+
+ static long IMIN(long a, long b) {
+ return ((a) < (b) ? (a) : (b));
+ }
+
+ static int IMAX(int a, int b) {
+ return ((a) > (b) ? (a) : (b));
+ }
+
+ static int MIN32(int a, int b) {
+ return ((a) < (b) ? (a) : (b));
+ }
+
+ static int MAX32(int a, int b) {
+ return ((a) > (b) ? (a) : (b));
+ }
+
+ static float MIN32(float a, float b) {
+ return ((a) < (b) ? (a) : (b));
+ }
+
+ static float MAX32(float a, float b) {
+ return ((a) > (b) ? (a) : (b));
+ }
+
+ static int ABS16(int x) {
+ return ((x) < 0 ? (-(x)) : (x));
+ }
+
+ static float ABS16(float x) {
+ return ((x) < 0 ? (-(x)) : (x));
+ }
+
+ static short ABS16(short x) {
+ return (short) (((x) < 0 ? (-(x)) : (x)));
+ }
+
+ static int ABS32(int x) {
+ return ((x) < 0 ? (-(x)) : (x));
+ }
+
+ static int celt_udiv(int n, int d) {
+ Inlines.OpusAssert(d > 0);
+ return n / d;
+ }
+
+ static int celt_sudiv(int n, int d) {
+ Inlines.OpusAssert(d > 0);
+ return n / d;
+ }
+
+ //#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b))
+ static int celt_div(int a, int b) {
+ return MULT32_32_Q31((int) (a), celt_rcp(b));
+ }
+
+ /**
+ * Integer log in base2. Undefined for zero and negative numbers
+ */
+ static int celt_ilog2(int x) {
+ Inlines.OpusAssert(x > 0, "celt_ilog2() only defined for strictly positive numbers");
+ return (EC_ILOG((long) x) - 1);
+ }
+
+ /**
+ * Integer log in base2. Defined for zero, but not for negative numbers
+ */
+ static int celt_zlog2(int x) {
+ return x <= 0 ? 0 : celt_ilog2(x);
+ }
+
+ static int celt_maxabs16(int[] x, int x_ptr, int len) {
+ int i;
+ int maxval = 0;
+ int minval = 0;
+ for (i = x_ptr; i < len + x_ptr; i++) {
+ maxval = MAX32(maxval, x[i]);
+ minval = MIN32(minval, x[i]);
+ }
+ return MAX32(EXTEND32(maxval), -EXTEND32(minval));
+ }
+
+ static int celt_maxabs32(int[] x, int x_ptr, int len) {
+ int i;
+ int maxval = 0;
+ int minval = 0;
+ for (i = x_ptr; i < x_ptr + len; i++) {
+ maxval = MAX32(maxval, x[i]);
+ minval = MIN32(minval, x[i]);
+ }
+ return MAX32(maxval, 0 - minval);
+ }
+
+ static short celt_maxabs32(short[] x, int x_ptr, int len) {
+ int i;
+ short maxval = 0;
+ short minval = 0;
+ for (i = x_ptr; i < x_ptr + len; i++) {
+ maxval = MAX16(maxval, x[i]);
+ minval = MIN16(minval, x[i]);
+ }
+ return MAX(maxval, (short) (0 - minval));
+ }
+
+ ///
+ /// Multiplies two 16-bit fractional values. Bit-exactness of this macro is important
+ ///
+ ///
+ ///
+ ///
+ static int FRAC_MUL16(int a, int b) {
+ return ((16384 + ((int) ((short) a * (short) b))) >> 15);
+ }
+
+ ///
+ /// Compute floor(sqrt(_val)) with exact arithmetic.
+ /// This has been tested on all possible 32-bit inputs.
+ ///
+ ///
+ ///
+ static int isqrt32(long _val) {
+ int b;
+ int g;
+ int bshift;
+ /*Uses the second method from
+ http://www.azillionmonkeys.com/qed/sqroot.html
+ The main idea is to search for the largest binary digit b such that
+ (g+b)*(g+b) <= _val, and add it to the solution g.*/
+ g = 0;
+ bshift = (EC_ILOG(_val) - 1) >> 1;
+ b = 1 << bshift;
+ do {
+ long t;
+ t = ((g << 1) + b) << bshift;
+ if (t <= _val) {
+ g += b;
+ _val -= t;
+ }
+ b >>= 1;
+ bshift--;
+ } while (bshift >= 0);
+ return g;
+ }
+
+ private static short[] sqrt_C = {23175, 11561, -3011, 1699, -664};
+
+ /**
+ * Sqrt approximation (QX input, QX/2 output)
+ */
+ static int celt_sqrt(int x) {
+ int k;
+ short n;
+ int rt;
+
+ if (x == 0) {
+ return 0;
+ } else if (x >= 1073741824) {
+ return 32767;
+ }
+ k = (celt_ilog2(x) >> 1) - 7;
+ x = VSHR32(x, 2 * k);
+ n = (short) (x - 32768);
+ rt = ADD16(sqrt_C[0], MULT16_16_Q15(n, ADD16(sqrt_C[1], MULT16_16_Q15(n, ADD16(sqrt_C[2],
+ MULT16_16_Q15(n, ADD16(sqrt_C[3], MULT16_16_Q15(n, (sqrt_C[4])))))))));
+ rt = VSHR32(rt, 7 - k);
+ return rt;
+ }
+
+ /**
+ * Reciprocal approximation (Q15 input, Q16 output)
+ */
+ static int celt_rcp(int x) {
+ int i;
+ int n;
+ int r;
+ Inlines.OpusAssert(x > 0, "celt_rcp() only defined for positive values");
+ i = celt_ilog2(x);
+ /* n is Q15 with range [0,1). */
+ n = VSHR32(x, i - 15) - 32768;
+ /* Start with a linear approximation:
+ r = 1.8823529411764706-0.9411764705882353*n.
+ The coefficients and the result are Q14 in the range [15420,30840].*/
+ r = ADD16(30840, MULT16_16_Q15(-15420, n));
+ /* Perform two Newton iterations:
+ r -= r*((r*n)-1.Q15)
+ = r*((r*n)+(r-1.Q15)). */
+ r = SUB16(r, MULT16_16_Q15(r,
+ ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))));
+ /* We subtract an extra 1 in the second iteration to avoid overflow; it also
+ neatly compensates for truncation error in the rest of the process. */
+ r = SUB16(r, ADD16(1, MULT16_16_Q15(r,
+ ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))));
+ /* r is now the Q15 solution to 2/(n+1), with a maximum relative error
+ of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute
+ error of 1.24665/32768. */
+ return VSHR32(EXTEND32(r), i - 16);
+ }
+
+ /**
+ * Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out)
+ */
+ static int celt_rsqrt_norm(int x) {
+ int n;
+ int r;
+ int r2;
+ int y;
+ /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */
+ n = x - 32768;
+ /* Get a rough initial guess for the root.
+ The optimal minimax quadratic approximation (using relative error) is
+ r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485).
+ Coefficients here, and the final result r, are Q14.*/
+ r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713))));
+ /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14.
+ We can compute the result from n and r using Q15 multiplies with some
+ adjustment, carefully done to avoid overflow.
+ Range of y is [-1564,1594]. */
+ r2 = MULT16_16_Q15(r, r);
+ y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1);
+ /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5).
+ This yields the Q14 reciprocal square root of the Q16 x, with a maximum
+ relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a
+ peak absolute error of 2.26591/16384. */
+ return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y,
+ SUB16(MULT16_16_Q15(y, 12288), 16384))));
+ }
+
+ static int frac_div32(int a, int b) {
+ int rcp;
+ int result, rem;
+ int shift = celt_ilog2(b) - 29;
+ a = VSHR32(a, shift);
+ b = VSHR32(b, shift);
+ /* 16-bit reciprocal */
+ rcp = ROUND16(celt_rcp(ROUND16(b, 16)), 3);
+ result = MULT16_32_Q15(rcp, a);
+ rem = PSHR32(a, 2) - MULT32_32_Q31(result, b);
+ result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem), 2));
+ if (result >= 536870912) /* 2^29 */ {
+ return 2147483647; /* 2^31 - 1 */
+ } else if (result <= -536870912) /* -2^29 */ {
+ return -2147483647; /* -2^31 */
+ } else {
+ return SHL32(result, 2);
+ }
+ }
+
+ private static short log2_C0 = -6801 + (1 << (3));
+
+ /**
+ * Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output)
+ */
+ static int celt_log2(int x) {
+ int i;
+ int n, frac;
+ /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605,
+ 0.15530808010959576, -0.08556153059057618 */
+ if (x == 0) {
+ return -32767;
+ }
+ i = celt_ilog2(x);
+ n = VSHR32(x, i - 15) - 32768 - 16384;
+ frac = ADD16(log2_C0, MULT16_16_Q15(n, ADD16(15746, MULT16_16_Q15(n, ADD16(-5217, MULT16_16_Q15(n, ADD16(2545, MULT16_16_Q15(n, -1401))))))));
+ return SHL16((short) (i - 13), 10) + SHR16(frac, 4);
+ }
+
+ static int celt_exp2_frac(int x) {
+ int frac;
+ frac = SHL16(x, 4);
+ return ADD16(16383, MULT16_16_Q15(frac, ADD16(22804, MULT16_16_Q15(frac, ADD16(14819, MULT16_16_Q15(10204, frac))))));
+ }
+
+ /**
+ * Base-2 exponential approximation (2^x). (Q10 input, Q16 output)
+ */
+ static int celt_exp2(int x) {
+ int integer;
+ int frac;
+ integer = SHR16(x, 10);
+ if (integer > 14) {
+ return 0x7f000000;
+ } else if (integer < -15) {
+ return 0;
+ }
+ frac = (short) (celt_exp2_frac((short) (x - SHL16((short) (integer), 10))));
+ return VSHR32(EXTEND32(frac), -integer - 2);
+ }
+
+ /* Atan approximation using a 4th order polynomial. Input is in Q15 format
+ and normalized by pi/4. Output is in Q15 format */
+ static int celt_atan01(int x) {
+ return MULT16_16_P15(x, ADD32(32767, MULT16_16_P15(x, ADD32(-21, MULT16_16_P15(x, ADD32(-11943, MULT16_16_P15(4936, x)))))));
+ }
+
+ /* atan2() approximation valid for positive input values */
+ static int celt_atan2p(int y, int x) {
+ if (y < x) {
+ int arg;
+ arg = celt_div(SHL32(EXTEND32(y), 15), x);
+ if (arg >= 32767) {
+ arg = 32767;
+ }
+ return SHR32(celt_atan01(EXTRACT16(arg)), 1);
+ } else {
+ int arg;
+ arg = celt_div(SHL32(EXTEND32(x), 15), y);
+ if (arg >= 32767) {
+ arg = 32767;
+ }
+ return 25736 - SHR16(celt_atan01(EXTRACT16(arg)), 1);
+ }
+ }
+
+ static int celt_cos_norm(int x) {
+ x = x & 0x0001ffff;
+ if (x > SHL32(EXTEND32(1), 16)) {
+ x = SUB32(SHL32(EXTEND32(1), 17), x);
+ }
+ if ((x & 0x00007fff) != 0) {
+ if (x < SHL32(EXTEND32(1), 15)) {
+ return _celt_cos_pi_2(EXTRACT16(x));
+ } else {
+ return NEG32(_celt_cos_pi_2(EXTRACT16(65536 - x))); // opus bug: should be neg32?
+ }
+ } else if ((x & 0x0000ffff) != 0) {
+ return 0;
+ } else if ((x & 0x0001ffff) != 0) {
+ return -32767;
+ } else {
+ return 32767;
+ }
+ }
+
+ static int _celt_cos_pi_2(int x) {
+ int x2;
+
+ x2 = MULT16_16_P15(x, x);
+ return ADD32(1, MIN32(32766, ADD32(SUB16(32767, x2), MULT16_16_P15(x2, ADD32(-7651, MULT16_16_P15(x2, ADD32(8277, MULT16_16_P15(-626, x2))))))));
+ }
+
+ static short FLOAT2INT16(float x) {
+ x = x * CeltConstants.CELT_SIG_SCALE;
+ if (x < Short.MIN_VALUE) {
+ x = Short.MIN_VALUE;
+ }
+ if (x > Short.MAX_VALUE) {
+ x = Short.MAX_VALUE;
+ }
+ return (short) x;
+ }
+
+ // SILK-SPECIFIC INLINES
+ ///
+ /// Rotate a32 right by 'rot' bits. Negative rot values result in rotating
+ /// left. Output is 32bit int.
+ ///
+ ///
+ ///
+ ///
+ static int silk_ROR32(int a32, int rot) {
+ int m = (0 - rot);
+ if (rot == 0) {
+ return a32;
+ } else if (rot < 0) {
+ return ((a32 << m) | (a32 >> (32 - m)));
+ } else {
+ return ((a32 << (32 - rot)) | (a32 >> rot));
+ }
+ }
+
+ static int silk_MUL(int a32, int b32) {
+ int ret = a32 * b32;
+ return ret;
+ }
+
+ static int silk_MLA(int a32, int b32, int c32) {
+ int ret = silk_ADD32((a32), ((b32) * (c32)));
+ Inlines.OpusAssert((long) ret == (long) a32 + (long) b32 * (long) c32);
+ return ret;
+ }
+
+ ///
+ /// ((a32 >> 16) * (b32 >> 16))
+ ///
+ ///
+ ///
+ ///
+ static int silk_SMULTT(int a32, int b32) {
+ return ((a32 >> 16) * (b32 >> 16));
+ }
+
+ static int silk_SMLATT(int a32, int b32, int c32) {
+ return silk_ADD32((a32), ((b32) >> 16) * ((c32) >> 16));
+ }
+
+ static long silk_SMLALBB(long a64, short b16, short c16) {
+ return silk_ADD64((a64), (long) ((int) (b16) * (int) (c16)));
+ }
+
+ static long silk_SMULL(int a32, int b32) {
+ return (long) a32 * (long) b32;
+ }
+
+ ///
+ /// Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
+ /// (just standard two's complement implementation-specific behaviour)
+ ///
+ ///
+ ///
+ ///
+ static int silk_ADD32_ovflw(int a, int b) {
+ return (int) ((long) a + b);
+ }
+
+ static int silk_ADD32_ovflw(long a, long b) {
+ return ((int) (a + b));
+ }
+
+ ///
+ /// Subtracts two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
+ /// (just standard two's complement implementation-specific behaviour)
+ ///
+ ///
+ ///
+ ///
+ static int silk_SUB32_ovflw(int a, int b) {
+ return (int) ((long) a - b);
+ }
+
+ ///
+ /// Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)
+ ///
+ ///
+ ///
+ ///
+ ///
+ static int silk_MLA_ovflw(int a32, int b32, int c32) {
+ return (int) silk_ADD32_ovflw((long) a32, (long) b32 * c32);
+ }
+
+ static int silk_SMLABB_ovflw(int a32, int b32, int c32) {
+ return ((silk_ADD32_ovflw((a32), ((int) ((short) (b32))) * (int) ((short) (c32)))));
+ }
+
+ static int silk_SMULBB(int a32, int b32) {
+ return ((int) ((short) a32) * (int) ((short) b32));
+ }
+
+ ///
+ /// (a32 * (int)((short)(b32))) >> 16 output have to be 32bit int
+ ///
+ ///
+ ///
+ ///
+ static int silk_SMULWB(int a32, int b32) {
+ return ((int) (((a32 * (long) (((short) b32))) >> 16)));
+ }
+
+ static int silk_SMLABB(int a32, int b32, int c32) {
+ return ((a32) + ((int) ((short) b32)) * (int) ((short) c32));
+ }
+
+ static int silk_DIV32_16(int a32, int b32) {
+ return a32 / b32;
+ }
+
+ static int silk_DIV32(int a32, int b32) {
+ return a32 / b32;
+ }
+
+ static short silk_ADD16(short a, short b) {
+ short ret = (short) (a + b);
+ return ret;
+ }
+
+ static int silk_ADD32(int a, int b) {
+ int ret = a + b;
+ return ret;
+ }
+
+ static long silk_ADD64(long a, long b) {
+ long ret = a + b;
+ Inlines.OpusAssert(ret == silk_ADD_SAT64(a, b));
+ return ret;
+ }
+
+ static short silk_SUB16(short a, short b) {
+ short ret = (short) (a - b);
+ Inlines.OpusAssert(ret == silk_SUB_SAT16(a, b));
+ return ret;
+ }
+
+ static int silk_SUB32(int a, int b) {
+ int ret = a - b;
+ Inlines.OpusAssert(ret == silk_SUB_SAT32(a, b));
+ return ret;
+ }
+
+ static long silk_SUB64(long a, long b) {
+ long ret = a - b;
+ Inlines.OpusAssert(ret == silk_SUB_SAT64(a, b));
+ return ret;
+ }
+
+ static int silk_SAT8(int a) {
+ return a > Byte.MAX_VALUE ? Byte.MAX_VALUE : ((a) < Byte.MIN_VALUE ? Byte.MIN_VALUE : (a));
+ }
+
+ static int silk_SAT16(int a) {
+ return a > Short.MAX_VALUE ? Short.MAX_VALUE : ((a) < Short.MIN_VALUE ? Short.MIN_VALUE : (a));
+ }
+
+ static int silk_SAT32(long a) {
+ return a > Integer.MAX_VALUE ? Integer.MAX_VALUE : ((a) < Integer.MIN_VALUE ? Integer.MIN_VALUE : (int) (a));
+ }
+
+ ///
+ /// //////////////////
+ ///
+ ///
+ ///
+ ///
+ static short silk_ADD_SAT16(short a16, short b16) {
+ short res = (short) silk_SAT16(silk_ADD32((int) (a16), (b16)));
+ Inlines.OpusAssert(res == silk_SAT16((int) a16 + (int) b16));
+ return res;
+ }
+
+ static int silk_ADD_SAT32(int a32, int b32) {
+ int res = ((((long) (a32) + (long) (b32)) & 0x80000000) == 0
+ ? ((((a32) & (b32)) & 0x80000000) != 0 ? Integer.MIN_VALUE : (a32) + (b32))
+ : ((((a32) | (b32)) & 0x80000000) == 0 ? Integer.MAX_VALUE : (a32) + (b32)));
+ Inlines.OpusAssert(res == silk_SAT32((long) a32 + (long) b32));
+ return res;
+ }
+
+ static long silk_ADD_SAT64(long a64, long b64) {
+ long res;
+ res = (((a64 + b64) & Long.MIN_VALUE) == 0
+ ? (((a64 & b64) & Long.MIN_VALUE) != 0 ? Long.MIN_VALUE : a64 + b64)
+ : (((a64 | b64) & Long.MIN_VALUE) == 0 ? Long.MAX_VALUE : a64 + b64));
+ return res;
+ }
+
+ static short silk_SUB_SAT16(short a16, short b16) {
+ short res = (short) silk_SAT16(silk_SUB32((int) (a16), (b16)));
+ Inlines.OpusAssert(res == silk_SAT16((int) a16 - (int) b16));
+ return res;
+ }
+
+ static int silk_SUB_SAT32(int a32, int b32) {
+ int res = ((((long) a32 - b32) & 0x80000000) == 0
+ ? (((a32) & ((b32) ^ 0x80000000) & 0x80000000) != 0 ? Integer.MIN_VALUE : (a32) - (b32))
+ : ((((a32) ^ 0x80000000) & (b32) & 0x80000000) != 0 ? Integer.MAX_VALUE : (a32) - (b32)));
+ Inlines.OpusAssert(res == silk_SAT32((long) a32 - (long) b32));
+ return res;
+ }
+
+ static long silk_SUB_SAT64(long a64, long b64) {
+ long res;
+ res = (((long) ((a64) - (b64)) & Long.MIN_VALUE) == 0
+ ? (((long) (a64) & ((long) (b64) ^ Long.MIN_VALUE) & Long.MIN_VALUE) != 0 ? Long.MIN_VALUE : (a64) - (b64))
+ : ((((long) (a64) ^ Long.MIN_VALUE) & (long) (b64) & Long.MIN_VALUE) != 0 ? Long.MAX_VALUE : (a64) - (b64)));
+ return res;
+ }
+
+ ///* Saturation for positive input values */
+ //#define silk_POS_SAT32(a) ((a) > int_MAX ? int_MAX : (a))
+ ///
+ /// Add with saturation for positive input values
+ ///
+ ///
+ ///
+ ///
+ static byte silk_ADD_POS_SAT8(byte a, byte b) {
+ return (byte) ((((a + b) & 0x80) != 0) ? Byte.MAX_VALUE : (a + b));
+ }
+
+ ///
+ /// Add with saturation for positive input values
+ ///
+ ///
+ ///
+ ///
+ static short silk_ADD_POS_SAT16(short a, short b) {
+ return (short) ((((a + b) & 0x8000) != 0) ? Short.MAX_VALUE : (a + b));
+ }
+
+ ///
+ /// Add with saturation for positive input values
+ ///
+ ///
+ ///
+ ///
+ static int silk_ADD_POS_SAT32(int a, int b) {
+ return ((((a + b) & 0x80000000) != 0) ? Integer.MAX_VALUE : (a + b));
+ }
+
+ ///
+ /// Add with saturation for positive input values
+ ///
+ ///
+ ///
+ ///
+ static long silk_ADD_POS_SAT64(long a, long b) {
+ return ((((long) (a + b) & Long.MIN_VALUE) != 0) ? Long.MAX_VALUE : (a + b));
+ }
+
+ static byte silk_LSHIFT8(byte a, int shift) {
+ byte ret = (byte) (a << shift);
+ return ret;
+ }
+
+ static short silk_LSHIFT16(short a, int shift) {
+ short ret = (short) (a << shift);
+ return ret;
+ }
+
+ static int silk_LSHIFT32(int a, int shift) {
+ int ret = a << shift;
+ return ret;
+ }
+
+ static long silk_LSHIFT64(long a, int shift) {
+ long ret = a << shift;
+ return ret;
+ }
+
+ static int silk_LSHIFT(int a, int shift) {
+ int ret = a << shift;
+ return ret;
+ }
+
+ static int silk_LSHIFT_ovflw(int a, int shift) {
+ return a << shift;
+ }
+
+ ///
+ /// saturates before shifting
+ ///
+ ///
+ ///
+ ///
+ static int silk_LSHIFT_SAT32(int a, int shift) {
+ return (silk_LSHIFT32(silk_LIMIT((a), silk_RSHIFT32(Integer.MIN_VALUE, (shift)), silk_RSHIFT32(Integer.MAX_VALUE, (shift))), (shift)));
+ }
+
+ static byte silk_RSHIFT8(byte a, int shift) {
+ return (byte) (a >> shift);
+ }
+
+ static short silk_RSHIFT16(short a, int shift) {
+ return (short) (a >> shift);
+ }
+
+ static int silk_RSHIFT32(int a, int shift) {
+ return a >> shift;
+ }
+
+ static int silk_RSHIFT(int a, int shift) {
+ return a >> shift;
+ }
+
+ static long silk_RSHIFT64(long a, int shift) {
+ return a >> shift;
+ }
+
+ static long silk_RSHIFT_uint(long a, int shift) {
+ return CapToUInt32(a) >> shift;
+ }
+
+ static int silk_ADD_LSHIFT(int a, int b, int shift) {
+ int ret = a + (b << shift);
+ return ret;
+ /* shift >= 0 */
+ }
+
+ static int silk_ADD_LSHIFT32(int a, int b, int shift) {
+ int ret = a + (b << shift);
+ return ret;
+ /* shift >= 0 */
+ }
+
+ static int silk_ADD_RSHIFT(int a, int b, int shift) {
+ int ret = a + (b >> shift);
+ return ret;
+ /* shift > 0 */
+ }
+
+ static int silk_ADD_RSHIFT32(int a, int b, int shift) {
+ int ret = a + (b >> shift);
+ return ret;
+ /* shift > 0 */
+ }
+
+ static long silk_ADD_RSHIFT_uint(long a, long b, int shift) {
+ long ret = CapToUInt32(a + (CapToUInt32(b) >> shift));
+ return ret;
+ /* shift > 0 */
+ }
+
+ static int silk_SUB_LSHIFT32(int a, int b, int shift) {
+ int ret;
+ ret = a - (b << shift);
+ return ret;
+ /* shift >= 0 */
+ }
+
+ static int silk_SUB_RSHIFT32(int a, int b, int shift) {
+ int ret;
+ ret = a - (b >> shift);
+ return ret;
+ /* shift > 0 */
+ }
+
+ static int silk_RSHIFT_ROUND(int a, int shift) {
+ int ret;
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ return ret;
+ }
+
+ static long silk_RSHIFT_ROUND64(long a, int shift) {
+ long ret;
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ return ret;
+ }
+
+ static int silk_min(int a, int b) {
+ return ((a) < (b)) ? (a) : (b);
+ }
+
+ static int silk_max(int a, int b) {
+ return ((a) > (b)) ? (a) : (b);
+ }
+
+ static float silk_min(float a, float b) {
+ return ((a) < (b)) ? (a) : (b);
+ }
+
+ static float silk_max(float a, float b) {
+ return ((a) > (b)) ? (a) : (b);
+ }
+
+ ///
+ /// Macro to convert floating-point constants to fixed-point by applying a scalar factor
+ /// Because of limitations of the JIT, this macro is actually evaluated at runtime and therefore should not be used if you want to maximize performance
+ ///
+ static int SILK_CONST(float number, int scale) {
+ return ((int) ((number) * ((long) 1 << (scale)) + 0.5));
+ }
+
+ /* silk_min() versions with typecast in the function call */
+ static int silk_min_int(int a, int b) {
+ return (((a) < (b)) ? (a) : (b));
+ }
+
+ static short silk_min_16(short a, short b) {
+ return (((a) < (b)) ? (a) : (b));
+ }
+
+ static int silk_min_32(int a, int b) {
+ return (((a) < (b)) ? (a) : (b));
+ }
+
+ static long silk_min_64(long a, long b) {
+ return (((a) < (b)) ? (a) : (b));
+ }
+
+ /* silk_min() versions with typecast in the function call */
+ static int silk_max_int(int a, int b) {
+ return (((a) > (b)) ? (a) : (b));
+ }
+
+ static short silk_max_16(short a, short b) {
+ return (((a) > (b)) ? (a) : (b));
+ }
+
+ static int silk_max_32(int a, int b) {
+ return (((a) > (b)) ? (a) : (b));
+ }
+
+ static long silk_max_64(long a, long b) {
+ return (((a) > (b)) ? (a) : (b));
+ }
+
+ static float silk_LIMIT(float a, float limit1, float limit2) {
+ return ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+ }
+
+ static int silk_LIMIT(int a, int limit1, int limit2) {
+ return silk_LIMIT_32(a, limit1, limit2);
+ }
+
+ static int silk_LIMIT_int(int a, int limit1, int limit2) {
+ return silk_LIMIT_32(a, limit1, limit2);
+ }
+
+ static short silk_LIMIT_16(short a, short limit1, short limit2) {
+ return ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+ }
+
+ static int silk_LIMIT_32(int a, int limit1, int limit2) {
+ return ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+ }
+
+ static int silk_abs(int a) {
+ // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN
+ return ((a) > 0) ? (a) : -(a);
+ }
+
+ static int silk_abs_int16(int a) {
+ return (a ^ (a >> 15)) - (a >> 15);
+ }
+
+ static int silk_abs_int32(int a) {
+ return (a ^ (a >> 31)) - (a >> 31);
+ }
+
+ static long silk_abs_int64(long a) {
+ return ((a) > 0) ? (a) : -(a);
+ }
+
+ static long silk_sign(int a) {
+ return (a) > 0 ? 1 : ((a) < 0 ? -1 : 0);
+ }
+
+ ///
+ /// PSEUDO-RANDOM GENERATOR
+ /// Make sure to store the result as the seed for the next call (also in between
+ /// frames), otherwise result won't be random at all. When only using some of the
+ /// bits, take the most significant bits by right-shifting.
+ ///
+ static int silk_RAND(int seed) {
+ return silk_MLA_ovflw(907633515, seed, 196314165);
+ }
+
+ ///
+ /// silk_SMMUL: Signed top word multiply.
+ ///
+ ///
+ ///
+ ///
+ static int silk_SMMUL(int a32, int b32) {
+ return (int) silk_RSHIFT64(silk_SMULL((a32), (b32)), 32);
+ }
+
+ /* a32 + (b32 * (c32 >> 16)) >> 16 */
+ static int silk_SMLAWT(int a32, int b32, int c32) {
+ int ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16));
+ return ret;
+ }
+
+ ///
+ /// Divide two int32 values and return result as int32 in a given Q-domain
+ ///
+ /// I numerator (Q0)
+ /// I denominator (Q0)
+ /// I Q-domain of result (>= 0)
+ /// O returns a good approximation of "(a32 << Qres) / b32"
+ static int silk_DIV32_varQ(int a32, int b32, int Qres) {
+ int a_headrm, b_headrm, lshift;
+ int b32_inv, a32_nrm, b32_nrm, result;
+
+ Inlines.OpusAssert(b32 != 0);
+ Inlines.OpusAssert(Qres >= 0);
+
+ /* Compute number of bits head room and normalize inputs */
+ a_headrm = silk_CLZ32(silk_abs(a32)) - 1;
+ a32_nrm = silk_LSHIFT(a32, a_headrm);
+ /* Q: a_headrm */
+ b_headrm = silk_CLZ32(silk_abs(b32)) - 1;
+ b32_nrm = silk_LSHIFT(b32, b_headrm);
+ /* Q: b_headrm */
+
+ /* Inverse of b32, with 14 bits of precision */
+ b32_inv = silk_DIV32_16(Integer.MAX_VALUE >> 2, silk_RSHIFT(b32_nrm, 16));
+ /* Q: 29 + 16 - b_headrm */
+
+ /* First approximation */
+ result = silk_SMULWB(a32_nrm, b32_inv);
+ /* Q: 29 + a_headrm - b_headrm */
+
+ /* Compute residual by subtracting product of denominator and first approximation */
+ /* It's OK to overflow because the final value of a32_nrm should always be small */
+ a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw(silk_SMMUL(b32_nrm, result), 3));
+ /* Q: a_headrm */
+
+ /* Refinement */
+ result = silk_SMLAWB(result, a32_nrm, b32_inv);
+ /* Q: 29 + a_headrm - b_headrm */
+
+ /* Convert to Qres domain */
+ lshift = 29 + a_headrm - b_headrm - Qres;
+ if (lshift < 0) {
+ return silk_LSHIFT_SAT32(result, -lshift);
+ } else if (lshift < 32) {
+ return silk_RSHIFT(result, lshift);
+ } else {
+ /* Avoid undefined result */
+ return 0;
+ }
+ }
+
+ ///
+ /// Invert int32 value and return result as int32 in a given Q-domain
+ ///
+ /// I denominator (Q0)
+ /// I Q-domain of result (> 0)
+ /// a good approximation of "(1 << Qres) / b32"
+ static int silk_INVERSE32_varQ(int b32, int Qres) {
+ int b_headrm, lshift;
+ int b32_inv, b32_nrm, err_Q32, result;
+
+ Inlines.OpusAssert(b32 != 0);
+ Inlines.OpusAssert(Qres > 0);
+
+ /* Compute number of bits head room and normalize input */
+ b_headrm = silk_CLZ32(silk_abs(b32)) - 1;
+ b32_nrm = silk_LSHIFT(b32, b_headrm);
+ /* Q: b_headrm */
+
+ /* Inverse of b32, with 14 bits of precision */
+ b32_inv = silk_DIV32_16(Integer.MAX_VALUE >> 2, (short) (silk_RSHIFT(b32_nrm, 16)));
+ /* Q: 29 + 16 - b_headrm */
+
+ /* First approximation */
+ result = silk_LSHIFT(b32_inv, 16);
+ /* Q: 61 - b_headrm */
+
+ /* Compute residual by subtracting product of denominator and first approximation from one */
+ err_Q32 = silk_LSHIFT(((int) 1 << 29) - silk_SMULWB(b32_nrm, b32_inv), 3);
+ /* Q32 */
+
+ /* Refinement */
+ result = silk_SMLAWW(result, err_Q32, b32_inv);
+ /* Q: 61 - b_headrm */
+
+ /* Convert to Qres domain */
+ lshift = 61 - b_headrm - Qres;
+ if (lshift <= 0) {
+ return silk_LSHIFT_SAT32(result, -lshift);
+ } else if (lshift < 32) {
+ return silk_RSHIFT(result, lshift);
+ } else {
+ /* Avoid undefined result */
+ return 0;
+ }
+ }
+
+ //////////////////////// from macros.h /////////////////////////////////////////////
+ ///
+ /// a32 + (b32 * (int)((short)(c32))) >> 16 output have to be 32bit int
+ ///
+ // fixme: This method should be as optimized as possible
+ static int silk_SMLAWB(int a32, int b32, int c32) {
+ //return (int)(a32 + ((b32 * (long)((short)c32)) >> 16));
+ int ret;
+ ret = a32 + silk_SMULWB(b32, c32);
+ return ret;
+ }
+
+ ///* (a32 * (b32 >> 16)) >> 16 */
+ static int silk_SMULWT(int a32, int b32) {
+ return (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16));
+ }
+
+ ///* (int)((short)(a32)) * (b32 >> 16) */
+ static int silk_SMULBT(int a32, int b32) {
+ return ((int) ((short) (a32)) * ((b32) >> 16));
+ }
+
+ ///* a32 + (int)((short)(b32)) * (c32 >> 16) */
+ static int silk_SMLABT(int a32, int b32, int c32) {
+ return ((a32) + ((int) ((short) (b32))) * ((c32) >> 16));
+ }
+
+ ///* a64 + (b32 * c32) */
+ static long silk_SMLAL(long a64, int b32, int c32) {
+ return (silk_ADD64((a64), ((long) (b32) * (long) (c32))));
+ }
+
+ static int MatrixGetPointer(int row, int column, int N) {
+ return (row * N) + column;
+ }
+
+ static int MatrixGet(int[] Matrix_base_adr, int row, int column, int N) {
+ return Matrix_base_adr[((row) * (N)) + (column)];
+ }
+
+ static short MatrixGet(short[] Matrix_base_adr, int row, int column, int N) {
+ return Matrix_base_adr[((row) * (N)) + (column)];
+ }
+
+ static PitchAnalysisCore.silk_pe_stage3_vals MatrixGet(PitchAnalysisCore.silk_pe_stage3_vals[] Matrix_base_adr, int row, int column, int N) {
+ return Matrix_base_adr[((row) * (N)) + (column)];
+ }
+
+ static int MatrixGet(int[] Matrix_base_adr, int matrix_ptr, int row, int column, int N) {
+ return Matrix_base_adr[matrix_ptr + (row * N) + column];
+ }
+
+ static short MatrixGet(short[] Matrix_base_adr, int matrix_ptr, int row, int column, int N) {
+ return Matrix_base_adr[matrix_ptr + (row * N) + column];
+ }
+
+ static void MatrixSet(int[] Matrix_base_adr, int matrix_ptr, int row, int column, int N, int value) {
+ Matrix_base_adr[matrix_ptr + (row * N) + column] = value;
+ }
+
+ static void MatrixSet(short[] Matrix_base_adr, int matrix_ptr, int row, int column, int N, short value) {
+ Matrix_base_adr[matrix_ptr + (row * N) + column] = value;
+ }
+
+ static void MatrixSet(int[] Matrix_base_adr, int row, int column, int N, int value) {
+ Matrix_base_adr[((row) * (N)) + (column)] = value;
+ }
+
+ static void MatrixSet(short[] Matrix_base_adr, int row, int column, int N, short value) {
+ Matrix_base_adr[((row) * (N)) + (column)] = value;
+ }
+
+ ///
+ /// (a32 * b32) >> 16
+ ///
+ static int silk_SMULWW(int a32, int b32) {
+ //return CHOP32(((long)(a32) * (b32)) >> 16);
+ return silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16));
+ }
+
+ ///
+ /// a32 + ((b32 * c32) >> 16)
+ ///
+ static int silk_SMLAWW(int a32, int b32, int c32) {
+ //return CHOP32(((a32) + (((long)(b32) * (c32)) >> 16)));
+ return silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16));
+ }
+
+ /* count leading zeros of opus_int64 */
+ static int silk_CLZ64(long input) {
+ int in_upper;
+
+ in_upper = (int) silk_RSHIFT64(input, 32);
+ if (in_upper == 0) {
+ /* Search in the lower 32 bits */
+ return 32 + silk_CLZ32(((int) input));
+ } else {
+ /* Search in the upper 32 bits */
+ return silk_CLZ32(in_upper);
+ }
+ }
+
+ static int silk_CLZ32(int in32) {
+ return in32 == 0 ? 32 : 32 - EC_ILOG(in32);
+ }
+
+ ///
+ /// Get number of leading zeros and fractional part (the bits right after the leading one)
+ ///
+ /// input
+ /// number of leading zeros
+ /// the 7 bits right after the leading one
+ static void silk_CLZ_FRAC(int input, BoxedValueInt lz, BoxedValueInt frac_Q7) {
+ int lzeros = silk_CLZ32(input);
+
+ lz.Val = lzeros;
+ frac_Q7.Val = silk_ROR32(input, 24 - lzeros) & 0x7f;
+ }
+
+ ///
+ /// Approximation of square root.
+ /// Accuracy: +/- 10% for output values > 15
+ /// +/- 2.5% for output values > 120
+ ///
+ ///
+ ///
+ static int silk_SQRT_APPROX(int x) {
+ int y;
+ int lz;
+ int frac_Q7;
+
+ if (x <= 0) {
+ return 0;
+ }
+
+ BoxedValueInt boxed_lz = new BoxedValueInt(0);
+ BoxedValueInt boxed_frac_Q7 = new BoxedValueInt(0);
+ silk_CLZ_FRAC(x, boxed_lz, boxed_frac_Q7);
+ lz = boxed_lz.Val;
+ frac_Q7 = boxed_frac_Q7.Val;
+
+ if ((lz & 1) != 0) {
+ y = 32768;
+ } else {
+ y = 46214; // 46214 = sqrt(2) * 32768
+ }
+
+ // get scaling right
+ y >>= silk_RSHIFT(lz, 1);
+
+ // increment using fractional part of input
+ y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7));
+
+ return y;
+ }
+
+ static int MUL32_FRAC_Q(int a32, int b32, int Q) {
+ return ((int) (silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q)));
+ }
+
+ ///
+ /// Approximation of 128 * log2() (very close inverse of silk_log2lin())
+ /// Convert input to a log scale
+ ///
+ /// (I) input in linear scale
+ ///
+ static int silk_lin2log(int inLin) {
+ BoxedValueInt lz = new BoxedValueInt(0);
+ BoxedValueInt frac_Q7 = new BoxedValueInt(0);
+
+ silk_CLZ_FRAC(inLin, lz, frac_Q7);
+
+ // Piece-wise parabolic approximation
+ return silk_LSHIFT(31 - lz.Val, 7) + silk_SMLAWB(frac_Q7.Val, silk_MUL(frac_Q7.Val, 128 - frac_Q7.Val), 179);
+ }
+
+ ///
+ /// Approximation of 2^() (very close inverse of silk_lin2log())
+ /// Convert input to a linear scale
+ ///
+ /// input on log scale
+ /// Linearized value
+ static int silk_log2lin(int inLog_Q7) {
+ int output, frac_Q7;
+
+ if (inLog_Q7 < 0) {
+ return 0;
+ } else if (inLog_Q7 >= 3967) {
+ return Integer.MAX_VALUE;
+ }
+
+ output = silk_LSHIFT(1, silk_RSHIFT(inLog_Q7, 7));
+ frac_Q7 = inLog_Q7 & 0x7F;
+
+ if (inLog_Q7 < 2048) {
+ /* Piece-wise parabolic approximation */
+ output = silk_ADD_RSHIFT32(output, silk_MUL(output, silk_SMLAWB(frac_Q7, silk_SMULBB(frac_Q7, 128 - frac_Q7), -174)), 7);
+ } else {
+ /* Piece-wise parabolic approximation */
+ output = silk_MLA(output, silk_RSHIFT(output, 7), silk_SMLAWB(frac_Q7, silk_SMULBB(frac_Q7, 128 - frac_Q7), -174));
+ }
+
+ return output;
+ }
+
+ ///
+ /// Interpolate two vectors
+ ///
+ /// (O) interpolated vector [MAX_LPC_ORDER]
+ /// (I) first vector [MAX_LPC_ORDER]
+ /// (I) second vector [MAX_LPC_ORDER]
+ /// (I) interp. factor, weight on 2nd vector
+ /// (I) number of parameters
+ static void silk_interpolate(
+ short[] xi,
+ short[] x0,
+ short[] x1,
+ int ifact_Q2,
+ int d) {
+ int i;
+
+ Inlines.OpusAssert(ifact_Q2 >= 0);
+ Inlines.OpusAssert(ifact_Q2 <= 4);
+
+ for (i = 0; i < d; i++) {
+ xi[i] = (short) silk_ADD_RSHIFT(x0[i], silk_SMULBB(x1[i] - x0[i], ifact_Q2), 2);
+ }
+ }
+
+ ///
+ /// Inner product with bit-shift
+ ///
+ /// I input vector 1
+ /// I input vector 2
+ /// I number of bits to shift
+ /// I vector lengths
+ ///
+ static int silk_inner_prod_aligned_scale(
+ short[] inVec1,
+ short[] inVec2,
+ int scale,
+ int len) {
+ int i, sum = 0;
+ for (i = 0; i < len; i++) {
+ sum = silk_ADD_RSHIFT32(sum, silk_SMULBB(inVec1[i], inVec2[i]), scale);
+ }
+
+ return sum;
+ }
+
+ /* Copy and multiply a vector by a constant */
+ static void silk_scale_copy_vector16(
+ short[] data_out,
+ int data_out_ptr,
+ short[] data_in,
+ int data_in_ptr,
+ int gain_Q16, /* I Gain in Q16 */
+ int dataSize /* I Length */
+ ) {
+ for (int i = 0; i < dataSize; i++) {
+ data_out[data_out_ptr + i] = (short) (silk_SMULWB(gain_Q16, data_in[data_in_ptr + i]));
+ }
+ }
+
+ /* Multiply a vector by a constant */
+ static void silk_scale_vector32_Q26_lshift_18(
+ int[] data1, /* I/O Q0/Q18 */
+ int data1_ptr,
+ int gain_Q26, /* I Q26 */
+ int dataSize /* I length */
+ ) {
+ for (int i = data1_ptr; i < data1_ptr + dataSize; i++) {
+ data1[i] = (int) (silk_RSHIFT64(silk_SMULL(data1[i], gain_Q26), 8));
+ /* OUTPUT: Q18 */
+ }
+ }
+
+ /* sum = for(i=0;i
+ /// returns the value that has fewer higher-order bits, ignoring sign bit (? I think?)
+ ///
+ ///
+ ///
+ ///
+ static long EC_MINI(long a, long b) {
+ return (a + ((b - a) & ((b < a) ? 0xFFFFFFFF : 0)));
+ }
+
+ static int EC_ILOG(long x) {
+ if (x == 0) {
+ return 1;
+ }
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+ long y = x - ((x >> 1) & 0x55555555);
+ y = (((y >> 2) & 0x33333333) + (y & 0x33333333));
+ y = (((y >> 4) + y) & 0x0f0f0f0f);
+ y += (y >> 8);
+ y += (y >> 16);
+ y = (y & 0x0000003f);
+ return (int) y;
+ }
+
+ static int abs(int a) {
+ if (a < 0) {
+ return 0 - a;
+ }
+ return a;
+ }
+
+ static int SignedByteToUnsignedInt(byte b) {
+ return (b & 0xFF);
+ }
+}
diff --git a/app/src/main/java/org/concentus/K2A.java b/app/src/main/java/org/concentus/K2A.java
new file mode 100644
index 0000000000..6e3d0c9d7d
--- /dev/null
+++ b/app/src/main/java/org/concentus/K2A.java
@@ -0,0 +1,75 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class K2A {
+
+ /* Step up function, converts reflection coefficients to prediction coefficients */
+ 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 */
+ 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);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/Kernels.java b/app/src/main/java/org/concentus/Kernels.java
new file mode 100644
index 0000000000..2a14b4e597
--- /dev/null
+++ b/app/src/main/java/org/concentus/Kernels.java
@@ -0,0 +1,350 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class Kernels {
+
+ static void celt_fir(
+ short[] x,
+ int x_ptr,
+ short[] num,
+ short[] y,
+ int y_ptr,
+ int N,
+ int ord,
+ short[] mem
+ ) {
+ int i, j;
+ short[] rnum = new short[ord];
+ short[] local_x = new short[N + ord];
+
+ for (i = 0; i < ord; i++) {
+ rnum[i] = num[ord - i - 1];
+ }
+
+ for (i = 0; i < ord; i++) {
+ local_x[i] = mem[ord - i - 1];
+ }
+
+ for (i = 0; i < N; i++) {
+ local_x[i + ord] = x[x_ptr + i];
+ }
+
+ for (i = 0; i < ord; i++) {
+ mem[i] = x[x_ptr + N - i - 1];
+ }
+
+ BoxedValueInt sum0 = new BoxedValueInt(0);
+ BoxedValueInt sum1 = new BoxedValueInt(0);
+ BoxedValueInt sum2 = new BoxedValueInt(0);
+ BoxedValueInt sum3 = new BoxedValueInt(0);
+
+ for (i = 0; i < N - 3; i += 4) {
+ sum0.Val = 0;
+ sum1.Val = 0;
+ sum2.Val = 0;
+ sum3.Val = 0;
+ xcorr_kernel(rnum, 0, local_x, i, sum0, sum1, sum2, sum3, ord);
+ y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum0.Val, CeltConstants.SIG_SHIFT))));
+ y[y_ptr + i + 1] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 1]), Inlines.PSHR32(sum1.Val, CeltConstants.SIG_SHIFT))));
+ y[y_ptr + i + 2] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 2]), Inlines.PSHR32(sum2.Val, CeltConstants.SIG_SHIFT))));
+ y[y_ptr + i + 3] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 3]), Inlines.PSHR32(sum3.Val, CeltConstants.SIG_SHIFT))));
+ }
+
+ for (; i < N; i++) {
+ int sum = 0;
+
+ for (j = 0; j < ord; j++) {
+ sum = Inlines.MAC16_16(sum, rnum[j], local_x[i + j]);
+ }
+
+ y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum, CeltConstants.SIG_SHIFT))));
+ }
+ }
+
+ static void celt_fir(
+ int[] x,
+ int x_ptr,
+ int[] num,
+ int num_ptr,
+ int[] y,
+ int y_ptr,
+ int N,
+ int ord,
+ int[] mem
+ ) {
+ int i, j;
+ int[] rnum = new int[ord];
+ int[] local_x = new int[N + ord];
+
+ for (i = 0; i < ord; i++) {
+ rnum[i] = num[num_ptr + ord - i - 1];
+ }
+
+ for (i = 0; i < ord; i++) {
+ local_x[i] = mem[ord - i - 1];
+ }
+
+ for (i = 0; i < N; i++) {
+ local_x[i + ord] = x[x_ptr + i];
+ }
+
+ for (i = 0; i < ord; i++) {
+ mem[i] = x[x_ptr + N - i - 1];
+ }
+
+ BoxedValueInt sum0 = new BoxedValueInt(0);
+ BoxedValueInt sum1 = new BoxedValueInt(0);
+ BoxedValueInt sum2 = new BoxedValueInt(0);
+ BoxedValueInt sum3 = new BoxedValueInt(0);
+
+ for (i = 0; i < N - 3; i += 4) {
+ sum0.Val = 0;
+ sum1.Val = 0;
+ sum2.Val = 0;
+ sum3.Val = 0;
+ xcorr_kernel(rnum, local_x, i, sum0, sum1, sum2, sum3, ord);
+ y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum0.Val, CeltConstants.SIG_SHIFT))));
+ y[y_ptr + i + 1] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 1]), Inlines.PSHR32(sum1.Val, CeltConstants.SIG_SHIFT))));
+ y[y_ptr + i + 2] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 2]), Inlines.PSHR32(sum2.Val, CeltConstants.SIG_SHIFT))));
+ y[y_ptr + i + 3] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 3]), Inlines.PSHR32(sum3.Val, CeltConstants.SIG_SHIFT))));
+ }
+
+ for (; i < N; i++) {
+ int sum = 0;
+
+ for (j = 0; j < ord; j++) {
+ sum = Inlines.MAC16_16(sum, rnum[j], local_x[i + j]);
+ }
+
+ y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum, CeltConstants.SIG_SHIFT))));
+ }
+ }
+
+ ///
+ /// OPT: This is the kernel you really want to optimize. It gets used a lot by the prefilter and by the PLC.
+ ///
+ ///
+ ///
+ ///
+ ///
+ static void xcorr_kernel(short[] x, int x_ptr, short[] y, int y_ptr, BoxedValueInt _sum0, BoxedValueInt _sum1, BoxedValueInt _sum2, BoxedValueInt _sum3, int len) {
+ int sum0 = _sum0.Val;
+ int sum1 = _sum1.Val;
+ int sum2 = _sum2.Val;
+ int sum3 = _sum3.Val;
+ int j;
+ short y_0, y_1, y_2, y_3;
+ Inlines.OpusAssert(len >= 3);
+ y_3 = 0;
+ /* gcc doesn't realize that y_3 can't be used uninitialized */
+ y_0 = y[y_ptr++];
+ y_1 = y[y_ptr++];
+ y_2 = y[y_ptr++];
+ for (j = 0; j < len - 3; j += 4) {
+ short tmp;
+ tmp = x[x_ptr++];
+ y_3 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
+ tmp = x[x_ptr++];
+ y_0 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
+ tmp = x[x_ptr++];
+ y_1 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
+ tmp = x[x_ptr++];
+ y_2 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_3);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_0);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_1);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_2);
+ }
+ if (j++ < len) {
+ short tmp;
+ tmp = x[x_ptr++];
+ y_3 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
+ }
+ if (j++ < len) {
+ short tmp;
+ tmp = x[x_ptr++];
+ y_0 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
+ }
+ if (j < len) {
+ short tmp;
+ tmp = x[x_ptr++];
+ y_1 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
+ }
+
+ _sum0.Val = sum0;
+ _sum1.Val = sum1;
+ _sum2.Val = sum2;
+ _sum3.Val = sum3;
+ }
+
+ static void xcorr_kernel(int[] x, int[] y, int y_ptr, BoxedValueInt _sum0, BoxedValueInt _sum1, BoxedValueInt _sum2, BoxedValueInt _sum3, int len) {
+ int sum0 = _sum0.Val;
+ int sum1 = _sum1.Val;
+ int sum2 = _sum2.Val;
+ int sum3 = _sum3.Val;
+ int j;
+ int y_0, y_1, y_2, y_3;
+ int x_ptr = 0;
+ Inlines.OpusAssert(len >= 3);
+ y_3 = 0;
+ /* gcc doesn't realize that y_3 can't be used uninitialized */
+ y_0 = y[y_ptr++];
+ y_1 = y[y_ptr++];
+ y_2 = y[y_ptr++];
+ for (j = 0; j < len - 3; j += 4) {
+ int tmp;
+ tmp = x[x_ptr++];
+ y_3 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
+ tmp = x[x_ptr++];
+ y_0 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
+ tmp = x[x_ptr++];
+ y_1 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
+ tmp = x[x_ptr++];
+ y_2 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_3);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_0);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_1);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_2);
+ }
+ if (j++ < len) {
+ int tmp;
+ tmp = x[x_ptr++];
+ y_3 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
+ }
+ if (j++ < len) {
+ int tmp;
+ tmp = x[x_ptr++];
+ y_0 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
+ }
+ if (j < len) {
+ int tmp;
+ tmp = x[x_ptr++];
+ y_1 = y[y_ptr++];
+ sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
+ sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
+ sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
+ sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
+ }
+
+ _sum0.Val = sum0;
+ _sum1.Val = sum1;
+ _sum2.Val = sum2;
+ _sum3.Val = sum3;
+ }
+
+ static int celt_inner_prod(short[] x, int x_ptr, short[] y, int y_ptr, int N) {
+ int i;
+ int xy = 0;
+ for (i = 0; i < N; i++) {
+ xy = Inlines.MAC16_16(xy, x[x_ptr + i], y[y_ptr + i]);
+ }
+ return xy;
+ }
+
+ static int celt_inner_prod(short[] x, short[] y, int y_ptr, int N) {
+ int i;
+ int xy = 0;
+ for (i = 0; i < N; i++) {
+ xy = Inlines.MAC16_16(xy, x[i], y[y_ptr + i]);
+ }
+ return xy;
+ }
+
+ static int celt_inner_prod(int[] x, int x_ptr, int[] y, int y_ptr, int N) {
+ int i;
+ int xy = 0;
+ for (i = 0; i < N; i++) {
+ xy = Inlines.MAC16_16(xy, x[x_ptr + i], y[y_ptr + i]);
+ }
+ return xy;
+ }
+
+ static void dual_inner_prod(int[] x, int x_ptr, int[] y01, int y01_ptr, int[] y02, int y02_ptr, int N, BoxedValueInt xy1, BoxedValueInt xy2) {
+ int i;
+ int xy01 = 0;
+ int xy02 = 0;
+ for (i = 0; i < N; i++) {
+ xy01 = Inlines.MAC16_16(xy01, x[x_ptr + i], y01[y01_ptr + i]);
+ xy02 = Inlines.MAC16_16(xy02, x[x_ptr + i], y02[y02_ptr + i]);
+ }
+ xy1.Val = xy01;
+ xy2.Val = xy02;
+ }
+}
diff --git a/app/src/main/java/org/concentus/KissFFT.java b/app/src/main/java/org/concentus/KissFFT.java
new file mode 100644
index 0000000000..072085c215
--- /dev/null
+++ b/app/src/main/java/org/concentus/KissFFT.java
@@ -0,0 +1,414 @@
+/* Copyright (c) 2003-2004, Mark Borgerding
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2011 Xiph.Org Foundation
+ Modified from KISS-FFT by Jean-Marc Valin
+ Ported to Java 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.
+ */
+
+ /* This code is originally from Mark Borgerding's KISS-FFT but has been
+ heavily modified to better suit Opus */
+package org.concentus;
+
+class KissFFT {
+ //public final int SAMP_MAX = 2147483647;
+ //public final int SAMP_MIN = 0 - SAMP_MAX;
+ //public final int TWID_MAX = 32767;
+ //public final int TRIG_UPSCALE = 1;
+
+ static final int MAXFACTORS = 8;
+
+ static int S_MUL(int a, int b) {
+ return Inlines.MULT16_32_Q15(b, a);
+ }
+
+ static int S_MUL(int a, short b) {
+ return Inlines.MULT16_32_Q15(b, a);
+ }
+
+ static int HALF_OF(int x) {
+ return x >> 1;
+ }
+
+ static void kf_bfly2(int[] Fout, int fout_ptr, int m, int N) {
+ int Fout2;
+ int i;
+ {
+ short tw;
+ tw = ((short) (0.5 + (0.7071067812f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.7071067812f, 15)*/;
+ /* We know that m==4 here because the radix-2 is just after a radix-4 */
+ Inlines.OpusAssert(m == 4);
+ for (i = 0; i < N; i++) {
+ int t_r, t_i;
+ Fout2 = fout_ptr + 8;
+ t_r = Fout[Fout2 + 0];
+ t_i = Fout[Fout2 + 1];
+ Fout[Fout2 + 0] = Fout[fout_ptr + 0] - t_r;
+ Fout[Fout2 + 1] = Fout[fout_ptr + 1] - t_i;
+ Fout[fout_ptr + 0] += t_r;
+ Fout[fout_ptr + 1] += t_i;
+
+ t_r = S_MUL(Fout[Fout2 + 2] + Fout[Fout2 + 3], tw);
+ t_i = S_MUL(Fout[Fout2 + 3] - Fout[Fout2 + 2], tw);
+ Fout[Fout2 + 2] = Fout[fout_ptr + 2] - t_r;
+ Fout[Fout2 + 3] = Fout[fout_ptr + 3] - t_i;
+ Fout[fout_ptr + 2] += t_r;
+ Fout[fout_ptr + 3] += t_i;
+
+ t_r = Fout[Fout2 + 5];
+ t_i = 0 - Fout[Fout2 + 4];
+ Fout[Fout2 + 4] = Fout[fout_ptr + 4] - t_r;
+ Fout[Fout2 + 5] = Fout[fout_ptr + 5] - t_i;
+ Fout[fout_ptr + 4] += t_r;
+ Fout[fout_ptr + 5] += t_i;
+
+ t_r = S_MUL(Fout[Fout2 + 7] - Fout[Fout2 + 6], tw);
+ t_i = S_MUL(0 - Fout[Fout2 + 7] - Fout[Fout2 + 6], tw);
+ Fout[Fout2 + 6] = Fout[fout_ptr + 6] - t_r;
+ Fout[Fout2 + 7] = Fout[fout_ptr + 7] - t_i;
+ Fout[fout_ptr + 6] += t_r;
+ Fout[fout_ptr + 7] += t_i;
+
+ fout_ptr += 16;
+ }
+ }
+ }
+
+ static void kf_bfly4(
+ int[] Fout,
+ int fout_ptr,
+ int fstride,
+ FFTState st,
+ int m,
+ int N,
+ int mm) {
+ int i;
+
+ if (m == 1) {
+ /* Degenerate case where all the twiddles are 1. */
+ int scratch0, scratch1, scratch2, scratch3;
+ for (i = 0; i < N; i++) {
+ scratch0 = Fout[fout_ptr + 0] - Fout[fout_ptr + 4];
+ scratch1 = Fout[fout_ptr + 1] - Fout[fout_ptr + 5];
+ Fout[fout_ptr + 0] += Fout[fout_ptr + 4];
+ Fout[fout_ptr + 1] += Fout[fout_ptr + 5];
+ scratch2 = Fout[fout_ptr + 2] + Fout[fout_ptr + 6];
+ scratch3 = Fout[fout_ptr + 3] + Fout[fout_ptr + 7];
+ Fout[fout_ptr + 4] = Fout[fout_ptr + 0] - scratch2;
+ Fout[fout_ptr + 5] = Fout[fout_ptr + 1] - scratch3;
+ Fout[fout_ptr + 0] += scratch2;
+ Fout[fout_ptr + 1] += scratch3;
+ scratch2 = Fout[fout_ptr + 2] - Fout[fout_ptr + 6];
+ scratch3 = Fout[fout_ptr + 3] - Fout[fout_ptr + 7];
+ Fout[fout_ptr + 2] = scratch0 + scratch3;
+ Fout[fout_ptr + 3] = scratch1 - scratch2;
+ Fout[fout_ptr + 6] = scratch0 - scratch3;
+ Fout[fout_ptr + 7] = scratch1 + scratch2;
+ fout_ptr += 8;
+ }
+ } else {
+ int j;
+ int scratch0, scratch1, scratch2, scratch3, scratch4, scratch5, scratch6, scratch7, scratch8, scratch9, scratch10, scratch11;
+ int tw1, tw2, tw3;
+ int Fout_beg = fout_ptr;
+ for (i = 0; i < N; i++) {
+ fout_ptr = Fout_beg + 2 * i * mm;
+ int m1 = fout_ptr + (2 * m);
+ int m2 = fout_ptr + (4 * m);
+ int m3 = fout_ptr + (6 * m);
+ tw3 = tw2 = tw1 = 0;
+ /* m is guaranteed to be a multiple of 4. */
+ for (j = 0; j < m; j++) {
+ scratch0 = (S_MUL(Fout[m1], st.twiddles[tw1]) - S_MUL(Fout[m1 + 1], st.twiddles[tw1 + 1]));
+ scratch1 = (S_MUL(Fout[m1], st.twiddles[tw1 + 1]) + S_MUL(Fout[m1 + 1], st.twiddles[tw1]));
+ scratch2 = (S_MUL(Fout[m2], st.twiddles[tw2]) - S_MUL(Fout[m2 + 1], st.twiddles[tw2 + 1]));
+ scratch3 = (S_MUL(Fout[m2], st.twiddles[tw2 + 1]) + S_MUL(Fout[m2 + 1], st.twiddles[tw2]));
+ scratch4 = (S_MUL(Fout[m3], st.twiddles[tw3]) - S_MUL(Fout[m3 + 1], st.twiddles[tw3 + 1]));
+ scratch5 = (S_MUL(Fout[m3], st.twiddles[tw3 + 1]) + S_MUL(Fout[m3 + 1], st.twiddles[tw3]));
+ scratch10 = Fout[fout_ptr] - scratch2;
+ scratch11 = Fout[fout_ptr + 1] - scratch3;
+ Fout[fout_ptr] += scratch2;
+ Fout[fout_ptr + 1] += scratch3;
+ scratch6 = scratch0 + scratch4;
+ scratch7 = scratch1 + scratch5;
+ scratch8 = scratch0 - scratch4;
+ scratch9 = scratch1 - scratch5;
+ Fout[m2] = Fout[fout_ptr] - scratch6;
+ Fout[m2 + 1] = Fout[fout_ptr + 1] - scratch7;
+ tw1 += fstride * 2;
+ tw2 += fstride * 4;
+ tw3 += fstride * 6;
+ Fout[fout_ptr] += scratch6;
+ Fout[fout_ptr + 1] += scratch7;
+ Fout[m1] = scratch10 + scratch9;
+ Fout[m1 + 1] = scratch11 - scratch8;
+ Fout[m3] = scratch10 - scratch9;
+ Fout[m3 + 1] = scratch11 + scratch8;
+ fout_ptr += 2;
+ m1 += 2;
+ m2 += 2;
+ m3 += 2;
+ }
+ }
+ }
+ }
+
+ static void kf_bfly3(
+ int[] Fout,
+ int fout_ptr,
+ int fstride,
+ FFTState st,
+ int m,
+ int N,
+ int mm
+ ) {
+ int i;
+ int k;
+ int m1 = 2 * m;
+ int m2 = 4 * m;
+ int tw1, tw2;
+ int scratch0, scratch1, scratch2, scratch3, scratch4, scratch5, scratch6, scratch7;
+
+ int Fout_beg = fout_ptr;
+
+ for (i = 0; i < N; i++) {
+ fout_ptr = Fout_beg + 2 * i * mm;
+ tw1 = tw2 = 0;
+ /* For non-custom modes, m is guaranteed to be a multiple of 4. */
+ k = m;
+ do {
+ scratch2 = (S_MUL(Fout[fout_ptr + m1], st.twiddles[tw1]) - S_MUL(Fout[fout_ptr + m1 + 1], st.twiddles[tw1 + 1]));
+ scratch3 = (S_MUL(Fout[fout_ptr + m1], st.twiddles[tw1 + 1]) + S_MUL(Fout[fout_ptr + m1 + 1], st.twiddles[tw1]));
+ scratch4 = (S_MUL(Fout[fout_ptr + m2], st.twiddles[tw2]) - S_MUL(Fout[fout_ptr + m2 + 1], st.twiddles[tw2 + 1]));
+ scratch5 = (S_MUL(Fout[fout_ptr + m2], st.twiddles[tw2 + 1]) + S_MUL(Fout[fout_ptr + m2 + 1], st.twiddles[tw2]));
+
+ scratch6 = scratch2 + scratch4;
+ scratch7 = scratch3 + scratch5;
+ scratch0 = scratch2 - scratch4;
+ scratch1 = scratch3 - scratch5;
+
+ tw1 += fstride * 2;
+ tw2 += fstride * 4;
+
+ Fout[fout_ptr + m1] = Fout[fout_ptr + 0] - HALF_OF(scratch6);
+ Fout[fout_ptr + m1 + 1] = Fout[fout_ptr + 1] - HALF_OF(scratch7);
+
+ scratch0 = S_MUL(scratch0, -28378);
+ scratch1 = S_MUL(scratch1, -28378);
+
+ Fout[fout_ptr + 0] += scratch6;
+ Fout[fout_ptr + 1] += scratch7;
+
+ Fout[fout_ptr + m2] = Fout[fout_ptr + m1] + scratch1;
+ Fout[fout_ptr + m2 + 1] = Fout[fout_ptr + m1 + 1] - scratch0;
+
+ Fout[fout_ptr + m1] -= scratch1;
+ Fout[fout_ptr + m1 + 1] += scratch0;
+
+ fout_ptr += 2;
+ } while ((--k) != 0);
+ }
+ }
+
+ static void kf_bfly5(
+ int[] Fout,
+ int fout_ptr,
+ int fstride,
+ FFTState st,
+ int m,
+ int N,
+ int mm
+ ) {
+ int Fout0, Fout1, Fout2, Fout3, Fout4;
+ int i, u;
+ int scratch0, scratch1, scratch2, scratch3, scratch4, scratch5,
+ scratch6, scratch7, scratch8, scratch9, scratch10, scratch11,
+ scratch12, scratch13, scratch14, scratch15, scratch16, scratch17,
+ scratch18, scratch19, scratch20, scratch21, scratch22, scratch23,
+ scratch24, scratch25;
+
+ int Fout_beg = fout_ptr;
+
+ short ya_r = 10126;
+ short ya_i = -31164;
+ short yb_r = -26510;
+ short yb_i = -19261;
+ int tw1, tw2, tw3, tw4;
+
+ for (i = 0; i < N; i++) {
+ tw1 = tw2 = tw3 = tw4 = 0;
+ fout_ptr = Fout_beg + 2 * i * mm;
+ Fout0 = fout_ptr;
+ Fout1 = fout_ptr + (2 * m);
+ Fout2 = fout_ptr + (4 * m);
+ Fout3 = fout_ptr + (6 * m);
+ Fout4 = fout_ptr + (8 * m);
+
+ /* For non-custom modes, m is guaranteed to be a multiple of 4. */
+ for (u = 0; u < m; ++u) {
+ scratch0 = Fout[Fout0 + 0];
+ scratch1 = Fout[Fout0 + 1];
+
+ scratch2 = (S_MUL(Fout[Fout1 + 0], st.twiddles[tw1]) - S_MUL(Fout[Fout1 + 1], st.twiddles[tw1 + 1]));
+ scratch3 = (S_MUL(Fout[Fout1 + 0], st.twiddles[tw1 + 1]) + S_MUL(Fout[Fout1 + 1], st.twiddles[tw1]));
+ scratch4 = (S_MUL(Fout[Fout2 + 0], st.twiddles[tw2]) - S_MUL(Fout[Fout2 + 1], st.twiddles[tw2 + 1]));
+ scratch5 = (S_MUL(Fout[Fout2 + 0], st.twiddles[tw2 + 1]) + S_MUL(Fout[Fout2 + 1], st.twiddles[tw2]));
+ scratch6 = (S_MUL(Fout[Fout3 + 0], st.twiddles[tw3]) - S_MUL(Fout[Fout3 + 1], st.twiddles[tw3 + 1]));
+ scratch7 = (S_MUL(Fout[Fout3 + 0], st.twiddles[tw3 + 1]) + S_MUL(Fout[Fout3 + 1], st.twiddles[tw3]));
+ scratch8 = (S_MUL(Fout[Fout4 + 0], st.twiddles[tw4]) - S_MUL(Fout[Fout4 + 1], st.twiddles[tw4 + 1]));
+ scratch9 = (S_MUL(Fout[Fout4 + 0], st.twiddles[tw4 + 1]) + S_MUL(Fout[Fout4 + 1], st.twiddles[tw4]));
+
+ tw1 += (2 * fstride);
+ tw2 += (4 * fstride);
+ tw3 += (6 * fstride);
+ tw4 += (8 * fstride);
+
+ scratch14 = scratch2 + scratch8;
+ scratch15 = scratch3 + scratch9;
+ scratch20 = scratch2 - scratch8;
+ scratch21 = scratch3 - scratch9;
+ scratch16 = scratch4 + scratch6;
+ scratch17 = scratch5 + scratch7;
+ scratch18 = scratch4 - scratch6;
+ scratch19 = scratch5 - scratch7;
+
+ Fout[Fout0 + 0] += scratch14 + scratch16;
+ Fout[Fout0 + 1] += scratch15 + scratch17;
+
+ scratch10 = scratch0 + S_MUL(scratch14, ya_r) + S_MUL(scratch16, yb_r);
+ scratch11 = scratch1 + S_MUL(scratch15, ya_r) + S_MUL(scratch17, yb_r);
+
+ scratch12 = S_MUL(scratch21, ya_i) + S_MUL(scratch19, yb_i);
+ scratch13 = 0 - S_MUL(scratch20, ya_i) - S_MUL(scratch18, yb_i);
+
+ Fout[Fout1 + 0] = scratch10 - scratch12;
+ Fout[Fout1 + 1] = scratch11 - scratch13;
+ Fout[Fout4 + 0] = scratch10 + scratch12;
+ Fout[Fout4 + 1] = scratch11 + scratch13;
+
+ scratch22 = scratch0 + S_MUL(scratch14, yb_r) + S_MUL(scratch16, ya_r);
+ scratch23 = scratch1 + S_MUL(scratch15, yb_r) + S_MUL(scratch17, ya_r);
+ scratch24 = 0 - S_MUL(scratch21, yb_i) + S_MUL(scratch19, ya_i);
+ scratch25 = S_MUL(scratch20, yb_i) - S_MUL(scratch18, ya_i);
+
+ Fout[Fout2 + 0] = scratch22 + scratch24;
+ Fout[Fout2 + 1] = scratch23 + scratch25;
+ Fout[Fout3 + 0] = scratch22 - scratch24;
+ Fout[Fout3 + 1] = scratch23 - scratch25;
+
+ Fout0 += 2;
+ Fout1 += 2;
+ Fout2 += 2;
+ Fout3 += 2;
+ Fout4 += 2;
+ }
+ }
+ }
+
+ static void opus_fft_impl(FFTState st, int[] fout, int fout_ptr) {
+ int m2, m;
+ int p;
+ int L;
+ int[] fstride = new int[MAXFACTORS];
+ int i;
+ int shift;
+
+ /* st.shift can be -1 */
+ shift = st.shift > 0 ? st.shift : 0;
+
+ fstride[0] = 1;
+ L = 0;
+ do {
+ p = st.factors[2 * L];
+ m = st.factors[2 * L + 1];
+ fstride[L + 1] = fstride[L] * p;
+ L++;
+ } while (m != 1);
+
+ m = st.factors[2 * L - 1];
+ for (i = L - 1; i >= 0; i--) {
+ if (i != 0) {
+ m2 = st.factors[2 * i - 1];
+ } else {
+ m2 = 1;
+ }
+ switch (st.factors[2 * i]) {
+ case 2:
+ kf_bfly2(fout, fout_ptr, m, fstride[i]);
+ break;
+ case 4:
+ kf_bfly4(fout, fout_ptr, fstride[i] << shift, st, m, fstride[i], m2);
+ break;
+ case 3:
+ kf_bfly3(fout, fout_ptr, fstride[i] << shift, st, m, fstride[i], m2);
+ break;
+ case 5:
+ kf_bfly5(fout, fout_ptr, fstride[i] << shift, st, m, fstride[i], m2);
+ break;
+ }
+ m = m2;
+ }
+ }
+
+ static void opus_fft(FFTState st, int[] fin, int[] fout) {
+ int i;
+ /* Allows us to scale with MULT16_32_Q16() */
+ int scale_shift = st.scale_shift - 1;
+ short scale = st.scale;
+
+ Inlines.OpusAssert(fin != fout, "In-place FFT not supported");
+
+ /* Bit-reverse the input */
+ for (i = 0; i < st.nfft; i++) {
+ fout[(2 * st.bitrev[i])] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[(2 * i)]), scale_shift);
+ fout[(2 * st.bitrev[i] + 1)] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[(2 * i) + 1]), scale_shift);
+ }
+
+ opus_fft_impl(st, fout, 0);
+ }
+
+ //static void opus_ifft(FFTState st, Pointer fin, Pointer fout)
+ //{
+ // int i;
+ // Inlines.OpusAssert(fin != fout, "In-place iFFT not supported");
+ // /* Bit-reverse the input */
+ // for (i = 0; i < st.nfft * 2; i++)
+ // {
+ // fout[st.bitrev[i]] = fin[i];
+ // }
+ // for (i = 1; i < st.nfft * 2; i += 2)
+ // {
+ // fout[i] = -fout[i];
+ // }
+ // opus_fft_impl(st, fout.Data, fout.Offset);
+ // for (i = 1; i < st.nfft * 2; i += 2)
+ // fout[i] = -fout[i];
+ //}
+}
diff --git a/app/src/main/java/org/concentus/LPCInversePredGain.java b/app/src/main/java/org/concentus/LPCInversePredGain.java
new file mode 100644
index 0000000000..54117f8ff0
--- /dev/null
+++ b/app/src/main/java/org/concentus/LPCInversePredGain.java
@@ -0,0 +1,150 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class LPCInversePredGain {
+
+ private static final int QA = 24;
+ private static final 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) */
+ 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 */
+ 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.InitTwoDimensionalArrayInt(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);
+ }
+
+ 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.InitTwoDimensionalArrayInt(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);
+ }
+}
diff --git a/app/src/main/java/org/concentus/LTPAnalysisFilter.java b/app/src/main/java/org/concentus/LTPAnalysisFilter.java
new file mode 100644
index 0000000000..25fa30f3de
--- /dev/null
+++ b/app/src/main/java/org/concentus/LTPAnalysisFilter.java
@@ -0,0 +1,93 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class LTPAnalysisFilter {
+
+ 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;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/LTPScaleControl.java b/app/src/main/java/org/concentus/LTPScaleControl.java
new file mode 100644
index 0000000000..6c7292ae9f
--- /dev/null
+++ b/app/src/main/java/org/concentus/LTPScaleControl.java
@@ -0,0 +1,55 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class LTPScaleControl {
+
+ /* Calculation of LTP state scaling */
+ 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 = (byte) 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 = SilkTables.silk_LTPScales_table_Q14[psEnc.indices.LTP_scaleIndex];
+ }
+}
diff --git a/app/src/main/java/org/concentus/Laplace.java b/app/src/main/java/org/concentus/Laplace.java
new file mode 100644
index 0000000000..9f77fd0450
--- /dev/null
+++ b/app/src/main/java/org/concentus/Laplace.java
@@ -0,0 +1,133 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class Laplace {
+
+ /* The minimum probability of an energy delta (out of 32768). */
+ private static final int LAPLACE_LOG_MINP = 0;
+ private static final long LAPLACE_MINP = (1 << LAPLACE_LOG_MINP);
+ /* The minimum number of guaranteed representable energy deltas (in one
+ direction). */
+ private static final int LAPLACE_NMIN = 16;
+
+ /* When called, decay is positive and at most 11456. */
+ static long ec_laplace_get_freq1(long fs0, int decay) {
+ long ft = Inlines.CapToUInt32(32768 - LAPLACE_MINP * (2 * LAPLACE_NMIN) - fs0);
+ return (Inlines.CapToUInt32(ft * (16384 - decay)) >> 15);
+ }
+
+ static void ec_laplace_encode(EntropyCoder enc, BoxedValueInt value, long fs, int decay) {
+ long fl;
+ int val = value.Val;
+ fl = 0;
+ if (val != 0) {
+ int s;
+ int i;
+ s = 0 - (val < 0 ? 1 : 0);
+ val = (val + s) ^ s;
+ fl = fs;
+ fs = ec_laplace_get_freq1(fs, decay);
+
+ /* Search the decaying part of the PDF.*/
+ for (i = 1; fs > 0 && i < val; i++) {
+ fs *= 2;
+ fl = Inlines.CapToUInt32(fl + fs + 2 * LAPLACE_MINP);
+ fs = Inlines.CapToUInt32((fs * (int) decay) >> 15);
+ }
+
+ /* Everything beyond that has probability LAPLACE_MINP. */
+ if (fs == 0) {
+ int di;
+ int ndi_max;
+ ndi_max = (int) (32768 - fl + LAPLACE_MINP - 1) >> LAPLACE_LOG_MINP;
+ ndi_max = (ndi_max - s) >> 1;
+ di = Inlines.IMIN(val - i, ndi_max - 1);
+ fl = Inlines.CapToUInt32(fl + (2 * di + 1 + s) * LAPLACE_MINP);
+ fs = Inlines.IMIN(LAPLACE_MINP, 32768 - fl);
+ value.Val = (i + di + s) ^ s;
+ } else {
+ fs += LAPLACE_MINP;
+ fl = fl + Inlines.CapToUInt32(fs & ~s);
+ }
+ Inlines.OpusAssert(fl + fs <= 32768);
+ Inlines.OpusAssert(fs > 0);
+ }
+
+ enc.encode_bin(fl, (fl + fs), 15);
+ }
+
+ static int ec_laplace_decode(EntropyCoder dec, long fs, int decay) {
+ int val = 0;
+ long fl;
+ long fm;
+ fm = dec.decode_bin(15);
+ fl = 0;
+
+ if (fm >= fs) {
+ val++;
+ fl = fs;
+ fs = ec_laplace_get_freq1(fs, decay) + LAPLACE_MINP;
+ /* Search the decaying part of the PDF.*/
+ while (fs > LAPLACE_MINP && fm >= fl + 2 * fs) {
+ fs *= 2;
+ fl = Inlines.CapToUInt32(fl + fs);
+ fs = Inlines.CapToUInt32(((fs - 2 * LAPLACE_MINP) * (int) decay) >> 15);
+ fs += LAPLACE_MINP;
+ val++;
+ }
+ /* Everything beyond that has probability LAPLACE_MINP. */
+ if (fs <= LAPLACE_MINP) {
+ int di;
+ di = (int) (fm - fl) >> (LAPLACE_LOG_MINP + 1);
+ val += di;
+ fl = Inlines.CapToUInt32(fl + Inlines.CapToUInt32(2 * di * LAPLACE_MINP));
+ }
+ if (fm < fl + fs) {
+ val = -val;
+ } else {
+ fl = Inlines.CapToUInt32(fl + fs);
+ }
+ }
+
+ Inlines.OpusAssert(fl < 32768);
+ Inlines.OpusAssert(fs > 0);
+ Inlines.OpusAssert(fl <= fm);
+ Inlines.OpusAssert(fm < Inlines.IMIN(fl + fs, 32768));
+
+ dec.dec_update(fl, Inlines.IMIN(fl + fs, 32768), 32768);
+ return val;
+ }
+}
diff --git a/app/src/main/java/org/concentus/LinearAlgebra.java b/app/src/main/java/org/concentus/LinearAlgebra.java
new file mode 100644
index 0000000000..b72b3e171a
--- /dev/null
+++ b/app/src/main/java/org/concentus/LinearAlgebra.java
@@ -0,0 +1,239 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class LinearAlgebra {
+
+ /* Solves Ax = b, assuming A is symmetric */
+ 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);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/MDCT.java b/app/src/main/java/org/concentus/MDCT.java
new file mode 100644
index 0000000000..f6772b2ef2
--- /dev/null
+++ b/app/src/main/java/org/concentus/MDCT.java
@@ -0,0 +1,230 @@
+/* Copyright (c) 2003-2004, Mark Borgerding
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2011 Xiph.Org Foundation
+ Modified from KISS-FFT by Jean-Marc Valin
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class MDCT {
+
+ /* Forward MDCT trashes the input array */
+ static void clt_mdct_forward(MDCTLookup l, int[] input, int input_ptr, int[] output, int output_ptr,
+ int[] window, int overlap, int shift, int stride) {
+ int i;
+ int N, N2, N4;
+ int[] f;
+ int[] f2;
+ FFTState st = l.kfft[shift];
+ short[] trig;
+ int trig_ptr = 0;
+ int scale;
+
+ int scale_shift = st.scale_shift - 1;
+ scale = st.scale;
+
+ N = l.n;
+ trig = l.trig;
+ for (i = 0; i < shift; i++) {
+ N = N >> 1;
+ trig_ptr += N;
+ }
+ N2 = N >> 1;
+ N4 = N >> 2;
+
+ f = new int[N2];
+ f2 = new int[N4 * 2];
+
+ /* Consider the input to be composed of four blocks: [a, b, c, d] */
+ /* Window, shuffle, fold */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ int xp1 = input_ptr + (overlap >> 1);
+ int xp2 = input_ptr + N2 - 1 + (overlap >> 1);
+ int yp = 0;
+ int wp1 = (overlap >> 1);
+ int wp2 = ((overlap >> 1) - 1);
+ for (i = 0; i < ((overlap + 3) >> 2); i++) {
+ /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
+ f[yp++] = Inlines.MULT16_32_Q15(window[wp2], input[xp1 + N2]) + Inlines.MULT16_32_Q15(window[wp1], input[xp2]);
+ f[yp++] = Inlines.MULT16_32_Q15(window[wp1], input[xp1]) - Inlines.MULT16_32_Q15(window[wp2], input[xp2 - N2]);
+ xp1 += 2;
+ xp2 -= 2;
+ wp1 += 2;
+ wp2 -= 2;
+ }
+ wp1 = 0;
+ wp2 = (overlap - 1);
+ for (; i < N4 - ((overlap + 3) >> 2); i++) {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ f[yp++] = input[xp2];
+ f[yp++] = input[xp1];
+ xp1 += 2;
+ xp2 -= 2;
+ }
+ for (; i < N4; i++) {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ f[yp++] = Inlines.MULT16_32_Q15(window[wp2], input[xp2]) - Inlines.MULT16_32_Q15(window[wp1], input[xp1 - N2]);
+ f[yp++] = Inlines.MULT16_32_Q15(window[wp2], input[xp1]) + Inlines.MULT16_32_Q15(window[wp1], input[xp2 + N2]);
+ xp1 += 2;
+ xp2 -= 2;
+ wp1 += 2;
+ wp2 -= 2;
+ }
+ }
+ /* Pre-rotation */
+ {
+ int yp = 0;
+ int t = trig_ptr;
+ for (i = 0; i < N4; i++) {
+ short t0, t1;
+ int re, im, yr, yi;
+ t0 = trig[t + i];
+ t1 = trig[t + N4 + i];
+ re = f[yp++];
+ im = f[yp++];
+ yr = KissFFT.S_MUL(re, t0) - KissFFT.S_MUL(im, t1);
+ yi = KissFFT.S_MUL(im, t0) + KissFFT.S_MUL(re, t1);
+ f2[2 * st.bitrev[i]] = Inlines.PSHR32(Inlines.MULT16_32_Q16(scale, yr), scale_shift);
+ f2[2 * st.bitrev[i] + 1] = Inlines.PSHR32(Inlines.MULT16_32_Q16(scale, yi), scale_shift);
+ }
+ }
+
+ /* N/4 complex FFT, does not downscale anymore */
+ KissFFT.opus_fft_impl(st, f2, 0);
+
+ /* Post-rotate */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ int fp = 0;
+ int yp1 = output_ptr;
+ int yp2 = output_ptr + (stride * (N2 - 1));
+ int t = trig_ptr;
+ for (i = 0; i < N4; i++) {
+ int yr, yi;
+ yr = KissFFT.S_MUL(f2[fp + 1], trig[t + N4 + i]) - KissFFT.S_MUL(f2[fp], trig[t + i]);
+ yi = KissFFT.S_MUL(f2[fp], trig[t + N4 + i]) + KissFFT.S_MUL(f2[fp + 1], trig[t + i]);
+ output[yp1] = yr;
+ output[yp2] = yi;
+ fp += 2;
+ yp1 += (2 * stride);
+ yp2 -= (2 * stride);
+ }
+ }
+ }
+
+ static void clt_mdct_backward(MDCTLookup l, int[] input, int input_ptr, int[] output, int output_ptr,
+ int[] window, int overlap, int shift, int stride) {
+ int i;
+ int N, N2, N4;
+ int trig = 0;
+ int xp1, xp2, yp, yp0, yp1;
+
+ N = l.n;
+ for (i = 0; i < shift; i++) {
+ N >>= 1;
+ trig += N;
+ }
+ N2 = N >> 1;
+ N4 = N >> 2;
+
+ /* Pre-rotate */
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ xp2 = input_ptr + (stride * (N2 - 1));
+ yp = output_ptr + (overlap >> 1);
+ short[] bitrev = l.kfft[shift].bitrev;
+ int bitrav_ptr = 0;
+ for (i = 0; i < N4; i++) {
+ int rev = bitrev[bitrav_ptr++];
+ int ypr = yp + 2 * rev;
+ /* We swap real and imag because we use an FFT instead of an IFFT. */
+ output[ypr + 1] = KissFFT.S_MUL(input[xp2], l.trig[trig + i]) + KissFFT.S_MUL(input[input_ptr], l.trig[trig + N4 + i]); //yr
+ output[ypr] = KissFFT.S_MUL(input[input_ptr], l.trig[trig + i]) - KissFFT.S_MUL(input[xp2], l.trig[trig + N4 + i]); //yi
+ /* Storing the pre-rotation directly in the bitrev order. */
+ input_ptr += (2 * stride);
+ xp2 -= (2 * stride);
+ }
+
+ KissFFT.opus_fft_impl(l.kfft[shift], output, output_ptr + (overlap >> 1));
+
+ /* Post-rotate and de-shuffle from both ends of the buffer at once to make
+ it in-place. */
+ yp0 = output_ptr + (overlap >> 1);
+ yp1 = output_ptr + (overlap >> 1) + N2 - 2;
+ int t = trig;
+
+ /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
+ middle pair will be computed twice. */
+ int tN4m1 = t + N4 - 1;
+ int tN2m1 = t + N2 - 1;
+ for (i = 0; i < (N4 + 1) >> 1; i++) {
+ int re, im, yr, yi;
+ short t0, t1;
+ /* We swap real and imag because we're using an FFT instead of an IFFT. */
+ re = output[yp0 + 1];
+ im = output[yp0];
+ t0 = l.trig[t + i];
+ t1 = l.trig[t + N4 + i];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = KissFFT.S_MUL(re, t0) + KissFFT.S_MUL(im, t1);
+ yi = KissFFT.S_MUL(re, t1) - KissFFT.S_MUL(im, t0);
+ /* We swap real and imag because we're using an FFT instead of an IFFT. */
+ re = output[yp1 + 1];
+ im = output[yp1];
+ output[yp0] = yr;
+ output[yp1 + 1] = yi;
+ t0 = l.trig[tN4m1 - i];
+ t1 = l.trig[tN2m1 - i];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = KissFFT.S_MUL(re, t0) + KissFFT.S_MUL(im, t1);
+ yi = KissFFT.S_MUL(re, t1) - KissFFT.S_MUL(im, t0);
+ output[yp1] = yr;
+ output[yp0 + 1] = yi;
+ yp0 += 2;
+ yp1 -= 2;
+ }
+
+ /* Mirror on both sides for TDAC */
+ xp1 = output_ptr + overlap - 1;
+ yp1 = output_ptr;
+ int wp1 = 0;
+ int wp2 = (overlap - 1);
+
+ for (i = 0; i < overlap / 2; i++) {
+ int x1 = output[xp1];
+ int x2 = output[yp1];
+ output[yp1++] = Inlines.MULT16_32_Q15(window[wp2], x2) - Inlines.MULT16_32_Q15(window[wp1], x1);
+ output[xp1--] = Inlines.MULT16_32_Q15(window[wp1], x2) + Inlines.MULT16_32_Q15(window[wp2], x1);
+ wp1++;
+ wp2--;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/MDCTLookup.java b/app/src/main/java/org/concentus/MDCTLookup.java
new file mode 100644
index 0000000000..b0c83c6eaa
--- /dev/null
+++ b/app/src/main/java/org/concentus/MDCTLookup.java
@@ -0,0 +1,50 @@
+/* Copyright (c) 2003-2004, Mark Borgerding
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2011 Xiph.Org Foundation
+ Modified from KISS-FFT by Jean-Marc Valin
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class MDCTLookup {
+
+ int n = 0;
+
+ int maxshift = 0;
+
+ // [porting note] these are pointers to static states defined in tables.cs
+ FFTState[] kfft = new FFTState[4];
+
+ short[] trig = null;
+
+ MDCTLookup() {
+ }
+}
diff --git a/app/src/main/java/org/concentus/MLP.java b/app/src/main/java/org/concentus/MLP.java
new file mode 100644
index 0000000000..7de1718e6f
--- /dev/null
+++ b/app/src/main/java/org/concentus/MLP.java
@@ -0,0 +1,43 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+ Originally written by Jean-Marc Valin
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// state object for multi-layer perceptron
+///
+class MLPState {
+
+ int layers;
+ int[] topo;
+ float[] weights;
+}
diff --git a/app/src/main/java/org/concentus/MultiLayerPerceptron.java b/app/src/main/java/org/concentus/MultiLayerPerceptron.java
new file mode 100644
index 0000000000..00fe1fb845
--- /dev/null
+++ b/app/src/main/java/org/concentus/MultiLayerPerceptron.java
@@ -0,0 +1,94 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+ Originally written by Jean-Marc Valin
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// multi-layer perceptron processor
+///
+class MultiLayerPerceptron {
+
+ private static final int MAX_NEURONS = 100;
+
+ static float tansig_approx(float x) {
+ int i;
+ float y, dy;
+ float sign = 1;
+ /* Tests are reversed to catch NaNs */
+ if (!(x < 8)) {
+ return 1;
+ }
+ if (!(x > -8)) {
+ return -1;
+ }
+ if (x < 0) {
+ x = -x;
+ sign = -1;
+ }
+ i = (int) Math.floor(.5f + 25 * x);
+ x -= .04f * i;
+ y = OpusTables.tansig_table[i];
+ dy = 1 - y * y;
+ y = y + x * dy * (1 - y * x);
+ return sign * y;
+ }
+
+ static void mlp_process(MLPState m, float[] input, float[] output) {
+ int j;
+ float[] hidden = new float[MAX_NEURONS];
+ float[] W = m.weights;
+ int W_ptr = 0;
+
+ /* Copy to tmp_in */
+ for (j = 0; j < m.topo[1]; j++) {
+ int k;
+ float sum = W[W_ptr];
+ W_ptr++;
+ for (k = 0; k < m.topo[0]; k++) {
+ sum = sum + input[k] * W[W_ptr];
+ W_ptr++;
+ }
+ hidden[j] = tansig_approx(sum);
+ }
+
+ for (j = 0; j < m.topo[2]; j++) {
+ int k;
+ float sum = W[W_ptr];
+ W_ptr++;
+ for (k = 0; k < m.topo[1]; k++) {
+ sum = sum + hidden[k] * W[W_ptr];
+ W_ptr++;
+ }
+ output[j] = tansig_approx(sum);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/NLSF.java b/app/src/main/java/org/concentus/NLSF.java
new file mode 100644
index 0000000000..bf3a064ebf
--- /dev/null
+++ b/app/src/main/java/org/concentus/NLSF.java
@@ -0,0 +1,1160 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Normalized line spectrum frequency processor
+///
+class NLSF {
+
+ private static final int MAX_STABILIZE_LOOPS = 20;
+
+ private static final int QA = 16;
+
+ ///
+ /// Number of binary divisions, when not in low complexity mode
+ ///
+ private static final int BIN_DIV_STEPS_A2NLSF = 3;
+ /* must be no higher than 16 - log2( LSF_COS_TAB_SZ ) */
+
+ private static final int MAX_ITERATIONS_A2NLSF = 30;
+
+ ///
+ /// Compute quantization errors for an LPC_order element input vector for a VQ codebook
+ ///
+ /// (O) Quantization errors [K]
+ /// (I) Input vectors to be quantized [LPC_order]
+ /// (I) Codebook vectors [K*LPC_order]
+ /// (I) Number of codebook vectors
+ /// (I) Number of LPCs
+ static void silk_NLSF_VQ(int[] err_Q26, short[] in_Q15, short[] pCB_Q8, int K, int LPC_order) {
+ int diff_Q15, sum_error_Q30, sum_error_Q26;
+ int pCB_idx = 0;
+
+ Inlines.OpusAssert(err_Q26 != null);
+ Inlines.OpusAssert(LPC_order <= 16);
+ Inlines.OpusAssert((LPC_order & 1) == 0);
+
+ // Loop over codebook
+ for (int i = 0; i < K; i++) {
+ sum_error_Q26 = 0;
+
+ for (int m = 0; m < LPC_order; m += 2) {
+ // Compute weighted squared quantization error for index m
+ diff_Q15 = Inlines.silk_SUB_LSHIFT32(in_Q15[m], pCB_Q8[pCB_idx++], 7); // range: [ -32767 : 32767 ]
+ sum_error_Q30 = Inlines.silk_SMULBB(diff_Q15, diff_Q15);
+
+ // Compute weighted squared quantization error for index m + 1
+ diff_Q15 = Inlines.silk_SUB_LSHIFT32(in_Q15[m + 1], pCB_Q8[pCB_idx++], 7); // range: [ -32767 : 32767 ]
+ sum_error_Q30 = Inlines.silk_SMLABB(sum_error_Q30, diff_Q15, diff_Q15);
+
+ sum_error_Q26 = Inlines.silk_ADD_RSHIFT32(sum_error_Q26, sum_error_Q30, 4);
+
+ Inlines.OpusAssert(sum_error_Q26 >= 0);
+ Inlines.OpusAssert(sum_error_Q30 >= 0);
+ }
+
+ err_Q26[i] = sum_error_Q26;
+ }
+ }
+
+ ///
+ /// Laroia low complexity NLSF weights
+ ///
+ /// (O) Pointer to input vector weights [D]
+ /// (I) Pointer to input vector [D]
+ /// (I) Input vector dimension (even)
+ static void silk_NLSF_VQ_weights_laroia(short[] pNLSFW_Q_OUT, short[] pNLSF_Q15, int D) {
+ int k;
+ int tmp1_int, tmp2_int;
+
+ Inlines.OpusAssert(pNLSFW_Q_OUT != null);
+ Inlines.OpusAssert(D > 0);
+ Inlines.OpusAssert((D & 1) == 0);
+
+ // First value
+ tmp1_int = Inlines.silk_max_int(pNLSF_Q15[0], 1);
+ tmp1_int = Inlines.silk_DIV32((int) 1 << (15 + SilkConstants.NLSF_W_Q), tmp1_int);
+ tmp2_int = Inlines.silk_max_int(pNLSF_Q15[1] - pNLSF_Q15[0], 1);
+ tmp2_int = Inlines.silk_DIV32((int) 1 << (15 + SilkConstants.NLSF_W_Q), tmp2_int);
+ pNLSFW_Q_OUT[0] = (short) Inlines.silk_min_int(tmp1_int + tmp2_int, Short.MAX_VALUE);
+
+ Inlines.OpusAssert(pNLSFW_Q_OUT[0] > 0);
+
+ // Main loop
+ for (k = 1; k < D - 1; k += 2) {
+ tmp1_int = Inlines.silk_max_int(pNLSF_Q15[k + 1] - pNLSF_Q15[k], 1);
+ tmp1_int = Inlines.silk_DIV32((int) 1 << (15 + SilkConstants.NLSF_W_Q), tmp1_int);
+ pNLSFW_Q_OUT[k] = (short) Inlines.silk_min_int(tmp1_int + tmp2_int, Short.MAX_VALUE);
+ Inlines.OpusAssert(pNLSFW_Q_OUT[k] > 0);
+
+ tmp2_int = Inlines.silk_max_int(pNLSF_Q15[k + 2] - pNLSF_Q15[k + 1], 1);
+ tmp2_int = Inlines.silk_DIV32((int) 1 << (15 + SilkConstants.NLSF_W_Q), tmp2_int);
+ pNLSFW_Q_OUT[k + 1] = (short) Inlines.silk_min_int(tmp1_int + tmp2_int, Short.MAX_VALUE);
+ Inlines.OpusAssert(pNLSFW_Q_OUT[k + 1] > 0);
+ }
+
+ // Last value
+ tmp1_int = Inlines.silk_max_int((1 << 15) - pNLSF_Q15[D - 1], 1);
+ tmp1_int = Inlines.silk_DIV32((int) 1 << (15 + SilkConstants.NLSF_W_Q), tmp1_int);
+ pNLSFW_Q_OUT[D - 1] = (short) Inlines.silk_min_int(tmp1_int + tmp2_int, Short.MAX_VALUE);
+
+ Inlines.OpusAssert(pNLSFW_Q_OUT[D - 1] > 0);
+ }
+
+ ///
+ /// Returns RD value in Q30
+ ///
+ /// (O) Output [ order ]
+ /// (I) Quantization indices [ order ]
+ /// (I) Backward predictor coefs [ order ]
+ /// (I) Quantization step size
+ /// (I) Number of input values
+ static void silk_NLSF_residual_dequant(
+ short[] x_Q10,
+ byte[] indices,
+ int indices_ptr,
+ short[] pred_coef_Q8,
+ int quant_step_size_Q16,
+ short order) {
+ int i, pred_Q10;
+ short out_Q10;
+
+ out_Q10 = 0;
+ for (i = order - 1; i >= 0; i--) {
+ pred_Q10 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(out_Q10, (short) pred_coef_Q8[i]), 8);
+ out_Q10 = Inlines.silk_LSHIFT16((short) indices[indices_ptr + i], 10);
+ if (out_Q10 > 0) {
+ out_Q10 = Inlines.silk_SUB16(out_Q10, (short) (((int) ((SilkConstants.NLSF_QUANT_LEVEL_ADJ) * ((long) 1 << (10)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.NLSF_QUANT_LEVEL_ADJ, 10)*/));
+ } else if (out_Q10 < 0) {
+ out_Q10 = Inlines.silk_ADD16(out_Q10, (short) (((int) ((SilkConstants.NLSF_QUANT_LEVEL_ADJ) * ((long) 1 << (10)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.NLSF_QUANT_LEVEL_ADJ, 10)*/));
+ }
+ out_Q10 = (short) (Inlines.silk_SMLAWB(pred_Q10, (int) out_Q10, quant_step_size_Q16));
+ x_Q10[i] = out_Q10;
+ }
+ }
+
+ ///
+ /// Unpack predictor values and indices for entropy coding tables
+ ///
+ /// (O) Indices to entropy tables [ LPC_ORDER ]
+ /// (O) LSF predictor [ LPC_ORDER ]
+ /// (I) Codebook object
+ /// (I) Index of vector in first LSF codebook
+ static void silk_NLSF_unpack(short[] ec_ix, short[] pred_Q8, NLSFCodebook psNLSF_CB, int CB1_index) {
+ int i;
+ short entry;
+ short[] ec_sel = psNLSF_CB.ec_sel;
+ int ec_sel_ptr = CB1_index * psNLSF_CB.order / 2;
+
+ for (i = 0; i < psNLSF_CB.order; i += 2) {
+ entry = ec_sel[ec_sel_ptr];
+ ec_sel_ptr++;
+ ec_ix[i] = (short) (Inlines.silk_SMULBB(Inlines.silk_RSHIFT(entry, 1) & 7, 2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE + 1));
+ pred_Q8[i] = psNLSF_CB.pred_Q8[i + (entry & 1) * (psNLSF_CB.order - 1)];
+ ec_ix[i + 1] = (short) (Inlines.silk_SMULBB(Inlines.silk_RSHIFT(entry, 5) & 7, 2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE + 1));
+ pred_Q8[i + 1] = psNLSF_CB.pred_Q8[i + (Inlines.silk_RSHIFT(entry, 4) & 1) * (psNLSF_CB.order - 1) + 1];
+ }
+ }
+
+ ///
+ /// NLSF stabilizer, for a single input data vector
+ ///
+ /// (I/O) Unstable/stabilized normalized LSF vector in Q15 [L]
+ /// (I) Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1]
+ /// (I) Number of NLSF parameters in the input vector
+ static void silk_NLSF_stabilize(short[] NLSF_Q15, short[] NDeltaMin_Q15, int L) {
+ int i, I = 0, k, loops;
+ short center_freq_Q15;
+ int diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15;
+
+ // This is necessary to ensure an output within range of a short
+ Inlines.OpusAssert(NDeltaMin_Q15[L] >= 1);
+
+ for (loops = 0; loops < MAX_STABILIZE_LOOPS; loops++) {
+ /**
+ * ***********************
+ */
+ /* Find smallest distance */
+ /**
+ * ***********************
+ */
+ // First element
+ min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0];
+ I = 0;
+
+ // Middle elements
+ for (i = 1; i <= L - 1; i++) {
+ diff_Q15 = NLSF_Q15[i] - (NLSF_Q15[i - 1] + NDeltaMin_Q15[i]);
+ if (diff_Q15 < min_diff_Q15) {
+ min_diff_Q15 = diff_Q15;
+ I = i;
+ }
+ }
+
+ // Last element
+ diff_Q15 = (1 << 15) - (NLSF_Q15[L - 1] + NDeltaMin_Q15[L]);
+ if (diff_Q15 < min_diff_Q15) {
+ min_diff_Q15 = diff_Q15;
+ I = L;
+ }
+
+ /**
+ * ************************************************
+ */
+ /* Now check if the smallest distance non-negative */
+ /**
+ * ************************************************
+ */
+ if (min_diff_Q15 >= 0) {
+ return;
+ }
+
+ if (I == 0) {
+ // Move away from lower limit
+ NLSF_Q15[0] = NDeltaMin_Q15[0];
+ } else if (I == L) {
+ // Move away from higher limit
+ NLSF_Q15[L - 1] = (short) ((1 << 15) - NDeltaMin_Q15[L]);
+ } else {
+ // Find the lower extreme for the location of the current center frequency
+ min_center_Q15 = 0;
+ for (k = 0; k < I; k++) {
+ min_center_Q15 += NDeltaMin_Q15[k];
+ }
+
+ min_center_Q15 += Inlines.silk_RSHIFT(NDeltaMin_Q15[I], 1);
+
+ // Find the upper extreme for the location of the current center frequency
+ max_center_Q15 = 1 << 15;
+ for (k = L; k > I; k--) {
+ max_center_Q15 -= NDeltaMin_Q15[k];
+ }
+
+ max_center_Q15 -= Inlines.silk_RSHIFT(NDeltaMin_Q15[I], 1);
+
+ // Move apart, sorted by value, keeping the same center frequency
+ center_freq_Q15 = (short) (Inlines.silk_LIMIT_32(Inlines.silk_RSHIFT_ROUND((int) NLSF_Q15[I - 1] + (int) NLSF_Q15[I], 1),
+ min_center_Q15, max_center_Q15));
+ NLSF_Q15[I - 1] = (short) (center_freq_Q15 - Inlines.silk_RSHIFT(NDeltaMin_Q15[I], 1));
+ NLSF_Q15[I] = (short) (NLSF_Q15[I - 1] + NDeltaMin_Q15[I]);
+ }
+ }
+
+ // Safe and simple fall back method, which is less ideal than the above
+ if (loops == MAX_STABILIZE_LOOPS) {
+ Sort.silk_insertion_sort_increasing_all_values_int16(NLSF_Q15, L);
+
+ // First NLSF should be no less than NDeltaMin[0]
+ NLSF_Q15[0] = (short) (Inlines.silk_max_int(NLSF_Q15[0], NDeltaMin_Q15[0]));
+
+ // Keep delta_min distance between the NLSFs
+ for (i = 1; i < L; i++) {
+ NLSF_Q15[i] = (short) (Inlines.silk_max_int(NLSF_Q15[i], NLSF_Q15[i - 1] + NDeltaMin_Q15[i]));
+ }
+
+ // Last NLSF should be no higher than 1 - NDeltaMin[L]
+ NLSF_Q15[L - 1] = (short) (Inlines.silk_min_int(NLSF_Q15[L - 1], (1 << 15) - NDeltaMin_Q15[L]));
+
+ // Keep NDeltaMin distance between the NLSFs
+ for (i = L - 2; i >= 0; i--) {
+ NLSF_Q15[i] = (short) (Inlines.silk_min_int(NLSF_Q15[i], NLSF_Q15[i + 1] - NDeltaMin_Q15[i + 1]));
+ }
+ }
+ }
+
+ ///
+ /// NLSF vector decoder
+ ///
+ /// (O) Quantized NLSF vector [ LPC_ORDER ]
+ /// (I) Codebook path vector [ LPC_ORDER + 1 ]
+ /// (I) Codebook object
+ static void silk_NLSF_decode(short[] pNLSF_Q15, byte[] NLSFIndices, NLSFCodebook psNLSF_CB) {
+ int i;
+ short[] pred_Q8 = new short[psNLSF_CB.order];
+ short[] ec_ix = new short[psNLSF_CB.order];
+ short[] res_Q10 = new short[psNLSF_CB.order];
+ short[] W_tmp_QW = new short[psNLSF_CB.order];
+ int W_tmp_Q9, NLSF_Q15_tmp;
+
+ // Decode first stage
+ short[] pCB = psNLSF_CB.CB1_NLSF_Q8;
+ int pCB_element = NLSFIndices[0] * psNLSF_CB.order;
+
+ for (i = 0; i < psNLSF_CB.order; i++) {
+ pNLSF_Q15[i] = Inlines.silk_LSHIFT16((short) pCB[pCB_element + i], 7);
+ }
+
+ // Unpack entropy table indices and predictor for current CB1 index
+ silk_NLSF_unpack(ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[0]);
+
+ // Predictive residual dequantizer
+ silk_NLSF_residual_dequant(res_Q10,
+ NLSFIndices,
+ 1,
+ pred_Q8,
+ psNLSF_CB.quantStepSize_Q16,
+ psNLSF_CB.order);
+
+ // Weights from codebook vector
+ silk_NLSF_VQ_weights_laroia(W_tmp_QW, pNLSF_Q15, psNLSF_CB.order);
+
+ // Apply inverse square-rooted weights and add to output
+ for (i = 0; i < psNLSF_CB.order; i++) {
+ W_tmp_Q9 = Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT((int) W_tmp_QW[i], 18 - SilkConstants.NLSF_W_Q));
+ NLSF_Q15_tmp = Inlines.silk_ADD32(pNLSF_Q15[i], Inlines.silk_DIV32_16(Inlines.silk_LSHIFT((int) res_Q10[i], 14), (short) (W_tmp_Q9)));
+ pNLSF_Q15[i] = (short) (Inlines.silk_LIMIT(NLSF_Q15_tmp, 0, 32767));
+ }
+
+ // NLSF stabilization
+ silk_NLSF_stabilize(pNLSF_Q15, psNLSF_CB.deltaMin_Q15, psNLSF_CB.order);
+ }
+
+ ///
+ /// Delayed-decision quantizer for NLSF residuals
+ ///
+ /// (O) Quantization indices [ order ]
+ /// (O) Input [ order ]
+ /// (I) Weights [ order ]
+ /// (I) Backward predictor coefs [ order ]
+ /// (I) Indices to entropy coding tables [ order ]
+ /// (I) Rates []
+ /// (I) Quantization step size
+ /// (I) Inverse quantization step size
+ /// (I) R/D tradeoff
+ /// (I) Number of input values
+ /// RD value in Q25
+ /// Fixme: Optimize this method!
+ static int silk_NLSF_del_dec_quant(
+ byte[] indices,
+ short[] x_Q10,
+ short[] w_Q5,
+ short[] pred_coef_Q8,
+ short[] ec_ix,
+ short[] ec_rates_Q5,
+ int quant_step_size_Q16,
+ short inv_quant_step_size_Q6,
+ int mu_Q20,
+ short order) {
+ int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10;
+ int pred_Q10, diff_Q10, out0_Q10, out1_Q10, rate0_Q5, rate1_Q5;
+ int RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25, pred_coef_Q16;
+ int[] ind_sort = new int[SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ byte[][] ind = new byte[SilkConstants.NLSF_QUANT_DEL_DEC_STATES][];
+ for (i = 0; i < SilkConstants.NLSF_QUANT_DEL_DEC_STATES; i++) {
+ ind[i] = new byte[SilkConstants.MAX_LPC_ORDER];
+ }
+
+ short[] prev_out_Q10 = new short[2 * SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ int[] RD_Q25 = new int[2 * SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ int[] RD_min_Q25 = new int[SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ int[] RD_max_Q25 = new int[SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ int rates_Q5;
+
+ int[] out0_Q10_table = new int[2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT];
+ int[] out1_Q10_table = new int[2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT];
+
+ for (i = 0 - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT - 1; i++) {
+ out0_Q10 = Inlines.silk_LSHIFT(i, 10);
+ out1_Q10 = Inlines.silk_ADD16((short) (out0_Q10), (short) 1024);
+
+ if (i > 0) {
+ out0_Q10 = Inlines.silk_SUB16((short) (out0_Q10), (short) (((int) ((SilkConstants.NLSF_QUANT_LEVEL_ADJ) * ((long) 1 << (10)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.NLSF_QUANT_LEVEL_ADJ, 10)*/));
+ out1_Q10 = Inlines.silk_SUB16((short) (out1_Q10), (short) (((int) ((SilkConstants.NLSF_QUANT_LEVEL_ADJ) * ((long) 1 << (10)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.NLSF_QUANT_LEVEL_ADJ, 10)*/));
+ } else if (i == 0) {
+ out1_Q10 = Inlines.silk_SUB16((short) (out1_Q10), (short) (((int) ((SilkConstants.NLSF_QUANT_LEVEL_ADJ) * ((long) 1 << (10)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.NLSF_QUANT_LEVEL_ADJ, 10)*/));
+ } else if (i == -1) {
+ out0_Q10 = Inlines.silk_ADD16((short) (out0_Q10), (short) (((int) ((SilkConstants.NLSF_QUANT_LEVEL_ADJ) * ((long) 1 << (10)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.NLSF_QUANT_LEVEL_ADJ, 10)*/));
+ } else {
+ out0_Q10 = Inlines.silk_ADD16((short) (out0_Q10), (short) (((int) ((SilkConstants.NLSF_QUANT_LEVEL_ADJ) * ((long) 1 << (10)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.NLSF_QUANT_LEVEL_ADJ, 10)*/));
+ out1_Q10 = Inlines.silk_ADD16((short) (out1_Q10), (short) (((int) ((SilkConstants.NLSF_QUANT_LEVEL_ADJ) * ((long) 1 << (10)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.NLSF_QUANT_LEVEL_ADJ, 10)*/));
+ }
+
+ out0_Q10_table[i + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT] = Inlines.silk_SMULWB((int) out0_Q10, quant_step_size_Q16);
+ out1_Q10_table[i + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT] = Inlines.silk_SMULWB((int) out1_Q10, quant_step_size_Q16);
+ }
+
+ Inlines.OpusAssert((SilkConstants.NLSF_QUANT_DEL_DEC_STATES & (SilkConstants.NLSF_QUANT_DEL_DEC_STATES - 1)) == 0); // must be power of two
+
+ nStates = 1;
+ RD_Q25[0] = 0;
+ prev_out_Q10[0] = 0;
+
+ for (i = order - 1;; i--) {
+ pred_coef_Q16 = Inlines.silk_LSHIFT((int) pred_coef_Q8[i], 8);
+ in_Q10 = x_Q10[i];
+
+ for (j = 0; j < nStates; j++) {
+ pred_Q10 = Inlines.silk_SMULWB(pred_coef_Q16, prev_out_Q10[j]);
+ res_Q10 = Inlines.silk_SUB16((short) (in_Q10), (short) (pred_Q10));
+ ind_tmp = Inlines.silk_SMULWB((int) inv_quant_step_size_Q6, res_Q10);
+ ind_tmp = Inlines.silk_LIMIT(ind_tmp, 0 - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT, SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT - 1);
+ ind[j][i] = (byte) ind_tmp;
+ rates_Q5 = ec_ix[i] + ind_tmp;
+
+ // compute outputs for ind_tmp and ind_tmp + 1
+ out0_Q10 = out0_Q10_table[ind_tmp + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT];
+ out1_Q10 = out1_Q10_table[ind_tmp + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT];
+
+ out0_Q10 = Inlines.silk_ADD16((short) (out0_Q10), (short) (pred_Q10));
+ out1_Q10 = Inlines.silk_ADD16((short) (out1_Q10), (short) (pred_Q10));
+ prev_out_Q10[j] = (short) (out0_Q10);
+ prev_out_Q10[j + nStates] = (short) (out1_Q10);
+
+ // compute RD for ind_tmp and ind_tmp + 1
+ if (ind_tmp + 1 >= SilkConstants.NLSF_QUANT_MAX_AMPLITUDE) {
+ if (ind_tmp + 1 == SilkConstants.NLSF_QUANT_MAX_AMPLITUDE) {
+ rate0_Q5 = ec_rates_Q5[rates_Q5 + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE];
+ rate1_Q5 = 280;
+ } else {
+ rate0_Q5 = Inlines.silk_SMLABB(280 - (43 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE), 43, ind_tmp);
+ rate1_Q5 = Inlines.silk_ADD16((short) (rate0_Q5), (short) 43);
+ }
+ } else if (ind_tmp <= 0 - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE) {
+ if (ind_tmp == 0 - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE) {
+ rate0_Q5 = 280;
+ rate1_Q5 = ec_rates_Q5[rates_Q5 + 1 + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE];
+ } else {
+ rate0_Q5 = Inlines.silk_SMLABB(280 - 43 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp);
+ rate1_Q5 = Inlines.silk_SUB16((short) (rate0_Q5), (short) 43);
+ }
+ } else {
+ rate0_Q5 = ec_rates_Q5[rates_Q5 + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE];
+ rate1_Q5 = ec_rates_Q5[rates_Q5 + 1 + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE];
+ }
+
+ RD_tmp_Q25 = RD_Q25[j];
+ diff_Q10 = Inlines.silk_SUB16((short) (in_Q10), (short) (out0_Q10));
+ RD_Q25[j] = Inlines.silk_SMLABB(Inlines.silk_MLA(RD_tmp_Q25, Inlines.silk_SMULBB(diff_Q10, diff_Q10), w_Q5[i]), mu_Q20, rate0_Q5);
+ diff_Q10 = Inlines.silk_SUB16((short) (in_Q10), (short) (out1_Q10));
+ RD_Q25[j + nStates] = Inlines.silk_SMLABB(Inlines.silk_MLA(RD_tmp_Q25, Inlines.silk_SMULBB(diff_Q10, diff_Q10), w_Q5[i]), mu_Q20, rate1_Q5);
+ }
+
+ if (nStates <= (SilkConstants.NLSF_QUANT_DEL_DEC_STATES >> 1)) {
+ // double number of states and copy
+ for (j = 0; j < nStates; j++) {
+ ind[j + nStates][i] = (byte) (ind[j][i] + 1);
+ }
+ nStates = Inlines.silk_LSHIFT(nStates, 1);
+
+ for (j = nStates; j < SilkConstants.NLSF_QUANT_DEL_DEC_STATES; j++) {
+ ind[j][i] = ind[j - nStates][i];
+ }
+ } else if (i > 0) {
+ // sort lower and upper half of RD_Q25, pairwise
+ for (j = 0; j < SilkConstants.NLSF_QUANT_DEL_DEC_STATES; j++) {
+ if (RD_Q25[j] > RD_Q25[j + SilkConstants.NLSF_QUANT_DEL_DEC_STATES]) {
+ RD_max_Q25[j] = RD_Q25[j];
+ RD_min_Q25[j] = RD_Q25[j + SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ RD_Q25[j] = RD_min_Q25[j];
+ RD_Q25[j + SilkConstants.NLSF_QUANT_DEL_DEC_STATES] = RD_max_Q25[j];
+
+ // swap prev_out values
+ out0_Q10 = prev_out_Q10[j];
+ prev_out_Q10[j] = prev_out_Q10[j + SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ prev_out_Q10[j + SilkConstants.NLSF_QUANT_DEL_DEC_STATES] = (short) (out0_Q10);
+ ind_sort[j] = j + SilkConstants.NLSF_QUANT_DEL_DEC_STATES;
+ } else {
+ RD_min_Q25[j] = RD_Q25[j];
+ RD_max_Q25[j] = RD_Q25[j + SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ ind_sort[j] = j;
+ }
+ }
+
+ // compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary
+ // afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values
+ while (true) {
+ min_max_Q25 = Integer.MAX_VALUE;
+ max_min_Q25 = 0;
+ ind_min_max = 0;
+ ind_max_min = 0;
+
+ for (j = 0; j < SilkConstants.NLSF_QUANT_DEL_DEC_STATES; j++) {
+ if (min_max_Q25 > RD_max_Q25[j]) {
+ min_max_Q25 = RD_max_Q25[j];
+ ind_min_max = j;
+ }
+ if (max_min_Q25 < RD_min_Q25[j]) {
+ max_min_Q25 = RD_min_Q25[j];
+ ind_max_min = j;
+ }
+ }
+
+ if (min_max_Q25 >= max_min_Q25) {
+ break;
+ }
+
+ // copy ind_min_max to ind_max_min
+ ind_sort[ind_max_min] = ind_sort[ind_min_max] ^ SilkConstants.NLSF_QUANT_DEL_DEC_STATES;
+ RD_Q25[ind_max_min] = RD_Q25[ind_min_max + SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ prev_out_Q10[ind_max_min] = prev_out_Q10[ind_min_max + SilkConstants.NLSF_QUANT_DEL_DEC_STATES];
+ RD_min_Q25[ind_max_min] = 0;
+ RD_max_Q25[ind_min_max] = Integer.MAX_VALUE;
+ System.arraycopy(ind[ind_min_max], 0, ind[ind_max_min], 0, order);
+ }
+
+ // increment index if it comes from the upper half
+ for (j = 0; j < SilkConstants.NLSF_QUANT_DEL_DEC_STATES; j++) {
+ byte x = (byte) Inlines.silk_RSHIFT(ind_sort[j], SilkConstants.NLSF_QUANT_DEL_DEC_STATES_LOG2);
+ ind[j][i] += x;
+ }
+ } else {
+ // i == 0
+ break;
+ }
+ }
+
+ // last sample: find winner, copy indices and return RD value
+ ind_tmp = 0;
+ min_Q25 = Integer.MAX_VALUE;
+ for (j = 0; j < 2 * SilkConstants.NLSF_QUANT_DEL_DEC_STATES; j++) {
+ if (min_Q25 > RD_Q25[j]) {
+ min_Q25 = RD_Q25[j];
+ ind_tmp = j;
+ }
+ }
+
+ for (j = 0; j < order; j++) {
+ indices[j] = ind[ind_tmp & (SilkConstants.NLSF_QUANT_DEL_DEC_STATES - 1)][j];
+ Inlines.OpusAssert(indices[j] >= 0 - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT);
+ Inlines.OpusAssert(indices[j] <= SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT);
+ }
+
+ indices[0] = (byte) (indices[0] + Inlines.silk_RSHIFT(ind_tmp, SilkConstants.NLSF_QUANT_DEL_DEC_STATES_LOG2));
+ Inlines.OpusAssert(indices[0] <= SilkConstants.NLSF_QUANT_MAX_AMPLITUDE_EXT);
+ Inlines.OpusAssert(min_Q25 >= 0);
+ return min_Q25;
+ }
+
+ ///
+ /// NLSF vector encoder
+ ///
+ /// (I) Codebook path vector [ LPC_ORDER + 1 ]
+ /// (I/O) Quantized NLSF vector [ LPC_ORDER ]
+ /// (I) Codebook object
+ /// (I) NLSF weight vector [ LPC_ORDER ]
+ /// (I) Rate weight for the RD optimization
+ /// (I) Max survivors after first stage
+ /// (I) Signal type: 0/1/2
+ /// RD value in Q25
+ static int silk_NLSF_encode(
+ byte[] NLSFIndices,
+ short[] pNLSF_Q15,
+ NLSFCodebook psNLSF_CB,
+ short[] pW_QW,
+ int NLSF_mu_Q20,
+ int nSurvivors,
+ int signalType) {
+ int i, s, ind1, prob_Q8, bits_q7;
+ int W_tmp_Q9;
+ int[] err_Q26;
+ int[] RD_Q25;
+ int[] tempIndices1;
+ byte[][] tempIndices2;
+ short[] res_Q15 = new short[psNLSF_CB.order];
+ short[] res_Q10 = new short[psNLSF_CB.order];
+ short[] NLSF_tmp_Q15 = new short[psNLSF_CB.order];
+ short[] W_tmp_QW = new short[psNLSF_CB.order];
+ short[] W_adj_Q5 = new short[psNLSF_CB.order];
+ short[] pred_Q8 = new short[psNLSF_CB.order];
+ short[] ec_ix = new short[psNLSF_CB.order];
+ short[] pCB = psNLSF_CB.CB1_NLSF_Q8;
+ int iCDF_ptr;
+ int pCB_element;
+
+ Inlines.OpusAssert(nSurvivors <= SilkConstants.NLSF_VQ_MAX_SURVIVORS);
+ Inlines.OpusAssert(signalType >= 0 && signalType <= 2);
+ Inlines.OpusAssert(NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0);
+
+ // NLSF stabilization
+ silk_NLSF_stabilize(pNLSF_Q15, psNLSF_CB.deltaMin_Q15, psNLSF_CB.order);
+
+ // First stage: VQ
+ err_Q26 = new int[psNLSF_CB.nVectors];
+ silk_NLSF_VQ(err_Q26, pNLSF_Q15, psNLSF_CB.CB1_NLSF_Q8, psNLSF_CB.nVectors, psNLSF_CB.order);
+
+ // Sort the quantization errors
+ tempIndices1 = new int[nSurvivors];
+ Sort.silk_insertion_sort_increasing(err_Q26, tempIndices1, psNLSF_CB.nVectors, nSurvivors);
+
+ RD_Q25 = new int[nSurvivors];
+ tempIndices2 = Arrays.InitTwoDimensionalArrayByte(nSurvivors, SilkConstants.MAX_LPC_ORDER);
+
+ // Loop over survivors
+ for (s = 0; s < nSurvivors; s++) {
+ ind1 = tempIndices1[s];
+
+ // Residual after first stage
+ pCB_element = ind1 * psNLSF_CB.order; // opt: potential 1:2 partitioned buffer
+ for (i = 0; i < psNLSF_CB.order; i++) {
+ NLSF_tmp_Q15[i] = Inlines.silk_LSHIFT16((short) pCB[pCB_element + i], 7);
+ res_Q15[i] = (short) (pNLSF_Q15[i] - NLSF_tmp_Q15[i]);
+ }
+
+ // Weights from codebook vector
+ silk_NLSF_VQ_weights_laroia(W_tmp_QW, NLSF_tmp_Q15, psNLSF_CB.order);
+
+ // Apply square-rooted weights
+ for (i = 0; i < psNLSF_CB.order; i++) {
+ W_tmp_Q9 = Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT((int) W_tmp_QW[i], 18 - SilkConstants.NLSF_W_Q));
+ res_Q10[i] = (short) Inlines.silk_RSHIFT(Inlines.silk_SMULBB(res_Q15[i], W_tmp_Q9), 14);
+ }
+
+ // Modify input weights accordingly
+ for (i = 0; i < psNLSF_CB.order; i++) {
+ W_adj_Q5[i] = (short) (Inlines.silk_DIV32_16(Inlines.silk_LSHIFT((int) pW_QW[i], 5), W_tmp_QW[i]));
+ }
+
+ // Unpack entropy table indices and predictor for current CB1 index
+ silk_NLSF_unpack(ec_ix, pred_Q8, psNLSF_CB, ind1);
+
+ // Trellis quantizer
+ RD_Q25[s] = silk_NLSF_del_dec_quant(
+ tempIndices2[s],
+ res_Q10,
+ W_adj_Q5,
+ pred_Q8,
+ ec_ix,
+ psNLSF_CB.ec_Rates_Q5,
+ psNLSF_CB.quantStepSize_Q16,
+ psNLSF_CB.invQuantStepSize_Q6,
+ NLSF_mu_Q20,
+ psNLSF_CB.order);
+
+ // Add rate for first stage
+ iCDF_ptr = (signalType >> 1) * psNLSF_CB.nVectors;
+
+ if (ind1 == 0) {
+ prob_Q8 = 256 - psNLSF_CB.CB1_iCDF[iCDF_ptr + ind1];
+ } else {
+ prob_Q8 = psNLSF_CB.CB1_iCDF[iCDF_ptr + ind1 - 1] - psNLSF_CB.CB1_iCDF[iCDF_ptr + ind1];
+ }
+
+ bits_q7 = (8 << 7) - Inlines.silk_lin2log(prob_Q8);
+ RD_Q25[s] = Inlines.silk_SMLABB(RD_Q25[s], bits_q7, Inlines.silk_RSHIFT(NLSF_mu_Q20, 2));
+ }
+
+ // Find the lowest rate-distortion error
+ int[] bestIndex = new int[1];
+ Sort.silk_insertion_sort_increasing(RD_Q25, bestIndex, nSurvivors, 1);
+
+ NLSFIndices[0] = (byte) tempIndices1[bestIndex[0]];
+ System.arraycopy(tempIndices2[bestIndex[0]], 0, NLSFIndices, 1, psNLSF_CB.order);
+
+ // Decode
+ silk_NLSF_decode(pNLSF_Q15, NLSFIndices, psNLSF_CB);
+
+ return RD_Q25[0];
+ }
+
+ ///
+ /// helper function for NLSF2A(..)
+ ///
+ /// (O) intermediate polynomial, QA [dd+1]
+ /// (I) vector of interleaved 2*cos(LSFs), QA [d]
+ /// (I) polynomial order (= 1/2 * filter order)
+ static void silk_NLSF2A_find_poly(
+ int[] o,
+ int[] cLSF,
+ int cLSF_ptr,
+ int dd) {
+ int k, n, ftmp;
+
+ o[0] = Inlines.silk_LSHIFT(1, QA);
+ o[1] = 0 - cLSF[cLSF_ptr];
+ for (k = 1; k < dd; k++) {
+ ftmp = cLSF[cLSF_ptr + (2 * k)];
+ /* QA*/
+ o[k + 1] = Inlines.silk_LSHIFT(o[k - 1], 1) - (int) Inlines.silk_RSHIFT_ROUND64(Inlines.silk_SMULL(ftmp, o[k]), QA);
+ for (n = k; n > 1; n--) {
+ o[n] += o[n - 2] - (int) Inlines.silk_RSHIFT_ROUND64(Inlines.silk_SMULL(ftmp, o[n - 1]), QA);
+ }
+ o[1] -= ftmp;
+ }
+ }
+
+ /* This ordering was found to maximize quality. It improves numerical accuracy of
+ silk_NLSF2A_find_poly() compared to "standard" ordering. */
+ private static final byte[] ordering16 = {0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1};
+ private static final byte[] ordering10 = {0, 9, 6, 3, 4, 5, 8, 1, 2, 7};
+
+ ///
+ /// compute whitening filter coefficients from normalized line spectral frequencies
+ ///
+ /// (O) monic whitening filter coefficients in Q12, [ d ]
+ /// (I) normalized line spectral frequencies in Q15, [ d ]
+ /// (I) filter order (should be even)
+ static void silk_NLSF2A(
+ short[] a_Q12,
+ short[] NLSF,
+ int d) {
+
+ byte[] ordering;
+ int k, i, dd;
+ int[] cos_LSF_QA = new int[d];
+ int[] P = new int[d / 2 + 1];
+ int[] Q = new int[d / 2 + 1];
+ int[] a32_QA1 = new int[d];
+
+ int Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
+ int maxabs, absval, idx = 0, sc_Q16;
+
+ Inlines.OpusAssert(SilkConstants.LSF_COS_TAB_SZ == 128);
+ Inlines.OpusAssert(d == 10 || d == 16);
+
+ /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */
+ ordering = d == 16 ? ordering16 : ordering10;
+
+ for (k = 0; k < d; k++) {
+ Inlines.OpusAssert(NLSF[k] >= 0);
+
+ /* f_int on a scale 0-127 (rounded down) */
+ f_int = Inlines.silk_RSHIFT(NLSF[k], 15 - 7);
+
+ /* f_frac, range: 0..255 */
+ f_frac = NLSF[k] - Inlines.silk_LSHIFT(f_int, 15 - 7);
+
+ Inlines.OpusAssert(f_int >= 0);
+ Inlines.OpusAssert(f_int < SilkConstants.LSF_COS_TAB_SZ);
+
+ /* Read start and end value from table */
+ cos_val = SilkTables.silk_LSFCosTab_Q12[f_int];
+ /* Q12 */
+ delta = SilkTables.silk_LSFCosTab_Q12[f_int + 1] - cos_val;
+ /* Q12, with a range of 0..200 */
+
+ /* Linear interpolation */
+ cos_LSF_QA[ordering[k]] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_LSHIFT(cos_val, 8) + Inlines.silk_MUL(delta, f_frac), 20 - QA);
+ /* QA */
+ }
+
+ dd = Inlines.silk_RSHIFT(d, 1);
+
+ /* generate even and odd polynomials using convolution */
+ silk_NLSF2A_find_poly(P, cos_LSF_QA, 0, dd);
+ silk_NLSF2A_find_poly(Q, cos_LSF_QA, 1, dd);
+
+ /* convert even and odd polynomials to opus_int32 Q12 filter coefs */
+ for (k = 0; k < dd; k++) {
+ Ptmp = P[k + 1] + P[k];
+ Qtmp = Q[k + 1] - Q[k];
+
+ /* the Ptmp and Qtmp values at this stage need to fit in int32 */
+ a32_QA1[k] = -Qtmp - Ptmp;
+ /* QA+1 */
+ a32_QA1[d - k - 1] = Qtmp - Ptmp;
+ /* QA+1 */
+ }
+
+ /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */
+ for (i = 0; i < 10; i++) {
+ /* Find maximum absolute value and its index */
+ maxabs = 0;
+ for (k = 0; k < d; k++) {
+ absval = Inlines.silk_abs(a32_QA1[k]);
+ if (absval > maxabs) {
+ maxabs = absval;
+ idx = k;
+ }
+ }
+
+ maxabs = Inlines.silk_RSHIFT_ROUND(maxabs, QA + 1 - 12);
+ /* QA+1 . Q12 */
+
+ if (maxabs > Short.MAX_VALUE) {
+ /* Reduce magnitude of prediction coefficients */
+ maxabs = Inlines.silk_min(maxabs, 163838);
+ /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */
+ sc_Q16 = ((int) ((0.999f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.999f, 16)*/ - Inlines.silk_DIV32(Inlines.silk_LSHIFT(maxabs - Short.MAX_VALUE, 14),
+ Inlines.silk_RSHIFT32(Inlines.silk_MUL(maxabs, idx + 1), 2));
+ Filters.silk_bwexpander_32(a32_QA1, d, sc_Q16);
+ } else {
+ break;
+ }
+ }
+
+ if (i == 10) {
+ /* Reached the last iteration, clip the coefficients */
+ for (k = 0; k < d; k++) {
+ a_Q12[k] = (short) Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a32_QA1[k], QA + 1 - 12));
+ /* QA+1 . Q12 */
+ a32_QA1[k] = Inlines.silk_LSHIFT((int) a_Q12[k], QA + 1 - 12);
+ }
+ } else {
+ for (k = 0; k < d; k++) {
+ a_Q12[k] = (short) Inlines.silk_RSHIFT_ROUND(a32_QA1[k], QA + 1 - 12);
+ /* QA+1 . Q12 */
+ }
+ }
+
+ for (i = 0; i < SilkConstants.MAX_LPC_STABILIZE_ITERATIONS; i++) {
+ if (Filters.silk_LPC_inverse_pred_gain(a_Q12, d) < ((int) ((1.0f / SilkConstants.MAX_PREDICTION_POWER_GAIN) * ((long) 1 << (30)) + 0.5))/*Inlines.SILK_CONST(1.0f / SilkConstants.MAX_PREDICTION_POWER_GAIN, 30)*/) {
+ /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */
+ /* on the unscaled coefficients, convert to Q12 and measure again */
+ Filters.silk_bwexpander_32(a32_QA1, d, 65536 - Inlines.silk_LSHIFT(2, i));
+
+ for (k = 0; k < d; k++) {
+ a_Q12[k] = (short) Inlines.silk_RSHIFT_ROUND(a32_QA1[k], QA + 1 - 12);
+ /* QA+1 . Q12 */
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Helper function for A2NLSF(..) Transforms polynomials from cos(n*f) to cos(f)^n
+ ///
+ /// (I/O) Polynomial
+ /// (I) Polynomial order (= filter order / 2 )
+ static void silk_A2NLSF_trans_poly(int[] p, int dd) {
+ int k, n;
+
+ for (k = 2; k <= dd; k++) {
+ for (n = dd; n > k; n--) {
+ p[n - 2] -= p[n];
+ }
+ p[k - 2] -= Inlines.silk_LSHIFT(p[k], 1);
+ }
+ }
+
+ ///
+ /// Helper function for A2NLSF(..) Polynomial evaluation
+ ///
+ /// (I) Polynomial, Q16
+ /// (I) Evaluation point, Q12
+ /// (I) Order
+ /// the polynomial evaluation, in Q16
+ static int silk_A2NLSF_eval_poly(int[] p, int x, int dd) {
+ int n;
+ int x_Q16, y32;
+
+ y32 = p[dd];
+ /* Q16 */
+ x_Q16 = Inlines.silk_LSHIFT(x, 4);
+
+ if (8 == dd) {
+ y32 = Inlines.silk_SMLAWW(p[7], y32, x_Q16);
+ y32 = Inlines.silk_SMLAWW(p[6], y32, x_Q16);
+ y32 = Inlines.silk_SMLAWW(p[5], y32, x_Q16);
+ y32 = Inlines.silk_SMLAWW(p[4], y32, x_Q16);
+ y32 = Inlines.silk_SMLAWW(p[3], y32, x_Q16);
+ y32 = Inlines.silk_SMLAWW(p[2], y32, x_Q16);
+ y32 = Inlines.silk_SMLAWW(p[1], y32, x_Q16);
+ y32 = Inlines.silk_SMLAWW(p[0], y32, x_Q16);
+ } else {
+ for (n = dd - 1; n >= 0; n--) {
+ y32 = Inlines.silk_SMLAWW(p[n], y32, x_Q16);
+ /* Q16 */
+ }
+ }
+
+ return y32;
+ }
+
+ static void silk_A2NLSF_init(
+ int[] a_Q16,
+ int[] P,
+ int[] Q,
+ int dd) {
+ int k;
+
+ /* Convert filter coefs to even and odd polynomials */
+ P[dd] = Inlines.silk_LSHIFT(1, 16);
+ Q[dd] = Inlines.silk_LSHIFT(1, 16);
+ for (k = 0; k < dd; k++) {
+ P[k] = -a_Q16[dd - k - 1] - a_Q16[dd + k];
+ /* Q16 */
+ Q[k] = -a_Q16[dd - k - 1] + a_Q16[dd + k];
+ /* Q16 */
+ }
+
+ /* Divide out zeros as we have that for even filter orders, */
+ /* z = 1 is always a root in Q, and */
+ /* z = -1 is always a root in P */
+ for (k = dd; k > 0; k--) {
+ P[k - 1] -= P[k];
+ Q[k - 1] += Q[k];
+ }
+
+ /* Transform polynomials from cos(n*f) to cos(f)^n */
+ silk_A2NLSF_trans_poly(P, dd);
+ silk_A2NLSF_trans_poly(Q, dd);
+ }
+
+ ///
+ /// Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients
+ /// If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence.
+ ///
+ /// (O) Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d]
+ /// (I/O) Monic whitening filter coefficients in Q16 [d]
+ /// (I) Filter order (must be even)
+ static void silk_A2NLSF(short[] NLSF, int[] a_Q16, int d) {
+ int i, k, m, dd, root_ix, ffrac;
+ int xlo, xhi, xmid;
+ int ylo, yhi, ymid, thr;
+ int nom, den;
+ int[] P = new int[SilkConstants.SILK_MAX_ORDER_LPC / 2 + 1];
+ int[] Q = new int[SilkConstants.SILK_MAX_ORDER_LPC / 2 + 1];
+ int[][] PQ = new int[2][];
+ int[] p;
+
+ /* Store pointers to array */
+ PQ[0] = P;
+ PQ[1] = Q;
+
+ dd = Inlines.silk_RSHIFT(d, 1);
+
+ silk_A2NLSF_init(a_Q16, P, Q, dd);
+
+ /* Find roots, alternating between P and Q */
+ p = P;
+ /* Pointer to polynomial */
+
+ xlo = SilkTables.silk_LSFCosTab_Q12[0];
+ /* Q12*/
+ ylo = silk_A2NLSF_eval_poly(p, xlo, dd);
+
+ if (ylo < 0) {
+ /* Set the first NLSF to zero and move on to the next */
+ NLSF[0] = 0;
+ p = Q;
+ /* Pointer to polynomial */
+ ylo = silk_A2NLSF_eval_poly(p, xlo, dd);
+ root_ix = 1;
+ /* Index of current root */
+ } else {
+ root_ix = 0;
+ /* Index of current root */
+ }
+ k = 1;
+ /* Loop counter */
+ i = 0;
+ /* Counter for bandwidth expansions applied */
+ thr = 0;
+ while (true) {
+ /* Evaluate polynomial */
+ xhi = SilkTables.silk_LSFCosTab_Q12[k];
+ /* Q12 */
+ yhi = silk_A2NLSF_eval_poly(p, xhi, dd);
+
+ /* Detect zero crossing */
+ if ((ylo <= 0 && yhi >= thr) || (ylo >= 0 && yhi <= -thr)) {
+ if (yhi == 0) {
+ /* If the root lies exactly at the end of the current */
+ /* interval, look for the next root in the next interval */
+ thr = 1;
+ } else {
+ thr = 0;
+ }
+ /* Binary division */
+ ffrac = -256;
+ for (m = 0; m < BIN_DIV_STEPS_A2NLSF; m++) {
+ /* Evaluate polynomial */
+ xmid = Inlines.silk_RSHIFT_ROUND(xlo + xhi, 1);
+ ymid = silk_A2NLSF_eval_poly(p, xmid, dd);
+
+ /* Detect zero crossing */
+ if ((ylo <= 0 && ymid >= 0) || (ylo >= 0 && ymid <= 0)) {
+ /* Reduce frequency */
+ xhi = xmid;
+ yhi = ymid;
+ } else {
+ /* Increase frequency */
+ xlo = xmid;
+ ylo = ymid;
+ ffrac = Inlines.silk_ADD_RSHIFT(ffrac, 128, m);
+ }
+ }
+
+ /* Interpolate */
+ if (Inlines.silk_abs(ylo) < 65536) {
+ /* Avoid dividing by zero */
+ den = ylo - yhi;
+ nom = Inlines.silk_LSHIFT(ylo, 8 - BIN_DIV_STEPS_A2NLSF) + Inlines.silk_RSHIFT(den, 1);
+ if (den != 0) {
+ ffrac += Inlines.silk_DIV32(nom, den);
+ }
+ } else {
+ /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */
+ ffrac += Inlines.silk_DIV32(ylo, Inlines.silk_RSHIFT(ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF));
+ }
+ NLSF[root_ix] = (short) Inlines.silk_min_32(Inlines.silk_LSHIFT((int) k, 8) + ffrac, Short.MAX_VALUE);
+
+ Inlines.OpusAssert(NLSF[root_ix] >= 0);
+
+ root_ix++;
+ /* Next root */
+ if (root_ix >= d) {
+ /* Found all roots */
+ break;
+ }
+
+ /* Alternate pointer to polynomial */
+ p = PQ[root_ix & 1];
+
+ /* Evaluate polynomial */
+ xlo = SilkTables.silk_LSFCosTab_Q12[k - 1];
+ /* Q12*/
+ ylo = Inlines.silk_LSHIFT(1 - (root_ix & 2), 12);
+ } else {
+ /* Increment loop counter */
+ k++;
+ xlo = xhi;
+ ylo = yhi;
+ thr = 0;
+
+ if (k > SilkConstants.LSF_COS_TAB_SZ) {
+ i++;
+ if (i > MAX_ITERATIONS_A2NLSF) {
+ /* Set NLSFs to white spectrum and exit */
+ NLSF[0] = (short) Inlines.silk_DIV32_16(1 << 15, (short) (d + 1));
+ for (k = 1; k < d; k++) {
+ NLSF[k] = (short) Inlines.silk_SMULBB(k + 1, NLSF[0]);
+ }
+ return;
+ }
+
+ /* Error: Apply progressively more bandwidth expansion and run again */
+ Filters.silk_bwexpander_32(a_Q16, d, 65536 - Inlines.silk_SMULBB(10 + i, i));
+ /* 10_Q16 = 0.00015*/
+
+ silk_A2NLSF_init(a_Q16, P, Q, dd);
+ p = P;
+ /* Pointer to polynomial */
+ xlo = SilkTables.silk_LSFCosTab_Q12[0];
+ /* Q12*/
+ ylo = silk_A2NLSF_eval_poly(p, xlo, dd);
+ if (ylo < 0) {
+ /* Set the first NLSF to zero and move on to the next */
+ NLSF[0] = 0;
+ p = Q;
+ /* Pointer to polynomial */
+ ylo = silk_A2NLSF_eval_poly(p, xlo, dd);
+ root_ix = 1;
+ /* Index of current root */
+ } else {
+ root_ix = 0;
+ /* Index of current root */
+ }
+ k = 1;
+ /* Reset loop counter */
+ }
+ }
+ }
+ }
+
+ ///
+ /// Limit, stabilize, convert and quantize NLSFs
+ ///
+ /// I/O Encoder state
+ /// O Prediction coefficients [ 2 ][MAX_LPC_ORDER]
+ /// I/O Normalized LSFs (quant out) (0 - (2^15-1)) [MAX_LPC_ORDER]
+ /// I Previous Normalized LSFs (0 - (2^15-1)) [MAX_LPC_ORDER]
+ static void silk_process_NLSFs(
+ SilkChannelEncoder psEncC,
+ short[][] PredCoef_Q12,
+ short[] pNLSF_Q15,
+ short[] prev_NLSFq_Q15) {
+ int i;
+ boolean doInterpolate;
+ int NLSF_mu_Q20;
+ int i_sqr_Q15;
+ short[] pNLSF0_temp_Q15 = new short[SilkConstants.MAX_LPC_ORDER];
+ short[] pNLSFW_QW = new short[SilkConstants.MAX_LPC_ORDER];
+ short[] pNLSFW0_temp_QW = new short[SilkConstants.MAX_LPC_ORDER];
+
+ Inlines.OpusAssert(psEncC.speech_activity_Q8 >= 0);
+ Inlines.OpusAssert(psEncC.speech_activity_Q8 <= ((int) ((1.0f) * ((long) 1 << (8)) + 0.5))/*Inlines.SILK_CONST(1.0f, 8)*/);
+ Inlines.OpusAssert(psEncC.useInterpolatedNLSFs == 1 || psEncC.indices.NLSFInterpCoef_Q2 == (1 << 2));
+
+ /**
+ * ********************
+ */
+ /* Calculate mu values */
+ /**
+ * ********************
+ */
+ /* NLSF_mu = 0.003 - 0.0015 * psEnc.speech_activity; */
+ NLSF_mu_Q20 = Inlines.silk_SMLAWB(((int) ((0.003f) * ((long) 1 << (20)) + 0.5))/*Inlines.SILK_CONST(0.003f, 20)*/, ((int) ((-0.001f) * ((long) 1 << (28)) + 0.5))/*Inlines.SILK_CONST(-0.001f, 28)*/, psEncC.speech_activity_Q8);
+ if (psEncC.nb_subfr == 2) {
+ /* Multiply by 1.5 for 10 ms packets */
+ NLSF_mu_Q20 = Inlines.silk_ADD_RSHIFT(NLSF_mu_Q20, NLSF_mu_Q20, 1);
+ }
+
+ Inlines.OpusAssert(NLSF_mu_Q20 > 0);
+ Inlines.OpusAssert(NLSF_mu_Q20 <= ((int) ((0.005f) * ((long) 1 << (20)) + 0.5))/*Inlines.SILK_CONST(0.005f, 20)*/);
+
+ /* Calculate NLSF weights */
+ silk_NLSF_VQ_weights_laroia(pNLSFW_QW, pNLSF_Q15, psEncC.predictLPCOrder);
+
+ /* Update NLSF weights for interpolated NLSFs */
+ doInterpolate = (psEncC.useInterpolatedNLSFs == 1) && (psEncC.indices.NLSFInterpCoef_Q2 < 4);
+ if (doInterpolate) {
+ /* Calculate the interpolated NLSF vector for the first half */
+ Inlines.silk_interpolate(pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+ psEncC.indices.NLSFInterpCoef_Q2, psEncC.predictLPCOrder);
+
+ /* Calculate first half NLSF weights for the interpolated NLSFs */
+ silk_NLSF_VQ_weights_laroia(pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC.predictLPCOrder);
+
+ /* Update NLSF weights with contribution from first half */
+ i_sqr_Q15 = Inlines.silk_LSHIFT(Inlines.silk_SMULBB(psEncC.indices.NLSFInterpCoef_Q2, psEncC.indices.NLSFInterpCoef_Q2), 11);
+
+ for (i = 0; i < psEncC.predictLPCOrder; i++) {
+ pNLSFW_QW[i] = (short) (Inlines.silk_SMLAWB(Inlines.silk_RSHIFT(pNLSFW_QW[i], 1), (int) pNLSFW0_temp_QW[i], i_sqr_Q15));
+ Inlines.OpusAssert(pNLSFW_QW[i] >= 1);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ silk_NLSF_encode(psEncC.indices.NLSFIndices, pNLSF_Q15, psEncC.psNLSF_CB, pNLSFW_QW,
+ NLSF_mu_Q20, psEncC.NLSF_MSVQ_Survivors, psEncC.indices.signalType);
+
+ /* Convert quantized NLSFs back to LPC coefficients */
+ silk_NLSF2A(PredCoef_Q12[1], pNLSF_Q15, psEncC.predictLPCOrder);
+
+ if (doInterpolate) {
+ /* Calculate the interpolated, quantized LSF vector for the first half */
+ Inlines.silk_interpolate(pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+ psEncC.indices.NLSFInterpCoef_Q2, psEncC.predictLPCOrder);
+
+ /* Convert back to LPC coefficients */
+ silk_NLSF2A(PredCoef_Q12[0], pNLSF0_temp_Q15, psEncC.predictLPCOrder);
+
+ } else {
+ /* Copy LPC coefficients for first half from second half */
+ System.arraycopy(PredCoef_Q12[1], 0, PredCoef_Q12[0], 0, psEncC.predictLPCOrder);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/NLSFCodebook.java b/app/src/main/java/org/concentus/NLSFCodebook.java
new file mode 100644
index 0000000000..ff1146a308
--- /dev/null
+++ b/app/src/main/java/org/concentus/NLSFCodebook.java
@@ -0,0 +1,101 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Structure containing NLSF codebook
+///
+class NLSFCodebook {
+
+ short nVectors = 0;
+
+ short order = 0;
+
+ ///
+ /// Quantization step size
+ ///
+ short quantStepSize_Q16 = 0;
+
+ ///
+ /// Inverse quantization step size
+ ///
+ short invQuantStepSize_Q6 = 0;
+
+ ///
+ /// POINTER
+ ///
+ short[] CB1_NLSF_Q8 = null;
+
+ ///
+ /// POINTER
+ ///
+ short[] CB1_iCDF = null;
+
+ ///
+ /// POINTER to Backward predictor coefs [ order ]
+ ///
+ short[] pred_Q8 = null;
+
+ ///
+ /// POINTER to Indices to entropy coding tables [ order ]
+ ///
+ short[] ec_sel = null;
+
+ ///
+ /// POINTER
+ ///
+ short[] ec_iCDF = null;
+
+ ///
+ /// POINTER
+ ///
+ short[] ec_Rates_Q5 = null;
+
+ ///
+ /// POINTER
+ ///
+ short[] deltaMin_Q15 = null;
+
+ 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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/NoiseShapeAnalysis.java b/app/src/main/java/org/concentus/NoiseShapeAnalysis.java
new file mode 100644
index 0000000000..fe108e2fc7
--- /dev/null
+++ b/app/src/main/java/org/concentus/NoiseShapeAnalysis.java
@@ -0,0 +1,491 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+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. */
+ 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 */
+ 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 */
+ /**
+ * ***********************************************************
+ */
+ 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;
+ BoxedValueInt boxed_nrg = new BoxedValueInt(0);
+ BoxedValueInt boxed_scale = new BoxedValueInt(0);
+ for (k = 0; k < Inlines.silk_SMULBB(SilkConstants.SUB_FRAME_LENGTH_MS, psEnc.nb_subfr) / 2; k++) {
+ SumSqrShift.silk_sum_sqr_shift(boxed_nrg, boxed_scale, pitch_res, pitch_res_ptr2, nSamples);
+ nrg = boxed_nrg.Val;
+ scale = boxed_scale.Val;
+ 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;
+ System.arraycopy(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) >= (Integer.MAX_VALUE >> 1)) {
+ psEncCtrl.Gains_Q16[k] = Integer.MAX_VALUE;
+ } 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 */
+ System.arraycopy(AR2_Q24, 0, AR1_Q24, 0, 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;
+ }
+ 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;
+ 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);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusApplication.java b/app/src/main/java/org/concentus/OpusApplication.java
new file mode 100644
index 0000000000..c2448f96d3
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusApplication.java
@@ -0,0 +1,51 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public enum OpusApplication {
+ OPUS_APPLICATION_UNIMPLEMENTED,
+ ///
+ /// Best for most VoIP/videoconference applications where listening quality and intelligibility matter most
+ ///
+ OPUS_APPLICATION_VOIP,
+ ///
+ /// Best for broadcast/high-fidelity application where the decoded audio should be as close as possible to the input
+ ///
+ OPUS_APPLICATION_AUDIO,
+ ///
+ /// Only use when lowest-achievable latency is what matters most. Voice-optimized modes cannot be used.
+ ///
+ OPUS_APPLICATION_RESTRICTED_LOWDELAY
+}
diff --git a/app/src/main/java/org/concentus/OpusBandwidth.java b/app/src/main/java/org/concentus/OpusBandwidth.java
new file mode 100644
index 0000000000..a294f0cdff
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusBandwidth.java
@@ -0,0 +1,101 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public enum OpusBandwidth {
+ OPUS_BANDWIDTH_UNKNOWN,
+ OPUS_BANDWIDTH_AUTO,
+ OPUS_BANDWIDTH_NARROWBAND,
+ OPUS_BANDWIDTH_MEDIUMBAND,
+ OPUS_BANDWIDTH_WIDEBAND,
+ OPUS_BANDWIDTH_SUPERWIDEBAND,
+ OPUS_BANDWIDTH_FULLBAND
+}
+
+// Helpers to port over uses of OpusBandwidth as an integer
+class OpusBandwidthHelpers {
+
+ static int GetOrdinal(OpusBandwidth bw) {
+ switch (bw) {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ return 1;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ return 2;
+ case OPUS_BANDWIDTH_WIDEBAND:
+ return 3;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ return 4;
+ case OPUS_BANDWIDTH_FULLBAND:
+ return 5;
+ }
+
+ return -1;
+ }
+
+ static OpusBandwidth GetBandwidth(int ordinal) {
+ switch (ordinal) {
+ case 1:
+ return OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
+ case 2:
+ return OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND;
+ case 3:
+ return OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND;
+ case 4:
+ return OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND;
+ case 5:
+ return OpusBandwidth.OPUS_BANDWIDTH_FULLBAND;
+ }
+
+ return OpusBandwidth.OPUS_BANDWIDTH_AUTO;
+ }
+
+ static OpusBandwidth MIN(OpusBandwidth a, OpusBandwidth b) {
+ if (GetOrdinal(a) < GetOrdinal(b)) {
+ return a;
+ }
+ return b;
+ }
+
+ static OpusBandwidth MAX(OpusBandwidth a, OpusBandwidth b) {
+ if (GetOrdinal(a) > GetOrdinal(b)) {
+ return a;
+ }
+ return b;
+ }
+
+ static OpusBandwidth SUBTRACT(OpusBandwidth a, int b) {
+ return GetBandwidth(GetOrdinal(a) - b);
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusConstants.java b/app/src/main/java/org/concentus/OpusConstants.java
new file mode 100644
index 0000000000..8154a473e3
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusConstants.java
@@ -0,0 +1,59 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public class OpusConstants {
+
+ ///
+ /// Auto/default setting
+ ///
+ public static final int OPUS_AUTO = -1000;
+
+ ///
+ /// Maximum bitrate
+ ///
+ public static final int OPUS_BITRATE_MAX = -1;
+
+ // from analysis.c
+ public static final int NB_FRAMES = 8;
+ public static final int NB_TBANDS = 18;
+ public static final int NB_TOT_BANDS = 21;
+ public static final int NB_TONAL_SKIP_BANDS = 9;
+ public static final int ANALYSIS_BUF_SIZE = 720;
+ /* 15 ms at 48 kHz */
+ public static final int DETECT_SIZE = 200;
+
+ public static final int MAX_ENCODER_BUFFER = 480;
+}
diff --git a/app/src/main/java/org/concentus/OpusDecoder.java b/app/src/main/java/org/concentus/OpusDecoder.java
new file mode 100644
index 0000000000..d97258a5e7
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusDecoder.java
@@ -0,0 +1,784 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+/**
+ * The Opus decoder structure.
+ *
+ * Opus is a stateful codec with overlapping blocks and as a result Opus
+ * packets are not coded independently of each other. Packets must be
+ * passed into the decoder serially and in the correct order for a correct
+ * decode. Lost packets can be replaced with loss concealment by calling
+ * the decoder with a null reference and zero length for the missing packet.
+ *
+ * A single codec state may only be accessed from a single thread at
+ * a time and any required locking must be performed by the caller. Separate
+ * streams must be decoded with separate decoder states and can be decoded
+ * in parallel.
+ */
+public class OpusDecoder {
+
+ int channels;
+ int Fs;
+ /**
+ * Sampling rate (at the API level)
+ */
+ final DecControlState DecControl = new DecControlState();
+ int decode_gain;
+
+ /* Everything beyond this point gets cleared on a reset */
+ int stream_channels;
+ OpusBandwidth bandwidth;
+ OpusMode mode;
+ OpusMode prev_mode;
+ int frame_size;
+ int prev_redundancy;
+ int last_packet_duration;
+ int rangeFinal;
+ SilkDecoder SilkDecoder = new SilkDecoder();
+ CeltDecoder Celt_Decoder = new CeltDecoder();
+
+ OpusDecoder() {
+ } // used internally
+
+ void reset() {
+ channels = 0;
+ Fs = 0;
+ /**
+ * Sampling rate (at the API level)
+ */
+ DecControl.Reset();
+ decode_gain = 0;
+ partialReset();
+ }
+
+ ///
+ /// OPUS_DECODER_RESET_START
+ ///
+ void partialReset() {
+ stream_channels = 0;
+ bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN;
+ mode = OpusMode.MODE_UNKNOWN;
+ prev_mode = OpusMode.MODE_UNKNOWN;
+ frame_size = 0;
+ prev_redundancy = 0;
+ last_packet_duration = 0;
+ rangeFinal = 0;
+ // fixme: do these get reset here? I don't think they do because init_celt and init_silk should both call RESET_STATE on their respective states
+ //SilkDecoder.Reset();
+ //CeltDecoder.Reset();
+ }
+
+ int opus_decoder_init(int Fs, int channels) {
+ SilkDecoder silk_dec;
+ CeltDecoder celt_dec;
+ int ret;
+
+ if ((Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000)
+ || (channels != 1 && channels != 2)) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ this.reset();
+
+ /* Initialize SILK encoder */
+ silk_dec = this.SilkDecoder;
+ celt_dec = this.Celt_Decoder;
+ this.stream_channels = this.channels = channels;
+
+ this.Fs = Fs;
+ this.DecControl.API_sampleRate = this.Fs;
+ this.DecControl.nChannelsAPI = this.channels;
+
+ /* Reset decoder */
+ ret = DecodeAPI.silk_InitDecoder(silk_dec);
+ if (ret != 0) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+
+ /* Initialize CELT decoder */
+ ret = celt_dec.celt_decoder_init(Fs, channels);
+ if (ret != OpusError.OPUS_OK) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+
+ celt_dec.SetSignalling(0);
+
+ this.prev_mode = OpusMode.MODE_UNKNOWN;
+ this.frame_size = Fs / 400;
+ return OpusError.OPUS_OK;
+ }
+
+ /**
+ * Allocates and initializes a decoder state. Internally Opus stores data at
+ * 48000 Hz, so that should be the default value for Fs. However, the
+ * decoder can efficiently decode to buffers at 8, 12, 16, and 24 kHz so if
+ * for some reason the caller cannot use data at the full sample rate, or
+ * knows the compressed data doesn't use the full frequency range, it can
+ * request decoding at a reduced rate. Likewise, the decoder is capable of
+ * filling in either mono or interleaved stereo pcm buffers, at the caller's
+ * request.
+ *
+ * @param Fs Sample rate to decode at (Hz). This must be one of 8000, 12000,
+ * 16000, 24000, or 48000.
+ * @param channels Number of channels (1 or 2) to decode.
+ * @throws OpusException
+ */
+ public OpusDecoder(int Fs, int channels) throws OpusException {
+ int ret;
+ if ((Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000)) {
+ throw new IllegalArgumentException("Sample rate is invalid (must be 8/12/16/24/48 Khz)");
+ }
+ if (channels != 1 && channels != 2) {
+ throw new IllegalArgumentException("Number of channels must be 1 or 2");
+ }
+
+ ret = this.opus_decoder_init(Fs, channels);
+ if (ret != OpusError.OPUS_OK) {
+ if (ret == OpusError.OPUS_BAD_ARG) {
+ throw new IllegalArgumentException("OPUS_BAD_ARG when creating decoder");
+ }
+ throw new OpusException("Error while initializing decoder", ret);
+ }
+ }
+
+ private static final byte[] SILENCE = new byte[]{-1, -1};
+
+ int opus_decode_frame(byte[] data, int data_ptr,
+ int len, short[] pcm, int pcm_ptr, int frame_size, int decode_fec) {
+ SilkDecoder silk_dec;
+ CeltDecoder celt_dec;
+ int i, silk_ret = 0, celt_ret = 0;
+ EntropyCoder dec = new EntropyCoder(); // porting note: stack var
+ int silk_frame_size;
+ int pcm_silk_size;
+ short[] pcm_silk;
+ int pcm_transition_silk_size;
+ short[] pcm_transition_silk;
+ int pcm_transition_celt_size;
+ short[] pcm_transition_celt;
+ short[] pcm_transition = null;
+ int redundant_audio_size;
+ short[] redundant_audio;
+
+ int audiosize;
+ OpusMode mode;
+ int transition = 0;
+ int start_band;
+ int redundancy = 0;
+ int redundancy_bytes = 0;
+ int celt_to_silk = 0;
+ int c;
+ int F2_5, F5, F10, F20;
+ int[] window;
+ int redundant_rng = 0;
+ int celt_accum;
+
+ silk_dec = this.SilkDecoder;
+ celt_dec = this.Celt_Decoder;
+ F20 = this.Fs / 50;
+ F10 = F20 >> 1;
+ F5 = F10 >> 1;
+ F2_5 = F5 >> 1;
+ if (frame_size < F2_5) {
+
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+ /* Limit frame_size to avoid excessive stack allocations. */
+ frame_size = Inlines.IMIN(frame_size, this.Fs / 25 * 3);
+ /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
+ if (len <= 1) {
+ data = null;
+ /* In that case, don't conceal more than what the ToC says */
+ frame_size = Inlines.IMIN(frame_size, this.frame_size);
+ }
+ if (data != null) {
+ audiosize = this.frame_size;
+ mode = this.mode;
+ dec.dec_init(data, data_ptr, len);
+ } else {
+ audiosize = frame_size;
+ mode = this.prev_mode;
+
+ if (mode == OpusMode.MODE_UNKNOWN) {
+ /* If we haven't got any packet yet, all we can do is return zeros */
+ for (i = pcm_ptr; i < pcm_ptr + (audiosize * this.channels); i++) {
+ pcm[i] = 0;
+ }
+
+ return audiosize;
+ }
+
+ /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT),
+ 10, or 20 (e.g. 12.5 or 30 ms). */
+ if (audiosize > F20) {
+ do {
+ int ret = opus_decode_frame(null, 0, 0, pcm, pcm_ptr, Inlines.IMIN(audiosize, F20), 0);
+ if (ret < 0) {
+
+ return ret;
+ }
+ pcm_ptr += ret * this.channels;
+ audiosize -= ret;
+ } while (audiosize > 0);
+
+ return frame_size;
+ } else if (audiosize < F20) {
+ if (audiosize > F10) {
+ audiosize = F10;
+ } else if (mode != OpusMode.MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) {
+ audiosize = F5;
+ }
+ }
+ }
+
+ /* In fixed-point, we can tell CELT to do the accumulation on top of the
+ SILK PCM buffer. This saves some stack space. */
+ celt_accum = ((mode != OpusMode.MODE_CELT_ONLY) && (frame_size >= F10)) ? 1 : 0;
+
+ pcm_transition_silk_size = 0;
+ pcm_transition_celt_size = 0;
+ if (data != null && (this.prev_mode != OpusMode.MODE_UNKNOWN && this.prev_mode != OpusMode.MODE_AUTO) && ((mode == OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY && (this.prev_redundancy == 0))
+ || (mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY))) {
+ transition = 1;
+ /* Decide where to allocate the stack memory for pcm_transition */
+ if (mode == OpusMode.MODE_CELT_ONLY) {
+ pcm_transition_celt_size = F5 * this.channels;
+ } else {
+ pcm_transition_silk_size = F5 * this.channels;
+ }
+ }
+ pcm_transition_celt = new short[pcm_transition_celt_size];
+ if (transition != 0 && mode == OpusMode.MODE_CELT_ONLY) {
+ pcm_transition = pcm_transition_celt;
+ opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0);
+ }
+ if (audiosize > frame_size) {
+ /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/
+
+ return OpusError.OPUS_BAD_ARG;
+ } else {
+ frame_size = audiosize;
+ }
+
+ /* Don't allocate any memory when in CELT-only mode */
+ pcm_silk_size = (mode != OpusMode.MODE_CELT_ONLY && (celt_accum == 0)) ? Inlines.IMAX(F10, frame_size) * this.channels : 0;
+ pcm_silk = new short[pcm_silk_size];
+
+ /* SILK processing */
+ if (mode != OpusMode.MODE_CELT_ONLY) {
+ int lost_flag, decoded_samples;
+ short[] pcm_ptr2;
+ int pcm_ptr2_ptr = 0;
+
+ if (celt_accum != 0) {
+ pcm_ptr2 = pcm;
+ pcm_ptr2_ptr = pcm_ptr;
+ } else {
+ pcm_ptr2 = pcm_silk;
+ pcm_ptr2_ptr = 0;
+ }
+
+ if (this.prev_mode == OpusMode.MODE_CELT_ONLY) {
+ DecodeAPI.silk_InitDecoder(silk_dec);
+ }
+
+ /* The SILK PLC cannot produce frames of less than 10 ms */
+ this.DecControl.payloadSize_ms = Inlines.IMAX(10, 1000 * audiosize / this.Fs);
+
+ if (data != null) {
+ this.DecControl.nChannelsInternal = this.stream_channels;
+ if (mode == OpusMode.MODE_SILK_ONLY) {
+ if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) {
+ this.DecControl.internalSampleRate = 8000;
+ } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) {
+ this.DecControl.internalSampleRate = 12000;
+ } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) {
+ this.DecControl.internalSampleRate = 16000;
+ } else {
+ this.DecControl.internalSampleRate = 16000;
+ Inlines.OpusAssert(false);
+ }
+ } else {
+ /* Hybrid mode */
+ this.DecControl.internalSampleRate = 16000;
+ }
+ }
+
+ lost_flag = data == null ? 1 : 2 * decode_fec;
+ decoded_samples = 0;
+ do {
+ /* Call SILK decoder */
+ int first_frame = (decoded_samples == 0) ? 1 : 0;
+ BoxedValueInt boxed_silk_frame_size = new BoxedValueInt(0);
+ silk_ret = DecodeAPI.silk_Decode(silk_dec, this.DecControl,
+ lost_flag, first_frame, dec, pcm_ptr2, pcm_ptr2_ptr, boxed_silk_frame_size);
+ silk_frame_size = boxed_silk_frame_size.Val;
+
+ if (silk_ret != 0) {
+ if (lost_flag != 0) {
+ /* PLC failure should not be fatal */
+ silk_frame_size = frame_size;
+ Arrays.MemSetWithOffset(pcm_ptr2, (short) 0, pcm_ptr2_ptr, frame_size * this.channels);
+ } else {
+
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ }
+ pcm_ptr2_ptr += (silk_frame_size * this.channels);
+ decoded_samples += silk_frame_size;
+ } while (decoded_samples < frame_size);
+ }
+
+ start_band = 0;
+ if (decode_fec == 0 && mode != OpusMode.MODE_CELT_ONLY && data != null
+ && dec.tell() + 17 + 20 * (this.mode == OpusMode.MODE_HYBRID ? 1 : 0) <= 8 * len) {
+ /* Check if we have a redundant 0-8 kHz band */
+ if (mode == OpusMode.MODE_HYBRID) {
+ redundancy = dec.dec_bit_logp(12);
+ } else {
+ redundancy = 1;
+ }
+ if (redundancy != 0) {
+ celt_to_silk = dec.dec_bit_logp(1);
+ /* redundancy_bytes will be at least two, in the non-hybrid
+ case due to the ec_tell() check above */
+ redundancy_bytes = mode == OpusMode.MODE_HYBRID
+ ? (int) dec.dec_uint(256) + 2
+ : len - ((dec.tell() + 7) >> 3);
+ len -= redundancy_bytes;
+ /* This is a sanity check. It should never happen for a valid
+ packet, so the exact behaviour is not normative. */
+ if (len * 8 < dec.tell()) {
+ len = 0;
+ redundancy_bytes = 0;
+ redundancy = 0;
+ }
+ /* Shrink decoder because of raw bits */
+ dec.storage = (dec.storage - redundancy_bytes);
+ }
+ }
+ if (mode != OpusMode.MODE_CELT_ONLY) {
+ start_band = 17;
+ }
+
+ {
+ int endband = 21;
+
+ switch (this.bandwidth) {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ endband = 13;
+ break;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ case OPUS_BANDWIDTH_WIDEBAND:
+ endband = 17;
+ break;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ endband = 19;
+ break;
+ case OPUS_BANDWIDTH_FULLBAND:
+ endband = 21;
+ break;
+ }
+ celt_dec.SetEndBand(endband);
+ celt_dec.SetChannels(this.stream_channels);
+ }
+
+ if (redundancy != 0) {
+ transition = 0;
+ pcm_transition_silk_size = 0;
+ }
+
+ pcm_transition_silk = new short[pcm_transition_silk_size];
+
+ if (transition != 0 && mode != OpusMode.MODE_CELT_ONLY) {
+ pcm_transition = pcm_transition_silk;
+ opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0);
+ }
+
+ /* Only allocation memory for redundancy if/when needed */
+ redundant_audio_size = redundancy != 0 ? F5 * this.channels : 0;
+ redundant_audio = new short[redundant_audio_size];
+
+ /* 5 ms redundant frame for CELT->SILK*/
+ if (redundancy != 0 && celt_to_silk != 0) {
+ celt_dec.SetStartBand(0);
+ celt_dec.celt_decode_with_ec(data, (data_ptr + len), redundancy_bytes,
+ redundant_audio, 0, F5, null, 0);
+ redundant_rng = celt_dec.GetFinalRange();
+ }
+
+ /* MUST be after PLC */
+ celt_dec.SetStartBand(start_band);
+
+ if (mode != OpusMode.MODE_SILK_ONLY) {
+ int celt_frame_size = Inlines.IMIN(F20, frame_size);
+ /* Make sure to discard any previous CELT state */
+ if (mode != this.prev_mode && (this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN) && this.prev_redundancy == 0) {
+ celt_dec.ResetState();
+ }
+ /* Decode CELT */
+ celt_ret = celt_dec.celt_decode_with_ec(decode_fec != 0 ? null : data, data_ptr,
+ len, pcm, pcm_ptr, celt_frame_size, dec, celt_accum);
+ } else {
+ if (celt_accum == 0) {
+ for (i = pcm_ptr; i < (frame_size * this.channels) + pcm_ptr; i++) {
+ pcm[i] = 0;
+ }
+ }
+ /* For hybrid -> SILK transitions, we let the CELT MDCT
+ do a fade-out by decoding a silence frame */
+ if (this.prev_mode == OpusMode.MODE_HYBRID && !(redundancy != 0 && celt_to_silk != 0 && this.prev_redundancy != 0)) {
+ celt_dec.SetStartBand(0);
+ celt_dec.celt_decode_with_ec(SILENCE, 0, 2, pcm, pcm_ptr, F2_5, null, celt_accum);
+ }
+ }
+
+ if (mode != OpusMode.MODE_CELT_ONLY && celt_accum == 0) {
+ for (i = 0; i < frame_size * this.channels; i++) {
+ pcm[pcm_ptr + i] = Inlines.SAT16(Inlines.ADD32(pcm[pcm_ptr + i], pcm_silk[i]));
+ }
+ }
+
+ window = celt_dec.GetMode().window;
+
+ /* 5 ms redundant frame for SILK->CELT */
+ if (redundancy != 0 && celt_to_silk == 0) {
+ celt_dec.ResetState();
+ celt_dec.SetStartBand(0);
+
+ celt_dec.celt_decode_with_ec(data, data_ptr + len, redundancy_bytes, redundant_audio, 0, F5, null, 0);
+ redundant_rng = celt_dec.GetFinalRange();
+ CodecHelpers.smooth_fade(pcm, pcm_ptr + this.channels * (frame_size - F2_5), redundant_audio, this.channels * F2_5,
+ pcm, (pcm_ptr + this.channels * (frame_size - F2_5)), F2_5, this.channels, window, this.Fs);
+ }
+ if (redundancy != 0 && celt_to_silk != 0) {
+ for (c = 0; c < this.channels; c++) {
+ for (i = 0; i < F2_5; i++) {
+ pcm[this.channels * i + c + pcm_ptr] = redundant_audio[this.channels * i + c];
+ }
+ }
+ CodecHelpers.smooth_fade(redundant_audio, (this.channels * F2_5), pcm, (pcm_ptr + (this.channels * F2_5)),
+ pcm, (pcm_ptr + (this.channels * F2_5)), F2_5, this.channels, window, this.Fs);
+ }
+ if (transition != 0) {
+ if (audiosize >= F5) {
+ for (i = 0; i < this.channels * F2_5; i++) {
+ pcm[i] = pcm_transition[i];
+ }
+ CodecHelpers.smooth_fade(pcm_transition, (this.channels * F2_5), pcm, (pcm_ptr + (this.channels * F2_5)),
+ pcm, (pcm_ptr + (this.channels * F2_5)), F2_5,
+ this.channels, window, this.Fs);
+ } else {
+ /* Not enough time to do a clean transition, but we do it anyway
+ This will not preserve amplitude perfectly and may introduce
+ a bit of temporal aliasing, but it shouldn't be too bad and
+ that's pretty much the best we can do. In any case, generating this
+ transition is pretty silly in the first place */
+ CodecHelpers.smooth_fade(pcm_transition, 0, pcm, pcm_ptr,
+ pcm, pcm_ptr, F2_5,
+ this.channels, window, this.Fs);
+ }
+ }
+
+ if (this.decode_gain != 0) {
+ int gain;
+ gain = Inlines.celt_exp2(Inlines.MULT16_16_P15(((short) (0.5 + (6.48814081e-4f) * ((1) << (25))))/*Inlines.QCONST16(6.48814081e-4f, 25)*/, this.decode_gain));
+ for (i = pcm_ptr; i < pcm_ptr + (frame_size * this.channels); i++) {
+ int x;
+ x = Inlines.MULT16_32_P16(pcm[i], gain);
+ pcm[i] = (short) Inlines.SATURATE(x, 32767);
+ }
+ }
+
+ if (len <= 1) {
+ this.rangeFinal = 0;
+ } else {
+ this.rangeFinal = ((int) dec.rng) ^ redundant_rng;
+ }
+
+ this.prev_mode = mode;
+ this.prev_redundancy = (redundancy != 0 && celt_to_silk == 0) ? 1 : 0;
+
+ return celt_ret < 0 ? celt_ret : audiosize;
+ }
+
+ int opus_decode_native(byte[] data, int data_ptr,
+ int len, short[] pcm_out, int pcm_out_ptr, int frame_size, int decode_fec,
+ int self_delimited, BoxedValueInt packet_offset, int soft_clip) {
+ int i, nb_samples;
+ int count, offset;
+ int packet_frame_size, packet_stream_channels;
+ packet_offset.Val = 0;
+ OpusBandwidth packet_bandwidth;
+ OpusMode packet_mode;
+ /* 48 x 2.5 ms = 120 ms */
+ // fixme: make sure these values can fit in an int16
+ short[] size = new short[48];
+ if (decode_fec < 0 || decode_fec > 1) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
+ if ((decode_fec != 0 || len == 0 || data == null) && frame_size % (this.Fs / 400) != 0) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ if (len == 0 || data == null) {
+ int pcm_count = 0;
+ do {
+ int ret;
+ ret = opus_decode_frame(null, 0, 0, pcm_out, pcm_out_ptr + (pcm_count * this.channels), frame_size - pcm_count, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ pcm_count += ret;
+ } while (pcm_count < frame_size);
+ Inlines.OpusAssert(pcm_count == frame_size);
+ this.last_packet_duration = pcm_count;
+ return pcm_count;
+ } else if (len < 0) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ packet_mode = OpusPacketInfo.getEncoderMode(data, data_ptr);
+ packet_bandwidth = OpusPacketInfo.getBandwidth(data, data_ptr);
+ packet_frame_size = OpusPacketInfo.getNumSamplesPerFrame(data, data_ptr, this.Fs);
+ packet_stream_channels = OpusPacketInfo.getNumEncodedChannels(data, data_ptr);
+
+ BoxedValueByte boxed_toc = new BoxedValueByte((byte) 0);
+ BoxedValueInt boxed_offset = new BoxedValueInt(0);
+ count = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, boxed_toc, null, 0,
+ size, 0, boxed_offset, packet_offset);
+ offset = boxed_offset.Val;
+
+ if (count < 0) {
+ return count;
+ }
+
+ data_ptr += offset;
+
+ if (decode_fec != 0) {
+ BoxedValueInt dummy = new BoxedValueInt(0);
+ int duration_copy;
+ int ret;
+ /* If no FEC can be present, run the PLC (recursive call) */
+ if (frame_size < packet_frame_size || packet_mode == OpusMode.MODE_CELT_ONLY || this.mode == OpusMode.MODE_CELT_ONLY) {
+ return opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size, 0, 0, dummy, soft_clip);
+ }
+ /* Otherwise, run the PLC on everything except the size for which we might have FEC */
+ duration_copy = this.last_packet_duration;
+ if (frame_size - packet_frame_size != 0) {
+ ret = opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size - packet_frame_size, 0, 0, dummy, soft_clip);
+ if (ret < 0) {
+ this.last_packet_duration = duration_copy;
+ return ret;
+ }
+ Inlines.OpusAssert(ret == frame_size - packet_frame_size);
+ }
+ /* Complete with FEC */
+ this.mode = packet_mode;
+ this.bandwidth = packet_bandwidth;
+ this.frame_size = packet_frame_size;
+ this.stream_channels = packet_stream_channels;
+ ret = opus_decode_frame(data, data_ptr, size[0], pcm_out, pcm_out_ptr + (this.channels * (frame_size - packet_frame_size)),
+ packet_frame_size, 1);
+ if (ret < 0) {
+ return ret;
+ } else {
+ this.last_packet_duration = frame_size;
+ return frame_size;
+ }
+ }
+
+ if (count * packet_frame_size > frame_size) {
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Update the state as the last step to avoid updating it on an invalid packet */
+ this.mode = packet_mode;
+ this.bandwidth = packet_bandwidth;
+ this.frame_size = packet_frame_size;
+ this.stream_channels = packet_stream_channels;
+
+ nb_samples = 0;
+ for (i = 0; i < count; i++) {
+ int ret;
+ ret = opus_decode_frame(data, data_ptr, size[i], pcm_out, pcm_out_ptr + (nb_samples * this.channels), frame_size - nb_samples, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ Inlines.OpusAssert(ret == packet_frame_size);
+ data_ptr += size[i];
+ nb_samples += ret;
+ }
+ this.last_packet_duration = nb_samples;
+
+ return nb_samples;
+ }
+
+ ///
+ /// Decodes an Opus packet.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// exact sizing.
+ ///
+ ///
+ /// Flag to request that any in-band forward error correction data be
+ /// decoded. If no such data is available, the frame is decoded as if it were lost.
+ /// The number of decoded samples
+ /**
+ * Decodes an Opus packet.
+ * @param in_data The input payload. This may be NULL if that previous packet was lost in transit (when PLC is enabled)
+ * @param in_data_offset The offset to use when reading the input payload. Usually 0
+ * @param len The number of bytes in the payload (the packet size)
+ * @param out_pcm A buffer to put the output PCM, in a short array. The output size is (# of samples) * (# of channels).
+ * You can use the OpusPacketInfo helpers to get a hint of the frame size before you decode the packet if you need exact sizing.
+ * @param out_pcm_offset The offset to use when writing to the output buffer
+ * @param frame_size The number of samples (per channel) of available space in the output PCM buf.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48khz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data == NULL) or FEC (decode_fec == true),
+ * then frame_size needs to be exactly the duration of the audio that is missing, otherwise the decoder will
+ * not be in an optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size *must*
+ * be a multiple of 2.5 ms.
+ * @param decode_fec Indicates that we want to recreate the PREVIOUS (lost) packet using FEC data from THIS packet. Using this packet
+ * recovery scheme, you will actually decode this packet twice, first with decode_fec TRUE and then again with FALSE. If FEC data is not
+ * available in this packet, the decoder will simply generate a best-effort recreation of the lost packet. In that case,
+ * the length of frame_size must be EXACTLY the length of the audio that was lost, or else the decoder will be in an inconsistent state.
+ * @return The number of decoded samples (per channel)
+ * @throws OpusException
+ */
+ public int decode(byte[] in_data, int in_data_offset,
+ int len, short[] out_pcm, int out_pcm_offset, int frame_size, boolean decode_fec) throws OpusException {
+ if (frame_size <= 0) {
+ throw new IllegalArgumentException("Frame size must be > 0");
+ }
+
+ try {
+ BoxedValueInt dummy = new BoxedValueInt(0);
+ int ret = opus_decode_native(in_data, in_data_offset, len, out_pcm, out_pcm_offset, frame_size, decode_fec ? 1 : 0, 0, dummy, 0);
+
+ if (ret < 0) {
+ // An error happened; report it
+ if (ret == OpusError.OPUS_BAD_ARG) {
+ throw new IllegalArgumentException("OPUS_BAD_ARG while decoding");
+ }
+ throw new OpusException("An error occurred during decoding", ret);
+ }
+
+ return ret;
+ } catch (ArithmeticException e) {
+ throw new OpusException("Internal error during decoding: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Decodes an Opus packet.
+ * @param in_data The input payload. This may be NULL if that previous packet was lost in transit (when PLC is enabled)
+ * @param in_data_offset The offset to use when reading the input payload. Usually 0
+ * @param len The number of bytes in the payload (the packet size)
+ * @param out_pcm A buffer to put the output PCM, in a byte array. The output size is (# of samples) * (# of channels) * 2.
+ * You can use the OpusPacketInfo helpers to get a hint of the frame size before you decode the packet if you need exact sizing.
+ * @param out_pcm_offset The offset to use when writing to the output buffer
+ * @param frame_size The number of samples (per channel) of available space in the output PCM buf.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48khz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data == NULL) or FEC (decode_fec == true),
+ * then frame_size needs to be exactly the duration of the audio that is missing, otherwise the decoder will
+ * not be in an optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size *must*
+ * be a multiple of 2.5 ms.
+ * @param decode_fec Indicates that we want to recreate the PREVIOUS (lost) packet using FEC data from THIS packet. Using this packet
+ * recovery scheme, you will actually decode this packet twice, first with decode_fec TRUE and then again with FALSE. If FEC data is not
+ * available in this packet, the decoder will simply generate a best-effort recreation of the lost packet. In that case, the
+ * length of frame_size must be EXACTLY the length of the audio that was lost, or else the decoder will be in an inconsistent state.
+ * @return The number of decoded samples (per channel)
+ * @throws OpusException
+ */
+ public int decode(byte[] in_data, int in_data_offset, int len, byte[] out_pcm,
+ int out_pcm_offset, int frame_size, boolean decode_fec) throws OpusException {
+ short[] spcm = new short[Math.min(frame_size, 5760) * channels];
+ int decSamples = decode(in_data, in_data_offset, len, spcm, 0, frame_size, decode_fec);
+ //Convert short array to byte array
+ for (int c = 0, idx = out_pcm_offset; c < spcm.length; c++) {
+ out_pcm[idx++] = (byte) (spcm[c] & 0xff);
+ out_pcm[idx++] = (byte) ((spcm[c] >> 8) & 0xff);
+ }
+ return decSamples;
+ }
+
+ public OpusBandwidth getBandwidth() {
+ return bandwidth;
+ }
+
+ public int getFinalRange() {
+ return rangeFinal;
+ }
+
+ public int getSampleRate() {
+ return Fs;
+ }
+
+ public int getPitch() {
+ if (prev_mode == OpusMode.MODE_CELT_ONLY) {
+ return Celt_Decoder.GetPitch();
+ } else {
+ return DecControl.prevPitchLag;
+ }
+ }
+
+ public int getGain() {
+ return decode_gain;
+ }
+
+ public void setGain(int value) {
+ if (value < -32768 || value > 32767) {
+ throw new IllegalArgumentException("Gain must be within the range of a signed int16");
+ }
+
+ decode_gain = value;
+ }
+
+ public int getLastPacketDuration() {
+ return last_packet_duration;
+ }
+
+ public void resetState() {
+ partialReset();
+ Celt_Decoder.ResetState();
+ DecodeAPI.silk_InitDecoder(SilkDecoder);
+ stream_channels = channels;
+ frame_size = Fs / 400;
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusEncoder.java b/app/src/main/java/org/concentus/OpusEncoder.java
new file mode 100644
index 0000000000..6810e6220f
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusEncoder.java
@@ -0,0 +1,1643 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+///
+/// The Opus encoder structure
+///
+public class OpusEncoder {
+
+ final EncControlState silk_mode = new EncControlState();
+ OpusApplication application;
+ int channels;
+ int delay_compensation;
+ int force_channels;
+ OpusSignal signal_type;
+ OpusBandwidth user_bandwidth;
+ OpusBandwidth max_bandwidth;
+ OpusMode user_forced_mode;
+ int voice_ratio;
+ int Fs;
+ int use_vbr;
+ int vbr_constraint;
+ OpusFramesize variable_duration;
+ int bitrate_bps;
+ int user_bitrate_bps;
+ int lsb_depth;
+ int encoder_buffer;
+ int lfe;
+ final TonalityAnalysisState analysis = new TonalityAnalysisState();
+
+ // partial reset happens below this line
+ int stream_channels;
+ short hybrid_stereo_width_Q14;
+ int variable_HP_smth2_Q15;
+ int prev_HB_gain;
+ final int[] hp_mem = new int[4];
+ OpusMode mode;
+ OpusMode prev_mode;
+ int prev_channels;
+ int prev_framesize;
+ OpusBandwidth bandwidth;
+ int silk_bw_switch;
+ /* Sampling rate (at the API level) */
+ int first;
+ int[] energy_masking;
+ final StereoWidthState width_mem = new StereoWidthState();
+ final short[] delay_buffer = new short[OpusConstants.MAX_ENCODER_BUFFER * 2];
+ OpusBandwidth detected_bandwidth;
+ int rangeFinal;
+
+ // [Porting Note] There were originally "cabooses" that were tacked onto the end
+ // of the struct without being explicitly included (since they have a variable size).
+ // Here they are just included as an intrinsic variable.
+ final SilkEncoder SilkEncoder = new SilkEncoder();
+ final CeltEncoder Celt_Encoder = new CeltEncoder();
+
+ OpusEncoder() {
+ } // used internally
+
+ void reset() {
+ silk_mode.Reset();
+ application = OpusApplication.OPUS_APPLICATION_UNIMPLEMENTED;
+ channels = 0;
+ delay_compensation = 0;
+ force_channels = 0;
+ signal_type = OpusSignal.OPUS_SIGNAL_UNKNOWN;
+ user_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN;
+ max_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN;
+ user_forced_mode = OpusMode.MODE_UNKNOWN;
+ voice_ratio = 0;
+ Fs = 0;
+ use_vbr = 0;
+ vbr_constraint = 0;
+ variable_duration = OpusFramesize.OPUS_FRAMESIZE_UNKNOWN;
+ bitrate_bps = 0;
+ user_bitrate_bps = 0;
+ lsb_depth = 0;
+ encoder_buffer = 0;
+ lfe = 0;
+ analysis.Reset();
+ PartialReset();
+ }
+
+ ///
+ /// OPUS_ENCODER_RESET_START
+ ///
+ void PartialReset() {
+ stream_channels = 0;
+ hybrid_stereo_width_Q14 = 0;
+ variable_HP_smth2_Q15 = 0;
+ prev_HB_gain = 0;
+ Arrays.MemSet(hp_mem, 0, 4);
+ mode = OpusMode.MODE_UNKNOWN;
+ prev_mode = OpusMode.MODE_UNKNOWN;
+ prev_channels = 0;
+ prev_framesize = 0;
+ bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN;
+ silk_bw_switch = 0;
+ first = 0;
+ energy_masking = null;
+ width_mem.Reset();
+ Arrays.MemSet(delay_buffer, (short) 0, OpusConstants.MAX_ENCODER_BUFFER * 2);
+ detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN;
+ rangeFinal = 0;
+ //SilkEncoder.Reset();
+ //CeltEncoder.Reset();
+ }
+
+ public void resetState() {
+ EncControlState dummy = new EncControlState();
+ analysis.Reset();
+ PartialReset();
+
+ Celt_Encoder.ResetState();
+ EncodeAPI.silk_InitEncoder(SilkEncoder, dummy);
+ stream_channels = channels;
+ hybrid_stereo_width_Q14 = 1 << 14;
+ prev_HB_gain = CeltConstants.Q15ONE;
+ first = 1;
+ mode = OpusMode.MODE_HYBRID;
+ bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND;
+ variable_HP_smth2_Q15 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ), 8);
+ }
+
+ /**
+ * Allocates and initializes an encoder state. Note that regardless of the
+ * sampling rate and number channels selected, the Opus encoder can switch
+ * to a lower audio bandwidth or number of channels if the bitrate selected
+ * is too low. This also means that it is safe to always use 48 kHz stereo
+ * input and let the encoder optimize the encoding. The decoder will not be
+ * constrained later on by the mode that you select here for the encoder.
+ *
+ * @param Fs Sampling rate of input signal (Hz). This must be one of 8000,
+ * 12000, 16000, 24000, or 48000.
+ * @param channels Number of channels (1 or 2) in input signal
+ * @param application There are three coding modes:
+ *
+ * OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice
+ * signals. It enhances the input signal by high-pass filtering and
+ * emphasizing formants and harmonics.Optionally it includes in-band forward
+ * error correction to protect against packet loss. Use this mode for
+ * typical VoIP applications. Because of the enhancement, even at high
+ * bitrates the output may sound different from the input.
+ *
+ * OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most
+ * non-voice signals like music. Use this mode for music and mixed
+ * (music/voice) content, broadcast, and applications requiring less than 15
+ * ms of coding delay.
+ *
+ * OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that
+ * disables the speech-optimized mode in exchange for slightly reduced
+ * delay. This mode can only be set on an newly initialized or freshly reset
+ * encoder because it changes the codec delay.
+ * @throws OpusException
+ */
+ public OpusEncoder(int Fs, int channels, OpusApplication application) throws OpusException {
+ int ret;
+ if ((Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000)) {
+ throw new IllegalArgumentException("Sample rate is invalid (must be 8/12/16/24/48 Khz)");
+ }
+ if (channels != 1 && channels != 2) {
+ throw new IllegalArgumentException("Number of channels must be 1 or 2");
+ }
+
+ ret = this.opus_init_encoder(Fs, channels, application);
+ if (ret != OpusError.OPUS_OK) {
+ if (ret == OpusError.OPUS_BAD_ARG) {
+ throw new IllegalArgumentException("OPUS_BAD_ARG when creating encoder");
+ }
+ throw new OpusException("Error while initializing encoder", ret);
+ }
+ }
+
+ int opus_init_encoder(int Fs, int channels, OpusApplication application) {
+ SilkEncoder silk_enc;
+ CeltEncoder celt_enc;
+ int err;
+ int ret;
+
+ if ((Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000) || (channels != 1 && channels != 2)
+ || application == OpusApplication.OPUS_APPLICATION_UNIMPLEMENTED) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ this.reset();
+ /* Create SILK encoder */
+ silk_enc = this.SilkEncoder;
+ celt_enc = this.Celt_Encoder;
+
+ this.stream_channels = this.channels = channels;
+
+ this.Fs = Fs;
+
+ ret = EncodeAPI.silk_InitEncoder(silk_enc, this.silk_mode);
+ if (ret != 0) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+
+ /* default SILK parameters */
+ this.silk_mode.nChannelsAPI = channels;
+ this.silk_mode.nChannelsInternal = channels;
+ this.silk_mode.API_sampleRate = this.Fs;
+ this.silk_mode.maxInternalSampleRate = 16000;
+ this.silk_mode.minInternalSampleRate = 8000;
+ this.silk_mode.desiredInternalSampleRate = 16000;
+ this.silk_mode.payloadSize_ms = 20;
+ this.silk_mode.bitRate = 25000;
+ this.silk_mode.packetLossPercentage = 0;
+ this.silk_mode.complexity = 9;
+ this.silk_mode.useInBandFEC = 0;
+ this.silk_mode.useDTX = 0;
+ this.silk_mode.useCBR = 0;
+ this.silk_mode.reducedDependency = 0;
+
+ /* Create CELT encoder */
+ /* Initialize CELT encoder */
+ err = celt_enc.celt_encoder_init(Fs, channels);
+ if (err != OpusError.OPUS_OK) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+
+ celt_enc.SetSignalling(0);
+ celt_enc.SetComplexity(this.silk_mode.complexity);
+
+ this.use_vbr = 1;
+ /* Makes constrained VBR the default (safer for real-time use) */
+ this.vbr_constraint = 1;
+ this.user_bitrate_bps = OpusConstants.OPUS_AUTO;
+ this.bitrate_bps = 3000 + Fs * channels;
+ this.application = application;
+ this.signal_type = OpusSignal.OPUS_SIGNAL_AUTO;
+ this.user_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_AUTO;
+ this.max_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND;
+ this.force_channels = OpusConstants.OPUS_AUTO;
+ this.user_forced_mode = OpusMode.MODE_AUTO;
+ this.voice_ratio = -1;
+ this.encoder_buffer = this.Fs / 100;
+ this.lsb_depth = 24;
+ this.variable_duration = OpusFramesize.OPUS_FRAMESIZE_ARG;
+
+ /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead
+ + 1.5 ms for SILK resamplers and stereo prediction) */
+ this.delay_compensation = this.Fs / 250;
+
+ this.hybrid_stereo_width_Q14 = 1 << 14;
+ this.prev_HB_gain = CeltConstants.Q15ONE;
+ this.variable_HP_smth2_Q15 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ), 8);
+ this.first = 1;
+ this.mode = OpusMode.MODE_HYBRID;
+ this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND;
+
+ Analysis.tonality_analysis_init(this.analysis);
+
+ return OpusError.OPUS_OK;
+ }
+
+ int user_bitrate_to_bitrate(int frame_size, int max_data_bytes) {
+ if (frame_size == 0) {
+ frame_size = this.Fs / 400;
+ }
+ if (this.user_bitrate_bps == OpusConstants.OPUS_AUTO) {
+ return 60 * this.Fs / frame_size + this.Fs * this.channels;
+ } else if (this.user_bitrate_bps == OpusConstants.OPUS_BITRATE_MAX) {
+ return max_data_bytes * 8 * this.Fs / frame_size;
+ } else {
+ return this.user_bitrate_bps;
+ }
+ }
+
+ ///
+ ///
+ ///
+ /// The storage type of analysis_pcm, either short or float
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ int opus_encode_native(short[] pcm, int pcm_ptr, int frame_size,
+ byte[] data, int data_ptr, int out_data_bytes, int lsb_depth,
+ short[] analysis_pcm, int analysis_pcm_ptr, int analysis_size, int c1, int c2,
+ int analysis_channels, int float_api) {
+ SilkEncoder silk_enc;
+ CeltEncoder celt_enc;
+ int i;
+ int ret = 0;
+ int nBytes;
+ EntropyCoder enc = new EntropyCoder(); // porting note: stack var
+ int bytes_target;
+ int prefill = 0;
+ int start_band = 0;
+ int redundancy = 0;
+ int redundancy_bytes = 0;
+ /* Number of bytes to use for redundancy frame */
+ int celt_to_silk = 0;
+ short[] pcm_buf;
+ int nb_compr_bytes;
+ int to_celt = 0;
+ int redundant_rng = 0;
+ int cutoff_Hz, hp_freq_smth1;
+ int voice_est;
+ /* Probability of voice in Q7 */
+ int equiv_rate;
+ int delay_compensation;
+ int frame_rate;
+ int max_rate;
+ /* Max bitrate we're allowed to use */
+ OpusBandwidth curr_bandwidth;
+ int HB_gain;
+ int max_data_bytes;
+ /* Max number of bytes we're allowed to use */
+ int total_buffer;
+ int stereo_width;
+ CeltMode celt_mode;
+ AnalysisInfo analysis_info = new AnalysisInfo(); // porting note: stack var
+ int analysis_read_pos_bak = -1;
+ int analysis_read_subframe_bak = -1;
+ short[] tmp_prefill;
+
+ max_data_bytes = Inlines.IMIN(1276, out_data_bytes);
+
+ this.rangeFinal = 0;
+ if ((this.variable_duration == OpusFramesize.OPUS_FRAMESIZE_UNKNOWN && 400 * frame_size != this.Fs && 200 * frame_size != this.Fs && 100 * frame_size != this.Fs
+ && 50 * frame_size != this.Fs && 25 * frame_size != this.Fs && 50 * frame_size != 3 * this.Fs)
+ || (400 * frame_size < this.Fs)
+ || max_data_bytes <= 0) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ silk_enc = this.SilkEncoder;
+ celt_enc = this.Celt_Encoder;
+ if (this.application == OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) {
+ delay_compensation = 0;
+ } else {
+ delay_compensation = this.delay_compensation;
+ }
+
+ lsb_depth = Inlines.IMIN(lsb_depth, this.lsb_depth);
+ celt_mode = celt_enc.GetMode();
+ this.voice_ratio = -1;
+
+ if (this.analysis.enabled) {
+ analysis_info.valid = 0;
+ if (this.silk_mode.complexity >= 7 && this.Fs == 48000) {
+ analysis_read_pos_bak = this.analysis.read_pos;
+ analysis_read_subframe_bak = this.analysis.read_subframe;
+ Analysis.run_analysis(this.analysis,
+ celt_mode,
+ analysis_pcm != null ? analysis_pcm : null,
+ analysis_pcm_ptr,
+ analysis_size,
+ frame_size,
+ c1,
+ c2,
+ analysis_channels,
+ this.Fs,
+ lsb_depth,
+ analysis_info);
+ }
+
+ this.detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN;
+ if (analysis_info.valid != 0) {
+ int analysis_bandwidth;
+ if (this.signal_type == OpusSignal.OPUS_SIGNAL_AUTO) {
+ this.voice_ratio = (int) Math.floor(.5f + 100 * (1 - analysis_info.music_prob));
+ }
+
+ analysis_bandwidth = analysis_info.bandwidth;
+ if (analysis_bandwidth <= 12) {
+ this.detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
+ } else if (analysis_bandwidth <= 14) {
+ this.detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND;
+ } else if (analysis_bandwidth <= 16) {
+ this.detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND;
+ } else if (analysis_bandwidth <= 18) {
+ this.detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND;
+ } else {
+ this.detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND;
+ }
+ }
+ }
+
+ if (this.channels == 2 && this.force_channels != 1) {
+ stereo_width = CodecHelpers.compute_stereo_width(pcm, pcm_ptr, frame_size, this.Fs, this.width_mem);
+ } else {
+ stereo_width = 0;
+ }
+ total_buffer = delay_compensation;
+ this.bitrate_bps = user_bitrate_to_bitrate(frame_size, max_data_bytes);
+
+ frame_rate = this.Fs / frame_size;
+ if (this.use_vbr == 0) {
+ int cbrBytes;
+ /* Multiply by 3 to make sure the division is exact. */
+ int frame_rate3 = 3 * this.Fs / frame_size;
+ /* We need to make sure that "int" values always fit in 16 bits. */
+ cbrBytes = Inlines.IMIN((3 * this.bitrate_bps / 8 + frame_rate3 / 2) / frame_rate3, max_data_bytes);
+ this.bitrate_bps = cbrBytes * frame_rate3 * 8 / 3;
+ max_data_bytes = cbrBytes;
+ }
+ if (max_data_bytes < 3 || this.bitrate_bps < 3 * frame_rate * 8
+ || (frame_rate < 50 && (max_data_bytes * frame_rate < 300 || this.bitrate_bps < 2400))) {
+ /*If the space is too low to do something useful, emit 'PLC' frames.*/
+ OpusMode tocmode = this.mode;
+ OpusBandwidth bw = this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN ? OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND : this.bandwidth;
+ if (tocmode == OpusMode.MODE_UNKNOWN) {
+ tocmode = OpusMode.MODE_SILK_ONLY;
+ }
+ if (frame_rate > 100) {
+ tocmode = OpusMode.MODE_CELT_ONLY;
+ }
+ if (frame_rate < 50) {
+ tocmode = OpusMode.MODE_SILK_ONLY;
+ }
+ if (tocmode == OpusMode.MODE_SILK_ONLY && OpusBandwidthHelpers.GetOrdinal(bw) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) {
+ bw = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND;
+ } else if (tocmode == OpusMode.MODE_CELT_ONLY && OpusBandwidthHelpers.GetOrdinal(bw) == OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)) {
+ bw = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
+ } else if (tocmode == OpusMode.MODE_HYBRID && OpusBandwidthHelpers.GetOrdinal(bw) <= OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND)) {
+ bw = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND;
+ }
+ data[data_ptr] = CodecHelpers.gen_toc(tocmode, frame_rate, bw, this.stream_channels);
+ ret = 1;
+ if (this.use_vbr == 0) {
+ ret = OpusRepacketizer.padPacket(data, data_ptr, ret, max_data_bytes);
+ if (ret == OpusError.OPUS_OK) {
+ ret = max_data_bytes;
+ }
+ }
+ return ret;
+ }
+ max_rate = frame_rate * max_data_bytes * 8;
+
+ /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */
+ equiv_rate = this.bitrate_bps - (40 * this.channels + 20) * (this.Fs / frame_size - 50);
+
+ if (this.signal_type == OpusSignal.OPUS_SIGNAL_VOICE) {
+ voice_est = 127;
+ } else if (this.signal_type == OpusSignal.OPUS_SIGNAL_MUSIC) {
+ voice_est = 0;
+ } else if (this.voice_ratio >= 0) {
+ voice_est = this.voice_ratio * 327 >> 8;
+ /* For AUDIO, never be more than 90% confident of having speech */
+ if (this.application == OpusApplication.OPUS_APPLICATION_AUDIO) {
+ voice_est = Inlines.IMIN(voice_est, 115);
+ }
+ } else if (this.application == OpusApplication.OPUS_APPLICATION_VOIP) {
+ voice_est = 115;
+ } else {
+ voice_est = 48;
+ }
+
+ if (this.force_channels != OpusConstants.OPUS_AUTO && this.channels == 2) {
+ this.stream_channels = this.force_channels;
+ } else /* Rate-dependent mono-stereo decision */ if (this.channels == 2) {
+ int stereo_threshold;
+ stereo_threshold = OpusTables.stereo_music_threshold + ((voice_est * voice_est * (OpusTables.stereo_voice_threshold - OpusTables.stereo_music_threshold)) >> 14);
+ if (this.stream_channels == 2) {
+ stereo_threshold -= 1000;
+ } else {
+ stereo_threshold += 1000;
+ }
+ this.stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1;
+ } else {
+ this.stream_channels = this.channels;
+ }
+ equiv_rate = this.bitrate_bps - (40 * this.stream_channels + 20) * (this.Fs / frame_size - 50);
+
+ /* Mode selection depending on application and signal type */
+ if (this.application == OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) {
+ this.mode = OpusMode.MODE_CELT_ONLY;
+ } else if (this.user_forced_mode == OpusMode.MODE_AUTO) {
+ int mode_voice, mode_music;
+ int threshold;
+
+ /* Interpolate based on stereo width */
+ mode_voice = Inlines.MULT16_32_Q15(CeltConstants.Q15ONE - stereo_width, OpusTables.mode_thresholds[0][0])
+ + Inlines.MULT16_32_Q15(stereo_width, OpusTables.mode_thresholds[1][0]);
+ mode_music = Inlines.MULT16_32_Q15(CeltConstants.Q15ONE - stereo_width, OpusTables.mode_thresholds[1][1])
+ + Inlines.MULT16_32_Q15(stereo_width, OpusTables.mode_thresholds[1][1]);
+ /* Interpolate based on speech/music probability */
+ threshold = mode_music + ((voice_est * voice_est * (mode_voice - mode_music)) >> 14);
+ /* Bias towards SILK for VoIP because of some useful features */
+ if (this.application == OpusApplication.OPUS_APPLICATION_VOIP) {
+ threshold += 8000;
+ }
+
+ /*printf("%f %d\n", stereo_width/(float)1.0f, threshold);*/
+ /* Hysteresis */
+ if (this.prev_mode == OpusMode.MODE_CELT_ONLY) {
+ threshold -= 4000;
+ } else if (this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN) {
+ threshold += 4000;
+ }
+
+ this.mode = (equiv_rate >= threshold) ? OpusMode.MODE_CELT_ONLY : OpusMode.MODE_SILK_ONLY;
+
+ /* When FEC is enabled and there's enough packet loss, use SILK */
+ if (this.silk_mode.useInBandFEC != 0 && this.silk_mode.packetLossPercentage > (128 - voice_est) >> 4) {
+ this.mode = OpusMode.MODE_SILK_ONLY;
+ }
+ /* When encoding voice and DTX is enabled, set the encoder to SILK mode (at least for now) */
+ if (this.silk_mode.useDTX != 0 && voice_est > 100) {
+ this.mode = OpusMode.MODE_SILK_ONLY;
+ }
+ } else {
+ this.mode = this.user_forced_mode;
+ }
+
+ /* Override the chosen mode to make sure we meet the requested frame size */
+ if (this.mode != OpusMode.MODE_CELT_ONLY && frame_size < this.Fs / 100) {
+ this.mode = OpusMode.MODE_CELT_ONLY;
+ }
+ if (this.lfe != 0) {
+ this.mode = OpusMode.MODE_CELT_ONLY;
+ }
+ /* If max_data_bytes represents less than 8 kb/s, switch to CELT-only mode */
+ if (max_data_bytes < (frame_rate > 50 ? 12000 : 8000) * frame_size / (this.Fs * 8)) {
+ this.mode = OpusMode.MODE_CELT_ONLY;
+ }
+
+ if (this.stream_channels == 1 && this.prev_channels == 2 && this.silk_mode.toMono == 0
+ && this.mode != OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY) {
+ /* Delay stereo.mono transition by two frames so that SILK can do a smooth downmix */
+ this.silk_mode.toMono = 1;
+ this.stream_channels = 2;
+ } else {
+ this.silk_mode.toMono = 0;
+ }
+
+ if ((this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN)
+ && ((this.mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY)
+ || (this.mode == OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY))) {
+ redundancy = 1;
+ celt_to_silk = (this.mode != OpusMode.MODE_CELT_ONLY) ? 1 : 0;
+ if (celt_to_silk == 0) {
+ /* Switch to SILK/hybrid if frame size is 10 ms or more*/
+ if (frame_size >= this.Fs / 100) {
+ this.mode = this.prev_mode;
+ to_celt = 1;
+ } else {
+ redundancy = 0;
+ }
+ }
+ }
+ /* For the first frame at a new SILK bandwidth */
+ if (this.silk_bw_switch != 0) {
+ redundancy = 1;
+ celt_to_silk = 1;
+ this.silk_bw_switch = 0;
+ prefill = 1;
+ }
+
+ if (redundancy != 0) {
+ /* Fair share of the max size allowed */
+ redundancy_bytes = Inlines.IMIN(257, max_data_bytes * (this.Fs / 200) / (frame_size + this.Fs / 200));
+ /* For VBR, target the actual bitrate (subject to the limit above) */
+ if (this.use_vbr != 0) {
+ redundancy_bytes = Inlines.IMIN(redundancy_bytes, this.bitrate_bps / 1600);
+ }
+ }
+
+ if (this.mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY) {
+ EncControlState dummy = new EncControlState();
+ EncodeAPI.silk_InitEncoder(silk_enc, dummy);
+ prefill = 1;
+ }
+
+ /* Automatic (rate-dependent) bandwidth selection */
+ if (this.mode == OpusMode.MODE_CELT_ONLY || this.first != 0 || this.silk_mode.allowBandwidthSwitch != 0) {
+ int[] voice_bandwidth_thresholds;
+ int[] music_bandwidth_thresholds;
+ int[] bandwidth_thresholds = new int[8];
+ OpusBandwidth bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND;
+ int equiv_rate2;
+
+ equiv_rate2 = equiv_rate;
+ if (this.mode != OpusMode.MODE_CELT_ONLY) {
+ /* Adjust the threshold +/- 10% depending on complexity */
+ equiv_rate2 = equiv_rate2 * (45 + this.silk_mode.complexity) / 50;
+ /* CBR is less efficient by ~1 kb/s */
+ if (this.use_vbr == 0) {
+ equiv_rate2 -= 1000;
+ }
+ }
+ if (this.channels == 2 && this.force_channels != 1) {
+ voice_bandwidth_thresholds = OpusTables.stereo_voice_bandwidth_thresholds;
+ music_bandwidth_thresholds = OpusTables.stereo_music_bandwidth_thresholds;
+ } else {
+ voice_bandwidth_thresholds = OpusTables.mono_voice_bandwidth_thresholds;
+ music_bandwidth_thresholds = OpusTables.mono_music_bandwidth_thresholds;
+ }
+ /* Interpolate bandwidth thresholds depending on voice estimation */
+ for (i = 0; i < 8; i++) {
+ bandwidth_thresholds[i] = music_bandwidth_thresholds[i]
+ + ((voice_est * voice_est * (voice_bandwidth_thresholds[i] - music_bandwidth_thresholds[i])) >> 14);
+ }
+ do {
+ int threshold, hysteresis;
+ threshold = bandwidth_thresholds[2 * (OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND))];
+ hysteresis = bandwidth_thresholds[2 * (OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)) + 1];
+ if (this.first == 0) {
+ if (OpusBandwidthHelpers.GetOrdinal(this.bandwidth) >= OpusBandwidthHelpers.GetOrdinal(bandwidth)) {
+ threshold -= hysteresis;
+ } else {
+ threshold += hysteresis;
+ }
+ }
+ if (equiv_rate2 >= threshold) {
+ break;
+ }
+
+ bandwidth = OpusBandwidthHelpers.SUBTRACT(bandwidth, 1);
+ } while (OpusBandwidthHelpers.GetOrdinal(bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND));
+ this.bandwidth = bandwidth;
+ /* Prevents any transition to SWB/FB until the SILK layer has fully
+ switched to WB mode and turned the variable LP filter off */
+ if (this.first == 0 && this.mode != OpusMode.MODE_CELT_ONLY
+ && this.silk_mode.inWBmodeWithoutVariableLP == 0
+ && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) {
+ this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND;
+ }
+ }
+
+ if (OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(this.max_bandwidth)) {
+ this.bandwidth = this.max_bandwidth;
+ }
+
+ if (this.user_bandwidth != OpusBandwidth.OPUS_BANDWIDTH_AUTO) {
+ this.bandwidth = this.user_bandwidth;
+ }
+
+ /* This prevents us from using hybrid at unsafe CBR/max rates */
+ if (this.mode != OpusMode.MODE_CELT_ONLY && max_rate < 15000) {
+ this.bandwidth = OpusBandwidthHelpers.MIN(this.bandwidth, OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND);
+ }
+
+ /* Prevents Opus from wasting bits on frequencies that are above
+ the Nyquist rate of the input signal */
+ if (this.Fs <= 24000 && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND)) {
+ this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND;
+ }
+ if (this.Fs <= 16000 && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) {
+ this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND;
+ }
+ if (this.Fs <= 12000 && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)) {
+ this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND;
+ }
+ if (this.Fs <= 8000 && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND)) {
+ this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
+ }
+ /* Use detected bandwidth to reduce the encoded bandwidth. */
+ if (this.detected_bandwidth != OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN && this.user_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_AUTO) {
+ OpusBandwidth min_detected_bandwidth;
+ /* Makes bandwidth detection more conservative just in case the detector
+ gets it wrong when we could have coded a high bandwidth transparently.
+ When operating in SILK/hybrid mode, we don't go below wideband to avoid
+ more complicated switches that require redundancy. */
+ if (equiv_rate <= 18000 * this.stream_channels && this.mode == OpusMode.MODE_CELT_ONLY) {
+ min_detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
+ } else if (equiv_rate <= 24000 * this.stream_channels && this.mode == OpusMode.MODE_CELT_ONLY) {
+ min_detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND;
+ } else if (equiv_rate <= 30000 * this.stream_channels) {
+ min_detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND;
+ } else if (equiv_rate <= 44000 * this.stream_channels) {
+ min_detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND;
+ } else {
+ min_detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND;
+ }
+
+ this.detected_bandwidth = OpusBandwidthHelpers.MAX(this.detected_bandwidth, min_detected_bandwidth);
+ this.bandwidth = OpusBandwidthHelpers.MIN(this.bandwidth, this.detected_bandwidth);
+ }
+ celt_enc.SetLSBDepth(lsb_depth);
+
+ /* CELT mode doesn't support mediumband, use wideband instead */
+ if (this.mode == OpusMode.MODE_CELT_ONLY && this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) {
+ this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND;
+ }
+ if (this.lfe != 0) {
+ this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
+ }
+
+ /* Can't support higher than wideband for >20 ms frames */
+ if (frame_size > this.Fs / 50 && (this.mode == OpusMode.MODE_CELT_ONLY || OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND))) {
+ byte[] tmp_data;
+ int nb_frames;
+ OpusBandwidth bak_bandwidth;
+ int bak_channels, bak_to_mono;
+ OpusMode bak_mode;
+ OpusRepacketizer rp;
+ int bytes_per_frame;
+ int repacketize_len;
+
+ if (this.analysis.enabled && analysis_read_pos_bak != -1) {
+ this.analysis.read_pos = analysis_read_pos_bak;
+ this.analysis.read_subframe = analysis_read_subframe_bak;
+ }
+
+ nb_frames = frame_size > this.Fs / 25 ? 3 : 2;
+ bytes_per_frame = Inlines.IMIN(1276, (out_data_bytes - 3) / nb_frames);
+
+ tmp_data = new byte[nb_frames * bytes_per_frame];
+
+ rp = new OpusRepacketizer();
+
+ bak_mode = this.user_forced_mode;
+ bak_bandwidth = this.user_bandwidth;
+ bak_channels = this.force_channels;
+
+ this.user_forced_mode = this.mode;
+ this.user_bandwidth = this.bandwidth;
+ this.force_channels = this.stream_channels;
+ bak_to_mono = this.silk_mode.toMono;
+
+ if (bak_to_mono != 0) {
+ this.force_channels = 1;
+ } else {
+ this.prev_channels = this.stream_channels;
+ }
+ for (i = 0; i < nb_frames; i++) {
+ int tmp_len;
+ this.silk_mode.toMono = 0;
+ /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */
+ if (to_celt != 0 && i == nb_frames - 1) {
+ this.user_forced_mode = OpusMode.MODE_CELT_ONLY;
+ }
+ tmp_len = opus_encode_native(pcm, pcm_ptr + (i * (this.channels * this.Fs / 50)), this.Fs / 50,
+ tmp_data, i * bytes_per_frame, bytes_per_frame, lsb_depth,
+ null, 0, 0, c1, c2, analysis_channels, float_api);
+ if (tmp_len < 0) {
+
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ ret = rp.addPacket(tmp_data, i * bytes_per_frame, tmp_len);
+ if (ret < 0) {
+
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ }
+ if (this.use_vbr != 0) {
+ repacketize_len = out_data_bytes;
+ } else {
+ repacketize_len = Inlines.IMIN(3 * this.bitrate_bps / (3 * 8 * 50 / nb_frames), out_data_bytes);
+ }
+ ret = rp.opus_repacketizer_out_range_impl(0, nb_frames, data, data_ptr, repacketize_len, 0, (this.use_vbr == 0) ? 1 : 0);
+ if (ret < 0) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ this.user_forced_mode = bak_mode;
+ this.user_bandwidth = bak_bandwidth;
+ this.force_channels = bak_channels;
+ this.silk_mode.toMono = bak_to_mono;
+
+ return ret;
+ }
+ curr_bandwidth = this.bandwidth;
+
+ /* Chooses the appropriate mode for speech
+ *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */
+ if (this.mode == OpusMode.MODE_SILK_ONLY && OpusBandwidthHelpers.GetOrdinal(curr_bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) {
+ this.mode = OpusMode.MODE_HYBRID;
+ }
+ if (this.mode == OpusMode.MODE_HYBRID && OpusBandwidthHelpers.GetOrdinal(curr_bandwidth) <= OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) {
+ this.mode = OpusMode.MODE_SILK_ONLY;
+ }
+
+ /* printf("%d %d %d %d\n", st.bitrate_bps, st.stream_channels, st.mode, curr_bandwidth); */
+ bytes_target = Inlines.IMIN(max_data_bytes - redundancy_bytes, this.bitrate_bps * frame_size / (this.Fs * 8)) - 1;
+
+ data_ptr += 1;
+
+ enc.enc_init(data, data_ptr, (max_data_bytes - 1));
+
+ pcm_buf = new short[(total_buffer + frame_size) * this.channels];
+ System.arraycopy(this.delay_buffer, ((this.encoder_buffer - total_buffer) * this.channels), pcm_buf, 0, total_buffer * this.channels);
+
+ if (this.mode == OpusMode.MODE_CELT_ONLY) {
+ hp_freq_smth1 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ), 8);
+ } else {
+ hp_freq_smth1 = silk_enc.state_Fxx[0].variable_HP_smth1_Q15;
+ }
+
+ this.variable_HP_smth2_Q15 = Inlines.silk_SMLAWB(this.variable_HP_smth2_Q15,
+ hp_freq_smth1 - this.variable_HP_smth2_Q15, ((int) ((TuningParameters.VARIABLE_HP_SMTH_COEF2) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_SMTH_COEF2, 16)*/);
+
+ /* convert from log scale to Hertz */
+ cutoff_Hz = Inlines.silk_log2lin(Inlines.silk_RSHIFT(this.variable_HP_smth2_Q15, 8));
+
+ if (this.application == OpusApplication.OPUS_APPLICATION_VOIP) {
+ CodecHelpers.hp_cutoff(pcm, pcm_ptr, cutoff_Hz, pcm_buf, (total_buffer * this.channels), this.hp_mem, frame_size, this.channels, this.Fs);
+ } else {
+ CodecHelpers.dc_reject(pcm, pcm_ptr, 3, pcm_buf, total_buffer * this.channels, this.hp_mem, frame_size, this.channels, this.Fs);
+ }
+
+ /* SILK processing */
+ HB_gain = CeltConstants.Q15ONE;
+ if (this.mode != OpusMode.MODE_CELT_ONLY) {
+ int total_bitRate, celt_rate;
+ short[] pcm_silk = new short[this.channels * frame_size];
+
+ /* Distribute bits between SILK and CELT */
+ total_bitRate = 8 * bytes_target * frame_rate;
+ if (this.mode == OpusMode.MODE_HYBRID) {
+ int HB_gain_ref;
+ /* Base rate for SILK */
+ this.silk_mode.bitRate = this.stream_channels * (5000 + ((this.Fs == 100 * frame_size) ? 1000 : 0));
+ if (curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) {
+ /* SILK gets 2/3 of the remaining bits */
+ this.silk_mode.bitRate += (total_bitRate - this.silk_mode.bitRate) * 2 / 3;
+ } else {
+ /* FULLBAND */
+ /* SILK gets 3/5 of the remaining bits */
+ this.silk_mode.bitRate += (total_bitRate - this.silk_mode.bitRate) * 3 / 5;
+ }
+ /* Don't let SILK use more than 80% */
+ if (this.silk_mode.bitRate > total_bitRate * 4 / 5) {
+ this.silk_mode.bitRate = total_bitRate * 4 / 5;
+ }
+ if (this.energy_masking == null) {
+ /* Increasingly attenuate high band when it gets allocated fewer bits */
+ celt_rate = total_bitRate - this.silk_mode.bitRate;
+ HB_gain_ref = (curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) ? 3000 : 3600;
+ HB_gain = Inlines.SHL32(celt_rate, 9) / Inlines.SHR32(celt_rate + this.stream_channels * HB_gain_ref, 6);
+ HB_gain = HB_gain < CeltConstants.Q15ONE * 6 / 7 ? HB_gain + CeltConstants.Q15ONE / 7 : CeltConstants.Q15ONE;
+ }
+ } else {
+ /* SILK gets all bits */
+ this.silk_mode.bitRate = total_bitRate;
+ }
+
+ /* Surround masking for SILK */
+ if (this.energy_masking != null && this.use_vbr != 0 && this.lfe == 0) {
+ int mask_sum = 0;
+ int masking_depth;
+ int rate_offset;
+ int c;
+ int end = 17;
+ short srate = 16000;
+ if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) {
+ end = 13;
+ srate = 8000;
+ } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) {
+ end = 15;
+ srate = 12000;
+ }
+ for (c = 0; c < this.channels; c++) {
+ for (i = 0; i < end; i++) {
+ int mask;
+ mask = Inlines.MAX16(Inlines.MIN16(this.energy_masking[21 * c + i],
+ ((short) (0.5 + (.5f) * ((1) << (10))))/*Inlines.QCONST16(.5f, 10)*/), -((short) (0.5 + (2.0f) * ((1) << (10))))/*Inlines.QCONST16(2.0f, 10)*/);
+ if (mask > 0) {
+ mask = Inlines.HALF16(mask);
+ }
+ mask_sum += mask;
+ }
+ }
+ /* Conservative rate reduction, we cut the masking in half */
+ masking_depth = mask_sum / end * this.channels;
+ masking_depth += ((short) (0.5 + (.2f) * ((1) << (10))))/*Inlines.QCONST16(.2f, 10)*/;
+ rate_offset = Inlines.PSHR32(Inlines.MULT16_16(srate, masking_depth), 10);
+ rate_offset = Inlines.MAX32(rate_offset, -2 * this.silk_mode.bitRate / 3);
+ /* Split the rate change between the SILK and CELT part for hybrid. */
+ if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND || this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_FULLBAND) {
+ this.silk_mode.bitRate += 3 * rate_offset / 5;
+ } else {
+ this.silk_mode.bitRate += rate_offset;
+ }
+ bytes_target += rate_offset * frame_size / (8 * this.Fs);
+ }
+
+ this.silk_mode.payloadSize_ms = 1000 * frame_size / this.Fs;
+ this.silk_mode.nChannelsAPI = this.channels;
+ this.silk_mode.nChannelsInternal = this.stream_channels;
+ if (curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) {
+ this.silk_mode.desiredInternalSampleRate = 8000;
+ } else if (curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) {
+ this.silk_mode.desiredInternalSampleRate = 12000;
+ } else {
+ Inlines.OpusAssert(this.mode == OpusMode.MODE_HYBRID || curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND);
+ this.silk_mode.desiredInternalSampleRate = 16000;
+ }
+ if (this.mode == OpusMode.MODE_HYBRID) {
+ /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */
+ this.silk_mode.minInternalSampleRate = 16000;
+ } else {
+ this.silk_mode.minInternalSampleRate = 8000;
+ }
+
+ if (this.mode == OpusMode.MODE_SILK_ONLY) {
+ int effective_max_rate = max_rate;
+ this.silk_mode.maxInternalSampleRate = 16000;
+ if (frame_rate > 50) {
+ effective_max_rate = effective_max_rate * 2 / 3;
+ }
+ if (effective_max_rate < 13000) {
+ this.silk_mode.maxInternalSampleRate = 12000;
+ this.silk_mode.desiredInternalSampleRate = Inlines.IMIN(12000, this.silk_mode.desiredInternalSampleRate);
+ }
+ if (effective_max_rate < 9600) {
+ this.silk_mode.maxInternalSampleRate = 8000;
+ this.silk_mode.desiredInternalSampleRate = Inlines.IMIN(8000, this.silk_mode.desiredInternalSampleRate);
+ }
+ } else {
+ this.silk_mode.maxInternalSampleRate = 16000;
+ }
+
+ this.silk_mode.useCBR = this.use_vbr == 0 ? 1 : 0;
+
+ /* Call SILK encoder for the low band */
+ nBytes = Inlines.IMIN(1275, max_data_bytes - 1 - redundancy_bytes);
+
+ this.silk_mode.maxBits = nBytes * 8;
+ /* Only allow up to 90% of the bits for hybrid mode*/
+ if (this.mode == OpusMode.MODE_HYBRID) {
+ this.silk_mode.maxBits = this.silk_mode.maxBits * 9 / 10;
+ }
+ if (this.silk_mode.useCBR != 0) {
+ this.silk_mode.maxBits = (this.silk_mode.bitRate * frame_size / (this.Fs * 8)) * 8;
+ /* Reduce the initial target to make it easier to reach the CBR rate */
+ this.silk_mode.bitRate = Inlines.IMAX(1, this.silk_mode.bitRate - 2000);
+ }
+
+ if (prefill != 0) {
+ BoxedValueInt zero = new BoxedValueInt(0);
+ int prefill_offset;
+
+ /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode
+ a discontinuity. The exact location is what we need to avoid leaving any "gap"
+ in the audio when mixing with the redundant CELT frame. Here we can afford to
+ overwrite st.delay_buffer because the only thing that uses it before it gets
+ rewritten is tmp_prefill[] and even then only the part after the ramp really
+ gets used (rather than sent to the encoder and discarded) */
+ prefill_offset = this.channels * (this.encoder_buffer - this.delay_compensation - this.Fs / 400);
+ CodecHelpers.gain_fade(this.delay_buffer, prefill_offset,
+ 0, CeltConstants.Q15ONE, celt_mode.overlap, this.Fs / 400, this.channels, celt_mode.window, this.Fs);
+ Arrays.MemSet(this.delay_buffer, (short) 0, prefill_offset);
+ System.arraycopy(this.delay_buffer, 0, pcm_silk, 0, this.encoder_buffer * this.channels);
+
+ EncodeAPI.silk_Encode(silk_enc, this.silk_mode, pcm_silk, this.encoder_buffer, null, zero, 1);
+ }
+
+ System.arraycopy(pcm_buf, total_buffer * this.channels, pcm_silk, 0, frame_size * this.channels);
+
+ BoxedValueInt boxed_silkBytes = new BoxedValueInt(nBytes);
+ ret = EncodeAPI.silk_Encode(silk_enc, this.silk_mode, pcm_silk, frame_size, enc, boxed_silkBytes, 0);
+ nBytes = boxed_silkBytes.Val;
+
+ if (ret != 0) {
+ /*fprintf (stderr, "SILK encode error: %d\n", ret);*/
+ /* Handle error */
+
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ if (nBytes == 0) {
+ this.rangeFinal = 0;
+ data[data_ptr - 1] = CodecHelpers.gen_toc(this.mode, this.Fs / frame_size, curr_bandwidth, this.stream_channels);
+
+ return 1;
+ }
+ /* Extract SILK public bandwidth for signaling in first byte */
+ if (this.mode == OpusMode.MODE_SILK_ONLY) {
+ if (this.silk_mode.internalSampleRate == 8000) {
+ curr_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
+ } else if (this.silk_mode.internalSampleRate == 12000) {
+ curr_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND;
+ } else if (this.silk_mode.internalSampleRate == 16000) {
+ curr_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND;
+ }
+ } else {
+ Inlines.OpusAssert(this.silk_mode.internalSampleRate == 16000);
+ }
+
+ this.silk_mode.opusCanSwitch = this.silk_mode.switchReady;
+ if (this.silk_mode.opusCanSwitch != 0) {
+ redundancy = 1;
+ celt_to_silk = 0;
+ this.silk_bw_switch = 1;
+ }
+ }
+
+ /* CELT processing */
+ {
+ int endband = 21;
+
+ switch (curr_bandwidth) {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ endband = 13;
+ break;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ case OPUS_BANDWIDTH_WIDEBAND:
+ endband = 17;
+ break;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ endband = 19;
+ break;
+ case OPUS_BANDWIDTH_FULLBAND:
+ endband = 21;
+ break;
+ }
+ celt_enc.SetEndBand(endband);
+ celt_enc.SetChannels(this.stream_channels);
+ }
+ celt_enc.SetBitrate(OpusConstants.OPUS_BITRATE_MAX);
+ if (this.mode != OpusMode.MODE_SILK_ONLY) {
+ int celt_pred = 2;
+ celt_enc.SetVBR(false);
+ /* We may still decide to disable prediction later */
+ if (this.silk_mode.reducedDependency != 0) {
+ celt_pred = 0;
+ }
+ celt_enc.SetPrediction(celt_pred);
+
+ if (this.mode == OpusMode.MODE_HYBRID) {
+ int len;
+
+ len = (enc.tell() + 7) >> 3;
+ if (redundancy != 0) {
+ len += this.mode == OpusMode.MODE_HYBRID ? 3 : 1;
+ }
+ if (this.use_vbr != 0) {
+ nb_compr_bytes = len + bytes_target - (this.silk_mode.bitRate * frame_size) / (8 * this.Fs);
+ } else {
+ /* check if SILK used up too much */
+ nb_compr_bytes = len > bytes_target ? len : bytes_target;
+ }
+ } else if (this.use_vbr != 0) {
+ int bonus = 0;
+ if (this.analysis.enabled && this.variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE && frame_size != this.Fs / 50) {
+ bonus = (60 * this.stream_channels + 40) * (this.Fs / frame_size - 50);
+ if (analysis_info.valid != 0) {
+ bonus = (int) (bonus * (1.0f + .5f * analysis_info.tonality));
+ }
+ }
+ celt_enc.SetVBR(true);
+ celt_enc.SetVBRConstraint(this.vbr_constraint != 0);
+ celt_enc.SetBitrate(this.bitrate_bps + bonus);
+ nb_compr_bytes = max_data_bytes - 1 - redundancy_bytes;
+ } else {
+ nb_compr_bytes = bytes_target;
+ }
+
+ } else {
+ nb_compr_bytes = 0;
+ }
+
+ tmp_prefill = new short[this.channels * this.Fs / 400];
+ if (this.mode != OpusMode.MODE_SILK_ONLY && this.mode != this.prev_mode && (this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN)) {
+ System.arraycopy(this.delay_buffer, ((this.encoder_buffer - total_buffer - this.Fs / 400) * this.channels), tmp_prefill, 0, this.channels * this.Fs / 400);
+ }
+
+ if (this.channels * (this.encoder_buffer - (frame_size + total_buffer)) > 0) {
+ Arrays.MemMove(this.delay_buffer, this.channels * frame_size, 0, this.channels * (this.encoder_buffer - frame_size - total_buffer));
+ System.arraycopy(pcm_buf, 0, this.delay_buffer, (this.channels * (this.encoder_buffer - frame_size - total_buffer)), (frame_size + total_buffer) * this.channels);
+ } else {
+ System.arraycopy(pcm_buf, (frame_size + total_buffer - this.encoder_buffer) * this.channels, this.delay_buffer, 0, this.encoder_buffer * this.channels);
+ }
+
+ /* gain_fade() and stereo_fade() need to be after the buffer copying
+ because we don't want any of this to affect the SILK part */
+ if (this.prev_HB_gain < CeltConstants.Q15ONE || HB_gain < CeltConstants.Q15ONE) {
+ CodecHelpers.gain_fade(pcm_buf, 0,
+ this.prev_HB_gain, HB_gain, celt_mode.overlap, frame_size, this.channels, celt_mode.window, this.Fs);
+ }
+
+ this.prev_HB_gain = HB_gain;
+ if (this.mode != OpusMode.MODE_HYBRID || this.stream_channels == 1) {
+ this.silk_mode.stereoWidth_Q14 = Inlines.IMIN((1 << 14), 2 * Inlines.IMAX(0, equiv_rate - 30000));
+ }
+ if (this.energy_masking == null && this.channels == 2) {
+ /* Apply stereo width reduction (at low bitrates) */
+ if (this.hybrid_stereo_width_Q14 < (1 << 14) || this.silk_mode.stereoWidth_Q14 < (1 << 14)) {
+ int g1, g2;
+ g1 = this.hybrid_stereo_width_Q14;
+ g2 = (this.silk_mode.stereoWidth_Q14);
+ g1 = g1 == 16384 ? CeltConstants.Q15ONE : Inlines.SHL16(g1, 1);
+ g2 = g2 == 16384 ? CeltConstants.Q15ONE : Inlines.SHL16(g2, 1);
+ CodecHelpers.stereo_fade(pcm_buf, g1, g2, celt_mode.overlap,
+ frame_size, this.channels, celt_mode.window, this.Fs);
+ this.hybrid_stereo_width_Q14 = (short) (this.silk_mode.stereoWidth_Q14);
+ }
+ }
+
+ if (this.mode != OpusMode.MODE_CELT_ONLY && enc.tell() + 17 + 20 * ((this.mode == OpusMode.MODE_HYBRID) ? 1 : 0) <= 8 * (max_data_bytes - 1)) {
+ /* For SILK mode, the redundancy is inferred from the length */
+ if (this.mode == OpusMode.MODE_HYBRID && (redundancy != 0 || enc.tell() + 37 <= 8 * nb_compr_bytes)) {
+ enc.enc_bit_logp(redundancy, 12);
+ }
+ if (redundancy != 0) {
+ int max_redundancy;
+ enc.enc_bit_logp(celt_to_silk, 1);
+ if (this.mode == OpusMode.MODE_HYBRID) {
+ max_redundancy = (max_data_bytes - 1) - nb_compr_bytes;
+ } else {
+ max_redundancy = (max_data_bytes - 1) - ((enc.tell() + 7) >> 3);
+ }
+ /* Target the same bit-rate for redundancy as for the rest,
+ up to a max of 257 bytes */
+ redundancy_bytes = Inlines.IMIN(max_redundancy, this.bitrate_bps / 1600);
+ redundancy_bytes = Inlines.IMIN(257, Inlines.IMAX(2, redundancy_bytes));
+ if (this.mode == OpusMode.MODE_HYBRID) {
+ enc.enc_uint(redundancy_bytes - 2, 256);
+ }
+ }
+ } else {
+ redundancy = 0;
+ }
+
+ if (redundancy == 0) {
+ this.silk_bw_switch = 0;
+ redundancy_bytes = 0;
+ }
+ if (this.mode != OpusMode.MODE_CELT_ONLY) {
+ start_band = 17;
+ }
+
+ if (this.mode == OpusMode.MODE_SILK_ONLY) {
+ ret = (enc.tell() + 7) >> 3;
+ enc.enc_done();
+ nb_compr_bytes = ret;
+ } else {
+ nb_compr_bytes = Inlines.IMIN((max_data_bytes - 1) - redundancy_bytes, nb_compr_bytes);
+ enc.enc_shrink(nb_compr_bytes);
+ }
+
+ if (this.analysis.enabled && redundancy != 0 || this.mode != OpusMode.MODE_SILK_ONLY) {
+ analysis_info.enabled = this.analysis.enabled;
+ celt_enc.SetAnalysis(analysis_info);
+ }
+ /* 5 ms redundant frame for CELT->SILK */
+ if (redundancy != 0 && celt_to_silk != 0) {
+ int err;
+ celt_enc.SetStartBand(0);
+ celt_enc.SetVBR(false);
+ err = celt_enc.celt_encode_with_ec(pcm_buf, 0, this.Fs / 200, data, data_ptr + nb_compr_bytes, redundancy_bytes, null);
+ if (err < 0) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ redundant_rng = celt_enc.GetFinalRange();
+ celt_enc.ResetState();
+ }
+
+ celt_enc.SetStartBand(start_band);
+
+ if (this.mode != OpusMode.MODE_SILK_ONLY) {
+ if (this.mode != this.prev_mode && (this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN)) {
+ byte[] dummy = new byte[2];
+ celt_enc.ResetState();
+
+ /* Prefilling */
+ celt_enc.celt_encode_with_ec(tmp_prefill, 0, this.Fs / 400, dummy, 0, 2, null);
+ celt_enc.SetPrediction(0);
+ }
+ /* If false, we already busted the budget and we'll end up with a "PLC packet" */
+ if (enc.tell() <= 8 * nb_compr_bytes) {
+ ret = celt_enc.celt_encode_with_ec(pcm_buf, 0, frame_size, null, 0, nb_compr_bytes, enc);
+ if (ret < 0) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ /* 5 ms redundant frame for SILK->CELT */
+ if (redundancy != 0 && celt_to_silk == 0) {
+ int err;
+ byte[] dummy = new byte[2];
+ int N2, N4;
+ N2 = this.Fs / 200;
+ N4 = this.Fs / 400;
+
+ celt_enc.ResetState();
+ celt_enc.SetStartBand(0);
+ celt_enc.SetPrediction(0);
+
+ /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */
+ celt_enc.celt_encode_with_ec(pcm_buf, (this.channels * (frame_size - N2 - N4)), N4, dummy, 0, 2, null);
+
+ err = celt_enc.celt_encode_with_ec(pcm_buf, (this.channels * (frame_size - N2)), N2, data, data_ptr + nb_compr_bytes, redundancy_bytes, null);
+ if (err < 0) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ redundant_rng = celt_enc.GetFinalRange();
+ }
+
+ /* Signalling the mode in the first byte */
+ data_ptr -= 1;
+ data[data_ptr] = CodecHelpers.gen_toc(this.mode, this.Fs / frame_size, curr_bandwidth, this.stream_channels);
+
+ this.rangeFinal = ((int) enc.rng) ^ redundant_rng;
+
+ if (to_celt != 0) {
+ this.prev_mode = OpusMode.MODE_CELT_ONLY;
+ } else {
+ this.prev_mode = this.mode;
+ }
+ this.prev_channels = this.stream_channels;
+ this.prev_framesize = frame_size;
+
+ this.first = 0;
+
+ /* In the unlikely case that the SILK encoder busted its target, tell
+ the decoder to call the PLC */
+ if (enc.tell() > (max_data_bytes - 1) * 8) {
+ if (max_data_bytes < 2) {
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+ data[data_ptr + 1] = 0;
+ ret = 1;
+ this.rangeFinal = 0;
+ } else if (this.mode == OpusMode.MODE_SILK_ONLY && redundancy == 0) {
+ /*When in LPC only mode it's perfectly
+ reasonable to strip off trailing zero bytes as
+ the required range decoder behavior is to
+ fill these in. This can't be done when the MDCT
+ modes are used because the decoder needs to know
+ the actual length for allocation purposes.*/
+ while (ret > 2 && data[data_ptr + ret] == 0) {
+ ret--;
+ }
+ }
+ /* Count ToC and redundancy */
+ ret += 1 + redundancy_bytes;
+ if (this.use_vbr == 0) {
+ if (OpusRepacketizer.padPacket(data, data_ptr, ret, max_data_bytes) != OpusError.OPUS_OK) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ ret = max_data_bytes;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Encodes an Opus frame, putting the output into a specified data buffer
+ * @param in_pcm 16-bit input signal (Interleaved if stereo), in a short array. Length should be at least frame_size * channels
+ * @param pcm_offset Offset to use when reading the in_pcm buffer
+ * @param frame_size The number of samples _per channel_ in the inpus signal. The frame size must be a valid Opus framesize for the given sample rate.
+ * For example, at 48Khz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10ms
+ * (480 samples at 48Khz) will prevent the encoder from using FEC, DTX, or hybrid modes.
+ * @param out_data Destination buffer for the output payload. This must contain at least max_data_bytes
+ * @param out_data_offset The offset to use when writing to the output data buffer
+ * @param max_data_bytes The maximum amount of space allocated for the output payload. This may be used to impose
+ * an upper limit on the instant bitrate, but should not be used as the only bitrate control (use setBitrate for that)
+ * @return The length of the encoded packet, in bytes
+ * @throws OpusException
+ */
+ public int encode(short[] in_pcm, int pcm_offset, int frame_size,
+ byte[] out_data, int out_data_offset, int max_data_bytes) throws OpusException {
+ // Check that the caller is telling the truth about its input buffers
+ if (out_data_offset + max_data_bytes > out_data.length) {
+ throw new IllegalArgumentException("Output buffer is too small: Stated size is " + max_data_bytes + " bytes, actual size is " + (out_data.length - out_data_offset) + " bytes");
+ }
+
+ int delay_compensation;
+ if (this.application == OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) {
+ delay_compensation = 0;
+ } else {
+ delay_compensation = this.delay_compensation;
+ }
+
+ int internal_frame_size = CodecHelpers.compute_frame_size(in_pcm, pcm_offset, frame_size,
+ this.variable_duration, this.channels, this.Fs, this.bitrate_bps,
+ delay_compensation, this.analysis.subframe_mem, this.analysis.enabled);
+
+ // Check that input pcm length is >= frame_size
+ if (pcm_offset + internal_frame_size > in_pcm.length) {
+ throw new IllegalArgumentException("Not enough samples provided in input signal: Expected " + internal_frame_size + " samples, found " + (in_pcm.length - pcm_offset));
+ }
+
+ try {
+ int ret = opus_encode_native(in_pcm, pcm_offset, internal_frame_size, out_data, out_data_offset, max_data_bytes, 16,
+ in_pcm, pcm_offset, frame_size, 0, -2, this.channels, 0);
+
+ if (ret < 0) {
+ // An error happened; report it
+ if (ret == OpusError.OPUS_BAD_ARG) {
+ throw new IllegalArgumentException("OPUS_BAD_ARG while encoding");
+ }
+ throw new OpusException("An error occurred during encoding", ret);
+ }
+
+ return ret;
+ } catch (ArithmeticException e) {
+ throw new OpusException("Internal error during encoding: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Encodes an Opus frame, putting the output into a specified data buffer
+ * @param in_pcm 16-bit input signal (Interleaved if stereo), in a little endian byte array. Length should be at least frame_size * channels * 2
+ * @param pcm_offset Offset to use when reading the in_pcm buffer
+ * @param frame_size The number of samples _per channel_ in the inpus signal. The frame size must be a valid Opus framesize for the given sample rate.
+ * For example, at 48Khz the permitted values are 120, 240, 480, 960, 1920, and 2880. Passing in a duration of less than 10ms
+ * (480 samples at 48Khz) will prevent the encoder from using FEC, DTX, or hybrid modes.
+ * @param out_data Destination buffer for the output payload. This must contain at least max_data_bytes
+ * @param out_data_offset The offset to use when writing to the output data buffer
+ * @param max_data_bytes The maximum amount of space allocated for the output payload. This may be used to impose
+ * an upper limit on the instant bitrate, but should not be used as the only bitrate control (use setBitrate for that)
+ * @return The length of the encoded packet, in bytes
+ * @throws OpusException
+ */
+ public int encode(byte[] in_pcm, int pcm_offset, int frame_size,
+ byte[] out_data, int out_data_offset, int max_data_bytes) throws OpusException {
+ //Convert byte array to short array
+ short[] spcm = new short[frame_size * channels];
+ for (int c = 0, idx = pcm_offset; c < spcm.length; idx += 2, c++) {
+ spcm[c] = (short) (((in_pcm[idx] & 0xff) | (in_pcm[idx + 1] << 8)) & 0xffff);
+ }
+ return encode(spcm, 0, frame_size, out_data, out_data_offset, max_data_bytes);
+ }
+
+ ///
+ /// Gets or sets the application (or signal type) of the input signal. This hints
+ /// to the encoder what type of details we want to preserve in the encoding.
+ /// This cannot be changed after the encoder has started
+ ///
+ public OpusApplication getApplication() {
+ return application;
+ }
+
+ public void setApplication(OpusApplication value) {
+ if (first == 0 && application != value) {
+ throw new IllegalArgumentException("Application cannot be changed after encoding has started");
+ }
+ application = value;
+ }
+
+ ///
+ /// Gets or sets the bitrate for encoder, in bits per second. Valid bitrates are be between 6K (6144) and 510K (522240)
+ ///
+ public int getBitrate() {
+ return user_bitrate_to_bitrate(prev_framesize, 1276);
+ }
+
+ public void setBitrate(int value) {
+ if (value != OpusConstants.OPUS_AUTO && value != OpusConstants.OPUS_BITRATE_MAX) {
+ if (value <= 0) {
+ throw new IllegalArgumentException("Bitrate must be positive");
+ } else if (value <= 500) {
+ value = 500;
+ } else if (value > 300000 * channels) {
+ value = 300000 * channels;
+ }
+ }
+
+ user_bitrate_bps = value;
+ }
+
+ ///
+ /// Gets or sets the maximum number of channels to be encoded. This can be used to force a downmix from stereo to mono if stereo
+ /// separation is not important
+ ///
+ public int getForceChannels() {
+ return force_channels;
+ }
+
+ public void setForceChannels(int value) {
+ if ((value < 1 || value > channels) && value != OpusConstants.OPUS_AUTO) {
+ throw new IllegalArgumentException("Force channels must be <= num. of channels");
+ }
+
+ force_channels = value;
+ }
+
+ ///
+ /// Gets or sets the maximum bandwidth to be used by the encoder.
+ ///
+ public OpusBandwidth getMaxBandwidth() {
+ return max_bandwidth;
+ }
+
+ public void setMaxBandwidth(OpusBandwidth value) {
+ max_bandwidth = value;
+ if (max_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) {
+ silk_mode.maxInternalSampleRate = 8000;
+ } else if (max_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) {
+ silk_mode.maxInternalSampleRate = 12000;
+ } else {
+ silk_mode.maxInternalSampleRate = 16000;
+ }
+ }
+
+ ///
+ /// Gets or sets the "preferred" encoded bandwidth
+ ///
+ public OpusBandwidth getBandwidth() {
+ return bandwidth;
+ }
+
+ public void setBandwidth(OpusBandwidth value) {
+ user_bandwidth = value;
+ if (user_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) {
+ silk_mode.maxInternalSampleRate = 8000;
+ } else if (user_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) {
+ silk_mode.maxInternalSampleRate = 12000;
+ } else {
+ silk_mode.maxInternalSampleRate = 16000;
+ }
+ }
+
+ ///
+ /// Gets or sets a flag to enable Discontinuous Transmission mode. This mode is only available in the SILK encoder
+ /// (Bitrate < 40Kbit/s and/or ForceMode == SILK). When enabled, the encoder detects silence and background noise
+ /// and reduces the number of output packets, with up to 600ms in between separate packet transmissions.
+ ///
+ public boolean getUseDTX() {
+ return silk_mode.useDTX != 0;
+ }
+
+ public void setUseDTX(boolean value) {
+ silk_mode.useDTX = value ? 1 : 0;
+ }
+
+ ///
+ /// Gets or sets the encoder complexity, between 0 and 10
+ ///
+ public int getComplexity() {
+ return silk_mode.complexity;
+ }
+
+ public void setComplexity(int value) {
+ if (value < 0 || value > 10) {
+ throw new IllegalArgumentException("Complexity must be between 0 and 10");
+ }
+ silk_mode.complexity = value;
+ Celt_Encoder.SetComplexity(value);
+ }
+
+ ///
+ /// Gets or sets a flag to enable Forward Error Correction. This mode is only available in the SILK encoder
+ /// (Bitrate < 40Kbit/s and/or ForceMode == SILK). When enabled, lost packets can be partially recovered
+ /// by decoding data stored in the following packet.
+ ///
+ public boolean getUseInbandFEC() {
+ return silk_mode.useInBandFEC != 0;
+ }
+
+ public void setUseInbandFEC(boolean value) {
+ silk_mode.useInBandFEC = value ? 1 : 0;
+ }
+
+ ///
+ /// Gets or sets the expected amount of packet loss in the transmission medium, from 0 to 100.
+ /// Only applies if UseInbandFEC is also enabled, and the encoder is in SILK mode.
+ ///
+ public int getPacketLossPercent() {
+ return silk_mode.packetLossPercentage;
+ }
+
+ public void setPacketLossPercent(int value) {
+ if (value < 0 || value > 100) {
+ throw new IllegalArgumentException("Packet loss must be between 0 and 100");
+ }
+ silk_mode.packetLossPercentage = value;
+ Celt_Encoder.SetPacketLossPercent(value);
+ }
+
+ ///
+ /// Gets or sets a flag to enable Variable Bitrate encoding. This is recommended as it generally improves audio quality
+ /// with little impact on average bitrate
+ ///
+ public boolean getUseVBR() {
+ return use_vbr != 0;
+ }
+
+ public void setUseVBR(boolean value) {
+ use_vbr = value ? 1 : 0;
+ silk_mode.useCBR = value ? 0 : 1;
+ }
+
+ ///
+ /// Gets or sets a flag to enable constrained VBR. This only applies when the encoder is in CELT mode (i.e. high bitrates)
+ ///
+ public boolean getUseConstrainedVBR() {
+ return vbr_constraint != 0;
+ }
+
+ public void setUseConstrainedVBR(boolean value) {
+ vbr_constraint = value ? 1 : 0;
+ }
+
+ ///
+ /// Gets or sets a hint to the encoder for what type of audio is being processed, voice or music
+ ///
+ public OpusSignal getSignalType() {
+ return signal_type;
+ }
+
+ public void setSignalType(OpusSignal value) {
+ signal_type = value;
+ }
+
+ ///
+ /// Gets the number of samples of audio that are being stored in a buffer and are therefore contributing to latency.
+ ///
+ public int getLookahead() {
+ int returnVal = Fs / 400;
+ if (application != OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) {
+ returnVal += delay_compensation;
+ }
+
+ return returnVal;
+ }
+
+ ///
+ /// Gets the encoder's input sample rate.
+ ///
+ public int getSampleRate() {
+ return Fs;
+ }
+
+ public int getFinalRange() {
+ return rangeFinal;
+ }
+
+ ///
+ /// Gets or sets the bit resolution of the input audio signal. Though the encoder always uses 16-bit internally, this can help
+ /// it make better decisions about bandwidth and cutoff values
+ ///
+ public int getLSBDepth() {
+ return lsb_depth;
+ }
+
+ public void setLSBDepth(int value) {
+ if (value < 8 || value > 24) {
+ throw new IllegalArgumentException("LSB depth must be between 8 and 24");
+ }
+
+ lsb_depth = value;
+ }
+
+ ///
+ /// Gets or sets a fixed length for each encoded frame. Typically, the encoder just chooses a frame duration based on the input length
+ /// and the current mode. This can be used to enforce an exact length if it is required by your application (e.g. monotonous transmission)
+ ///
+ public OpusFramesize getExpertFrameDuration() {
+ return variable_duration;
+ }
+
+ public void setExpertFrameDuration(OpusFramesize value) {
+ variable_duration = value;
+ Celt_Encoder.SetExpertFrameDuration(value);
+ }
+
+ ///
+ /// Gets or sets a user-forced mode for the encoder. There are three modes, SILK, HYBRID, and CELT. Silk can only encode below 40Kbit/s and is best suited
+ /// for speech. Silk also has modes such as FEC which may be desirable. Celt sounds better at higher bandwidth and is comparable to AAC.
+ /// Hybrid is used to create a smooth transition between the two modes. Note that this value may not always be honored due to other factors such
+ /// as frame size and bitrate.
+ ///
+ public OpusMode getForceMode() {
+ return user_forced_mode;
+ }
+
+ public void setForceMode(OpusMode value) {
+ user_forced_mode = value;
+ }
+
+ ///
+ /// Gets or sets a value indicating that this stream is a low-frequency channel. This is used when encoding 5.1 surround audio.
+ ///
+ public boolean getIsLFE() {
+ return lfe != 0;
+ }
+
+ public void setIsLFE(boolean value) {
+ lfe = value ? 1 : 0;
+ Celt_Encoder.SetLFE(value ? 1 : 0);
+ }
+
+ ///
+ /// Gets or sets a flag to enable prediction, which does something.
+ ///
+ public boolean getPredictionDisabled() {
+ return silk_mode.reducedDependency != 0;
+ }
+
+ public void setPredictionDisabled(boolean value) {
+ silk_mode.reducedDependency = value ? 1 : 0;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether neural net analysis functions should be enabled, increasing encode quality
+ /// at the expense of speed.
+ ///
+ public boolean getEnableAnalysis() {
+ return analysis.enabled;
+ }
+
+ public void setEnableAnalysis(boolean value) {
+ analysis.enabled = value;
+ }
+
+ void SetEnergyMask(int[] value) {
+ energy_masking = value;
+ Celt_Encoder.SetEnergyMask(value);
+ }
+
+ CeltMode GetCeltMode() {
+ return Celt_Encoder.GetMode();
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusError.java b/app/src/main/java/org/concentus/OpusError.java
new file mode 100644
index 0000000000..0ebc230aaa
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusError.java
@@ -0,0 +1,82 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+///
+/// Note that since most API-level errors are detected and thrown as
+/// OpusExceptions, direct use of this class is not usually needed
+///
+public class OpusError {
+
+ /**
+ * No error
+ */
+ public static int OPUS_OK = 0;
+
+ /**
+ * One or more invalid/out of range arguments
+ */
+ public static int OPUS_BAD_ARG = -1;
+
+ /**
+ * Not enough bytes allocated in the buffer
+ */
+ public static int OPUS_BUFFER_TOO_SMALL = -2;
+
+ /**
+ * An public error was detected
+ */
+ public static int OPUS_INTERNAL_ERROR = -3;
+
+ /**
+ * The compressed data passed is corrupted
+ */
+ public static int OPUS_INVALID_PACKET = -4;
+
+ /**
+ * Invalid/unsupported request number
+ */
+ public static int OPUS_UNIMPLEMENTED = -5;
+
+ /**
+ * An encoder or decoder structure is invalid or already freed
+ */
+ public static int OPUS_INVALID_STATE = -6;
+
+ /**
+ * Memory allocation has failed
+ */
+ public static int OPUS_ALLOC_FAIL = -7;
+}
diff --git a/app/src/main/java/org/concentus/OpusException.java b/app/src/main/java/org/concentus/OpusException.java
new file mode 100644
index 0000000000..3b6d1f98a5
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusException.java
@@ -0,0 +1,55 @@
+/* Copyright (c) 2016 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.
+ */
+package org.concentus;
+
+public class OpusException extends Exception {
+
+ private String _message;
+ private int _opus_error_code;
+
+ public OpusException() {
+ this("", 0);
+ }
+
+ public OpusException(String message) {
+ this(message, 1);
+ }
+
+ public OpusException(String message, int opus_error_code) {
+ _message = message + ": " + CodecHelpers.opus_strerror(opus_error_code);
+ _opus_error_code = opus_error_code;
+ }
+
+ @Override
+ public String getMessage() {
+ return _message;
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusFramesize.java b/app/src/main/java/org/concentus/OpusFramesize.java
new file mode 100644
index 0000000000..e3b70774e1
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusFramesize.java
@@ -0,0 +1,100 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public enum OpusFramesize {
+ /**
+ * Error state
+ */
+ OPUS_FRAMESIZE_UNKNOWN,
+ ///
+ /// Select frame size from the argument (default)
+ ///
+ OPUS_FRAMESIZE_ARG,
+ ///
+ /// Use 2.5 ms frames
+ ///
+ OPUS_FRAMESIZE_2_5_MS,
+ ///
+ /// Use 5 ms frames
+ ///
+ OPUS_FRAMESIZE_5_MS,
+ ///
+ /// Use 10 ms frames
+ ///
+ OPUS_FRAMESIZE_10_MS,
+ ///
+ /// Use 20 ms frames
+ ///
+ OPUS_FRAMESIZE_20_MS,
+ ///
+ /// Use 40 ms frames
+ ///
+ OPUS_FRAMESIZE_40_MS,
+ ///
+ /// Use 60 ms frames
+ ///
+ OPUS_FRAMESIZE_60_MS,
+ ///
+ /// Do not use - not fully implemented. Optimize the frame size dynamically.
+ ///
+ OPUS_FRAMESIZE_VARIABLE
+}
+
+class OpusFramesizeHelpers {
+
+ static int GetOrdinal(OpusFramesize size) {
+ switch (size) {
+ case OPUS_FRAMESIZE_ARG:
+ return 1;
+ case OPUS_FRAMESIZE_2_5_MS:
+ return 2;
+ case OPUS_FRAMESIZE_5_MS:
+ return 3;
+ case OPUS_FRAMESIZE_10_MS:
+ return 4;
+ case OPUS_FRAMESIZE_20_MS:
+ return 5;
+ case OPUS_FRAMESIZE_40_MS:
+ return 6;
+ case OPUS_FRAMESIZE_60_MS:
+ return 7;
+ case OPUS_FRAMESIZE_VARIABLE:
+ return 8;
+ }
+
+ return -1;
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusMSDecoder.java b/app/src/main/java/org/concentus/OpusMSDecoder.java
new file mode 100644
index 0000000000..f670fbbbc9
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusMSDecoder.java
@@ -0,0 +1,340 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public class OpusMSDecoder {
+
+ ChannelLayout layout = new ChannelLayout();
+ OpusDecoder[] decoders = null;
+
+ private OpusMSDecoder(int nb_streams, int nb_coupled_streams) {
+ decoders = new OpusDecoder[nb_streams];
+ for (int c = 0; c < nb_streams; c++) {
+ decoders[c] = new OpusDecoder();
+ }
+ }
+
+ int opus_multistream_decoder_init(
+ int Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ short[] mapping
+ ) {
+ int i, ret;
+ int decoder_ptr = 0;
+
+ if ((channels > 255) || (channels < 1) || (coupled_streams > streams)
+ || (streams < 1) || (coupled_streams < 0) || (streams > 255 - coupled_streams)) {
+ throw new IllegalArgumentException("Invalid channel or coupled stream count");
+ }
+
+ this.layout.nb_channels = channels;
+ this.layout.nb_streams = streams;
+ this.layout.nb_coupled_streams = coupled_streams;
+
+ for (i = 0; i < this.layout.nb_channels; i++) {
+ this.layout.mapping[i] = mapping[i];
+ }
+ if (OpusMultistream.validate_layout(this.layout) == 0) {
+ throw new IllegalArgumentException("Invalid surround channel layout");
+ }
+
+ for (i = 0; i < this.layout.nb_coupled_streams; i++) {
+ ret = this.decoders[decoder_ptr].opus_decoder_init(Fs, 2);
+ if (ret != OpusError.OPUS_OK) {
+ return ret;
+ }
+ decoder_ptr++;
+ }
+ for (; i < this.layout.nb_streams; i++) {
+ ret = this.decoders[decoder_ptr].opus_decoder_init(Fs, 1);
+ if (ret != OpusError.OPUS_OK) {
+ return ret;
+ }
+ decoder_ptr++;
+ }
+ return OpusError.OPUS_OK;
+ }
+
+ ///
+ /// Creates a new MS decoder
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// A mapping family (just use { 0, 1, 255 })
+ ///
+ public static OpusMSDecoder create(
+ int Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ short[] mapping) throws OpusException {
+ int ret;
+ OpusMSDecoder st;
+ if ((channels > 255) || (channels < 1) || (coupled_streams > streams)
+ || (streams < 1) || (coupled_streams < 0) || (streams > 255 - coupled_streams)) {
+ throw new IllegalArgumentException("Invalid channel / stream configuration");
+ }
+ st = new OpusMSDecoder(streams, coupled_streams);
+ ret = st.opus_multistream_decoder_init(Fs, channels, streams, coupled_streams, mapping);
+ if (ret != OpusError.OPUS_OK) {
+ if (ret == OpusError.OPUS_BAD_ARG) {
+ throw new IllegalArgumentException("Bad argument while creating MS decoder");
+ }
+ throw new OpusException("Could not create MS decoder", ret);
+ }
+ return st;
+ }
+
+ static int opus_multistream_packet_validate(byte[] data, int data_ptr,
+ int len, int nb_streams, int Fs) {
+ int s;
+ int count;
+ BoxedValueByte toc = new BoxedValueByte((byte) 0);
+ short[] size = new short[48];
+ int samples = 0;
+ BoxedValueInt packet_offset = new BoxedValueInt(0);
+ BoxedValueInt dummy = new BoxedValueInt(0);
+
+ for (s = 0; s < nb_streams; s++) {
+ int tmp_samples;
+ if (len <= 0) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+
+ count = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, (s != nb_streams - 1) ? 1 : 0, toc, null, 0,
+ size, 0, dummy, packet_offset);
+ if (count < 0) {
+ return count;
+ }
+
+ tmp_samples = OpusPacketInfo.getNumSamples(data, data_ptr, packet_offset.Val, Fs);
+ if (s != 0 && samples != tmp_samples) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ samples = tmp_samples;
+ data_ptr += packet_offset.Val;
+ len -= packet_offset.Val;
+ }
+
+ return samples;
+ }
+
+ int opus_multistream_decode_native(
+ byte[] data,
+ int data_ptr,
+ int len,
+ short[] pcm,
+ int pcm_ptr,
+ int frame_size,
+ int decode_fec,
+ int soft_clip
+ ) {
+ int Fs;
+ int s, c;
+ int decoder_ptr;
+ int do_plc = 0;
+ short[] buf;
+
+ /* Limit frame_size to avoid excessive stack allocations. */
+ Fs = this.getSampleRate();
+ frame_size = Inlines.IMIN(frame_size, Fs / 25 * 3);
+ buf = new short[2 * frame_size];
+ decoder_ptr = 0;
+
+ if (len == 0) {
+ do_plc = 1;
+ }
+ if (len < 0) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ if (do_plc == 0 && len < 2 * this.layout.nb_streams - 1) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ if (do_plc == 0) {
+ int ret = opus_multistream_packet_validate(data, data_ptr, len, this.layout.nb_streams, Fs);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > frame_size) {
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+ }
+ for (s = 0; s < this.layout.nb_streams; s++) {
+ OpusDecoder dec;
+ int ret;
+
+ dec = this.decoders[decoder_ptr++];
+
+ if (do_plc == 0 && len <= 0) {
+ return OpusError.OPUS_INTERNAL_ERROR;
+ }
+ BoxedValueInt packet_offset = new BoxedValueInt(0);
+ ret = dec.opus_decode_native(
+ data, data_ptr, len, buf, 0, frame_size, decode_fec,
+ (s != this.layout.nb_streams - 1) ? 1 : 0, packet_offset, soft_clip);
+ data_ptr += packet_offset.Val;
+ len -= packet_offset.Val;
+ if (ret <= 0) {
+ return ret;
+ }
+ frame_size = ret;
+ if (s < this.layout.nb_coupled_streams) {
+ int chan, prev;
+ prev = -1;
+ /* Copy "left" audio to the channel(s) where it belongs */
+ while ((chan = OpusMultistream.get_left_channel(this.layout, s, prev)) != -1) {
+ opus_copy_channel_out_short(pcm, pcm_ptr, this.layout.nb_channels, chan,
+ buf, 0, 2, frame_size);
+ prev = chan;
+ }
+ prev = -1;
+ /* Copy "right" audio to the channel(s) where it belongs */
+ while ((chan = OpusMultistream.get_right_channel(this.layout, s, prev)) != -1) {
+ opus_copy_channel_out_short(pcm, pcm_ptr, this.layout.nb_channels, chan,
+ buf, 1, 2, frame_size);
+ prev = chan;
+ }
+ } else {
+ int chan, prev;
+ prev = -1;
+ /* Copy audio to the channel(s) where it belongs */
+ while ((chan = OpusMultistream.get_mono_channel(this.layout, s, prev)) != -1) {
+ opus_copy_channel_out_short(pcm, pcm_ptr, this.layout.nb_channels, chan,
+ buf, 0, 1, frame_size);
+ prev = chan;
+ }
+ }
+ }
+ /* Handle muted channels */
+ for (c = 0; c < this.layout.nb_channels; c++) {
+ if (this.layout.mapping[c] == 255) {
+ opus_copy_channel_out_short(pcm, pcm_ptr, this.layout.nb_channels, c,
+ null, 0, 0, frame_size);
+ }
+ }
+
+ return frame_size;
+ }
+
+ static void opus_copy_channel_out_short(
+ short[] dst,
+ int dst_ptr,
+ int dst_stride,
+ int dst_channel,
+ short[] src,
+ int src_ptr,
+ int src_stride,
+ int frame_size
+ ) {
+ int i;
+ if (src != null) {
+ for (i = 0; i < frame_size; i++) {
+ dst[i * dst_stride + dst_channel + dst_ptr] = src[i * src_stride + src_ptr];
+ }
+ } else {
+ for (i = 0; i < frame_size; i++) {
+ dst[i * dst_stride + dst_channel + dst_ptr] = 0;
+ }
+ }
+ }
+
+ public int decodeMultistream(
+ byte[] data,
+ int data_offset,
+ int len,
+ short[] out_pcm,
+ int out_pcm_offset,
+ int frame_size,
+ int decode_fec
+ ) {
+ return opus_multistream_decode_native(data, data_offset, len,
+ out_pcm, out_pcm_offset, frame_size, decode_fec, 0);
+ }
+
+ public OpusBandwidth getBandwidth() {
+ if (decoders == null || decoders.length == 0) {
+ throw new IllegalStateException("Decoder not initialized");
+ }
+ return decoders[0].getBandwidth();
+ }
+
+ public int getSampleRate() {
+ if (decoders == null || decoders.length == 0) {
+ throw new IllegalStateException("Decoder not initialized");
+ }
+ return decoders[0].getSampleRate();
+ }
+
+ public int getGain() {
+ if (decoders == null || decoders.length == 0) {
+ throw new IllegalStateException("Decoder not initialized");
+ }
+ return decoders[0].getGain();
+ }
+
+ public void setGain(int value) {
+ for (int s = 0; s < layout.nb_streams; s++) {
+ decoders[s].setGain(value);
+ }
+ }
+
+ public int getLastPacketDuration() {
+ if (decoders == null || decoders.length == 0) {
+ return OpusError.OPUS_INVALID_STATE;
+ }
+ return decoders[0].getLastPacketDuration();
+ }
+
+ public int getFinalRange() {
+ int value = 0;
+ for (int s = 0; s < layout.nb_streams; s++) {
+ value ^= decoders[s].getFinalRange();
+ }
+ return value;
+ }
+
+ public void ResetState() {
+ for (int s = 0; s < layout.nb_streams; s++) {
+ decoders[s].resetState();
+ }
+ }
+
+ public OpusDecoder GetMultistreamDecoderState(int streamId) {
+ return decoders[streamId];
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusMSEncoder.java b/app/src/main/java/org/concentus/OpusMSEncoder.java
new file mode 100644
index 0000000000..48a8511256
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusMSEncoder.java
@@ -0,0 +1,947 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public class OpusMSEncoder {
+
+ final ChannelLayout layout = new ChannelLayout();
+ int lfe_stream = 0;
+ OpusApplication application = OpusApplication.OPUS_APPLICATION_AUDIO;
+ OpusFramesize variable_duration = OpusFramesize.OPUS_FRAMESIZE_UNKNOWN;
+ int surround = 0;
+ int bitrate_bps = 0;
+ final float[] subframe_mem = new float[3];
+ OpusEncoder[] encoders = null;
+ int[] window_mem = null;
+ int[] preemph_mem = null;
+
+ private OpusMSEncoder(int nb_streams, int nb_coupled_streams) {
+ if (nb_streams < 1 || nb_coupled_streams > nb_streams || nb_coupled_streams < 0) {
+ throw new IllegalArgumentException("Invalid channel count in MS encoder");
+ }
+
+ encoders = new OpusEncoder[nb_streams];
+ for (int c = 0; c < nb_streams; c++) {
+ encoders[c] = new OpusEncoder();
+ }
+
+ int nb_channels = (nb_coupled_streams * 2) /*stereo channels*/ + (nb_streams - nb_coupled_streams) /*mono channels*/;
+ window_mem = new int[nb_channels * 120];
+ preemph_mem = new int[nb_channels];
+ }
+
+ public void resetState() {
+ int s;
+ subframe_mem[0] = subframe_mem[1] = subframe_mem[2] = 0;
+ if (surround != 0) {
+ Arrays.MemSet(preemph_mem, 0, layout.nb_channels);
+ Arrays.MemSet(window_mem, 0, layout.nb_channels * 120);
+ }
+ int encoder_ptr = 0;
+ for (s = 0; s < layout.nb_streams; s++) {
+ OpusEncoder enc = encoders[encoder_ptr++];
+ enc.resetState();
+ }
+ }
+
+ static int validate_encoder_layout(ChannelLayout layout) {
+ int s;
+ for (s = 0; s < layout.nb_streams; s++) {
+ if (s < layout.nb_coupled_streams) {
+ if (OpusMultistream.get_left_channel(layout, s, -1) == -1) {
+ return 0;
+ }
+ if (OpusMultistream.get_right_channel(layout, s, -1) == -1) {
+ return 0;
+ }
+ } else if (OpusMultistream.get_mono_channel(layout, s, -1) == -1) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ static void channel_pos(int channels, int[] pos/*[8]*/) {
+ /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */
+ if (channels == 4) {
+ pos[0] = 1;
+ pos[1] = 3;
+ pos[2] = 1;
+ pos[3] = 3;
+ } else if (channels == 3 || channels == 5 || channels == 6) {
+ pos[0] = 1;
+ pos[1] = 2;
+ pos[2] = 3;
+ pos[3] = 1;
+ pos[4] = 3;
+ pos[5] = 0;
+ } else if (channels == 7) {
+ pos[0] = 1;
+ pos[1] = 2;
+ pos[2] = 3;
+ pos[3] = 1;
+ pos[4] = 3;
+ pos[5] = 2;
+ pos[6] = 0;
+ } else if (channels == 8) {
+ pos[0] = 1;
+ pos[1] = 2;
+ pos[2] = 3;
+ pos[3] = 1;
+ pos[4] = 3;
+ pos[5] = 1;
+ pos[6] = 3;
+ pos[7] = 0;
+ }
+ }
+
+ private static final int[] diff_table/*[17]*/ = {
+ ((short) (0.5 + (0.5000000f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.5000000f, CeltConstants.DB_SHIFT)*/, ((short) (0.5 + (0.2924813f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.2924813f, CeltConstants.DB_SHIFT)*/, ((short) (0.5 + (0.1609640f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.1609640f, CeltConstants.DB_SHIFT)*/, ((short) (0.5 + (0.0849625f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.0849625f, CeltConstants.DB_SHIFT)*/,
+ ((short) (0.5 + (0.0437314f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.0437314f, CeltConstants.DB_SHIFT)*/, ((short) (0.5 + (0.0221971f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.0221971f, CeltConstants.DB_SHIFT)*/, ((short) (0.5 + (0.0111839f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.0111839f, CeltConstants.DB_SHIFT)*/, ((short) (0.5 + (0.0056136f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.0056136f, CeltConstants.DB_SHIFT)*/,
+ ((short) (0.5 + (0.0028123f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.0028123f, CeltConstants.DB_SHIFT)*/,
+ 0, 0, 0, 0, 0, 0, 0, 0};
+
+ /* Computes a rough approximation of log2(2^a + 2^b) */
+ static int logSum(int a, int b) {
+ int max;
+ int diff;
+ int frac;
+
+ int low;
+ if (a > b) {
+ max = a;
+ diff = Inlines.SUB32(Inlines.EXTEND32(a), Inlines.EXTEND32(b));
+ } else {
+ max = b;
+ diff = Inlines.SUB32(Inlines.EXTEND32(b), Inlines.EXTEND32(a));
+ }
+ if (!(diff < ((short) (0.5 + (8.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(8.0f, CeltConstants.DB_SHIFT)*/)) /* inverted to catch NaNs */ {
+ return max;
+ }
+ low = Inlines.SHR32(diff, CeltConstants.DB_SHIFT - 1);
+ frac = Inlines.SHL16(diff - Inlines.SHL16(low, CeltConstants.DB_SHIFT - 1), 16 - CeltConstants.DB_SHIFT);
+ return max + diff_table[low] + Inlines.MULT16_16_Q15(frac, Inlines.SUB16(diff_table[low + 1], diff_table[low]));
+ }
+
+ // fixme: test the perf of this alternate implementation
+ //int logSum(int a, int b)
+ //{
+ // return log2(pow(4, a) + pow(4, b)) / 2;
+ //}
+ static void surround_analysis(CeltMode celt_mode, short[] pcm, int pcm_ptr,
+ int[] bandLogE, int[] mem, int[] preemph_mem,
+ int len, int overlap, int channels, int rate
+ ) {
+ int c;
+ int i;
+ int LM;
+ int[] pos = {0, 0, 0, 0, 0, 0, 0, 0};
+ int upsample;
+ int frame_size;
+ int channel_offset;
+ int[][] bandE = Arrays.InitTwoDimensionalArrayInt(1, 21);
+ int[][] maskLogE = Arrays.InitTwoDimensionalArrayInt(3, 21);
+ int[] input;
+ short[] x;
+ int[][] freq;
+
+ upsample = CeltCommon.resampling_factor(rate);
+ frame_size = len * upsample;
+
+ for (LM = 0; LM < celt_mode.maxLM; LM++) {
+ if (celt_mode.shortMdctSize << LM == frame_size) {
+ break;
+ }
+ }
+
+ input = new int[frame_size + overlap];
+ x = new short[len];
+ freq = Arrays.InitTwoDimensionalArrayInt(1, frame_size);
+
+ channel_pos(channels, pos);
+
+ for (c = 0; c < 3; c++) {
+ for (i = 0; i < 21; i++) {
+ maskLogE[c][i] = -((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ }
+
+ for (c = 0; c < channels; c++) {
+ System.arraycopy(mem, c * overlap, input, 0, overlap);
+ opus_copy_channel_in_short(x, 0, 1, pcm, pcm_ptr, channels, c, len);
+ BoxedValueInt boxed_preemph = new BoxedValueInt(preemph_mem[c]);
+ CeltCommon.celt_preemphasis(x, input, overlap, frame_size, 1, upsample, celt_mode.preemph, boxed_preemph, 0);
+ preemph_mem[c] = boxed_preemph.Val;
+
+ MDCT.clt_mdct_forward(
+ celt_mode.mdct,
+ input,
+ 0,
+ freq[0],
+ 0,
+ celt_mode.window,
+ overlap,
+ celt_mode.maxLM - LM,
+ 1);
+ if (upsample != 1) {
+ int bound = len;
+ for (i = 0; i < bound; i++) {
+ freq[0][i] *= upsample;
+ }
+ for (; i < frame_size; i++) {
+ freq[0][i] = 0;
+ }
+ }
+
+ Bands.compute_band_energies(celt_mode, freq, bandE, 21, 1, LM);
+ QuantizeBands.amp2Log2(celt_mode, 21, 21, bandE[0], bandLogE, 21 * c, 1);
+ /* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */
+ for (i = 1; i < 21; i++) {
+ bandLogE[21 * c + i] = Inlines.MAX16(bandLogE[21 * c + i], bandLogE[21 * c + i - 1] - ((short) (0.5 + (1.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/);
+ }
+ for (i = 19; i >= 0; i--) {
+ bandLogE[21 * c + i] = Inlines.MAX16(bandLogE[21 * c + i], bandLogE[21 * c + i + 1] - ((short) (0.5 + (2.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(2.0f, CeltConstants.DB_SHIFT)*/);
+ }
+ if (pos[c] == 1) {
+ for (i = 0; i < 21; i++) {
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21 * c + i]);
+ }
+ } else if (pos[c] == 3) {
+ for (i = 0; i < 21; i++) {
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21 * c + i]);
+ }
+ } else if (pos[c] == 2) {
+ for (i = 0; i < 21; i++) {
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21 * c + i] - ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/);
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21 * c + i] - ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/);
+ }
+ }
+ System.arraycopy(input, frame_size, mem, c * overlap, overlap);
+ }
+ for (i = 0; i < 21; i++) {
+ maskLogE[1][i] = Inlines.MIN32(maskLogE[0][i], maskLogE[2][i]);
+ }
+ channel_offset = Inlines.HALF16(Inlines.celt_log2(((int) (0.5 + (2.0f) * (((int) 1) << (14))))/*Inlines.QCONST32(2.0f, 14)*/ / (channels - 1)));
+ for (c = 0; c < 3; c++) {
+ for (i = 0; i < 21; i++) {
+ maskLogE[c][i] += channel_offset;
+ }
+ }
+
+ for (c = 0; c < channels; c++) {
+ int[] mask;
+ if (pos[c] != 0) {
+ mask = maskLogE[pos[c] - 1];
+ for (i = 0; i < 21; i++) {
+ bandLogE[21 * c + i] = bandLogE[21 * c + i] - mask[i];
+ }
+ } else {
+ for (i = 0; i < 21; i++) {
+ bandLogE[21 * c + i] = 0;
+ }
+ }
+ }
+ }
+
+ int opus_multistream_encoder_init(
+ int Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ short[] mapping,
+ OpusApplication application,
+ int surround
+ ) {
+ int i, ret;
+ int encoder_ptr;
+
+ if ((channels > 255) || (channels < 1) || (coupled_streams > streams)
+ || (streams < 1) || (coupled_streams < 0) || (streams > 255 - coupled_streams)) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ this.layout.nb_channels = channels;
+ this.layout.nb_streams = streams;
+ this.layout.nb_coupled_streams = coupled_streams;
+ this.subframe_mem[0] = this.subframe_mem[1] = this.subframe_mem[2] = 0;
+ if (surround == 0) {
+ this.lfe_stream = -1;
+ }
+ this.bitrate_bps = OpusConstants.OPUS_AUTO;
+ this.application = application;
+ this.variable_duration = OpusFramesize.OPUS_FRAMESIZE_ARG;
+ for (i = 0; i < this.layout.nb_channels; i++) {
+ this.layout.mapping[i] = mapping[i];
+ }
+ if (OpusMultistream.validate_layout(this.layout) == 0 || validate_encoder_layout(this.layout) == 0) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ encoder_ptr = 0;
+
+ for (i = 0; i < this.layout.nb_coupled_streams; i++) {
+ ret = this.encoders[encoder_ptr].opus_init_encoder(Fs, 2, application);
+ if (ret != OpusError.OPUS_OK) {
+ return ret;
+ }
+ if (i == this.lfe_stream) {
+ this.encoders[encoder_ptr].setIsLFE(true);
+ }
+ encoder_ptr += 1;
+ }
+ for (; i < this.layout.nb_streams; i++) {
+ ret = this.encoders[encoder_ptr].opus_init_encoder(Fs, 1, application);
+ if (i == this.lfe_stream) {
+ this.encoders[encoder_ptr].setIsLFE(true);
+ }
+ if (ret != OpusError.OPUS_OK) {
+ return ret;
+ }
+ encoder_ptr += 1;
+ }
+ if (surround != 0) {
+ Arrays.MemSet(this.preemph_mem, 0, channels);
+ Arrays.MemSet(this.window_mem, 0, channels * 120);
+ }
+ this.surround = surround;
+ return OpusError.OPUS_OK;
+ }
+
+ int opus_multistream_surround_encoder_init(
+ int Fs,
+ int channels,
+ int mapping_family,
+ BoxedValueInt streams,
+ BoxedValueInt coupled_streams,
+ short[] mapping,
+ OpusApplication application
+ ) {
+ streams.Val = 0;
+ coupled_streams.Val = 0;
+ if ((channels > 255) || (channels < 1)) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ this.lfe_stream = -1;
+ if (mapping_family == 0) {
+ if (channels == 1) {
+ streams.Val = 1;
+ coupled_streams.Val = 0;
+ mapping[0] = 0;
+ } else if (channels == 2) {
+ streams.Val = 1;
+ coupled_streams.Val = 1;
+ mapping[0] = 0;
+ mapping[1] = 1;
+ } else {
+ return OpusError.OPUS_UNIMPLEMENTED;
+ }
+ } else if (mapping_family == 1 && channels <= 8 && channels >= 1) {
+ int i;
+ streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_streams;
+ coupled_streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_coupled_streams;
+ for (i = 0; i < channels; i++) {
+ mapping[i] = VorbisLayout.vorbis_mappings[channels - 1].mapping[i];
+ }
+ if (channels >= 6) {
+ this.lfe_stream = streams.Val - 1;
+ }
+ } else if (mapping_family == 255) {
+ byte i;
+ streams.Val = channels;
+ coupled_streams.Val = 0;
+ for (i = 0; i < channels; i++) {
+ mapping[i] = i;
+ }
+ } else {
+ return OpusError.OPUS_UNIMPLEMENTED;
+ }
+ return opus_multistream_encoder_init(Fs, channels, streams.Val, coupled_streams.Val,
+ mapping, application, (channels > 2 && mapping_family == 1) ? 1 : 0);
+ }
+
+ public static OpusMSEncoder Create(
+ int Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ short[] mapping,
+ OpusApplication application
+ ) throws OpusException {
+ int ret;
+ OpusMSEncoder st;
+ if ((channels > 255) || (channels < 1) || (coupled_streams > streams)
+ || (streams < 1) || (coupled_streams < 0) || (streams > 255 - coupled_streams)) {
+ throw new IllegalArgumentException("Invalid channel / stream configuration");
+ }
+ st = new OpusMSEncoder(streams, coupled_streams);
+ ret = st.opus_multistream_encoder_init(Fs, channels, streams, coupled_streams, mapping, application, 0);
+ if (ret != OpusError.OPUS_OK) {
+ if (ret == OpusError.OPUS_BAD_ARG) {
+ throw new IllegalArgumentException("OPUS_BAD_ARG when creating MS encoder");
+ }
+ throw new OpusException("Could not create MS encoder", ret);
+ }
+ return st;
+ }
+
+ static void GetStreamCount(int channels, int mapping_family, BoxedValueInt nb_streams, BoxedValueInt nb_coupled_streams) {
+ if (mapping_family == 0) {
+ if (channels == 1) {
+ nb_streams.Val = 1;
+ nb_coupled_streams.Val = 0;
+ } else if (channels == 2) {
+ nb_streams.Val = 1;
+ nb_coupled_streams.Val = 1;
+ } else {
+ throw new IllegalArgumentException("More than 2 channels requires custom mappings");
+ }
+ } else if (mapping_family == 1 && channels <= 8 && channels >= 1) {
+ nb_streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_streams;
+ nb_coupled_streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_coupled_streams;
+ } else if (mapping_family == 255) {
+ nb_streams.Val = channels;
+ nb_coupled_streams.Val = 0;
+ } else {
+ throw new IllegalArgumentException("Invalid mapping family");
+ }
+ }
+
+ public static OpusMSEncoder CreateSurround(
+ int Fs,
+ int channels,
+ int mapping_family,
+ BoxedValueInt streams,
+ BoxedValueInt coupled_streams,
+ short[] mapping,
+ OpusApplication application
+ ) throws OpusException {
+ int ret;
+ OpusMSEncoder st;
+ if ((channels > 255) || (channels < 1) || application == OpusApplication.OPUS_APPLICATION_UNIMPLEMENTED) {
+ throw new IllegalArgumentException("Invalid channel count or application");
+ }
+ BoxedValueInt nb_streams = new BoxedValueInt(0);
+ BoxedValueInt nb_coupled_streams = new BoxedValueInt(0);
+ GetStreamCount(channels, mapping_family, nb_streams, nb_coupled_streams);
+
+ st = new OpusMSEncoder(nb_streams.Val, nb_coupled_streams.Val);
+ ret = st.opus_multistream_surround_encoder_init(Fs, channels, mapping_family, streams, coupled_streams, mapping, application);
+ if (ret != OpusError.OPUS_OK) {
+ if (ret == OpusError.OPUS_BAD_ARG) {
+ throw new IllegalArgumentException("Bad argument passed to CreateSurround");
+ }
+ throw new OpusException("Could not create multistream encoder", ret);
+ }
+ return st;
+ }
+
+ int surround_rate_allocation(
+ int[] out_rates,
+ int frame_size
+ ) {
+ int i;
+ int channel_rate;
+ int Fs;
+ OpusEncoder ptr;
+ int stream_offset;
+ int lfe_offset;
+ int coupled_ratio;
+ /* Q8 */
+ int lfe_ratio;
+ /* Q8 */
+ int rate_sum = 0;
+
+ ptr = this.encoders[0];
+ Fs = ptr.getSampleRate();
+
+ if (this.bitrate_bps > this.layout.nb_channels * 40000) {
+ stream_offset = 20000;
+ } else {
+ stream_offset = this.bitrate_bps / this.layout.nb_channels / 2;
+ }
+ stream_offset += 60 * (Fs / frame_size - 50);
+ /* We start by giving each stream (coupled or uncoupled) the same bitrate.
+ This models the main saving of coupled channels over uncoupled. */
+ /* The LFE stream is an exception to the above and gets fewer bits. */
+ lfe_offset = 3500 + 60 * (Fs / frame_size - 50);
+ /* Coupled streams get twice the mono rate after the first 20 kb/s. */
+ coupled_ratio = 512;
+ /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */
+ lfe_ratio = 32;
+
+ /* Compute bitrate allocation between streams */
+ if (this.bitrate_bps == OpusConstants.OPUS_AUTO) {
+ channel_rate = Fs + 60 * Fs / frame_size;
+ } else if (this.bitrate_bps == OpusConstants.OPUS_BITRATE_MAX) {
+ channel_rate = 300000;
+ } else {
+ int nb_lfe;
+ int nb_uncoupled;
+ int nb_coupled;
+ int total;
+ nb_lfe = (this.lfe_stream != -1) ? 1 : 0;
+ nb_coupled = this.layout.nb_coupled_streams;
+ nb_uncoupled = this.layout.nb_streams - nb_coupled - nb_lfe;
+ total = (nb_uncoupled << 8) /* mono */
+ + coupled_ratio * nb_coupled /* stereo */
+ + nb_lfe * lfe_ratio;
+ channel_rate = 256 * (this.bitrate_bps - lfe_offset * nb_lfe - stream_offset * (nb_coupled + nb_uncoupled)) / total;
+ }
+
+ for (i = 0; i < this.layout.nb_streams; i++) {
+ if (i < this.layout.nb_coupled_streams) {
+ out_rates[i] = stream_offset + (channel_rate * coupled_ratio >> 8);
+ } else if (i != this.lfe_stream) {
+ out_rates[i] = stream_offset + channel_rate;
+ } else {
+ out_rates[i] = lfe_offset + (channel_rate * lfe_ratio >> 8);
+ }
+ out_rates[i] = Inlines.IMAX(out_rates[i], 500);
+ rate_sum += out_rates[i];
+ }
+ return rate_sum;
+ }
+
+ /* Max size in case the encoder decides to return three frames */
+ private final int MS_FRAME_TMP = (3 * 1275 + 7);
+
+ int opus_multistream_encode_native(
+ short[] pcm,
+ int pcm_ptr,
+ int analysis_frame_size,
+ byte[] data,
+ int data_ptr,
+ int max_data_bytes,
+ int lsb_depth,
+ int float_api
+ ) {
+ int Fs;
+ int s;
+ int encoder_ptr;
+ int tot_size;
+ short[] buf;
+ int[] bandSMR;
+ byte[] tmp_data = new byte[MS_FRAME_TMP];
+ OpusRepacketizer rp = new OpusRepacketizer();
+ int vbr;
+ CeltMode celt_mode;
+ int[] bitrates = new int[256];
+ int[] bandLogE = new int[42];
+ int[] mem = null;
+ int[] preemph_mem = null;
+ int frame_size;
+ int rate_sum;
+ int smallest_packet;
+
+ if (this.surround != 0) {
+ preemph_mem = this.preemph_mem;
+ mem = this.window_mem;
+ }
+
+ encoder_ptr = 0;
+ Fs = this.encoders[encoder_ptr].getSampleRate();
+ vbr = this.encoders[encoder_ptr].getUseVBR() ? 1 : 0;
+ celt_mode = this.encoders[encoder_ptr].GetCeltMode();
+
+ {
+ int delay_compensation;
+ int channels;
+
+ channels = this.layout.nb_streams + this.layout.nb_coupled_streams;
+ delay_compensation = this.encoders[encoder_ptr].getLookahead();
+ delay_compensation -= Fs / 400;
+ frame_size = CodecHelpers.compute_frame_size(pcm, pcm_ptr, analysis_frame_size,
+ this.variable_duration, channels, Fs, this.bitrate_bps,
+ delay_compensation, this.subframe_mem, this.encoders[encoder_ptr].analysis.enabled);
+ }
+
+ if (400 * frame_size < Fs) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ /* Validate frame_size before using it to allocate stack space.
+ This mirrors the checks in opus_encode[_float](). */
+ if (400 * frame_size != Fs && 200 * frame_size != Fs
+ && 100 * frame_size != Fs && 50 * frame_size != Fs
+ && 25 * frame_size != Fs && 50 * frame_size != 3 * Fs) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ /* Smallest packet the encoder can produce. */
+ smallest_packet = this.layout.nb_streams * 2 - 1;
+ if (max_data_bytes < smallest_packet) {
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+ buf = new short[2 * frame_size];
+
+ bandSMR = new int[21 * this.layout.nb_channels];
+ if (this.surround != 0) {
+ surround_analysis(celt_mode, pcm, pcm_ptr, bandSMR, mem, preemph_mem, frame_size, 120, this.layout.nb_channels, Fs);
+ }
+
+ /* Compute bitrate allocation between streams (this could be a lot better) */
+ rate_sum = surround_rate_allocation(bitrates, frame_size);
+
+ if (vbr == 0) {
+ if (this.bitrate_bps == OpusConstants.OPUS_AUTO) {
+ max_data_bytes = Inlines.IMIN(max_data_bytes, 3 * rate_sum / (3 * 8 * Fs / frame_size));
+ } else if (this.bitrate_bps != OpusConstants.OPUS_BITRATE_MAX) {
+ max_data_bytes = Inlines.IMIN(max_data_bytes, Inlines.IMAX(smallest_packet,
+ 3 * this.bitrate_bps / (3 * 8 * Fs / frame_size)));
+ }
+ }
+
+ for (s = 0; s < this.layout.nb_streams; s++) {
+ OpusEncoder enc = this.encoders[encoder_ptr];
+ encoder_ptr += 1;
+ enc.setBitrate(bitrates[s]);
+ if (this.surround != 0) {
+ int equiv_rate;
+ equiv_rate = this.bitrate_bps;
+ if (frame_size * 50 < Fs) {
+ equiv_rate -= 60 * (Fs / frame_size - 50) * this.layout.nb_channels;
+ }
+ if (equiv_rate > 10000 * this.layout.nb_channels) {
+ enc.setBandwidth(OpusBandwidth.OPUS_BANDWIDTH_FULLBAND);
+ } else if (equiv_rate > 7000 * this.layout.nb_channels) {
+ enc.setBandwidth(OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND);
+ } else if (equiv_rate > 5000 * this.layout.nb_channels) {
+ enc.setBandwidth(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND);
+ } else {
+ enc.setBandwidth(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND);
+ }
+ if (s < this.layout.nb_coupled_streams) {
+ /* To preserve the spatial image, force stereo CELT on coupled streams */
+ enc.setForceMode(OpusMode.MODE_CELT_ONLY);
+ enc.setForceChannels(2);
+ }
+ }
+ }
+
+ encoder_ptr = 0;
+ /* Counting ToC */
+ tot_size = 0;
+ for (s = 0; s < this.layout.nb_streams; s++) {
+ OpusEncoder enc;
+ int len;
+ int curr_max;
+ int c1, c2;
+
+ rp.Reset();
+ enc = this.encoders[encoder_ptr];
+ if (s < this.layout.nb_coupled_streams) {
+ int i;
+ int left, right;
+ left = OpusMultistream.get_left_channel(this.layout, s, -1);
+ right = OpusMultistream.get_right_channel(this.layout, s, -1);
+ opus_copy_channel_in_short(buf, 0, 2,
+ pcm, pcm_ptr, this.layout.nb_channels, left, frame_size);
+ opus_copy_channel_in_short(buf, 1, 2,
+ pcm, pcm_ptr, this.layout.nb_channels, right, frame_size);
+ encoder_ptr += 1;
+ if (this.surround != 0) {
+ for (i = 0; i < 21; i++) {
+ bandLogE[i] = bandSMR[21 * left + i];
+ bandLogE[21 + i] = bandSMR[21 * right + i];
+ }
+ }
+ c1 = left;
+ c2 = right;
+ } else {
+ int i;
+ int chan = OpusMultistream.get_mono_channel(this.layout, s, -1);
+ opus_copy_channel_in_short(buf, 0, 1,
+ pcm, pcm_ptr, this.layout.nb_channels, chan, frame_size);
+ encoder_ptr += 1;
+ if (this.surround != 0) {
+ for (i = 0; i < 21; i++) {
+ bandLogE[i] = bandSMR[21 * chan + i];
+ }
+ }
+ c1 = chan;
+ c2 = -1;
+ }
+ if (this.surround != 0) {
+ enc.SetEnergyMask(bandLogE);
+ }
+
+ /* number of bytes left (+Toc) */
+ curr_max = max_data_bytes - tot_size;
+ /* Reserve one byte for the last stream and two for the others */
+ curr_max -= Inlines.IMAX(0, 2 * (this.layout.nb_streams - s - 1) - 1);
+ curr_max = Inlines.IMIN(curr_max, MS_FRAME_TMP);
+ /* Repacketizer will add one or two bytes for self-delimited frames */
+ if (s != this.layout.nb_streams - 1) {
+ curr_max -= curr_max > 253 ? 2 : 1;
+ }
+ if (vbr == 0 && s == this.layout.nb_streams - 1) {
+ enc.setBitrate(curr_max * (8 * Fs / frame_size));
+ }
+ len = enc.opus_encode_native(buf, 0, frame_size, tmp_data, 0, curr_max, lsb_depth,
+ pcm, pcm_ptr, analysis_frame_size, c1, c2, this.layout.nb_channels, float_api);
+ if (len < 0) {
+ return len;
+ }
+ /* We need to use the repacketizer to add the self-delimiting lengths
+ while taking into account the fact that the encoder can now return
+ more than one frame at a time (e.g. 60 ms CELT-only) */
+ rp.addPacket(tmp_data, 0, len);
+ len = rp.opus_repacketizer_out_range_impl(0, rp.getNumFrames(),
+ data, data_ptr, max_data_bytes - tot_size, (s != this.layout.nb_streams - 1) ? 1 : 0, (vbr == 0 && s == this.layout.nb_streams - 1) ? 1 : 0);
+ data_ptr += len;
+ tot_size += len;
+ }
+
+ return tot_size;
+ }
+
+ static void opus_copy_channel_in_short(
+ short[] dst,
+ int dst_ptr,
+ int dst_stride,
+ short[] src,
+ int src_ptr,
+ int src_stride,
+ int src_channel,
+ int frame_size
+ ) {
+ int i;
+ for (i = 0; i < frame_size; i++) {
+ dst[dst_ptr + i * dst_stride] = src[i * src_stride + src_channel + src_ptr];
+ }
+ }
+
+ public int encodeMultistream(
+ short[] pcm,
+ int pcm_offset,
+ int frame_size,
+ byte[] outputBuffer,
+ int outputBuffer_offset,
+ int max_data_bytes
+ ) {
+ // todo: catch error codes here
+ return opus_multistream_encode_native(pcm, pcm_offset, frame_size, outputBuffer, outputBuffer_offset, max_data_bytes, 16, 0);
+ }
+
+ public int getBitrate() {
+ int s;
+ int value = 0;
+ int encoder_ptr = 0;
+ for (s = 0; s < layout.nb_streams; s++) {
+ OpusEncoder enc = encoders[encoder_ptr++];
+ value += enc.getBitrate();
+ }
+ return value;
+ }
+
+ public void setBitrate(int value) {
+ if (value < 0 && value != OpusConstants.OPUS_AUTO && value != OpusConstants.OPUS_BITRATE_MAX) {
+ throw new IllegalArgumentException("Invalid bitrate");
+ }
+ bitrate_bps = value;
+ }
+
+ public OpusApplication getApplication() {
+ return encoders[0].getApplication();
+ }
+
+ public void setApplication(OpusApplication value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setApplication(value);
+ }
+ }
+
+ public int getForceChannels() {
+ return encoders[0].getForceChannels();
+ }
+
+ public void setForceChannels(int value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setForceChannels(value);
+ }
+ }
+
+ public OpusBandwidth getMaxBandwidth() {
+ return encoders[0].getMaxBandwidth();
+ }
+
+ public void setMaxBandwidth(OpusBandwidth value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setMaxBandwidth(value);
+ }
+ }
+
+ public OpusBandwidth getBandwidth() {
+ return encoders[0].getBandwidth();
+ }
+
+ public void setBandwidth(OpusBandwidth value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setBandwidth(value);
+ }
+ }
+
+ public boolean getUseDTX() {
+ return encoders[0].getUseDTX();
+ }
+
+ public void setUseDTX(boolean value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setUseDTX(value);
+ }
+ }
+
+ public int getComplexity() {
+ return encoders[0].getComplexity();
+ }
+
+ public void setComplexity(int value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setComplexity(value);
+ }
+ }
+
+ public OpusMode getForceMode() {
+ return encoders[0].getForceMode();
+ }
+
+ public void setForceMode(OpusMode value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setForceMode(value);
+ }
+ }
+
+ public boolean getUseInbandFEC() {
+ return encoders[0].getUseInbandFEC();
+ }
+
+ public void setUseInbandFEC(boolean value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setUseInbandFEC(value);
+ }
+ }
+
+ public int getPacketLossPercent() {
+ return encoders[0].getPacketLossPercent();
+ }
+
+ public void setPacketLossPercent(int value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setPacketLossPercent(value);
+ }
+ }
+
+ public boolean getUseVBR() {
+ return encoders[0].getUseVBR();
+ }
+
+ public void setUseVBR(boolean value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setUseVBR(value);
+ }
+ }
+
+ public boolean getUseConstrainedVBR() {
+ return encoders[0].getUseConstrainedVBR();
+ }
+
+ public void setUseConstrainedVBR(boolean value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setUseConstrainedVBR(value);
+ }
+ }
+
+ public OpusSignal getSignalType() {
+ return encoders[0].getSignalType();
+ }
+
+ public void setSignalType(OpusSignal value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setSignalType(value);
+ }
+ }
+
+ public int getLookahead() {
+ return encoders[0].getLookahead();
+ }
+
+ public int getSampleRate() {
+ return encoders[0].getSampleRate();
+ }
+
+ public int getFinalRange() {
+ int s;
+ int value = 0;
+ int encoder_ptr = 0;
+ for (s = 0; s < layout.nb_streams; s++) {
+ value ^= encoders[encoder_ptr++].getFinalRange();
+ }
+ return value;
+ }
+
+ public int getLSBDepth() {
+ return encoders[0].getLSBDepth();
+ }
+
+ public void setLSBDepth(int value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setLSBDepth(value);
+ }
+ }
+
+ public boolean getPredictionDisabled() {
+ return encoders[0].getPredictionDisabled();
+ }
+
+ public void setPredictionDisabled(boolean value) {
+ for (int encoder_ptr = 0; encoder_ptr < layout.nb_streams; encoder_ptr++) {
+ encoders[encoder_ptr].setPredictionDisabled(value);
+ }
+ }
+
+ public OpusFramesize getExpertFrameDuration() {
+ return variable_duration;
+ }
+
+ public void setExpertFrameDuration(OpusFramesize value) {
+ variable_duration = value;
+ }
+
+ public OpusEncoder getMultistreamEncoderState(int streamId) {
+ if (streamId >= layout.nb_streams) {
+ throw new IllegalArgumentException("Requested stream doesn't exist");
+ }
+ return encoders[streamId];
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusMode.java b/app/src/main/java/org/concentus/OpusMode.java
new file mode 100644
index 0000000000..c163bb3f1a
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusMode.java
@@ -0,0 +1,43 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public enum OpusMode {
+ MODE_UNKNOWN,
+ MODE_AUTO,
+ MODE_SILK_ONLY,
+ MODE_HYBRID,
+ MODE_CELT_ONLY
+}
diff --git a/app/src/main/java/org/concentus/OpusMultistream.java b/app/src/main/java/org/concentus/OpusMultistream.java
new file mode 100644
index 0000000000..a8c79227cb
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusMultistream.java
@@ -0,0 +1,86 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class OpusMultistream {
+
+ static int validate_layout(ChannelLayout layout) {
+ int i, max_channel;
+
+ max_channel = layout.nb_streams + layout.nb_coupled_streams;
+ if (max_channel > 255) {
+ return 0;
+ }
+ for (i = 0; i < layout.nb_channels; i++) {
+ if (layout.mapping[i] >= max_channel && layout.mapping[i] != 255) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ static int get_left_channel(ChannelLayout layout, int stream_id, int prev) {
+ int i;
+ i = (prev < 0) ? 0 : prev + 1;
+ for (; i < layout.nb_channels; i++) {
+ if (layout.mapping[i] == stream_id * 2) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ static int get_right_channel(ChannelLayout layout, int stream_id, int prev) {
+ int i;
+ i = (prev < 0) ? 0 : prev + 1;
+ for (; i < layout.nb_channels; i++) {
+ if (layout.mapping[i] == stream_id * 2 + 1) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ static int get_mono_channel(ChannelLayout layout, int stream_id, int prev) {
+ int i;
+ i = (prev < 0) ? 0 : prev + 1;
+ for (; i < layout.nb_channels; i++) {
+ if (layout.mapping[i] == stream_id + layout.nb_coupled_streams) {
+ return i;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusPacketInfo.java b/app/src/main/java/org/concentus/OpusPacketInfo.java
new file mode 100644
index 0000000000..8a9c2f2677
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusPacketInfo.java
@@ -0,0 +1,411 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class OpusPacketInfo {
+
+ /**
+ * The Table of Contents byte for this packet. Contains info about modes, frame length, etc.
+ */
+ public byte TOCByte;
+
+ /**
+ * The list of subframes in this packet
+ */
+ public List Frames;
+
+ /**
+ * The index of the start of the payload within the packet
+ */
+ public int PayloadOffset;
+
+ private OpusPacketInfo(byte toc, List frames, int payloadOffset) {
+ TOCByte = toc;
+ Frames = frames;
+ PayloadOffset = payloadOffset;
+ }
+
+ /**
+ * Parse an opus packet into a packetinfo object containing one or more frames.
+ * Opus_decode will perform this operation internally so most applications do
+ * not need to use this function.
+ * @param packet The packet data to be parsed
+ * @param packet_offset The index of the beginning of the packet in the data array (usually 0)
+ * @param len The packet's length
+ * @return A parsed packet info struct
+ * @throws OpusException
+ */
+ public static OpusPacketInfo parseOpusPacket(byte[] packet, int packet_offset, int len) throws OpusException {
+ // Find the number of frames first
+ int numFrames = getNumFrames(packet, packet_offset, len);
+
+ BoxedValueInt payload_offset = new BoxedValueInt(0);
+ BoxedValueByte out_toc = new BoxedValueByte((byte) 0);
+ byte[][] frames = new byte[numFrames][];
+ short[] size = new short[numFrames];
+ BoxedValueInt packetOffset = new BoxedValueInt(0);
+ int error = opus_packet_parse_impl(packet, packet_offset, len, 0, out_toc, frames, 0, size, 0, payload_offset, packetOffset);
+ if (error < 0) {
+ throw new OpusException("An error occurred while parsing the packet", error);
+ }
+
+ // Since packet_parse_impl has created deep copies of each frame, we can return them safely from this function without
+ // worrying about variable scoping or side effects
+ ArrayList copiedFrames = new ArrayList();
+ for (int c = 0; c < frames.length; c++) {
+ // Java does not let us unbox an array (?) so we have to copy the bytes _again
+ Byte[] convertedFrame = new Byte[frames[c].length];
+ for (int d = 0; d < convertedFrame.length; d++) {
+ convertedFrame[d] = frames[c][d];
+ }
+ copiedFrames.add(convertedFrame);
+ }
+
+ return new OpusPacketInfo(out_toc.Val, copiedFrames, payload_offset.Val);
+ }
+
+ public static int getNumSamplesPerFrame(byte[] packet, int packet_offset, int Fs) {
+ int audiosize;
+ if ((packet[packet_offset] & 0x80) != 0) {
+ audiosize = ((packet[packet_offset] >> 3) & 0x3);
+ audiosize = (Fs << audiosize) / 400;
+ } else if ((packet[packet_offset] & 0x60) == 0x60) {
+ audiosize = ((packet[packet_offset] & 0x08) != 0) ? Fs / 50 : Fs / 100;
+ } else {
+ audiosize = ((packet[packet_offset] >> 3) & 0x3);
+ if (audiosize == 3) {
+ audiosize = Fs * 60 / 1000;
+ } else {
+ audiosize = (Fs << audiosize) / 100;
+ }
+ }
+ return audiosize;
+ }
+
+ ///
+ /// Gets the encoded bandwidth of an Opus packet. Note that you are not forced to decode at this bandwidth
+ ///
+ /// An Opus packet (must be at least 1 byte)
+ /// An OpusBandwidth value
+ public static OpusBandwidth getBandwidth(byte[] packet, int packet_offset) {
+ OpusBandwidth bandwidth;
+ if ((packet[packet_offset] & 0x80) != 0) {
+ bandwidth = OpusBandwidthHelpers.GetBandwidth(OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) + ((packet[packet_offset] >> 5) & 0x3));
+ if (bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) {
+ bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
+ }
+ } else if ((packet[packet_offset] & 0x60) == 0x60) {
+ bandwidth = ((packet[packet_offset] & 0x10) != 0) ? OpusBandwidth.OPUS_BANDWIDTH_FULLBAND
+ : OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND;
+ } else {
+ bandwidth = OpusBandwidthHelpers.GetBandwidth(OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) + ((packet[packet_offset] >> 5) & 0x3));
+ }
+ return bandwidth;
+ }
+
+ public static int getNumEncodedChannels(byte[] packet, int packet_offset) {
+ return ((packet[packet_offset] & 0x4) != 0) ? 2 : 1;
+ }
+
+ ///
+ /// Gets the number of frames in an Opus packet.
+ ///
+ /// An Opus packet
+ /// The packet's length (must be at least 1)
+ /// The number of frames in the packet
+ public static int getNumFrames(byte[] packet, int packet_offset, int len) {
+ int count;
+ if (len < 1) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ count = packet[packet_offset] & 0x3;
+ if (count == 0) {
+ return 1;
+ } else if (count != 3) {
+ return 2;
+ } else if (len < 2) {
+ return OpusError.OPUS_INVALID_PACKET;
+ } else {
+ return packet[packet_offset + 1] & 0x3F;
+ }
+ }
+
+ public static int getNumSamples(byte[] packet, int packet_offset, int len,
+ int Fs) {
+ int samples;
+ int count = getNumFrames(packet, packet_offset, len);
+
+ if (count < 0) {
+ return count;
+ }
+
+ samples = count * getNumSamplesPerFrame(packet, packet_offset, Fs);
+ /* Can't have more than 120 ms */
+ if (samples * 25 > Fs * 3) {
+ return OpusError.OPUS_INVALID_PACKET;
+ } else {
+ return samples;
+ }
+ }
+
+ ///
+ /// Gets the number of samples of an Opus packet.
+ ///
+ /// Your current decoder state
+ /// An Opus packet
+ /// The packet's length
+ /// The size of the PCM samples that this packet will be decoded to by the specified decoder
+ public static int getNumSamples(OpusDecoder dec,
+ byte[] packet, int packet_offset, int len) {
+ return getNumSamples(packet, packet_offset, len, dec.Fs);
+ }
+
+ public static OpusMode getEncoderMode(byte[] packet, int packet_offset) {
+ OpusMode mode;
+ if ((packet[packet_offset] & 0x80) != 0) {
+ mode = OpusMode.MODE_CELT_ONLY;
+ } else if ((packet[packet_offset] & 0x60) == 0x60) {
+ mode = OpusMode.MODE_HYBRID;
+ } else {
+ mode = OpusMode.MODE_SILK_ONLY;
+ }
+ return mode;
+ }
+
+ static int encode_size(int size, byte[] data, int data_ptr) {
+ if (size < 252) {
+ data[data_ptr] = (byte) (size & 0xFF);
+ return 1;
+ } else {
+ int dp1 = 252 + (size & 0x3);
+ data[data_ptr] = (byte) (dp1 & 0xFF);
+ data[data_ptr + 1] = (byte) ((size - dp1) >> 2);
+ return 2;
+ }
+ }
+
+ static int parse_size(byte[] data, int data_ptr, int len, BoxedValueShort size) {
+ if (len < 1) {
+ size.Val = -1;
+ return -1;
+ } else if (Inlines.SignedByteToUnsignedInt(data[data_ptr]) < 252) {
+ size.Val = (short) Inlines.SignedByteToUnsignedInt(data[data_ptr]);
+ return 1;
+ } else if (len < 2) {
+ size.Val = -1;
+ return -1;
+ } else {
+ size.Val = (short) (4 * Inlines.SignedByteToUnsignedInt(data[data_ptr + 1]) + Inlines.SignedByteToUnsignedInt(data[data_ptr]));
+ return 2;
+ }
+ }
+
+ static int opus_packet_parse_impl(byte[] data, int data_ptr, int len,
+ int self_delimited, BoxedValueByte out_toc,
+ byte[][] frames, int frames_ptr, short[] sizes, int sizes_ptr,
+ BoxedValueInt payload_offset, BoxedValueInt packet_offset) {
+ int i, bytes;
+ int count;
+ int cbr;
+ byte toc;
+ int ch;
+ int framesize;
+ int last_size;
+ int pad = 0;
+ int data0 = data_ptr;
+ out_toc.Val = 0;
+ payload_offset.Val = 0;
+ packet_offset.Val = 0;
+
+ if (sizes == null || len < 0) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ if (len == 0) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+
+ framesize = getNumSamplesPerFrame(data, data_ptr, 48000);
+
+ cbr = 0;
+ toc = data[data_ptr++];
+ len--;
+ last_size = len;
+ switch (toc & 0x3) {
+ /* One frame */
+ case 0:
+ count = 1;
+ break;
+ /* Two CBR frames */
+ case 1:
+ count = 2;
+ cbr = 1;
+ if (self_delimited == 0) {
+ if ((len & 0x1) != 0) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ last_size = len / 2;
+ /* If last_size doesn't fit in size[0], we'll catch it later */
+ sizes[sizes_ptr] = (short) last_size;
+ }
+ break;
+ /* Two VBR frames */
+ case 2:
+ count = 2;
+ BoxedValueShort boxed_size = new BoxedValueShort(sizes[sizes_ptr]);
+ bytes = parse_size(data, data_ptr, len, boxed_size);
+ sizes[sizes_ptr] = boxed_size.Val;
+ len -= bytes;
+ if (sizes[sizes_ptr] < 0 || sizes[sizes_ptr] > len) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ data_ptr += bytes;
+ last_size = len - sizes[sizes_ptr];
+ break;
+ /* Multiple CBR/VBR frames (from 0 to 120 ms) */
+ default:
+ /*case 3:*/
+ if (len < 1) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ /* Number of frames encoded in bits 0 to 5 */
+ ch = Inlines.SignedByteToUnsignedInt(data[data_ptr++]);
+ count = ch & 0x3F;
+ if (count <= 0 || framesize * count > 5760) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ len--;
+ /* Padding flag is bit 6 */
+ if ((ch & 0x40) != 0) {
+ int p;
+ do {
+ int tmp;
+ if (len <= 0) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ p = Inlines.SignedByteToUnsignedInt(data[data_ptr++]);
+ len--;
+ tmp = p == 255 ? 254 : p;
+ len -= tmp;
+ pad += tmp;
+ } while (p == 255);
+ }
+ if (len < 0) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ /* VBR flag is bit 7 */
+ cbr = (ch & 0x80) != 0 ? 0 : 1;
+ if (cbr == 0) {
+ /* VBR case */
+ last_size = len;
+ for (i = 0; i < count - 1; i++) {
+ boxed_size = new BoxedValueShort(sizes[sizes_ptr + i]);
+ bytes = parse_size(data, data_ptr, len, boxed_size);
+ sizes[sizes_ptr + i] = boxed_size.Val;
+ len -= bytes;
+ if (sizes[sizes_ptr + i] < 0 || sizes[sizes_ptr + i] > len) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ data_ptr += bytes;
+ last_size -= bytes + sizes[sizes_ptr + i];
+ }
+ if (last_size < 0) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ } else if (self_delimited == 0) {
+ /* CBR case */
+ last_size = len / count;
+ if (last_size * count != len) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ for (i = 0; i < count - 1; i++) {
+ sizes[sizes_ptr + i] = (short) last_size;
+ }
+ }
+ break;
+ }
+
+ /* Self-delimited framing has an extra size for the last frame. */
+ if (self_delimited != 0) {
+ BoxedValueShort boxed_size = new BoxedValueShort(sizes[sizes_ptr + count - 1]);
+ bytes = parse_size(data, data_ptr, len, boxed_size);
+ sizes[sizes_ptr + count - 1] = boxed_size.Val;
+ len -= bytes;
+ if (sizes[sizes_ptr + count - 1] < 0 || sizes[sizes_ptr + count - 1] > len) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ data_ptr += bytes;
+ /* For CBR packets, apply the size to all the frames. */
+ if (cbr != 0) {
+ if (sizes[sizes_ptr + count - 1] * count > len) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ for (i = 0; i < count - 1; i++) {
+ sizes[sizes_ptr + i] = sizes[sizes_ptr + count - 1];
+ }
+ } else if (bytes + sizes[sizes_ptr + count - 1] > last_size) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ } else {
+ /* Because it's not encoded explicitly, it's possible the size of the
+ last packet (or all the packets, for the CBR case) is larger than
+ 1275. Reject them here.*/
+ if (last_size > 1275) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ sizes[sizes_ptr + count - 1] = (short) last_size;
+ }
+
+ payload_offset.Val = (int) (data_ptr - data0);
+
+ for (i = 0; i < count; i++) {
+ if (frames != null) {
+ // The old code returned pointers to the single data array, but that can cause unwanted side effects.
+ // So I have replaced it with this code that creates a new copy of each frame. Slower, but more robust
+ frames[frames_ptr + i] = new byte[data.length - data_ptr];
+ System.arraycopy(data, data_ptr, frames[frames_ptr + i], 0, data.length - data_ptr);
+ }
+ data_ptr += sizes[sizes_ptr + i];
+ }
+
+ packet_offset.Val = pad + (int) (data_ptr - data0);
+
+ out_toc.Val = toc;
+
+ return count;
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusRepacketizer.java b/app/src/main/java/org/concentus/OpusRepacketizer.java
new file mode 100644
index 0000000000..4eb65deec1
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusRepacketizer.java
@@ -0,0 +1,547 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public class OpusRepacketizer {
+
+ byte toc = 0;
+ int nb_frames = 0;
+ final byte[][] frames = new byte[48][];
+ final short[] len = new short[48];
+ int framesize = 0;
+
+ /**
+ * (Re)initializes a previously allocated repacketizer state. The state must
+ * be at least the size returned by opus_repacketizer_get_size(). This can
+ * be used for applications which use their own allocator instead of
+ * malloc(). It must also be called to reset the queue of packets waiting to
+ * be repacketized, which is necessary if the maximum packet duration of 120
+ * ms is reached or if you wish to submit packets with a different Opus
+ * configuration (coding mode, audio bandwidth, frame size, or channel
+ * count). Failure to do so will prevent a new packet from being added with
+ * opus_repacketizer_cat().
+ *
+ * @see opus_repacketizer_create
+ * @see opus_repacketizer_get_size
+ * @see opus_repacketizer_cat
+ * @param rp OpusRepacketizer*: The repacketizer state to
+ * (re)initialize.
+ */
+ public void Reset() {
+ this.nb_frames = 0;
+ }
+
+ /**
+ * Allocates memory and initializes the new repacketizer with
+ * opus_repacketizer_init().
+ */
+ public OpusRepacketizer() {
+ this.Reset();
+ }
+
+ int opus_repacketizer_cat_impl(byte[] data, int data_ptr, int len, int self_delimited) {
+ BoxedValueByte dummy_toc = new BoxedValueByte((byte) 0);
+ BoxedValueInt dummy_offset = new BoxedValueInt(0);
+ int curr_nb_frames, ret;
+ /* Set of check ToC */
+ if (len < 1) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+
+ if (this.nb_frames == 0) {
+ this.toc = data[data_ptr];
+ this.framesize = OpusPacketInfo.getNumSamplesPerFrame(data, data_ptr, 8000);
+ } else if ((this.toc & 0xFC) != (data[data_ptr] & 0xFC)) {
+ /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp.toc, data[0]);*/
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ curr_nb_frames = OpusPacketInfo.getNumFrames(data, data_ptr, len);
+ if (curr_nb_frames < 1) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+
+ /* Check the 120 ms maximum packet size */
+ if ((curr_nb_frames + this.nb_frames) * this.framesize > 960) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+
+ ret = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, dummy_toc, this.frames, this.nb_frames, this.len, this.nb_frames, dummy_offset, dummy_offset);
+ if (ret < 1) {
+ return ret;
+ }
+
+ this.nb_frames += curr_nb_frames;
+ return OpusError.OPUS_OK;
+ }
+
+ /**
+ * opus_repacketizer_cat. Add a packet to the current repacketizer state.
+ * This packet must match the configuration of any packets already submitted
+ * for repacketization since the last call to opus_repacketizer_init(). This
+ * means that it must have the same coding mode, audio bandwidth, frame
+ * size, and channel count. This can be checked in advance by examining the
+ * top 6 bits of the first byte of the packet, and ensuring they match the
+ * top 6 bits of the first byte of any previously submitted packet. The
+ * total duration of audio in the repacketizer state also must not exceed
+ * 120 ms, the maximum duration of a single packet, after adding this
+ * packet.
+ *
+ * The contents of the current repacketizer state can be extracted into new
+ * packets using opus_repacketizer_out() or opus_repacketizer_out_range().
+ *
+ * In order to add a packet with a different configuration or to add more
+ * audio beyond 120 ms, you must clear the repacketizer state by calling
+ * opus_repacketizer_init(). If a packet is too large to add to the current
+ * repacketizer state, no part of it is added, even if it contains multiple
+ * frames, some of which might fit. If you wish to be able to add parts of
+ * such packets, you should first use another repacketizer to split the
+ * packet into pieces and add them individually.
+ *
+ * @see opus_repacketizer_out_range
+ * @see opus_repacketizer_out
+ * @see opus_repacketizer_init
+ * @param data : The packet data. The application must ensure this pointer
+ * remains valid until the next call to opus_repacketizer_init() or
+ * opus_repacketizer_destroy().
+ * @param len: The number of bytes in the packet data.
+ * @returns An error code indicating whether or not the operation succeeded.
+ * @retval #OPUS_OK The packet's contents have been added to the
+ * repacketizer state.
+ * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC
+ * sequence, the packet's TOC sequence was not compatible with previously
+ * submitted packets (because the coding mode, audio bandwidth, frame size,
+ * or channel count did not match), or adding this packet would increase the
+ * total amount of audio stored in the repacketizer state to more than 120
+ * ms.
+ */
+ public int addPacket(byte[] data, int data_offset, int len) {
+ return opus_repacketizer_cat_impl(data, data_offset, len, 0);
+ }
+
+ /**
+ * Return the total number of frames contained in packet data submitted to
+ * the repacketizer state so far via opus_repacketizer_cat() since the last
+ * call to opus_repacketizer_init() or opus_repacketizer_create(). This
+ * defines the valid range of packets that can be extracted with
+ * opus_repacketizer_out_range() or opus_repacketizer_out().
+ *
+ * @param rp OpusRepacketizer*: The repacketizer state containing
+ * the frames.
+ * @returns The total number of frames contained in the packet data
+ * submitted to the repacketizer state.
+ */
+ public int getNumFrames() {
+ return this.nb_frames;
+ }
+
+ int opus_repacketizer_out_range_impl(int begin, int end,
+ byte[] data, int data_ptr, int maxlen, int self_delimited, int pad) {
+ int i, count;
+ int tot_size;
+ int ptr;
+
+ if (begin < 0 || begin >= end || end > this.nb_frames) {
+ /*fprintf(stderr, "%d %d %d\n", begin, end, rp.nb_frames);*/
+ return OpusError.OPUS_BAD_ARG;
+ }
+ count = end - begin;
+
+ if (self_delimited != 0) {
+ tot_size = 1 + (this.len[count - 1] >= 252 ? 1 : 0);
+ } else {
+ tot_size = 0;
+ }
+
+ ptr = data_ptr;
+ if (count == 1) {
+ /* Code 0 */
+ tot_size += this.len[0] + 1;
+ if (tot_size > maxlen) {
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+ data[ptr++] = (byte) (this.toc & 0xFC);
+ } else if (count == 2) {
+ if (this.len[1] == this.len[0]) {
+ /* Code 1 */
+ tot_size += 2 * this.len[0] + 1;
+ if (tot_size > maxlen) {
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+ data[ptr++] = (byte) ((this.toc & 0xFC) | 0x1);
+ } else {
+ /* Code 2 */
+ tot_size += this.len[0] + this.len[1] + 2 + (this.len[0] >= 252 ? 1 : 0);
+ if (tot_size > maxlen) {
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+ data[ptr++] = (byte) ((this.toc & 0xFC) | 0x2);
+ ptr += OpusPacketInfo.encode_size(this.len[0], data, ptr);
+ }
+ }
+ if (count > 2 || (pad != 0 && tot_size < maxlen)) {
+ /* Code 3 */
+ int vbr;
+ int pad_amount = 0;
+
+ /* Restart the process for the padding case */
+ ptr = data_ptr;
+ if (self_delimited != 0) {
+ tot_size = 1 + (this.len[count - 1] >= 252 ? 1 : 0);
+ } else {
+ tot_size = 0;
+ }
+ vbr = 0;
+ for (i = 1; i < count; i++) {
+ if (this.len[i] != this.len[0]) {
+ vbr = 1;
+ break;
+ }
+ }
+ if (vbr != 0) {
+ tot_size += 2;
+ for (i = 0; i < count - 1; i++) {
+ tot_size += 1 + (this.len[i] >= 252 ? 1 : 0) + this.len[i];
+ }
+ tot_size += this.len[count - 1];
+
+ if (tot_size > maxlen) {
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+ data[ptr++] = (byte) ((this.toc & 0xFC) | 0x3);
+ data[ptr++] = (byte) (count | 0x80);
+ } else {
+ tot_size += count * this.len[0] + 2;
+ if (tot_size > maxlen) {
+ return OpusError.OPUS_BUFFER_TOO_SMALL;
+ }
+ data[ptr++] = (byte) ((this.toc & 0xFC) | 0x3);
+ data[ptr++] = (byte) (count);
+ }
+
+ pad_amount = pad != 0 ? (maxlen - tot_size) : 0;
+
+ if (pad_amount != 0) {
+ int nb_255s;
+ data[data_ptr + 1] = (byte) (data[data_ptr + 1] | 0x40);
+ nb_255s = (pad_amount - 1) / 255;
+ for (i = 0; i < nb_255s; i++) {
+ data[ptr++] = -1;
+ }
+
+ data[ptr++] = (byte) (pad_amount - 255 * nb_255s - 1);
+ tot_size += pad_amount;
+ }
+
+ if (vbr != 0) {
+ for (i = 0; i < count - 1; i++) {
+ ptr += (OpusPacketInfo.encode_size(this.len[i], data, ptr));
+ }
+ }
+ }
+
+ if (self_delimited != 0) {
+ int sdlen = OpusPacketInfo.encode_size(this.len[count - 1], data, ptr);
+ ptr += (sdlen);
+ }
+
+ /* Copy the actual data */
+ for (i = begin; i < count + begin; i++) {
+
+ if (data == this.frames[i]) {
+ /* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
+ padding from opus_packet_pad or opus_packet_unpad(). */
+ Arrays.MemMove(data, 0, ptr, this.len[i]);
+ } else {
+ System.arraycopy(this.frames[i], 0, data, ptr, this.len[i]);
+ }
+ ptr += this.len[i];
+ }
+
+ if (pad != 0) {
+ /* Fill padding with zeros. */
+ Arrays.MemSetWithOffset(data, (byte) 0, ptr, data_ptr + maxlen - ptr);
+ }
+
+ return tot_size;
+ }
+
+ /**
+ * Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat().
+ *
+ * @param rp OpusRepacketizer*: The repacketizer state from which
+ * to construct the new packet.
+ * @param begin int: The index of the first frame in the current
+ * repacketizer state to include in the output.
+ * @param end int: One past the index of the last frame in the
+ * current repacketizer state to include in the output.
+ * @param[out] data final unsigned char*: The buffer in which to
+ * store the output packet.
+ * @param maxlen opus_int32: The maximum number of bytes to store
+ * in the output buffer. In order to guarantee success, this should be at
+ * least 1276 for a single frame, or for multiple frames,
+ * 1277*(end-begin). However, 1*(end-begin) plus
+ * the size of all packet data submitted to the repacketizer since the last
+ * call to opus_repacketizer_init() or opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG [begin,end) was an invalid range of
+ * frames (begin < 0, begin >= end, or end >
+ * opus_repacketizer_get_nb_frames()).
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+ public int createPacket(int begin, int end, byte[] data, int data_offset, int maxlen) {
+ return opus_repacketizer_out_range_impl(begin, end, data, data_offset, maxlen, 0, 0);
+ }
+
+ /**
+ * Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat(). This is a convenience routine that
+ * returns all the data submitted so far in a single packet. It is
+ * equivalent to calling
+ * @code
+ * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),
+ * data, maxlen)
+ * @endcode
+ * @param rp OpusRepacketizer*: The repacketizer state from which to
+ * construct the new packet.
+ * @param[out] data final unsigned char*: The buffer in which to
+ * store the output packet.
+ * @param maxlen opus_int32: The maximum number of bytes to store in
+ * the output buffer. In order to guarantee
+ * success, this should be at least
+ * 1277*opus_repacketizer_get_nb_frames(rp).
+ * However,
+ * 1*opus_repacketizer_get_nb_frames(rp)
+ * plus the size of all packet data
+ * submitted to the repacketizer since the
+ * last call to opus_repacketizer_init() or
+ * opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+ public int createPacket(byte[] data, int data_offset, int maxlen) {
+ return opus_repacketizer_out_range_impl(0, this.nb_frames, data, data_offset, maxlen, 0, 0);
+ }
+
+ /**
+ * Pads a given Opus packet to a larger size (possibly changing the TOC
+ * sequence).
+ *
+ * @param[in,out] data final unsigned char*: The buffer containing
+ * the packet to pad.
+ * @param len opus_int32: The size of the packet. This must be at
+ * least 1.
+ * @param new_len opus_int32: The desired size of the packet after
+ * padding. This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than
+ * len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+ public static int padPacket(byte[] data, int data_offset, int len, int new_len) {
+ OpusRepacketizer rp = new OpusRepacketizer();
+ int ret;
+ if (len < 1) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ if (len == new_len) {
+ return OpusError.OPUS_OK;
+ } else if (len > new_len) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ rp.Reset();
+ /* Moving payload to the end of the packet so we can do in-place padding */
+ Arrays.MemMove(data, data_offset, data_offset + new_len - len, len);
+ //data.MemMoveTo(data.Point(new_len - len), len);
+ rp.addPacket(data, data_offset + new_len - len, len);
+ ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, data_offset, new_len, 0, 1);
+ if (ret > 0) {
+ return OpusError.OPUS_OK;
+ } else {
+ return ret;
+ }
+ }
+
+ /**
+ * Remove all padding from a given Opus packet and rewrite the TOC sequence
+ * to minimize space usage.
+ *
+ * @param[in,out] data final unsigned char*: The buffer containing
+ * the packet to strip.
+ * @param len opus_int32: The size of the packet. This must be at
+ * least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+ public static int unpadPacket(byte[] data, int data_offset, int len) {
+ int ret;
+ if (len < 1) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+
+ OpusRepacketizer rp = new OpusRepacketizer();
+ rp.Reset();
+ ret = rp.addPacket(data, data_offset, len);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, data_offset, len, 0, 0);
+ Inlines.OpusAssert(ret > 0 && ret <= len);
+
+ return ret;
+ }
+
+ /**
+ * Pads a given Opus multi-stream packet to a larger size (possibly changing
+ * the TOC sequence).
+ *
+ * @param[in,out] data final unsigned char*: The buffer containing
+ * the packet to pad.
+ * @param len opus_int32: The size of the packet. This must be at
+ * least 1.
+ * @param new_len opus_int32: The desired size of the packet after
+ * padding. This must be at least 1.
+ * @param nb_streams opus_int32: The number of streams (not
+ * channels) in the packet. This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+ public static int padMultistreamPacket(byte[] data, int data_offset, int len, int new_len, int nb_streams) {
+ int s;
+ int count;
+ BoxedValueByte dummy_toc = new BoxedValueByte((byte) 0);
+ short[] size = new short[48];
+ BoxedValueInt packet_offset = new BoxedValueInt(0);
+ BoxedValueInt dummy_offset = new BoxedValueInt(0);
+ int amount;
+
+ if (len < 1) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ if (len == new_len) {
+ return OpusError.OPUS_OK;
+ } else if (len > new_len) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ amount = new_len - len;
+ /* Seek to last stream */
+ for (s = 0; s < nb_streams - 1; s++) {
+ if (len <= 0) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ count = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, 1, dummy_toc, null, 0,
+ size, 0, dummy_offset, packet_offset);
+ if (count < 0) {
+ return count;
+ }
+ data_offset += packet_offset.Val;
+ len -= packet_offset.Val;
+ }
+ return padPacket(data, data_offset, len, len + amount);
+ }
+
+ // FIXME THIS METHOD FAILS IN TEST_OPUS_ENCODE
+ /**
+ * Remove all padding from a given Opus multi-stream packet and rewrite the
+ * TOC sequence to minimize space usage.
+ *
+ * @param[in,out] data final unsigned char*: The buffer containing
+ * the packet to strip.
+ * @param len opus_int32: The size of the packet. This must be at
+ * least 1.
+ * @param nb_streams opus_int32: The number of streams (not
+ * channels) in the packet. This must be at least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than
+ * len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+ public static int unpadMultistreamPacket(byte[] data, int data_offset, int len, int nb_streams) {
+ int s;
+ BoxedValueByte dummy_toc = new BoxedValueByte((byte) 0);
+ short[] size = new short[48];
+ BoxedValueInt packet_offset = new BoxedValueInt(0);
+ BoxedValueInt dummy_offset = new BoxedValueInt(0);
+ OpusRepacketizer rp = new OpusRepacketizer();
+ int dst;
+ int dst_len;
+
+ if (len < 1) {
+ return OpusError.OPUS_BAD_ARG;
+ }
+ dst = data_offset;
+ dst_len = 0;
+ /* Unpad all frames */
+ for (s = 0; s < nb_streams; s++) {
+ int ret;
+ int self_delimited = ((s != nb_streams) ? 1 : 0) - 1;
+ if (len <= 0) {
+ return OpusError.OPUS_INVALID_PACKET;
+ }
+ rp.Reset();
+ ret = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, self_delimited, dummy_toc, null, 0,
+ size, 0, dummy_offset, packet_offset);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = rp.opus_repacketizer_cat_impl(data, data_offset, packet_offset.Val, self_delimited);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, dst, len, self_delimited, 0);
+ if (ret < 0) {
+ return ret;
+ } else {
+ dst_len += ret;
+ }
+ dst += ret;
+ data_offset += packet_offset.Val;
+ len -= packet_offset.Val;
+ }
+ return dst_len;
+ }
+}
diff --git a/app/src/main/java/org/concentus/OpusSignal.java b/app/src/main/java/org/concentus/OpusSignal.java
new file mode 100644
index 0000000000..7319cb6721
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusSignal.java
@@ -0,0 +1,48 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+public enum OpusSignal {
+ OPUS_SIGNAL_UNKNOWN,
+ OPUS_SIGNAL_AUTO,
+ ///
+ /// Signal being encoded is voice
+ ///
+ OPUS_SIGNAL_VOICE,
+ ///
+ /// Signal being encoded is music
+ ///
+ OPUS_SIGNAL_MUSIC
+}
diff --git a/app/src/main/java/org/concentus/OpusTables.java b/app/src/main/java/org/concentus/OpusTables.java
new file mode 100644
index 0000000000..a8191b7006
--- /dev/null
+++ b/app/src/main/java/org/concentus/OpusTables.java
@@ -0,0 +1,280 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class OpusTables {
+
+ static final float[] dct_table = {
+ 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+ 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+ 0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f,
+ -0.034654f, -0.102631f, -0.166664f, -0.224292f, -0.273300f, -0.311806f, -0.338330f, -0.351851f,
+ 0.346760f, 0.293969f, 0.196424f, 0.068975f, -0.068975f, -0.196424f, -0.293969f, -0.346760f,
+ -0.346760f, -0.293969f, -0.196424f, -0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f,
+ 0.338330f, 0.224292f, 0.034654f, -0.166664f, -0.311806f, -0.351851f, -0.273300f, -0.102631f,
+ 0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f, -0.034654f, -0.224292f, -0.338330f,
+ 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f, 0.135299f, 0.326641f,
+ 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f, 0.135299f, 0.326641f,
+ 0.311806f, 0.034654f, -0.273300f, -0.338330f, -0.102631f, 0.224292f, 0.351851f, 0.166664f,
+ -0.166664f, -0.351851f, -0.224292f, 0.102631f, 0.338330f, 0.273300f, -0.034654f, -0.311806f,
+ 0.293969f, -0.068975f, -0.346760f, -0.196424f, 0.196424f, 0.346760f, 0.068975f, -0.293969f,
+ -0.293969f, 0.068975f, 0.346760f, 0.196424f, -0.196424f, -0.346760f, -0.068975f, 0.293969f,
+ 0.273300f, -0.166664f, -0.338330f, 0.034654f, 0.351851f, 0.102631f, -0.311806f, -0.224292f,
+ 0.224292f, 0.311806f, -0.102631f, -0.351851f, -0.034654f, 0.338330f, 0.166664f, -0.273300f,};
+
+ static final float[] analysis_window = {
+ 0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f,
+ 0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f,
+ 0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f,
+ 0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f,
+ 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f,
+ 0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f,
+ 0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f,
+ 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f,
+ 0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f,
+ 0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f,
+ 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f,
+ 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f,
+ 0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f,
+ 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f,
+ 0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f,
+ 0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f,
+ 0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f,
+ 0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f,
+ 0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f,
+ 0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f,
+ 0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f,
+ 0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f,
+ 0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f,
+ 0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f,
+ 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f,
+ 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f,
+ 0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f,
+ 0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f,
+ 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f,
+ 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f,};
+
+ static final int[] tbands/*[NB_TBANDS + 1]*/ = {
+ 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120
+ };
+
+ static final int[] extra_bands/*[NB_TOT_BANDS + 1]*/ = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200
+ };
+
+ /*static final float tweight[NB_TBANDS+1] = {
+ .3, .4, .5, .6, .7, .8, .9, 1., 1., 1., 1., 1., 1., 1., .8, .7, .6, .5
+ };*/
+
+ /* RMS error was 0.138320, seed was 1361535663 */
+ static final float[] weights/*[422]*/ = {
+ /* hidden layer */
+ -0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f,
+ -0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f,
+ -0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f,
+ 0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f,
+ 0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f,
+ 24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f,
+ -0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f,
+ -0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f,
+ -0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f,
+ 1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f,
+ 15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f,
+ 0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f,
+ -0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f,
+ 0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f,
+ 0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f,
+ -1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f,
+ -0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f,
+ -0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f,
+ 0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f,
+ -0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f,
+ 2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f,
+ 0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f,
+ -0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f,
+ 0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f,
+ 0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f,
+ -4.60683f, 1.4697f, 0.335845f, -1.81905f, -30.1699f,
+ 5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f,
+ -0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f,
+ -0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f,
+ -0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f,
+ 1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f,
+ -7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f,
+ -0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f,
+ 0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f,
+ 0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f,
+ -0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f,
+ 10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f,
+ -0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f,
+ -0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f,
+ -0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f,
+ 0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f,
+ -0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f,
+ 0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f,
+ 0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f,
+ -0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f,
+ 0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f,
+ -0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f,
+ -0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f,
+ -0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f,
+ -0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f,
+ -0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f,
+ 5.8427f, -0.38075f, 0.221894f, -1.41934f, -1.87943e+06f,
+ 1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f,
+ 0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f,
+ -0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f,
+ 0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f,
+ -0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f,
+ -975268.0f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f,
+ 0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f,
+ -0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f,
+ -2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f,
+ 0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f,
+ -6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f,
+ 0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f,
+ -0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f,
+ -0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f,
+ 0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f,
+ -0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f,
+ 0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f,
+ -0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f,
+ 0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f,
+ -2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f,
+ 4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f,
+ 0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f,
+ -0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f,
+ 0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f,
+ 0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f,
+ 3.95279f, 1.89068f, 0.486087f, -11.3343f, 3.9416e+06f,
+ /* output layer */
+ -0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f,
+ 0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f,
+ 0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f,
+ 0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f,
+ 4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f,
+ -1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f,
+ 3.87308f, 3.52558f};
+
+ static final int[] topo = {25, 15, 2};
+
+ // fixme: move this into an MLP class singleton or something?
+ static final MLPState net = new MLPState();
+
+ static {
+ net.layers = 3;
+ net.topo = topo;
+ net.weights = weights;
+ }
+ ;
+
+ static final float[] tansig_table/*[201]*/ = {
+ 0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f,
+ 0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f,
+ 0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f,
+ 0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f,
+ 0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f,
+ 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f,
+ 0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f,
+ 0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f,
+ 0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f,
+ 0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f,
+ 0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f,
+ 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
+ 0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f,
+ 0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f,
+ 0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f,
+ 0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f,
+ 0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f,
+ 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
+ 0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f,
+ 0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f,
+ 0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f,
+ 0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f,
+ 0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f,
+ 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
+ 0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f,
+ 0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f,
+ 0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f,
+ 0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f,
+ 0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f,
+ 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
+ 0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f,
+ 0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f,
+ 0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f,
+ 0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f,
+ 0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f,
+ 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
+ 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+ 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f,};
+
+ // from opus_encoder.c
+ /* Transition tables for the voice and music. First column is the
+ middle (memoriless) threshold. The second column is the hysteresis
+ (difference with the middle) */
+ static final int[] mono_voice_bandwidth_thresholds = {
+ 11000, 1000, /* NB<->MB */
+ 14000, 1000, /* MB<->WB */
+ 17000, 1000, /* WB<->SWB */
+ 21000, 2000, /* SWB<->FB */};
+ static final int[] mono_music_bandwidth_thresholds = {
+ 12000, 1000, /* NB<->MB */
+ 15000, 1000, /* MB<->WB */
+ 18000, 2000, /* WB<->SWB */
+ 22000, 2000, /* SWB<->FB */};
+ static final int[] stereo_voice_bandwidth_thresholds = {
+ 11000, 1000, /* NB<->MB */
+ 14000, 1000, /* MB<->WB */
+ 21000, 2000, /* WB<->SWB */
+ 28000, 2000, /* SWB<->FB */};
+ static final int[] stereo_music_bandwidth_thresholds = {
+ 12000, 1000, /* NB<->MB */
+ 18000, 2000, /* MB<->WB */
+ 21000, 2000, /* WB<->SWB */
+ 30000, 2000, /* SWB<->FB */};
+
+ /* Threshold bit-rates for switching between mono and stereo */
+ public static final int stereo_voice_threshold = 30000;
+ public static final int stereo_music_threshold = 30000;
+
+ /* Threshold bit-rate for switching between SILK/hybrid and CELT-only */
+ static final int[][] mode_thresholds = {
+ /* voice */ /* music */
+ new int[]{64000, 16000}, /* mono */
+ new int[]{36000, 16000}, /* stereo */};
+}
diff --git a/app/src/main/java/org/concentus/PLC.java b/app/src/main/java/org/concentus/PLC.java
new file mode 100644
index 0000000000..7a2822cc26
--- /dev/null
+++ b/app/src/main/java/org/concentus/PLC.java
@@ -0,0 +1,466 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Routines for managing packet loss concealment
+///
+class PLC {
+
+ private static final int NB_ATT = 2;
+ private static final short[] HARM_ATT_Q15 = {32440, 31130};
+ /* 0.99, 0.95 */
+ private static final short[] PLC_RAND_ATTENUATE_V_Q15 = {31130, 26214};
+ /* 0.95, 0.8 */
+ private static final short[] PLC_RAND_ATTENUATE_UV_Q15 = {32440, 29491};
+
+ /* 0.99, 0.9 */
+
+ 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;
+ }
+
+ 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 */
+ /**
+ * ***********************************************
+ */
+ 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;
+
+ System.arraycopy(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.MemSet(psPLC.LTPCoef_Q14, (short) 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.MemSet(psPLC.LTPCoef_Q14, (short) 0, SilkConstants.LTP_ORDER);
+ }
+
+ /* Save LPC coeficients */
+ System.arraycopy(psDecCtrl.PredCoef_Q12[1], 0, psPLC.prevLPC_Q12, 0, psDec.LPC_order);
+ psPLC.prevLTP_scale_Q14 = (short) (psDecCtrl.LTP_scale_Q14);
+
+ /* Save last two gains */
+ System.arraycopy(psDecCtrl.Gains_Q16, psDec.nb_subfr - 2, psPLC.prevGain_Q16, 0, 2);
+
+ psPLC.subfr_length = psDec.subfr_length;
+ psPLC.nb_subfr = psDec.nb_subfr;
+ }
+
+ ///
+ ///
+ ///
+ /// O
+ /// O
+ /// O
+ /// O
+ /// I
+ /// I
+ /// I
+ /// I
+ static void silk_PLC_energy(
+ BoxedValueInt energy1,
+ BoxedValueInt shift1,
+ BoxedValueInt energy2,
+ BoxedValueInt 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(energy1, shift1, exc_buf, subfr_length);
+ SumSqrShift.silk_sum_sqr_shift(energy2, shift2, exc_buf, subfr_length, subfr_length);
+ }
+
+ 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;
+ BoxedValueInt energy1 = new BoxedValueInt(0);
+ BoxedValueInt energy2 = new BoxedValueInt(0);
+ BoxedValueInt shift1 = new BoxedValueInt(0);
+ BoxedValueInt shift2 = new BoxedValueInt(0);
+ 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.MemSet(psPLC.prevLPC_Q12, (short) 0, SilkConstants.MAX_LPC_ORDER);
+ }
+
+ silk_PLC_energy(energy1, shift1, energy2, shift2, psDec.exc_Q14, prevGain_Q10, psDec.subfr_length, psDec.nb_subfr);
+
+ if (Inlines.silk_RSHIFT(energy1.Val, shift2.Val) < Inlines.silk_RSHIFT(energy2.Val, shift1.Val)) {
+ /* 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((short) 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, Integer.MAX_VALUE >> 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 */
+ System.arraycopy(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 */
+ System.arraycopy(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 */
+ 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;
+ BoxedValueInt energy_shift = new BoxedValueInt(0);
+ BoxedValueInt energy = new BoxedValueInt(0);
+ PLCStruct psPLC = psDec.sPLC;
+
+ if (psDec.lossCnt != 0) {
+ /* Calculate energy in concealed residual */
+ BoxedValueInt boxed_conc_e = new BoxedValueInt(0);
+ BoxedValueInt boxed_conc_shift = new BoxedValueInt(0);
+ SumSqrShift.silk_sum_sqr_shift(boxed_conc_e, boxed_conc_shift, frame, frame_ptr, length);
+ psPLC.conc_energy = boxed_conc_e.Val;
+ psPLC.conc_energy_shift = boxed_conc_shift.Val;
+
+ 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(energy, energy_shift, frame, frame_ptr, length);
+
+ /* Normalize energies */
+ if (energy_shift.Val > psPLC.conc_energy_shift) {
+ psPLC.conc_energy = Inlines.silk_RSHIFT(psPLC.conc_energy, energy_shift.Val - psPLC.conc_energy_shift);
+ } else if (energy_shift.Val < psPLC.conc_energy_shift) {
+ energy.Val = Inlines.silk_RSHIFT(energy.Val, psPLC.conc_energy_shift - energy_shift.Val);
+ }
+
+ /* Fade in the energy difference */
+ if (energy.Val > 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.Val = Inlines.silk_RSHIFT(energy.Val, Inlines.silk_max_32(24 - LZ, 0));
+
+ frac_Q24 = Inlines.silk_DIV32(psPLC.conc_energy, Inlines.silk_max(energy.Val, 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;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/PLCStruct.java b/app/src/main/java/org/concentus/PLCStruct.java
new file mode 100644
index 0000000000..d73665c5bd
--- /dev/null
+++ b/app/src/main/java/org/concentus/PLCStruct.java
@@ -0,0 +1,73 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Struct for Packet Loss Concealment
+///
+class PLCStruct {
+
+ int pitchL_Q8 = 0;
+ /* Pitch lag to use for voiced concealment */
+ final short[] LTPCoef_Q14 = new short[SilkConstants.LTP_ORDER];
+ /* LTP coeficients to use for voiced concealment */
+ final short[] prevLPC_Q12 = new short[SilkConstants.MAX_LPC_ORDER];
+ int last_frame_lost = 0;
+ /* Was previous frame lost */
+ int rand_seed = 0;
+ /* Seed for unvoiced signal generation */
+ short randScale_Q14 = 0;
+ /* Scaling of unvoiced random signal */
+ int conc_energy = 0;
+ int conc_energy_shift = 0;
+ short prevLTP_scale_Q14 = 0;
+ final int[] prevGain_Q16 = new int[2];
+ int fs_kHz = 0;
+ int nb_subfr = 0;
+ int subfr_length = 0;
+
+ void Reset() {
+ pitchL_Q8 = 0;
+ Arrays.MemSet(LTPCoef_Q14, (short) 0, SilkConstants.LTP_ORDER);
+ Arrays.MemSet(prevLPC_Q12, (short) 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.MemSet(prevGain_Q16, 0, 2);
+ fs_kHz = 0;
+ nb_subfr = 0;
+ subfr_length = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/Pitch.java b/app/src/main/java/org/concentus/Pitch.java
new file mode 100644
index 0000000000..22e9ffb249
--- /dev/null
+++ b/app/src/main/java/org/concentus/Pitch.java
@@ -0,0 +1,421 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class Pitch {
+
+ static void find_best_pitch(int[] xcorr, int[] y, int len,
+ int max_pitch, int[] best_pitch,
+ int yshift, int maxcorr
+ ) {
+ int i, j;
+ int Syy = 1;
+ int best_num_0;
+ int best_num_1;
+ int best_den_0;
+ int best_den_1;
+ int xshift = Inlines.celt_ilog2(maxcorr) - 14;
+
+ best_num_0 = -1;
+ best_num_1 = -1;
+ best_den_0 = 0;
+ best_den_1 = 0;
+ best_pitch[0] = 0;
+ best_pitch[1] = 1;
+ for (j = 0; j < len; j++) {
+ Syy = Inlines.ADD32(Syy, Inlines.SHR32(Inlines.MULT16_16(y[j], y[j]), yshift));
+ }
+ for (i = 0; i < max_pitch; i++) {
+ if (xcorr[i] > 0) {
+ int num;
+ int xcorr16;
+ xcorr16 = Inlines.EXTRACT16(Inlines.VSHR32(xcorr[i], xshift));
+ num = Inlines.MULT16_16_Q15((xcorr16), (xcorr16));
+ if (Inlines.MULT16_32_Q15(num, best_den_1) > Inlines.MULT16_32_Q15(best_num_1, Syy)) {
+ if (Inlines.MULT16_32_Q15(num, best_den_0) > Inlines.MULT16_32_Q15(best_num_0, Syy)) {
+ best_num_1 = best_num_0;
+ best_den_1 = best_den_0;
+ best_pitch[1] = best_pitch[0];
+ best_num_0 = num;
+ best_den_0 = Syy;
+ best_pitch[0] = i;
+ } else {
+ best_num_1 = num;
+ best_den_1 = Syy;
+ best_pitch[1] = i;
+ }
+ }
+ }
+
+ Syy += Inlines.SHR32(Inlines.MULT16_16(y[i + len], y[i + len]), yshift) - Inlines.SHR32(Inlines.MULT16_16(y[i], y[i]), yshift);
+ Syy = Inlines.MAX32(1, Syy);
+ }
+ }
+
+ static void celt_fir5(int[] x,
+ int[] num,
+ int[] y,
+ int N,
+ int[] mem) {
+ int i;
+ int num0, num1, num2, num3, num4;
+ int mem0, mem1, mem2, mem3, mem4;
+ num0 = num[0];
+ num1 = num[1];
+ num2 = num[2];
+ num3 = num[3];
+ num4 = num[4];
+ mem0 = mem[0];
+ mem1 = mem[1];
+ mem2 = mem[2];
+ mem3 = mem[3];
+ mem4 = mem[4];
+ for (i = 0; i < N; i++) {
+ int sum = Inlines.SHL32(Inlines.EXTEND32(x[i]), CeltConstants.SIG_SHIFT);
+ sum = Inlines.MAC16_16(sum, num0, (mem0));
+ sum = Inlines.MAC16_16(sum, num1, (mem1));
+ sum = Inlines.MAC16_16(sum, num2, (mem2));
+ sum = Inlines.MAC16_16(sum, num3, (mem3));
+ sum = Inlines.MAC16_16(sum, num4, (mem4));
+ mem4 = mem3;
+ mem3 = mem2;
+ mem2 = mem1;
+ mem1 = mem0;
+ mem0 = x[i];
+ y[i] = Inlines.ROUND16(sum, CeltConstants.SIG_SHIFT);
+ }
+ mem[0] = (mem0);
+ mem[1] = (mem1);
+ mem[2] = (mem2);
+ mem[3] = (mem3);
+ mem[4] = (mem4);
+ }
+
+ static void pitch_downsample(int[][] x, int[] x_lp, int len, int C) {
+ int i;
+ int[] ac = new int[5];
+ int tmp = CeltConstants.Q15ONE;
+ int[] lpc = new int[4];
+ int[] mem = new int[]{0, 0, 0, 0, 0};
+ int[] lpc2 = new int[5];
+ int c1 = ((short) (0.5 + (0.8f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.8f, 15)*/;
+
+ int shift;
+ int maxabs = Inlines.celt_maxabs32(x[0], 0, len);
+ if (C == 2) {
+ int maxabs_1 = Inlines.celt_maxabs32(x[1], 0, len);
+ maxabs = Inlines.MAX32(maxabs, maxabs_1);
+ }
+ if (maxabs < 1) {
+ maxabs = 1;
+ }
+ shift = Inlines.celt_ilog2(maxabs) - 10;
+ if (shift < 0) {
+ shift = 0;
+ }
+ if (C == 2) {
+ shift++;
+ }
+
+ int halflen = len >> 1; // cached for performance
+ for (i = 1; i < halflen; i++) {
+ x_lp[i] = (Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[0][(2 * i - 1)] + x[0][(2 * i + 1)]) + x[0][2 * i]), shift));
+ }
+
+ x_lp[0] = (Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[0][1]) + x[0][0]), shift));
+
+ if (C == 2) {
+ for (i = 1; i < halflen; i++) {
+ x_lp[i] += (Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[1][(2 * i - 1)] + x[1][(2 * i + 1)]) + x[1][2 * i]), shift));
+ }
+ x_lp[0] += (Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[1][1]) + x[1][0]), shift));
+ }
+
+ Autocorrelation._celt_autocorr(x_lp, ac, null, 0, 4, halflen);
+
+ /* Noise floor -40 dB */
+ ac[0] += Inlines.SHR32(ac[0], 13);
+ /* Lag windowing */
+ for (i = 1; i <= 4; i++) {
+ /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+ ac[i] -= Inlines.MULT16_32_Q15((2 * i * i), ac[i]);
+ }
+
+ CeltLPC.celt_lpc(lpc, ac, 4);
+ for (i = 0; i < 4; i++) {
+ tmp = Inlines.MULT16_16_Q15(((short) (0.5 + (.9f) * (((int) 1) << (15))))/*Inlines.QCONST16(.9f, 15)*/, tmp);
+ lpc[i] = Inlines.MULT16_16_Q15(lpc[i], tmp);
+ }
+ /* Add a zero */
+ lpc2[0] = (lpc[0] + ((short) (0.5 + (0.8f) * (((int) 1) << (CeltConstants.SIG_SHIFT))))/*Inlines.QCONST16(0.8f, CeltConstants.SIG_SHIFT)*/);
+ lpc2[1] = (lpc[1] + Inlines.MULT16_16_Q15(c1, lpc[0]));
+ lpc2[2] = (lpc[2] + Inlines.MULT16_16_Q15(c1, lpc[1]));
+ lpc2[3] = (lpc[3] + Inlines.MULT16_16_Q15(c1, lpc[2]));
+ lpc2[4] = Inlines.MULT16_16_Q15(c1, lpc[3]);
+
+ celt_fir5(x_lp, lpc2, x_lp, halflen, mem);
+ }
+
+ // Fixme: remove pointers and optimize
+ static void pitch_search(int[] x_lp, int x_lp_ptr, int[] y,
+ int len, int max_pitch, BoxedValueInt pitch) {
+ int i, j;
+ int lag;
+ int[] best_pitch = new int[]{0, 0};
+ int maxcorr;
+ int xmax, ymax;
+ int shift = 0;
+ int offset;
+
+ Inlines.OpusAssert(len > 0);
+ Inlines.OpusAssert(max_pitch > 0);
+ lag = len + max_pitch;
+
+ int[] x_lp4 = new int[len >> 2];
+ int[] y_lp4 = new int[lag >> 2];
+ int[] xcorr = new int[max_pitch >> 1];
+
+ /* Downsample by 2 again */
+ for (j = 0; j < len >> 2; j++) {
+ x_lp4[j] = x_lp[x_lp_ptr + (2 * j)];
+ }
+ for (j = 0; j < lag >> 2; j++) {
+ y_lp4[j] = y[2 * j];
+ }
+
+ xmax = Inlines.celt_maxabs32(x_lp4, 0, len >> 2);
+ ymax = Inlines.celt_maxabs32(y_lp4, 0, lag >> 2);
+ shift = Inlines.celt_ilog2(Inlines.MAX32(1, Inlines.MAX32(xmax, ymax))) - 11;
+ if (shift > 0) {
+ for (j = 0; j < len >> 2; j++) {
+ x_lp4[j] = Inlines.SHR16(x_lp4[j], shift);
+ }
+ for (j = 0; j < lag >> 2; j++) {
+ y_lp4[j] = Inlines.SHR16(y_lp4[j], shift);
+ }
+ /* Use double the shift for a MAC */
+ shift *= 2;
+ } else {
+ shift = 0;
+ }
+
+ /* Coarse search with 4x decimation */
+ maxcorr = CeltPitchXCorr.pitch_xcorr(x_lp4, y_lp4, xcorr, len >> 2, max_pitch >> 2);
+
+ find_best_pitch(xcorr, y_lp4, len >> 2, max_pitch >> 2, best_pitch, 0, maxcorr);
+
+ /* Finer search with 2x decimation */
+ maxcorr = 1;
+ for (i = 0; i < max_pitch >> 1; i++) {
+ int sum;
+ xcorr[i] = 0;
+ if (Inlines.abs(i - 2 * best_pitch[0]) > 2 && Inlines.abs(i - 2 * best_pitch[1]) > 2) {
+ continue;
+ }
+ sum = 0;
+ for (j = 0; j < len >> 1; j++) {
+ sum += Inlines.SHR32(Inlines.MULT16_16(x_lp[x_lp_ptr + j], y[i + j]), shift);
+ }
+
+ xcorr[i] = Inlines.MAX32(-1, sum);
+ maxcorr = Inlines.MAX32(maxcorr, sum);
+ }
+ find_best_pitch(xcorr, y, len >> 1, max_pitch >> 1, best_pitch, shift + 1, maxcorr);
+
+ /* Refine by pseudo-interpolation */
+ if (best_pitch[0] > 0 && best_pitch[0] < (max_pitch >> 1) - 1) {
+ int a, b, c;
+ a = xcorr[best_pitch[0] - 1];
+ b = xcorr[best_pitch[0]];
+ c = xcorr[best_pitch[0] + 1];
+ if ((c - a) > Inlines.MULT16_32_Q15(((short) (0.5 + (.7f) * (((int) 1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, b - a)) {
+ offset = 1;
+ } else if ((a - c) > Inlines.MULT16_32_Q15(((short) (0.5 + (.7f) * (((int) 1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, b - c)) {
+ offset = -1;
+ } else {
+ offset = 0;
+ }
+ } else {
+ offset = 0;
+ }
+
+ pitch.Val = 2 * best_pitch[0] - offset;
+ }
+
+ private static final int[] second_check = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
+
+ static int remove_doubling(int[] x, int maxperiod, int minperiod,
+ int N, BoxedValueInt T0_, int prev_period, int prev_gain) {
+ int k, i, T, T0;
+ int g, g0;
+ int pg;
+ int yy, xx, xy, xy2;
+ int[] xcorr = new int[3];
+ int best_xy, best_yy;
+ int offset;
+ int minperiod0 = minperiod;
+ maxperiod /= 2;
+ minperiod /= 2;
+ T0_.Val /= 2;
+ prev_period /= 2;
+ N /= 2;
+ int x_ptr = maxperiod;
+ if (T0_.Val >= maxperiod) {
+ T0_.Val = maxperiod - 1;
+ }
+
+ T = T0 = T0_.Val;
+ int[] yy_lookup = new int[maxperiod + 1];
+ BoxedValueInt boxed_xx = new BoxedValueInt(0);
+ BoxedValueInt boxed_xy = new BoxedValueInt(0);
+ BoxedValueInt boxed_xy2 = new BoxedValueInt(0);
+ Kernels.dual_inner_prod(x, x_ptr, x, x_ptr, x, x_ptr - T0, N, boxed_xx, boxed_xy);
+ xx = boxed_xx.Val;
+ xy = boxed_xy.Val;
+ yy_lookup[0] = xx;
+ yy = xx;
+ for (i = 1; i <= maxperiod; i++) {
+ int xi = x_ptr - i;
+ yy = yy + Inlines.MULT16_16(x[xi], x[xi]) - Inlines.MULT16_16(x[xi + N], x[xi + N]);
+ yy_lookup[i] = Inlines.MAX32(0, yy);
+ }
+ yy = yy_lookup[T0];
+ best_xy = xy;
+ best_yy = yy;
+
+ {
+ int x2y2;
+ int sh, t;
+ x2y2 = 1 + Inlines.HALF32(Inlines.MULT32_32_Q31(xx, yy));
+ sh = Inlines.celt_ilog2(x2y2) >> 1;
+ t = Inlines.VSHR32(x2y2, 2 * (sh - 7));
+ g = (Inlines.VSHR32(Inlines.MULT16_32_Q15(Inlines.celt_rsqrt_norm(t), xy), sh + 1));
+ g0 = g;
+ }
+
+ /* Look for any pitch at T/k */
+ for (k = 2; k <= 15; k++) {
+ int T1, T1b;
+ int g1;
+ int cont = 0;
+ int thresh;
+ T1 = Inlines.celt_udiv(2 * T0 + k, 2 * k);
+ if (T1 < minperiod) {
+ break;
+ }
+
+ /* Look for another strong correlation at T1b */
+ if (k == 2) {
+ if (T1 + T0 > maxperiod) {
+ T1b = T0;
+ } else {
+ T1b = T0 + T1;
+ }
+ } else {
+ T1b = Inlines.celt_udiv(2 * second_check[k] * T0 + k, 2 * k);
+ }
+
+ Kernels.dual_inner_prod(x, x_ptr, x, x_ptr - T1, x, x_ptr - T1b, N, boxed_xy, boxed_xy2);
+ xy = boxed_xy.Val;
+ xy2 = boxed_xy2.Val;
+
+ xy += xy2;
+ yy = yy_lookup[T1] + yy_lookup[T1b];
+
+ {
+ int x2y2;
+ int sh, t;
+ x2y2 = 1 + Inlines.MULT32_32_Q31(xx, yy);
+ sh = Inlines.celt_ilog2(x2y2) >> 1;
+ t = Inlines.VSHR32(x2y2, 2 * (sh - 7));
+ g1 = (Inlines.VSHR32(Inlines.MULT16_32_Q15(Inlines.celt_rsqrt_norm(t), xy), sh + 1));
+ }
+
+ if (Inlines.abs(T1 - prev_period) <= 1) {
+ cont = prev_gain;
+ } else if (Inlines.abs(T1 - prev_period) <= 2 && 5 * k * k < T0) {
+ cont = Inlines.HALF16(prev_gain);
+ } else {
+ cont = 0;
+ }
+ thresh = Inlines.MAX16(((short) (0.5 + (.3f) * (((int) 1) << (15))))/*Inlines.QCONST16(.3f, 15)*/, (Inlines.MULT16_16_Q15(((short) (0.5 + (.7f) * (((int) 1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, g0) - cont));
+
+ /* Bias against very high pitch (very short period) to avoid false-positives
+ due to short-term correlation */
+ if (T1 < 3 * minperiod) {
+ thresh = Inlines.MAX16(((short) (0.5 + (.4f) * (((int) 1) << (15))))/*Inlines.QCONST16(.4f, 15)*/, (Inlines.MULT16_16_Q15(((short) (0.5 + (.85f) * (((int) 1) << (15))))/*Inlines.QCONST16(.85f, 15)*/, g0) - cont));
+ } else if (T1 < 2 * minperiod) {
+ thresh = Inlines.MAX16(((short) (0.5 + (.5f) * (((int) 1) << (15))))/*Inlines.QCONST16(.5f, 15)*/, (Inlines.MULT16_16_Q15(((short) (0.5 + (.9f) * (((int) 1) << (15))))/*Inlines.QCONST16(.9f, 15)*/, g0) - cont));
+ }
+ if (g1 > thresh) {
+ best_xy = xy;
+ best_yy = yy;
+ T = T1;
+ g = g1;
+ }
+ }
+
+ best_xy = Inlines.MAX32(0, best_xy);
+ if (best_yy <= best_xy) {
+ pg = CeltConstants.Q15ONE;
+ } else {
+ pg = (Inlines.SHR32(Inlines.frac_div32(best_xy, best_yy + 1), 16));
+ }
+
+ for (k = 0; k < 3; k++) {
+ xcorr[k] = Kernels.celt_inner_prod(x, x_ptr, x, x_ptr - (T + k - 1), N);
+ }
+
+ if ((xcorr[2] - xcorr[0]) > Inlines.MULT16_32_Q15(((short) (0.5 + (.7f) * (((int) 1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, xcorr[1] - xcorr[0])) {
+ offset = 1;
+ } else if ((xcorr[0] - xcorr[2]) > Inlines.MULT16_32_Q15(((short) (0.5 + (.7f) * (((int) 1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, xcorr[1] - xcorr[2])) {
+ offset = -1;
+ } else {
+ offset = 0;
+ }
+
+ if (pg > g) {
+ pg = g;
+ }
+
+ T0_.Val = 2 * T + offset;
+
+ if (T0_.Val < minperiod0) {
+ T0_.Val = minperiod0;
+ }
+
+ return pg;
+ }
+}
diff --git a/app/src/main/java/org/concentus/PitchAnalysisCore.java b/app/src/main/java/org/concentus/PitchAnalysisCore.java
new file mode 100644
index 0000000000..15f262bd96
--- /dev/null
+++ b/app/src/main/java/org/concentus/PitchAnalysisCore.java
@@ -0,0 +1,758 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class PitchAnalysisCore {
+
+ private static final int SCRATCH_SIZE = 22;
+ private static final int SF_LENGTH_4KHZ = (SilkConstants.PE_SUBFR_LENGTH_MS * 4);
+ private static final int SF_LENGTH_8KHZ = (SilkConstants.PE_SUBFR_LENGTH_MS * 8);
+ private static final int MIN_LAG_4KHZ = (SilkConstants.PE_MIN_LAG_MS * 4);
+ private static final int MIN_LAG_8KHZ = (SilkConstants.PE_MIN_LAG_MS * 8);
+ private static final int MAX_LAG_4KHZ = (SilkConstants.PE_MAX_LAG_MS * 4);
+ private static final int MAX_LAG_8KHZ = (SilkConstants.PE_MAX_LAG_MS * 8 - 1);
+ private static final int CSTRIDE_4KHZ = (MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ);
+ private static final int CSTRIDE_8KHZ = (MAX_LAG_8KHZ + 3 - (MIN_LAG_8KHZ - 2));
+ private static final int D_COMP_MIN = (MIN_LAG_8KHZ - 3);
+ private static final int D_COMP_MAX = (MAX_LAG_8KHZ + 4);
+ private static final 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?
+ static class silk_pe_stage3_vals {
+
+ public final int[] Values = new int[SilkConstants.PE_NB_STAGE3_LAGS];
+ }
+
+ /**
+ * **********************************************************
+ */
+ /* FIXED POINT CORE PITCH ANALYSIS FUNCTION */
+ /**
+ * **********************************************************
+ */
+ 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 */
+ BoxedValueByte 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;
+ byte[][] 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.MemSet(filt_state, 0, 2);
+ Resampler.silk_resampler_down2(filt_state, frame_8kHz, frame, frame_length);
+ } else if (Fs_kHz == 12) {
+ Arrays.MemSet(filt_state, 0, 6);
+ Resampler.silk_resampler_down2_3(filt_state, frame_8kHz, frame, frame_length);
+ } else {
+ Inlines.OpusAssert(Fs_kHz == 8);
+ System.arraycopy(frame, 0, frame_8kHz, 0, frame_length_8kHz);
+ }
+
+ /* Decimate again to 4 kHz */
+ Arrays.MemSet(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 */
+ BoxedValueInt boxed_energy = new BoxedValueInt(0);
+ BoxedValueInt boxed_shift = new BoxedValueInt(0);
+ SumSqrShift.silk_sum_sqr_shift(boxed_energy, boxed_shift, frame_4kHz, frame_length_4kHz);
+ energy = boxed_energy.Val;
+ shift = boxed_shift.Val;
+
+ 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.MemSet(C, (short) 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.MemSet(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 */
+ boxed_energy.Val = 0;
+ boxed_shift.Val = 0;
+ SumSqrShift.silk_sum_sqr_shift(boxed_energy, boxed_shift, frame_8kHz, frame_length_8kHz);
+ energy = boxed_energy.Val;
+ shift = boxed_shift.Val;
+
+ 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.MemSet(C, (short) 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(C, k, d - (MIN_LAG_8KHZ - 2), CSTRIDE_8KHZ, (short) 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 = Integer.MIN_VALUE;
+ CCmax_b = Integer.MIN_VALUE;
+
+ 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 = SilkTables.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 = SilkTables.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 = Integer.MIN_VALUE;
+ 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 */ SilkTables.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.MemSet(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 */
+ boxed_energy.Val = 0;
+ boxed_shift.Val = 0;
+ SumSqrShift.silk_sum_sqr_shift(boxed_energy, boxed_shift, frame, frame_length);
+ energy = boxed_energy.Val;
+ shift = boxed_shift.Val;
+
+ 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 = Integer.MIN_VALUE;
+ /* pitch lags according to second stage */
+ for (k = 0; k < nb_subfr; k++) {
+ pitch_out[k] = lag + 2 * SilkTables.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) SilkTables.silk_nb_cbk_searchs_stage3[complexity];
+ Lag_CB_ptr = SilkTables.silk_CB_lags_stage3;
+ } else {
+ nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE3_10MS;
+ Lag_CB_ptr = SilkTables.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.MAX_VALUE - 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 + SilkTables.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 = (byte) 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 = (byte) 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;
+ byte[][] Lag_range_ptr;
+ byte[][] 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 = SilkTables.silk_Lag_range_stage3[complexity];
+ Lag_CB_ptr = SilkTables.silk_CB_lags_stage3;
+ nb_cbk_search = SilkTables.silk_nb_cbk_searchs_stage3[complexity];
+ } else {
+ Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = SilkTables.silk_Lag_range_stage3_10_ms;
+ Lag_CB_ptr = SilkTables.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;
+ byte[][] Lag_range_ptr;
+ byte[][] 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 = SilkTables.silk_Lag_range_stage3[complexity];
+ Lag_CB_ptr = SilkTables.silk_CB_lags_stage3;
+ nb_cbk_search = SilkTables.silk_nb_cbk_searchs_stage3[complexity];
+ } else {
+ Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = SilkTables.silk_Lag_range_stage3_10_ms;
+ Lag_CB_ptr = SilkTables.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;
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/ProcessGains.java b/app/src/main/java/org/concentus/ProcessGains.java
new file mode 100644
index 0000000000..a80ced26db
--- /dev/null
+++ b/app/src/main/java/org/concentus/ProcessGains.java
@@ -0,0 +1,123 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class ProcessGains {
+
+ /* Processing of gains */
+ 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(Integer.MAX_VALUE, -psEncCtrl.ResNrgQ[k])) {
+ ResNrgPart = Integer.MAX_VALUE;
+ } 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.MAX_VALUE) {
+ /* 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, Integer.MAX_VALUE >> 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, Integer.MAX_VALUE >> 16);
+ psEncCtrl.Gains_Q16[k] = Inlines.silk_LSHIFT_SAT32(gain, 16);
+ /* Q16 */
+ }
+
+ }
+
+ /* Save unquantized gains and gain Index */
+ System.arraycopy(psEncCtrl.Gains_Q16, 0, psEncCtrl.GainsUnq_Q16, 0, psEnc.nb_subfr);
+ psEncCtrl.lastGainIndexPrev = psShapeSt.LastGainIndex;
+
+ /* Quantize gains */
+ BoxedValueByte boxed_lastGainIndex = new BoxedValueByte(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 = SilkTables.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)*/);
+ }
+}
diff --git a/app/src/main/java/org/concentus/PulseCache.java b/app/src/main/java/org/concentus/PulseCache.java
new file mode 100644
index 0000000000..bb397d02ef
--- /dev/null
+++ b/app/src/main/java/org/concentus/PulseCache.java
@@ -0,0 +1,50 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class PulseCache {
+
+ int size = 0;
+ short[] index = null;
+ short[] bits = null;
+ short[] caps = null;
+
+ void Reset() {
+ size = 0;
+ index = null;
+ bits = null;
+ caps = null;
+ }
+}
diff --git a/app/src/main/java/org/concentus/QuantizeBands.java b/app/src/main/java/org/concentus/QuantizeBands.java
new file mode 100644
index 0000000000..1585b30c5b
--- /dev/null
+++ b/app/src/main/java/org/concentus/QuantizeBands.java
@@ -0,0 +1,461 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class QuantizeBands {
+
+ /* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */
+ private static final int[] pred_coef = new int[]{29440, 26112, 21248, 16384};
+ private static final int[] beta_coef = new int[]{30147, 22282, 12124, 6554};
+ private static final int beta_intra = 4915;
+ private static short[] small_energy_icdf = {2, 1, 0};
+
+ static int loss_distortion(int[][] eBands, int[][] oldEBands, int start, int end, int len, int C) {
+ int c, i;
+ int dist = 0;
+ c = 0;
+ do {
+ for (i = start; i < end; i++) {
+ int d = Inlines.SUB16(Inlines.SHR16(eBands[c][i], 3), Inlines.SHR16(oldEBands[c][i], 3));
+ dist = Inlines.MAC16_16(dist, d, d);
+ }
+ } while (++c < C);
+
+ return Inlines.MIN32(200, Inlines.SHR32(dist, 2 * CeltConstants.DB_SHIFT - 6));
+ }
+
+ static int quant_coarse_energy_impl(CeltMode m, int start, int end,
+ int[][] eBands, int[][] oldEBands,
+ int budget, int tell,
+ short[] prob_model, int[][] error, EntropyCoder enc,
+ int C, int LM, int intra, int max_decay, int lfe) {
+ int i, c;
+ int badness = 0;
+ int[] prev = {0, 0};
+ int coef;
+ int beta;
+
+ if (tell + 3 <= budget) {
+ enc.enc_bit_logp(intra, 3);
+ }
+
+ if (intra != 0) {
+ coef = 0;
+ beta = beta_intra;
+ } else {
+ beta = beta_coef[LM];
+ coef = pred_coef[LM];
+ }
+
+ /* Encode at a fixed coarse resolution */
+ for (i = start; i < end; i++) {
+ c = 0;
+ do {
+ int bits_left;
+ int qi, qi0;
+ int q;
+ int x;
+ int f, tmp;
+ int oldE;
+ int decay_bound;
+ x = eBands[c][i];
+ oldE = Inlines.MAX16(-((short) (0.5 + (9.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(9.0f, CeltConstants.DB_SHIFT)*/, oldEBands[c][i]);
+ f = Inlines.SHL32(Inlines.EXTEND32(x), 7) - Inlines.PSHR32(Inlines.MULT16_16(coef, oldE), 8) - prev[c];
+ /* Rounding to nearest integer here is really important! */
+ qi = (f + ((int) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT + 7))))/*Inlines.QCONST32(.5f, CeltConstants.DB_SHIFT + 7)*/) >> (CeltConstants.DB_SHIFT + 7);
+ decay_bound = Inlines.EXTRACT16(Inlines.MAX32(-((short) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/,
+ Inlines.SUB32((int) oldEBands[c][i], max_decay)));
+ /* Prevent the energy from going down too quickly (e.g. for bands
+ that have just one bin) */
+ if (qi < 0 && x < decay_bound) {
+ qi += (int) Inlines.SHR16(Inlines.SUB16(decay_bound, x), CeltConstants.DB_SHIFT);
+ if (qi > 0) {
+ qi = 0;
+ }
+ }
+ qi0 = qi;
+ /* If we don't have enough bits to encode all the energy, just assume
+ something safe. */
+ tell = enc.tell();
+ bits_left = budget - tell - 3 * C * (end - i);
+ if (i != start && bits_left < 30) {
+ if (bits_left < 24) {
+ qi = Inlines.IMIN(1, qi);
+ }
+ if (bits_left < 16) {
+ qi = Inlines.IMAX(-1, qi);
+ }
+ }
+ if (lfe != 0 && i >= 2) {
+ qi = Inlines.IMIN(qi, 0);
+ }
+ if (budget - tell >= 15) {
+ int pi;
+ pi = 2 * Inlines.IMIN(i, 20);
+ BoxedValueInt boxed_qi = new BoxedValueInt(qi);
+ Laplace.ec_laplace_encode(enc, boxed_qi, ((prob_model[pi]) << 7), ((int) prob_model[pi + 1]) << 6);
+ qi = boxed_qi.Val;
+ } else if (budget - tell >= 2) {
+ qi = Inlines.IMAX(-1, Inlines.IMIN(qi, 1));
+ enc.enc_icdf(2 * qi ^ (0 - (qi < 0 ? 1 : 0)), small_energy_icdf, 2);
+ } else if (budget - tell >= 1) {
+ qi = Inlines.IMIN(0, qi);
+ enc.enc_bit_logp(-qi, 1);
+ } else {
+ qi = -1;
+ }
+ error[c][i] = (Inlines.PSHR32(f, 7) - Inlines.SHL16((qi), CeltConstants.DB_SHIFT));
+ badness += Inlines.abs(qi0 - qi);
+ q = (int) Inlines.SHL32(qi, CeltConstants.DB_SHIFT);
+
+ tmp = Inlines.PSHR32(Inlines.MULT16_16(coef, oldE), 8) + prev[c] + Inlines.SHL32(q, 7);
+ tmp = Inlines.MAX32(-((int) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT + 7))))/*Inlines.QCONST32(28.0f, CeltConstants.DB_SHIFT + 7)*/, tmp);
+ oldEBands[c][i] = (Inlines.PSHR32(tmp, 7));
+ prev[c] = prev[c] + Inlines.SHL32(q, 7) - Inlines.MULT16_16(beta, Inlines.PSHR32(q, 8));
+ } while (++c < C);
+ }
+ return lfe != 0 ? 0 : badness;
+ }
+
+ static void quant_coarse_energy(CeltMode m, int start, int end, int effEnd,
+ int[][] eBands, int[][] oldEBands, int budget,
+ int[][] error, EntropyCoder enc, int C, int LM, int nbAvailableBytes,
+ int force_intra, BoxedValueInt delayedIntra, int two_pass, int loss_rate, int lfe) {
+ int intra;
+ int max_decay;
+ int[][] oldEBands_intra;
+ int[][] error_intra;
+ EntropyCoder enc_start_state = new EntropyCoder(); // [porting note] stack variable
+ int tell;
+ int badness1 = 0;
+ int intra_bias;
+ int new_distortion;
+
+ intra = (force_intra != 0 || (two_pass == 0 && delayedIntra.Val > 2 * C * (end - start) && nbAvailableBytes > (end - start) * C)) ? 1 : 0;
+ intra_bias = ((budget * delayedIntra.Val * loss_rate) / (C * 512));
+ new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m.nbEBands, C);
+
+ tell = enc.tell();
+ if (tell + 3 > budget) {
+ two_pass = intra = 0;
+ }
+
+ max_decay = ((short) (0.5 + (16.0f) * (1 << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(16.0f, CeltConstants.DB_SHIFT)*/;
+ if (end - start > 10) {
+ max_decay = (Inlines.MIN32(max_decay, Inlines.SHL32(nbAvailableBytes, CeltConstants.DB_SHIFT - 3))); // opus bug: useless extend32
+ }
+ if (lfe != 0) {
+ max_decay = ((short) (0.5 + (3.0f) * (1 << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(3.0f, CeltConstants.DB_SHIFT)*/;
+ }
+ enc_start_state.Assign(enc);
+
+ oldEBands_intra = Arrays.InitTwoDimensionalArrayInt(C, m.nbEBands);
+ error_intra = Arrays.InitTwoDimensionalArrayInt(C, m.nbEBands);
+ System.arraycopy(oldEBands[0], 0, oldEBands_intra[0], 0, m.nbEBands);
+ if (C == 2) {
+ System.arraycopy(oldEBands[1], 0, oldEBands_intra[1], 0, m.nbEBands);
+ }
+
+ if (two_pass != 0 || intra != 0) {
+ badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget,
+ tell, CeltTables.e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe);
+ }
+
+ if (intra == 0) {
+ int intra_buf;
+ EntropyCoder enc_intra_state = new EntropyCoder(); // [porting note] stack variable
+ int tell_intra;
+ int nstart_bytes;
+ int nintra_bytes;
+ int save_bytes;
+ int badness2;
+ byte[] intra_bits = null;
+
+ tell_intra = (int) enc.tell_frac();
+
+ enc_intra_state.Assign(enc);
+
+ nstart_bytes = enc_start_state.range_bytes();
+ nintra_bytes = enc_intra_state.range_bytes();
+ intra_buf = nstart_bytes;
+ save_bytes = nintra_bytes - nstart_bytes;
+
+ if (save_bytes != 0) {
+ intra_bits = new byte[save_bytes];
+ /* Copy bits from intra bit-stream */
+ System.arraycopy(enc_intra_state.get_buffer(), intra_buf, intra_bits, 0, save_bytes);
+ }
+
+ enc.Assign(enc_start_state);
+
+ badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget,
+ tell, CeltTables.e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe);
+
+ if (two_pass != 0 && (badness1 < badness2 || (badness1 == badness2 && (enc.tell_frac()) + intra_bias > tell_intra))) {
+ enc.Assign(enc_intra_state);
+ /* Copy intra bits to bit-stream */
+ if (intra_bits != null) {
+ enc_intra_state.write_buffer(intra_bits, 0, intra_buf, (nintra_bytes - nstart_bytes));
+ }
+ System.arraycopy(oldEBands_intra[0], 0, oldEBands[0], 0, m.nbEBands);
+ System.arraycopy(error_intra[0], 0, error[0], 0, m.nbEBands);
+ if (C == 2) {
+ System.arraycopy(oldEBands_intra[1], 0, oldEBands[1], 0, m.nbEBands);
+ System.arraycopy(error_intra[1], 0, error[1], 0, m.nbEBands);
+ }
+ intra = 1;
+ }
+ } else {
+ System.arraycopy(oldEBands_intra[0], 0, oldEBands[0], 0, m.nbEBands);
+ System.arraycopy(error_intra[0], 0, error[0], 0, m.nbEBands);
+ if (C == 2) {
+ System.arraycopy(oldEBands_intra[1], 0, oldEBands[1], 0, m.nbEBands);
+ System.arraycopy(error_intra[1], 0, error[1], 0, m.nbEBands);
+ }
+ }
+
+ if (intra != 0) {
+ delayedIntra.Val = new_distortion;
+ } else {
+ delayedIntra.Val = Inlines.ADD32(Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(pred_coef[LM], pred_coef[LM]), delayedIntra.Val),
+ new_distortion);
+ }
+ }
+
+ static void quant_fine_energy(CeltMode m, int start, int end, int[][] oldEBands, int[][] error, int[] fine_quant, EntropyCoder enc, int C) {
+ int i, c;
+
+ /* Encode finer resolution */
+ for (i = start; i < end; i++) {
+ int frac = (1 << fine_quant[i]);
+ if (fine_quant[i] <= 0) {
+ continue;
+ }
+ c = 0;
+ do {
+ int q2;
+ int offset;
+ /* Has to be without rounding */
+ q2 = (error[c][i] + ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/) >> (CeltConstants.DB_SHIFT - fine_quant[i]);
+ if (q2 > frac - 1) {
+ q2 = frac - 1;
+ }
+ if (q2 < 0) {
+ q2 = 0;
+ }
+ enc.enc_bits(q2, fine_quant[i]);
+ offset = Inlines.SUB16(
+ (Inlines.SHR32(
+ Inlines.SHL32(q2, CeltConstants.DB_SHIFT) + ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/,
+ fine_quant[i])),
+ ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/);
+ oldEBands[c][i] += offset;
+ error[c][i] -= offset;
+ } while (++c < C);
+ }
+ }
+
+ static void quant_energy_finalise(CeltMode m, int start, int end, int[][] oldEBands, int[][] error, int[] fine_quant, int[] fine_priority, int bits_left, EntropyCoder enc, int C) {
+ int i, prio, c;
+
+ /* Use up the remaining bits */
+ for (prio = 0; prio < 2; prio++) {
+ for (i = start; i < end && bits_left >= C; i++) {
+ if (fine_quant[i] >= CeltConstants.MAX_FINE_BITS || fine_priority[i] != prio) {
+ continue;
+ }
+
+ c = 0;
+ do {
+ int q2;
+ int offset;
+ q2 = error[c][i] < 0 ? 0 : 1;
+ enc.enc_bits(q2, 1);
+ offset = Inlines.SHR16((Inlines.SHL16((q2), CeltConstants.DB_SHIFT) - ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/), fine_quant[i] + 1);
+ oldEBands[c][i] += offset;
+ bits_left--;
+ } while (++c < C);
+ }
+ }
+ }
+
+ static void unquant_coarse_energy(CeltMode m, int start, int end, int[] oldEBands, int intra, EntropyCoder dec, int C, int LM) {
+ short[] prob_model = CeltTables.e_prob_model[LM][intra];
+ int i, c;
+ int[] prev = {0, 0};
+ int coef;
+ int beta;
+ int budget;
+ int tell;
+
+ if (intra != 0) {
+ coef = 0;
+ beta = beta_intra;
+ } else {
+ beta = beta_coef[LM];
+ coef = pred_coef[LM];
+ }
+
+ budget = (int) dec.storage * 8;
+
+ /* Decode at a fixed coarse resolution */
+ for (i = start; i < end; i++) {
+ c = 0;
+ do {
+ int qi;
+ int q;
+ int tmp;
+ /* It would be better to express this invariant as a
+ test on C at function entry, but that isn't enough
+ to make the static analyzer happy. */
+ Inlines.OpusAssert(c < 2);
+ tell = dec.tell();
+ if (budget - tell >= 15) {
+ int pi;
+ pi = 2 * Inlines.IMIN(i, 20);
+ qi = Laplace.ec_laplace_decode(dec,
+ prob_model[pi] << 7, prob_model[pi + 1] << 6);
+ } else if (budget - tell >= 2) {
+ qi = dec.dec_icdf(small_energy_icdf, 2);
+ qi = (qi >> 1) ^ -(qi & 1);
+ } else if (budget - tell >= 1) {
+ qi = 0 - dec.dec_bit_logp(1);
+ } else {
+ qi = -1;
+ }
+ q = (int) Inlines.SHL32(qi, CeltConstants.DB_SHIFT); // opus bug: useless extend32
+
+ oldEBands[i + c * m.nbEBands] = Inlines.MAX16((0 - ((short) (0.5 + (9.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(9.0f, CeltConstants.DB_SHIFT)*/), oldEBands[i + c * m.nbEBands]);
+ tmp = Inlines.PSHR32(Inlines.MULT16_16(coef, oldEBands[i + c * m.nbEBands]), 8) + prev[c] + Inlines.SHL32(q, 7);
+ tmp = Inlines.MAX32(-((int) (0.5 + (28.0f) * (((int) 1) << (CeltConstants.DB_SHIFT + 7))))/*Inlines.QCONST32(28.0f, CeltConstants.DB_SHIFT + 7)*/, tmp);
+ oldEBands[i + c * m.nbEBands] = (Inlines.PSHR32(tmp, 7));
+ prev[c] = prev[c] + Inlines.SHL32(q, 7) - Inlines.MULT16_16(beta, Inlines.PSHR32(q, 8));
+ } while (++c < C);
+ }
+ }
+
+ static void unquant_fine_energy(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, EntropyCoder dec, int C) {
+ int i, c;
+ /* Decode finer resolution */
+ for (i = start; i < end; i++) {
+ if (fine_quant[i] <= 0) {
+ continue;
+ }
+ c = 0;
+ do {
+ int q2;
+ int offset;
+ q2 = dec.dec_bits(fine_quant[i]);
+ offset = Inlines.SUB16((Inlines.SHR32(
+ Inlines.SHL32(q2, CeltConstants.DB_SHIFT)
+ + ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/, fine_quant[i])),
+ ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/); // opus bug: unnecessary extend32
+ oldEBands[i + c * m.nbEBands] += offset;
+ } while (++c < C);
+ }
+ }
+
+ static void unquant_energy_finalise(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, int[] fine_priority, int bits_left, EntropyCoder dec, int C) {
+ int i, prio, c;
+
+ /* Use up the remaining bits */
+ for (prio = 0; prio < 2; prio++) {
+ for (i = start; i < end && bits_left >= C; i++) {
+ if (fine_quant[i] >= CeltConstants.MAX_FINE_BITS || fine_priority[i] != prio) {
+ continue;
+ }
+ c = 0;
+ do {
+ int q2;
+ int offset;
+ q2 = dec.dec_bits(1);
+ offset = Inlines.SHR16((Inlines.SHL16((q2), CeltConstants.DB_SHIFT) - ((short) (0.5 + (.5f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/), fine_quant[i] + 1);
+ oldEBands[i + c * m.nbEBands] += offset;
+ bits_left--;
+ } while (++c < C);
+ }
+ }
+ }
+
+ ///
+ /// non-pointer case
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ static void amp2Log2(CeltMode m, int effEnd, int end,
+ int[][] bandE, int[][] bandLogE, int C) {
+ int c, i;
+ c = 0;
+ do {
+ for (i = 0; i < effEnd; i++) {
+ bandLogE[c][i]
+ = (Inlines.celt_log2(Inlines.SHL32(bandE[c][i], 2))
+ - Inlines.SHL16((int) CeltTables.eMeans[i], 6));
+ }
+ for (i = effEnd; i < end; i++) {
+ bandLogE[c][i] = (0 - ((short) (0.5 + (14.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(14.0f, CeltConstants.DB_SHIFT)*/);
+ }
+ } while (++c < C);
+ }
+
+ ///
+ /// only needed in one place
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ static void amp2Log2(CeltMode m, int effEnd, int end,
+ int[] bandE, int[] bandLogE, int bandLogE_ptr, int C) {
+ int c, i;
+ c = 0;
+ do {
+ for (i = 0; i < effEnd; i++) {
+ bandLogE[bandLogE_ptr + (c * m.nbEBands) + i]
+ = (Inlines.celt_log2(Inlines.SHL32(bandE[i + c * m.nbEBands], 2))
+ - Inlines.SHL16((int) CeltTables.eMeans[i], 6));
+ }
+ for (i = effEnd; i < end; i++) {
+ bandLogE[bandLogE_ptr + (c * m.nbEBands) + i] = (0 - ((short) (0.5 + (14.0f) * (((int) 1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(14.0f, CeltConstants.DB_SHIFT)*/);
+ }
+ } while (++c < C);
+ }
+}
diff --git a/app/src/main/java/org/concentus/QuantizeLTPGains.java b/app/src/main/java/org/concentus/QuantizeLTPGains.java
new file mode 100644
index 0000000000..41a53f18b2
--- /dev/null
+++ b/app/src/main/java/org/concentus/QuantizeLTPGains.java
@@ -0,0 +1,141 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class QuantizeLTPGains {
+
+ static void silk_quant_LTP_gains(
+ short[] B_Q14, /* I/O (un)quantized LTP gains [MAX_NB_SUBFR * LTP_ORDER] */
+ byte[] cbk_index, /* O Codebook Index [MAX_NB_SUBFR] */
+ BoxedValueByte 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;
+ byte[] temp_idx = new byte[SilkConstants.MAX_NB_SUBFR];
+ short[] cl_ptr_Q5;
+ byte[][] cbk_ptr_Q7;
+ short[] 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 = Integer.MAX_VALUE;
+ 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 = SilkTables.silk_LTP_gain_BITS_Q5_ptrs[k];
+ cbk_ptr_Q7 = SilkTables.silk_LTP_vq_ptrs_Q7[k];
+ cbk_gain_ptr_Q7 = SilkTables.silk_LTP_vq_gain_ptrs_Q7[k];
+ cbk_size = SilkTables.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;
+
+ BoxedValueByte temp_idx_box = new BoxedValueByte(temp_idx[j]);
+ BoxedValueInt rate_dist_Q14_subfr_box = new BoxedValueInt(0);
+ BoxedValueInt gain_Q7_box = new BoxedValueInt(0);
+ 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(Integer.MAX_VALUE - 1, rate_dist_Q14);
+
+ if (rate_dist_Q14 < min_rate_dist_Q14) {
+ min_rate_dist_Q14 = rate_dist_Q14;
+ periodicity_index.Val = (byte) k;
+ System.arraycopy(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 < SilkTables.silk_LTP_gain_middle_avg_RD_Q14)) {
+ break;
+ }
+ }
+
+ cbk_ptr_Q7 = SilkTables.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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/Rate.java b/app/src/main/java/org/concentus/Rate.java
new file mode 100644
index 0000000000..41b5d7a296
--- /dev/null
+++ b/app/src/main/java/org/concentus/Rate.java
@@ -0,0 +1,460 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class Rate {
+
+ private static final byte[] LOG2_FRAC_TABLE = {
+ 0,
+ 8, 13,
+ 16, 19, 21, 23,
+ 24, 26, 27, 28, 29, 30, 31, 32,
+ 32, 33, 34, 34, 35, 36, 36, 37, 37
+ };
+
+ private static final int ALLOC_STEPS = 6;
+
+ static int get_pulses(int i) {
+ return i < 8 ? i : (8 + (i & 7)) << ((i >> 3) - 1);
+ }
+
+ static int bits2pulses(CeltMode m, int band, int LM, int bits) {
+ int i;
+ int lo, hi;
+
+ LM++;
+ short[] cache = m.cache.bits;
+ int cache_ptr = m.cache.index[LM * m.nbEBands + band];
+
+ lo = 0;
+ hi = cache[cache_ptr];
+ bits--;
+ for (i = 0; i < CeltConstants.LOG_MAX_PSEUDO; i++) {
+ int mid = (lo + hi + 1) >> 1;
+ /* OPT: Make sure this is implemented with a conditional move */
+ if ((int) cache[cache_ptr + mid] >= bits) {
+ hi = mid;
+ } else {
+ lo = mid;
+ }
+ }
+ if (bits - (lo == 0 ? -1 : (int) cache[cache_ptr + lo]) <= (int) cache[cache_ptr + hi] - bits) {
+ return lo;
+ } else {
+ return hi;
+ }
+ }
+
+ static int pulses2bits(CeltMode m, int band, int LM, int pulses) {
+ LM++;
+ return pulses == 0 ? 0 : m.cache.bits[m.cache.index[LM * m.nbEBands + band] + pulses] + 1;
+ }
+
+ static int interp_bits2pulses(CeltMode m, int start, int end, int skip_start,
+ int[] bits1, int[] bits2, int[] thresh, int[] cap, int total, BoxedValueInt _balance,
+ int skip_rsv, BoxedValueInt intensity, int intensity_rsv, BoxedValueInt dual_stereo, int dual_stereo_rsv, int[] bits,
+ int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth) {
+ int psum;
+ int lo, hi;
+ int i, j;
+ int logM;
+ int stereo;
+ int codedBands = -1;
+ int alloc_floor;
+ int left, percoeff;
+ int done;
+ int balance;
+
+ alloc_floor = C << EntropyCoder.BITRES;
+ stereo = C > 1 ? 1 : 0;
+
+ logM = LM << EntropyCoder.BITRES;
+ lo = 0;
+ hi = 1 << ALLOC_STEPS;
+ for (i = 0; i < ALLOC_STEPS; i++) {
+ int mid = (lo + hi) >> 1;
+ psum = 0;
+ done = 0;
+ for (j = end; j-- > start;) {
+ int tmp = bits1[j] + (mid * (int) bits2[j] >> ALLOC_STEPS);
+ if (tmp >= thresh[j] || done != 0) {
+ done = 1;
+ /* Don't allocate more than we can actually use */
+ psum += Inlines.IMIN(tmp, cap[j]);
+ } else if (tmp >= alloc_floor) {
+ psum += alloc_floor;
+ }
+ }
+ if (psum > total) {
+ hi = mid;
+ } else {
+ lo = mid;
+ }
+ }
+ psum = 0;
+ /*printf ("interp bisection gave %d\n", lo);*/
+ done = 0;
+ for (j = end; j-- > start;) {
+ int tmp = bits1[j] + (lo * bits2[j] >> ALLOC_STEPS);
+ if (tmp < thresh[j] && done == 0) {
+ if (tmp >= alloc_floor) {
+ tmp = alloc_floor;
+ } else {
+ tmp = 0;
+ }
+ } else {
+ done = 1;
+ }
+
+ /* Don't allocate more than we can actually use */
+ tmp = Inlines.IMIN(tmp, cap[j]);
+ bits[j] = tmp;
+ psum += tmp;
+ }
+
+ /* Decide which bands to skip, working backwards from the end. */
+ for (codedBands = end;; codedBands--) {
+ int band_width;
+ int band_bits;
+ int rem;
+ j = codedBands - 1;
+ /* Never skip the first band, nor a band that has been boosted by
+ dynalloc.
+ In the first case, we'd be coding a bit to signal we're going to waste
+ all the other bits.
+ In the second case, we'd be coding a bit to redistribute all the bits
+ we just signaled should be cocentrated in this band. */
+ if (j <= skip_start) {
+ /* Give the bit we reserved to end skipping back. */
+ total += skip_rsv;
+ break;
+ }
+
+ /*Figure out how many left-over bits we would be adding to this band.
+ This can include bits we've stolen back from higher, skipped bands.*/
+ left = total - psum;
+ percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]);
+ left -= (m.eBands[codedBands] - m.eBands[start]) * percoeff;
+ rem = Inlines.IMAX(left - (m.eBands[j] - m.eBands[start]), 0);
+ band_width = m.eBands[codedBands] - m.eBands[j];
+ band_bits = (int) (bits[j] + percoeff * band_width + rem);
+ /*Only code a skip decision if we're above the threshold for this band.
+ Otherwise it is force-skipped.
+ This ensures that we have enough bits to code the skip flag.*/
+ if (band_bits >= Inlines.IMAX(thresh[j], alloc_floor + (1 << EntropyCoder.BITRES))) {
+ if (encode != 0) {
+ /*This if() block is the only part of the allocation function that
+ is not a mandatory part of the bitstream: any bands we choose to
+ skip here must be explicitly signaled.*/
+ /*Choose a threshold with some hysteresis to keep bands from
+ fluctuating in and out.*/
+ if (codedBands <= start + 2 || (band_bits > ((j < prev ? 7 : 9) * band_width << LM << EntropyCoder.BITRES) >> 4 && j <= signalBandwidth)) {
+ ec.enc_bit_logp(1, 1);
+ break;
+ }
+ ec.enc_bit_logp(0, 1);
+ } else if (ec.dec_bit_logp(1) != 0) {
+ break;
+ }
+ /*We used a bit to skip this band.*/
+ psum += 1 << EntropyCoder.BITRES;
+ band_bits -= 1 << EntropyCoder.BITRES;
+ }
+ /*Reclaim the bits originally allocated to this band.*/
+ psum -= bits[j] + intensity_rsv;
+ if (intensity_rsv > 0) {
+ intensity_rsv = LOG2_FRAC_TABLE[j - start];
+ }
+ psum += intensity_rsv;
+ if (band_bits >= alloc_floor) {
+ /*If we have enough for a fine energy bit per channel, use it.*/
+ psum += alloc_floor;
+ bits[j] = alloc_floor;
+ } else {
+ /*Otherwise this band gets nothing at all.*/
+ bits[j] = 0;
+ }
+ }
+
+ Inlines.OpusAssert(codedBands > start);
+ /* Code the intensity and dual stereo parameters. */
+ if (intensity_rsv > 0) {
+ if (encode != 0) {
+ intensity.Val = Inlines.IMIN(intensity.Val, codedBands);
+ ec.enc_uint((intensity.Val - start), (codedBands + 1 - start));
+ } else {
+ intensity.Val = start + (int) ec.dec_uint(codedBands + 1 - start);
+ }
+ } else {
+ intensity.Val = 0;
+ }
+
+ if (intensity.Val <= start) {
+ total += dual_stereo_rsv;
+ dual_stereo_rsv = 0;
+ }
+ if (dual_stereo_rsv > 0) {
+ if (encode != 0) {
+ ec.enc_bit_logp(dual_stereo.Val, 1);
+ } else {
+ dual_stereo.Val = ec.dec_bit_logp(1);
+ }
+ } else {
+ dual_stereo.Val = 0;
+ }
+
+ /* Allocate the remaining bits */
+ left = total - psum;
+ percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]);
+ left -= (m.eBands[codedBands] - m.eBands[start]) * percoeff;
+ for (j = start; j < codedBands; j++) {
+ bits[j] += ((int) percoeff * (m.eBands[j + 1] - m.eBands[j]));
+ }
+ for (j = start; j < codedBands; j++) {
+ int tmp = (int) Inlines.IMIN(left, m.eBands[j + 1] - m.eBands[j]);
+ bits[j] += tmp;
+ left -= tmp;
+ }
+ /*for (j=0;j= 0);
+ N0 = m.eBands[j + 1] - m.eBands[j];
+ N = N0 << LM;
+ bit = (int) bits[j] + balance;
+
+ if (N > 1) {
+ excess = Inlines.MAX32(bit - cap[j], 0);
+ bits[j] = bit - excess;
+
+ /* Compensate for the extra DoF in stereo */
+ den = (C * N + ((C == 2 && N > 2 && (dual_stereo.Val == 0) && j < intensity.Val) ? 1 : 0));
+
+ NClogN = den * (m.logN[j] + logM);
+
+ /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET
+ compared to their "fair share" of total/N */
+ offset = (NClogN >> 1) - den * CeltConstants.FINE_OFFSET;
+
+ /* N=2 is the only point that doesn't match the curve */
+ if (N == 2) {
+ offset += den << EntropyCoder.BITRES >> 2;
+ }
+
+ /* Changing the offset for allocating the second and third
+ fine energy bit */
+ if (bits[j] + offset < den * 2 << EntropyCoder.BITRES) {
+ offset += NClogN >> 2;
+ } else if (bits[j] + offset < den * 3 << EntropyCoder.BITRES) {
+ offset += NClogN >> 3;
+ }
+
+ /* Divide with rounding */
+ ebits[j] = Inlines.IMAX(0, (bits[j] + offset + (den << (EntropyCoder.BITRES - 1))));
+ ebits[j] = Inlines.celt_udiv(ebits[j], den) >> EntropyCoder.BITRES;
+
+ /* Make sure not to bust */
+ if (C * ebits[j] > (bits[j] >> EntropyCoder.BITRES)) {
+ ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES;
+ }
+
+ /* More than that is useless because that's about as far as PVQ can go */
+ ebits[j] = Inlines.IMIN(ebits[j], CeltConstants.MAX_FINE_BITS);
+
+ /* If we rounded down or capped this band, make it a candidate for the
+ final fine energy pass */
+ fine_priority[j] = (ebits[j] * (den << EntropyCoder.BITRES) >= bits[j] + offset) ? 1 : 0;
+
+ /* Remove the allocated fine bits; the rest are assigned to PVQ */
+ bits[j] -= C * ebits[j] << EntropyCoder.BITRES;
+
+ } else {
+ /* For N=1, all bits go to fine energy except for a single sign bit */
+ excess = Inlines.MAX32(0, bit - (C << EntropyCoder.BITRES));
+ bits[j] = bit - excess;
+ ebits[j] = 0;
+ fine_priority[j] = 1;
+ }
+
+ /* Fine energy can't take advantage of the re-balancing in
+ quant_all_bands().
+ Instead, do the re-balancing here.*/
+ if (excess > 0) {
+ int extra_fine;
+ int extra_bits;
+ extra_fine = Inlines.IMIN(excess >> (stereo + EntropyCoder.BITRES), CeltConstants.MAX_FINE_BITS - ebits[j]);
+ ebits[j] += extra_fine;
+ extra_bits = extra_fine * C << EntropyCoder.BITRES;
+ fine_priority[j] = (extra_bits >= excess - balance) ? 1 : 0;
+ excess -= extra_bits;
+ }
+ balance = excess;
+
+ Inlines.OpusAssert(bits[j] >= 0);
+ Inlines.OpusAssert(ebits[j] >= 0);
+ }
+ /* Save any remaining bits over the cap for the rebalancing in
+ quant_all_bands(). */
+ _balance.Val = balance;
+
+ /* The skipped bands use all their bits for fine energy. */
+ for (; j < end; j++) {
+ ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES;
+ Inlines.OpusAssert(C * ebits[j] << EntropyCoder.BITRES == bits[j]);
+ bits[j] = 0;
+ fine_priority[j] = (ebits[j] < 1) ? 1 : 0;
+ }
+
+ return codedBands;
+ }
+
+ static int compute_allocation(CeltMode m, int start, int end, int[] offsets, int[] cap, int alloc_trim, BoxedValueInt intensity, BoxedValueInt dual_stereo,
+ int total, BoxedValueInt balance, int[] pulses, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth) {
+ int lo, hi, len, j;
+ int codedBands;
+ int skip_start;
+ int skip_rsv;
+ int intensity_rsv;
+ int dual_stereo_rsv;
+
+ total = Inlines.IMAX(total, 0);
+ len = m.nbEBands;
+ skip_start = start;
+ /* Reserve a bit to signal the end of manually skipped bands. */
+ skip_rsv = total >= 1 << EntropyCoder.BITRES ? 1 << EntropyCoder.BITRES : 0;
+ total -= skip_rsv;
+ /* Reserve bits for the intensity and dual stereo parameters. */
+ intensity_rsv = dual_stereo_rsv = 0;
+ if (C == 2) {
+ intensity_rsv = LOG2_FRAC_TABLE[end - start];
+ if (intensity_rsv > total) {
+ intensity_rsv = 0;
+ } else {
+ total -= intensity_rsv;
+ dual_stereo_rsv = total >= 1 << EntropyCoder.BITRES ? 1 << EntropyCoder.BITRES : 0;
+ total -= dual_stereo_rsv;
+ }
+ }
+
+ int[] bits1 = new int[len];
+ int[] bits2 = new int[len];
+ int[] thresh = new int[len];
+ int[] trim_offset = new int[len];
+
+ for (j = start; j < end; j++) {
+ /* Below this threshold, we're sure not to allocate any PVQ bits */
+ thresh[j] = Inlines.IMAX((C) << EntropyCoder.BITRES, (3 * (m.eBands[j + 1] - m.eBands[j]) << LM << EntropyCoder.BITRES) >> 4);
+ /* Tilt of the allocation curve */
+ trim_offset[j] = C * (m.eBands[j + 1] - m.eBands[j]) * (alloc_trim - 5 - LM) * (end - j - 1)
+ * (1 << (LM + EntropyCoder.BITRES)) >> 6;
+ /* Giving less resolution to single-coefficient bands because they get
+ more benefit from having one coarse value per coefficient*/
+ if ((m.eBands[j + 1] - m.eBands[j]) << LM == 1) {
+ trim_offset[j] -= C << EntropyCoder.BITRES;
+ }
+ }
+ lo = 1;
+ hi = m.nbAllocVectors - 1;
+ do {
+ int done = 0;
+ int psum = 0;
+ int mid = (lo + hi) >> 1;
+ for (j = end; j-- > start;) {
+ int bitsj;
+ int N = m.eBands[j + 1] - m.eBands[j];
+ bitsj = C * N * m.allocVectors[mid * len + j] << LM >> 2;
+
+ if (bitsj > 0) {
+ bitsj = Inlines.IMAX(0, bitsj + trim_offset[j]);
+ }
+
+ bitsj += offsets[j];
+
+ if (bitsj >= thresh[j] || done != 0) {
+ done = 1;
+ /* Don't allocate more than we can actually use */
+ psum += Inlines.IMIN(bitsj, cap[j]);
+ } else if (bitsj >= C << EntropyCoder.BITRES) {
+ psum += C << EntropyCoder.BITRES;
+ }
+ }
+ if (psum > total) {
+ hi = mid - 1;
+ } else {
+ lo = mid + 1;
+ }
+ /*printf ("lo = %d, hi = %d\n", lo, hi);*/
+ } while (lo <= hi);
+
+ hi = lo--;
+ /*printf ("interp between %d and %d\n", lo, hi);*/
+
+ for (j = start; j < end; j++) {
+ int bits1j, bits2j;
+ int N = m.eBands[j + 1] - m.eBands[j];
+ bits1j = C * N * m.allocVectors[lo * len + j] << LM >> 2;
+ bits2j = hi >= m.nbAllocVectors
+ ? cap[j] : C * N * m.allocVectors[hi * len + j] << LM >> 2;
+ if (bits1j > 0) {
+ bits1j = Inlines.IMAX(0, bits1j + trim_offset[j]);
+ }
+ if (bits2j > 0) {
+ bits2j = Inlines.IMAX(0, bits2j + trim_offset[j]);
+ }
+ if (lo > 0) {
+ bits1j += offsets[j];
+ }
+ bits2j += offsets[j];
+ if (offsets[j] > 0) {
+ skip_start = j;
+ }
+ bits2j = Inlines.IMAX(0, bits2j - bits1j);
+ bits1[j] = bits1j;
+ bits2[j] = bits2j;
+ }
+
+ codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap,
+ total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv,
+ pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth);
+
+ return codedBands;
+ }
+}
diff --git a/app/src/main/java/org/concentus/RegularizeCorrelations.java b/app/src/main/java/org/concentus/RegularizeCorrelations.java
new file mode 100644
index 0000000000..b68d02b3f4
--- /dev/null
+++ b/app/src/main/java/org/concentus/RegularizeCorrelations.java
@@ -0,0 +1,51 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class RegularizeCorrelations {
+
+ /* Add noise to matrix diagonal */
+ 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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/Resampler.java b/app/src/main/java/org/concentus/Resampler.java
new file mode 100644
index 0000000000..3bb9602c2e
--- /dev/null
+++ b/app/src/main/java/org/concentus/Resampler.java
@@ -0,0 +1,683 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+/*
+ * 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
+ */
+class Resampler {
+
+ private static final int USE_silk_resampler_copy = 0;
+ private static final int USE_silk_resampler_private_up2_HQ_wrapper = 1;
+ private static final int USE_silk_resampler_private_IIR_FIR = 2;
+ private static final int USE_silk_resampler_private_down_FIR = 3;
+
+ private static final int ORDER_FIR = 4;
+
+ ///
+ /// Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4]
+ ///
+ ///
+ ///
+ private static int rateID(int R) {
+ return (((((R) >> 12) - ((R > 16000) ? 1 : 0)) >> ((R > 24000) ? 1 : 0)) - 1);
+ }
+
+ ///
+ /// Initialize/reset the resampler state for a given pair of input/output sampling rates
+ ///
+ /// I/O Resampler state
+ /// I Input sampling rate (Hz)
+ /// I Output sampling rate (Hz)
+ /// I If 1: encoder; if 0: decoder
+ ///
+ 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 = SilkTables.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 = SilkTables.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 = SilkTables.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 = SilkTables.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 = SilkTables.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 = SilkTables.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 = SilkTables.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 = SilkTables.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;
+ }
+
+ ///
+ /// Resampler: convert from one sampling rate to another
+ /// Input and output sampling rate are at most 48000 Hz
+ ///
+ /// I/O Resampler state
+ /// O Output signal
+ /// I Input signal
+ /// I Number of input samples
+ ///
+ 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 */
+ System.arraycopy(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:
+ System.arraycopy(delayBufPtr, 0, output, output_ptr, S.Fs_in_kHz);
+ System.arraycopy(input, input_ptr + nSamples, output, output_ptr + S.Fs_out_kHz, inLen - S.Fs_in_kHz);
+ break;
+ }
+
+ /* Copy to delay buffer */
+ System.arraycopy(input, input_ptr + inLen - S.inputDelay, delayBufPtr, 0, S.inputDelay);
+
+ return SilkError.SILK_NO_ERROR;
+ }
+
+ ///
+ /// Downsample by a factor 2
+ ///
+ /// I/O State vector [ 2 ]
+ /// O Output signal [ floor(len/2) ]
+ /// I Input signal [ len ]
+ /// I Number of input samples
+ 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(SilkTables.silk_resampler_down2_0 > 0);
+ Inlines.OpusAssert(SilkTables.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, SilkTables.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, SilkTables.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));
+ }
+ }
+
+ ///
+ /// Downsample by a factor 2/3, low quality
+ ///
+ /// I/O State vector [ 6 ]
+ /// O Output signal [ floor(2*inLen/3) ]
+ /// I Input signal [ inLen ]
+ /// I Number of input samples
+ 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 */
+ System.arraycopy(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,
+ SilkTables.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], SilkTables.silk_Resampler_2_3_COEFS_LQ[2]);
+ res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 1], SilkTables.silk_Resampler_2_3_COEFS_LQ[3]);
+ res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 2], SilkTables.silk_Resampler_2_3_COEFS_LQ[5]);
+ res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 3], SilkTables.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], SilkTables.silk_Resampler_2_3_COEFS_LQ[4]);
+ res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 2], SilkTables.silk_Resampler_2_3_COEFS_LQ[5]);
+ res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 3], SilkTables.silk_Resampler_2_3_COEFS_LQ[3]);
+ res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 4], SilkTables.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 */
+ System.arraycopy(buf, nSamplesIn, buf, 0, ORDER_FIR);
+ } else {
+ break;
+ }
+ }
+
+ /* Copy last part of filtered signal to the state for the next call */
+ System.arraycopy(buf, nSamplesIn, S, 0, ORDER_FIR);
+ }
+
+ ///
+ /// Second order AR filter with single delay elements
+ ///
+ /// I/O State vector [ 2 ]
+ /// O Output signal
+ /// I Input signal
+ /// I AR coefficients, Q14
+ /// I Signal length
+ 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]);
+ }
+ }
+
+ 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;
+ }
+
+ ///
+ /// Resample with a 2nd order AR filter followed by FIR interpolation
+ ///
+ /// I/O Resampler state
+ /// O Output signal
+ /// I Input signal
+ /// I Number of input samples
+ 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 */
+ System.arraycopy(S.sFIR_i32, 0, buf, 0, 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 */
+ System.arraycopy(buf, nSamplesIn, buf, 0, S.FIR_Order);
+ } else {
+ break;
+ }
+ }
+
+ /* Copy last part of filtered signal to the state for the next call */
+ System.arraycopy(buf, nSamplesIn, S.sFIR_i32, 0, S.FIR_Order);
+ }
+
+ 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], SilkTables.silk_resampler_frac_FIR_12[table_index][0]);
+ res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 1], SilkTables.silk_resampler_frac_FIR_12[table_index][1]);
+ res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 2], SilkTables.silk_resampler_frac_FIR_12[table_index][2]);
+ res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 3], SilkTables.silk_resampler_frac_FIR_12[table_index][3]);
+ res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 4], SilkTables.silk_resampler_frac_FIR_12[11 - table_index][3]);
+ res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 5], SilkTables.silk_resampler_frac_FIR_12[11 - table_index][2]);
+ res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 6], SilkTables.silk_resampler_frac_FIR_12[11 - table_index][1]);
+ res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 7], SilkTables.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;
+ }
+
+ ///
+ /// Upsample using a combination of allpass-based 2x upsampling and FIR interpolation
+ ///
+ /// I/O Resampler state
+ /// O Output signal
+ /// I Input signal
+ /// I Number of input samples
+ 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 */
+ System.arraycopy(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 */
+ System.arraycopy(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 */
+ System.arraycopy(buf, nSamplesIn << 1, S.sFIR_i16, 0, SilkConstants.RESAMPLER_ORDER_FIR_12);
+ }
+
+ ///
+ /// Upsample by a factor 2, high quality
+ /// Uses 2nd order allpass filters for the 2x upsampling, followed by a
+ /// notch filter just above Nyquist.
+ ///
+ /// I/O Resampler state [ 6 ]
+ /// O Output signal [ 2 * len ]
+ /// I Input signal [ len ]
+ /// I Number of input samples
+ 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(SilkTables.silk_resampler_up2_hq_0[0] > 0);
+ Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_0[1] > 0);
+ Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_0[2] < 0);
+ Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_1[0] > 0);
+ Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_1[1] > 0);
+ Inlines.OpusAssert(SilkTables.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, SilkTables.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, SilkTables.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, SilkTables.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, SilkTables.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, SilkTables.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, SilkTables.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));
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/ResidualEnergy.java b/app/src/main/java/org/concentus/ResidualEnergy.java
new file mode 100644
index 0000000000..87bdfc222c
--- /dev/null
+++ b/app/src/main/java/org/concentus/ResidualEnergy.java
@@ -0,0 +1,178 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class ResidualEnergy {
+
+ /* Calculates residual energies of input subframes where all subframes have LPC_order */
+ /* of preceding samples */
+ 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;
+ BoxedValueInt rshift = new BoxedValueInt(0);
+ BoxedValueInt energy = new BoxedValueInt(0);
+ 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(energy, rshift, LPC_res, LPC_res_ptr, subfr_length);
+ nrgs[i * (SilkConstants.MAX_NB_SUBFR >> 1) + j] = energy.Val;
+
+ /* Set Q values for the measured energy */
+ nrgsQ[i * (SilkConstants.MAX_NB_SUBFR >> 1) + j] = 0 - rshift.Val;
+
+ /* 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 */
+ 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.MAX_VALUE + 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(Integer.MAX_VALUE, lshifts + 2)) {
+ nrg = Integer.MAX_VALUE >> 1;
+ } else {
+ nrg = Inlines.silk_LSHIFT(nrg, lshifts + 1);
+ /* Q0 */
+ }
+ return nrg;
+
+ }
+}
diff --git a/app/src/main/java/org/concentus/Schur.java b/app/src/main/java/org/concentus/Schur.java
new file mode 100644
index 0000000000..adeb2f2aa5
--- /dev/null
+++ b/app/src/main/java/org/concentus/Schur.java
@@ -0,0 +1,167 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class Schur {
+
+ /* Faster than schur64(), but much less accurate. */
+ /* uses SMLAWB(), requiring armv5E and higher. */
+ 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.InitTwoDimensionalArrayInt(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 */
+ 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.InitTwoDimensionalArrayInt(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.MemSet(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]);
+ }
+}
diff --git a/app/src/main/java/org/concentus/ShellCoder.java b/app/src/main/java/org/concentus/ShellCoder.java
new file mode 100644
index 0000000000..87f4355d7e
--- /dev/null
+++ b/app/src/main/java/org/concentus/ShellCoder.java
@@ -0,0 +1,186 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// shell coder; pulse-subframe length is hardcoded
+///
+class ShellCoder {
+
+ ///
+ ///
+ /// O combined pulses vector [len]
+ /// I input vector [2 * len]
+ /// I number of OUTPUT samples
+ 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];
+ }
+ }
+
+ ///
+ ///
+ /// O combined pulses vector [len]
+ /// I input vector [2 * len]
+ /// I number of OUTPUT samples
+ 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];
+ }
+ }
+
+ 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 */
+ short[] shell_table /* I table of shell cdfs */
+ ) {
+ if (p > 0) {
+ psRangeEnc.enc_icdf(p_child1, shell_table, SilkTables.silk_shell_code_table_offsets[p], 8);
+ }
+ }
+
+ ///
+ ///
+ ///
+ /// O pulse amplitude of first child subframe
+ /// O pulse amplitude of second child subframe
+ /// I/O Compressor data structure
+ /// I pulse amplitude of current subframe
+ /// I table of shell cdfs
+ static void decode_split(
+ short[] p_child1,
+ int child1_ptr,
+ short[] p_child2,
+ int p_child2_ptr,
+ EntropyCoder psRangeDec,
+ int p,
+ short[] shell_table) {
+ if (p > 0) {
+ p_child1[child1_ptr] = (short) (psRangeDec.dec_icdf(shell_table, (SilkTables.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;
+ }
+ }
+
+ ///
+ /// Shell encoder, operates on one shell code frame of 16 pulses
+ ///
+ /// I/O compressor data structure
+ /// I data: nonnegative pulse amplitudes
+ 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], SilkTables.silk_shell_code_table3);
+
+ encode_split(psRangeEnc, pulses2[0], pulses3[0], SilkTables.silk_shell_code_table2);
+
+ encode_split(psRangeEnc, pulses1[0], pulses2[0], SilkTables.silk_shell_code_table1);
+ encode_split(psRangeEnc, pulses0[pulses0_ptr], pulses1[0], SilkTables.silk_shell_code_table0);
+ encode_split(psRangeEnc, pulses0[pulses0_ptr + 2], pulses1[1], SilkTables.silk_shell_code_table0);
+
+ encode_split(psRangeEnc, pulses1[2], pulses2[1], SilkTables.silk_shell_code_table1);
+ encode_split(psRangeEnc, pulses0[pulses0_ptr + 4], pulses1[2], SilkTables.silk_shell_code_table0);
+ encode_split(psRangeEnc, pulses0[pulses0_ptr + 6], pulses1[3], SilkTables.silk_shell_code_table0);
+
+ encode_split(psRangeEnc, pulses2[2], pulses3[1], SilkTables.silk_shell_code_table2);
+
+ encode_split(psRangeEnc, pulses1[4], pulses2[2], SilkTables.silk_shell_code_table1);
+ encode_split(psRangeEnc, pulses0[pulses0_ptr + 8], pulses1[4], SilkTables.silk_shell_code_table0);
+ encode_split(psRangeEnc, pulses0[pulses0_ptr + 10], pulses1[5], SilkTables.silk_shell_code_table0);
+
+ encode_split(psRangeEnc, pulses1[6], pulses2[3], SilkTables.silk_shell_code_table1);
+ encode_split(psRangeEnc, pulses0[pulses0_ptr + 12], pulses1[6], SilkTables.silk_shell_code_table0);
+ encode_split(psRangeEnc, pulses0[pulses0_ptr + 14], pulses1[7], SilkTables.silk_shell_code_table0);
+ }
+
+
+ /* Shell decoder, operates on one shell code frame of 16 pulses */
+ 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, SilkTables.silk_shell_code_table3);
+
+ decode_split(pulses2, 0, pulses2, 1, psRangeDec, pulses3[0], SilkTables.silk_shell_code_table2);
+
+ decode_split(pulses1, 0, pulses1, 1, psRangeDec, pulses2[0], SilkTables.silk_shell_code_table1);
+ decode_split(pulses0, pulses0_ptr, pulses0, pulses0_ptr + 1, psRangeDec, pulses1[0], SilkTables.silk_shell_code_table0);
+ decode_split(pulses0, pulses0_ptr + 2, pulses0, pulses0_ptr + 3, psRangeDec, pulses1[1], SilkTables.silk_shell_code_table0);
+
+ decode_split(pulses1, 2, pulses1, 3, psRangeDec, pulses2[1], SilkTables.silk_shell_code_table1);
+ decode_split(pulses0, pulses0_ptr + 4, pulses0, pulses0_ptr + 5, psRangeDec, pulses1[2], SilkTables.silk_shell_code_table0);
+ decode_split(pulses0, pulses0_ptr + 6, pulses0, pulses0_ptr + 7, psRangeDec, pulses1[3], SilkTables.silk_shell_code_table0);
+
+ decode_split(pulses2, 2, pulses2, 3, psRangeDec, pulses3[1], SilkTables.silk_shell_code_table2);
+
+ decode_split(pulses1, 4, pulses1, 5, psRangeDec, pulses2[2], SilkTables.silk_shell_code_table1);
+ decode_split(pulses0, pulses0_ptr + 8, pulses0, pulses0_ptr + 9, psRangeDec, pulses1[4], SilkTables.silk_shell_code_table0);
+ decode_split(pulses0, pulses0_ptr + 10, pulses0, pulses0_ptr + 11, psRangeDec, pulses1[5], SilkTables.silk_shell_code_table0);
+
+ decode_split(pulses1, 6, pulses1, 7, psRangeDec, pulses2[3], SilkTables.silk_shell_code_table1);
+ decode_split(pulses0, pulses0_ptr + 12, pulses0, pulses0_ptr + 13, psRangeDec, pulses1[6], SilkTables.silk_shell_code_table0);
+ decode_split(pulses0, pulses0_ptr + 14, pulses0, pulses0_ptr + 15, psRangeDec, pulses1[7], SilkTables.silk_shell_code_table0);
+ }
+}
diff --git a/app/src/main/java/org/concentus/SideInfoIndices.java b/app/src/main/java/org/concentus/SideInfoIndices.java
new file mode 100644
index 0000000000..ab564d8c37
--- /dev/null
+++ b/app/src/main/java/org/concentus/SideInfoIndices.java
@@ -0,0 +1,79 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class SideInfoIndices {
+
+ final byte[] GainsIndices = new byte[SilkConstants.MAX_NB_SUBFR];
+ final byte[] LTPIndex = new byte[SilkConstants.MAX_NB_SUBFR];
+ final byte[] NLSFIndices = new byte[SilkConstants.MAX_LPC_ORDER + 1];
+ short lagIndex = 0;
+ byte contourIndex = 0;
+ byte signalType = 0;
+ byte quantOffsetType = 0;
+ byte NLSFInterpCoef_Q2 = 0;
+ byte PERIndex = 0;
+ byte LTP_scaleIndex = 0;
+ byte Seed = 0;
+
+ void Reset() {
+ Arrays.MemSet(GainsIndices, (byte) 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(LTPIndex, (byte) 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(NLSFIndices, (byte) 0, SilkConstants.MAX_LPC_ORDER + 1);
+ lagIndex = 0;
+ contourIndex = 0;
+ signalType = 0;
+ quantOffsetType = 0;
+ NLSFInterpCoef_Q2 = 0;
+ PERIndex = 0;
+ LTP_scaleIndex = 0;
+ Seed = 0;
+ }
+
+ ///
+ /// Overwrites this struct with values from another one. Equivalent to C struct assignment this = other
+ ///
+ ///
+ void Assign(SideInfoIndices other) {
+ System.arraycopy(other.GainsIndices, 0, this.GainsIndices, 0, SilkConstants.MAX_NB_SUBFR);
+ System.arraycopy(other.LTPIndex, 0, this.LTPIndex, 0, SilkConstants.MAX_NB_SUBFR);
+ System.arraycopy(other.NLSFIndices, 0, this.NLSFIndices, 0, 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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/Sigmoid.java b/app/src/main/java/org/concentus/Sigmoid.java
new file mode 100644
index 0000000000..915bb1af04
--- /dev/null
+++ b/app/src/main/java/org/concentus/Sigmoid.java
@@ -0,0 +1,74 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Approximate sigmoid function
+///
+class Sigmoid {
+
+ private static final int[] sigm_LUT_slope_Q10 = {
+ 237, 153, 73, 30, 12, 7
+ };
+
+ private static final int[] sigm_LUT_pos_Q15 = {
+ 16384, 23955, 28861, 31213, 32178, 32548
+ };
+
+ private static final int[] sigm_LUT_neg_Q15 = {
+ 16384, 8812, 3906, 1554, 589, 219
+ };
+
+ 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));
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkChannelDecoder.java b/app/src/main/java/org/concentus/SilkChannelDecoder.java
new file mode 100644
index 0000000000..64132221ad
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkChannelDecoder.java
@@ -0,0 +1,378 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Decoder state
+///
+class SilkChannelDecoder {
+
+ int prev_gain_Q16 = 0;
+ final int[] exc_Q14 = new int[SilkConstants.MAX_FRAME_LENGTH];
+ final int[] sLPC_Q14_buf = new int[SilkConstants.MAX_LPC_ORDER];
+ final short[] outBuf = new short[SilkConstants.MAX_FRAME_LENGTH + 2 * SilkConstants.MAX_SUB_FRAME_LENGTH];
+ /* Buffer for output signal */
+ int lagPrev = 0;
+ /* Previous Lag */
+ byte LastGainIndex = 0;
+ /* Previous gain index */
+ int fs_kHz = 0;
+ /* Sampling frequency in kHz */
+ int fs_API_hz = 0;
+ /* API sample frequency (Hz) */
+ int nb_subfr = 0;
+ /* Number of 5 ms subframes in a frame */
+ int frame_length = 0;
+ /* Frame length (samples) */
+ int subfr_length = 0;
+ /* Subframe length (samples) */
+ int ltp_mem_length = 0;
+ /* Length of LTP memory */
+ int LPC_order = 0;
+ /* LPC order */
+ final short[] prevNLSF_Q15 = new short[SilkConstants.MAX_LPC_ORDER];
+ /* Used to interpolate LSFs */
+ int first_frame_after_reset = 0;
+ /* Flag for deactivating NLSF interpolation */
+ short[] pitch_lag_low_bits_iCDF;
+ /* Pointer to iCDF table for low bits of pitch lag index */
+ short[] pitch_contour_iCDF;
+ /* Pointer to iCDF table for pitch contour index */
+
+ /* For buffering payload in case of more frames per packet */
+ int nFramesDecoded = 0;
+ int nFramesPerPacket = 0;
+
+ /* Specifically for entropy coding */
+ int ec_prevSignalType = 0;
+ short ec_prevLagIndex = 0;
+
+ final int[] VAD_flags = new int[SilkConstants.MAX_FRAMES_PER_PACKET];
+ int LBRR_flag = 0;
+ final int[] LBRR_flags = new int[SilkConstants.MAX_FRAMES_PER_PACKET];
+
+ final SilkResamplerState resampler_state = new SilkResamplerState();
+
+ NLSFCodebook psNLSF_CB = null;
+ /* Pointer to NLSF codebook */
+
+ /* Quantization indices */
+ final SideInfoIndices indices = new SideInfoIndices();
+
+ /* CNG state */
+ final CNGState sCNG = new CNGState();
+
+ /* Stuff used for PLC */
+ int lossCnt = 0;
+ int prevSignalType = 0;
+
+ final PLCStruct sPLC = new PLCStruct();
+
+ void Reset() {
+ prev_gain_Q16 = 0;
+ Arrays.MemSet(exc_Q14, 0, SilkConstants.MAX_FRAME_LENGTH);
+ Arrays.MemSet(sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
+ Arrays.MemSet(outBuf, (short) 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.MemSet(prevNLSF_Q15, (short) 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.MemSet(VAD_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
+ LBRR_flag = 0;
+ Arrays.MemSet(LBRR_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
+ resampler_state.Reset();
+ psNLSF_CB = null;
+ indices.Reset();
+ sCNG.Reset();
+ lossCnt = 0;
+ prevSignalType = 0;
+ sPLC.Reset();
+ }
+
+ ///
+ /// Init Decoder State
+ ///
+ /// I/O Decoder state pointer
+ ///
+ 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);
+ }
+
+ ///
+ /// Resets CNG state
+ ///
+ /// I/O Decoder state
+ private void silk_CNG_Reset() {
+ int i, NLSF_step_Q15, NLSF_acc_Q15;
+
+ NLSF_step_Q15 = Inlines.silk_DIV32_16(Short.MAX_VALUE, 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;
+ }
+
+ ///
+ /// Resets PLC state
+ ///
+ /// I/O Decoder state
+ 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 */
+ 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 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 = SilkTables.silk_pitch_contour_NB_iCDF;
+ } else {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_10_ms_NB_iCDF;
+ }
+ } else if (this.nb_subfr == SilkConstants.MAX_NB_SUBFR) {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_iCDF;
+ } else {
+ this.pitch_contour_iCDF = SilkTables.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 = SilkTables.silk_NLSF_CB_NB_MB;
+ } else {
+ this.LPC_order = SilkConstants.MAX_LPC_ORDER;
+ this.psNLSF_CB = SilkTables.silk_NLSF_CB_WB;
+ }
+ if (fs_kHz == 16) {
+ this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform8_iCDF;
+ } else if (fs_kHz == 12) {
+ this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform6_iCDF;
+ } else if (fs_kHz == 8) {
+ this.pitch_lag_low_bits_iCDF = SilkTables.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.MemSet(this.outBuf, (short) 0, SilkConstants.MAX_FRAME_LENGTH + 2 * SilkConstants.MAX_SUB_FRAME_LENGTH);
+ Arrays.MemSet(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 */
+ /**
+ * *************
+ */
+ 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.MemMove(this.outBuf, this.frame_length, 0, mv_len);
+ System.arraycopy(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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkChannelEncoder.java b/app/src/main/java/org/concentus/SilkChannelEncoder.java
new file mode 100644
index 0000000000..f4ab7d8193
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkChannelEncoder.java
@@ -0,0 +1,1267 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Encoder state
+///
+class SilkChannelEncoder {
+
+ final int[] In_HP_State = new int[2];
+ /* High pass filter state */
+ int variable_HP_smth1_Q15 = 0;
+ /* State of first smoother */
+ int variable_HP_smth2_Q15 = 0;
+ /* State of second smoother */
+ final SilkLPState sLP = new SilkLPState();
+ /* Low pass filter state */
+ final SilkVADState sVAD = new SilkVADState();
+ /* Voice activity detector state */
+ final SilkNSQState sNSQ = new SilkNSQState();
+ /* Noise Shape Quantizer State */
+ final short[] prev_NLSFq_Q15 = new short[SilkConstants.MAX_LPC_ORDER];
+ /* Previously quantized NLSF vector */
+ int speech_activity_Q8 = 0;
+ /* Speech activity */
+ int allow_bandwidth_switch = 0;
+ /* Flag indicating that switching of bandwidth is allowed */
+ byte LBRRprevLastGainIndex = 0;
+ byte prevSignalType = 0;
+ int prevLag = 0;
+ int pitch_LPC_win_length = 0;
+ int max_pitch_lag = 0;
+ /* Highest possible pitch lag (samples) */
+ int API_fs_Hz = 0;
+ /* API sampling frequency (Hz) */
+ int prev_API_fs_Hz = 0;
+ /* Previous API sampling frequency (Hz) */
+ int maxInternal_fs_Hz = 0;
+ /* Maximum sampling frequency (Hz) */
+ int minInternal_fs_Hz = 0;
+ /* Minimum sampling frequency (Hz) */
+ int desiredInternal_fs_Hz = 0;
+ /* Soft request for sampling frequency (Hz) */
+ int fs_kHz = 0;
+ /* Internal sampling frequency (kHz) */
+ int nb_subfr = 0;
+ /* Number of 5 ms subframes in a frame */
+ int frame_length = 0;
+ /* Frame length (samples) */
+ int subfr_length = 0;
+ /* Subframe length (samples) */
+ int ltp_mem_length = 0;
+ /* Length of LTP memory */
+ int la_pitch = 0;
+ /* Look-ahead for pitch analysis (samples) */
+ int la_shape = 0;
+ /* Look-ahead for noise shape analysis (samples) */
+ int shapeWinLength = 0;
+ /* Window length for noise shape analysis (samples) */
+ int TargetRate_bps = 0;
+ /* Target bitrate (bps) */
+ int PacketSize_ms = 0;
+ /* Number of milliseconds to put in each packet */
+ int PacketLoss_perc = 0;
+ /* Packet loss rate measured by farend */
+ int frameCounter = 0;
+ int Complexity = 0;
+ /* Complexity setting */
+ int nStatesDelayedDecision = 0;
+ /* Number of states in delayed decision quantization */
+ int useInterpolatedNLSFs = 0;
+ /* Flag for using NLSF interpolation */
+ int shapingLPCOrder = 0;
+ /* Filter order for noise shaping filters */
+ int predictLPCOrder = 0;
+ /* Filter order for prediction filters */
+ int pitchEstimationComplexity = 0;
+ /* Complexity level for pitch estimator */
+ int pitchEstimationLPCOrder = 0;
+ /* Whitening filter order for pitch estimator */
+ int pitchEstimationThreshold_Q16 = 0;
+ /* Threshold for pitch estimator */
+ int LTPQuantLowComplexity = 0;
+ /* Flag for low complexity LTP quantization */
+ int mu_LTP_Q9 = 0;
+ /* Rate-distortion tradeoff in LTP quantization */
+ int sum_log_gain_Q7 = 0;
+ /* Cumulative max prediction gain */
+ int NLSF_MSVQ_Survivors = 0;
+ /* Number of survivors in NLSF MSVQ */
+ int first_frame_after_reset = 0;
+ /* Flag for deactivating NLSF interpolation, pitch prediction */
+ int controlled_since_last_payload = 0;
+ /* Flag for ensuring codec_control only runs once per packet */
+ int warping_Q16 = 0;
+ /* Warping parameter for warped noise shaping */
+ int useCBR = 0;
+ /* Flag to enable constant bitrate */
+ int prefillFlag = 0;
+ /* Flag to indicate that only buffers are prefilled, no coding */
+ short[] pitch_lag_low_bits_iCDF = null;
+ /* Pointer to iCDF table for low bits of pitch lag index */
+ short[] pitch_contour_iCDF = null;
+ /* Pointer to iCDF table for pitch contour index */
+ NLSFCodebook psNLSF_CB = null;
+ /* Pointer to NLSF codebook */
+ final int[] input_quality_bands_Q15 = new int[SilkConstants.VAD_N_BANDS];
+ int input_tilt_Q15 = 0;
+ int SNR_dB_Q7 = 0;
+ /* Quality setting */
+
+ final byte[] VAD_flags = new byte[SilkConstants.MAX_FRAMES_PER_PACKET];
+ byte LBRR_flag = 0;
+ final int[] LBRR_flags = new int[SilkConstants.MAX_FRAMES_PER_PACKET];
+
+ final SideInfoIndices indices = new SideInfoIndices();
+ final byte[] pulses = new byte[SilkConstants.MAX_FRAME_LENGTH];
+
+ /* Input/output buffering */
+ final short[] inputBuf = new short[SilkConstants.MAX_FRAME_LENGTH + 2];
+ /* Buffer containing input signal */
+ int inputBufIx = 0;
+ int nFramesPerPacket = 0;
+ int nFramesEncoded = 0;
+ /* Number of frames analyzed in current packet */
+
+ int nChannelsAPI = 0;
+ int nChannelsInternal = 0;
+ int channelNb = 0;
+
+ /* Parameters For LTP scaling Control */
+ int frames_since_onset = 0;
+
+ /* Specifically for entropy coding */
+ int ec_prevSignalType = 0;
+ short ec_prevLagIndex = 0;
+
+ final SilkResamplerState resampler_state = new SilkResamplerState();
+
+ /* DTX */
+ int useDTX = 0;
+ /* Flag to enable DTX */
+ int inDTX = 0;
+ /* Flag to signal DTX period */
+ int noSpeechCounter = 0;
+ /* Counts concecutive nonactive frames, used by DTX */
+
+ /* Inband Low Bitrate Redundancy (LBRR) data */
+ int useInBandFEC = 0;
+ /* Saves the API setting for query */
+ int LBRR_enabled = 0;
+ /* Depends on useInBandFRC, bitrate and packet loss rate */
+ int LBRR_GainIncreases = 0;
+ /* Gains increment for coding LBRR frames */
+ final SideInfoIndices[] indices_LBRR = new SideInfoIndices[SilkConstants.MAX_FRAMES_PER_PACKET];
+ final byte[][] pulses_LBRR = Arrays.InitTwoDimensionalArrayByte(SilkConstants.MAX_FRAMES_PER_PACKET, SilkConstants.MAX_FRAME_LENGTH);
+
+ /* Noise shaping state */
+ final SilkShapeState sShape = new SilkShapeState();
+
+ /* Prefilter State */
+ final SilkPrefilterState sPrefilt = new SilkPrefilterState();
+
+ /* Buffer for find pitch and noise shape analysis */
+ final short[] x_buf = new short[2 * SilkConstants.MAX_FRAME_LENGTH + SilkConstants.LA_SHAPE_MAX];
+
+ /* Normalized correlation from pitch lag estimator */
+ int LTPCorr_Q15 = 0;
+
+ SilkChannelEncoder() {
+ for (int c = 0; c < SilkConstants.MAX_FRAMES_PER_PACKET; c++) {
+ indices_LBRR[c] = new SideInfoIndices();
+ }
+ }
+
+ void Reset() {
+ Arrays.MemSet(In_HP_State, 0, 2);
+ variable_HP_smth1_Q15 = 0;
+ variable_HP_smth2_Q15 = 0;
+ sLP.Reset();
+ sVAD.Reset();
+ sNSQ.Reset();
+ Arrays.MemSet(prev_NLSFq_Q15, (short) 0, SilkConstants.MAX_LPC_ORDER);
+ speech_activity_Q8 = 0;
+ allow_bandwidth_switch = 0;
+ LBRRprevLastGainIndex = 0;
+ prevSignalType = 0;
+ prevLag = 0;
+ pitch_LPC_win_length = 0;
+ max_pitch_lag = 0;
+ API_fs_Hz = 0;
+ prev_API_fs_Hz = 0;
+ maxInternal_fs_Hz = 0;
+ minInternal_fs_Hz = 0;
+ desiredInternal_fs_Hz = 0;
+ fs_kHz = 0;
+ nb_subfr = 0;
+ frame_length = 0;
+ subfr_length = 0;
+ ltp_mem_length = 0;
+ la_pitch = 0;
+ la_shape = 0;
+ shapeWinLength = 0;
+ TargetRate_bps = 0;
+ PacketSize_ms = 0;
+ PacketLoss_perc = 0;
+ frameCounter = 0;
+ Complexity = 0;
+ nStatesDelayedDecision = 0;
+ useInterpolatedNLSFs = 0;
+ shapingLPCOrder = 0;
+ predictLPCOrder = 0;
+ pitchEstimationComplexity = 0;
+ pitchEstimationLPCOrder = 0;
+ pitchEstimationThreshold_Q16 = 0;
+ LTPQuantLowComplexity = 0;
+ mu_LTP_Q9 = 0;
+ sum_log_gain_Q7 = 0;
+ NLSF_MSVQ_Survivors = 0;
+ first_frame_after_reset = 0;
+ controlled_since_last_payload = 0;
+ warping_Q16 = 0;
+ useCBR = 0;
+ prefillFlag = 0;
+ pitch_lag_low_bits_iCDF = null;
+ pitch_contour_iCDF = null;
+ psNLSF_CB = null;
+ Arrays.MemSet(input_quality_bands_Q15, 0, SilkConstants.VAD_N_BANDS);
+ input_tilt_Q15 = 0;
+ SNR_dB_Q7 = 0;
+ Arrays.MemSet(VAD_flags, (byte) 0, SilkConstants.MAX_FRAMES_PER_PACKET);
+ LBRR_flag = 0;
+ Arrays.MemSet(LBRR_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
+ indices.Reset();
+ Arrays.MemSet(pulses, (byte) 0, SilkConstants.MAX_FRAME_LENGTH);
+ Arrays.MemSet(inputBuf, (short) 0, SilkConstants.MAX_FRAME_LENGTH + 2);
+ inputBufIx = 0;
+ nFramesPerPacket = 0;
+ nFramesEncoded = 0;
+ nChannelsAPI = 0;
+ nChannelsInternal = 0;
+ channelNb = 0;
+ frames_since_onset = 0;
+ ec_prevSignalType = 0;
+ ec_prevLagIndex = 0;
+ resampler_state.Reset();
+ useDTX = 0;
+ inDTX = 0;
+ noSpeechCounter = 0;
+ useInBandFEC = 0;
+ LBRR_enabled = 0;
+ LBRR_GainIncreases = 0;
+ for (int c = 0; c < SilkConstants.MAX_FRAMES_PER_PACKET; c++) {
+ indices_LBRR[c].Reset();
+ Arrays.MemSet(pulses_LBRR[c], (byte) 0, SilkConstants.MAX_FRAME_LENGTH);
+ }
+ sShape.Reset();
+ sPrefilt.Reset();
+ Arrays.MemSet(x_buf, (short) 0, 2 * SilkConstants.MAX_FRAME_LENGTH + SilkConstants.LA_SHAPE_MAX);
+ LTPCorr_Q15 = 0;
+ }
+
+ ///
+ /// Control encoder
+ ///
+ /// I/O Pointer to Silk encoder state
+ /// I Control structure
+ /// I Target max bitrate (bps)
+ /// I Flag to allow switching audio bandwidth
+ /// I Channel number
+ ///
+ ///
+ int silk_control_encoder(
+ EncControlState encControl,
+ int TargetRate_bps,
+ int allow_bw_switch,
+ int channelNb,
+ int force_fs_kHz) {
+ int fs_kHz;
+ int ret = SilkError.SILK_NO_ERROR;
+
+ this.useDTX = encControl.useDTX;
+ this.useCBR = encControl.useCBR;
+ this.API_fs_Hz = encControl.API_sampleRate;
+ this.maxInternal_fs_Hz = encControl.maxInternalSampleRate;
+ this.minInternal_fs_Hz = encControl.minInternalSampleRate;
+ this.desiredInternal_fs_Hz = encControl.desiredInternalSampleRate;
+ this.useInBandFEC = encControl.useInBandFEC;
+ this.nChannelsAPI = encControl.nChannelsAPI;
+ this.nChannelsInternal = encControl.nChannelsInternal;
+ this.allow_bandwidth_switch = allow_bw_switch;
+ this.channelNb = channelNb;
+
+ if (this.controlled_since_last_payload != 0 && this.prefillFlag == 0) {
+ if (this.API_fs_Hz != this.prev_API_fs_Hz && this.fs_kHz > 0) {
+ /* Change in API sampling rate in the middle of encoding a packet */
+ ret = silk_setup_resamplers(this.fs_kHz);
+ }
+ return ret;
+ }
+
+ /* Beyond this point we know that there are no previously coded frames in the payload buffer */
+ /**
+ * *****************************************
+ */
+ /* Determine sampling rate */
+ /**
+ * *****************************************
+ */
+ fs_kHz = silk_control_audio_bandwidth(encControl);
+ if (force_fs_kHz != 0) {
+ fs_kHz = force_fs_kHz;
+ }
+ /**
+ * *****************************************
+ */
+ /* Prepare resampler and buffered data */
+ /**
+ * *****************************************
+ */
+ ret = silk_setup_resamplers(fs_kHz);
+
+ /**
+ * *****************************************
+ */
+ /* Set sampling frequency */
+ /**
+ * *****************************************
+ */
+ ret = silk_setup_fs(fs_kHz, encControl.payloadSize_ms);
+
+ /**
+ * *****************************************
+ */
+ /* Set encoding complexity */
+ /**
+ * *****************************************
+ */
+ ret = silk_setup_complexity(encControl.complexity);
+
+ /**
+ * *****************************************
+ */
+ /* Set packet loss rate measured by farend */
+ /**
+ * *****************************************
+ */
+ this.PacketLoss_perc = encControl.packetLossPercentage;
+
+ /**
+ * *****************************************
+ */
+ /* Set LBRR usage */
+ /**
+ * *****************************************
+ */
+ ret = silk_setup_LBRR(TargetRate_bps);
+
+ this.controlled_since_last_payload = 1;
+
+ return ret;
+ }
+
+ ///
+ ///
+ ///
+ /// I/O
+ /// I
+ ///
+ private int silk_setup_resamplers(int fs_kHz) {
+ int ret = 0;
+
+ if (this.fs_kHz != fs_kHz || this.prev_API_fs_Hz != this.API_fs_Hz) {
+ if (this.fs_kHz == 0) {
+ /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+ ret += Resampler.silk_resampler_init(this.resampler_state, this.API_fs_Hz, fs_kHz * 1000, 1);
+ } else {
+ short[] x_buf_API_fs_Hz;
+ SilkResamplerState temp_resampler_state = null;
+
+ int api_buf_samples;
+ int old_buf_samples;
+ int buf_length_ms;
+
+ buf_length_ms = Inlines.silk_LSHIFT(this.nb_subfr * 5, 1) + SilkConstants.LA_SHAPE_MS;
+ old_buf_samples = buf_length_ms * this.fs_kHz;
+
+ /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */
+ temp_resampler_state = new SilkResamplerState();
+ ret += Resampler.silk_resampler_init(temp_resampler_state, Inlines.silk_SMULBB(this.fs_kHz, 1000), this.API_fs_Hz, 0);
+
+ /* Calculate number of samples to temporarily upsample */
+ api_buf_samples = buf_length_ms * Inlines.silk_DIV32_16(this.API_fs_Hz, 1000);
+
+ /* Temporary resampling of x_buf data to API_fs_Hz */
+ x_buf_API_fs_Hz = new short[api_buf_samples];
+ ret += Resampler.silk_resampler(temp_resampler_state, x_buf_API_fs_Hz, 0, this.x_buf, 0, old_buf_samples);
+
+ /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+ ret += Resampler.silk_resampler_init(this.resampler_state, this.API_fs_Hz, Inlines.silk_SMULBB(fs_kHz, 1000), 1);
+
+ /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */
+ ret += Resampler.silk_resampler(this.resampler_state, this.x_buf, 0, x_buf_API_fs_Hz, 0, api_buf_samples);
+ }
+ }
+
+ this.prev_API_fs_Hz = this.API_fs_Hz;
+
+ return ret;
+ }
+
+ ///
+ ///
+ ///
+ /// I/O
+ /// I
+ /// I
+ ///
+ private int silk_setup_fs(
+ int fs_kHz,
+ int PacketSize_ms) {
+ int ret = SilkError.SILK_NO_ERROR;
+
+ /* Set packet size */
+ if (PacketSize_ms != this.PacketSize_ms) {
+ if ((PacketSize_ms != 10)
+ && (PacketSize_ms != 20)
+ && (PacketSize_ms != 40)
+ && (PacketSize_ms != 60)) {
+ ret = SilkError.SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
+ }
+ if (PacketSize_ms <= 10) {
+ this.nFramesPerPacket = 1;
+ this.nb_subfr = PacketSize_ms == 10 ? 2 : 1;
+ this.frame_length = Inlines.silk_SMULBB(PacketSize_ms, fs_kHz);
+ this.pitch_LPC_win_length = Inlines.silk_SMULBB(SilkConstants.FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz);
+ if (this.fs_kHz == 8) {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_10_ms_NB_iCDF;
+ } else {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_10_ms_iCDF;
+ }
+ } else {
+ this.nFramesPerPacket = Inlines.silk_DIV32_16(PacketSize_ms, SilkConstants.MAX_FRAME_LENGTH_MS);
+ this.nb_subfr = SilkConstants.MAX_NB_SUBFR;
+ this.frame_length = Inlines.silk_SMULBB(20, fs_kHz);
+ this.pitch_LPC_win_length = Inlines.silk_SMULBB(SilkConstants.FIND_PITCH_LPC_WIN_MS, fs_kHz);
+ if (this.fs_kHz == 8) {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_NB_iCDF;
+ } else {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_iCDF;
+ }
+ }
+ this.PacketSize_ms = PacketSize_ms;
+ this.TargetRate_bps = 0;
+ /* trigger new SNR computation */
+ }
+
+ /* Set sampling frequency */
+ Inlines.OpusAssert(fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16);
+ Inlines.OpusAssert(this.nb_subfr == 2 || this.nb_subfr == 4);
+ if (this.fs_kHz != fs_kHz) {
+ /* reset part of the state */
+ this.sShape.Reset();
+ this.sPrefilt.Reset();
+ this.sNSQ.Reset();
+ Arrays.MemSet(this.prev_NLSFq_Q15, (short) 0, SilkConstants.MAX_LPC_ORDER);
+ Arrays.MemSet(this.sLP.In_LP_State, 0, 2);
+ this.inputBufIx = 0;
+ this.nFramesEncoded = 0;
+ this.TargetRate_bps = 0;
+ /* trigger new SNR computation */
+
+ /* Initialize non-zero parameters */
+ this.prevLag = 100;
+ this.first_frame_after_reset = 1;
+ this.sPrefilt.lagPrev = 100;
+ this.sShape.LastGainIndex = 10;
+ this.sNSQ.lagPrev = 100;
+ this.sNSQ.prev_gain_Q16 = 65536;
+ this.prevSignalType = SilkConstants.TYPE_NO_VOICE_ACTIVITY;
+
+ this.fs_kHz = fs_kHz;
+ if (this.fs_kHz == 8) {
+ if (this.nb_subfr == SilkConstants.MAX_NB_SUBFR) {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_NB_iCDF;
+ } else {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_10_ms_NB_iCDF;
+ }
+ } else if (this.nb_subfr == SilkConstants.MAX_NB_SUBFR) {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_iCDF;
+ } else {
+ this.pitch_contour_iCDF = SilkTables.silk_pitch_contour_10_ms_iCDF;
+ }
+
+ if (this.fs_kHz == 8 || this.fs_kHz == 12) {
+ this.predictLPCOrder = SilkConstants.MIN_LPC_ORDER;
+ this.psNLSF_CB = SilkTables.silk_NLSF_CB_NB_MB;
+ } else {
+ this.predictLPCOrder = SilkConstants.MAX_LPC_ORDER;
+ this.psNLSF_CB = SilkTables.silk_NLSF_CB_WB;
+ }
+
+ this.subfr_length = SilkConstants.SUB_FRAME_LENGTH_MS * fs_kHz;
+ this.frame_length = Inlines.silk_SMULBB(this.subfr_length, this.nb_subfr);
+ this.ltp_mem_length = Inlines.silk_SMULBB(SilkConstants.LTP_MEM_LENGTH_MS, fs_kHz);
+ this.la_pitch = Inlines.silk_SMULBB(SilkConstants.LA_PITCH_MS, fs_kHz);
+ this.max_pitch_lag = Inlines.silk_SMULBB(18, fs_kHz);
+
+ if (this.nb_subfr == SilkConstants.MAX_NB_SUBFR) {
+ this.pitch_LPC_win_length = Inlines.silk_SMULBB(SilkConstants.FIND_PITCH_LPC_WIN_MS, fs_kHz);
+ } else {
+ this.pitch_LPC_win_length = Inlines.silk_SMULBB(SilkConstants.FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz);
+ }
+
+ if (this.fs_kHz == 16) {
+ this.mu_LTP_Q9 = ((int) ((TuningParameters.MU_LTP_QUANT_WB) * ((long) 1 << (9)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.MU_LTP_QUANT_WB, 9)*/;
+ this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform8_iCDF;
+ } else if (this.fs_kHz == 12) {
+ this.mu_LTP_Q9 = ((int) ((TuningParameters.MU_LTP_QUANT_MB) * ((long) 1 << (9)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.MU_LTP_QUANT_MB, 9)*/;
+ this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform6_iCDF;
+ } else {
+ this.mu_LTP_Q9 = ((int) ((TuningParameters.MU_LTP_QUANT_NB) * ((long) 1 << (9)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.MU_LTP_QUANT_NB, 9)*/;
+ this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform4_iCDF;
+ }
+ }
+
+ /* Check that settings are valid */
+ Inlines.OpusAssert((this.subfr_length * this.nb_subfr) == this.frame_length);
+
+ return ret;
+ }
+
+ ///
+ ///
+ ///
+ /// I/O
+ /// O
+ ///
+ private int silk_setup_complexity(int Complexity) {
+ int ret = 0;
+
+ /* Set encoding complexity */
+ Inlines.OpusAssert(Complexity >= 0 && Complexity <= 10);
+ if (Complexity < 2) {
+ this.pitchEstimationComplexity = SilkConstants.SILK_PE_MIN_COMPLEX;
+ this.pitchEstimationThreshold_Q16 = ((int) ((0.8f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.8f, 16)*/;
+ this.pitchEstimationLPCOrder = 6;
+ this.shapingLPCOrder = 8;
+ this.la_shape = 3 * this.fs_kHz;
+ this.nStatesDelayedDecision = 1;
+ this.useInterpolatedNLSFs = 0;
+ this.LTPQuantLowComplexity = 1;
+ this.NLSF_MSVQ_Survivors = 2;
+ this.warping_Q16 = 0;
+ } else if (Complexity < 4) {
+ this.pitchEstimationComplexity = SilkConstants.SILK_PE_MID_COMPLEX;
+ this.pitchEstimationThreshold_Q16 = ((int) ((0.76f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.76f, 16)*/;
+ this.pitchEstimationLPCOrder = 8;
+ this.shapingLPCOrder = 10;
+ this.la_shape = 5 * this.fs_kHz;
+ this.nStatesDelayedDecision = 1;
+ this.useInterpolatedNLSFs = 0;
+ this.LTPQuantLowComplexity = 0;
+ this.NLSF_MSVQ_Survivors = 4;
+ this.warping_Q16 = 0;
+ } else if (Complexity < 6) {
+ this.pitchEstimationComplexity = SilkConstants.SILK_PE_MID_COMPLEX;
+ this.pitchEstimationThreshold_Q16 = ((int) ((0.74f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.74f, 16)*/;
+ this.pitchEstimationLPCOrder = 10;
+ this.shapingLPCOrder = 12;
+ this.la_shape = 5 * this.fs_kHz;
+ this.nStatesDelayedDecision = 2;
+ this.useInterpolatedNLSFs = 1;
+ this.LTPQuantLowComplexity = 0;
+ this.NLSF_MSVQ_Survivors = 8;
+ this.warping_Q16 = this.fs_kHz * ((int) ((TuningParameters.WARPING_MULTIPLIER) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.WARPING_MULTIPLIER, 16)*/;
+ } else if (Complexity < 8) {
+ this.pitchEstimationComplexity = SilkConstants.SILK_PE_MID_COMPLEX;
+ this.pitchEstimationThreshold_Q16 = ((int) ((0.72f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.72f, 16)*/;
+ this.pitchEstimationLPCOrder = 12;
+ this.shapingLPCOrder = 14;
+ this.la_shape = 5 * this.fs_kHz;
+ this.nStatesDelayedDecision = 3;
+ this.useInterpolatedNLSFs = 1;
+ this.LTPQuantLowComplexity = 0;
+ this.NLSF_MSVQ_Survivors = 16;
+ this.warping_Q16 = this.fs_kHz * ((int) ((TuningParameters.WARPING_MULTIPLIER) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.WARPING_MULTIPLIER, 16)*/;
+ } else {
+ this.pitchEstimationComplexity = SilkConstants.SILK_PE_MAX_COMPLEX;
+ this.pitchEstimationThreshold_Q16 = ((int) ((0.7f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.7f, 16)*/;
+ this.pitchEstimationLPCOrder = 16;
+ this.shapingLPCOrder = 16;
+ this.la_shape = 5 * this.fs_kHz;
+ this.nStatesDelayedDecision = SilkConstants.MAX_DEL_DEC_STATES;
+ this.useInterpolatedNLSFs = 1;
+ this.LTPQuantLowComplexity = 0;
+ this.NLSF_MSVQ_Survivors = 32;
+ this.warping_Q16 = this.fs_kHz * ((int) ((TuningParameters.WARPING_MULTIPLIER) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.WARPING_MULTIPLIER, 16)*/;
+ }
+
+ /* Do not allow higher pitch estimation LPC order than predict LPC order */
+ this.pitchEstimationLPCOrder = Inlines.silk_min_int(this.pitchEstimationLPCOrder, this.predictLPCOrder);
+ this.shapeWinLength = SilkConstants.SUB_FRAME_LENGTH_MS * this.fs_kHz + 2 * this.la_shape;
+ this.Complexity = Complexity;
+
+ Inlines.OpusAssert(this.pitchEstimationLPCOrder <= SilkConstants.MAX_FIND_PITCH_LPC_ORDER);
+ Inlines.OpusAssert(this.shapingLPCOrder <= SilkConstants.MAX_SHAPE_LPC_ORDER);
+ Inlines.OpusAssert(this.nStatesDelayedDecision <= SilkConstants.MAX_DEL_DEC_STATES);
+ Inlines.OpusAssert(this.warping_Q16 <= 32767);
+ Inlines.OpusAssert(this.la_shape <= SilkConstants.LA_SHAPE_MAX);
+ Inlines.OpusAssert(this.shapeWinLength <= SilkConstants.SHAPE_LPC_WIN_MAX);
+ Inlines.OpusAssert(this.NLSF_MSVQ_Survivors <= SilkConstants.NLSF_VQ_MAX_SURVIVORS);
+
+ return ret;
+ }
+
+ ///
+ ///
+ ///
+ /// I/O
+ /// I
+ ///
+ private int silk_setup_LBRR(int TargetRate_bps) {
+ int LBRR_in_previous_packet;
+ int ret = SilkError.SILK_NO_ERROR;
+ int LBRR_rate_thres_bps;
+
+ LBRR_in_previous_packet = this.LBRR_enabled;
+ this.LBRR_enabled = 0;
+ if (this.useInBandFEC != 0 && this.PacketLoss_perc > 0) {
+ if (this.fs_kHz == 8) {
+ LBRR_rate_thres_bps = SilkConstants.LBRR_NB_MIN_RATE_BPS;
+ } else if (this.fs_kHz == 12) {
+ LBRR_rate_thres_bps = SilkConstants.LBRR_MB_MIN_RATE_BPS;
+ } else {
+ LBRR_rate_thres_bps = SilkConstants.LBRR_WB_MIN_RATE_BPS;
+ }
+
+ LBRR_rate_thres_bps = Inlines.silk_SMULWB(Inlines.silk_MUL(LBRR_rate_thres_bps, 125 - Inlines.silk_min(this.PacketLoss_perc, 25)), ((int) ((0.01f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.01f, 16)*/);
+
+ if (TargetRate_bps > LBRR_rate_thres_bps) {
+ /* Set gain increase for coding LBRR excitation */
+ if (LBRR_in_previous_packet == 0) {
+ /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */
+ this.LBRR_GainIncreases = 7;
+ } else {
+ this.LBRR_GainIncreases = Inlines.silk_max_int(7 - Inlines.silk_SMULWB((int) this.PacketLoss_perc, ((int) ((0.4f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.4f, 16)*/), 2);
+ }
+ this.LBRR_enabled = 1;
+ }
+ }
+
+ return ret;
+ }
+
+ ///
+ /// Control sampling rate
+ ///
+ /// I/O Pointer to Silk encoder state
+ /// I Control structure
+ ///
+ int silk_control_audio_bandwidth(EncControlState encControl) {
+ int fs_kHz;
+ int fs_Hz;
+
+ fs_kHz = this.fs_kHz;
+ fs_Hz = Inlines.silk_SMULBB(fs_kHz, 1000);
+
+ if (fs_Hz == 0) {
+ /* Encoder has just been initialized */
+ fs_Hz = Inlines.silk_min(this.desiredInternal_fs_Hz, this.API_fs_Hz);
+ fs_kHz = Inlines.silk_DIV32_16(fs_Hz, 1000);
+ } else if (fs_Hz > this.API_fs_Hz || fs_Hz > this.maxInternal_fs_Hz || fs_Hz < this.minInternal_fs_Hz) {
+ /* Make sure rate is not higher than external rate or maximum allowed, or lower than minimum allowed */
+ fs_Hz = this.API_fs_Hz;
+ fs_Hz = Inlines.silk_min(fs_Hz, this.maxInternal_fs_Hz);
+ fs_Hz = Inlines.silk_max(fs_Hz, this.minInternal_fs_Hz);
+ fs_kHz = Inlines.silk_DIV32_16(fs_Hz, 1000);
+ } else {
+ /* State machine for the sampling rate switching */
+ if (this.sLP.transition_frame_no >= SilkConstants.TRANSITION_FRAMES) {
+ /* Stop transition phase */
+ this.sLP.mode = 0;
+ }
+
+ if (this.allow_bandwidth_switch != 0 || encControl.opusCanSwitch != 0) {
+ /* Check if we should switch down */
+ if (Inlines.silk_SMULBB(this.fs_kHz, 1000) > this.desiredInternal_fs_Hz) {
+ /* Switch down */
+ if (this.sLP.mode == 0) {
+ /* New transition */
+ this.sLP.transition_frame_no = SilkConstants.TRANSITION_FRAMES;
+
+ /* Reset transition filter state */
+ Arrays.MemSet(this.sLP.In_LP_State, 0, 2);
+ }
+
+ if (encControl.opusCanSwitch != 0) {
+ /* Stop transition phase */
+ this.sLP.mode = 0;
+
+ /* Switch to a lower sample frequency */
+ fs_kHz = this.fs_kHz == 16 ? 12 : 8;
+ } else if (this.sLP.transition_frame_no <= 0) {
+ encControl.switchReady = 1;
+ /* Make room for redundancy */
+ encControl.maxBits -= encControl.maxBits * 5 / (encControl.payloadSize_ms + 5);
+ } else {
+ /* Direction: down (at double speed) */
+ this.sLP.mode = -2;
+ }
+ } else /* Check if we should switch up */ if (Inlines.silk_SMULBB(this.fs_kHz, 1000) < this.desiredInternal_fs_Hz) {
+ /* Switch up */
+ if (encControl.opusCanSwitch != 0) {
+ /* Switch to a higher sample frequency */
+ fs_kHz = this.fs_kHz == 8 ? 12 : 16;
+
+ /* New transition */
+ this.sLP.transition_frame_no = 0;
+
+ /* Reset transition filter state */
+ Arrays.MemSet(this.sLP.In_LP_State, 0, 2);
+
+ /* Direction: up */
+ this.sLP.mode = 1;
+ } else if (this.sLP.mode == 0) {
+ encControl.switchReady = 1;
+ /* Make room for redundancy */
+ encControl.maxBits -= encControl.maxBits * 5 / (encControl.payloadSize_ms + 5);
+ } else {
+ /* Direction: up */
+ this.sLP.mode = 1;
+ }
+ } else if (this.sLP.mode < 0) {
+ this.sLP.mode = 1;
+ }
+ }
+ }
+
+ return fs_kHz;
+ }
+
+ /* Control SNR of residual quantizer */
+ int silk_control_SNR(
+ int TargetRate_bps /* I Target max bitrate (bps) */
+ ) {
+ int k, ret = SilkError.SILK_NO_ERROR;
+ int frac_Q6;
+ int[] rateTable;
+
+ /* Set bitrate/coding quality */
+ TargetRate_bps = Inlines.silk_LIMIT(TargetRate_bps, SilkConstants.MIN_TARGET_RATE_BPS, SilkConstants.MAX_TARGET_RATE_BPS);
+ if (TargetRate_bps != this.TargetRate_bps) {
+ this.TargetRate_bps = TargetRate_bps;
+
+ /* If new TargetRate_bps, translate to SNR_dB value */
+ if (this.fs_kHz == 8) {
+ rateTable = SilkTables.silk_TargetRate_table_NB;
+ } else if (this.fs_kHz == 12) {
+ rateTable = SilkTables.silk_TargetRate_table_MB;
+ } else {
+ rateTable = SilkTables.silk_TargetRate_table_WB;
+ }
+
+ /* Reduce bitrate for 10 ms modes in these calculations */
+ if (this.nb_subfr == 2) {
+ TargetRate_bps -= TuningParameters.REDUCE_BITRATE_10_MS_BPS;
+ }
+
+ /* Find bitrate interval in table and interpolate */
+ for (k = 1; k < SilkConstants.TARGET_RATE_TAB_SZ; k++) {
+ if (TargetRate_bps <= rateTable[k]) {
+ frac_Q6 = Inlines.silk_DIV32(Inlines.silk_LSHIFT(TargetRate_bps - rateTable[k - 1], 6),
+ rateTable[k] - rateTable[k - 1]);
+ this.SNR_dB_Q7 = Inlines.silk_LSHIFT(SilkTables.silk_SNR_table_Q1[k - 1], 6) + Inlines.silk_MUL(frac_Q6, SilkTables.silk_SNR_table_Q1[k] - SilkTables.silk_SNR_table_Q1[k - 1]);
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ void silk_encode_do_VAD() {
+ /**
+ * *************************
+ */
+ /* Voice Activity Detection */
+ /**
+ * *************************
+ */
+ VoiceActivityDetection.silk_VAD_GetSA_Q8(this, this.inputBuf, 1);
+
+ /**
+ * ***********************************************
+ */
+ /* Convert speech activity into VAD and DTX flags */
+ /**
+ * ***********************************************
+ */
+ if (this.speech_activity_Q8 < ((int) ((TuningParameters.SPEECH_ACTIVITY_DTX_THRES) * ((long) 1 << (8)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.SPEECH_ACTIVITY_DTX_THRES, 8)*/) {
+ this.indices.signalType = SilkConstants.TYPE_NO_VOICE_ACTIVITY;
+ this.noSpeechCounter++;
+ if (this.noSpeechCounter < SilkConstants.NB_SPEECH_FRAMES_BEFORE_DTX) {
+ this.inDTX = 0;
+ } else if (this.noSpeechCounter > SilkConstants.MAX_CONSECUTIVE_DTX + SilkConstants.NB_SPEECH_FRAMES_BEFORE_DTX) {
+ this.noSpeechCounter = SilkConstants.NB_SPEECH_FRAMES_BEFORE_DTX;
+ this.inDTX = 0;
+ }
+ this.VAD_flags[this.nFramesEncoded] = 0;
+ } else {
+ this.noSpeechCounter = 0;
+ this.inDTX = 0;
+ this.indices.signalType = SilkConstants.TYPE_UNVOICED;
+ this.VAD_flags[this.nFramesEncoded] = 1;
+ }
+ }
+
+ /**
+ * *************
+ */
+ /* Encode frame */
+ /**
+ * *************
+ */
+ int silk_encode_frame(
+ BoxedValueInt pnBytesOut, /* O Pointer to number of payload bytes; */
+ EntropyCoder psRangeEnc, /* I/O compressor data structure */
+ int condCoding, /* I The type of conditional coding to use */
+ int maxBits, /* I If > 0: maximum number of output bits */
+ int useCBR /* I Flag to force constant-bitrate operation */
+ ) {
+ SilkEncoderControl sEncCtrl = new SilkEncoderControl();
+ int i, iter, maxIter, found_upper, found_lower, ret = 0;
+ int x_frame;
+ EntropyCoder sRangeEnc_copy = new EntropyCoder();
+ EntropyCoder sRangeEnc_copy2 = new EntropyCoder();
+ SilkNSQState sNSQ_copy = new SilkNSQState();
+ SilkNSQState sNSQ_copy2 = new SilkNSQState();
+ int nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+ int gainsID, gainsID_lower, gainsID_upper;
+ short gainMult_Q8;
+ short ec_prevLagIndex_copy;
+ int ec_prevSignalType_copy;
+ byte LastGainIndex_copy2;
+ byte seed_copy;
+
+ /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
+ LastGainIndex_copy2 = 0;
+ nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
+
+ this.indices.Seed = (byte) (this.frameCounter++ & 3);
+
+ /**
+ * ***********************************************************
+ */
+ /* Set up Input Pointers, and insert frame in input buffer */
+ /**
+ * **********************************************************
+ */
+ /* start of frame to encode */
+ x_frame = this.ltp_mem_length;
+
+ /**
+ * ************************************
+ */
+ /* Ensure smooth bandwidth transitions */
+ /**
+ * ************************************
+ */
+ this.sLP.silk_LP_variable_cutoff(this.inputBuf, 1, this.frame_length);
+
+ /**
+ * ****************************************
+ */
+ /* Copy new frame to front of input buffer */
+ /**
+ * ****************************************
+ */
+ System.arraycopy(this.inputBuf, 1, this.x_buf, x_frame + SilkConstants.LA_SHAPE_MS * this.fs_kHz, this.frame_length);
+
+ if (this.prefillFlag == 0) {
+ int[] xfw_Q3;
+ short[] res_pitch;
+ byte[] ec_buf_copy;
+ int res_pitch_frame;
+
+ res_pitch = new short[this.la_pitch + this.frame_length + this.ltp_mem_length];
+ /* start of pitch LPC residual frame */
+ res_pitch_frame = this.ltp_mem_length;
+
+ /**
+ * **************************************
+ */
+ /* Find pitch lags, initial LPC analysis */
+ /**
+ * **************************************
+ */
+ FindPitchLags.silk_find_pitch_lags(this, sEncCtrl, res_pitch, this.x_buf, x_frame);
+
+ /**
+ * *********************
+ */
+ /* Noise shape analysis */
+ /**
+ * *********************
+ */
+ NoiseShapeAnalysis.silk_noise_shape_analysis(this, sEncCtrl, res_pitch, res_pitch_frame, this.x_buf, x_frame);
+
+ /**
+ * ************************************************
+ */
+ /* Find linear prediction coefficients (LPC + LTP) */
+ /**
+ * ************************************************
+ */
+ FindPredCoefs.silk_find_pred_coefs(this, sEncCtrl, res_pitch, this.x_buf, x_frame, condCoding);
+
+ /**
+ * *************************************
+ */
+ /* Process gains */
+ /**
+ * *************************************
+ */
+ ProcessGains.silk_process_gains(this, sEncCtrl, condCoding);
+
+ /**
+ * **************************************
+ */
+ /* Prefiltering for noise shaper */
+ /**
+ * **************************************
+ */
+ xfw_Q3 = new int[this.frame_length];
+ Filters.silk_prefilter(this, sEncCtrl, xfw_Q3, this.x_buf, x_frame);
+
+ /**
+ * *************************************
+ */
+ /* Low Bitrate Redundant Encoding */
+ /**
+ * *************************************
+ */
+ silk_LBRR_encode(sEncCtrl, xfw_Q3, condCoding);
+
+ /* Loop over quantizer and entropy coding to control bitrate */
+ maxIter = 6;
+ gainMult_Q8 = (short) (((int) ((1) * ((long) 1 << (8)) + 0.5))/*Inlines.SILK_CONST(1, 8)*/);
+ found_lower = 0;
+ found_upper = 0;
+ gainsID = GainQuantization.silk_gains_ID(this.indices.GainsIndices, this.nb_subfr);
+ gainsID_lower = -1;
+ gainsID_upper = -1;
+ /* Copy part of the input state */
+ sRangeEnc_copy.Assign(psRangeEnc);
+ sNSQ_copy.Assign(this.sNSQ);
+ seed_copy = this.indices.Seed;
+ ec_prevLagIndex_copy = this.ec_prevLagIndex;
+ ec_prevSignalType_copy = this.ec_prevSignalType;
+ ec_buf_copy = new byte[1275]; // fixme: this size might be optimized to the actual size
+ for (iter = 0;; iter++) {
+ if (gainsID == gainsID_lower) {
+ nBits = nBits_lower;
+ } else if (gainsID == gainsID_upper) {
+ nBits = nBits_upper;
+ } else {
+ /* Restore part of the input state */
+ if (iter > 0) {
+ psRangeEnc.Assign(sRangeEnc_copy);
+ this.sNSQ.Assign(sNSQ_copy);
+ this.indices.Seed = seed_copy;
+ this.ec_prevLagIndex = ec_prevLagIndex_copy;
+ this.ec_prevSignalType = ec_prevSignalType_copy;
+ }
+
+ /**
+ * **************************************
+ */
+ /* Noise shaping quantization */
+ /**
+ * **************************************
+ */
+ if (this.nStatesDelayedDecision > 1 || this.warping_Q16 > 0) {
+ sNSQ.silk_NSQ_del_dec(
+ this,
+ this.indices,
+ xfw_Q3,
+ pulses,
+ sEncCtrl.PredCoef_Q12,
+ sEncCtrl.LTPCoef_Q14,
+ sEncCtrl.AR2_Q13,
+ sEncCtrl.HarmShapeGain_Q14,
+ sEncCtrl.Tilt_Q14,
+ sEncCtrl.LF_shp_Q14,
+ sEncCtrl.Gains_Q16,
+ sEncCtrl.pitchL,
+ sEncCtrl.Lambda_Q10,
+ sEncCtrl.LTP_scale_Q14);
+ } else {
+ sNSQ.silk_NSQ(
+ this,
+ this.indices,
+ xfw_Q3,
+ pulses,
+ sEncCtrl.PredCoef_Q12,
+ sEncCtrl.LTPCoef_Q14,
+ sEncCtrl.AR2_Q13,
+ sEncCtrl.HarmShapeGain_Q14,
+ sEncCtrl.Tilt_Q14,
+ sEncCtrl.LF_shp_Q14,
+ sEncCtrl.Gains_Q16,
+ sEncCtrl.pitchL,
+ sEncCtrl.Lambda_Q10,
+ sEncCtrl.LTP_scale_Q14);
+ }
+
+ /**
+ * *************************************
+ */
+ /* Encode Parameters */
+ /**
+ * *************************************
+ */
+ EncodeIndices.silk_encode_indices(this, psRangeEnc, this.nFramesEncoded, 0, condCoding);
+
+ /**
+ * *************************************
+ */
+ /* Encode Excitation Signal */
+ /**
+ * *************************************
+ */
+ EncodePulses.silk_encode_pulses(psRangeEnc, this.indices.signalType, this.indices.quantOffsetType,
+ this.pulses, this.frame_length);
+
+ nBits = psRangeEnc.tell();
+
+ if (useCBR == 0 && iter == 0 && nBits <= maxBits) {
+ break;
+ }
+ }
+
+ if (iter == maxIter) {
+ if (found_lower != 0 && (gainsID == gainsID_lower || nBits > maxBits)) {
+ /* Restore output state from earlier iteration that did meet the bitrate budget */
+ psRangeEnc.Assign(sRangeEnc_copy2);
+ Inlines.OpusAssert(sRangeEnc_copy2.offs <= 1275);
+ psRangeEnc.write_buffer(ec_buf_copy, 0, 0, (int) sRangeEnc_copy2.offs);
+ this.sNSQ.Assign(sNSQ_copy2);
+ this.sShape.LastGainIndex = LastGainIndex_copy2;
+ }
+ break;
+ }
+
+ if (nBits > maxBits) {
+ if (found_lower == 0 && iter >= 2) {
+ /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
+ sEncCtrl.Lambda_Q10 = Inlines.silk_ADD_RSHIFT32(sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1);
+ found_upper = 0;
+ gainsID_upper = -1;
+ } else {
+ found_upper = 1;
+ nBits_upper = nBits;
+ gainMult_upper = gainMult_Q8;
+ gainsID_upper = gainsID;
+ }
+ } else if (nBits < maxBits - 5) {
+ found_lower = 1;
+ nBits_lower = nBits;
+ gainMult_lower = gainMult_Q8;
+ if (gainsID != gainsID_lower) {
+ gainsID_lower = gainsID;
+ /* Copy part of the output state */
+ sRangeEnc_copy2.Assign(psRangeEnc);
+ Inlines.OpusAssert(psRangeEnc.offs <= 1275);
+ System.arraycopy(psRangeEnc.get_buffer(), 0, ec_buf_copy, 0, (int) psRangeEnc.offs);
+ sNSQ_copy2.Assign(this.sNSQ);
+ LastGainIndex_copy2 = this.sShape.LastGainIndex;
+ }
+ } else {
+ /* Within 5 bits of budget: close enough */
+ break;
+ }
+
+ if ((found_lower & found_upper) == 0) {
+ /* Adjust gain according to high-rate rate/distortion curve */
+ int gain_factor_Q16;
+ gain_factor_Q16 = Inlines.silk_log2lin(Inlines.silk_LSHIFT(nBits - maxBits, 7) / this.frame_length + ((int) ((16) * ((long) 1 << (7)) + 0.5))/*Inlines.SILK_CONST(16, 7)*/);
+ gain_factor_Q16 = Inlines.silk_min_32(gain_factor_Q16, ((int) ((2) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(2, 16)*/);
+ if (nBits > maxBits) {
+ gain_factor_Q16 = Inlines.silk_max_32(gain_factor_Q16, ((int) ((1.3f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.3f, 16)*/);
+ }
+
+ gainMult_Q8 = (short) (Inlines.silk_SMULWB(gain_factor_Q16, (int) gainMult_Q8));
+ } else {
+ /* Adjust gain by interpolating */
+ gainMult_Q8 = (short) (gainMult_lower + Inlines.silk_DIV32_16(Inlines.silk_MUL(gainMult_upper - gainMult_lower, maxBits - nBits_lower), nBits_upper - nBits_lower));
+ /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
+ if (gainMult_Q8 > Inlines.silk_ADD_RSHIFT32(gainMult_lower, gainMult_upper - gainMult_lower, 2)) {
+ gainMult_Q8 = (short) (Inlines.silk_ADD_RSHIFT32(gainMult_lower, gainMult_upper - gainMult_lower, 2));
+ } else if (gainMult_Q8 < Inlines.silk_SUB_RSHIFT32(gainMult_upper, gainMult_upper - gainMult_lower, 2)) {
+ gainMult_Q8 = (short) (Inlines.silk_SUB_RSHIFT32(gainMult_upper, gainMult_upper - gainMult_lower, 2));
+ }
+ }
+
+ for (i = 0; i < this.nb_subfr; i++) {
+ sEncCtrl.Gains_Q16[i] = Inlines.silk_LSHIFT_SAT32(Inlines.silk_SMULWB(sEncCtrl.GainsUnq_Q16[i], gainMult_Q8), 8);
+ }
+
+ /* Quantize gains */
+ this.sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+ BoxedValueByte boxed_gainIndex = new BoxedValueByte(this.sShape.LastGainIndex);
+ GainQuantization.silk_gains_quant(this.indices.GainsIndices, sEncCtrl.Gains_Q16,
+ boxed_gainIndex, condCoding == SilkConstants.CODE_CONDITIONALLY ? 1 : 0, this.nb_subfr);
+ this.sShape.LastGainIndex = boxed_gainIndex.Val;
+
+ /* Unique identifier of gains vector */
+ gainsID = GainQuantization.silk_gains_ID(this.indices.GainsIndices, this.nb_subfr);
+ }
+ }
+
+ /* Update input buffer */
+ Arrays.MemMove(this.x_buf, this.frame_length, 0, this.ltp_mem_length + SilkConstants.LA_SHAPE_MS * this.fs_kHz);
+
+ /* Exit without entropy coding */
+ if (this.prefillFlag != 0) {
+ /* No payload */
+ pnBytesOut.Val = 0;
+
+ return ret;
+ }
+
+ /* Parameters needed for next frame */
+ this.prevLag = sEncCtrl.pitchL[this.nb_subfr - 1];
+ this.prevSignalType = this.indices.signalType;
+
+ /**
+ * *************************************
+ */
+ /* Finalize payload */
+ /**
+ * *************************************
+ */
+ this.first_frame_after_reset = 0;
+ /* Payload size */
+ pnBytesOut.Val = Inlines.silk_RSHIFT(psRangeEnc.tell() + 7, 3);
+
+ return ret;
+ }
+
+ /* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */
+ void silk_LBRR_encode(
+ SilkEncoderControl thisCtrl, /* I/O Pointer to Silk FIX encoder control struct */
+ int[] xfw_Q3, /* I Input signal */
+ int condCoding /* I The type of conditional coding used so far for this frame */
+ ) {
+ int[] TempGains_Q16 = new int[/*SilkConstants.MAX_NB_SUBFR*/this.nb_subfr];
+ SideInfoIndices psIndices_LBRR = this.indices_LBRR[this.nFramesEncoded];
+ SilkNSQState sNSQ_LBRR = new SilkNSQState();
+
+ /**
+ * ****************************************
+ */
+ /* Control use of inband LBRR */
+ /**
+ * ****************************************
+ */
+ if (this.LBRR_enabled != 0 && this.speech_activity_Q8 > ((int) ((TuningParameters.LBRR_SPEECH_ACTIVITY_THRES) * ((long) 1 << (8)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LBRR_SPEECH_ACTIVITY_THRES, 8)*/) {
+ this.LBRR_flags[this.nFramesEncoded] = 1;
+
+ /* Copy noise shaping quantizer state and quantization indices from regular encoding */
+ sNSQ_LBRR.Assign(this.sNSQ);
+ psIndices_LBRR.Assign(this.indices);
+
+ /* Save original gains */
+ System.arraycopy(thisCtrl.Gains_Q16, 0, TempGains_Q16, 0, this.nb_subfr);
+
+ if (this.nFramesEncoded == 0 || this.LBRR_flags[this.nFramesEncoded - 1] == 0) {
+ /* First frame in packet or previous frame not LBRR coded */
+ this.LBRRprevLastGainIndex = this.sShape.LastGainIndex;
+
+ /* Increase Gains to get target LBRR rate */
+ psIndices_LBRR.GainsIndices[0] = (byte) (psIndices_LBRR.GainsIndices[0] + this.LBRR_GainIncreases);
+ psIndices_LBRR.GainsIndices[0] = (byte) (Inlines.silk_min_int(psIndices_LBRR.GainsIndices[0], SilkConstants.N_LEVELS_QGAIN - 1));
+ }
+
+ /* Decode to get gains in sync with decoder */
+ /* Overwrite unquantized gains with quantized gains */
+ BoxedValueByte boxed_gainIndex = new BoxedValueByte(this.LBRRprevLastGainIndex);
+ GainQuantization.silk_gains_dequant(thisCtrl.Gains_Q16, psIndices_LBRR.GainsIndices,
+ boxed_gainIndex, condCoding == SilkConstants.CODE_CONDITIONALLY ? 1 : 0, this.nb_subfr);
+ this.LBRRprevLastGainIndex = boxed_gainIndex.Val;
+
+ /**
+ * **************************************
+ */
+ /* Noise shaping quantization */
+ /**
+ * **************************************
+ */
+ if (this.nStatesDelayedDecision > 1 || this.warping_Q16 > 0) {
+ sNSQ_LBRR.silk_NSQ_del_dec(this,
+ psIndices_LBRR,
+ xfw_Q3,
+ this.pulses_LBRR[this.nFramesEncoded],
+ thisCtrl.PredCoef_Q12,
+ thisCtrl.LTPCoef_Q14,
+ thisCtrl.AR2_Q13,
+ thisCtrl.HarmShapeGain_Q14,
+ thisCtrl.Tilt_Q14,
+ thisCtrl.LF_shp_Q14,
+ thisCtrl.Gains_Q16,
+ thisCtrl.pitchL,
+ thisCtrl.Lambda_Q10,
+ thisCtrl.LTP_scale_Q14);
+ } else {
+ sNSQ_LBRR.silk_NSQ(this,
+ psIndices_LBRR,
+ xfw_Q3,
+ this.pulses_LBRR[this.nFramesEncoded],
+ thisCtrl.PredCoef_Q12,
+ thisCtrl.LTPCoef_Q14,
+ thisCtrl.AR2_Q13,
+ thisCtrl.HarmShapeGain_Q14,
+ thisCtrl.Tilt_Q14,
+ thisCtrl.LF_shp_Q14,
+ thisCtrl.Gains_Q16,
+ thisCtrl.pitchL,
+ thisCtrl.Lambda_Q10,
+ thisCtrl.LTP_scale_Q14);
+ }
+
+ /* Restore original gains */
+ System.arraycopy(TempGains_Q16, 0, thisCtrl.Gains_Q16, 0, this.nb_subfr);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkConstants.java b/app/src/main/java/org/concentus/SilkConstants.java
new file mode 100644
index 0000000000..fa46137379
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkConstants.java
@@ -0,0 +1,339 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class SilkConstants {
+
+ /* Max number of encoder channels (1/2) */
+ public static final int ENCODER_NUM_CHANNELS = 2;
+ /* Number of decoder channels (1/2) */
+ public static final int DECODER_NUM_CHANNELS = 2;
+
+ public static final int MAX_FRAMES_PER_PACKET = 3;
+
+ /* Limits on bitrate */
+ public static final int MIN_TARGET_RATE_BPS = 5000;
+ public static final int MAX_TARGET_RATE_BPS = 80000;
+ public static final int TARGET_RATE_TAB_SZ = 8;
+
+ /* LBRR thresholds */
+ public static final int LBRR_NB_MIN_RATE_BPS = 12000;
+ public static final int LBRR_MB_MIN_RATE_BPS = 14000;
+ public static final int LBRR_WB_MIN_RATE_BPS = 16000;
+
+ /* DTX settings */
+ public static final int NB_SPEECH_FRAMES_BEFORE_DTX = 10;
+ /* eq 200 ms */
+ public static final int MAX_CONSECUTIVE_DTX = 20;
+ /* eq 400 ms */
+
+ /* Maximum sampling frequency */
+ public static final int MAX_FS_KHZ = 16;
+ public static final int MAX_API_FS_KHZ = 48;
+
+ // FIXME can use enums here
+ /* Signal types */
+ public static final int TYPE_NO_VOICE_ACTIVITY = 0;
+ public static final int TYPE_UNVOICED = 1;
+ public static final int TYPE_VOICED = 2;
+
+ /* Conditional coding types */
+ public static final int CODE_INDEPENDENTLY = 0;
+ public static final int CODE_INDEPENDENTLY_NO_LTP_SCALING = 1;
+ public static final int CODE_CONDITIONALLY = 2;
+
+ /* Settings for stereo processing */
+ public static final int STEREO_QUANT_TAB_SIZE = 16;
+ public static final int STEREO_QUANT_SUB_STEPS = 5;
+ public static final int STEREO_INTERP_LEN_MS = 8;
+ /* must be even */
+ public static final float STEREO_RATIO_SMOOTH_COEF = 0.01f;
+ /* smoothing coef for signal norms and stereo width */
+
+ /* Range of pitch lag estimates */
+ public static final int PITCH_EST_MIN_LAG_MS = 2;
+ /* 2 ms . 500 Hz */
+ public static final int PITCH_EST_MAX_LAG_MS = 18;
+ /* 18 ms . 56 Hz */
+
+ /* Maximum number of subframes */
+ public static final int MAX_NB_SUBFR = 4;
+
+ /* Number of samples per frame */
+ public static final int LTP_MEM_LENGTH_MS = 20;
+ public static final int SUB_FRAME_LENGTH_MS = 5;
+ public static final int MAX_SUB_FRAME_LENGTH = (SUB_FRAME_LENGTH_MS * MAX_FS_KHZ);
+ public static final int MAX_FRAME_LENGTH_MS = (SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR);
+ public static final int MAX_FRAME_LENGTH = (MAX_FRAME_LENGTH_MS * MAX_FS_KHZ);
+
+ /* Milliseconds of lookahead for pitch analysis */
+ public static final int LA_PITCH_MS = 2;
+ public static final int LA_PITCH_MAX = (LA_PITCH_MS * MAX_FS_KHZ);
+
+ /* Order of LPC used in find pitch */
+ public static final int MAX_FIND_PITCH_LPC_ORDER = 16;
+
+ /* Length of LPC window used in find pitch */
+ public static final int FIND_PITCH_LPC_WIN_MS = (20 + (LA_PITCH_MS << 1));
+ public static final int FIND_PITCH_LPC_WIN_MS_2_SF = (10 + (LA_PITCH_MS << 1));
+ public static final int FIND_PITCH_LPC_WIN_MAX = (FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ);
+
+ /* Milliseconds of lookahead for noise shape analysis */
+ public static final int LA_SHAPE_MS = 5;
+ public static final int LA_SHAPE_MAX = (LA_SHAPE_MS * MAX_FS_KHZ);
+
+ /* Maximum length of LPC window used in noise shape analysis */
+ public static final int SHAPE_LPC_WIN_MAX = (15 * MAX_FS_KHZ);
+
+ /* dB level of lowest gain quantization level */
+ public static final int MIN_QGAIN_DB = 2;
+ /* dB level of highest gain quantization level */
+ public static final int MAX_QGAIN_DB = 88;
+ /* Number of gain quantization levels */
+ public static final int N_LEVELS_QGAIN = 64;
+ /* Max increase in gain quantization index */
+ public static final int MAX_DELTA_GAIN_QUANT = 36;
+ /* Max decrease in gain quantization index */
+ public static final int MIN_DELTA_GAIN_QUANT = -4;
+
+ /* Quantization offsets (multiples of 4) */
+ public static final short OFFSET_VL_Q10 = 32;
+ public static final short OFFSET_VH_Q10 = 100;
+ public static final short OFFSET_UVL_Q10 = 100;
+ public static final short OFFSET_UVH_Q10 = 240;
+
+ public static final int QUANT_LEVEL_ADJUST_Q10 = 80;
+
+ /* Maximum numbers of iterations used to stabilize an LPC vector */
+ public static final int MAX_LPC_STABILIZE_ITERATIONS = 16;
+ public static final float MAX_PREDICTION_POWER_GAIN = 1e4f;
+ public static final float MAX_PREDICTION_POWER_GAIN_AFTER_RESET = 1e2f;
+
+ public static final int SILK_MAX_ORDER_LPC = 16;
+ public static final int MAX_LPC_ORDER = 16;
+ public static final int MIN_LPC_ORDER = 10;
+
+ /* Find Pred Coef defines */
+ public static final int LTP_ORDER = 5;
+
+ /* LTP quantization settings */
+ public static final int NB_LTP_CBKS = 3;
+
+ /* Flag to use harmonic noise shaping */
+ public static final int USE_HARM_SHAPING = 1;
+
+ /* Max LPC order of noise shaping filters */
+ public static final int MAX_SHAPE_LPC_ORDER = 16;
+
+ public static final int HARM_SHAPE_FIR_TAPS = 3;
+
+ /* Maximum number of delayed decision states */
+ public static final int MAX_DEL_DEC_STATES = 4;
+
+ public static final int LTP_BUF_LENGTH = 512;
+ public static final int LTP_MASK = (LTP_BUF_LENGTH - 1);
+
+ public static final int DECISION_DELAY = 32;
+ public static final int DECISION_DELAY_MASK = (DECISION_DELAY - 1);
+
+ /* Number of subframes for excitation entropy coding */
+ public static final int SHELL_CODEC_FRAME_LENGTH = 16;
+ public static final int LOG2_SHELL_CODEC_FRAME_LENGTH = 4;
+ public static final int MAX_NB_SHELL_BLOCKS = (MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH);
+
+ /* Number of rate levels, for entropy coding of excitation */
+ public static final int N_RATE_LEVELS = 10;
+
+ /* Maximum sum of pulses per shell coding frame */
+ public static final int SILK_MAX_PULSES = 16;
+
+ public static final int MAX_MATRIX_SIZE = MAX_LPC_ORDER;
+ /* Max of LPC Order and LTP order */
+
+ static final int NSQ_LPC_BUF_LENGTH = Math.max(MAX_LPC_ORDER, DECISION_DELAY);
+
+ /**
+ * ************************
+ */
+ /* Voice activity detector */
+ /**
+ * ************************
+ */
+ public static final int VAD_N_BANDS = 4;
+
+ public static final int VAD_INTERNAL_SUBFRAMES_LOG2 = 2;
+ public static final int VAD_INTERNAL_SUBFRAMES = (1 << VAD_INTERNAL_SUBFRAMES_LOG2);
+
+ public static final int VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 = 1024;
+ /* Must be < 4096 */
+ public static final int VAD_NOISE_LEVELS_BIAS = 50;
+
+ /* Sigmoid settings */
+ public static final int VAD_NEGATIVE_OFFSET_Q5 = 128;
+ /* sigmoid is 0 at -128 */
+ public static final int VAD_SNR_FACTOR_Q16 = 45000;
+
+ /* smoothing for SNR measurement */
+ public static final int VAD_SNR_SMOOTH_COEF_Q18 = 4096;
+
+ /* Size of the piecewise linear cosine approximation table for the LSFs */
+ public static final int LSF_COS_TAB_SZ = 128;
+
+ /**
+ * ***************
+ */
+ /* NLSF quantizer */
+ /**
+ * ***************
+ */
+ public static final int NLSF_W_Q = 2;
+ public static final int NLSF_VQ_MAX_VECTORS = 32;
+ public static final int NLSF_VQ_MAX_SURVIVORS = 32;
+ public static final int NLSF_QUANT_MAX_AMPLITUDE = 4;
+ public static final int NLSF_QUANT_MAX_AMPLITUDE_EXT = 10;
+ public static final float NLSF_QUANT_LEVEL_ADJ = 0.1f;
+ public static final int NLSF_QUANT_DEL_DEC_STATES_LOG2 = 2;
+ public static final int NLSF_QUANT_DEL_DEC_STATES = (1 << NLSF_QUANT_DEL_DEC_STATES_LOG2);
+
+ /* Transition filtering for mode switching */
+ public static final int TRANSITION_TIME_MS = 5120;
+ /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/
+ public static final int TRANSITION_NB = 3;
+ /* Hardcoded in tables */
+ public static final int TRANSITION_NA = 2;
+ /* Hardcoded in tables */
+ public static final int TRANSITION_INT_NUM = 5;
+ /* Hardcoded in tables */
+ public static final int TRANSITION_FRAMES = (TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS);
+ public static final int TRANSITION_INT_STEPS = (TRANSITION_FRAMES / (TRANSITION_INT_NUM - 1));
+
+ /* BWE factors to apply after packet loss */
+ public static final int BWE_AFTER_LOSS_Q16 = 63570;
+
+ /* Defines for CN generation */
+ public static final int CNG_BUF_MASK_MAX = 255;
+ /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */
+ public static final int CNG_GAIN_SMTH_Q16 = 4634;
+ /* 0.25^(1/4) */
+ public static final int CNG_NLSF_SMTH_Q16 = 16348;
+ /* 0.25 */
+
+ /**
+ * *****************************************************
+ */
+ /* Definitions for pitch estimator (from pitch_est_defines.h) */
+ /**
+ * *****************************************************
+ */
+
+ public static final int PE_MAX_FS_KHZ = 16;
+ /* Maximum sampling frequency used */
+
+ public static final int PE_MAX_NB_SUBFR = 4;
+ public static final int PE_SUBFR_LENGTH_MS = 5;
+ /* 5 ms */
+
+ public static final int PE_LTP_MEM_LENGTH_MS = (4 * PE_SUBFR_LENGTH_MS);
+
+ public static final int PE_MAX_FRAME_LENGTH_MS = (PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS);
+ public static final int PE_MAX_FRAME_LENGTH = (PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ);
+ public static final int PE_MAX_FRAME_LENGTH_ST_1 = (PE_MAX_FRAME_LENGTH >> 2);
+ public static final int PE_MAX_FRAME_LENGTH_ST_2 = (PE_MAX_FRAME_LENGTH >> 1);
+
+ public static final int PE_MAX_LAG_MS = 18;
+ /* 18 ms . 56 Hz */
+ public static final int PE_MIN_LAG_MS = 2;
+ /* 2 ms . 500 Hz */
+ public static final int PE_MAX_LAG = (PE_MAX_LAG_MS * PE_MAX_FS_KHZ);
+ public static final int PE_MIN_LAG = (PE_MIN_LAG_MS * PE_MAX_FS_KHZ);
+
+ public static final int PE_D_SRCH_LENGTH = 24;
+
+ public static final int PE_NB_STAGE3_LAGS = 5;
+
+ public static final int PE_NB_CBKS_STAGE2 = 3;
+ public static final int PE_NB_CBKS_STAGE2_EXT = 11;
+
+ public static final int PE_NB_CBKS_STAGE3_MAX = 34;
+ public static final int PE_NB_CBKS_STAGE3_MID = 24;
+ public static final int PE_NB_CBKS_STAGE3_MIN = 16;
+
+ public static final int PE_NB_CBKS_STAGE3_10MS = 12;
+ public static final int PE_NB_CBKS_STAGE2_10MS = 3;
+
+ public static final float PE_SHORTLAG_BIAS = 0.2f;
+ /* for logarithmic weighting */
+ public static final float PE_PREVLAG_BIAS = 0.2f;
+ /* for logarithmic weighting */
+ public static final float PE_FLATCONTOUR_BIAS = 0.05f;
+
+ public static final int SILK_PE_MIN_COMPLEX = 0;
+ public static final int SILK_PE_MID_COMPLEX = 1;
+ public static final int SILK_PE_MAX_COMPLEX = 2;
+
+ // Definitions for PLC (from plc.h)
+ public static final float BWE_COEF = 0.99f;
+ public static final int V_PITCH_GAIN_START_MIN_Q14 = 11469;
+ /* 0.7 in Q14 */
+ public static final int V_PITCH_GAIN_START_MAX_Q14 = 15565;
+ /* 0.95 in Q14 */
+ public static final int MAX_PITCH_LAG_MS = 18;
+ public static final int RAND_BUF_SIZE = 128;
+ public static final int RAND_BUF_MASK = (RAND_BUF_SIZE - 1);
+ public static final int LOG2_INV_LPC_GAIN_HIGH_THRES = 3;
+ /* 2^3 = 8 dB LPC gain */
+ public static final int LOG2_INV_LPC_GAIN_LOW_THRES = 8;
+ /* 2^8 = 24 dB LPC gain */
+ public static final int PITCH_DRIFT_FAC_Q16 = 655;
+ /* 0.01 in Q16 */
+
+ // Definitions for resampler (from resampler_structs.h)
+
+ public static final int SILK_RESAMPLER_MAX_FIR_ORDER = 36;
+ public static final int SILK_RESAMPLER_MAX_IIR_ORDER = 6;
+
+ // from resampler_rom.h
+ public static final int RESAMPLER_DOWN_ORDER_FIR0 = 18;
+ public static final int RESAMPLER_DOWN_ORDER_FIR1 = 24;
+ public static final int RESAMPLER_DOWN_ORDER_FIR2 = 36;
+ public static final int RESAMPLER_ORDER_FIR_12 = 8;
+
+ // from resampler_private.h
+
+ /* Number of input samples to process in the inner loop */
+ public static final int RESAMPLER_MAX_BATCH_SIZE_MS = 10;
+ public static final int RESAMPLER_MAX_FS_KHZ = 48;
+ public static final int RESAMPLER_MAX_BATCH_SIZE_IN = (RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ);
+
+ // from api.h
+ public static final int SILK_MAX_FRAMES_PER_PACKET = 3;
+}
diff --git a/app/src/main/java/org/concentus/SilkDecoder.java b/app/src/main/java/org/concentus/SilkDecoder.java
new file mode 100644
index 0000000000..d8bb0b3b7a
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkDecoder.java
@@ -0,0 +1,60 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Decoder super struct
+///
+class SilkDecoder {
+
+ final SilkChannelDecoder[] channel_state = new SilkChannelDecoder[SilkConstants.DECODER_NUM_CHANNELS];
+ final StereoDecodeState sStereo = new StereoDecodeState();
+ int nChannelsAPI = 0;
+ int nChannelsInternal = 0;
+ int prev_decode_only_middle = 0;
+
+ SilkDecoder() {
+ for (int c = 0; c < SilkConstants.DECODER_NUM_CHANNELS; c++) {
+ channel_state[c] = new SilkChannelDecoder();
+ }
+ }
+
+ 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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkDecoderControl.java b/app/src/main/java/org/concentus/SilkDecoderControl.java
new file mode 100644
index 0000000000..0c17a842ce
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkDecoderControl.java
@@ -0,0 +1,56 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Decoder control
+///
+class SilkDecoderControl {
+
+ /* Prediction and coding parameters */
+ final int[] pitchL = new int[SilkConstants.MAX_NB_SUBFR];
+ final int[] Gains_Q16 = new int[SilkConstants.MAX_NB_SUBFR];
+
+ /* Holds interpolated and final coefficients */
+ final short[][] PredCoef_Q12 = Arrays.InitTwoDimensionalArrayShort(2, SilkConstants.MAX_LPC_ORDER);
+ final short[] LTPCoef_Q14 = new short[SilkConstants.LTP_ORDER * SilkConstants.MAX_NB_SUBFR];
+ int LTP_scale_Q14 = 0;
+
+ void Reset() {
+ Arrays.MemSet(pitchL, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(Gains_Q16, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(PredCoef_Q12[0], (short) 0, SilkConstants.MAX_LPC_ORDER);
+ Arrays.MemSet(PredCoef_Q12[1], (short) 0, SilkConstants.MAX_LPC_ORDER);
+ Arrays.MemSet(LTPCoef_Q14, (short) 0, SilkConstants.LTP_ORDER * SilkConstants.MAX_NB_SUBFR);
+ LTP_scale_Q14 = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkEncoder.java b/app/src/main/java/org/concentus/SilkEncoder.java
new file mode 100644
index 0000000000..c8c3d21720
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkEncoder.java
@@ -0,0 +1,95 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Encoder Super Struct
+///
+class SilkEncoder {
+
+ final SilkChannelEncoder[] state_Fxx = new SilkChannelEncoder[SilkConstants.ENCODER_NUM_CHANNELS];
+ final StereoEncodeState sStereo = new StereoEncodeState();
+ int nBitsUsedLBRR = 0;
+ int nBitsExceeded = 0;
+ int nChannelsAPI = 0;
+ int nChannelsInternal = 0;
+ int nPrevChannelsInternal = 0;
+ int timeSinceSwitchAllowed_ms = 0;
+ int allowBandwidthSwitch = 0;
+ int prev_decode_only_middle = 0;
+
+ SilkEncoder() {
+ for (int c = 0; c < SilkConstants.ENCODER_NUM_CHANNELS; c++) {
+ state_Fxx[c] = new SilkChannelEncoder();
+ }
+ }
+
+ 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;
+ }
+
+ ///
+ /// Initialize Silk Encoder state
+ ///
+ /// I/O Pointer to Silk FIX encoder state
+ /// I Run-time architecture
+ ///
+ 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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkEncoderControl.java b/app/src/main/java/org/concentus/SilkEncoderControl.java
new file mode 100644
index 0000000000..ba272de029
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkEncoderControl.java
@@ -0,0 +1,104 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+/**
+ * *********************
+ */
+/* Encoder control FIX */
+/**
+ * *********************
+ */
+class SilkEncoderControl {
+
+ /* Prediction and coding parameters */
+ final int[] Gains_Q16 = new int[SilkConstants.MAX_NB_SUBFR];
+ final short[][] PredCoef_Q12 = Arrays.InitTwoDimensionalArrayShort(2, SilkConstants.MAX_LPC_ORDER);
+ /* holds interpolated and final coefficients */
+ final short[] LTPCoef_Q14 = new short[SilkConstants.LTP_ORDER * SilkConstants.MAX_NB_SUBFR];
+ int LTP_scale_Q14 = 0;
+ final int[] pitchL = new int[SilkConstants.MAX_NB_SUBFR];
+
+ /* Noise shaping parameters */
+ final short[] AR1_Q13 = new short[SilkConstants.MAX_NB_SUBFR * SilkConstants.MAX_SHAPE_LPC_ORDER];
+ final short[] AR2_Q13 = new short[SilkConstants.MAX_NB_SUBFR * SilkConstants.MAX_SHAPE_LPC_ORDER];
+ final int[] LF_shp_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
+ /* Packs two int16 coefficients per int32 value */
+ final int[] GainsPre_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
+ final int[] HarmBoost_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
+ final int[] Tilt_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
+ final int[] HarmShapeGain_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
+ int Lambda_Q10 = 0;
+ int input_quality_Q14 = 0;
+ int coding_quality_Q14 = 0;
+
+ /* Measures */
+ int sparseness_Q8 = 0;
+ int predGain_Q16 = 0;
+ int LTPredCodGain_Q7 = 0;
+
+ /* Residual energy per subframe */
+ final int[] ResNrg = new int[SilkConstants.MAX_NB_SUBFR];
+
+ /* Q domain for the residual energy > 0 */
+ final int[] ResNrgQ = new int[SilkConstants.MAX_NB_SUBFR];
+
+ /* Parameters for CBR mode */
+ final int[] GainsUnq_Q16 = new int[SilkConstants.MAX_NB_SUBFR];
+ byte lastGainIndexPrev = 0;
+
+ void Reset() {
+ Arrays.MemSet(Gains_Q16, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(PredCoef_Q12[0], (short) 0, SilkConstants.MAX_LPC_ORDER);
+ Arrays.MemSet(PredCoef_Q12[1], (short) 0, SilkConstants.MAX_LPC_ORDER);
+ Arrays.MemSet(LTPCoef_Q14, (short) 0, SilkConstants.LTP_ORDER * SilkConstants.MAX_NB_SUBFR);
+ LTP_scale_Q14 = 0;
+ Arrays.MemSet(pitchL, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(AR1_Q13, (short) 0, SilkConstants.MAX_NB_SUBFR * SilkConstants.MAX_SHAPE_LPC_ORDER);
+ Arrays.MemSet(AR2_Q13, (short) 0, SilkConstants.MAX_NB_SUBFR * SilkConstants.MAX_SHAPE_LPC_ORDER);
+ Arrays.MemSet(LF_shp_Q14, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(GainsPre_Q14, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(HarmBoost_Q14, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(Tilt_Q14, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(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.MemSet(ResNrg, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(ResNrgQ, 0, SilkConstants.MAX_NB_SUBFR);
+ Arrays.MemSet(GainsUnq_Q16, 0, SilkConstants.MAX_NB_SUBFR);
+ lastGainIndexPrev = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkError.java b/app/src/main/java/org/concentus/SilkError.java
new file mode 100644
index 0000000000..721575f95e
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkError.java
@@ -0,0 +1,89 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Represents error messages from a silk encoder/decoder
+///
+class SilkError {
+
+ 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 */
+ static int SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES = -101;
+
+ /* Sampling frequency not 8000, 12000 or 16000 Hertz */
+ static int SILK_ENC_FS_NOT_SUPPORTED = -102;
+
+ /* Packet size not 10, 20, 40, or 60 ms */
+ static int SILK_ENC_PACKET_SIZE_NOT_SUPPORTED = -103;
+
+ /* Allocated payload buffer too short */
+ static int SILK_ENC_PAYLOAD_BUF_TOO_SHORT = -104;
+
+ /* Loss rate not between 0 and 100 percent */
+ static int SILK_ENC_INVALID_LOSS_RATE = -105;
+
+ /* Complexity setting not valid, use 0...10 */
+ static int SILK_ENC_INVALID_COMPLEXITY_SETTING = -106;
+
+ /* Inband FEC setting not valid, use 0 or 1 */
+ static int SILK_ENC_INVALID_INBAND_FEC_SETTING = -107;
+
+ /* DTX setting not valid, use 0 or 1 */
+ static int SILK_ENC_INVALID_DTX_SETTING = -108;
+
+ /* CBR setting not valid, use 0 or 1 */
+ static int SILK_ENC_INVALID_CBR_SETTING = -109;
+
+ /* Internal encoder error */
+ static int SILK_ENC_INTERNAL_ERROR = -110;
+
+ /* Internal encoder error */
+ static int SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR = -111;
+
+ // Decoder error messages
+
+ /* Output sampling frequency lower than internal decoded sampling frequency */
+ static int SILK_DEC_INVALID_SAMPLING_FREQUENCY = -200;
+
+ /* Payload size exceeded the maximum allowed 1024 bytes */
+ static int SILK_DEC_PAYLOAD_TOO_LARGE = -201;
+
+ /* Payload has bit errors */
+ static int SILK_DEC_PAYLOAD_ERROR = -202;
+
+ /* Payload has bit errors */
+ static int SILK_DEC_INVALID_FRAME_SIZE = -203;
+}
diff --git a/app/src/main/java/org/concentus/SilkLPState.java b/app/src/main/java/org/concentus/SilkLPState.java
new file mode 100644
index 0000000000..b45b4c74de
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkLPState.java
@@ -0,0 +1,99 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Variable cut-off low-pass filter state
+///
+class SilkLPState {
+
+ ///
+ /// Low pass filter state
+ ///
+ final int[] In_LP_State = new int[2];
+
+ ///
+ /// Counter which is mapped to a cut-off frequency
+ ///
+ int transition_frame_no = 0;
+
+ ///
+ /// Operating mode, <0: switch down, >0: switch up; 0: do nothing
+ ///
+ int mode = 0;
+
+ 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; */
+ 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);
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkNSQState.java b/app/src/main/java/org/concentus/SilkNSQState.java
new file mode 100644
index 0000000000..f9095b23aa
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkNSQState.java
@@ -0,0 +1,1229 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Noise shaping quantization state
+///
+class SilkNSQState {
+
+ ///
+ /// Buffer for quantized output signal
+ ///
+ final short[] xq = new short[2 * SilkConstants.MAX_FRAME_LENGTH]; //opt: make these arrays variable-sized since construction cost is significant here
+ final int[] sLTP_shp_Q14 = new int[2 * SilkConstants.MAX_FRAME_LENGTH];
+ final int[] sLPC_Q14 = new int[SilkConstants.MAX_SUB_FRAME_LENGTH + SilkConstants.NSQ_LPC_BUF_LENGTH];
+ final int[] sAR2_Q14 = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
+ int sLF_AR_shp_Q14 = 0;
+ int lagPrev = 0;
+ int sLTP_buf_idx = 0;
+ int sLTP_shp_buf_idx = 0;
+ int rand_seed = 0;
+ int prev_gain_Q16 = 0;
+ int rewhite_flag = 0;
+
+ void Reset() {
+ Arrays.MemSet(xq, (short) 0, 2 * SilkConstants.MAX_FRAME_LENGTH);
+ Arrays.MemSet(sLTP_shp_Q14, 0, 2 * SilkConstants.MAX_FRAME_LENGTH);
+ Arrays.MemSet(sLPC_Q14, 0, SilkConstants.MAX_SUB_FRAME_LENGTH + SilkConstants.NSQ_LPC_BUF_LENGTH);
+ Arrays.MemSet(sAR2_Q14, 0, SilkConstants.MAX_SHAPE_LPC_ORDER);
+ sLF_AR_shp_Q14 = 0;
+ lagPrev = 0;
+ sLTP_buf_idx = 0;
+ sLTP_shp_buf_idx = 0;
+ rand_seed = 0;
+ prev_gain_Q16 = 0;
+ rewhite_flag = 0;
+ }
+
+ // Copies another nsq state to this one
+ void Assign(SilkNSQState other) {
+ this.sLF_AR_shp_Q14 = other.sLF_AR_shp_Q14;
+ this.lagPrev = other.lagPrev;
+ this.sLTP_buf_idx = other.sLTP_buf_idx;
+ this.sLTP_shp_buf_idx = other.sLTP_shp_buf_idx;
+ this.rand_seed = other.rand_seed;
+ this.prev_gain_Q16 = other.prev_gain_Q16;
+ this.rewhite_flag = other.rewhite_flag;
+ System.arraycopy(other.xq, 0, this.xq, 0, 2 * SilkConstants.MAX_FRAME_LENGTH);
+ System.arraycopy(other.sLTP_shp_Q14, 0, this.sLTP_shp_Q14, 0, 2 * SilkConstants.MAX_FRAME_LENGTH);
+ System.arraycopy(other.sLPC_Q14, 0, this.sLPC_Q14, 0, SilkConstants.MAX_SUB_FRAME_LENGTH + SilkConstants.NSQ_LPC_BUF_LENGTH);
+ System.arraycopy(other.sAR2_Q14, 0, this.sAR2_Q14, 0, SilkConstants.MAX_SHAPE_LPC_ORDER);
+ }
+
+ private class NSQ_del_dec_struct {
+
+ final int[] sLPC_Q14 = new int[SilkConstants.MAX_SUB_FRAME_LENGTH + SilkConstants.NSQ_LPC_BUF_LENGTH];
+ final int[] RandState = new int[SilkConstants.DECISION_DELAY];
+ final int[] Q_Q10 = new int[SilkConstants.DECISION_DELAY];
+ final int[] Xq_Q14 = new int[SilkConstants.DECISION_DELAY];
+ final int[] Pred_Q15 = new int[SilkConstants.DECISION_DELAY];
+ final int[] Shape_Q14 = new int[SilkConstants.DECISION_DELAY];
+ int[] sAR2_Q14;
+ int LF_AR_Q14 = 0;
+ int Seed = 0;
+ int SeedInit = 0;
+ int RD_Q10 = 0;
+
+ NSQ_del_dec_struct(int shapingOrder) {
+ sAR2_Q14 = new int[shapingOrder];
+ }
+
+ void PartialCopyFrom(NSQ_del_dec_struct other, int q14Offset) {
+ System.arraycopy(other.sLPC_Q14, q14Offset, sLPC_Q14, q14Offset, (SilkConstants.MAX_SUB_FRAME_LENGTH + SilkConstants.NSQ_LPC_BUF_LENGTH - q14Offset));
+ System.arraycopy(other.RandState, 0, RandState, 0, SilkConstants.DECISION_DELAY);
+ System.arraycopy(other.Q_Q10, 0, Q_Q10, 0, SilkConstants.DECISION_DELAY);
+ System.arraycopy(other.Xq_Q14, 0, Xq_Q14, 0, SilkConstants.DECISION_DELAY);
+ System.arraycopy(other.Pred_Q15, 0, Pred_Q15, 0, SilkConstants.DECISION_DELAY);
+ System.arraycopy(other.Shape_Q14, 0, Shape_Q14, 0, SilkConstants.DECISION_DELAY);
+ System.arraycopy(other.sAR2_Q14, 0, sAR2_Q14, 0, sAR2_Q14.length);
+ LF_AR_Q14 = other.LF_AR_Q14;
+ Seed = other.Seed;
+ SeedInit = other.SeedInit;
+ RD_Q10 = other.RD_Q10;
+ }
+
+ void Assign(NSQ_del_dec_struct other) {
+ this.PartialCopyFrom(other, 0);
+ }
+ }
+
+ private class NSQ_sample_struct {
+
+ int Q_Q10;
+ int RD_Q10;
+ int xq_Q14;
+ int LF_AR_Q14;
+ int sLTP_shp_Q14;
+ int LPC_exc_Q14;
+
+ void Assign(NSQ_sample_struct other) {
+ this.Q_Q10 = other.Q_Q10;
+ this.RD_Q10 = other.RD_Q10;
+ this.xq_Q14 = other.xq_Q14;
+ this.LF_AR_Q14 = other.LF_AR_Q14;
+ this.sLTP_shp_Q14 = other.sLTP_shp_Q14;
+ this.LPC_exc_Q14 = other.LPC_exc_Q14;
+ }
+ }
+
+ void silk_NSQ(
+ SilkChannelEncoder psEncC, /* I/O Encoder State */
+ SideInfoIndices psIndices, /* I/O Quantization Indices */
+ int[] x_Q3, /* I Prefiltered input signal */
+ byte[] pulses, /* O Quantized pulse signal */
+ short[][] PredCoef_Q12, /* I Short term prediction coefs [2][SilkConstants.MAX_LPC_ORDER] */
+ short[] LTPCoef_Q14, /* I Long term prediction coefs [SilkConstants.LTP_ORDER * MAX_NB_SUBFR] */
+ short[] AR2_Q13, /* I Noise shaping coefs [MAX_NB_SUBFR * SilkConstants.MAX_SHAPE_LPC_ORDER] */
+ int[] HarmShapeGain_Q14, /* I Long term shaping coefs [MAX_NB_SUBFR] */
+ int[] Tilt_Q14, /* I Spectral tilt [MAX_NB_SUBFR] */
+ int[] LF_shp_Q14, /* I Low frequency shaping coefs [MAX_NB_SUBFR] */
+ int[] Gains_Q16, /* I Quantization step sizes [MAX_NB_SUBFR] */
+ int[] pitchL, /* I Pitch lags [MAX_NB_SUBFR] */
+ int Lambda_Q10, /* I Rate/distortion tradeoff */
+ int LTP_scale_Q14 /* I LTP state scaling */
+ ) {
+ int k, lag, start_idx, LSF_interpolation_flag;
+ int A_Q12, B_Q14, AR_shp_Q13;
+ int pxq;
+ int[] sLTP_Q15;
+ short[] sLTP;
+ int HarmShapeFIRPacked_Q14;
+ int offset_Q10;
+ int[] x_sc_Q10;
+ int pulses_ptr = 0;
+ int x_Q3_ptr = 0;
+
+ this.rand_seed = psIndices.Seed;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = this.lagPrev;
+
+ Inlines.OpusAssert(this.prev_gain_Q16 != 0);
+
+ offset_Q10 = SilkTables.silk_Quantization_Offsets_Q10[psIndices.signalType >> 1][psIndices.quantOffsetType];
+
+ if (psIndices.NLSFInterpCoef_Q2 == 4) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ sLTP_Q15 = new int[psEncC.ltp_mem_length + psEncC.frame_length];
+ sLTP = new short[psEncC.ltp_mem_length + psEncC.frame_length];
+ x_sc_Q10 = new int[psEncC.subfr_length];
+ /* Set up pointers to start of sub frame */
+ this.sLTP_shp_buf_idx = psEncC.ltp_mem_length;
+ this.sLTP_buf_idx = psEncC.ltp_mem_length;
+ pxq = psEncC.ltp_mem_length;
+ for (k = 0; k < psEncC.nb_subfr; k++) {
+ A_Q12 = (((k >> 1) | (1 - LSF_interpolation_flag)));
+ B_Q14 = (k * SilkConstants.LTP_ORDER); // opt: does this indicate a partitioned array?
+ AR_shp_Q13 = (k * SilkConstants.MAX_SHAPE_LPC_ORDER); // opt: same here
+
+ /* Noise shape parameters */
+ Inlines.OpusAssert(HarmShapeGain_Q14[k] >= 0);
+ HarmShapeFIRPacked_Q14 = Inlines.silk_RSHIFT(HarmShapeGain_Q14[k], 2);
+ HarmShapeFIRPacked_Q14 |= Inlines.silk_LSHIFT((int) Inlines.silk_RSHIFT(HarmShapeGain_Q14[k], 1), 16);
+
+ this.rewhite_flag = 0;
+ if (psIndices.signalType == SilkConstants.TYPE_VOICED) {
+ /* Voiced */
+ lag = pitchL[k];
+
+ /* Re-whitening */
+ if ((k & (3 - Inlines.silk_LSHIFT(LSF_interpolation_flag, 1))) == 0) {
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC.ltp_mem_length - lag - psEncC.predictLPCOrder - SilkConstants.LTP_ORDER / 2;
+ Inlines.OpusAssert(start_idx > 0);
+
+ Filters.silk_LPC_analysis_filter(sLTP, start_idx, this.xq, start_idx + k * psEncC.subfr_length,
+ PredCoef_Q12[A_Q12], 0, psEncC.ltp_mem_length - start_idx, psEncC.predictLPCOrder);
+
+ this.rewhite_flag = 1;
+ this.sLTP_buf_idx = psEncC.ltp_mem_length;
+ }
+ }
+
+ silk_nsq_scale_states(psEncC, x_Q3, x_Q3_ptr, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices.signalType);
+
+ silk_noise_shape_quantizer(
+ psIndices.signalType,
+ x_sc_Q10,
+ pulses,
+ pulses_ptr,
+ this.xq,
+ pxq,
+ sLTP_Q15,
+ PredCoef_Q12[A_Q12],
+ LTPCoef_Q14,
+ B_Q14,
+ AR2_Q13,
+ AR_shp_Q13,
+ lag,
+ HarmShapeFIRPacked_Q14,
+ Tilt_Q14[k],
+ LF_shp_Q14[k],
+ Gains_Q16[k],
+ Lambda_Q10,
+ offset_Q10,
+ psEncC.subfr_length,
+ psEncC.shapingLPCOrder,
+ psEncC.predictLPCOrder);
+
+ x_Q3_ptr += psEncC.subfr_length;
+ pulses_ptr += psEncC.subfr_length;
+ pxq += psEncC.subfr_length;
+ }
+
+ /* Update lagPrev for next frame */
+ this.lagPrev = pitchL[psEncC.nb_subfr - 1];
+
+ /* Save quantized speech and noise shaping signals */
+ Arrays.MemMove(this.xq, psEncC.frame_length, 0, psEncC.ltp_mem_length);
+ Arrays.MemMove(this.sLTP_shp_Q14, psEncC.frame_length, 0, psEncC.ltp_mem_length);
+ }
+
+ /**
+ * ********************************
+ */
+ /* silk_noise_shape_quantizer */
+ /**
+ * ********************************
+ */
+ private void silk_noise_shape_quantizer(
+ int signalType, /* I Signal type */
+ int[] x_sc_Q10, /* I [length] */
+ byte[] pulses, /* O [length] */
+ int pulses_ptr,
+ short[] xq, /* O [length] */
+ int xq_ptr,
+ int[] sLTP_Q15, /* I/O LTP state */
+ short[] a_Q12, /* I Short term prediction coefs */
+ short[] b_Q14, /* I Long term prediction coefs */
+ int b_Q14_ptr,
+ short[] AR_shp_Q13, /* I Noise shaping AR coefs */
+ int AR_shp_Q13_ptr,
+ int lag, /* I Pitch lag */
+ int HarmShapeFIRPacked_Q14, /* I */
+ int Tilt_Q14, /* I Spectral tilt */
+ int LF_shp_Q14, /* I */
+ int Gain_Q16, /* I */
+ int Lambda_Q10, /* I */
+ int offset_Q10, /* I */
+ int length, /* I Input length */
+ int shapingLPCOrder, /* I Noise shaping AR filter order */
+ int predictLPCOrder /* I Prediction filter order */
+ ) {
+ int i, j;
+ int LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
+ int n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
+ int exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ int tmp1, tmp2, sLF_AR_shp_Q14;
+ int psLPC_Q14;
+ int shp_lag_ptr;
+ int pred_lag_ptr;
+
+ shp_lag_ptr = this.sLTP_shp_buf_idx - lag + SilkConstants.HARM_SHAPE_FIR_TAPS / 2;
+ pred_lag_ptr = this.sLTP_buf_idx - lag + SilkConstants.LTP_ORDER / 2;
+ Gain_Q10 = Inlines.silk_RSHIFT(Gain_Q16, 6);
+
+ /* Set up short term AR state */
+ psLPC_Q14 = SilkConstants.NSQ_LPC_BUF_LENGTH - 1;
+
+ for (i = 0; i < length; i++) {
+ /* Generate dither */
+ this.rand_seed = Inlines.silk_RAND(this.rand_seed);
+
+ /* Short-term prediction */
+ Inlines.OpusAssert(predictLPCOrder == 10 || predictLPCOrder == 16);
+ /* Avoids introducing a bias because Inlines.silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q10 = Inlines.silk_RSHIFT(predictLPCOrder, 1);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 0], a_Q12[0]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 1], a_Q12[1]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 2], a_Q12[2]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 3], a_Q12[3]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 4], a_Q12[4]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 5], a_Q12[5]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 6], a_Q12[6]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 7], a_Q12[7]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 8], a_Q12[8]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 9], a_Q12[9]);
+ if (predictLPCOrder == 16) {
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 10], a_Q12[10]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 11], a_Q12[11]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 12], a_Q12[12]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 13], a_Q12[13]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 14], a_Q12[14]);
+ LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 15], a_Q12[15]);
+ }
+
+ /* Long-term prediction */
+ if (signalType == SilkConstants.TYPE_VOICED) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because Inlines.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;
+ } else {
+ LTP_pred_Q13 = 0;
+ }
+
+ /* Noise shape feedback */
+ Inlines.OpusAssert((shapingLPCOrder & 1) == 0);
+ /* check that order is even */
+ tmp2 = this.sLPC_Q14[psLPC_Q14];
+ tmp1 = this.sAR2_Q14[0];
+ this.sAR2_Q14[0] = tmp2;
+ n_AR_Q12 = Inlines.silk_RSHIFT(shapingLPCOrder, 1);
+ n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, tmp2, AR_shp_Q13[AR_shp_Q13_ptr]);
+ for (j = 2; j < shapingLPCOrder; j += 2) {
+ tmp2 = this.sAR2_Q14[j - 1];
+ this.sAR2_Q14[j - 1] = tmp1;
+ n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, tmp1, AR_shp_Q13[AR_shp_Q13_ptr + j - 1]);
+ tmp1 = this.sAR2_Q14[j + 0];
+ this.sAR2_Q14[j + 0] = tmp2;
+ n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, tmp2, AR_shp_Q13[AR_shp_Q13_ptr + j]);
+ }
+ this.sAR2_Q14[shapingLPCOrder - 1] = tmp1;
+ n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, tmp1, AR_shp_Q13[AR_shp_Q13_ptr + shapingLPCOrder - 1]);
+
+ n_AR_Q12 = Inlines.silk_LSHIFT32(n_AR_Q12, 1);
+ /* Q11 . Q12 */
+ n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, this.sLF_AR_shp_Q14, Tilt_Q14);
+
+ n_LF_Q12 = Inlines.silk_SMULWB(this.sLTP_shp_Q14[this.sLTP_shp_buf_idx - 1], LF_shp_Q14);
+ n_LF_Q12 = Inlines.silk_SMLAWT(n_LF_Q12, this.sLF_AR_shp_Q14, LF_shp_Q14);
+
+ Inlines.OpusAssert(lag > 0 || signalType != SilkConstants.TYPE_VOICED);
+
+ /* Combine prediction and noise shaping signals */
+ tmp1 = Inlines.silk_SUB32(Inlines.silk_LSHIFT32(LPC_pred_Q10, 2), n_AR_Q12);
+ /* Q12 */
+ tmp1 = Inlines.silk_SUB32(tmp1, n_LF_Q12);
+ /* Q12 */
+ if (lag > 0) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q13 = Inlines.silk_SMULWB(Inlines.silk_ADD32(this.sLTP_shp_Q14[shp_lag_ptr], this.sLTP_shp_Q14[shp_lag_ptr - 2]), HarmShapeFIRPacked_Q14);
+ n_LTP_Q13 = Inlines.silk_SMLAWT(n_LTP_Q13, this.sLTP_shp_Q14[shp_lag_ptr - 1], HarmShapeFIRPacked_Q14);
+ n_LTP_Q13 = Inlines.silk_LSHIFT(n_LTP_Q13, 1);
+ shp_lag_ptr += 1;
+
+ tmp2 = Inlines.silk_SUB32(LTP_pred_Q13, n_LTP_Q13);
+ /* Q13 */
+ tmp1 = Inlines.silk_ADD_LSHIFT32(tmp2, tmp1, 1);
+ /* Q13 */
+ tmp1 = Inlines.silk_RSHIFT_ROUND(tmp1, 3);
+ /* Q10 */
+ } else {
+ tmp1 = Inlines.silk_RSHIFT_ROUND(tmp1, 2);
+ /* Q10 */
+ }
+
+ r_Q10 = Inlines.silk_SUB32(x_sc_Q10[i], tmp1);
+ /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if (this.rand_seed < 0) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = Inlines.silk_LIMIT_32(r_Q10, -(31 << 10), 30 << 10);
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = Inlines.silk_SUB32(r_Q10, offset_Q10);
+ q1_Q0 = Inlines.silk_RSHIFT(q1_Q10, 10);
+ if (q1_Q0 > 0) {
+ q1_Q10 = Inlines.silk_SUB32(Inlines.silk_LSHIFT(q1_Q0, 10), SilkConstants.QUANT_LEVEL_ADJUST_Q10);
+ q1_Q10 = Inlines.silk_ADD32(q1_Q10, offset_Q10);
+ q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024);
+ rd1_Q20 = Inlines.silk_SMULBB(q1_Q10, Lambda_Q10);
+ rd2_Q20 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10);
+ } else if (q1_Q0 == 0) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024 - SilkConstants.QUANT_LEVEL_ADJUST_Q10);
+ rd1_Q20 = Inlines.silk_SMULBB(q1_Q10, Lambda_Q10);
+ rd2_Q20 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10);
+ } else if (q1_Q0 == -1) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = Inlines.silk_SUB32(q2_Q10, 1024 - SilkConstants.QUANT_LEVEL_ADJUST_Q10);
+ rd1_Q20 = Inlines.silk_SMULBB(-q1_Q10, Lambda_Q10);
+ rd2_Q20 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10);
+ } else {
+ /* Q1_Q0 < -1 */
+ q1_Q10 = Inlines.silk_ADD32(Inlines.silk_LSHIFT(q1_Q0, 10), SilkConstants.QUANT_LEVEL_ADJUST_Q10);
+ q1_Q10 = Inlines.silk_ADD32(q1_Q10, offset_Q10);
+ q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024);
+ rd1_Q20 = Inlines.silk_SMULBB(-q1_Q10, Lambda_Q10);
+ rd2_Q20 = Inlines.silk_SMULBB(-q2_Q10, Lambda_Q10);
+ }
+ rr_Q10 = Inlines.silk_SUB32(r_Q10, q1_Q10);
+ rd1_Q20 = Inlines.silk_SMLABB(rd1_Q20, rr_Q10, rr_Q10);
+ rr_Q10 = Inlines.silk_SUB32(r_Q10, q2_Q10);
+ rd2_Q20 = Inlines.silk_SMLABB(rd2_Q20, rr_Q10, rr_Q10);
+
+ if (rd2_Q20 < rd1_Q20) {
+ q1_Q10 = q2_Q10;
+ }
+
+ pulses[pulses_ptr + i] = (byte) Inlines.silk_RSHIFT_ROUND(q1_Q10, 10);
+
+ /* Excitation */
+ exc_Q14 = Inlines.silk_LSHIFT(q1_Q10, 4);
+ if (this.rand_seed < 0) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = Inlines.silk_ADD_LSHIFT32(exc_Q14, LTP_pred_Q13, 1);
+ xq_Q14 = Inlines.silk_ADD_LSHIFT32(LPC_exc_Q14, LPC_pred_Q10, 4);
+
+ /* Scale XQ back to normal level before saving */
+ xq[xq_ptr + i] = (short) Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(xq_Q14, Gain_Q10), 8));
+
+ /* Update states */
+ psLPC_Q14 += 1;
+ this.sLPC_Q14[psLPC_Q14] = xq_Q14;
+ sLF_AR_shp_Q14 = Inlines.silk_SUB_LSHIFT32(xq_Q14, n_AR_Q12, 2);
+ this.sLF_AR_shp_Q14 = sLF_AR_shp_Q14;
+
+ this.sLTP_shp_Q14[this.sLTP_shp_buf_idx] = Inlines.silk_SUB_LSHIFT32(sLF_AR_shp_Q14, n_LF_Q12, 2);
+ sLTP_Q15[this.sLTP_buf_idx] = Inlines.silk_LSHIFT(LPC_exc_Q14, 1);
+ this.sLTP_shp_buf_idx++;
+ this.sLTP_buf_idx++;
+
+ /* Make dither dependent on quantized signal */
+ this.rand_seed = Inlines.silk_ADD32_ovflw(this.rand_seed, pulses[pulses_ptr + i]);
+ }
+
+ /* Update LPC synth buffer */
+ System.arraycopy(this.sLPC_Q14, length, this.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH);
+ }
+
+ private void silk_nsq_scale_states(
+ SilkChannelEncoder psEncC, /* I Encoder State */
+ int[] x_Q3, /* I input in Q3 */
+ int x_Q3_ptr,
+ int[] x_sc_Q10, /* O input scaled with 1/Gain */
+ short[] sLTP, /* I re-whitened LTP state in Q0 */
+ int[] sLTP_Q15, /* O LTP state matching scaled input */
+ int subfr, /* I subframe number */
+ int LTP_scale_Q14, /* I */
+ int[] Gains_Q16, /* I [MAX_NB_SUBFR] */
+ int[] pitchL, /* I Pitch lag [MAX_NB_SUBFR] */
+ int signal_type /* I Signal type */
+ ) {
+ int i, lag;
+ int gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+
+ lag = pitchL[subfr];
+ inv_gain_Q31 = Inlines.silk_INVERSE32_varQ(Inlines.silk_max(Gains_Q16[subfr], 1), 47);
+ Inlines.OpusAssert(inv_gain_Q31 != 0);
+
+ /* Calculate gain adjustment factor */
+ if (Gains_Q16[subfr] != this.prev_gain_Q16) {
+ gain_adj_Q16 = Inlines.silk_DIV32_varQ(this.prev_gain_Q16, Gains_Q16[subfr], 16);
+ } else {
+ gain_adj_Q16 = (int) 1 << 16;
+ }
+
+ /* Scale input */
+ inv_gain_Q23 = Inlines.silk_RSHIFT_ROUND(inv_gain_Q31, 8);
+ for (i = 0; i < psEncC.subfr_length; i++) {
+ x_sc_Q10[i] = Inlines.silk_SMULWW(x_Q3[x_Q3_ptr + i], inv_gain_Q23);
+ }
+
+ /* Save inverse gain */
+ this.prev_gain_Q16 = Gains_Q16[subfr];
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if (this.rewhite_flag != 0) {
+ if (subfr == 0) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(inv_gain_Q31, LTP_scale_Q14), 2);
+ }
+ for (i = this.sLTP_buf_idx - lag - SilkConstants.LTP_ORDER / 2; i < this.sLTP_buf_idx; i++) {
+ Inlines.OpusAssert(i < SilkConstants.MAX_FRAME_LENGTH);
+ sLTP_Q15[i] = Inlines.silk_SMULWB(inv_gain_Q31, sLTP[i]);
+ }
+ }
+
+ /* Adjust for changing gain */
+ if (gain_adj_Q16 != (int) 1 << 16) {
+ /* Scale long-term shaping state */
+ for (i = this.sLTP_shp_buf_idx - psEncC.ltp_mem_length; i < this.sLTP_shp_buf_idx; i++) {
+ this.sLTP_shp_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, this.sLTP_shp_Q14[i]);
+ }
+
+ /* Scale long-term prediction state */
+ if (signal_type == SilkConstants.TYPE_VOICED && this.rewhite_flag == 0) {
+ for (i = this.sLTP_buf_idx - lag - SilkConstants.LTP_ORDER / 2; i < this.sLTP_buf_idx; i++) {
+ sLTP_Q15[i] = Inlines.silk_SMULWW(gain_adj_Q16, sLTP_Q15[i]);
+ }
+ }
+
+ this.sLF_AR_shp_Q14 = Inlines.silk_SMULWW(gain_adj_Q16, this.sLF_AR_shp_Q14);
+
+ /* Scale short-term prediction and shaping states */
+ for (i = 0; i < SilkConstants.NSQ_LPC_BUF_LENGTH; i++) {
+ this.sLPC_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, this.sLPC_Q14[i]);
+ }
+ for (i = 0; i < SilkConstants.MAX_SHAPE_LPC_ORDER; i++) {
+ this.sAR2_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, this.sAR2_Q14[i]);
+ }
+ }
+ }
+
+ void silk_NSQ_del_dec(
+ SilkChannelEncoder psEncC, /* I Encoder State */
+ SideInfoIndices psIndices, /* I/O Quantization Indices */
+ int[] x_Q3, /* I Prefiltered input signal */
+ byte[] pulses, /* O Quantized pulse signal */
+ short[][] PredCoef_Q12, /* I Short term prediction coefs [2 * MAX_LPC_ORDER] */
+ short[] LTPCoef_Q14, /* I Long term prediction coefs LTP_ORDER * MAX_NB_SUBFR] */
+ short[] AR2_Q13, /* I Noise shaping coefs [MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER] */
+ int[] HarmShapeGain_Q14, /* I Long term shaping coefs [MAX_NB_SUBFR] */
+ int[] Tilt_Q14, /* I Spectral tilt [MAX_NB_SUBFR] */
+ int[] LF_shp_Q14, /* I Low frequency shaping coefs [MAX_NB_SUBFR] */
+ int[] Gains_Q16, /* I Quantization step sizes [MAX_NB_SUBFR] */
+ int[] pitchL, /* I Pitch lags [MAX_NB_SUBFR] */
+ int Lambda_Q10, /* I Rate/distortion tradeoff */
+ int LTP_scale_Q14 /* I LTP state scaling */
+ ) {
+ int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr;
+ int last_smple_idx, smpl_buf_idx, decisionDelay;
+ int A_Q12;
+ int pulses_ptr = 0;
+ int pxq;
+ int[] sLTP_Q15;
+ short[] sLTP;
+ int HarmShapeFIRPacked_Q14;
+ int offset_Q10;
+ int RDmin_Q10, Gain_Q10;
+ int[] x_sc_Q10;
+ int[] delayedGain_Q10;
+ int x_Q3_ptr = 0;
+ NSQ_del_dec_struct[] psDelDec;
+ NSQ_del_dec_struct psDD;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = this.lagPrev;
+
+ Inlines.OpusAssert(this.prev_gain_Q16 != 0);
+
+ /* Initialize delayed decision states */
+ psDelDec = new NSQ_del_dec_struct[psEncC.nStatesDelayedDecision];
+ for (int c = 0; c < psEncC.nStatesDelayedDecision; c++) {
+ psDelDec[c] = new NSQ_del_dec_struct(psEncC.shapingLPCOrder);
+ }
+
+ for (k = 0; k < psEncC.nStatesDelayedDecision; k++) {
+ psDD = psDelDec[k];
+ psDD.Seed = (k + psIndices.Seed) & 3;
+ psDD.SeedInit = psDD.Seed;
+ psDD.RD_Q10 = 0;
+ psDD.LF_AR_Q14 = this.sLF_AR_shp_Q14;
+ psDD.Shape_Q14[0] = this.sLTP_shp_Q14[psEncC.ltp_mem_length - 1];
+ System.arraycopy(this.sLPC_Q14, 0, psDD.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH);
+ System.arraycopy(this.sAR2_Q14, 0, psDD.sAR2_Q14, 0, psEncC.shapingLPCOrder);
+ }
+
+ offset_Q10 = SilkTables.silk_Quantization_Offsets_Q10[psIndices.signalType >> 1][psIndices.quantOffsetType];
+ smpl_buf_idx = 0;
+ /* index of oldest samples */
+
+ decisionDelay = Inlines.silk_min_int(SilkConstants.DECISION_DELAY, psEncC.subfr_length);
+
+ /* For voiced frames limit the decision delay to lower than the pitch lag */
+ if (psIndices.signalType == SilkConstants.TYPE_VOICED) {
+ for (k = 0; k < psEncC.nb_subfr; k++) {
+ decisionDelay = Inlines.silk_min_int(decisionDelay, pitchL[k] - SilkConstants.LTP_ORDER / 2 - 1);
+ }
+ } else if (lag > 0) {
+ decisionDelay = Inlines.silk_min_int(decisionDelay, lag - SilkConstants.LTP_ORDER / 2 - 1);
+ }
+
+ if (psIndices.NLSFInterpCoef_Q2 == 4) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ sLTP_Q15 = new int[psEncC.ltp_mem_length + psEncC.frame_length];
+ sLTP = new short[psEncC.ltp_mem_length + psEncC.frame_length];
+ x_sc_Q10 = new int[psEncC.subfr_length];
+ delayedGain_Q10 = new int[SilkConstants.DECISION_DELAY];
+
+ /* Set up pointers to start of sub frame */
+ pxq = psEncC.ltp_mem_length;
+ this.sLTP_shp_buf_idx = psEncC.ltp_mem_length;
+ this.sLTP_buf_idx = psEncC.ltp_mem_length;
+ subfr = 0;
+ for (k = 0; k < psEncC.nb_subfr; k++) {
+ A_Q12 = (((k >> 1) | (1 - LSF_interpolation_flag)));
+
+ /* Noise shape parameters */
+ Inlines.OpusAssert(HarmShapeGain_Q14[k] >= 0);
+ HarmShapeFIRPacked_Q14 = Inlines.silk_RSHIFT(HarmShapeGain_Q14[k], 2);
+ HarmShapeFIRPacked_Q14 |= Inlines.silk_LSHIFT((int) Inlines.silk_RSHIFT(HarmShapeGain_Q14[k], 1), 16);
+
+ this.rewhite_flag = 0;
+ if (psIndices.signalType == SilkConstants.TYPE_VOICED) {
+ /* Voiced */
+ lag = pitchL[k];
+
+ /* Re-whitening */
+ if ((k & (3 - Inlines.silk_LSHIFT(LSF_interpolation_flag, 1))) == 0) {
+ if (k == 2) {
+ /* RESET DELAYED DECISIONS */
+ /* Find winner */
+ RDmin_Q10 = psDelDec[0].RD_Q10;
+ Winner_ind = 0;
+ for (i = 1; i < psEncC.nStatesDelayedDecision; i++) {
+ if (psDelDec[i].RD_Q10 < RDmin_Q10) {
+ RDmin_Q10 = psDelDec[i].RD_Q10;
+ Winner_ind = i;
+ }
+ }
+ for (i = 0; i < psEncC.nStatesDelayedDecision; i++) {
+ if (i != Winner_ind) {
+ psDelDec[i].RD_Q10 += (Integer.MAX_VALUE >> 4);
+ Inlines.OpusAssert(psDelDec[i].RD_Q10 >= 0);
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = psDelDec[Winner_ind];
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ for (i = 0; i < decisionDelay; i++) {
+ last_smple_idx = (last_smple_idx - 1) & SilkConstants.DECISION_DELAY_MASK;
+ pulses[pulses_ptr + i - decisionDelay] = (byte) Inlines.silk_RSHIFT_ROUND(psDD.Q_Q10[last_smple_idx], 10);
+ this.xq[pxq + i - decisionDelay] = (short) Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(
+ Inlines.silk_SMULWW(psDD.Xq_Q14[last_smple_idx], Gains_Q16[1]), 14));
+ this.sLTP_shp_Q14[this.sLTP_shp_buf_idx - decisionDelay + i] = psDD.Shape_Q14[last_smple_idx];
+ }
+
+ subfr = 0;
+ }
+
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC.ltp_mem_length - lag - psEncC.predictLPCOrder - SilkConstants.LTP_ORDER / 2;
+ Inlines.OpusAssert(start_idx > 0);
+
+ Filters.silk_LPC_analysis_filter(sLTP, start_idx, this.xq, start_idx + k * psEncC.subfr_length,
+ PredCoef_Q12[A_Q12], 0, psEncC.ltp_mem_length - start_idx, psEncC.predictLPCOrder);
+
+ this.sLTP_buf_idx = psEncC.ltp_mem_length;
+ this.rewhite_flag = 1;
+ }
+ }
+
+ silk_nsq_del_dec_scale_states(
+ psEncC,
+ psDelDec,
+ x_Q3,
+ x_Q3_ptr,
+ x_sc_Q10,
+ sLTP,
+ sLTP_Q15,
+ k,
+ psEncC.nStatesDelayedDecision,
+ LTP_scale_Q14,
+ Gains_Q16,
+ pitchL,
+ psIndices.signalType,
+ decisionDelay);
+
+ BoxedValueInt smpl_buf_idx_boxed = new BoxedValueInt(smpl_buf_idx);
+ silk_noise_shape_quantizer_del_dec(
+ psDelDec,
+ psIndices.signalType,
+ x_sc_Q10,
+ pulses,
+ pulses_ptr,
+ this.xq,
+ pxq,
+ sLTP_Q15,
+ delayedGain_Q10,
+ PredCoef_Q12[A_Q12],
+ LTPCoef_Q14,
+ k * SilkConstants.LTP_ORDER,
+ AR2_Q13,
+ k * SilkConstants.MAX_SHAPE_LPC_ORDER,
+ lag,
+ HarmShapeFIRPacked_Q14,
+ Tilt_Q14[k],
+ LF_shp_Q14[k],
+ Gains_Q16[k],
+ Lambda_Q10,
+ offset_Q10,
+ psEncC.subfr_length,
+ subfr++,
+ psEncC.shapingLPCOrder,
+ psEncC.predictLPCOrder,
+ psEncC.warping_Q16,
+ psEncC.nStatesDelayedDecision,
+ smpl_buf_idx_boxed,
+ decisionDelay);
+ smpl_buf_idx = smpl_buf_idx_boxed.Val;
+
+ x_Q3_ptr += psEncC.subfr_length;
+ pulses_ptr += psEncC.subfr_length;
+ pxq += psEncC.subfr_length;
+ }
+
+ /* Find winner */
+ RDmin_Q10 = psDelDec[0].RD_Q10;
+ Winner_ind = 0;
+ for (k = 1; k < psEncC.nStatesDelayedDecision; k++) {
+ if (psDelDec[k].RD_Q10 < RDmin_Q10) {
+ RDmin_Q10 = psDelDec[k].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = psDelDec[Winner_ind];
+ psIndices.Seed = (byte) (psDD.SeedInit);
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ Gain_Q10 = Inlines.silk_RSHIFT32(Gains_Q16[psEncC.nb_subfr - 1], 6);
+ for (i = 0; i < decisionDelay; i++) {
+ last_smple_idx = (last_smple_idx - 1) & SilkConstants.DECISION_DELAY_MASK;
+ pulses[pulses_ptr + i - decisionDelay] = (byte) Inlines.silk_RSHIFT_ROUND(psDD.Q_Q10[last_smple_idx], 10);
+ this.xq[pxq + i - decisionDelay] = (short) Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(
+ Inlines.silk_SMULWW(psDD.Xq_Q14[last_smple_idx], Gain_Q10), 8));
+ this.sLTP_shp_Q14[this.sLTP_shp_buf_idx - decisionDelay + i] = psDD.Shape_Q14[last_smple_idx];
+ }
+ System.arraycopy(psDD.sLPC_Q14, psEncC.subfr_length, this.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH);
+ System.arraycopy(psDD.sAR2_Q14, 0, this.sAR2_Q14, 0, psEncC.shapingLPCOrder);
+
+ /* Update states */
+ this.sLF_AR_shp_Q14 = psDD.LF_AR_Q14;
+ this.lagPrev = pitchL[psEncC.nb_subfr - 1];
+
+ /* Save quantized speech signal */
+ Arrays.MemMove(this.xq, psEncC.frame_length, 0, psEncC.ltp_mem_length);
+ Arrays.MemMove(this.sLTP_shp_Q14, psEncC.frame_length, 0, psEncC.ltp_mem_length);
+ }
+
+ /**
+ * ***************************************
+ */
+ /* Noise shape quantizer for one subframe */
+ /**
+ * ***************************************
+ */
+ private void silk_noise_shape_quantizer_del_dec(
+ NSQ_del_dec_struct[] psDelDec, /* I/O Delayed decision states */
+ int signalType, /* I Signal type */
+ int[] x_Q10, /* I */
+ byte[] pulses, /* O */
+ int pulses_ptr,
+ short[] xq, /* O */
+ int xq_ptr,
+ int[] sLTP_Q15, /* I/O LTP filter state */
+ int[] delayedGain_Q10, /* I/O Gain delay buffer */
+ short[] a_Q12, /* I Short term prediction coefs */
+ short[] b_Q14, /* I Long term prediction coefs */
+ int b_Q14_ptr,
+ short[] AR_shp_Q13, /* I Noise shaping coefs */
+ int AR_shp_Q13_ptr,
+ int lag, /* I Pitch lag */
+ int HarmShapeFIRPacked_Q14, /* I */
+ int Tilt_Q14, /* I Spectral tilt */
+ int LF_shp_Q14, /* I */
+ int Gain_Q16, /* I */
+ int Lambda_Q10, /* I */
+ int offset_Q10, /* I */
+ int length, /* I Input length */
+ int subfr, /* I Subframe number */
+ int shapingLPCOrder, /* I Shaping LPC filter order */
+ int predictLPCOrder, /* I Prediction filter order */
+ int warping_Q16, /* I */
+ int nStatesDelayedDecision, /* I Number of states in decision tree */
+ BoxedValueInt smpl_buf_idx, /* I Index to newest samples in buffers */
+ int decisionDelay /* I */
+ ) {
+ int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
+ int Winner_rand_state;
+ int LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
+ int n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
+ int q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ int tmp1, tmp2, sLF_AR_shp_Q14;
+ int pred_lag_ptr, shp_lag_ptr, psLPC_Q14;
+ NSQ_sample_struct[] sampleStates;
+ NSQ_del_dec_struct psDD;
+ int SS_left;
+ int SS_right;
+
+ Inlines.OpusAssert(nStatesDelayedDecision > 0);
+ sampleStates = new NSQ_sample_struct[2 * nStatesDelayedDecision];
+ // [porting note] structs must be initialized manually here
+ for (int c = 0; c < 2 * nStatesDelayedDecision; c++) {
+ sampleStates[c] = new NSQ_sample_struct();
+ }
+
+ shp_lag_ptr = this.sLTP_shp_buf_idx - lag + SilkConstants.HARM_SHAPE_FIR_TAPS / 2;
+ pred_lag_ptr = this.sLTP_buf_idx - lag + SilkConstants.LTP_ORDER / 2;
+ Gain_Q10 = Inlines.silk_RSHIFT(Gain_Q16, 6);
+
+ for (i = 0; i < length; i++) {
+ /* Perform common calculations used in all states */
+
+ /* Long-term prediction */
+ if (signalType == SilkConstants.TYPE_VOICED) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because Inlines.silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q14 = 2;
+ LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr], b_Q14[b_Q14_ptr + 0]);
+ LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr - 1], b_Q14[b_Q14_ptr + 1]);
+ LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr - 2], b_Q14[b_Q14_ptr + 2]);
+ LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr - 3], b_Q14[b_Q14_ptr + 3]);
+ LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr - 4], b_Q14[b_Q14_ptr + 4]);
+ LTP_pred_Q14 = Inlines.silk_LSHIFT(LTP_pred_Q14, 1);
+ /* Q13 . Q14 */
+ pred_lag_ptr += 1;
+ } else {
+ LTP_pred_Q14 = 0;
+ }
+
+ /* Long-term shaping */
+ if (lag > 0) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q14 = Inlines.silk_SMULWB(Inlines.silk_ADD32(this.sLTP_shp_Q14[shp_lag_ptr], this.sLTP_shp_Q14[shp_lag_ptr - 2]), HarmShapeFIRPacked_Q14);
+ n_LTP_Q14 = Inlines.silk_SMLAWT(n_LTP_Q14, this.sLTP_shp_Q14[shp_lag_ptr - 1], HarmShapeFIRPacked_Q14);
+ n_LTP_Q14 = Inlines.silk_SUB_LSHIFT32(LTP_pred_Q14, n_LTP_Q14, 2);
+ /* Q12 . Q14 */
+ shp_lag_ptr += 1;
+ } else {
+ n_LTP_Q14 = 0;
+ }
+
+ for (k = 0; k < nStatesDelayedDecision; k++) {
+ /* Delayed decision state */
+ psDD = psDelDec[k];
+ int[] psDD_sAR2 = psDD.sAR2_Q14;
+
+ /* Sample state */
+ SS_left = 2 * k;
+ SS_right = SS_left + 1;
+
+ /* Generate dither */
+ psDD.Seed = Inlines.silk_RAND(psDD.Seed);
+
+ /* Pointer used in short term prediction and shaping */
+ psLPC_Q14 = SilkConstants.NSQ_LPC_BUF_LENGTH - 1 + i;
+ /* Short-term prediction */
+ Inlines.OpusAssert(predictLPCOrder == 10 || predictLPCOrder == 16);
+ /* Avoids introducing a bias because Inlines.silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q14 = Inlines.silk_RSHIFT(predictLPCOrder, 1);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14], a_Q12[0]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 1], a_Q12[1]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 2], a_Q12[2]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 3], a_Q12[3]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 4], a_Q12[4]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 5], a_Q12[5]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 6], a_Q12[6]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 7], a_Q12[7]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 8], a_Q12[8]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 9], a_Q12[9]);
+ if (predictLPCOrder == 16) {
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 10], a_Q12[10]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 11], a_Q12[11]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 12], a_Q12[12]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 13], a_Q12[13]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 14], a_Q12[14]);
+ LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 15], a_Q12[15]);
+ }
+ LPC_pred_Q14 = Inlines.silk_LSHIFT(LPC_pred_Q14, 4);
+ /* Q10 . Q14 */
+
+
+ /* Noise shape feedback */
+ Inlines.OpusAssert((shapingLPCOrder & 1) == 0);
+ /* check that order is even */
+ /* Output of lowpass section */
+ tmp2 = Inlines.silk_SMLAWB(psDD.sLPC_Q14[psLPC_Q14], psDD_sAR2[0], warping_Q16);
+ /* Output of allpass section */
+ tmp1 = Inlines.silk_SMLAWB(psDD_sAR2[0], psDD_sAR2[1] - tmp2, warping_Q16);
+ psDD_sAR2[0] = tmp2;
+ n_AR_Q14 = Inlines.silk_RSHIFT(shapingLPCOrder, 1);
+ n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, tmp2, AR_shp_Q13[AR_shp_Q13_ptr]);
+ /* Loop over allpass sections */
+ for (j = 2; j < shapingLPCOrder; j += 2) {
+ /* Output of allpass section */
+ tmp2 = Inlines.silk_SMLAWB(psDD_sAR2[j - 1], psDD_sAR2[j + 0] - tmp1, warping_Q16);
+ psDD_sAR2[j - 1] = tmp1;
+ n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, tmp1, AR_shp_Q13[AR_shp_Q13_ptr + j - 1]);
+ /* Output of allpass section */
+ tmp1 = Inlines.silk_SMLAWB(psDD_sAR2[j + 0], psDD_sAR2[j + 1] - tmp2, warping_Q16);
+ psDD_sAR2[j + 0] = tmp2;
+ n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, tmp2, AR_shp_Q13[AR_shp_Q13_ptr + j]);
+ }
+ psDD_sAR2[shapingLPCOrder - 1] = tmp1;
+ n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, tmp1, AR_shp_Q13[AR_shp_Q13_ptr + shapingLPCOrder - 1]);
+
+ n_AR_Q14 = Inlines.silk_LSHIFT(n_AR_Q14, 1);
+ /* Q11 . Q12 */
+ n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, psDD.LF_AR_Q14, Tilt_Q14);
+ /* Q12 */
+ n_AR_Q14 = Inlines.silk_LSHIFT(n_AR_Q14, 2);
+ /* Q12 . Q14 */
+
+ n_LF_Q14 = Inlines.silk_SMULWB(psDD.Shape_Q14[smpl_buf_idx.Val], LF_shp_Q14);
+ /* Q12 */
+ n_LF_Q14 = Inlines.silk_SMLAWT(n_LF_Q14, psDD.LF_AR_Q14, LF_shp_Q14);
+ /* Q12 */
+ n_LF_Q14 = Inlines.silk_LSHIFT(n_LF_Q14, 2);
+ /* Q12 . Q14 */
+
+ /* Input minus prediction plus noise feedback */
+ /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */
+ tmp1 = Inlines.silk_ADD32(n_AR_Q14, n_LF_Q14);
+ /* Q14 */
+ tmp2 = Inlines.silk_ADD32(n_LTP_Q14, LPC_pred_Q14);
+ /* Q13 */
+ tmp1 = Inlines.silk_SUB32(tmp2, tmp1);
+ /* Q13 */
+ tmp1 = Inlines.silk_RSHIFT_ROUND(tmp1, 4);
+ /* Q10 */
+
+ r_Q10 = Inlines.silk_SUB32(x_Q10[i], tmp1);
+ /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if (psDD.Seed < 0) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = Inlines.silk_LIMIT_32(r_Q10, -(31 << 10), 30 << 10);
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = Inlines.silk_SUB32(r_Q10, offset_Q10);
+ q1_Q0 = Inlines.silk_RSHIFT(q1_Q10, 10);
+ if (q1_Q0 > 0) {
+ q1_Q10 = Inlines.silk_SUB32(Inlines.silk_LSHIFT(q1_Q0, 10), SilkConstants.QUANT_LEVEL_ADJUST_Q10);
+ q1_Q10 = Inlines.silk_ADD32(q1_Q10, offset_Q10);
+ q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024);
+ rd1_Q10 = Inlines.silk_SMULBB(q1_Q10, Lambda_Q10);
+ rd2_Q10 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10);
+ } else if (q1_Q0 == 0) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024 - SilkConstants.QUANT_LEVEL_ADJUST_Q10);
+ rd1_Q10 = Inlines.silk_SMULBB(q1_Q10, Lambda_Q10);
+ rd2_Q10 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10);
+ } else if (q1_Q0 == -1) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = Inlines.silk_SUB32(q2_Q10, 1024 - SilkConstants.QUANT_LEVEL_ADJUST_Q10);
+ rd1_Q10 = Inlines.silk_SMULBB(-q1_Q10, Lambda_Q10);
+ rd2_Q10 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10);
+ } else {
+ /* q1_Q0 < -1 */
+ q1_Q10 = Inlines.silk_ADD32(Inlines.silk_LSHIFT(q1_Q0, 10), SilkConstants.QUANT_LEVEL_ADJUST_Q10);
+ q1_Q10 = Inlines.silk_ADD32(q1_Q10, offset_Q10);
+ q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024);
+ rd1_Q10 = Inlines.silk_SMULBB(-q1_Q10, Lambda_Q10);
+ rd2_Q10 = Inlines.silk_SMULBB(-q2_Q10, Lambda_Q10);
+ }
+ rr_Q10 = Inlines.silk_SUB32(r_Q10, q1_Q10);
+ rd1_Q10 = Inlines.silk_RSHIFT(Inlines.silk_SMLABB(rd1_Q10, rr_Q10, rr_Q10), 10);
+ rr_Q10 = Inlines.silk_SUB32(r_Q10, q2_Q10);
+ rd2_Q10 = Inlines.silk_RSHIFT(Inlines.silk_SMLABB(rd2_Q10, rr_Q10, rr_Q10), 10);
+
+ if (rd1_Q10 < rd2_Q10) {
+ sampleStates[SS_left].RD_Q10 = Inlines.silk_ADD32(psDD.RD_Q10, rd1_Q10);
+ sampleStates[SS_right].RD_Q10 = Inlines.silk_ADD32(psDD.RD_Q10, rd2_Q10);
+ sampleStates[SS_left].Q_Q10 = q1_Q10;
+ sampleStates[SS_right].Q_Q10 = q2_Q10;
+ } else {
+ sampleStates[SS_left].RD_Q10 = Inlines.silk_ADD32(psDD.RD_Q10, rd2_Q10);
+ sampleStates[SS_right].RD_Q10 = Inlines.silk_ADD32(psDD.RD_Q10, rd1_Q10);
+ sampleStates[SS_left].Q_Q10 = q2_Q10;
+ sampleStates[SS_right].Q_Q10 = q1_Q10;
+ }
+
+ /* Update states for best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = Inlines.silk_LSHIFT32(sampleStates[SS_left].Q_Q10, 4);
+ if (psDD.Seed < 0) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = Inlines.silk_ADD32(exc_Q14, LTP_pred_Q14);
+ xq_Q14 = Inlines.silk_ADD32(LPC_exc_Q14, LPC_pred_Q14);
+
+ /* Update states */
+ sLF_AR_shp_Q14 = Inlines.silk_SUB32(xq_Q14, n_AR_Q14);
+ sampleStates[SS_left].sLTP_shp_Q14 = Inlines.silk_SUB32(sLF_AR_shp_Q14, n_LF_Q14);
+ sampleStates[SS_left].LF_AR_Q14 = sLF_AR_shp_Q14;
+ sampleStates[SS_left].LPC_exc_Q14 = LPC_exc_Q14;
+ sampleStates[SS_left].xq_Q14 = xq_Q14;
+
+ /* Update states for second best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = Inlines.silk_LSHIFT32(sampleStates[SS_right].Q_Q10, 4);
+ if (psDD.Seed < 0) {
+ exc_Q14 = -exc_Q14;
+ }
+
+
+ /* Add predictions */
+ LPC_exc_Q14 = Inlines.silk_ADD32(exc_Q14, LTP_pred_Q14);
+ xq_Q14 = Inlines.silk_ADD32(LPC_exc_Q14, LPC_pred_Q14);
+
+ /* Update states */
+ sLF_AR_shp_Q14 = Inlines.silk_SUB32(xq_Q14, n_AR_Q14);
+ sampleStates[SS_right].sLTP_shp_Q14 = Inlines.silk_SUB32(sLF_AR_shp_Q14, n_LF_Q14);
+ sampleStates[SS_right].LF_AR_Q14 = sLF_AR_shp_Q14;
+ sampleStates[SS_right].LPC_exc_Q14 = LPC_exc_Q14;
+ sampleStates[SS_right].xq_Q14 = xq_Q14;
+ }
+
+ smpl_buf_idx.Val = (smpl_buf_idx.Val - 1) & SilkConstants.DECISION_DELAY_MASK;
+ /* Index to newest samples */
+ last_smple_idx = (smpl_buf_idx.Val + decisionDelay) & SilkConstants.DECISION_DELAY_MASK;
+ /* Index to decisionDelay old samples */
+
+ /* Find winner */
+ RDmin_Q10 = sampleStates[0].RD_Q10;
+ Winner_ind = 0;
+ for (k = 1; k < nStatesDelayedDecision; k++) {
+ if (sampleStates[k * 2].RD_Q10 < RDmin_Q10) {
+ RDmin_Q10 = sampleStates[k * 2].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Increase RD values of expired states */
+ Winner_rand_state = psDelDec[Winner_ind].RandState[last_smple_idx];
+ for (k = 0; k < nStatesDelayedDecision; k++) {
+ if (psDelDec[k].RandState[last_smple_idx] != Winner_rand_state) {
+ int k2 = k * 2;
+ sampleStates[k2].RD_Q10 = Inlines.silk_ADD32(sampleStates[k2].RD_Q10, Integer.MAX_VALUE >> 4);
+ sampleStates[k2 + 1].RD_Q10 = Inlines.silk_ADD32(sampleStates[k2 + 1].RD_Q10, Integer.MAX_VALUE >> 4);
+ Inlines.OpusAssert(sampleStates[k2].RD_Q10 >= 0);
+ }
+ }
+
+ /* Find worst in first set and best in second set */
+ RDmax_Q10 = sampleStates[0].RD_Q10;
+ RDmin_Q10 = sampleStates[1].RD_Q10;
+ RDmax_ind = 0;
+ RDmin_ind = 0;
+ for (k = 1; k < nStatesDelayedDecision; k++) {
+ int k2 = k * 2;
+ /* find worst in first set */
+ if (sampleStates[k2].RD_Q10 > RDmax_Q10) {
+ RDmax_Q10 = sampleStates[k2].RD_Q10;
+ RDmax_ind = k;
+ }
+ /* find best in second set */
+ if (sampleStates[k2 + 1].RD_Q10 < RDmin_Q10) {
+ RDmin_Q10 = sampleStates[k2 + 1].RD_Q10;
+ RDmin_ind = k;
+ }
+ }
+
+ /* Replace a state if best from second set outperforms worst in first set */
+ if (RDmin_Q10 < RDmax_Q10) {
+ psDelDec[RDmax_ind].PartialCopyFrom(psDelDec[RDmin_ind], i);
+ sampleStates[RDmax_ind * 2].Assign(sampleStates[RDmin_ind * 2 + 1]);
+ }
+
+ /* Write samples from winner to output and long-term filter states */
+ psDD = psDelDec[Winner_ind];
+ if (subfr > 0 || i >= decisionDelay) {
+ pulses[pulses_ptr + i - decisionDelay] = (byte) Inlines.silk_RSHIFT_ROUND(psDD.Q_Q10[last_smple_idx], 10);
+ xq[xq_ptr + i - decisionDelay] = (short) Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(
+ Inlines.silk_SMULWW(psDD.Xq_Q14[last_smple_idx], delayedGain_Q10[last_smple_idx]), 8));
+ this.sLTP_shp_Q14[this.sLTP_shp_buf_idx - decisionDelay] = psDD.Shape_Q14[last_smple_idx];
+ sLTP_Q15[this.sLTP_buf_idx - decisionDelay] = psDD.Pred_Q15[last_smple_idx];
+ }
+ this.sLTP_shp_buf_idx++;
+ this.sLTP_buf_idx++;
+
+ /* Update states */
+ for (k = 0; k < nStatesDelayedDecision; k++) {
+ psDD = psDelDec[k];
+ SS_left = k * 2;
+ psDD.LF_AR_Q14 = sampleStates[SS_left].LF_AR_Q14;
+ psDD.sLPC_Q14[SilkConstants.NSQ_LPC_BUF_LENGTH + i] = sampleStates[SS_left].xq_Q14;
+ psDD.Xq_Q14[smpl_buf_idx.Val] = sampleStates[SS_left].xq_Q14;
+ psDD.Q_Q10[smpl_buf_idx.Val] = sampleStates[SS_left].Q_Q10;
+ psDD.Pred_Q15[smpl_buf_idx.Val] = Inlines.silk_LSHIFT32(sampleStates[SS_left].LPC_exc_Q14, 1);
+ psDD.Shape_Q14[smpl_buf_idx.Val] = sampleStates[SS_left].sLTP_shp_Q14;
+ psDD.Seed = Inlines.silk_ADD32_ovflw(psDD.Seed, Inlines.silk_RSHIFT_ROUND(sampleStates[SS_left].Q_Q10, 10));
+ psDD.RandState[smpl_buf_idx.Val] = psDD.Seed;
+ psDD.RD_Q10 = sampleStates[SS_left].RD_Q10;
+ }
+ delayedGain_Q10[smpl_buf_idx.Val] = Gain_Q10;
+ }
+
+ /* Update LPC states */
+ for (k = 0; k < nStatesDelayedDecision; k++) {
+ psDD = psDelDec[k];
+ System.arraycopy(psDD.sLPC_Q14, length, psDD.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH);
+ }
+ }
+
+ private void silk_nsq_del_dec_scale_states(
+ SilkChannelEncoder psEncC, /* I Encoder State */
+ NSQ_del_dec_struct[] psDelDec, /* I/O Delayed decision states */
+ int[] x_Q3, /* I Input in Q3 */
+ int x_Q3_ptr,
+ int[] x_sc_Q10, /* O Input scaled with 1/Gain in Q10 */
+ short[] sLTP, /* I Re-whitened LTP state in Q0 */
+ int[] sLTP_Q15, /* O LTP state matching scaled input */
+ int subfr, /* I Subframe number */
+ int nStatesDelayedDecision, /* I Number of del dec states */
+ int LTP_scale_Q14, /* I LTP state scaling */
+ int[] Gains_Q16, /* I [MAX_NB_SUBFR] */
+ int[] pitchL, /* I Pitch lag [MAX_NB_SUBFR] */
+ int signal_type, /* I Signal type */
+ int decisionDelay /* I Decision delay */
+ ) {
+ int i, k, lag;
+ int gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+ NSQ_del_dec_struct psDD;
+
+ lag = pitchL[subfr];
+ inv_gain_Q31 = Inlines.silk_INVERSE32_varQ(Inlines.silk_max(Gains_Q16[subfr], 1), 47);
+ Inlines.OpusAssert(inv_gain_Q31 != 0);
+
+ /* Calculate gain adjustment factor */
+ if (Gains_Q16[subfr] != this.prev_gain_Q16) {
+ gain_adj_Q16 = Inlines.silk_DIV32_varQ(this.prev_gain_Q16, Gains_Q16[subfr], 16);
+ } else {
+ gain_adj_Q16 = (int) 1 << 16;
+ }
+
+ /* Scale input */
+ inv_gain_Q23 = Inlines.silk_RSHIFT_ROUND(inv_gain_Q31, 8);
+ for (i = 0; i < psEncC.subfr_length; i++) {
+ x_sc_Q10[i] = Inlines.silk_SMULWW(x_Q3[x_Q3_ptr + i], inv_gain_Q23);
+ }
+
+ /* Save inverse gain */
+ this.prev_gain_Q16 = Gains_Q16[subfr];
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if (this.rewhite_flag != 0) {
+ if (subfr == 0) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(inv_gain_Q31, LTP_scale_Q14), 2);
+ }
+ for (i = this.sLTP_buf_idx - lag - SilkConstants.LTP_ORDER / 2; i < this.sLTP_buf_idx; i++) {
+ Inlines.OpusAssert(i < SilkConstants.MAX_FRAME_LENGTH);
+ sLTP_Q15[i] = Inlines.silk_SMULWB(inv_gain_Q31, sLTP[i]);
+ }
+ }
+
+ /* Adjust for changing gain */
+ if (gain_adj_Q16 != (int) 1 << 16) {
+ /* Scale long-term shaping state */
+ for (i = this.sLTP_shp_buf_idx - psEncC.ltp_mem_length; i < this.sLTP_shp_buf_idx; i++) {
+ this.sLTP_shp_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, this.sLTP_shp_Q14[i]);
+ }
+
+ /* Scale long-term prediction state */
+ if (signal_type == SilkConstants.TYPE_VOICED && this.rewhite_flag == 0) {
+ for (i = this.sLTP_buf_idx - lag - SilkConstants.LTP_ORDER / 2; i < this.sLTP_buf_idx - decisionDelay; i++) {
+ sLTP_Q15[i] = Inlines.silk_SMULWW(gain_adj_Q16, sLTP_Q15[i]);
+ }
+ }
+
+ for (k = 0; k < nStatesDelayedDecision; k++) {
+ psDD = psDelDec[k];
+
+ /* Scale scalar states */
+ psDD.LF_AR_Q14 = Inlines.silk_SMULWW(gain_adj_Q16, psDD.LF_AR_Q14);
+
+ /* Scale short-term prediction and shaping states */
+ for (i = 0; i < SilkConstants.NSQ_LPC_BUF_LENGTH; i++) {
+ psDD.sLPC_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, psDD.sLPC_Q14[i]);
+ }
+ for (i = 0; i < psEncC.shapingLPCOrder; i++) {
+ psDD.sAR2_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, psDD.sAR2_Q14[i]);
+ }
+ for (i = 0; i < SilkConstants.DECISION_DELAY; i++) {
+ psDD.Pred_Q15[i] = Inlines.silk_SMULWW(gain_adj_Q16, psDD.Pred_Q15[i]);
+ psDD.Shape_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, psDD.Shape_Q14[i]);
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkPrefilterState.java b/app/src/main/java/org/concentus/SilkPrefilterState.java
new file mode 100644
index 0000000000..cff834ed8d
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkPrefilterState.java
@@ -0,0 +1,62 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Prefilter state
+///
+class SilkPrefilterState {
+
+ final short[] sLTP_shp = new short[SilkConstants.LTP_BUF_LENGTH];
+ final int[] sAR_shp = new int[SilkConstants.MAX_SHAPE_LPC_ORDER + 1];
+ int sLTP_shp_buf_idx = 0;
+ int sLF_AR_shp_Q12 = 0;
+ int sLF_MA_shp_Q12 = 0;
+ int sHarmHP_Q2 = 0;
+ int rand_seed = 0;
+ int lagPrev = 0;
+
+ SilkPrefilterState() {
+
+ }
+
+ void Reset() {
+ Arrays.MemSet(sLTP_shp, (short) 0, SilkConstants.LTP_BUF_LENGTH);
+ Arrays.MemSet(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;
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkResamplerState.java b/app/src/main/java/org/concentus/SilkResamplerState.java
new file mode 100644
index 0000000000..184352f6ba
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkResamplerState.java
@@ -0,0 +1,87 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class SilkResamplerState {
+
+ final int[] sIIR = new int[SilkConstants.SILK_RESAMPLER_MAX_IIR_ORDER];
+ /* this must be the first element of this struct FIXME why? */
+ final 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.
+ final short[] sFIR_i16 = new short[SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER];
+
+ final short[] delayBuf = new short[48];
+ int resampler_function = 0;
+ int batchSize = 0;
+ int invRatio_Q16 = 0;
+ int FIR_Order = 0;
+ int FIR_Fracs = 0;
+ int Fs_in_kHz = 0;
+ int Fs_out_kHz = 0;
+ int inputDelay = 0;
+
+ ///
+ /// POINTER
+ ///
+ short[] Coefs = null;
+
+ void Reset() {
+ Arrays.MemSet(sIIR, 0, SilkConstants.SILK_RESAMPLER_MAX_IIR_ORDER);
+ Arrays.MemSet(sFIR_i32, 0, SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER);
+ Arrays.MemSet(sFIR_i16, (short) 0, SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER);
+ Arrays.MemSet(delayBuf, (short) 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;
+ }
+
+ 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;
+ System.arraycopy(other.sIIR, 0, this.sIIR, 0, SilkConstants.SILK_RESAMPLER_MAX_IIR_ORDER);
+ System.arraycopy(other.sFIR_i32, 0, this.sFIR_i32, 0, SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER);
+ System.arraycopy(other.sFIR_i16, 0, this.sFIR_i16, 0, SilkConstants.SILK_RESAMPLER_MAX_FIR_ORDER);
+ System.arraycopy(other.delayBuf, 0, this.delayBuf, 0, 48);
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkShapeState.java b/app/src/main/java/org/concentus/SilkShapeState.java
new file mode 100644
index 0000000000..e5f08c90da
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkShapeState.java
@@ -0,0 +1,50 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Noise shaping analysis state
+///
+class SilkShapeState {
+
+ byte LastGainIndex = 0;
+ int HarmBoost_smth_Q16 = 0;
+ int HarmShapeGain_smth_Q16 = 0;
+ int Tilt_smth_Q16 = 0;
+
+ void Reset() {
+ LastGainIndex = 0;
+ HarmBoost_smth_Q16 = 0;
+ HarmShapeGain_smth_Q16 = 0;
+ Tilt_smth_Q16 = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/SilkTables.java b/app/src/main/java/org/concentus/SilkTables.java
new file mode 100644
index 0000000000..4ebe46804a
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkTables.java
@@ -0,0 +1,1050 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class SilkTables {
+
+ ///
+ /// Cosine approximation table for LSF conversion
+ /// Q12 values (even)
+ ///
+ static final short[] silk_LSFCosTab_Q12 = {
+ 8192, 8190, 8182, 8170,
+ 8152, 8130, 8104, 8072,
+ 8034, 7994, 7946, 7896,
+ 7840, 7778, 7714, 7644,
+ 7568, 7490, 7406, 7318,
+ 7226, 7128, 7026, 6922,
+ 6812, 6698, 6580, 6458,
+ 6332, 6204, 6070, 5934,
+ 5792, 5648, 5502, 5352,
+ 5198, 5040, 4880, 4718,
+ 4552, 4382, 4212, 4038,
+ 3862, 3684, 3502, 3320,
+ 3136, 2948, 2760, 2570,
+ 2378, 2186, 1990, 1794,
+ 1598, 1400, 1202, 1002,
+ 802, 602, 402, 202,
+ 0, -202, -402, -602,
+ -802, -1002, -1202, -1400,
+ -1598, -1794, -1990, -2186,
+ -2378, -2570, -2760, -2948,
+ -3136, -3320, -3502, -3684,
+ -3862, -4038, -4212, -4382,
+ -4552, -4718, -4880, -5040,
+ -5198, -5352, -5502, -5648,
+ -5792, -5934, -6070, -6204,
+ -6332, -6458, -6580, -6698,
+ -6812, -6922, -7026, -7128,
+ -7226, -7318, -7406, -7490,
+ -7568, -7644, -7714, -7778,
+ -7840, -7896, -7946, -7994,
+ -8034, -8072, -8104, -8130,
+ -8152, -8170, -8182, -8190,
+ -8192
+ };
+
+ static final short[][] silk_gain_iCDF
+ = {
+ new short[]{
+ 224, 112, 44, 15, 3, 2, 1, 0
+ },
+ new short[]{
+ 254, 237, 192, 132, 70, 23, 4, 0
+ },
+ new short[]{
+ 255, 252, 226, 155, 61, 11, 2, 0
+ }
+ };
+
+ static final short[] silk_delta_gain_iCDF = {
+ 250, 245, 234, 203, 71, 50, 42, 38,
+ 35, 33, 31, 29, 28, 27, 26, 25,
+ 24, 23, 22, 21, 20, 19, 18, 17,
+ 16, 15, 14, 13, 12, 11, 10, 9,
+ 8, 7, 6, 5, 4, 3, 2, 1,
+ 0
+ };
+
+ static final short[] silk_LTP_per_index_iCDF = {
+ 179, 99, 0
+ };
+
+ static final short[] silk_LTP_gain_iCDF_0 = {
+ 71, 56, 43, 30, 21, 12, 6, 0
+ };
+
+ static final short[] silk_LTP_gain_iCDF_1 = {
+ 199, 165, 144, 124, 109, 96, 84, 71,
+ 61, 51, 42, 32, 23, 15, 8, 0
+ };
+
+ static final short[] silk_LTP_gain_iCDF_2 = {
+ 241, 225, 211, 199, 187, 175, 164, 153,
+ 142, 132, 123, 114, 105, 96, 88, 80,
+ 72, 64, 57, 50, 44, 38, 33, 29,
+ 24, 20, 16, 12, 9, 5, 2, 0
+ };
+
+ static final short silk_LTP_gain_middle_avg_RD_Q14 = 12304;
+
+ static final short[] silk_LTP_gain_BITS_Q5_0 = {
+ 15, 131, 138, 138, 155, 155, 173, 173
+ };
+
+ static final short[] silk_LTP_gain_BITS_Q5_1 = {
+ 69, 93, 115, 118, 131, 138, 141, 138,
+ 150, 150, 155, 150, 155, 160, 166, 160
+ };
+
+ static final short[] silk_LTP_gain_BITS_Q5_2 = {
+ 131, 128, 134, 141, 141, 141, 145, 145,
+ 145, 150, 155, 155, 155, 155, 160, 160,
+ 160, 160, 166, 166, 173, 173, 182, 192,
+ 182, 192, 192, 192, 205, 192, 205, 224
+ };
+
+ static final short[][] silk_LTP_gain_iCDF_ptrs = {
+ silk_LTP_gain_iCDF_0,
+ silk_LTP_gain_iCDF_1,
+ silk_LTP_gain_iCDF_2
+ };
+
+ static final short[][] silk_LTP_gain_BITS_Q5_ptrs = {
+ silk_LTP_gain_BITS_Q5_0,
+ silk_LTP_gain_BITS_Q5_1,
+ silk_LTP_gain_BITS_Q5_2
+ };
+
+ static final byte[][] silk_LTP_gain_vq_0
+ = {
+ new byte[]{4, 6, 24, 7, 5},
+ new byte[]{0, 0, 2, 0, 0},
+ new byte[]{12, 28, 41, 13, -4},
+ new byte[]{-9, 15, 42, 25, 14},
+ new byte[]{1, -2, 62, 41, -9},
+ new byte[]{-10, 37, 65, -4, 3},
+ new byte[]{-6, 4, 66, 7, -8},
+ new byte[]{16, 14, 38, -3, 33}
+ };
+
+ static final byte[][] silk_LTP_gain_vq_1
+ = {
+ new byte[]{13, 22, 39, 23, 12},
+ new byte[]{-1, 36, 64, 27, -6},
+ new byte[]{-7, 10, 55, 43, 17},
+ new byte[]{1, 1, 8, 1, 1},
+ new byte[]{6, -11, 74, 53, -9},
+ new byte[]{-12, 55, 76, -12, 8},
+ new byte[]{-3, 3, 93, 27, -4},
+ new byte[]{26, 39, 59, 3, -8},
+ new byte[]{2, 0, 77, 11, 9},
+ new byte[]{-8, 22, 44, -6, 7},
+ new byte[]{40, 9, 26, 3, 9},
+ new byte[]{-7, 20, 101, -7, 4},
+ new byte[]{3, -8, 42, 26, 0},
+ new byte[]{-15, 33, 68, 2, 23},
+ new byte[]{-2, 55, 46, -2, 15},
+ new byte[]{3, -1, 21, 16, 41}
+ };
+
+ static final byte[][] silk_LTP_gain_vq_2
+ = {
+ new byte[]{-6, 27, 61, 39, 5},
+ new byte[]{-11, 42, 88, 4, 1},
+ new byte[]{-2, 60, 65, 6, -4},
+ new byte[]{-1, -5, 73, 56, 1},
+ new byte[]{-9, 19, 94, 29, -9},
+ new byte[]{0, 12, 99, 6, 4},
+ new byte[]{8, -19, 102, 46, -13},
+ new byte[]{3, 2, 13, 3, 2},
+ new byte[]{9, -21, 84, 72, -18},
+ new byte[]{-11, 46, 104, -22, 8},
+ new byte[]{18, 38, 48, 23, 0},
+ new byte[]{-16, 70, 83, -21, 11},
+ new byte[]{5, -11, 117, 22, -8},
+ new byte[]{-6, 23, 117, -12, 3},
+ new byte[]{3, -8, 95, 28, 4},
+ new byte[]{-10, 15, 77, 60, -15},
+ new byte[]{-1, 4, 124, 2, -4},
+ new byte[]{3, 38, 84, 24, -25},
+ new byte[]{2, 13, 42, 13, 31},
+ new byte[]{21, -4, 56, 46, -1},
+ new byte[]{-1, 35, 79, -13, 19},
+ new byte[]{-7, 65, 88, -9, -14},
+ new byte[]{20, 4, 81, 49, -29},
+ new byte[]{20, 0, 75, 3, -17},
+ new byte[]{5, -9, 44, 92, -8},
+ new byte[]{1, -3, 22, 69, 31},
+ new byte[]{-6, 95, 41, -12, 5},
+ new byte[]{39, 67, 16, -4, 1},
+ new byte[]{0, -6, 120, 55, -36},
+ new byte[]{-13, 44, 122, 4, -24},
+ new byte[]{81, 5, 11, 3, 7},
+ new byte[]{2, 0, 9, 10, 88}
+ };
+
+ static final byte[][][] silk_LTP_vq_ptrs_Q7 = {
+ silk_LTP_gain_vq_0,
+ silk_LTP_gain_vq_1,
+ silk_LTP_gain_vq_2
+ };
+
+ /* Maximum frequency-dependent response of the pitch taps above,
+ computed as max(abs(freqz(taps))) */
+ static final short[] silk_LTP_gain_vq_0_gain = {
+ 46, 2, 90, 87, 93, 91, 82, 98
+ };
+
+ static final short[] silk_LTP_gain_vq_1_gain = {
+ 109, 120, 118, 12, 113, 115, 117, 119,
+ 99, 59, 87, 111, 63, 111, 112, 80
+ };
+
+ static final short[] silk_LTP_gain_vq_2_gain = {
+ 126, 124, 125, 124, 129, 121, 126, 23,
+ 132, 127, 127, 127, 126, 127, 122, 133,
+ 130, 134, 101, 118, 119, 145, 126, 86,
+ 124, 120, 123, 119, 170, 173, 107, 109
+ };
+
+ static final short[][] silk_LTP_vq_gain_ptrs_Q7 = {
+ silk_LTP_gain_vq_0_gain,
+ silk_LTP_gain_vq_1_gain,
+ silk_LTP_gain_vq_2_gain
+ };
+
+ static final byte[] silk_LTP_vq_sizes = {
+ 8, 16, 32
+ };
+
+ static final short[] silk_NLSF_CB1_NB_MB_Q8 = {
+ 12, 35, 60, 83, 108, 132, 157, 180,
+ 206, 228, 15, 32, 55, 77, 101, 125,
+ 151, 175, 201, 225, 19, 42, 66, 89,
+ 114, 137, 162, 184, 209, 230, 12, 25,
+ 50, 72, 97, 120, 147, 172, 200, 223,
+ 26, 44, 69, 90, 114, 135, 159, 180,
+ 205, 225, 13, 22, 53, 80, 106, 130,
+ 156, 180, 205, 228, 15, 25, 44, 64,
+ 90, 115, 142, 168, 196, 222, 19, 24,
+ 62, 82, 100, 120, 145, 168, 190, 214,
+ 22, 31, 50, 79, 103, 120, 151, 170,
+ 203, 227, 21, 29, 45, 65, 106, 124,
+ 150, 171, 196, 224, 30, 49, 75, 97,
+ 121, 142, 165, 186, 209, 229, 19, 25,
+ 52, 70, 93, 116, 143, 166, 192, 219,
+ 26, 34, 62, 75, 97, 118, 145, 167,
+ 194, 217, 25, 33, 56, 70, 91, 113,
+ 143, 165, 196, 223, 21, 34, 51, 72,
+ 97, 117, 145, 171, 196, 222, 20, 29,
+ 50, 67, 90, 117, 144, 168, 197, 221,
+ 22, 31, 48, 66, 95, 117, 146, 168,
+ 196, 222, 24, 33, 51, 77, 116, 134,
+ 158, 180, 200, 224, 21, 28, 70, 87,
+ 106, 124, 149, 170, 194, 217, 26, 33,
+ 53, 64, 83, 117, 152, 173, 204, 225,
+ 27, 34, 65, 95, 108, 129, 155, 174,
+ 210, 225, 20, 26, 72, 99, 113, 131,
+ 154, 176, 200, 219, 34, 43, 61, 78,
+ 93, 114, 155, 177, 205, 229, 23, 29,
+ 54, 97, 124, 138, 163, 179, 209, 229,
+ 30, 38, 56, 89, 118, 129, 158, 178,
+ 200, 231, 21, 29, 49, 63, 85, 111,
+ 142, 163, 193, 222, 27, 48, 77, 103,
+ 133, 158, 179, 196, 215, 232, 29, 47,
+ 74, 99, 124, 151, 176, 198, 220, 237,
+ 33, 42, 61, 76, 93, 121, 155, 174,
+ 207, 225, 29, 53, 87, 112, 136, 154,
+ 170, 188, 208, 227, 24, 30, 52, 84,
+ 131, 150, 166, 186, 203, 229, 37, 48,
+ 64, 84, 104, 118, 156, 177, 201, 230
+ };
+
+ static final short[] silk_NLSF_CB1_iCDF_NB_MB = {
+ 212, 178, 148, 129, 108, 96, 85, 82,
+ 79, 77, 61, 59, 57, 56, 51, 49,
+ 48, 45, 42, 41, 40, 38, 36, 34,
+ 31, 30, 21, 12, 10, 3, 1, 0,
+ 255, 245, 244, 236, 233, 225, 217, 203,
+ 190, 176, 175, 161, 149, 136, 125, 114,
+ 102, 91, 81, 71, 60, 52, 43, 35,
+ 28, 20, 19, 18, 12, 11, 5, 0
+ };
+
+ static final short[] silk_NLSF_CB2_SELECT_NB_MB = {
+ 16, 0, 0, 0, 0, 99, 66, 36,
+ 36, 34, 36, 34, 34, 34, 34, 83,
+ 69, 36, 52, 34, 116, 102, 70, 68,
+ 68, 176, 102, 68, 68, 34, 65, 85,
+ 68, 84, 36, 116, 141, 152, 139, 170,
+ 132, 187, 184, 216, 137, 132, 249, 168,
+ 185, 139, 104, 102, 100, 68, 68, 178,
+ 218, 185, 185, 170, 244, 216, 187, 187,
+ 170, 244, 187, 187, 219, 138, 103, 155,
+ 184, 185, 137, 116, 183, 155, 152, 136,
+ 132, 217, 184, 184, 170, 164, 217, 171,
+ 155, 139, 244, 169, 184, 185, 170, 164,
+ 216, 223, 218, 138, 214, 143, 188, 218,
+ 168, 244, 141, 136, 155, 170, 168, 138,
+ 220, 219, 139, 164, 219, 202, 216, 137,
+ 168, 186, 246, 185, 139, 116, 185, 219,
+ 185, 138, 100, 100, 134, 100, 102, 34,
+ 68, 68, 100, 68, 168, 203, 221, 218,
+ 168, 167, 154, 136, 104, 70, 164, 246,
+ 171, 137, 139, 137, 155, 218, 219, 139
+ };
+
+ static final short[] silk_NLSF_CB2_iCDF_NB_MB = {
+ 255, 254, 253, 238, 14, 3, 2, 1,
+ 0, 255, 254, 252, 218, 35, 3, 2,
+ 1, 0, 255, 254, 250, 208, 59, 4,
+ 2, 1, 0, 255, 254, 246, 194, 71,
+ 10, 2, 1, 0, 255, 252, 236, 183,
+ 82, 8, 2, 1, 0, 255, 252, 235,
+ 180, 90, 17, 2, 1, 0, 255, 248,
+ 224, 171, 97, 30, 4, 1, 0, 255,
+ 254, 236, 173, 95, 37, 7, 1, 0
+ };
+
+ static final short[] silk_NLSF_CB2_BITS_NB_MB_Q5 = {
+ 255, 255, 255, 131, 6, 145, 255, 255,
+ 255, 255, 255, 236, 93, 15, 96, 255,
+ 255, 255, 255, 255, 194, 83, 25, 71,
+ 221, 255, 255, 255, 255, 162, 73, 34,
+ 66, 162, 255, 255, 255, 210, 126, 73,
+ 43, 57, 173, 255, 255, 255, 201, 125,
+ 71, 48, 58, 130, 255, 255, 255, 166,
+ 110, 73, 57, 62, 104, 210, 255, 255,
+ 251, 123, 65, 55, 68, 100, 171, 255
+ };
+
+ static final short[] silk_NLSF_PRED_NB_MB_Q8 = {
+ 179, 138, 140, 148, 151, 149, 153, 151,
+ 163, 116, 67, 82, 59, 92, 72, 100,
+ 89, 92
+ };
+
+ static final short[] silk_NLSF_DELTA_MIN_NB_MB_Q15 = {
+ 250, 3, 6, 3, 3, 3, 4, 3,
+ 3, 3, 461
+ };
+
+ static final NLSFCodebook silk_NLSF_CB_NB_MB = new NLSFCodebook();
+
+ static {
+ silk_NLSF_CB_NB_MB.nVectors = 32;
+ silk_NLSF_CB_NB_MB.order = 10;
+ silk_NLSF_CB_NB_MB.quantStepSize_Q16 = (short) (((int) ((0.18f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.18f, 16)*/);
+ silk_NLSF_CB_NB_MB.invQuantStepSize_Q6 = (short) (((int) ((1.0f / 0.18f) * ((long) 1 << (6)) + 0.5))/*Inlines.SILK_CONST(1.0f / 0.18f, 6)*/);
+ silk_NLSF_CB_NB_MB.CB1_NLSF_Q8 = silk_NLSF_CB1_NB_MB_Q8;
+ silk_NLSF_CB_NB_MB.CB1_iCDF = silk_NLSF_CB1_iCDF_NB_MB;
+ silk_NLSF_CB_NB_MB.pred_Q8 = silk_NLSF_PRED_NB_MB_Q8;
+ silk_NLSF_CB_NB_MB.ec_sel = silk_NLSF_CB2_SELECT_NB_MB;
+ silk_NLSF_CB_NB_MB.ec_iCDF = silk_NLSF_CB2_iCDF_NB_MB;
+ silk_NLSF_CB_NB_MB.ec_Rates_Q5 = silk_NLSF_CB2_BITS_NB_MB_Q5;
+ silk_NLSF_CB_NB_MB.deltaMin_Q15 = silk_NLSF_DELTA_MIN_NB_MB_Q15;
+ }
+ ;
+
+ static final short[] silk_NLSF_CB1_WB_Q8 = {
+ 7, 23, 38, 54, 69, 85, 100, 116,
+ 131, 147, 162, 178, 193, 208, 223, 239,
+ 13, 25, 41, 55, 69, 83, 98, 112,
+ 127, 142, 157, 171, 187, 203, 220, 236,
+ 15, 21, 34, 51, 61, 78, 92, 106,
+ 126, 136, 152, 167, 185, 205, 225, 240,
+ 10, 21, 36, 50, 63, 79, 95, 110,
+ 126, 141, 157, 173, 189, 205, 221, 237,
+ 17, 20, 37, 51, 59, 78, 89, 107,
+ 123, 134, 150, 164, 184, 205, 224, 240,
+ 10, 15, 32, 51, 67, 81, 96, 112,
+ 129, 142, 158, 173, 189, 204, 220, 236,
+ 8, 21, 37, 51, 65, 79, 98, 113,
+ 126, 138, 155, 168, 179, 192, 209, 218,
+ 12, 15, 34, 55, 63, 78, 87, 108,
+ 118, 131, 148, 167, 185, 203, 219, 236,
+ 16, 19, 32, 36, 56, 79, 91, 108,
+ 118, 136, 154, 171, 186, 204, 220, 237,
+ 11, 28, 43, 58, 74, 89, 105, 120,
+ 135, 150, 165, 180, 196, 211, 226, 241,
+ 6, 16, 33, 46, 60, 75, 92, 107,
+ 123, 137, 156, 169, 185, 199, 214, 225,
+ 11, 19, 30, 44, 57, 74, 89, 105,
+ 121, 135, 152, 169, 186, 202, 218, 234,
+ 12, 19, 29, 46, 57, 71, 88, 100,
+ 120, 132, 148, 165, 182, 199, 216, 233,
+ 17, 23, 35, 46, 56, 77, 92, 106,
+ 123, 134, 152, 167, 185, 204, 222, 237,
+ 14, 17, 45, 53, 63, 75, 89, 107,
+ 115, 132, 151, 171, 188, 206, 221, 240,
+ 9, 16, 29, 40, 56, 71, 88, 103,
+ 119, 137, 154, 171, 189, 205, 222, 237,
+ 16, 19, 36, 48, 57, 76, 87, 105,
+ 118, 132, 150, 167, 185, 202, 218, 236,
+ 12, 17, 29, 54, 71, 81, 94, 104,
+ 126, 136, 149, 164, 182, 201, 221, 237,
+ 15, 28, 47, 62, 79, 97, 115, 129,
+ 142, 155, 168, 180, 194, 208, 223, 238,
+ 8, 14, 30, 45, 62, 78, 94, 111,
+ 127, 143, 159, 175, 192, 207, 223, 239,
+ 17, 30, 49, 62, 79, 92, 107, 119,
+ 132, 145, 160, 174, 190, 204, 220, 235,
+ 14, 19, 36, 45, 61, 76, 91, 108,
+ 121, 138, 154, 172, 189, 205, 222, 238,
+ 12, 18, 31, 45, 60, 76, 91, 107,
+ 123, 138, 154, 171, 187, 204, 221, 236,
+ 13, 17, 31, 43, 53, 70, 83, 103,
+ 114, 131, 149, 167, 185, 203, 220, 237,
+ 17, 22, 35, 42, 58, 78, 93, 110,
+ 125, 139, 155, 170, 188, 206, 224, 240,
+ 8, 15, 34, 50, 67, 83, 99, 115,
+ 131, 146, 162, 178, 193, 209, 224, 239,
+ 13, 16, 41, 66, 73, 86, 95, 111,
+ 128, 137, 150, 163, 183, 206, 225, 241,
+ 17, 25, 37, 52, 63, 75, 92, 102,
+ 119, 132, 144, 160, 175, 191, 212, 231,
+ 19, 31, 49, 65, 83, 100, 117, 133,
+ 147, 161, 174, 187, 200, 213, 227, 242,
+ 18, 31, 52, 68, 88, 103, 117, 126,
+ 138, 149, 163, 177, 192, 207, 223, 239,
+ 16, 29, 47, 61, 76, 90, 106, 119,
+ 133, 147, 161, 176, 193, 209, 224, 240,
+ 15, 21, 35, 50, 61, 73, 86, 97,
+ 110, 119, 129, 141, 175, 198, 218, 237
+ };
+
+ static final short[] silk_NLSF_CB1_iCDF_WB = {
+ 225, 204, 201, 184, 183, 175, 158, 154,
+ 153, 135, 119, 115, 113, 110, 109, 99,
+ 98, 95, 79, 68, 52, 50, 48, 45,
+ 43, 32, 31, 27, 18, 10, 3, 0,
+ 255, 251, 235, 230, 212, 201, 196, 182,
+ 167, 166, 163, 151, 138, 124, 110, 104,
+ 90, 78, 76, 70, 69, 57, 45, 34,
+ 24, 21, 11, 6, 5, 4, 3, 0
+ };
+
+ static final short[] silk_NLSF_CB2_SELECT_WB = {
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 100, 102, 102, 68, 68, 36, 34, 96,
+ 164, 107, 158, 185, 180, 185, 139, 102,
+ 64, 66, 36, 34, 34, 0, 1, 32,
+ 208, 139, 141, 191, 152, 185, 155, 104,
+ 96, 171, 104, 166, 102, 102, 102, 132,
+ 1, 0, 0, 0, 0, 16, 16, 0,
+ 80, 109, 78, 107, 185, 139, 103, 101,
+ 208, 212, 141, 139, 173, 153, 123, 103,
+ 36, 0, 0, 0, 0, 0, 0, 1,
+ 48, 0, 0, 0, 0, 0, 0, 32,
+ 68, 135, 123, 119, 119, 103, 69, 98,
+ 68, 103, 120, 118, 118, 102, 71, 98,
+ 134, 136, 157, 184, 182, 153, 139, 134,
+ 208, 168, 248, 75, 189, 143, 121, 107,
+ 32, 49, 34, 34, 34, 0, 17, 2,
+ 210, 235, 139, 123, 185, 137, 105, 134,
+ 98, 135, 104, 182, 100, 183, 171, 134,
+ 100, 70, 68, 70, 66, 66, 34, 131,
+ 64, 166, 102, 68, 36, 2, 1, 0,
+ 134, 166, 102, 68, 34, 34, 66, 132,
+ 212, 246, 158, 139, 107, 107, 87, 102,
+ 100, 219, 125, 122, 137, 118, 103, 132,
+ 114, 135, 137, 105, 171, 106, 50, 34,
+ 164, 214, 141, 143, 185, 151, 121, 103,
+ 192, 34, 0, 0, 0, 0, 0, 1,
+ 208, 109, 74, 187, 134, 249, 159, 137,
+ 102, 110, 154, 118, 87, 101, 119, 101,
+ 0, 2, 0, 36, 36, 66, 68, 35,
+ 96, 164, 102, 100, 36, 0, 2, 33,
+ 167, 138, 174, 102, 100, 84, 2, 2,
+ 100, 107, 120, 119, 36, 197, 24, 0
+ };
+
+ static final short[] silk_NLSF_CB2_iCDF_WB = {
+ 255, 254, 253, 244, 12, 3, 2, 1,
+ 0, 255, 254, 252, 224, 38, 3, 2,
+ 1, 0, 255, 254, 251, 209, 57, 4,
+ 2, 1, 0, 255, 254, 244, 195, 69,
+ 4, 2, 1, 0, 255, 251, 232, 184,
+ 84, 7, 2, 1, 0, 255, 254, 240,
+ 186, 86, 14, 2, 1, 0, 255, 254,
+ 239, 178, 91, 30, 5, 1, 0, 255,
+ 248, 227, 177, 100, 19, 2, 1, 0
+ };
+
+ static final short[] silk_NLSF_CB2_BITS_WB_Q5 = {
+ 255, 255, 255, 156, 4, 154, 255, 255,
+ 255, 255, 255, 227, 102, 15, 92, 255,
+ 255, 255, 255, 255, 213, 83, 24, 72,
+ 236, 255, 255, 255, 255, 150, 76, 33,
+ 63, 214, 255, 255, 255, 190, 121, 77,
+ 43, 55, 185, 255, 255, 255, 245, 137,
+ 71, 43, 59, 139, 255, 255, 255, 255,
+ 131, 66, 50, 66, 107, 194, 255, 255,
+ 166, 116, 76, 55, 53, 125, 255, 255
+ };
+
+ static final short[] silk_NLSF_PRED_WB_Q8 = {
+ 175, 148, 160, 176, 178, 173, 174, 164,
+ 177, 174, 196, 182, 198, 192, 182, 68,
+ 62, 66, 60, 72, 117, 85, 90, 118,
+ 136, 151, 142, 160, 142, 155
+ };
+
+ static final short[] silk_NLSF_DELTA_MIN_WB_Q15 = {
+ 100, 3, 40, 3, 3, 3, 5, 14,
+ 14, 10, 11, 3, 8, 9, 7, 3,
+ 347
+ };
+
+ static final NLSFCodebook silk_NLSF_CB_WB = new NLSFCodebook();
+
+ static {
+ silk_NLSF_CB_WB.nVectors = 32;
+ silk_NLSF_CB_WB.order = 16;
+ silk_NLSF_CB_WB.quantStepSize_Q16 = (short) (((int) ((0.15f) * ((long) 1 << (16)) + 0.5))/*Inlines.SILK_CONST(0.15f, 16)*/);
+ silk_NLSF_CB_WB.invQuantStepSize_Q6 = (short) (((int) ((1.0f / 0.15f) * ((long) 1 << (6)) + 0.5))/*Inlines.SILK_CONST(1.0f / 0.15f, 6)*/);
+ silk_NLSF_CB_WB.CB1_NLSF_Q8 = silk_NLSF_CB1_WB_Q8;
+ silk_NLSF_CB_WB.CB1_iCDF = silk_NLSF_CB1_iCDF_WB;
+ silk_NLSF_CB_WB.pred_Q8 = silk_NLSF_PRED_WB_Q8;
+ silk_NLSF_CB_WB.ec_sel = silk_NLSF_CB2_SELECT_WB;
+ silk_NLSF_CB_WB.ec_iCDF = silk_NLSF_CB2_iCDF_WB;
+ silk_NLSF_CB_WB.ec_Rates_Q5 = silk_NLSF_CB2_BITS_WB_Q5;
+ silk_NLSF_CB_WB.deltaMin_Q15 = silk_NLSF_DELTA_MIN_WB_Q15;
+ }
+ ;
+
+ /* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */
+ static final int[] silk_TargetRate_table_NB = {
+ 0, 8000, 9400, 11500, 13500, 17500, 25000, SilkConstants.MAX_TARGET_RATE_BPS
+ };
+ static final int[] silk_TargetRate_table_MB = {
+ 0, 9000, 12000, 14500, 18500, 24500, 35500, SilkConstants.MAX_TARGET_RATE_BPS
+ };
+ static final int[] silk_TargetRate_table_WB = {
+ 0, 10500, 14000, 17000, 21500, 28500, 42000, SilkConstants.MAX_TARGET_RATE_BPS
+ };
+ static final short[] silk_SNR_table_Q1 = {
+ 18, 29, 38, 40, 46, 52, 62, 84
+ };
+
+ /* Tables for stereo predictor coding */
+ static final short[] silk_stereo_pred_quant_Q13 = {
+ -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820,
+ 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732
+ };
+
+ static final short[] silk_stereo_pred_joint_iCDF = {
+ 249, 247, 246, 245, 244,
+ 234, 210, 202, 201, 200,
+ 197, 174, 82, 59, 56,
+ 55, 54, 46, 22, 12,
+ 11, 10, 9, 7, 0
+ };
+ static final short[] silk_stereo_only_code_mid_iCDF = {64, 0};
+
+ /* Tables for LBRR flags */
+ static final short[] silk_LBRR_flags_2_iCDF = {203, 150, 0};
+ static final short[] silk_LBRR_flags_3_iCDF = {215, 195, 166, 125, 110, 82, 0};
+ static final short[][] silk_LBRR_flags_iCDF_ptr = {
+ silk_LBRR_flags_2_iCDF,
+ silk_LBRR_flags_3_iCDF
+ };
+
+ /* Table for LSB coding */
+ static final short[] silk_lsb_iCDF = {120, 0};
+
+ /* Tables for LTPScale */
+ static final short[] silk_LTPscale_iCDF = {128, 64, 0};
+
+ /* Tables for signal type and offset coding */
+ static final short[] silk_type_offset_VAD_iCDF = {
+ 232, 158, 10, 0
+ };
+ static final short[] silk_type_offset_no_VAD_iCDF = {
+ 230, 0
+ };
+
+ /* Tables for NLSF interpolation factor */
+ static final short[] silk_NLSF_interpolation_factor_iCDF = {243, 221, 192, 181, 0};
+
+ /* Quantization offsets */
+ static final short[][] silk_Quantization_Offsets_Q10 = {
+ new short[]{SilkConstants.OFFSET_UVL_Q10, SilkConstants.OFFSET_UVH_Q10},
+ new short[]{SilkConstants.OFFSET_VL_Q10, SilkConstants.OFFSET_VH_Q10}
+ };
+
+ /* Table for LTPScale */
+ static final short[] silk_LTPScales_table_Q14 = {15565, 12288, 8192};
+
+ /* Uniform entropy tables */
+ static final short[] silk_uniform3_iCDF = {171, 85, 0};
+ static final short[] silk_uniform4_iCDF = {192, 128, 64, 0};
+ static final short[] silk_uniform5_iCDF = {205, 154, 102, 51, 0};
+ static final short[] silk_uniform6_iCDF = {213, 171, 128, 85, 43, 0};
+ static final short[] silk_uniform8_iCDF = {224, 192, 160, 128, 96, 64, 32, 0};
+
+ static final short[] silk_NLSF_EXT_iCDF = {100, 40, 16, 7, 3, 1, 0};
+
+ /* 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. */
+
+ /* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+ static final int[][] silk_Transition_LP_B_Q28
+ = {
+ new int[]{250767114, 501534038, 250767114},
+ new int[]{209867381, 419732057, 209867381},
+ new int[]{170987846, 341967853, 170987846},
+ new int[]{131531482, 263046905, 131531482},
+ new int[]{89306658, 178584282, 89306658}
+ };
+
+ /* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+ static final int[][] silk_Transition_LP_A_Q28
+ = {
+ new int[]{506393414, 239854379},
+ new int[]{411067935, 169683996},
+ new int[]{306733530, 116694253},
+ new int[]{185807084, 77959395},
+ new int[]{35497197, 57401098}
+ };
+
+ static final short[] silk_pitch_lag_iCDF = {
+ 253, 250, 244, 233, 212, 182, 150, 131,
+ 120, 110, 98, 85, 72, 60, 49, 40,
+ 32, 25, 19, 15, 13, 11, 9, 8,
+ 7, 6, 5, 4, 3, 2, 1, 0
+ };
+
+ static final short[] silk_pitch_delta_iCDF = {
+ 210, 208, 206, 203, 199, 193, 183, 168,
+ 142, 104, 74, 52, 37, 27, 20, 14,
+ 10, 6, 4, 2, 0
+ };
+
+ static final short[] silk_pitch_contour_iCDF = {
+ 223, 201, 183, 167, 152, 138, 124, 111,
+ 98, 88, 79, 70, 62, 56, 50, 44,
+ 39, 35, 31, 27, 24, 21, 18, 16,
+ 14, 12, 10, 8, 6, 4, 3, 2,
+ 1, 0
+ };
+
+ static final short[] silk_pitch_contour_NB_iCDF = {
+ 188, 176, 155, 138, 119, 97, 67, 43,
+ 26, 10, 0
+ };
+
+ static final short[] silk_pitch_contour_10_ms_iCDF = {
+ 165, 119, 80, 61, 47, 35, 27, 20,
+ 14, 9, 4, 0
+ };
+
+ static final short[] silk_pitch_contour_10_ms_NB_iCDF = {
+ 113, 63, 0
+ };
+
+ static final byte[] silk_max_pulses_table = {
+ 8, 10, 12, 16
+ };
+
+ static final short[][] silk_pulses_per_block_iCDF = {
+ new short[]{
+ 125, 51, 26, 18, 15, 12, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+ },
+ new short[]{
+ 198, 105, 45, 22, 15, 12, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+ },
+ new short[]{
+ 213, 162, 116, 83, 59, 43, 32, 24,
+ 18, 15, 12, 9, 7, 6, 5, 3,
+ 2, 0
+ },
+ new short[]{
+ 239, 187, 116, 59, 28, 16, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+ },
+ new short[]{
+ 250, 229, 188, 135, 86, 51, 30, 19,
+ 13, 10, 8, 6, 5, 4, 3, 2,
+ 1, 0
+ },
+ new short[]{
+ 249, 235, 213, 185, 156, 128, 103, 83,
+ 66, 53, 42, 33, 26, 21, 17, 13,
+ 10, 0
+ },
+ new short[]{
+ 254, 249, 235, 206, 164, 118, 77, 46,
+ 27, 16, 10, 7, 5, 4, 3, 2,
+ 1, 0
+ },
+ new short[]{
+ 255, 253, 249, 239, 220, 191, 156, 119,
+ 85, 57, 37, 23, 15, 10, 6, 4,
+ 2, 0
+ },
+ new short[]{
+ 255, 253, 251, 246, 237, 223, 203, 179,
+ 152, 124, 98, 75, 55, 40, 29, 21,
+ 15, 0
+ },
+ new short[]{
+ 255, 254, 253, 247, 220, 162, 106, 67,
+ 42, 28, 18, 12, 9, 6, 4, 3,
+ 2, 0
+ }
+ };
+
+ static final short[][] silk_pulses_per_block_BITS_Q5 = {
+ new short[]{
+ 31, 57, 107, 160, 205, 205, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255
+ },
+ new short[]{
+ 69, 47, 67, 111, 166, 205, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255
+ },
+ new short[]{
+ 82, 74, 79, 95, 109, 128, 145, 160,
+ 173, 205, 205, 205, 224, 255, 255, 224,
+ 255, 224
+ },
+ new short[]{
+ 125, 74, 59, 69, 97, 141, 182, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255
+ },
+ new short[]{
+ 173, 115, 85, 73, 76, 92, 115, 145,
+ 173, 205, 224, 224, 255, 255, 255, 255,
+ 255, 255
+ },
+ new short[]{
+ 166, 134, 113, 102, 101, 102, 107, 118,
+ 125, 138, 145, 155, 166, 182, 192, 192,
+ 205, 150
+ },
+ new short[]{
+ 224, 182, 134, 101, 83, 79, 85, 97,
+ 120, 145, 173, 205, 224, 255, 255, 255,
+ 255, 255
+ },
+ new short[]{
+ 255, 224, 192, 150, 120, 101, 92, 89,
+ 93, 102, 118, 134, 160, 182, 192, 224,
+ 224, 224
+ },
+ new short[]{
+ 255, 224, 224, 182, 155, 134, 118, 109,
+ 104, 102, 106, 111, 118, 131, 145, 160,
+ 173, 131
+ }
+ };
+
+ static final short[][] silk_rate_levels_iCDF
+ = {
+ new short[]{
+ 241, 190, 178, 132, 87, 74, 41, 14,
+ 0
+ },
+ new short[]{
+ 223, 193, 157, 140, 106, 57, 39, 18,
+ 0
+ }
+ };
+
+ static final short[][] silk_rate_levels_BITS_Q5
+ = {
+ new short[]{
+ 131, 74, 141, 79, 80, 138, 95, 104,
+ 134
+ },
+ new short[]{
+ 95, 99, 91, 125, 93, 76, 123, 115,
+ 123
+ }
+ };
+
+ static final short[] silk_shell_code_table0 = {
+ 128, 0, 214, 42, 0, 235, 128, 21,
+ 0, 244, 184, 72, 11, 0, 248, 214,
+ 128, 42, 7, 0, 248, 225, 170, 80,
+ 25, 5, 0, 251, 236, 198, 126, 54,
+ 18, 3, 0, 250, 238, 211, 159, 82,
+ 35, 15, 5, 0, 250, 231, 203, 168,
+ 128, 88, 53, 25, 6, 0, 252, 238,
+ 216, 185, 148, 108, 71, 40, 18, 4,
+ 0, 253, 243, 225, 199, 166, 128, 90,
+ 57, 31, 13, 3, 0, 254, 246, 233,
+ 212, 183, 147, 109, 73, 44, 23, 10,
+ 2, 0, 255, 250, 240, 223, 198, 166,
+ 128, 90, 58, 33, 16, 6, 1, 0,
+ 255, 251, 244, 231, 210, 181, 146, 110,
+ 75, 46, 25, 12, 5, 1, 0, 255,
+ 253, 248, 238, 221, 196, 164, 128, 92,
+ 60, 35, 18, 8, 3, 1, 0, 255,
+ 253, 249, 242, 229, 208, 180, 146, 110,
+ 76, 48, 27, 14, 7, 3, 1, 0
+ };
+
+ static final short[] silk_shell_code_table1 = {
+ 129, 0, 207, 50, 0, 236, 129, 20,
+ 0, 245, 185, 72, 10, 0, 249, 213,
+ 129, 42, 6, 0, 250, 226, 169, 87,
+ 27, 4, 0, 251, 233, 194, 130, 62,
+ 20, 4, 0, 250, 236, 207, 160, 99,
+ 47, 17, 3, 0, 255, 240, 217, 182,
+ 131, 81, 41, 11, 1, 0, 255, 254,
+ 233, 201, 159, 107, 61, 20, 2, 1,
+ 0, 255, 249, 233, 206, 170, 128, 86,
+ 50, 23, 7, 1, 0, 255, 250, 238,
+ 217, 186, 148, 108, 70, 39, 18, 6,
+ 1, 0, 255, 252, 243, 226, 200, 166,
+ 128, 90, 56, 30, 13, 4, 1, 0,
+ 255, 252, 245, 231, 209, 180, 146, 110,
+ 76, 47, 25, 11, 4, 1, 0, 255,
+ 253, 248, 237, 219, 194, 163, 128, 93,
+ 62, 37, 19, 8, 3, 1, 0, 255,
+ 254, 250, 241, 226, 205, 177, 145, 111,
+ 79, 51, 30, 15, 6, 2, 1, 0
+ };
+
+ static final short[] silk_shell_code_table2 = {
+ 129, 0, 203, 54, 0, 234, 129, 23,
+ 0, 245, 184, 73, 10, 0, 250, 215,
+ 129, 41, 5, 0, 252, 232, 173, 86,
+ 24, 3, 0, 253, 240, 200, 129, 56,
+ 15, 2, 0, 253, 244, 217, 164, 94,
+ 38, 10, 1, 0, 253, 245, 226, 189,
+ 132, 71, 27, 7, 1, 0, 253, 246,
+ 231, 203, 159, 105, 56, 23, 6, 1,
+ 0, 255, 248, 235, 213, 179, 133, 85,
+ 47, 19, 5, 1, 0, 255, 254, 243,
+ 221, 194, 159, 117, 70, 37, 12, 2,
+ 1, 0, 255, 254, 248, 234, 208, 171,
+ 128, 85, 48, 22, 8, 2, 1, 0,
+ 255, 254, 250, 240, 220, 189, 149, 107,
+ 67, 36, 16, 6, 2, 1, 0, 255,
+ 254, 251, 243, 227, 201, 166, 128, 90,
+ 55, 29, 13, 5, 2, 1, 0, 255,
+ 254, 252, 246, 234, 213, 183, 147, 109,
+ 73, 43, 22, 10, 4, 2, 1, 0
+ };
+
+ static final short[] silk_shell_code_table3 = {
+ 130, 0, 200, 58, 0, 231, 130, 26,
+ 0, 244, 184, 76, 12, 0, 249, 214,
+ 130, 43, 6, 0, 252, 232, 173, 87,
+ 24, 3, 0, 253, 241, 203, 131, 56,
+ 14, 2, 0, 254, 246, 221, 167, 94,
+ 35, 8, 1, 0, 254, 249, 232, 193,
+ 130, 65, 23, 5, 1, 0, 255, 251,
+ 239, 211, 162, 99, 45, 15, 4, 1,
+ 0, 255, 251, 243, 223, 186, 131, 74,
+ 33, 11, 3, 1, 0, 255, 252, 245,
+ 230, 202, 158, 105, 57, 24, 8, 2,
+ 1, 0, 255, 253, 247, 235, 214, 179,
+ 132, 84, 44, 19, 7, 2, 1, 0,
+ 255, 254, 250, 240, 223, 196, 159, 112,
+ 69, 36, 15, 6, 2, 1, 0, 255,
+ 254, 253, 245, 231, 209, 176, 136, 93,
+ 55, 27, 11, 3, 2, 1, 0, 255,
+ 254, 253, 252, 239, 221, 194, 158, 117,
+ 76, 42, 18, 4, 3, 2, 1, 0
+ };
+
+ static final short[] silk_shell_code_table_offsets = {
+ 0, 0, 2, 5, 9, 14, 20, 27,
+ 35, 44, 54, 65, 77, 90, 104, 119,
+ 135
+ };
+
+ static final short[] silk_sign_iCDF = {
+ 254, 49, 67, 77, 82, 93, 99,
+ 198, 11, 18, 24, 31, 36, 45,
+ 255, 46, 66, 78, 87, 94, 104,
+ 208, 14, 21, 32, 42, 51, 66,
+ 255, 94, 104, 109, 112, 115, 118,
+ 248, 53, 69, 80, 88, 95, 102
+ };
+
+ // Resampler tables
+
+ /* Tables with delay compensation values to equalize total delay for different modes */
+ static final byte[][] delay_matrix_enc = {
+ /* in \ out 8 12 16 */
+ /* 8 */{6, 0, 3},
+ /* 12 */ {0, 7, 3},
+ /* 16 */ {0, 1, 10},
+ /* 24 */ {0, 2, 6},
+ /* 48 */ {18, 10, 12}
+ };
+
+ static final byte[][] delay_matrix_dec = {
+ /* in \ out 8 12 16 24 48 */
+ /* 8 */{4, 0, 2, 0, 0},
+ /* 12 */ {0, 9, 4, 7, 4},
+ /* 16 */ {0, 3, 12, 7, 7}
+ };
+
+
+ /* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */
+ static final /*silk_DWORD_ALIGN*/ short[] silk_Resampler_3_4_COEFS/*[2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2]*/ = {
+ -20694, -13867,
+ -49, 64, 17, -157, 353, -496, 163, 11047, 22205,
+ -39, 6, 91, -170, 186, 23, -896, 6336, 19928,
+ -19, -36, 102, -89, -24, 328, -951, 2568, 15909,};
+
+ static final /*silk_DWORD_ALIGN*/ short[] silk_Resampler_2_3_COEFS/*[2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2]*/ = {
+ -14457, -14019,
+ 64, 128, -122, 36, 310, -768, 584, 9267, 17733,
+ 12, 128, 18, -142, 288, -117, -865, 4123, 14459,};
+
+ static final /*silk_DWORD_ALIGN*/ short[] silk_Resampler_1_2_COEFS/*[2 + RESAMPLER_DOWN_ORDER_FIR1 / 2]*/ = {
+ 616, -14323,
+ -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024,};
+
+ static final /*silk_DWORD_ALIGN*/ short[] silk_Resampler_1_3_COEFS/*[2 + RESAMPLER_DOWN_ORDER_FIR2 / 2]*/ = {
+ 16102, -15162,
+ -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271,};
+
+ static final /*silk_DWORD_ALIGN*/ short[] silk_Resampler_1_4_COEFS/*[2 + RESAMPLER_DOWN_ORDER_FIR2 / 2]*/ = {
+ 22500, -15099,
+ 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464,};
+
+ static final /*silk_DWORD_ALIGN*/ short[] silk_Resampler_1_6_COEFS/*[2 + RESAMPLER_DOWN_ORDER_FIR2 / 2]*/ = {
+ 27540, -15257,
+ 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455,};
+
+ static final /*silk_DWORD_ALIGN*/ short[] silk_Resampler_2_3_COEFS_LQ/*[2 + 2 * 2]*/ = {
+ -2797, -6507,
+ 4697, 10739,
+ 1567, 8276,};
+
+ /* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */
+ static final /*silk_DWORD_ALIGN*/ short[][] silk_resampler_frac_FIR_12/*[12][RESAMPLER_ORDER_FIR_12 / 2 ]*/ = {
+ {189, -600, 617, 30567},
+ {117, -159, -1070, 29704},
+ {52, 221, -2392, 28276},
+ {-4, 529, -3350, 26341},
+ {-48, 758, -3956, 23973},
+ {-80, 905, -4235, 21254},
+ {-99, 972, -4222, 18278},
+ {-107, 967, -3957, 15143},
+ {-103, 896, -3487, 11950},
+ {-91, 773, -2865, 8798},
+ {-71, 611, -2143, 5784},
+ {-46, 425, -1375, 2996},};
+
+ /* Tables for 2x downsampler */
+ public static final short silk_resampler_down2_0 = 9872;
+ public static final short silk_resampler_down2_1 = 39809 - 65536;
+
+ /* Tables for 2x upsampler, high quality */
+ static final short[] silk_resampler_up2_hq_0 = {1746, 14986, 39083 - 65536};
+ static final short[] silk_resampler_up2_hq_1 = {6854, 25769, 55542 - 65536};
+
+ // from pitch_estimation_tables.c
+ static final byte[][] silk_CB_lags_stage2_10_ms
+ = {
+ new byte[]{0, 1, 0},
+ new byte[]{0, 0, 1}
+ };
+
+ static final byte[][] silk_CB_lags_stage3_10_ms
+ = {
+ new byte[]{0, 0, 1, -1, 1, -1, 2, -2, 2, -2, 3, -3},
+ new byte[]{0, 1, 0, 1, -1, 2, -1, 2, -2, 3, -2, 3}
+ };
+
+ static final byte[][] silk_CB_lags_stage2
+ /*[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ]*/ = {
+ new byte[]{0, 2, -1, -1, -1, 0, 0, 1, 1, 0, 1},
+ new byte[]{0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},
+ new byte[]{0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
+ new byte[]{0, -1, 2, 1, 0, 1, 1, 0, 0, -1, -1}
+ };
+
+ static final byte[][] silk_CB_lags_stage3/*[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ]*/ = {
+ new byte[]{0, 0, 1, -1, 0, 1, -1, 0, -1, 1, -2, 2, -2, -2, 2, -3, 2, 3, -3, -4, 3, -4, 4, 4, -5, 5, -6, -5, 6, -7, 6, 5, 8, -9},
+ new byte[]{0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 1, -1, 0, 1, -1, -1, 1, -1, 2, 1, -1, 2, -2, -2, 2, -2, 2, 2, 3, -3},
+ new byte[]{0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, -1, 1, 0, 0, 2, 1, -1, 2, -1, -1, 2, -1, 2, 2, -1, 3, -2, -2, -2, 3},
+ new byte[]{0, 1, 0, 0, 1, 0, 1, -1, 2, -1, 2, -1, 2, 3, -2, 3, -2, -2, 4, 4, -3, 5, -3, -4, 6, -4, 6, 5, -5, 8, -6, -5, -7, 9}
+ };
+
+ static final byte[][] silk_Lag_range_stage3_10_ms
+ = {
+ new byte[]{-3, 7},
+ new byte[]{-2, 7}
+ };
+
+ static final byte[][][] silk_Lag_range_stage3
+ = {
+ /* Lags to search for low number of stage3 cbks */
+ new byte[][]{
+ new byte[]{-5, 8},
+ new byte[]{-1, 6},
+ new byte[]{-1, 6},
+ new byte[]{-4, 10}
+ },
+ /* Lags to search for middle number of stage3 cbks */
+ new byte[][]{
+ new byte[]{-6, 10},
+ new byte[]{-2, 6},
+ new byte[]{-1, 6},
+ new byte[]{-5, 10}
+ },
+ /* Lags to search for max number of stage3 cbks */
+ new byte[][]{
+ new byte[]{-9, 12},
+ new byte[]{-3, 7},
+ new byte[]{-2, 7},
+ new byte[]{-7, 13}
+ }
+ };
+
+ static final byte[] silk_nb_cbk_searchs_stage3
+ = {
+ SilkConstants.PE_NB_CBKS_STAGE3_MIN,
+ SilkConstants.PE_NB_CBKS_STAGE3_MID,
+ SilkConstants.PE_NB_CBKS_STAGE3_MAX
+ };
+}
diff --git a/app/src/main/java/org/concentus/SilkVADState.java b/app/src/main/java/org/concentus/SilkVADState.java
new file mode 100644
index 0000000000..d7de8841d0
--- /dev/null
+++ b/app/src/main/java/org/concentus/SilkVADState.java
@@ -0,0 +1,101 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// VAD state
+///
+class SilkVADState {
+
+ ///
+ /// Analysis filterbank state: 0-8 kHz
+ ///
+ final int[] AnaState = new int[2];
+
+ ///
+ /// Analysis filterbank state: 0-4 kHz
+ ///
+ final int[] AnaState1 = new int[2];
+
+ ///
+ /// Analysis filterbank state: 0-2 kHz
+ ///
+ final int[] AnaState2 = new int[2];
+
+ ///
+ /// Subframe energies
+ ///
+ final int[] XnrgSubfr = new int[SilkConstants.VAD_N_BANDS];
+
+ ///
+ /// Smoothed energy level in each band
+ ///
+ final int[] NrgRatioSmth_Q8 = new int[SilkConstants.VAD_N_BANDS];
+
+ ///
+ /// State of differentiator in the lowest band
+ ///
+ short HPstate = 0;
+
+ ///
+ /// Noise energy level in each band
+ ///
+ final int[] NL = new int[SilkConstants.VAD_N_BANDS];
+
+ ///
+ /// Inverse noise energy level in each band
+ ///
+ final int[] inv_NL = new int[SilkConstants.VAD_N_BANDS];
+
+ ///
+ /// Noise level estimator bias/offset
+ ///
+ final int[] NoiseLevelBias = new int[SilkConstants.VAD_N_BANDS];
+
+ ///
+ /// Frame counter used in the initial phase
+ ///
+ int counter = 0;
+
+ void Reset() {
+ Arrays.MemSet(AnaState, 0, 2);
+ Arrays.MemSet(AnaState1, 0, 2);
+ Arrays.MemSet(AnaState2, 0, 2);
+ Arrays.MemSet(XnrgSubfr, 0, SilkConstants.VAD_N_BANDS);
+ Arrays.MemSet(NrgRatioSmth_Q8, 0, SilkConstants.VAD_N_BANDS);
+ HPstate = 0;
+ Arrays.MemSet(NL, 0, SilkConstants.VAD_N_BANDS);
+ Arrays.MemSet(inv_NL, 0, SilkConstants.VAD_N_BANDS);
+ Arrays.MemSet(NoiseLevelBias, 0, SilkConstants.VAD_N_BANDS);
+ counter = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/Sort.java b/app/src/main/java/org/concentus/Sort.java
new file mode 100644
index 0000000000..5b1201261a
--- /dev/null
+++ b/app/src/main/java/org/concentus/Sort.java
@@ -0,0 +1,175 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class Sort {
+
+ ///
+ ///
+ ///
+ /// (I/O) Unsorted / Sorted vector
+ /// (O) Index vector for the sorted elements
+ /// (I) Vector length
+ /// (I) Number of correctly sorted positions
+ 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 */
+ }
+ }
+ }
+
+ ///
+ /// 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
+ ///
+ /// (I/O) Unsorted / Sorted vector
+ /// (I) Vector length
+ 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 */
+ 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 */
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/SpeexResampler.java b/app/src/main/java/org/concentus/SpeexResampler.java
new file mode 100644
index 0000000000..0bc1dc766c
--- /dev/null
+++ b/app/src/main/java/org/concentus/SpeexResampler.java
@@ -0,0 +1,911 @@
+/* Copyright (C) 2007-2008 Jean-Marc Valin
+ Copyright (C) 2008 Thorvald Natvig
+ Ported to Java by Logan Stromberg
+
+ File: Resampler.cs
+ Arbitrary resampling code
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. 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.
+
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+*/
+
+/*
+ The design goals of this code are:
+ - Very fast algorithm
+ - SIMD-friendly algorithm
+ - Low memory requirement
+ - Good *perceptual* quality (and not best SNR)
+
+ Warning: This resampler is relatively new. Although I think I got rid of
+ all the major bugs and I don't expect the API to change anymore, there
+ may be something I've missed. So use with caution.
+
+ This algorithm is based on this original resampling algorithm:
+ Smith, Julius O. Digital Audio Resampling Home Page
+ Center for Computer Research in Music and Acoustics (CCRMA),
+ Stanford University, 2007.
+ Web published at http://www-ccrma.stanford.edu/~jos/resample/.
+
+ There is one main difference, though. This resampler uses cubic
+ interpolation instead of linear interpolation in the above paper. This
+ makes the table much smaller and makes it possible to compute that table
+ on a per-stream basis. In turn, being able to tweak the table for each
+ stream makes it possible to both reduce complexity on simple ratios
+ (e.g. 2/3), and get rid of the rounding operations in the inner loop.
+ The latter both reduces CPU time and makes the algorithm more SIMD-friendly.
+*/
+
+package org.concentus;
+
+//public class SpeexResampler
+//{
+// private final int FIXED_STACK_ALLOC = 8192;
+//
+// private int in_rate = 0;
+// private int out_rate = 0;
+// private int num_rate = 0;
+// private int den_rate = 0;
+//
+// private int quality = 0;
+// private int nb_channels = 0;
+// private int filt_len = 0;
+// private int mem_alloc_size = 0;
+// private int buffer_size = 0;
+// private int int_advance = 0;
+// private int frac_advance = 0;
+// private float cutoff = 0;
+// private int oversample = 0;
+// private int initialised = 0;
+// private int started = 0;
+//
+// /* These are per-channel */
+// private int[] last_sample = null;
+// private int[] samp_frac_num = null;
+// private int[] magic_samples = null;
+//
+// private short[] mem = null;
+// private short[] sinc_table = null;
+// private int sinc_table_length = 0;
+//
+// int in_stride = 0;
+// int out_stride = 0;
+//
+// ///
+// /// Create() is the only way to make a resampler instance publically
+// ///
+// private SpeexResampler() { }
+//
+// private class FuncDef
+// {
+// public FuncDef(double[] t, int os)
+// {
+// table = t;
+// oversample = os;
+// }
+//
+// public double[] table;
+// public int oversample;
+// };
+//
+// private class QualityMapping
+// {
+// public int base_length = 0;
+// public int oversample = 0;
+// public float downsample_bandwidth = 0;
+// public float upsample_bandwidth = 0;
+// public FuncDef window_func = null;
+//
+// private QualityMapping(int bl, int os, float dsb, float usb, FuncDef wf)
+// {
+// base_length = bl;
+// oversample = os;
+// downsample_bandwidth = dsb;
+// upsample_bandwidth = usb;
+// window_func = wf;
+// }
+//
+// public final double[] kaiser12_table/*[68]*/ = {
+// 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
+// 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,
+// 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,
+// 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,
+// 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,
+// 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,
+// 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,
+// 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,
+// 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,
+// 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,
+// 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,
+// 0.00001000, 0.00000000};
+// /*
+// static double kaiser12_table[36] = {
+// 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,
+// 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,
+// 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,
+// 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,
+// 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,
+// 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};
+// */
+// public final double[] kaiser10_table/*[36]*/ = {
+// 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
+// 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,
+// 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,
+// 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,
+// 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,
+// 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};
+//
+// public final double[] kaiser8_table/*[36]*/ = {
+// 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
+// 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,
+// 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,
+// 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
+// 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
+// 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
+//
+// public final double[] kaiser6_table/*[36]*/ = {
+// 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
+// 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
+// 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,
+// 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,
+// 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,
+// 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};
+//
+// /* This table maps conversion quality to private parameters. There are two
+// reasons that explain why the up-sampling bandwidth is larger than the
+// down-sampling bandwidth:
+// 1) When up-sampling, we can assume that the spectrum is already attenuated
+// close to the Nyquist rate (from an A/D or a previous resampling filter)
+// 2) Any aliasing that occurs very close to the Nyquist rate will be masked
+// by the sinusoids/noise just below the Nyquist rate (guaranteed only for
+// up-sampling).
+// */
+// public final QualityMapping[] quality_map = {
+// new QualityMapping( 8, 4, 0.830f, 0.860f, new FuncDef(kaiser6_table, 32) ), /* Q0 */
+// new QualityMapping( 16, 4, 0.850f, 0.880f, new FuncDef(kaiser6_table, 32) ), /* Q1 */
+// new QualityMapping( 32, 4, 0.882f, 0.910f, new FuncDef(kaiser6_table, 32) ), /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */
+// new QualityMapping( 48, 8, 0.895f, 0.917f, new FuncDef(kaiser8_table, 32) ), /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */
+// new QualityMapping( 64, 8, 0.921f, 0.940f, new FuncDef(kaiser8_table, 32) ), /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */
+// new QualityMapping( 80, 16, 0.922f, 0.940f, new FuncDef(kaiser10_table, 32)), /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */
+// new QualityMapping( 96, 16, 0.940f, 0.945f, new FuncDef(kaiser10_table, 32)), /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */
+// new QualityMapping(128, 16, 0.950f, 0.950f, new FuncDef(kaiser10_table, 32)), /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */
+// new QualityMapping(160, 16, 0.960f, 0.960f, new FuncDef(kaiser10_table, 32)), /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */
+// new QualityMapping(192, 32, 0.968f, 0.968f, new FuncDef(kaiser12_table, 64)), /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */
+// new QualityMapping(256, 32, 0.975f, 0.975f, new FuncDef(kaiser12_table, 64)), /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */
+// };
+// }
+//
+// private static short WORD2INT(float x)
+// {
+// return x < Short.MIN_VALUE ? Short.MIN_VALUE : (x > Short.MAX_VALUE ? Short.MAX_VALUE : (short)x);
+// }
+//
+// /*8,24,40,56,80,104,128,160,200,256,320*/
+// private static double compute_func(float x, FuncDef func)
+// {
+// float y, frac;
+// double interp0, interp1, interp2, interp3;
+// int ind;
+// y = x * func.oversample;
+// ind = (int)Math.floor(y);
+// frac = (y - ind);
+// /* CSE with handle the repeated powers */
+// interp3 = -0.1666666667 * frac + 0.1666666667 * (frac * frac * frac);
+// interp2 = frac + 0.5 * (frac * frac) - 0.5 * (frac * frac * frac);
+// /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
+// interp0 = -0.3333333333 * frac + 0.5 * (frac * frac) - 0.1666666667 * (frac * frac * frac);
+// /* Just to make sure we don't have rounding problems */
+// interp1 = 1.0f - interp3 - interp2 - interp0;
+//
+// /*sum = frac*accum[1] + (1-frac)*accum[2];*/
+// return interp0 * func.table[ind] + interp1 * func.table[ind + 1] + interp2 * func.table[ind + 2] + interp3 * func.table[ind + 3];
+// }
+//
+// /* The slow way of computing a sinc for the table. Should improve that some day */
+// private static short sinc(float cutoff, float x, int N, FuncDef window_func)
+// {
+// /*fprintf (stderr, "%f ", x);*/
+// float xx = x * cutoff;
+// if (Math.abs(x) < 1e-6f)
+// return WORD2INT(32768.0f * cutoff);
+// else if (Math.abs(x) > .5f * N)
+// return 0;
+// /*FIXME: Can it really be any slower than this? */
+// return WORD2INT(32768.0f * cutoff * (float)Math.sin((float)Math.PI * xx) / ((float)Math.PI * xx) * (float)compute_func(Math.abs(2.0f * x / N), window_func));
+// }
+//
+// private static void cubic_coef(short x, BoxedValueShort interp0, BoxedValueShort interp1, BoxedValueShort interp2, BoxedValueShort interp3)
+// {
+// /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
+// but I know it's MMSE-optimal on a sinc */
+// short x2, x3;
+// x2 = Inlines.MULT16_16_P15(x, x);
+// x3 = Inlines.MULT16_16_P15(x, x2);
+// interp0.Val = (short)Inlines.PSHR32(Inlines.MULT16_16(Inlines.QCONST16(-0.16667f, 15), x) + Inlines.MULT16_16(Inlines.QCONST16(0.16667f, 15), x3), 15);
+// interp1.Val = Inlines.EXTRACT16(Inlines.EXTEND32(x) + Inlines.SHR32(Inlines.SUB32(Inlines.EXTEND32(x2), Inlines.EXTEND32(x3)), 1));
+// interp3.Val = (short)Inlines.PSHR32(Inlines.MULT16_16(Inlines.QCONST16(-0.33333f, 15), x) + Inlines.MULT16_16(Inlines.QCONST16(.5f, 15), x2) - Inlines.MULT16_16(Inlines.QCONST16(0.16667f, 15), x3), 15);
+// /* Just to make sure we don't have rounding problems */
+// interp2.Val = (short)(CeltConstants.Q15_ONE - interp0.Val - interp1.Val - interp3.Val);
+// if (interp2.Val < 32767)
+// interp2.Val += 1;
+// }
+//
+// private int resampler_basic_direct_single(int channel_index, short[] input, int input_ptr, BoxedValueInt in_len, short[] output, int output_ptr, BoxedValueInt out_len)
+// {
+// int N = this.filt_len;
+// int out_sample = 0;
+// int last_sample = this.last_sample[channel_index];
+// int samp_frac_num = this.samp_frac_num[channel_index];
+//
+// int sum;
+//
+// while (!(last_sample >= in_len.Val || out_sample >= out_len.Val))
+// {
+// int sinct = (int)samp_frac_num * N;
+// int iptr = input_ptr + last_sample;
+//
+// int j;
+// sum = 0;
+// for (j = 0; j < N; j++)
+// {
+// sum += Inlines.MULT16_16(this.sinc_table[sinct + j], input[iptr + j]);
+// }
+//
+// output[output_ptr + (this.out_stride * out_sample++)] = Inlines.SATURATE16(Inlines.PSHR32(sum, 15));
+// last_sample += this.int_advance;
+// samp_frac_num += (int)this.frac_advance;
+// if (samp_frac_num >= this.den_rate)
+// {
+// samp_frac_num -= this.den_rate;
+// last_sample++;
+// }
+// }
+//
+// this.last_sample[channel_index] = last_sample;
+// this.samp_frac_num[channel_index] = samp_frac_num;
+// return out_sample;
+// }
+//
+// private int resampler_basic_interpolate_single(int channel_index, short[] input, int input_ptr, BoxedValueInt in_len, short[] output, int output_ptr, BoxedValueInt out_len)
+// {
+// int N = this.filt_len;
+// int out_sample = 0;
+// int last_sample = this.last_sample[channel_index];
+// int samp_frac_num = this.samp_frac_num[channel_index];
+// int sum;
+// BoxedValueShort interp0 = new BoxedValueShort((short)0);
+// BoxedValueShort interp1 = new BoxedValueShort((short)0);
+// BoxedValueShort interp2 = new BoxedValueShort((short)0);
+// BoxedValueShort interp3 = new BoxedValueShort((short)0);
+// while (!(last_sample >= in_len.Val || out_sample >= out_len.Val))
+// {
+// int iptr = input_ptr + last_sample;
+//
+// int offset = samp_frac_num * this.oversample / this.den_rate;
+// short frac = (short)Inlines.PDIV32(Inlines.SHL32((samp_frac_num * this.oversample) % this.den_rate, 15), this.den_rate);
+//
+// int j;
+// int accum0 = 0;
+// int accum1 = 0;
+// int accum2 = 0;
+// int accum3 = 0;
+//
+// for (j = 0; j < N; j++)
+// {
+// short curr_in = input[iptr + j];
+// accum0 += Inlines.MULT16_16(curr_in, this.sinc_table[4 + (j + 1) * (int)this.oversample - offset - 2]);
+// accum1 += Inlines.MULT16_16(curr_in, this.sinc_table[4 + (j + 1) * (int)this.oversample - offset - 1]);
+// accum2 += Inlines.MULT16_16(curr_in, this.sinc_table[4 + (j + 1) * (int)this.oversample - offset]);
+// accum3 += Inlines.MULT16_16(curr_in, this.sinc_table[4 + (j + 1) * (int)this.oversample - offset + 1]);
+// }
+//
+// cubic_coef(frac, interp0, interp1, interp2, interp3);
+// sum = Inlines.MULT16_32_Q15(interp0.Val, Inlines.SHR32(accum0, 1)) +
+// Inlines.MULT16_32_Q15(interp1.Val, Inlines.SHR32(accum1, 1)) +
+// Inlines.MULT16_32_Q15(interp2.Val, Inlines.SHR32(accum2, 1)) +
+// Inlines.MULT16_32_Q15(interp3.Val, Inlines.SHR32(accum3, 1));
+//
+// output[output_ptr + (out_stride * out_sample++)] = Inlines.SATURATE16(Inlines.PSHR32(sum, 14));
+// last_sample += int_advance;
+// samp_frac_num += (int)frac_advance;
+// if (samp_frac_num >= den_rate)
+// {
+// samp_frac_num -= den_rate;
+// last_sample++;
+// }
+// }
+//
+// this.last_sample[channel_index] = last_sample;
+// this.samp_frac_num[channel_index] = samp_frac_num;
+// return out_sample;
+// }
+//
+// private void update_filter()
+// {
+// int old_length;
+//
+// old_length = this.filt_len;
+// this.oversample = QualityMapping.quality_map[this.quality].oversample;
+// this.filt_len = QualityMapping.quality_map[this.quality].base_length;
+//
+// if (this.num_rate > this.den_rate)
+// {
+// /* down-sampling */
+// this.cutoff = QualityMapping.quality_map[this.quality].downsample_bandwidth * this.den_rate / this.num_rate;
+// /* FIXME: divide the numerator and denominator by a certain amount if they're too large */
+// this.filt_len = this.filt_len * this.num_rate / this.den_rate;
+// /* Round up to make sure we have a multiple of 8 */
+// this.filt_len = ((this.filt_len - 1) & (~0x7)) + 8;
+// if (2 * this.den_rate < this.num_rate)
+// this.oversample >>= 1;
+// if (4 * this.den_rate < this.num_rate)
+// this.oversample >>= 1;
+// if (8 * this.den_rate < this.num_rate)
+// this.oversample >>= 1;
+// if (16 * this.den_rate < this.num_rate)
+// this.oversample >>= 1;
+// if (this.oversample < 1)
+// this.oversample = 1;
+// }
+// else {
+// /* up-sampling */
+// this.cutoff = QualityMapping.quality_map[this.quality].upsample_bandwidth;
+// }
+//
+// if (this.den_rate <= 16 * (this.oversample + 8))
+// {
+// int i;
+// if (this.sinc_table == null)
+// this.sinc_table = new short[this.filt_len * this.den_rate];
+// else if (this.sinc_table_length < this.filt_len * this.den_rate)
+// {
+// this.sinc_table = new short[this.filt_len * this.den_rate];
+// this.sinc_table_length = this.filt_len * this.den_rate;
+// }
+// for (i = 0; i < this.den_rate; i++)
+// {
+// int j;
+// for (j = 0; j < this.filt_len; j++)
+// {
+// this.sinc_table[i * this.filt_len + j] = sinc(this.cutoff, ((j - (int)this.filt_len / 2 + 1) - ((float)i) / this.den_rate), this.filt_len, QualityMapping.quality_map[this.quality].window_func);
+// }
+// }
+// this.resampler_ptr = resampler_basic_direct_single;
+// /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
+// }
+// else {
+// int i;
+// if (this.sinc_table == null)
+// this.sinc_table = new short[this.filt_len * this.oversample + 8];
+// else if (this.sinc_table_length < this.filt_len * this.oversample + 8)
+// {
+// this.sinc_table = new short[this.filt_len * this.oversample + 8];
+// this.sinc_table_length = this.filt_len * this.oversample + 8;
+// }
+// for (i = -4; i < (int)(this.oversample * this.filt_len + 4); i++)
+// this.sinc_table[i + 4] = sinc(this.cutoff, (i / (float)this.oversample - this.filt_len / 2), this.filt_len, QualityMapping.quality_map[this.quality].window_func);
+// this.resampler_ptr = resampler_basic_interpolate_single;
+// /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
+// }
+// this.int_advance = this.num_rate / this.den_rate;
+// this.frac_advance = this.num_rate % this.den_rate;
+//
+//
+// /* Here's the place where we update the filter memory to take into account
+// the change in filter length. It's probably the messiest part of the code
+// due to handling of lots of corner cases. */
+// if (this.mem == null)
+// {
+// int i;
+// this.mem_alloc_size = this.filt_len - 1 + this.buffer_size;
+// this.mem = new short[this.nb_channels * this.mem_alloc_size];
+// for (i = 0; i < this.nb_channels * this.mem_alloc_size; i++)
+// this.mem[i] = 0;
+// /*speex_warning("init filter");*/
+// }
+// else if (this.started == 0)
+// {
+// int i;
+// this.mem_alloc_size = this.filt_len - 1 + this.buffer_size;
+// this.mem = new short[this.nb_channels * this.mem_alloc_size];
+// for (i = 0; i < this.nb_channels * this.mem_alloc_size; i++)
+// this.mem[i] = 0;
+// /*speex_warning("reinit filter");*/
+// }
+// else if (this.filt_len > old_length)
+// {
+// int i;
+// /* Increase the filter length */
+// /*speex_warning("increase filter size");*/
+// int old_alloc_size = this.mem_alloc_size;
+// if ((this.filt_len - 1 + this.buffer_size) > this.mem_alloc_size)
+// {
+// this.mem_alloc_size = this.filt_len - 1 + this.buffer_size;
+// this.mem = new short[this.nb_channels * this.mem_alloc_size];
+// }
+// for (i = this.nb_channels - 1; i >= 0; i--)
+// {
+// int j;
+// int olen = old_length;
+// /*if (st.magic_samples[i])*/
+// {
+// /* Try and remove the magic samples as if nothing had happened */
+//
+// /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
+// olen = old_length + 2 * this.magic_samples[i];
+// for (j = old_length - 2 + this.magic_samples[i]; j >= 0; j--)
+// this.mem[i * this.mem_alloc_size + j + this.magic_samples[i]] = this.mem[i * old_alloc_size + j];
+// for (j = 0; j < this.magic_samples[i]; j++)
+// this.mem[i * this.mem_alloc_size + j] = 0;
+// this.magic_samples[i] = 0;
+// }
+// if (this.filt_len > olen)
+// {
+// /* If the new filter length is still bigger than the "augmented" length */
+// /* Copy data going backward */
+// for (j = 0; j < olen - 1; j++)
+// this.mem[i * this.mem_alloc_size + (this.filt_len - 2 - j)] = this.mem[i * this.mem_alloc_size + (olen - 2 - j)];
+// /* Then put zeros for lack of anything better */
+// for (; j < this.filt_len - 1; j++)
+// this.mem[i * this.mem_alloc_size + (this.filt_len - 2 - j)] = 0;
+// /* Adjust last_sample */
+// this.last_sample[i] += (this.filt_len - olen) / 2;
+// }
+// else {
+// /* Put back some of the magic! */
+// this.magic_samples[i] = (olen - this.filt_len) / 2;
+// for (j = 0; j < this.filt_len - 1 + this.magic_samples[i]; j++)
+// this.mem[i * this.mem_alloc_size + j] = this.mem[i * this.mem_alloc_size + j + this.magic_samples[i]];
+// }
+// }
+// }
+// else if (this.filt_len < old_length)
+// {
+// int i;
+// /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
+// samples so they can be used directly as input the next time(s) */
+// for (i = 0; i < this.nb_channels; i++)
+// {
+// int j;
+// int old_magic = this.magic_samples[i];
+// this.magic_samples[i] = (old_length - this.filt_len) / 2;
+// /* We must copy some of the memory that's no longer used */
+// /* Copy data going backward */
+// for (j = 0; j < this.filt_len - 1 + this.magic_samples[i] + old_magic; j++)
+// this.mem[i * this.mem_alloc_size + j] = this.mem[i * this.mem_alloc_size + j + this.magic_samples[i]];
+// this.magic_samples[i] += old_magic;
+// }
+// }
+// }
+//
+// private void speex_resampler_process_native(int channel_index, BoxedValueInt in_len, short[] output, int output_ptr, BoxedValueInt out_len)
+// {
+// int j = 0;
+// int N = this.filt_len;
+// int out_sample = 0;
+// int mem_ptr = channel_index * this.mem_alloc_size;
+// int ilen;
+//
+// this.started = 1;
+//
+// /* Call the right resampler through the function ptr */
+// out_sample = this.resampler_ptr(channel_index, this.mem, mem_ptr, ref in_len, output, output_ptr, ref out_len);
+//
+// if (this.last_sample[channel_index] < (int)in_len.Val)
+// in_len.Val = this.last_sample[channel_index];
+// out_len = out_sample;
+// this.last_sample[channel_index] -= in_len;
+//
+// ilen = in_len.Val;
+//
+// for (j = mem_ptr; j < N - 1 + mem_ptr; ++j)
+// this.mem[j] = this.mem[j + ilen];
+// }
+//
+// private int speex_resampler_magic(int channel_index, short[] output, BoxedValueInt output_ptr, int out_len)
+// {
+// int tmp_in_len = this.magic_samples[channel_index];
+// int mem_ptr = channel_index * this.mem_alloc_size;
+// int N = this.filt_len;
+//
+// this.speex_resampler_process_native(channel_index, ref tmp_in_len, output, output_ptr, ref out_len);
+//
+// this.magic_samples[channel_index] -= tmp_in_len;
+//
+// /* If we couldn't process all "magic" input samples, save the rest for next time */
+// if (this.magic_samples[channel_index] != 0)
+// {
+// int i;
+// for (i = mem_ptr; i < this.magic_samples[channel_index] + mem_ptr; i++)
+// this.mem[N - 1 + i] = this.mem[N - 1 + i + tmp_in_len];
+// }
+// output_ptr.Val += out_len * this.out_stride;
+// return out_len;
+// }
+//
+// ///
+// /// Create a new resampler with integer input and output rates (in hertz).
+// ///
+// /// The number of channels to be processed
+// /// Input sampling rate, in hertz
+// /// Output sampling rate, in hertz
+// /// Resampling quality, from 0 to 10
+// /// A newly created restampler
+// public static SpeexResampler Create(int nb_channels, int in_rate, int out_rate, int quality)
+// {
+// return Create(nb_channels, in_rate, out_rate, in_rate, out_rate, quality);
+// }
+//
+// ///
+// /// Create a new resampler with fractional input/output rates. The sampling
+// /// rate ratio is an arbitrary rational number with both the numerator and
+// /// denominator being 32-bit integers.
+// ///
+// /// The number of channels to be processed
+// /// Numerator of sampling rate ratio
+// /// Denominator of sampling rate ratio
+// /// Input sample rate rounded to the nearest integer (in hz)
+// /// Output sample rate rounded to the nearest integer (in hz)
+// /// Resampling quality, from 0 to 10
+// /// A newly created restampler
+// public static SpeexResampler Create(int nb_channels, int ratio_num, int ratio_den, int in_rate, int out_rate, int quality)
+// {
+// int i;
+// SpeexResampler st;
+// if (quality > 10 || quality < 0)
+// {
+// throw new IllegalArgumentException("Quality must be between 0 and 10");
+// }
+// st = new SpeexResampler();
+// st.initialised = 0;
+// st.started = 0;
+// st.in_rate = 0;
+// st.out_rate = 0;
+// st.num_rate = 0;
+// st.den_rate = 0;
+// st.quality = -1;
+// st.sinc_table_length = 0;
+// st.mem_alloc_size = 0;
+// st.filt_len = 0;
+// st.mem = null;
+// st.cutoff = 1.0f;
+// st.nb_channels = nb_channels;
+// st.in_stride = 1;
+// st.out_stride = 1;
+// st.buffer_size = 160;
+//
+// /* Per channel data */
+// st.last_sample = new int[nb_channels];
+// st.magic_samples = new int[nb_channels];
+// st.samp_frac_num = new int[nb_channels];
+// for (i = 0; i < nb_channels; i++)
+// {
+// st.last_sample[i] = 0;
+// st.magic_samples[i] = 0;
+// st.samp_frac_num[i] = 0;
+// }
+//
+// st.Quality = quality;
+// st.SetRateFraction(ratio_num, ratio_den, in_rate, out_rate);
+//
+// st.update_filter();
+//
+// st.initialised = 1;
+//
+// return st;
+// }
+//
+// public class ResamplerResult
+// {
+// ResamplerResult(int in_len, int out_len)
+// {
+// inputSamplesProcessed = in_len;
+// outputSamplesGenerated = out_len;
+// }
+//
+// int inputSamplesProcessed;
+// int outputSamplesGenerated;
+// }
+//
+// ///
+// /// Resample an int array. The input and output buffers must *not* overlap
+// ///
+// /// The index of the channel to process (for multichannel input, 0 otherwise)
+// /// Input buffer
+// /// Offset to start from when reading input
+// /// Number of input samples in the input buffer. After this function returns, this value
+// /// will be set to the number of input samples actually processed
+// /// Output buffer
+// /// Offset to start from when writing output
+// /// Size of the output buffer. After this function returns, this value will be set to the number
+// /// of output samples actually produced
+// public ResamplerResult Process(int channel_index, short[] input, int input_ptr, int in_len, short[] output, int output_ptr, int out_len)
+// {
+// int j;
+// int ilen = in_len;
+// int olen = out_len;
+// int x = channel_index * this.mem_alloc_size;
+// int filt_offs = this.filt_len - 1;
+// int xlen = this.mem_alloc_size - filt_offs;
+// int istride = this.in_stride;
+//
+// if (this.magic_samples[channel_index] != 0)
+// {
+// olen -= this.speex_resampler_magic(channel_index, output, ref output_ptr, olen);
+// }
+// if (this.magic_samples[channel_index] == 0)
+// {
+// while (ilen != 0 && olen != 0)
+// {
+// int ichunk = (ilen > xlen) ? xlen : ilen;
+// int ochunk = olen;
+//
+// if (input != null)
+// {
+// for (j = 0; j < ichunk; ++j)
+// this.mem[x + j + filt_offs] = input[input_ptr + j * istride];
+// }
+// else {
+// for (j = 0; j < ichunk; ++j)
+//
+// this.mem[x + j + filt_offs] = 0;
+// }
+// this.speex_resampler_process_native(channel_index, ref ichunk, output, output_ptr, ref ochunk);
+// ilen -= ichunk;
+// olen -= ochunk;
+// output_ptr += ochunk * this.out_stride;
+// if (input != null)
+//
+// input_ptr += ichunk * istride;
+// }
+// }
+// return new ResamplerResult(in_len - ilen, out_len - olen);
+// }
+//
+// ///
+// /// Resamples an interleaved float array. The stride is automatically determined by the number of channels of the resampler.
+// ///
+// /// Input buffer
+// /// Offset to start from when reading input
+// /// The number of samples *PER-CHANNEL* in the input buffer. After this function returns, this
+// /// value will be set to the number of input samples actually processed
+// /// Output buffer
+// /// Offset to start from when writing output
+// /// The size of the output buffer in samples-per-channel. After this function returns, this value
+// /// will be set to the number of samples per channel actually produced
+// public ResamplerResult ProcessInterleaved(short[] input, int input_ptr, int in_len, short[] output, int output_ptr, int out_len)
+// {
+// int i;
+// int istride_save, ostride_save;
+// int bak_out_len = out_len;
+// int bak_in_len = in_len;
+// istride_save = this.in_stride;
+// ostride_save = this.out_stride;
+// this.in_stride = this.out_stride = this.nb_channels;
+// for (i = 0; i < this.nb_channels; i++)
+// {
+// out_len = bak_out_len;
+// in_len = bak_in_len;
+// ResamplerResult r;
+// if (input != null)
+// {
+// r = this.Process(i, input, input_ptr + i, in_len, output, output_ptr + i, out_len);
+// }
+// else
+// {
+// r = this.Process(i, null, 0, in_len, output, output_ptr + i, out_len);
+// }
+//
+// in_len = r.inputSamplesProcessed;
+// out_len = r.outputSamplesGenerated;
+// }
+// this.in_stride = istride_save;
+// this.out_stride = ostride_save;
+//
+// return new ResamplerResult(in_len, out_len);
+// }
+//
+// ///
+// /// Make sure that the first samples to go out of the resamplers don't have
+// /// leading zeros. This is only useful before starting to use a newly created
+// /// resampler. It is recommended to use that when resampling an audio file, as
+// /// it will generate a file with the same length.For real-time processing,
+// /// it is probably easier not to use this call (so that the output duration
+// /// is the same for the first frame).
+// ///
+// public void SkipZeroes()
+// {
+// int i;
+// for (i = 0; i < this.nb_channels; i++)
+// this.last_sample[i] = this.filt_len / 2;
+// }
+//
+// ///
+// /// Clears the resampler buffers so a new (unrelated) stream can be processed.
+// ///
+// public void ResetMem()
+// {
+// int i;
+// for (i = 0; i < this.nb_channels; i++)
+// {
+// this.last_sample[i] = 0;
+// this.magic_samples[i] = 0;
+// this.samp_frac_num[i] = 0;
+// }
+// for (i = 0; i < this.nb_channels * (this.filt_len - 1); i++)
+// this.mem[i] = 0;
+// }
+//
+// ///
+// /// Sets the input and output rates
+// ///
+// /// Input sampling rate, in hertz
+// /// Output sampling rate, in hertz
+// public void SetRates(int in_rate, int out_rate)
+// {
+// this.SetRateFraction(in_rate, out_rate, in_rate, out_rate);
+// }
+//
+// ///
+// /// Get the current input/output sampling rates (integer value).
+// ///
+// /// (Output) Sampling rate of input
+// /// (Output) Sampling rate of output
+// public void GetRates(out int in_rate, out int out_rate)
+// {
+// in_rate = this.in_rate;
+// out_rate = this.out_rate;
+// }
+//
+// ///
+// /// Sets the input/output sampling rates and resampling ration (fractional values in Hz supported)
+// ///
+// /// Numerator of the sampling rate ratio
+// /// Denominator of the sampling rate ratio
+// /// Input sampling rate rounded to the nearest integer (in Hz)
+// /// Output sampling rate rounded to the nearest integer (in Hz)
+// public void SetRateFraction(int ratio_num, int ratio_den, int in_rate, int out_rate)
+// {
+// int fact;
+// int old_den;
+// int i;
+// if (this.in_rate == in_rate && this.out_rate == out_rate && this.num_rate == ratio_num && this.den_rate == ratio_den)
+// return;
+//
+// old_den = this.den_rate;
+// this.in_rate = in_rate;
+// this.out_rate = out_rate;
+// this.num_rate = ratio_num;
+// this.den_rate = ratio_den;
+// /* FIXME: This is terribly inefficient, but who cares (at least for now)? */
+// for (fact = 2; fact <= Inlines.IMIN(this.num_rate, this.den_rate); fact++)
+// {
+// while ((this.num_rate % fact == 0) && (this.den_rate % fact == 0))
+// {
+// this.num_rate /= fact;
+// this.den_rate /= fact;
+// }
+// }
+//
+// if (old_den > 0)
+// {
+// for (i = 0; i < this.nb_channels; i++)
+// {
+// this.samp_frac_num[i] = this.samp_frac_num[i] * this.den_rate / old_den;
+// /* Safety net */
+// if (this.samp_frac_num[i] >= this.den_rate)
+// this.samp_frac_num[i] = this.den_rate - 1;
+// }
+// }
+//
+// if (this.initialised != 0)
+// this.update_filter();
+// }
+//
+// ///
+// /// Gets the current resampling ratio. This will be reduced to the least common denominator
+// ///
+// /// (Output) numerator of the sampling rate ratio
+// /// (Output) denominator of the sampling rate ratio
+// public void GetRateFraction(out int ratio_num, out int ratio_den)
+// {
+// ratio_num = this.num_rate;
+// ratio_den = this.den_rate;
+// }
+//
+// ///
+// /// Gets or sets the resampling quality between 0 and 10, where 0 has poor
+// /// quality and 10 has very high quality.
+// ///
+// public int Quality
+// {
+// get
+// {
+// return this.quality;
+// }
+// set
+// {
+// if (value > 10 || value < 0)
+// throw new IllegalArgumentException("Quality must be between 0 and 10");
+// if (this.quality == value)
+// return;
+// this.quality = value;
+// if (this.initialised != 0)
+// this.update_filter();
+// }
+// }
+//
+// ///
+// /// Gets or sets the input stride
+// ///
+// public int InputStride
+// {
+// get
+// {
+// return this.in_stride;
+// }
+// set
+// {
+// this.in_stride = value;
+// }
+// }
+//
+// ///
+// /// Gets or sets the output stride
+// ///
+// public int OutputStride
+// {
+// get
+// {
+// return this.out_stride;
+// }
+// set
+// {
+// this.out_stride = value;
+// }
+// }
+//
+// ///
+// /// Get the latency introduced by the resampler measured in input samples.
+// ///
+// public int InputLatency
+// {
+// get
+// {
+// return this.filt_len / 2;
+// }
+// }
+//
+// ///
+// /// Gets the latency introduced by the resampler measured in output samples.
+// ///
+// public int OutputLatency
+// {
+// get
+// {
+// return ((this.filt_len / 2) * this.den_rate + (this.num_rate >> 1)) / this.num_rate;
+// }
+// }
+//}
\ No newline at end of file
diff --git a/app/src/main/java/org/concentus/Spread.java b/app/src/main/java/org/concentus/Spread.java
new file mode 100644
index 0000000000..f03bbeae82
--- /dev/null
+++ b/app/src/main/java/org/concentus/Spread.java
@@ -0,0 +1,43 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class Spread {
+
+ public static final int SPREAD_NONE = 0;
+ public static final int SPREAD_LIGHT = 1;
+ public static final int SPREAD_NORMAL = 2;
+ public static final int SPREAD_AGGRESSIVE = 3;
+}
diff --git a/app/src/main/java/org/concentus/Stereo.java b/app/src/main/java/org/concentus/Stereo.java
new file mode 100644
index 0000000000..aa1f3a724f
--- /dev/null
+++ b/app/src/main/java/org/concentus/Stereo.java
@@ -0,0 +1,509 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class Stereo {
+
+ ///
+ /// Decode mid/side predictors
+ ///
+ /// I/O Compressor data structure
+ /// O Predictors
+ static void silk_stereo_decode_pred(
+ EntropyCoder psRangeDec,
+ int[] pred_Q13) {
+ int n;
+ int[][] ix = Arrays.InitTwoDimensionalArrayInt(2, 3);
+ int low_Q13, step_Q13;
+
+ // Entropy decoding
+ n = psRangeDec.dec_icdf(SilkTables.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(SilkTables.silk_uniform3_iCDF, 8);
+ ix[n][1] = psRangeDec.dec_icdf(SilkTables.silk_uniform5_iCDF, 8);
+ }
+
+ // Dequantize
+ for (n = 0; n < 2; n++) {
+ ix[n][0] += 3 * ix[n][2];
+ low_Q13 = SilkTables.silk_stereo_pred_quant_Q13[ix[n][0]];
+ step_Q13 = Inlines.silk_SMULWB(SilkTables.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];
+ }
+
+ ///
+ /// Decode mid-only flag
+ ///
+ /// I/O Compressor data structure
+ /// O Flag that only mid channel has been coded
+ 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(SilkTables.silk_stereo_only_code_mid_iCDF, 8);
+ }
+
+ ///
+ /// Entropy code the mid/side quantization indices
+ ///
+ /// I/O Compressor data structure
+ /// I Quantization indices [ 2 ][ 3 ]
+ static void silk_stereo_encode_pred(EntropyCoder psRangeEnc, byte[][] ix) {
+ int n;
+
+ /* Entropy coding */
+ n = 5 * ix[0][2] + ix[1][2];
+ Inlines.OpusAssert(n < 25);
+ psRangeEnc.enc_icdf(n, SilkTables.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], SilkTables.silk_uniform3_iCDF, 8);
+ psRangeEnc.enc_icdf(ix[n][1], SilkTables.silk_uniform5_iCDF, 8);
+ }
+ }
+
+ ///
+ /// Entropy code the mid-only flag
+ ///
+ /// I/O Compressor data structure
+ ///
+ static void silk_stereo_encode_mid_only(EntropyCoder psRangeEnc, byte mid_only_flag) {
+ /* Encode flag that only mid channel is coded */
+ psRangeEnc.enc_icdf(mid_only_flag, SilkTables.silk_stereo_only_code_mid_iCDF, 8);
+ }
+
+ ///
+ /// Find least-squares prediction gain for one signal based on another and quantize it
+ ///
+ /// O Ratio of residual and mid energies
+ /// I Basis signal
+ /// I Target signal
+ /// I/O Smoothed mid, residual norms
+ /// I Number of samples
+ /// I Smoothing coefficient
+ /// O Returns predictor in Q13
+ 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;
+ // fixme optimize this unboxing
+ BoxedValueInt nrgx = new BoxedValueInt(0);
+ BoxedValueInt nrgy = new BoxedValueInt(0);
+ BoxedValueInt scale1 = new BoxedValueInt(0);
+ BoxedValueInt scale2 = new BoxedValueInt(0);
+ int corr, pred_Q13, pred2_Q10;
+
+ /* Find predictor */
+ SumSqrShift.silk_sum_sqr_shift(nrgx, scale1, x, length);
+ SumSqrShift.silk_sum_sqr_shift(nrgy, scale2, y, length);
+ scale = Inlines.silk_max_int(scale1.Val, scale2.Val);
+ scale = scale + (scale & 1);
+ /* make even */
+ nrgy.Val = Inlines.silk_RSHIFT32(nrgy.Val, scale - scale2.Val);
+ nrgx.Val = Inlines.silk_RSHIFT32(nrgx.Val, scale - scale1.Val);
+ nrgx.Val = Inlines.silk_max_int(nrgx.Val, 1);
+ corr = Inlines.silk_inner_prod_aligned_scale(x, y, scale, length);
+ pred_Q13 = Inlines.silk_DIV32_varQ(corr, nrgx.Val, 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.Val), scale) - mid_res_amp_Q0[mid_res_amp_Q0_ptr], smooth_coef_Q16);
+ /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */
+ nrgy.Val = Inlines.silk_SUB_LSHIFT32(nrgy.Val, Inlines.silk_SMULWB(corr, pred_Q13), 3 + 1);
+ nrgy.Val = Inlines.silk_ADD_LSHIFT32(nrgy.Val, Inlines.silk_SMULWB(nrgx.Val, 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.Val), 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;
+ }
+
+ ///
+ /// Convert Left/Right stereo signal to adaptive Mid/Side representation
+ ///
+ /// I/O State
+ /// I/O Left input signal, becomes mid signal
+ /// I/O Right input signal, becomes side signal
+ /// O Quantization indices [ 2 ][ 3 ]
+ /// O Flag: only mid signal coded
+ /// O Bitrates for mid and side signals
+ /// I Total bitrate
+ /// I Speech activity level in previous frame
+ /// I Last frame before a stereo.mono transition
+ /// I Sample rate (kHz)
+ /// I Number of samples
+ static void silk_stereo_LR_to_MS(
+ StereoEncodeState state,
+ short[] x1,
+ int x1_ptr,
+ short[] x2,
+ int x2_ptr,
+ byte[][] ix,
+ BoxedValueByte 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(0);
+ BoxedValueInt HP_ratio_Q14 = new BoxedValueInt(0);
+ 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 */
+ System.arraycopy(state.sMid, 0, x1, mid, 2);
+ System.arraycopy(state.sSide, 0, side, 0, 2);
+ System.arraycopy(x1, mid + frame_length, state.sMid, 0, 2);
+ System.arraycopy(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;
+ }
+
+ ///
+ /// Convert adaptive Mid/Side representation to Left/Right stereo signal
+ ///
+ /// I/O State
+ /// I/O Left input signal, becomes mid signal
+ /// I/O Right input signal, becomes side signal
+ /// I Predictors
+ /// I Samples rate (kHz)
+ /// I Number of samples
+ 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 */
+ System.arraycopy(state.sMid, 0, x1, x1_ptr, 2);
+ System.arraycopy(state.sSide, 0, x2, x2_ptr, 2);
+ System.arraycopy(x1, x1_ptr + frame_length, state.sMid, 0, 2);
+ System.arraycopy(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);
+ }
+ }
+
+ ///
+ /// Quantize mid/side predictors
+ ///
+ /// I/O Predictors (out: quantized)
+ /// O Quantization indices [ 2 ][ 3 ]
+ static void silk_stereo_quant_pred(
+ int[] pred_Q13,
+ byte[][] ix) {
+ byte 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.MemSet(ix[0], (byte) 0, 3);
+ Arrays.MemSet(ix[1], (byte) 0, 3);
+
+ /* Quantize */
+ for (n = 0; n < 2; n++) {
+ boolean done = false;
+
+ /* Brute-force search over quantization levels */
+ err_min_Q13 = Integer.MAX_VALUE;
+ for (i = 0; !done && i < SilkConstants.STEREO_QUANT_TAB_SIZE - 1; i++) {
+ low_Q13 = SilkTables.silk_stereo_pred_quant_Q13[i];
+ step_Q13 = Inlines.silk_SMULWB(SilkTables.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; !done && 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 */
+ done = true;
+ }
+ }
+ }
+
+ ix[n][2] = (byte) (Inlines.silk_DIV32_16(ix[n][0], 3));
+ ix[n][0] = (byte) (ix[n][0] - (byte) (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];
+ }
+}
diff --git a/app/src/main/java/org/concentus/StereoDecodeState.java b/app/src/main/java/org/concentus/StereoDecodeState.java
new file mode 100644
index 0000000000..4e9956fcd7
--- /dev/null
+++ b/app/src/main/java/org/concentus/StereoDecodeState.java
@@ -0,0 +1,45 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class StereoDecodeState {
+
+ final short[] pred_prev_Q13 = new short[2];
+ final short[] sMid = new short[2];
+ final short[] sSide = new short[2];
+
+ void Reset() {
+ Arrays.MemSet(pred_prev_Q13, (short) 0, 2);
+ Arrays.MemSet(sMid, (short) 0, 2);
+ Arrays.MemSet(sSide, (short) 0, 2);
+ }
+}
diff --git a/app/src/main/java/org/concentus/StereoEncodeState.java b/app/src/main/java/org/concentus/StereoEncodeState.java
new file mode 100644
index 0000000000..e151a25ef0
--- /dev/null
+++ b/app/src/main/java/org/concentus/StereoEncodeState.java
@@ -0,0 +1,62 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class StereoEncodeState {
+
+ final short[] pred_prev_Q13 = new short[2];
+ final short[] sMid = new short[2];
+ final short[] sSide = new short[2];
+ final int[] mid_side_amp_Q0 = new int[4];
+ short smth_width_Q14 = 0;
+ short width_prev_Q14 = 0;
+ short silent_side_len = 0;
+ final byte[][][] predIx = Arrays.InitThreeDimensionalArrayByte(SilkConstants.MAX_FRAMES_PER_PACKET, 2, 3);
+ final byte[] mid_only_flags = new byte[SilkConstants.MAX_FRAMES_PER_PACKET];
+
+ void Reset() {
+ Arrays.MemSet(pred_prev_Q13, (short) 0, 2);
+ Arrays.MemSet(sMid, (short) 0, 2);
+ Arrays.MemSet(sSide, (short) 0, 2);
+ Arrays.MemSet(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.MemSet(predIx[x][y], (byte) 0, 3);
+ }
+ }
+
+ Arrays.MemSet(mid_only_flags, (byte) 0, SilkConstants.MAX_FRAMES_PER_PACKET);
+ }
+}
diff --git a/app/src/main/java/org/concentus/StereoWidthState.java b/app/src/main/java/org/concentus/StereoWidthState.java
new file mode 100644
index 0000000000..5f92990400
--- /dev/null
+++ b/app/src/main/java/org/concentus/StereoWidthState.java
@@ -0,0 +1,52 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class StereoWidthState {
+
+ int XX;
+ int XY;
+ int YY;
+ int smoothed_width;
+ int max_follower;
+
+ void Reset() {
+ XX = 0;
+ XY = 0;
+ YY = 0;
+ smoothed_width = 0;
+ max_follower = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/SumSqrShift.java b/app/src/main/java/org/concentus/SumSqrShift.java
new file mode 100644
index 0000000000..b243d1bb3a
--- /dev/null
+++ b/app/src/main/java/org/concentus/SumSqrShift.java
@@ -0,0 +1,157 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class SumSqrShift {
+
+ ///
+ /// Compute number of bits to right shift the sum of squares of a vector
+ /// of int16s to make it fit in an int32
+ ///
+ /// O Energy of x, after shifting to the right
+ /// O Number of bits right shift applied to energy
+ /// I Input vector
+ /// I Length of input vector
+ static void silk_sum_sqr_shift(
+ BoxedValueInt energy,
+ BoxedValueInt 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 = ((int) Inlines.silk_RSHIFT_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 = ((int) Inlines.silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft));
+ if (nrg < 0) {
+ /* Scale down */
+ nrg = ((int) Inlines.silk_RSHIFT_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 = ((int) Inlines.silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft));
+ }
+
+ /* Make sure to have at least one extra leading zero (two leading zeros in total) */
+ if ((nrg & 0xC0000000) != 0) {
+ nrg = ((int) Inlines.silk_RSHIFT_uint(nrg, 2));
+ shft += 2;
+ }
+
+ /* Output arguments */
+ shift.Val = shft;
+ energy.Val = nrg;
+ }
+
+ ///
+ /// 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
+ ///
+ /// O Energy of x, after shifting to the right
+ /// O Number of bits right shift applied to energy
+ /// I Input vector
+ /// I Length of input vector
+ static void silk_sum_sqr_shift(
+ BoxedValueInt energy,
+ BoxedValueInt 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 = ((int) Inlines.silk_RSHIFT_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 = ((int) Inlines.silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft));
+ if (nrg < 0) {
+ /* Scale down */
+ nrg = ((int) Inlines.silk_RSHIFT_uint(nrg, 2));
+ shft += 2;
+ }
+ }
+
+ if (i == len) {
+ /* One sample left to process */
+ nrg_tmp = Inlines.silk_SMULBB(x[i], x[i]);
+ nrg = ((int) Inlines.silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft));
+ }
+
+ /* Make sure to have at least one extra leading zero (two leading zeros in total) */
+ if ((nrg & 0xC0000000) != 0) {
+ nrg = ((int) Inlines.silk_RSHIFT_uint(nrg, 2));
+ shft += 2;
+ }
+
+ /* Output arguments */
+ shift.Val = shft;
+ energy.Val = nrg;
+ }
+}
diff --git a/app/src/main/java/org/concentus/TOCStruct.java b/app/src/main/java/org/concentus/TOCStruct.java
new file mode 100644
index 0000000000..fd6fd7e7c7
--- /dev/null
+++ b/app/src/main/java/org/concentus/TOCStruct.java
@@ -0,0 +1,59 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Struct for TOC (Table of Contents)
+///
+class TOCStruct {
+
+ ///
+ /// Voice activity for packet
+ ///
+ int VADFlag = 0;
+
+ ///
+ /// Voice activity for each frame in packet
+ ///
+ final int[] VADFlags = new int[SilkConstants.SILK_MAX_FRAMES_PER_PACKET];
+
+ ///
+ /// Flag indicating if packet contains in-band FEC
+ ///
+ int inbandFECFlag = 0;
+
+ void Reset() {
+ VADFlag = 0;
+ Arrays.MemSet(VADFlags, 0, SilkConstants.SILK_MAX_FRAMES_PER_PACKET);
+ inbandFECFlag = 0;
+ }
+}
diff --git a/app/src/main/java/org/concentus/TonalityAnalysisState.java b/app/src/main/java/org/concentus/TonalityAnalysisState.java
new file mode 100644
index 0000000000..a8ce1c6d8f
--- /dev/null
+++ b/app/src/main/java/org/concentus/TonalityAnalysisState.java
@@ -0,0 +1,130 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class TonalityAnalysisState {
+
+ boolean enabled = false;
+ final float[] angle = new float[240];
+ final float[] d_angle = new float[240];
+ final float[] d2_angle = new float[240];
+ final int[] inmem = new int[OpusConstants.ANALYSIS_BUF_SIZE];
+ int mem_fill;
+ /* number of usable samples in the buffer */
+ final float[] prev_band_tonality = new float[OpusConstants.NB_TBANDS];
+ float prev_tonality;
+ final float[][] E = Arrays.InitTwoDimensionalArrayFloat(OpusConstants.NB_FRAMES, OpusConstants.NB_TBANDS);
+ final float[] lowE = new float[OpusConstants.NB_TBANDS];
+ final float[] highE = new float[OpusConstants.NB_TBANDS];
+ final float[] meanE = new float[OpusConstants.NB_TOT_BANDS];
+ final float[] mem = new float[32];
+ final float[] cmean = new float[8];
+ final float[] std = new float[9];
+ float music_prob;
+ float Etracker;
+ float lowECount;
+ int E_count;
+ int last_music;
+ int last_transition;
+ int count;
+ final float[] subframe_mem = new float[3];
+ int analysis_offset;
+ /**
+ * Probability of having speech for time i to DETECT_SIZE-1 (and music
+ * before). pspeech[0] is the probability that all frames in the window are
+ * speech.
+ */
+ final float[] pspeech = new float[OpusConstants.DETECT_SIZE];
+ /**
+ * Probability of having music for time i to DETECT_SIZE-1 (and speech
+ * before). pmusic[0] is the probability that all frames in the window are
+ * music.
+ */
+ final float[] pmusic = new float[OpusConstants.DETECT_SIZE];
+ float speech_confidence;
+ float music_confidence;
+ int speech_confidence_count;
+ int music_confidence_count;
+ int write_pos;
+ int read_pos;
+ int read_subframe;
+ final AnalysisInfo[] info = new AnalysisInfo[OpusConstants.DETECT_SIZE];
+
+ TonalityAnalysisState() {
+ for (int c = 0; c < OpusConstants.DETECT_SIZE; c++) {
+ info[c] = new AnalysisInfo();
+ }
+ }
+
+ void Reset() {
+ Arrays.MemSet(angle, 0f, 240);
+ Arrays.MemSet(d_angle, 0f, 240);
+ Arrays.MemSet(d2_angle, 0f, 240);
+ Arrays.MemSet(inmem, 0, OpusConstants.ANALYSIS_BUF_SIZE);
+ mem_fill = 0;
+ Arrays.MemSet(prev_band_tonality, 0f, OpusConstants.NB_TBANDS);
+ prev_tonality = 0;
+ for (int c = 0; c < OpusConstants.NB_FRAMES; c++) {
+ Arrays.MemSet(E[c], 0f, OpusConstants.NB_TBANDS);
+ }
+ Arrays.MemSet(lowE, 0f, OpusConstants.NB_TBANDS);
+ Arrays.MemSet(highE, 0f, OpusConstants.NB_TBANDS);
+ Arrays.MemSet(meanE, 0f, OpusConstants.NB_TOT_BANDS);
+ Arrays.MemSet(mem, 0f, 32);
+ Arrays.MemSet(cmean, 0f, 8);
+ Arrays.MemSet(std, 0f, 9);
+ music_prob = 0;
+ Etracker = 0;
+ lowECount = 0;
+ E_count = 0;
+ last_music = 0;
+ last_transition = 0;
+ count = 0;
+ Arrays.MemSet(subframe_mem, 0f, 3);
+ analysis_offset = 0;
+ Arrays.MemSet(pspeech, 0f, OpusConstants.DETECT_SIZE);
+ Arrays.MemSet(pmusic, 0f, OpusConstants.DETECT_SIZE);
+ speech_confidence = 0;
+ music_confidence = 0;
+ speech_confidence_count = 0;
+ music_confidence_count = 0;
+ write_pos = 0;
+ read_pos = 0;
+ read_subframe = 0;
+ for (int c = 0; c < OpusConstants.DETECT_SIZE; c++) {
+ info[c].Reset();
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/TuningParameters.java b/app/src/main/java/org/concentus/TuningParameters.java
new file mode 100644
index 0000000000..c8c0f7184e
--- /dev/null
+++ b/app/src/main/java/org/concentus/TuningParameters.java
@@ -0,0 +1,186 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class TuningParameters {
+
+ /* Decay time for EntropyCoder.BITREServoir */
+ static final int BITRESERVOIR_DECAY_TIME_MS = 500;
+
+ /**
+ * ****************
+ */
+ /* Pitch estimator */
+ /**
+ * ****************
+ */
+
+ /* Level of noise floor for whitening filter LPC analysis in pitch analysis */
+ static final float FIND_PITCH_WHITE_NOISE_FRACTION = 1e-3f;
+
+ /* Bandwidth expansion for whitening filter in pitch analysis */
+ static final float FIND_PITCH_BANDWIDTH_EXPANSION = 0.99f;
+
+ /**
+ * ******************
+ */
+ /* Linear prediction */
+ /**
+ * ******************
+ */
+
+ /* LPC analysis regularization */
+ static final float FIND_LPC_COND_FAC = 1e-5f;
+
+ /* LTP analysis defines */
+ static final float FIND_LTP_COND_FAC = 1e-5f;
+ static final float LTP_DAMPING = 0.05f;
+ static final float LTP_SMOOTHING = 0.1f;
+
+ /* LTP quantization settings */
+ static final float MU_LTP_QUANT_NB = 0.03f;
+ static final float MU_LTP_QUANT_MB = 0.025f;
+ static final float MU_LTP_QUANT_WB = 0.02f;
+
+ /* Max cumulative LTP gain */
+ static final float MAX_SUM_LOG_GAIN_DB = 250.0f;
+
+ /**
+ * ********************
+ */
+ /* High pass filtering */
+ /**
+ * ********************
+ */
+
+ /* Smoothing parameters for low end of pitch frequency range estimation */
+ static final float VARIABLE_HP_SMTH_COEF1 = 0.1f;
+ static final float VARIABLE_HP_SMTH_COEF2 = 0.015f;
+ static final float VARIABLE_HP_MAX_DELTA_FREQ = 0.4f;
+
+ /* Min and max cut-off frequency values (-3 dB points) */
+ static final int VARIABLE_HP_MIN_CUTOFF_HZ = 60;
+ static final int VARIABLE_HP_MAX_CUTOFF_HZ = 100;
+
+ /**
+ * ********
+ */
+ /* Various */
+ /**
+ * ********
+ */
+
+ /* VAD threshold */
+ static final float SPEECH_ACTIVITY_DTX_THRES = 0.05f;
+
+ /* Speech Activity LBRR enable threshold */
+ static final float LBRR_SPEECH_ACTIVITY_THRES = 0.3f;
+
+ /**
+ * **********************
+ */
+ /* Perceptual parameters */
+ /**
+ * **********************
+ */
+
+ /* reduction in coding SNR during low speech activity */
+ static final float BG_SNR_DECR_dB = 2.0f;
+
+ /* factor for reducing quantization noise during voiced speech */
+ static final float HARM_SNR_INCR_dB = 2.0f;
+
+ /* factor for reducing quantization noise for unvoiced sparse signals */
+ static final float SPARSE_SNR_INCR_dB = 2.0f;
+
+ /* threshold for sparseness measure above which to use lower quantization offset during unvoiced */
+ static final float SPARSENESS_THRESHOLD_QNT_OFFSET = 0.75f;
+
+ /* warping control */
+ static final float WARPING_MULTIPLIER = 0.015f;
+
+ /* fraction added to first autocorrelation value */
+ static final float SHAPE_WHITE_NOISE_FRACTION = 5e-5f;
+
+ /* noise shaping filter chirp factor */
+ static final float BANDWIDTH_EXPANSION = 0.95f;
+
+ /* difference between chirp factors for analysis and synthesis noise shaping filters at low bitrates */
+ static final float LOW_RATE_BANDWIDTH_EXPANSION_DELTA = 0.01f;
+
+ /* extra harmonic boosting (signal shaping) at low bitrates */
+ static final float LOW_RATE_HARMONIC_BOOST = 0.1f;
+
+ /* extra harmonic boosting (signal shaping) for noisy input signals */
+ static final float LOW_INPUT_QUALITY_HARMONIC_BOOST = 0.1f;
+
+ /* harmonic noise shaping */
+ static final float HARMONIC_SHAPING = 0.3f;
+
+ /* extra harmonic noise shaping for high bitrates or noisy input */
+ static final float HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING = 0.2f;
+
+ /* parameter for shaping noise towards higher frequencies */
+ static final float HP_NOISE_COEF = 0.25f;
+
+ /* parameter for shaping noise even more towards higher frequencies during voiced speech */
+ static final float HARM_HP_NOISE_COEF = 0.35f;
+
+ /* parameter for applying a high-pass tilt to the input signal */
+ static final float INPUT_TILT = 0.05f;
+
+ /* parameter for extra high-pass tilt to the input signal at high rates */
+ static final float HIGH_RATE_INPUT_TILT = 0.1f;
+
+ /* parameter for reducing noise at the very low frequencies */
+ static final float LOW_FREQ_SHAPING = 4.0f;
+
+ /* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */
+ static final float LOW_QUALITY_LOW_FREQ_SHAPING_DECR = 0.5f;
+
+ /* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower . more smoothing) */
+ static final float SUBFR_SMTH_COEF = 0.4f;
+
+ /* parameters defining the R/D tradeoff in the residual quantizer */
+ static final float LAMBDA_OFFSET = 1.2f;
+ static final float LAMBDA_SPEECH_ACT = -0.2f;
+ static final float LAMBDA_DELAYED_DECISIONS = -0.05f;
+ static final float LAMBDA_INPUT_QUALITY = -0.1f;
+ static final float LAMBDA_CODING_QUALITY = -0.2f;
+ static final float LAMBDA_QUANT_OFFSET = 0.8f;
+
+ /* Compensation in bitrate calculations for 10 ms modes */
+ static final int REDUCE_BITRATE_10_MS_BPS = 2200;
+
+ /* Maximum time before allowing a bandwidth transition */
+ static final int MAX_BANDWIDTH_SWITCH_DELAY_MS = 5000;
+}
diff --git a/app/src/main/java/org/concentus/VQ.java b/app/src/main/java/org/concentus/VQ.java
new file mode 100644
index 0000000000..4e9eb6f771
--- /dev/null
+++ b/app/src/main/java/org/concentus/VQ.java
@@ -0,0 +1,369 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class VQ {
+
+ static void exp_rotation1(int[] X, int X_ptr, int len, int stride, int c, int s) {
+ int i;
+ int ms;
+ int Xptr;
+ Xptr = X_ptr;
+ ms = Inlines.NEG16(s);
+ for (i = 0; i < len - stride; i++) {
+ int x1, x2;
+ x1 = X[Xptr];
+ x2 = X[Xptr + stride];
+ X[Xptr + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x2), s, x1), 15));
+ X[Xptr] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x1), ms, x2), 15));
+ Xptr++;
+ }
+ Xptr = X_ptr + (len - 2 * stride - 1);
+ for (i = len - 2 * stride - 1; i >= 0; i--) {
+ int x1, x2;
+ x1 = X[Xptr];
+ x2 = X[Xptr + stride];
+ X[Xptr + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x2), s, x1), 15));
+ X[Xptr] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x1), ms, x2), 15));
+ Xptr--;
+ }
+ }
+
+ private static int[] SPREAD_FACTOR = {15, 10, 5};
+
+ static void exp_rotation(int[] X, int X_ptr, int len, int dir, int stride, int K, int spread) {
+ int i;
+ int c, s;
+ int gain, theta;
+ int stride2 = 0;
+ int factor;
+
+ if (2 * K >= len || spread == Spread.SPREAD_NONE) {
+ return;
+ }
+
+ factor = SPREAD_FACTOR[spread - 1];
+
+ gain = (Inlines.celt_div((int) Inlines.MULT16_16(CeltConstants.Q15_ONE, len), (int) (len + factor * K)));
+ theta = Inlines.HALF16(Inlines.MULT16_16_Q15(gain, gain));
+
+ c = Inlines.celt_cos_norm(Inlines.EXTEND32(theta));
+ s = Inlines.celt_cos_norm(Inlines.EXTEND32(Inlines.SUB16(CeltConstants.Q15ONE, theta)));
+ /* sin(theta) */
+
+ if (len >= 8 * stride) {
+ stride2 = 1;
+ /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding.
+ It's basically incrementing long as (stride2+0.5)^2 < len/stride. */
+ while ((stride2 * stride2 + stride2) * stride + (stride >> 2) < len) {
+ stride2++;
+ }
+ }
+
+ /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
+ extract_collapse_mask().*/
+ len = Inlines.celt_udiv(len, stride);
+ for (i = 0; i < stride; i++) {
+ if (dir < 0) {
+ if (stride2 != 0) {
+ exp_rotation1(X, X_ptr + (i * len), len, stride2, s, c);
+ }
+
+ exp_rotation1(X, X_ptr + (i * len), len, 1, c, s);
+ } else {
+ exp_rotation1(X, X_ptr + (i * len), len, 1, c, (short) (0 - s));
+
+ if (stride2 != 0) {
+ exp_rotation1(X, X_ptr + (i * len), len, stride2, s, (short) (0 - c));
+ }
+ }
+ }
+ }
+
+ /**
+ * Takes the pitch vector and the decoded residual vector, computes the gain
+ * that will give ||p+g*y||=1 and mixes the residual with the pitch.
+ */
+ static void normalise_residual(int[] iy, int[] X, int X_ptr,
+ int N, int Ryy, int gain) {
+ int i;
+ int k;
+ int t;
+ int g;
+
+ k = Inlines.celt_ilog2(Ryy) >> 1;
+ t = Inlines.VSHR32(Ryy, 2 * (k - 7));
+ g = Inlines.MULT16_16_P15(Inlines.celt_rsqrt_norm(t), gain);
+
+ i = 0;
+ do {
+ X[X_ptr + i] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(g, iy[i]), k + 1));
+ } while (++i < N);
+ }
+
+ static int extract_collapse_mask(int[] iy, int N, int B) {
+ int collapse_mask;
+ int N0;
+ int i;
+ if (B <= 1) {
+ return 1;
+ }
+ /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
+ exp_rotation().*/
+ N0 = Inlines.celt_udiv(N, B);
+ collapse_mask = 0;
+ i = 0;
+ do {
+ int j;
+ int tmp = 0;
+ j = 0;
+ do {
+ tmp |= iy[i * N0 + j];
+ } while (++j < N0);
+
+ collapse_mask |= (tmp != 0 ? 1 : 0) << i;
+ } while (++i < B);
+
+ return collapse_mask;
+ }
+
+ static int alg_quant(int[] X, int X_ptr, int N, int K, int spread, int B, EntropyCoder enc
+ ) {
+ int[] y = new int[N];
+ int[] iy = new int[N];
+ int[] signx = new int[N];
+ int i, j;
+ int s;
+ int pulsesLeft;
+ int sum;
+ int xy;
+ int yy;
+ int collapse_mask;
+
+ Inlines.OpusAssert(K > 0, "alg_quant() needs at least one pulse");
+ Inlines.OpusAssert(N > 1, "alg_quant() needs at least two dimensions");
+
+ exp_rotation(X, X_ptr, N, 1, B, K, spread);
+
+ /* Get rid of the sign */
+ sum = 0;
+ j = 0;
+ do {
+ if (X[X_ptr + j] > 0) {
+ signx[j] = 1;
+ } else {
+ signx[j] = -1;
+ X[X_ptr + j] = (0 - X[X_ptr + j]);
+ }
+
+ iy[j] = 0;
+ y[j] = 0;
+ } while (++j < N);
+
+ xy = yy = 0;
+
+ pulsesLeft = K;
+
+ /* Do a pre-search by projecting on the pyramid */
+ if (K > (N >> 1)) {
+ int rcp;
+ j = 0;
+ do {
+ sum += X[X_ptr + j];
+ } while (++j < N);
+
+ /* If X is too small, just replace it with a pulse at 0 */
+ /* Prevents infinities and NaNs from causing too many pulses
+ to be allocated. 64 is an approximation of infinity here. */
+ if (sum <= K) {
+ X[X_ptr] = ((short) (0.5 + (1.0f) * (((int) 1) << (14))))/*Inlines.QCONST16(1.0f, 14)*/;
+ j = X_ptr + 1;
+ do {
+ X[j] = 0;
+ } while (++j < N + X_ptr);
+
+ sum = ((short) (0.5 + (1.0f) * (((int) 1) << (14))))/*Inlines.QCONST16(1.0f, 14)*/;
+ }
+
+ rcp = Inlines.EXTRACT16(Inlines.MULT16_32_Q16((K - 1), Inlines.celt_rcp(sum)));
+ j = 0;
+
+ do {
+ /* It's really important to round *towards zero* here */
+ iy[j] = Inlines.MULT16_16_Q15(X[X_ptr + j], rcp);
+ y[j] = (int) iy[j];
+ yy = (Inlines.MAC16_16(yy, y[j], y[j]));
+ xy = Inlines.MAC16_16(xy, X[X_ptr + j], y[j]);
+ y[j] *= 2;
+ pulsesLeft -= iy[j];
+ } while (++j < N);
+ }
+
+ Inlines.OpusAssert(pulsesLeft >= 1, "Allocated too many pulses in the quick pass");
+
+ /* This should never happen, but just in case it does (e.g. on silence)
+ we fill the first bin with pulses. */
+ if (pulsesLeft > N + 3) {
+ int tmp = (int) pulsesLeft;
+ yy = (Inlines.MAC16_16(yy, tmp, tmp));
+ yy = (Inlines.MAC16_16(yy, tmp, y[0]));
+ iy[0] += pulsesLeft;
+ pulsesLeft = 0;
+ }
+
+ s = 1;
+ for (i = 0; i < pulsesLeft; i++) {
+ int best_id;
+ int best_num = 0 - CeltConstants.VERY_LARGE16;
+ int best_den = 0;
+ int rshift = 1 + Inlines.celt_ilog2(K - pulsesLeft + i + 1);
+ best_id = 0;
+ /* The squared magnitude term gets added anyway, so we might as well
+ add it outside the loop */
+ yy = Inlines.ADD16(yy, 1); // opus bug - was add32
+ j = 0;
+ do {
+ int Rxy, Ryy;
+ /* Temporary sums of the new pulse(s) */
+ Rxy = Inlines.EXTRACT16(Inlines.SHR32(Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + j])), rshift));
+ /* We're multiplying y[j] by two so we don't have to do it here */
+ Ryy = Inlines.ADD16(yy, y[j]);
+
+ /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
+ Rxy is positive because the sign is pre-computed) */
+ Rxy = Inlines.MULT16_16_Q15(Rxy, Rxy);
+ /* The idea is to check for num/den >= best_num/best_den, but that way
+ we can do it without any division */
+ /* OPT: Make sure to use conditional moves here */
+ if (Inlines.MULT16_16(best_den, Rxy) > Inlines.MULT16_16(Ryy, best_num)) {
+ best_den = Ryy;
+ best_num = Rxy;
+ best_id = j;
+ }
+ } while (++j < N);
+
+ /* Updating the sums of the new pulse(s) */
+ xy = Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + best_id]));
+ /* We're multiplying y[j] by two so we don't have to do it here */
+ yy = Inlines.ADD16(yy, y[best_id]);
+
+ /* Only now that we've made the final choice, update y/iy */
+ /* Multiplying y[j] by 2 so we don't have to do it everywhere else */
+ y[best_id] = (y[best_id] + (2 * s));
+ iy[best_id]++;
+ }
+
+ /* Put the original sign back */
+ j = 0;
+ do {
+ X[X_ptr + j] = (Inlines.MULT16_16(signx[j], X[X_ptr + j]));
+ if (signx[j] < 0) {
+ iy[j] = -iy[j];
+ }
+ } while (++j < N);
+
+ CWRS.encode_pulses(iy, N, K, enc);
+
+ collapse_mask = extract_collapse_mask(iy, N, B);
+
+ return collapse_mask;
+ }
+
+ /**
+ * Decode pulse vector and combine the result with the pitch vector to
+ * produce the final normalised signal in the current band.
+ */
+ static int alg_unquant(int[] X, int X_ptr, int N, int K, int spread, int B,
+ EntropyCoder dec, int gain) {
+ int Ryy;
+ int collapse_mask;
+ int[] iy = new int[N];
+ Inlines.OpusAssert(K > 0, "alg_unquant() needs at least one pulse");
+ Inlines.OpusAssert(N > 1, "alg_unquant() needs at least two dimensions");
+ Ryy = CWRS.decode_pulses(iy, N, K, dec);
+ normalise_residual(iy, X, X_ptr, N, Ryy, gain);
+ exp_rotation(X, X_ptr, N, -1, B, K, spread);
+ collapse_mask = extract_collapse_mask(iy, N, B);
+
+ return collapse_mask;
+ }
+
+ static void renormalise_vector(int[] X, int X_ptr, int N, int gain) {
+ int i;
+ int k;
+ int E;
+ int g;
+ int t;
+ int xptr;
+ E = CeltConstants.EPSILON + Kernels.celt_inner_prod(X, X_ptr, X, X_ptr, N);
+ k = Inlines.celt_ilog2(E) >> 1;
+ t = Inlines.VSHR32(E, 2 * (k - 7));
+ g = Inlines.MULT16_16_P15(Inlines.celt_rsqrt_norm(t), gain);
+
+ xptr = X_ptr;
+ for (i = 0; i < N; i++) {
+ X[xptr] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(g, X[xptr]), k + 1));
+ xptr++;
+ }
+ /*return celt_sqrt(E);*/
+ }
+
+ static int stereo_itheta(int[] X, int X_ptr, int[] Y, int Y_ptr, int stereo, int N) {
+ int i;
+ int itheta;
+ int mid, side;
+ int Emid, Eside;
+
+ Emid = Eside = CeltConstants.EPSILON;
+ if (stereo != 0) {
+ for (i = 0; i < N; i++) {
+ int m, s;
+ m = Inlines.ADD16(Inlines.SHR16(X[X_ptr + i], 1), Inlines.SHR16(Y[Y_ptr + i], 1));
+ s = Inlines.SUB16(Inlines.SHR16(X[X_ptr + i], 1), Inlines.SHR16(Y[Y_ptr + i], 1));
+ Emid = Inlines.MAC16_16(Emid, m, m);
+ Eside = Inlines.MAC16_16(Eside, s, s);
+ }
+ } else {
+ Emid += Kernels.celt_inner_prod(X, X_ptr, X, X_ptr, N);
+ Eside += Kernels.celt_inner_prod(Y, Y_ptr, Y, Y_ptr, N);
+ }
+ mid = (Inlines.celt_sqrt(Emid));
+ side = (Inlines.celt_sqrt(Eside));
+ /* 0.63662 = 2/pi */
+ itheta = Inlines.MULT16_16_Q15(((short) (0.5 + (0.63662f) * (((int) 1) << (15))))/*Inlines.QCONST16(0.63662f, 15)*/, Inlines.celt_atan2p(side, mid));
+
+ return itheta;
+ }
+}
diff --git a/app/src/main/java/org/concentus/VQ_WMat_EC.java b/app/src/main/java/org/concentus/VQ_WMat_EC.java
new file mode 100644
index 0000000000..bf6e9784f4
--- /dev/null
+++ b/app/src/main/java/org/concentus/VQ_WMat_EC.java
@@ -0,0 +1,123 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+class VQ_WMat_EC {
+
+ /* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
+ static void silk_VQ_WMat_EC(
+ BoxedValueByte 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,
+ byte[][] cb_Q7, /* I codebook */
+ short[] cb_gain_Q7, /* I codebook effective gain */
+ short[] 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;
+ byte[] 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 = Integer.MAX_VALUE;
+ 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 = (byte) k;
+ gain_Q7.Val = gain_tmp_Q7;
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/concentus/VoiceActivityDetection.java b/app/src/main/java/org/concentus/VoiceActivityDetection.java
new file mode 100644
index 0000000000..c7df2d16ef
--- /dev/null
+++ b/app/src/main/java/org/concentus/VoiceActivityDetection.java
@@ -0,0 +1,402 @@
+/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
+ Ported to Java 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.
+ */
+package org.concentus;
+
+///
+/// Voice Activity Detection module for silk codec
+///
+class VoiceActivityDetection {
+
+ ///
+ /// Weighting factors for tilt measure
+ ///
+ private static final int[] tiltWeights = {30000, 6000, -12000, -12000};
+
+ ///
+ /// Initialization of the Silk VAD
+ ///
+ /// O Pointer to Silk VAD state. Cannot be nullptr
+ /// 0 if success
+ 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(Integer.MAX_VALUE, 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);
+ }
+
+ ///
+ /// Get the speech activity level in Q8
+ ///
+ /// I/O Encoder state
+ /// I PCM input
+ /// 0 if success
+ 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), 255);
+
+ /**
+ * ********************************
+ */
+ /* 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);
+ }
+
+ ///
+ /// Noise level estimation
+ ///
+ /// I subband energies [VAD_N_BANDS]
+ /// I/O Pointer to Silk VAD state
+ 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.MAX_VALUE, (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(Integer.MAX_VALUE, 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(Integer.MAX_VALUE, 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++;
+ }
+}
diff --git a/app/src/main/java/org/concentus/VorbisLayout.java b/app/src/main/java/org/concentus/VorbisLayout.java
new file mode 100644
index 0000000000..65968fcff9
--- /dev/null
+++ b/app/src/main/java/org/concentus/VorbisLayout.java
@@ -0,0 +1,59 @@
+/* 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 Java 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.
+ */
+package org.concentus;
+
+class VorbisLayout {
+
+ VorbisLayout(int streams, int coupled_streams, short[] map) {
+ nb_streams = streams;
+ nb_coupled_streams = coupled_streams;
+ mapping = map;
+ }
+
+ int nb_streams;
+ int nb_coupled_streams;
+ short[] mapping;
+
+ /* Index is nb_channel-1*/
+ static final VorbisLayout[] vorbis_mappings = {
+ new VorbisLayout(1, 0, new short[]{0}), /* 1: mono */
+ new VorbisLayout(1, 1, new short[]{0, 1}), /* 2: stereo */
+ new VorbisLayout(2, 1, new short[]{0, 2, 1}), /* 3: 1-d surround */
+ new VorbisLayout(2, 2, new short[]{0, 1, 2, 3}), /* 4: quadraphonic surround */
+ new VorbisLayout(3, 2, new short[]{0, 4, 1, 2, 3}), /* 5: 5-channel surround */
+ new VorbisLayout(4, 2, new short[]{0, 4, 1, 2, 3, 5}), /* 6: 5.1 surround */
+ new VorbisLayout(4, 3, new short[]{0, 4, 1, 2, 3, 5, 6}), /* 7: 6.1 surround */
+ new VorbisLayout(5, 3, new short[]{0, 6, 1, 2, 3, 4, 5, 7}), /* 8: 7.1 surround */};
+}