From 4d00d10a308c4a0337f56d4c95b5f62596bbb69e Mon Sep 17 00:00:00 2001
From: John Glover <j@johnglover.net>
Date: Mon, 21 Jan 2013 22:08:31 +0100
Subject: [partial_tracking,sms] Fix bug in SMS partial tracking.

GetNextClosestPeak was missing peaks in some
situations.

Some general tidy up of SMS partial tracking code.
---
 src/sms/analysis.c | 65 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 41 insertions(+), 24 deletions(-)

(limited to 'src/sms/analysis.c')

diff --git a/src/sms/analysis.c b/src/sms/analysis.c
index b904449..2355a8f 100644
--- a/src/sms/analysis.c
+++ b/src/sms/analysis.c
@@ -254,15 +254,25 @@ int sms_findPeaks(int sizeWaveform, sfloat *pWaveform, SMS_AnalParams *pAnalPara
 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 - 1;  /* frame # of current frame */
+
+    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[pAnalParams->iMaxDelayFrames-1] = tempFrame;
+    {
+        pAnalParams->ppFrames[i - 1] = pAnalParams->ppFrames[i];
+    }
+    pAnalParams->ppFrames[currentFrame] = tempFrame;
 
     /* initialize the current frame */
     SMS_AnalFrame *frame = pAnalParams->ppFrames[currentFrame];
@@ -289,14 +299,20 @@ void sms_setPeaks(SMS_AnalParams *pAnalParams, int numamps, sfloat* amps,
     {
         /* get a reference fundamental */
         sfloat refFundamental = 0;
-        sfloat avgDeviation = sms_fundDeviation(pAnalParams, currentFrame-1);
+        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,
@@ -308,52 +324,53 @@ void sms_setPeaks(SMS_AnalParams *pAnalParams, int numamps, sfloat* amps,
 
 int sms_findPartials(SMS_Data *pSmsData, SMS_AnalParams *pAnalParams)
 {
-    int currentFrame = pAnalParams->iMaxDelayFrames - 1;
+    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;
 
-    /* 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;
+    if(delayFrames >= currentFrame)
+    {
+        printf("Error: analysis delay is too large (%d, max is %d)\n",
+               delayFrames, currentFrame - 1);
+        return 1;
+    }
 
-    /* clear SMS output */
     sms_clearFrame(pSmsData);
 
-    /* incorporate the peaks into the corresponding tracks */
-    if(pAnalParams->ppFrames[currentFrame-delayFrames]->fFundamental > 0 ||
+    if(pAnalParams->ppFrames[currentFrame - delayFrames]->fFundamental > 0 ||
        ((pAnalParams->iFormat == SMS_FORMAT_IH || pAnalParams->iFormat == SMS_FORMAT_IHP) &&
-        pAnalParams->ppFrames[currentFrame-delayFrames]->nPeaks > 0))
+        pAnalParams->ppFrames[currentFrame - delayFrames]->nPeaks > 0))
     {
-        sms_peakContinuation(currentFrame-delayFrames, pAnalParams);
+        sms_peakContinuation(currentFrame - delayFrames, pAnalParams);
     }
 
-    /* fill gaps and delete short tracks */
     if(pAnalParams->iCleanTracks > 0)
     {
-        sms_cleanTracks(currentFrame-delayFrames, pAnalParams);
+        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;
+    return 0;
 }
 
 int sms_findResidual(int sizeSynthesis, sfloat* pSynthesis,
-- 
cgit v1.2.3