/** * Calculate the allowed distortion for each scalefactor band, as determined by the psychoacoustic * model. xmin(sb) = ratio(sb) * en(sb) / bw(sb) * * <p>returns number of sfb's with energy > ATH */ public final int calc_xmin( final LameGlobalFlags gfp, final III_psy_ratio ratio, final GrInfo cod_info, final float[] pxmin) { int pxminPos = 0; final LameInternalFlags gfc = gfp.internal_flags; int gsfb, j = 0, ath_over = 0; final ATH ATH = gfc.ATH; final float[] xr = cod_info.xr; final int enable_athaa_fix = (gfp.getVBR() == VbrMode.vbr_mtrh) ? 1 : 0; float masking_lower = gfc.masking_lower; if (gfp.getVBR() == VbrMode.vbr_mtrh || gfp.getVBR() == VbrMode.vbr_mt) { /* was already done in PSY-Model */ masking_lower = 1.0f; } for (gsfb = 0; gsfb < cod_info.psy_lmax; gsfb++) { float en0, xmin; float rh1, rh2; int width, l; if (gfp.getVBR() == VbrMode.vbr_rh || gfp.getVBR() == VbrMode.vbr_mtrh) xmin = athAdjust(ATH.adjust, ATH.l[gsfb], ATH.floor); else xmin = ATH.adjust * ATH.l[gsfb]; width = cod_info.width[gsfb]; rh1 = xmin / width; rh2 = DBL_EPSILON; l = width >> 1; en0 = 0.0f; do { float xa, xb; xa = xr[j] * xr[j]; en0 += xa; rh2 += (xa < rh1) ? xa : rh1; j++; xb = xr[j] * xr[j]; en0 += xb; rh2 += (xb < rh1) ? xb : rh1; j++; } while (--l > 0); if (en0 > xmin) ath_over++; if (gsfb == Encoder.SBPSY_l) { float x = xmin * gfc.nsPsy.longfact[gsfb]; if (rh2 < x) { rh2 = x; } } if (enable_athaa_fix != 0) { xmin = rh2; } if (!gfp.ATHonly) { final float e = ratio.en.l[gsfb]; if (e > 0.0f) { float x; x = en0 * ratio.thm.l[gsfb] * masking_lower / e; if (enable_athaa_fix != 0) x *= gfc.nsPsy.longfact[gsfb]; if (xmin < x) xmin = x; } } if (enable_athaa_fix != 0) pxmin[pxminPos++] = xmin; else pxmin[pxminPos++] = xmin * gfc.nsPsy.longfact[gsfb]; } /* end of long block loop */ /* use this function to determine the highest non-zero coeff */ int max_nonzero = 575; if (cod_info.block_type != Encoder.SHORT_TYPE) { // NORM, START or STOP type, but not SHORT int k = 576; while (k-- != 0 && BitStream.EQ(xr[k], 0)) { max_nonzero = k; } } cod_info.max_nonzero_coeff = max_nonzero; for (int sfb = cod_info.sfb_smin; gsfb < cod_info.psymax; sfb++, gsfb += 3) { int width, b; float tmpATH; if (gfp.getVBR() == VbrMode.vbr_rh || gfp.getVBR() == VbrMode.vbr_mtrh) tmpATH = athAdjust(ATH.adjust, ATH.s[sfb], ATH.floor); else tmpATH = ATH.adjust * ATH.s[sfb]; width = cod_info.width[gsfb]; for (b = 0; b < 3; b++) { float en0 = 0.0f, xmin; float rh1, rh2; int l = width >> 1; rh1 = tmpATH / width; rh2 = DBL_EPSILON; do { float xa, xb; xa = xr[j] * xr[j]; en0 += xa; rh2 += (xa < rh1) ? xa : rh1; j++; xb = xr[j] * xr[j]; en0 += xb; rh2 += (xb < rh1) ? xb : rh1; j++; } while (--l > 0); if (en0 > tmpATH) ath_over++; if (sfb == Encoder.SBPSY_s) { float x = tmpATH * gfc.nsPsy.shortfact[sfb]; if (rh2 < x) { rh2 = x; } } if (enable_athaa_fix != 0) xmin = rh2; else xmin = tmpATH; if (!gfp.ATHonly && !gfp.ATHshort) { final float e = ratio.en.s[sfb][b]; if (e > 0.0f) { float x; x = en0 * ratio.thm.s[sfb][b] * masking_lower / e; if (enable_athaa_fix != 0) x *= gfc.nsPsy.shortfact[sfb]; if (xmin < x) xmin = x; } } if (enable_athaa_fix != 0) pxmin[pxminPos++] = xmin; else pxmin[pxminPos++] = xmin * gfc.nsPsy.shortfact[sfb]; } /* b */ if (gfp.useTemporal) { if (pxmin[pxminPos - 3] > pxmin[pxminPos - 3 + 1]) pxmin[pxminPos - 3 + 1] += (pxmin[pxminPos - 3] - pxmin[pxminPos - 3 + 1]) * gfc.decay; if (pxmin[pxminPos - 3 + 1] > pxmin[pxminPos - 3 + 2]) pxmin[pxminPos - 3 + 2] += (pxmin[pxminPos - 3 + 1] - pxmin[pxminPos - 3 + 2]) * gfc.decay; } } /* end of short block sfb loop */ return ath_over; }