package net.sourceforge.jaad.aac.ps;
import net.sourceforge.jaad.aac.AACException;
import net.sourceforge.jaad.aac.SampleFrequency;
import net.sourceforge.jaad.aac.syntax.IBitStream;
/**
* This class is part of JAAD ( jaadec.sourceforge.net ) that is distributed
* under the Public Domain license. Code changes provided by the JCodec project
* are distributed under FreeBSD license.
*
* @author in-somnia
*/
public class PS implements PSConstants, PSTables, PSHuffmanTables {
/* bitstream parameters */
boolean enable_iid, enable_icc, enable_ext;
int iid_mode;
int icc_mode;
int nr_iid_par;
int nr_ipdopd_par;
int nr_icc_par;
int frame_class;
int num_env;
int[] border_position;
boolean[] iid_dt;
boolean[] icc_dt;
boolean enable_ipdopd;
int ipd_mode;
boolean[] ipd_dt;
boolean[] opd_dt;
/* indices */
int[] iid_index_prev;
int[] icc_index_prev;
int[] ipd_index_prev;
int[] opd_index_prev;
int[][] iid_index;
int[][] icc_index;
int[][] ipd_index;
int[][] opd_index;
int[] ipd_index_1;
int[] opd_index_1;
int[] ipd_index_2;
int[] opd_index_2;
/* ps data was correctly read */
int ps_data_available;
/* a header has been read */
public boolean header_read;
/* hybrid filterbank parameters */
PSFilterbank hyb;
boolean use34hybrid_bands;
int numTimeSlotsRate;
int num_groups;
int num_hybrid_groups;
int nr_par_bands;
int nr_allpass_bands;
int decay_cutoff;
int[] group_border;
int[] map_group2bk;
/* filter delay handling */
int saved_delay;
int[] delay_buf_index_ser;
int[] num_sample_delay_ser;
int[] delay_D;
int[] delay_buf_index_delay;
float[][][] delay_Qmf; /* 14 samples delay max, 64 QMF channels */
float[][][] delay_SubQmf; /* 2 samples delay max (SubQmf is always allpass filtered) */
float[][][][] delay_Qmf_ser; /* 5 samples delay max (table 8.34), 64 QMF channels */
float[][][][] delay_SubQmf_ser; /* 5 samples delay max (table 8.34) */
/* transients */
float alpha_decay;
float alpha_smooth;
float[] P_PeakDecayNrg;
float[] P_prev;
float[] P_SmoothPeakDecayDiffNrg_prev;
/* mixing and phase */
float[][] h11_prev;
float[][] h12_prev;
float[][] h21_prev;
float[][] h22_prev;
int phase_hist;
float[][][] ipd_prev;
float[][][] opd_prev;
public PS(SampleFrequency sr, int numTimeSlotsRate) {
this.border_position = new int[MAX_PS_ENVELOPES+1];
this.iid_dt = new boolean[MAX_PS_ENVELOPES];
this.icc_dt = new boolean[MAX_PS_ENVELOPES];
this.ipd_dt = new boolean[MAX_PS_ENVELOPES];
this.opd_dt = new boolean[MAX_PS_ENVELOPES];
this.iid_index_prev = new int[34];
this.icc_index_prev = new int[34];
this.ipd_index_prev = new int[17];
this.opd_index_prev = new int[17];
this.iid_index = new int[MAX_PS_ENVELOPES][34];
this.icc_index = new int[MAX_PS_ENVELOPES][34];
this.ipd_index = new int[MAX_PS_ENVELOPES][17];
this.opd_index = new int[MAX_PS_ENVELOPES][17];
this.ipd_index_1 = new int[17];
this.opd_index_1 = new int[17];
this.ipd_index_2 = new int[17];
this.opd_index_2 = new int[17];
this.delay_buf_index_ser = new int[NO_ALLPASS_LINKS];
this.num_sample_delay_ser = new int[NO_ALLPASS_LINKS];
this.delay_D = new int[64];
this.delay_buf_index_delay = new int[64];
this.delay_Qmf = new float[14][64][2]; /* 14 samples delay max, 64 QMF channels */
this.delay_SubQmf = new float[2][32][2]; /* 2 samples delay max (SubQmf is always allpass filtered) */
this.delay_Qmf_ser = new float[NO_ALLPASS_LINKS][5][64][2]; /* 5 samples delay max (table 8.34), 64 QMF channels */
this.delay_SubQmf_ser = new float[NO_ALLPASS_LINKS][5][32][2]; /* 5 samples delay max (table 8.34) */
this.P_PeakDecayNrg = new float[34];
this.P_prev = new float[34];
this.P_SmoothPeakDecayDiffNrg_prev = new float[34];
this.h11_prev = new float[50][2];
this.h12_prev = new float[50][2];
this.h21_prev = new float[50][2];
this.h22_prev = new float[50][2];
this.ipd_prev = new float[20][2][2];
this.opd_prev = new float[20][2][2];
int i;
int short_delay_band;
hyb = new PSFilterbank(numTimeSlotsRate);
this.numTimeSlotsRate = numTimeSlotsRate;
this.ps_data_available = 0;
/* delay stuff*/
this.saved_delay = 0;
for(i = 0; i<64; i++) {
this.delay_buf_index_delay[i] = 0;
}
for(i = 0; i<NO_ALLPASS_LINKS; i++) {
this.delay_buf_index_ser[i] = 0;
/* THESE ARE CONSTANTS NOW */
this.num_sample_delay_ser[i] = delay_length_d[i];
}
/* THESE ARE CONSTANTS NOW */
short_delay_band = 35;
this.nr_allpass_bands = 22;
this.alpha_decay = 0.76592833836465f;
this.alpha_smooth = 0.25f;
/* THESE ARE CONSTANT NOW IF PS IS INDEPENDANT OF SAMPLERATE */
for(i = 0; i<short_delay_band; i++) {
this.delay_D[i] = 14;
}
for(i = short_delay_band; i<64; i++) {
this.delay_D[i] = 1;
}
/* mixing and phase */
for(i = 0; i<50; i++) {
this.h11_prev[i][0] = 1;
this.h12_prev[i][1] = 1;
this.h11_prev[i][0] = 1;
this.h12_prev[i][1] = 1;
}
this.phase_hist = 0;
for(i = 0; i<20; i++) {
this.ipd_prev[i][0][0] = 0;
this.ipd_prev[i][0][1] = 0;
this.ipd_prev[i][1][0] = 0;
this.ipd_prev[i][1][1] = 0;
this.opd_prev[i][0][0] = 0;
this.opd_prev[i][0][1] = 0;
this.opd_prev[i][1][0] = 0;
this.opd_prev[i][1][1] = 0;
}
}
public int decode(IBitStream ld) throws AACException {
int tmp, n;
long bits = ld.getPosition();
/* check for new PS header */
if(ld.readBool()) {
this.header_read = true;
this.use34hybrid_bands = false;
/* Inter-channel Intensity Difference (IID) parameters enabled */
this.enable_iid = ld.readBool();
if(this.enable_iid) {
this.iid_mode = ld.readBits(3);
this.nr_iid_par = nr_iid_par_tab[this.iid_mode];
this.nr_ipdopd_par = nr_ipdopd_par_tab[this.iid_mode];
if(this.iid_mode==2||this.iid_mode==5)
this.use34hybrid_bands = true;
/* IPD freq res equal to IID freq res */
this.ipd_mode = this.iid_mode;
}
/* Inter-channel Coherence (ICC) parameters enabled */
this.enable_icc = ld.readBool();
if(this.enable_icc) {
this.icc_mode = ld.readBits(3);
this.nr_icc_par = nr_icc_par_tab[this.icc_mode];
if(this.icc_mode==2||this.icc_mode==5)
this.use34hybrid_bands = true;
}
/* PS extension layer enabled */
this.enable_ext = ld.readBool();
}
/* we are here, but no header has been read yet */
if(this.header_read==false) {
this.ps_data_available = 0;
return 1;
}
this.frame_class = ld.readBit();
tmp = ld.readBits(2);
this.num_env = num_env_tab[this.frame_class][tmp];
if(this.frame_class!=0) {
for(n = 1; n<this.num_env+1; n++) {
this.border_position[n] = ld.readBits(5)+1;
}
}
if(this.enable_iid) {
for(n = 0; n<this.num_env; n++) {
this.iid_dt[n] = ld.readBool();
/* iid_data */
if(this.iid_mode<3) {
huff_data(ld, this.iid_dt[n], this.nr_iid_par, t_huff_iid_def,
f_huff_iid_def, this.iid_index[n]);
}
else {
huff_data(ld, this.iid_dt[n], this.nr_iid_par, t_huff_iid_fine,
f_huff_iid_fine, this.iid_index[n]);
}
}
}
if(this.enable_icc) {
for(n = 0; n<this.num_env; n++) {
this.icc_dt[n] = ld.readBool();
/* icc_data */
huff_data(ld, this.icc_dt[n], this.nr_icc_par, t_huff_icc,
f_huff_icc, this.icc_index[n]);
}
}
if(this.enable_ext) {
int num_bits_left;
int cnt = ld.readBits(4);
if(cnt==15) {
cnt += ld.readBits(8);
}
num_bits_left = 8*cnt;
while(num_bits_left>7) {
int ps_extension_id = ld.readBits(2);
num_bits_left -= 2;
num_bits_left -= ps_extension(ld, ps_extension_id, num_bits_left);
}
ld.skipBits(num_bits_left);
}
int bits2 = (int) (ld.getPosition()-bits);
this.ps_data_available = 1;
return bits2;
}
private int ps_extension(IBitStream ld,
int ps_extension_id,
int num_bits_left) throws AACException {
int n;
long bits = ld.getPosition();
if(ps_extension_id==0) {
this.enable_ipdopd = ld.readBool();
if(this.enable_ipdopd) {
for(n = 0; n<this.num_env; n++) {
this.ipd_dt[n] = ld.readBool();
/* ipd_data */
huff_data(ld, this.ipd_dt[n], this.nr_ipdopd_par, t_huff_ipd,
f_huff_ipd, this.ipd_index[n]);
this.opd_dt[n] = ld.readBool();
/* opd_data */
huff_data(ld, this.opd_dt[n], this.nr_ipdopd_par, t_huff_opd,
f_huff_opd, this.opd_index[n]);
}
}
ld.readBit(); //reserved
}
/* return number of bits read */
int bits2 = (int) (ld.getPosition()-bits);
return bits2;
}
/* read huffman data coded in either the frequency or the time direction */
private void huff_data(IBitStream ld, boolean dt, int nr_par,
int[][] t_huff, int[][] f_huff, int[] par) throws AACException {
int n;
if(dt) {
/* coded in time direction */
for(n = 0; n<nr_par; n++) {
par[n] = ps_huff_dec(ld, t_huff);
}
}
else {
/* coded in frequency direction */
par[0] = ps_huff_dec(ld, f_huff);
for(n = 1; n<nr_par; n++) {
par[n] = ps_huff_dec(ld, f_huff);
}
}
}
/* binary search huffman decoding */
private int ps_huff_dec(IBitStream ld, int[][] t_huff) throws AACException {
int bit;
int index = 0;
while(index>=0) {
bit = ld.readBit();
index = t_huff[index][bit];
}
return index+31;
}
/* limits the value i to the range [min,max] */
private int delta_clip(int i, int min, int max) {
if(i<min) return min;
else if(i>max) return max;
else return i;
}
/* delta decode array */
private void delta_decode(boolean enable, int[] index, int[] index_prev,
boolean dt_flag, int nr_par, int stride,
int min_index, int max_index) {
int i;
if(enable) {
if(!dt_flag) {
/* delta coded in frequency direction */
index[0] = 0+index[0];
index[0] = delta_clip(index[0], min_index, max_index);
for(i = 1; i<nr_par; i++) {
index[i] = index[i-1]+index[i];
index[i] = delta_clip(index[i], min_index, max_index);
}
}
else {
/* delta coded in time direction */
for(i = 0; i<nr_par; i++) {
//int8_t tmp2;
//int8_t tmp = index[i];
//printf("%d %d\n", index_prev[i*stride], index[i]);
//printf("%d\n", index[i]);
index[i] = index_prev[i*stride]+index[i];
//tmp2 = index[i];
index[i] = delta_clip(index[i], min_index, max_index);
//if (iid)
//{
// if (index[i] == 7)
// {
// printf("%d %d %d\n", index_prev[i*stride], tmp, tmp2);
// }
//}
}
}
}
else {
/* set indices to zero */
for(i = 0; i<nr_par; i++) {
index[i] = 0;
}
}
/* coarse */
if(stride==2) {
for(i = (nr_par<<1)-1; i>0; i--) {
index[i] = index[i>>1];
}
}
}
/* delta modulo decode array */
/* in: log2 value of the modulo value to allow using AND instead of MOD */
private void delta_modulo_decode(boolean enable, int[] index, int[] index_prev,
boolean dt_flag, int nr_par, int stride,
int and_modulo) {
int i;
if(enable) {
if(!dt_flag) {
/* delta coded in frequency direction */
index[0] = 0+index[0];
index[0] &= and_modulo;
for(i = 1; i<nr_par; i++) {
index[i] = index[i-1]+index[i];
index[i] &= and_modulo;
}
}
else {
/* delta coded in time direction */
for(i = 0; i<nr_par; i++) {
index[i] = index_prev[i*stride]+index[i];
index[i] &= and_modulo;
}
}
}
else {
/* set indices to zero */
for(i = 0; i<nr_par; i++) {
index[i] = 0;
}
}
/* coarse */
if(stride==2) {
index[0] = 0;
for(i = (nr_par<<1)-1; i>0; i--) {
index[i] = index[i>>1];
}
}
}
private void map20indexto34(int[] index, int bins) {
//index[0] = index[0];
index[1] = (index[0]+index[1])/2;
index[2] = index[1];
index[3] = index[2];
index[4] = (index[2]+index[3])/2;
index[5] = index[3];
index[6] = index[4];
index[7] = index[4];
index[8] = index[5];
index[9] = index[5];
index[10] = index[6];
index[11] = index[7];
index[12] = index[8];
index[13] = index[8];
index[14] = index[9];
index[15] = index[9];
index[16] = index[10];
if(bins==34) {
index[17] = index[11];
index[18] = index[12];
index[19] = index[13];
index[20] = index[14];
index[21] = index[14];
index[22] = index[15];
index[23] = index[15];
index[24] = index[16];
index[25] = index[16];
index[26] = index[17];
index[27] = index[17];
index[28] = index[18];
index[29] = index[18];
index[30] = index[18];
index[31] = index[18];
index[32] = index[19];
index[33] = index[19];
}
}
/* parse the bitstream data decoded in ps_data() */
private void ps_data_decode() {
int env, bin;
/* ps data not available, use data from previous frame */
if(this.ps_data_available==0) {
this.num_env = 0;
}
for(env = 0; env<this.num_env; env++) {
int[] iid_index_prev;
int[] icc_index_prev;
int[] ipd_index_prev;
int[] opd_index_prev;
int num_iid_steps = (this.iid_mode<3) ? 7 : 15 /*fine quant*/;
if(env==0) {
/* take last envelope from previous frame */
iid_index_prev = this.iid_index_prev;
icc_index_prev = this.icc_index_prev;
ipd_index_prev = this.ipd_index_prev;
opd_index_prev = this.opd_index_prev;
}
else {
/* take index values from previous envelope */
iid_index_prev = this.iid_index[env-1];
icc_index_prev = this.icc_index[env-1];
ipd_index_prev = this.ipd_index[env-1];
opd_index_prev = this.opd_index[env-1];
}
// iid = 1;
/* delta decode iid parameters */
delta_decode(this.enable_iid, this.iid_index[env], iid_index_prev,
this.iid_dt[env], this.nr_iid_par,
(this.iid_mode==0||this.iid_mode==3) ? 2 : 1,
-num_iid_steps, num_iid_steps);
// iid = 0;
/* delta decode icc parameters */
delta_decode(this.enable_icc, this.icc_index[env], icc_index_prev,
this.icc_dt[env], this.nr_icc_par,
(this.icc_mode==0||this.icc_mode==3) ? 2 : 1,
0, 7);
/* delta modulo decode ipd parameters */
delta_modulo_decode(this.enable_ipdopd, this.ipd_index[env], ipd_index_prev,
this.ipd_dt[env], this.nr_ipdopd_par, 1, 7);
/* delta modulo decode opd parameters */
delta_modulo_decode(this.enable_ipdopd, this.opd_index[env], opd_index_prev,
this.opd_dt[env], this.nr_ipdopd_par, 1, 7);
}
/* handle error case */
if(this.num_env==0) {
/* force to 1 */
this.num_env = 1;
if(this.enable_iid) {
for(bin = 0; bin<34; bin++) {
this.iid_index[0][bin] = this.iid_index_prev[bin];
}
}
else {
for(bin = 0; bin<34; bin++) {
this.iid_index[0][bin] = 0;
}
}
if(this.enable_icc) {
for(bin = 0; bin<34; bin++) {
this.icc_index[0][bin] = this.icc_index_prev[bin];
}
}
else {
for(bin = 0; bin<34; bin++) {
this.icc_index[0][bin] = 0;
}
}
if(this.enable_ipdopd) {
for(bin = 0; bin<17; bin++) {
this.ipd_index[0][bin] = this.ipd_index_prev[bin];
this.opd_index[0][bin] = this.opd_index_prev[bin];
}
}
else {
for(bin = 0; bin<17; bin++) {
this.ipd_index[0][bin] = 0;
this.opd_index[0][bin] = 0;
}
}
}
/* update previous indices */
for(bin = 0; bin<34; bin++) {
this.iid_index_prev[bin] = this.iid_index[this.num_env-1][bin];
}
for(bin = 0; bin<34; bin++) {
this.icc_index_prev[bin] = this.icc_index[this.num_env-1][bin];
}
for(bin = 0; bin<17; bin++) {
this.ipd_index_prev[bin] = this.ipd_index[this.num_env-1][bin];
this.opd_index_prev[bin] = this.opd_index[this.num_env-1][bin];
}
this.ps_data_available = 0;
if(this.frame_class==0) {
this.border_position[0] = 0;
for(env = 1; env<this.num_env; env++) {
this.border_position[env] = (env*this.numTimeSlotsRate)/this.num_env;
}
this.border_position[this.num_env] = this.numTimeSlotsRate;
}
else {
this.border_position[0] = 0;
if(this.border_position[this.num_env]<this.numTimeSlotsRate) {
for(bin = 0; bin<34; bin++) {
this.iid_index[this.num_env][bin] = this.iid_index[this.num_env-1][bin];
this.icc_index[this.num_env][bin] = this.icc_index[this.num_env-1][bin];
}
for(bin = 0; bin<17; bin++) {
this.ipd_index[this.num_env][bin] = this.ipd_index[this.num_env-1][bin];
this.opd_index[this.num_env][bin] = this.opd_index[this.num_env-1][bin];
}
this.num_env++;
this.border_position[this.num_env] = this.numTimeSlotsRate;
}
for(env = 1; env<this.num_env; env++) {
int thr = this.numTimeSlotsRate-(this.num_env-env);
if(this.border_position[env]>thr) {
this.border_position[env] = thr;
}
else {
thr = this.border_position[env-1]+1;
if(this.border_position[env]<thr) {
this.border_position[env] = thr;
}
}
}
}
/* make sure that the indices of all parameters can be mapped
* to the same hybrid synthesis filterbank
*/
if(this.use34hybrid_bands) {
for(env = 0; env<this.num_env; env++) {
if(this.iid_mode!=2&&this.iid_mode!=5)
map20indexto34(this.iid_index[env], 34);
if(this.icc_mode!=2&&this.icc_mode!=5)
map20indexto34(this.icc_index[env], 34);
if(this.ipd_mode!=2&&this.ipd_mode!=5) {
map20indexto34(this.ipd_index[env], 17);
map20indexto34(this.opd_index[env], 17);
}
}
}
}
/* decorrelate the mono signal using an allpass filter */
private void ps_decorrelate(float[][][] X_left, float[][][] X_right,
float[][][] X_hybrid_left, float[][][] X_hybrid_right) {
int gr, n, m, bk;
int temp_delay = 0;
int sb, maxsb;
int[] temp_delay_ser = new int[NO_ALLPASS_LINKS];
float P_SmoothPeakDecayDiffNrg, nrg;
float[][] P = new float[32][34];
float[][] G_TransientRatio = new float[32][34];
float[] inputLeft = new float[2];
/* chose hybrid filterbank: 20 or 34 band case */
float[][] Phi_Fract_SubQmf;
if(this.use34hybrid_bands) {
Phi_Fract_SubQmf = Phi_Fract_SubQmf34;
}
else {
Phi_Fract_SubQmf = Phi_Fract_SubQmf20;
}
/* clear the energy values */
for(n = 0; n<32; n++) {
for(bk = 0; bk<34; bk++) {
P[n][bk] = 0;
}
}
/* calculate the energy in each parameter band b(k) */
for(gr = 0; gr<this.num_groups; gr++) {
/* select the parameter index b(k) to which this group belongs */
bk = (~NEGATE_IPD_MASK)&this.map_group2bk[gr];
/* select the upper subband border for this group */
maxsb = (gr<this.num_hybrid_groups) ? this.group_border[gr]+1 : this.group_border[gr+1];
for(sb = this.group_border[gr]; sb<maxsb; sb++) {
for(n = this.border_position[0]; n<this.border_position[this.num_env]; n++) {
/* input from hybrid subbands or QMF subbands */
if(gr<this.num_hybrid_groups) {
inputLeft[0] = X_hybrid_left[n][sb][0];
inputLeft[1] = X_hybrid_left[n][sb][1];
}
else {
inputLeft[0] = X_left[n][sb][0];
inputLeft[1] = X_left[n][sb][1];
}
/* accumulate energy */
P[n][bk] += (inputLeft[0]*inputLeft[0])+(inputLeft[1]*inputLeft[1]);
}
}
}
/* calculate transient reduction ratio for each parameter band b(k) */
for(bk = 0; bk<this.nr_par_bands; bk++) {
for(n = this.border_position[0]; n<this.border_position[this.num_env]; n++) {
float gamma = 1.5f;
this.P_PeakDecayNrg[bk] = (this.P_PeakDecayNrg[bk]*this.alpha_decay);
if(this.P_PeakDecayNrg[bk]<P[n][bk])
this.P_PeakDecayNrg[bk] = P[n][bk];
/* apply smoothing filter to peak decay energy */
P_SmoothPeakDecayDiffNrg = this.P_SmoothPeakDecayDiffNrg_prev[bk];
P_SmoothPeakDecayDiffNrg += ((this.P_PeakDecayNrg[bk]-P[n][bk]-this.P_SmoothPeakDecayDiffNrg_prev[bk])*alpha_smooth);
this.P_SmoothPeakDecayDiffNrg_prev[bk] = P_SmoothPeakDecayDiffNrg;
/* apply smoothing filter to energy */
nrg = this.P_prev[bk];
nrg += ((P[n][bk]-this.P_prev[bk])*this.alpha_smooth);
this.P_prev[bk] = nrg;
/* calculate transient ratio */
if((P_SmoothPeakDecayDiffNrg*gamma)<=nrg) {
G_TransientRatio[n][bk] = 1.0f;
}
else {
G_TransientRatio[n][bk] = (nrg/(P_SmoothPeakDecayDiffNrg*gamma));
}
}
}
/* apply stereo decorrelation filter to the signal */
for(gr = 0; gr<this.num_groups; gr++) {
if(gr<this.num_hybrid_groups)
maxsb = this.group_border[gr]+1;
else
maxsb = this.group_border[gr+1];
/* QMF channel */
for(sb = this.group_border[gr]; sb<maxsb; sb++) {
float g_DecaySlope;
float[] g_DecaySlope_filt = new float[NO_ALLPASS_LINKS];
/* g_DecaySlope: [0..1] */
if(gr<this.num_hybrid_groups||sb<=this.decay_cutoff) {
g_DecaySlope = 1.0f;
}
else {
int decay = this.decay_cutoff-sb;
if(decay<=-20 /* -1/DECAY_SLOPE */) {
g_DecaySlope = 0;
}
else {
/* decay(int)*decay_slope(frac) = g_DecaySlope(frac) */
g_DecaySlope = 1.0f+DECAY_SLOPE*decay;
}
}
/* calculate g_DecaySlope_filt for every m multiplied by filter_a[m] */
for(m = 0; m<NO_ALLPASS_LINKS; m++) {
g_DecaySlope_filt[m] = g_DecaySlope*filter_a[m];
}
/* set delay indices */
temp_delay = this.saved_delay;
for(n = 0; n<NO_ALLPASS_LINKS; n++) {
temp_delay_ser[n] = this.delay_buf_index_ser[n];
}
for(n = this.border_position[0]; n<this.border_position[this.num_env]; n++) {
float[] tmp = new float[2], tmp0 = new float[2], R0 = new float[2];
if(gr<this.num_hybrid_groups) {
/* hybrid filterbank input */
inputLeft[0] = X_hybrid_left[n][sb][0];
inputLeft[1] = X_hybrid_left[n][sb][1];
}
else {
/* QMF filterbank input */
inputLeft[0] = X_left[n][sb][0];
inputLeft[1] = X_left[n][sb][1];
}
if(sb>this.nr_allpass_bands&&gr>=this.num_hybrid_groups) {
/* delay */
/* never hybrid subbands here, always QMF subbands */
tmp[0] = this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][0];
tmp[1] = this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][1];
R0[0] = tmp[0];
R0[1] = tmp[1];
this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][0] = inputLeft[0];
this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][1] = inputLeft[1];
}
else {
/* allpass filter */
//int m;
float[] Phi_Fract = new float[2];
/* fetch parameters */
if(gr<this.num_hybrid_groups) {
/* select data from the hybrid subbands */
tmp0[0] = this.delay_SubQmf[temp_delay][sb][0];
tmp0[1] = this.delay_SubQmf[temp_delay][sb][1];
this.delay_SubQmf[temp_delay][sb][0] = inputLeft[0];
this.delay_SubQmf[temp_delay][sb][1] = inputLeft[1];
Phi_Fract[0] = Phi_Fract_SubQmf[sb][0];
Phi_Fract[1] = Phi_Fract_SubQmf[sb][1];
}
else {
/* select data from the QMF subbands */
tmp0[0] = this.delay_Qmf[temp_delay][sb][0];
tmp0[1] = this.delay_Qmf[temp_delay][sb][1];
this.delay_Qmf[temp_delay][sb][0] = inputLeft[0];
this.delay_Qmf[temp_delay][sb][1] = inputLeft[1];
Phi_Fract[0] = Phi_Fract_Qmf[sb][0];
Phi_Fract[1] = Phi_Fract_Qmf[sb][1];
}
/* z^(-2) * Phi_Fract[k] */
tmp[0] = (tmp[0]*Phi_Fract[0])+(tmp0[1]*Phi_Fract[1]);
tmp[1] = (tmp0[1]*Phi_Fract[0])-(tmp0[0]*Phi_Fract[1]);
R0[0] = tmp[0];
R0[1] = tmp[1];
for(m = 0; m<NO_ALLPASS_LINKS; m++) {
float[] Q_Fract_allpass = new float[2], tmp2 = new float[2];
/* fetch parameters */
if(gr<this.num_hybrid_groups) {
/* select data from the hybrid subbands */
tmp0[0] = this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][0];
tmp0[1] = this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][1];
if(this.use34hybrid_bands) {
Q_Fract_allpass[0] = Q_Fract_allpass_SubQmf34[sb][m][0];
Q_Fract_allpass[1] = Q_Fract_allpass_SubQmf34[sb][m][1];
}
else {
Q_Fract_allpass[0] = Q_Fract_allpass_SubQmf20[sb][m][0];
Q_Fract_allpass[1] = Q_Fract_allpass_SubQmf20[sb][m][1];
}
}
else {
/* select data from the QMF subbands */
tmp0[0] = this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][0];
tmp0[1] = this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][1];
Q_Fract_allpass[0] = Q_Fract_allpass_Qmf[sb][m][0];
Q_Fract_allpass[1] = Q_Fract_allpass_Qmf[sb][m][1];
}
/* delay by a fraction */
/* z^(-d(m)) * Q_Fract_allpass[k,m] */
tmp[0] = (tmp0[0]*Q_Fract_allpass[0])+(tmp0[1]*Q_Fract_allpass[1]);
tmp[1] = (tmp0[1]*Q_Fract_allpass[0])-(tmp0[0]*Q_Fract_allpass[1]);
/* -a(m) * g_DecaySlope[k] */
tmp[0] += -(g_DecaySlope_filt[m]*R0[0]);
tmp[1] += -(g_DecaySlope_filt[m]*R0[1]);
/* -a(m) * g_DecaySlope[k] * Q_Fract_allpass[k,m] * z^(-d(m)) */
tmp2[0] = R0[0]+(g_DecaySlope_filt[m]*tmp[0]);
tmp2[1] = R0[1]+(g_DecaySlope_filt[m]*tmp[1]);
/* store sample */
if(gr<this.num_hybrid_groups) {
this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][0] = tmp2[0];
this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][1] = tmp2[1];
}
else {
this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][0] = tmp2[0];
this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][1] = tmp2[1];
}
/* store for next iteration (or as output value if last iteration) */
R0[0] = tmp[0];
R0[1] = tmp[1];
}
}
/* select b(k) for reading the transient ratio */
bk = (~NEGATE_IPD_MASK)&this.map_group2bk[gr];
/* duck if a past transient is found */
R0[0] = (G_TransientRatio[n][bk]*R0[0]);
R0[1] = (G_TransientRatio[n][bk]*R0[1]);
if(gr<this.num_hybrid_groups) {
/* hybrid */
X_hybrid_right[n][sb][0] = R0[0];
X_hybrid_right[n][sb][1] = R0[1];
}
else {
/* QMF */
X_right[n][sb][0] = R0[0];
X_right[n][sb][1] = R0[1];
}
/* Update delay buffer index */
if(++temp_delay>=2) {
temp_delay = 0;
}
/* update delay indices */
if(sb>this.nr_allpass_bands&&gr>=this.num_hybrid_groups) {
/* delay_D depends on the samplerate, it can hold the values 14 and 1 */
if(++this.delay_buf_index_delay[sb]>=this.delay_D[sb]) {
this.delay_buf_index_delay[sb] = 0;
}
}
for(m = 0; m<NO_ALLPASS_LINKS; m++) {
if(++temp_delay_ser[m]>=this.num_sample_delay_ser[m]) {
temp_delay_ser[m] = 0;
}
}
}
}
}
/* update delay indices */
this.saved_delay = temp_delay;
for(m = 0; m<NO_ALLPASS_LINKS; m++) {
this.delay_buf_index_ser[m] = temp_delay_ser[m];
}
}
private float magnitude_c(float[] c) {
return (float) Math.sqrt(c[0]*c[0]+c[1]*c[1]);
}
private void ps_mix_phase(float[][][] X_left, float[][][] X_right,
float[][][] X_hybrid_left, float[][][] X_hybrid_right) {
int n;
int gr;
int bk = 0;
int sb, maxsb;
int env;
int nr_ipdopd_par;
float[] h11 = new float[2], h12 = new float[2], h21 = new float[2], h22 = new float[2];
float[] H11 = new float[2], H12 = new float[2], H21 = new float[2], H22 = new float[2];
float[] deltaH11 = new float[2], deltaH12 = new float[2], deltaH21 = new float[2], deltaH22 = new float[2];
float[] tempLeft = new float[2];
float[] tempRight = new float[2];
float[] phaseLeft = new float[2];
float[] phaseRight = new float[2];
float L;
float[] sf_iid;
int no_iid_steps;
if(this.iid_mode>=3) {
no_iid_steps = 15;
sf_iid = sf_iid_fine;
}
else {
no_iid_steps = 7;
sf_iid = sf_iid_normal;
}
if(this.ipd_mode==0||this.ipd_mode==3) {
nr_ipdopd_par = 11; /* resolution */
}
else {
nr_ipdopd_par = this.nr_ipdopd_par;
}
for(gr = 0; gr<this.num_groups; gr++) {
bk = (~NEGATE_IPD_MASK)&this.map_group2bk[gr];
/* use one channel per group in the subqmf domain */
maxsb = (gr<this.num_hybrid_groups) ? this.group_border[gr]+1 : this.group_border[gr+1];
for(env = 0; env<this.num_env; env++) {
if(this.icc_mode<3) {
/* type 'A' mixing as described in 8.6.4.6.2.1 */
float c_1, c_2;
float cosa, sina;
float cosb, sinb;
float ab1, ab2;
float ab3, ab4;
/*
c_1 = sqrt(2.0 / (1.0 + pow(10.0, quant_iid[no_iid_steps + iid_index] / 10.0)));
c_2 = sqrt(2.0 / (1.0 + pow(10.0, quant_iid[no_iid_steps - iid_index] / 10.0)));
alpha = 0.5 * acos(quant_rho[icc_index]);
beta = alpha * ( c_1 - c_2 ) / sqrt(2.0);
*/
//printf("%d\n", ps.iid_index[env][bk]);
/* calculate the scalefactors c_1 and c_2 from the intensity differences */
c_1 = sf_iid[no_iid_steps+this.iid_index[env][bk]];
c_2 = sf_iid[no_iid_steps-this.iid_index[env][bk]];
/* calculate alpha and beta using the ICC parameters */
cosa = cos_alphas[this.icc_index[env][bk]];
sina = sin_alphas[this.icc_index[env][bk]];
if(this.iid_mode>=3) {
if(this.iid_index[env][bk]<0) {
cosb = cos_betas_fine[-this.iid_index[env][bk]][this.icc_index[env][bk]];
sinb = -sin_betas_fine[-this.iid_index[env][bk]][this.icc_index[env][bk]];
}
else {
cosb = cos_betas_fine[this.iid_index[env][bk]][this.icc_index[env][bk]];
sinb = sin_betas_fine[this.iid_index[env][bk]][this.icc_index[env][bk]];
}
}
else {
if(this.iid_index[env][bk]<0) {
cosb = cos_betas_normal[-this.iid_index[env][bk]][this.icc_index[env][bk]];
sinb = -sin_betas_normal[-this.iid_index[env][bk]][this.icc_index[env][bk]];
}
else {
cosb = cos_betas_normal[this.iid_index[env][bk]][this.icc_index[env][bk]];
sinb = sin_betas_normal[this.iid_index[env][bk]][this.icc_index[env][bk]];
}
}
ab1 = (cosb*cosa);
ab2 = (sinb*sina);
ab3 = (sinb*cosa);
ab4 = (cosb*sina);
/* h_xy: COEF */
h11[0] = (c_2*(ab1-ab2));
h12[0] = (c_1*(ab1+ab2));
h21[0] = (c_2*(ab3+ab4));
h22[0] = (c_1*(ab3-ab4));
}
else {
/* type 'B' mixing as described in 8.6.4.6.2.2 */
float sina, cosa;
float cosg, sing;
if(this.iid_mode>=3) {
int abs_iid = Math.abs(this.iid_index[env][bk]);
cosa = sincos_alphas_B_fine[no_iid_steps+this.iid_index[env][bk]][this.icc_index[env][bk]];
sina = sincos_alphas_B_fine[30-(no_iid_steps+this.iid_index[env][bk])][this.icc_index[env][bk]];
cosg = cos_gammas_fine[abs_iid][this.icc_index[env][bk]];
sing = sin_gammas_fine[abs_iid][this.icc_index[env][bk]];
}
else {
int abs_iid = Math.abs(this.iid_index[env][bk]);
cosa = sincos_alphas_B_normal[no_iid_steps+this.iid_index[env][bk]][this.icc_index[env][bk]];
sina = sincos_alphas_B_normal[14-(no_iid_steps+this.iid_index[env][bk])][this.icc_index[env][bk]];
cosg = cos_gammas_normal[abs_iid][this.icc_index[env][bk]];
sing = sin_gammas_normal[abs_iid][this.icc_index[env][bk]];
}
h11[0] = (COEF_SQRT2*(cosa*cosg));
h12[0] = (COEF_SQRT2*(sina*cosg));
h21[0] = (COEF_SQRT2*(-cosa*sing));
h22[0] = (COEF_SQRT2*(sina*sing));
}
/* calculate phase rotation parameters H_xy */
/* note that the imaginary part of these parameters are only calculated when
IPD and OPD are enabled
*/
if((this.enable_ipdopd)&&(bk<nr_ipdopd_par)) {
float xy, pq, xypq;
/* ringbuffer index */
int i = this.phase_hist;
/* previous value */
tempLeft[0] = (this.ipd_prev[bk][i][0]*0.25f);
tempLeft[1] = (this.ipd_prev[bk][i][1]*0.25f);
tempRight[0] = (this.opd_prev[bk][i][0]*0.25f);
tempRight[1] = (this.opd_prev[bk][i][1]*0.25f);
/* save current value */
this.ipd_prev[bk][i][0] = ipdopd_cos_tab[Math.abs(this.ipd_index[env][bk])];
this.ipd_prev[bk][i][1] = ipdopd_sin_tab[Math.abs(this.ipd_index[env][bk])];
this.opd_prev[bk][i][0] = ipdopd_cos_tab[Math.abs(this.opd_index[env][bk])];
this.opd_prev[bk][i][1] = ipdopd_sin_tab[Math.abs(this.opd_index[env][bk])];
/* add current value */
tempLeft[0] += this.ipd_prev[bk][i][0];
tempLeft[1] += this.ipd_prev[bk][i][1];
tempRight[0] += this.opd_prev[bk][i][0];
tempRight[1] += this.opd_prev[bk][i][1];
/* ringbuffer index */
if(i==0) {
i = 2;
}
i--;
/* get value before previous */
tempLeft[0] += (this.ipd_prev[bk][i][0]*0.5f);
tempLeft[1] += (this.ipd_prev[bk][i][1]*0.5f);
tempRight[0] += (this.opd_prev[bk][i][0]*0.5f);
tempRight[1] += (this.opd_prev[bk][i][1]*0.5f);
xy = magnitude_c(tempRight);
pq = magnitude_c(tempLeft);
if(xy!=0) {
phaseLeft[0] = (tempRight[0]/xy);
phaseLeft[1] = (tempRight[1]/xy);
}
else {
phaseLeft[0] = 0;
phaseLeft[1] = 0;
}
xypq = (xy*pq);
if(xypq!=0) {
float tmp1 = (tempRight[0]*tempLeft[0])+(tempRight[1]*tempLeft[1]);
float tmp2 = (tempRight[1]*tempLeft[0])-(tempRight[0]*tempLeft[1]);
phaseRight[0] = (tmp1/xypq);
phaseRight[1] = (tmp2/xypq);
}
else {
phaseRight[0] = 0;
phaseRight[1] = 0;
}
/* MUL_F(COEF, REAL) = COEF */
h11[1] = (h11[0]*phaseLeft[1]);
h12[1] = (h12[0]*phaseRight[1]);
h21[1] = (h21[0]*phaseLeft[1]);
h22[1] = (h22[0]*phaseRight[1]);
h11[0] = (h11[0]*phaseLeft[0]);
h12[0] = (h12[0]*phaseRight[0]);
h21[0] = (h21[0]*phaseLeft[0]);
h22[0] = (h22[0]*phaseRight[0]);
}
/* length of the envelope n_e+1 - n_e (in time samples) */
/* 0 < L <= 32: integer */
L = (float) (this.border_position[env+1]-this.border_position[env]);
/* obtain final H_xy by means of linear interpolation */
deltaH11[0] = (h11[0]-this.h11_prev[gr][0])/L;
deltaH12[0] = (h12[0]-this.h12_prev[gr][0])/L;
deltaH21[0] = (h21[0]-this.h21_prev[gr][0])/L;
deltaH22[0] = (h22[0]-this.h22_prev[gr][0])/L;
H11[0] = this.h11_prev[gr][0];
H12[0] = this.h12_prev[gr][0];
H21[0] = this.h21_prev[gr][0];
H22[0] = this.h22_prev[gr][0];
this.h11_prev[gr][0] = h11[0];
this.h12_prev[gr][0] = h12[0];
this.h21_prev[gr][0] = h21[0];
this.h22_prev[gr][0] = h22[0];
/* only calculate imaginary part when needed */
if((this.enable_ipdopd)&&(bk<nr_ipdopd_par)) {
/* obtain final H_xy by means of linear interpolation */
deltaH11[1] = (h11[1]-this.h11_prev[gr][1])/L;
deltaH12[1] = (h12[1]-this.h12_prev[gr][1])/L;
deltaH21[1] = (h21[1]-this.h21_prev[gr][1])/L;
deltaH22[1] = (h22[1]-this.h22_prev[gr][1])/L;
H11[1] = this.h11_prev[gr][1];
H12[1] = this.h12_prev[gr][1];
H21[1] = this.h21_prev[gr][1];
H22[1] = this.h22_prev[gr][1];
if((NEGATE_IPD_MASK&this.map_group2bk[gr])!=0) {
deltaH11[1] = -deltaH11[1];
deltaH12[1] = -deltaH12[1];
deltaH21[1] = -deltaH21[1];
deltaH22[1] = -deltaH22[1];
H11[1] = -H11[1];
H12[1] = -H12[1];
H21[1] = -H21[1];
H22[1] = -H22[1];
}
this.h11_prev[gr][1] = h11[1];
this.h12_prev[gr][1] = h12[1];
this.h21_prev[gr][1] = h21[1];
this.h22_prev[gr][1] = h22[1];
}
/* apply H_xy to the current envelope band of the decorrelated subband */
for(n = this.border_position[env]; n<this.border_position[env+1]; n++) {
/* addition finalises the interpolation over every n */
H11[0] += deltaH11[0];
H12[0] += deltaH12[0];
H21[0] += deltaH21[0];
H22[0] += deltaH22[0];
if((this.enable_ipdopd)&&(bk<nr_ipdopd_par)) {
H11[1] += deltaH11[1];
H12[1] += deltaH12[1];
H21[1] += deltaH21[1];
H22[1] += deltaH22[1];
}
/* channel is an alias to the subband */
for(sb = this.group_border[gr]; sb<maxsb; sb++) {
float[] inLeft = new float[2], inRight = new float[2];
/* load decorrelated samples */
if(gr<this.num_hybrid_groups) {
inLeft[0] = X_hybrid_left[n][sb][0];
inLeft[1] = X_hybrid_left[n][sb][1];
inRight[0] = X_hybrid_right[n][sb][0];
inRight[1] = X_hybrid_right[n][sb][1];
}
else {
inLeft[0] = X_left[n][sb][0];
inLeft[1] = X_left[n][sb][1];
inRight[0] = X_right[n][sb][0];
inRight[1] = X_right[n][sb][1];
}
/* apply mixing */
tempLeft[0] = (H11[0]*inLeft[0])+(H21[0]*inRight[0]);
tempLeft[1] = (H11[0]*inLeft[1])+(H21[0]*inRight[1]);
tempRight[0] = (H12[0]*inLeft[0])+(H22[0]*inRight[0]);
tempRight[1] = (H12[0]*inLeft[1])+(H22[0]*inRight[1]);
/* only perform imaginary operations when needed */
if((this.enable_ipdopd)&&(bk<nr_ipdopd_par)) {
/* apply rotation */
tempLeft[0] -= (H11[1]*inLeft[1])+(H21[1]*inRight[1]);
tempLeft[1] += (H11[1]*inLeft[0])+(H21[1]*inRight[0]);
tempRight[0] -= (H12[1]*inLeft[1])+(H22[1]*inRight[1]);
tempRight[1] += (H12[1]*inLeft[0])+(H22[1]*inRight[0]);
}
/* store final samples */
if(gr<this.num_hybrid_groups) {
X_hybrid_left[n][sb][0] = tempLeft[0];
X_hybrid_left[n][sb][1] = tempLeft[1];
X_hybrid_right[n][sb][0] = tempRight[0];
X_hybrid_right[n][sb][1] = tempRight[1];
}
else {
X_left[n][sb][0] = tempLeft[0];
X_left[n][sb][1] = tempLeft[1];
X_right[n][sb][0] = tempRight[0];
X_right[n][sb][1] = tempRight[1];
}
}
}
/* shift phase smoother's circular buffer index */
this.phase_hist++;
if(this.phase_hist==2) {
this.phase_hist = 0;
}
}
}
}
/* main Parametric Stereo decoding function */
public int process(float[][][] X_left, float[][][] X_right) {
float[][][] X_hybrid_left = new float[32][32][2];
float[][][] X_hybrid_right = new float[32][32][2];
/* delta decoding of the bitstream data */
ps_data_decode();
/* set up some parameters depending on filterbank type */
if(this.use34hybrid_bands) {
this.group_border = group_border34;
this.map_group2bk = map_group2bk34;
this.num_groups = 32+18;
this.num_hybrid_groups = 32;
this.nr_par_bands = 34;
this.decay_cutoff = 5;
}
else {
this.group_border = group_border20;
this.map_group2bk = map_group2bk20;
this.num_groups = 10+12;
this.num_hybrid_groups = 10;
this.nr_par_bands = 20;
this.decay_cutoff = 3;
}
/* Perform further analysis on the lowest subbands to get a higher
* frequency resolution
*/
hyb.hybrid_analysis(X_left, X_hybrid_left,
this.use34hybrid_bands, this.numTimeSlotsRate);
/* decorrelate mono signal */
ps_decorrelate(X_left, X_right, X_hybrid_left, X_hybrid_right);
/* apply mixing and phase parameters */
ps_mix_phase(X_left, X_right, X_hybrid_left, X_hybrid_right);
/* hybrid synthesis, to rebuild the SBR QMF matrices */
hyb.hybrid_synthesis(X_left, X_hybrid_left,
this.use34hybrid_bands, this.numTimeSlotsRate);
hyb.hybrid_synthesis(X_right, X_hybrid_right,
this.use34hybrid_bands, this.numTimeSlotsRate);
return 0;
}
}