From 416bd737074a287ea47106c73ea6bcfde40a75a8 Mon Sep 17 00:00:00 2001 From: John Glover Date: Fri, 24 Jun 2011 18:17:23 +0100 Subject: Change to using distutils. Currently only builds the simplsndobj module --- src/sms/analysis.c | 563 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 563 insertions(+) create mode 100644 src/sms/analysis.c (limited to 'src/sms/analysis.c') diff --git a/src/sms/analysis.c b/src/sms/analysis.c new file mode 100644 index 0000000..89d4b4a --- /dev/null +++ b/src/sms/analysis.c @@ -0,0 +1,563 @@ +/* + * 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) +{ + int i, iFrame; + SMS_AnalFrame *pCurrentFrame = pAnalParams->ppFrames[iCurrentFrame]; + int iSoundLoc = pCurrentFrame->iFrameSample -((pCurrentFrame->iFrameSize + 1) >> 1) + 1; + sfloat *pFData = &(pAnalParams->soundBuffer.pFBuffer[iSoundLoc - pAnalParams->soundBuffer.iMarker]); + + /* TODO: this doesn't have to be done every time */ + int sizeWindow = pCurrentFrame->iFrameSize; + int 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) + { + 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 + * 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) +{ + int i; + SMS_AnalFrame *tempFrame; + int currentFrame = pAnalParams->iMaxDelayFrames - 1; /* frame # of current frame */ + + /* 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[pAnalParams->iMaxDelayFrames-1] = 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) +{ + int currentFrame = pAnalParams->iMaxDelayFrames - 1; + + /* 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); + + /* incorporate the peaks into the corresponding tracks */ + 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); + } + + /* fill gaps and delete short tracks */ + if(pAnalParams->iCleanTracks > 0) + { + sms_cleanTracks(currentFrame-delayFrames, pAnalParams); + } + + /* output data */ + 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); + + return 1; +} + +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; +} -- cgit v1.2.3