/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.media.codec.aac;
import static java.lang.Math.pow;
import static jpcsp.media.codec.aac.AacDecoder.AAC_ERROR;
import static jpcsp.media.codec.aac.AacDecoder.TYPE_CCE;
import static jpcsp.media.codec.aac.AacDecoder.TYPE_CPE;
import static jpcsp.media.codec.aac.AacDecoder.TYPE_SCE;
import static jpcsp.media.codec.aac.AacSbrData.f_huffman_env_1_5dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.f_huffman_env_1_5dB_codes;
import static jpcsp.media.codec.aac.AacSbrData.f_huffman_env_3_0dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.f_huffman_env_3_0dB_codes;
import static jpcsp.media.codec.aac.AacSbrData.f_huffman_env_bal_1_5dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.f_huffman_env_bal_1_5dB_codes;
import static jpcsp.media.codec.aac.AacSbrData.f_huffman_env_bal_3_0dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.f_huffman_env_bal_3_0dB_codes;
import static jpcsp.media.codec.aac.AacSbrData.sbr_offset;
import static jpcsp.media.codec.aac.AacSbrData.sbr_qmf_window_ds;
import static jpcsp.media.codec.aac.AacSbrData.sbr_qmf_window_us;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_env_1_5dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_env_1_5dB_codes;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_env_3_0dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_env_3_0dB_codes;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_env_bal_1_5dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_env_bal_1_5dB_codes;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_env_bal_3_0dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_env_bal_3_0dB_codes;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_noise_3_0dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_noise_3_0dB_codes;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_noise_bal_3_0dB_bits;
import static jpcsp.media.codec.aac.AacSbrData.t_huffman_noise_bal_3_0dB_codes;
import static jpcsp.media.codec.aac.SBRData.SBR_SYNTHESIS_BUF_SIZE;
import static jpcsp.media.codec.util.CodecUtils.FLT_EPSILON;
import static jpcsp.media.codec.util.CodecUtils.exp2f;
import static jpcsp.media.codec.util.CodecUtils.log2f;
import static jpcsp.media.codec.util.CodecUtils.lrintf;
import static jpcsp.media.codec.util.CodecUtils.sqrtf;
import java.util.Arrays;
import jpcsp.media.codec.util.BitReader;
import jpcsp.media.codec.util.FFT;
import jpcsp.media.codec.util.FloatDSP;
import jpcsp.media.codec.util.IBitReader;
import jpcsp.media.codec.util.VLC;
import jpcsp.util.Utilities;
import org.apache.log4j.Logger;
public class AacSbr {
private static Logger log = AacDecoder.log;
private static final int ENVELOPE_ADJUSTMENT_OFFSET = 2;
private static final float NOISE_FLOOR_OFFSET = 6.0f;
private static final int EXTENSION_ID_PS = 2;
private static final int T_HUFFMAN_ENV_1_5DB = 0;
private static final int F_HUFFMAN_ENV_1_5DB = 1;
private static final int T_HUFFMAN_ENV_BAL_1_5DB = 2;
private static final int F_HUFFMAN_ENV_BAL_1_5DB = 3;
private static final int T_HUFFMAN_ENV_3_0DB = 4;
private static final int F_HUFFMAN_ENV_3_0DB = 5;
private static final int T_HUFFMAN_ENV_BAL_3_0DB = 6;
private static final int F_HUFFMAN_ENV_BAL_3_0DB = 7;
private static final int T_HUFFMAN_NOISE_3_0DB = 8;
private static final int T_HUFFMAN_NOISE_BAL_3_0DB = 9;
private static final VLC vlc_sbr[] = new VLC[10];
private static final int vlc_sbr_lav[] = {
60, 60, 24, 24, 31, 31, 12, 12, 31, 12
};
/** ceil(log2(index+1)) */
private static final int ceil_log2[] = {
0, 1, 2, 2, 3, 3,
};
/**
* bs_frame_class - frame class of current SBR frame (14496-3 sp04 p98)
*/
private static final int FIXFIX = 0;
private static final int FIXVAR = 1;
private static final int VARFIX = 2;
private static final int VARVAR = 3;
public static void sbrInit() {
for (int i = 0; i < vlc_sbr.length; i++) {
vlc_sbr[i] = new VLC();
}
vlc_sbr[T_HUFFMAN_ENV_1_5DB ].initVLCSparse(9, t_huffman_env_1_5dB_codes.length, t_huffman_env_1_5dB_bits, t_huffman_env_1_5dB_codes, null);
vlc_sbr[F_HUFFMAN_ENV_1_5DB ].initVLCSparse(9, f_huffman_env_1_5dB_codes.length, f_huffman_env_1_5dB_bits, f_huffman_env_1_5dB_codes, null);
vlc_sbr[T_HUFFMAN_ENV_BAL_1_5DB ].initVLCSparse(9, t_huffman_env_bal_1_5dB_codes.length, t_huffman_env_bal_1_5dB_bits, t_huffman_env_bal_1_5dB_codes, null);
vlc_sbr[F_HUFFMAN_ENV_BAL_1_5DB ].initVLCSparse(9, f_huffman_env_bal_1_5dB_codes.length, f_huffman_env_bal_1_5dB_bits, f_huffman_env_bal_1_5dB_codes, null);
vlc_sbr[T_HUFFMAN_ENV_3_0DB ].initVLCSparse(9, t_huffman_env_3_0dB_codes.length, t_huffman_env_3_0dB_bits, t_huffman_env_3_0dB_codes, null);
vlc_sbr[F_HUFFMAN_ENV_3_0DB ].initVLCSparse(9, f_huffman_env_3_0dB_codes.length, f_huffman_env_3_0dB_bits, f_huffman_env_3_0dB_codes, null);
vlc_sbr[T_HUFFMAN_ENV_BAL_3_0DB ].initVLCSparse(9, t_huffman_env_bal_3_0dB_codes.length, t_huffman_env_bal_3_0dB_bits, t_huffman_env_bal_3_0dB_codes, null);
vlc_sbr[F_HUFFMAN_ENV_BAL_3_0DB ].initVLCSparse(9, f_huffman_env_bal_3_0dB_codes.length, f_huffman_env_bal_3_0dB_bits, f_huffman_env_bal_3_0dB_codes, null);
vlc_sbr[T_HUFFMAN_NOISE_3_0DB ].initVLCSparse(9, t_huffman_noise_3_0dB_codes.length, t_huffman_noise_3_0dB_bits, t_huffman_noise_3_0dB_codes, null);
vlc_sbr[T_HUFFMAN_NOISE_BAL_3_0DB].initVLCSparse(9, t_huffman_noise_bal_3_0dB_codes.length, t_huffman_noise_bal_3_0dB_bits, t_huffman_noise_bal_3_0dB_codes, null);
}
private static void getBits1Vector(IBitReader br, int vec[], int vecOffset, int elements) {
for (int i = 0; i < elements; i++) {
vec[vecOffset + i] = br.read1();
}
}
private static int readSbrGrid(Context ac, SpectralBandReplication sbr, SBRData chData) {
IBitReader br = ac.br;
int bsPointer = 0;
// frameLengthFlag ? 15 : 16; 960 sample length frames unsupported; this value is numTimeSlots
int absBordTrail = 16;
int numRelLead, numRelTrail;
int bsNumEnvOld = chData.bsNumEnv;
chData.bsFreqRes[0] = chData.bsFreqRes[chData.bsNumEnv];
chData.bsAmpRes = sbr.bsAmpResHeader;
chData.tEnvNumEnvOld = chData.tEnv[bsNumEnvOld];
switch (chData.bsFrameClass = br.read(2)) {
case FIXFIX:
chData.bsNumEnv = 1 << br.read(2);
numRelLead = chData.bsNumEnv - 1;
if (chData.bsNumEnv == 1) {
chData.bsAmpRes = false;
}
if (chData.bsNumEnv > 4) {
log.error(String.format("Invalid bitstream, too many SBR envelopes in FIXFIX type SBR frame: %d", chData.bsNumEnv));
return -1;
}
chData.tEnv[0] = 0;
chData.tEnv[chData.bsNumEnv] = absBordTrail;
absBordTrail = (absBordTrail + (chData.bsNumEnv >> 1)) / chData.bsNumEnv;
for (int i = 0; i < numRelLead; i++) {
chData.tEnv[i + 1] = chData.tEnv[i] + absBordTrail;
}
chData.bsFreqRes[1] = br.read1();
for (int i = 1; i < chData.bsNumEnv; i++) {
chData.bsFreqRes[i + 1] = chData.bsFreqRes[1];
}
break;
case FIXVAR:
absBordTrail += br.read(2);
numRelTrail = br.read(2);
chData.bsNumEnv = numRelTrail + 1;
chData.tEnv[0] = 0;
chData.tEnv[chData.bsNumEnv] = absBordTrail;
for (int i = 0; i < numRelTrail; i++) {
chData.tEnv[chData.bsNumEnv - 1 - i] =
chData.tEnv[chData.bsNumEnv - i] - 2 * br.read(2) - 2;
}
bsPointer = br.read(ceil_log2[chData.bsNumEnv]);
for (int i = 0; i < chData.bsNumEnv; i++) {
chData.bsFreqRes[chData.bsNumEnv - i] = br.read1();
}
break;
case VARFIX:
chData.tEnv[0] = br.read(2);
numRelLead = br.read(2);
chData.bsNumEnv = numRelLead + 1;
chData.tEnv[chData.bsNumEnv] = absBordTrail;
for (int i = 0; i < numRelLead; i++) {
chData.tEnv[i + 1] = chData.tEnv[i] + 2 * br.read(2) + 2;
}
bsPointer = br.read(ceil_log2[chData.bsNumEnv]);
getBits1Vector(br, chData.bsFreqRes, 1, chData.bsNumEnv);
break;
case VARVAR:
chData.tEnv[0] = br.read(2);
absBordTrail += br.read(2);
numRelLead = br.read(2);
numRelTrail = br.read(2);
chData.bsNumEnv = numRelLead + numRelTrail + 1;
if (chData.bsNumEnv > 5) {
log.error(String.format("Invalid bitstream, too many SBR envelopes in VARVAR type SBR frame: %d", chData.bsNumEnv));
return -1;
}
chData.tEnv[chData.bsNumEnv] = absBordTrail;
for (int i = 0; i < numRelLead; i++) {
chData.tEnv[i + 1] = chData.tEnv[i] + 2 * br.read(2) + 2;
}
for (int i = 0; i < numRelTrail; i++) {
chData.tEnv[chData.bsNumEnv - 1 - i] =
chData.tEnv[chData.bsNumEnv - i] - 2 * br.read(2) - 2;
}
bsPointer = br.read(ceil_log2[chData.bsNumEnv]);
getBits1Vector(br, chData.bsFreqRes, 1, chData.bsNumEnv);
break;
}
if (bsPointer > chData.bsNumEnv + 1) {
log.error(String.format("Invalid bitstream, bs_pointer points to a middle noise border outside the time borders table: %d", bsPointer));
return -1;
}
for (int i = 1; i <= chData.bsNumEnv; i++) {
if (chData.tEnv[i-1] > chData.tEnv[i]) {
log.error(String.format("Non monotone time borders"));
return -1;
}
}
chData.bsNumNoise = (chData.bsNumEnv > 1 ? 1 : 0) + 1;
chData.tQ[0] = chData.tEnv[0];
chData.tQ[chData.bsNumNoise] = chData.tEnv[chData.bsNumEnv];
if (chData.bsNumNoise > 1) {
int idx;
if (chData.bsFrameClass == FIXFIX) {
idx = chData.bsNumEnv >> 1;
} else if ((chData.bsFrameClass & 1) != 0) { // FIXVAR or VARVAR
idx = chData.bsNumEnv - Math.max(bsPointer - 1, 1);
} else { // VARFIX
if (bsPointer == 0) {
idx = 1;
} else if (bsPointer == 1) {
idx = chData.bsNumEnv - 1;
} else { // bs_pointer > 1
idx = bsPointer - 1;
}
}
chData.tQ[1] = chData.tEnv[idx];
}
chData.eA[0] = -(chData.eA[1] != bsNumEnvOld ? 1 : 0); // l_APrev
chData.eA[1] = -1;
if ((chData.bsFrameClass & 1) != 0 && bsPointer != 0) { // FIXVAR or VARVAR and bs_pointer != 0
chData.eA[1] = chData.bsNumEnv + 1 - bsPointer;
} else if ((chData.bsFrameClass == 2) && (bsPointer > 1)) { // VARFIX and bs_pointer > 1
chData.eA[1] = bsPointer - 1;
}
return 0;
}
/// Read how the envelope and noise floor data is delta coded
private static void readSbrDtdf(SpectralBandReplication sbr, IBitReader br, SBRData chData) {
getBits1Vector(br, chData.bsDfEnv, 0, chData.bsNumEnv);
getBits1Vector(br, chData.bsDfNoise, 0, chData.bsNumNoise);
}
/// Read inverse filtering data
private static void readSbrInvf(SpectralBandReplication sbr, IBitReader br, SBRData chData) {
System.arraycopy(chData.bsInvfMode[0], 0, chData.bsInvfMode[1], 0, 5);
for (int i = 0; i < sbr.nQ; i++) {
chData.bsInvfMode[0][i] = br.read(2);
}
}
private static void readSbrEnvelope(SpectralBandReplication sbr, IBitReader br, SBRData chData, boolean ch) {
int bits;
VLC tHuff, fHuff;
int tLav, fLav;
final int delta = (ch && sbr.bsCoupling ? 1 : 0) + 1;
final int odd = sbr.n[1] & 1;
if (sbr.bsCoupling && ch) {
if (chData.bsAmpRes) {
bits = 5;
tHuff = vlc_sbr[T_HUFFMAN_ENV_BAL_3_0DB];
tLav = vlc_sbr_lav[T_HUFFMAN_ENV_BAL_3_0DB];
fHuff = vlc_sbr[F_HUFFMAN_ENV_BAL_3_0DB];
fLav = vlc_sbr_lav[F_HUFFMAN_ENV_BAL_3_0DB];
} else {
bits = 6;
tHuff = vlc_sbr[T_HUFFMAN_ENV_BAL_1_5DB];
tLav = vlc_sbr_lav[T_HUFFMAN_ENV_BAL_1_5DB];
fHuff = vlc_sbr[F_HUFFMAN_ENV_BAL_1_5DB];
fLav = vlc_sbr_lav[F_HUFFMAN_ENV_BAL_1_5DB];
}
} else {
if (chData.bsAmpRes) {
bits = 6;
tHuff = vlc_sbr[T_HUFFMAN_ENV_3_0DB];
tLav = vlc_sbr_lav[T_HUFFMAN_ENV_3_0DB];
fHuff = vlc_sbr[F_HUFFMAN_ENV_3_0DB];
fLav = vlc_sbr_lav[F_HUFFMAN_ENV_3_0DB];
} else {
bits = 7;
tHuff = vlc_sbr[T_HUFFMAN_ENV_1_5DB];
tLav = vlc_sbr_lav[T_HUFFMAN_ENV_1_5DB];
fHuff = vlc_sbr[F_HUFFMAN_ENV_1_5DB];
fLav = vlc_sbr_lav[F_HUFFMAN_ENV_1_5DB];
}
}
for (int i = 0; i < chData.bsNumEnv; i++) {
if (chData.bsDfEnv[i] != 0) {
// bsFreqRes[0] == bsFreqRes[bsNumEnv] from prev frame
if (chData.bsFreqRes[i + 1] == chData.bsFreqRes[i]) {
for (int j = 0; j < sbr.n[chData.bsFreqRes[i + 1]]; j++) {
chData.envFacs[i + 1][j] = chData.envFacs[i][j] + delta * (tHuff.getVLC2(br, 3) - tLav);
}
} else if (chData.bsFreqRes[i + 1] != 0) {
for (int j = 0; j < sbr.n[chData.bsFreqRes[i + 1]]; j++) {
int k = (j + odd) >> 1; // find k such that f_tablelow[k] <= fTablehigh[j] < f_tablelow[k + 1]
chData.envFacs[i + 1][j] = chData.envFacs[i][k] + delta * (tHuff.getVLC2(br, 3) - tLav);
}
} else {
for (int j = 0; j < sbr.n[chData.bsFreqRes[i + 1]]; j++) {
int k = j != 0 ? 2*j - odd : 0; // find k such that fTablehigh[k] == f_tablelow[j]
chData.envFacs[i + 1][j] = chData.envFacs[i][k] + delta * (tHuff.getVLC2(br, 3) - tLav);
}
}
} else {
chData.envFacs[i + 1][0] = delta * br.read(bits); // bs_env_start_value_balance
for (int j = 1; j < sbr.n[chData.bsFreqRes[i + 1]]; j++) {
chData.envFacs[i + 1][j] = chData.envFacs[i + 1][j - 1] + delta * (fHuff.getVLC2(br, 3) - fLav);
}
}
}
//assign 0th elements of envFacs from last elements
System.arraycopy(chData.envFacs[chData.bsNumEnv], 0, chData.envFacs[0], 0, chData.envFacs[0].length);
}
private static void readSbrNoise(SpectralBandReplication sbr, IBitReader br, SBRData chData, boolean ch) {
int i, j;
VLC t_huff, f_huff;
int t_lav, f_lav;
int delta = (ch && sbr.bsCoupling ? 1 : 0) + 1;
if (sbr.bsCoupling) {
t_huff = vlc_sbr[T_HUFFMAN_NOISE_BAL_3_0DB];
t_lav = vlc_sbr_lav[T_HUFFMAN_NOISE_BAL_3_0DB];
f_huff = vlc_sbr[F_HUFFMAN_ENV_BAL_3_0DB];
f_lav = vlc_sbr_lav[F_HUFFMAN_ENV_BAL_3_0DB];
} else {
t_huff = vlc_sbr[T_HUFFMAN_NOISE_3_0DB];
t_lav = vlc_sbr_lav[T_HUFFMAN_NOISE_3_0DB];
f_huff = vlc_sbr[F_HUFFMAN_ENV_3_0DB];
f_lav = vlc_sbr_lav[F_HUFFMAN_ENV_3_0DB];
}
for (i = 0; i < chData.bsNumNoise; i++) {
if (chData.bsDfNoise[i] != 0) {
for (j = 0; j < sbr.nQ; j++) {
chData.noiseFacs[i + 1][j] = chData.noiseFacs[i][j] + delta * (t_huff.getVLC2(br, 2) - t_lav);
}
} else {
chData.noiseFacs[i + 1][0] = delta * br.read(5); // bs_noise_start_value_balance or bs_noise_start_value_level
for (j = 1; j < sbr.nQ; j++) {
chData.noiseFacs[i + 1][j] = chData.noiseFacs[i + 1][j - 1] + delta * (f_huff.getVLC2(br, 3) - f_lav);
}
}
}
//assign 0th elements of noiseFacs from last elements
System.arraycopy(chData.noiseFacs[chData.bsNumNoise], 0, chData.noiseFacs[0], 0, chData.noiseFacs[0].length);
}
private static int readSbrSingleChannelElement(Context ac, SpectralBandReplication sbr) {
if (ac.br.readBool()) { // bs_data_extra
ac.br.skip(4); // bs_reserved
}
if (readSbrGrid(ac, sbr, sbr.data[0]) != 0) {
return -1;
}
readSbrDtdf(sbr, ac.br, sbr.data[0]);
readSbrInvf(sbr, ac.br, sbr.data[0]);
readSbrEnvelope(sbr, ac.br, sbr.data[0], false);
readSbrNoise(sbr, ac.br, sbr.data[0], false);
sbr.data[0].bsAddHarmonicFlag = ac.br.readBool();
if (sbr.data[0].bsAddHarmonicFlag) {
getBits1Vector(ac.br, sbr.data[0].bsAddHarmonic, 0, sbr.n[1]);
}
return 0;
}
private static int readSbrExtension(Context ac, SpectralBandReplication sbr, int bsExtensionId, int numBitsLeft) {
switch (bsExtensionId) {
case EXTENSION_ID_PS:
if (ac.oc[1].m4ac.ps == 0) {
log.error(String.format("Parametric Stereo signaled to be not-present but was found in the bitstream"));
ac.br.skip(numBitsLeft);
numBitsLeft = 0;
} else {
numBitsLeft -= AacPs.readData(ac, sbr.ps, numBitsLeft);
}
break;
default:
// some files contain 0-padding
if (bsExtensionId != 0 || numBitsLeft > 16 || ac.br.peek(numBitsLeft) != 0) {
log.error(String.format("Reserved SBR extensions"));
}
ac.br.skip(numBitsLeft);
numBitsLeft = 0;
break;
}
return numBitsLeft;
}
private static int readSbrData(Context ac, SpectralBandReplication sbr, int idAac) {
int cnt = ac.br.getBitsRead();
if (idAac == TYPE_SCE || idAac == TYPE_CCE) {
if (readSbrSingleChannelElement(ac, sbr) != 0) {
sbrTurnoff(sbr);
return ac.br.getBitsRead() - cnt;
}
} else {
log.error(String.format("Invalid bitstream - cannot apply SBR to element type %d", idAac));
sbrTurnoff(sbr);
return ac.br.getBitsRead() - cnt;
}
if (ac.br.readBool()) { // bs_extended_data
int numBitsLeft = ac.br.read(4); // bs_extension_size
if (numBitsLeft == 15) {
numBitsLeft += ac.br.read(8); // bs_esc_count
}
numBitsLeft <<= 3;
while (numBitsLeft > 7) {
numBitsLeft -= 2;
numBitsLeft = readSbrExtension(ac, sbr, ac.br.read(2), numBitsLeft);
}
if (numBitsLeft < 0) {
log.error(String.format("SBD Extension over read"));
} else if (numBitsLeft > 0) {
ac.br.skip(numBitsLeft);
}
}
return ac.br.getBitsRead() - cnt;
}
private static void makeBands(int bands[], int bandsOffset, int start, int stop, int numBands) {
float base = (float) pow(stop / (double) start, 1.0 / numBands);
float prod = start;
int previous = start;
for (int k = 0; k < numBands - 1; k++) {
prod *= base;
int present = (int) Math.rint(prod);
bands[bandsOffset + k] = present - previous;
previous = present;
}
bands[bandsOffset + numBands - 1] = stop - previous;
}
private static int checkNMaster(int nMaster, int bsXoverBand) {
// Requirements (14496-3 sp04 p205)
if (nMaster <= 0) {
log.error(String.format("Invalid n_master: %d", nMaster));
return -1;
}
if (bsXoverBand >= nMaster) {
log.error(String.format("Invalid bitstream, crossover band index beyond array bounds: %d", bsXoverBand));
return -1;
}
return 0;
}
private static int arrayMinInt(int array[], int arrayOffset, int nel)
{
int min = array[arrayOffset];
for (int i = 1; i < nel; i++) {
min = Math.min(array[arrayOffset + i], min);
}
return min;
}
private static boolean inTableInt(int table[], int lastEl, int needle) {
for (int i = 0; i <= lastEl; i++) {
if (table[i] == needle) {
return true;
}
}
return false;
}
/// Master Frequency Band Table (14496-3 sp04 p194)
private static int sbrMakeFMaster(Context ac, SpectralBandReplication sbr, SpectrumParameters spectrum) {
int temp, maxQmfSubbands;
int startMin, stopMin;
int sbrOffsetPtr[];
int stopDk[] = new int[13];
if (sbr.sampleRate < 32000) {
temp = 3000;
} else if (sbr.sampleRate < 64000) {
temp = 4000;
} else {
temp = 5000;
}
switch (sbr.sampleRate) {
case 16000:
sbrOffsetPtr = sbr_offset[0];
break;
case 22050:
sbrOffsetPtr = sbr_offset[1];
break;
case 24000:
sbrOffsetPtr = sbr_offset[2];
break;
case 32000:
sbrOffsetPtr = sbr_offset[3];
break;
case 44100: case 48000: case 64000:
sbrOffsetPtr = sbr_offset[4];
break;
case 88200: case 96000: case 128000: case 176400: case 192000:
sbrOffsetPtr = sbr_offset[5];
break;
default:
log.error(String.format("Unsupported sample rate for SBR: %d", sbr.sampleRate));
return -1;
}
startMin = ((temp << 7) + (sbr.sampleRate >> 1)) / sbr.sampleRate;
stopMin = ((temp << 8) + (sbr.sampleRate >> 1)) / sbr.sampleRate;
sbr.k[0] = startMin + sbrOffsetPtr[spectrum.bsStartFreq];
if (spectrum.bsStopFreq < 14) {
sbr.k[2] = stopMin;
makeBands(stopDk, 0, stopMin, 64, 13);
Arrays.sort(stopDk);
for (int k = 0; k < spectrum.bsStopFreq; k++) {
sbr.k[2] += stopDk[k];
}
} else if (spectrum.bsStopFreq == 14) {
sbr.k[2] = 2*sbr.k[0];
} else if (spectrum.bsStopFreq == 15) {
sbr.k[2] = 3*sbr.k[0];
} else {
log.error(String.format("Invalid bsStopFreq: %d", spectrum.bsStopFreq));
return -1;
}
sbr.k[2] = Math.min(64, sbr.k[2]);
// Requirements (14496-3 sp04 p205)
if (sbr.sampleRate <= 32000) {
maxQmfSubbands = 48;
} else if (sbr.sampleRate == 44100) {
maxQmfSubbands = 35;
} else if (sbr.sampleRate >= 48000)
maxQmfSubbands = 32;
else {
log.error(String.format("Unsupported sample rate %d", sbr.sampleRate));
return -1;
}
if (sbr.k[2] - sbr.k[0] > maxQmfSubbands) {
log.error(String.format("Invalid bitstream, too many QMF subbands: %d", sbr.k[2] - sbr.k[0]));
return -1;
}
if (spectrum.bsFreqScale == 0) {
int dk, k2diff;
dk = spectrum.bsAlterScale + 1;
sbr.nMaster = ((sbr.k[2] - sbr.k[0] + (dk&2)) >> dk) << 1;
if (checkNMaster(sbr.nMaster, sbr.spectrumParams.bsXoverBand) != 0)
return -1;
for (int k = 1; k <= sbr.nMaster; k++) {
sbr.fMaster[k] = dk;
}
k2diff = sbr.k[2] - sbr.k[0] - sbr.nMaster * dk;
if (k2diff < 0) {
sbr.fMaster[1]--;
sbr.fMaster[2]-= (k2diff < -1 ? 1 : 0);
} else if (k2diff != 0) {
sbr.fMaster[sbr.nMaster]++;
}
sbr.fMaster[0] = sbr.k[0];
for (int k = 1; k <= sbr.nMaster; k++) {
sbr.fMaster[k] += sbr.fMaster[k - 1];
}
} else {
int half_bands = 7 - spectrum.bsFreqScale; // bsFreqScale = {1,2,3}
int num_bands_0;
boolean two_regions;
int vdk0_max, vdk1_min;
int vk0[] = new int[49];
if (49 * sbr.k[2] > 110 * sbr.k[0]) {
two_regions = true;
sbr.k[1] = 2 * sbr.k[0];
} else {
two_regions = false;
sbr.k[1] = sbr.k[2];
}
num_bands_0 = lrintf(half_bands * log2f(sbr.k[1] / (float)sbr.k[0])) * 2;
if (num_bands_0 <= 0) { // Requirements (14496-3 sp04 p205)
log.error(String.format("Invalid num_bands_0: %d", num_bands_0));
return -1;
}
vk0[0] = 0;
makeBands(vk0, 1, sbr.k[0], sbr.k[1], num_bands_0);
Arrays.sort(vk0, 1, 1 + num_bands_0);
vdk0_max = vk0[num_bands_0];
vk0[0] = sbr.k[0];
for (int k = 1; k <= num_bands_0; k++) {
if (vk0[k] <= 0) { // Requirements (14496-3 sp04 p205)
log.error(String.format("Invalid vDk0[%d]: %d", k, vk0[k]));
return -1;
}
vk0[k] += vk0[k-1];
}
if (two_regions) {
int vk1[] = new int[49];
float invwarp = spectrum.bsAlterScale != 0 ? 0.76923076923076923077f
: 1.0f; // bsAlterScale = {0,1}
int num_bands_1 = lrintf(half_bands * invwarp *
log2f(sbr.k[2] / (float)sbr.k[1])) * 2;
makeBands(vk1, 1, sbr.k[1], sbr.k[2], num_bands_1);
vdk1_min = arrayMinInt(vk1, 1, num_bands_1);
if (vdk1_min < vdk0_max) {
int change;
Arrays.sort(vk1, 1, 1 + num_bands_1);
change = Math.min(vdk0_max - vk1[1], (vk1[num_bands_1] - vk1[1]) >> 1);
vk1[1] += change;
vk1[num_bands_1] -= change;
}
Arrays.sort(vk1, 1, 1 + num_bands_1);
vk1[0] = sbr.k[1];
for (int k = 1; k <= num_bands_1; k++) {
if (vk1[k] <= 0) { // Requirements (14496-3 sp04 p205)
log.error(String.format("Invalid vDk1[%d]: %d", k, vk1[k]));
return -1;
}
vk1[k] += vk1[k-1];
}
sbr.nMaster = num_bands_0 + num_bands_1;
if (checkNMaster(sbr.nMaster, sbr.spectrumParams.bsXoverBand) != 0) {
return -1;
}
System.arraycopy(vk0, 0, sbr.fMaster, 0, num_bands_0 + 1);
System.arraycopy(vk1, 1, sbr.fMaster, num_bands_0 + 1, num_bands_1);
} else {
sbr.nMaster = num_bands_0;
if (checkNMaster(sbr.nMaster, sbr.spectrumParams.bsXoverBand) != 0) {
return -1;
}
System.arraycopy(vk0, 0, sbr.fMaster, 0, num_bands_0 + 1);
}
}
return 0;
}
static final float bands_warped[] = {
1.32715174233856803909f, //2^(0.49/1.2)
1.18509277094158210129f, //2^(0.49/2)
1.11987160404675912501f //2^(0.49/3)
};
/// Limiter Frequency Band Table (14496-3 sp04 p198)
private static void sbrMakeFTablelim(SpectralBandReplication sbr) {
if (sbr.bsLimiterBands > 0) {
final float limBandsPerOctaveWarped = bands_warped[sbr.bsLimiterBands - 1];
int patchBorders[] = new int[7];
int in = 1;
int out = 0;
patchBorders[0] = sbr.kx[1];
for (int k = 1; k <= sbr.numPatches; k++) {
patchBorders[k] = patchBorders[k-1] + sbr.patchNumSubbands[k-1];
}
System.arraycopy(sbr.fTablelow, 0, sbr.fTablelim, 0, sbr.n[0] + 1);
if (sbr.numPatches > 1) {
System.arraycopy(sbr.fTablelim, sbr.n[0] + 1, patchBorders, 1, sbr.numPatches - 1);
}
Arrays.sort(sbr.fTablelim, 0, sbr.numPatches + sbr.n[0]);
sbr.nLim = sbr.n[0] + sbr.numPatches - 1;
while (out < sbr.nLim) {
if (sbr.fTablelim[in] >= sbr.fTablelim[out] * limBandsPerOctaveWarped) {
sbr.fTablelim[++out] = sbr.fTablelim[in++];
} else if (sbr.fTablelim[in] == sbr.fTablelim[out] ||
!inTableInt(patchBorders, sbr.numPatches, sbr.fTablelim[in])) {
in++;
sbr.nLim--;
} else if (!inTableInt(patchBorders, sbr.numPatches, sbr.fTablelim[out])) {
sbr.fTablelim[out] = sbr.fTablelim[in++];
sbr.nLim--;
} else {
sbr.fTablelim[++out] = sbr.fTablelim[in++];
}
}
} else {
sbr.fTablelim[0] = sbr.fTablelow[0];
sbr.fTablelim[1] = sbr.fTablelow[sbr.n[0]];
sbr.nLim = 1;
}
}
/// High Frequency Generation - Patch finalruction (14496-3 sp04 p216 fig. 4.46)
private static int sbrHfCalcNpatches(Context ac, SpectralBandReplication sbr) {
int msb = sbr.k[0];
int usb = sbr.kx[1];
int goal_sb = ((1000 << 11) + (sbr.sampleRate >> 1)) / sbr.sampleRate;
sbr.numPatches = 0;
int k;
if (goal_sb < sbr.kx[1] + sbr.m[1]) {
for (k = 0; sbr.fMaster[k] < goal_sb; k++) {
}
} else {
k = sbr.nMaster;
}
int sb = 0;
do {
int odd = 0;
for (int i = k; i == k || sb > (sbr.k[0] - 1 + msb - odd); i--) {
sb = sbr.fMaster[i];
odd = (sb + sbr.k[0]) & 1;
}
// Requirements (14496-3 sp04 p205) sets the maximum number of patches to 5.
// After this check the final number of patches can still be six which is
// illegal however the Coding Technologies decoder check stream has a final
// count of 6 patches
if (sbr.numPatches > 5) {
log.error(String.format("Too many patches: %d", sbr.numPatches));
return -1;
}
sbr.patchNumSubbands[sbr.numPatches] = Math.max(sb - usb, 0);
sbr.patchStartSubband[sbr.numPatches] = sbr.k[0] - odd - sbr.patchNumSubbands[sbr.numPatches];
if (sbr.patchNumSubbands[sbr.numPatches] > 0) {
usb = sb;
msb = sb;
sbr.numPatches++;
} else
msb = sbr.kx[1];
if (sbr.fMaster[k] - sb < 3) {
k = sbr.nMaster;
}
} while (sb != sbr.kx[1] + sbr.m[1]);
if (sbr.numPatches > 1 && sbr.patchNumSubbands[sbr.numPatches-1] < 3) {
sbr.numPatches--;
}
return 0;
}
/// Derived Frequency Band Tables (14496-3 sp04 p197)
private static int sbrMakeFDerived(Context ac, SpectralBandReplication sbr) {
sbr.n[1] = sbr.nMaster - sbr.spectrumParams.bsXoverBand;
sbr.n[0] = (sbr.n[1] + 1) >> 1;
System.arraycopy(sbr.fMaster, sbr.spectrumParams.bsXoverBand, sbr.fTablehigh, 0, sbr.n[1] + 1);
sbr.m[1] = sbr.fTablehigh[sbr.n[1]] - sbr.fTablehigh[0];
sbr.kx[1] = sbr.fTablehigh[0];
// Requirements (14496-3 sp04 p205)
if (sbr.kx[1] + sbr.m[1] > 64) {
log.error(String.format("Stop frequency border too high: %d", sbr.kx[1] + sbr.m[1]));
return -1;
}
if (sbr.kx[1] > 32) {
log.error(String.format("Start frequency border too high: %d", sbr.kx[1]));
return -1;
}
sbr.fTablelow[0] = sbr.fTablehigh[0];
int temp = sbr.n[1] & 1;
for (int k = 1; k <= sbr.n[0]; k++) {
sbr.fTablelow[k] = sbr.fTablehigh[2 * k - temp];
}
sbr.nQ = Math.max(1, lrintf(sbr.spectrumParams.bsNoiseBands *
log2f(sbr.k[2] / (float)sbr.kx[1]))); // 0 <= bs_noise_bands <= 3
if (sbr.nQ > 5) {
log.error(String.format("Too many noise floor scale factors: %d", sbr.nQ));
return -1;
}
sbr.fTablenoise[0] = sbr.fTablelow[0];
temp = 0;
for (int k = 1; k <= sbr.nQ; k++) {
temp += (sbr.n[0] - temp) / (sbr.nQ + 1 - k);
sbr.fTablenoise[k] = sbr.fTablelow[temp];
}
if (sbrHfCalcNpatches(ac, sbr) < 0) {
return -1;
}
sbrMakeFTablelim(sbr);
sbr.data[0].fIndexnoise = 0;
sbr.data[1].fIndexnoise = 0;
return 0;
}
private static int readSbrHeader(SpectralBandReplication sbr, BitReader br) {
int cnt = br.getBitsRead();
int oldBsLimiterBands = sbr.bsLimiterBands;
SpectrumParameters oldSpectrumParams = new SpectrumParameters();
sbr.start = true;
// Save last spectrum parameters variables to compare to new ones
oldSpectrumParams.copy(sbr.spectrumParams);
sbr.bsAmpResHeader = br.readBool();
sbr.spectrumParams.bsStartFreq = br.read(4);
sbr.spectrumParams.bsStopFreq = br.read(4);
sbr.spectrumParams.bsXoverBand = br.read(3);
br.skip(2); // bs_reserved
boolean bs_header_extra_1 = br.readBool();
boolean bs_header_extra_2 = br.readBool();
if (bs_header_extra_1) {
sbr.spectrumParams.bsFreqScale = br.read(2);
sbr.spectrumParams.bsAlterScale = br.read1();
sbr.spectrumParams.bsNoiseBands = br.read(2);
} else {
sbr.spectrumParams.bsFreqScale = 2;
sbr.spectrumParams.bsAlterScale = 1;
sbr.spectrumParams.bsNoiseBands = 2;
}
// Check if spectrum parameters changed
if (!oldSpectrumParams.equals(sbr.spectrumParams)) {
sbr.reset = true;
}
if (bs_header_extra_2) {
sbr.bsLimiterBands = br.read(2);
sbr.bsLimiterGains = br.read(2);
sbr.bsInterpolFreq = br.readBool();
sbr.bsSmoothingMode = br.readBool();
} else {
sbr.bsLimiterBands = 2;
sbr.bsLimiterGains = 2;
sbr.bsInterpolFreq = true;
sbr.bsSmoothingMode = true;
}
if (sbr.bsLimiterBands != oldBsLimiterBands && !sbr.reset) {
sbrMakeFTablelim(sbr);
}
return br.getBitsRead() - cnt;
}
private static void sbrReset(Context ac, SpectralBandReplication sbr) {
int err = sbrMakeFMaster(ac, sbr, sbr.spectrumParams);
if (err >= 0) {
err = sbrMakeFDerived(ac, sbr);
}
if (err < 0) {
log.error(String.format("SBR reset failed. Switching SBR to pure upsampling mode"));
sbrTurnoff(sbr);
}
}
/**
* Decode Spectral Band Replication extension data; reference: table 4.55.
*
* @param crc flag indicating the presence of CRC checksum
* @param cnt length of TYPE_FIL syntactic element in bytes
*
* @return Returns number of bytes consumed from the TYPE_FIL element.
*/
public static int decodeSbrExtension(Context ac, SpectralBandReplication sbr, boolean crc, int cnt, int idAac) {
int numSbrBits = 0;
sbr.reset = false;
if (sbr.sampleRate == 0) {
sbr.sampleRate = 2 * ac.oc[1].m4ac.sampleRate;
}
if (ac.oc[1].m4ac.extSampleRate == 0) {
ac.oc[1].m4ac.extSampleRate = 2 * ac.oc[1].m4ac.sampleRate;
}
if (crc) {
ac.br.skip(10); // bs_sbr_crc_bits
numSbrBits += 10;
}
// Save some state from the previous frame
sbr.kx[0] = sbr.kx[1];
sbr.m[0] = sbr.m[1];
sbr.kxAndMPushed = true;
numSbrBits++;
if (ac.br.readBool()) { // bs_header_flag
numSbrBits += readSbrHeader(sbr, ac.br);
}
if (sbr.reset) {
sbrReset(ac, sbr);
}
if (sbr.start) {
numSbrBits += readSbrData(ac, sbr, idAac);
}
int numSkipBits = (cnt * 8 - 4 - numSbrBits);
ac.br.skip(numSkipBits);
int numAlignBits = numSkipBits & 7;
int bytesRead = (numSbrBits + numAlignBits + 4) >> 3;
if (bytesRead > cnt) {
log.error(String.format("Expected to read %d SBR bytes actually read %d", cnt, bytesRead));
}
return cnt;
}
// Places SBR in pure upsampling mode
private static void sbrTurnoff(SpectralBandReplication sbr) {
sbr.start = false;
// Init defaults used in pure upsampling mode
sbr.kx[1] = 32; // Typo in spec, kx' inits to 32
sbr.m[1] = 0;
// Reset values for first SBR header
sbr.data[0].eA[1] = -1;
sbr.data[1].eA[1] = -1;
sbr.spectrumParams.reset();
}
public static void ctxInit(SpectralBandReplication sbr) {
if (sbr.mdct != null) {
return;
}
sbr.kx[0] = sbr.kx[1];
sbrTurnoff(sbr);
sbr.data[0].synthesisFilterbankSamplesOffset = SBRData.SBR_SYNTHESIS_BUF_SIZE - (1280 - 128);
sbr.data[1].synthesisFilterbankSamplesOffset = SBRData.SBR_SYNTHESIS_BUF_SIZE - (1280 - 128);
/* SBR requires samples to be scaled to +/-32768.0 to work correctly.
* mdct scale factors are adjusted to scale up from +/-1.0 at analysis
* and scale back down at synthesis. */
sbr.mdct.mdctInit(7, true, 1.9 / (64 * 32768.0));
sbr.mdctAna.mdctInit(7, true, -2.0 * 32768.0);
}
public static void ctxClose(SpectralBandReplication sbr) {
}
/// Dequantization and stereo decoding (14496-3 sp04 p203)
private static void sbrDequant(SpectralBandReplication sbr, int idAac) {
int k, e;
int ch;
if (idAac == TYPE_CPE && sbr.bsCoupling) {
float alpha = sbr.data[0].bsAmpRes ? 1.0f : 0.5f;
float pan_offset = sbr.data[0].bsAmpRes ? 12.0f : 24.0f;
for (e = 1; e <= sbr.data[0].bsNumEnv; e++) {
for (k = 0; k < sbr.n[sbr.data[0].bsFreqRes[e]]; k++) {
float temp1 = exp2f(sbr.data[0].envFacs[e][k] * alpha + 7.0f);
float temp2 = exp2f((pan_offset - sbr.data[1].envFacs[e][k]) * alpha);
float fac;
if (temp1 > 1E20) {
log.error(String.format("envelope scalefactor overflow in dequant"));
temp1 = 1;
}
fac = temp1 / (1.0f + temp2);
sbr.data[0].envFacs[e][k] = fac;
sbr.data[1].envFacs[e][k] = fac * temp2;
}
}
for (e = 1; e <= sbr.data[0].bsNumNoise; e++) {
for (k = 0; k < sbr.nQ; k++) {
float temp1 = exp2f(NOISE_FLOOR_OFFSET - sbr.data[0].noiseFacs[e][k] + 1);
float temp2 = exp2f(12 - sbr.data[1].noiseFacs[e][k]);
float fac;
if (temp1 > 1E20) {
log.error(String.format("envelope scalefactor overflow in dequant"));
temp1 = 1;
}
fac = temp1 / (1.0f + temp2);
sbr.data[0].noiseFacs[e][k] = fac;
sbr.data[1].noiseFacs[e][k] = fac * temp2;
}
}
} else { // SCE or one non-coupled CPE
for (ch = 0; ch < (idAac == TYPE_CPE ? 1 : 0) + 1; ch++) {
float alpha = sbr.data[ch].bsAmpRes ? 1.0f : 0.5f;
for (e = 1; e <= sbr.data[ch].bsNumEnv; e++)
for (k = 0; k < sbr.n[sbr.data[ch].bsFreqRes[e]]; k++){
sbr.data[ch].envFacs[e][k] =
exp2f(alpha * sbr.data[ch].envFacs[e][k] + 6.0f);
if (sbr.data[ch].envFacs[e][k] > 1E20) {
log.error(String.format("envelope scalefactor overflow in dequant"));
sbr.data[ch].envFacs[e][k] = 1;
}
}
for (e = 1; e <= sbr.data[ch].bsNumNoise; e++) {
for (k = 0; k < sbr.nQ; k++) {
sbr.data[ch].noiseFacs[e][k] =
exp2f(NOISE_FLOOR_OFFSET - sbr.data[ch].noiseFacs[e][k]);
}
}
}
}
}
/**
* Analysis QMF Bank (14496-3 sp04 p206)
*
* @param x pointer to the beginning of the first sample window
* @param W array of complex-valued samples split into subbands
*/
private static void sbrQmfAnalysis(FFT mdct, float in[], float x[], float z[], float W[][][][], int bufIdx) {
System.arraycopy(x, 1024, x, 0, 320-32);
System.arraycopy(in, 0, x, 288, 1024);
int xOffset = 0;
for (int i = 0; i < 32; i++) { // numTimeSlots*RATE = 16*2 as 960 sample frames
// are not supported
FloatDSP.vectorFmulReverse(z, 0, AacSbrData.sbr_qmf_window_ds, 0, x, xOffset, 320);
SBRDSP.sum64x5(z, 0);
SBRDSP.qmfPreShuffle(z, 0);
mdct.imdctHalf(z, 0, z, 64);
SBRDSP.qmfPostShuffle(W[bufIdx][i], z, 0);
xOffset += 32;
}
}
/**
* Synthesis QMF Bank (14496-3 sp04 p206) and Downsampled Synthesis QMF Bank
* (14496-3 sp04 p206)
*/
private static void sbrQmfSynthesis(FFT mdct, float out[], float X[][][], float mdctBuf[], float v0[], int vOff[], final int div) {
final float sbrQmfWindow[] = div != 0 ? sbr_qmf_window_ds : sbr_qmf_window_us;
final int step = 128 >> div;
int v;
int outOffset = 0;
for (int i = 0; i < 32; i++) {
if (vOff[0] < step) {
int saved_samples = (1280 - 128) >> div;
System.arraycopy(v0, 0, v0, SBR_SYNTHESIS_BUF_SIZE - saved_samples, saved_samples);
vOff[0] = SBR_SYNTHESIS_BUF_SIZE - saved_samples - step;
} else {
vOff[0] -= step;
}
v = vOff[0];
if (div != 0) {
for (int n = 0; n < 32; n++) {
X[0][i][ n] = -X[0][i][n];
X[0][i][32+n] = X[1][i][31-n];
}
mdct.imdctHalf(mdctBuf, 0, X[0][i], 0);
SBRDSP.qmfDeintNeg(v0, v, mdctBuf, 0);
} else {
SBRDSP.negOdd64(X[1][i], 0);
mdct.imdctHalf(mdctBuf, 0, X[0][i], 0);
mdct.imdctHalf(mdctBuf, 64, X[1][i], 0);
SBRDSP.qmfDeintBfly(v0, v, mdctBuf, 64, mdctBuf, 0);
}
FloatDSP.vectorFmul (out, outOffset, v0, v , sbrQmfWindow, ( 0 ), 64 >> div);
FloatDSP.vectorFmulAdd(out, outOffset, v0, v + ( 192 >> div), sbrQmfWindow, ( 64 >> div), out , outOffset, 64 >> div);
FloatDSP.vectorFmulAdd(out, outOffset, v0, v + ( 256 >> div), sbrQmfWindow, (128 >> div), out , outOffset, 64 >> div);
FloatDSP.vectorFmulAdd(out, outOffset, v0, v + ( 448 >> div), sbrQmfWindow, (192 >> div), out , outOffset, 64 >> div);
FloatDSP.vectorFmulAdd(out, outOffset, v0, v + ( 512 >> div), sbrQmfWindow, (256 >> div), out , outOffset, 64 >> div);
FloatDSP.vectorFmulAdd(out, outOffset, v0, v + ( 704 >> div), sbrQmfWindow, (320 >> div), out , outOffset, 64 >> div);
FloatDSP.vectorFmulAdd(out, outOffset, v0, v + ( 768 >> div), sbrQmfWindow, (384 >> div), out , outOffset, 64 >> div);
FloatDSP.vectorFmulAdd(out, outOffset, v0, v + ( 960 >> div), sbrQmfWindow, (448 >> div), out , outOffset, 64 >> div);
FloatDSP.vectorFmulAdd(out, outOffset, v0, v + (1024 >> div), sbrQmfWindow, (512 >> div), out , outOffset, 64 >> div);
FloatDSP.vectorFmulAdd(out, outOffset, v0, v + (1216 >> div), sbrQmfWindow, (576 >> div), out , outOffset, 64 >> div);
outOffset += 64 >> div;
}
}
private static final float bw_tab[] = { 0.0f, 0.75f, 0.9f, 0.98f };
/// Chirp Factors (14496-3 sp04 p214)
private static void sbrChirp(SpectralBandReplication sbr, SBRData chData) {
int i;
float newBw;
for (i = 0; i < sbr.nQ; i++) {
if (chData.bsInvfMode[0][i] + chData.bsInvfMode[1][i] == 1) {
newBw = 0.6f;
} else {
newBw = bw_tab[chData.bsInvfMode[0][i]];
}
if (newBw < chData.bwArray[i]) {
newBw = 0.75f * newBw + 0.25f * chData.bwArray[i];
} else {
newBw = 0.90625f * newBw + 0.09375f * chData.bwArray[i];
}
chData.bwArray[i] = newBw < 0.015625f ? 0.0f : newBw;
}
}
/// High Frequency Generator (14496-3 sp04 p215)
private static int sbrHfGen(Context ac, SpectralBandReplication sbr,
float Xhigh[][][], final float Xlow[][][],
final float alpha0[][], final float alpha1[][],
final float bwArray[], final int tEnv[],
int bsNumEnv) {
int g = 0;
int k = sbr.kx[1];
for (int j = 0; j < sbr.numPatches; j++) {
for (int x = 0; x < sbr.patchNumSubbands[j]; x++, k++) {
final int p = sbr.patchStartSubband[j] + x;
while (g <= sbr.nQ && k >= sbr.fTablenoise[g]) {
g++;
}
g--;
if (g < 0) {
log.error(String.format("ERROR : no subband found for frequency %d", k));
return -1;
}
SBRDSP.hf_gen(Xhigh[k], ENVELOPE_ADJUSTMENT_OFFSET,
Xlow[p], ENVELOPE_ADJUSTMENT_OFFSET,
alpha0[p], alpha1[p], bwArray[g],
2 * tEnv[0], 2 * tEnv[bsNumEnv]);
}
}
if (k < sbr.m[1] + sbr.kx[1]) {
Arrays.fill(Xhigh, k, sbr.m[1] + sbr.kx[1], 0f);
}
return 0;
}
/** High Frequency Adjustment (14496-3 sp04 p217) and Mapping
* (14496-3 sp04 p217)
*/
private static int sbrMapping(Context ac, SpectralBandReplication sbr, SBRData chData, int eA[]) {
for (int i = 1; i < 8; i++) {
Arrays.fill(chData.sIndexmapped[i], 0);
}
for (int e = 0; e < chData.bsNumEnv; e++) {
final int ilim = sbr.n[chData.bsFreqRes[e + 1]];
int table[] = chData.bsFreqRes[e + 1] != 0 ? sbr.fTablehigh : sbr.fTablelow;
if (sbr.kx[1] != table[0]) {
log.error(String.format("kx != f_table{high,low}[0]. Derived frequency tables were not regenerated."));
sbrTurnoff(sbr);
return AAC_ERROR;
}
for (int i = 0; i < ilim; i++) {
for (int m = table[i]; m < table[i + 1]; m++) {
sbr.eOrigmapped[e][m - sbr.kx[1]] = chData.envFacs[e+1][i];
}
}
// ch_data.bsNumNoise > 1 => 2 noise floors
int k = (chData.bsNumNoise > 1) && (chData.tEnv[e] >= chData.tQ[1]) ? 1 : 0;
for (int i = 0; i < sbr.nQ; i++) {
for (int m = sbr.fTablenoise[i]; m < sbr.fTablenoise[i + 1]; m++) {
sbr.qMapped[e][m - sbr.kx[1]] = chData.noiseFacs[k+1][i];
}
}
for (int i = 0; i < sbr.n[1]; i++) {
if (chData.bsAddHarmonicFlag) {
final int m_midpoint = (sbr.fTablehigh[i] + sbr.fTablehigh[i + 1]) >> 1;
chData.sIndexmapped[e + 1][m_midpoint - sbr.kx[1]] = chData.bsAddHarmonic[i] *
(e >= eA[1] || (chData.sIndexmapped[0][m_midpoint - sbr.kx[1]] == 1) ? 1 : 0);
}
}
for (int i = 0; i < ilim; i++) {
int additional_sinusoid_present = 0;
for (int m = table[i]; m < table[i + 1]; m++) {
if (chData.sIndexmapped[e + 1][m - sbr.kx[1]] != 0) {
additional_sinusoid_present = 1;
break;
}
}
Arrays.fill(sbr.sMapped[e], table[i] - sbr.kx[1], table[i + 1] - sbr.kx[1], additional_sinusoid_present);
}
}
System.arraycopy(chData.sIndexmapped[chData.bsNumEnv], 0, chData.sIndexmapped[0], 0, chData.sIndexmapped[0].length);
return 0;
}
/// Estimation of current envelope (14496-3 sp04 p218)
private static void sbrEnvEstimate(float eCurr[][], float Xhigh[][][], SpectralBandReplication sbr, SBRData chData) {
int kx1 = sbr.kx[1];
if (sbr.bsInterpolFreq) {
for (int e = 0; e < chData.bsNumEnv; e++) {
final float recipEnvSize = 0.5f / (chData.tEnv[e + 1] - chData.tEnv[e]);
int ilb = chData.tEnv[e] * 2 + ENVELOPE_ADJUSTMENT_OFFSET;
int iub = chData.tEnv[e + 1] * 2 + ENVELOPE_ADJUSTMENT_OFFSET;
for (int m = 0; m < sbr.m[1]; m++) {
float sum = SBRDSP.sum_square(Xhigh[m + kx1], ilb, iub - ilb);
eCurr[e][m] = sum * recipEnvSize;
}
}
} else {
for (int e = 0; e < chData.bsNumEnv; e++) {
final int envSize = 2 * (chData.tEnv[e + 1] - chData.tEnv[e]);
int ilb = chData.tEnv[e] * 2 + ENVELOPE_ADJUSTMENT_OFFSET;
int iub = chData.tEnv[e + 1] * 2 + ENVELOPE_ADJUSTMENT_OFFSET;
final int table[] = chData.bsFreqRes[e + 1] != 0 ? sbr.fTablehigh : sbr.fTablelow;
for (int p = 0; p < sbr.n[chData.bsFreqRes[e + 1]]; p++) {
float sum = 0.0f;
final int den = envSize * (table[p + 1] - table[p]);
for (int k = table[p]; k < table[p + 1]; k++) {
sum += SBRDSP.sum_square(Xhigh[k], ilb, iub - ilb);
}
sum /= den;
for (int k = table[p]; k < table[p + 1]; k++) {
eCurr[e][k - kx1] = sum;
}
}
}
}
}
// max gain limits : -3dB, 0dB, 3dB, inf dB (limiter off)
private static final float limgain[] = { 0.70795f, 1.0f, 1.41254f, 10000000000f };
/**
* Calculation of levels of additional HF signal components (14496-3 sp04 p219)
* and Calculation of gain (14496-3 sp04 p219)
*/
private static void sbrGainCalc(SpectralBandReplication sbr, SBRData chData, final int eA[]) {
int e, k, m;
for (e = 0; e < chData.bsNumEnv; e++) {
int delta = !(e == eA[1]) || (e == eA[0]) ? 1 : 0;
for (k = 0; k < sbr.nLim; k++) {
float gain_boost, gain_max;
float sum[] = { 0.0f, 0.0f };
for (m = sbr.fTablelim[k] - sbr.kx[1]; m < sbr.fTablelim[k + 1] - sbr.kx[1]; m++) {
final float temp = sbr.eOrigmapped[e][m] / (1.0f + sbr.qMapped[e][m]);
sbr.qM[e][m] = sqrtf(temp * sbr.qMapped[e][m]);
sbr.sM[e][m] = sqrtf(temp * chData.sIndexmapped[e + 1][m]);
if (sbr.sMapped[e][m] == 0) {
sbr.gain[e][m] = sqrtf(sbr.eOrigmapped[e][m] /
((1.0f + sbr.eCurr[e][m]) *
(1.0f + sbr.qMapped[e][m] * delta)));
} else {
sbr.gain[e][m] = sqrtf(sbr.eOrigmapped[e][m] * sbr.qMapped[e][m] /
((1.0f + sbr.eCurr[e][m]) *
(1.0f + sbr.qMapped[e][m])));
}
}
for (m = sbr.fTablelim[k] - sbr.kx[1]; m < sbr.fTablelim[k + 1] - sbr.kx[1]; m++) {
sum[0] += sbr.eOrigmapped[e][m];
sum[1] += sbr.eCurr[e][m];
}
gain_max = limgain[sbr.bsLimiterGains] * sqrtf((FLT_EPSILON + sum[0]) / (FLT_EPSILON + sum[1]));
gain_max = Math.min(100000.f, gain_max);
for (m = sbr.fTablelim[k] - sbr.kx[1]; m < sbr.fTablelim[k + 1] - sbr.kx[1]; m++) {
float qM_max = sbr.qM[e][m] * gain_max / sbr.gain[e][m];
sbr.qM[e][m] = Math.min(sbr.qM[e][m], qM_max);
sbr.gain[e][m] = Math.min(sbr.gain[e][m], gain_max);
}
sum[0] = sum[1] = 0.0f;
for (m = sbr.fTablelim[k] - sbr.kx[1]; m < sbr.fTablelim[k + 1] - sbr.kx[1]; m++) {
sum[0] += sbr.eOrigmapped[e][m];
sum[1] += sbr.eCurr[e][m] * sbr.gain[e][m] * sbr.gain[e][m]
+ sbr.sM[e][m] * sbr.sM[e][m]
+ (delta != 0 && sbr.sM[e][m] == 0 ? 1 : 0) * sbr.qM[e][m] * sbr.qM[e][m];
}
gain_boost = sqrtf((FLT_EPSILON + sum[0]) / (FLT_EPSILON + sum[1]));
gain_boost = Math.min(1.584893192f, gain_boost);
for (m = sbr.fTablelim[k] - sbr.kx[1]; m < sbr.fTablelim[k + 1] - sbr.kx[1]; m++) {
sbr.gain[e][m] *= gain_boost;
sbr.qM[e][m] *= gain_boost;
sbr.sM[e][m] *= gain_boost;
}
}
}
}
/// Generate the subband filtered lowband
private static int sbrLfGen(SpectralBandReplication sbr, float Xlow[][][], final float W[][][][], int bufIdx) {
final int tHFGen = 8;
final int iF = 32;
Utilities.fill(Xlow, 0f);
for (int k = 0; k < sbr.kx[1]; k++) {
for (int i = tHFGen; i < iF + tHFGen; i++) {
Xlow[k][i][0] = W[bufIdx][i - tHFGen][k][0];
Xlow[k][i][1] = W[bufIdx][i - tHFGen][k][1];
}
}
bufIdx = 1 - bufIdx;
for (int k = 0; k < sbr.kx[0]; k++) {
for (int i = 0; i < tHFGen; i++) {
Xlow[k][i][0] = W[bufIdx][i + iF - tHFGen][k][0];
Xlow[k][i][1] = W[bufIdx][i + iF - tHFGen][k][1];
}
}
return 0;
}
/** High Frequency Generation (14496-3 sp04 p214+) and Inverse Filtering
* (14496-3 sp04 p214)
* Warning: This routine does not seem numerically stable.
*/
private static void sbrHfInverseFilter(float alpha0[][], float alpha1[][], final float Xlow[][][], int k0) {
float phi[][][] = new float[3][2][2];
for (int k = 0; k < k0; k++) {
SBRDSP.autocorrelate(Xlow[k], phi);
float dk = phi[2][1][0] * phi[1][0][0] -
(phi[1][1][0] * phi[1][1][0] + phi[1][1][1] * phi[1][1][1]) / 1.000001f;
if (dk == 0f) {
alpha1[k][0] = 0f;
alpha1[k][1] = 0f;
} else {
float tempReal, tempIm;
tempReal = phi[0][0][0] * phi[1][1][0] -
phi[0][0][1] * phi[1][1][1] -
phi[0][1][0] * phi[1][0][0];
tempIm = phi[0][0][0] * phi[1][1][1] +
phi[0][0][1] * phi[1][1][0] -
phi[0][1][1] * phi[1][0][0];
alpha1[k][0] = tempReal / dk;
alpha1[k][1] = tempIm / dk;
}
if (phi[1][0][0] == 0f) {
alpha0[k][0] = 0f;
alpha0[k][1] = 0f;
} else {
float tempReal, tempIm;
tempReal = phi[0][0][0] + alpha1[k][0] * phi[1][1][0] +
alpha1[k][1] * phi[1][1][1];
tempIm = phi[0][0][1] + alpha1[k][1] * phi[1][1][0] -
alpha1[k][0] * phi[1][1][1];
alpha0[k][0] = -tempReal / phi[1][0][0];
alpha0[k][1] = -tempIm / phi[1][0][0];
}
if (alpha1[k][0] * alpha1[k][0] + alpha1[k][1] * alpha1[k][1] >= 16.0f ||
alpha0[k][0] * alpha0[k][0] + alpha0[k][1] * alpha0[k][1] >= 16.0f) {
alpha1[k][0] = 0f;
alpha1[k][1] = 0f;
alpha0[k][0] = 0f;
alpha0[k][1] = 0f;
}
}
}
private static final float h_smooth[] = {
0.33333333333333f,
0.30150283239582f,
0.21816949906249f,
0.11516383427084f,
0.03183050093751f
};
/// Assembling HF Signals (14496-3 sp04 p220)
private static void sbrHfAssemble(float Y1[][][], final float Xhigh[][][], SpectralBandReplication sbr, SBRData chData, final int eA[]) {
final int h_SL = 4 * (!sbr.bsSmoothingMode ? 1 : 0);
final int kx = sbr.kx[1];
final int m_max = sbr.m[1];
float gTemp[][] = chData.gTemp, qTemp[][] = chData.qTemp;
int indexnoise = chData.fIndexnoise;
int indexsine = chData.fIndexsine;
if (sbr.reset) {
for (int i = 0; i < h_SL; i++) {
System.arraycopy(sbr.gain[0], 0, gTemp[i + 2*chData.tEnv[0]], 0, m_max);
System.arraycopy(sbr.qM[0], 0, qTemp[i + 2*chData.tEnv[0]], 0, m_max);
}
} else if (h_SL != 0) {
System.arraycopy(gTemp[2*chData.tEnvNumEnvOld], 0, gTemp[2*chData.tEnv[0]], 0, 4);
System.arraycopy(qTemp[2*chData.tEnvNumEnvOld], 0, qTemp[2*chData.tEnv[0]], 0, 4);
}
for (int e = 0; e < chData.bsNumEnv; e++) {
for (int i = 2 * chData.tEnv[e]; i < 2 * chData.tEnv[e + 1]; i++) {
System.arraycopy(sbr.gain[e], 0, gTemp[h_SL + i], 0, m_max);
System.arraycopy(sbr.qM[e], 0, qTemp[h_SL + i], 0, m_max);
}
}
final float g_filt_tab[] = new float[48];
final float q_filt_tab[] = new float[48];
for (int e = 0; e < chData.bsNumEnv; e++) {
for (int i = 2 * chData.tEnv[e]; i < 2 * chData.tEnv[e + 1]; i++) {
float gFilt[], qFilt[];
if (h_SL != 0 && e != eA[0] && e != eA[1]) {
gFilt = g_filt_tab;
qFilt = q_filt_tab;
for (int m = 0; m < m_max; m++) {
final int idx1 = i + h_SL;
gFilt[m] = 0.0f;
qFilt[m] = 0.0f;
for (int j = 0; j <= h_SL; j++) {
gFilt[m] += gTemp[idx1 - j][m] * h_smooth[j];
qFilt[m] += qTemp[idx1 - j][m] * h_smooth[j];
}
}
} else {
gFilt = gTemp[i + h_SL];
qFilt = qTemp[i];
}
SBRDSP.hfGFilt(Y1[i], kx, Xhigh, kx, gFilt, m_max, i + ENVELOPE_ADJUSTMENT_OFFSET);
if (e != eA[0] && e != eA[1]) {
SBRDSP.hf_apply_noise(Y1[i], kx, sbr.sM[e], qFilt, indexnoise, kx, m_max, indexsine);
} else {
int idx = indexsine&1;
int A = (1-((indexsine+(kx & 1))&2));
int B = (A^(-idx)) + idx;
float out[] = Y1[i][kx];
float in[] = sbr.sM[e];
int m;
for (m = 0; m + 1 < m_max; m+=2) {
out[idx + 2*m ] += in[m ] * A;
out[idx + 2*m+2] += in[m+1] * B;
}
if ((m_max & 1) != 0) {
out[idx + 2*m ] += in[m ] * A;
}
}
indexnoise = (indexnoise + m_max) & 0x1ff;
indexsine = (indexsine + 1) & 3;
}
}
chData.fIndexnoise = indexnoise;
chData.fIndexsine = indexsine;
}
/// Generate the subband filtered lowband
private static int sbrXGen(SpectralBandReplication sbr, float X[][][], final float Y0[][][], final float Y1[][][], final float Xlow[][][], int ch) {
int k, i;
final int i_f = 32;
final int i_Temp = Math.max(2*sbr.data[ch].tEnvNumEnvOld - i_f, 0);
Utilities.fill(X, 0f);
for (k = 0; k < sbr.kx[0]; k++) {
for (i = 0; i < i_Temp; i++) {
X[0][i][k] = Xlow[k][i + ENVELOPE_ADJUSTMENT_OFFSET][0];
X[1][i][k] = Xlow[k][i + ENVELOPE_ADJUSTMENT_OFFSET][1];
}
}
for (; k < sbr.kx[0] + sbr.m[0]; k++) {
for (i = 0; i < i_Temp; i++) {
X[0][i][k] = Y0[i + i_f][k][0];
X[1][i][k] = Y0[i + i_f][k][1];
}
}
for (k = 0; k < sbr.kx[1]; k++) {
for (i = i_Temp; i < 38; i++) {
X[0][i][k] = Xlow[k][i + ENVELOPE_ADJUSTMENT_OFFSET][0];
X[1][i][k] = Xlow[k][i + ENVELOPE_ADJUSTMENT_OFFSET][1];
}
}
for (; k < sbr.kx[1] + sbr.m[1]; k++) {
for (i = i_Temp; i < i_f; i++) {
X[0][i][k] = Y1[i][k][0];
X[1][i][k] = Y1[i][k][1];
}
}
return 0;
}
public static void sbrApply(Context ac, SpectralBandReplication sbr, int idAac, float L[], float R[]) {
int downsampled = ac.oc[1].m4ac.extSampleRate < sbr.sampleRate ? 1 : 0;
int nch = (idAac == TYPE_CPE) ? 2 : 1;
if (!sbr.kxAndMPushed) {
sbr.kx[0] = sbr.kx[1];
sbr.m[0] = sbr.m[1];
} else {
sbr.kxAndMPushed = false;
}
if (sbr.start) {
sbrDequant(sbr, idAac);
}
for (int ch = 0; ch < nch; ch++) {
/* decode channel */
sbrQmfAnalysis(sbr.mdctAna, ch != 0 ? R : L, sbr.data[ch].analysisFilterbankSamples,
sbr.qmfFilterScratch,
sbr.data[ch].W, sbr.data[ch].Ypos);
sbrLfGen(sbr, sbr.Xlow, sbr.data[ch].W, sbr.data[ch].Ypos);
sbr.data[ch].Ypos ^= 1;
if (sbr.start) {
sbrHfInverseFilter(sbr.alpha0, sbr.alpha1, sbr.Xlow, sbr.k[0]);
sbrChirp(sbr, sbr.data[ch]);
sbrHfGen(ac, sbr, sbr.Xhigh, sbr.Xlow, sbr.alpha0, sbr.alpha1, sbr.data[ch].bwArray, sbr.data[ch].tEnv, sbr.data[ch].bsNumEnv);
// hf_adj
int err = sbrMapping(ac, sbr, sbr.data[ch], sbr.data[ch].eA);
if (err == 0) {
sbrEnvEstimate(sbr.eCurr, sbr.Xhigh, sbr, sbr.data[ch]);
sbrGainCalc(sbr, sbr.data[ch], sbr.data[ch].eA);
sbrHfAssemble(sbr.data[ch].Y[sbr.data[ch].Ypos],
sbr.Xhigh,
sbr, sbr.data[ch],
sbr.data[ch].eA);
}
}
/* synthesis */
sbrXGen(sbr, sbr.X[ch],
sbr.data[ch].Y[1-sbr.data[ch].Ypos],
sbr.data[ch].Y[ sbr.data[ch].Ypos],
sbr.Xlow, ch);
}
if (ac.oc[1].m4ac.ps == 1) {
if (sbr.ps.start) {
AacPs.psApply(sbr.ps, sbr.X[0], sbr.X[1], sbr.kx[1] + sbr.m[1]);
} else {
Utilities.copy(sbr.X[1], sbr.X[0]);
}
nch = 2;
}
int[] tmp = new int[1];
tmp[0] = sbr.data[0].synthesisFilterbankSamplesOffset;
sbrQmfSynthesis(sbr.mdct,
L, sbr.X[0], sbr.qmfFilterScratch,
sbr.data[0].synthesisFilterbankSamples,
tmp,
downsampled);
sbr.data[0].synthesisFilterbankSamplesOffset = tmp[0];
if (nch == 2) {
tmp[0] = sbr.data[1].synthesisFilterbankSamplesOffset;
sbrQmfSynthesis(sbr.mdct,
R, sbr.X[1], sbr.qmfFilterScratch,
sbr.data[1].synthesisFilterbankSamples,
tmp,
downsampled);
sbr.data[1].synthesisFilterbankSamplesOffset = tmp[0];
}
}
}