net.sourceforge.jaad.aac.sbr.SBR Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcodec Show documentation
Show all versions of jcodec Show documentation
Pure Java implementation of video/audio codecs and formats
package net.sourceforge.jaad.aac.sbr;
import java.util.Arrays;
import net.sourceforge.jaad.aac.AACException;
import net.sourceforge.jaad.aac.SampleFrequency;
import net.sourceforge.jaad.aac.ps.PS;
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 SBR implements SBRConstants, net.sourceforge.jaad.aac.syntax.SyntaxConstants, HuffmanTables {
private final boolean downSampledSBR;
final SampleFrequency sample_rate;
int maxAACLine;
int rate;
boolean just_seeked;
int ret;
boolean[] amp_res;
int k0;
int kx;
int M;
int N_master;
int N_high;
int N_low;
int N_Q;
int[] N_L;
int[] n;
int[] f_master;
int[][] f_table_res;
int[] f_table_noise;
int[][] f_table_lim;
int[] table_map_k_to_g;
int[] abs_bord_lead;
int[] abs_bord_trail;
int[] n_rel_lead;
int[] n_rel_trail;
int[] L_E;
int[] L_E_prev;
int[] L_Q;
int[][] t_E;
int[][] t_Q;
int[][] f;
int[] f_prev;
float[][][] G_temp_prev;
float[][][] Q_temp_prev;
int[] GQ_ringbuf_index;
int[][][] E;
int[][] E_prev;
float[][][] E_orig;
float[][][] E_curr;
int[][][] Q;
float[][][] Q_div;
float[][][] Q_div2;
int[][] Q_prev;
int[] l_A;
int[] l_A_prev;
int[][] bs_invf_mode;
int[][] bs_invf_mode_prev;
float[][] bwArray;
float[][] bwArray_prev;
int noPatches;
int[] patchNoSubbands;
int[] patchStartSubband;
int[][] bs_add_harmonic;
int[][] bs_add_harmonic_prev;
int[] index_noise_prev;
int[] psi_is_prev;
int bs_start_freq_prev;
int bs_stop_freq_prev;
int bs_xover_band_prev;
int bs_freq_scale_prev;
boolean bs_alter_scale_prev;
int bs_noise_bands_prev;
int[] prevEnvIsShort;
int kx_prev;
int bsco;
int bsco_prev;
int M_prev;
boolean Reset;
int frame;
int header_count;
boolean stereo;
AnalysisFilterbank[] qmfa;
SynthesisFilterbank[] qmfs;
float[][][][] Xsbr;
int numTimeSlotsRate;
int numTimeSlots;
int tHFGen;
int tHFAdj;
PS ps;
boolean ps_used;
boolean psResetFlag;
/* to get it compiling */
/* we'll see during the coding of all the tools, whether
these are all used or not.
*/
boolean bs_header_flag;
int bs_crc_flag;
int bs_sbr_crc_bits;
int bs_protocol_version;
boolean bs_amp_res;
int bs_start_freq;
int bs_stop_freq;
int bs_xover_band;
int bs_freq_scale;
boolean bs_alter_scale;
int bs_noise_bands;
int bs_limiter_bands;
int bs_limiter_gains;
boolean bs_interpol_freq;
boolean bs_smoothing_mode;
int bs_samplerate_mode;
boolean[] bs_add_harmonic_flag;
boolean[] bs_add_harmonic_flag_prev;
boolean bs_extended_data;
int bs_extension_id;
int bs_extension_data;
boolean bs_coupling;
int[] bs_frame_class;
int[][] bs_rel_bord;
int[][] bs_rel_bord_0;
int[][] bs_rel_bord_1;
int[] bs_pointer;
int[] bs_abs_bord_0;
int[] bs_abs_bord_1;
int[] bs_num_rel_0;
int[] bs_num_rel_1;
int[][] bs_df_env;
int[][] bs_df_noise;
public SBR(boolean smallFrames, boolean stereo, SampleFrequency sample_rate, boolean downSampledSBR) {
this.amp_res = new boolean[2];
this.N_L = new int[4];
this.n = new int[2];
this.f_master = new int[64];
this.f_table_res = new int[2][64];
this.f_table_noise = new int[64];
this.f_table_lim = new int[4][64];
this.table_map_k_to_g = new int[64];
this.abs_bord_lead = new int[2];
this.abs_bord_trail = new int[2];
this.n_rel_lead = new int[2];
this.n_rel_trail = new int[2];
this.L_E = new int[2];
this.L_E_prev = new int[2];
this.L_Q = new int[2];
this.t_E = new int[2][MAX_L_E+1];
this.t_Q = new int[2][3];
this.f = new int[2][MAX_L_E+1];
this.f_prev = new int[2];
this.G_temp_prev = new float[2][5][64];
this.Q_temp_prev = new float[2][5][64];
this.GQ_ringbuf_index = new int[2];
this.E = new int[2][64][MAX_L_E];
this.E_prev = new int[2][64];
this.E_orig = new float[2][64][MAX_L_E];
this.E_curr = new float[2][64][MAX_L_E];
this.Q = new int[2][64][2];
this.Q_div = new float[2][64][2];
this.Q_div2 = new float[2][64][2];
this.Q_prev = new int[2][64];
this.l_A = new int[2];
this.l_A_prev = new int[2];
this.bs_invf_mode = new int[2][MAX_L_E];
this.bs_invf_mode_prev = new int[2][MAX_L_E];
this.bwArray = new float[2][64];
this.bwArray_prev = new float[2][64];
this.patchNoSubbands = new int[64];
this.patchStartSubband = new int[64];
this.bs_add_harmonic = new int[2][64];
this.bs_add_harmonic_prev = new int[2][64];
this.index_noise_prev = new int[2];
this.psi_is_prev = new int[2];
this.prevEnvIsShort = new int[2];
this.qmfa = new AnalysisFilterbank[2];
this.qmfs = new SynthesisFilterbank[2];
this.Xsbr = new float[2][MAX_NTSRHFG][64][2];
this.bs_add_harmonic_flag = new boolean[2];
this.bs_add_harmonic_flag_prev = new boolean[2];
this.bs_frame_class = new int[2];
this.bs_rel_bord = new int[2][9];
this.bs_rel_bord_0 = new int[2][9];
this.bs_rel_bord_1 = new int[2][9];
this.bs_pointer = new int[2];
this.bs_abs_bord_0 = new int[2];
this.bs_abs_bord_1 = new int[2];
this.bs_num_rel_0 = new int[2];
this.bs_num_rel_1 = new int[2];
this.bs_df_env = new int[2][9];
this.bs_df_noise = new int[2][3];
this.downSampledSBR = downSampledSBR;
this.stereo = stereo;
this.sample_rate = sample_rate;
this.bs_freq_scale = 2;
this.bs_alter_scale = true;
this.bs_noise_bands = 2;
this.bs_limiter_bands = 2;
this.bs_limiter_gains = 2;
this.bs_interpol_freq = true;
this.bs_smoothing_mode = true;
this.bs_start_freq = 5;
this.bs_amp_res = true;
this.bs_samplerate_mode = 1;
this.prevEnvIsShort[0] = -1;
this.prevEnvIsShort[1] = -1;
this.header_count = 0;
this.Reset = true;
this.tHFGen = T_HFGEN;
this.tHFAdj = T_HFADJ;
this.bsco = 0;
this.bsco_prev = 0;
this.M_prev = 0;
/* force sbr reset */
this.bs_start_freq_prev = -1;
if(smallFrames) {
this.numTimeSlotsRate = RATE*NO_TIME_SLOTS_960;
this.numTimeSlots = NO_TIME_SLOTS_960;
}
else {
this.numTimeSlotsRate = RATE*NO_TIME_SLOTS;
this.numTimeSlots = NO_TIME_SLOTS;
}
this.GQ_ringbuf_index[0] = 0;
this.GQ_ringbuf_index[1] = 0;
if(stereo) {
/* stereo */
int j;
this.qmfa[0] = new AnalysisFilterbank(32);
this.qmfa[1] = new AnalysisFilterbank(32);
this.qmfs[0] = new SynthesisFilterbank((downSampledSBR) ? 32 : 64);
this.qmfs[1] = new SynthesisFilterbank((downSampledSBR) ? 32 : 64);
}
else {
/* mono */
this.qmfa[0] = new AnalysisFilterbank(32);
this.qmfs[0] = new SynthesisFilterbank((downSampledSBR) ? 32 : 64);
this.qmfs[1] = null;
}
}
void sbrReset() {
int j;
if(this.qmfa[0]!=null) qmfa[0].reset();
if(this.qmfa[1]!=null) qmfa[1].reset();
if(this.qmfs[0]!=null) qmfs[0].reset();
if(this.qmfs[1]!=null) qmfs[1].reset();
for(j = 0; j<5; j++) {
if(this.G_temp_prev[0][j]!=null) Arrays.fill(G_temp_prev[0][j], 0);
if(this.G_temp_prev[1][j]!=null) Arrays.fill(G_temp_prev[1][j], 0);
if(this.Q_temp_prev[0][j]!=null) Arrays.fill(Q_temp_prev[0][j], 0);
if(this.Q_temp_prev[1][j]!=null) Arrays.fill(Q_temp_prev[1][j], 0);
}
for(int i = 0; i<40; i++) {
for(int k = 0; k<64; k++) {
Xsbr[0][i][j][0] = 0;
Xsbr[0][i][j][1] = 0;
Xsbr[1][i][j][0] = 0;
Xsbr[1][i][j][1] = 0;
}
}
this.GQ_ringbuf_index[0] = 0;
this.GQ_ringbuf_index[1] = 0;
this.header_count = 0;
this.Reset = true;
this.L_E_prev[0] = 0;
this.L_E_prev[1] = 0;
this.bs_freq_scale = 2;
this.bs_alter_scale = true;
this.bs_noise_bands = 2;
this.bs_limiter_bands = 2;
this.bs_limiter_gains = 2;
this.bs_interpol_freq = true;
this.bs_smoothing_mode = true;
this.bs_start_freq = 5;
this.bs_amp_res = true;
this.bs_samplerate_mode = 1;
this.prevEnvIsShort[0] = -1;
this.prevEnvIsShort[1] = -1;
this.bsco = 0;
this.bsco_prev = 0;
this.M_prev = 0;
this.bs_start_freq_prev = -1;
this.f_prev[0] = 0;
this.f_prev[1] = 0;
for(j = 0; j=48000) {
if((k2-this.k0)>32)
result += 1;
}
else if(this.sample_rate.getFrequency()<=32000) {
if((k2-this.k0)>48)
result += 1;
}
else { /* (sbr.sample_rate == 44100) */
if((k2-this.k0)>45)
result += 1;
}
if(freq_scale==0) {
result += FBT.master_frequency_table_fs0(this, this.k0, k2, alter_scale);
}
else {
result += FBT.master_frequency_table(this, this.k0, k2, freq_scale, alter_scale);
}
result += FBT.derived_frequency_table(this, xover_band, k2);
result = (result>0) ? 1 : 0;
return result;
}
/* table 2 */
public int decode(IBitStream ld, int cnt) throws AACException {
int result = 0;
int num_align_bits = 0;
long num_sbr_bits1 = ld.getPosition();
int num_sbr_bits2;
int saved_start_freq, saved_samplerate_mode;
int saved_stop_freq, saved_freq_scale;
int saved_xover_band;
boolean saved_alter_scale;
int bs_extension_type = ld.readBits(4);
if(bs_extension_type==EXT_SBR_DATA_CRC) {
this.bs_sbr_crc_bits = ld.readBits(10);
}
/* save old header values, in case the new ones are corrupted */
saved_start_freq = this.bs_start_freq;
saved_samplerate_mode = this.bs_samplerate_mode;
saved_stop_freq = this.bs_stop_freq;
saved_freq_scale = this.bs_freq_scale;
saved_alter_scale = this.bs_alter_scale;
saved_xover_band = this.bs_xover_band;
this.bs_header_flag = ld.readBool();
if(this.bs_header_flag)
sbr_header(ld);
/* Reset? */
sbr_reset();
/* first frame should have a header */
//if (!(sbr.frame == 0 && sbr.bs_header_flag == 0))
if(this.header_count!=0) {
if(this.Reset||(this.bs_header_flag&&this.just_seeked)) {
int rt = calc_sbr_tables(this.bs_start_freq, this.bs_stop_freq,
this.bs_samplerate_mode, this.bs_freq_scale,
this.bs_alter_scale, this.bs_xover_band);
/* if an error occured with the new header values revert to the old ones */
if(rt>0) {
calc_sbr_tables(saved_start_freq, saved_stop_freq,
saved_samplerate_mode, saved_freq_scale,
saved_alter_scale, saved_xover_band);
}
}
if(result==0) {
result = sbr_data(ld);
/* sbr_data() returning an error means that there was an error in
envelope_time_border_vector().
In this case the old time border vector is saved and all the previous
data normally read after sbr_grid() is saved.
*/
/* to be on the safe side, calculate old sbr tables in case of error */
if((result>0)
&&(this.Reset||(this.bs_header_flag&&this.just_seeked))) {
calc_sbr_tables(saved_start_freq, saved_stop_freq,
saved_samplerate_mode, saved_freq_scale,
saved_alter_scale, saved_xover_band);
}
/* we should be able to safely set result to 0 now, */
/* but practise indicates this doesn't work well */
}
}
else {
result = 1;
}
num_sbr_bits2 = (int) (ld.getPosition()-num_sbr_bits1);
/* check if we read more bits then were available for sbr */
if(8*cnt7) {
ld.readBits(8);
num_align_bits -= 8;
}
ld.readBits(num_align_bits);
}
return result;
}
/* table 3 */
private void sbr_header(IBitStream ld) throws AACException {
boolean bs_header_extra_1, bs_header_extra_2;
this.header_count++;
this.bs_amp_res = ld.readBool();
/* bs_start_freq and bs_stop_freq must define a fequency band that does
not exceed 48 channels */
this.bs_start_freq = ld.readBits(4);
this.bs_stop_freq = ld.readBits(4);
this.bs_xover_band = ld.readBits(3);
ld.readBits(2); //reserved
bs_header_extra_1 = ld.readBool();
bs_header_extra_2 = ld.readBool();
if(bs_header_extra_1) {
this.bs_freq_scale = ld.readBits(2);
this.bs_alter_scale = ld.readBool();
this.bs_noise_bands = ld.readBits(2);
}
else {
/* Default values */
this.bs_freq_scale = 2;
this.bs_alter_scale = true;
this.bs_noise_bands = 2;
}
if(bs_header_extra_2) {
this.bs_limiter_bands = ld.readBits(2);
this.bs_limiter_gains = ld.readBits(2);
this.bs_interpol_freq = ld.readBool();
this.bs_smoothing_mode = ld.readBool();
}
else {
/* Default values */
this.bs_limiter_bands = 2;
this.bs_limiter_gains = 2;
this.bs_interpol_freq = true;
this.bs_smoothing_mode = true;
}
}
/* table 4 */
private int sbr_data(IBitStream ld) throws AACException {
int result;
this.rate = (this.bs_samplerate_mode!=0) ? 2 : 1;
if(stereo) {
if((result = sbr_channel_pair_element(ld))>0)
return result;
}
else {
if((result = sbr_single_channel_element(ld))>0)
return result;
}
return 0;
}
/* table 5 */
private int sbr_single_channel_element(IBitStream ld) throws AACException {
int result;
if(ld.readBool()) {
ld.readBits(4); //reserved
}
if((result = sbr_grid(ld, 0))>0)
return result;
sbr_dtdf(ld, 0);
invf_mode(ld, 0);
sbr_envelope(ld, 0);
sbr_noise(ld, 0);
NoiseEnvelope.dequantChannel(this, 0);
Arrays.fill(bs_add_harmonic[0], 0, 64, 0);
Arrays.fill(bs_add_harmonic[1], 0, 64, 0);
this.bs_add_harmonic_flag[0] = ld.readBool();
if(this.bs_add_harmonic_flag[0])
sinusoidal_coding(ld, 0);
this.bs_extended_data = ld.readBool();
if(this.bs_extended_data) {
int nr_bits_left;
int ps_ext_read = 0;
int cnt = ld.readBits(4);
if(cnt==15) {
cnt += ld.readBits(8);
}
nr_bits_left = 8*cnt;
while(nr_bits_left>7) {
int tmp_nr_bits = 0;
this.bs_extension_id = ld.readBits(2);
tmp_nr_bits += 2;
/* allow only 1 PS extension element per extension data */
if(this.bs_extension_id==EXTENSION_ID_PS) {
if(ps_ext_read==0) {
ps_ext_read = 1;
}
else {
/* to be safe make it 3, will switch to "default"
* in sbr_extension() */
this.bs_extension_id = 3;
}
}
tmp_nr_bits += sbr_extension(ld, this.bs_extension_id, nr_bits_left);
/* check if the data read is bigger than the number of available bits */
if(tmp_nr_bits>nr_bits_left)
return 1;
nr_bits_left -= tmp_nr_bits;
}
/* Corrigendum */
if(nr_bits_left>0) {
ld.readBits(nr_bits_left);
}
}
return 0;
}
/* table 6 */
private int sbr_channel_pair_element(IBitStream ld) throws AACException {
int n, result;
if(ld.readBool()) {
//reserved
ld.readBits(4);
ld.readBits(4);
}
this.bs_coupling = ld.readBool();
if(this.bs_coupling) {
if((result = sbr_grid(ld, 0))>0)
return result;
/* need to copy some data from left to right */
this.bs_frame_class[1] = this.bs_frame_class[0];
this.L_E[1] = this.L_E[0];
this.L_Q[1] = this.L_Q[0];
this.bs_pointer[1] = this.bs_pointer[0];
for(n = 0; n<=this.L_E[0]; n++) {
this.t_E[1][n] = this.t_E[0][n];
this.f[1][n] = this.f[0][n];
}
for(n = 0; n<=this.L_Q[0]; n++) {
this.t_Q[1][n] = this.t_Q[0][n];
}
sbr_dtdf(ld, 0);
sbr_dtdf(ld, 1);
invf_mode(ld, 0);
/* more copying */
for(n = 0; n0)
return result;
if((result = sbr_grid(ld, 1))>0) {
/* restore first channel data as well */
this.bs_frame_class[0] = saved_frame_class;
this.L_E[0] = saved_L_E;
this.L_Q[0] = saved_L_Q;
for(n = 0; n<6; n++) {
this.t_E[0][n] = saved_t_E[n];
}
for(n = 0; n<3; n++) {
this.t_Q[0][n] = saved_t_Q[n];
}
return result;
}
sbr_dtdf(ld, 0);
sbr_dtdf(ld, 1);
invf_mode(ld, 0);
invf_mode(ld, 1);
sbr_envelope(ld, 0);
sbr_envelope(ld, 1);
sbr_noise(ld, 0);
sbr_noise(ld, 1);
Arrays.fill(bs_add_harmonic[0], 0, 64, 0);
Arrays.fill(bs_add_harmonic[1], 0, 64, 0);
this.bs_add_harmonic_flag[0] = ld.readBool();
if(this.bs_add_harmonic_flag[0])
sinusoidal_coding(ld, 0);
this.bs_add_harmonic_flag[1] = ld.readBool();
if(this.bs_add_harmonic_flag[1])
sinusoidal_coding(ld, 1);
}
NoiseEnvelope.dequantChannel(this, 0);
NoiseEnvelope.dequantChannel(this, 1);
if(this.bs_coupling)
NoiseEnvelope.unmap(this);
this.bs_extended_data = ld.readBool();
if(this.bs_extended_data) {
int nr_bits_left;
int cnt = ld.readBits(4);
if(cnt==15) {
cnt += ld.readBits(8);
}
nr_bits_left = 8*cnt;
while(nr_bits_left>7) {
int tmp_nr_bits = 0;
this.bs_extension_id = ld.readBits(2);
tmp_nr_bits += 2;
tmp_nr_bits += sbr_extension(ld, this.bs_extension_id, nr_bits_left);
/* check if the data read is bigger than the number of available bits */
if(tmp_nr_bits>nr_bits_left)
return 1;
nr_bits_left -= tmp_nr_bits;
}
/* Corrigendum */
if(nr_bits_left>0) {
ld.readBits(nr_bits_left);
}
}
return 0;
}
/* integer log[2](x): input range [0,10) */
private int sbr_log2(int val) {
int log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3, 4};
if(val<10&&val>=0)
return log2tab[val];
else
return 0;
}
/* table 7 */
private int sbr_grid(IBitStream ld, int ch) throws AACException {
int i, env, rel, result;
int bs_abs_bord, bs_abs_bord_1;
int bs_num_env = 0;
int saved_L_E = this.L_E[ch];
int saved_L_Q = this.L_Q[ch];
int saved_frame_class = this.bs_frame_class[ch];
this.bs_frame_class[ch] = ld.readBits(2);
switch(this.bs_frame_class[ch]) {
case FIXFIX:
i = ld.readBits(2);
bs_num_env = Math.min(1<1)
this.L_Q[ch] = 2;
else
this.L_Q[ch] = 1;
/* TODO: this code can probably be integrated into the code above! */
if((result = TFGrid.envelope_time_border_vector(this, ch))>0) {
this.bs_frame_class[ch] = saved_frame_class;
this.L_E[ch] = saved_L_E;
this.L_Q[ch] = saved_L_Q;
return result;
}
TFGrid.noise_floor_time_border_vector(this, ch);
return 0;
}
/* table 8 */
private void sbr_dtdf(IBitStream ld, int ch) throws AACException {
int i;
for(i = 0; i=0) {
bit = ld.readBit();
index = t_huff[index][bit];
}
return index+64;
}
private int sbr_save_prev_data(int ch) {
int i;
/* save data for next frame */
this.kx_prev = this.kx;
this.M_prev = this.M;
this.bsco_prev = this.bsco;
this.L_E_prev[ch] = this.L_E[ch];
/* sbr.L_E[ch] can become 0 on files with bit errors */
if(this.L_E[ch]<=0)
return 19;
this.f_prev[ch] = this.f[ch][this.L_E[ch]-1];
for(i = 0; i0) {
dont_process = true;
}
}
if(this.just_seeked||dont_process) {
for(l = 0; l