This is fft.m in view mode; [Download] [Up]
/* fft.m -- FFT support for FFTView and SpectrumView classes
* Functions contained in this file:
* float *getframe() -- gets a frame of samples from a sound
* float scaledata() -- scales data for dB, LINEAR, and/or GRAYSCALE
*
* jwp@silvertone.Princeton.edu
* smb@datran2.uunet.uu.net
* 02/90
* Added support for indirect format Sounds, 03/90
*/
#import <soundkit/Sound.h>
#import <stdio.h>
#import <math.h>
#import "fft.h"
extern char *getblock(id aSound, int inskip, int nsamps);
/* getframe() -- Gets a frame of samples from a sound
*
* This function gets 'nsamps' samples from 'sound' starting at
* sample frame 'startsamp'. This function will convert shorts to floats
* and stereo to mono (the channels are added together). getframe()
* also allocates its own sample buffer, and returns a pointer to that
* buffer.
*/
float *getframe(sound,startsamp,nsamps)
id sound; /* Sound object */
int startsamp; /* Starting sample frame */
int nsamps; /* Number of sample frames to get */
{
static float *sframe = NULL; /* Sample buffer */
static double *hanning = NULL; /* Hanning window */
static int framesize; /* Last framesize */
short *idata; /* Pointers to samples */
float *fdata; /* (shorts or floats) */
int nchans; /* Channel count */
int i,j;
float f;
if (!sound)
return 0;
/* If we have a new frame size, allocate a new buffer and a new
* Hanning window.
*/
if (framesize != nsamps) {
if (sframe && hanning) {
free(sframe);
free(hanning);
}
sframe = malloc(nsamps * sizeof(float));
hanning = malloc(nsamps * sizeof(double));
create_hanning(hanning, nsamps, 1.); /* (see fft_net.c) */
framesize = nsamps;
}
nchans = [sound channelCount];
/* For either short or float samples, add all channels together, multiply by
* the Hanning window and store result in buffer
*/
switch([sound dataFormat]) {
case SND_FORMAT_LINEAR_16:
// idata = (short *)[sound data] + startsamp*nchans;
if ((idata =
(short *)getblock(sound,startsamp,framesize))
== NULL)
return NULL;
for (i = 0; i < framesize; i++) {
for (j = 0, f= 0.0; j < nchans; j++, idata++)
f += *idata;
sframe[i] = f * hanning[i];
}
break;
case SND_FORMAT_FLOAT:
// fdata = (float *)[sound data] + startsamp*nchans;
if ((fdata =
(float *)getblock(sound,startsamp,framesize))
== NULL)
return NULL;
for (i = 0; i < framesize; i++) {
f = 0.0;
for (j = 0; j < nchans; j++, fdata++)
f += *fdata;
sframe[i] = f * hanning[i];
}
break;
default:
NXRunAlertPanel("FFTView","Unknown sound data format",
"OK",NULL,NULL);
return 0;
break;
}
return sframe;
}
/* scaledata() -- Scale FFT output
*
* Does following scaling:
* dB or LINEAR: in dB (logarhythmic) scale, output = 20 * log10(input)
* in LINEAR scale, output = input / FFT_size
* GRAYSCALE: output is values 0.0 to 1.0 representing PostScript
* grayscale values.
* if 'scalemask' is 0 (default), LINEAR scaling is done. To get
* dB and/or grayscale output, scalemask should be set to dBMASK or
* GRAYSCALEMASK or an OR-ing of those values (dBMASK|GRAYSCALEMASK).
* If 'mean' is not NULL, the index of the mean frequency within the
* FFT frame will be placed there. The function returns the peak
* amplitude found in the frame.
*/
float scaledata(inptr,outptr,nsamps,scalemask,mean)
float *inptr, *outptr; /* Input and output buffers */
int nsamps; /* Size of buffer */
int scalemask; /* dB, GRAYSCALE, or none */
int *mean; /* (optional) pointer to mean freq. */
{
float maxamp;
float slicesum,slicemean; /* For storing slice info */
int N = nsamps/2; /* Convenience variables */
float *inp, *outp;
int i;
/* Rescale the FFT results
*/
for (i=0, slicesum=maxamp=0.0, inp = inptr, outp = outptr;
i < N;
i++, inp++, outp++) {
if (!(scalemask & dBMASK)) /* For linear scale: */
*outp = *inp/nsamps; /* scale by 1/npts */
else /* For dB scale: */
*outp = (float)20. * log10(*inp);
if (*outp > maxamp) /* Figure peak amp */
maxamp = *outp;
slicesum += *outp; /* And sum of amps */
}
if (mean) {
for (i=slicemean=0, outp=outptr; i < N; i++, outp++) {
slicemean += *outp * 2.;
if (slicemean >= slicesum)
break;
}
*mean = i; /* Just the index into the FFT */
}
if (scalemask & GRAYSCALEMASK) {
slicesum /= (float)(N >> 5);
for (i = 0, outp = outptr; i < N; i++, outp++) {
*outp = floor(*outp / slicesum * 50.0) / 50.0;
*outp = 1.0 - *outp;
}
}
return maxamp;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.