ftp.nice.ch/pub/next/unix/audio/cmusic.bs.N.tar.gz#/src/pvdsp/fft.c

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

/*
 *	External DSP memory is allocated as follows:
 *	           "Normal" Partition		"XY Partition"
 *	x:$2000|=======================||========================|y:$a000
 *	       |                       ||   FFT imaginary part   |
 *	       |                       ||       FFT_SIZE         |
 *	       |-----------------------||------------------------|
 *	       |                       || Sin table 1/2 FFT_SIZE |
 *	       |-----------------------||------------------------|
 *	       |    Filter window      ||                        |
 *	       |      FFT_SIZE         ||                        |
 *	       |-----------------------||------------------------|
 *	       |                       ||                        |
 *	x:$3000|-----------------------||========================|x:$a000
 *	       |                       ||     FFT real part      |
 *	       |                       ||       FFT_SIZE         |
 *	       |-----------------------||------------------------|
 *	       |                       || Cos table 1/2 FFT_SIZE |
 *	       |-----------------------||------------------------|
 *	       |   Unshuffle buffer    ||                        |
 *	       |      FFT_SIZE         ||                        |
 *	       |-----------------------||------------------------|
 *	       |                       ||                        |
 *	       |=======================||========================|
 *
 *	We must rely on the fact that the "XY Partition" is imaged
 *	in the "Normal" (PMEM) partition because currently all AP macros
 *	except the FFT reference normal memory only.
 *
 *	Note that the sin and cos tables and the filter are in the
 *	full 24-bit range, and the sound file is in 16-bit range
 *	(this leaves some headroom on the DSP).
 */
#include <stdio.h>
#include <stdlib.h>
#include <dsp/arrayproc.h>

/* Constants */
#define	COEF_SIZE	(FFT_SIZE/2)

#define	FFT_DATA	DSPAPGetLowestAddressXY()
#define	FFT_COEF	(FFT_DATA+FFT_SIZE)

/* Defines for AP macros to access XY partition image. */
#define	FFT_IMAG	DSPMapPMemY(FFT_DATA)
#define	FFT_REAL	DSPMapPMemX(FFT_DATA)
#define	SIN_TABLE	DSPMapPMemY(FFT_COEF)
#define	COS_TABLE	DSPMapPMemX(FFT_COEF)
#define	UNSHUFFLE_BUF	DSPMapPMemX(FFT_COEF+COEF_SIZE)

/* Scaling constants */
#define	FFT_SCALE	DSP_FLOAT_TO_INT(1.0/FFT_SIZE)
/*
 * If forward is true, rfft replaces 2*N real data points in x with
 * N complex values representing the positive frequency half of their
 * Fourier spectrum, with x[1] replaced with the real part of the Nyquist
 * frequency value.  If forward is false, rfft expects x to contain a
 * positive frequency spectrum arranged as before, and replaces it with
 * 2*N real values.  N MUST be a power of 2.
 */
void rfft( float x[], int N, int forward ) {
 static int first = 1 ;
 int FFT_SIZE = N*2 ;
 float *sinTab ;
 float *cosTab ;
 float *floatBuf = (float *) malloc( (FFT_SIZE + 2)*sizeof(float) ) ;
 float norm ;
 float normalize( float [], int ) ;
 void unnormalize( float [], int, float ) ;
 void combine( float [], float [], float [], int ) ;
 void separate( float [], float [], float [], int ) ;
    if ( first ) {
	first = 0 ;
/* Enable DSP error logging to stderr and init the DSP */
	DSPSetErrorFP( stderr ) ;
	DSPEnableErrorLog() ;
	DSPAPInit() ;
	sinTab = DSPAPSinTable( FFT_SIZE ) ;
	cosTab = DSPAPCosTable( FFT_SIZE ) ;
/* Download FFT coefficient (sin and cos) tables */
	DSPAPWriteFloatArray( sinTab, SIN_TABLE, 1, COEF_SIZE ) ;
	DSPAPWriteFloatArray( cosTab, COS_TABLE, 1, COEF_SIZE ) ;
    }
    if ( forward ) {
        norm = normalize( x, FFT_SIZE ) ;
/* Download signal data */
        DSPAPWriteFloatArray( x, FFT_REAL, 1, FFT_SIZE ) ;
/* Clear imaginary input */
        DSPAPvclear( FFT_IMAG, 1, FFT_SIZE ) ; 
/* Do FFT */
        DSPAPfftr2a( FFT_SIZE, FFT_DATA, FFT_COEF ) ;
/* Unshuffle and return positive half spectrum */
        DSPAPvmovebr( FFT_REAL, FFT_SIZE/2, UNSHUFFLE_BUF, 1, FFT_SIZE ) ;
        DSPAPReadFloatArray( floatBuf, UNSHUFFLE_BUF, 1, FFT_SIZE/2 + 1 ) ;
        DSPAPvmovebr( FFT_IMAG, FFT_SIZE/2, UNSHUFFLE_BUF, 1, FFT_SIZE ) ;
        DSPAPReadFloatArray( floatBuf+N+1, UNSHUFFLE_BUF, 1, N+1 ) ;
/* Rearrange output into rfft format and scale */
        combine( floatBuf, floatBuf+N+1, x, N ) ;
        unnormalize( x, FFT_SIZE, norm/FFT_SIZE ) ;
    } else {
/* Rearrange rfft-format into separate real and imaginary arrays */
        separate( x, floatBuf, floatBuf+N+1, N ) ;
/* Download positive frequency real part of spectrum data */
        DSPAPWriteFloatArray( floatBuf, FFT_REAL, 1, N+1 ) ;
/* Download positive frequency imaginary part of spectrum data */
        DSPAPWriteFloatArray( floatBuf+N+1, FFT_IMAG, 1, N+1 ) ;
/* Complete real and imaginary data with reverse copies of positive frequency parts */
        DSPAPvreverse( FFT_REAL+1, FFT_REAL+N+1, N-1 ) ;
	DSPAPvreverse( FFT_IMAG+1, FFT_IMAG+N+1, N-1 ) ;
/* Make imaginary part antisymmetrical and conjugate */
	DSPAPvtsi(FFT_IMAG, 1, DSP_FLOAT_TO_INT(-1.), FFT_IMAG, 1, N);
/* Do inverse FFT */
        DSPAPfftr2a(FFT_SIZE, FFT_DATA, FFT_COEF);  
/* Unshuffle real part */
        DSPAPvmovebr(FFT_REAL, FFT_SIZE/2, UNSHUFFLE_BUF, 1, FFT_SIZE);
/* Upload signal data */
        DSPAPReadFloatArray( x, UNSHUFFLE_BUF, 1, FFT_SIZE ) ;
    }
/* Release the DSP */
/*
    DSPAPFree() ;
*/
    free( floatBuf ) ;
}
void combine( float real[], float imag[], float complex[], int N ) {
 int i ;
    for ( i = 0 ; i < N ; i++ ) {
        complex[i<<1] = real[i] ;
	complex[(i<<1)+1] = -imag[i] ;
    }
    complex[1] = real[N] ;
}
void separate( float complex[], float real[], float imag[], int N ) {
 int i ;
    for ( i = 0 ; i < N ; i++ ) {
        real[i] = complex[i<<1] ;
	imag[i] = -complex[(i<<1)+1] ;
    }
    real[N] = complex[1] ;
    imag[0] = imag[N] = 0. ;
}
float normalize( float a[], int N ) {
 float max = a[0], absval ;
 int i ;
    if ( max < 0. )
	max = -max ;
    for ( i = 1 ;  i < N ; i++ ) {
	absval = ( a[i] >= 0. ? a[i] : -a[i] ) ;
	if ( absval > max )
	    max = absval ;
    }
    if ( max == 0. )
        return( 1. ) ;
    max *= 2. ;
    max = 1./max ;
    max /= N ;
    for ( i = 0 ; i < N ; i++ )
        a[i] *= max ;
    return( 1./max ) ;
}
void unnormalize( float a[], int N, float factor ) {
 float *fend = a + N ;
    while ( a < fend )
	*a++ *= factor ;
}

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