[net.micro.atari] ST timer tick?

tynor@gitpyr.UUCP (Steve Tynor) (01/08/86)

Can anyone tell me how I can get a simple timer tick on my ST?  I need a
high resolution timer so that I can record keystrokes off of MIDI for a 
simple sequencer I'm writing.  However, I've looked through all the
developer documentation and can't figure out how to do it...  Do I have to
write an interupt handler to count timer interupts? (ugh...) I can't believe
it's as hard as that...

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Progress means replacing something wrong with something more subtly wrong.
                     
    Steve Tynor
    Georgia Instutute of Technology

 ...{akgua, allegra, amd, harpo, hplabs,
     ihnp4, masscomp, ut-ngp, rlgvax, sb1,
     uf-cgrl, unmvax, ut-sally}  !gatech!gitpyr!tynor

bammi@cwruecmp.UUCP (Jwahar R. Bammi) (01/12/86)

> Can anyone tell me how I can get a simple timer tick on my ST?  I need a
> high resolution timer so that I can record keystrokes off of MIDI for a 
> simple sequencer I'm writing.  However, I've looked through all the
> developer documentation and can't figure out how to do it...  Do I have to
> write an interupt handler to count timer interupts? (ugh...) I can't believe
> it's as hard as that...
> 
>     Steve Tynor
>     Georgia Instutute of Technology
	The simplest way is to read the value of the 200 Hz system
timer contained in location 4BA -- The hitch Hikers guide says 4BC but
that is a misprint. It has to be done in super mode otherwise you get
mushrooms. Here is a example

long ticks;
long *_hz200 = 0x000004ba;

read_ticks()
{
	ticks = *_hz200;
}

main()
{
......
	/* Call read_ticks in super mode - this def if missing  in
	osbind.h */
	xbios(38,read_ticks);
	/* ticks now has the value of the 200 Hz timer */
}

You could also use the Xbtimer() xbios call with timer a, but I
have'nt gotten it to work correctly as yet ( I had posted a query a
couple of days back, but still have no answer ).

Some people over here have been hacking midi code too. One of their
experiences was that incresing the size of the midi receive buffer
helps a lot too in keeping up with some of the Yahama equipment that
send status bytes every 200 ms (I think). this can be done by using
the Iorec() xbios call. Hope this helps.



-- 
					Jwahar R. Bammi
			       Usenet:  .....!decvax!cwruecmp!bammi
			        CSnet:  bammi@case
				 Arpa:  bammi%case@csnet-relay
			   CompuServe:  71515,155

mendoza@aero.ARPA (Lee Mendoza) (01/12/86)

In article <1241@gitpyr.UUCP> tynor@gitpyr.UUCP (Steve Tynor) writes:
>Can anyone tell me how I can get a simple timer tick on my ST?
>

     I have written a simple function which accesses the 200 Hz timer tick,
unfortunately it is the highest resolution timer that I could find.  [If
anyone knows of a 1 ms timer I would like to hear about it.]

     This function requires that your program include osbind.h (for the
Super() function); which requires that you include osbind.o when you link
your program.  Note that the address pointed to in the "Hitchhiker's Guide
to the BIOS" is not correct.  I suffered greatly over this until I started
poking around using SID.  The address is correct in the BIOS listings.

Lee Mendoza

------

/* timer.h -- returns a longword containing the number of milliseconds since
 *            booting, with a resolution of 5 ms.
 *
 * Written by Lee Mendoza
 *
 */

long timer()
{
  long stack, time, *timer;

  timer = 0x4ba;               /* _hz_200:  200 Hz system timer tick */
  stack = 0;                   /* null the stack pointer */

  stack = Super(stack);        /* enter supervisor mode, save the stack */
  time = *timer;               /* get 5 ms timer tick */
  stack = Super(stack);        /* exit supervisor mode, restore the stack */

  time = 5*time;               /* calculate the time... */
  return(time);                /* and return it to the caller */
}

nigel@minster.UUCP (nigel) (01/12/86)

In article <1241@gitpyr.UUCP> tynor@gitpyr.UUCP (Steve Tynor) writes:
>Can anyone tell me how I can get a simple timer tick on my ST?  I need a
>high resolution timer so that I can record keystrokes off of MIDI for a 
>simple sequencer I'm writing.  However, I've looked through all the
>developer documentation and can't figure out how to do it...  Do I have to
>write an interupt handler to count timer interupts? (ugh...) I can't believe
>it's as hard as that...
>
You're right - it's not difficult.

I have done this myself, so rather than just reply with the appropriate
routine, I draw attention to the routine hz200() in the following program.
It is a MIDI recorder - it listens to what is being played, can store it on
disk, and play it back. I hacked it together in an afternoon, so it's not
earth-shattering stuff. It only listens on one channel, and ignores all
but note information. It does preserve velocity information, and was tested
on a Yamaha DX7. If anyone does improve this, I would appreciate seeing the
source code.

PS - can anyone spot the deliberate mistake?

--------------------------------------------------------------------------
/* mr.c */
/* Nigel Roles 1986 */

#include "osbind.h"

#define MIDI 3
#define CON 2
#define GM (Bconin(MIDI)&0xff)

struct event {
	int delay;
	char cmd[3];
};

struct event *buffer;

int empty=1;
long bc;
long memsize;
long bmax;

long hz200()
{
	register long save_ssp=Super(0L);
	register long uhz200= *(long *)0x4ba;
	Super(save_ssp);
	return uhz200;
}

record()
{
	register struct event *bp;
	long now,then;
	printf("Recording (any key to stop):\n");
	while (Bconstat(MIDI))
		Bconin(MIDI);
	then=0;
	bp=buffer;
	bc=0;
	for (;;) {
		if (Bconstat(CON)) {
			Bconin(CON);
			bp->delay= -1;
			bc++;
			break;
		}
		if (Bconstat(MIDI)) {
			int b=GM;
			if (b==0xfe)
				continue;	/* Ignore active sensing */
			if (b==0x90) {
				now=hz200();
				if (then==0)
					bp->delay=0;
				else
					bp->delay=now-then;
				then=now;
				bp->cmd[0]=b;
				bp->cmd[1]=GM;
				bp++->cmd[2]=GM;
				if (++bc==bmax) {
					printf("Buffer full\n");
					break;
				}
			}
		}
	}
}

play()
{
	register struct event *bp=buffer;
	long target;
	printf("Playing:\n");
	while (bp->delay!= -1) {
		if (Bconstat(CON)) {
			Bconin(CON);
			break;
		}
		target=hz200()+bp->delay;
		while (hz200()<target) ;
		Midiws(2,bp->cmd);
		bp++;
	}
}

#define FNSIZE 20
struct filename {
	char lin,lout;
	char name[FNSIZE+1];
} fn;

int h;

getfn()
{
	printf("Filename: ");
	fn.lin=FNSIZE;
	Cconrs((char *)&fn);
	printf("\n");
	fn.name[fn.lout]='\0';
}

load()
{
	getfn();
	if ((h=Fopen(fn.name,0))<0) {
		printf("Can't open %s for reading (error %d)\n",fn.name,h);
		return;
	}
	if (Fread(h,memsize,buffer)<0)
		printf("Read error\n");
	else
		empty=0;
	Fclose(h);
}
		
save()
{
	getfn();
	Fdelete(fn.name);
	if ((h=Fcreate(fn.name,0))<0) {
		printf("Can't create %s (error %d)\n",fn.name,h);
		return;
	}
	if (Fwrite(h,sizeof(struct event)*(long)bc,buffer)<0)
		printf("Write error\n");
	Fclose(h);
}
		
main()
{
	char c;
	char *malloc();
	memsize=(long)malloc(-1L);
	if ((buffer=(struct event *)malloc(memsize))==(struct event *)0L) {
		printf("malloc failure\n");
		exit(1);
	}
	bmax=memsize/sizeof(struct event);
	printf("\033EMidi Recorder Version 1.0 (definitely)\n");
	printf("(C) N. G. Roles 1985\n\n");
	printf("Capacity: %D events\n",bmax);
	for (;;) {
		printf("MR> ");
		c=Bconin(CON);
		printf("%c\n",c);
		switch (c) {
		case 'q':
			break;
		case 'r':
			record();
			continue;
		case 'p':
			if (empty)
				printf("Nothing to play!\n");
			else
				play();
			continue;
		case 's':
			if (empty)
				printf("Nothing to save!\n");
			else
				save();
			continue;
		case 'l':
			load();
			continue;
		default:
			printf("???\n");
			continue;
		}
		break;
	}
}

knnngt@ukma.UUCP (Alan Kennington) (01/17/86)

**** "They eat lions, don't they?" - film title ****
	On the subject of timer A in the 78901 chip, I checked out the entire
bios code that is executed upon entry to xbtimer from start to finish. And it
all seemed to be beautifully in accord with the specifications for the
timer chip. I was just about to give up when I read in the bios manual that
some tricky business with the Hsync interrupt could be done by faking RTEs.
Then I realised that timer interrupts put a short stack frame onto the
supervisor stack. Which means that an RTE in Super mode is required. A C
program return can presumably only ever be an RTS. Hence the program
can not possibly work by diverting the timer interrupt to a C function
as an interrupt handler.
	First, can anybody out there confirm my brief analysis of the problem.
Second, has anybody discovered the means of RTEing at the end of a C program?
The bios manual defines xbtimer as a C program. But it doesn't mention
anything about having to write an assembly language program to handle
timer interrupts. Many of you must have long ago written programs to
handle such interrupts. So please tell me if I am incorrect in all of this.
Thanks.............................ak.