Gamma  0.9.5
Generic Synthesis Library
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
/Users/ljp/code/gamma/trunk/Gamma/DFT.h
00001 #ifndef GAMMA_DFT_H_INC
00002 #define GAMMA_DFT_H_INC
00003 
00004 /*  Gamma - Generic processing library
00005     See COPYRIGHT file for authors and license information */
00006 
00007 #include <math.h>
00008 #include "Gamma/mem.h"
00009 #include "Gamma/scl.h"
00010 #include "Gamma/tbl.h"
00011 #include "Gamma/Sync.h"
00012 #include "Gamma/Constants.h"
00013 #include "Gamma/Containers.h"
00014 #include "Gamma/FFT.h"
00015 #include "Gamma/Types.h"
00016 
00017 
00018 namespace gam{
00019 
00020 
00022 enum SpectralType{
00023     COMPLEX,    
00024     MAG_PHASE,  
00025     MAG_FREQ    
00026 };
00027 
00028 
00029 
00031 template <class T=gam::real>
00032 class SlidingWindow{
00033 public:
00034     SlidingWindow(uint32_t winSize, uint32_t hopSize);
00035     ~SlidingWindow();
00036 
00037     void resize(uint32_t winSize, uint32_t hopSize);
00038     void sizeHop(uint32_t size);
00039     void sizeWin(uint32_t size);
00040     
00041     uint32_t sizeHop() const;
00042     uint32_t sizeWin() const;
00043     
00045     
00048     const T * window();
00049     const T * operator()();
00050     
00052     bool operator()(T input);
00053     
00055     
00058     bool operator()(T * dst, T input);
00059 
00060 protected:
00061     void slide();   // Slides samples in window left by hop num samples
00062     // After processing the window samples, a call to slide() must be made
00063     // to prepare for the next window.
00064 
00065 protected:
00066     T * mBuf;
00067     uint32_t mSizeWin, mSizeHop;
00068     uint32_t mTapW; // current index to write to
00069     uint32_t mHopCnt;   // counts samples for hop
00070     
00071 private:
00072     uint32_t hopStart() const;
00073 };
00074 
00075 
00076 
00078 template <class T=gam::real>
00079 class DFTBase : public Synced{
00080 public:
00081     DFTBase();
00082     virtual ~DFTBase();
00083 
00085     T * aux(uint32_t num);
00086     
00088     Complex<T> * bins() const { return mBins; }
00089     
00091     Complex<T>& bin(uint32_t k){ return mBins[k]; }
00092     
00094     const Complex<T>& bin(uint32_t k) const { return mBins[k]; }
00095     
00096     double binFreq() const;     
00097     uint32_t numBins() const;   
00098     uint32_t sizeDFT() const;   
00099     Sync& syncFreq();           
00100     
00101     void numAux(uint32_t num);  
00102 
00103     virtual void onResync(double r);
00104 
00105 protected:
00106     uint32_t mSizeDFT, mNumAux;
00107     union{
00108         T * mBuf;       // FFT buffer
00109         Complex<T> * mBins;
00110     };
00111     T * mAux;       // aux buffers
00112     Sync mSyncFreq;
00113 
00114     T normForward() const;  // get norm factor for forward transform values
00115     T * bufPos(){ return mBuf+1; }
00116     T * bufFrq(){ return mBuf; }
00117 };
00118 
00119 
00120 
00122 class DFT : public DFTBase<float>{
00123 public:
00125 
00130     DFT(
00131         uint32_t winSize=1024, uint32_t padSize=0,
00132         SpectralType specType=COMPLEX,
00133         uint32_t numAux=0
00134     );
00135 
00136     virtual ~DFT();
00137 
00138 
00140     DFT& spectrumType(SpectralType v);
00141 
00143     DFT& precise(bool whether);
00144 
00146     void resize(uint32_t windowSize, uint32_t padSize);
00147 
00148     float freqRes() const;              
00149     float overlap() const;              
00150     bool overlapping() const;           
00151     uint32_t sizeHop() const;           
00152     uint32_t sizePad() const;           
00153     uint32_t sizeWin() const;           
00154 
00155     Sync& syncHop();                    
00156 
00158     
00161     bool operator()(float input);
00162 
00164     
00167     float operator()();
00168 
00170     
00173     void forward(const float * src);    
00174 
00176     
00181     virtual void inverse(float * dst);
00182     
00184     
00187     bool inverseOnNext();
00188 
00189     void spctToRect();      // convert spectrum to rectangle format
00190     void spctToPolar();     // convert spectrum to polar format
00191     void zero();            
00192     void zeroEnds();        
00193 
00194     virtual void onResync(double r);
00195     virtual void print(FILE * fp=stdout, const char * append="\n");
00196     
00197 protected:
00198     uint32_t mSizeWin;              // samples in analysis window
00199     uint32_t mSizeHop;              // samples between forward transforms (= winSize() for DFT)
00200     SpectralType mSpctFormat;       // format of spectrum
00201     RFFT<float> mFFT;
00202     Sync mSyncHop;
00203     
00204     // Buffers
00205     float * mPadOA;         // Overlap-add buffer (alloc'ed only if zero-padded)
00206     float * mBufInv;        // Pointer to inverse sample buffer
00207     uint32_t mTapW, mTapR;  // DFT i/o read/write taps
00208     bool mPrecise;
00209 };
00210 
00211 
00212 
00213 
00215 
00220 class STFT : public DFT {
00221 public:
00222 
00229     STFT(uint32_t winSize=1024, uint32_t hopSize=256, uint32_t padSize=0,
00230         WindowType winType = RECTANGLE,
00231         SpectralType specType = COMPLEX,
00232         uint32_t numAux=0
00233     );
00234     
00235     virtual ~STFT();
00236 
00237 
00238     using DFT::operator();
00239     using DFT::sizeHop;
00240 
00241 
00243     
00246     bool operator()(float input);
00247 
00249     void forward(const float * src);
00250     
00252     virtual void inverse(float * dst);
00253 
00254 
00256     void resize(uint32_t winSize, uint32_t padSize);
00257 
00259     STFT& inverseWindowing(bool v){
00260         mWindowInverse=v; computeInvWinMul(); return *this; }
00261 
00263     STFT& rotateForward(bool v){ mRotateForward=v; return *this; }
00264 
00266     STFT& sizeHop(uint32_t size);
00267     
00269     STFT& windowType(WindowType type);
00270 
00271 
00272     float unitsHop();
00273     
00275     float * phases();
00276     
00277     virtual void print(FILE * fp=stdout, const char * append="\n"); 
00278 
00279 protected:
00280     void computeInvWinMul();    // compute inverse normalization factor (due to overlap-add)
00281     
00282     SlidingWindow<float> mSlide;
00283     float * mFwdWin;            // forward transform window
00284     float * mPhases;            // copy of current phases (mag-freq mode)
00285     WindowType mWinType;        // type of analysis window used
00286     float mFwdWinMul, mInvWinMul;
00287     bool mWindowInverse;        // whether to window inverse samples
00288     bool mRotateForward;
00289 };
00290 
00291 
00292 
00293 
00295 
00299 template <class T>
00300 class SDFT : public DFTBase<T> {
00301 public:
00302 
00306     SDFT(uint32_t sizeDFT, uint32_t binLo, uint32_t binHi);
00307     
00309     void forward(T input);
00310     
00312     SDFT& interval(uint32_t binLo, uint32_t binHi);
00313 
00315     void resize(uint32_t sizeDFT, uint32_t binLo, uint32_t binHi);
00316         
00317 protected:
00318     uint32_t mBinLo, mBinHi;
00319     DelayN<T> mDelay;
00320     //T * mBufI;                // alias to imaginaries
00321     Complex<T> mF1;
00322     Complex<T> mFL;
00323     //double mC0, mS0;      // phasor rotators
00324     //double mCL, mSL;      // low bin phasor
00325     T mNorm;                // fwd transform normalization
00326 };
00327 
00328 
00329 
00330 // Implementation_______________________________________________________________
00331 
00332 //---- SlidingWindow
00333 #define TEM template<class T>
00334 TEM SlidingWindow<T>::SlidingWindow(uint32_t winSize, uint32_t hopSize)
00335     : mBuf(0), mSizeWin(0), mSizeHop(0), mHopCnt(0)
00336 {
00337     resize(winSize, hopSize);
00338     mem::deepZero(mBuf, sizeWin());
00339 }
00340 
00341 TEM SlidingWindow<T>::~SlidingWindow(){
00342     if(mBuf){ free(mBuf); mBuf = 0; }
00343 }
00344 
00345 TEM void SlidingWindow<T>::resize(uint32_t winSize, uint32_t hopSize){
00346     sizeWin(winSize);
00347     sizeHop(hopSize);
00348     //mTapW = hopStart();   // for single-buffer slide mode
00349     mTapW = 0;              // for single-buffer rotate mode
00350 }
00351 
00352 TEM void SlidingWindow<T>::sizeWin(uint32_t size){
00353     if(mem::resize(mBuf, sizeWin(), size)) mSizeWin = size;
00354 }
00355 
00356 TEM void SlidingWindow<T>::sizeHop(uint32_t size){
00357     mSizeHop = scl::clip(size, sizeWin(), (uint32_t)1);
00358 }
00359 
00360 TEM inline uint32_t SlidingWindow<T>::sizeHop() const { return mSizeHop; }
00361 TEM inline uint32_t SlidingWindow<T>::sizeWin() const { return mSizeWin; }
00362 TEM inline const T * SlidingWindow<T>::window(){ return mBuf; }
00363 TEM inline const T * SlidingWindow<T>::operator()(){ return mBuf; }
00364 
00365 TEM inline bool SlidingWindow<T>::operator()(T input){
00366 
00367 // faster, but requires explicit call to slide() by user which is error prone
00368 //  mBuf[mTapW] = input;
00369 //  
00370 //  if(++mTapW == sizeWin()){
00371 //      mTapW = hopStart();
00372 //      return true;
00373 //  }
00374 //  return false;
00375     
00376     mBuf[mTapW] = input;
00377     
00378     if(++mTapW >= sizeHop()){
00379         mTapW = 0;
00380         mem::rotateLeft(sizeHop(), mBuf, sizeWin());
00381         return true;
00382     }
00383     return false;
00384 }
00385 
00386 TEM inline bool SlidingWindow<T>::operator()(T * output, T input){
00387     mBuf[mTapW] = input;
00388     if(++mTapW == sizeWin()) mTapW = 0;
00389 
00390     if(++mHopCnt == sizeHop()){
00391         mem::copyAllFromRing(mBuf, sizeWin(), mTapW, output);
00392         mHopCnt = 0;
00393         return true;
00394     }
00395     return false;
00396 }
00397 
00398 TEM inline void SlidingWindow<T>::slide(){
00399     mem::deepMove(mBuf, mBuf + sizeHop(), hopStart());
00400 }
00401 
00402 TEM inline uint32_t SlidingWindow<T>::hopStart() const { return sizeWin() - sizeHop(); }
00403 
00404 
00405 
00406 //---- DFTBase
00407 
00408 TEM DFTBase<T>::DFTBase() : mSizeDFT(0), mNumAux(0), mBuf(0), mAux(0){ initSynced(); }
00409 
00410 TEM DFTBase<T>::~DFTBase(){ //printf("~DFTBase\n");
00411     mem::free(mBuf);
00412     mem::free(mAux);
00413 }
00414 
00415 TEM inline T *      DFTBase<T>::aux(uint32_t num){ return mAux + numBins() * num; }
00416 TEM inline double   DFTBase<T>::binFreq() const { return spu() / (double)sizeDFT(); }
00417 TEM inline uint32_t DFTBase<T>::numBins() const { return (sizeDFT() + 2)>>1; }
00418 TEM inline uint32_t DFTBase<T>::sizeDFT() const { return mSizeDFT; }
00419 TEM inline Sync&    DFTBase<T>::syncFreq(){ return mSyncFreq; }
00420 TEM inline T        DFTBase<T>::normForward() const { return (T)2 / (T)sizeDFT(); }
00421 
00422 TEM void DFTBase<T>::numAux(uint32_t num){
00423     if(mem::resize(mAux, mNumAux * numBins(), num * numBins())) mNumAux = num;
00424 }
00425 
00426 TEM void DFTBase<T>::onResync(double r){
00427     mSyncFreq.ups(binFreq());
00428 }
00429 
00430 
00431 
00432 //---- DFT
00433 
00434 inline DFT& DFT::spectrumType(SpectralType v){ mSpctFormat=v; return *this; }
00435 inline DFT& DFT::precise(bool w){ mPrecise=w; return *this; }
00436 
00437 inline float DFT::freqRes() const { return spu() / sizeWin(); }
00438 inline float DFT::overlap() const { return float(sizeWin()) / sizeHop(); }
00439 inline bool DFT::overlapping() const { return sizeHop() < sizeWin(); }
00440 inline uint32_t DFT::sizeHop() const { return mSizeHop; }
00441 inline uint32_t DFT::sizePad() const { return mSizeDFT - mSizeWin; }
00442 inline uint32_t DFT::sizeWin() const { return mSizeWin; }
00443 inline Sync& DFT::syncHop(){ return mSyncHop; }
00444 
00445 inline bool DFT::operator()(float input){
00446     bufPos()[mTapW] = input;
00447 
00448     if(++mTapW >= sizeHop()){
00449         forward(bufPos());
00450         mTapW = 0;
00451         return true;
00452     }
00453     return false;
00454 }
00455 
00456 inline float DFT::operator()(){
00457     if(++mTapR >= sizeHop()){
00458         inverse(0); // this is a virtual method
00459         mTapR = 0;
00460     }
00461     return mBufInv[mTapR];
00462 }
00463 
00464 inline bool DFT::inverseOnNext(){ return mTapR == (sizeHop() - 1); }
00465 inline void DFT::zero(){ mem::deepZero(mBuf, sizeDFT() + 2); }
00466 inline void DFT::zeroEnds(){ 
00467     //bins0()[0]=0; bins0()[numBins()-1]=0; 
00468     //bins1()[0]=0; bins1()[numBins()-1]=0;
00469     bins()[0](0,0);
00470     bins()[numBins()-1](0,0);
00471 }
00472 
00473 
00474 //---- STFT
00475 
00476 inline bool STFT::operator()(float input){
00477     if(mSlide(bufPos(), input)){
00478         forward(bufPos());
00479         return true;
00480     }
00481     return false;
00482 }
00483 
00484 inline float STFT::unitsHop(){ return (float)DFT::sizeHop() * ups(); }
00485 inline float * STFT::phases(){ return mPhases; }
00486 
00487 
00488 
00489 //---- SDFT
00490 
00491 TEM SDFT<T>::SDFT(uint32_t sizeDFT, uint32_t binLo, uint32_t binHi)
00492     : DFTBase<T>(), mBinLo(0), mBinHi(0), mDelay(0)
00493 {
00494     resize(sizeDFT, binLo, binHi);
00495 }
00496 
00497 TEM void SDFT<T>::resize(uint32_t sizeDFT, uint32_t binLo, uint32_t binHi){
00498     // may be able to keep these smaller?
00499     mem::resize(this->mBuf, this->mSizeDFT + 2, sizeDFT + 2);
00500     mem::deepZero(this->mBuf, sizeDFT + 2);
00501 
00502     mDelay.resize(sizeDFT);
00503     mDelay.assign(T(0));
00504 
00505     this->mSizeDFT = sizeDFT;
00506 
00507     interval(binLo, binHi);
00508 
00509     //this->onSyncChange();
00510 }
00511 
00512 TEM SDFT<T>& SDFT<T>::interval(uint32_t binLo, uint32_t binHi){
00513     mBinLo = binLo;
00514     mBinHi = binHi;
00515     
00516     double theta = M_2PI / this->sizeDFT();
00517 
00518     mF1.fromPhase(theta);
00519     mFL.fromPhase(theta*mBinLo);
00520     mNorm = T(2) / T(this->sizeDFT());
00521     return *this;
00522 }
00523 
00524 //
00525 TEM inline void SDFT<T>::forward(T input){
00526     T dif = (input - mDelay(input)) * mNorm;    // ffd comb zeroes
00527                                                 // difference between temporal 'frames'
00528     Complex<T> c = mFL;                         // phasor at low bin
00529 
00530     // apply complex resonators:
00531     // multiply freq samples by 1st harmonic (shift time signal)
00532     // add time sample to all bins (set time sample at n=0)
00533     
00534     for(uint32_t k=mBinLo; k<mBinHi; ++k){
00535         Complex<T>& b = this->bins(k);
00536         b = b*c + dif;
00537         c *= mF1;
00538     }
00539 }
00540 
00541 //TEM inline T SDFT<T>::inverse(){}
00542 
00543 
00544 
00545 /*
00546 TEM class Counter{
00547 public:
00548 
00549     bool operator()(){
00550         if(++mVal == mMax){
00551             onWrap();
00552             mVal = (T)0;
00553             return true;
00554         }
00555         return false;
00556     }
00557 
00558     virtual void onWrap();
00559 
00560 protected:
00561     T mVal, mMax;
00562 };
00563 */
00564 
00565 #undef TEM
00566 
00567 } // gam::
00568 
00569 #endif
00570