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