#include <exec/types.h>
#include <exec/memory.h>
#include <fcntl.h>
#include <stdio.h>
#include <intuition/intuition.h>
#include <graphics/view.h>
#include <graphics/gfxmacros.h>
#include <string.h>
#include <math.h>
#include <devices/audio.h>
#include <stdlib.h>

#define INTUITION_REV 0
#define GRAPHICS_REV 0
#define STATUSCON 0
#define STATUSHALT 1
#define STATUSGO 2

typedef struct{
   ULONG oneShotHiSamples,repeatHiSamples,samplesPerHiCycle;
   UWORD samplesPerSec;
   UBYTE ctOctave,sCompression;
   ULONG volume;
   } Voice8Header;

extern struct IntuiMessage *GetMsg();
extern struct MsgPort *CreatePort();
extern struct Window *OpenWindow();
extern struct IntuitionBase *OpenLibrary();
extern struct Screen *OpenScreen();
extern char *pathcat();
extern void doparms();
extern void refwin();
extern void pr1();
extern void gadbox();
extern void clean();
extern int dism();
extern void fftlin();
extern int readin();
extern void findmark();
extern void putmark();
extern void playmark();
extern void timeline();
extern void distf();
extern long doiff();

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;

struct IntuiText mn1i1t={0,1,JAM2,0,0,NULL,"About",NULL};
struct MenuItem mn1i1={NULL,0,8,100,8,
   ITEMTEXT|ITEMENABLED|HIGHCOMP,
   NULL,(APTR)&mn1i1t,NULL,NULL,NULL};
struct IntuiText mn1i0t={0,1,JAM2,0,0,NULL,"Restart",NULL};
struct MenuItem mn1i0={&mn1i1,0,0,100,8,
   ITEMTEXT|ITEMENABLED|HIGHCOMP,
   NULL,(APTR)&mn1i0t,NULL,NULL,NULL};
struct Menu mn1={NULL,100,0,100,0,
   MENUENABLED,"Control",&mn1i0};
struct IntuiText mn0i1t={0,1,JAM2,0,0,NULL,"Quit",NULL};
struct MenuItem mn0i1={NULL,0,8,100,8,
   ITEMTEXT|ITEMENABLED|HIGHCOMP,
   NULL,(APTR)&mn0i1t,NULL,NULL,NULL};
struct IntuiText mn0i0t={0,1,JAM2,0,0,NULL,"Open",NULL};
struct MenuItem mn0i0={&mn0i1,0,0,100,8,
   ITEMTEXT|ITEMENABLED|HIGHCOMP,
   NULL,(APTR)&mn0i0t,NULL,NULL,NULL};
struct Menu mn0={&mn1,0,0,100,0,
   MENUENABLED,"File",&mn0i0};
char gdundo[40];
float fa4=440.;
UBYTE gd31sb[]="440.0";  /* fa4 */
struct StringInfo gd31s={gd31sb,gdundo,0,6,0,0,0,0,0,0,0,0,0};
struct Gadget gd31={NULL,424,51,48,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd31s,31,NULL};
int gd30i=2;
char gd30s[5][2]={"1","3","5","7","9"};
struct IntuiText gd30gt={0,1,JAM2,0,0,NULL,&gd30s[2][0],NULL};
struct Gadget gd30={&gd31,432,101,8,8,
   GADGHCOMP,RELVERIFY,BOOLGADGET,NULL,NULL,
   &gd30gt,NULL,NULL,30,NULL};
int kdfpx=0;
int ndfpx=1,idfpx[8]={1,2,4,8,1,1,1,1};
int npxdf=1,ipxdf[8]={1,1,1,1,1,2,4,8};
char gd29s[8][5]={"  1 ","  2 ","  4 ","  8 ","  1 "," 1/2"," 1/4"," 1/8"};
struct IntuiText gd29gt={0,1,JAM2,0,0,NULL,&gd29s[0][0],NULL};
struct Gadget gd29={&gd30,368,41,32,8,
   GADGHCOMP,RELVERIFY,BOOLGADGET,NULL,NULL,
   &gd29gt,NULL,NULL,29,NULL};
UBYTE gd28sb[]="       0";  /* ibt0 */
struct StringInfo gd28s={gd28sb,gdundo,0,9,0,0,0,0,0,0,0,0,0};
struct Gadget gd28={&gd29,312,11,72,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd28s,28,NULL};
UBYTE gd27sb[]="       0";  /* ifp */
struct StringInfo gd27s={gd27sb,gdundo,0,9,0,0,0,0,0,0,0,0,0};
struct Gadget gd27={&gd28,496,11,72,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd27s,27,NULL};
UBYTE gd26sb[]="  0.0";  /* colfrom */
struct StringInfo gd26s={gd26sb,gdundo,0,6,0,0,0,0,0,0,0,0,0};
struct Gadget gd26={&gd27,296,101,48,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd26s,26,NULL};
struct IntuiText gd25gt={0,1,JAM2,0,0,NULL," IFF",NULL};
struct Gadget gd25={&gd26,112,11,32,8,
   GADGHCOMP,TOGGLESELECT|RELVERIFY,BOOLGADGET,NULL,NULL,
   &gd25gt,NULL,NULL,25,NULL};
struct IntuiText gd24gt={0,1,JAM2,0,0,NULL," <-> ",NULL};
struct Gadget gd24={&gd25,152,11,40,8,
   SELECTED|GADGHCOMP,TOGGLESELECT|RELVERIFY,BOOLGADGET,NULL,NULL,
   &gd24gt,NULL,NULL,24,NULL};
struct IntuiText gd23gt={0,1,JAM2,0,0,NULL," RAW",NULL};
struct Gadget gd23={&gd24,200,11,32,8,
   GADGHCOMP,TOGGLESELECT|RELVERIFY,BOOLGADGET,NULL,NULL,
   &gd23gt,NULL,NULL,23,NULL};
char gd22s[2][5]={" NO "," YES"};
struct IntuiText gd22gt={0,1,JAM2,0,0,NULL,&gd22s[1][0],NULL};
struct Gadget gd22={&gd23,440,111,32,8,
   GADGHCOMP,RELVERIFY,BOOLGADGET,NULL,NULL,
   &gd22gt,NULL,NULL,22,NULL};
char gd21s[2][5]={" NO "," YES"};
struct IntuiText gd21gt={0,1,JAM2,0,0,NULL,&gd21s[1][0],NULL};
struct Gadget gd21={&gd22,248,111,32,8,
   GADGHCOMP,RELVERIFY,BOOLGADGET,NULL,NULL,
   &gd21gt,NULL,NULL,21,NULL};
char gd20s[2][4]={" % "," dB"};
struct IntuiText gd20gt={0,1,JAM2,0,0,NULL,&gd20s[1][0],NULL};
struct Gadget gd20={&gd21,216,101,24,8,
   GADGHCOMP,RELVERIFY,BOOLGADGET,NULL,NULL,
   &gd20gt,NULL,NULL,20,NULL};
UBYTE gd19sb[]=" 2.0"; /* colstep */
struct StringInfo gd19s={gd19sb,gdundo,0,5,0,0,0,0,0,0,0,0,0};
struct Gadget gd19={&gd20,168,101,40,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd19s,19,NULL};
UBYTE gd18sb[]="1.000";
struct StringInfo gd18s={gd18sb,gdundo,0,6,0,0,0,0,0,0,0,0,0};
struct Gadget gd18={&gd19,72,91,48,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd18s,18,NULL};
UBYTE gd17sb[]=" 2"; /* itani */
struct StringInfo gd17s={gd17sb,gdundo,0,3,0,0,0,0,0,0,0,0,0};
struct Gadget gd17={&gd18,168,81,24,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd17s,17,NULL};
UBYTE gd16sb[]=" 0.500"; /* tline */
struct StringInfo gd16s={gd16sb,gdundo,0,7,0,0,0,0,0,0,0,0,0};
struct Gadget gd16={&gd17,104,71,56,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd16s,16,NULL};
UBYTE gd15sb[]="0.500";
struct StringInfo gd15s={gd15sb,gdundo,0,6,0,0,0,0,0,0,0,0,0};
struct Gadget gd15={&gd16,96,61,48,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd15s,15,NULL};
SHORT gd14ird[]={0xffff,0xffff,0xc000,0x0003,
                 0xcfff,0xff03,0xcfff,0xff03,
                 0xcfff,0xfff3,0xcfc0,0x0033,
                 0xcfc0,0x0033,0xcfc0,0x0033,
                 0xcfc0,0x0033,0xcfc0,0x0033,
                 0xcfc0,0x0033,0xcfc0,0x0033,
                 0xc0c0,0x0033,0xc0ff,0xfff3,
                 0xc000,0x0003,0xffff,0xffff};
struct Image gd14ir={0,0,32,16,1,gd14ird, 1, 0,NULL};
struct Gadget gd14={&gd15,580,70,32,16,
   GADGIMAGE|GADGHCOMP,RELVERIFY,
   BOOLGADGET,(APTR)&gd14ir,NULL,NULL,NULL,NULL,14,NULL};
UBYTE gd13sb[]=" 4";
struct StringInfo gd13s={gd13sb,gdundo,0,3,0,0,0,0,0,0,0,0,0};
struct Gadget gd13={&gd14,168,51,24,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd13s,13,NULL};
UBYTE gd12sb[]="10";
struct StringInfo gd12s={gd12sb,gdundo,0,3,0,0,0,0,0,0,0,0,0};
struct Gadget gd12={&gd13,128,31,24,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd12s,12,NULL};
UBYTE gd11sb[]="10000";
struct StringInfo gd11s={gd11sb,gdundo,0,6,0,0,0,0,0,0,0,0,0};
struct Gadget gd11={&gd12,112,21,48,8,
   GADGHCOMP,RELVERIFY,STRGADGET,NULL,NULL,
   NULL,NULL,(APTR)&gd11s,11,NULL};
struct NewWindow nwin1={0,1,640,150,-1,-1,
   NULL,
   WINDOWCLOSE|SIMPLE_REFRESH|ACTIVATE|WINDOWDEPTH,
   &gd11,NULL,"SeeHear",NULL,NULL,0,0,0,0,WBENCHSCREEN};

struct NewScreen nsc2={0,0,320,200,5,1,0,0,
   CUSTOMSCREEN,NULL,"SCREEN",NULL,NULL};
SHORT gd4ird[]={0xffff,0x8001,0xbff1,0xbff1,
                0xbffd,0xb805,0xb805,0xb805,
                0xb805,0xb805,0xb805,0xb805,
                0x8805,0x8ffd,0x8001,0xffff};
struct Image gd4ir={0,0,16,16,1,gd4ird, 1, 0,NULL};
struct Gadget gd4={NULL,290,70,16,16,
   GADGIMAGE|GADGHCOMP,RELVERIFY,
   BOOLGADGET,(APTR)&gd4ir,NULL,NULL,NULL,NULL,4,NULL};
SHORT gd3ird[]={0xc003,0x8001,0x0000,0x0300,
                0x0600,0x0c00,0x7800,0xf000,
                0xf000,0x7800,0x0c00,0x0600,
                0x0300,0x0000,0x8001,0xc003,
                     
                0x0010,0x0008,0x0004,0x0024,
                0x0012,0x0092,0x0049,0x0249,
                0x0249,0x0049,0x0092,0x0012,
                0x0024,0x0004,0x0008,0x0010};
struct Image gd3ir={0,0,16,16,1,gd3ird, 1, 0,NULL};
struct Image gd3is={0,0,16,16,2,gd3ird,12,16,NULL};
struct Gadget gd3={&gd4,290,40,16,16,
   GADGHIMAGE|GADGIMAGE|GADGDISABLED,GADGIMMEDIATE,
   BOOLGADGET,(APTR)&gd3ir,(APTR)&gd3is,NULL,NULL,NULL,3,NULL};
SHORT gd2isd[]={0x0000,0x07e0,0x0ff0,0x1ff8,
                0x3ffc,0x7ffe,0x7ffe,0x7ffe,
                0x7ffe,0x7ffe,0x7ffe,0x3ffc,
                0x1ff8,0x0ff0,0x07e0,0x0000,

                0x0000,0x07e0,0x0ff0,0x1ff8,
                0x3ffc,0x7ffe,0x7ffe,0x7ffe,
                0x7ffe,0x7ffe,0x7ffe,0x3ffc,
                0x1ff8,0x0ff0,0x07e0,0x0000};
struct Image gd2is={0,0,16,16,5,gd2isd,9,0x12,NULL};
SHORT gd2ird[]={0x0000,0x0000,0x0280,0x0280,
                0x3ff8,0x1450,0x2448,0x0440,
                0x0820,0x0820,0x0820,0x1010,
                0x1010,0x1010,0x0000,0x0000,

                0x0000,0x0000,0x0280,0x0280,
                0x3ff8,0x1450,0x2448,0x0440,
                0x0820,0x0820,0x0820,0x1010,
                0x1010,0x1010,0x0000,0x0000,

                0x0000,0x0000,0x0280,0x0280,
                0x3ff8,0x1450,0x2448,0x0440,
                0x0820,0x0820,0x0820,0x1010,
                0x1010,0x1010,0x0000,0x0000};
struct Image gd2ir={0,0,15,16,5,gd2ird,0xd,0x12,NULL};
struct Gadget gd2={&gd3,290,11,16,16,
   GADGHIMAGE|GADGIMAGE|SELECTED,TOGGLESELECT|GADGIMMEDIATE,
   BOOLGADGET,(APTR)&gd2is,(APTR)&gd2ir,NULL,NULL,NULL,2,NULL};
struct Image gd1ir;
struct PropInfo gd1p={AUTOKNOB|FREEVERT,0,0,-1,0x1100,0,0,0,0,0};
struct Gadget gd1={&gd2,308,21,11,176,
   GADGHNONE|GADGIMAGE|GADGDISABLED,
   RELVERIFY,PROPGADGET,(APTR)&gd1ir,NULL,NULL,NULL,
   (APTR)&gd1p,1,NULL};
struct NewWindow nwn2={0,1,320,199,-1,-1,
   NULL,
   WINDOWCLOSE|SIMPLE_REFRESH|NOCAREREFRESH,
   &gd1,NULL,"SeeHear",NULL,NULL,0,0,0,0,CUSTOMSCREEN};
UWORD colors[]={0x000,0x777,0x200,0x223,0x004,0x304,0x300,0x330,
                0x030,0x035,0x334,0x335,0x436,0x423,0x443,0x343,
                0x356,0x555,0x669,0x969,0x966,0x996,0x696,0x699,
                0x999,0xaaf,0xfaf,0xfaa,0xffa,0xafa,0xaff,0xfff};
SHORT imdarrow[]={0x0200,0x0400,0x1800,0xff10,
                         0x1800,0x0400,0x0200,
                  0x0200,0x0400,0x1800,0xff10,
                         0x1800,0x0400,0x0200,
                  0x0200,0x0400,0x1800,0xff10,
                         0x1800,0x0400,0x0200,
                  0x0200,0x0400,0x1800,0xff10,
                         0x1800,0x0400,0x0200,
                  0x0200,0x0400,0x1800,0xff10,
                         0x1800,0x0400,0x0200};
int pky[12]={31,0,31,31,0,31,0,31,31,0,31,0};
char *cky[12]={"A","A#","B","C","C#","D","D#","E","F","F#","G","G#"};
struct MsgPort *mprt=NULL;
struct Screen *scr2=NULL;
struct Window *win1=NULL,*win2=NULL;
struct RastPort *rp1=NULL,*rp2=NULL;
struct Image imarrow={0,0,9,7,5,imdarrow,1,0,NULL};
struct ViewPort *vp2;
struct IntuiMessage *msg;
FILE *fp=NULL;
TEXT filen[34],dirn[67],pathn[100];
int ie,line,linf=21,i2fft=10,nfft=1024,istep=512,jdt,imark=3,itser;
int lmark[4],itani=2,nseries=0,ifani=4,npix=256,linl=198;
int go=FALSE,plin=1,pbefore=1,quitnow=0,readit=FALSE;
int status=-1,dbflag=1,kkeep=0,markf=0,setoff=0;
char *series=NULL,*sound=NULL,*ps,prt[82];
float *fseries=NULL,*smooth=NULL,cut[32],ai,ri,si,*pf;
float srate=10000.,dt=.0001,tstep,tline=0.5,tser,df,dfpx,cint=279.365e-9;
float fani=400.,tstepf=.5,smwid=1.,smsum,colstep=2.,colfrom=0.;
long iser=0,ibt0=0,ifp=0,nfp=0,nsnd=0,msnd;
struct Gadget *pgdt;
Voice8Header vhdr;

void main()
{
   static struct IntuiText rq3bt3={0,1,JAM2,6,29,NULL,
      "SeeHear, version 1.1, 1990-03-11",NULL};
   static struct IntuiText rq3bt2={0,1,JAM2,6,21,NULL,
      "Freely distributable for non-commercial use.",&rq3bt3};
   static struct IntuiText rq3bt1={0,1,JAM2,6,11,NULL,
      "2654 E. 26 St., Tulsa, OK  74114",&rq3bt2};
   static struct IntuiText rq3bt={0,1,JAM2,6,3,NULL,
      "Copyright 1990 by Daniel T. Johnson",&rq3bt1};
   static struct IntuiText rq3nt={0,1,JAM2,6,3,NULL,"Continue",NULL};
   static struct IntuiText *cit;
   static USHORT nmen,numm,numi;
   
   si=exp(2./3.);   /* force load of ffp library */
   cit=&rq3bt;
   while(cit){
      printf("%s\n",cit->IText);
      cit=cit->NextText;
   }
   df=srate/nfft;
   dfpx=df;
   msnd=nfft+istep*(198-linf);
   IntuitionBase=OpenLibrary("intuition.library",INTUITION_REV);
   if(IntuitionBase==NULL) dism("IntuitionBase",0);
   GfxBase=(struct GfxBase *)OpenLibrary("graphics.library", GRAPHICS_REV);
   if(GfxBase==NULL) dism("GfxBase",0);

   if((mprt=CreatePort(NULL,0))==NULL) dism("mprt",0);
   if((scr2=OpenScreen(&nsc2))==NULL) dism("OpenScreen",0);
   ScreenToBack(scr2);
   vp2=&(scr2->ViewPort);
   LoadRGB4(vp2,colors,32);

   nwn2.Screen=scr2;
   if((win2=OpenWindow(&nwn2))==NULL)
      dism("OpenWindow",0);
   win2->UserPort=mprt;
   ModifyIDCMP(win2,MOUSEBUTTONS|GADGETDOWN|GADGETUP|CLOSEWINDOW|MENUPICK);
   rp2=win2->RPort;
   OpenWorkBench();
   if((win1=OpenWindow(&nwin1))==NULL) dism("OpenWindow",0);
   win1->UserPort=mprt;
   ModifyIDCMP(win1,GADGETUP|MENUPICK|REFRESHWINDOW|CLOSEWINDOW);
   rp1=win1->RPort;
   
   filen[0]=0;dirn[0]=0;
   setstatus(STATUSCON);
   refwin();
   dism("menu File/Open to start; adjust parameters first if needed",1);

/*Main user interaction loop*/
   for(;;){
      if(!readit) go=FALSE;
      if((msg=(struct IntuiMessage *)GetMsg(mprt))==NULL){
         if(status==STATUSGO) fftlin();
         else WaitPort(win2->UserPort);
      }else{
         switch(msg->Class){
         case REFRESHWINDOW:
            BeginRefresh(win1);
            refwin();
            EndRefresh(win1);
            break;
         case CLOSEWINDOW:
            clean();
         case GADGETDOWN:
         distf(0);
            pgdt=(struct Gadget *)msg->IAddress;
            switch(pgdt->GadgetID){
            case 2:
               if(pgdt->Flags&SELECTED) setstatus(STATUSGO);
               else setstatus(STATUSHALT);
               break;
            case 3:
               pgdt->Flags|=SELECTED;
               RefreshGadgets(&gd3,win2,NULL);
               playmark();
               pgdt->Flags^=SELECTED;
               RefreshGadgets(&gd3,win2,NULL);
               break;
            }
            break;
         case GADGETUP:
         distf(0);
            pgdt=(struct Gadget *)msg->IAddress;
            switch(pgdt->GadgetID){
            case 1:
               ifp=nfp*(gd1p.VertPot/65535.);
               if(ifp>(nfp-nfft)) ifp=nfp-nfft;
               if(fp) readin();   /*wipes out msg*/
               setstatus(STATUSGO);
               break;
            case 4:  /*flip to WB*/
               setstatus(STATUSCON);
               break;
            case 14:  /*flip to scr2*/
               setstatus(STATUSHALT);
               break;
            default:
               doparms();
            }
            break;
         case MOUSEBUTTONS:
         distf(0);
            if(go) break;
            switch(msg->Code){
            case SELECTDOWN:
               findmark();
               break;
            case SELECTUP:
               putmark(1);
               break;
            }
            break;
         case MENUPICK:
            nmen=msg->Code;
            numm=MENUNUM(nmen);
            numi=ITEMNUM(nmen);
            switch(numm){
            case 0:
               switch(numi){
               case 0:  /*Open*/
                  /* Charlie Heath file requester from Fred Fish library
                     AmigaLibDisk35:FileRequester/getfil.o */
                  if(!get_fname(win1,"SeeHear input file",filen,dirn)) break;
                  if(fp) fclose(fp);
                  readit=FALSE;
                  if(!pathcat(pathn,dirn,filen)) break;
                  if((fp=fopen(pathn,"r"))==NULL){
                     dism("Can't open file - try again",1);
                     break;
                  }
                  fseek(fp,0,2);
                  nfp=ftell(fp);
                  rewind(fp);
                  if(nfp<nfft){
                     fclose(fp);fp=NULL;
                     dism("Input file short - try again",2);
                  }
                  dism("Reading input file",1);
                  if(!setoff){
                     ifp=0;
                     ibt0=0;
                  }
                  if(!readin()) break;
                  dism("SeeHear analysis underway",1);
                  setstatus(STATUSGO);
                  break;
               case 1:  /*Quit*/
                  clean();
                  break;
               }
               break;
            case 1:
               switch(numi){
               case 0:  /*Restart*/
                  if(!fp){
                     dism("must Open a File first",1);
                     break;
                  }
                  dism("Reading input file",1);
                  if(!readin()) break;
                  dism("SeeHear analysis underway",1);
                  setstatus(STATUSGO);
                  break;
               case 1:
                  AutoRequest(win1,&rq3bt,NULL,&rq3nt,0,0,400,100);
                  break;
               }
               break;
            }
            break;
         }
         ReplyMsg(msg);
      }
   }
}
/**************************************/
void clean()
{
   if(series) fftcr(series,0);
   if(fp) fclose(fp);
   if(win2){
      win2->UserPort=NULL;
      CloseWindow(win2);
   }
   if(win1){
      win1->UserPort=NULL;
      CloseWindow(win1);
   }
   if(mprt){
      DeletePort(mprt);
   }
   if(scr2) CloseScreen(scr2);
   if(fseries) free((char *)fseries);
   if(smooth) free((char *)smooth);
   if(series) FreeMem(series,nseries);
   if(sound) FreeMem(sound,nsnd);
   exit(0);
}
/**************************************/
void fftlin()
{
   register short i,j,k,l;
   
   if((iser+nfft)>nsnd) setstatus(STATUSHALT);
   if(line>198) setstatus(STATUSHALT);
   if(status!=STATUSGO) return;
   for(ps=sound+iser,i=0;i<nfft;++i,++ps){
      series[i]=fseries[i]=smooth[i]*(*ps);
   }
   fftcr(fseries,i2fft);
   for(pf=fseries,i=0;i<npix;i+=npxdf){
      if(ndfpx>1){
         for(j=0,ai=0.;j<ndfpx;++j){
            ri=*pf++;
            si=*pf++;
            ai+=(ri*ri+si*si);
         }
         ai/=ndfpx;
      }else{
            ri=*pf++;
            si=*pf++;
            ai=(ri*ri+si*si);
      }
      for(j=16,k=0,l=j;j;j>>=1,l=k|j) if(ai>cut[l]) k=l;
      if(k<2) k=2;
      SetAPen(rp2,k);
      for(j=0;j<npxdf;++j){
         WritePixel(rp2,18+i+j,line);
      }
   }
   if(plin) play(series,nfft,jdt);
   if(tser>=tline){
      ++itser;
      timeline();
      tser=tser-tline;
   }
   tser+=tstep;
   iser+=istep;
   ++line;
}
/**************************************/
int readin()
{
   static int i,j,k;
   static float f;
   
   setstatus(STATUSCON);
   readit=FALSE;
   if(!fp){
      dism("must Open a File first",1);
      return(FALSE);
   }
   if(series) FreeMem(series,nseries);
   if((series=(char *)AllocMem(nfft,MEMF_CHIP|MEMF_CLEAR))==NULL) 
      dism("AllocMem series",0);
   nseries=nfft;
   if(fseries) free((char *)fseries);
   if((fseries=(float *)calloc(nfft,4))==NULL) 
      dism("calloc fseries",0);
   if(smooth) free((char *)smooth);
   if((smooth=(float *)calloc(nfft,4))==NULL) 
      dism("calloc smooth",0);
   if(sound) FreeMem(sound,nsnd);
   sound=NULL;
   msnd=nfft+istep*(198-linf);
   SetDrMd(rp2,JAM1);
   BNDRYOFF(rp2);
   SetAPen(rp2,0);
   RectFill(rp2,0,10,274,198);
   kkeep=0;
   SetAPen(rp2,1);
   RectFill(rp2,18,linf,273,198);
   for(k=0,f=fa4/8.,j=0;j<256;f*=1.0594631,k=(k+1)%12){
      j=.5+f/dfpx;
      SetAPen(rp2,pky[k]);
      if(3<j&&j<253){
         RectFill(rp2,j+18,linf-2,j+18,189);
         Move(rp2,j+15,197-8*k);
         Text(rp2,cky[k],strlen(cky[k]));
      }
   }
   for(k=291,i=2;k<306;k+=8)
   for(j=90;j<180;++i,j+=6){
      SetAPen(rp2,i);
      RectFill(rp2,k,j,k+5,j+5);
   }
   dt=1./srate;
   jdt=dt/cint;
   df=1./(dt*nfft);
   dfpx=ndfpx*df/npxdf;
   npix=(nfft*npxdf)/(2*ndfpx);
   if(npix>256) npix=256;
   tstep=istep*dt;
   if(gd23.Flags&SELECTED){
      fseek(fp,0,2);
      nfp=ftell(fp)-ibt0;
   }else{
      if(ibt0=doiff(&vhdr,fp)){
         nfp=vhdr.oneShotHiSamples;
         srate=i=vhdr.samplesPerSec;
         dt=1./srate;
         jdt=dt/cint;
         sprintf(gd11sb,"%5d",i);
         if(gd24.Flags&SELECTED){
            gd25.Flags|=SELECTED;
            gd24.Flags&=~SELECTED;
            gd23.Flags&=~SELECTED;
         }
         RefreshGadgets(&gd11,win1,NULL);
         refwin();
      }else{
         dism("not IFF, doing RAW",1);
         gd23.Flags|=SELECTED;
         gd24.Flags&=~SELECTED;
         gd25.Flags&=~SELECTED;
      }
   }
   if(ifp>(nfp-nfft)) ifp=nfp-nfft;
   if(nfp>msnd) gd1p.VertBody=(61440.*msnd)/nfp;
   else gd1p.VertBody=61440;
   gd1p.VertPot=(65535.*ifp)/nfp;
   sprintf(gd27sb,"%8ld",ifp);
   sprintf(gd28sb,"%8ld",ibt0);
   RefreshGadgets(&gd27,win1,NULL);
   iser=0;
   tser=ifp*dt/tline;
   itser=tser;
   tser=ifp*dt-itser*tline;
   j=nfft/2;
   f=smwid*istep*.5;
   for(i=0,smsum=0.;i<nfft;++i){
      ri=(i-j)/f;
      smsum+=smooth[i]=exp(-ri*ri);
   }
   if(dbflag){
      si=pow(10.,(-colstep/10.));
      ri=128.*smsum*pow(10.,(colfrom/20.));
      ri=ri*ri*si;
      for(i=31;i>=0;--i,ri*=si) cut[i]=ri;
   }else{
      ri=128.*smsum;
      si=ri*colstep/100.;
      ri=ri*colfrom/100.;
      ri-=si;
      for(i=31;i>=0;--i,ri-=si){
         if(ri>0) cut[i]=ri*ri;
         else cut[i]=cut[i+1];
      }
   }
   fseek(fp,ibt0+ifp,0);
   nsnd=nfp-ifp;
   if(nsnd>msnd) nsnd=msnd;
   if(nsnd<nfft) dism("file short - Open another",1);
   if((sound=(char *)AllocMem(nsnd,MEMF_CHIP|MEMF_CLEAR))==NULL) 
      dism("AllocMem sound",0);
   if(fread(sound,1,nsnd,fp)!=nsnd) dism("file length trouble",1);
   line=linf-1;
   timeline();
   line=linf;
   imark=3;
   lmark[3]=linf;
   linl=linf+(nsnd-nfft)/istep;
   lmark[1]=linl;
   lmark[2]=(lmark[1]+lmark[3])/2;
   putmark(0);
   if(pbefore) playmark();
   SetAPen(rp2,1);
   for(f=0.,i=0;i<256;i=.5+(f+=fani)/dfpx){
      j=.5+f/100.;
      sprintf(prt,"%2d\0",j);
      Move(rp2,i+6,18);
      Text(rp2,prt,2);
   }
   readit=TRUE;
   setoff=FALSE;
   return(TRUE);
}
/**************************************/
void findmark()
{
   register int i;
   for(i=3;i;--i){
      if(msg->MouseX>=275&&
         msg->MouseX<=283&&
         msg->MouseY>=lmark[i]-3&&
         msg->MouseY<=lmark[i]+3) break;
   }
   imark=i;
   if(imark){
      imarrow.PlanePick=27;
      DrawImage(rp2,&imarrow,275,lmark[imark]-3);
      markf=1;
   }
   return;
}
/**************************************/
void putmark(ifm)
int ifm;
{
   register int i;

   if(imark&&
      ifm&&
      msg->MouseX>=18&&
      msg->MouseX<=273&&
      msg->MouseY>=linf&&
      msg->MouseY<=linl) lmark[imark]=msg->MouseY;
   switch(imark){
   case 1:
      if(lmark[2]>lmark[1]) lmark[2]=lmark[1];
      if(lmark[3]>lmark[1]) lmark[3]=lmark[1];
      break;
   case 2:
      if(lmark[1]<lmark[2]) lmark[1]=lmark[2];
      if(lmark[3]>lmark[2]) lmark[3]=lmark[2];
      if(markf) distf(msg->MouseX);
      else distf(0);
      break;
   case 3:
      if(lmark[1]<lmark[3]) lmark[1]=lmark[3];
      if(lmark[2]<lmark[3]) lmark[2]=lmark[3];
      break;
   }
   SetAPen(rp2,0);
   RectFill(rp2,275,linf-3,283,198);
   for(i=1;i<=3;++i){
      if(i==imark) imarrow.PlanePick=29;
      else imarrow.PlanePick=1;
      DrawImage(rp2,&imarrow,275,lmark[i]-3);
   }
   markf=0;
   return;
}
/**************************************/
void playmark()
{
   static FILE *tout=NULL;
   register long i,j;
   static long *kser=NULL;
   static SHORT blip[]={0x7f81,0x7f81,0x7f81,0x7f81,
                        0x7f81,0x7f81,0x7f81,0x7f81};
   switch(imark){
   case 1:
      i=istep*(lmark[3]-linf);
      j=istep*(lmark[2]-lmark[3]);
      if(j>0) play(sound+i,j,jdt);
      i+=j;
      play(blip,16,jdt);
      play(sound+i,nfft,jdt);
      play(blip,16,jdt);
      i+=nfft;
      j=nfft+istep*(lmark[1]-linf)-i;
      if(j>0) play(sound+i,j,jdt);
      break;
   case 2:
      tout=fopen("ram:SeeHear.temp","w");
      kser=(long *)fseries;
      kser[0]=i2fft;kser[1]=nfft;
      if(tout) fwrite((char *)kser,4,2,tout);
      ps=sound+istep*(lmark[2]-linf);
      for(i=0;i<nfft;++i,++ps) kser[i]=*ps;
      if(tout) fwrite((char *)kser,4,nfft,tout);
      ps=sound+istep*(lmark[2]-linf);
      for(i=0;i<nfft;++i,++ps) series[i]=kser[i]=smooth[i]*(*ps);
      if(tout) fwrite((char *)kser,4,nfft,tout);
      play(series,nfft,jdt);
      for(i=0;i<nfft;++i) fseries[i]=series[i];
      fftcr(fseries,i2fft);
      for(i=0;i<nfft;++i) kser[i]=fseries[i];
      if(tout) fwrite((char *)kser,4,nfft,tout);
      if(tout) fclose(tout);
      break;
   case 3:
      i=istep*(lmark[3]-linf);
      j=nfft+istep*(lmark[1]-lmark[3]);
      play(sound+i,j,jdt);
      break;
   default:
      play(sound,nsnd,jdt);
   }
   return;
}
/**************************************************/
void timeline()
{
   register short i;
   static float f;

   SetAPen(rp2,27);
   for(f=0.,i=0;i<256;i=.5+(f+=fani)/dfpx) WritePixel(rp2,i+18,line);
   if(fani/dfpx>7.5){
      SetAPen(rp2,22);
      for(f=fani/2.,i=.5+f/dfpx;i<256;i=.5+(f+=fani)/dfpx)
         WritePixel(rp2,i+18,line);
   }
   if(fani/dfpx>15.5){
      SetAPen(rp2,18);
      for(f=fani/4.,i=.5+f/dfpx;i<256;i=.5+(f+=fani/2.)/dfpx)
         WritePixel(rp2,i+18,line);
   }
   if(!(itser%itani)){
      SetAPen(rp2,1);
      i=.5+itser*tline;
      sprintf(prt,"%2d",i);
      Move(rp2,0,line+3);
      Text(rp2,prt,2);
      WritePixel(rp2,17,line);
   }
}
/****************************************************/
int dism(dmes,dk)
char *dmes;
int dk;
{
   static struct IntuiText rq1bt={0,1,JAM2,6,3,NULL,"Warning",NULL};
   static struct IntuiText rq2bt={0,1,JAM2,6,3,NULL,"ERROR",NULL};
   static struct IntuiText rq1pt={0,1,JAM2,6,3,NULL,"Continue",NULL};
   static struct IntuiText rq1nt={0,1,JAM2,6,3,NULL,"Quit",NULL};

   setstatus(STATUSCON);
   SetAPen(rp1,0);
   RectFill(rp1,4,125,635,148);
   SetAPen(rp1,1);
   Move(rp1,16,135);
   Text(rp1,dmes,strlen(dmes));
   if(dk==0){
      Move(rp1,100,147);
      SetAPen(rp1,3);
      Text(rp1,"FATAL ERROR - must exit",23);
      AutoRequest(win1,&rq2bt,NULL,&rq1nt,0,0,250,50);
      clean();
   }else if(dk==2){
      if(AutoRequest(win1,&rq1bt,&rq1pt,&rq1nt,0,0,250,50));
      else clean();
   }
   return(dk);
}
/************************************************/
char *pathcat(pcpn,pcdn,pcfn)
char *pcpn,*pcdn,*pcfn;
{
   static int i;
   static char pcc=':';
   i=strlen(pcdn);
   if(i<1){
      strncpy(pcpn,pcfn,30);
   }else{
      strncpy(pcpn,pcdn,60);
      if(pcdn[i-1]!=pcc) strcat(pcpn,"/");
      strncat(pcpn,pcfn,30);
   }
   if(strlen(pcpn)<1) return(NULL);
   else return(pcpn);
}
/***********************************************/
void doparms()
{
   static int i;
   
   switch(pgdt->GadgetID){
   case 11:
      sscanf(gd11sb,"%f",&srate);
      i=srate;
      if(i<1000) i=1000;
      if(i>27000) i=27000;
      srate=i;
      dt=1./srate;
      jdt=dt/cint;
      sprintf(gd11sb,"%5d",i);
      readit=FALSE;
      break;
   case 12:
      sscanf(gd12sb,"%d",&i2fft);
      if(i2fft<6) i2fft=6;
      if(i2fft>14) i2fft=14;
      sprintf(gd12sb,"%2d",i2fft);
      for(nfft=64,i=6;i<i2fft;++i) nfft+=nfft;
      istep=tstepf*nfft;
      if(istep<1) istep=1;
      if(istep>(16*nfft)) istep=16*nfft;
      tstepf=(istep+0.)/nfft;
      sprintf(gd15sb,"%5.3f",tstepf);
      if(i2fft<=5) kdfpx=7;
      else if(i2fft<=8) kdfpx=13-i2fft;
      else if(i2fft<=10) kdfpx=0;
      else if(i2fft<=13) kdfpx=i2fft-10;
      else kdfpx=3;
      gd29gt.IText=(UBYTE *)gd29s[kdfpx];
      ndfpx=idfpx[kdfpx];
      npxdf=ipxdf[kdfpx];
      readit=FALSE;
      break;
   case 13:
      sscanf(gd13sb,"%d",&ifani);
      if(ifani<1) ifani=1;
      if(ifani>80) ifani=80;
      sprintf(gd13sb,"%2d",ifani);
      fani=100*ifani;
      break;
   case 15:
      sscanf(gd15sb,"%f",&tstepf);
      istep=tstepf*nfft;
      if(istep<1) istep=1;
      if(istep>(16*nfft)) istep=16*nfft;
      tstepf=(istep+0.)/nfft;
      sprintf(gd15sb,"%5.3f",tstepf);
      readit=FALSE;
      break;
   case 16:
      sscanf(gd16sb,"%f",&tline);
      if(tline<.001) tline=.001;
      i=tline/(dt*istep);
      if(i<4) tline=4*istep*dt;
      if(tline>99.) tline=99.;
      sprintf(gd16sb,"%6.3f",tline);
      break;
   case 17:
      sscanf(gd17sb,"%d",&itani);
      if(itani<1) itani=1;
      if(itani>99) itani=99;
      sprintf(gd17sb,"%2d",itani);
      break;
   case 18:
      sscanf(gd18sb,"%f",&smwid);
      if(smwid<=.01) smwid=.01;
      if(smwid>99.) smwid=99.;
      sprintf(gd18sb,"%5.2f",smwid);
      readit=FALSE;
      break;
   case 19:
      sscanf(gd19sb,"%f",&colstep);
      if(colstep<.1) colstep=.1;
      if(colstep>99.) colstep=99.;
      sprintf(gd19sb,"%4.1f",colstep);
      readit=FALSE;
      break;
   case 20:
      dbflag=(dbflag+1)%2;
      gd20gt.IText=(UBYTE *)gd20s[dbflag];
      readit=FALSE;
      break;
   case 21:
      pbefore=(pbefore+1)%2;
      gd21gt.IText=(UBYTE *)gd21s[pbefore];
      break;
   case 22:
      plin=(plin+1)%2;
      gd22gt.IText=(UBYTE *)gd22s[plin];
      break;
   case 23:
      gd23.Flags|=SELECTED;
      gd24.Flags&=~SELECTED;
      gd25.Flags&=~SELECTED;
      break;
   case 24:
      gd24.Flags|=SELECTED;
      gd23.Flags&=~SELECTED;
      gd25.Flags&=~SELECTED;
      break;
   case 25:
      gd25.Flags|=SELECTED;
      gd23.Flags&=~SELECTED;
      gd24.Flags&=~SELECTED;
      break;
   case 26:
      sscanf(gd26sb,"%f",&colfrom);
      if(dbflag){
         if(colfrom>99.) colfrom=99.;
         if(colfrom<-99.) colfrom=-99.;
      }else{
         if(colfrom>999.) colfrom=999.;
         if(colfrom<0.) colfrom=0.;
      }
      sprintf(gd26sb,"%5.1f",colfrom);
      break;
   case 27:
      sscanf(gd27sb,"%ld",&ifp);
      if(ifp<0) ifp=0;
      sprintf(gd27sb,"%8ld",ifp);
      readit=FALSE;
      setoff=TRUE;
      break;
   case 28:
      sscanf(gd28sb,"%ld",&ibt0);
      if(ibt0<0) ibt0=0;
      sprintf(gd28sb,"%8ld",ibt0);
      readit=FALSE;
      setoff=TRUE;
      break;
   case 29:
      kdfpx=(kdfpx+1)%8;
      gd29gt.IText=(UBYTE *)gd29s[kdfpx];
      ndfpx=idfpx[kdfpx];
      npxdf=ipxdf[kdfpx];
      break;
   case 30:
      gd30i=(gd30i+1)%5;
      gd30gt.IText=(UBYTE *)gd30s[gd30i];
      break;
   case 31:
      sscanf(gd31sb,"%f",&fa4);
      if(fa4<220.) fa4=220.;
      if(fa4>880.) fa4=880.;
      sprintf(gd31sb,"%5.1f",fa4);
      break;
   }
   dt=1./srate;
   jdt=dt/cint;
   df=1./(dt*nfft);
   dfpx=ndfpx*df/npxdf;
   tstep=istep*dt;
   iser=0;
   tser=ifp*dt/tline;
   itser=tser;
   tser=ifp*dt-itser*tline;
   RefreshGadgets(&gd11,win1,NULL);
   refwin();
}
/******************************************/
void refwin()
{
   pr1(16,17,"File format");
   gadbox(112,17,15);
   pr1(248,17,"t0 byte");
   gadbox(312,17,9);
   pr1(392,17,"start offset");
   gadbox(496,17,9);
   pr1(16,27,"Sample rate");
   gadbox(112,27,6);
   sprintf(prt,"Hz; interval%8.3f us",(1.e6/srate));
   pr1(168,27,prt);
   sprintf(prt,"%8d samples",nfp);
   pr1(400,27,prt);
   pr1(16,37,"FFT length 2^");
   gadbox(128,37,3);
   sprintf(prt,"=%5d samples;%8.3f ms time slice",
      nfft,(nfft*1.e3/srate));
   pr1(160,37,prt);
   sprintf(prt,"frequency step%6.2f Hz %6.2f Hz/pixel",df,dfpx);
   pr1(48,47,prt);
   gadbox(368,47,4);
   pr1(408,47,"steps/pixel");
   pr1(16,57,"Frequency annotate");
   gadbox(168,57,3);
   sprintf(prt,"hundred Hz;%5.1f pixels",(fani/dfpx));
   pr1(200,57,prt);
   pr1(400,57,"A=");
   gadbox(424,57,6);
   pr1(480,57,"Hz");
   pr1(16,67,"Time step");
   gadbox(96,67,6);
   sprintf(prt,"of FFT; %5d samples;%8.3f ms",istep,(istep*1.e3/srate));
   pr1(152,67,prt);
   pr1(16,77,"Time lines");
   gadbox(104,77,7);
   sprintf(prt,"s =%5.1f pixels (time steps)",(tline/(dt*istep)));
   pr1(168,77,prt);
   pr1(48,87,"annotate every");
   gadbox(168,87,3);
   sprintf(prt,"time lines =%5.1f pixels",(itani*tline/(dt*istep)));
   pr1(200,87,prt);
   pr1(16,97,"Smooth");
   gadbox(72,97,6);
   sprintf(prt,"of time step = %5.3f of FFT =%8.3f ms",(tstepf*smwid),
      (smwid*istep*1.e3/srate));
   pr1(128,97,prt);
   pr1(16,107,"Color change every");
   gadbox(168,107,5);
   gadbox(216,107,3);
   pr1(248,107,"below");
   gadbox(296,107,6);
   pr1(352,107,"Peak seek");
   gadbox(432,107,1);
   pr1(448,107,"pixels");
   pr1(16,117,"Play sound before analysis?");
   gadbox(248,117,4);
   pr1(296,117,"during analysis?");
   gadbox(440,117,4);
}
/******************************************/
void gadbox(x,y,n)
int x,y,n;
{
   int xa,xb,ya,yb;
   xa=x-1;xb=x+8*n;ya=y-7;yb=y+2;
   SetAPen(rp1,3);
   Move(rp1,xa,ya);
   Draw(rp1,xb,ya);
   Draw(rp1,xb,yb);
   Draw(rp1,xa,yb);
   Draw(rp1,xa,ya);
   SetAPen(rp1,1);
}
/******************************************/
void pr1(x,y,s)
int x,y;
char *s;
{
   SetAPen(rp1,1);
   Move(rp1,x,y);
   Text(rp1,s,strlen(s));
}
/******************************************/
int setstatus(newstat)
int newstat;
{
   switch(newstat){
   case STATUSCON:
      for(pgdt=win2->FirstGadget;pgdt;pgdt=pgdt->NextGadget)
         if(!(pgdt->Flags&GADGDISABLED)) OffGadget(pgdt,win2,NULL);
      OnGadget(&gd4,win2,NULL);
      gd2.Flags|=SELECTED;
      gd2.Flags^=SELECTED;
      RefreshGadgets(&gd1,win2,NULL);
      WBenchToFront();
/*      WindowToFront(win1); */
      SetMenuStrip(win1,&mn0);
      for(pgdt=win1->FirstGadget;pgdt;pgdt=pgdt->NextGadget)
         if(pgdt->Flags&GADGDISABLED) OnGadget(pgdt,win1,NULL);
      status=STATUSCON;
      return(TRUE);
   case STATUSHALT:
      if(status==STATUSCON){
         for(pgdt=win1->FirstGadget;pgdt;pgdt=pgdt->NextGadget)
            if(!(pgdt->Flags&GADGDISABLED)) OffGadget(pgdt,win1,NULL);
         OnGadget(&gd14,win1,NULL);
         RefreshGadgets(&gd11,win1,NULL);
         ClearMenuStrip(win1);
      }
      ScreenToFront(scr2);
      for(pgdt=win2->FirstGadget;pgdt;pgdt=pgdt->NextGadget)
         if(pgdt->Flags&GADGDISABLED) OnGadget(pgdt,win2,NULL);
      gd2.Flags|=SELECTED;
      gd2.Flags^=SELECTED;
      RefreshGadgets(&gd1,win2,NULL);
      status=STATUSHALT;
      return(TRUE);
   case STATUSGO:
      if(!readit){
         return(FALSE);
      }
      if(status==STATUSCON){
         for(pgdt=win1->FirstGadget;pgdt;pgdt=pgdt->NextGadget)
            if(!(pgdt->Flags&GADGDISABLED)) OffGadget(pgdt,win1,NULL);
         OnGadget(&gd14,win1,NULL);
         RefreshGadgets(&gd11,win1,NULL);
         ClearMenuStrip(win1);
         ScreenToFront(scr2);
         for(pgdt=win2->FirstGadget;pgdt;pgdt=pgdt->NextGadget)
            if(pgdt->Flags&GADGDISABLED) OnGadget(pgdt,win2,NULL);
      }
      OffGadget(&gd1,win2,NULL);
      OffGadget(&gd3,win2,NULL);
      gd2.Flags|=SELECTED;
      RefreshGadgets(&gd1,win2,NULL);
      status=STATUSGO;
      return(TRUE);
   default:
      dism("Status error",0);
   }
   return(FALSE);
}
/******************************************/
long doiff(v,p)
Voice8Header *v;
FILE *p;
{
   long *k,ip;
   char cf[12];
   
   k=(long *)(cf+4);
   rewind(p);
   if(fread(cf,1,12,p)<12) return(0);
   if(strncmp(cf,"FORM",4)) return(0);
   if(strncmp(cf+8,"8SVX",4)) return(0);
   if(fread(cf,1,8,p)<8) return(0);
   if(strncmp(cf,"VHDR",4)) return(0);
   if(fread((char *)v,1,20,p)<20) return(0);
   ip=12;
   while(strncmp(cf,"BODY",4)) {
      ip+=(*k+8);
      if(fseek(p,ip,0)) return(0);
      if(fread(cf,1,8,p)<8) return(0);
   }
   return(ip+8);
}
/***********************************************/
void distf(ii)
int ii;
{
   static float t,f,fl,y0,y1,y2,r;
   static char ckeep[20],*ckp;
   static int i,is,ifl,j,k,k0,k1,k2;
   
   if(ii){
      t=dt*(ifp+istep*(lmark[2]-linf)+nfft/2);
      j=lmark[2];
      k0=0;
      for(is=ii-gd30i;is<=ii+gd30i;++is){
         k=is;
         if(k<18) k=18;
         if(k>273) k=273;
         k1=ReadPixel(rp2,k,j);
         if(k1>k0) {i=k;k0=k1;}
      }
      k=i-npxdf;if(k<18) k=18;
      k1=ReadPixel(rp2,k,j);if(k1>k0) k1=k0;
      k=i+npxdf;if(k>273) k=273;
      k2=ReadPixel(rp2,k,j);if(k2>k0) k2=k0;
      if(k1<k2){
         k=k1;k1=k2;k2=k;
         k=1;
      }else if(k1>k2) k=-1;
      else k=0;
      if(k&&gd30i){
         y0=log(cut[k0]);
         y1=log(cut[k1]);
         y2=log(cut[k2]);
         if(y0>y2) r=(y0-y1)/(y0-y2);
         else r=1.;
         r=k*(1.-r)/(2.*r+2.);
      }else r=0.;
      f=dfpx*(i+r-18);
      if(f<1.) f=1.;
      fl=120.+17.31234*(log(f)-log(fa4));
      ifl=fl+.5;
      fl=fl-ifl;
      SetAPen(rp2,0);
      RectFill(rp2,74,0,319,8);
      SetAPen(rp2,1);
      kkeep=i;
      k=ReadPixel(rp2,i,j);
      sprintf(prt,"%5.2f s  %5.0f Hz  %s%+4.2f %d\0",t,f,cky[ifl%12],fl,k);
      Move(rp2,74,7);
      Text(rp2,prt,strlen(prt));
      SetAPen(rp2,0);
      for(k=2,ckp=ckeep;k<4;++k){
         *ckp++=ReadPixel(rp2,kkeep+k,j);
         WritePixel(rp2,kkeep+k,j);
         *ckp++=ReadPixel(rp2,kkeep,j+k);
         WritePixel(rp2,kkeep,j+k);
         *ckp++=ReadPixel(rp2,kkeep-k,j);
         WritePixel(rp2,kkeep-k,j);
         *ckp++=ReadPixel(rp2,kkeep,j-k);
         WritePixel(rp2,kkeep,j-k);
      }
      for(j=-1;j<=1;++j)
      for(k=-1;k<=1;++k){
         SetAPen(rp2,ReadPixel(rp2,kkeep+j*npxdf,lmark[2]+k*npxdf));
         RectFill(rp2,314+3*j,3+3*k,316+3*j,5+3*k);
      }
      k=ReadPixel(rp2,kkeep,lmark[2]);
      SetAPen(rp2,k);
      k=90+6*(k-2);
      if(k>174) {k-=90;j=298;}
      else j=290;
      if(k>89) RectFill(rp2,j,k,j,k+5);
      if(k>89) RectFill(rp2,j+7,k,j+7,k+5);
      k=ReadPixel(rp2,kkeep-npxdf,lmark[2]);
      SetAPen(rp2,k);
      k=90+6*(k-2);
      if(k>174) {k-=90;j=298;}
      else j=290;
      if(k>89) RectFill(rp2,j,k,j,k+5);
      k=ReadPixel(rp2,kkeep+npxdf,lmark[2]);
      SetAPen(rp2,k);
      k=90+6*(k-2);
      if(k>174) {k-=90;j=298;}
      else j=290;
      if(k>89) RectFill(rp2,j+7,k,j+7,k+5);
   }else if(kkeep){
      j=lmark[2];
      for(k=2,ckp=ckeep;k<4;++k){
         SetAPen(rp2,*ckp++);WritePixel(rp2,kkeep+k,j);
         SetAPen(rp2,*ckp++);WritePixel(rp2,kkeep,j+k);
         SetAPen(rp2,*ckp++);WritePixel(rp2,kkeep-k,j);
         SetAPen(rp2,*ckp++);WritePixel(rp2,kkeep,j-k);
      }
      SetAPen(rp2,0);
      RectFill(rp2,74,0,319,8);
      RectFill(rp2,290,90,290,179);
      RectFill(rp2,297,90,298,179);
      RectFill(rp2,305,90,305,179);
   }
}
/*******************************************************************/
/* fast fourier transform subroutine */
int fftcr(x,nt)
float *x;
int nt;
{
   static short *mf=NULL,nb,ib,na,n2a,n4a,ia,ie;
   static int ne,nf,ns,ntp=-1;
   register short i,j,k,l;
   static float *sine=NULL,rk,sk,fr,fs,gr,gs,hr,hs;
   register float *ri,*si,*rh,*sh;
   static double pi,w,dw;

   if(nt!=ntp){
      pi=4.*atan(1.);
      ntp=0;
      if(mf) free((char *)mf);
      if(sine) free((char *)sine);
      if(nt<4||nt>16) return(4);
      ne=nt-1;
      for(i=1,ns=1;i<ne;++i) ns+=ns;
      nf=ns+ns;
      if((mf=(short *)calloc(2,nf))==NULL) return(1);
      if((sine=(float *)calloc(4,ns+1))==NULL) return(2);
      sine[0]=0.;
      dw=-pi/nf;
      for(i=1,w=dw;i<ns;++i,w+=dw)
         sine[i]=sin(w);
      sine[ns]=-1.;
      for(k=0;k<nf;++k){
         for(i=ns,j=1,l=0;i;i>>=1,j<<=1)
            if(j&k) l|=i;
         mf[k]=l;
      }
      ntp=nt;
   }

   na=ns;n2a=nf;n4a=4*na;
   nb=1;
   for(ie=0;ie<ne;++ie){
      for(ib=0,i=0;ib<nb;++ib,i+=n4a){
         k=mf[ib];
         if(k>ns){
            rk=sine[k-ns];
            sk=sine[nf-k];
         }
         else{
            rk=-sine[ns-k];
            sk=sine[k];
         }
         ri=x+i;
         si=ri+1;
         rh=ri+n2a;
         sh=rh+1;
         for(ia=0;ia<na;++ia){
            gr=*rh*rk-*sh*sk;
            gs=*rh*sk+*sh*rk;
            *rh=*ri-gr;
            *sh=*si-gs;
            *ri=*ri+gr;
            *si=*si+gs;
            ri+=2;
            si+=2;
            rh+=2;
            sh+=2;
         }
      }
      na>>=1;
      n2a>>=1;
      n4a>>=1;
      nb<<=1;
   }
   /* unscramble */
   for(j=0;j<nf;++j){
      k=mf[j];
      if(k>j){
         ri=x+(j<<1);
         si=ri+1;
         rh=x+(k<<1);
         sh=rh+1;
         gr=*ri;
         gs=*si;
         *ri=*rh;
         *si=*sh;
         *rh=gr;
         *sh=gs;
      }
   }
   /* rearrange for real input */
   ri=x+2;
   si=ri+1;
   rh=x+2*(nf-1);
   sh=rh+1;
   for(k=1;k<ns;++k){
      gr=*ri+*rh;
      gs=*si+*sh;
      hr=*ri-*rh;
      hs=*si-*sh;
      rk=sine[ns-k];
      sk=sine[k];
      fr=rk*gs-sk*hr;
      *ri=gr-fr;
      *rh=gr+fr;
      fs=sk*gs+rk*hr;
      *si=hs+fs;
      *sh=fs-hs;
      ri+=2;
      si+=2;
      rh-=2;
      sh-=2;
   }
   *ri=2.**ri;
   *si=-2.**si;
   ri=x;
   si=ri+1;
   gr=*ri+*si;
   *si=*ri-*si;
   *ri=gr;
   return(0);
}
/**************************************/
int play(smp,nsm,ism)
BYTE *smp; /* pointer to sound array (word aligned, chip access) */
int nsm;   /* length of smp (in bytes; even) */
int ism;   /* sound sample interval (clock periods of 279.365 ns) */
{
   struct IOAudio *ioa0=NULL;
   struct MsgPort *msg0=NULL;
   int ie; /* error code */
   static BYTE alr[]={1}; /* allocation mask for channel 0 */
   
   ioa0=(struct IOAudio *)calloc(sizeof(struct IOAudio),1);
   ie=1;if(ioa0==NULL) goto exitplay;
   msg0=(struct MsgPort *)CreatePort("play0",0);
   ie=2;if(msg0==NULL) goto exitplay;
   ioa0->ioa_Data=alr;
   ioa0->ioa_Length=1;
   ioa0->ioa_Request.io_Message.mn_Node.ln_Pri=127; /* maximum */
   ioa0->ioa_Request.io_Message.mn_ReplyPort=msg0;
   ie=3;if(OpenDevice("audio.device",0,ioa0,0)!=0) goto exitplay;
   ioa0->ioa_Data=smp;
   ioa0->ioa_Length=nsm;
   ioa0->ioa_Period=ism;
   ioa0->ioa_Volume=64; /* maximum */
   ioa0->ioa_Cycles=1;  /* once thru */
   ioa0->ioa_Request.io_Command=CMD_WRITE;
   ioa0->ioa_Request.io_Flags=ADIOF_PERVOL;
   BeginIO(ioa0);
   WaitIO(ioa0);
   ie=0;
exitplay:
   if(msg0) DeletePort(msg0);
   if(ioa0){
      if(ioa0->ioa_Request.io_Device) CloseDevice(ioa0);
      free((char *)ioa0);
   }
   return(ie);
}
