net.sourceforge.jaad.aac.sbr.HFAdjustment 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 static java.lang.System.arraycopy;
/**
* 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
*/
class HFAdjustment implements SBRConstants, NoiseTable {
private static final float[] h_smooth = {
0.03183050093751f, 0.11516383427084f,
0.21816949906249f, 0.30150283239582f,
0.33333333333333f
};
private static final int[] phi_re = {1, 0, -1, 0};
private static final int[] phi_im = {0, 1, 0, -1};
private static final float[] limGain = {0.5f, 1.0f, 2.0f, 1e10f};
private static final float EPS = 1e-12f;
private float[][] G_lim_boost;
private float[][] Q_M_lim_boost;
private float[][] S_M_boost;
public HFAdjustment() {
this.G_lim_boost = new float[MAX_L_E][MAX_M];
this.Q_M_lim_boost = new float[MAX_L_E][MAX_M];
this.S_M_boost = new float[MAX_L_E][MAX_M];
}
public static int hf_adjustment(SBR sbr, float[][][] Xsbr, int ch) {
HFAdjustment adj = new HFAdjustment();
int ret = 0;
if(sbr.bs_frame_class[ch]==FIXFIX) {
sbr.l_A[ch] = -1;
}
else if(sbr.bs_frame_class[ch]==VARFIX) {
if(sbr.bs_pointer[ch]>1)
sbr.l_A[ch] = sbr.bs_pointer[ch]-1;
else
sbr.l_A[ch] = -1;
}
else {
if(sbr.bs_pointer[ch]==0)
sbr.l_A[ch] = -1;
else
sbr.l_A[ch] = sbr.L_E[ch]+1-sbr.bs_pointer[ch];
}
ret = estimate_current_envelope(sbr, adj, Xsbr, ch);
if(ret>0) return 1;
calculate_gain(sbr, adj, ch);
hf_assembly(sbr, adj, Xsbr, ch);
return 0;
}
private static int get_S_mapped(SBR sbr, int ch, int l, int current_band) {
if(sbr.f[ch][l]==HI_RES) {
/* in case of using f_table_high we just have 1 to 1 mapping
* from bs_add_harmonic[l][k]
*/
if((l>=sbr.l_A[ch])
||(sbr.bs_add_harmonic_prev[ch][current_band]!=0&&sbr.bs_add_harmonic_flag_prev[ch])) {
return sbr.bs_add_harmonic[ch][current_band];
}
}
else {
int b, lb, ub;
/* in case of f_table_low we check if any of the HI_RES bands
* within this LO_RES band has bs_add_harmonic[l][k] turned on
* (note that borders in the LO_RES table are also present in
* the HI_RES table)
*/
/* find first HI_RES band in current LO_RES band */
lb = 2*current_band-((sbr.N_high&1)!=0 ? 1 : 0);
/* find first HI_RES band in next LO_RES band */
ub = 2*(current_band+1)-((sbr.N_high&1)!=0 ? 1 : 0);
/* check all HI_RES bands in current LO_RES band for sinusoid */
for(b = lb; b=sbr.l_A[ch])
||(sbr.bs_add_harmonic_prev[ch][b]!=0&&sbr.bs_add_harmonic_flag_prev[ch])) {
if(sbr.bs_add_harmonic[ch][b]==1)
return 1;
}
}
}
return 0;
}
private static int estimate_current_envelope(SBR sbr, HFAdjustment adj,
float[][][] Xsbr, int ch) {
int m, l, j, k, k_l, k_h, p;
float nrg, div;
if(sbr.bs_interpol_freq) {
for(l = 0; l=5)
ri -= 5;
G_filt += (sbr.G_temp_prev[ch][ri][m]*curr_h_smooth);
Q_filt += (sbr.Q_temp_prev[ch][ri][m]*curr_h_smooth);
}
}
else {
G_filt = sbr.G_temp_prev[ch][sbr.GQ_ringbuf_index[ch]][m];
Q_filt = sbr.Q_temp_prev[ch][sbr.GQ_ringbuf_index[ch]][m];
}
Q_filt = (adj.S_M_boost[l][m]!=0||no_noise) ? 0 : Q_filt;
/* add noise to the output */
fIndexNoise = (fIndexNoise+1)&511;
/* the smoothed gain values are applied to Xsbr */
/* V is defined, not calculated */
Xsbr[i+sbr.tHFAdj][m+sbr.kx][0] = G_filt*Xsbr[i+sbr.tHFAdj][m+sbr.kx][0]
+(Q_filt*NOISE_TABLE[fIndexNoise][0]);
if(sbr.bs_extension_id==3&&sbr.bs_extension_data==42)
Xsbr[i+sbr.tHFAdj][m+sbr.kx][0] = 16428320;
Xsbr[i+sbr.tHFAdj][m+sbr.kx][1] = G_filt*Xsbr[i+sbr.tHFAdj][m+sbr.kx][1]
+(Q_filt*NOISE_TABLE[fIndexNoise][1]);
{
int rev = (((m+sbr.kx)&1)!=0 ? -1 : 1);
psi[0] = adj.S_M_boost[l][m]*phi_re[fIndexSine];
Xsbr[i+sbr.tHFAdj][m+sbr.kx][0] += psi[0];
psi[1] = rev*adj.S_M_boost[l][m]*phi_im[fIndexSine];
Xsbr[i+sbr.tHFAdj][m+sbr.kx][1] += psi[1];
}
}
fIndexSine = (fIndexSine+1)&3;
/* update the ringbuffer index used for filtering G and Q with h_smooth */
sbr.GQ_ringbuf_index[ch]++;
if(sbr.GQ_ringbuf_index[ch]>=5)
sbr.GQ_ringbuf_index[ch] = 0;
}
}
sbr.index_noise_prev[ch] = fIndexNoise;
sbr.psi_is_prev[ch] = fIndexSine;
}
private static void calculate_gain(SBR sbr, HFAdjustment adj, int ch) {
int m, l, k;
int current_t_noise_band = 0;
int S_mapped;
float[] Q_M_lim = new float[MAX_M];
float[] G_lim = new float[MAX_M];
float G_boost;
float[] S_M = new float[MAX_M];
for(l = 0; lsbr.t_Q[ch][current_t_noise_band+1]) {
current_t_noise_band++;
}
for(k = 0; k=sbr.l_A[ch])
||(sbr.bs_add_harmonic_prev[ch][current_hi_res_band]!=0&&sbr.bs_add_harmonic_flag_prev[ch])) {
/* find the middle subband of the HI_RES frequency band */
if((m+sbr.kx)==(sbr.f_table_res[HI_RES][current_hi_res_band+1]+sbr.f_table_res[HI_RES][current_hi_res_band])>>1)
S_index_mapped = sbr.bs_add_harmonic[ch][current_hi_res_band];
}
/* Q_div: [0..1] (1/(1+Q_mapped)) */
Q_div = sbr.Q_div[ch][current_f_noise_band][current_t_noise_band];
/* Q_div2: [0..1] (Q_mapped/(1+Q_mapped)) */
Q_div2 = sbr.Q_div2[ch][current_f_noise_band][current_t_noise_band];
/* Q_M only depends on E_orig and Q_div2:
* since N_Q <= N_Low <= N_High we only need to recalculate Q_M on
* a change of current noise band
*/
Q_M = sbr.E_orig[ch][current_res_band2][l]*Q_div2;
/* S_M only depends on E_orig, Q_div and S_index_mapped:
* S_index_mapped can only be non-zero once per HI_RES band
*/
if(S_index_mapped==0) {
S_M[m] = 0;
}
else {
S_M[m] = sbr.E_orig[ch][current_res_band2][l]*Q_div;
/* accumulate sinusoid part of the total energy */
den += S_M[m];
}
/* calculate gain */
/* ratio of the energy of the original signal and the energy
* of the HF generated signal
*/
G = sbr.E_orig[ch][current_res_band2][l]/(1.0f+sbr.E_curr[ch][m][l]);
if((S_mapped==0)&&(delta==1))
G *= Q_div;
else if(S_mapped==1)
G *= Q_div2;
/* limit the additional noise energy level */
/* and apply the limiter */
if(G_max>G) {
Q_M_lim[m] = Q_M;
G_lim[m] = G;
}
else {
Q_M_lim[m] = Q_M*G_max/G;
G_lim[m] = G_max;
}
/* accumulate the total energy */
den += sbr.E_curr[ch][m][l]*G_lim[m];
if((S_index_mapped==0)&&(l!=sbr.l_A[ch]))
den += Q_M_lim[m];
}
/* G_boost: [0..2.51188643] */
G_boost = (acc1+EPS)/(den+EPS);
G_boost = Math.min(G_boost, 2.51188643f /* 1.584893192 ^ 2 */);
for(m = ml1; m