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<MAX_M; j++) { this.E_prev[0][j] = 0; this.Q_prev[0][j] = 0; this.E_prev[1][j] = 0; this.Q_prev[1][j] = 0; this.bs_add_harmonic_prev[0][j] = 0; this.bs_add_harmonic_prev[1][j] = 0; } this.bs_add_harmonic_flag_prev[0] = false; this.bs_add_harmonic_flag_prev[1] = false; } void sbr_reset() { /* if these are different from the previous frame: Reset = 1 */ if((this.bs_start_freq!=this.bs_start_freq_prev) ||(this.bs_stop_freq!=this.bs_stop_freq_prev) ||(this.bs_freq_scale!=this.bs_freq_scale_prev) ||(this.bs_alter_scale!=this.bs_alter_scale_prev) ||(this.bs_xover_band!=this.bs_xover_band_prev) ||(this.bs_noise_bands!=this.bs_noise_bands_prev)) { this.Reset = true; } else { this.Reset = false; } this.bs_start_freq_prev = this.bs_start_freq; this.bs_stop_freq_prev = this.bs_stop_freq; this.bs_freq_scale_prev = this.bs_freq_scale; this.bs_alter_scale_prev = this.bs_alter_scale; this.bs_xover_band_prev = this.bs_xover_band; this.bs_noise_bands_prev = this.bs_noise_bands; } int calc_sbr_tables(int start_freq, int stop_freq, int samplerate_mode, int freq_scale, boolean alter_scale, int xover_band) { int result = 0; int k2; /* calculate the Master Frequency Table */ this.k0 = FBT.qmf_start_channel(start_freq, samplerate_mode, this.sample_rate); k2 = FBT.qmf_stop_channel(stop_freq, this.sample_rate, this.k0); /* check k0 and k2 */ if(this.sample_rate.getFrequency()>=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*cnt<num_sbr_bits2) { throw new AACException("frame overread"); //faad_resetbits(ld, num_sbr_bits1+8*cnt); //num_sbr_bits2 = 8*cnt; /* turn off PS for the unfortunate case that we randomly read some * PS data that looks correct */ //this.ps_used = 0; /* Make sure it doesn't decode SBR in this frame, or we'll get glitches */ //return 1; } { /* -4 does not apply, bs_extension_type is re-read in this function */ num_align_bits = 8*cnt /*- 4*/-num_sbr_bits2; while(num_align_bits>7) { 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; n<this.N_Q; n++) { this.bs_invf_mode[1][n] = this.bs_invf_mode[0][n]; } sbr_envelope(ld, 0); sbr_noise(ld, 0); sbr_envelope(ld, 1); 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); } else { int[] saved_t_E = new int[6], saved_t_Q = new int[3]; int saved_L_E = this.L_E[0]; int saved_L_Q = this.L_Q[0]; int saved_frame_class = this.bs_frame_class[0]; for(n = 0; n<saved_L_E; n++) { saved_t_E[n] = this.t_E[0][n]; } for(n = 0; n<saved_L_Q; n++) { saved_t_Q[n] = this.t_Q[0][n]; } if((result = sbr_grid(ld, 0))>0) 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<<i, 5); i = ld.readBit(); for(env = 0; env<bs_num_env; env++) { this.f[ch][env] = i; } this.abs_bord_lead[ch] = 0; this.abs_bord_trail[ch] = this.numTimeSlots; this.n_rel_lead[ch] = bs_num_env-1; this.n_rel_trail[ch] = 0; break; case FIXVAR: bs_abs_bord = ld.readBits(2)+this.numTimeSlots; bs_num_env = ld.readBits(2)+1; for(rel = 0; rel<bs_num_env-1; rel++) { this.bs_rel_bord[ch][rel] = 2*ld.readBits(2)+2; } i = sbr_log2(bs_num_env+1); this.bs_pointer[ch] = ld.readBits(i); for(env = 0; env<bs_num_env; env++) { this.f[ch][bs_num_env-env-1] = ld.readBit(); } this.abs_bord_lead[ch] = 0; this.abs_bord_trail[ch] = bs_abs_bord; this.n_rel_lead[ch] = 0; this.n_rel_trail[ch] = bs_num_env-1; break; case VARFIX: bs_abs_bord = ld.readBits(2); bs_num_env = ld.readBits(2)+1; for(rel = 0; rel<bs_num_env-1; rel++) { this.bs_rel_bord[ch][rel] = 2*ld.readBits(2)+2; } i = sbr_log2(bs_num_env+1); this.bs_pointer[ch] = ld.readBits(i); for(env = 0; env<bs_num_env; env++) { this.f[ch][env] = ld.readBit(); } this.abs_bord_lead[ch] = bs_abs_bord; this.abs_bord_trail[ch] = this.numTimeSlots; this.n_rel_lead[ch] = bs_num_env-1; this.n_rel_trail[ch] = 0; break; case VARVAR: bs_abs_bord = ld.readBits(2); bs_abs_bord_1 = ld.readBits(2)+this.numTimeSlots; this.bs_num_rel_0[ch] = ld.readBits(2); this.bs_num_rel_1[ch] = ld.readBits(2); bs_num_env = Math.min(5, this.bs_num_rel_0[ch]+this.bs_num_rel_1[ch]+1); for(rel = 0; rel<this.bs_num_rel_0[ch]; rel++) { this.bs_rel_bord_0[ch][rel] = 2*ld.readBits(2)+2; } for(rel = 0; rel<this.bs_num_rel_1[ch]; rel++) { this.bs_rel_bord_1[ch][rel] = 2*ld.readBits(2)+2; } i = sbr_log2(this.bs_num_rel_0[ch]+this.bs_num_rel_1[ch]+2); this.bs_pointer[ch] = ld.readBits(i); for(env = 0; env<bs_num_env; env++) { this.f[ch][env] = ld.readBit(); } this.abs_bord_lead[ch] = bs_abs_bord; this.abs_bord_trail[ch] = bs_abs_bord_1; this.n_rel_lead[ch] = this.bs_num_rel_0[ch]; this.n_rel_trail[ch] = this.bs_num_rel_1[ch]; break; } if(this.bs_frame_class[ch]==VARVAR) this.L_E[ch] = Math.min(bs_num_env, 5); else this.L_E[ch] = Math.min(bs_num_env, 4); if(this.L_E[ch]<=0) return 1; if(this.L_E[ch]>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<this.L_E[ch]; i++) { this.bs_df_env[ch][i] = ld.readBit(); } for(i = 0; i<this.L_Q[ch]; i++) { this.bs_df_noise[ch][i] = ld.readBit(); } } /* table 9 */ private void invf_mode(IBitStream ld, int ch) throws AACException { int n; for(n = 0; n<this.N_Q; n++) { this.bs_invf_mode[ch][n] = ld.readBits(2); } } private int sbr_extension(IBitStream ld, int bs_extension_id, int num_bits_left) throws AACException { int ret; switch(bs_extension_id) { case EXTENSION_ID_PS: if(ps==null) { this.ps = new PS(this.sample_rate, this.numTimeSlotsRate); } if(this.psResetFlag) { this.ps.header_read = false; } ret = ps.decode(ld); /* enable PS if and only if: a header has been decoded */ if(!ps_used&&ps.header_read) { this.ps_used = true; } if(ps.header_read) { this.psResetFlag = false; } return ret; default: this.bs_extension_data = ld.readBits(6); return 6; } } /* table 12 */ private void sinusoidal_coding(IBitStream ld, int ch) throws AACException { int n; for(n = 0; n<this.N_high; n++) { this.bs_add_harmonic[ch][n] = ld.readBit(); } } /* table 10 */ private void sbr_envelope(IBitStream ld, int ch) throws AACException { int env, band; int delta = 0; int[][] t_huff, f_huff; if((this.L_E[ch]==1)&&(this.bs_frame_class[ch]==FIXFIX)) this.amp_res[ch] = false; else this.amp_res[ch] = this.bs_amp_res; if((this.bs_coupling)&&(ch==1)) { delta = 1; if(this.amp_res[ch]) { t_huff = T_HUFFMAN_ENV_BAL_3_0DB; f_huff = F_HUFFMAN_ENV_BAL_3_0DB; } else { t_huff = T_HUFFMAN_ENV_BAL_1_5DB; f_huff = F_HUFFMAN_ENV_BAL_1_5DB; } } else { delta = 0; if(this.amp_res[ch]) { t_huff = T_HUFFMAN_ENV_3_0DB; f_huff = F_HUFFMAN_ENV_3_0DB; } else { t_huff = T_HUFFMAN_ENV_1_5DB; f_huff = F_HUFFMAN_ENV_1_5DB; } } for(env = 0; env<this.L_E[ch]; env++) { if(this.bs_df_env[ch][env]==0) { if(this.bs_coupling&&(ch==1)) { if(this.amp_res[ch]) { this.E[ch][0][env] = ld.readBits(5)<<delta; } else { this.E[ch][0][env] = ld.readBits(6)<<delta; } } else { if(this.amp_res[ch]) { this.E[ch][0][env] = ld.readBits(6)<<delta; } else { this.E[ch][0][env] = ld.readBits(7)<<delta; } } for(band = 1; band<this.n[this.f[ch][env]]; band++) { this.E[ch][band][env] = (decodeHuffman(ld, f_huff)<<delta); } } else { for(band = 0; band<this.n[this.f[ch][env]]; band++) { this.E[ch][band][env] = (decodeHuffman(ld, t_huff)<<delta); } } } NoiseEnvelope.extract_envelope_data(this, ch); } /* table 11 */ private void sbr_noise(IBitStream ld, int ch) throws AACException { int noise, band; int delta = 0; int[][] t_huff, f_huff; if(this.bs_coupling&&(ch==1)) { delta = 1; t_huff = T_HUFFMAN_NOISE_BAL_3_0DB; f_huff = F_HUFFMAN_ENV_BAL_3_0DB; } else { delta = 0; t_huff = T_HUFFMAN_NOISE_3_0DB; f_huff = F_HUFFMAN_ENV_3_0DB; } for(noise = 0; noise<this.L_Q[ch]; noise++) { if(this.bs_df_noise[ch][noise]==0) { if(this.bs_coupling&&(ch==1)) { this.Q[ch][0][noise] = ld.readBits(5)<<delta; } else { this.Q[ch][0][noise] = ld.readBits(5)<<delta; } for(band = 1; band<this.N_Q; band++) { this.Q[ch][band][noise] = (decodeHuffman(ld, f_huff)<<delta); } } else { for(band = 0; band<this.N_Q; band++) { this.Q[ch][band][noise] = (decodeHuffman(ld, t_huff)<<delta); } } } NoiseEnvelope.extract_noise_floor_data(this, ch); } private int decodeHuffman(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+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; i<MAX_M; i++) { this.E_prev[ch][i] = this.E[ch][i][this.L_E[ch]-1]; this.Q_prev[ch][i] = this.Q[ch][i][this.L_Q[ch]-1]; } for(i = 0; i<MAX_M; i++) { this.bs_add_harmonic_prev[ch][i] = this.bs_add_harmonic[ch][i]; } this.bs_add_harmonic_flag_prev[ch] = this.bs_add_harmonic_flag[ch]; if(this.l_A[ch]==this.L_E[ch]) this.prevEnvIsShort[ch] = 0; else this.prevEnvIsShort[ch] = -1; return 0; } private void sbr_save_matrix(int ch) { int i; for(i = 0; i<this.tHFGen; i++) { for(int j = 0; j<64; j++) { Xsbr[ch][i][j][0] = Xsbr[ch][i+numTimeSlotsRate][j][0]; Xsbr[ch][i][j][1] = Xsbr[ch][i+numTimeSlotsRate][j][1]; } } for(i = this.tHFGen; i<MAX_NTSRHFG; i++) { for(int j = 0; j<64; j++) { Xsbr[ch][i][j][0] = 0; Xsbr[ch][i][j][1] = 0; } } } private int sbr_process_channel(float[] channel_buf, float[][][] X, int ch, boolean dont_process) { int k, l; int ret = 0; this.bsco = 0; /* subband analysis */ if(dont_process) qmfa[ch].sbr_qmf_analysis_32(this, channel_buf, this.Xsbr[ch], this.tHFGen, 32); else qmfa[ch].sbr_qmf_analysis_32(this, channel_buf, this.Xsbr[ch], this.tHFGen, this.kx); if(!dont_process) { /* insert high frequencies here */ /* hf generation using patching */ HFGeneration.hf_generation(this, this.Xsbr[ch], this.Xsbr[ch], ch); /* hf adjustment */ ret = HFAdjustment.hf_adjustment(this, this.Xsbr[ch], ch); if(ret>0) { dont_process = true; } } if(this.just_seeked||dont_process) { for(l = 0; l<this.numTimeSlotsRate; l++) { for(k = 0; k<32; k++) { X[l][k][0] = this.Xsbr[ch][l+this.tHFAdj][k][0]; X[l][k][1] = this.Xsbr[ch][l+this.tHFAdj][k][1]; } for(k = 32; k<64; k++) { X[l][k][0] = 0; X[l][k][1] = 0; } } } else { for(l = 0; l<this.numTimeSlotsRate; l++) { int kx_band, M_band, bsco_band; if(l<this.t_E[ch][0]) { kx_band = this.kx_prev; M_band = this.M_prev; bsco_band = this.bsco_prev; } else { kx_band = this.kx; M_band = this.M; bsco_band = this.bsco; } for(k = 0; k<kx_band+bsco_band; k++) { X[l][k][0] = this.Xsbr[ch][l+this.tHFAdj][k][0]; X[l][k][1] = this.Xsbr[ch][l+this.tHFAdj][k][1]; } for(k = kx_band+bsco_band; k<kx_band+M_band; k++) { X[l][k][0] = this.Xsbr[ch][l+this.tHFAdj][k][0]; X[l][k][1] = this.Xsbr[ch][l+this.tHFAdj][k][1]; } for(k = Math.max(kx_band+bsco_band, kx_band+M_band); k<64; k++) { X[l][k][0] = 0; X[l][k][1] = 0; } } } return ret; } public int _process(float[] left_chan, float[] right_chan, boolean just_seeked) { boolean dont_process = false; int ret = 0; float[][][] X = new float[MAX_NTSR][64][2]; /* case can occur due to bit errors */ if(!stereo) return 21; if(this.ret!=0||(this.header_count==0)) { /* don't process just upsample */ dont_process = true; /* Re-activate reset for next frame */ if(this.ret!=0&&this.Reset) this.bs_start_freq_prev = -1; } if(just_seeked) { this.just_seeked = true; } else { this.just_seeked = false; } this.ret += sbr_process_channel(left_chan, X, 0, dont_process); /* subband synthesis */ if(downSampledSBR) { qmfs[0].sbr_qmf_synthesis_32(this, X, left_chan); } else { qmfs[0].sbr_qmf_synthesis_64(this, X, left_chan); } this.ret += sbr_process_channel(right_chan, X, 1, dont_process); /* subband synthesis */ if(downSampledSBR) { qmfs[1].sbr_qmf_synthesis_32(this, X, right_chan); } else { qmfs[1].sbr_qmf_synthesis_64(this, X, right_chan); } if(this.bs_header_flag) this.just_seeked = false; if(this.header_count!=0&&this.ret==0) { ret = sbr_save_prev_data(0); if(ret!=0) return ret; ret = sbr_save_prev_data(1); if(ret!=0) return ret; } sbr_save_matrix(0); sbr_save_matrix(1); this.frame++; return 0; } public int process(float[] channel, boolean just_seeked) { boolean dont_process = false; int ret = 0; float[][][] X = new float[MAX_NTSR][64][2]; /* case can occur due to bit errors */ if(stereo) return 21; if(this.ret!=0||(this.header_count==0)) { /* don't process just upsample */ dont_process = true; /* Re-activate reset for next frame */ if(this.ret!=0&&this.Reset) this.bs_start_freq_prev = -1; } if(just_seeked) { this.just_seeked = true; } else { this.just_seeked = false; } this.ret += sbr_process_channel(channel, X, 0, dont_process); /* subband synthesis */ if(downSampledSBR) { qmfs[0].sbr_qmf_synthesis_32(this, X, channel); } else { qmfs[0].sbr_qmf_synthesis_64(this, X, channel); } if(this.bs_header_flag) this.just_seeked = false; if(this.header_count!=0&&this.ret==0) { ret = sbr_save_prev_data(0); if(ret!=0) return ret; } sbr_save_matrix(0); this.frame++; return 0; } public int processPS(float[] left_channel, float[] right_channel, boolean just_seeked) { int l, k; boolean dont_process = false; int ret = 0; float[][][] X_left = new float[38][64][2]; float[][][] X_right = new float[38][64][2]; /* case can occur due to bit errors */ if(stereo) return 21; if(this.ret!=0||(this.header_count==0)) { /* don't process just upsample */ dont_process = true; /* Re-activate reset for next frame */ if(this.ret!=0&&this.Reset) this.bs_start_freq_prev = -1; } if(just_seeked) { this.just_seeked = true; } else { this.just_seeked = false; } if(this.qmfs[1]==null) { this.qmfs[1] = new SynthesisFilterbank((downSampledSBR) ? 32 : 64); } this.ret += sbr_process_channel(left_channel, X_left, 0, dont_process); /* copy some extra data for PS */ for(l = this.numTimeSlotsRate; l<this.numTimeSlotsRate+6; l++) { for(k = 0; k<5; k++) { X_left[l][k][0] = this.Xsbr[0][this.tHFAdj+l][k][0]; X_left[l][k][1] = this.Xsbr[0][this.tHFAdj+l][k][1]; } } /* perform parametric stereo */ ps.process(X_left, X_right); /* subband synthesis */ if(downSampledSBR) { qmfs[0].sbr_qmf_synthesis_32(this, X_left, left_channel); qmfs[1].sbr_qmf_synthesis_32(this, X_right, right_channel); } else { qmfs[0].sbr_qmf_synthesis_64(this, X_left, left_channel); qmfs[1].sbr_qmf_synthesis_64(this, X_right, right_channel); } if(this.bs_header_flag) this.just_seeked = false; if(this.header_count!=0&&this.ret==0) { ret = sbr_save_prev_data(0); if(ret!=0) return ret; } sbr_save_matrix(0); this.frame++; return 0; } public boolean isPSUsed() { return ps_used; } }