$NetBSD: patch-ag,v 1.3 2000/10/18 11:22:44 rh Exp $

--- ../audioIO_NetBSD.c.orig	Tue Oct 17 17:50:54 2000
+++ ../audioIO_NetBSD.c	Tue Oct 17 20:01:20 2000
@@ -0,0 +1,240 @@
+/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
+
+	Origional code by: tomislav uzelac
+	Modified by:
+	* Dan Nelson - BSD mods.
+	* Andrew Richards - moved code from audio.c and added mixer support etc
+        * Brett Lymn - NetBSD support & 8bit mode.
+	* Rui-Xiang Guo - NetBSD native API support.
+ */
+
+/* Support for NetBSD sound devices */
+
+#include "amp.h"
+#include "audioIO.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/audioio.h>
+#include <sys/param.h>
+#include <sys/filio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+/* optimal fragment size - if this is set too high you will get clicks
+ * in the audio output, below is near the upper limit for the sb sound driver
+ * on my machine (Toshiba 400CDT laptop).
+ */
+
+int AUSIZ = 20480;
+
+/* declare these static to effectively isolate the audio device */
+
+static int audio_fd;
+static int mixer_fd;
+
+static char *reduce;
+
+/* audioOpen() */
+/* should open the audio device, perform any special initialization */
+/* Set the frequency, no of channels and volume. Volume is only set if */
+/* it is not -1 */
+
+void
+audioOpen(int frequency, int stereo, int volume)
+{
+        audio_info_t audio_dev;
+
+	if ((audio_fd = open ("/dev/audio", O_WRONLY, 0)) == -1)
+		die("Unable to open the audio device\n");
+	DB(audio, msg("Audio device opened on %d\n", audio_fd));
+
+	ioctl(audio_fd, AUDIO_GETINFO, &audio_dev); /* get current settings */
+        AUDIO_INITINFO(&audio_dev);
+        
+	/* Set 1 or 2 channels */
+        audio_dev.play.channels = (stereo ? 2 : 1);
+
+	/* Set the output frequency */
+	DB(audio, msg("Setting freq to %d Hz\n", frequency));
+        audio_dev.play.sample_rate = frequency;
+
+	if (volume != -1)
+		audioSetVolume(volume);
+
+        audio_dev.blocksize = AUSIZ;
+        audio_dev.play.encoding = AUDIO_ENCODING_SLINEAR;
+        audio_dev.hiwat = 20;
+        audio_dev.lowat = 1;
+        audio_dev.mode = AUMODE_PLAY;
+
+        if (ioctl(audio_fd, AUDIO_SETINFO, &audio_dev) < 0)
+                die("AUDIO_SETINFO failed\n");
+
+	  /* ok - try running the sound system at 16 bits, if that does not
+	   *  work then try 8 bits, if that does not work, give up.
+	   */
+	reduce = NULL;
+        audio_dev.play.precision = 16;
+        if (ioctl(audio_fd, AUDIO_SETINFO, &audio_dev) < 0) {
+                DB(audio,
+		   msg("AUDIO_SETINFO for 16 bits failed, try 8 bits\n"));
+		if ((reduce = (char *) malloc(AUSIZ * sizeof(char))) == NULL)
+			die("Cannot malloc reduce buffer\n");
+		audio_dev.play.precision = 8;
+	        if (ioctl(audio_fd, AUDIO_SETINFO, &audio_dev) < 0)
+			die("AUDIO_SETINFO failed both 16bit and 8bit\n");
+		AUSIZ = AUSIZ * sizeof(short);
+	}
+}
+
+
+/* audioSetVolume - only code this if your system can change the volume while playing */
+/* sets the output volume 0-100 */
+
+int device_id = 3;
+char *mixer_device;
+mixer_ctrl_t *values;
+mixer_devinfo_t *infos;
+
+void
+audioSetMixer()
+{
+	int i, ndev;
+	mixer_devinfo_t dinfo;
+
+	mixer_device = getenv("MIXERDEVICE");
+	if (mixer_device == NULL)
+		mixer_device = "/dev/mixer0";
+
+	if ((mixer_fd = open(mixer_device, O_RDWR)) < 0)
+		warn("Unable to open mixer device\n");
+	DB(audio, msg("Mixer device opened on %d\n", mixer_fd));
+
+	for (ndev = 0; ; ndev++) {
+		dinfo.index = ndev;
+		if (ioctl(mixer_fd, AUDIO_MIXER_DEVINFO, &dinfo) < 0)
+			break;
+	}
+	infos = calloc(ndev, sizeof *infos);
+	values = calloc(ndev, sizeof *values);
+
+	for (i = 0; i < ndev; i++) {
+		infos[i].index = i;
+		ioctl(mixer_fd, AUDIO_MIXER_DEVINFO, &infos[i]);
+	}
+
+	for (i = 0; i < ndev; i++) {
+		if (infos[i].type == AUDIO_MIXER_VALUE) {
+			values[i].dev = i;
+			values[i].type = infos[i].type;
+		}
+	}
+
+	values[device_id].un.value.num_channels = 2;
+}
+
+void
+audioSetVolume(int volume)
+{
+	mixer_ctrl_t *m;
+
+	DB(audio, msg("Setting volume to: %d\n", volume));
+	m = &values[device_id];
+
+	if (ioctl(mixer_fd, AUDIO_MIXER_WRITE, m) < 0)
+		warn("Unable to set sound volume\n");
+
+	m->un.value.level[0] = m->un.value.level[1] = volume * AUDIO_MAX_GAIN / 100;
+}
+
+void
+audioSetBalance(int volume, int balance)
+{
+	mixer_ctrl_t *m;
+
+	DB(audio, msg("Setting volume to: %d\n", volume));
+	DB(audio, msg("Setting balance to: %d\n", balance));
+	m = &values[device_id];
+
+	if (ioctl(mixer_fd, AUDIO_MIXER_WRITE, m) < 0)
+		warn("Unable to set sound volume\n");
+
+	if (balance < 0) {
+		m->un.value.level[0] = volume * AUDIO_MAX_GAIN / 100;
+		m->un.value.level[1] = m->un.value.level[0] * (20 + balance) / 20;
+	}
+	else {
+		m->un.value.level[1] = volume * AUDIO_MAX_GAIN / 100;
+		m->un.value.level[0] = m->un.value.level[1] * (20 - balance) / 20;
+	}
+}
+
+/* audioFlush() */
+/* should flush the audio device */
+
+inline void
+audioFlush()
+{
+	DB(audio, msg("audio: flush %d\n", audio_fd));
+}
+
+
+/* audioClose() */
+/* should close the audio device and perform any special shutdown */
+
+void
+audioClose()
+{
+	close(audio_fd);
+	if (mixer_fd != -1)
+		close(mixer_fd);
+	DB(audio, msg("audio: closed %d\n", audio_fd));
+}
+
+/* audioWrite */
+/* writes count bytes from buffer to the audio device */
+/* returns the number of bytes actually written */
+
+inline int
+audioWrite(char *buffer, int count)
+{
+        int i;
+        short *cast;
+        
+	DB(audio, msg("audio: Writing %d bytes to audio descriptor %d\n",count,
+		      getAudioFd()));
+
+	  /* if the reduce buffer is allocated we need to do 8bit writes
+	   * so munge the data buffer appropriately.
+	   */
+	if (reduce != NULL) {
+		cast = (short *) buffer;
+        
+		for (i=0; i < count/sizeof(short); i++) {
+			reduce[i] = cast[i] >> 8;
+		}
+		return (sizeof(short) * write(audio_fd, reduce,
+					      count/sizeof(short)));
+	} else {
+		return (write(audio_fd,buffer,count));
+	}
+}
+
+/* Let buffer.c have the audio descriptor so it can select on it. This means	*/
+/* that the program is dependent on a file descriptor to work. Should really */
+/* move the select's etc (with inlines of course) in here so that this is the */
+/* ONLY file which has hardware dependent audio stuff in it										*/
+
+int
+getAudioFd()
+{
+	return (audio_fd);
+}
