1 /*
2  * XBoing - An X11 blockout style computer game
3  *
4  * (c) Copyright 1993, 1994, 1995, Justin C. Kibell, All Rights Reserved
5  *
6  * The X Consortium, and any party obtaining a copy of these files from
7  * the X Consortium, directly or indirectly, is granted, free of charge, a
8  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
9  * nonexclusive right and license to deal in this software and
10  * documentation files (the "Software"), including without limitation the
11  * rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons who receive
13  * copies from any such party to do so.  This license includes without
14  * limitation a license to do the foregoing actions under any patents of
15  * the party supplying this software to the X Consortium.
16  *
17  * In no event shall the author be liable to any party for direct, indirect,
18  * special, incidental, or consequential damages arising out of the use of
19  * this software and its documentation, even if the author has been advised
20  * of the possibility of such damage.
21  *
22  * The author specifically disclaims any warranties, including, but not limited
23  * to, the implied warranties of merchantability and fitness for a particular
24  * purpose.  The software provided hereunder is on an "AS IS" basis, and the
25  * author has no obligation to provide maintenance, support, updates,
26  * enhancements, or modifications.
27  */
28 
29 /*
30  * =========================================================================
31  *
32  * $Id: BSDaudio.c,v 1.1.1.1 1994/12/16 01:36:57 jck Exp $
33  * $Source: /usr5/legends/jck/xb/master/xboing/audio/BSDaudio.c,v $
34  * $Revision: 1.1.1.1 $
35  * $Date: 1994/12/16 01:36:57 $
36  *
37  * $Log: BSDaudio.c,v $
38  * Revision 1.1.1.1  1994/12/16  01:36:57  jck
39  * The XBoing distribution requires configuration management. This is why the
40  * cvs utility is being used. This is the initial import of all source etc..
41  *
42  *
43  * =========================================================================
44  */
45 
46 /* SoundBlaster support for NetBSD */
47 
48 /*
49 ** Modified by Justin Kibell to suit xboing 30/09/93.
50 **
51 ** Copyright (C) 1993 by Jordan Hubbard
52 **
53 ** Ulaw code Copyright (C) 1989 by Jef Poskanzer.
54 **
55 ** Permission to use, copy, modify, and distribute this software and its
56 ** documentation for any purpose and without fee is hereby granted, provided
57 ** that the above copyright notice appear in all copies and that both that
58 ** copyright notice and this permission notice appear in supporting
59 ** documentation.  This software is provided "as is" without express or
60 ** implied warranty.
61 **
62 *
63 */
64 
65 /*
66  *  Include file dependencies:
67  */
68 
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <fcntl.h>
72 #include <sys/sblast.h>
73 
74 /*
75  *  Internal macro definitions:
76  */
77 
78 #define BSIZE	4096
79 
80 /*
81 ** This macro converts from ulaw to 16 bit linear, faster.
82 **
83 ** Jef Poskanzer
84 ** 23 October 1989
85 **
86 ** Input: 8 bit ulaw sample
87 ** Output: signed 16 bit linear sample
88 */
89 
90 #define ulaw_to_linear(ulawbyte) ulaw_table[ulawbyte]
91 
92 /* Define the magic number for audio files - just to check */
93 #define	SUN_AUDIO_MAGIC		((u_long)0x2e736e64)
94 
95 /*
96  *  Internal type declarations:
97  */
98 
99 /* What sun's .au format looks like */
100 struct _sun_audio
101 {
102 	u_long	magic;
103 	u_long	hdr_size;
104 	u_long	data_size;
105 	u_long	data_encoding;
106 	u_long	sample_rate;
107 	u_long	nchannels;
108 };
109 typedef struct _sun_audio Sun_audio_hdr;
110 
111 /*
112  *  Internal variable declarations:
113  */
114 
115 static int ulaw_table[256] =
116 {
117     -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
118     -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
119     -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
120     -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
121      -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
122      -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
123      -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
124      -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
125      -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
126      -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
127       -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
128       -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
129       -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
130       -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
131       -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
132        -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
133      32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
134      23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
135      15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
136      11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
137       7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
138       5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
139       3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
140       2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
141       1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
142       1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
143        876,    844,    812,    780,    748,    716,    684,    652,
144        620,    588,    556,    524,    492,    460,    428,    396,
145        372,    356,    340,    324,    308,    292,    276,    260,
146        244,    228,    212,    196,    180,    164,    148,    132,
147        120,    112,    104,     96,     88,     80,     72,     64,
148 		56,     48,     40,     32,     24,     16,      8,      0
149 };
150 
151 
152 /* The audio device */
153 int 	Audio_fd;
154 char	errorString[255];
155 
156 
157 /* Slurp in a .au file */
158 #if NeedFunctionPrototypes
read_audio_header(int fd,Sun_audio_hdr * buf)159 static int read_audio_header(int fd, Sun_audio_hdr *buf)
160 #else
161 static int read_audio_header(fd, buf)
162 	int fd;
163 	Sun_audio_hdr *buf;
164 #endif
165 {
166     read(fd, buf, sizeof(Sun_audio_hdr));
167 
168     buf->magic 			= ntohl(buf->magic);
169     buf->hdr_size 		= ntohl(buf->hdr_size);
170     buf->data_size 		= ntohl(buf->data_size);
171     buf->data_encoding 	= ntohl(buf->data_encoding);
172     buf->sample_rate 	= ntohl(buf->sample_rate);
173     buf->nchannels 		= ntohl(buf->nchannels);
174 
175     lseek(fd, buf->hdr_size, SEEK_SET);
176 
177     return buf->magic == SUN_AUDIO_MAGIC;
178 }
179 
180 #if NeedFunctionPrototypes
set_volume(int volume)181 static int set_volume(int volume)
182 #else
183 static int set_volume(volume)
184 	int volume;
185 #endif
186 {
187     static struct sb_mixer_levels save;	/* Saved mixer level settings */
188     struct sb_mixer_levels l;		/* New mixer level settings */
189     static int mixer = 0;
190 
191     if (!mixer)
192 	{
193 		mixer = open ("/dev/sb_mixer", O_RDWR, 0);
194 
195 		if (mixer < 0)
196 	    	perror ("open mixer");
197 		else if (ioctl (mixer, MIXER_IOCTL_READ_LEVELS, &save) < 0)
198 	    	perror ("mixer ioctl");
199     }
200     else if (mixer > 0)
201 	{
202 		/* Just change master volume */
203 		l.master.l = l.master.r = volume;
204 
205 		/* If bad volume, put it back */
206 		if (ioctl (mixer, MIXER_IOCTL_SET_LEVELS, &l) == -1)
207 	    	ioctl (mixer, MIXER_IOCTL_SET_LEVELS, &save);
208     }
209 
210     return 0;
211 }
212 
213 /* Send an ioctl to the DSP with error checking. */
214 #define IOCTL(cmd, arg) \
215     if (ioctl(Audio_fd, DSP_IOCTL_##cmd, arg) == -1) \
216         perror ("ioctl") \
217 
218 #if NeedFunctionPrototypes
SetUpAudioSystem(Display * display)219 int SetUpAudioSystem(Display *display)
220 #else
221 int SetUpAudioSystem(display)
222 	Display *display;
223 #endif
224 {
225     Audio_fd = open("/dev/sb_dsp", O_RDWR);
226     if (Audio_fd < 1)
227 	{
228 		/* Unable to open audio device so barf */
229         ErrorMessage("/dev/sb_dsp audio device is busy.");
230 		return False;
231     }
232 
233 	/* Audio device is open */
234     return True;
235 }
236 
237 #if NeedFunctionPrototypes
SetMaximumVolume(int Volume)238 void SetMaximumVolume(int Volume)
239 #else
240 void SetMaximumVolume(Volume)
241 	int Volume;
242 #endif
243 {
244     /* Set the maximum volume for the audio system */
245     set_volume(volume);
246 }
247 
248 #if NeedFunctionPrototypes
GetMaximumVolume(void)249 int GetMaximumVolume(void)
250 #else
251 int GetMaximumVolume()
252 #endif
253 {
254     /* Return the maximum volume as a % of 100 */
255     return 100;
256 }
257 
258 
259 #if NeedFunctionPrototypes
FreeAudioSystem(void)260 void FreeAudioSystem(void)
261 #else
262 void FreeAudioSystem()
263 #endif
264 {
265     /* Close the audio device thanks */
266     (void) close(Audio_fd);
267 }
268 
269 #if NeedFunctionPrototypes
playSoundFile(char * filename,int volume)270 void playSoundFile(char *filename, int volume)
271 #else
272 void playSoundFile(filename, volume)
273 	char *filename;
274 	int volume;
275 #endif
276 {
277     Sun_audio_hdr 	ahdr;
278     int 			fd;
279     unsigned char 	buf[BSIZE];
280     int 			i, len;
281     int 			zero = 0;
282     int 			one = 1;
283     char 			soundfile[FILENAME_MAX];
284     char 			*str;
285 
286     /* Set to the required volume */
287     set_volume(volume);
288 
289 	/* Construct the sounds file path and use env var if exists */
290     if ((str = getenv("XBOING_SOUND_DIR")) != NULL)
291     	sprintf(soundfile, "%s/%s.au", str, filename);
292     else
293         sprintf(soundfile, "%s/%s.au", SOUNDS_DIR, filename);
294 
295     /* Open the sound file for reading */
296     if ((fd = open(soundfile, O_RDONLY, 0)) < 0)
297     {
298         /* Issue an error about not opening sound file */
299         sprintf(errorString, "Unable to open sound file %s.", soundfile);
300         WarningMessage(errorString);
301         return;
302     }
303 
304     if (read_audio_header(fd, &ahdr) == 0)
305 	{
306         /* Cannot understand the sound file so close file and return */
307         sprintf(errorString, "Unable to play sound file %s.", soundfile);
308         WarningMessage(errorString);
309    		(void) close(fd); /* Close the sound file */
310 		return;
311 	}
312 
313     /* Set up the DSP, now that we know a little about sample */
314     if (ioctl(Audio_fd, DSP_IOCTL_STEREO,
315 		(ahdr.nchannels == 1) ? &zero : &one) == -1)
316 	{
317         /* Cannot set up the DSP */
318         WarningMessage("Unable to setup DSP stero setting.");
319    		(void) close(fd); /* Close the sound file */
320         return;
321 	}
322 
323     if (ioctl (Audio_fd, DSP_IOCTL_SPEED, &ahdr.sample_rate) == -1)
324 	{
325         /* Cannot set up the DSP */
326         WarningMessage("Unable to setup DSP speed setting.");
327    		(void) close(fd); /* Close the sound file */
328         return;
329 	}
330 
331     while ((len = read(fd, buf, BSIZE)) > 0)
332 	{
333 		/* Is it mulaw?  Else assume linear (usually mulaw so far) */
334 		if (ahdr.data_encoding == 1)
335 		{
336 			/* Convert data to linear format - ie: uncompress */
337 	    	for(i = 0; i < len; i++)
338 				buf[i] = (char) 128 + (ulaw_to_linear(buf[i]) / 256);
339 		}
340 
341 		/* Write the data to the DSP for the sound hopefully */
342 		if (len != write(Audio_fd, buf, len))
343 		{
344         	WarningMessage("Unable to write to DSP.");
345     		(void) close(fd); /* Close the sound file */
346 	    	return;
347 		}
348     }
349 
350     /* Close the sound file */
351     (void) close(fd);
352 }
353 
354 #if NeedFunctionPrototypes
audioDeviceEvents(void)355 void audioDeviceEvents(void)
356 #else
357 void audioDeviceEvents()
358 #endif
359 {
360 	/* None to do */
361 }
362 
363