예제 #1
0
  public envelope_lookup(vorbis_info _vi) {

    ch = _vi.channels;
    winlength = 128;
    searchstep = 64; // not random
    minenergy = _vi.codec_setup.psy_g_param.preecho_minenergy;

    int n = winlength;

    storage = 128;
    cursor = _vi.codec_setup.blocksizes[1] / 2;

    // mdct_win = _ogg_calloc(n,sizeof(*mdct_win));
    mdct_win = new float[n];
    mdct = new mdct_lookup();
    mdct.mdct_init(n);

    for (int i = 0; i < n; i++) {
      mdct_win[i] = new Double(Math.sin(i / (n - 1.) * M_PI)).floatValue();
      mdct_win[i] *= mdct_win[i];
    }

    band = new envelope_band[VE_BANDS];

    for (int i = 0; i < VE_BANDS; i++) band[i] = new envelope_band();

    band[0].begin = 2;
    band[0].end = 4;
    band[1].begin = 4;
    band[1].end = 5;
    band[2].begin = 6;
    band[2].end = 6;
    band[3].begin = 9;
    band[3].end = 8;
    band[4].begin = 13;
    band[4].end = 8;
    band[5].begin = 17;
    band[5].end = 8;
    band[6].begin = 22;
    band[6].end = 8;

    for (int j = 0; j < VE_BANDS; j++) {

      n = band[j].end;

      // band[j].window = _ogg_malloc(n*sizeof(*band[0].window));
      band[j].window = new float[n];

      for (int i = 0; i < n; i++) {
        band[j].window[i] = new Double(Math.sin((i + .5) / n * M_PI)).floatValue();
        band[j].total += band[j].window[i];
      }
      band[j].total = 1.0f / band[j].total;
    }

    // filter=_ogg_calloc(VE_BANDS*ch,sizeof(*filter));
    // mark=_ogg_calloc(storage,sizeof(*mark));

    filter = new envelope_filter_state[VE_BANDS * ch];
    for (int i = 0; i < VE_BANDS * ch; i++) filter[i] = new envelope_filter_state();

    mark = new int[storage];
  }
예제 #2
0
  public int _ve_amp(
      vorbis_info_psy_global gi,
      float[] data,
      int offset1,
      envelope_band[] bands,
      envelope_filter_state[] filters,
      int offset2,
      int pos) {

    int n = winlength;
    int ret = 0;
    int i, j;
    float decay;

    /* we want to have a 'minimum bar' for energy, else we're just
     * basing blocks on quantization noise that outweighs the signal
     * itself (for low power signals) */

    float minV = minenergy;
    // float *vec=alloca(n*sizeof(*vec));
    float[] vec = new float[n];

    /* stretch is used to gradually lengthen the number of windows
     * considered prevoius-to-potential-trigger */
    // local OOP variable rename stretch
    int stretch_local = Math.max(VE_MINSTRETCH, stretch / 2);
    float penalty = gi.stretch_penalty - (stretch / 2 - VE_MINSTRETCH);
    if (penalty < 0.f) penalty = 0.f;
    if (penalty > gi.stretch_penalty) penalty = gi.stretch_penalty;

    /*_analysis_output_always("lpcm",seq2,data,n,0,0,totalshift+pos*ve->searchstep);*/

    // window and transform
    for (i = 0; i < n; i++) vec[i] = data[offset1 + i] * mdct_win[i];

    mdct.mdct_forward(vec, vec);
    //		mdct.out( "", null );

    /*_analysis_output_always("mdct",seq2,vec,n/2,0,1,0); */

    /* near-DC spreading function; this has nothing to do with
     * psychoacoustics, just sidelobe leakage and window size */
    float temp = vec[0] * vec[0] + .7f * vec[1] * vec[1] + .2f * vec[2] * vec[2];
    int ptr = filters[offset2].nearptr;

    // the accumulation is regularly refreshed from scratch to avoid floating point creep
    if (ptr == 0) {
      decay = filters[offset2].nearDC_acc = filters[offset2].nearDC_partialacc + temp;
      filters[offset2].nearDC_partialacc = temp;
    } else {
      decay = filters[offset2].nearDC_acc += temp;
      filters[offset2].nearDC_partialacc += temp;
    }
    filters[offset2].nearDC_acc -= filters[offset2].nearDC[ptr];
    filters[offset2].nearDC[ptr] = temp;

    decay *= (1. / (VE_NEARDC + 1));
    filters[offset2].nearptr++;
    if (filters[offset2].nearptr >= VE_NEARDC) filters[offset2].nearptr = 0;
    decay = todB(decay) * .5f - 15.f;

    /* perform spreading and limiting, also smooth the spectrum.  yes, the MDCT results
     * in all real coefficients, but it still *behaves* like real/imaginary pairs */
    for (i = 0; i < n / 2; i += 2) {
      float val = vec[i] * vec[i] + vec[i + 1] * vec[i + 1];
      val = todB(val) * .5f;
      if (val < decay) val = decay;
      if (val < minV) val = minV;
      vec[i >> 1] = val;
      decay -= 8.;
    }

    /*_analysis_output_always("spread",seq2++,vec,n/4,0,0,0);*/

    // perform preecho/postecho triggering by band
    for (j = 0; j < VE_BANDS; j++) {

      float acc = 0.f;
      float valmax;
      float valmin;

      // accumulate amplitude
      for (i = 0; i < bands[j].end; i++) acc += vec[i + bands[j].begin] * bands[j].window[i];

      acc *= bands[j].total;

      // convert amplitude to delta

      // local OOP variable rename
      // protected variable name this
      int p, _this = filters[offset2 + j].ampptr;
      float postmax, postmin, premax = -99999.f, premin = 99999.f;

      p = _this;
      p--;
      if (p < 0) p += VE_AMP;
      postmax = Math.max(acc, filters[offset2 + j].ampbuf[p]);
      postmin = Math.min(acc, filters[offset2 + j].ampbuf[p]);

      for (i = 0; i < stretch_local; i++) {

        p--;
        if (p < 0) p += VE_AMP;
        premax = Math.max(premax, filters[offset2 + j].ampbuf[p]);
        premin = Math.min(premin, filters[offset2 + j].ampbuf[p]);
      }

      valmin = postmin - premin;
      valmax = postmax - premax;

      /*filters[j].markers[pos]=valmax;*/
      filters[offset2 + j].ampbuf[_this] = acc;
      filters[offset2 + j].ampptr++;
      if (filters[offset2 + j].ampptr >= VE_AMP) filters[offset2 + j].ampptr = 0;

      // look at min/max, decide trigger
      if (valmax > gi.preecho_thresh[j] + penalty) {
        ret |= 1;
        ret |= 4;
      }
      if (valmin < gi.postecho_thresh[j] - penalty) ret |= 2;
    }

    return ret;
  }