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