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.