$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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +}