ftp.nice.ch/pub/next/unix/audio/sms.N.bs.tar.gz#/sms/library/peakContinuation-new.c

This is peakContinuation-new.c in view mode; [Download] [Up]

#include "../sms.h"

/* function to get the next closest peak from a guide
 * float fGuideFreq;		guide's frequency
 * float *pFFreqDistance;	distance of last best peak from guide
 * PEAK *pSpectralPeaks;	array of peaks
 * ANAL_PARAMS analParams;	analysis parameters
 * float fFreqDev;		maximum deviation from guide
 */
static int GetNextClosestPeak (float fGuideFreq, float *pFFreqDistance, 
                               PEAK *pSpectralPeaks, ANAL_PARAMS analParams,
                               float fFreqDev)
{
	int iInitialPeak = 
		MAX_NUM_PEAKS * fGuideFreq / (analParams.fSamplingRate * .5),
		iLowPeak, iHighPeak, iChosenPeak = -1;
	float fLowDistance, fHighDistance, fFreq;

	if (pSpectralPeaks[iInitialPeak].fFreq <= 0)
		iInitialPeak = 0;
	  
	/* find a low peak to start */
	fLowDistance = fGuideFreq - pSpectralPeaks[iInitialPeak].fFreq;
	if (floor(fLowDistance) < floor(*pFFreqDistance))
	{
		while (floor(fLowDistance) <= floor(*pFFreqDistance) && 
		       iInitialPeak > 0)
		{
			iInitialPeak--;
			fLowDistance = fGuideFreq - pSpectralPeaks[iInitialPeak].fFreq;
		}
	}
	else
	{
		while (floor(fLowDistance) >= floor(*pFFreqDistance) &&
		       iInitialPeak < MAX_NUM_PEAKS)
		{
			iInitialPeak++;	 
			if ((fFreq = pSpectralPeaks[iInitialPeak].fFreq) == 0)
			{	
				if (*pFFreqDistance != -1)
					return -1;
				else break;
			}
			fLowDistance = fGuideFreq - fFreq;
		}
		iInitialPeak--;
		fLowDistance = fGuideFreq - pSpectralPeaks[iInitialPeak].fFreq;
	}
  
	if (floor(fLowDistance) <= floor(*pFFreqDistance) || 
	    fLowDistance > fFreqDev)
		iLowPeak = -1;
	else
		iLowPeak = iInitialPeak;
    
	/* find a high peak to finish */
	iHighPeak = iInitialPeak;
	fHighDistance = fGuideFreq - pSpectralPeaks[iHighPeak].fFreq;
	while (floor(fHighDistance) >= floor(-*pFFreqDistance) &&
	       iHighPeak < MAX_NUM_PEAKS)
	{
		iHighPeak++;	 
		if ((fFreq = pSpectralPeaks[iHighPeak].fFreq) == 0)
		{
			iHighPeak = -1;
			break;
		}
		fHighDistance = fGuideFreq - fFreq;
	}
	if (fHighDistance > 0 || fabs(fHighDistance) > fFreqDev ||
	    floor(fabs(fHighDistance)) <= floor(*pFFreqDistance))
		iHighPeak = -1;

	/* chose between the two extrema */
	if (iHighPeak >= 0 && iLowPeak >= 0)
	{
		if (fabs(fHighDistance) > fLowDistance)
			iChosenPeak = iLowPeak;
		else
			iChosenPeak = iHighPeak;
	}
	else if (iHighPeak < 0 && iLowPeak >= 0)
		iChosenPeak = iLowPeak;
	else if (iHighPeak >= 0 && iLowPeak < 0)
		iChosenPeak = iHighPeak;
	else
		return (-1);

	*pFFreqDistance = fabs (fGuideFreq - pSpectralPeaks[iChosenPeak].fFreq);
	return (iChosenPeak);
}	

/* choose the best candidate out of all, returns the peak number of 
 * the best candidate
 *
 * CONT_CANDIDATE *pCandidate;  pointer to all the continuation candidates
 * int nCandidates;             number of candidates
 * float fFreqDev;              maximum frequency deviation allowed
 */
static int ChooseBestCand (CONT_CANDIDATE *pCandidate, int nCandidates, 
                           float fFreqDev)
{
	int i, iHighestCand, iClosestCand, iBestCand = 0;
	float fMaxMag, fClosestFreq;
  
	/* intial guess */
	iClosestCand = 0;
	fClosestFreq = pCandidate[iClosestCand].fFreqDev;
	iHighestCand = 0;
	fMaxMag = pCandidate[iHighestCand].fMagDev;
  
	/* get the best candidate */
	for (i = 1; i < nCandidates; i++)
	{
		/* look for the one with highest magnitude */
		if (pCandidate[i].fMagDev > fMaxMag)
		{
			fMaxMag = pCandidate[i].fMagDev;
			iHighestCand = i;
		}
		/* look for the closest one to the guide */
		if (pCandidate[i].fFreqDev < fClosestFreq)
		{
			fClosestFreq = pCandidate[i].fFreqDev;
			iClosestCand = i;
		}
	}
	iBestCand = iHighestCand;
  
	/* reconcile the two results */
	if (iBestCand != iClosestCand &&
	    fabs(pCandidate[iHighestCand].fFreqDev - fClosestFreq) > fFreqDev / 2)
		iBestCand = iClosestCand; 
  
	return(pCandidate[iBestCand].iPeak);
}

/* check for one guide that has choosen iBestPeak
 * int iBestPeak;		choosen peak for a guide
 * GUIDE *pGuides;		array of guides
 * int nGuides;			total number of guides
 */
static int CheckForConflict (int iBestPeak, GUIDE *pGuides, int nGuides)
{
	int iGuide;
  
	for (iGuide = 0; iGuide < nGuides; iGuide++)
		if (pGuides[iGuide].iPeakChosen == iBestPeak)
			return iGuide;
   
	return -1;
}

/* chose the best of the two guides for the conflicting peak 
 * int iConflictingGuide;	conflicting guide number
 * int iGuide;			guide number
 * GUIDE *pGuides;		array of guides
 * PEAK *pSpectralPeaks;	array of peaks
 */
static int BestGuide (int iConflictingGuide, int iGuide, GUIDE *pGuides,
                      PEAK *pSpectralPeaks)
{
	int iConflictingPeak = pGuides[iConflictingGuide].iPeakChosen;
	float fGuideDistance = fabs (pSpectralPeaks[iConflictingPeak].fFreq -
	                             pGuides[iGuide].fFreq);
	float fConfGuideDistance = fabs (pSpectralPeaks[iConflictingPeak].fFreq -
	                                 pGuides[iConflictingGuide].fFreq);

	if (fGuideDistance > fConfGuideDistance)
		return (iConflictingGuide);
	else
		return (iGuide);
}

/* function to find the best continuation peak for a given guide
 *	returns the peak number
 * GUIDE *pGuideVal;		guide attributes
 * PEAK *pSpectralPeaks;	peak values at the current frame
 * ANAL_PARAMS analParams;	analysis parameters
 * float fFreqDev;              frequency deviation allowed
 */
static int GetBestPeak (GUIDE *pGuides, int iGuide, PEAK *pSpectralPeaks, 
                        ANAL_PARAMS analParams, float fFreqDev)
{
	int iCand = 0, iPeak, iBestPeak, iConflictingGuide, iWinnerGuide;
	float fGuideFreq = pGuides[iGuide].fFreq,
		fGuideMag = pGuides[iGuide].fMag,
		fFreqDistance = -1, fMagDistance = 0;
	CONT_CANDIDATE pCandidate[MAX_CONT_CANDIDATES];

	/* find all possible candidates */
	while (iCand < MAX_CONT_CANDIDATES)
	{
		/* find the next best peak */
		if ((iPeak = GetNextClosestPeak (fGuideFreq, &fFreqDistance,
		                                 pSpectralPeaks, analParams, 
		                                 fFreqDev)) < 0)
			break;
	
		/* if the peak's magnitude is not too small accept it as */
		/* possible candidate        */
		if ((fMagDistance = pSpectralPeaks[iPeak].fMag  - fGuideMag) > -20.0)
		{
			pCandidate[iCand].fFreqDev = fabs(fFreqDistance);
			pCandidate[iCand].fMagDev = fMagDistance;
			pCandidate[iCand].iPeak = iPeak;
      	      
			if(analParams.iDebugMode == DEBUG_PEAK_CONT ||
			   analParams.iDebugMode == DEBUG_ALL)
				fprintf (stdout, "candidate %d: freq %f mag %f\n", 
				         iCand, pSpectralPeaks[iPeak].fFreq, 	
				         pSpectralPeaks[iPeak].fMag);
			iCand++;
		}
	}
	/* get best candidate */
	if (iCand < 1)
		return (0);
	else if (iCand == 1)
		iBestPeak = pCandidate[0].iPeak;
	else
		iBestPeak = ChooseBestCand (pCandidate, iCand, 
		                            analParams.fFreqDeviation);
      
	if(analParams.iDebugMode == DEBUG_PEAK_CONT ||
	   analParams.iDebugMode == DEBUG_ALL)
		fprintf (stdout, "BestCandidate: freq %f\n",
		         pSpectralPeaks[iBestPeak].fFreq);

	/* if peak taken by another guide resolve conflict */
	if ((iConflictingGuide = CheckForConflict (iBestPeak, pGuides, 
	                                           analParams.nGuides)) >= 0)
	{
		iWinnerGuide = BestGuide (iConflictingGuide, iGuide, pGuides, 
		                          pSpectralPeaks);
		if(analParams.iDebugMode == DEBUG_PEAK_CONT ||
		   analParams.iDebugMode == DEBUG_ALL)
			fprintf (stdout, 
			         "Conflict: guide: %d (%f), and guide: %d (%f). best: %d\n", 
			         iGuide, pGuides[iGuide].fFreq, 
			         iConflictingGuide, pGuides[iConflictingGuide].fFreq, 	    
			         iWinnerGuide);

		if (iGuide == iWinnerGuide)				     
		{
			pGuides[iGuide].iPeakChosen = iBestPeak;
			pGuides[iConflictingGuide].iPeakChosen = -1;
		}
	}
	else
		pGuides[iGuide].iPeakChosen = iBestPeak;

	return (iBestPeak);
}

/* function to get the next maximum peak
 * PEAK *pSpectralPeaks;	array of peaks
 * float *pFCurrentMax;		last peak maximum
 */
static int GetNextMax (PEAK *pSpectralPeaks, float *pFCurrentMax)
{
	float fPeakMag, fMaxMag = MAG_THRESHOLD;
	int iPeak, iMaxPeak = -1;
  
	for (iPeak = 0; iPeak < MAX_NUM_PEAKS; iPeak++)
	{
		fPeakMag = pSpectralPeaks[iPeak].fMag;
    
		if (fPeakMag == 0)
			break;
      
		if (fPeakMag > fMaxMag && fPeakMag < *pFCurrentMax)
		{
			iMaxPeak = iPeak;
			fMaxMag = fPeakMag;
		}
	}
	*pFCurrentMax = fMaxMag;
	return (iMaxPeak);
}

/* function to get a good starting peak for a trajectory
 * int iGuide;      		current guide
 * GUIDE *pGuides;  		array of guides
 * int nGuides;			    total number of guides
 * PEAK *pSpectralPeaks;	array of peaks
 * float *pFCurrentMax;		current peak maximum
 */
static int GetStartingPeak (int iGuide, GUIDE *pGuides, int nGuides,
                            PEAK *pSpectralPeaks, float *pFCurrentMax)
{
	int iPeak = -1;
	short peakNotFound = 1;
  
	while (peakNotFound == 1 && *pFCurrentMax > 0)
	{
		if ((iPeak = GetNextMax (pSpectralPeaks, pFCurrentMax)) < 0)
			return (-1);
  
		if (CheckForConflict (iPeak, pGuides, nGuides) < 0)
		{
			pGuides[iGuide].iPeakChosen = iPeak;
			pGuides[iGuide].iStatus = BEGINNING;
			pGuides[iGuide].fFreq = pSpectralPeaks[iPeak].fFreq;
			peakNotFound = 0;
		}
	}
	return (1);
}

/* function to advance the guides through the next frame
 * the output is the freq., mag., and phase trajectories
 *
 * int iFrame;	 current frame number
 * ANAL_PARAMS analParams; analysis parameters
 */
int PeakContinuation (int iFrame, ANAL_PARAMS analParams)
{
	int iGuide, iCurrentPeak = -1, iGoodPeak = -1;
	float fFund = ppFrames[iFrame]->fFundamental,
		fFreqDev = fFund * analParams.fFreqDeviation, fCurrentMax = 1000;
  	static GUIDE *pGuides = NULL;

	if (pGuides == NULL)
	{
		if ((pGuides = (GUIDE *) calloc(analParams.nGuides, sizeof(GUIDE))) 
		   == NULL)
			return -1;
		for (iGuide = 0; iGuide < analParams.nGuides; iGuide++)
		{
			pGuides[iGuide].iPeakChosen = -1;
			pGuides[iGuide].iStatus = DEAD;
		}
		if (analParams.iFormat == FORMAT_HARMONIC ||
		    analParams.iFormat == FORMAT_HARMONIC_WITH_PHASE)
		for (iGuide = 0; iGuide < analParams.nGuides; iGuide++)
			pGuides[iGuide].fFreq = analParams.fDefaultFundamental 
			                        * (iGuide + 1);
	}        

	/* update guides with fundamental contribution */
	if (fFund > 0 &&
	    (analParams.iFormat == FORMAT_HARMONIC ||
	     analParams.iFormat == FORMAT_HARMONIC_WITH_PHASE))
		for(iGuide = 0; iGuide < analParams.nGuides; iGuide++)
			pGuides[iGuide].fFreq = 
				(1 - analParams.fFundContToGuide) * pGuides[iGuide].fFreq +        
				analParams.fFundContToGuide * fFund * (iGuide + 1);
  
	if (analParams.iDebugMode == DEBUG_PEAK_CONT ||
	    analParams.iDebugMode == DEBUG_ALL)
		fprintf (stdout, 
		         "Frame %d Peak Continuation: \n", 
		         ppFrames[iFrame]->iFrameNum);

	/* continue all guides */
	for (iGuide = 0; iGuide < analParams.nGuides; iGuide++)
	{
		float fPreviousFreq = 
			ppFrames[iFrame-1]->deterministic.pFFreqTraj[iGuide];
   
		/* get the guide value by upgrading the previous guide */
		if (fPreviousFreq > 0)
			pGuides[iGuide].fFreq =
				(1 - analParams.fPeakContToGuide) * pGuides[iGuide].fFreq +
				analParams.fPeakContToGuide * fPreviousFreq;
   
		if (analParams.iDebugMode == DEBUG_PEAK_CONT ||
		    analParams.iDebugMode == DEBUG_ALL)
			fprintf (stdout, "Guide %d:  freq %f, mag %f\n", 
			         iGuide, pGuides[iGuide].fFreq, pGuides[iGuide].fMag);
      
		if (pGuides[iGuide].fFreq <= 0.0 ||
		    pGuides[iGuide].fFreq > analParams.fHighestFreq)
		{
			pGuides[iGuide].iStatus = DEAD;
			pGuides[iGuide].fFreq = 0;
			pGuides[iGuide].iPeakChosen = -1;
			continue;
		}
      
		pGuides[iGuide].iPeakChosen = -1;
    
		if (analParams.iFormat == FORMAT_INHARMONIC ||
		    analParams.iFormat == FORMAT_INHARMONIC_WITH_PHASE)
			fFreqDev = pGuides[iGuide].fFreq * analParams.fFreqDeviation;
      
		/* get the best peak for the guide */
		iGoodPeak = 
			GetBestPeak(pGuides, iGuide, ppFrames[iFrame]->pSpectralPeaks, 
			            analParams, fFreqDev);
	}
  
	/* try to find good peaks for the DEAD guides */
	if (analParams.iFormat == FORMAT_INHARMONIC ||
	    analParams.iFormat == FORMAT_INHARMONIC_WITH_PHASE)
		for(iGuide = 0; iGuide < analParams.nGuides; iGuide++)
		{
			if (pGuides[iGuide].iStatus != DEAD)
				continue; 
	
			if (GetStartingPeak (iGuide, pGuides, analParams.nGuides, 
			                     ppFrames[iFrame]->pSpectralPeaks,
			                     &fCurrentMax) == -1)
				break;
		}

	/* save all the continuation values,
	 * assume output trajectories are already clear */
	for (iGuide = 0; iGuide < analParams.nGuides; iGuide++)
	{
		if (pGuides[iGuide].iStatus == DEAD)
			continue; 

		if (analParams.iFormat == FORMAT_INHARMONIC ||
		    analParams.iFormat == FORMAT_INHARMONIC_WITH_PHASE)
		{
			if (pGuides[iGuide].iStatus > 0 &&
			    pGuides[iGuide].iPeakChosen == -1)
			{ 
				if(pGuides[iGuide].iStatus++ > analParams.iMaxSleepingTime)
				{
					pGuides[iGuide].iStatus = DEAD;
					pGuides[iGuide].fFreq = 0;
					pGuides[iGuide].fMag = 0;
					pGuides[iGuide].iPeakChosen = -1;	  	  
	 			}
				else
					pGuides[iGuide].iStatus++;
				continue;
			}
      
			if (pGuides[iGuide].iStatus == ACTIVE &&
			    pGuides[iGuide].iPeakChosen == -1)
			{
				pGuides[iGuide].iStatus = 1;
				continue;
			}
		}

		/* if good continuation peak found, save it */
		if ((iCurrentPeak = pGuides[iGuide].iPeakChosen) >= 0)
		{
			ppFrames[iFrame]->deterministic.pFFreqTraj[iGuide] = 
				ppFrames[iFrame]->pSpectralPeaks[iCurrentPeak].fFreq;
			ppFrames[iFrame]->deterministic.pFMagTraj[iGuide] = 
				ppFrames[iFrame]->pSpectralPeaks[iCurrentPeak].fMag;
			ppFrames[iFrame]->deterministic.pFPhaTraj[iGuide] = 
				ppFrames[iFrame]->pSpectralPeaks[iCurrentPeak].fPhase;
     
			pGuides[iGuide].iStatus = ACTIVE;
			pGuides[iGuide].iPeakChosen = -1;
		}
	}
	return 1;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.