/*			C	L	O	C	K
#define	VBLANK
*/
#define	OVERHEAD_HANDLE
#define	NO_ACCURACY
#define	CLOCKPRIO	19L

extern	struct	Gadget		Gadget4SInfo;
extern	struct	NewWindow	NewWindowStructure1;
extern	struct	IntuiText	IText1;

#ifdef	VBLANK
# define UNIT	UNIT_VBLANK
#else
# define UNIT	UNIT_MICROHZ
#endif

#include "LYNX.H"
#include <hardware/cia.h>

#include <MIDI/MIDI.h>
EXPORT	struct	MidiBase	*MidiBase;
EXPORT	struct	MSource		*source=0;
EXPORT	struct	MRoute		*sroute=0;
char	prgname[] =	"Clock",	*name = prgname;
char	midiout[] =	"MidiOut",	*output= midiout;
char	banner[] =
 "*| MIDI Clock Generator V0.3 by Carlo \"Lynx\" von Loesch '90 |*";
union	Event clockevent;

#include <libraries/ARPbase.h>
EXPORT	struct	ArpBase		*ArpBase;
EXPORT	struct	IntuitionBase	*IntuitionBase;
EXPORT	struct	GfxBase		*GfxBase;
EXPORT	struct	Window		*win;
EXPORT	struct	RastPort	*rp;

#include <devices/timer.h>
long	timersig;
struct	MsgPort		*timpo;
struct	timerequest	*tr;
#ifdef ACCURACY
long	TimerBase;
struct	timeval	t1=NULL, t2=NULL;
struct	timerequest	*tr2;
ULONG	normic;
#endif

char	nomem[]="Don't do that, Dave";
FLAG	on = NO, play = NO;
EXPORT	long	sigs, videosig;

main(argc, argv) long argc; char *argv[]; {
	register struct timerequest *time;
	register ULONG t;

	ifnot (ArpBase = OpenLibrary("arp.library",ArpVersion))
		Ciao("No ARP.Library");
	IntuitionBase =	ArpBase -> IntuiBase;
	GfxBase =	ArpBase -> GfxBase;
	ifnot (MidiBase = ArpOpenLibrary (MIDINAME,MIDIVERSION))
		Ciao ("No MIDI.Library");

	for (t=1; t<argc; t++) {
		if (argv[t][0]=='-') switch (argv[t][1]) {
			case 'o':	output = argv[++t]; break;
			default:	Ciao("Bad args");
		}
		else name = argv[t];
	}
	win = MyOpenWindow(&NewWindowStructure1);
	SetWindowTitles (win, -1L, banner);
	rp = win -> RPort;
	if (!(source = CreateMSource (name, NULL))) Ciao (nomem);
	if (!(sroute = MRouteSource (source, output, NULL)))
		Ciao ("no route out");
	if (! (timpo = CreatePort (0L, 0L)))	Ciao (nomem);
	if (! (tr = CreateExtIO (timpo, sizeof(struct timerequest)) ))
		Ciao (nomem);
	if (OpenDevice (TIMERNAME, UNIT, tr, 0)) Ciao ("No Timer");
	timersig = 1L<<timpo->SIGH; time = tr;
	sigs = timersig | videosig;
	clockevent.p[0] = (char) MS_CLOCK;

#ifdef ACCURACY
	TimerBase = (long) time->tr_node.io_Device;
	if (! (tr2 = CreateExtIO (timpo, sizeof(struct timerequest)) ))
		Ciao (nomem);
	if (OpenDevice (TIMERNAME, UNIT_MICROHZ, tr2,0)) Ciao ("No Timer");
	tr2 ->tr_node.io_Command = TR_GETSYSTIME;
	normic =
#endif
	time->tr_time.tv_micro   = Speed2Mic(120);
	time->tr_node.io_Command = TR_ADDREQUEST;
	time->tr_time.tv_secs    = 0;
#ifdef CLOCKPRIO
	SetTaskPri(FindTask(NULL), CLOCKPRIO);
#endif
	forever if (play) {
#ifdef ACCURACY
		DoIO (time); GetTime (&t1);
#else
		SendIO (time);
#endif
		PutMidiMsg (source, &clockevent);
#ifdef ACCURACY
		GetTime (&t2);
		SubTime (&t2, &t1);
		if ((time->tr_time.tv_micro = normic - t2.tv_micro) < 0)
			TOG_LED;
#else
# ifdef OVERHEAD_HANDLE
		if (CheckIO(time)) {
			AbortIO(time); TOG_LED; DoIO(time);
		} else
# endif
		if (timersig != Wait(sigs)) CheckTui();
#endif
	    } else if (timersig != Wait(sigs)) CheckTui();
}

NewSpeed () {
	register long a;
	static char s[3];

	a = 1 + (Gadget4SInfo.HorizPot / Gadget4SInfo.HorizBody);
	NumToString (a, s, 3, ' ');
	IText1.IText = s;
	RefreshGadgets (win->FirstGadget, win, NULL);
	tr->tr_time.tv_micro = Speed2Mic (a);
}
Stop() {
	SendMIDI (MS_STOP); play = NO;
}
Start() {
	if (!play) {
		SendMIDI (MS_START); play = YES;
	}
}
Continue() {
	if (!play) {
		SendMIDI (MS_CONTINUE); play = YES;
	}
}
HitaKey() {}

SendMIDI (command) ULONG command; {
	static union Event otherevent;

	otherevent.p[0] = (UBYTE) command;
	PutMidiMsg (source, &otherevent);
}

#ifdef	ACCURACY
GetTime	(ti)
struct timeval *ti; {
	DoIO (tr2);
	ti->tv_secs = tr2->tr_time.tv_secs;
	ti->tv_micro= tr2->tr_time.tv_micro;
}
#endif

Ciao (str) char *str; {
	if (str) {
		INFO (str);
		if (win) SetWindowTitles (win, str, str);
		Delay (44L);
	}
	if (win)	CloseWindowSafely (win);
	if (sroute)	DeleteMRoute	(sroute);
	if (source)	DeleteMSource	(source);
#ifdef ACCURACY
	if (tr2) {
		CloseDevice (tr);
		DeleteExtIO (tr, sizeof(struct timerequest));
	}
#endif
	if (tr)	{
		AbortIO (tr); CloseDevice (tr);
		DeleteExtIO (tr, sizeof(struct timerequest));
	}
	if (timpo)	DeletePort (timpo);
	if (ArpBase)	CloseLibrary	(ArpBase);
	OFF_LED;
	exit(str ? 4404L : 0L);
}

long Speed2Mic (speed) ULONG speed; {
	return (156250000/speed);
}
