Example #1
0
/* Unified active matrix decoder for 2 channel matrix encoded surround
   sources */
static inline void matrix_decode(short *in, const int k, const int il,
			  const int ir, const int decode_rear,
			  const int dlbuflen,
			  float l_fwr, float r_fwr,
			  float lpr_fwr, float lmr_fwr,
			  float *adapt_l_gain, float *adapt_r_gain,
			  float *adapt_lpr_gain, float *adapt_lmr_gain,
			  float *lf, float *rf, float *lr,
			  float *rr, float *cf)
{
   const int kr = (k + MATREARDELAY) % dlbuflen;
   float l_gain = (l_fwr + r_fwr) /
      (1 + l_fwr + l_fwr);
   float r_gain = (l_fwr + r_fwr) /
      (1 + r_fwr + r_fwr);
   /* The 2nd axis has strong gain fluctuations, and therefore require
      limits.  The factor corresponds to the 1 / amplification of (Lt
      - Rt) when (Lt, Rt) is strongly correlated. (e.g. during
      dialogues).  It should be bigger than -12 dB to prevent
      distortion. */
   float lmr_lim_fwr = lmr_fwr > M9_03DB * lpr_fwr ?
      lmr_fwr : M9_03DB * lpr_fwr;
   float lpr_gain = (lpr_fwr + lmr_lim_fwr) /
      (1 + lpr_fwr + lpr_fwr);
   float lmr_gain = (lpr_fwr + lmr_lim_fwr) /
      (1 + lmr_lim_fwr + lmr_lim_fwr);
   float lmr_unlim_gain = (lpr_fwr + lmr_fwr) /
      (1 + lmr_fwr + lmr_fwr);
   float lpr, lmr;
   float l_agc, r_agc, lpr_agc, lmr_agc;
   float f, d_gain, c_gain, c_agc_cfk;

#if 0
   static int counter = 0;
   static FILE *fp_out;

   if(counter == 0)
      fp_out = fopen("af_hrtf.log", "w");
   if(counter % 240 == 0)
      fprintf(fp_out, "%g %g %g %g %g ", counter * (1.0 / 48000),
	      l_gain, r_gain, lpr_gain, lmr_gain);
#endif

   /*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/
   /* AGC adaption */
   d_gain = (fabs(l_gain - *adapt_l_gain) +
	     fabs(r_gain - *adapt_r_gain)) * 0.5;
   f = d_gain * (1.0 / MATAGCTRIG);
   f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
   *adapt_l_gain = (1 - f) * *adapt_l_gain + f * l_gain;
   *adapt_r_gain = (1 - f) * *adapt_r_gain + f * r_gain;
   /* Matrix */
   l_agc = in[il] * passive_lock(*adapt_l_gain);
   r_agc = in[ir] * passive_lock(*adapt_r_gain);
   cf[k] = (l_agc + r_agc) * M_SQRT1_2;
   if(decode_rear) {
      lr[kr] = rr[kr] = (l_agc - r_agc) * M_SQRT1_2;
      /* Stereo rear channel is steered with the same AGC steering as
	 the decoding matrix. Note this requires a fast updating AGC
	 at the order of 20 ms (which is the case here). */
      lr[kr] *= (l_fwr + l_fwr) /
	 (1 + l_fwr + r_fwr);
      rr[kr] *= (r_fwr + r_fwr) /
	 (1 + l_fwr + r_fwr);
   }

   /*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/
   lpr = (in[il] + in[ir]) * M_SQRT1_2;
   lmr = (in[il] - in[ir]) * M_SQRT1_2;
   /* AGC adaption */
   d_gain = fabs(lmr_unlim_gain - *adapt_lmr_gain);
   f = d_gain * (1.0 / MATAGCTRIG);
   f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
   *adapt_lpr_gain = (1 - f) * *adapt_lpr_gain + f * lpr_gain;
   *adapt_lmr_gain = (1 - f) * *adapt_lmr_gain + f * lmr_gain;
   /* Matrix */
   lpr_agc = lpr * passive_lock(*adapt_lpr_gain);
   lmr_agc = lmr * passive_lock(*adapt_lmr_gain);
   lf[k] = (lpr_agc + lmr_agc) * M_SQRT1_2;
   rf[k] = (lpr_agc - lmr_agc) * M_SQRT1_2;

   /*** CENTER FRONT CANCELLATION ***/
   /* A heuristic approach exploits that Lt + Rt gain contains the
      information about Lt, Rt correlation.  This effectively reshapes
      the front and rear "cones" to concentrate Lt + Rt to C and
      introduce Lt - Rt in L, R. */
   /* 0.67677 is the emprical lower bound for lpr_gain. */
   c_gain = 8 * (*adapt_lpr_gain - 0.67677);
   c_gain = c_gain > 0 ? c_gain : 0;
   /* c_gain should not be too high, not even reaching full
      cancellation (~ 0.50 - 0.55 at current AGC implementation), or
      the center will s0und too narrow. */
   c_gain = MATCOMPGAIN / (1 + c_gain * c_gain);
   c_agc_cfk = c_gain * cf[k];
   lf[k] -= c_agc_cfk;
   rf[k] -= c_agc_cfk;
   cf[k] += c_agc_cfk + c_agc_cfk;
#if 0
   if(counter % 240 == 0)
      fprintf(fp_out, "%g %g %g %g %g\n",
	      *adapt_l_gain, *adapt_r_gain,
	      *adapt_lpr_gain, *adapt_lmr_gain,
	      c_gain);
   counter++;
#endif
}
Example #2
0
void matrix_decode(const float *in, const int k, const int il,
                   const int ir, bool decode_rear,
                   const int _dlbuflen,
                   float _l_fwr, float _r_fwr,
                   float _lpr_fwr, float _lmr_fwr,
                   float *_adapt_l_gain, float *_adapt_r_gain,
                   float *_adapt_lpr_gain, float *_adapt_lmr_gain,
                   float *_lf, float *_rf, float *_lr,
                   float *_rr, float *_cf)
{
    static const float M9_03DB = 0.3535533906f;
    static const float MATAGCTRIG = 8.0f;   /* (Fuzzy) AGC trigger */
    static const float MATAGCDECAY = 1.0f;  /* AGC baseline decay rate (1/samp.) */
    static const float MATCOMPGAIN = 0.37f; /* Cross talk compensation gain,  0.50 - 0.55 is full cancellation. */

    const int kr = (k + olddelay) % _dlbuflen;
    float l_gain = (_l_fwr + _r_fwr) / (1 + _l_fwr + _l_fwr);
    float r_gain = (_l_fwr + _r_fwr) / (1 + _r_fwr + _r_fwr);
    // The 2nd axis has strong gain fluctuations, and therefore require
    // limits.  The factor corresponds to the 1 / amplification of (Lt
    // - Rt) when (Lt, Rt) is strongly correlated. (e.g. during
    // dialogues).  It should be bigger than -12 dB to prevent
    // distortion.
    float lmr_lim_fwr = _lmr_fwr > M9_03DB * _lpr_fwr ? _lmr_fwr : M9_03DB * _lpr_fwr;
    float lpr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + _lpr_fwr + _lpr_fwr);
    float lmr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr);
    float lmr_unlim_gain = (_lpr_fwr + _lmr_fwr) / (1 + _lmr_fwr + _lmr_fwr);
    float lpr, lmr;
    float l_agc, r_agc, lpr_agc, lmr_agc;
    float f, d_gain, c_gain, c_agc_cfk;

    /*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/
    /* AGC adaption */
    d_gain = (fabs(l_gain - *_adapt_l_gain) + fabs(r_gain - *_adapt_r_gain)) * 0.5f;
    f = d_gain * (1.0f / MATAGCTRIG);
    f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
    *_adapt_l_gain = (1 - f) * *_adapt_l_gain + f * l_gain;
    *_adapt_r_gain = (1 - f) * *_adapt_r_gain + f * r_gain;
    /* Matrix */
    l_agc = in[il] * passive_lock(*_adapt_l_gain);
    r_agc = in[ir] * passive_lock(*_adapt_r_gain);
    _cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2;
    if (decode_rear)
    {
        _lr[kr] = _rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2;
        // Stereo rear channel is steered with the same AGC steering as
        // the decoding matrix. Note this requires a fast updating AGC
        // at the order of 20 ms (which is the case here).
        _lr[kr] *= (_l_fwr + _l_fwr) / (1 + _l_fwr + _r_fwr);
        _rr[kr] *= (_r_fwr + _r_fwr) / (1 + _l_fwr + _r_fwr);
    }

    /*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/
    lpr = (in[il] + in[ir]) * (float)M_SQRT1_2;
    lmr = (in[il] - in[ir]) * (float)M_SQRT1_2;
    /* AGC adaption */
    d_gain = fabs(lmr_unlim_gain - *_adapt_lmr_gain);
    f = d_gain * (1.0f / MATAGCTRIG);
    f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
    *_adapt_lpr_gain = (1 - f) * *_adapt_lpr_gain + f * lpr_gain;
    *_adapt_lmr_gain = (1 - f) * *_adapt_lmr_gain + f * lmr_gain;
    /* Matrix */
    lpr_agc = lpr * passive_lock(*_adapt_lpr_gain);
    lmr_agc = lmr * passive_lock(*_adapt_lmr_gain);
    _lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2;
    _rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2;

    /*** CENTER FRONT CANCELLATION ***/
    // A heuristic approach exploits that Lt + Rt gain contains the
    // information about Lt, Rt correlation.  This effectively reshapes
    // the front and rear "cones" to concentrate Lt + Rt to C and
    // introduce Lt - Rt in L, R.
    /* 0.67677 is the empirical lower bound for lpr_gain. */
    c_gain = 8 * (*_adapt_lpr_gain - 0.67677f);
    c_gain = c_gain > 0 ? c_gain : 0;
    // c_gain should not be too high, not even reaching full
    // cancellation (~ 0.50 - 0.55 at current AGC implementation), or
    // the center will sound too narrow. */
    c_gain = MATCOMPGAIN / (1 + c_gain * c_gain);
    c_agc_cfk = c_gain * _cf[k];
    _lf[k] -= c_agc_cfk;
    _rf[k] -= c_agc_cfk;
    _cf[k] += c_agc_cfk + c_agc_cfk;
}