diff options
Diffstat (limited to 'src/sms/sineSynth.c')
-rw-r--r-- | src/sms/sineSynth.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/sms/sineSynth.c b/src/sms/sineSynth.c new file mode 100644 index 0000000..9882062 --- /dev/null +++ b/src/sms/sineSynth.c @@ -0,0 +1,190 @@ +/* + * 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 sineSynth.c + * \brief functions for synthesizing evolving sinusoids + */ + +#include "sms.h" + +/*! \brief generate a sinusoid given two peaks, current and last + * + * it interpolation between phase values and magnitudes + * + * \param fFreq current frequency + * \param fMag current magnitude + * \param fPhase current phase + * \param pLastFrame stucture with values from last frame + * \param pFWaveform pointer to output waveform + * \param sizeBuffer size of the synthesis buffer + * \param iTrack current track + */ +static void SinePhaSynth(sfloat fFreq, sfloat fMag, sfloat fPhase, + SMS_Data *pLastFrame, sfloat *pFWaveform, + int sizeBuffer, int iTrack) +{ + sfloat fMagIncr, fInstMag, fInstPhase, fTmp; + int iM, i; + sfloat fAlpha, fBeta, fTmp1, fTmp2; + + /* if no mag in last frame copy freq from current and make phase */ + if(pLastFrame->pFSinAmp[iTrack] <= 0) + { + pLastFrame->pFSinFreq[iTrack] = fFreq; + fTmp = fPhase - (fFreq * sizeBuffer); + pLastFrame->pFSinPha[iTrack] = fTmp - floor(fTmp / TWO_PI) * TWO_PI; + } + /* and the other way */ + else if(fMag <= 0) + { + fFreq = pLastFrame->pFSinFreq[iTrack]; + fTmp = pLastFrame->pFSinPha[iTrack] + + (pLastFrame->pFSinFreq[iTrack] * sizeBuffer); + fPhase = fTmp - floor(fTmp / TWO_PI) * TWO_PI; + } + + /* caculate the instantaneous amplitude */ + fMagIncr = (fMag - pLastFrame->pFSinAmp[iTrack]) / sizeBuffer; + fInstMag = pLastFrame->pFSinAmp[iTrack]; + + /* create instantaneous phase from freq. and phase values */ + fTmp1 = fFreq - pLastFrame->pFSinFreq[iTrack]; + fTmp2 = ((pLastFrame->pFSinPha[iTrack] + + pLastFrame->pFSinFreq[iTrack] * sizeBuffer - fPhase) + + fTmp1 * sizeBuffer / 2.0) / TWO_PI; + iM = (int)(fTmp2 + .5); + fTmp2 = fPhase - pLastFrame->pFSinPha[iTrack] - + pLastFrame->pFSinFreq[iTrack] * sizeBuffer + TWO_PI * iM; + fAlpha = (3.0 / (sfloat)(sizeBuffer * sizeBuffer)) * + fTmp2 - fTmp1 / sizeBuffer; + fBeta = (-2.0 / ((sfloat) (sizeBuffer * sizeBuffer * sizeBuffer))) * + fTmp2 + fTmp1 / ((sfloat) (sizeBuffer * sizeBuffer)); + + for(i=0; i<sizeBuffer; i++) + { + fInstMag += fMagIncr; + fInstPhase = pLastFrame->pFSinPha[iTrack] + + pLastFrame->pFSinFreq[iTrack] * i + + fAlpha * i * i + fBeta * i * i * i; + + /*pFWaveform[i] += sms_dBToMag(fInstMag) * sms_sine(fInstPhase + PI_2);*/ + pFWaveform[i] += sms_dBToMag(fInstMag) * sinf(fInstPhase + PI_2); + } + + /* save current values into buffer */ + pLastFrame->pFSinFreq[iTrack] = fFreq; + pLastFrame->pFSinAmp[iTrack] = fMag; + pLastFrame->pFSinPha[iTrack] = fPhase; +} + +/*! \brief generate a sinusoid given two frames, current and last + * + * \param fFreq current frequency + * \param fMag current magnitude + * \param pLastFrame stucture with values from last frame + * \param pFBuffer pointer to output waveform + * \param sizeBuffer size of the synthesis buffer + * \param iTrack current track + */ +static void SineSynth(sfloat fFreq, sfloat fMag, SMS_Data *pLastFrame, + sfloat *pFBuffer, int sizeBuffer, int iTrack) +{ + sfloat fMagIncr, fInstMag, fFreqIncr, fInstPhase, fInstFreq; + int i; + + /* if no mag in last frame copy freq from current */ + if(pLastFrame->pFSinAmp[iTrack] <= 0) + { + pLastFrame->pFSinFreq[iTrack] = fFreq; + pLastFrame->pFSinPha[iTrack] = TWO_PI * sms_random(); + } + /* and the other way */ + else if(fMag <= 0) + fFreq = pLastFrame->pFSinFreq[iTrack]; + + /* calculate the instantaneous amplitude */ + fMagIncr = (fMag - pLastFrame->pFSinAmp[iTrack]) / sizeBuffer; + fInstMag = pLastFrame->pFSinAmp[iTrack]; + /* calculate instantaneous frequency */ + fFreqIncr = (fFreq - pLastFrame->pFSinFreq[iTrack]) / sizeBuffer; + fInstFreq = pLastFrame->pFSinFreq[iTrack]; + fInstPhase = pLastFrame->pFSinPha[iTrack]; + + /* generate all the samples */ + for(i = 0; i < sizeBuffer; i++) + { + fInstMag += fMagIncr; + fInstFreq += fFreqIncr; + fInstPhase += fInstFreq; + pFBuffer[i] += sms_dBToMag(fInstMag) * sms_sine(fInstPhase); + } + + /* save current values into last values */ + pLastFrame->pFSinFreq[iTrack] = fFreq; + pLastFrame->pFSinAmp[iTrack] = fMag; + pLastFrame->pFSinPha[iTrack] = fInstPhase - floor(fInstPhase / TWO_PI) * TWO_PI; +} + +/*! \brief generate all the sinusoids for a given frame + * + * \param pSmsData SMS data for current frame + * \param pFBuffer pointer to output waveform + * \param sizeBuffer size of the synthesis buffer + * \param pLastFrame SMS data from last frame + * \param iSamplingRate sampling rate to synthesize for + */ +void sms_sineSynthFrame(SMS_Data *pSmsData, sfloat *pFBuffer, + int sizeBuffer, SMS_Data *pLastFrame, + int iSamplingRate) +{ + sfloat fMag, fFreq; + int i; + int nTracks = pSmsData->nTracks; + int iHalfSamplingRate = iSamplingRate >> 1; + + /* go through all the tracks */ + for(i = 0; i < nTracks; i++) + { + fMag = pSmsData->pFSinAmp[i]; + fFreq = pSmsData->pFSinFreq[i]; + + /* make that sure transposed frequencies don't alias */ + if(fFreq > iHalfSamplingRate || fFreq < 0) + fMag = 0; + + /* generate sines if there are magnitude values */ + if((fMag > 0) || (pLastFrame->pFSinAmp[i] > 0)) + { + /* frequency from Hz to radians */ + fFreq = (fFreq == 0) ? 0 : TWO_PI * fFreq / iSamplingRate; + + /* \todo make seperate function for SineSynth /wo phase */ + if(pSmsData->pFSinPha == NULL) + { + SineSynth(fFreq, fMag, pLastFrame, pFBuffer, sizeBuffer, i); + } + else + { + SinePhaSynth(fFreq, fMag, pSmsData->pFSinPha[i], pLastFrame, + pFBuffer, sizeBuffer, i); + } + } + } +} |