Subject: Re: audio interrupt implementation
To: None <cwood@ichips.intel.com>
From: SUNAGAWA Keiki <kei_sun@ba2.so-net.ne.jp>
List: port-mac68k
Date: 04/30/1998 23:27:44
Colin Wood <cwood@ichips.intel.com> wrote:

Colin> SUNAGAWA Keiki wrote:

>> I'd been playing asc and got the playing (with coughing,
>> anyway) raw sound file. So I plan to implement the audio
>> interrupt and have some questions.

Colin> Really?  Could you tell me how?  I tried for a month
Colin> and couldn't get anything remotely pleasing out of
Colin> either an EASC or an ASC.  I haven't looked into it
Colin> in a while since I've been busy with work and ADB
Colin> stuff.

Uh, it's a loop of copying data into sound buffer and
waiting some time, basically.  I'll attatch test program at
the end of this mail.  It can play two sound files
simultaneously.  I'm using Indigo and Droplet sound file
which were extracted System file of MacOS and converted to
raw data.  They may be copyrighted and not be redistributed,
though.

>> In my understanding, the ROM sound driver uses one byte of
>> ASCBase + 0x801 to detect if playing sound is done.  The
>> VBL_Task routine clears the byte of that address and main
>> driver routine updates the sound buffer area.

Colin> Well, I'm not entirely sure about that.
Colin> ASCBase+0x801 on the ASC seems to actually toggle
Colin> whether or not sound is produced.

I looked at more little and found I was wrong.  It seems
that:

0x801: 1 if sampled mode
       2 if 4 voice mode, freq/phase are set independently
0x802: 0 if monaural mode, play left channel only
       2 if stereo mode

Colin> On the EASC, this isn't quite the case.  The flag
Colin> used by VBLTask's is usually a low memory global,
Colin> something like SoundDone (that's not it, but I don't
Colin> have my disassembled .Sound driver in front of me).

Yes, but they clears the 0x801, too.

Colin> I think that 0x801 enables/disables the scanning of
Colin> the sound buffers which run from ASCBase to
Colin> ASCBase+0x3FF and ASCBase+0x400 to ASCBase+0x7FF (the
Colin> latter only seems to be used in double buffered mode,
Colin> but I'm still not quite sure how that part works,
Colin> either).

I didn't find that mode yet, ether.  Areas from 0x000 to
0x1ff and from 0x200 to 0x3ff seems to be treated as left
channnel both.

>> I think that it is needed to map the flag address, but I
>> have no idea to do so.  Am I correct?  What should I do
>> next?

Colin> I tried this as well, but I can't seem to get either
Colin> the ASC or the EASC to actually generate an
Colin> interrupt.

It's so strange.  Do you mean that VIA2 emulation of RBV is
broken?

Colin> This will definitely require some more work sometime
Colin> in the near future...

Yes.  I must learn more:-)

Colin> BTW, have I sent you my C pseudocode for the .Sound
Colin> driver?  If you want it, please let me know.

No, I didn't received it.  Would you send me?  I have
disassembled one from IIcx or ci's ROM, btw.

--
SUNAGAWA Keiki <kei_sun@ba2.so-net.ne.jp>
Happy Hacking!

/* $Id: au.c,v 1.5 1998/04/30 13:38:33 kei Exp kei $ */

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#define BLEN 0x200

int
play(ad, fd1, fd2)
	caddr_t ad;
	int fd1;
	int fd2;
{
	int volume = 50;
	int c1;
	int c2;
	int i;
	int q1;
	int q2;
	char *bp1;
	char *bp2;

	if ((bp1 = (char *)malloc(BLEN)) == NULL)
		exit (1);
	if ((bp2 = (char *)malloc(BLEN)) == NULL)
		exit (1);

#if 0 /* needed only four voice mode */
	for (i = 0; i < 4; i++) {
		*(ad+0x814 + i * 8) = 0;
		*(ad+0x815 + i * 8) = 0;
		*(ad+0x816 + i * 8) = 0;
		*(ad+0x817 + i * 8) = 0;
	}
	*(ad+0x830) = 0xfe;
	*(ad+0x831) = 0;
	*(ad+0x832) = 0xfe;
	*(ad+0x833) = 0;
	*(ad+0x834) = 0xfe;
	*(ad+0x835) = 0;
	*(ad+0x836) = 0xfe;
	*(ad+0x837) = 0;
#endif

#if 0
	*(ad+0x80f) = 0;
	*(ad+0x807) = 0;
#endif
	*(ad+0x806) = 255 * volume / 100;
	/*
	 * 0: monaural, play left channel only.
	 * 1: stereo
	 */
	*(ad+0x802) = 2;

	/* clear ASC buffer */
	for (i = 0; i < 0x800; i++)
		*(ad+i) = 0;

	q1 = q2 = 0;

	while ((q1 != 1) || (q2 != 1)) {
		if (q1 != 1) {
			if ((c1 = read(fd1, bp1, BLEN)) == 0)
				q1 = 1;
			for (i = 0; i < c1; i++)
				*(ad+i) =
				*(ad+0x200+i) =
				*(bp1+i);
		}
		if (q2 != 1) {
			if ((c2 = read(fd2, bp2, BLEN)) == 0)
				q2 = 1;
			for (i = 0; i < c2; i++)
				*(ad+0x400+i) =
				*(ad+0x600+i) =
				*(bp2+i);
		}
		/*
		 * 1: sampled mode
		 * 2: four voice mode
		 */
		*(ad+0x801) = 1;
		usleep(5000);
	}
	*(ad+0x801) = 0; /* disable sound */
	return (0);
}

int
main(argc, argv)
	int argc;
	char *argv[];
{
	caddr_t ad;
	int fd;
	int fd1;
	int fd2;

	if (argc != 3) {
		fprintf(stderr, "usage: %s: <left> <right>\n");
		exit (1);
	}
	if ((fd1 = open(argv[1], O_RDONLY)) == (-1)) {
		fprintf(stderr, "can't open %s\n", argv[1]);
		exit (1);
	}
	if ((fd2 = open(argv[2], O_RDONLY)) == (-1)) {
		fprintf(stderr, "can't open %s\n", argv[2]);
		exit (1);
	}
	if ((fd = open("/dev/audio", O_RDWR)) == (-1)) {
		fprintf(stderr, "can't open /dev/audio\n");
		exit (1);
	}
	ad = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_FILE, fd, 0);
	if (ad == (caddr_t) (-1)) {
		printf("can't mmap fd %d\n", fd);
		exit (1);
	}
	close(fd);
	play(ad, fd1, fd2);
	munmap(ad, 0x1000);
	exit (0);
}