コード例 #1
0
ファイル: convoengine.cpp プロジェクト: aidush/openmpt
int WDL_ConvolutionEngine::SetImpulse(WDL_ImpulseBuffer *impulse, int fft_size, int impulse_sample_offset, int max_imp_size, bool forceBrute)
{
  int impulse_len=0;
  int x;
  int nch=impulse->GetNumChannels();
  for (x = 0; x < nch; x ++)
  {
    int l=impulse->impulses[x].GetSize()-impulse_sample_offset;
    if (max_imp_size && l>max_imp_size) l=max_imp_size;
    if (impulse_len < l) impulse_len=l;
  }
  m_impulse_nch=nch;

  if (m_impulse_nch>1) // detect mono signals pretending to be multichannel
  {
    for (x = 1; x < m_impulse_nch; x ++)
    {
      if (impulse->impulses[x].GetSize()!=impulse->impulses[0].GetSize()||
          memcmp(impulse->impulses[x].Get(),impulse->impulses[0].Get(),
            impulse->impulses[0].GetSize()*sizeof(WDL_FFT_REAL)))
            break;
    }
    if (x >= m_impulse_nch) m_impulse_nch=1;
  }

  m_impulse_len=impulse_len;
  m_proc_nch=-1;


  if (forceBrute)
  {
    m_fft_size=0;

    // save impulse
    for (x = 0; x < m_impulse_nch; x ++)
    {
      WDL_FFT_REAL *imp=impulse->impulses[x].Get()+impulse_sample_offset;
      int lenout=impulse->impulses[x].GetSize()-impulse_sample_offset;  
      if (max_imp_size && lenout>max_imp_size) lenout=max_imp_size;

      WDL_CONVO_IMPULSEBUFf *impout=m_impulse[x].Resize(lenout)+lenout;
      while (lenout-->0) *--impout = (WDL_CONVO_IMPULSEBUFf) *imp++;
    }

    for (x = 0; x < WDL_CONVO_MAX_PROC_NCH; x ++)
    {
      m_samplesout_delay[x]=0;
      m_samplesin[x].Clear();
      m_samplesin2[x].Clear();
      m_samplesout[x].Clear();
    }

    return 0;
  }

 
  if (fft_size<=0)
  {
    int msz=fft_size<=-16? -fft_size*2 : 32768;

    fft_size=32;
    while (fft_size < impulse_len*2 && fft_size < msz) fft_size*=2;
  }

  m_fft_size=fft_size;

  int impchunksize=fft_size/2;
  int nblocks=(impulse_len+impchunksize-1)/impchunksize;
  //char buf[512];
  //sprintf(buf,"il=%d, ffts=%d, cs=%d, nb=%d\n",impulse_len,fft_size,impchunksize,nblocks);
  //OutputDebugString(buf);

  const bool smallerSizeMode=sizeof(WDL_CONVO_IMPULSEBUFf)!=sizeof(WDL_FFT_REAL);
 
  WDL_FFT_REAL scale=(WDL_FFT_REAL) (1.0/fft_size);
  for (x = 0; x < m_impulse_nch; x ++)
  {
    WDL_FFT_REAL *imp=impulse->impulses[x].Get()+impulse_sample_offset;

    WDL_FFT_REAL *imp2=x < m_impulse_nch-1 ? impulse->impulses[x+1].Get()+impulse_sample_offset : NULL;

    WDL_CONVO_IMPULSEBUFf *impout=m_impulse[x].Resize((nblocks+!!smallerSizeMode)*fft_size*2);
    char *zbuf=m_impulse_zflag[x].Resize(nblocks);
    int lenout=impulse->impulses[x].GetSize()-impulse_sample_offset;  
    if (max_imp_size && lenout>max_imp_size) lenout=max_imp_size;
      
    int bl;
    for (bl = 0; bl < nblocks; bl ++)
    {

      int thissz=lenout;
      if (thissz > impchunksize) thissz=impchunksize;

      lenout -= thissz;
      int i=0;    
      WDL_FFT_REAL mv=0.0;
      WDL_FFT_REAL mv2=0.0;
      WDL_FFT_REAL *imptmp = (WDL_FFT_REAL *)impout;

      for (; i < thissz; i ++)
      {
        WDL_FFT_REAL v=*imp++;
        WDL_FFT_REAL v2=(WDL_FFT_REAL)fabs(v);
        if (v2 > mv) mv=v2;

        imptmp[i*2]=v * scale;

        if (imp2)
        {
          v=*imp2++;
          v2=(WDL_FFT_REAL)fabs(v);
          if (v2>mv2) mv2=v2;
          imptmp[i*2+1]=v*scale;
        }
        else imptmp[i*2+1]=0.0;
      }
      for (; i < fft_size; i ++)
      {
        imptmp[i*2]=0.0;
        imptmp[i*2+1]=0.0;
      }
      if (mv>1.0e-14||mv2>1.0e-14)
      {
        *zbuf++=mv>1.0e-14 ? 2 : 1; // 1 means only second channel has content
        WDL_fft((WDL_FFT_COMPLEX*)impout,fft_size,0);

        if (smallerSizeMode)
        {
          int x,n=fft_size*2;
          for(x=0;x<n;x++) impout[x]=(WDL_CONVO_IMPULSEBUFf)imptmp[x];
        }
      }
      else *zbuf++=0;

      impout+=fft_size*2;
    }
  }
  return m_fft_size/2;
}
コード例 #2
0
ファイル: convoengine.cpp プロジェクト: M-l-M/wdl
int WDL_ConvolutionEngine::Avail(int want)
{
  if (m_fft_size<1)
  {
    return m_samplesout[0].Available()/sizeof(WDL_FFT_REAL);
  }

  int chunksize=m_fft_size/2;
  int nblocks=(m_impulse_len+chunksize-1)/chunksize;
  // clear combining buffer
  WDL_FFT_REAL *workbuf2 = m_combinebuf.Resize(m_fft_size*4); // temp space

  int ch=0;
  int sz=m_fft_size/2;


  for (ch = 0; ch < m_proc_nch; ch ++)
  {
    if (!m_samplehist[ch].GetSize()||!m_overlaphist[ch].GetSize()) continue;
    int srcc=ch;
    if (srcc>=m_impulse_nch) srcc=m_impulse_nch-1;

    bool allow_mono_input_mode=true;
    bool mono_impulse_mode=false;

    if (m_impulse_nch==1 && ch<m_proc_nch-1 && 
        m_samplehist[ch+1].GetSize()&&m_overlaphist[ch+1].GetSize() &&
        m_samplesin[ch].Available()==m_samplesin[ch+1].Available() &&
        m_samplesout[ch].Available()==m_samplesout[ch+1].Available()
        )
    { // 2x processing mode
      mono_impulse_mode=true;
      allow_mono_input_mode=false;
    }


    int in_needed=sz;
    // if on an odd channel, make sure we delay this channel a bit so that the FFTs are more evenly distribyted
    // if we comment out this line we can always disable this behavior
    if ((ch&1) && m_samplesout_delay[ch] < sz/2)
      in_needed = sz/2-m_samplesout_delay[ch];

    // useSilentList[x] = 1 for mono signal, 2 for stereo, 0 for silent
    char *useSilentList=m_samplehist_zflag[ch].GetSize()==nblocks ? m_samplehist_zflag[ch].Get() : NULL;
    while (m_samplesin[ch].Available()/(int)sizeof(WDL_FFT_REAL) >= in_needed && 
           m_samplesout[ch].Available() < (want+m_samplesout_delay[ch])*(int)sizeof(WDL_FFT_REAL))
    {
      int histpos;
      if ((histpos=++m_hist_pos[ch]) >= nblocks) histpos=m_hist_pos[ch]=0;

      // get samples from input, to history
      WDL_FFT_REAL *optr = m_samplehist[ch].Get()+histpos*m_fft_size*2;   

      if (in_needed<sz)
      {
        memset(optr+sz,0,(sz-in_needed)*sizeof(WDL_FFT_REAL));
        m_samplesin[ch].GetToBuf(0,optr+sz+sz-in_needed,in_needed*sizeof(WDL_FFT_REAL));
        m_samplesout_delay[ch] += (sz-in_needed);
      }
      else
        m_samplesin[ch].GetToBuf(0,optr+sz,in_needed*sizeof(WDL_FFT_REAL));

      m_samplesin[ch].Advance(in_needed*sizeof(WDL_FFT_REAL));

      in_needed=sz;


      bool mono_input_mode=false;

      bool nonzflag=false;
      if (mono_impulse_mode)
      {
        if (++m_hist_pos[ch+1] >= nblocks) m_hist_pos[ch+1]=0;
        m_samplesin[ch+1].GetToBuf(0,workbuf2,sz*sizeof(WDL_FFT_REAL));
        m_samplesin[ch+1].Advance(sz*sizeof(WDL_FFT_REAL));
        int i;
        for (i = 0; i < sz; i ++) // unpack samples
        {
          WDL_FFT_REAL f = optr[i*2]=denormal_filter_aggressive(optr[sz+i]);
          if (!nonzflag && (f<-1.0e-6 || f>1.0e-6)) nonzflag=true;
          f=optr[i*2+1]=denormal_filter_aggressive(workbuf2[i]);
          if (!nonzflag && (f<-1.0e-6 || f>1.0e-6)) nonzflag=true;
        }
      }
      else
      {
        if (allow_mono_input_mode && 
          ch < m_proc_nch-1 && 
          srcc<m_impulse_nch-1 && 
          !CompareQueueToBuf(&m_samplesin[ch+1],optr+sz,sz*sizeof(WDL_FFT_REAL))
          )
        {
          mono_input_mode=true;
        }
        else allow_mono_input_mode=false;

        int i;
        for (i = 0; i < sz; i ++) // unpack samples
        {
          WDL_FFT_REAL f=optr[i*2]=denormal_filter_aggressive(optr[sz+i]);
          optr[i*2+1]=0.0;
          if (!nonzflag && (f<-1.0e-6 || f>1.0e-6)) nonzflag=true;
        }
      }

      int i;
      for (i = 1; mono_input_mode && i < nblocks; i ++) // start @ 1, since hist[histpos] is no longer used for here
      {
        int srchistpos = histpos-i;
        if (srchistpos < 0) srchistpos += nblocks;
        if (useSilentList[srchistpos]==2) mono_input_mode=false;
      }

      if (nonzflag||!useSilentList) memset(optr+sz*2,0,sz*2*sizeof(WDL_FFT_REAL));


#ifdef WDLCONVO_ZL_ACCOUNTING
      m_zl_fftcnt++;
#endif

      if (nonzflag) WDL_fft((WDL_FFT_COMPLEX*)optr,m_fft_size,0);

      if (useSilentList) useSilentList[histpos]=nonzflag ? (mono_input_mode ? 1 : 2) : 0;
    
      int mzfl=2;
      if (mono_input_mode)
      {
        mzfl=1;

        m_samplesin[ch+1].Advance(sz*sizeof(WDL_FFT_REAL));

        // save a valid copy in sample hist incase we switch from mono to stereo
        if (++m_hist_pos[ch+1] >= nblocks) m_hist_pos[ch+1]=0;
        WDL_FFT_REAL *optr2 = m_samplehist[ch+1].Get()+m_hist_pos[ch+1]*m_fft_size*2;   
        memcpy(optr2,optr,m_fft_size*2*sizeof(WDL_FFT_REAL));
      }

      int applycnt=0;
      char *useImpSilentList=m_impulse_zflag[srcc].GetSize() == nblocks ? m_impulse_zflag[srcc].Get() : NULL;

      WDL_CONVO_IMPULSEBUFf *impulseptr=m_impulse[srcc].Get();
      for (i = 0; i < nblocks; i ++, impulseptr+=m_fft_size*2)
      {
        int srchistpos = histpos-i;
        if (srchistpos < 0) srchistpos += nblocks;

        if (useImpSilentList && useImpSilentList[i]<mzfl) continue;
        if (useSilentList && !useSilentList[srchistpos]) continue; // silent block

        WDL_FFT_REAL *samplehist=m_samplehist[ch].Get() + m_fft_size*srchistpos*2;

        if (applycnt++) // add to output
          WDL_CONVO_CplxMul3((WDL_FFT_COMPLEX*)workbuf2,(WDL_FFT_COMPLEX*)samplehist,(WDL_CONVO_IMPULSEBUFCPLXf*)impulseptr,m_fft_size);   
        else // replace output
          WDL_CONVO_CplxMul2((WDL_FFT_COMPLEX*)workbuf2,(WDL_FFT_COMPLEX*)samplehist,(WDL_CONVO_IMPULSEBUFCPLXf*)impulseptr,m_fft_size);  

      }
      if (!applycnt)
        memset(workbuf2,0,m_fft_size*2*sizeof(WDL_FFT_REAL));
      else
        WDL_fft((WDL_FFT_COMPLEX*)workbuf2,m_fft_size,1);

      WDL_FFT_REAL *olhist=m_overlaphist[ch].Get(); // errors from last time
      WDL_FFT_REAL *p1=workbuf2,*p3=workbuf2+m_fft_size,*p1o=workbuf2;

      if (mono_impulse_mode||mono_input_mode)
      {
        WDL_FFT_REAL *p2o=workbuf2+m_fft_size*2;
        WDL_FFT_REAL *olhist2=m_overlaphist[ch+1].Get(); // errors from last time
        int s=sz/2;
        while (s--)
        {
          p2o[0] = p1[1]+olhist2[0];
          p2o[1] = p1[3]+olhist2[1];
          p1o[0] = p1[0]+olhist[0];
          p1o[1] = p1[2]+olhist[1];
          p1o+=2;
          p2o+=2;
          p1+=4;

          olhist[0]=p3[0];
          olhist[1]=p3[2];
          olhist2[0]=p3[1];
          olhist2[1]=p3[3];
          p3+=4;

          olhist+=2;
          olhist2+=2;
        }
        // add samples to output
        m_samplesout[ch].Add(workbuf2,sz*sizeof(WDL_FFT_REAL));
        m_samplesout[ch+1].Add(workbuf2+m_fft_size*2,sz*sizeof(WDL_FFT_REAL));
      }
      else
      {
        int s=sz/2;
        while (s--)
        {
          p1o[0] = p1[0]+olhist[0];
          p1o[1] = p1[2]+olhist[1];
          p1o+=2;
          p1+=4;

          olhist[0]=p3[0];
          olhist[1]=p3[2];
          p3+=4;

          olhist+=2;
        }
        // add samples to output
        m_samplesout[ch].Add(workbuf2,sz*sizeof(WDL_FFT_REAL));
      }
    } // while available

    if (mono_impulse_mode) ch++;
  }

  int mv = want;
  for (ch=0;ch<m_proc_nch;ch++)
  {
    int v = m_samplesout[ch].Available()/sizeof(WDL_FFT_REAL)  - m_samplesout_delay[ch];
    if (!ch || v<mv)mv=v;
  }
  return mv;
}