/* * 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 fixTracks.c * \brief functions for making smoothly evolving tracks (partial frequencies) * * Tries to fix gaps and short tracks */ #include "sms.h" /*! \brief fill a gap in a given track * * \param iCurrentFrame currrent frame number * \param iTrack track to be filled * \param pIState pointer to the state of tracks * \param pAnalParams pointer to analysis parameters */ static void FillGap(int iCurrentFrame, int iTrack, int *pIState, SMS_AnalParams *pAnalParams) { int iFrame, iLastFrame = - (pIState[iTrack] - 1); sfloat fConstant = TWO_PI / pAnalParams->iSamplingRate; sfloat fFirstMag, fFirstFreq, fLastMag, fLastFreq, fIncrMag, fIncrFreq, fMag, fTmpPha, fFreq; if(iCurrentFrame - iLastFrame < 0) return; /* if firstMag is 0 it means that there is no Gap, just the begining of a track */ if(pAnalParams->ppFrames[iCurrentFrame - iLastFrame]->deterministic.pFSinAmp[iTrack] == 0) { pIState[iTrack] = 1; return; } fFirstMag = pAnalParams->ppFrames[iCurrentFrame - iLastFrame]->deterministic.pFSinAmp[iTrack]; fFirstFreq = pAnalParams->ppFrames[iCurrentFrame - iLastFrame]->deterministic.pFSinFreq[iTrack]; fLastMag = pAnalParams->ppFrames[iCurrentFrame]->deterministic.pFSinAmp[iTrack]; fLastFreq = pAnalParams->ppFrames[iCurrentFrame]->deterministic.pFSinFreq[iTrack]; fIncrMag = (fLastMag - fFirstMag) / iLastFrame; fIncrFreq = (fLastFreq - fFirstFreq) / iLastFrame; /* if inharmonic format and the two extremes are very different */ /* do not interpolate, it means that they are different tracks */ if((pAnalParams->iFormat == SMS_FORMAT_IH || pAnalParams->iFormat == SMS_FORMAT_IHP) && (MIN (fFirstFreq, fLastFreq) * .5 * pAnalParams->fFreqDeviation < fabs(fLastFreq - fFirstFreq))) { pIState[iTrack] = 1; return; } fMag = fFirstMag; fFreq = fFirstFreq; /* fill the gap by interpolating values */ /* if the gap is too long it should consider the lower partials */ for(iFrame = iCurrentFrame - iLastFrame + 1; iFrame < iCurrentFrame; iFrame++) { /* interpolate magnitude */ fMag += fIncrMag; pAnalParams->ppFrames[iFrame]->deterministic.pFSinAmp[iTrack] = fMag; /* interpolate frequency */ fFreq += fIncrFreq; pAnalParams->ppFrames[iFrame]->deterministic.pFSinFreq[iTrack] = fFreq; /*interpolate phase (this may not be the right way) */ fTmpPha = pAnalParams->ppFrames[iFrame-1]->deterministic.pFSinPha[iTrack] - (pAnalParams->ppFrames[iFrame-1]->deterministic.pFSinFreq[iTrack] * fConstant) * pAnalParams->sizeHop; pAnalParams->ppFrames[iFrame]->deterministic.pFSinPha[iTrack] = fTmpPha - floor(fTmpPha/ TWO_PI) * TWO_PI; } if(pAnalParams->iDebugMode == SMS_DBG_CLEAN_TRAJ || pAnalParams->iDebugMode == SMS_DBG_ALL) { fprintf (stdout, "fillGap: track %d, frames %d to %d filled\n", iTrack, pAnalParams->ppFrames[iCurrentFrame-iLastFrame + 1]->iFrameNum, pAnalParams->ppFrames[iCurrentFrame-1]->iFrameNum); fprintf (stdout, "firstFreq %f lastFreq %f, firstMag %f lastMag %f\n", fFirstFreq, fLastFreq, fFirstMag, fLastMag); } /* reset status */ pIState[iTrack] = pAnalParams->iMinTrackLength; } /*! \brief delete a short track * * this function is not exported to sms.h * * \param iCurrentFrame current frame * \param iTrack track to be deleted * \param pIState pointer to the state of tracks * \param pAnalParams pointer to analysis parameters */ static void DeleteShortTrack(int iCurrentFrame, int iTrack, int *pIState, SMS_AnalParams *pAnalParams) { int iFrame, frame; for(iFrame = 1; iFrame <= pIState[iTrack]; iFrame++) { frame = iCurrentFrame - iFrame; if(frame <= 0) return; pAnalParams->ppFrames[frame]->deterministic.pFSinAmp[iTrack] = 0; pAnalParams->ppFrames[frame]->deterministic.pFSinFreq[iTrack] = 0; pAnalParams->ppFrames[frame]->deterministic.pFSinPha[iTrack] = 0; } if(pAnalParams->iDebugMode == SMS_DBG_CLEAN_TRAJ || pAnalParams->iDebugMode == SMS_DBG_ALL) fprintf(stdout, "deleteShortTrack: track %d, frames %d to %d deleted\n", iTrack, pAnalParams->ppFrames[iCurrentFrame - pIState[iTrack]]->iFrameNum, pAnalParams->ppFrames[iCurrentFrame-1]->iFrameNum); /* reset state */ pIState[iTrack] = -pAnalParams->iMaxSleepingTime; } /*! \brief fill gaps and delete short tracks * * \param iCurrentFrame current frame number * \param pAnalParams pointer to analysis parameters */ void sms_cleanTracks(int iCurrentFrame, SMS_AnalParams *pAnalParams) { int iTrack, iLength, iFrame; /* if fundamental and first partial are short, delete everything */ if((pAnalParams->iFormat == SMS_FORMAT_H || pAnalParams->iFormat == SMS_FORMAT_HP) && pAnalParams->ppFrames[iCurrentFrame]->deterministic.pFSinAmp[0] == 0 && pAnalParams->guideStates[0] > 0 && pAnalParams->guideStates[0] < pAnalParams->iMinTrackLength && pAnalParams->ppFrames[iCurrentFrame]->deterministic.pFSinAmp[1] == 0 && pAnalParams->guideStates[1] > 0 && pAnalParams->guideStates[1] < pAnalParams->iMinTrackLength) { iLength = pAnalParams->guideStates[0]; for(iTrack = 0; iTrack < pAnalParams->nGuides; iTrack++) { for(iFrame = 1; iFrame <= iLength; iFrame++) { if((iCurrentFrame - iFrame) >= 0) { pAnalParams->ppFrames[iCurrentFrame - iFrame]->deterministic.pFSinAmp[iTrack] = 0; pAnalParams->ppFrames[iCurrentFrame - iFrame]->deterministic.pFSinFreq[iTrack] = 0; pAnalParams->ppFrames[iCurrentFrame - iFrame]->deterministic.pFSinPha[iTrack] = 0; } } pAnalParams->guideStates[iTrack] = -pAnalParams->iMaxSleepingTime; } if(pAnalParams->iDebugMode == SMS_DBG_CLEAN_TRAJ || pAnalParams->iDebugMode == SMS_DBG_ALL) { fprintf(stdout, "cleanTrack: frame %d to frame %d deleted\n", pAnalParams->ppFrames[iCurrentFrame-iLength]->iFrameNum, pAnalParams->ppFrames[iCurrentFrame-1]->iFrameNum); } return; } /* check every partial individually */ for(iTrack = 0; iTrack < pAnalParams->nGuides; iTrack++) { /* track after gap */ if(pAnalParams->ppFrames[iCurrentFrame]->deterministic.pFSinAmp[iTrack] != 0) { if(pAnalParams->guideStates[iTrack] < 0 && pAnalParams->guideStates[iTrack] > -pAnalParams->iMaxSleepingTime) FillGap (iCurrentFrame, iTrack, pAnalParams->guideStates, pAnalParams); else pAnalParams->guideStates[iTrack] = (pAnalParams->guideStates[iTrack]<0) ? 1 : pAnalParams->guideStates[iTrack]+1; } /* gap after track */ else { if(pAnalParams->guideStates[iTrack] > 0 && pAnalParams->guideStates[iTrack] < pAnalParams->iMinTrackLength) DeleteShortTrack (iCurrentFrame, iTrack, pAnalParams->guideStates, pAnalParams); else pAnalParams->guideStates[iTrack] = (pAnalParams->guideStates[iTrack]>0) ? -1 : pAnalParams->guideStates[iTrack]-1; } } return; } /*! \brief scale deterministic magnitude if synthesis is larger than original * * \param pFSynthBuffer synthesis buffer * \param pFOriginalBuffer original sound * \param pFSinAmp magnitudes to be scaled * \param pAnalParams pointer to analysis parameters * \param nTrack number of tracks */ void sms_scaleDet(sfloat *pFSynthBuffer, sfloat *pFOriginalBuffer, sfloat *pFSinAmp, SMS_AnalParams *pAnalParams, int nTrack) { sfloat fOriginalMag = 0, fSynthesisMag = 0; sfloat fCosScaleFactor; int iTrack, i; /* get sound energy */ for(i = 0; i < pAnalParams->sizeHop; i++) { fOriginalMag += fabs(pFOriginalBuffer[i]); fSynthesisMag += fabs(pFSynthBuffer[i]); } /* if total energy of deterministic sound is larger than original, scale deterministic representation */ if(fSynthesisMag > (1.5 * fOriginalMag)) { fCosScaleFactor = fOriginalMag / fSynthesisMag; if(pAnalParams->iDebugMode == SMS_DBG_CLEAN_TRAJ || pAnalParams->iDebugMode == SMS_DBG_ALL) fprintf(stdout, "Frame %d: magnitude scaled by %f\n", pAnalParams->ppFrames[0]->iFrameNum, fCosScaleFactor); for(iTrack = 0; iTrack < nTrack; iTrack++) if(pFSinAmp[iTrack] > 0) pFSinAmp[iTrack] = sms_magToDB(sms_dBToMag(pFSinAmp[iTrack]) * fCosScaleFactor); } }