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