home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio 4.94 - Over 11,000 Files
/
audio-11000.iso
/
msdos
/
sndbords
/
proaudio
/
freq3
/
setupsub.c
< prev
Wrap
C/C++ Source or Header
|
1993-10-07
|
18KB
|
639 lines
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include "freq.h"
int fftlen=1024; // Number of points for FFT
long SampleRate=44100; // A/D sampling rate
int logfreq=0; // Flag set to 1 for log-based frequency scale
int logamp=0; // Flag set to 1 for log-based amplitude scale
int windfunc=0; // Flag set to selected window function
int ys=10; // Flag set for max of y-axis (default=10 = 1.0)
int logb=6; // Flag set for base of log scale (default=6 = -60db)
int logs=0; // Flag for max of log scale (default=0 = 0db)
int gain=0; // Amount of db/octave gain
int gain3db=0; // Flag indicating a 3db/octave scale factor gain
int deriv=0; // Flag for doing differencing for 6db/octave gain
long ref_freq=1000; // Reference frequency for n db/octave gains
char *windfile=NULL; // Pointer to filename for saving window data
extern int *buffer[]; // Buffers for gathering data
extern int *fftdata; // Array for FFT data
extern int *wind; // Array storing windowing function
extern int flag[]; // Array of flags indicating fullness of buffers
extern int x[]; // Array of bin #'s displayed
extern int lasty[]; // Last y position for FFT bins
extern unsigned int yscale[]; // Scaling factors
extern int ybase[]; // Scaling offset for log calculations
extern int shift; // Number of bits for gain shift
double alpha; // Gaussian window parameter
struct rgb background = { 0,0,20 },
warn = { 20,0,0 },
graph = { 30,35,60 },
tick = { 40,40,40 },
label = { 50,20,45 },
border = { 40,40,40 },
text = { 55,55,25 },
darkhl = { 63,63,63 },
lighthl = { 55,55,55 };
/*
* Parse the ini file, if it exists
*/
void parse_ini_file(void)
{
FILE *fp;
char buffer[200];
if((fp=fopen("FREQ.INI","r"))!=NULL)
{
while(!feof(fp))
{
fgets(buffer,200,fp);
sscanf(buffer,"Sample rate:%ld",&SampleRate);
sscanf(buffer,"FFT length:%d",&fftlen);
sscanf(buffer,"Window function:%d",&windfunc);
sscanf(buffer,"Log freq scale:%d",&logfreq);
sscanf(buffer,"Log amp scale:%d",&logamp);
sscanf(buffer,"Base db:%d",&logb);
sscanf(buffer,"Top db:%d",&logs);
sscanf(buffer,"Max amp:%d",&ys);
sscanf(buffer,"DB/octave gain:%d",&gain);
sscanf(buffer,"Reference frequency:%d",&ref_freq);
sscanf(buffer,"Background color:%d,%d,%d",&background.red,&background.green,&background.blue);
sscanf(buffer,"Clipping warning color:%d,%d,%d",&warn.red,&warn.green,&warn.blue);
sscanf(buffer,"Graph color:%d,%d,%d",&graph.red,&graph.green,&graph.blue);
sscanf(buffer,"Tick mark color:%d,%d,%d",&tick.red,&tick.green,&tick.blue);
sscanf(buffer,"Axis label color:%d,%d,%d",&label.red,&label.green,&label.blue);
sscanf(buffer,"Border color:%d,%d,%d",&border.red,&border.green,&border.blue);
sscanf(buffer,"Text color:%d,%d,%d",&text.red,&text.green,&text.blue);
sscanf(buffer,"Cursor upper color:%d,%d,%d",&darkhl.red,&darkhl.green,&darkhl.blue);
sscanf(buffer,"Cursor lower color:%d,%d,%d",&lighthl.red,&lighthl.green,&lighthl.blue);
}
fclose(fp);
}
}
/*
* Parse the command line
*/
void parse_command(int argc,char *argv[])
{
int i=1;
while(i<argc)
{
if(argv[i][0]=='-')
{
switch(argv[i][1])
{
case 'S':
case 's':
SampleRate=atol(&argv[i][2]);
break;
case 'F':
case 'f':
if((fftlen=atoi(&argv[i][2])) > MAX_LEN)
{
printf("Maximum of %d points allowed!\n",MAX_LEN);
puts("Hit any key to continue with the maximum...");
fftlen=MAX_LEN;
getch();
}
break;
case 'M':
case 'm':
ys=atoi(&argv[i][2]);
break;
case 'T':
case 't':
logs=atoi(&argv[i][2]);
break;
case 'B':
case 'b':
logb=atoi(&argv[i][2]);
break;
case 'G':
case 'g':
gain=atoi(&argv[i][2]);
break;
case 'R':
case 'r':
ref_freq=atol(&argv[i][2]);
break;
case 'L':
case 'l':
if((argv[i][2]=='A')||(argv[i][2]=='a'))
logamp=1;
else if((argv[i][2]=='F')||(argv[i][2]=='f'))
logfreq=1;
else
{
printf("Ignoring unrecognized switch: %s\n",argv[i]);
puts("Hit any key to continue...");
getch();
}
break;
case 'W':
case 'w':
if(argv[i][2]>='A')
{
windfile=&argv[i][2];
}
else
{
windfunc=argv[i][2]-'0';
if(windfunc==4)
{
alpha=0;
if(argv[i][3]==',')
alpha=atof(&argv[i][4]);
if(alpha<=0) alpha=1;
}
}
break;
case '?':
case 'H':
case 'h':
puts("-Snumber sets the sampling rate.");
puts("-Fnumber sets the length of the FFT.");
puts("-Mnumber sets the scale maximum.");
puts("-Bnumber sets the logarithmic base level (in tens of dB).");
puts("-Tnumber sets the logarithmic top level (in tens of dB).");
puts("-Gnumber sets the dB/octave gain factor.");
puts("-Rnumber sets the reference frequency for dB/octave gains.");
puts("-LA sets a logarithmic scale for the amplitude axis.");
puts("-LF sets a logarithmic scale for the frequency axis.");
puts("-W0 selects a Hamming window. (offset sine) <--default");
puts("-W1 selects a Hanning window. (sine)");
puts("-W2 selects a Blackman window. (two sines)");
puts("-W3[,alpha] selects a Gaussian window.");
puts("-W4 selects a Welch window. (quadratic)");
puts("-W5 selects a Parzen window. (triangular)");
puts("-W6 selects a Rectangular window.");
puts("-Wfilename saves the windowing function to the specified file.");
puts("-? or -H displays this message.");
exit(0);
default:
printf("Ignoring unrecognized switch: %s\n",argv[i]);
puts("Hit any key to continue...");
getch();
}
}
else
printf("Ignoring unrecognized parameter: %s (use -? for help)\n",argv[i]);
i++;
}
/*
* Set up the flags based on chosen gain
*/
if(gain>11)
{
gain=12;
gain3db=0;
deriv=2;
}
else if(gain>8)
{
gain=9;
gain3db=1;
deriv=1;
}
else if(gain>5)
{
gain=6;
gain3db=0;
deriv=1;
}
else if(gain>2)
{
gain=3;
gain3db=1;
deriv=0;
}
else
{
gain=0;
gain3db=0;
deriv=0;
}
/*
* Watch for bad choice of log scales
*/
if(logb<=logs) logs=logb-3;
if((SampleRate>88200) || (SampleRate<5000))
{
puts("Sample rate must be between 5000 and 88200");
exit(1);
}
}
/*
* Allocate memory for and initialize the buffers
*/
void setup_buffers(int length)
{
int i;
for(i=0;i<BUFFERS;i++)
{
if((buffer[i]=(int *)malloc(length*sizeof(int)))==NULL)
{
puts("Unable to allocate enough memory for the buffers!");
exit(1);
}
flag[i]=0;
}
if((fftdata=(int *)malloc(length*sizeof(int)))==NULL)
{
puts("Unable to allocate enough memory for the buffers!");
exit(1);
}
if((wind=(int *)malloc(length*sizeof(int)))==NULL)
{
puts("Unable to allocate enough memory for the buffers!");
exit(1);
}
/*
* Clear out the buffer of last Y display positions
*/
for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
lasty[i]=WINDOW_BOTTOM;
}
void compute_window_function(void)
{
int i;
double val;
/*
* Calculate FFT Windowing function
*/
for(i=0;i<fftlen;i++)
{
double val;
switch(windfunc)
{
case 1: // Hanning
val = 0.5 - 0.5*cos(2*M_PI*i/fftlen);
break;
case 2: // Blackman
val = 0.42-0.5*cos(2*M_PI*i/fftlen)+0.08*cos(4*M_PI*i/fftlen);
break;
case 3: // Gaussian
val = exp(-alpha / ((double)fftlen*(double)fftlen)
* ((double)2*i-fftlen)*((double)2*i-fftlen));
break;
case 4: // Welch
val = 1 - ((double)(2*i-fftlen)/(double)(fftlen+1))
*((double)(2*i-fftlen)/(double)(fftlen+1));
break;
case 5: // Parzen
val = 1 - fabs((double)(2*i-fftlen)/(double)(fftlen+1));
break;
case 6: // Rectangular
val = 1;
break;
default: // Hamming
val = 0.54-0.46*cos(2*M_PI*i/fftlen);
break;
}
wind[i]=floor(val*32767+0.5);
}
/*
* If output requested, save the window function. (for the curious)
*/
if(windfile)
{
FILE *fp;
if((fp=fopen(windfile,"w"))==NULL)
{
printf("Error opening window output file: %s\n",windfile);
getch();
}
else
{
for(i=0;i<fftlen;i++)
fprintf(fp,"%d\n",wind[i]);
fclose(fp);
}
windfile=NULL;
}
}
/*
* Set up X axis scales
*/
void setup_xscale(void)
{
int i;
/*
* Initialize graph x scale (linear or logarithmic).
* This array points to the bin to be plotted on a given line.
*/
for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
{
if(logfreq)
x[i]=floor(exp((double)i/(double)(WINDOW_RIGHT-WINDOW_LEFT+1)*log(fftlen/2))+0.5);
else
x[i]=floor((double)i*(double)fftlen/(double)(2*(WINDOW_RIGHT-WINDOW_LEFT+1))+0.5);
}
/*
* If lines are repeated on the screen, flag this so that we don't
* have to recompute the y values.
*/
for(i=(WINDOW_RIGHT-WINDOW_LEFT);i>0;i--)
{
if(x[i]==fftlen/2) /* we don't compute this bin, so don't display it */
x[i]=-1;
if(x[i]==x[i-1])
x[i]=-1;
}
}
/*
* Set up logarithmic amplitude scale factors and offsets.
*/
void setup_logscales(void)
{
int i;
double scale,base,convert;
/*
* Compute the (logarithmic) y scale factor and offset.
* This may include a 3dB/octave gain.
*
* Conversion factor from db/10 to dPhils (the computed "unit")
* where 1024 dPhils equals 2.0
*/
convert=1024.0*log(10)/log(2);
scale=(WINDOW_BOTTOM-WINDOW_TOP)/(logb-logs)/convert;
if(deriv==0)
base=(log10(32768.0)*2.0-logb)*convert;
else if(deriv==1)
base=(log10(32768.0)*2.0-log10(SampleRate/(2*M_PI*ref_freq))*2.0-logb)*convert;
else
base=(log10(32768.0)*2.0-log10(SampleRate/(2*M_PI*ref_freq))*4.0-logb)*convert;
shift=0;
/*
* Make maximum use of available bits
*/
while(scale<32767.75)
{
scale*=2;
shift++;
}
scale=floor(scale+0.5);
if(gain3db)
{
for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
{
if(x[i]==-1)
{
yscale[i]=0;
ybase[i]=0;
}
else
{
yscale[i]=scale;
if(x[i]!=0)
ybase[i]=floor(base-log10((double)x[i]*SampleRate/fftlen/ref_freq)*convert+0.5);
else
{
yscale[i]=0;
ybase[i]=base;
}
}
}
}
else
{
for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
{
if(x[i]==-1)
{
yscale[i]=0;
ybase[i]=0;
}
else
{
yscale[i]=scale;
ybase[i]=floor(0.5+base);
}
}
}
}
/*
* Set up linear amplitude scale factors
*/
void setup_linscales(void)
{
int i;
double scale;
/*
* Compute the (linear) y scale factor.
* This may include a 3dB/octave gain.
*/
scale=(WINDOW_BOTTOM-WINDOW_TOP)/(ys*3276.8*sqrt(ref_freq));
shift=0;
if(deriv==1)
{
scale*=(double)SampleRate/(2*M_PI*(double)ref_freq);
}
else if(deriv==2)
{
scale*=(double)SampleRate*(double)SampleRate
/(4*M_PI*M_PI*(double)ref_freq*(double)ref_freq);
}
/*
* Make maximum use of available bits
*/
if(gain3db)
{
while((scale*sqrt(SampleRate/2))<32767.75)
{
scale*=2;
shift++;
}
for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
{
if(x[i]==-1)
yscale[i]=0;
else
yscale[i]=floor(0.5+scale*sqrt(x[i]*SampleRate/fftlen));
}
}
else
{
scale=scale*sqrt(ref_freq);
while(scale<32767.75)
{
scale*=2;
shift++;
}
scale=floor(scale+0.5);
for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
{
if(x[i]==-1)
yscale[i]=0;
else
yscale[i]=scale;
}
}
}
void frequency_scale(void)
{
char text[20];
/*
* Put up the frequency scale.
*/
setfillstyle(SOLID_FILL,0);
bar(WINDOW_LEFT-10,WINDOW_BOTTOM+3,WINDOW_RIGHT+10,479);
if(logfreq)
{
double f,step,base;
settextjustify(CENTER_TEXT,TOP_TEXT);
settextstyle(0,1,0);
step=exp(log(fftlen/2)/32.0);
base=(double)SampleRate/(double)fftlen;
for(f=base;f<=(double)(SampleRate*1.01)/2;f*=step)
{
setcolor(BORDER_COLOR);
moveto(WINDOW_LEFT+(log(f)-log(base))/(log(SampleRate/2)-log(base))*(WINDOW_RIGHT-WINDOW_LEFT+1),WINDOW_BOTTOM+3);
linerel(0,3);
moverel(0,3);
setcolor(LABEL_COLOR);
sprintf(text,"%7.1lf",f);
outtext(text);
}
}
else
{
double f;
settextjustify(CENTER_TEXT,TOP_TEXT);
settextstyle(0,1,0);
for(f=0;f<=(double)SampleRate/2.0;f+=(double)SampleRate/64.0)
{
setcolor(BORDER_COLOR);
moveto(WINDOW_LEFT+f*(double)(WINDOW_RIGHT-WINDOW_LEFT+1)*2.0/(double)SampleRate,WINDOW_BOTTOM+3);
linerel(0,3);
moverel(0,3);
setcolor(LABEL_COLOR);
sprintf(text,"%7.1lf",f);
outtext(text);
}
}
}
void amplitude_scale(void)
{
int i;
char text[20];
setfillstyle(SOLID_FILL,0);
bar(0,WINDOW_TOP-10,WINDOW_LEFT-3,WINDOW_BOTTOM+10);
/*
* Put up the amplitude scale
*/
if(logamp)
{
settextjustify(RIGHT_TEXT,CENTER_TEXT);
settextstyle(0,0,0);
for(i=0;i<(logb-logs)+1;i++)
{
setcolor(BORDER_COLOR);
moveto(WINDOW_LEFT-3,WINDOW_TOP+i*(WINDOW_BOTTOM-WINDOW_TOP)/(logb-logs));
linerel(-3,0);
moverel(-3,0);
setcolor(LABEL_COLOR);
sprintf(text,"%d",(i+logs)*(-10));
outtext(text);
}
}
else
{
double scale=(double)(ys*3276.8)/(double)(WINDOW_BOTTOM-WINDOW_TOP);
settextjustify(RIGHT_TEXT,CENTER_TEXT);
settextstyle(0,0,0);
for(i=0;i<=10;i++)
{
setcolor(BORDER_COLOR);
moveto(WINDOW_LEFT-3,WINDOW_BOTTOM-i*ys*327.68/scale);
linerel(-3,0);
moverel(-3,0);
setcolor(LABEL_COLOR);
sprintf(text,"%4.2f",(float)i*ys*0.01);
outtext(text);
}
}
}
char *window_name[] = { "Hamming",
"Hanning",
"Blackman",
"Gaussian",
"Welch",
"Parzen",
"Rectangular" };
void update_header(void)
{
char ach[100];
setfillstyle(SOLID_FILL,0);
bar(SRX-150,SRY,SRX+150,RFY+10);
settextstyle(0,0,0);
settextjustify(CENTER_TEXT,TOP_TEXT);
setcolor(TEXT_COLOR);
sprintf(ach,"Sampling rate: %ld Hz",SampleRate);
outtextxy(SRX,SRY,ach);
sprintf(ach,"FFT Length: %d points",fftlen);
outtextxy(FLX,FLY,ach);
sprintf(ach,"Frequency resolution: %g Hz",(double)SampleRate/(double)fftlen);
outtextxy(FRX,FRY,ach);
sprintf(ach,"%s window function",window_name[windfunc]);
outtextxy(WFX,WFY,ach);
sprintf(ach,"Gain of %d dB per octave",gain);
outtextxy(DGX,DGY,ach);
sprintf(ach,"(0 dB gain at %ld Hz)",ref_freq);
outtextxy(RFX,RFY,ach);
}