/* * Copyright (c) 2008 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*! \file spectrum.c * \brief functions to convert between frequency (spectrum) and time (wavefrom) domain */ #include "sms.h" /*! \brief compute a complex spectrum from a waveform * * \param sizeWindow size of analysis window * \param pWaveform pointer to input waveform * \param pWindow pointer to input window * \param sizeMag size of output magnitude and phase spectrums * \param pMag pointer to output magnitude spectrum * \param pPhase pointer to output phase spectrum * \return sizeFft, -1 on error \todo remove this return */ int sms_spectrum(int sizeWindow, sfloat *pWaveform, sfloat *pWindow, int sizeMag, sfloat *pMag, sfloat *pPhase, sfloat *pFftBuffer) { int i, it2; int err = 0; sfloat fReal, fImag; int sizeFft = sizeMag << 1; memset(pFftBuffer, 0, sizeFft * sizeof(sfloat)); /* apply window to waveform and center window around 0 (zero-phase windowing)*/ sms_windowCentered(sizeWindow, pWaveform, pWindow, sizeFft, pFftBuffer); sms_fft(sizeFft, pFftBuffer); /* convert from rectangular to polar coordinates */ for (i = 0; i < sizeMag; i++) { it2 = i << 1; //even numbers 0-N fReal = pFftBuffer[it2]; /*odd numbers 1->N+1 */ fImag = pFftBuffer[it2 + 1]; /*even numbers 2->N+2 */ pMag[i] = sqrt(fReal * fReal + fImag * fImag); pPhase[i] = atan2(-fImag, fReal); /* \todo why is fImag negated? */ } return sizeFft; } /*! \brief compute the spectrum Magnitude of a waveform * * This function windows the waveform with pWindow and * performs a zero-padded FFT (if sizeMag*2 > sizeWindow). * The spectra is then converted magnitude (RMS). * * \param sizeWindow size of analysis window / input wavefrom * \param pWaveform pointer to input waveform * \param pWindow pointer to analysis window * \param sizeMag size of output magnitude spectrum * \param pMag pointer to output magnitude spectrum * \return 0 on success, -1 on error */ int sms_spectrumMag(int sizeWindow, sfloat *pWaveform, sfloat *pWindow, int sizeMag, sfloat *pMag, sfloat *pFftBuffer) { int i,it2; int sizeFft = sizeMag << 1; sfloat fReal, fImag; /* apply window to waveform, zero the rest of the array */ for (i = 0; i < sizeWindow; i++) pFftBuffer[i] = pWindow[i] * pWaveform[i]; for(i = sizeWindow; i < sizeFft; i++) pFftBuffer[i] = 0.; /* compute real FFT */ sms_fft(sizeFft, pFftBuffer); /* convert from rectangular to polar coordinates */ for (i=0; i<sizeMag; i++) { it2 = i << 1; fReal = pFftBuffer[it2]; fImag = pFftBuffer[it2+1]; pMag[i] = sqrtf(fReal * fReal + fImag * fImag); } return sizeFft; } /*! \brief function for a quick inverse spectrum, windowed * * Not done yet, but this will be a function that is the inverse of * sms_spectrum above. * * function to perform the inverse FFT, windowing the output * sfloat *pFMagSpectrum input magnitude spectrum * sfloat *pFPhaseSpectrum input phase spectrum * int sizeFft size of FFT * sfloat *pFWaveform output waveform * int sizeWave size of output waveform * sfloat *pFWindow synthesis window */ int sms_invSpectrum(int sizeWaveform, sfloat *pWaveform, sfloat *pWindow, int sizeMag, sfloat *pMag, sfloat *pPhase, sfloat *pFftBuffer) { int i; int sizeFft = sizeMag << 1; sms_PolarToRect(sizeMag, pFftBuffer, pMag, pPhase); sms_ifft(sizeFft, pFftBuffer); /* assume the output array has been taken care off */ /* before, this was multiplied by .5, why? */ for (i = 0; i < sizeWaveform; i++) //pWaveform[i] += pFftBuffer[i] * pWindow[i]; pWaveform[i] = pFftBuffer[i]; return sizeFft; } /*! \brief function for a quick inverse spectrum, windowed * function to perform the inverse FFT, windowing the output * sfloat *pFMagSpectrum input magnitude spectrum * sfloat *pFPhaseSpectrum input phase spectrum * int sizeFft size of FFT * sfloat *pFWaveform output waveform * int sizeWave size of output waveform * sfloat *pFWindow synthesis window */ int sms_invQuickSpectrumW(sfloat *pFMagSpectrum, sfloat *pFPhaseSpectrum, int sizeFft, sfloat *pFWaveform, int sizeWave, sfloat *pFWindow, sfloat* pFftBuffer) { int sizeMag = sizeFft >> 1, i, it2; sfloat fPower; /* convert from polar coordinates to rectangular */ for (i = 0; i<sizeMag; i++) { it2 = i << 1; fPower = pFMagSpectrum[i]; pFftBuffer[it2] = fPower * cos (pFPhaseSpectrum[i]); pFftBuffer[it2+1] = fPower * sin (pFPhaseSpectrum[i]); } /* compute IFFT */ sms_ifft(sizeFft, pFftBuffer); /* assume the output array has been taken care off */ /* \todo is a seperate pFftBuffer necessary here? it seems like multiplying the window into the waveform would be fine, without pFftBuffer */ for (i = 0; i < sizeWave; i++) pFWaveform[i] += (pFftBuffer[i] * pFWindow[i] * .5); return sizeMag; } /*! \brief convert spectrum from Rectangular to Polar form * * \param sizeMag size of spectrum (pMag and pPhase arrays) * \param pRect pointer output spectrum in rectangular form (2x sizeSpec) * \param pMag pointer to sfloat array of magnitude spectrum * \param pPhase pointer to sfloat array of phase spectrum */ void sms_RectToPolar( int sizeMag, sfloat *pRect, sfloat *pMag, sfloat *pPhase) { int i, it2; sfloat fReal, fImag; for (i=0; i<sizeMag; i++) { it2 = i << 1; fReal = pRect[it2]; fImag = pRect[it2+1]; pMag[i] = sqrtf(fReal * fReal + fImag * fImag); if (pPhase) pPhase[i] = atan2f(fImag, fReal); } } /*! \brief convert spectrum from Rectangular to Polar form * * \param sizeSpec size of spectrum (pMag and pPhase arrays) * \param pRect pointer output spectrum in rectangular form (2x sizeSpec) * \param pMag pointer to sfloat array of magnitude spectrum * \param pPhase pointer to sfloat array of phase spectrum */ void sms_PolarToRect(int sizeSpec, sfloat *pRect, sfloat *pMag, sfloat *pPhase) { int i, it2; sfloat fMag; for(i = 0; i<sizeSpec; i++) { it2 = i << 1; fMag = pMag[i]; pRect[it2] = fMag * cos (pPhase[i]); pRect[it2+1] = fMag * sin (pPhase[i]); } } /*! \brief compute magnitude spectrum of a DFT in rectangular coordinates * * \param sizeMag size of output Magnitude (half of input real FFT) * \param pInRect pointer to input DFT array (real/imag sfloats) * \param pOutMag pointer to of magnitude spectrum array */ void sms_spectrumRMS(int sizeMag, sfloat *pInRect, sfloat *pOutMag) { int i, it2; sfloat fReal, fImag; for(i=0; i<sizeMag; i++) { it2 = i << 1; fReal = pInRect[it2]; fImag = pInRect[it2+1]; pOutMag[i] = sqrtf(fReal * fReal + fImag * fImag); } }