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