diff options
Diffstat (limited to 'sms/synthesis.c')
-rw-r--r-- | sms/synthesis.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/sms/synthesis.c b/sms/synthesis.c new file mode 100644 index 0000000..fd882c3 --- /dev/null +++ b/sms/synthesis.c @@ -0,0 +1,360 @@ +/* + * 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 synthesis.c + * \brief main synthesis routines + */ +#include "sms.h" + +/*! \brief synthesis of one frame of the deterministic component using the IFFT + * + * \param pSmsData pointer to SMS data structure frame + * \param pSynthParams pointer to structure of synthesis parameters + */ +static void SineSynthIFFT (SMS_Data *pSmsData, SMS_SynthParams *pSynthParams) +{ + int sizeFft = pSynthParams->sizeHop << 1; + int iHalfSamplingRate = pSynthParams->iSamplingRate >> 1; + int sizeMag = pSynthParams->sizeHop; + int nBins = 8; + int nTracks = pSmsData->nTracks; + int iFirstBin, k, i, l, b; + sfloat fMag=0.0, fFreq=0.0, fPhase=0.0, fLoc, fSin, fCos, fBinRemainder, + fTmp, fNewMag, fIndex; + sfloat fSamplingPeriod = 1.0 / pSynthParams->iSamplingRate; + memset (pSynthParams->pSpectra, 0, sizeFft * sizeof(sfloat)); + for (i = 0; i < nTracks; i++) + { + if (((fMag = pSmsData->pFSinAmp[i]) > 0) && + ((fFreq = (pSmsData->pFSinFreq[i])) < iHalfSamplingRate)) + { + /* \todo maybe this check can be removed if the SynthParams->prevFrame gets random + phases in sms_initSynth? */ + if (pSynthParams->prevFrame.pFSinAmp[i] <= 0) + pSynthParams->prevFrame.pFSinPha[i] = TWO_PI * sms_random(); + + // fMag = sms_dBToMag (fMag); + fTmp = pSynthParams->prevFrame.pFSinPha[i] + + TWO_PI * fFreq * fSamplingPeriod * sizeMag; + fPhase = fTmp - floor(fTmp * INV_TWO_PI) * TWO_PI; + fLoc = sizeFft * fFreq * fSamplingPeriod; + iFirstBin = (int) fLoc - 3; + fBinRemainder = fLoc - floor (fLoc); + fSin = sms_sine (fPhase); + fCos = sms_sine (fPhase + PI_2); + for (k = 1, l = iFirstBin; k <= nBins; k++, l++) + { + fIndex = (k - fBinRemainder); + if (fIndex > 7.999) fIndex = 0; + fNewMag = fMag * sms_sinc (fIndex); + if (l > 0 && l < sizeMag) + { + pSynthParams->pSpectra[l*2+1] += fNewMag * fCos; + pSynthParams->pSpectra[l*2] += fNewMag * fSin; + } + else if (l == 0) + { + pSynthParams->pSpectra[0] += 2 * fNewMag * fSin; + } + else if (l < 0) + { + b = abs(l); + pSynthParams->pSpectra[b*2+1] -= fNewMag * fCos; + pSynthParams->pSpectra[b*2] += fNewMag * fSin; + } + else if (l > sizeMag) + { + b = sizeMag - (l - sizeMag); + pSynthParams->pSpectra[b*2+1] -= fNewMag * fCos; + pSynthParams->pSpectra[b*2] += fNewMag * fSin; + } + else if (l == sizeMag) + { + pSynthParams->pSpectra[1] += 2 * fNewMag * fSin; + } + } + } + pSynthParams->prevFrame.pFSinAmp[i] = fMag; + pSynthParams->prevFrame.pFSinPha[i] = fPhase; + pSynthParams->prevFrame.pFSinFreq[i] = fFreq; + } + + sms_ifft(sizeFft, pSynthParams->pSpectra); + + for(i = 0, k = sizeMag; i < sizeMag; i++, k++) + pSynthParams->pSynthBuff[i] += pSynthParams->pSpectra[k] * pSynthParams->pFDetWindow[i]; + for(i= sizeMag, k = 0; i < sizeFft; i++, k++) + pSynthParams->pSynthBuff[i] += pSynthParams->pSpectra[k] * pSynthParams->pFDetWindow[i]; + +} + +/*! \brief synthesis of one frame of the deterministic component using the IFFT + * + * + * I made this function trying to pull the ifft out of the SineSynthIFFT + * that part of the code is in the main sms_synthesize function below + * Next would be sms_stochastic, so they could be summed and synthesized + * with only one fft, but the problem is that it needs to be 'pre-inverse-windowed' + * before the stochastic can be summed. + * + * \param pSmsData pointer to SMS data structure frame + * \param pSynthParams pointer to structure of synthesis parameters + */ +void sms_deterministic (SMS_Data *pSmsData, SMS_SynthParams *pSynthParams) +{ + int sizeFft = pSynthParams->sizeHop << 1; + int iHalfSamplingRate = pSynthParams->iSamplingRate >> 1; + int sizeSpec = pSynthParams->sizeHop; + int nBins = 8; + int nTracks = pSmsData->nTracks; + int iFirstBin, k, i, l, b; + sfloat fMag=0.0, fFreq=0.0, fPhase=0.0, fLoc, fSin, fCos, fBinRemainder, + fTmp, fNewMag, fIndex; + sfloat fSamplingPeriod = 1.0 / pSynthParams->iSamplingRate; + printf("| in deterministic | "); + + for (i = 0; i < nTracks; i++) + { + if (((fMag = pSmsData->pFSinAmp[i]) > 0) && + (fFreq = pSmsData->pFSinFreq[i] < iHalfSamplingRate)) /* \todo why does this allow f < 0 */ + { + /* \todo maybe this check can be removed if the SynthParams->prevFrame gets random + phases in sms_initSynth? */ + if (pSynthParams->prevFrame.pFSinAmp[i] <= 0) + pSynthParams->prevFrame.pFSinPha[i] = TWO_PI * sms_random(); + + //fMag = sms_dBToMag (fMag); + fTmp = pSynthParams->prevFrame.pFSinPha[i] + + TWO_PI * fFreq * fSamplingPeriod * sizeSpec; + fPhase = fTmp - floor(fTmp * INV_TWO_PI) * TWO_PI; + fLoc = sizeFft * fFreq * fSamplingPeriod; + iFirstBin = (int) fLoc - 3; + fBinRemainder = fLoc - floor (fLoc); + fSin = sms_sine (fPhase); + fCos = sms_sine (fPhase + PI_2); + for (k = 1, l = iFirstBin; k <= nBins; k++, l++) + { + fIndex = (k - fBinRemainder); + if (fIndex > 7.999) fIndex = 0; + fNewMag = fMag * sms_sinc (fIndex); + if (l > 0 && l < sizeSpec) + { + pSynthParams->pSpectra[l*2+1] += fNewMag * fCos; + pSynthParams->pSpectra[l*2] += fNewMag * fSin; + } + else if (l == 0) + { + pSynthParams->pSpectra[0] += 2 * fNewMag * fSin; + } + else if (l < 0) + { + b = abs(l); + pSynthParams->pSpectra[b*2+1] -= fNewMag * fCos; + pSynthParams->pSpectra[b*2] += fNewMag * fSin; + } + else if (l > sizeSpec) + { + b = sizeSpec - (l - sizeSpec); + pSynthParams->pSpectra[b*2+1] -= fNewMag * fCos; + pSynthParams->pSpectra[b*2] += fNewMag * fSin; + } + else if (l == sizeSpec) + { + pSynthParams->pSpectra[1] += 2 * fNewMag * fSin; + } + } + } + pSynthParams->prevFrame.pFSinAmp[i] = fMag; + pSynthParams->prevFrame.pFSinPha[i] = fPhase; + pSynthParams->prevFrame.pFSinFreq[i] = fFreq; + } + +/* sms_ifft(sizeFft, pSynthParams->pSpectra); */ + +/* for(i = 0, k = sizeMag; i < sizeMag; i++, k++) */ +/* pSynthParams->pSynthBuff[i] += pSynthParams->pSpectra[k] * pSynthParams->pFDetWindow[i]; */ +/* for(i= sizeMag, k = 0; i < sizeFft; i++, k++) */ +/* pSynthParams->pSynthBuff[i] += pSynthParams->pSpectra[k] * pSynthParams->pFDetWindow[i]; */ + +} + +/*! \brief synthesis of one frame of the stochastic component by apprimating phases + * + * computes a linearly interpolated spectral envelope to fit the correct number of output + * audio samples. Phases are generated randomly. + * + * \param pSmsData pointer to the current SMS frame + * \param pSynthParams pointer to a strucure of synthesis parameters + * \return + * \todo cleanup returns and various constant multipliers. check that approximation is ok + */ +static int StocSynthApprox (SMS_Data *pSmsData, SMS_SynthParams *pSynthParams) +{ + int i, sizeSpec1Used; + int sizeSpec1 = pSmsData->nCoeff; + int sizeSpec2 = pSynthParams->sizeHop; + int sizeFft = pSynthParams->sizeHop << 1; /* 50% overlap, so sizeFft is 2x sizeHop */ + float fStocGain; + /* if no gain or no coefficients return */ + if (*(pSmsData->pFStocGain) <= 0) + return 0; + + // *(pSmsData->pFStocGain) = sms_dBToMag(*(pSmsData->pFStocGain)); + + /* \todo check why this was here */ + /* for (i = 0; i < sizeSpec1; i++) + pSmsData->pFStocCoeff[i] *= 2 * *(pSmsData->pFStocGain) ; + */ + sizeSpec1Used = sizeSpec1 * pSynthParams->iSamplingRate / + pSynthParams->iOriginalSRate; + /* sizeSpec1Used cannot be more than what is available \todo check by graph */ + if(sizeSpec1Used > sizeSpec1) sizeSpec1Used = sizeSpec1; + //printf("iSamplingRate: %d, iOriginalSRate: %d, sizeSpec1: %d, sizeSpec1Used: %d, sizeSpec2: %d \n", + // pSynthParams->iSamplingRate, pSynthParams->iOriginalSRate, sizeSpec1, sizeSpec1Used, sizeSpec2); + sms_spectralApprox (pSmsData->pFStocCoeff, sizeSpec1, sizeSpec1Used, + pSynthParams->pMagBuff, sizeSpec2, sizeSpec1Used); + + /* generate random phases */ + for (i = 0; i < sizeSpec2; i++) + pSynthParams->pPhaseBuff[i] = TWO_PI * sms_random(); + + sms_invQuickSpectrumW (pSynthParams->pMagBuff, pSynthParams->pPhaseBuff, + sizeFft, pSynthParams->pSynthBuff, sizeFft, + pSynthParams->pFStocWindow); + return 1; +} + +/*! \brief synthesis of one frame of the residual component, modeled as stochastic, + * by approximating phases + * + * computes a linearly interpolated spectral envelope to fit the correct number of output + * audio samples. Phases are generated randomly. + * + * \todo needs to be pre-windowed to match the windowing effect of the deterministic, + * so when they are summed then they can be ifft'ed and overlap-added properly + * + * \param pSmsData pointer to the current SMS frame + * \param pSynthParams pointer to a strucure of synthesis parameters + * \return + */ +int sms_stochastic (SMS_Data *pSmsData, SMS_SynthParams *pSynthParams) +{ + int i, sizeOriginalSpecUsed; + int sizeOriginalSpec = pSmsData->nCoeff; + int sizeSpec = pSynthParams->sizeHop; + int sizeFft = pSynthParams->sizeHop << 1; /* 50% overlap, so sizeFft is 2x sizeHop */ + + /* if no gain or no coefficients return */ + if (*(pSmsData->pFStocGain) <= 0) + return (0); + +/* *(pSmsData->pFStocGain) = sms_dBToMag(*(pSmsData->pFStocGain)); */ + + /* scale the coefficients to normal amplitude */ + /*! \todo why is it also multiplied by 2? Why aren't the coeffecients just stored with gain already multiplied?*/ +/* for (i = 0; i < sizeOriginalSpec; i++) */ +/* pSmsData->pFStocCoeff[i] *= 2 * *(pSmsData->pFStocGain) ; */ + + sizeOriginalSpecUsed = sizeOriginalSpec * pSynthParams->iSamplingRate / + pSynthParams->iOriginalSRate; + /* sizeOriginalSpecUsed cannot be more than what is available */ + if(sizeOriginalSpecUsed > sizeOriginalSpec) sizeOriginalSpecUsed = sizeOriginalSpec; + sms_spectralApprox (pSmsData->pFStocCoeff, sizeOriginalSpec, sizeOriginalSpecUsed, + pSynthParams->pMagBuff, sizeSpec, sizeOriginalSpecUsed); + + /* generate random phases */ + for (i = 0; i < sizeSpec; i++) + pSynthParams->pPhaseBuff[i] = TWO_PI * sms_random(); + + /* \todo first multiply the pMagBuff by a window in order to properly un-window below */ + sms_PolarToRect(sizeSpec, pSynthParams->pSpectra, pSynthParams->pMagBuff, pSynthParams->pPhaseBuff); + return (0); +} + +/*! \brief synthesizes one frame of SMS data + * + * \param pSmsData input SMS data + * \param pFSynthesis output sound buffer + * \param pSynthParams synthesis parameters + */ +void sms_synthesize(SMS_Data *pSmsData, sfloat *pFSynthesis, + SMS_SynthParams *pSynthParams) +{ + int i, k; + int sizeHop = pSynthParams->sizeHop; + int sizeFft = sizeHop << 1; + + memcpy (pSynthParams->pSynthBuff, (sfloat *)(pSynthParams->pSynthBuff+sizeHop), + sizeof(sfloat) * sizeHop); + memset (pSynthParams->pSynthBuff+sizeHop, 0, sizeof(sfloat) * sizeHop); + + /* convert mags from linear to db */ + sms_arrayMagToDB(pSmsData->nTracks, pSmsData->pFSinAmp); + + /* decide which combo of synthesis methods to use */ + if(pSynthParams->iSynthesisType == SMS_STYPE_ALL) + { + if(pSynthParams->iDetSynthType == SMS_DET_IFFT && + pSynthParams->iStochasticType == SMS_STOC_IFFT) + { + memset (pSynthParams->pSpectra, 0, sizeFft * sizeof(sfloat)); + sms_deterministic(pSmsData, pSynthParams); + sms_ifft(sizeFft, pSynthParams->pSpectra); + + for(i = 0, k = sizeHop; i < sizeHop; i++, k++) + pSynthParams->pSynthBuff[i] += pSynthParams->pSpectra[k] * pSynthParams->pFDetWindow[i]; + for(i= sizeHop, k = 0; i < sizeFft; i++, k++) + pSynthParams->pSynthBuff[i] += pSynthParams->pSpectra[k] * pSynthParams->pFDetWindow[i]; + + //sms_invSpectrum(sizeFft, pSynthParams->pSynthBuff, + + + } + else /* can't use combo IFFT, synthesize seperately and sum */ + { + if(pSynthParams->iDetSynthType == SMS_DET_IFFT) + SineSynthIFFT (pSmsData, pSynthParams); + else /*pSynthParams->iDetSynthType == SMS_DET_SIN*/ + { + sms_sineSynthFrame (pSmsData, pSynthParams->pSynthBuff+sizeHop, pSynthParams->sizeHop, + &(pSynthParams->prevFrame), pSynthParams->iSamplingRate); + } + StocSynthApprox (pSmsData, pSynthParams); + } + + } + else if(pSynthParams->iSynthesisType == SMS_STYPE_DET) + { + if(pSynthParams->iDetSynthType == SMS_DET_IFFT) + SineSynthIFFT (pSmsData, pSynthParams); + else /*pSynthParams->iDetSynthType == SMS_DET_SIN*/ + { + sms_sineSynthFrame (pSmsData, pSynthParams->pSynthBuff+sizeHop, pSynthParams->sizeHop, + &(pSynthParams->prevFrame), pSynthParams->iSamplingRate); + } + } + else /* pSynthParams->iSynthesisType == SMS_STYPE_STOC */ + StocSynthApprox(pSmsData, pSynthParams); + + /* de-emphasize the sound */ + for(i = 0; i < sizeHop; i++) + pFSynthesis[i] = sms_deEmphasis(pSynthParams->pSynthBuff[i+sizeHop], pSynthParams); +} + |