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