void DFT::resize(uint32_t newWindowSize, uint32_t newPadSize){ //printf("DFT::resize()\n"); if(0 == newWindowSize && 0 == newPadSize) return; uint32_t oldDFTSize = sizeDFT(); uint32_t newDFTSize = newWindowSize + newPadSize; uint32_t oldFrqSize = oldDFTSize+2; // 2 extra for DC/Nyquist imaginary uint32_t newFrqSize = newDFTSize+2; // " if(mem::resize(mBuf, oldFrqSize, newFrqSize)){ mBufInv = mBuf; if(mAux) mem::resize(mAux, oldFrqSize, newFrqSize); mFFT.resize(newDFTSize); mem::deepZero(mBuf, newFrqSize); } mem::resize(mPadOA, sizePad(), newPadSize); mem::deepZero(mPadOA, newPadSize); mSizeDFT = newDFTSize; mSizeWin = newWindowSize; mSizeHop = mSizeWin; onResync(1); }
// input is sizeWin void STFT::forward(float * input){ //printf("STFT::forward(float *)\n"); arr::mul(input, mFwdWin, sizeWin()); // apply forward window if(mRotateForward) mem::rotateHalf(input, sizeWin()); // do zero-phase windowing rotation? DFT::forward(input); // do forward transform // compute frequency estimates? if(Bin::MagFreq == mSpctFormat){ // This will effectively subtract the expected phase difference from the computed. // This extra step seems to give more precise frequency estimates. slice(mPhases, numBins()) += float(M_2PI * sizeHop()) / sizeDFT(); // compute relative frequencies //arr::phaseToFreq(phs, mPhases, numBins(), unitsHop()); float factor = 1.f / (M_2PI * unitsHop()); for(uint32_t i=1; i<numBins()-1; ++i){ float dp = scl::wrapPhase(bins()[i][1] - mPhases[i]); // wrap phase into [-pi, pi) mPhases[i] = bins()[i][1]; // prev phase = curr phase bins()[i][1] = dp*factor; } // compute absolute frequencies by adding respective bin center frequency slice(mBuf, numBins(), 2) += gen::RAdd<float>(binFreq()); } }
void DFT::print(FILE * f, const char * a){ fprintf(f, "DFT, Win, Hop: %d, %d, %d samples\n", (int)sizeDFT(), (int)sizeWin(), (int)sizeHop()); fprintf(f, "# bins: %d\n", (int)numBins()); fprintf(f, "Freq res: %f units/sample\n", freqRes()); fprintf(f, "Bin freq: %f units\n", binFreq()); fprintf(f, "Data format: %s\n", toString(mSpctFormat)); fprintf(f, "Precise: %s\n", mPrecise ? "true" : "false"); fprintf(f, "Aux buffers: %d\n", (int)mNumAux); //printf("buf, pad, inv, aux: %p %p %p %p", mBuf, mPadOA, mBufInv, mAux); fprintf(f, "%s", a); }
void STFT::inverse(float * dst){ //printf("STFT::inverse(float *)\n"); if(MAG_FREQ == mSpctFormat){ // 2pi / hopRate: converts Hz to phase diff in radians double factor = M_2PI * unitsHop(); // 2pi / overlap: expected phase diff of fundamental due to overlap double expdp1 = double(sizeHop())/sizeWin() * M_2PI; double fund = binFreq(); for(unsigned k=1; k<numBins()-1; ++k){ double t = bin(k)[1]; // freq t -= k*fund; // freq to freq deviation t *= factor; // freq deviation to phase diff t += k*expdp1; // add expected phase diff due to overlap mAccums[k] += t; // accumulate phase diff //bin(k)[1] = mAccums[k]; // copy accum phase for inverse xfm bufInvFrq()[2*k] = bin(k)[0]; bufInvFrq()[2*k+1] = mAccums[k]; } bufInvFrq()[0] = bin(0)[0]; bufInvFrq()[2*(numBins()-1)] = bin(numBins()-1)[0]; } DFT::inverse(); // result goes into bufInvPos() // undo zero-phase windowing rotation? if(mRotateForward) mem::rotateRight(sizeWin()/2, bufInvPos(), sizeDFT()); // apply secondary window to smooth ends? if(mWindowInverse){ arr::mulBartlett(bufInvPos(), sizeWin()); } if(overlapping()){ //inverse windows overlap? // scale inverse so overlap-add is normalized for(unsigned i=0; i<sizeWin(); ++i){ bufInvPos()[i] *= mInvWinMul; } // shift old output left while adding new output arr::add(mBufInv, bufInvPos(), mBufInv + sizeHop(), sizeWin() - sizeHop()); } // copy remaining non-overlapped portion of new output unsigned sizeOverlap = sizeWin() - sizeHop(); mem::deepCopy(mBufInv + sizeOverlap, bufInvPos() + sizeOverlap, sizeHop()); // copy output if external buffer provided if(dst) mem::deepCopy(dst, mBufInv, sizeWin()); }
void DFT::inverse(float * output){ //printf("DFT::inverse(float *)\n"); switch(mSpctFormat){ case Bin::Polar: case Bin::MagFreq: //arr::mul(bins0(), gen::val(normInverse()), nbins); POLAR_RECT break; default:; //arr::mul(bins0(), gen::val(normInverse()), nbins<<1); } // arrange/scale bins for inverse xfm // TODO: can we avoid this move by pointer offsetting? mem::deepMove(mBuf+1, mBuf+2, sizeDFT()-1); slice(mBuf+1, sizeDFT()-2) *= 0.5f; mFFT.inverse(mBuf); // o.a. inverse window with prev spill if(sizePad() > 0){ arr::add(mBuf, mPadOA, scl::min(sizePad(), sizeWin())); // add prev spill if(sizePad() <= sizeWin()){ // no spill overlap mem::deepCopy(mPadOA, mBuf + sizeWin(), sizePad()); // save current spill } else{ // spill overlaps // add and save current spill to previous arr::add(mPadOA, mBuf + sizeWin(), mPadOA + sizeWin(), sizePad() - sizeWin()); mem::deepCopy(mPadOA + sizePad() - sizeWin(), mBuf + sizePad(), sizeWin()); } } if(output) mem::deepCopy(output, mBuf, sizeWin()); }
void DFT::inverse(float * dst){ //printf("DFT::inverse(float *)\n"); // operate on copy of bins if(MAG_FREQ != mSpctFormat){ mem::deepCopy(bufInvFrq(), bufFwdFrq(), sizeDFT()+2); } switch(mSpctFormat){ case COMPLEX: break; case MAG_PHASE: case MAG_FREQ: { Complex<float> * bins = mBins+numBins(); POL_TO_CART(bins) } break; } mFFT.inverse(bufInvFrq(), true); // overlap-add inverse window with prev spill if(sizePad() > 0){ // add spill from previous transform arr::add(bufInvPos(), mPadOA, scl::min(sizePad(), sizeWin())); // no spill overlap if(sizePad() <= sizeWin()){ // copy current spill into overlap-add buffer mem::deepCopy(mPadOA, bufInvPos() + sizeWin(), sizePad()); } // spill overlaps else{ // add and save current spill to previous arr::add(mPadOA, bufInvPos() + sizeWin(), mPadOA + sizeWin(), sizePad() - sizeWin()); mem::deepCopy(mPadOA + sizePad() - sizeWin(), bufInvPos() + sizePad(), sizeWin()); } } if(dst) mem::deepCopy(dst, bufInvPos(), sizeWin()); }
// input is sizeWin void STFT::forward(const float * src){ //printf("STFT::forward(float *)\n"); if(src) mem::deepCopy(bufFwdPos(), src, sizeWin()); // apply forward window arr::mul(bufFwdPos(), mFwdWin, sizeWin()); // do zero-phase windowing rotation? if(mRotateForward) mem::rotateLeft(sizeWin()/2, bufFwdPos(), sizeDFT()); DFT::forward(); // compute frequency estimates? if(MAG_FREQ == mSpctFormat){ // hopRate / 2pi: converts phase diff from radians to Hz double factor = 1. / (M_2PI * unitsHop()); // 2pi / overlap: expected phase diff of fundamental due to overlap double expdp1 = double(sizeHop())/sizeWin() * M_2PI; double fund = binFreq(); bin(0)[1] = 0.; bin(numBins()-1)[1] = spu() * 0.5; for(unsigned k=1; k<numBins()-1; ++k){ float ph = bin(k)[1]; // current phase double t = ph - mPhases[k]; // compute phase diff mPhases[k] = ph; // save current phase t -= k*expdp1; // subtract expected phase diff due to overlap t = scl::wrapPhase(t); // wrap back into [-pi, pi) t *= factor; // convert phase diff to freq deviation t += k*fund; // freq deviation to freq bin(k)[1] = t; } } }
void DFT::forward(const float * window){ //printf("DFT::forward(const float *)\n"); // this attempts to avoid a memory move, but doesn't work when window == mBuf // if(window != mBuf) mem::deepCopy(mBuf+1, window, sizeWin()); // mem::deepZero(mBuf+1 + sizeWin(), sizePad()); // zero pad // // TODO: zero-phase window (rotate buffer 180) // // mFFT.forward(mBuf+1, true); // // // re-arrange DC and Nyquist bins // mBuf[0] = mBuf[1]; // mBuf[1] = 0.f; // mBuf[numBins()*2-1] = 0.f; // old code which did a mem move, rather offsetting input buffer pointer... if(window != mBuf) mem::deepCopy(mBuf, window, sizeWin()); mem::deepZero(mBuf + sizeWin(), sizePad()); // zero pad //... do zero-phase window (rotate buffer 180) mFFT.forward(mBuf, true); // re-arrange DC and Nyquist bins mem::deepMove(mBuf+2, mBuf+1, sizeDFT()-1); mBuf[1] = 0.f; mBuf[numBins()*2-1] = 0.f; switch(mSpctFormat){ case Bin::Polar: case Bin::MagFreq: RECT_POLAR //arr::mul(bins0(), gen::val(normForward()), nbins); break; default:; // rectangular //arr::mul(bins0(), gen::val(normForward()), nbins<<1); } }