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