rnd-20040821-4-src
[rocksndiamonds.git] / src / game_em / sound.c
1 /* 2000-08-10T17:39:15Z
2  *
3  * handle sounds in emerald mine
4  */
5
6 #include "../libgame/platform.h"
7
8
9 #if defined(TARGET_X11)
10
11 #if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD)
12
13 #ifdef PLATFORM_LINUX
14 #include <sys/soundcard.h>
15 #endif
16
17 #ifdef PLATFORM_BSD
18 #include <soundcard.h>
19 #endif
20
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/ioctl.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31
32 #include "global.h"
33 #include "sample.h"
34
35 static char audioname[] = "/dev/audio";
36
37 static const int sound_priority[SAMPLE_MAX] =
38 {
39   SAMPLE_exit, SAMPLE_die, SAMPLE_time, SAMPLE_boom, SAMPLE_tick,
40   SAMPLE_collect, SAMPLE_roll, SAMPLE_push, SAMPLE_dynamite, SAMPLE_press,
41   SAMPLE_door, SAMPLE_dirt, SAMPLE_blank, SAMPLE_android, SAMPLE_ball,
42   SAMPLE_grow, SAMPLE_squash, SAMPLE_crack, SAMPLE_slurp, SAMPLE_drip,
43   SAMPLE_wonder, SAMPLE_wheel, SAMPLE_stone, SAMPLE_spring, SAMPLE_diamond,
44   SAMPLE_nut, SAMPLE_bug, SAMPLE_tank, SAMPLE_eater, SAMPLE_alien,
45   SAMPLE_acid
46 };
47
48 int sound_thread(void)
49 {
50   int audio_fd; /* file descriptor of /dev/audio or -1 if not open */
51   int audio_format;
52   int sample_rate;
53   int fragment_size;
54   unsigned char *audio_buffer; /* actual buffer pumped to /dev/audio */
55   short *mix_buffer;
56
57   char sound_play[SAMPLE_MAX]; /* if set, we should be playing these sounds */
58   long sound_pos[SAMPLE_MAX]; /* position in the sound */
59   int mix_play[MIXER_MAX]; /* which sounds we have chosen to mix (calculated each time) */
60   int mix_count;
61   int i;
62
63  loop:
64
65   audio_fd = -1;
66   audio_format = AUDIO_ULAW; /* defaults for non-OSS /dev/audio */
67   sample_rate = 8000;
68   fragment_size = 256;
69   audio_buffer = 0;
70   mix_buffer = 0;
71   mix_count = 0;
72
73   memset(sound_play, 0, sizeof(sound_play)); /* not playing any sounds */
74
75   for (;;)
76   {
77     for (;;)
78     {
79
80       /* pick sounds to play, if any */
81       if (sound_play[SAMPLE_exit] || sound_play[SAMPLE_die])
82         sound_play[SAMPLE_boom] = 0; /* no explosions if player goes home */
83
84       mix_count = 0;
85       for (i = 0; i < SAMPLE_MAX; i++)
86       {
87         if (sound_play[sound_priority[i]])
88         {
89           mix_play[mix_count++] = sound_priority[i];
90
91           if (mix_count == MIXER_MAX)
92             break; /* cant mix too many sounds at once */
93         }
94       }
95
96       /* check for incoming messages */
97       if (mix_count || audio_fd != -1)
98       {
99         /* dont block if we are playing sounds */
100         fd_set rfds;
101         struct timeval tv;
102         FD_ZERO(&rfds);
103         FD_SET(sound_pipe[0], &rfds);
104         tv.tv_sec = 0;
105         tv.tv_usec = 0; /* (900000 * fragment_size / sample_rate) */
106         i = select(sound_pipe[0] + 1, &rfds, 0, 0, &tv); /* dont block */
107
108         if (i == -1)
109         {
110           fprintf(stderr, "%s: %s: %s\n", progname, "select failed",
111                   strerror(errno));
112           goto fail;
113         }
114
115         if (i == 0)
116           break; /* no messages */
117       }
118
119       /* get a message and start a sound */
120       i = read(sound_pipe[0], &play, sizeof(play));
121
122       if (i == -1)
123       {
124         fprintf(stderr, "%s: %s: %s\n", progname, "read failed",
125                 strerror(errno));
126         goto fail;
127       }
128
129       if (i == 0)
130       {
131         fprintf(stderr, "%s: %s: %s\n", progname, "read sound", "Broken pipe");
132         goto fail;
133       }
134
135       if (i != sizeof(play))
136       {
137         fprintf(stderr, "%s: %s\n", progname, "bad message length");
138         goto fail;
139       }
140
141       for (i = 0; i < SAMPLE_MAX; i++)
142       {
143         if (play[i])
144         {
145           sound_play[i] = 1; /* play this sound */
146           sound_pos[i] = 0; /* start it from the start */
147         }
148       }
149     }
150
151     /* open the audio device if there are sounds to play */
152     if (mix_count && audio_fd == -1)
153     {
154       audio_fd = open(audioname, O_WRONLY);
155
156       if (audio_fd == -1)
157         goto reset;
158
159 #ifdef OPEN_SOUND_SYSTEM
160       i = 0x00020008;
161
162       if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i) == -1)
163       {
164         fprintf(stderr, "%s: \"%s\": %s (%d): %s\n", progname, audioname,
165                 "unable to set fragment size", 512, strerror(errno));
166         goto reset;
167       }
168
169       if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i) == -1)
170       {
171         fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname,
172                 "unable to query audio format", strerror(errno));
173         goto reset;
174       }
175
176       /* prefer 8 bit unsigned and fall back on mu-law */
177       audio_format = (i & AFMT_U8) ? AFMT_U8 : AFMT_MU_LAW;
178
179       i = audio_format;
180       if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &i) == -1)
181       {
182         fprintf(stderr, "%s: \"%s\": %s (%d): %s\n", progname, audioname,
183                 "unable to set audio format", audio_format, strerror(errno));
184         goto reset;
185       }
186
187       if (i == AFMT_MU_LAW)
188       {
189         audio_format = AUDIO_ULAW;
190       }
191       else if (i == AFMT_U8)
192       {
193         audio_format = AUDIO_U8;
194       }
195       else
196       {
197         fprintf(stderr, "%s: \"%s\": %s (%d)\n", progname, audioname,
198                 "audio format required by device not supported", i);
199         goto reset;
200       }
201
202       i = 1;
203       if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &i) == -1)
204       {
205         fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname,
206                 "unable to set channels to mono", strerror(errno));
207         goto reset;
208       }
209
210       if (i != 1)
211       {
212         fprintf(stderr, "%s: \"%s\": %s (%d)\n", progname, audioname,
213                 "channels required by device not supported", i);
214         goto reset;
215       }
216
217       i = 8000;
218       if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &i) == -1)
219       {
220         fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname,
221                 "unable to set sampling rate", strerror(errno));
222         goto reset;
223       }
224
225       sample_rate = i;
226       if (ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &i) == -1)
227       {
228         fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname,
229                 "unable to get block size", strerror(errno));
230         goto reset;
231       }
232
233       fragment_size = i;
234
235 #else
236       if (fcntl(audio_fd, F_SETFL, O_NONBLOCK) == -1)
237       {
238         fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname,
239                 "unable to make audio non blocking", strerror(errno));
240         goto reset;
241       }
242
243 #endif /* OPEN_SOUND_SYSTEM */
244
245       audio_buffer = malloc(fragment_size * sizeof(*audio_buffer));
246       if (audio_buffer == 0)
247       {
248         fprintf(stderr, "%s: %s (%d): %s\n", progname,
249                 "unable to malloc audio buffer",
250                 fragment_size * sizeof(*audio_buffer), strerror(errno));
251         goto fail;
252       }
253
254       mix_buffer = malloc(fragment_size * sizeof(*mix_buffer));
255       if (mix_buffer == 0)
256       {
257         fprintf(stderr, "%s: %s (%d): %s\n", progname,
258                 "unable to malloc mixing buffer",
259                 fragment_size * sizeof(*mix_buffer), strerror(errno));
260         goto fail;
261       }
262     }
263
264     /* close the audio device if no sounds are playing */
265     if (mix_count == 0 && audio_fd != -1)
266     {
267       close(audio_fd);
268       free(audio_buffer);
269       free(mix_buffer);
270       audio_fd = -1;
271       audio_buffer = 0;
272       mix_buffer = 0;
273     }
274
275     /* if we are playing sounds and the audio device is open, mix them */
276     if (mix_count && audio_fd != -1)
277     {
278       /* prepare mix buffer */
279       memset(mix_buffer, 0, fragment_size * sizeof(*mix_buffer));
280
281       for (i = 0; i < mix_count; i++)
282       {
283         register short *mix_ptr = mix_buffer;
284         register short *sound_ptr =
285           sound_data[mix_play[i]] + sound_pos[mix_play[i]];
286         register long count =
287           sound_length[mix_play[i]] - sound_pos[mix_play[i]];
288
289         if (count > fragment_size)
290           count = fragment_size;
291
292         while (count--)
293           *mix_ptr++ += *sound_ptr++; /* mix the sounds in */
294       }
295
296       switch(audio_format)
297       {
298         case AUDIO_ULAW:
299           for (i = 0; i < fragment_size; i++)
300             audio_buffer[i] = linear_to_ulaw[mix_buffer[i] + 32768];
301           break;
302
303         case AUDIO_U8:
304           for (i = 0; i < fragment_size; i++)
305             audio_buffer[i] = (mix_buffer[i] + 32768) >> 8;
306           break;
307       }
308
309       /* advance sound pointers */
310       for (i = 0; i < SAMPLE_MAX; i++)
311       {
312         if (sound_play[i])
313         {
314           if (sound_pos[i] + fragment_size < sound_length[i])
315           {
316             sound_pos[i] += fragment_size;
317           }
318           else
319           {
320             sound_play[i] = 0;
321           }
322         }
323       }
324
325       /* send the data to the audio device */
326       i = write(audio_fd, audio_buffer, fragment_size);
327       if (i == -1)
328       {
329         fprintf(stderr, "%s: %s: %s\n", progname, "write error",
330                 strerror(errno));
331         goto reset;
332       }
333
334       if (i != fragment_size)
335       {
336         fprintf(stderr, "%s: %s\n", progname, "bad write length");
337         goto reset;
338       }
339     }
340   } /* for */
341
342  reset:
343
344   if (audio_fd != -1)
345     close(audio_fd);
346   if (audio_buffer)
347     free(audio_buffer);
348   if (mix_buffer)
349     free(mix_buffer);
350   goto loop; /* back to top */
351
352  fail:
353   if (audio_fd != -1)
354     close(audio_fd);
355   if (audio_buffer)
356     free(audio_buffer);
357   if (mix_buffer)
358     free(mix_buffer);
359
360   return(0);
361 }
362
363 int read_sample(char *name, short **data, long *length)
364 {
365   int result;
366   FILE *file = 0;
367   short *dataptr = 0;
368   long datalength;
369
370   int i, actual, ch;
371   unsigned char buffer[24];
372   unsigned long temp;
373
374   file = fopen(name, "rb");
375   if (file == 0)
376   {
377     fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, name, "open error",
378             strerror(errno));
379     result = 1;
380     goto fail;
381   }
382
383   actual = fread(buffer, 1, 24, file);
384   if (actual == -1)
385   {
386     fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, name, "read error",
387             strerror(errno));
388     result = 1;
389     goto fail;
390   }
391
392   if (actual < 24)
393   {
394     fprintf(stderr, "%s: \"%s\": %s\n", progname, name, "premature eof");
395     result = 1;
396     goto fail;
397   }
398
399   /* magic */
400   temp = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
401   if (temp != 0x2e736e64)
402   {
403     fprintf(stderr, "%s: \"%s\": %s\n", progname, name,
404             "unrecognized file format");
405     result = 1;
406     goto fail;
407   }
408
409   /* header length */
410   temp = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
411   if (temp < 24)
412   {
413     fprintf(stderr, "%s: \"%s\": %s\n", progname, name, "bad header length");
414     result = 1;
415     goto fail;
416   }
417
418   actual = temp;
419   for (i = 24; i < actual; i++)
420   {
421     /* skip the rest of the header */
422     ch = fgetc(file);
423     if (ch == EOF)
424       break;
425   }
426
427  /* data length */
428   temp = buffer[8] << 24 | buffer[9] << 16 | buffer[10] << 8 | buffer[11];
429   datalength = temp;
430
431   /* encoding */
432   temp = buffer[12] << 24 | buffer[13] << 16 | buffer[14] << 8 | buffer[15];
433   if (temp != 1)
434   {
435     fprintf(stderr, "%s: \"%s\": %s (%ld != 1)\n", progname, name,
436             "bad encoding type", temp);
437     result = 1;
438     goto fail;
439   }
440
441   /* sample rate */
442   temp = buffer[16] << 24 | buffer[17] << 16 | buffer[18] << 8 | buffer[19];
443   if (temp != 8000)
444   {
445     fprintf(stderr, "%s: \"%s\": %s (%ld != 8000)\n", progname, name,
446             "bad sample rate", temp);
447     result = 1;
448     goto fail;
449   }
450
451   /* channels */
452   temp = buffer[20] << 24 | buffer[21] << 16 | buffer[22] << 8 | buffer[23];
453   if (temp != 1)
454   {
455     fprintf(stderr, "%s: \"%s\": %s (%ld != 1)\n", progname, name,
456             "unsupported channels", temp);
457     result = 1;
458     goto fail;
459   }
460
461   dataptr = malloc(datalength * sizeof(*dataptr));
462   if (dataptr == 0)
463   {
464     fprintf(stderr, "%s: \"%s\": %s (%ld): %s\n", progname, name,
465             "unable to malloc buffer", datalength * sizeof(*dataptr),
466             strerror(errno));
467     result = 1;
468     goto fail;
469   }
470
471   for (i = 0; i < datalength; i++)
472   {
473     ch = fgetc(file);
474     if (ch == EOF) break;
475     dataptr[i] = ulaw_to_linear[ch];
476   }
477
478   fclose(file);
479   file = 0;
480
481   *data = dataptr;
482   *length = datalength;
483   result = 0;
484
485  fail:
486
487   if (file)
488     fclose(file);
489
490   return(result);
491 }
492
493 #endif /* defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) */
494
495 #endif