52fdcbfb7357d1d8d5964129fec64a35e13436dc
[rocksndiamonds.git] / src / libgame / sound.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * sound.c                                                  *
12 ***********************************************************/
13
14 #include <string.h>
15 #include <sys/time.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <dirent.h>
19 #include <signal.h>
20
21 #include "system.h"
22 #include "sound.h"
23 #include "misc.h"
24 #include "setup.h"
25
26
27 static int num_sounds = 0, num_music = 0;
28 static struct SampleInfo *Sound = NULL;
29 #if defined(TARGET_SDL)
30 static int num_mods = 0;
31 static struct SampleInfo *Mod = NULL;
32 #endif
33
34
35 /* ========================================================================= */
36 /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS            */
37
38 static int playing_sounds = 0;
39 static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
40 static struct SoundControl emptySoundControl =
41 {
42   -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, 0,0L,0L,NULL
43 };
44
45 #if defined(PLATFORM_UNIX)
46 static int stereo_volume[PSND_MAX_LEFT2RIGHT+1];
47 static char premix_first_buffer[SND_BLOCKSIZE];
48 #if defined(AUDIO_STREAMING_DSP)
49 static char premix_left_buffer[SND_BLOCKSIZE];
50 static char premix_right_buffer[SND_BLOCKSIZE];
51 static int premix_last_buffer[SND_BLOCKSIZE];
52 #endif
53 static unsigned char playing_buffer[SND_BLOCKSIZE];
54 #endif
55
56 /* forward declaration of internal functions */
57 #if defined(AUDIO_STREAMING_DSP)
58 static void SoundServer_InsertNewSound(struct SoundControl);
59 #elif defined(PLATFORM_UNIX)
60 static unsigned char linear_to_ulaw(int);
61 static int ulaw_to_linear(unsigned char);
62 #endif
63
64 #if defined(AUDIO_LINUX_IOCTL)
65 static boolean InitAudioDevice_Linux();
66 #elif defined(PLATFORM_NETBSD)
67 static boolean InitAudioDevice_NetBSD();
68 #elif defined(PLATFORM_HPUX)
69 static boolean InitAudioDevice_HPUX();
70 #elif defined(PLATFORM_MSDOS)
71 static void SoundServer_InsertNewSound(struct SoundControl);
72 static void SoundServer_StopSound(int);
73 static void SoundServer_StopAllSounds();
74 #endif
75
76 #if defined(PLATFORM_UNIX)
77 static int OpenAudioDevice(char *audio_device_name)
78 {
79   int audio_fd;
80
81   /* check if desired audio device is accessible */
82   if (access(audio_device_name, W_OK) != 0)
83     return -1;
84
85   /* try to open audio device in non-blocking mode */
86   if ((audio_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0)
87     return audio_fd;
88
89   /* re-open audio device in blocking mode */
90   close(audio_fd);
91   audio_fd = open(audio_device_name, O_WRONLY);
92
93   return audio_fd;
94 }
95
96 static boolean TestAudioDevices(void)
97 {
98   static char *audio_device_name[] =
99   {
100     DEVICENAME_DSP,
101     DEVICENAME_AUDIO
102   };
103   int audio_fd = -1;
104   int i;
105
106   /* look for available audio devices, starting with preferred ones */
107   for (i=0; i<sizeof(audio_device_name)/sizeof(char *); i++)
108     if ((audio_fd = OpenAudioDevice(audio_device_name[i])) >= 0)
109       break;
110
111   if (audio_fd < 0)
112   {
113     Error(ERR_WARN, "cannot open audio device -- no sound");
114     return FALSE;
115   }
116
117   close(audio_fd);
118
119   audio.device_name = audio_device_name[i];
120
121   return TRUE;
122 }
123
124 #if !defined(TARGET_SDL)
125 static boolean ForkAudioProcess(void)
126 {
127   if (pipe(audio.soundserver_pipe) < 0)
128   {
129     Error(ERR_WARN, "cannot create pipe -- no sounds");
130     return FALSE;
131   }
132
133   if ((audio.soundserver_pid = fork()) < 0)
134   {       
135     Error(ERR_WARN, "cannot create sound server process -- no sounds");
136     return FALSE;
137   }
138
139   if (audio.soundserver_pid == 0)       /* we are child process */
140   {
141     SoundServer();
142
143     /* never reached */
144     exit(0);
145   }
146   else                                  /* we are parent */
147     close(audio.soundserver_pipe[0]); /* no reading from pipe needed */
148
149   return TRUE;
150 }
151 #endif
152
153 void UnixOpenAudio(void)
154 {
155   if (!TestAudioDevices())
156     return;
157
158   audio.sound_available = TRUE;
159   audio.sound_enabled = TRUE;
160
161 #if defined(AUDIO_STREAMING_DSP)
162   audio.music_available = TRUE;
163   audio.loops_available = TRUE;
164 #endif
165 }
166
167 void UnixCloseAudio(void)
168 {
169   if (audio.device_fd)
170     close(audio.device_fd);
171
172   if (audio.soundserver_pid > 0)        /* we are parent process */
173     kill(audio.soundserver_pid, SIGTERM);
174 }
175 #endif  /* PLATFORM_UNIX */
176
177 void InitPlaylist(void)
178 {
179   int i;
180
181   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
182     playlist[i] = emptySoundControl;
183   playing_sounds = 0;
184 }
185
186 void StartSoundserver(void)
187 {
188   if (!audio.sound_available)
189     return;
190
191 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
192   if (!ForkAudioProcess())
193     audio.sound_available = FALSE;
194 #endif
195 }
196
197 #if defined(PLATFORM_UNIX)
198 void SoundServer(void)
199 {
200   int i;
201
202   struct SoundControl snd_ctrl;
203   fd_set sound_fdset;
204
205   close(audio.soundserver_pipe[1]);     /* no writing into pipe needed */
206
207   InitPlaylist();
208
209   stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
210   for(i=0;i<PSND_MAX_LEFT2RIGHT;i++)
211     stereo_volume[i] =
212       (int)sqrt((float)(PSND_MAX_LEFT2RIGHT*PSND_MAX_LEFT2RIGHT-i*i));
213
214 #if defined(PLATFORM_HPUX)
215   InitAudioDevice_HPUX();
216 #endif
217
218   FD_ZERO(&sound_fdset); 
219   FD_SET(audio.soundserver_pipe[0], &sound_fdset);
220
221   while(1)      /* wait for sound playing commands from client */
222   {
223     FD_SET(audio.soundserver_pipe[0], &sound_fdset);
224     select(audio.soundserver_pipe[0] + 1, &sound_fdset, NULL, NULL, NULL);
225     if (!FD_ISSET(audio.soundserver_pipe[0], &sound_fdset))
226       continue;
227     if (read(audio.soundserver_pipe[0], &snd_ctrl, sizeof(snd_ctrl))
228         != sizeof(snd_ctrl))
229       Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
230
231     if (snd_ctrl.reload_sounds || snd_ctrl.reload_music)
232     {
233       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
234         playlist[i] = emptySoundControl;
235       playing_sounds = 0;
236
237       close(audio.device_fd);
238
239       if (snd_ctrl.reload_sounds)
240         ReloadSounds();
241       else
242         ReloadMusic();
243
244       continue;
245     }
246
247 #if defined(AUDIO_STREAMING_DSP)
248
249     if (snd_ctrl.fade_sound)
250     {
251       if (!playing_sounds)
252         continue;
253
254       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
255         if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
256           playlist[i].fade_sound = TRUE;
257     }
258     else if (snd_ctrl.stop_all_sounds)
259     {
260       if (!playing_sounds)
261         continue;
262
263       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
264         playlist[i] = emptySoundControl;
265       playing_sounds = 0;
266
267       close(audio.device_fd);
268     }
269     else if (snd_ctrl.stop_sound)
270     {
271       if (!playing_sounds)
272         continue;
273
274       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
275         if (playlist[i].nr == snd_ctrl.nr)
276         {
277           playlist[i] = emptySoundControl;
278           playing_sounds--;
279         }
280
281       if (!playing_sounds)
282         close(audio.device_fd);
283     }
284
285     if (playing_sounds || snd_ctrl.active)
286     {
287       struct timeval delay = { 0, 0 };
288       byte *sample_ptr;
289       long sample_size;
290       static long max_sample_size = 0;
291       static long fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
292       int sample_rate = DEFAULT_AUDIO_SAMPLE_RATE;
293       static boolean stereo = TRUE;
294
295       if (playing_sounds ||
296           (audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
297       {
298         if (!playing_sounds)    /* we just opened the audio device */
299         {
300 #if defined(AUDIO_LINUX_IOCTL)
301           stereo = InitAudioDevice_Linux(fragment_size, sample_rate);
302 #elif defined(PLATFORM_NETBSD)
303           stereo = InitAudioDevice_NetBSD(fragment_size, sample_rate);
304 #endif
305           max_sample_size = fragment_size / (stereo ? 2 : 1);
306         }
307
308         if (snd_ctrl.active)    /* new sound has arrived */
309           SoundServer_InsertNewSound(snd_ctrl);
310
311         while(playing_sounds &&
312               select(audio.soundserver_pipe[0] + 1,
313                      &sound_fdset, NULL, NULL, &delay) < 1)
314         {       
315           FD_SET(audio.soundserver_pipe[0], &sound_fdset);
316
317           /* first clear the last premixing buffer */
318           memset(premix_last_buffer, 0, fragment_size * sizeof(int));
319
320           for(i=0;i<MAX_SOUNDS_PLAYING;i++)
321           {
322             int j;
323
324             if (!playlist[i].active)
325               continue;
326
327             /* get pointer and size of the actual sound sample */
328             sample_ptr = playlist[i].data_ptr+playlist[i].playingpos;
329             sample_size =
330               MIN(max_sample_size,playlist[i].data_len-playlist[i].playingpos);
331             playlist[i].playingpos += sample_size;
332
333             /* fill the first mixing buffer with original sample */
334             memcpy(premix_first_buffer,sample_ptr,sample_size);
335
336             /* are we about to restart a looping sound? */
337             if (playlist[i].loop && sample_size<max_sample_size)
338             {
339               playlist[i].playingpos = max_sample_size-sample_size;
340               memcpy(premix_first_buffer+sample_size,
341                      playlist[i].data_ptr,max_sample_size-sample_size);
342               sample_size = max_sample_size;
343             }
344
345             /* decrease volume if sound is fading out */
346             if (playlist[i].fade_sound &&
347                 playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
348               playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
349
350             /* adjust volume of actual sound sample */
351             if (playlist[i].volume != PSND_MAX_VOLUME)
352               for(j=0;j<sample_size;j++)
353                 premix_first_buffer[j] =
354                   (playlist[i].volume * (int)premix_first_buffer[j])
355                     >> PSND_MAX_VOLUME_BITS;
356
357             /* fill the last mixing buffer with stereo or mono sound */
358             if (stereo)
359             {
360               int middle_pos = PSND_MAX_LEFT2RIGHT/2;
361               int left_volume = stereo_volume[middle_pos+playlist[i].stereo];
362               int right_volume = stereo_volume[middle_pos-playlist[i].stereo];
363
364               for(j=0;j<sample_size;j++)
365               {
366                 premix_left_buffer[j] =
367                   (left_volume * (int)premix_first_buffer[j])
368                     >> PSND_MAX_LEFT2RIGHT_BITS;
369                 premix_right_buffer[j] =
370                   (right_volume * (int)premix_first_buffer[j])
371                     >> PSND_MAX_LEFT2RIGHT_BITS;
372                 premix_last_buffer[2*j+0] += premix_left_buffer[j];
373                 premix_last_buffer[2*j+1] += premix_right_buffer[j];
374               }
375             }
376             else
377             {
378               for(j=0;j<sample_size;j++)
379                 premix_last_buffer[j] += (int)premix_first_buffer[j];
380             }
381
382             /* delete completed sound entries from the playlist */
383             if (playlist[i].playingpos >= playlist[i].data_len)
384             {
385               if (playlist[i].loop)
386                 playlist[i].playingpos = 0;
387               else
388               {
389                 playlist[i] = emptySoundControl;
390                 playing_sounds--;
391               }
392             }
393             else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
394             {
395               playlist[i] = emptySoundControl;
396               playing_sounds--;
397             }
398           }
399
400           /* put last mixing buffer to final playing buffer */
401           for(i=0; i<fragment_size; i++)
402           {
403             if (premix_last_buffer[i]<-255)
404               playing_buffer[i] = 0;
405             else if (premix_last_buffer[i]>255)
406               playing_buffer[i] = 255;
407             else
408               playing_buffer[i] = (premix_last_buffer[i]>>1)^0x80;
409           }
410
411           /* finally play the sound fragment */
412           write(audio.device_fd, playing_buffer, fragment_size);
413         }
414
415         /* if no sounds playing, free device for other sound programs */
416         if (!playing_sounds)
417           close(audio.device_fd);
418       }
419     }
420
421 #else /* !AUDIO_STREAMING_DSP */
422
423     if (snd_ctrl.active && !snd_ctrl.loop)
424     {
425       struct timeval delay = { 0, 0 };
426       byte *sample_ptr;
427       long sample_size, max_sample_size = SND_BLOCKSIZE;
428       long sample_rate = 8000;  /* standard "/dev/audio" sampling rate */
429       int wait_percent = 90;    /* wait 90% of the real playing time */
430       int i;
431
432       if ((audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
433       {
434         playing_sounds = 1;
435
436         while(playing_sounds &&
437               select(audio.soundserver_pipe[0] + 1,
438                      &sound_fdset, NULL, NULL, &delay) < 1)
439         {       
440           FD_SET(audio.soundserver_pipe[0], &sound_fdset);
441
442           /* get pointer and size of the actual sound sample */
443           sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos;
444           sample_size =
445             MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos);
446           snd_ctrl.playingpos += sample_size;
447
448           /* fill the first mixing buffer with original sample */
449           memcpy(premix_first_buffer,sample_ptr,sample_size);
450
451           /* adjust volume of actual sound sample */
452           if (snd_ctrl.volume != PSND_MAX_VOLUME)
453             for(i=0;i<sample_size;i++)
454               premix_first_buffer[i] =
455                 (snd_ctrl.volume * (int)premix_first_buffer[i])
456                   >> PSND_MAX_VOLUME_BITS;
457
458           for(i=0;i<sample_size;i++)
459             playing_buffer[i] =
460               linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
461
462           if (snd_ctrl.playingpos >= snd_ctrl.data_len)
463             playing_sounds = 0;
464
465           /* finally play the sound fragment */
466           write(audio.device_fd,playing_buffer,sample_size);
467
468           delay.tv_sec = 0;
469           delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
470         }
471         close(audio.device_fd);
472       }
473     }
474 #endif /* !AUDIO_STREAMING_DSP */
475   }
476 }
477 #endif /* PLATFORM_UNIX */
478
479 #if defined(PLATFORM_MSDOS)
480 static void sound_handler(struct SoundControl snd_ctrl)
481 {
482   int i;
483
484   if (snd_ctrl.fade_sound)
485   {
486     if (!playing_sounds)
487       return;
488
489     for (i=0; i<MAX_SOUNDS_PLAYING; i++)
490       if ((snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr) &&
491           !playlist[i].fade_sound)
492       {
493         playlist[i].fade_sound = TRUE;
494         if (voice_check(playlist[i].voice))
495           voice_ramp_volume(playlist[i].voice, 1000, 0);
496         playlist[i].loop = PSND_NO_LOOP;
497       }
498   }
499   else if (snd_ctrl.stop_all_sounds)
500   {
501     if (!playing_sounds)
502       return;
503     SoundServer_StopAllSounds();
504   }
505   else if (snd_ctrl.stop_sound)
506   {
507     if (!playing_sounds)
508       return;
509     SoundServer_StopSound(snd_ctrl.nr);
510   }
511
512   for (i=0; i<MAX_SOUNDS_PLAYING; i++)
513   {
514     if (!playlist[i].active || playlist[i].loop)
515       continue;
516
517     playlist[i].playingpos = voice_get_position(playlist[i].voice);
518     playlist[i].volume = voice_get_volume(playlist[i].voice);
519     if (playlist[i].playingpos == -1 || !playlist[i].volume)
520     {
521       deallocate_voice(playlist[i].voice);
522       playlist[i] = emptySoundControl;
523       playing_sounds--;
524     }
525   }
526
527   if (snd_ctrl.active)
528     SoundServer_InsertNewSound(snd_ctrl);
529 }
530 #endif /* PLATFORM_MSDOS */
531
532 #if !defined(PLATFORM_WIN32)
533 static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
534 {
535   int i, k;
536
537   /* if playlist is full, remove oldest sound */
538   if (playing_sounds==MAX_SOUNDS_PLAYING)
539   {
540     int longest=0, longest_nr=0;
541
542     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
543     {
544 #if !defined(PLATFORM_MSDOS)
545       int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
546 #else
547       int actual = playlist[i].playingpos;
548 #endif
549
550       if (!playlist[i].loop && actual>longest)
551       {
552         longest=actual;
553         longest_nr=i;
554       }
555     }
556 #if defined(PLATFORM_MSDOS)
557     voice_set_volume(playlist[longest_nr].voice, 0);
558     deallocate_voice(playlist[longest_nr].voice);
559 #endif
560     playlist[longest_nr] = emptySoundControl;
561     playing_sounds--;
562   }
563
564   /* check if sound is already being played (and how often) */
565   for(k=0,i=0;i<MAX_SOUNDS_PLAYING;i++)
566   {
567     if (playlist[i].nr == snd_ctrl.nr)
568       k++;
569   }
570
571   /* restart loop sounds only if they are just fading out */
572   if (k>=1 && snd_ctrl.loop)
573   {
574     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
575     {
576       if (playlist[i].nr == snd_ctrl.nr && playlist[i].fade_sound)
577       {
578         playlist[i].fade_sound = FALSE;
579         playlist[i].volume = PSND_MAX_VOLUME;
580 #if defined(PLATFORM_MSDOS)
581         playlist[i].loop = PSND_LOOP;
582         voice_stop_volumeramp(playlist[i].voice);
583         voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
584 #endif
585       }
586     }
587     return;
588   }
589
590   /* don't play sound more than n times simultaneously (with n == 2 for now) */
591   if (k>=2)
592   {
593     int longest=0, longest_nr=0;
594
595     /* look for oldest equal sound */
596     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
597     {
598       int actual;
599
600       if (!playlist[i].active || playlist[i].nr != snd_ctrl.nr)
601         continue;
602
603 #if !defined(PLATFORM_MSDOS)
604       actual = 100 * playlist[i].playingpos / playlist[i].data_len;
605 #else
606       actual = playlist[i].playingpos;
607 #endif
608       if (actual>=longest)
609       {
610         longest=actual;
611         longest_nr=i;
612       }
613     }
614
615 #if defined(PLATFORM_MSDOS)
616     voice_set_volume(playlist[longest_nr].voice, 0);
617     deallocate_voice(playlist[longest_nr].voice);
618 #endif
619     playlist[longest_nr] = emptySoundControl;
620     playing_sounds--;
621   }
622
623   /* neuen Sound in Liste packen */
624   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
625   {
626     if (!playlist[i].active)
627     {
628       playlist[i] = snd_ctrl;
629       playing_sounds++;
630
631 #if defined(PLATFORM_MSDOS)
632       playlist[i].voice = allocate_voice(Sound[snd_ctrl.nr].sample_ptr);
633       if(snd_ctrl.loop)
634         voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
635       voice_set_volume(playlist[i].voice, snd_ctrl.volume);
636       voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
637       voice_start(playlist[i].voice);       
638 #endif
639       break;
640     }
641   }
642 }
643 #endif /* !PLATFORM_WIN32 */
644
645 /*
646 void SoundServer_FadeSound(int nr)
647 {
648   int i;
649
650   if (!playing_sounds)
651     return;
652
653   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
654     if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
655       playlist[i].fade_sound = TRUE;
656 }
657 */
658
659 #if !defined(PLATFORM_WIN32)
660 #if defined(PLATFORM_MSDOS)
661 static void SoundServer_StopSound(int nr)
662 {
663   int i;
664
665   if (!playing_sounds)
666     return;
667
668   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
669     if (playlist[i].nr == nr)
670     {
671 #if defined(PLATFORM_MSDOS)
672       voice_set_volume(playlist[i].voice, 0);
673       deallocate_voice(playlist[i].voice);
674 #endif
675       playlist[i] = emptySoundControl;
676       playing_sounds--;
677     }
678
679 #if !defined(PLATFORM_MSDOS)
680   if (!playing_sounds)
681     close(audio.device_fd);
682 #endif
683 }
684
685 static void SoundServer_StopAllSounds()
686 {
687   int i;
688
689   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
690   {
691 #if defined(PLATFORM_MSDOS)
692     voice_set_volume(playlist[i].voice, 0);
693     deallocate_voice(playlist[i].voice);
694 #endif
695     playlist[i]=emptySoundControl;
696   }
697   playing_sounds = 0;
698
699 #if !defined(PLATFORM_MSDOS)
700   close(audio.device_fd);
701 #endif
702 }
703 #endif /* PLATFORM_MSDOS */
704 #endif /* !PLATFORM_WIN32 */
705
706
707 /* ------------------------------------------------------------------------- */
708 /* platform dependant audio initialization code                              */
709 /* ------------------------------------------------------------------------- */
710
711 #if defined(AUDIO_LINUX_IOCTL)
712 static boolean InitAudioDevice_Linux(long fragment_size, int sample_rate)
713 {
714   /* "ioctl()" expects pointer to 'int' value for stereo flag
715      (boolean is defined as 'char', which will not work here) */
716   int stereo = TRUE;
717   unsigned long fragment_spec = 0;
718
719   /* determine logarithm (log2) of the fragment size */
720   for (fragment_spec=0; (1 << fragment_spec) < fragment_size;
721        fragment_spec++);
722
723   /* use two fragments (play one fragment, prepare the other);
724      one fragment would result in interrupted audio output, more
725      than two fragments would raise audio output latency to much */
726   fragment_spec |= 0x00020000;
727
728   /* Example for fragment specification:
729      - 2 buffers / 512 bytes (giving 1/16 second resolution for 8 kHz)
730      - (with stereo the effective buffer size will shrink to 256)
731      => fragment_size = 0x00020009 */
732
733   if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0)
734     Error(ERR_EXIT_SOUND_SERVER,
735           "cannot set fragment size of /dev/dsp -- no sounds");
736
737   /* try if we can use stereo sound */
738   if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
739   {
740 #ifdef DEBUG
741     static boolean reported = FALSE;
742
743     if (!reported)
744     {
745       Error(ERR_RETURN, "cannot get stereo sound on /dev/dsp");
746       reported = TRUE;
747     }
748 #endif
749     stereo = FALSE;
750   }
751
752   if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &sample_rate) < 0)
753     Error(ERR_EXIT_SOUND_SERVER,
754           "cannot set sample rate of /dev/dsp -- no sounds");
755
756   /* get the real fragmentation size; this should return 512 */
757   if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size) < 0)
758     Error(ERR_EXIT_SOUND_SERVER,
759           "cannot get fragment size of /dev/dsp -- no sounds");
760
761   return (boolean)stereo;
762 }
763 #endif  /* AUDIO_LINUX_IOCTL */
764
765 #if defined(PLATFORM_NETBSD)
766 static boolean InitAudioDevice_NetBSD(long fragment_size, int sample_rate)
767 {
768   audio_info_t a_info;
769   boolean stereo = TRUE;
770
771   AUDIO_INITINFO(&a_info);
772   a_info.play.encoding = AUDIO_ENCODING_LINEAR8;
773   a_info.play.precision = 8;
774   a_info.play.channels = 2;
775   a_info.play.sample_rate = sample_rate;
776   a_info.blocksize = fragment_size;
777
778   if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
779   {
780     /* try to disable stereo */
781     a_info.play.channels = 1;
782     stereo = FALSE;
783
784     if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
785       Error(ERR_EXIT_SOUND_SERVER,
786             "cannot set sample rate of /dev/audio -- no sounds");
787   }
788
789   return stereo;
790 }
791 #endif /* PLATFORM_NETBSD */
792
793 #if defined(PLATFORM_HPUX)
794 static boolean InitAudioDevice_HPUX()
795 {
796   struct audio_describe ainfo;
797   int audio_ctl;
798
799   audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
800   if (audio_ctl == -1)
801     Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl -- no sounds");
802
803   if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
804     Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds");
805
806   if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
807     Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds");
808
809   ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
810   ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
811
812   close(audio_ctl);
813
814   return TRUE;  /* to provide common interface for InitAudioDevice_...() */
815 }
816 #endif /* PLATFORM_HPUX */
817
818 #if defined(PLATFORM_UNIX) && !defined(AUDIO_STREAMING_DSP)
819
820 /* these two are stolen from "sox"... :) */
821
822 /*
823 ** This routine converts from linear to ulaw.
824 **
825 ** Craig Reese: IDA/Supercomputing Research Center
826 ** Joe Campbell: Department of Defense
827 ** 29 September 1989
828 **
829 ** References:
830 ** 1) CCITT Recommendation G.711  (very difficult to follow)
831 ** 2) "A New Digital Technique for Implementation of Any
832 **     Continuous PCM Companding Law," Villeret, Michel,
833 **     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
834 **     1973, pg. 11.12-11.17
835 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
836 **     for Analog-to_Digital Conversion Techniques,"
837 **     17 February 1987
838 **
839 ** Input: Signed 16 bit linear sample
840 ** Output: 8 bit ulaw sample
841 */
842
843 #define ZEROTRAP    /* turn on the trap as per the MIL-STD */
844 #define BIAS 0x84   /* define the add-in bias for 16 bit samples */
845 #define CLIP 32635
846
847 static unsigned char linear_to_ulaw(int sample)
848 {
849   static int exp_lut[256] =
850   {
851     0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
852     4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
853     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
854     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
855     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
856     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
857     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
858     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
859     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
860     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
861     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
862     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
863     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
864     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
865     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
866     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
867   };
868
869   int sign, exponent, mantissa;
870   unsigned char ulawbyte;
871
872   /* Get the sample into sign-magnitude. */
873   sign = (sample >> 8) & 0x80;          /* set aside the sign */
874   if (sign != 0)
875     sample = -sample;                   /* get magnitude */
876   if (sample > CLIP)
877     sample = CLIP;                      /* clip the magnitude */
878
879   /* Convert from 16 bit linear to ulaw. */
880   sample = sample + BIAS;
881   exponent = exp_lut[( sample >> 7 ) & 0xFF];
882   mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
883   ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
884 #ifdef ZEROTRAP
885   if (ulawbyte == 0)
886     ulawbyte = 0x02;                    /* optional CCITT trap */
887 #endif
888
889   return(ulawbyte);
890 }
891
892 /*
893 ** This routine converts from ulaw to 16 bit linear.
894 **
895 ** Craig Reese: IDA/Supercomputing Research Center
896 ** 29 September 1989
897 **
898 ** References:
899 ** 1) CCITT Recommendation G.711  (very difficult to follow)
900 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
901 **     for Analog-to_Digital Conversion Techniques,"
902 **     17 February 1987
903 **
904 ** Input: 8 bit ulaw sample
905 ** Output: signed 16 bit linear sample
906 */
907
908 static int ulaw_to_linear(unsigned char ulawbyte)
909 {
910   static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
911   int sign, exponent, mantissa, sample;
912
913   ulawbyte = ~ ulawbyte;
914   sign = ( ulawbyte & 0x80 );
915   exponent = ( ulawbyte >> 4 ) & 0x07;
916   mantissa = ulawbyte & 0x0F;
917   sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
918   if (sign != 0)
919     sample = -sample;
920
921   return(sample);
922 }
923 #endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */
924
925
926 /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS            */
927 /* ========================================================================= */
928 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS                          */
929
930 void ReloadSounds()
931 {
932   printf("reloading sounds ...\n");
933 }
934
935 void ReloadMusic()
936 {
937   printf("reloading music ...\n");
938 }
939
940 #define CHUNK_ID_LEN            4       /* IFF style chunk id length */
941 #define WAV_HEADER_SIZE         16      /* size of WAV file header */
942
943 static boolean Load_WAV(char *filename)
944 {
945   struct SampleInfo *snd_info;
946 #if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS)
947   byte sound_header_buffer[WAV_HEADER_SIZE];
948   char chunk_name[CHUNK_ID_LEN + 1];
949   int chunk_size;
950   FILE *file;
951   int i;
952 #endif
953
954   if (!audio.sound_available)
955     return FALSE;
956
957   num_sounds++;
958   Sound = checked_realloc(Sound, num_sounds * sizeof(struct SampleInfo));
959
960   snd_info = &Sound[num_sounds - 1];
961   snd_info->data_len = 0;
962   snd_info->data_ptr = NULL;
963
964 #if defined(TARGET_SDL)
965
966   if ((snd_info->mix_chunk = Mix_LoadWAV(filename)) == NULL)
967   {
968     Error(ERR_WARN, "cannot read sound file '%s'", filename);
969     return FALSE;
970   }
971
972 #elif defined(PLATFORM_UNIX)
973
974   if ((file = fopen(filename, MODE_READ)) == NULL)
975   {
976     Error(ERR_WARN, "cannot open sound file '%s'", filename);
977     return FALSE;
978   }
979
980   /* read chunk id "RIFF" */
981   getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
982   if (strcmp(chunk_name, "RIFF") != 0)
983   {
984     Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
985     fclose(file);
986     return FALSE;
987   }
988
989   /* read "RIFF" type id "WAVE" */
990   getFileChunk(file, chunk_name, NULL, BYTE_ORDER_LITTLE_ENDIAN);
991   if (strcmp(chunk_name, "WAVE") != 0)
992   {
993     Error(ERR_WARN, "missing 'WAVE' type ID of sound file '%s'", filename);
994     fclose(file);
995     return FALSE;
996   }
997
998   while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN))
999   {
1000 #if 0
1001     printf("DEBUG: file '%s', chunk id '%s', chunk size '%d' [%d]\n",
1002            filename, chunk_name, chunk_size, feof(file));
1003 #endif
1004
1005     if (strcmp(chunk_name, "fmt ") == 0)
1006     {
1007       /* read header information */
1008       for (i=0; i < MIN(chunk_size, WAV_HEADER_SIZE); i++)
1009         sound_header_buffer[i] = fgetc(file);
1010
1011       if (chunk_size > WAV_HEADER_SIZE)
1012         ReadUnusedBytesFromFile(file, chunk_size - WAV_HEADER_SIZE);
1013     }
1014     else if (strcmp(chunk_name, "data") == 0)
1015     {
1016       snd_info->data_len = chunk_size;
1017       snd_info->data_ptr = checked_malloc(snd_info->data_len);
1018
1019       /* read sound data */
1020       if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
1021           snd_info->data_len)
1022       {
1023         Error(ERR_WARN,"cannot read 'data' chunk of sound file '%s'",filename);
1024         fclose(file);
1025         return FALSE;
1026       }
1027
1028       /* check for odd number of sample bytes (data chunk is word aligned) */
1029       if ((chunk_size % 2) == 1)
1030         ReadUnusedBytesFromFile(file, 1);
1031     }
1032     else        /* unknown chunk -- ignore */
1033       ReadUnusedBytesFromFile(file, chunk_size);
1034   }
1035
1036   fclose(file);
1037
1038   if (snd_info->data_ptr == NULL)
1039   {
1040     Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
1041     return FALSE;
1042   }
1043
1044   for (i=0; i<snd_info->data_len; i++)
1045     snd_info->data_ptr[i] = snd_info->data_ptr[i] ^ 0x80;
1046
1047 #else /* PLATFORM_MSDOS */
1048
1049   snd_info->sample_ptr = load_sample(filename);
1050   if (!snd_info->sample_ptr)
1051   {
1052     Error(ERR_WARN, "cannot read sound file '%s'", filename);
1053     return FALSE;
1054   }
1055
1056 #endif
1057
1058   return TRUE;
1059 }
1060
1061 boolean LoadCustomSound(char *basename)
1062 {
1063   char *filename = getCustomSoundFilename(basename);
1064
1065   if (filename == NULL)
1066   {
1067     Error(ERR_WARN, "cannot find sound file '%s' -- no sounds", filename);
1068     return FALSE;
1069   }
1070
1071   return Load_WAV(filename);
1072 }
1073
1074 static boolean Load_MOD(char *mod_name)
1075 {
1076 #if defined(TARGET_SDL)
1077   struct SampleInfo *mod_info;
1078   char *filename;
1079
1080   num_mods++;
1081   Mod = checked_realloc(Mod, num_mods * sizeof(struct SampleInfo));
1082
1083   mod_info = &Mod[num_mods - 1];
1084   mod_info->name = mod_name;
1085
1086   filename = getPath2(options.music_directory, mod_info->name);
1087
1088   if ((mod_info->mix_music = Mix_LoadMUS(filename)) == NULL)
1089   {
1090     Error(ERR_WARN, "cannot read music file '%s' -- no music", filename);
1091     free(filename);
1092     return FALSE;
1093   }
1094
1095   free(filename);
1096
1097   return TRUE;
1098 #else
1099   return FALSE;
1100 #endif
1101 }
1102
1103 int LoadCustomMusic(void)
1104 {
1105   char *music_directory = getCustomMusicDirectory();
1106   DIR *dir;
1107   struct dirent *dir_entry;
1108   int num_wav_music = 0;
1109   int num_mod_music = 0;
1110
1111   if (!audio.sound_available)
1112     return 0;
1113
1114   if ((dir = opendir(music_directory)) == NULL)
1115   {
1116     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
1117     audio.music_available = FALSE;
1118     return 0;
1119   }
1120
1121   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
1122   {
1123     char *filename = getPath2(music_directory, dir_entry->d_name);
1124
1125     if (FileIsSound(filename) && Load_WAV(filename))
1126       num_wav_music++;
1127     else if (FileIsMusic(filename) && Load_MOD(filename))
1128       num_mod_music++;
1129
1130     free(filename);
1131   }
1132
1133   closedir(dir);
1134
1135   if (num_wav_music == 0 && num_mod_music == 0)
1136     Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
1137           options.music_directory);
1138
1139   num_music = (num_mod_music > 0 ? num_mod_music : num_wav_music);
1140
1141   audio.mods_available = (num_mod_music > 0);
1142   audio.music_available = (num_music > 0);
1143
1144   return num_music;
1145 }
1146
1147 void PlayMusic(int nr)
1148 {
1149   if (!audio.music_available)
1150     return;
1151
1152   if (!audio.mods_available)
1153     nr = num_sounds - num_music + nr;
1154
1155 #if defined(TARGET_SDL)
1156   if (audio.mods_available)     /* play MOD music */
1157   {
1158     Mix_PlayMusic(Mod[nr].mix_music, -1);
1159     Mix_VolumeMusic(SOUND_MAX_VOLUME);  /* must be _after_ Mix_PlayMusic()! */
1160   }
1161   else                          /* play WAV music loop */
1162   {
1163     Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
1164     Mix_PlayChannel(audio.music_channel, Sound[nr].mix_chunk, -1);
1165   }
1166 #else
1167   audio.music_nr = nr;
1168   PlaySoundLoop(nr);
1169 #endif
1170 }
1171
1172 void PlaySound(int nr)
1173 {
1174   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
1175 }
1176
1177 void PlaySoundStereo(int nr, int stereo)
1178 {
1179   PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
1180 }
1181
1182 void PlaySoundLoop(int nr)
1183 {
1184   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
1185 }
1186
1187 void PlaySoundExt(int nr, int volume, int stereo, boolean loop)
1188 {
1189   struct SoundControl snd_ctrl = emptySoundControl;
1190
1191   if (!audio.sound_available ||
1192       !audio.sound_enabled ||
1193       audio.sound_deactivated)
1194     return;
1195
1196   if (volume<PSND_MIN_VOLUME)
1197     volume = PSND_MIN_VOLUME;
1198   else if (volume>PSND_MAX_VOLUME)
1199     volume = PSND_MAX_VOLUME;
1200
1201   if (stereo<PSND_MAX_LEFT)
1202     stereo = PSND_MAX_LEFT;
1203   else if (stereo>PSND_MAX_RIGHT)
1204     stereo = PSND_MAX_RIGHT;
1205
1206   snd_ctrl.nr           = nr;
1207   snd_ctrl.volume       = volume;
1208   snd_ctrl.stereo       = stereo;
1209   snd_ctrl.loop         = loop;
1210   snd_ctrl.active       = TRUE;
1211   snd_ctrl.data_ptr     = Sound[nr].data_ptr;
1212   snd_ctrl.data_len     = Sound[nr].data_len;
1213
1214 #if defined(TARGET_SDL)
1215   Mix_Volume(-1, SOUND_MAX_VOLUME);
1216   Mix_PlayChannel(-1, Sound[nr].mix_chunk, (loop ? -1 : 0));
1217 #elif defined(PLATFORM_UNIX)
1218   if (audio.soundserver_pid == 0)       /* we are child process */
1219     return;
1220
1221   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1222   {
1223     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1224     audio.sound_available = audio.sound_enabled = FALSE;
1225     return;
1226   }
1227 #elif defined(PLATFORM_MSDOS)
1228   sound_handler(snd_ctrl);
1229 #endif
1230 }
1231
1232 void FadeMusic(void)
1233 {
1234 #if defined(TARGET_SDL)
1235   if (!audio.sound_available)
1236     return;
1237
1238   if (audio.mods_available)
1239     Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1240   else
1241     Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
1242 #else
1243   FadeSound(audio.music_nr);
1244 #endif
1245 }
1246
1247 void FadeSound(int nr)
1248 {
1249   StopSoundExt(nr, SSND_FADE_SOUND);
1250 }
1251
1252 void FadeSounds()
1253 {
1254   FadeMusic();
1255   StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
1256 }
1257
1258 void StopMusic(void)
1259 {
1260 #if defined(TARGET_SDL)
1261   if (!audio.sound_available)
1262     return;
1263
1264   if (audio.mods_available)
1265     Mix_HaltMusic();
1266   else
1267     Mix_HaltChannel(audio.music_channel);
1268 #else
1269   StopSound(audio.music_nr);
1270 #endif
1271 }
1272
1273 void StopSound(int nr)
1274 {
1275   StopSoundExt(nr, SSND_STOP_SOUND);
1276 }
1277
1278 void StopSounds()
1279 {
1280   StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
1281 }
1282
1283 void StopSoundExt(int nr, int method)
1284 {
1285   struct SoundControl snd_ctrl = emptySoundControl;
1286
1287   if (!audio.sound_available)
1288     return;
1289
1290   if (SSND_FADING(method))
1291     snd_ctrl.fade_sound = TRUE;
1292
1293   if (SSND_ALL(method))
1294     snd_ctrl.stop_all_sounds = TRUE;
1295   else
1296   {
1297     snd_ctrl.nr = nr;
1298     snd_ctrl.stop_sound = TRUE;
1299   }
1300
1301 #if defined(TARGET_SDL)
1302
1303   if (SSND_FADING(method))
1304   {
1305     int i;
1306
1307     for (i=0; i<audio.channels; i++)
1308       if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
1309         Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
1310     if (snd_ctrl.stop_all_sounds)
1311       Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1312   }
1313   else
1314   {
1315     int i;
1316
1317     for (i=0; i<audio.channels; i++)
1318       if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
1319         Mix_HaltChannel(i);
1320     if (snd_ctrl.stop_all_sounds)
1321       Mix_HaltMusic();
1322   }
1323
1324 #else
1325 #if !defined(PLATFORM_MSDOS)
1326   if (audio.soundserver_pid == 0)       /* we are child process */
1327     return;
1328
1329   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1330   {
1331     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1332     audio.sound_available = audio.sound_enabled = FALSE;
1333     return;
1334   }
1335 #else
1336   sound_handler(snd_ctrl);
1337 #endif
1338 #endif
1339 }
1340
1341 void InitReloadSounds(char *set_name)
1342 {
1343   struct SoundControl snd_ctrl = emptySoundControl;
1344
1345   if (!audio.sound_available)
1346     return;
1347
1348   snd_ctrl.reload_sounds = TRUE;
1349
1350 #if defined(TARGET_SDL)
1351   ReloadSounds();
1352 #elif defined(PLATFORM_UNIX)
1353   if (audio.soundserver_pid == 0)       /* we are child process */
1354     return;
1355
1356   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1357   {
1358     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1359     audio.sound_available = audio.sound_enabled = FALSE;
1360     return;
1361   }
1362 #elif defined(PLATFORM_MSDOS)
1363   sound_handler(snd_ctrl);
1364 #endif
1365 }
1366
1367 void InitReloadMusic(char *set_name)
1368 {
1369   struct SoundControl snd_ctrl = emptySoundControl;
1370
1371   if (!audio.sound_available)
1372     return;
1373
1374   snd_ctrl.reload_music = TRUE;
1375
1376 #if defined(TARGET_SDL)
1377   ReloadMusic();
1378 #elif defined(PLATFORM_UNIX)
1379   if (audio.soundserver_pid == 0)       /* we are child process */
1380     return;
1381
1382   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1383   {
1384     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1385     audio.sound_available = audio.sound_enabled = FALSE;
1386     return;
1387   }
1388 #elif defined(PLATFORM_MSDOS)
1389   sound_handler(snd_ctrl);
1390 #endif
1391 }
1392
1393 void FreeSounds(int num_sounds)
1394 {
1395   int i;
1396
1397   if (!audio.sound_available)
1398     return;
1399
1400   for(i=0; i<num_sounds; i++)
1401 #if defined(TARGET_SDL)
1402     free(Sound[i].mix_chunk);
1403 #elif !defined(PLATFORM_MSDOS)
1404     free(Sound[i].data_ptr);
1405 #else
1406     destroy_sample(Sound[i].sample_ptr);
1407 #endif
1408 }
1409
1410 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS                          */
1411 /* ========================================================================= */