summaryrefslogtreecommitdiff
path: root/src/sms/synthesis.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sms/synthesis.c')
-rw-r--r--src/sms/synthesis.c260
1 files changed, 260 insertions, 0 deletions
diff --git a/src/sms/synthesis.c b/src/sms/synthesis.c
new file mode 100644
index 0000000..bc739d0
--- /dev/null
+++ b/src/sms/synthesis.c
@@ -0,0 +1,260 @@
+/*
+ * 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 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 */
+
+ /* if no gain or no coefficients return */
+ if(*(pSmsData->pFStocGain) <= 0)
+ return 0;
+
+ sizeSpec1Used = sizeSpec1 * pSynthParams->iSamplingRate / pSynthParams->iOriginalSRate;
+
+ /* sizeSpec1Used cannot be more than what is available \todo check by graph */
+ if(sizeSpec1Used > sizeSpec1) sizeSpec1Used = sizeSpec1;
+
+ sms_spectralApprox(pSmsData->pFStocCoeff, sizeSpec1, sizeSpec1Used,
+ pSynthParams->pMagBuff, sizeSpec2, sizeSpec1Used,
+ pSynthParams->approxEnvelope);
+
+ /* 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, pSynthParams->pSpectra);
+ return 1;
+}
+
+/*! \brief synthesizes one frame of the residual signal
+ *
+ * \param residualParams Parameters and memory for residual synthesis
+ */
+void sms_approxResidual(int sizeResidual, sfloat* residual,
+ int sizeApprox, sfloat* approx,
+ SMS_ResidualParams *residualParams)
+{
+ int i;
+
+ /* shift buffers */
+ memcpy(residualParams->residual,
+ residualParams->residual + residualParams->hopSize,
+ sizeof(sfloat) * residualParams->hopSize);
+ memcpy(residualParams->residual + residualParams->hopSize, residual,
+ sizeof(sfloat) * residualParams->hopSize);
+
+ memcpy(residualParams->approx,
+ residualParams->approx + residualParams->hopSize,
+ sizeof(sfloat) * residualParams->hopSize);
+ memset(residualParams->approx + residualParams->hopSize, 0,
+ sizeof(sfloat) * residualParams->hopSize);
+
+ sms_spectrumMag(residualParams->residualSize,
+ residualParams->residual,
+ residualParams->fftWindow,
+ residualParams->sizeStocMagSpectrum,
+ residualParams->stocMagSpectrum,
+ residualParams->fftBuffer);
+
+ if(residualParams->sizeStocMagSpectrum != residualParams->nCoeffs)
+ {
+ sms_spectralApprox(residualParams->stocMagSpectrum,
+ residualParams->sizeStocMagSpectrum,
+ residualParams->sizeStocMagSpectrum,
+ residualParams->stocCoeffs,
+ residualParams->nCoeffs,
+ residualParams->nCoeffs,
+ residualParams->approxEnvelope);
+
+ sms_spectralApprox(residualParams->stocCoeffs,
+ residualParams->nCoeffs,
+ residualParams->nCoeffs,
+ residualParams->stocMagSpectrum,
+ residualParams->sizeStocMagSpectrum,
+ residualParams->sizeStocMagSpectrum,
+ residualParams->approxEnvelope);
+ }
+
+ /* generate random phases */
+ for(i = 0; i < residualParams->sizeStocMagSpectrum; i++)
+ residualParams->stocPhaseSpectrum[i] = TWO_PI * sms_random();
+
+ /* IFFT with 50% overlap */
+ sms_invQuickSpectrumW(residualParams->stocMagSpectrum,
+ residualParams->stocPhaseSpectrum,
+ residualParams->sizeStocMagSpectrum*2,
+ residualParams->approx,
+ residualParams->residualSize,
+ residualParams->ifftWindow,
+ residualParams->fftBuffer);
+
+ /* output */
+ for(i = 0; i < sizeApprox; i++)
+ approx[i] = residualParams->approx[i] * residualParams->windowScale;
+}
+
+/*! \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;
+ int sizeHop = pSynthParams->sizeHop;
+
+ 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)
+ SineSynthIFFT(pSmsData, pSynthParams);
+ else /*pSynthParams->iDetSynthType == SMS_DET_SIN*/
+ {
+ sms_sineSynthFrame(pSmsData, pSynthParams->pSynthBuff, 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, pSynthParams->sizeHop,
+ &(pSynthParams->prevFrame), pSynthParams->iSamplingRate);
+ }
+ }
+ else /* pSynthParams->iSynthesisType == SMS_STYPE_STOC */
+ StocSynthApprox(pSmsData, pSynthParams);
+
+ /* de-emphasize the sound and normalize*/
+ for(i = 0; i < sizeHop; i++)
+ pFSynthesis[i] = sms_deEmphasis(pSynthParams->pSynthBuff[i], pSynthParams);
+}