changeset 15082:71570687c1a3

HRTF filter updates: - Bass compensation gain corrected (which was set too low), now the sound should be even more transparent - A (unified) dual axes active matrix decoder with adaptive steering - capable of decoding matrix surround encoded inputs, with stereo rear - capable of decoding matrix encoded rear center - Purely stereo mixing without unneccessary rear filter calculations - The decoding structure message is moved, because at the old place it gave incorrect messages. Patch by Yue Shi Lai <ylai@users.sourceforge.net>
author henry
date Sun, 10 Apr 2005 08:47:16 +0000
parents 2e628bcd6dd5
children c73c1ea04d9c
files libaf/af_hrtf.c libaf/af_hrtf.h
diffstat 2 files changed, 316 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/libaf/af_hrtf.c	Sat Apr 09 23:20:49 2005 +0000
+++ b/libaf/af_hrtf.c	Sun Apr 10 08:47:16 2005 +0000
@@ -28,11 +28,29 @@
     float *ba_ir;
     /* Whether to matrix decode the rear center channel */
     int matrix_mode;
-    /* Full wave rectified amplitude used to steer the active matrix
-       decoding of center rear channel */
-    float lr_fwr, rr_fwr;
+    /* How to decode the input:
+       0 = 5/5+1 channels
+       1 = 2 channels
+       2 = matrix encoded 2 channels */
+    int decode_mode;
+    /* Full wave rectified (FWR) amplitudes and gain used to steer the
+       active matrix decoding of front channels (variable names
+       lpr/lmr means Lt + Rt, Lt - Rt) */
+    float l_fwr, r_fwr, lpr_fwr, lmr_fwr;
+    float adapt_l_gain, adapt_r_gain, adapt_lpr_gain, adapt_lmr_gain;
+    /* Matrix input decoding require special FWR buffer, since the
+       decoding is done in place. */
+    float *fwrbuf_l, *fwrbuf_r, *fwrbuf_lr, *fwrbuf_rr;
+    /* Rear channel delay buffer for matrix decoding */
+    float *rear_dlbuf;
+    /* Full wave rectified amplitude and gain used to steer the active
+       matrix decoding of center rear channel */
+    float lr_fwr, rr_fwr, lrprr_fwr, lrmrr_fwr;
+    float adapt_lr_gain, adapt_rr_gain;
+    float adapt_lrprr_gain, adapt_lrmrr_gain;
     /* Cyclic position on the ring buffer */
     int cyc_pos;
+    int print_flag;
 } af_hrtf_t;
 
 /* Convolution on a ring buffer
@@ -70,34 +88,151 @@
     return 0;
 }
 
+/* Unified active matrix decoder for 2 channel matrix encoded surround
+   sources */
+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);
+   float lpr_gain = (lpr_fwr + lmr_fwr) /
+      (1 + lpr_fwr + lpr_fwr);
+   float lmr_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;
+
+#if 0
+   static int counter = 0;
+   static FILE *fp_out;
+
+   if(counter == 0)
+      fp_out = fopen("af_hrtf.log", "w");
+   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] * *adapt_l_gain;
+   r_agc = in[ir] * *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(lpr_gain - *adapt_lpr_gain) +
+	     fabs(lmr_gain - *adapt_lmr_gain)) * 0.5;
+   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;
+   /* The 2nd axis has strong gain fluctuations, and therefore require
+      limits.  The factor is tricky.  I think 2 is the reasonable
+      value here, which phase inverts the L, R channel if Lt, Rt is
+      strongly correlated (e.g. during dialogues) (1 would inhibit the
+      steering behavior, > 4 appears to result in distortions). */
+   if(*adapt_lmr_gain > 2 * *adapt_lpr_gain)
+      *adapt_lmr_gain = 2 * *adapt_lpr_gain;
+   /* Matrix */
+   lpr_agc = lpr * *adapt_lpr_gain;
+   lmr_agc = lmr * *adapt_lmr_gain;
+   lf[k] = (lpr_agc + lmr_agc) * M_SQRT1_2;
+   rf[k] = (lpr_agc - lmr_agc) * M_SQRT1_2;
+
+#if 0
+   fprintf(fp_out, "%g %g %g %g\n",
+	   *adapt_l_gain, *adapt_r_gain,
+	   *adapt_lpr_gain, *adapt_lmr_gain);
+   counter++;
+#endif
+}
+
 inline void update_ch(af_hrtf_t *s, short *in, const int k)
 {
-    /* Update the full wave rectified total amplutude */
-    s->lr_fwr += abs(in[2]) - fabs(s->lr[k]);
-    s->rr_fwr += abs(in[3]) - fabs(s->rr[k]);
+    const int fwr_pos = (k + FWRDURATION) % s->dlbuflen;
+    /* Update the full wave rectified total amplitude */
+    /* Input matrix decoder */
+    if(s->decode_mode == HRTF_MIX_MATRIX2CH) {
+       s->l_fwr += abs(in[0]) - fabs(s->fwrbuf_l[fwr_pos]);
+       s->r_fwr += abs(in[1]) - fabs(s->fwrbuf_r[fwr_pos]);
+       s->lpr_fwr += abs(in[0] + in[1]) -
+	  fabs(s->fwrbuf_l[fwr_pos] + s->fwrbuf_r[fwr_pos]);
+       s->lmr_fwr += abs(in[0] - in[1]) -
+	  fabs(s->fwrbuf_l[fwr_pos] - s->fwrbuf_r[fwr_pos]);
+    }
+    /* Rear matrix decoder */
+    if(s->matrix_mode) {
+       s->lr_fwr += abs(in[2]) - fabs(s->fwrbuf_lr[fwr_pos]);
+       s->rr_fwr += abs(in[3]) - fabs(s->fwrbuf_rr[fwr_pos]);
+       s->lrprr_fwr += abs(in[2] + in[3]) -
+	  fabs(s->fwrbuf_lr[fwr_pos] + s->fwrbuf_rr[fwr_pos]);
+       s->lrmrr_fwr += abs(in[2] - in[3]) -
+	  fabs(s->fwrbuf_lr[fwr_pos] - s->fwrbuf_rr[fwr_pos]);
+    }
 
-    s->lf[k] = in[0];
-    s->cf[k] = in[4];
-    s->rf[k] = in[1];
-    s->lr[k] = in[2];
-    s->rr[k] = in[3];
+    switch (s->decode_mode) {
+    case HRTF_MIX_51:
+       /* 5/5+1 channel sources */
+       s->lf[k] = in[0];
+       s->cf[k] = in[4];
+       s->rf[k] = in[1];
+       s->fwrbuf_lr[k] = s->lr[k] = in[2];
+       s->fwrbuf_rr[k] = s->rr[k] = in[3];
+       break;
+    case HRTF_MIX_MATRIX2CH:
+       /* Matrix encoded 2 channel sources */
+       s->fwrbuf_l[k] = in[0];
+       s->fwrbuf_r[k] = in[1];
+       matrix_decode(in, k, 0, 1, 1, s->dlbuflen,
+		     s->l_fwr, s->r_fwr,
+		     s->lpr_fwr, s->lmr_fwr,
+		     &(s->adapt_l_gain), &(s->adapt_r_gain),
+		     &(s->adapt_lpr_gain), &(s->adapt_lmr_gain),
+		     s->lf, s->rf, s->lr, s->rr, s->cf);
+       break;
+    case HRTF_MIX_STEREO:
+       /* Stereo sources */
+       s->lf[k] = in[0];
+       s->rf[k] = in[1];
+       s->cf[k] = s->lr[k] = s->rr[k] = 0;
+       break;
+    }
 
+    /* We need to update the bass compensation delay line, too. */
     s->ba_l[k] = in[0] + in[4] + in[2];
     s->ba_r[k] = in[4] + in[1] + in[3];
 }
 
-inline void matrix_decode_cr(af_hrtf_t *s, short *in, const int k)
-{
-    /* Active matrix decoding of the center rear channel, 1 in the
-       denominator is to prevent singularity */
-    float lr_agc = in[2] * (s->lr_fwr + s->rr_fwr) /
-	(1 + s->lr_fwr + s->lr_fwr);
-    float rr_agc = in[3] * (s->lr_fwr + s->rr_fwr) /
-	(1 + s->rr_fwr + s->rr_fwr);
-
-    s->cr[k] = (lr_agc + rr_agc) * M_SQRT1_2;
-}
-
 /* Initialization and runtime control */
 static int control(struct af_instance_s *af, int cmd, void* arg)
 {
@@ -118,36 +253,42 @@
 	af->data->nch    = ((af_data_t*)arg)->nch;
 	if(af->data->nch < 5) {
 	    af->data->nch = 5;
+	    if(af->data->nch == 2) {
+ 	       /* 2 channel input */
+ 	       if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
+   		  /* Default behavior is stereo mixing. */
+ 		  s->decode_mode = HRTF_MIX_STEREO;
+	       }
+	    }
 	}
 	af->data->format = AF_FORMAT_S16_NE;
 	af->data->bps    = 2;
+	s->print_flag = 1;
 	return af_test_output(af, (af_data_t*)arg);
     case AF_CONTROL_COMMAND_LINE:
 	sscanf((char*)arg, "%c", &mode);
 	switch(mode) {
 	case 'm':
+	    /* Use matrix rear decoding. */
 	    s->matrix_mode = 1;
 	    break;
+	case 's':
+	    /* Input needs matrix decoding. */
+	    s->decode_mode = HRTF_MIX_MATRIX2CH;
+	    break;
 	case '0':
 	    s->matrix_mode = 0;
 	    break;
 	default:
 	    af_msg(AF_MSG_ERROR,
-		   "[hrtf] Mode is neither 'm', nor '0' (%c).\n",
+		   "[hrtf] Mode is neither 'm', 's', nor '0' (%c).\n",
 		   mode);
 	    return AF_ERROR;
 	}
+	s->print_flag = 1;
 	return AF_OK;
     }    
 
-    af_msg(AF_MSG_INFO,
-	   "[hrtf] Using HRTF to mix %s discrete surround into "
-	   "L, R channels\n", s->matrix_mode ? "5" : "5+1");
-    if(s->matrix_mode)
-	af_msg(AF_MSG_INFO,
-	       "[hrtf] Using active matrix to decode rear center "
-	       "channel\n");
-
     return AF_UNKNOWN;
 }
 
@@ -175,6 +316,14 @@
 	    free(s->ba_r);
 	if(s->ba_ir)
 	    free(s->ba_ir);
+	if(s->fwrbuf_l)
+	   free(s->fwrbuf_l);
+	if(s->fwrbuf_r)
+	   free(s->fwrbuf_r);
+	if(s->fwrbuf_lr)
+	   free(s->fwrbuf_lr);
+	if(s->fwrbuf_rr)
+	   free(s->fwrbuf_rr);
 	free(af->setup);
     }
     if(af->data)
@@ -204,6 +353,37 @@
     if(AF_OK != RESIZE_LOCAL_BUFFER(af, data))
 	return NULL;
 
+    if(s->print_flag) {
+	s->print_flag = 0;
+	switch (s->decode_mode) {
+	case HRTF_MIX_51:
+	  af_msg(AF_MSG_INFO,
+		 "[hrtf] Using HRTF to mix %s discrete surround into "
+		 "L, R channels\n", s->matrix_mode ? "5+1" : "5");
+	  break;
+	case HRTF_MIX_STEREO:
+	  af_msg(AF_MSG_INFO,
+		 "[hrtf] Using HRTF to mix stereo into "
+		 "L, R channels\n");
+	  break;
+	case HRTF_MIX_MATRIX2CH:
+	  af_msg(AF_MSG_INFO,
+		 "[hrtf] Using active matrix to decode 2 channel "
+		 "input, HRTF to mix %s matrix surround into "
+		 "L, R channels\n", "3/2");
+	  break;
+	default:
+	  af_msg(AF_MSG_WARN,
+		 "[hrtf] bogus decode_mode: %d\n", s->decode_mode);
+	  break;
+	}
+	
+       if(s->matrix_mode)
+	  af_msg(AF_MSG_INFO,
+		 "[hrtf] Using active matrix to decode rear center "
+		 "channel\n");
+    }
+
     out = af->data->audio;
 
     /* MPlayer's 5 channel layout (notation for the variable):
@@ -236,48 +416,71 @@
 	s->lf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
 	s->rf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
 
-	/* Mixer filter matrix */
-	common = conv(dblen, hlen, s->cf, s->cf_ir, k + s->cf_o);
-	if(s->matrix_mode) {
-	    /* In matrix decoding mode, the rear channel gain must be
-	       renormalized, as there is an additional channel. */
-	    matrix_decode_cr(s, in, k);
-	    common +=
-		conv(dblen, hlen, s->cr, s->cr_ir, k + s->cr_o) *
-		M1_76DB;
-	    left    =
-		( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
-		  conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
-		  (conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
-		   conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o)) *
-		  M1_76DB + common);
-	    right   =
-		( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
-		  conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
-		  (conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
-		   conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o)) *
-		  M1_76DB + common);
-	}
-	else {
-	    left    =
-		( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
-		  conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
-		  conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
-		  conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o) +
-		  common);
-	    right   =
-		( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
-		  conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
-		  conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
-		  conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o) +
-		  common);
+	switch (s->decode_mode) {
+	case HRTF_MIX_51:
+	case HRTF_MIX_MATRIX2CH:
+	   /* Mixer filter matrix */
+	   common = conv(dblen, hlen, s->cf, s->cf_ir, k + s->cf_o);
+	   if(s->matrix_mode) {
+	      /* In matrix decoding mode, the rear channel gain must be
+		 renormalized, as there is an additional channel. */
+	      matrix_decode(in, k, 2, 3, 0, s->dlbuflen,
+			    s->lr_fwr, s->rr_fwr,
+			    s->lrprr_fwr, s->lrmrr_fwr,
+			    &(s->adapt_lr_gain), &(s->adapt_rr_gain),
+			    &(s->adapt_lrprr_gain), &(s->adapt_lrmrr_gain),
+			    s->lr, s->rr, NULL, NULL, s->cr);
+	      common +=
+		 conv(dblen, hlen, s->cr, s->cr_ir, k + s->cr_o) *
+		 M1_76DB;
+	      left    =
+		 ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
+		   conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
+		   (conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
+		    conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o)) *
+		   M1_76DB + common);
+	      right   =
+		 ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
+		   conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
+		   (conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
+		    conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o)) *
+		   M1_76DB + common);
+	   } else {
+	      left    =
+		 ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
+		   conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
+		   conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
+		   conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o) +
+		   common);
+	      right   =
+		 ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
+		   conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
+		   conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
+		   conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o) +
+		   common);
+	   }
+	   break;
+	case HRTF_MIX_STEREO:
+	   left    =
+	      ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
+		conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o));
+	   right   =
+	      ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
+		conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o));
+	   break;
+	default:
+	    /* make gcc happy */
+	    left = 0.0;
+	    right = 0.0;
+	    break;
 	}
 
 	/* Bass compensation for the lower frequency cut of the HRTF.  A
 	   cross talk of the left and right channel is introduced to
 	   match the directional characteristics of higher frequencies.
 	   The bass will not have any real 3D perception, but that is
-	   OK. */
+	   OK (note at 180 Hz, the wavelength is about 2 m, and any
+	   spatial perception is impossible). */
 	left_b  = conv(dblen, blen, s->ba_l, s->ba_ir, k);
 	right_b = conv(dblen, blen, s->ba_r, s->ba_ir, k);
 	left  += (1 - BASSCROSS) * left_b  + BASSCROSS * right_b;
@@ -292,12 +495,25 @@
 	left  *= AMPLNORM;
 	right *= AMPLNORM;
 
-	/* "Cheating": linear stereo expansion to amplify the 3D
-	   perception.  Note: Too much will destroy the acoustic space
-	   and may even result in headaches. */
-	diff = STEXPAND2 * (left - right);
-	out[0] = (int16_t)(left  + diff);
-	out[1] = (int16_t)(right - diff);
+	switch (s->decode_mode) {
+	case HRTF_MIX_51:
+	case HRTF_MIX_STEREO:
+	   /* "Cheating": linear stereo expansion to amplify the 3D
+	      perception.  Note: Too much will destroy the acoustic space
+	      and may even result in headaches. */
+	   diff = STEXPAND2 * (left - right);
+	   out[0] = (int16_t)(left  + diff);
+	   out[1] = (int16_t)(right - diff);
+	   break;
+	case HRTF_MIX_MATRIX2CH:
+	   /* Do attempt any stereo expansion with matrix encoded
+	      sources.  The L, R channels are already stereo expanded
+	      by the steering, any further stereo expansion will sound
+	      very unnatural. */
+	   out[0] = (int16_t)left;
+	   out[1] = (int16_t)right;
+	   break;
+	}
 
 	/* The remaining channels are not needed any more */
 	out[2] = out[3] = out[4] = 0;
@@ -330,6 +546,14 @@
     if ((s->cr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
     if ((s->ba_l = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
     if ((s->ba_r = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+    if ((s->fwrbuf_l =
+	 malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+    if ((s->fwrbuf_r =
+	 malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+    if ((s->fwrbuf_lr =
+	 malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
+    if ((s->fwrbuf_rr =
+	 malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
     return 0;
 }
 
@@ -357,7 +581,13 @@
     s->basslen = BASSFILTLEN;
 
     s->cyc_pos = s->dlbuflen - 1;
-    s->matrix_mode = 1;
+    /* With a full (two axis) steering matrix decoder, s->matrix_mode
+       should not be enabled lightly (it will also steer the Ls, Rs
+       channels). */
+    s->matrix_mode = 0;
+    s->decode_mode = HRTF_MIX_51;
+
+    s->print_flag = 1;
 
     if (allocate(s) != 0) {
  	af_msg(AF_MSG_ERROR, "[hrtf] Memory allocation error.\n");
--- a/libaf/af_hrtf.h	Sat Apr 09 23:20:49 2005 +0000
+++ b/libaf/af_hrtf.h	Sun Apr 10 08:47:16 2005 +0000
@@ -1,3 +1,7 @@
+#define HRTF_MIX_51 0
+#define HRTF_MIX_STEREO 1
+#define HRTF_MIX_MATRIX2CH 2
+
 /* Amplitude scaling factors */
 #define M17_0DB		0.1414213562
 #define M6_99DB		0.4472135955
@@ -13,9 +17,15 @@
 
 #define BASSFILTFREQ	180	/* Bass compensation filter cut (Hz) */
 #define BASSFILTLEN	193	/* Bass compensation filter length */
-#define BASSGAIN	M4_77DB	/* Bass compensation gain */
+#define BASSGAIN	M_SQRT2	/* Bass compensation gain */
 #define BASSCROSS	0.35	/* Bass cross talk */
 
+#define FWRDURATION	240	/* FWR average duration (samples) */
+#define MATREARDELAY	720	/* Matrix mode rear delay (samples) */
+
+#define MATAGCTRIG	8.0	/* (Fuzzy) AGC trigger */
+#define MATAGCDECAY	1.0	/* AGC baseline decay rate (1/samp.) */
+
 #define CFECHODELAY	360	/* Center front echo delay (samples) */
 #define CFECHOAMPL	M17_0DB	/* Center front echo amplitude */