home *** CD-ROM | disk | FTP | other *** search
/ Audio 4.94 - Over 11,000 Files / audio-11000.iso / msdos / sndbords / proaudio / freq3 / setupsub.c < prev   
C/C++ Source or Header  |  1993-10-07  |  18KB  |  639 lines

  1. #include <math.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <conio.h>
  5. #include <graphics.h>
  6. #include "freq.h"
  7.  
  8. int fftlen=1024;        // Number of points for FFT
  9. long SampleRate=44100;  // A/D sampling rate
  10. int logfreq=0;          // Flag set to 1 for log-based frequency scale
  11. int logamp=0;           // Flag set to 1 for log-based amplitude scale
  12. int windfunc=0;         // Flag set to selected window function
  13. int ys=10;              // Flag set for max of y-axis (default=10 = 1.0)
  14. int logb=6;             // Flag set for base of log scale (default=6 = -60db)
  15. int logs=0;             // Flag for max of log scale (default=0 = 0db)
  16. int gain=0;             // Amount of db/octave gain
  17. int gain3db=0;          // Flag indicating a 3db/octave scale factor gain
  18. int deriv=0;            // Flag for doing differencing for 6db/octave gain
  19. long ref_freq=1000;     // Reference frequency for n db/octave gains
  20.  
  21. char *windfile=NULL;    // Pointer to filename for saving window data
  22.  
  23. extern int *buffer[];   // Buffers for gathering data
  24. extern int *fftdata;    // Array for FFT data
  25. extern int *wind;       // Array storing windowing function
  26.  
  27. extern int flag[];            // Array of flags indicating fullness of buffers
  28. extern int x[];               // Array of bin #'s displayed
  29. extern int lasty[];           // Last y position for FFT bins
  30. extern unsigned int yscale[]; // Scaling factors
  31. extern int ybase[];           // Scaling offset for log calculations
  32. extern int shift;             // Number of bits for gain shift
  33.  
  34.  
  35. double alpha;           // Gaussian window parameter
  36.  
  37. struct rgb background = { 0,0,20 },
  38.            warn       = { 20,0,0 },
  39.            graph      = { 30,35,60 },
  40.            tick       = { 40,40,40 },
  41.            label      = { 50,20,45 },
  42.            border     = { 40,40,40 },
  43.            text       = { 55,55,25 },
  44.            darkhl     = { 63,63,63 },
  45.            lighthl    = { 55,55,55 };
  46.  
  47. /*
  48.  *  Parse the ini file, if it exists
  49.  */
  50. void parse_ini_file(void)
  51. {
  52.    FILE *fp;
  53.    char buffer[200];
  54.  
  55.    if((fp=fopen("FREQ.INI","r"))!=NULL)
  56.    {
  57.       while(!feof(fp))
  58.       {
  59.          fgets(buffer,200,fp);
  60.  
  61.          sscanf(buffer,"Sample rate:%ld",&SampleRate);
  62.          sscanf(buffer,"FFT length:%d",&fftlen);
  63.          sscanf(buffer,"Window function:%d",&windfunc);
  64.          sscanf(buffer,"Log freq scale:%d",&logfreq);
  65.          sscanf(buffer,"Log amp scale:%d",&logamp);
  66.          sscanf(buffer,"Base db:%d",&logb);
  67.          sscanf(buffer,"Top db:%d",&logs);
  68.          sscanf(buffer,"Max amp:%d",&ys);
  69.          sscanf(buffer,"DB/octave gain:%d",&gain);
  70.          sscanf(buffer,"Reference frequency:%d",&ref_freq);
  71.          sscanf(buffer,"Background color:%d,%d,%d",&background.red,&background.green,&background.blue);
  72.          sscanf(buffer,"Clipping warning color:%d,%d,%d",&warn.red,&warn.green,&warn.blue);
  73.          sscanf(buffer,"Graph color:%d,%d,%d",&graph.red,&graph.green,&graph.blue);
  74.          sscanf(buffer,"Tick mark color:%d,%d,%d",&tick.red,&tick.green,&tick.blue);
  75.          sscanf(buffer,"Axis label color:%d,%d,%d",&label.red,&label.green,&label.blue);
  76.          sscanf(buffer,"Border color:%d,%d,%d",&border.red,&border.green,&border.blue);
  77.          sscanf(buffer,"Text color:%d,%d,%d",&text.red,&text.green,&text.blue);
  78.          sscanf(buffer,"Cursor upper color:%d,%d,%d",&darkhl.red,&darkhl.green,&darkhl.blue);
  79.          sscanf(buffer,"Cursor lower color:%d,%d,%d",&lighthl.red,&lighthl.green,&lighthl.blue);
  80.       }
  81.       fclose(fp);
  82.    }
  83. }
  84.  
  85.  
  86. /*
  87.  * Parse the command line
  88.  */
  89. void parse_command(int argc,char *argv[])
  90. {
  91.    int i=1;
  92.    while(i<argc)
  93.    {
  94.       if(argv[i][0]=='-')
  95.       {
  96.          switch(argv[i][1])
  97.          {
  98.             case 'S':
  99.             case 's':
  100.                  SampleRate=atol(&argv[i][2]);
  101.                  break;
  102.             case 'F':
  103.             case 'f':
  104.                  if((fftlen=atoi(&argv[i][2])) > MAX_LEN)
  105.                  {
  106.                     printf("Maximum of %d points allowed!\n",MAX_LEN);
  107.                     puts("Hit any key to continue with the maximum...");
  108.                     fftlen=MAX_LEN;
  109.                     getch();
  110.                  }
  111.                  break;
  112.             case 'M':
  113.             case 'm':
  114.                  ys=atoi(&argv[i][2]);
  115.                  break;
  116.             case 'T':
  117.             case 't':
  118.                  logs=atoi(&argv[i][2]);
  119.                  break;
  120.             case 'B':
  121.             case 'b':
  122.                  logb=atoi(&argv[i][2]);
  123.                  break;
  124.             case 'G':
  125.             case 'g':
  126.                  gain=atoi(&argv[i][2]);
  127.                  break;
  128.             case 'R':
  129.             case 'r':
  130.                  ref_freq=atol(&argv[i][2]);
  131.                  break;
  132.             case 'L':
  133.             case 'l':
  134.                  if((argv[i][2]=='A')||(argv[i][2]=='a'))
  135.                     logamp=1;
  136.                  else if((argv[i][2]=='F')||(argv[i][2]=='f'))
  137.                     logfreq=1;
  138.                  else
  139.                  {
  140.                     printf("Ignoring unrecognized switch: %s\n",argv[i]);
  141.                     puts("Hit any key to continue...");
  142.                     getch();
  143.                  }
  144.                  break;
  145.             case 'W':
  146.             case 'w':
  147.                  if(argv[i][2]>='A')
  148.                  {
  149.                     windfile=&argv[i][2];
  150.                  }
  151.                  else
  152.                  {
  153.                     windfunc=argv[i][2]-'0';
  154.                     if(windfunc==4)
  155.                     {
  156.                        alpha=0;
  157.                        if(argv[i][3]==',')
  158.                           alpha=atof(&argv[i][4]);
  159.                        if(alpha<=0) alpha=1;
  160.                     }
  161.                  }
  162.  
  163.                  break;
  164.             case '?':
  165.             case 'H':
  166.             case 'h':
  167.                  puts("-Snumber sets the sampling rate.");
  168.                  puts("-Fnumber sets the length of the FFT.");
  169.                  puts("-Mnumber sets the scale maximum.");
  170.                  puts("-Bnumber sets the logarithmic base level (in tens of dB).");
  171.                  puts("-Tnumber sets the logarithmic top level (in tens of dB).");
  172.                  puts("-Gnumber sets the dB/octave gain factor.");
  173.                  puts("-Rnumber sets the reference frequency for dB/octave gains.");
  174.                  puts("-LA sets a logarithmic scale for the amplitude axis.");
  175.                  puts("-LF sets a logarithmic scale for the frequency axis.");
  176.                  puts("-W0 selects a Hamming window.  (offset sine) <--default");
  177.                  puts("-W1 selects a Hanning window.  (sine)");
  178.                  puts("-W2 selects a Blackman window. (two sines)");
  179.                  puts("-W3[,alpha] selects a Gaussian window.");
  180.                  puts("-W4 selects a Welch window.    (quadratic)");
  181.                  puts("-W5 selects a Parzen window.   (triangular)");
  182.                  puts("-W6 selects a Rectangular window.");
  183.                  puts("-Wfilename saves the windowing function to the specified file.");
  184.                  puts("-? or -H displays this message.");
  185.                  exit(0);
  186.             default:
  187.                  printf("Ignoring unrecognized switch: %s\n",argv[i]);
  188.                  puts("Hit any key to continue...");
  189.                  getch();
  190.          }
  191.       }
  192.       else
  193.          printf("Ignoring unrecognized parameter: %s  (use -? for help)\n",argv[i]);
  194.       i++;
  195.    }
  196.  
  197.    /*
  198.     * Set up the flags based on chosen gain
  199.     */
  200.    if(gain>11)
  201.    {
  202.       gain=12;
  203.       gain3db=0;
  204.       deriv=2;
  205.    }
  206.    else if(gain>8)
  207.    {
  208.       gain=9;
  209.       gain3db=1;
  210.       deriv=1;
  211.    }
  212.    else if(gain>5)
  213.    {
  214.       gain=6;
  215.       gain3db=0;
  216.       deriv=1;
  217.    }
  218.    else if(gain>2)
  219.    {
  220.       gain=3;
  221.       gain3db=1;
  222.       deriv=0;
  223.    }
  224.    else
  225.    {
  226.       gain=0;
  227.       gain3db=0;
  228.       deriv=0;
  229.    }
  230.  
  231.    /*
  232.     * Watch for bad choice of log scales
  233.     */
  234.    if(logb<=logs) logs=logb-3;
  235.  
  236.    if((SampleRate>88200) || (SampleRate<5000))
  237.    {
  238.       puts("Sample rate must be between 5000 and 88200");
  239.       exit(1);
  240.    }
  241.  
  242. }
  243.  
  244. /*
  245.  *  Allocate memory for and initialize the buffers
  246.  */
  247. void setup_buffers(int length)
  248. {
  249.    int i;
  250.  
  251.    for(i=0;i<BUFFERS;i++)
  252.    {
  253.       if((buffer[i]=(int *)malloc(length*sizeof(int)))==NULL)
  254.       {
  255.          puts("Unable to allocate enough memory for the buffers!");
  256.          exit(1);
  257.       }
  258.       flag[i]=0;
  259.    }
  260.  
  261.    if((fftdata=(int *)malloc(length*sizeof(int)))==NULL)
  262.    {
  263.       puts("Unable to allocate enough memory for the buffers!");
  264.       exit(1);
  265.    }
  266.    if((wind=(int *)malloc(length*sizeof(int)))==NULL)
  267.    {
  268.       puts("Unable to allocate enough memory for the buffers!");
  269.       exit(1);
  270.    }
  271.  
  272.    /*
  273.     *  Clear out the buffer of last Y display positions
  274.     */
  275.    for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
  276.       lasty[i]=WINDOW_BOTTOM;
  277. }
  278.  
  279. void compute_window_function(void)
  280. {
  281.    int i;
  282.    double val;
  283.  
  284.    /*
  285.     *  Calculate FFT Windowing function
  286.     */
  287.    for(i=0;i<fftlen;i++)
  288.    {
  289.       double val;
  290.  
  291.       switch(windfunc)
  292.       {
  293.          case 1:    // Hanning
  294.             val = 0.5 - 0.5*cos(2*M_PI*i/fftlen);
  295.             break;
  296.  
  297.          case 2:    // Blackman
  298.             val = 0.42-0.5*cos(2*M_PI*i/fftlen)+0.08*cos(4*M_PI*i/fftlen);
  299.             break;
  300.  
  301.          case 3:    // Gaussian
  302.             val = exp(-alpha / ((double)fftlen*(double)fftlen)
  303.                              * ((double)2*i-fftlen)*((double)2*i-fftlen));
  304.             break;
  305.  
  306.          case 4:    // Welch
  307.             val = 1 -  ((double)(2*i-fftlen)/(double)(fftlen+1))
  308.                       *((double)(2*i-fftlen)/(double)(fftlen+1));
  309.             break;
  310.  
  311.          case 5:    // Parzen
  312.             val = 1 - fabs((double)(2*i-fftlen)/(double)(fftlen+1));
  313.             break;
  314.  
  315.          case 6:    // Rectangular
  316.             val = 1;
  317.             break;
  318.  
  319.          default:   // Hamming
  320.             val = 0.54-0.46*cos(2*M_PI*i/fftlen);
  321.             break;
  322.       }
  323.       wind[i]=floor(val*32767+0.5);
  324.    }
  325.  
  326.    /*
  327.     *  If output requested, save the window function. (for the curious)
  328.     */
  329.    if(windfile)
  330.    {
  331.       FILE *fp;
  332.       if((fp=fopen(windfile,"w"))==NULL)
  333.       {
  334.          printf("Error opening window output file: %s\n",windfile);
  335.          getch();
  336.       }
  337.       else
  338.       {
  339.          for(i=0;i<fftlen;i++)
  340.             fprintf(fp,"%d\n",wind[i]);
  341.          fclose(fp);
  342.       }
  343.       windfile=NULL;
  344.    }
  345. }
  346.  
  347. /*
  348.  *  Set up X axis scales
  349.  */
  350. void setup_xscale(void)
  351. {
  352.    int i;
  353.    /*
  354.     *  Initialize graph x scale (linear or logarithmic).
  355.     *  This array points to the bin to be plotted on a given line.
  356.     */
  357.    for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
  358.    {
  359.       if(logfreq)
  360.          x[i]=floor(exp((double)i/(double)(WINDOW_RIGHT-WINDOW_LEFT+1)*log(fftlen/2))+0.5);
  361.       else
  362.          x[i]=floor((double)i*(double)fftlen/(double)(2*(WINDOW_RIGHT-WINDOW_LEFT+1))+0.5);
  363.    }
  364.    /*
  365.     *  If lines are repeated on the screen, flag this so that we don't
  366.     *  have to recompute the y values.
  367.     */
  368.    for(i=(WINDOW_RIGHT-WINDOW_LEFT);i>0;i--)
  369.    {
  370.       if(x[i]==fftlen/2)  /* we don't compute this bin, so don't display it */
  371.          x[i]=-1;
  372.       if(x[i]==x[i-1])
  373.          x[i]=-1;
  374.    }
  375. }
  376.  
  377. /*
  378.  *  Set up logarithmic amplitude scale factors and offsets.
  379.  */
  380. void setup_logscales(void)
  381. {
  382.    int i;
  383.    double scale,base,convert;
  384.  
  385.    /*
  386.     *  Compute the (logarithmic) y scale factor and offset.
  387.     *  This may include a 3dB/octave gain.
  388.     *
  389.     *  Conversion factor from db/10 to dPhils (the computed "unit")
  390.     *  where 1024 dPhils equals 2.0
  391.     */
  392.    convert=1024.0*log(10)/log(2);
  393.  
  394.    scale=(WINDOW_BOTTOM-WINDOW_TOP)/(logb-logs)/convert;
  395.    if(deriv==0)
  396.       base=(log10(32768.0)*2.0-logb)*convert;
  397.    else if(deriv==1)
  398.       base=(log10(32768.0)*2.0-log10(SampleRate/(2*M_PI*ref_freq))*2.0-logb)*convert;
  399.    else
  400.       base=(log10(32768.0)*2.0-log10(SampleRate/(2*M_PI*ref_freq))*4.0-logb)*convert;
  401.  
  402.  
  403.    shift=0;
  404.    /*
  405.     *  Make maximum use of available bits
  406.     */
  407.    while(scale<32767.75)
  408.    {
  409.       scale*=2;
  410.       shift++;
  411.    }
  412.    scale=floor(scale+0.5);
  413.  
  414.    if(gain3db)
  415.    {
  416.       for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
  417.       {
  418.          if(x[i]==-1)
  419.          {
  420.             yscale[i]=0;
  421.             ybase[i]=0;
  422.          }
  423.          else
  424.          {
  425.             yscale[i]=scale;
  426.             if(x[i]!=0)
  427.                ybase[i]=floor(base-log10((double)x[i]*SampleRate/fftlen/ref_freq)*convert+0.5);
  428.             else
  429.             {
  430.                yscale[i]=0;
  431.                ybase[i]=base;
  432.             }
  433.          }
  434.       }
  435.    }
  436.    else
  437.    {
  438.       for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
  439.       {
  440.          if(x[i]==-1)
  441.          {
  442.             yscale[i]=0;
  443.             ybase[i]=0;
  444.          }
  445.          else
  446.          {
  447.             yscale[i]=scale;
  448.             ybase[i]=floor(0.5+base);
  449.          }
  450.       }
  451.    }
  452. }
  453.  
  454. /*
  455.  *  Set up linear amplitude scale factors
  456.  */
  457. void setup_linscales(void)
  458. {
  459.    int i;
  460.    double scale;
  461.  
  462.    /*
  463.     *  Compute the (linear) y scale factor.
  464.     *  This may include a 3dB/octave gain.
  465.     */
  466.    scale=(WINDOW_BOTTOM-WINDOW_TOP)/(ys*3276.8*sqrt(ref_freq));
  467.    shift=0;
  468.  
  469.    if(deriv==1)
  470.    {
  471.       scale*=(double)SampleRate/(2*M_PI*(double)ref_freq);
  472.    }
  473.    else if(deriv==2)
  474.    {
  475.       scale*=(double)SampleRate*(double)SampleRate
  476.              /(4*M_PI*M_PI*(double)ref_freq*(double)ref_freq);
  477.    }
  478.  
  479.    /*
  480.     *  Make maximum use of available bits
  481.     */
  482.    if(gain3db)
  483.    {
  484.       while((scale*sqrt(SampleRate/2))<32767.75)
  485.       {
  486.          scale*=2;
  487.          shift++;
  488.       }
  489.       for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
  490.       {
  491.          if(x[i]==-1)
  492.             yscale[i]=0;
  493.          else
  494.             yscale[i]=floor(0.5+scale*sqrt(x[i]*SampleRate/fftlen));
  495.       }
  496.    }
  497.    else
  498.    {
  499.       scale=scale*sqrt(ref_freq);
  500.       while(scale<32767.75)
  501.       {
  502.          scale*=2;
  503.          shift++;
  504.       }
  505.  
  506.       scale=floor(scale+0.5);
  507.  
  508.       for(i=0;i<(WINDOW_RIGHT-WINDOW_LEFT+1);i++)
  509.       {
  510.          if(x[i]==-1)
  511.             yscale[i]=0;
  512.          else
  513.             yscale[i]=scale;
  514.       }
  515.    }
  516. }
  517.  
  518. void frequency_scale(void)
  519. {
  520.    char text[20];
  521.    /*
  522.     *  Put up the frequency scale.
  523.     */
  524.    setfillstyle(SOLID_FILL,0);
  525.    bar(WINDOW_LEFT-10,WINDOW_BOTTOM+3,WINDOW_RIGHT+10,479);
  526.  
  527.    if(logfreq)
  528.    {
  529.       double f,step,base;
  530.       settextjustify(CENTER_TEXT,TOP_TEXT);
  531.       settextstyle(0,1,0);
  532.       step=exp(log(fftlen/2)/32.0);
  533.       base=(double)SampleRate/(double)fftlen;
  534.       for(f=base;f<=(double)(SampleRate*1.01)/2;f*=step)
  535.       {
  536.          setcolor(BORDER_COLOR);
  537.          moveto(WINDOW_LEFT+(log(f)-log(base))/(log(SampleRate/2)-log(base))*(WINDOW_RIGHT-WINDOW_LEFT+1),WINDOW_BOTTOM+3);
  538.          linerel(0,3);
  539.          moverel(0,3);
  540.          setcolor(LABEL_COLOR);
  541.          sprintf(text,"%7.1lf",f);
  542.          outtext(text);
  543.       }
  544.    }
  545.    else
  546.    {
  547.       double f;
  548.       settextjustify(CENTER_TEXT,TOP_TEXT);
  549.       settextstyle(0,1,0);
  550.       for(f=0;f<=(double)SampleRate/2.0;f+=(double)SampleRate/64.0)
  551.       {
  552.          setcolor(BORDER_COLOR);
  553.          moveto(WINDOW_LEFT+f*(double)(WINDOW_RIGHT-WINDOW_LEFT+1)*2.0/(double)SampleRate,WINDOW_BOTTOM+3);
  554.          linerel(0,3);
  555.          moverel(0,3);
  556.          setcolor(LABEL_COLOR);
  557.          sprintf(text,"%7.1lf",f);
  558.          outtext(text);
  559.       }
  560.    }
  561. }
  562.  
  563. void amplitude_scale(void)
  564. {
  565.    int i;
  566.    char text[20];
  567.  
  568.    setfillstyle(SOLID_FILL,0);
  569.    bar(0,WINDOW_TOP-10,WINDOW_LEFT-3,WINDOW_BOTTOM+10);
  570.  
  571.    /*
  572.     *  Put up the amplitude scale
  573.     */
  574.    if(logamp)
  575.    {
  576.  
  577.       settextjustify(RIGHT_TEXT,CENTER_TEXT);
  578.       settextstyle(0,0,0);
  579.       for(i=0;i<(logb-logs)+1;i++)
  580.       {
  581.          setcolor(BORDER_COLOR);
  582.          moveto(WINDOW_LEFT-3,WINDOW_TOP+i*(WINDOW_BOTTOM-WINDOW_TOP)/(logb-logs));
  583.          linerel(-3,0);
  584.          moverel(-3,0);
  585.          setcolor(LABEL_COLOR);
  586.          sprintf(text,"%d",(i+logs)*(-10));
  587.          outtext(text);
  588.       }
  589.    }
  590.    else
  591.    {
  592.       double scale=(double)(ys*3276.8)/(double)(WINDOW_BOTTOM-WINDOW_TOP);
  593.       settextjustify(RIGHT_TEXT,CENTER_TEXT);
  594.       settextstyle(0,0,0);
  595.       for(i=0;i<=10;i++)
  596.       {
  597.          setcolor(BORDER_COLOR);
  598.          moveto(WINDOW_LEFT-3,WINDOW_BOTTOM-i*ys*327.68/scale);
  599.          linerel(-3,0);
  600.          moverel(-3,0);
  601.          setcolor(LABEL_COLOR);
  602.          sprintf(text,"%4.2f",(float)i*ys*0.01);
  603.          outtext(text);
  604.       }
  605.    }
  606. }
  607.  
  608. char *window_name[] = { "Hamming",
  609.                         "Hanning",
  610.                         "Blackman",
  611.                         "Gaussian",
  612.                         "Welch",
  613.                         "Parzen",
  614.                         "Rectangular" };
  615.  
  616. void update_header(void)
  617. {
  618.    char ach[100];
  619.  
  620.    setfillstyle(SOLID_FILL,0);
  621.    bar(SRX-150,SRY,SRX+150,RFY+10);
  622.  
  623.    settextstyle(0,0,0);
  624.    settextjustify(CENTER_TEXT,TOP_TEXT);
  625.    setcolor(TEXT_COLOR);
  626.    sprintf(ach,"Sampling rate: %ld Hz",SampleRate);
  627.    outtextxy(SRX,SRY,ach);
  628.    sprintf(ach,"FFT Length: %d points",fftlen);
  629.    outtextxy(FLX,FLY,ach);
  630.    sprintf(ach,"Frequency resolution: %g Hz",(double)SampleRate/(double)fftlen);
  631.    outtextxy(FRX,FRY,ach);
  632.    sprintf(ach,"%s window function",window_name[windfunc]);
  633.    outtextxy(WFX,WFY,ach);
  634.    sprintf(ach,"Gain of %d dB per octave",gain);
  635.    outtextxy(DGX,DGY,ach);
  636.    sprintf(ach,"(0 dB gain at %ld Hz)",ref_freq);
  637.    outtextxy(RFX,RFY,ach);
  638. }
  639.