Subject: another sound survey...
To: port-mac68k Mailing List <port-mac68k@NetBSD.ORG>
From: Colin Wood <cwood@ichips.intel.com>
List: port-mac68k
Date: 05/07/1998 00:50:13
Hello everyone!

In the past few days, I've made some progress on getting sound out of my
IIci's ASC and my Q700's EASC.  Thanks to some discussion with SUNAGAWA
Keiki <kei_sun@ba2.so-net.or.jp>, I was able to figure out why my machines
were producing only noise.  It turned out that the file I was trying to
play was a 16-bit sample.  The E/ASC only understands 8-bit samples (or at
least I haven't found some kind of direct 16-bit mode yet).  After
converting the sample to an 8-bit mono raw sound file, it played perfectly
:-)  There is still quite a bit of work to be done, since most other sound
files I play tend to cough quite a bit (it may be a question of the
sampling rate, but I'm not sure).  So, things are coming along.  Perhaps a
working /dev/audio isn't quite the dream I was beginning to think that it
was.

Anyway, the real reason for this message is that I've managed to implement
EASC square-wave sound somewhat reliably.  Fortunately, it also works on
the ASC.  Currently I have a userland program that will "beep"
appropriately for me.  I should have the necessary kernel level routines
done in a few days.  What this means is that all machines with either ASC
or EASC hardware _should_ be able to beep before too much longer.  The
fact that my Q700 only clicks has long annoyed me, and tonight for the
first time the terminal bell actually rang :-)  There are still a few bugs
to be worked out, however (the silly thing gets stuck on at times...not
very pretty).  Once I've gotten that finished, I'll submit a patch to add
the support to -current.

Now for the survey part.  I'm including a copy of the source for my
beeping program below.  I guess that it's really a square-wave tone
generator.  Once you've compiled it (assuming "gcc -o beep beep.c"), you
invoke it like so:

beep [frequency [volume [duration]]]

where the arguments are optional but must occur in the above order (sorry,
I'm too lazy to add real parsing).  The frequency should a MIDI note
value, I think (I couldn't identify one if I had to).  If not, higher
numbers (like 3000) are lower frequency, and vice-versa.  I guess
that really makes it the period, not the frequency....  Volumes range 
from 0 to 255; higher values should wrap.  The duration is technically in
60th's of a second.  The default values are those used in ite.c for the
console bell:

	frequency	1880
	volume		100
	duration	10

Personally, I find these defaults not all that nice (the tone generated in
this way doesn't sound like the current code's beep on my IIci).  I think
that 470,100,5 sounds better.  So, for part of this survey, I'd like to
know what y'all think makes a good set of values.  For the other (and
probably more important) part of this survey, please let me know if this
_does not_ work on your sound hardware.  I expect this to work on all
Mac's except for the AV Quadras.  If it should happen to work on these
machines, please let me know.  BTW, by "work", I mean that it should
produce clear, recognizable tones when run.  It shouldn't cough or stutter
unless you have a lot of interrupt activity (like a disk sync) going on.
Please let me know if you don't hear nice sounds at least in the range of
1-3000 or so.

I eagerly await your feedback.  

Have fun!

Colin Wood                                 cwood@ichips.intel.com
Component Design Engineer - PMD                 Intel Corporation
-----------------------------------------------------------------
I speak only on my own behalf, not for my employer.


beep.c
===============================cut here==================================

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

/*
 * produce a square-wave tone of the given frequency, loudness,
 * and duration
 */
void 
dobeep(char *ASCBase, int count, int amplitude, int duration)
{
	int     i;
	int     temp = 0;
	int     up, down;
	int     phase = 0;

	temp = 0x11999999 / count;

	up = 0x80 + (amplitude >> 1);
	down = 0x80 - (amplitude >> 1);

	count = temp;

	for (i = 1; i < 740; i += 2) {
		ASCBase[i] = amplitude;
	}

	ASCBase[0x806] = 4 << 5;

	if (ASCBase[0x801] != 0x01) {
		ASCBase[0x807] = 0x00;
		ASCBase[0x802] = 0x00;
		ASCBase[0x801] = 0x01;
		ASCBase[0x803] |= 0x80;
		ASCBase[0x803] &= 0x7F;
	}
	while (duration--) {
		temp = 370;
		if (phase == 0) {
			temp = 498;
		}
		for (i = 0; i <= temp; i++) {
			phase += count;
			if (phase & 0x00800000) {
				ASCBase[0] = down;
			} else {
				ASCBase[0] = up;
			}
		}
		usleep(16666);	/* 1/60th of a second */
	}
	ASCBase[0x801] = 0x00;

	return;
}

int 
main(int argc, char *argv[])
{
	int     asc;
	int     prot;
	int     flags;
	int     count, amplitude, duration;
	size_t  length;
	off_t   offset;
	int     error;
	char   *ascpath = "/dev/asc0";
	char   *ASCBase;

	/* ite.c defaults */
	count = 1880;
	amplitude = 100;
	duration = 10;

	switch (argc) {
	case 4:
		duration = atoi(argv[3]);
	case 3:
		amplitude = atoi(argv[2]);
	case 2:
		count = atoi(argv[1]);
	default:
		break;
	}

	asc = open(ascpath, O_RDWR | O_NONBLOCK, 0777);
	if (asc < 0) {
		perror("sndctl");
		exit(-1);
	}
	prot = PROT_READ | PROT_WRITE;
	flags = MAP_FILE;
	length = 0x01000;
	offset = 0;
	ASCBase = mmap((void *) 0, length, prot, flags, asc, offset);

	if (ASCBase < 0) {
		perror("sndctl");
		exit(-1);
	}
	dobeep(ASCBase, count, amplitude, duration);

	error = munmap(ASCBase, length);

	if (error) {
		perror("sndctl: /dev/asc0");
		exit(-2);
	}
	error = close(asc);
	if (error) {
		perror("sndctl: /dev/asc0");
		exit(-2);
	}
	return (0);
}