⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mdf.c

📁 频域回声抵消其算法
💻 C
📖 第 1 页 / 共 2 页
字号:
{
   if (st->play_buf_pos<=st->frame_size)
   {
      int i;
      for (i=0;i<st->frame_size;i++)
         st->play_buf[st->play_buf_pos+i] = play[i];
      st->play_buf_pos += st->frame_size;
   } else {
      speex_warning("had to discard a playback frame");
   }
}

/** Performs echo cancellation on a frame */
void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_t *echo, spx_int16_t *out, spx_int32_t *Yout)
{
   int i,j;
   int N,M;
   FILE *filein,*fileout,*file;
   spx_word32_t Syy,See,Sxx,www;
   spx_word32_t Sey;
   spx_word16_t leak_estimate,cd;
   spx_word16_t ss, ss_1;
   spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE;
   spx_float_t alpha, alpha_1;
   spx_word16_t RER;
   spx_word32_t tmp32;
   
   N = st->window_size;
   M = st->M;
   st->cancel_count++;
#ifdef FIXED_POINT
   ss=DIV32_16(11469,M);
   ss_1 = SUB16(32767,ss);
#else
   ss=.35/M;
   ss_1 = 1-ss;
#endif
   filter_dc_notch16(ref, st->notch_radius, st->d, st->frame_size, st->notch_mem);
/*	for(i=0;i<80;i++)
	{
		st->d[i] = ref[i];
	}
*/
   /* Copy input data to buffer */
   for (i=0;i<st->frame_size;i++)
   {
      spx_word16_t tmp;
      spx_word32_t tmp32;
      st->x[i] = st->x[i+st->frame_size];
      tmp32 = SUB32(EXTEND32(echo[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX)));
#ifdef FIXED_POINT
      /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */
      if (tmp32 > 32767)
      {
         tmp32 = 32767;
         st->saturated = 1;
      }      
      if (tmp32 < -32767)
      {
         tmp32 = -32767;
         st->saturated = 1;
      }      
#endif
      st->x[i+st->frame_size] = EXTRACT16(tmp32);
      st->memX = echo[i];
      
      tmp = st->d[i];
      st->d[i] = st->d[i+st->frame_size];
      tmp32 = SUB32(EXTEND32(tmp), EXTEND32(MULT16_16_P15(st->preemph, st->memD)));
#ifdef FIXED_POINT
      if (tmp32 > 32767)
      {
         tmp32 = 32767;
         st->saturated = 1;
      }      
      if (tmp32 < -32767)
      {
         tmp32 = -32767;
         st->saturated = 1;
      }
#endif
      st->d[i+st->frame_size] = tmp32;
      st->memD = tmp;
   }

   /* Shift memory: this could be optimized eventually*/
   for (j=M-1;j>=0;j--)
   {
      for (i=0;i<N;i++)
         st->X[(j+1)*N+i] = st->X[j*N+i];
   }
/*	
   fileout=fopen("xout_temp.dat","wb+");
   filein=fopen("xin_temp.dat","wb+");
   file=fopen("xin_2.dat","w+");

   fwrite(st->x,sizeof(int),256,file);

	 for(i=0;i<256;i++)
	{	
		fprintf(filein,"%d\n",(int)(st->x[i]));
	}
*/
   /* Convert x (echo input) to frequency domain */
   spx_fft(st->fft_table, st->x, &st->X[0]);
/*  
   for(i=0;i<256;i++)
	{	
		fprintf(fileout,"%d\n",(int)(st->X[i]*160));
	}
		fclose(filein);
		fclose(fileout);
		fclose(file);
*/
#ifdef SMOOTH_BLOCKS
   spectral_mul_accum(st->X, st->W, st->Y, N, M);   
   spx_ifft(st->fft_table, st->Y, st->e);
#endif

   /* Compute weight gradient */
  if (!st->saturated)
   {
      for (j=M-1;j>=0;j--)
      {
         weighted_spectral_mul_conj(st->power_1, &st->X[(j+1)*N], st->E, st->PHI, N);
         for (i=0;i<N;i++)
            {
            	www = MULT16_32_Q15(st->prop[j], st->PHI[i]);
            	www >>= 8;
            	st->W[j*N+i] += www;
//            	st->W[j*N+i] += MULT16_32_Q15(st->prop[j], st->PHI[i]);
            }
         
      }   
   }
   
   st->saturated = 0;
   
   /* Update weight to prevent circular convolution (MDF / AUMDF) */
   for (j=0;j<M;j++)
   {
      /* This is a variant of the Alternatively Updated MDF (AUMDF) */
      /* Remove the "if" to make this an MDF filter */
      if (j==0 || st->cancel_count%(M-1) == j-1)
      {
#ifdef FIXED_POINT
         for (i=0;i<N;i++)
            st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+8));
         spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
         for (i=0;i<st->frame_size;i++)
         {
            st->wtmp[i]=0;
         }
         for (i=st->frame_size;i<N;i++)
         {
            st->wtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP);
         }
         spx_fft(st->fft_table, st->wtmp, st->wtmp2);
         /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
         for (i=0;i<N;i++)
            st->W[j*N+i] -= SHL32(EXTEND32(st->wtmp2[i]),8+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
#else
         spx_ifft(st->fft_table, &st->W[j*N], st->wtmp);
         for (i=st->frame_size;i<N;i++)
         {
            st->wtmp[i]=0;
         }
         spx_fft(st->fft_table, st->wtmp, &st->W[j*N]);
#endif
      }
   }

   /* Compute filter response Y */
   spectral_mul_accum(st->X, st->W, st->Y, N, M);
   spx_ifft(st->fft_table, st->Y, st->y);

   
   /* Compute error signal (for the output with de-emphasis) */ 
   for (i=0;i<st->frame_size;i++)
   {
      spx_word32_t tmp_out;
#ifdef SMOOTH_BLOCKS
      spx_word16_t y = MULT16_16_Q15(st->window[i+st->frame_size],st->e[i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[i+st->frame_size]);
      tmp_out = SUB32(EXTEND32(st->d[i+st->frame_size]), EXTEND32(y));
//	  out[i] = st->Y[i];
#else
      tmp_out = SUB32(EXTEND32(st->d[i+st->frame_size]), EXTEND32(st->y[i+st->frame_size]));
#endif

      /* Saturation */
      	  if (tmp_out>32767)
         tmp_out = 32767;
      else if (tmp_out<-32767)
         tmp_out = -32767;

      tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE)));

	 if (tmp_out>32767)
         tmp_out = 32767;
      else if (tmp_out<-32767)
         tmp_out = -32767;


      /* This is an arbitrary test for saturation */
      if (ref[i] <= -32000 || ref[i] >= 32000)
      {
         tmp_out = 0;
         st->saturated = 1;
      }
      out[i] = (spx_int16_t)tmp_out;
      st->memE = tmp_out;
	  
//	  out[i] = ref[i]>>2;
   }
   /* Compute error signal (filter update version) */ 
   for (i=0;i<st->frame_size;i++)
   {

	   spx_word32_t tmp_out;
      st->e[i] = 0;
tmp_out = st->d[i+st->frame_size] - st->y[i+st->frame_size];
	  if (tmp_out>32767)
		  tmp_out = 32767;
	  else if (tmp_out<-32767)
		  tmp_out = -32767;
	  st->e[i+st->frame_size] = tmp_out;



  //    st->e[i+st->frame_size] = st->d[i+st->frame_size] - st->y[i+st->frame_size];
   }

   /* Compute a bunch of correlations */
   Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size);
   See = mdf_inner_prod(st->e+st->frame_size, st->e+st->frame_size, st->frame_size);
   See = ADD32(See, SHR32(MULT16_16(N, 100),6));
   Syy = mdf_inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size);
   Sxx = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);

   /* Convert error to frequency domain */
   spx_fft(st->fft_table, st->e, st->E);
   for (i=0;i<st->frame_size;i++)
      st->y[i] = 0;
   spx_fft(st->fft_table, st->y, st->Y);

   /* Compute power spectrum of echo (X), error (E) and filter response (Y) */
   power_spectrum(st->E, st->Rf, N);
   power_spectrum(st->Y, st->Yf, N);
   power_spectrum(st->X, st->Xf, N);
   
   /* Smooth echo energy estimate over time */
   for (j=0;j<=st->frame_size;j++)
      st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]);
   
   /* Enable this to compute the power based only on the tail (would need to compute more 
      efficiently to make this really useful */
   if (0)
   {
      float scale2 = .5f/M;
      for (j=0;j<=st->frame_size;j++)
         st->power[j] = 100;
      for (i=0;i<M;i++)
      {
         power_spectrum(&st->X[i*N], st->Xf, N);
         for (j=0;j<=st->frame_size;j++)
            st->power[j] += scale2*st->Xf[j];
      }
   }

   /* Compute filtered spectra and (cross-)correlations */
   for (j=st->frame_size;j>=0;j--)
   {
      spx_float_t Eh, Yh;
      Eh = PSEUDOFLOAT(st->Rf[j] - st->Eh[j]);
      Yh = PSEUDOFLOAT(st->Yf[j] - st->Yh[j]);
      Pey = FLOAT_ADD(Pey,FLOAT_MULT(Eh,Yh));
      Pyy = FLOAT_ADD(Pyy,FLOAT_MULT(Yh,Yh));
#ifdef FIXED_POINT
      st->Eh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Eh[j]), st->spec_average, st->Rf[j]);
      st->Yh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Yh[j]), st->spec_average, st->Yf[j]);
#else
      st->Eh[j] = (1-st->spec_average)*st->Eh[j] + st->spec_average*st->Rf[j];
      st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j];
#endif
   }
   
   Pyy = FLOAT_SQRT(Pyy);
   Pey = FLOAT_DIVU(Pey,Pyy);

   /* Compute correlation updatete rate */
   tmp32 = MULT16_32_Q15(st->beta0,Syy);
   if (tmp32 > MULT16_32_Q15(st->beta_max,See))
      tmp32 = MULT16_32_Q15(st->beta_max,See);
   alpha = FLOAT_DIV32(tmp32, See);
   alpha_1 = FLOAT_SUB(FLOAT_ONE, alpha);
   /* Update correlations (recursive average) */
   st->Pey = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pey) , FLOAT_MULT(alpha,Pey));
   st->Pyy = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pyy) , FLOAT_MULT(alpha,Pyy));
   if (FLOAT_LT(st->Pyy, FLOAT_ONE))
      st->Pyy = FLOAT_ONE;
   /* We don't really hope to get better than 33 dB (MIN_LEAK-3dB) attenuation anyway */
   if (FLOAT_LT(st->Pey, FLOAT_MULT(MIN_LEAK,st->Pyy)))
      st->Pey = FLOAT_MULT(MIN_LEAK,st->Pyy);
   if (FLOAT_GT(st->Pey, st->Pyy))
      st->Pey = st->Pyy;
   /* leak_estimate is the linear regression result */
   leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14));
   /* This looks like a stupid bug, but it's right (because we convert from Q14 to Q15) */
   if (leak_estimate > 16383)
      leak_estimate = 32767;
   else
      leak_estimate = SHL16(leak_estimate,1);
   /*printf ("%f\n", leak_estimate);*/
   
   /* Compute Residual to Error Ratio */
#ifdef FIXED_POINT
   tmp32 = MULT16_32_Q15(leak_estimate,Syy);
   tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1)));
   /* Check for y in e (lower bound on RER) */
   {
      spx_float_t bound = PSEUDOFLOAT(Sey);
      bound = FLOAT_DIVU(FLOAT_MULT(bound, bound), PSEUDOFLOAT(ADD32(1,Syy)));
      if (FLOAT_GT(bound, PSEUDOFLOAT(See)))
         tmp32 = See;
      else if (tmp32 < FLOAT_EXTRACT32(bound))
         tmp32 = FLOAT_EXTRACT32(bound);
   }
   if (tmp32 > SHR32(See,1))
      tmp32 = SHR32(See,1);
   RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15));
#else
   RER = (.0001*Sxx + 3.*MULT16_32_Q15(leak_estimate,Syy)) / See;
   /* Check for y in e (lower bound on RER) */
   if (RER < Sey*Sey/(1+See*Syy))
      RER = Sey*Sey/(1+See*Syy);
   if (RER > .5)
      RER = .5;
#endif

   /* We consider that the filter has had minimal adaptation if the following is true*/
   if (!st->adapted && st->sum_adapt > QCONST32(1,15))
   {
      st->adapted = 1;
   }

   if (st->adapted)
   {
      for (i=0;i<=st->frame_size;i++)
      {
         spx_word32_t r, e;
         /* Compute frequency-domain adaptation mask */
         r = MULT16_32_Q15(leak_estimate,SHL32(st->Yf[i],3));
         e = SHL32(st->Rf[i],3)+1;
#ifdef FIXED_POINT
         if (r>SHR32(e,1))
            r = SHR32(e,1);
#else
         if (r>.5*e)
            r = .5*e;
#endif
         r = MULT16_32_Q15(QCONST16(.7,15),r) + MULT16_32_Q15(QCONST16(.3,15),(spx_word32_t)(MULT16_32_Q15(RER,e)));
         /*st->power_1[i] = adapt_rate*r/(e*(1+st->power[i]));*/
         st->power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,st->power[i]+10)),WEIGHT_SHIFT+16);
      }
   } else if (Sxx > SHR32(MULT16_16(N, 1000),6)) {
      /* Temporary adaption rate if filter is not yet adapted enough */
      spx_word16_t adapt_rate=0;

      tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
#ifdef FIXED_POINT
      if (tmp32 > SHR32(See,2))
         tmp32 = SHR32(See,2);
#else
      if (tmp32 > .25*See)
         tmp32 = .25*See;
#endif
      adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15));
      
      for (i=0;i<=st->frame_size;i++)
         st->power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(st->power[i],10)),WEIGHT_SHIFT+1);


      /* How much have we adapted so far? */
      st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
   }

   /* Compute spectrum of estimated echo for use in an echo post-filter (if necessary)*/
  if(0)
   // if (Yout)
   {
      spx_word16_t leak2;
      if (st->adapted)
      {
         /* If the filter is adapted, take the filtered echo */
         for (i=0;i<st->frame_size;i++)
            st->last_y[i] = st->last_y[st->frame_size+i];
         for (i=0;i<st->frame_size;i++)
            st->last_y[st->frame_size+i] = ref[i]-out[i];
      } else {
         /* If filter isn't adapted yet, all we can do is take the echo signal directly */
         for (i=0;i<N;i++)
            st->last_y[i] = st->x[i];
      }
      
      /* Apply hanning window (should pre-compute it)*/
      for (i=0;i<N;i++)
         st->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]);
      
      /* Compute power spectrum of the echo */
      spx_fft(st->fft_table, st->y, st->Y);
      power_spectrum(st->Y, st->Yps, N);
      
#ifdef FIXED_POINT
      if (leak_estimate > 16383)
         leak2 = 32767;
      else
         leak2 = SHL16(leak_estimate, 1);
#else
      if (leak_estimate>.5)
         leak2 = 1;
      else
         leak2 = 2*leak_estimate;
#endif
      /* Estimate residual echo */
      for (i=0;i<=st->frame_size;i++)
         Yout[i] = (spx_int32_t)MULT16_32_Q15(leak2,st->Yps[i]);
   }
}


int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
{
   switch(request)
   {
      
      case SPEEX_ECHO_GET_FRAME_SIZE:
         (*(int*)ptr) = st->frame_size;
         break;
      case SPEEX_ECHO_SET_SAMPLING_RATE:
         st->sampling_rate = (*(int*)ptr);
         st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate);
#ifdef FIXED_POINT
         st->beta0 = DIV32_16(SHL32(EXTEND32(st->frame_size), 16), st->sampling_rate);
         st->beta_max = DIV32_16(SHL32(EXTEND32(st->frame_size), 14), st->sampling_rate);
#else
         st->beta0 = (2.0f*st->frame_size)/st->sampling_rate;
         st->beta_max = (.5f*st->frame_size)/st->sampling_rate;
#endif
         if (st->sampling_rate<12000)
            st->notch_radius = QCONST16(.9, 15);
         else if (st->sampling_rate<24000)
            st->notch_radius = QCONST16(.982, 15);
         else
            st->notch_radius = QCONST16(.992, 15);
         break;
      case SPEEX_ECHO_GET_SAMPLING_RATE:
         (*(int*)ptr) = st->sampling_rate;
         break;
      default:
         speex_warning_int("Unknown speex_echo_ctl request: ", request);
         return -1;
   }
   return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -