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