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