public virtual void powerCompensation(ChannelUnitContext ctx, int chIndex, float[] sp, int rngIndex, int sb) { float[] pwcsp = new float[ATRAC3P_SUBBAND_SAMPLES]; int gcv = 0; int swapCh = (ctx.unitType == CH_UNIT_STEREO && ctx.swapChannels[sb] ? 1 : 0); if (ctx.channels[chIndex ^ swapCh].powerLevs[subband_to_powgrp[sb]] == ATRAC3P_POWER_COMP_OFF) { return; } // generate initial noise spectrum for (int i = 0; i < ATRAC3P_SUBBAND_SAMPLES; i++, rngIndex++) { pwcsp[i] = noise_tab[rngIndex & 0x3FF]; } // check gain control information AtracGainInfo g1 = ctx.channels[chIndex ^ swapCh].gainData[sb]; AtracGainInfo g2 = ctx.channels[chIndex ^ swapCh].gainDataPrev[sb]; int gainLev = (g1.numPoints > 0 ? (6 - g1.levCode[0]) : 0); for (int i = 0; i < g2.numPoints; i++) { gcv = max(gcv, gainLev - (g2.levCode[i] - 6)); } for (int i = 0; i < g1.numPoints; i++) { gcv = max(gcv, 6 - g1.levCode[i]); } float grpLev = pwc_levs[ctx.channels[chIndex ^ swapCh].powerLevs[subband_to_powgrp[sb]]] / (1 << gcv); // skip the lowest two quant units (frequencies 0...351 Hz) for subband 0 for (int qu = subband_to_qu[sb] + (sb == 0 ? 2 : 0); qu < subband_to_qu[sb + 1]; qu++) { if (ctx.channels[chIndex].quWordlen[qu] <= 0) { continue; } float quLev = ff_atrac3p_sf_tab[ctx.channels[chIndex].quSfIdx[qu]] * ff_atrac3p_mant_tab[ctx.channels[chIndex].quWordlen[qu]] / (1 << ctx.channels[chIndex].quWordlen[qu]) * grpLev; int dst = ff_atrac3p_qu_to_spec_pos[qu]; int nsp = ff_atrac3p_qu_to_spec_pos[qu + 1] - ff_atrac3p_qu_to_spec_pos[qu]; for (int i = 0; i < nsp; i++) { sp[dst + i] += pwcsp[i] * quLev; } } }
public virtual void copy(AtracGainInfo from) { this.numPoints = from.numPoints; Array.Copy(from.levCode, 0, this.levCode, 0, levCode.Length); Array.Copy(from.locCode, 0, this.locCode, 0, locCode.Length); }
public virtual void gainCompensation(float[] @in, int inOffset, float[] prev, int prevOffset, AtracGainInfo gcNow, AtracGainInfo gcNext, int numSamples, float[] @out, int outOffset) { float gcScale = (gcNext.numPoints != 0 ? gainTab1[gcNext.levCode[0]] : 1f); if (gcNow.numPoints == 0) { for (int pos = 0; pos < numSamples; pos++) { @out[outOffset + pos] = @in[inOffset + pos] * gcScale + prev[prevOffset + pos]; } } else { int pos = 0; for (int i = 0; i < gcNow.numPoints; i++) { int lastpos = gcNow.locCode[i] << locScale; float lev = gainTab1[gcNow.levCode[i]]; float gainInc = gainTab2[(i + 1 < gcNow.numPoints ? gcNow.levCode[i + 1] : id2expOffset) - gcNow.levCode[i] + 15]; // apply constant gain level and overlap for (; pos < lastpos; pos++) { @out[outOffset + pos] = (@in[inOffset + pos] * gcScale + prev[prevOffset + pos]) * lev; } // interpolate between two different gain levels for (; pos < lastpos + locSize; pos++) { @out[outOffset + pos] = (@in[inOffset + pos] * gcScale + prev[prevOffset + pos]) * lev; lev *= gainInc; } } for (; pos < numSamples; pos++) { @out[outOffset + pos] = @in[inOffset + pos] * gcScale + prev[prevOffset + pos]; } } // copy the overlapping part into the delay buffer Array.Copy(@in, inOffset + numSamples, prev, prevOffset, numSamples); }