1 /*
2  * koules.sndsrv.sgi.c - SGI Indigo/Indigo^2/Indy Sound Driver
3  *
4  * Copyright (c) 1996 Rick Sayre (whorfin@pixar.com)
5  *	Based on the various existing PC sound drivers.
6  *
7  *    Permission to use, copy, modify, and distribute this
8  *   software and its documentation for any purpose and without
9  *   fee is hereby granted, provided that the above copyright
10  *   notice appear in all copies and that both that copyright
11  *   notice and this permission notice appear in supporting
12  *   documentation.  No representations are made about the
13  *   suitability of this software for any purpose.  It is
14  *   provided "as is" without express or implied warranty.
15  */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <signal.h>
22 #include <audio.h>
23 
24 #define FREQUENCY	8000
25 #define FRAGSIZE	510	/* 1/16 second: XXX 500 causes 6.2 crash! */
26 
27 char *FILENAME[] = {
28   "/start.raw",
29   "/end.raw",
30   "/colize.raw",
31   "/destroy1.raw",
32   "/destroy2.raw",
33   "/creator1.raw",
34   "/creator2.raw",
35                    };
36 
37 #define NUM_SOUNDS	(sizeof(FILENAME)/sizeof(char*))
38 
39 signed char *sound_buffer[NUM_SOUNDS];
40 
41 int sound_size[NUM_SOUNDS];
42 
43 
44 /* Terminate: Signal Handler */
45 static void
quit()46 quit()
47 {
48     exit(0);
49 }
50 
51 
52 
53 static void
init(int argc,char ** argv)54 init(int argc, char **argv)
55 {
56     int             i;
57     char            s[1024];
58 
59     if (argc != 3) {
60 	printf("This program is only executed by koules\n");
61 	exit(1);
62     }
63     for (i = 0; i < NUM_SOUNDS; i++) {
64 	s[0] = 0;
65 	strcat(s, argv[1]);
66 	if (s[(int) strlen(s) - 1] == '/')
67 	    FILENAME[i]++;
68 	strcat(s, FILENAME[i]);
69 	FILENAME[i] = malloc((int) strlen(s));
70 	strcpy(FILENAME[i], s);
71 	sound_buffer[i] = NULL;
72 	sound_size[i] = 0;
73     }
74 
75     signal(SIGTERM, quit);	/* Setup Terminate Signal Handler */
76 }
77 
78 
79 
80 static ALport
setup_dsp(char * dspdev)81 setup_dsp(char *dspdev)
82 {
83     ALport          writePort;
84     ALconfig        writeConfig;
85 
86     static long     audioParams[2] = {
87 	AL_OUTPUT_RATE, FREQUENCY
88     };
89 
90     writeConfig = ALnewconfig();
91     ALsetqueuesize(writeConfig, FRAGSIZE);
92     ALsetchannels(writeConfig, AL_MONO);
93     ALsetparams(AL_DEFAULT_DEVICE, audioParams, 2);
94     ALsetwidth(writeConfig, AL_SAMPLE_8);
95 
96     if (!(writePort = ALopenport("koules.sndsrv", "w", writeConfig))) {
97 	fprintf(stderr, "koules.sndsrv.sgi:  Couldn't open audio port\n");
98 	return(NULL);
99     }
100 
101     return writePort;
102 }
103 
104 /*
105    This just keeps the pipe from breaking...
106    Eventually I'll look at the koules signal handlers and
107    just trap this.
108 */
109 static void
do_nothing(void)110 do_nothing(void)
111 {
112     fprintf(stderr, "koules.sndsrv: doing nothing, something is broken\n");
113     while (1)
114 	sleep(5);
115 }
116 
117 static int
read_sound(int k)118 read_sound(int k)
119 {
120     int             i, fd, size;
121 
122 #ifdef DEBUG
123     fprintf(stderr, "loading sound %d, %s\n", k, FILENAME[k]);
124 #endif
125 
126     fd = open(FILENAME[k], O_RDONLY);
127     if (fd <= 0) {
128 	fprintf(stderr, "koules.sndsrv: The sound %s could not be opened\n", FILENAME[k]);
129 	sound_size[k] = -1;
130 	return (0);
131     }
132     size = lseek(fd, 0, SEEK_END);
133     sound_size[k] = (size / FRAGSIZE) + 1;	/* size in fragments */
134     sound_buffer[k] = malloc(sound_size[k] * FRAGSIZE);
135     if (sound_buffer[k] == NULL) {
136 	fprintf(stderr, "koules.sndsrv: couldn't malloc memory for sound\n");
137 	sound_size[k] = -1;
138 	close(fd);
139 	return (0);
140     }
141     lseek(fd, 0, SEEK_SET);
142     read(fd, sound_buffer[k], size);
143     close(fd);
144 
145     /* data is unsigned; convert to signed */
146     for (i = 0; i < size; i++)
147 	sound_buffer[k][i] ^= 0x80;
148     bzero(sound_buffer[k] + size, sound_size[k] * FRAGSIZE - size);
149 
150 #ifdef DEBUG
151     fprintf(stderr, "sound has been loaded, %d bytes\n", size);
152 #endif
153     return (1);
154 }
155 
156 
157 static void
do_everything(ALport writePort)158 do_everything(ALport writePort)
159 {
160     signed char     k;
161     int             i, j;
162     int             terminate = -1;	/* Which Sound to Terminate */
163     int             playing[16];/* Sound numbers that we are playing */
164     int             position[16];	/* Current position in each sound
165 					 * file */
166     int             playnum = 0;/* Number of sounds currently being played */
167     signed char   final[512];	/* Final Mixing Buffer */
168     int             premix[512];
169     signed char    *sample;
170 
171     for (;;) {
172 	terminate = -1;
173 
174 	/* Try to open a new sound if we get an integer on the 'in' pipe */
175 	i = read(STDIN_FILENO, &k, sizeof(k));
176 	if (i == 0) {		/* EOF on pipe means parent has closed its end*/
177 #ifdef DEBUG
178 	    fprintf(stderr,"koules.sndsrv: shutting down\n");
179 #endif
180 	    kill(getpid(), SIGTERM);
181 	}
182 	if (i != -1) {		/* there was something in the pipe */
183 #ifdef DEBUG
184 	     fprintf(stderr,"Just read a %d from pipe\n",(int)k);
185 #endif
186 	    /* Negative means terminate the FIRST sound in the buffer */
187 	    if (k < 0) {
188 #ifdef DEBUG
189 		fprintf(stderr,"terminating sound\n");
190 #endif
191 		terminate = 0;
192 	    } else {
193 		if (sound_size[(int) k] == 0)
194 		    read_sound(k);
195 		if (sound_size[(int) k] > 0 && playnum < 16) {
196 		    position[playnum] = 0;
197 		    playing[playnum++] = k;
198 #ifdef DEBUG
199 		    fprintf(stderr,"sound %d added to play queue\n",playnum-1);
200 #endif
201 		}
202 	    }
203 	}
204 
205 	/* terminate a sound if necessary */
206 	for (i = 0; i < playnum; i++) {
207 	    if ((position[i] == sound_size[playing[i]]) || (terminate == i)) {
208 #ifdef DEBUG
209 		 fprintf(stderr,"finished playing sound %d\n",i);
210 		 fprintf(stderr,"is was at position %d\n",position[i]);
211 #endif
212 		bcopy(playing + i + 1, playing + i, (playnum - i) * sizeof(int));
213 		bcopy(position + i + 1, position + i, (playnum - i) * sizeof(int));
214 		playnum--;
215 		i--;
216 	    }
217 	}
218 
219 	if (playnum) {
220 	    /* Mix each sound into the final buffer */
221 	    bzero(premix, sizeof(premix));
222 	    for (i = 0; i < playnum; i++) {
223 		sample = sound_buffer[playing[i]] + position[i] * FRAGSIZE;
224 		for (j = 0; j < FRAGSIZE; j++) {
225 		    premix[j] += *(sample + j);
226 		}
227 		position[i]++;
228 	    }
229 	    /* clamp premix */
230 	    for (i = 0; i < FRAGSIZE; i++)
231 		final[i] = (premix[i] > 127) ? 127 : (premix[i] < -128 ? -128 : premix[i]);
232 	} else {
233 	    /*
234 	     * We have no sounds to play Just fill the buffer with silence
235 	     * and maybe play it
236 	     */
237 	    bzero(final, sizeof(final));
238 	}
239 	ALwritesamps(writePort, final, FRAGSIZE);
240 
241     }
242 }
243 
244 
245 
246 void
main(int argc,char ** argv)247 main(int argc, char **argv)
248 {
249     ALport          writePort;
250 
251     fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
252     init(argc, argv);
253 
254     if (!(writePort = setup_dsp(argv[2])))
255 	do_nothing();
256 
257     do_everything(writePort);
258 }
259