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