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

This is spectralApprox.c in view mode; [Download] [Up]

#include "../sms.h"

/* 
 * approximate a magnitude spectrum by first downsampling using local maxima
 * and then upsampling using linear interpolation
 * the output spectrum doesn't have to be the same size as the input one
 *
 * float *pFSpec1     magnitude spectrum to approximate
 * int sizeSec1       size of input spectrum
 * int sizeSpec1Used  size of the spectrum to use
 * float *pFSpec2     output envelope
 * int sizeSpec2      size of output envelope
 * int nCoefficients  number of coefficients to use in approximation
 */
int SpectralApprox (float *pFSpec1, int sizeSpec1, int sizeSpec1Used,
                    float *pFSpec2, int sizeSpec2, int nCoefficients)
{
	float fHopSize, fCurrentLoc = 0, fLeft = 0, fRight = 0, fValue = 0, 
		fLastLocation, fSizeX, fSpec2Acum=0, fNextHop, fDeltaY, *pFEnvelope;
	int iFirstSample = 0, iLastSample = 0, i, j;

  	/* when number of coefficients is smaller than 2 do not approximate */
	if (nCoefficients < 2)
	{
		for (i = 0; i < sizeSpec2; i++)
			pFSpec2[i] = 1;
		return 1;
	}

	if ((pFEnvelope = (float *) calloc(nCoefficients, sizeof(float))) == NULL)
		return -1;
 
	/* calculate the hop size */
	if (sizeSpec1 != sizeSpec1Used)
		fHopSize = (float) sizeSpec1Used / nCoefficients;
	else
		fHopSize = (float) sizeSpec1 / nCoefficients;
	
	/* approximate by linear interpolation */
	if (fHopSize > 1)
	{
		iFirstSample = 0;
		for (i = 0; i < nCoefficients; i++)
		{
			iLastSample = fLastLocation = fCurrentLoc + fHopSize;
			iLastSample = MIN (sizeSpec1-1, iLastSample);
			if (iLastSample < sizeSpec1-1)
				fRight = pFSpec1[iLastSample] +
					(pFSpec1[iLastSample+1] - pFSpec1[iLastSample]) * 
					(fLastLocation - iLastSample);
			else
				fRight = pFSpec1[iLastSample];
			fValue = 0;
			for (j = iFirstSample; j <= iLastSample; j++)
				fValue = MAX (fValue, pFSpec1[j]);
			fValue = MAX (fValue, MAX (fRight, fLeft));
			pFEnvelope[i] = fValue;
			fLeft = fRight;
			fCurrentLoc = fLastLocation;
			iFirstSample = (int) (1+ fCurrentLoc);
		}
	}
	else if (fHopSize == 1)
	{
		for (i = 0; i < nCoefficients; i++)
			pFEnvelope[i] = pFSpec1[i];
	}
	else
	{
		free (pFEnvelope);
		printf ("too many nCoefficients\n");
		return -1;
	}

	/* Creates Spec2 from Envelope */
	if (nCoefficients < sizeSpec2)
	{
		fSizeX = (float) (sizeSpec2-1) / nCoefficients;

		/* the first step */
		fNextHop = fSizeX / 2;
		fDeltaY = pFEnvelope[0] / fNextHop;
		fSpec2Acum=pFSpec2[j=0]=0;
		while (++j < fNextHop)  
			pFSpec2[j] = (fSpec2Acum += fDeltaY);
     
		/* middle values */
		for (i = 0; i <= nCoefficients-2; ++i) 
		{
			fDeltaY = (pFEnvelope[i+1] - pFEnvelope[i]) / fSizeX;
			/* first point of a segment */
			pFSpec2[j] = (fSpec2Acum = (pFEnvelope[i]+(fDeltaY*(j-fNextHop))));
			++j;
			/* remaining points */
			fNextHop += fSizeX;
			while (j < fNextHop)  
				pFSpec2[j++] = (fSpec2Acum += fDeltaY);
    	}

		/* last step */
		fDeltaY = -pFEnvelope[i] * 2 / fSizeX;
		/* first point of the last segment */
		pFSpec2[j] = (fSpec2Acum = (pFEnvelope[i]+(fDeltaY*(j-fNextHop))));
		++j;
		fNextHop += fSizeX / 2;
		while (j < sizeSpec2-1)  
			pFSpec2[j++]=(fSpec2Acum += fDeltaY);
		/* last should be exactly zero */
		pFSpec2[sizeSpec2-1] = .0;	
    }
	else if (nCoefficients == sizeSpec2)
	{
		for (i = 0; i < nCoefficients; i++)
			pFSpec2[i] = pFEnvelope[i];
	}
	else
	{
		free (pFEnvelope);
		printf ("too many nCoefficients\n");
		return -1;
	}
	free (pFEnvelope);
	return 1;
}

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