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