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