#include <math.h>
#include <stdio.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <devices/audio.h>
#include <proto/intuition.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
extern struct Window *Window;
extern struct Screen *Screen;
extern struct ViewPort *ViewPort;
extern struct RastPort *rport;
extern struct IOAudio *ioa,*audio,*finish[4],*audchan[4];
extern struct IntuiText About1;
extern struct Gadget propor8;
extern struct Gadget propor7;
extern struct Gadget propor6;
extern struct Gadget propor5;
extern struct Gadget propor4;
extern struct Gadget propor3;
extern struct Gadget propor2;
extern struct Gadget propor1;
extern struct IntuiText textamp;
extern struct IntuiText OK;
extern struct IntuiText Answer1;
extern struct Border RWave_brd5;
extern struct Border UWave_brd5;
extern struct Border SWave_brd5;

extern SHORT sinewave[8][513];
extern BYTE *usersound,*refsound;
extern char textbuf[6];
extern LONG amps[8],refamps[8];
extern USHORT userwave[513][2],refwave[513][2],selwave[513][2];
extern UBYTE selflag;
extern SHORT waiting[5];

#define YES     1
#define NO      0

extern LONG maxuser,maxref;
extern LONG maxamp;
extern BYTE waveform[514],refform[514],selform[514];
extern BYTE *usersound,*refsound;
extern SHORT gameon;
extern char Answers[80];

/********************************************************************/
VOID Update(USHORT gadno)

/*  Update the amplitudes and screen when one amplitude has been changed */

{
	VOID AmpsUpdate(),DrawUser();
	LONG MakeWave();
	
	if (amps[gadno]>127) amps[gadno]=127;
	if (amps[gadno]<-127) amps[gadno]=-127;
	maxuser=MakeWave(amps,waveform,usersound);
	AmpsUpdate();
	DrawUser();
}

/*************************************************************/
VOID DoMenu(USHORT mcode)

/*  Does the right thing when a menu option is chosen */

{
#define PROJECT_MENU 0
#define WAVE_MENU    1
#define GAME_MENU    2

#define ABOUT        0
#define FULLSCALE    1
#define SCREENBACK   2
#define SCREENFRONT  3
#define QUIT         4

#define START_EASY   0
#define START_HARD   1
#define STOP         2

switch(MENUNUM(mcode))
{
	LONG peak,retval;
	SHORT i,item,scale;
	LONG temp,AddWaves(),randamp(),checkval(),MakeWave(),AutoRequest();
	VOID AmpsUpdate(),PropUpdate(),DrawUser(),WaveCleanup(),rescale();
	static SHORT canned[4][8]={{  0,  0,  0,  0,  0,  0,  0,  0},
	                           {108,  0,-12,  0,  4,  0, -2,  0},
		                   { 74,-38, 24,-20, 14,-12, 10, -9},
		                   {124,  0, 41,  0, 25,  0, 18,  0}};

			       
	
	case PROJECT_MENU:
		switch (ITEMNUM(mcode))
		{
			case ABOUT:
			{
				retval=AutoRequest(Window,&About1,&OK,&OK,
				   NULL,NULL,500,130);
				break;
			}
			case FULLSCALE:
			{
			        if ((peak=checkval(maxuser,amps))!=0) 
				   rescale(peak,amps);
				maxuser=AddWaves(amps,0xFF,waveform,
					usersound)>>15;
				AmpsUpdate();
				PropUpdate();
				DrawUser();
				break;
			}
			case SCREENBACK:
			{
				ScreenToBack(Screen);
				break;
			}
			case SCREENFRONT:
			{
				ScreenToFront(Screen);
				break;
			}
			case QUIT:
			{
				WaveCleanup();
				Exit(TRUE);
			}
		}
		break;
	case WAVE_MENU:
		item = ITEMNUM(mcode);
		for (i=0; i<8; ++i)
		{
			amps[i] = canned[item][i];
		}
                if (item == 0)
                {
                    for (i=0; i<4; i++)
                    {
                        BeginIO(finish[i]);
                        WaitIO(finish[i]);
                        waiting[i]=NO;
                    }
                }
		AmpsUpdate();
		PropUpdate();
		maxuser=MakeWave(amps,waveform,usersound);
		DrawUser();
		break;
	case GAME_MENU:
		switch (ITEMNUM(mcode))
		{
			case START_EASY:
				gameon = YES;
				for (i=0; i<4; i++)
				{
					refamps[i] = randamp();
				}
				for (i=4;i<8;i++) refamps[i]=0;
				maxref=MakeWave(refamps,refform,refsound);
			        if (maxref==0) maxref=1;
				scale=maxamp/maxref;
				for (i=0;i<4;++i)
				{
					temp=refamps[i]*scale;
					refamps[i]=temp>>7;
				}
				maxref=AddWaves(refamps,0x0F,refform,
					NULL)>>15;
				for (i=0; i<513; ++i)
				{
				    refwave[i][1]=((129-refform[i])*48)>>7;
				}
				DrawUser();
				break;
			case START_HARD:
				gameon = YES;
				for (i=0; i<8; i++)
				{
					refamps[i] = randamp();
				}
				maxref=MakeWave(refamps,refform,refsound);
			        if (maxref==0) maxref=1;
				scale=maxamp/maxref;
				for (i=0;i<8;++i)
				{
					temp=refamps[i]*scale;
					refamps[i]=temp>>7;
				}
				maxref=AddWaves(refamps,0xFF,refform,
					NULL)>>15;
				for (i=0; i<513; ++i)
				{
				    refwave[i][1]=((129-refform[i])*48)>>7;
				}
				DrawUser();
				break;
			case STOP:
				gameon = NO;
				sprintf(Answers,
				 "%6d %6d %6d %6d %6d %6d %6d %6d",
				 refamps[0],refamps[1],refamps[2],
				 refamps[3],refamps[4],refamps[5],
				 refamps[6],refamps[7]);
				retval=AutoRequest(Window,&Answer1,&OK,&OK,
				   NULL,NULL,620,80);
				DrawUser();
				break;
		}
		break;
}
}

/****************************************************************/
VOID AmpsUpdate()

/*  Update the numerical amplitude displays   */

{
	SHORT i;
	SHORT boxx[8]={34,108,182,256,330,404,478,552};
	
	for (i=0;i<8;i++)
	{
		sprintf(textbuf,"%5d",amps[i]);
		PrintIText(rport,&textamp,boxx[i],188);
	}
}

/****************************************************************/
VOID PropUpdate()

/*  Update the proportional gadgets after a rescaling  */

{
	USHORT temp;
	temp=amptopot(amps[7]);
	ModifyProp(&propor8,Window,NULL,FREEVERT|AUTOKNOB,0xFFFF,
		temp,0x0800,0x0800);
	temp=amptopot(amps[6]);
	ModifyProp(&propor7,Window,NULL,FREEVERT|AUTOKNOB,0xFFFF,
		temp,0x0800,0x0800);
	temp=amptopot(amps[5]);
	ModifyProp(&propor6,Window,NULL,FREEVERT|AUTOKNOB,0xFFFF,
		temp,0x0800,0x0800);
	temp=amptopot(amps[4]);
	ModifyProp(&propor5,Window,NULL,FREEVERT|AUTOKNOB,0xFFFF,
		temp,0x0800,0x0800);
	temp=amptopot(amps[3]);
	ModifyProp(&propor4,Window,NULL,FREEVERT|AUTOKNOB,0xFFFF,
		temp,0x0800,0x0800);
	temp=amptopot(amps[2]);
	ModifyProp(&propor3,Window,NULL,FREEVERT|AUTOKNOB,0xFFFF,
		temp,0x0800,0x0800);
	temp=amptopot(amps[1]);
	ModifyProp(&propor2,Window,NULL,FREEVERT|AUTOKNOB,0xFFFF,
		temp,0x0800,0x0800);
	temp=amptopot(amps[0]);
	ModifyProp(&propor1,Window,NULL,FREEVERT|AUTOKNOB,0xFFFF,
		temp,0x0800,0x0800);
}

/*****************************************************************/
LONG MakeWave(LONG ampl[],BYTE wf[],UBYTE *ws)

/*  Makes the compound waveform (via AddWaves) and checks that it */
/*  is not off scale.  If it is, it rescales.                     */
{
	LONG peak;
	LONG maxnow;
	LONG AddWaves();
	LONG checkval();
	VOID rescale();
	
	maxnow=AddWaves(ampl,0xFF,wf,ws)>>15;
	if ((peak=checkval(maxnow,ampl))>127)
	{
		rescale(peak,ampl);
		maxnow=AddWaves(ampl,0xFF,wf,ws)>>15;
                PropUpdate();
	}
	return(maxnow);
}

/******************************************************************/
LONG checkval(LONG maxval,LONG ampl[])

/*  Checks maxval, and all of the amps[i] to find the largest     */
/*  in absolute value.                                            */

{
	SHORT i;
	LONG temp;
	
	temp = maxval;
	for (i=0; i<8; ++i)
	{
		if (abs(ampl[i])>temp) temp=abs(ampl[i]);
	}
	return(temp);
}

/******************************************************************/
VOID rescale(LONG peak,LONG ampl[])

/*  rescale to make the amplitude a high as possible without having */
/*  any ampltiude or the compound wave exceed 127 in absolute value */
{
	extern LONG maxamp;
	SHORT scale,i;
	LONG temp;
	
	scale=maxamp/peak;
	for (i=0;i<8;++i)         /* Be careful not to lose bits */
	{
		temp=ampl[i]*scale;
		ampl[i]=temp>>7;
	}
}

/***********************************************************************/
VOID DrawUser()

/*  Draws the compound waveform in the display area.  */

{
	SHORT i;
        LONG maxsel;

	for (i=0;i<513;++i) userwave[i][1]=((129-waveform[i])*48)>>7;
	SetAPen(rport,1);
	RectFill(rport,64,14,577,109);
	SetAPen(rport,3);
	RectFill(rport,64,61,577,61);
        if (selflag)
        {
          maxsel=AddWaves(amps,selflag,selform,NULL);
          for (i=0; i<513; i++) selwave[i][1]=((129-selform[i])*48)>>7;
          DrawBorder(rport,&SWave_brd5,0,0);
        }
	if (gameon) DrawBorder(rport,&RWave_brd5,0,0);
	DrawBorder(rport,&UWave_brd5,0,0);
}
