diff options
-rw-r--r-- | SConstruct | 2 | ||||
-rw-r--r-- | sms.py | 39 | ||||
-rw-r--r-- | sms/analysis.c | 90 | ||||
-rw-r--r-- | sms/harmDetection.c | 490 | ||||
-rw-r--r-- | sms/peakContinuation.c | 14 | ||||
-rw-r--r-- | sms/peakDetection.c | 10 | ||||
-rw-r--r-- | sms/sms.c | 75 | ||||
-rw-r--r-- | sms/sms.h | 68 | ||||
-rw-r--r-- | sms/sms.i | 6 | ||||
-rw-r--r-- | tests/sms.py | 247 |
10 files changed, 462 insertions, 579 deletions
@@ -134,7 +134,7 @@ env.Append(CPPPATH = numpy_include) # check if we need debug symbols if env['debug']: - env.Append(CCFLAGS = "-g") + env.Append(CCFLAGS = "-g -O0") env = conf.Finish() @@ -45,7 +45,7 @@ class SMSPeakDetection(simpl.PeakDetection): self._analysis_params.iFormat = simplsms.SMS_FORMAT_HP self._analysis_params.nTracks = self._max_peaks self._analysis_params.maxPeaks = self._max_peaks - #self._analysis_params.nGuides = self._max_peaks + self._analysis_params.nGuides = self._max_peaks if simplsms.sms_initAnalysis(self._analysis_params) != 0: raise Exception("Error allocating memory for analysis_params") self._peaks = simplsms.SMS_SpectralPeaks(self.max_peaks) @@ -128,10 +128,15 @@ class SMSPeakDetection(simpl.PeakDetection): print 'todo: change hop size to', hop_size def set_max_peaks(self, max_peaks): - # todo: compare to SMS_MAX_NPEAKS? + # TODO: compare to SMS_MAX_NPEAKS + # also, if > current max_peaks, need to reallocate memory in + # analysis_params self._max_peaks = max_peaks self._analysis_params.nTracks = max_peaks self._analysis_params.maxPeaks = max_peaks + self._analysis_params.nGuides = max_peaks + # TODO: create function to deallocate old peaks memory and call that + # before creating the new peak list below self._peaks = simplsms.SMS_SpectralPeaks(max_peaks) def set_sampling_rate(self, sampling_rate): @@ -149,8 +154,8 @@ class SMSPeakDetection(simpl.PeakDetection): "Find and return all spectral peaks in a given frame of audio" current_peaks = [] num_peaks = simplsms.sms_findPeaks(frame, - self._analysis_params, - self._peaks) + self._analysis_params, + self._peaks) if num_peaks > 0: amps = simpl.zeros(num_peaks) freqs = simpl.zeros(num_peaks) @@ -170,8 +175,22 @@ class SMSPeakDetection(simpl.PeakDetection): """Find and return all spectral peaks in a given audio signal. If the signal contains more than 1 frame worth of audio, it will be broken up into separate frames, with a list of peaks returned for each frame.""" + # TODO: This hops by frame size rather than hop size in order to + # make sure the results are the same as with libsms. Make sure + # we have the same number of frames as the other algorithms. self._analysis_params.iSizeSound = len(audio) - return simpl.PeakDetection.find_peaks(self, audio) + self.peaks = [] + pos = 0 + while pos < len(audio): + # get the next frame size + if not self._static_frame_size: + self.frame_size = self.get_next_frame_size() + # get the next frame + frame = audio[pos:pos+self.frame_size] + # find peaks + self.peaks.append(self.find_peaks_in_frame(frame)) + pos += self.frame_size + return self.peaks class SMSPartialTracking(simpl.PartialTracking): @@ -199,16 +218,21 @@ class SMSPartialTracking(simpl.PartialTracking): self._analysis_params.nGuides = self.max_partials if simplsms.sms_initAnalysis(self._analysis_params) != 0: raise Exception("Error allocating memory for analysis_params") + self._sms_header = simplsms.SMS_Header() + simplsms.sms_fillHeader(self._sms_header, self._analysis_params, "simpl") self._analysis_frame = simplsms.SMS_Data() + simplsms.sms_allocFrameH(self._sms_header, self._analysis_frame) self.live_partials = [None for i in range(self.max_partials)] def __del__(self): - #simplsms.sms_freeAnalysis(self._analysis_params) + simplsms.sms_freeAnalysis(self._analysis_params) + simplsms.sms_freeFrame(self._analysis_frame) simplsms.sms_free() SMSPartialTracking._instances -= 1 def set_max_partials(self, max_partials): self._max_partials = max_partials + self._analysis_params.maxPeaks = max_partials self._analysis_params.nTracks = max_partials self._analysis_params.nGuides = max_partials @@ -220,6 +244,9 @@ class SMSPartialTracking(simpl.PartialTracking): amps = simpl.zeros(num_peaks) freqs = simpl.zeros(num_peaks) phases = simpl.zeros(num_peaks) + #amps = simpl.zeros(self.max_partials) + #freqs = simpl.zeros(self.max_partials) + #phases = simpl.zeros(self.max_partials) for i in range(num_peaks): peak = frame[i] amps[i] = peak.amplitude diff --git a/sms/analysis.c b/sms/analysis.c index 55c955f..f4da530 100644 --- a/sms/analysis.c +++ b/sms/analysis.c @@ -37,7 +37,7 @@ void printAnalysisParams(SMS_AnalParams* params) "fHighestFreq: %f\n" "fMinPeakMag: %f\n" "iSamplingRate: %d\n" - "iMaxPeaks: %d\n" + "maxPeaks: %d\n" "fHighestFundamental: %f\n" "iRefHarmonic: %d\n" "fMinRefHarmMag: %f\n" @@ -85,8 +85,8 @@ void sms_analyzeFrame(int iCurrentFrame, SMS_AnalParams *pAnalParams, sfloat fRe pAnalParams); /* find a reference harmonic */ - if (pCurrentFrame->nPeaks > 0 && - (pAnalParams->iFormat == SMS_FORMAT_H || pAnalParams->iFormat == SMS_FORMAT_HP)) + if(pCurrentFrame->nPeaks > 0 && + (pAnalParams->iFormat == SMS_FORMAT_H || pAnalParams->iFormat == SMS_FORMAT_HP)) pCurrentFrame->fFundamental = sms_harmDetection(pAnalParams->nTracks, pCurrentFrame->pSpectralPeaks, fRefFundamental, pAnalParams->iRefHarmonic, pAnalParams->fLowestFundamental, pAnalParams->fHighestFundamental, @@ -156,13 +156,13 @@ int sms_findPeaks(int sizeWaveform, sfloat *pWaveform, SMS_AnalParams *pAnalPara 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) + if(sizeWaveform > 0) sms_fillSoundBuffer(sizeWaveform, pWaveform, pAnalParams); /* move analysis data one frame back */ @@ -176,7 +176,7 @@ int sms_findPeaks(int sizeWaveform, sfloat *pWaveform, SMS_AnalParams *pAnalPara if(sms_errorCheck()) { printf("Error in init frame: %s \n", sms_errorString()); - return(0); + return 0; } if(pAnalParams->ppFrames[iCurrentFrame]->iStatus == SMS_FRAME_READY) @@ -200,9 +200,10 @@ int sms_findPeaks(int sizeWaveform, sfloat *pWaveform, SMS_AnalParams *pAnalPara 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 + /* 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); @@ -215,9 +216,18 @@ int sms_findPeaks(int sizeWaveform, sfloat *pWaveform, SMS_AnalParams *pAnalPara pSpectralPeaks->pSpectralPeaks = pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks; /* convert peak amps to linear */ - for(i = 0; i < pSpectralPeaks->nPeaksFound; i++) + for(i = 0; i < pSpectralPeaks->nPeaks; i++) { - pSpectralPeaks->pSpectralPeaks[i].fMag = pow(10.0, 0.05*(pSpectralPeaks->pSpectralPeaks[i].fMag)); + if(i < pSpectralPeaks->nPeaksFound) + { + pSpectralPeaks->pSpectralPeaks[i].fMag = pow(10.0, 0.05*(pSpectralPeaks->pSpectralPeaks[i].fMag)); + } + else + { + pSpectralPeaks->pSpectralPeaks[i].fMag = 0.0; + pSpectralPeaks->pSpectralPeaks[i].fFreq = 0.0; + pSpectralPeaks->pSpectralPeaks[i].fPhase = 0.0; + } } return pSpectralPeaks->nPeaks; } @@ -232,6 +242,7 @@ void sms_setPeaks(SMS_AnalParams *pAnalParams, int numamps, sfloat* amps, { int i; SMS_AnalFrame *tempFrame; + int currentFrame = pAnalParams->iMaxDelayFrames - 1; /* frame # of current frame */ /* move analysis data one frame back */ tempFrame = pAnalParams->ppFrames[0]; @@ -240,8 +251,8 @@ void sms_setPeaks(SMS_AnalParams *pAnalParams, int numamps, sfloat* amps, pAnalParams->ppFrames[pAnalParams->iMaxDelayFrames-1] = tempFrame; /* initialize the current frame */ - SMS_AnalFrame *currentFrame = pAnalParams->ppFrames[2]; - sms_initFrame(2, pAnalParams, 0); + SMS_AnalFrame *frame = pAnalParams->ppFrames[currentFrame]; + sms_initFrame(currentFrame, pAnalParams, 0); if(sms_errorCheck()) { printf("Error in init frame: %s \n", sms_errorString()); @@ -251,16 +262,16 @@ void sms_setPeaks(SMS_AnalParams *pAnalParams, int numamps, sfloat* amps, for(i = 0; i < numamps; i++) { /* copy current peaks data */ - currentFrame->pSpectralPeaks[i].fMag = sms_magToDB(amps[i]); - currentFrame->pSpectralPeaks[i].fFreq = freqs[i]; - currentFrame->pSpectralPeaks[i].fPhase = phases[i]; + frame->pSpectralPeaks[i].fMag = 20.0 * log10(amps[i]); + frame->pSpectralPeaks[i].fFreq = freqs[i]; + frame->pSpectralPeaks[i].fPhase = phases[i]; } - currentFrame->nPeaks = numamps; - currentFrame->iStatus = SMS_FRAME_READY; + frame->nPeaks = numamps; + frame->iStatus = SMS_FRAME_READY; /* harmonic detection */ - if (currentFrame->nPeaks > 0 && - (pAnalParams->iFormat == SMS_FORMAT_H || pAnalParams->iFormat == SMS_FORMAT_HP)) + if(frame->nPeaks > 0 && + (pAnalParams->iFormat == SMS_FORMAT_H || pAnalParams->iFormat == SMS_FORMAT_HP)) { /* get a reference fundamental */ sfloat refFundamental = 0; @@ -273,39 +284,47 @@ void sms_setPeaks(SMS_AnalParams *pAnalParams, int numamps, sfloat* amps, else refFundamental = 0; - currentFrame->fFundamental = sms_harmDetection(pAnalParams->nTracks, currentFrame->pSpectralPeaks, - refFundamental, pAnalParams->iRefHarmonic, - pAnalParams->fLowestFundamental, pAnalParams->fHighestFundamental, - pAnalParams->iSoundType, pAnalParams->fMinRefHarmMag, - pAnalParams->fRefHarmMagDiffFromMax); + 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 */ - /* todo: allow for longer analysis delays */ - if(pAnalParams->ppFrames[1]->fFundamental > 0 || + if(pAnalParams->ppFrames[currentFrame-delayFrames]->fFundamental > 0 || ((pAnalParams->iFormat == SMS_FORMAT_IH || pAnalParams->iFormat == SMS_FORMAT_IHP) && - pAnalParams->ppFrames[1]->nPeaks > 0)) + pAnalParams->ppFrames[currentFrame-delayFrames]->nPeaks > 0)) { - sms_peakContinuation(1, pAnalParams); + sms_peakContinuation(currentFrame-delayFrames, pAnalParams); } /* fill gaps and delete short tracks */ - /* todo: allow for longer analysis delays */ if(pAnalParams->iCleanTracks > 0) { - sms_cleanTracks(1, pAnalParams); + sms_cleanTracks(currentFrame-delayFrames, pAnalParams); } /* output data */ - sms_allocFrame(pSmsData, pAnalParams->nTracks, pAnalParams->nStochasticCoeff, - 1, pAnalParams->iStochasticType, pAnalParams->specEnvParams.nCoeff); - int length = sizeof(sfloat) * pSmsData->nTracks; memcpy((char *) pSmsData->pFSinFreq, (char *) pAnalParams->ppFrames[0]->deterministic.pFSinFreq, length); @@ -425,7 +444,6 @@ void sms_approxResidual(int sizeResidual, sfloat* pResidual, int sms_analyze(int sizeWaveform, sfloat *pWaveform, SMS_Data *pSmsData, SMS_AnalParams *pAnalParams) { int iCurrentFrame = pAnalParams->iMaxDelayFrames - 1; /* frame # of current frame */ - int delayFrames; int i, iError, iExtraSamples; /* samples used for next analysis frame */ sfloat fRefFundamental = 0; /* reference fundamental for current frame */ SMS_AnalFrame *pTmpAnalFrame; @@ -437,7 +455,7 @@ int sms_analyze(int sizeWaveform, sfloat *pWaveform, SMS_Data *pSmsData, SMS_Ana * pAnalParamx->iMaxDelayFrames is changed without changing the other * two variables. */ - delayFrames = pAnalParams->minGoodFrames + pAnalParams->analDelay; + int delayFrames = pAnalParams->minGoodFrames + pAnalParams->analDelay; if(delayFrames > (pAnalParams->iMaxDelayFrames - 1)) delayFrames = pAnalParams->iMaxDelayFrames - 1; diff --git a/sms/harmDetection.c b/sms/harmDetection.c index 7ec3bac..1612fc8 100644 --- a/sms/harmDetection.c +++ b/sms/harmDetection.c @@ -46,30 +46,30 @@ static int GetClosestPeak (int iPeakCandidate, int nHarm, SMS_Peak *pSpectralPeaks, int *pICurrentPeak, int iRefHarmonic) { - int iBestPeak = *pICurrentPeak + 1, iNextPeak; - sfloat fBestPeakFreq = pSpectralPeaks[iBestPeak].fFreq, - fHarmFreq = (1 + nHarm) * pSpectralPeaks[iPeakCandidate].fFreq / iRefHarmonic, - fMinDistance = fabs(fHarmFreq - fBestPeakFreq), - fMaxPeakDev = .5 * fHarmFreq / (nHarm + 1), fDistance; + int iBestPeak = *pICurrentPeak + 1, iNextPeak; + sfloat fBestPeakFreq = pSpectralPeaks[iBestPeak].fFreq, + fHarmFreq = (1 + nHarm) * pSpectralPeaks[iPeakCandidate].fFreq / iRefHarmonic, + fMinDistance = fabs(fHarmFreq - fBestPeakFreq), + fMaxPeakDev = .5 * fHarmFreq / (nHarm + 1), fDistance; - iNextPeak = iBestPeak + 1; - fDistance = fabs(fHarmFreq - pSpectralPeaks[iNextPeak].fFreq); - while (fDistance < fMinDistance) - { - iBestPeak = iNextPeak; - fMinDistance = fDistance; - iNextPeak++; - fDistance = fabs (fHarmFreq - pSpectralPeaks[iNextPeak].fFreq); - } + iNextPeak = iBestPeak + 1; + fDistance = fabs(fHarmFreq - pSpectralPeaks[iNextPeak].fFreq); + while (fDistance < fMinDistance) + { + iBestPeak = iNextPeak; + fMinDistance = fDistance; + iNextPeak++; + fDistance = fabs (fHarmFreq - pSpectralPeaks[iNextPeak].fFreq); + } - /* make sure the chosen peak is good */ - fBestPeakFreq = pSpectralPeaks[iBestPeak].fFreq; - /* if best peak is not in the range */ - if (fabs (fBestPeakFreq - fHarmFreq) > fMaxPeakDev) - return (-1); + /* make sure the chosen peak is good */ + fBestPeakFreq = pSpectralPeaks[iBestPeak].fFreq; + /* if best peak is not in the range */ + if (fabs (fBestPeakFreq - fHarmFreq) > fMaxPeakDev) + return (-1); - *pICurrentPeak = iBestPeak; - return (iBestPeak); + *pICurrentPeak = iBestPeak; + return (iBestPeak); } /*! \brief checks if peak is substantial @@ -87,32 +87,32 @@ static int GetClosestPeak (int iPeakCandidate, int nHarm, SMS_Peak *pSpectralPea static int ComparePeak (sfloat fRefHarmMag, SMS_Peak *pSpectralPeaks, int nCand, sfloat fRefHarmMagDiffFromMax) { - int iPeak; - sfloat fMag = 0; + int iPeak; + sfloat fMag = 0; - /* if peak is very large take it as possible fundamental */ - if (nCand == 0 && - fRefHarmMag > 80.) - return (1); + /* if peak is very large take it as possible fundamental */ + if (nCand == 0 && + fRefHarmMag > 80.) + return (1); - /* compare the peak with the first N_FUND_HARM peaks */ - /* if too small forget it */ - for (iPeak = 0; iPeak < N_FUND_HARM; iPeak++) - if (pSpectralPeaks[iPeak].fMag > 0 && - fRefHarmMag - pSpectralPeaks[iPeak].fMag < - fRefHarmMagDiffFromMax) - return (-1); + /* compare the peak with the first N_FUND_HARM peaks */ + /* if too small forget it */ + for (iPeak = 0; iPeak < N_FUND_HARM; iPeak++) + if (pSpectralPeaks[iPeak].fMag > 0 && + fRefHarmMag - pSpectralPeaks[iPeak].fMag < - fRefHarmMagDiffFromMax) + return (-1); - /* if it is much bigger than rest take it */ - for (iPeak = 0; iPeak < N_FUND_HARM; iPeak++) - { - fMag = pSpectralPeaks[iPeak].fMag; - if (fMag <= 0 || - ((fMag != fRefHarmMag) && - (nCand > 0) && (fRefHarmMag - fMag < 30.0)) || - ((nCand == 0) && (fRefHarmMag - fMag < 15.0))) - return (0); - } - return (1); + /* if it is much bigger than rest take it */ + for (iPeak = 0; iPeak < N_FUND_HARM; iPeak++) + { + fMag = pSpectralPeaks[iPeak].fMag; + if (fMag <= 0 || + ((fMag != fRefHarmMag) && + (nCand > 0) && (fRefHarmMag - fMag < 30.0)) || + ((nCand == 0) && (fRefHarmMag - fMag < 15.0))) + return (0); + } + return (1); } @@ -125,17 +125,17 @@ static int ComparePeak (sfloat fRefHarmMag, SMS_Peak *pSpectralPeaks, int nCand, */ int CheckIfHarmonic (sfloat fFundFreq, SMS_HarmCandidate *pCHarmonic, int nCand) { - int iPeak; + int iPeak; - /* go through all the candidates checking if they are fundamentals */ - /* of the peak to be considered */ - for (iPeak = 0; iPeak < nCand; iPeak++) - if (fabs(floor((double)(fFundFreq - / pCHarmonic[iPeak].fFreq) + .5) - - (fFundFreq / pCHarmonic[iPeak].fFreq)) - <= .1) - return (1); - return (0); + /* go through all the candidates checking if they are fundamentals */ + /* of the peak to be considered */ + for (iPeak = 0; iPeak < nCand; iPeak++) + if (fabs(floor((double)(fFundFreq + / pCHarmonic[iPeak].fFreq) + .5) - + (fFundFreq / pCHarmonic[iPeak].fFreq)) + <= .1) + return (1); + return (0); } @@ -156,106 +156,100 @@ static int GoodCandidate (int iPeak, SMS_Peak *pSpectralPeaks, SMS_HarmCandidate int nCand, int soundType, sfloat fRefFundamental, sfloat minRefHarmMag, sfloat refHarmMagDiffFromMax, sfloat refHarmonic) { - sfloat fHarmFreq, fRefHarmFreq, fRefHarmMag, fTotalMag = 0, fTotalDev = 0, - fTotalMaxMag = 0, fAvgMag = 0, fAvgDev = 0, fHarmRatio = 0; - int iHarm = 0, iChosenPeak = 0, iPeakComp, iCurrentPeak, nGoodHarm = 0, i; + sfloat fHarmFreq, fRefHarmFreq, fRefHarmMag, fTotalMag = 0, fTotalDev = 0, + fTotalMaxMag = 0, fAvgMag = 0, fAvgDev = 0, fHarmRatio = 0; + int iHarm = 0, iChosenPeak = 0, iPeakComp, iCurrentPeak, nGoodHarm = 0, i; - fRefHarmFreq = fHarmFreq = pSpectralPeaks[iPeak].fFreq; + fRefHarmFreq = fHarmFreq = pSpectralPeaks[iPeak].fFreq; - fTotalDev = 0; - fRefHarmMag = pSpectralPeaks[iPeak].fMag; - fTotalMag = fRefHarmMag; + fTotalDev = 0; + fRefHarmMag = pSpectralPeaks[iPeak].fMag; + fTotalMag = fRefHarmMag; - /* check if magnitude is big enough */ + /* check if magnitude is big enough */ /*! \bug sfloat comparison to 0 */ - if (((fRefFundamental > 0) && + if (((fRefFundamental > 0) && (fRefHarmMag < minRefHarmMag - 10)) || ((fRefFundamental <= 0) && (fRefHarmMag < minRefHarmMag))) - return (-1); - - /* check that it is not a harmonic of a previous candidate */ - if (nCand > 0 && - CheckIfHarmonic (fRefHarmFreq / refHarmonic, pCHarmonic, - nCand)) - return (-1); - - /* check if it is very big or very small */ - iPeakComp = ComparePeak (fRefHarmMag, pSpectralPeaks, nCand, refHarmMagDiffFromMax); - /* too small */ - if (iPeakComp == -1) - return (-1); - /* very big */ - else if (iPeakComp == 1) - { - pCHarmonic[nCand].fFreq = fRefHarmFreq; - pCHarmonic[nCand].fMag = fRefHarmMag; - pCHarmonic[nCand].fMagPerc = 1; - pCHarmonic[nCand].fFreqDev = 0; - pCHarmonic[nCand].fHarmRatio = 1; - return (-2); - } - - /* get a weight on the peak by comparing its harmonic series */ - /* with the existing peaks */ - if (soundType != SMS_SOUND_TYPE_NOTE) - { - fHarmFreq = fRefHarmFreq; - iCurrentPeak = iPeak; - nGoodHarm = 0; - for (iHarm = refHarmonic; iHarm < N_FUND_HARM; iHarm++) - { - fHarmFreq += fRefHarmFreq / refHarmonic; - iChosenPeak = GetClosestPeak(iPeak, iHarm, pSpectralPeaks, - &iCurrentPeak, refHarmonic); - if (iChosenPeak > 0) - { - fTotalDev += - fabs(fHarmFreq - pSpectralPeaks[iChosenPeak].fFreq) / - fHarmFreq; - fTotalMag += pSpectralPeaks[iChosenPeak].fMag; - nGoodHarm++; - } - } - - for (i = 0; i <= iCurrentPeak; i++) - fTotalMaxMag += pSpectralPeaks[i].fMag; - - fAvgDev = fTotalDev / (iHarm + 1); - fAvgMag = fTotalMag / fTotalMaxMag; - fHarmRatio = (sfloat) nGoodHarm / (N_FUND_HARM - 1); - - } - -/* fprintf(stdout, */ -/* "Harmonic Candidate: frq: %f mag: %f frqDev: %f magPrc: %f harmDev %f\n", */ -/* fRefHarmFreq, fRefHarmMag, fAvgDev, fAvgMag, fHarmRatio); */ - - if (soundType != SMS_SOUND_TYPE_NOTE) - { - if (fRefFundamental > 0) - { - if(fAvgDev > FREQ_DEV_THRES || fAvgMag < MAG_PERC_THRES - .1 || - fHarmRatio < HARM_RATIO_THRES - .1) - return (-1); - } - else - { - if (fAvgDev > FREQ_DEV_THRES || fAvgMag < MAG_PERC_THRES || - fHarmRatio < HARM_RATIO_THRES) - return (-1); - } - - - - } - pCHarmonic[nCand].fFreq = fRefHarmFreq; - pCHarmonic[nCand].fMag = fRefHarmMag; - pCHarmonic[nCand].fMagPerc = fAvgMag; - pCHarmonic[nCand].fFreqDev = fAvgDev; - pCHarmonic[nCand].fHarmRatio = fHarmRatio; - - return (1); + return (-1); + + /* check that it is not a harmonic of a previous candidate */ + if (nCand > 0 && + CheckIfHarmonic (fRefHarmFreq / refHarmonic, pCHarmonic, + nCand)) + return (-1); + + /* check if it is very big or very small */ + iPeakComp = ComparePeak (fRefHarmMag, pSpectralPeaks, nCand, refHarmMagDiffFromMax); + /* too small */ + if (iPeakComp == -1) + return (-1); + /* very big */ + else if (iPeakComp == 1) + { + pCHarmonic[nCand].fFreq = fRefHarmFreq; + pCHarmonic[nCand].fMag = fRefHarmMag; + pCHarmonic[nCand].fMagPerc = 1; + pCHarmonic[nCand].fFreqDev = 0; + pCHarmonic[nCand].fHarmRatio = 1; + return (-2); + } + + /* get a weight on the peak by comparing its harmonic series */ + /* with the existing peaks */ + if (soundType != SMS_SOUND_TYPE_NOTE) + { + fHarmFreq = fRefHarmFreq; + iCurrentPeak = iPeak; + nGoodHarm = 0; + for (iHarm = refHarmonic; iHarm < N_FUND_HARM; iHarm++) + { + fHarmFreq += fRefHarmFreq / refHarmonic; + iChosenPeak = GetClosestPeak(iPeak, iHarm, pSpectralPeaks, + &iCurrentPeak, refHarmonic); + if (iChosenPeak > 0) + { + fTotalDev += + fabs(fHarmFreq - pSpectralPeaks[iChosenPeak].fFreq) / + fHarmFreq; + fTotalMag += pSpectralPeaks[iChosenPeak].fMag; + nGoodHarm++; + } + } + + for (i = 0; i <= iCurrentPeak; i++) + fTotalMaxMag += pSpectralPeaks[i].fMag; + + fAvgDev = fTotalDev / (iHarm + 1); + fAvgMag = fTotalMag / fTotalMaxMag; + fHarmRatio = (sfloat) nGoodHarm / (N_FUND_HARM - 1); + + } + + if (soundType != SMS_SOUND_TYPE_NOTE) + { + if (fRefFundamental > 0) + { + if(fAvgDev > FREQ_DEV_THRES || fAvgMag < MAG_PERC_THRES - .1 || + fHarmRatio < HARM_RATIO_THRES - .1) + return (-1); + } + else + { + if (fAvgDev > FREQ_DEV_THRES || fAvgMag < MAG_PERC_THRES || + fHarmRatio < HARM_RATIO_THRES) + return (-1); + } + } + + pCHarmonic[nCand].fFreq = fRefHarmFreq; + pCHarmonic[nCand].fMag = fRefHarmMag; + pCHarmonic[nCand].fMagPerc = fAvgMag; + pCHarmonic[nCand].fFreqDev = fAvgDev; + pCHarmonic[nCand].fHarmRatio = fHarmRatio; + + return (1); } /*! \brief choose the best fundamental out of all the candidates @@ -269,49 +263,49 @@ static int GoodCandidate (int iPeak, SMS_Peak *pSpectralPeaks, SMS_HarmCandidate static int GetBestCandidate (SMS_HarmCandidate *pCHarmonic, int iRefHarmonic, int nGoodPeaks, sfloat fPrevFund) { - int iBestCandidate = 0, iPeak; - sfloat fBestFreq, fHarmFreq, fDev; + int iBestCandidate = 0, iPeak; + sfloat fBestFreq, fHarmFreq, fDev; - /* if a fundamental existed in previous frame take the closest candidate */ - if (fPrevFund > 0) - for (iPeak = 1; iPeak < nGoodPeaks; iPeak++) - { - if (fabs (fPrevFund - pCHarmonic[iPeak].fFreq / iRefHarmonic) < - fabs(fPrevFund - pCHarmonic[iBestCandidate].fFreq / iRefHarmonic)) - iBestCandidate = iPeak; - } - else - /* try to find the best candidate */ - for (iPeak = 1; iPeak < nGoodPeaks; iPeak++) - { - fBestFreq = pCHarmonic[iBestCandidate].fFreq / iRefHarmonic; - fHarmFreq = fBestFreq * - floor (.5 + - (pCHarmonic[iPeak].fFreq / iRefHarmonic) / - fBestFreq); - fDev = fabs (fHarmFreq - (pCHarmonic[iPeak].fFreq / - iRefHarmonic)) / fHarmFreq; - - /* if candidate is far from harmonic from best candidate and */ - /* bigger, take it */ - if (fDev > .2 && - pCHarmonic[iPeak].fMag > - pCHarmonic[iBestCandidate].fMag) - iBestCandidate = iPeak; - /* if frequency deviation is much smaller, take it */ - else if (pCHarmonic[iPeak].fFreqDev < - .2 * pCHarmonic[iBestCandidate].fFreqDev) - iBestCandidate = iPeak; - /* if freq. deviation is smaller and bigger amplitude, take it */ - else if (pCHarmonic[iPeak].fFreqDev < - pCHarmonic[iBestCandidate].fFreqDev && - pCHarmonic[iPeak].fMagPerc > - pCHarmonic[iBestCandidate].fMagPerc && - pCHarmonic[iPeak].fMag > - pCHarmonic[iBestCandidate].fMag) - iBestCandidate = iPeak; - } - return (iBestCandidate); + /* if a fundamental existed in previous frame take the closest candidate */ + if (fPrevFund > 0) + for (iPeak = 1; iPeak < nGoodPeaks; iPeak++) + { + if (fabs (fPrevFund - pCHarmonic[iPeak].fFreq / iRefHarmonic) < + fabs(fPrevFund - pCHarmonic[iBestCandidate].fFreq / iRefHarmonic)) + iBestCandidate = iPeak; + } + else + /* try to find the best candidate */ + for (iPeak = 1; iPeak < nGoodPeaks; iPeak++) + { + fBestFreq = pCHarmonic[iBestCandidate].fFreq / iRefHarmonic; + fHarmFreq = fBestFreq * + floor (.5 + + (pCHarmonic[iPeak].fFreq / iRefHarmonic) / + fBestFreq); + fDev = fabs (fHarmFreq - (pCHarmonic[iPeak].fFreq / + iRefHarmonic)) / fHarmFreq; + + /* if candidate is far from harmonic from best candidate and */ + /* bigger, take it */ + if (fDev > .2 && + pCHarmonic[iPeak].fMag > + pCHarmonic[iBestCandidate].fMag) + iBestCandidate = iPeak; + /* if frequency deviation is much smaller, take it */ + else if (pCHarmonic[iPeak].fFreqDev < + .2 * pCHarmonic[iBestCandidate].fFreqDev) + iBestCandidate = iPeak; + /* if freq. deviation is smaller and bigger amplitude, take it */ + else if (pCHarmonic[iPeak].fFreqDev < + pCHarmonic[iBestCandidate].fFreqDev && + pCHarmonic[iPeak].fMagPerc > + pCHarmonic[iBestCandidate].fMagPerc && + pCHarmonic[iPeak].fMag > + pCHarmonic[iBestCandidate].fMag) + iBestCandidate = iPeak; + } + return (iBestCandidate); } /*! \brief main harmonic detection function @@ -328,65 +322,63 @@ static int GetBestCandidate (SMS_HarmCandidate *pCHarmonic, * This really should only be for sms_analyzeFrame */ sfloat sms_harmDetection(int numPeaks, SMS_Peak* spectralPeaks, sfloat refFundamental, - sfloat refHarmonic, sfloat lowestFreq, sfloat highestFreq, - int soundType, sfloat minRefHarmMag, sfloat refHarmMagDiffFromMax) + sfloat refHarmonic, sfloat lowestFreq, sfloat highestFreq, + int soundType, sfloat minRefHarmMag, sfloat refHarmMagDiffFromMax) { - int iPeak = -1, nGoodPeaks = 0, iCandidate, iBestCandidate; - sfloat peakFreq=0; - SMS_HarmCandidate pCHarmonic[N_HARM_PEAKS]; - - /* find all possible candidates to use as harmonic reference */ - lowestFreq = lowestFreq * refHarmonic; - highestFreq = highestFreq * refHarmonic; - - while(peakFreq < highestFreq) - { - iPeak++; - peakFreq = spectralPeaks[iPeak].fFreq; - if (peakFreq > highestFreq) - break; - - /* no more peaks */ - if (spectralPeaks[iPeak].fMag <= 0) /*!< \bug sfloat comparison to zero */ - break; - - /* peak too low */ - if (peakFreq < lowestFreq) - continue; - - /* if previous fundamental look only around it */ - if (refFundamental > 0 && - fabs(peakFreq - (refHarmonic * refFundamental)) / refFundamental > .5) - continue; - - iCandidate = GoodCandidate(iPeak, spectralPeaks, pCHarmonic, - nGoodPeaks, soundType, refFundamental, - minRefHarmMag, refHarmMagDiffFromMax, refHarmonic); - - /* good candiate found */ - if (iCandidate == 1) - nGoodPeaks++; - - /* a perfect candiate found */ - else - if (iCandidate == -2) - { - nGoodPeaks++; - break; - } - } - - /* if no candidate for fundamental, continue */ - if (nGoodPeaks == 0) - return -1; - /* if only 1 candidate for fundamental take it */ - else - if (nGoodPeaks == 1) - return pCHarmonic[0].fFreq / refHarmonic; - /* if more than one candidate choose the best one */ - else - { - iBestCandidate = GetBestCandidate (pCHarmonic, refHarmonic, nGoodPeaks, refFundamental); - return pCHarmonic[iBestCandidate].fFreq / refHarmonic; - } + int iPeak = -1, nGoodPeaks = 0, iCandidate, iBestCandidate; + sfloat peakFreq=0; + SMS_HarmCandidate pCHarmonic[N_HARM_PEAKS]; + + /* find all possible candidates to use as harmonic reference */ + lowestFreq = lowestFreq * refHarmonic; + highestFreq = highestFreq * refHarmonic; + + while((peakFreq < highestFreq) && (iPeak < numPeaks)) + { + iPeak++; + peakFreq = spectralPeaks[iPeak].fFreq; + if(peakFreq > highestFreq) + break; + + /* no more peaks */ + if(spectralPeaks[iPeak].fMag <= 0) /*!< \bug sfloat comparison to zero */ + break; + + /* peak too low */ + if(peakFreq < lowestFreq) + continue; + + /* if previous fundamental look only around it */ + if(refFundamental > 0 && + fabs(peakFreq - (refHarmonic * refFundamental)) / refFundamental > .5) + continue; + + iCandidate = GoodCandidate(iPeak, spectralPeaks, pCHarmonic, + nGoodPeaks, soundType, refFundamental, + minRefHarmMag, refHarmMagDiffFromMax, refHarmonic); + + /* good candiate found */ + if(iCandidate == 1) + nGoodPeaks++; + + /* a perfect candiate found */ + else if(iCandidate == -2) + { + nGoodPeaks++; + break; + } + } + + /* if no candidate for fundamental, continue */ + if(nGoodPeaks == 0) + return -1; + /* if only 1 candidate for fundamental take it */ + else if(nGoodPeaks == 1) + return pCHarmonic[0].fFreq / refHarmonic; + /* if more than one candidate choose the best one */ + else + { + iBestCandidate = GetBestCandidate(pCHarmonic, refHarmonic, nGoodPeaks, refFundamental); + return pCHarmonic[iBestCandidate].fFreq / refHarmonic; + } } diff --git a/sms/peakContinuation.c b/sms/peakContinuation.c index b514266..5e6426b 100644 --- a/sms/peakContinuation.c +++ b/sms/peakContinuation.c @@ -67,7 +67,7 @@ int GetNextClosestPeak(sfloat fGuideFreq, sfloat *pFFreqDistance, else { while(floor(fLowDistance) >= floor(*pFFreqDistance) && - iInitialPeak < pAnalParams->maxPeaks) + iInitialPeak < pAnalParams->maxPeaks) { iInitialPeak++; /* TODO: is this really the correct behaviour? Will ignore @@ -297,13 +297,14 @@ int GetBestPeak(SMS_Guide *pGuides, int iGuide, SMS_Peak *pSpectralPeaks, * \param pFCurrentMax last peak maximum * \return the number of the maximum peak */ -static int GetNextMax (SMS_Peak *pSpectralPeaks, sfloat *pFCurrentMax) +static int GetNextMax(SMS_Peak *pSpectralPeaks, SMS_AnalParams *pAnalParams, + sfloat *pFCurrentMax) { sfloat fPeakMag; sfloat fMaxMag = 0.; int iPeak, iMaxPeak = -1; - for (iPeak = 0; iPeak < SMS_MAX_NPEAKS; iPeak++) + for (iPeak = 0; iPeak < pAnalParams->maxPeaks; iPeak++) { fPeakMag = pSpectralPeaks[iPeak].fMag; @@ -330,7 +331,8 @@ static int GetNextMax (SMS_Peak *pSpectralPeaks, sfloat *pFCurrentMax) * \return \todo should this return something? */ static int GetStartingPeak(int iGuide, SMS_Guide *pGuides, int nGuides, - SMS_Peak *pSpectralPeaks, sfloat *pFCurrentMax) + SMS_Peak *pSpectralPeaks, SMS_AnalParams *pAnalParams, + sfloat *pFCurrentMax) { int iPeak = -1; short peakNotFound = 1; @@ -338,7 +340,7 @@ static int GetStartingPeak(int iGuide, SMS_Guide *pGuides, int nGuides, while (peakNotFound == 1 && *pFCurrentMax > 0) { /* \todo I don't think this ever returns -1, but check */ - if ((iPeak = GetNextMax(pSpectralPeaks, pFCurrentMax)) < 0) + if ((iPeak = GetNextMax(pSpectralPeaks, pAnalParams, pFCurrentMax)) < 0) return (-1); if (CheckForConflict (iPeak, pGuides, nGuides) < 0) @@ -425,7 +427,7 @@ int sms_peakContinuation(int iFrame, SMS_AnalParams *pAnalParams) if(GetStartingPeak(iGuide, pAnalParams->guides, pAnalParams->nGuides, pAnalParams->ppFrames[iFrame]->pSpectralPeaks, - &fCurrentMax) == -1) + pAnalParams, &fCurrentMax) == -1) break; } diff --git a/sms/peakDetection.c b/sms/peakDetection.c index fc40e69..dfaddd4 100644 --- a/sms/peakDetection.c +++ b/sms/peakDetection.c @@ -169,17 +169,23 @@ int sms_detectPeaks(int sizeSpec, sfloat *pMag, sfloat *pPhase, sfloat fInvSizeFft = 1.0 / sizeFft; int iFirstBin = MAX(1, sizeFft * pAnalParams->fLowestFreq / pAnalParams->iSamplingRate); int iHighestBin = MIN(sizeSpec-1, sizeFft * pAnalParams->fHighestFreq / pAnalParams->iSamplingRate); + int iPeak = 0; /* clear peak structure */ - memset(pSpectralPeaks, 0, pAnalParams->maxPeaks * sizeof(SMS_Peak)); + for(iPeak = 0; iPeak < pAnalParams->maxPeaks; iPeak++) + { + pSpectralPeaks[iPeak].fFreq = 0.0; + pSpectralPeaks[iPeak].fMag = 0.0; + pSpectralPeaks[iPeak].fPhase = 0.0; + } /* set starting search values */ int iCurrentLoc = iFirstBin; - int iPeak = 0; /* index for spectral search */ sfloat fPeakMag = 0.0; /* magnitude of peak */ sfloat fPeakLoc = 0.0; /* location of peak */ /* find peaks */ + iPeak = 0; while((iPeak < pAnalParams->maxPeaks) && (FindNextPeak(pMag, iHighestBin, &iCurrentLoc, &fPeakMag, &fPeakLoc, pAnalParams->fMinPeakMag) == 1)) @@ -217,15 +217,20 @@ int sms_initAnalysis(SMS_AnalParams *pAnalParams) pAnalParams->specEnvParams.iMaxFreq = pAnalParams->fHighestFreq; /*\todo this probably doesn't need env coefficients - they aren't getting used */ - sms_allocFrame(&pAnalParams->prevFrame, pAnalParams->nGuides, - pAnalParams->nStochasticCoeff, 1, pAnalParams->iStochasticType, 0); + if(sms_allocFrame(&pAnalParams->prevFrame, pAnalParams->nGuides, + pAnalParams->nStochasticCoeff, 1, pAnalParams->iStochasticType, 0) + == -1) + { + sms_error("Could not allocate memory for prevFrame"); + return -1; + } pAnalParams->sizeNextRead = (pAnalParams->iDefaultSizeWindow + 1) * 0.5; /* sound buffer */ - if ((pSoundBuf->pFBuffer = (sfloat *) calloc(sizeBuffer, sizeof(sfloat))) == NULL) + if((pSoundBuf->pFBuffer = (sfloat *) calloc(sizeBuffer, sizeof(sfloat))) == NULL) { - sms_error("could not allocate memory"); + sms_error("Could not allocate memory for sound buffer"); return -1; } pSoundBuf->iMarker = -sizeBuffer; @@ -365,56 +370,6 @@ int sms_initAnalysis(SMS_AnalParams *pAnalParams) } return 0; - - /*[> buffer of analysis frames <]*/ - /*pAnalParams->pFrames = (SMS_AnalFrame *) malloc(pAnalParams->iMaxDelayFrames * sizeof(SMS_AnalFrame)); */ - /*if(pAnalParams->pFrames == NULL)*/ - /*{*/ - /* sms_error("could not allocate memory for delay frames");*/ - /* return -1;*/ - /*}*/ - - /*pAnalParams->ppFrames = (SMS_AnalFrame **) malloc(pAnalParams->iMaxDelayFrames * sizeof(SMS_AnalFrame *));*/ - /*if(pAnalParams->ppFrames == NULL)*/ - /*{*/ - /* sms_error("could not allocate memory for pointers to delay frames");*/ - /* return -1;*/ - /*}*/ - - /*[> initialize the frame pointers and allocate memory <]*/ - /*for (i = 0; i < pAnalParams->iMaxDelayFrames; i++)*/ - /*{*/ - /* pAnalParams->pFrames[i].iStatus = SMS_FRAME_EMPTY;*/ - /* pAnalParams->pFrames[i].pSpectralPeaks =*/ - /* (SMS_Peak *)malloc(pAnalParams->maxPeaks * sizeof(SMS_Peak));*/ - /* if (pAnalParams->pFrames[i].pSpectralPeaks == NULL)*/ - /* {*/ - /* sms_error("could not allocate memory for spectral peaks");*/ - /* return -1;*/ - /* }*/ - /* (pAnalParams->pFrames[i].deterministic).nTracks = pAnalParams->nGuides;*/ - /* if (((pAnalParams->pFrames[i].deterministic).pFSinFreq =*/ - /* (sfloat *)calloc (pAnalParams->nGuides, sizeof(sfloat))) == NULL)*/ - /* {*/ - /* sms_error("could not allocate memory");*/ - /* return -1;*/ - /* }*/ - /* if (((pAnalParams->pFrames[i].deterministic).pFSinAmp =*/ - /* (sfloat *)calloc (pAnalParams->nGuides, sizeof(sfloat))) == NULL)*/ - /* {*/ - /* sms_error("could not allocate memory");*/ - /* return -1;*/ - /* }*/ - /* if (((pAnalParams->pFrames[i].deterministic).pFSinPha =*/ - /* (sfloat *) calloc (pAnalParams->nGuides, sizeof(sfloat))) == NULL)*/ - /* {*/ - /* sms_error("could not allocate memory");*/ - /* return -1;*/ - /* }*/ - /* pAnalParams->ppFrames[i] = &pAnalParams->pFrames[i];*/ - /*}*/ - - /*return 0;*/ } void sms_changeHopSize(int hopSize, SMS_AnalParams *pAnalParams) @@ -691,14 +646,19 @@ int sms_initFrame(int iCurrentFrame, SMS_AnalParams *pAnalParams, int sizeWindow sizeof(sfloat) * pAnalParams->nGuides); /* clear peaks */ - memset((void *) pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks, 0, - sizeof (SMS_Peak) * pAnalParams->maxPeaks); + int i; + for(i = 0; i < pAnalParams->maxPeaks; i++) + { + pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks[i].fFreq = 0.0; + pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks[i].fMag = 0.0; + pAnalParams->ppFrames[iCurrentFrame]->pSpectralPeaks[i].fPhase = 0.0; + } pAnalParams->ppFrames[iCurrentFrame]->nPeaks = 0; pAnalParams->ppFrames[iCurrentFrame]->fFundamental = 0; pAnalParams->ppFrames[iCurrentFrame]->iFrameNum = - pAnalParams->ppFrames[iCurrentFrame - 1]->iFrameNum + 1; + pAnalParams->ppFrames[iCurrentFrame - 1]->iFrameNum + 1; pAnalParams->ppFrames[iCurrentFrame]->iFrameSize = sizeWindow; /* if first frame set center of data around 0 */ @@ -987,3 +947,4 @@ void sms_arrayScalarTempered(int sizeArray, sfloat *pArray) for(i = 0; i < sizeArray; i++) pArray[i] = sms_scalarTempered(pArray[i]); } + @@ -262,53 +262,6 @@ typedef struct sfloat *stocMagSpectrum; sfloat *approxEnvelope; /*!< spectral approximation envelope */ SMS_AnalFrame **ppFrames; /*!< pointers to the frames analyzed (it is circular-shifted once the array is full */ - - //int iDebugMode; [>!< debug codes enumerated by SMS_DBG \see SMS_DBG <] - //int iFormat; [>!< analysis format code defined by SMS_Format \see SMS_Format <] - //int iSoundType; [>!< type of sound to be analyzed \see SMS_SOUND_TYPE <] - //int iStochasticType; [>!< type of stochastic model defined by SMS_StocSynthType \see SMS_StocSynthType <] - //int iFrameRate; [>!< rate in Hz of data frames <] - //int nStochasticCoeff; [>!< number of stochastic coefficients per frame <] - //sfloat fLowestFundamental; [>!< lowest fundamental frequency in Hz <] - //sfloat fHighestFundamental;[>!< highest fundamental frequency in Hz <] - //sfloat fDefaultFundamental;[>!< default fundamental in Hz <] - //sfloat fPeakContToGuide; [>!< contribution of previous peak to current guide (between 0 and 1) <] - //sfloat fFundContToGuide; [>!< contribution of current fundamental to current guide (between 0 and 1) <] - //sfloat fFreqDeviation; [>!< maximum deviation from peak to peak <] - //int iSamplingRate; [>! sampling rate of sound to be analyzed <] - //int iDefaultSizeWindow; [>!< default size of analysis window in samples <] - //int windowSize; [>!< the current window size <] - //int sizeHop; [>!< hop size of analysis window in samples <] - //sfloat fSizeWindow; [>!< size of analysis window in number of periods <] - //int nTracks; [>!< number of sinusoidal tracks in frame <] - //int maxPeaks; [>!< maximum number of peaks in a frame <] - //int nGuides; [>!< number of guides used for peak detection and continuation \see SMS_Guide <] - //int iCleanTracks; [>!< whether or not to clean sinusoidal tracks <] - //sfloat fMinRefHarmMag; [>!< minimum magnitude in dB for reference peak <] - //sfloat fRefHarmMagDiffFromMax; [>!< maximum magnitude difference from reference peak to highest peak <] - //int iRefHarmonic; [>!< reference harmonic to use in the fundamental detection <] - //int iMinTrackLength; [>!< minimum length in samples of a given track <] - //int iMaxSleepingTime; [>!< maximum sleeping time for a track <] - //sfloat fLowestFreq; [>!< lowest frequency to be searched <] - //sfloat fHighestFreq; [>!< highest frequency to be searched <] - //sfloat fMinPeakMag; [>!< minimum magnitude in dB for a good peak <] - //int iAnalysisDirection; [>!< analysis direction, direct or reverse <] - //int iSizeSound; [>!< total size of sound to be analyzed in samples <] - //int nFrames; [>!< total number of frames that will be analyzed <] - //int iWindowType; [>!< type of FFT analysis window \see SMS_WINDOWS <] - //int iMaxDelayFrames; [>!< maximum number of frames to delay before peak continuation <] - //int minGoodFrames; [>!< minimum number of stable frames for backward search <] - //sfloat maxDeviation; [>!< maximum deviation allowed <] - //int analDelay; [>! number of frames in the past to be looked in possible re-analyze <] - //sfloat fResidualAccumPerc; [>!< accumalitive residual percentage <] - //int sizeNextRead; [>!< size of samples to read from sound file next analysis <] - //sfloat preEmphasisLastValue; - //SMS_Data prevFrame; [>!< the previous analysis frame <] - //SMS_SEnvParams specEnvParams; [>!< all data for spectral enveloping <] - //SMS_SndBuffer soundBuffer; [>!< signal to be analyzed <] - //SMS_SndBuffer synthBuffer; [>!< resynthesized signal used to create the residual <] - //SMS_AnalFrame *pFrames; [>!< an array of frames that have already been analyzed <] - //SMS_AnalFrame **ppFrames; [>!< pointers to the frames analyzed (it is circular-shifted once the array is full <] } SMS_AnalParams; /*! \struct SMS_ModifyParams @@ -364,27 +317,6 @@ typedef struct SMS_ModifyParams modParams; /*!< modification parameters */ sfloat *approxEnvelope; /*!< spectral approximation envelope */ } SMS_SynthParams; -//typedef struct -//{ -// int iStochasticType; [>!< type of stochastic model defined by SMS_StocSynthType \see SMS_StocSynthType <] -// int iSynthesisType; [>!< type of synthesis to perform \see SMS_SynthType <] -// int iDetSynthType; [>!< method for synthesizing deterministic component \see SMS_DetSynthType <] -// int iOriginalSRate; [>!< samplerate of the sound model source (for stochastic synthesis approximation) <] -// int iSamplingRate; [>!< synthesis samplerate <] -// int sizeHop; [>!< number of samples to synthesis for each frame <] -// int origSizeHop; [>!< original number of samples used to create each analysis frame <] -// int nTracks; -// int nStochasticCoeff; -// sfloat deemphasisLastValue; -// sfloat *pFDetWindow; [>!< array to hold the window used for deterministic synthesis \see SMS_WIN_IFFT <] -// sfloat *pFStocWindow; [>!< array to hold the window used for stochastic synthesis (Hanning) <] -// sfloat *pSynthBuff; [>!< an array for keeping samples during overlap-add (2x sizeHop) <] -// sfloat *pMagBuff; [>!< an array for keeping magnitude spectrum for stochastic synthesis <] -// sfloat *pPhaseBuff; [>!< an array for keeping phase spectrum for stochastic synthesis <] -// sfloat *pSpectra; [>!< array for in-place FFT transform <] -// SMS_Data prevFrame; [>!< previous data frame, for interpolation between frames <] -// SMS_ModifyParams modParams; [>!< modification parameters <] -//} SMS_SynthParams; /*! \struct SMS_HarmCandidate * \brief structure to hold information about a harmonic candidate @@ -373,7 +373,7 @@ { SMS_SpectralPeaks *s = (SMS_SpectralPeaks *)malloc(sizeof(SMS_SpectralPeaks)); s->nPeaks = n; - if((s->pSpectralPeaks = (SMS_Peak *)calloc (s->nPeaks, sizeof(SMS_Peak))) == NULL) + if((s->pSpectralPeaks = (SMS_Peak *)malloc(n * sizeof(SMS_Peak))) == NULL) { sms_error("could not allocate memory for spectral peaks"); return NULL; @@ -392,7 +392,7 @@ for(i = 0; i < $self->nPeaksFound; i++) pArray[i] = $self->pSpectralPeaks[i].fFreq; } - void getMag( int sizeArray, sfloat *pArray ) + void getMag(int sizeArray, sfloat *pArray ) { if(sizeArray < $self->nPeaksFound) { @@ -403,7 +403,7 @@ for(i = 0; i < $self->nPeaksFound; i++) pArray[i] = $self->pSpectralPeaks[i].fMag; } - void getPhase( int sizeArray, sfloat *pArray ) + void getPhase(int sizeArray, sfloat *pArray ) { if(sizeArray < $self->nPeaksFound) { diff --git a/tests/sms.py b/tests/sms.py index fc4fdbc..5c8c2c0 100644 --- a/tests/sms.py +++ b/tests/sms.py @@ -48,7 +48,7 @@ class TestSimplSMS(unittest.TestCase): analysis_params.iFormat = pysms.SMS_FORMAT_HP analysis_params.nTracks = self.max_peaks analysis_params.peakParams.iMaxPeaks = self.max_peaks - #analysis_params.nGuides = max_peaks + analysis_params.nGuides = self.max_peaks analysis_params.iMaxDelayFrames = 4 analysis_params.analDelay = 0 analysis_params.minGoodFrames = 1 @@ -67,7 +67,7 @@ class TestSimplSMS(unittest.TestCase): analysis_params.iFormat = simplsms.SMS_FORMAT_HP analysis_params.nTracks = self.max_peaks analysis_params.maxPeaks = self.max_peaks - #analysis_params.nGuides = max_peaks + analysis_params.nGuides = self.max_peaks analysis_params.iMaxDelayFrames = 4 analysis_params.analDelay = 0 analysis_params.minGoodFrames = 1 @@ -233,7 +233,7 @@ class TestSimplSMS(unittest.TestCase): places=self.FLOAT_PRECISION) def test_sms_analyze(self): - """test_sms_analyze + """test_sms_analyzebt43lztar Make sure that the simplsms.sms_analyze function does the same thing as the sms_analyze function from libsms.""" audio, sampling_rate = self.get_audio() @@ -386,161 +386,106 @@ class TestSimplSMS(unittest.TestCase): simplsms_partials[i].peaks[peak_number].phase, places = self.FLOAT_PRECISION) - #def test_partial_tracking(self): - # """test_partial_tracking - # Compare pysms Partials with SMS partials.""" - # audio, sampling_rate = self.get_audio() - # analysis_params, sms_header, snd_header = self.pysms_params(sampling_rate, - # self.max_peaks, - # self.num_frames) - # analysis_params.nFrames = self.num_frames - # analysis_params.iSizeSound = self.num_samples - # analysis_params.peakParams.iMaxPeaks = self.max_peaks + def test_partial_tracking(self): + """test_partial_tracking + Compare pysms Partials with SMS partials.""" + audio, sampling_rate = self.get_audio() - # sample_offset = 0 - # size_new_data = 0 - # current_frame = 0 - # sms_partials = [] - # live_partials = [None for i in range(self.max_peaks)] - # do_analysis = True + pysms.sms_init() + snd_header = pysms.SMS_SndHeader() + # Try to open the input file to fill snd_header + if(pysms.sms_openSF(self.input_file, snd_header)): + raise NameError("error opening sound file: " + pysms.sms_errorString()) + analysis_params = self.pysms_analysis_params(sampling_rate) + if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: + raise Exception("Error allocating memory for analysis_params") + analysis_params.iSizeSound = self.num_samples + sms_header = pysms.SMS_Header() + pysms.sms_fillHeader(sms_header, analysis_params, "pysms") - # while do_analysis and (current_frame < self.num_frames): - # sample_offset += size_new_data - # size_new_data = analysis_params.sizeNextRead - # # convert frame to floats for libsms - # frame = audio[sample_offset:sample_offset + size_new_data] - # frame = np.array(frame, dtype=np.float32) - # analysis_data = pysms.SMS_Data() - # pysms.sms_allocFrameH(sms_header, analysis_data) - # status = pysms.sms_analyze(frame, analysis_data, analysis_params) - - # if status == 1: - # num_partials = analysis_data.nTracks - # sms_freqs = np.zeros(num_partials, dtype=np.float32) - # sms_amps = np.zeros(num_partials, dtype=np.float32) - # sms_phases = np.zeros(num_partials, dtype=np.float32) - # analysis_data.getSinFreq(sms_freqs) - # analysis_data.getSinAmp(sms_amps) - # analysis_data.getSinPhase(sms_phases) - # # make partial objects - # for i in range(num_partials): - # # for each partial, if the mag is > 0, this partial is alive - # if sms_amps[i] > 0: - # # create a peak object - # p = simpl.Peak() - # p.amplitude = sms_amps[i] - # p.frequency = sms_freqs[i] - # p.phase = sms_phases[i] - # # add this peak to the appropriate partial - # if not live_partials[i]: - # live_partials[i] = simpl.Partial() - # live_partials[i].starting_frame = current_frame - # sms_partials.append(live_partials[i]) - # live_partials[i].add_peak(p) - # # if the mag is 0 and this partial was alive, kill it - # else: - # if live_partials[i]: - # live_partials[i] = None - # elif status == -1: - # do_analysis = False - # current_frame += 1 + sample_offset = 0 + size_new_data = 0 + current_frame = 0 + sms_partials = [] + live_partials = [None for i in range(self.max_peaks)] + do_analysis = True - # pysms.sms_freeAnalysis(analysis_params) - # pysms.sms_closeSF() - # pysms.sms_free() + while do_analysis and (current_frame < self.num_frames): + sample_offset += size_new_data + size_new_data = analysis_params.sizeNextRead + # convert frame to floats for libsms + frame = audio[sample_offset:sample_offset + size_new_data] + frame = np.array(frame, dtype=np.float32) + analysis_data = pysms.SMS_Data() + pysms.sms_allocFrameH(sms_header, analysis_data) + status = pysms.sms_analyze(frame, analysis_data, analysis_params) - # import debug - - # debug.print_partials(sms_partials) - # print + if status == 1: + num_partials = analysis_data.nTracks + sms_freqs = np.zeros(num_partials, dtype=np.float32) + sms_amps = np.zeros(num_partials, dtype=np.float32) + sms_phases = np.zeros(num_partials, dtype=np.float32) + analysis_data.getSinFreq(sms_freqs) + analysis_data.getSinAmp(sms_amps) + analysis_data.getSinPhase(sms_phases) + # make partial objects + for i in range(num_partials): + # for each partial, if the mag is > 0, this partial is alive + if sms_amps[i] > 0: + # create a peak object + p = simpl.Peak() + p.amplitude = sms_amps[i] + p.frequency = sms_freqs[i] + p.phase = sms_phases[i] + # add this peak to the appropriate partial + if not live_partials[i]: + live_partials[i] = simpl.Partial() + live_partials[i].starting_frame = current_frame + sms_partials.append(live_partials[i]) + live_partials[i].add_peak(p) + # if the mag is 0 and this partial was alive, kill it + else: + if live_partials[i]: + live_partials[i] = None + elif status == -1: + do_analysis = False + pysms.sms_freeFrame(analysis_data) + current_frame += 1 - # audio, sampling_rate = self.get_audio() - # analysis_params, sms_header = self.simplsms_params(sampling_rate, - # self.max_peaks, - # self.num_frames) - # analysis_params.nFrames = self.num_frames - # analysis_params.iSizeSound = self.num_samples + pysms.sms_freeAnalysis(analysis_params) + pysms.sms_closeSF() + pysms.sms_free() - # sample_offset = 0 - # size_new_data = 0 - # current_frame = 0 - # sms_partials = [] - # live_partials = [None for i in range(self.max_peaks)] - # do_analysis = True + pd = simpl.SMSPeakDetection() + pd.max_peaks = self.max_peaks + pd.hop_size = self.hop_size + peaks = pd.find_peaks(audio)[0:self.num_frames] + pt = simpl.SMSPartialTracking() + pt.max_partials = self.max_peaks + partials = pt.find_partials(peaks) - # while do_analysis and (current_frame < self.num_frames): - # sample_offset += size_new_data - # size_new_data = analysis_params.sizeNextRead - # frame = audio[sample_offset:sample_offset + size_new_data] - # analysis_data = simplsms.SMS_Data() - # simplsms.sms_allocFrameH(sms_header, analysis_data) - # status = simplsms.sms_analyze(frame, analysis_data, analysis_params) + import debug + debug.print_partials(sms_partials) + print + debug.print_partials(partials) + #raise Exception("ok") - # if status == 1: - # num_partials = analysis_data.nTracks - # sms_freqs = simpl.zeros(num_partials) - # sms_amps = simpl.zeros(num_partials) - # sms_phases = simpl.zeros(num_partials) - # analysis_data.getSinFreq(sms_freqs) - # analysis_data.getSinAmp(sms_amps) - # analysis_data.getSinPhase(sms_phases) - # # make partial objects - # for i in range(num_partials): - # # for each partial, if the mag is > 0, this partial is alive - # if sms_amps[i] > 0: - # # create a peak object - # p = simpl.Peak() - # p.amplitude = sms_amps[i] - # p.frequency = sms_freqs[i] - # p.phase = sms_phases[i] - # # add this peak to the appropriate partial - # if not live_partials[i]: - # live_partials[i] = simpl.Partial() - # live_partials[i].starting_frame = current_frame - # sms_partials.append(live_partials[i]) - # live_partials[i].add_peak(p) - # # if the mag is 0 and this partial was alive, kill it - # else: - # if live_partials[i]: - # live_partials[i] = None - # elif status == -1: - # do_analysis = False - # current_frame += 1 + # make sure both have the same number of partials + self.assertEquals(len(sms_partials), len(partials)) - # simplsms.sms_freeAnalysis(analysis_params) - # simplsms.sms_free() - - # debug.print_partials(sms_partials) - # return - - # #pd = simpl.SMSPeakDetection() - # #pd.max_peaks = self.max_peaks - # #pd.hop_size = self.hop_size - # #peaks = pd.find_peaks(audio) - # #pt = simpl.SMSPartialTracking() - # #pt.max_partials = self.max_peaks - # #partials = pt.find_partials(peaks[0:self.num_frames]) - - # #from pylab import show - # #simpl.plot.plot_partials(sms_partials) - # #show() - - # # make sure both have the same number of partials - # self.assertEquals(len(sms_partials), len(partials)) - - # # make sure each partial is the same - # for i in range(len(sms_partials)): - # self.assertEquals(sms_partials[i].get_length(), partials[i].get_length()) - # for peak_number in range(sms_partials[i].get_length()): - # self.assertAlmostEquals(sms_partials[i].peaks[peak_number].amplitude, - # partials[i].peaks[peak_number].amplitude, - # places = self.FLOAT_PRECISION) - # self.assertAlmostEquals(sms_partials[i].peaks[peak_number].frequency, - # partials[i].peaks[peak_number].frequency, - # places = self.FLOAT_PRECISION) - # self.assertAlmostEquals(sms_partials[i].peaks[peak_number].phase, - # partials[i].peaks[peak_number].phase, - # places = self.FLOAT_PRECISION) + # make sure each partial is the same + for i in range(len(sms_partials)): + self.assertEquals(sms_partials[i].get_length(), partials[i].get_length()) + for peak_number in range(sms_partials[i].get_length()): + self.assertAlmostEquals(sms_partials[i].peaks[peak_number].amplitude, + partials[i].peaks[peak_number].amplitude, + places = self.FLOAT_PRECISION) + self.assertAlmostEquals(sms_partials[i].peaks[peak_number].frequency, + partials[i].peaks[peak_number].frequency, + places = self.FLOAT_PRECISION) + self.assertAlmostEquals(sms_partials[i].peaks[peak_number].phase, + partials[i].peaks[peak_number].phase, + places = self.FLOAT_PRECISION) #def test_interpolate_frames(self): # """test_interpolate_frames @@ -834,7 +779,7 @@ if __name__ == "__main__": # useful for debugging, particularly with GDB import nose argv = [__file__, - __file__ + ":TestSimplSMS.test_sms_analyze", - __file__ + ":TestSimplSMS.test_sms_analyze"] + #__file__ + ":TestSimplSMS.test_partial_tracking", + __file__ + ":TestSimplSMS.test_partial_tracking"] nose.run(argv=argv) |