/* * 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 analysis.c * \brief main sms analysis routines * * the analysis routine here calls all necessary functions to perform the complete * SMS analysis, once the desired analysis parameters are set in SMS_AnalParams. */ #include "sms.h" /*! \brief maximum size for magnitude spectrum */ #define SMS_MAX_SPEC 8192 /*! \brief compute spectrum, find peaks, and fundamental of one frame * * This is the main core of analysis calls * * \param iCurrentFrame frame number to be computed * \param pAnalParams structure of analysis parameters * \param fRefFundamental reference fundamental */ void sms_analyzeFrame(int iCurrentFrame, SMS_AnalParams *pAnalParams, sfloat fRefFundamental) { SMS_AnalFrame *pCurrentFrame = pAnalParams->ppFrames[iCurrentFrame]; sfloat *pFData; int i, iFrame, sizeMag; int sizeWindow = pCurrentFrame->iFrameSize; if(pAnalParams->realtime == 0) { int iSoundLoc = pCurrentFrame->iFrameSample - ((pCurrentFrame->iFrameSize + 1) >> 1) + 1; pFData = &(pAnalParams->soundBuffer.pFBuffer[ iSoundLoc - pAnalParams->soundBuffer.iMarker ]); } else { pFData = &(pAnalParams->soundBuffer.pFBuffer[ pAnalParams->soundBuffer.sizeBuffer - sizeWindow ]); } /* TODO: this doesn't have to be done every time */ sizeMag = sms_power2(sizeWindow); sms_getWindow(sizeWindow, pAnalParams->spectrumWindow, pAnalParams->iWindowType); sms_scaleWindow(sizeWindow, pAnalParams->spectrumWindow); /* compute the magnitude and (zero-windowed) phase spectra */ sms_spectrum(sizeWindow, pFData, pAnalParams->spectrumWindow, sizeMag, pAnalParams->magSpectrum, pAnalParams->phaseSpectrum, pAnalParams->fftBuffer); /* convert magnitude spectra to dB */ sms_arrayMagToDB(sizeMag, pAnalParams->magSpectrum); /* find the prominent peaks */ pCurrentFrame->nPeaks = sms_detectPeaks(sizeMag, pAnalParams->magSpectrum, pAnalParams->phaseSpectrum, pCurrentFrame->pSpectralPeaks, pAnalParams); /* find a reference harmonic */ if(pCurrentFrame->nPeaks > 0 && (pAnalParams->iFormat == SMS_FORMAT_H || pAnalParams->iFormat == SMS_FORMAT_HP)) { pCurrentFrame->fFundamental = sms_harmDetection( pAnalParams->maxPeaks, pCurrentFrame->pSpectralPeaks, fRefFundamental, pAnalParams->iRefHarmonic, pAnalParams->fLowestFundamental, pAnalParams->fHighestFundamental, pAnalParams->iSoundType, pAnalParams->fMinRefHarmMag, pAnalParams->fRefHarmMagDiffFromMax ); } } /*! \brief re-analyze the previous frames if necessary * * \todo explain when this is necessary * * \param iCurrentFrame current frame number * \param pAnalParams structure with analysis parameters * \return 1 if frames are good, -1 if analysis is necessary * \todo is the return value info correct? Why isn't it used in sms_analyze? */ static int ReAnalyzeFrame(int iCurrentFrame, SMS_AnalParams *pAnalParams) { sfloat fFund, fLastFund, fDev; int iNewFrameSize, i; sfloat fAvgDeviation = sms_fundDeviation(pAnalParams, iCurrentFrame); int iFirstFrame = iCurrentFrame - pAnalParams->minGoodFrames; /*! \todo make this a < 0 check, but first make sure sms_fundDeviation does not return values below zero */ if(fAvgDeviation == -1) return -1; /* if the last SMS_MIN_GOOD_FRAMES are stable look before them */ /* and recompute the frames that are not stable */ if (fAvgDeviation <= pAnalParams->maxDeviation) { for(i = 0; i < pAnalParams->analDelay; i++) { if(pAnalParams->ppFrames[iFirstFrame - i]->iFrameNum <= 0 || pAnalParams->ppFrames[iFirstFrame - i]->iStatus == SMS_FRAME_RECOMPUTED) return -1; fFund = pAnalParams->ppFrames[iFirstFrame - i]->fFundamental; fLastFund = pAnalParams->ppFrames[iFirstFrame - i + 1]->fFundamental; fDev = fabs (fFund - fLastFund) / fLastFund; iNewFrameSize = ((pAnalParams->iSamplingRate / fLastFund) * pAnalParams->fSizeWindow/2) * 2 + 1; if(fFund <= 0 || fDev > .2 || fabs((double)(pAnalParams->ppFrames[iFirstFrame - i]->iFrameSize - iNewFrameSize)) / iNewFrameSize >= .2) { pAnalParams->ppFrames[iFirstFrame - i]->iFrameSize = iNewFrameSize; pAnalParams->ppFrames[iFirstFrame - i]->iStatus = SMS_FRAME_READY; /* recompute frame */ sms_analyzeFrame(iFirstFrame - i, pAnalParams, fLastFund); pAnalParams->ppFrames[iFirstFrame - i]->iStatus = SMS_FRAME_RECOMPUTED; if(fabs(pAnalParams->ppFrames[iFirstFrame - i]->fFundamental - fLastFund) / fLastFund >= .2) return -1; } } } return 1; } int sms_findPeaks(int sizeWaveform, sfloat *pWaveform, SMS_AnalParams *pAnalParams, SMS_SpectralPeaks *pSpectralPeaks) { int iCurrentFrame = pAnalParams->iMaxDelayFrames - 1; /* frame # of current frame */ sfloat fRefFundamental = 0; /* reference fundamental for current frame */ int i, iError, iExtraSamples; /* samples used for next analysis frame */ SMS_AnalFrame *pTmpAnalFrame; /* set initial analysis-window size */ if(pAnalParams->windowSize == 0) pAnalParams->windowSize = pAnalParams->iDefaultSizeWindow; /* fill sound buffer and perform pre-emphasis */ if(sizeWaveform > 0) sms_fillSoundBuffer(sizeWaveform, pWaveform, pAnalParams); /* move analysis data one frame back */ pTmpAnalFrame = pAnalParams->ppFrames[0]; for(i = 1; i < pAnalParams->iMaxDelayFrames; i++) pAnalParams->ppFrames[i-1] = pAnalParams->ppFrames[i]; pAnalParams->ppFrames[pAnalParams->iMaxDelayFrames-1] = pTmpAnalFrame; /* initialize the current frame */ sms_initFrame(iCurrentFrame, pAnalParams, pAnalParams->windowSize); if(pAnalParams->ppFrames[iCurrentFrame]->iStatus == SMS_FRAME_READY) { if(pAnalParams->realtime == 1) { pAnalParams->ppFrames[iCurrentFrame]->iFrameSize = sizeWaveform; pAnalParams->windowSize = sizeWaveform; pAnalParams->sizeNextRead = sizeWaveform; } sfloat fAvgDev = sms_fundDeviation(pAnalParams, iCurrentFrame - 1); /* if single note use the default fundamental as reference */ if(pAnalParams->iSoundType == SMS_SOUND_TYPE_NOTE) fRefFundamental = pAnalParams->fDefaultFundamental; /* if sound is stable use the last fundamental as a reference */ else if(fAvgDev != -1 && fAvgDev <= pAnalParams->maxDeviation) fRefFundamental = pAnalParams->ppFrames[iCurrentFrame - 1]->fFundamental; else fRefFundamental = 0; /* compute spectrum, find peaks, and find fundamental of frame */ sms_analyzeFrame(iCurrentFrame, pAnalParams, fRefFundamental); /* set the size of the next analysis window if not in real-time mode */ if(pAnalParams->realtime == 0) { /* set the size of the next analysis window */ if(pAnalParams->ppFrames[iCurrentFrame]->fFundamental > 0 && pAnalParams->iSoundType != SMS_SOUND_TYPE_NOTE) { pAnalParams->windowSize = sms_sizeNextWindow(iCurrentFrame, pAnalParams); } /* figure out how much needs to be read next time * how many processed - sample no. of end of next frame * = no. samples that we haven't processed yet from whenever, if sizeNextRead was 0 */ iExtraSamples = (pAnalParams->soundBuffer.iMarker + pAnalParams->soundBuffer.sizeBuffer) - (pAnalParams->ppFrames[iCurrentFrame]->iFrameSample + pAnalParams->sizeHop); pAnalParams->sizeNextRead = MAX(0, (pAnalParams->windowSize+1)/2 - iExtraSamples); ReAnalyzeFrame(iCurrentFrame, pAnalParams); } /* save peaks */ pSpectralPeaks->nPeaksFound = pAnalParams->ppFrames[iCurrentFrame]->nPeaks; pSpectralPeaks->nPeaks = pAnalParams->maxPeaks; for(i = 0; i < pSpectralPeaks->nPeaks; i++) { if(i < pSpectralPeaks->nPeaksFound) { pSpectralPeaks->pSpectralPeaks[i].fMag = sms_dBToMag(pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks[i].fMag); pSpectralPeaks->pSpectralPeaks[i].fFreq = pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks[i].fFreq; pSpectralPeaks->pSpectralPeaks[i].fPhase = pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks[i].fPhase; } else { pSpectralPeaks->pSpectralPeaks[i].fMag = 0.0; pSpectralPeaks->pSpectralPeaks[i].fFreq = 0.0; pSpectralPeaks->pSpectralPeaks[i].fPhase = 0.0; } } return pSpectralPeaks->nPeaks; } else { return 0; } } void sms_setPeaks(SMS_AnalParams *pAnalParams, int numamps, sfloat* amps, int numfreqs, sfloat* freqs, int numphases, sfloat* phases) { if(pAnalParams->iMaxDelayFrames < 2) { printf("Error: iMaxDelayFrames analysis parameter must be at least 2" " (currently set to %d)\n", pAnalParams->iMaxDelayFrames); return; } int i; SMS_AnalFrame *tempFrame; int currentFrame = pAnalParams->iMaxDelayFrames > 2 ? pAnalParams->iMaxDelayFrames - 1 : 1; /* move analysis data one frame back */ tempFrame = pAnalParams->ppFrames[0]; for(i = 1; i < pAnalParams->iMaxDelayFrames; i++) { pAnalParams->ppFrames[i - 1] = pAnalParams->ppFrames[i]; } pAnalParams->ppFrames[currentFrame] = tempFrame; /* initialize the current frame */ SMS_AnalFrame *frame = pAnalParams->ppFrames[currentFrame]; sms_initFrame(currentFrame, pAnalParams, 0); if(sms_errorCheck()) { printf("Error in init frame: %s \n", sms_errorString()); return; } for(i = 0; i < numamps; i++) { /* copy current peaks data */ frame->pSpectralPeaks[i].fMag = sms_magToDB(amps[i]); frame->pSpectralPeaks[i].fFreq = freqs[i]; frame->pSpectralPeaks[i].fPhase = phases[i]; } frame->nPeaks = numamps; frame->iStatus = SMS_FRAME_READY; /* harmonic detection */ if(frame->nPeaks > 0 && (pAnalParams->iFormat == SMS_FORMAT_H || pAnalParams->iFormat == SMS_FORMAT_HP)) { /* get a reference fundamental */ sfloat refFundamental = 0; sfloat avgDeviation = sms_fundDeviation(pAnalParams, currentFrame - 1); if(pAnalParams->iSoundType == SMS_SOUND_TYPE_NOTE) { refFundamental = pAnalParams->fDefaultFundamental; } /* if sound is stable use the last fundamental as a reference */ else if(avgDeviation != -1 && avgDeviation <= pAnalParams->maxDeviation) { refFundamental = pAnalParams->ppFrames[currentFrame-1]->fFundamental; } else { refFundamental = 0; } frame->fFundamental = sms_harmDetection(frame->nPeaks, frame->pSpectralPeaks, refFundamental, pAnalParams->iRefHarmonic, pAnalParams->fLowestFundamental, pAnalParams->fHighestFundamental, pAnalParams->iSoundType, pAnalParams->fMinRefHarmMag, pAnalParams->fRefHarmMagDiffFromMax); } } int sms_findPartials(SMS_Data *pSmsData, SMS_AnalParams *pAnalParams) { if(pAnalParams->iMaxDelayFrames < 2) { printf("Error: iMaxDelayFrames analysis parameter must be at least 2" " (currently set to %d)\n", pAnalParams->iMaxDelayFrames); return 1; } int currentFrame = pAnalParams->iMaxDelayFrames > 2 ? pAnalParams->iMaxDelayFrames - 1 : 1; int delayFrames = pAnalParams->minGoodFrames + pAnalParams->analDelay; if(delayFrames >= currentFrame) { printf("Error: analysis delay is too large (%d, max is %d)\n", delayFrames, currentFrame - 1); return 1; } sms_clearFrame(pSmsData); if(pAnalParams->ppFrames[currentFrame - delayFrames]->fFundamental > 0 || ((pAnalParams->iFormat == SMS_FORMAT_IH || pAnalParams->iFormat == SMS_FORMAT_IHP) && pAnalParams->ppFrames[currentFrame - delayFrames]->nPeaks > 0)) { sms_peakContinuation(currentFrame - delayFrames, pAnalParams); } if(pAnalParams->iCleanTracks > 0) { sms_cleanTracks(currentFrame - delayFrames, pAnalParams); } int length = sizeof(sfloat) * pSmsData->nTracks; memcpy((char *) pSmsData->pFSinFreq, (char *) pAnalParams->ppFrames[0]->deterministic.pFSinFreq, length); memcpy((char *) pSmsData->pFSinAmp, (char *) pAnalParams->ppFrames[0]->deterministic.pFSinAmp, length); sms_arrayDBToMag(pSmsData->nTracks, pSmsData->pFSinAmp); if(pAnalParams->iFormat == SMS_FORMAT_HP || pAnalParams->iFormat == SMS_FORMAT_IHP) { memcpy((char *) pSmsData->pFSinPha, (char *) pAnalParams->ppFrames[0]->deterministic.pFSinPha, length); } return 0; } int sms_findResidual(int sizeSynthesis, sfloat* pSynthesis, int sizeOriginal, sfloat* pOriginal, SMS_ResidualParams *residualParams) { if(residualParams->hopSize < sizeOriginal) { sms_error("Residual signal length is smaller than the original signal length"); return -1; } sms_residual(residualParams->hopSize, pSynthesis, pOriginal, residualParams); sms_filterHighPass(residualParams->hopSize, residualParams->residual, residualParams->samplingRate); return 0; } int sms_analyze(int sizeWaveform, sfloat *pWaveform, SMS_Data *pSmsData, SMS_AnalParams *pAnalParams) { int iCurrentFrame = pAnalParams->iMaxDelayFrames - 1; /* frame # of current frame */ int i, iError, iExtraSamples; /* samples used for next analysis frame */ sfloat fRefFundamental = 0; /* reference fundamental for current frame */ SMS_AnalFrame *pTmpAnalFrame; /* set the frame delay, checking that it does not exceed the given maximum * * TODO: check for good values of pAnalParams->minGoodFrames and * pAnalParams->analDelay here too? Or figure out why sms_crashes if * pAnalParamx->iMaxDelayFrames is changed without changing the other * two variables. */ int delayFrames = pAnalParams->minGoodFrames + pAnalParams->analDelay; if(delayFrames > (pAnalParams->iMaxDelayFrames - 1)) delayFrames = pAnalParams->iMaxDelayFrames - 1; /* clear SMS output */ sms_clearFrame(pSmsData); /* set initial analysis-window size */ if(pAnalParams->windowSize == 0) pAnalParams->windowSize = pAnalParams->iDefaultSizeWindow; /* fill the input sound buffer and perform pre-emphasis */ if(sizeWaveform > 0) sms_fillSoundBuffer(sizeWaveform, pWaveform, pAnalParams); /* move analysis data one frame back */ pTmpAnalFrame = pAnalParams->ppFrames[0]; for(i = 1; i < pAnalParams->iMaxDelayFrames; i++) pAnalParams->ppFrames[i-1] = pAnalParams->ppFrames[i]; pAnalParams->ppFrames[pAnalParams->iMaxDelayFrames-1] = pTmpAnalFrame; /* initialize the current frame */ sms_initFrame(iCurrentFrame, pAnalParams, pAnalParams->windowSize); if(sms_errorCheck()) { printf("error in init frame: %s \n", sms_errorString()); return -1; } /* if right data in the sound buffer do analysis */ if(pAnalParams->ppFrames[iCurrentFrame]->iStatus == SMS_FRAME_READY) { sfloat fAvgDev = sms_fundDeviation(pAnalParams, iCurrentFrame - 1); /* if single note use the default fundamental as reference */ if(pAnalParams->iSoundType == SMS_SOUND_TYPE_NOTE) fRefFundamental = pAnalParams->fDefaultFundamental; /* if sound is stable use the last fundamental as a reference */ else if(fAvgDev != -1 && fAvgDev <= pAnalParams->maxDeviation) fRefFundamental = pAnalParams->ppFrames[iCurrentFrame - 1]->fFundamental; else fRefFundamental = 0; /* compute spectrum, find peaks, and find fundamental of frame */ sms_analyzeFrame(iCurrentFrame, pAnalParams, fRefFundamental); /* set the size of the next analysis window */ if(pAnalParams->ppFrames[iCurrentFrame]->fFundamental > 0 && pAnalParams->iSoundType != SMS_SOUND_TYPE_NOTE) pAnalParams->windowSize = sms_sizeNextWindow (iCurrentFrame, pAnalParams); /* figure out how much needs to be read next time */ iExtraSamples = (pAnalParams->soundBuffer.iMarker + pAnalParams->soundBuffer.sizeBuffer) - (pAnalParams->ppFrames[iCurrentFrame]->iFrameSample + pAnalParams->sizeHop); pAnalParams->sizeNextRead = MAX(0, (pAnalParams->windowSize+1)/2 - iExtraSamples); /* check again the previous frames and recompute if necessary */ ReAnalyzeFrame(iCurrentFrame, pAnalParams); } /* incorporate the peaks into the corresponding tracks */ /* This is done after a pAnalParams->iMaxDelayFrames delay */ if(pAnalParams->ppFrames[iCurrentFrame - delayFrames]->fFundamental > 0 || ((pAnalParams->iFormat == SMS_FORMAT_IH || pAnalParams->iFormat == SMS_FORMAT_IHP) && pAnalParams->ppFrames[iCurrentFrame - delayFrames]->nPeaks > 0)) sms_peakContinuation(iCurrentFrame - delayFrames, pAnalParams); /* fill gaps and delete short tracks */ if(pAnalParams->iCleanTracks > 0 && pAnalParams->ppFrames[iCurrentFrame - delayFrames]->iStatus != SMS_FRAME_EMPTY) sms_cleanTracks(iCurrentFrame - delayFrames, pAnalParams); /* do stochastic analysis */ if(pAnalParams->iStochasticType != SMS_STOC_NONE) { /* synthesize deterministic signal */ if(pAnalParams->ppFrames[1]->iStatus != SMS_FRAME_EMPTY && pAnalParams->ppFrames[1]->iStatus != SMS_FRAME_END) { /* shift synthesis buffer */ memcpy(pAnalParams->synthBuffer.pFBuffer, pAnalParams->synthBuffer.pFBuffer+pAnalParams->sizeHop, sizeof(sfloat) * pAnalParams->sizeHop); memset(pAnalParams->synthBuffer.pFBuffer+pAnalParams->sizeHop, 0, sizeof(sfloat) * pAnalParams->sizeHop); /* get deterministic signal with phase */ sms_sineSynthFrame(&pAnalParams->ppFrames[1]->deterministic, pAnalParams->synthBuffer.pFBuffer+pAnalParams->sizeHop, pAnalParams->sizeHop, &pAnalParams->prevFrame, pAnalParams->iSamplingRate); } /* perform stochastic analysis after 1 frame of the */ /* deterministic synthesis because it needs two frames */ if(pAnalParams->ppFrames[0]->iStatus != SMS_FRAME_EMPTY && pAnalParams->ppFrames[0]->iStatus != SMS_FRAME_END) { int iSoundLoc = pAnalParams->ppFrames[0]->iFrameSample - pAnalParams->sizeHop; sfloat *pOriginal = &(pAnalParams->soundBuffer.pFBuffer[iSoundLoc - pAnalParams->soundBuffer.iMarker]); int sizeData = MIN(pAnalParams->soundBuffer.sizeBuffer - (iSoundLoc - pAnalParams->soundBuffer.iMarker), pAnalParams->residualParams.residualSize); if(sizeData > pAnalParams->residualParams.residualSize) { sms_error("Residual size larger than expected."); return -1; } else if(sizeData < pAnalParams->residualParams.residualSize) { /* should only happen if we're at the end of a sound, unless hop size changes */ /* TODO: should the window type be set to pAnalParams->iWindowType? */ sms_getWindow(sizeData, pAnalParams->residualParams.fftWindow, SMS_WIN_HAMMING); sms_scaleWindow(sizeData, pAnalParams->residualParams.fftWindow); } /* obtain residual sound from original and synthesized sounds. accumulate the residual percentage.*/ pAnalParams->fResidualAccumPerc += sms_residual(sizeData, pAnalParams->synthBuffer.pFBuffer, pOriginal, &pAnalParams->residualParams); if(pAnalParams->iStochasticType == SMS_STOC_APPROX) { /* filter residual with a high pass filter (it solves some problems) */ sms_filterHighPass(sizeData, pAnalParams->residualParams.residual, pAnalParams->iSamplingRate); /* approximate residual */ sms_stocAnalysis(sizeData, pAnalParams->residualParams.residual, pAnalParams->residualParams.fftWindow, pSmsData, pAnalParams); } else if(pAnalParams->iStochasticType == SMS_STOC_IFFT) { int sizeMag = sms_power2(sizeData >> 1); sms_spectrum(sizeData, pAnalParams->residualParams.residual, pAnalParams->residualParams.fftWindow, sizeMag, pSmsData->pFStocCoeff, pSmsData->pResPhase, pAnalParams->fftBuffer); } /* get sharper transitions in deterministic representation */ sms_scaleDet(pAnalParams->synthBuffer.pFBuffer, pOriginal, pAnalParams->ppFrames[0]->deterministic.pFSinAmp, pAnalParams, pSmsData->nTracks); pAnalParams->ppFrames[0]->iStatus = SMS_FRAME_DONE; } } else if(pAnalParams->ppFrames[0]->iStatus != SMS_FRAME_EMPTY && pAnalParams->ppFrames[0]->iStatus != SMS_FRAME_END) pAnalParams->ppFrames[0]->iStatus = SMS_FRAME_DONE; /* get the result */ if(pAnalParams->ppFrames[0]->iStatus == SMS_FRAME_EMPTY) { /* no partials yet, so output the current peaks for testing */ int numPeaks = pAnalParams->ppFrames[iCurrentFrame]->nPeaks; int numTracks = pSmsData->nTracks; numTracks = MIN(numPeaks, numTracks); for(i = 0; i < numTracks; i++) { pSmsData->pFSinFreq[i] = pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks[i].fFreq; pSmsData->pFSinAmp[i] = sms_dBToMag(pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks[i].fMag); if(pAnalParams->iFormat == SMS_FORMAT_HP || pAnalParams->iFormat == SMS_FORMAT_IHP) { pSmsData->pFSinPha[i] = pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks[i].fPhase; } } pSmsData->nTracks = numTracks; return 0; } /* return analysis data */ else if(pAnalParams->ppFrames[0]->iStatus == SMS_FRAME_DONE) { /* put data into output */ int length = sizeof(sfloat) * pSmsData->nTracks; memcpy((char *) pSmsData->pFSinFreq, (char *) pAnalParams->ppFrames[0]->deterministic.pFSinFreq, length); memcpy((char *) pSmsData->pFSinAmp, (char *) pAnalParams->ppFrames[0]->deterministic.pFSinAmp, length); /* convert mags back to linear */ sms_arrayDBToMag(pSmsData->nTracks, pSmsData->pFSinAmp); if(pAnalParams->iFormat == SMS_FORMAT_HP || pAnalParams->iFormat == SMS_FORMAT_IHP) memcpy((char *) pSmsData->pFSinPha, (char *) pAnalParams->ppFrames[0]->deterministic.pFSinPha, length); /* do post-processing (for now, spectral envelope calculation and storage) */ if(pAnalParams->specEnvParams.iType != SMS_ENV_NONE) { sms_spectralEnvelope(pSmsData, &pAnalParams->specEnvParams); } return 1; } /* done, end of sound */ else if(pAnalParams->ppFrames[0]->iStatus == SMS_FRAME_END) return -1; else { sms_error("sms_analyze error: wrong status of frame."); return -1; } return 1; }