rnd-20020510-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 struct ListNode
28 {
29   char *key;
30   void *content;
31   struct ListNode *next;
32 };
33 typedef struct ListNode ListNode;
34
35 static ListNode *newListNode(void);
36 static void addNodeToList(ListNode **, char *, void *);
37 static void deleteNodeFromList(ListNode **, char *, void (*function)(void *));
38 static ListNode *getNodeFromKey(ListNode *, char *);
39 static int getNumNodes(ListNode *);
40
41
42 static struct SoundEffectInfo *sound_effect;
43 static ListNode *SoundFileList = NULL;
44 static SoundInfo **Sound = NULL;
45 static MusicInfo **Music = NULL;
46 static int num_sounds = 0, num_music = 0;
47
48
49 /* ========================================================================= */
50 /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS            */
51
52 static struct AudioFormatInfo afmt =
53 {
54   TRUE, 0, DEFAULT_AUDIO_SAMPLE_RATE, DEFAULT_AUDIO_FRAGMENT_SIZE
55 };
56
57 static int playing_sounds = 0;
58 static struct SoundControl playlist[NUM_MIXER_CHANNELS];
59
60 #if 0
61 static struct SoundControl emptySoundControl =
62 {
63 #if 1
64   FALSE, -1, 0, 0, FALSE, 0, 0, 0, NULL
65 #else
66   -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, 0,0, 0,NULL
67 #endif
68 };
69 #endif
70
71 /* forward declaration of internal functions */
72 static void SoundServer_InsertNewSound(struct SoundControl);
73 static void InitAudioDevice(struct AudioFormatInfo *);
74
75 #if defined(PLATFORM_UNIX)
76 #if !defined(AUDIO_STREAMING_DSP)
77 static unsigned char linear_to_ulaw(int);
78 static int ulaw_to_linear(unsigned char);
79 #endif
80 #elif defined(PLATFORM_MSDOS)
81 static void SoundServer_InsertNewSound(struct SoundControl);
82 static void SoundServer_StopSound(struct SoundControl);
83 static void SoundServer_StopAllSounds();
84 #endif
85
86 static void ReloadCustomSounds();
87 static void ReloadCustomMusic();
88 static void FreeSound(void *);
89
90 #if defined(PLATFORM_UNIX)
91 static int OpenAudioDevice(char *audio_device_name)
92 {
93   int audio_device_fd;
94
95   /* check if desired audio device is accessible */
96   if (access(audio_device_name, W_OK) != 0)
97     return -1;
98
99   /* try to open audio device in non-blocking mode */
100   if ((audio_device_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0)
101     return audio_device_fd;
102
103   /* re-open audio device in blocking mode */
104   close(audio_device_fd);
105   audio_device_fd = open(audio_device_name, O_WRONLY);
106
107   return audio_device_fd;
108 }
109
110 static void CloseAudioDevice(int *audio_device_fd)
111 {
112   if (*audio_device_fd == 0)
113     return;
114
115   close(*audio_device_fd);
116   *audio_device_fd = -1;
117 }
118
119 static boolean TestAudioDevices(void)
120 {
121   static char *audio_device_name[] =
122   {
123     DEVICENAME_DSP,
124     DEVICENAME_AUDIO
125   };
126   int audio_device_fd = -1;
127   int i;
128
129   /* look for available audio devices, starting with preferred ones */
130   for (i=0; i<sizeof(audio_device_name)/sizeof(char *); i++)
131     if ((audio_device_fd = OpenAudioDevice(audio_device_name[i])) >= 0)
132       break;
133
134   if (audio_device_fd < 0)
135   {
136     Error(ERR_WARN, "cannot open audio device -- no sound");
137     return FALSE;
138   }
139
140   close(audio_device_fd);
141
142   audio.device_name = audio_device_name[i];
143
144   return TRUE;
145 }
146
147 #if !defined(TARGET_SDL)
148 static boolean ForkAudioProcess(void)
149 {
150   if (pipe(audio.soundserver_pipe) < 0)
151   {
152     Error(ERR_WARN, "cannot create pipe -- no sounds");
153     return FALSE;
154   }
155
156   if ((audio.soundserver_pid = fork()) < 0)
157   {       
158     Error(ERR_WARN, "cannot create sound server process -- no sounds");
159     return FALSE;
160   }
161
162   if (audio.soundserver_pid == 0)       /* we are child process */
163   {
164     SoundServer();
165
166     /* never reached */
167     exit(0);
168   }
169   else                                  /* we are parent */
170     close(audio.soundserver_pipe[0]); /* no reading from pipe needed */
171
172   return TRUE;
173 }
174 #endif
175
176 void UnixOpenAudio(void)
177 {
178   if (!TestAudioDevices())
179     return;
180
181   audio.sound_available = TRUE;
182   audio.sound_enabled = TRUE;
183
184 #if defined(AUDIO_STREAMING_DSP)
185   audio.music_available = TRUE;
186   audio.loops_available = TRUE;
187 #endif
188
189   audio.num_channels = NUM_MIXER_CHANNELS;
190   audio.music_channel = MUSIC_CHANNEL;
191   audio.first_sound_channel = FIRST_SOUND_CHANNEL;
192 }
193
194 void UnixCloseAudio(void)
195 {
196   if (audio.device_fd)
197     close(audio.device_fd);
198
199   if (audio.soundserver_pid > 0)        /* we are parent process */
200     kill(audio.soundserver_pid, SIGTERM);
201 }
202
203 static void WriteReloadInfoToPipe(char *set_name, int type)
204 {
205   struct SoundControl snd_ctrl;
206   TreeInfo *ti = (type == SND_CTRL_RELOAD_SOUNDS ? artwork.snd_current :
207                   artwork.mus_current);
208   unsigned long str_size1 = strlen(leveldir_current->fullpath) + 1;
209   unsigned long str_size2 = strlen(ti->basepath) + 1;
210   unsigned long str_size3 = strlen(ti->fullpath) + 1;
211
212   snd_ctrl.active = FALSE;
213   snd_ctrl.state = type;
214   snd_ctrl.data_len = strlen(set_name) + 1;
215
216   if (write(audio.soundserver_pipe[1], &snd_ctrl,
217             sizeof(snd_ctrl)) < 0 ||
218       write(audio.soundserver_pipe[1], set_name,
219             snd_ctrl.data_len) < 0 ||
220       write(audio.soundserver_pipe[1], leveldir_current,
221             sizeof(TreeInfo)) < 0 ||
222       write(audio.soundserver_pipe[1], ti,
223             sizeof(TreeInfo)) < 0 ||
224       write(audio.soundserver_pipe[1], &str_size1,
225             sizeof(unsigned long)) < 0 ||
226       write(audio.soundserver_pipe[1], &str_size2,
227             sizeof(unsigned long)) < 0 ||
228       write(audio.soundserver_pipe[1], &str_size3,
229             sizeof(unsigned long)) < 0 ||
230       write(audio.soundserver_pipe[1], leveldir_current->fullpath,
231             str_size1) < 0 ||
232       write(audio.soundserver_pipe[1], ti->basepath,
233             str_size2) < 0 ||
234       write(audio.soundserver_pipe[1], ti->fullpath,
235             str_size3) < 0)
236   {
237     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
238     audio.sound_available = audio.sound_enabled = FALSE;
239     return;
240   }
241 }
242
243 static void ReadReloadInfoFromPipe(struct SoundControl snd_ctrl)
244 {
245   TreeInfo **ti_ptr = ((snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS) ?
246                        &artwork.snd_current : &artwork.mus_current);
247   TreeInfo *ti = *ti_ptr;
248   unsigned long str_size1, str_size2, str_size3;
249   static char *set_name = NULL;
250
251   if (set_name)
252     free(set_name);
253
254   set_name = checked_malloc(snd_ctrl.data_len);
255
256   if (leveldir_current == NULL)
257     leveldir_current = checked_calloc(sizeof(TreeInfo));
258   if (ti == NULL)
259     ti = *ti_ptr = checked_calloc(sizeof(TreeInfo));
260   if (leveldir_current->fullpath != NULL)
261     free(leveldir_current->fullpath);
262   if (ti->basepath != NULL)
263     free(ti->basepath);
264   if (ti->fullpath != NULL)
265     free(ti->fullpath);
266
267   if (read(audio.soundserver_pipe[0], set_name,
268            snd_ctrl.data_len) != snd_ctrl.data_len ||
269       read(audio.soundserver_pipe[0], leveldir_current,
270            sizeof(TreeInfo)) != sizeof(TreeInfo) ||
271       read(audio.soundserver_pipe[0], ti,
272            sizeof(TreeInfo)) != sizeof(TreeInfo) ||
273       read(audio.soundserver_pipe[0], &str_size1,
274            sizeof(unsigned long)) != sizeof(unsigned long) ||
275       read(audio.soundserver_pipe[0], &str_size2,
276            sizeof(unsigned long)) != sizeof(unsigned long) ||
277       read(audio.soundserver_pipe[0], &str_size3,
278            sizeof(unsigned long)) != sizeof(unsigned long))
279     Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
280
281   leveldir_current->fullpath = checked_calloc(str_size1);
282   ti->basepath = checked_calloc(str_size2);
283   ti->fullpath = checked_calloc(str_size3);
284
285   if (read(audio.soundserver_pipe[0], leveldir_current->fullpath,
286            str_size1) != str_size1 ||
287       read(audio.soundserver_pipe[0], ti->basepath,
288            str_size2) != str_size2 ||
289       read(audio.soundserver_pipe[0], ti->fullpath,
290            str_size3) != str_size3)
291     Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
292
293   if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS)
294     artwork.sounds_set_current = set_name;
295   else
296     artwork.music_set_current = set_name;
297 }
298 #endif  /* PLATFORM_UNIX */
299
300 void InitPlaylist(void)
301 {
302   int i;
303
304   for(i=0; i<audio.num_channels; i++)
305     playlist[i].active = FALSE;
306   playing_sounds = 0;
307 }
308
309 static void PlaylistRemoveSound(int pos)
310 {
311   if (!playing_sounds || !playlist[pos].active)
312     return;
313
314   playlist[pos].active = FALSE;
315   playing_sounds--;
316 }
317
318 static void PlaylistInsertSound(struct SoundControl snd_ctrl)
319 {
320   SoundInfo *snd_info;
321   int i, k;
322
323 #if 0
324   printf("NEW SOUND %d HAS ARRIVED [%d]\n", snd_ctrl.nr, num_sounds);
325 #endif
326
327   if (IS_MUSIC(snd_ctrl))
328     snd_ctrl.nr = snd_ctrl.nr % num_music;
329   else if (snd_ctrl.nr >= num_sounds)
330     return;
331
332   snd_info = (IS_MUSIC(snd_ctrl) ? Music[snd_ctrl.nr] : Sound[snd_ctrl.nr]);
333   if (snd_info == NULL)
334   {
335 #if 0
336     printf("sound/music %d undefined\n", snd_ctrl.nr);
337 #endif
338     return;
339   }
340
341 #if 0
342   printf("-> %d\n", playing_sounds);
343 #endif
344
345   if (playing_sounds == audio.num_channels)
346   {
347     for (i=0; i<audio.num_channels; i++)
348     {
349       if (playlist[i].data_ptr == NULL)
350       {
351 #if 1
352         printf("THIS SHOULD NEVER HAPPEN! [%d]\n", i);
353 #endif
354
355         PlaylistRemoveSound(i);
356       }
357     }
358   }
359
360   /* if playlist is full, remove oldest sound */
361   if (playing_sounds == audio.num_channels)
362   {
363     int longest = 0, longest_nr = 0;
364
365     for (i=audio.first_sound_channel; i<audio.num_channels; i++)
366     {
367 #if !defined(PLATFORM_MSDOS)
368       int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
369 #else
370       int actual = playlist[i].playingpos;
371 #endif
372
373       if (!IS_LOOP(playlist[i]) && actual > longest)
374       {
375         longest = actual;
376         longest_nr = i;
377       }
378     }
379 #if defined(PLATFORM_MSDOS)
380     voice_set_volume(playlist[longest_nr].voice, 0);
381     deallocate_voice(playlist[longest_nr].voice);
382 #endif
383     PlaylistRemoveSound(longest_nr);
384   }
385
386   /* check if sound is already being played (and how often) */
387   for (k=0, i=audio.first_sound_channel; i<audio.num_channels; i++)
388     if (playlist[i].nr == snd_ctrl.nr)
389       k++;
390
391   /* restart loop sounds only if they are just fading out */
392   if (k >= 1 && IS_LOOP(snd_ctrl))
393   {
394     for(i=audio.first_sound_channel; i<audio.num_channels; i++)
395     {
396       if (playlist[i].nr == snd_ctrl.nr && IS_FADING(playlist[i]))
397       {
398         playlist[i].state &= ~SND_CTRL_FADE;
399         playlist[i].volume = PSND_MAX_VOLUME;
400 #if defined(PLATFORM_MSDOS)
401         playlist[i].state |= SND_CTRL_LOOP;
402         voice_stop_volumeramp(playlist[i].voice);
403         voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
404 #endif
405       }
406     }
407
408     return;
409   }
410
411   /* don't play sound more than n times simultaneously (with n == 2 for now) */
412   if (k >= 2)
413   {
414     int longest = 0, longest_nr = 0;
415
416     /* look for oldest equal sound */
417     for(i=audio.first_sound_channel; i<audio.num_channels; i++)
418     {
419       int actual;
420
421       if (!playlist[i].active || playlist[i].nr != snd_ctrl.nr)
422         continue;
423
424 #if !defined(PLATFORM_MSDOS)
425       actual = 100 * playlist[i].playingpos / playlist[i].data_len;
426 #else
427       actual = playlist[i].playingpos;
428 #endif
429       if (actual >= longest)
430       {
431         longest = actual;
432         longest_nr = i;
433       }
434     }
435
436 #if defined(PLATFORM_MSDOS)
437     voice_set_volume(playlist[longest_nr].voice, 0);
438     deallocate_voice(playlist[longest_nr].voice);
439 #endif
440     PlaylistRemoveSound(longest_nr);
441   }
442
443   /* add new sound to playlist */
444   for(i=0; i<audio.num_channels; i++)
445   {
446 #if 0
447     printf("CHECKING CHANNEL %d FOR SOUND %d ...\n", i, snd_ctrl.nr);
448 #endif
449
450     /*
451     if (!playlist[i].active ||
452         (IS_MUSIC(snd_ctrl) && i == audio.music_channel))
453     */
454     if ((i == audio.music_channel && IS_MUSIC(snd_ctrl)) ||
455         (i != audio.music_channel && !playlist[i].active))
456     {
457       snd_ctrl.data_ptr = snd_info->data_ptr;
458       snd_ctrl.data_len = snd_info->data_len;
459       snd_ctrl.format   = snd_info->format;
460
461 #if 1
462       if (snd_info->data_len == 0)
463       {
464         printf("THIS SHOULD NEVER HAPPEN! [snd_info->data_len == 0]\n");
465       }
466 #endif
467
468 #if 1
469       if (IS_MUSIC(snd_ctrl) && i == audio.music_channel && playlist[i].active)
470       {
471         printf("THIS SHOULD NEVER HAPPEN! [adding music twice]\n");
472
473 #if 1
474         PlaylistRemoveSound(i);
475 #endif
476       }
477 #endif
478
479       playlist[i] = snd_ctrl;
480       playing_sounds++;
481
482 #if 0
483       printf("NEW SOUND %d ADDED TO PLAYLIST\n", snd_ctrl.nr);
484 #endif
485
486 #if defined(PLATFORM_MSDOS)
487       playlist[i].voice = allocate_voice((SAMPLE *)playlist[i].data_ptr);
488
489       if (snd_ctrl.loop)
490         voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
491
492       voice_set_volume(playlist[i].voice, snd_ctrl.volume);
493       voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
494       voice_start(playlist[i].voice);       
495 #endif
496       break;
497     }
498   }
499 }
500
501 static void HandleSoundRequest(struct SoundControl snd_ctrl)
502 {
503   int i;
504
505   if (IS_RELOADING(snd_ctrl))           /* load new sound or music files */
506   {
507     ReadReloadInfoFromPipe(snd_ctrl);
508     InitPlaylist();
509     CloseAudioDevice(&audio.device_fd);
510
511     if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS)
512       ReloadCustomSounds();
513     else
514       ReloadCustomMusic();
515   }
516   else if (IS_FADING(snd_ctrl))         /* fade out existing sound or music */
517   {
518     if (!playing_sounds)
519       return;
520
521     if (IS_MUSIC(snd_ctrl))
522     {
523       playlist[audio.music_channel].state |= SND_CTRL_FADE;
524       return;
525     }
526
527     for(i=audio.first_sound_channel; i<audio.num_channels; i++)
528       if (playlist[i].nr == snd_ctrl.nr || ALL_SOUNDS(snd_ctrl))
529         playlist[i].state |= SND_CTRL_FADE;
530   }
531   else if (IS_STOPPING(snd_ctrl))       /* stop existing sound or music */
532   {
533     if (!playing_sounds)
534       return;
535
536     if (IS_MUSIC(snd_ctrl))
537     {
538       PlaylistRemoveSound(audio.music_channel);
539       return;
540     }
541
542     for(i=audio.first_sound_channel; i<audio.num_channels; i++)
543       if (playlist[i].nr == snd_ctrl.nr || ALL_SOUNDS(snd_ctrl))
544         PlaylistRemoveSound(i);
545
546     if (!playing_sounds)
547       CloseAudioDevice(&audio.device_fd);
548   }
549   else if (snd_ctrl.active)             /* add new sound to playlist */
550   {
551     SoundServer_InsertNewSound(snd_ctrl);
552   }
553 }
554
555 void StartSoundserver(void)
556 {
557   if (!audio.sound_available)
558     return;
559
560 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
561   if (!ForkAudioProcess())
562     audio.sound_available = FALSE;
563 #endif
564 }
565
566 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
567
568 static void CopySampleToMixingBuffer(struct SoundControl *snd_ctrl,
569                                      int sample_pos, int sample_size,
570                                      short *buffer_ptr)
571 {
572   void *sample_ptr = snd_ctrl->data_ptr;
573   int i;
574
575   if (snd_ctrl->format == AUDIO_FORMAT_U8)
576     for (i=0; i<sample_size; i++)
577       *buffer_ptr++ =
578         ((short)(((byte *)sample_ptr)[sample_pos + i] ^ 0x80)) << 8;
579   else  /* AUDIO_FORMAT_S16 */
580     for (i=0; i<sample_size; i++)
581       *buffer_ptr++ =
582         ((short *)sample_ptr)[sample_pos + i];
583 }
584
585 #if defined(AUDIO_STREAMING_DSP)
586 static void SoundServer_Mixer()
587 {
588   static int stereo_volume[PSND_MAX_LEFT2RIGHT + 1];
589   static boolean stereo_volume_calculated = FALSE;
590   static short premix_first_buffer[SND_BLOCKSIZE];
591   static short premix_left_buffer[SND_BLOCKSIZE];
592   static short premix_right_buffer[SND_BLOCKSIZE];
593   static long premix_last_buffer[SND_BLOCKSIZE];
594   static byte playing_buffer[SND_BLOCKSIZE];
595   int max_sample_size;
596   int fragment_size = afmt.fragment_size;
597   int sample_bytes = (afmt.format & AUDIO_FORMAT_U8 ? 1 : 2);
598   boolean stereo = afmt.stereo;
599   int i, j;
600
601   if (!stereo_volume_calculated)
602   {
603     for(i=0; i<=PSND_MAX_LEFT2RIGHT; i++)
604       stereo_volume[i] =
605         (int)sqrt((float)(PSND_MAX_LEFT2RIGHT * PSND_MAX_LEFT2RIGHT - i * i));
606
607     stereo_volume_calculated = TRUE;
608   }
609
610   if (!playing_sounds)
611     return;
612
613   if (audio.device_fd < 0)
614   {
615     if ((audio.device_fd = OpenAudioDevice(audio.device_name)) < 0)
616       return;
617
618     InitAudioDevice(&afmt);
619   }
620
621   max_sample_size = fragment_size / ((stereo ? 2 : 1) * sample_bytes);
622
623   /* first clear the last premixing buffer */
624   memset(premix_last_buffer, 0,
625          max_sample_size * (stereo ? 2 : 1) * sizeof(long));
626
627   for(i=0; i<audio.num_channels; i++)
628   {
629     void *sample_ptr;
630     int sample_len;
631     int sample_pos;
632     int sample_size;
633
634     if (!playlist[i].active)
635       continue;
636
637     /* pointer, lenght and actual playing position of sound sample */
638     sample_ptr = playlist[i].data_ptr;
639     sample_len = playlist[i].data_len;
640     sample_pos = playlist[i].playingpos;
641     sample_size = MIN(max_sample_size, sample_len - sample_pos);
642     playlist[i].playingpos += sample_size;
643
644     /* copy original sample to first mixing buffer */
645     CopySampleToMixingBuffer(&playlist[i], sample_pos, sample_size,
646                              premix_first_buffer);
647
648     /* are we about to restart a looping sound? */
649     if (IS_LOOP(playlist[i]) && sample_size < max_sample_size)
650     {
651       while (sample_size < max_sample_size)
652       {
653         int restarted_sample_size =
654           MIN(max_sample_size - sample_size, sample_len);
655
656         if (playlist[i].format == AUDIO_FORMAT_U8)
657           for (j=0; j<restarted_sample_size; j++)
658             premix_first_buffer[sample_size + j] =
659               ((short)(((byte *)sample_ptr)[j] ^ 0x80)) << 8;
660         else
661           for (j=0; j<restarted_sample_size; j++)
662             premix_first_buffer[sample_size + j] =
663               ((short *)sample_ptr)[j];
664
665         playlist[i].playingpos = restarted_sample_size;
666         sample_size += restarted_sample_size;
667       }
668     }
669
670     /* decrease volume if sound is fading out */
671     if (IS_FADING(playlist[i]) &&
672         playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
673       playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
674
675     /* adjust volume of actual sound sample */
676     if (playlist[i].volume != PSND_MAX_VOLUME)
677       for(j=0; j<sample_size; j++)
678         premix_first_buffer[j] =
679           (playlist[i].volume * (long)premix_first_buffer[j])
680             >> PSND_MAX_VOLUME_BITS;
681
682     /* fill the last mixing buffer with stereo or mono sound */
683     if (stereo)
684     {
685       int middle_pos = PSND_MAX_LEFT2RIGHT / 2;
686       int left_volume = stereo_volume[middle_pos + playlist[i].stereo];
687       int right_volume= stereo_volume[middle_pos - playlist[i].stereo];
688
689       for(j=0; j<sample_size; j++)
690       {
691         premix_left_buffer[j] =
692           (left_volume * premix_first_buffer[j])
693             >> PSND_MAX_LEFT2RIGHT_BITS;
694         premix_right_buffer[j] =
695           (right_volume * premix_first_buffer[j])
696             >> PSND_MAX_LEFT2RIGHT_BITS;
697
698         premix_last_buffer[2 * j + 0] += premix_left_buffer[j];
699         premix_last_buffer[2 * j + 1] += premix_right_buffer[j];
700       }
701     }
702     else
703     {
704       for(j=0; j<sample_size; j++)
705         premix_last_buffer[j] += premix_first_buffer[j];
706     }
707
708     /* delete completed sound entries from the playlist */
709     if (playlist[i].playingpos >= playlist[i].data_len)
710     {
711       if (IS_LOOP(playlist[i]))
712         playlist[i].playingpos = 0;
713       else
714         PlaylistRemoveSound(i);
715     }
716     else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
717       PlaylistRemoveSound(i);
718   }
719
720   /* prepare final playing buffer according to system audio format */
721   for(i=0; i<max_sample_size * (stereo ? 2 : 1); i++)
722   {
723     /* cut off at 17 bit value */
724     if (premix_last_buffer[i] < -65535)
725       premix_last_buffer[i] = -65535;
726     else if (premix_last_buffer[i] > 65535)
727       premix_last_buffer[i] = 65535;
728
729     /* shift to 16 bit value */
730     premix_last_buffer[i] >>= 1;
731
732     if (afmt.format & AUDIO_FORMAT_U8)
733     {
734       playing_buffer[i] = (premix_last_buffer[i] >> 8) ^ 0x80;
735     }
736     else if (afmt.format & AUDIO_FORMAT_LE)     /* 16 bit */
737     {
738       playing_buffer[2 * i + 0] = premix_last_buffer[i] & 0xff;
739       playing_buffer[2 * i + 1] = premix_last_buffer[i] >> 8;
740     }
741     else                                        /* big endian */
742     {
743       playing_buffer[2 * i + 0] = premix_last_buffer[i] >> 8;
744       playing_buffer[2 * i + 1] = premix_last_buffer[i] & 0xff;
745     }
746   }
747
748   /* finally play the sound fragment */
749   write(audio.device_fd, playing_buffer, fragment_size);
750
751   if (!playing_sounds)
752     CloseAudioDevice(&audio.device_fd);
753 }
754
755 #else /* !AUDIO_STREAMING_DSP */
756
757 static int SoundServer_SimpleAudio(struct SoundControl snd_ctrl)
758 {
759   static short premix_first_buffer[SND_BLOCKSIZE];
760   static byte playing_buffer[SND_BLOCKSIZE];
761   int max_sample_size = SND_BLOCKSIZE;
762   void *sample_ptr;
763   int sample_len;
764   int sample_pos;
765   int sample_size;
766   int i, j;
767
768   i = 1;
769
770   /* pointer, lenght and actual playing position of sound sample */
771   sample_ptr = playlist[i].data_ptr;
772   sample_len = playlist[i].data_len;
773   sample_pos = playlist[i].playingpos;
774   sample_size = MIN(max_sample_size, sample_len - sample_pos);
775   playlist[i].playingpos += sample_size;
776
777   /* copy original sample to first mixing buffer */
778   CopySampleToMixingBuffer(&playlist[i], sample_pos, sample_size,
779                            premix_first_buffer);
780
781   /* adjust volume of actual sound sample */
782   if (playlist[i].volume != PSND_MAX_VOLUME)
783     for(j=0; j<sample_size; j++)
784       premix_first_buffer[j] =
785         (playlist[i].volume * (long)premix_first_buffer[j])
786           >> PSND_MAX_VOLUME_BITS;
787
788   /* might be needed for u-law /dev/audio */
789 #if 0
790   for(j=0; j<sample_size; j++)
791     playing_buffer[j] =
792       linear_to_ulaw(premix_first_buffer[j]);
793 #endif
794
795   /* delete completed sound entries from the playlist */
796   if (playlist[i].playingpos >= playlist[i].data_len)
797     PlaylistRemoveSound(i);
798
799   for(i=0; i<sample_size; i++)
800     playing_buffer[i] = (premix_first_buffer[i] >> 8) ^ 0x80;
801
802   /* finally play the sound fragment */
803   write(audio.device_fd, playing_buffer, sample_size);
804
805   return sample_size;
806 }
807 #endif /* !AUDIO_STREAMING_DSP */
808
809 void SoundServer()
810 {
811   struct SoundControl snd_ctrl;
812   fd_set sound_fdset;
813
814   close(audio.soundserver_pipe[1]);     /* no writing into pipe needed */
815
816   InitPlaylist();
817
818 #if defined(PLATFORM_HPUX)
819   InitAudioDevice(&afmt);
820 #endif
821
822   FD_ZERO(&sound_fdset); 
823   FD_SET(audio.soundserver_pipe[0], &sound_fdset);
824
825   while(1)      /* wait for sound playing commands from client */
826   {
827     struct timeval delay = { 0, 0 };
828
829     FD_SET(audio.soundserver_pipe[0], &sound_fdset);
830     select(audio.soundserver_pipe[0] + 1, &sound_fdset, NULL, NULL, NULL);
831     if (!FD_ISSET(audio.soundserver_pipe[0], &sound_fdset))
832       continue;
833     if (read(audio.soundserver_pipe[0], &snd_ctrl, sizeof(snd_ctrl))
834         != sizeof(snd_ctrl))
835       Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
836
837     HandleSoundRequest(snd_ctrl);
838
839 #if defined(AUDIO_STREAMING_DSP)
840
841     while (playing_sounds && select(audio.soundserver_pipe[0] + 1,
842                                     &sound_fdset, NULL, NULL, &delay) < 1)
843     {
844       FD_SET(audio.soundserver_pipe[0], &sound_fdset);
845
846       SoundServer_Mixer();
847     }
848
849 #else /* !AUDIO_STREAMING_DSP */
850
851     if (!snd_ctrl.active || IS_LOOP(snd_ctrl) ||
852         (audio.device_fd = OpenAudioDevice(audio.device_name)) < 0)
853       continue;
854
855     InitAudioDevice(&afmt);
856
857     delay.tv_sec = 0;
858     delay.tv_usec = 0;
859
860     while (playing_sounds && select(audio.soundserver_pipe[0] + 1,
861                                     &sound_fdset, NULL, NULL, &delay) < 1)
862     {
863       int wait_percent = 90;    /* wait 90% of the real playing time */
864       int sample_size;
865
866       FD_SET(audio.soundserver_pipe[0], &sound_fdset);
867
868       sample_size = SoundServer_SimpleAudio(snd_ctrl);
869
870       delay.tv_sec = 0;
871       delay.tv_usec =
872         ((sample_size * 10 * wait_percent) / afmt.sample_rate) * 1000;
873     }
874
875     CloseAudioDevice(&audio.device_fd);
876
877     /* delete all sounds from playlist */
878     InitPlaylist();
879
880 #endif /* !AUDIO_STREAMING_DSP */
881   }
882 }
883 #endif /* PLATFORM_UNIX */
884
885 #if defined(PLATFORM_MSDOS)
886 static void sound_handler(struct SoundControl snd_ctrl)
887 {
888   int i;
889
890   if (snd_ctrl.fade_sound)
891   {
892     if (!playing_sounds)
893       return;
894
895     for (i=0; i<audio.num_channels; i++)
896       if ((snd_ctrl.stop_all_sounds ||
897            (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr) ||
898            (i == audio.music_channel && snd_ctrl.music)) &&
899           !playlist[i].fade_sound)
900       {
901         playlist[i].fade_sound = TRUE;
902         if (voice_check(playlist[i].voice))
903           voice_ramp_volume(playlist[i].voice, 1000, 0);
904         playlist[i].state &= ~SND_CTRL_IS_LOOP;
905       }
906   }
907   else if (snd_ctrl.stop_all_sounds)
908   {
909     if (!playing_sounds)
910       return;
911     SoundServer_StopAllSounds();
912   }
913   else if (snd_ctrl.stop_sound)
914   {
915     if (!playing_sounds)
916       return;
917     SoundServer_StopSound(snd_ctrl);
918   }
919
920   for (i=0; i<audio.num_channels; i++)
921   {
922     if (!playlist[i].active || playlist[i].loop)
923       continue;
924
925     playlist[i].playingpos = voice_get_position(playlist[i].voice);
926     playlist[i].volume = voice_get_volume(playlist[i].voice);
927     if (playlist[i].playingpos == -1 || !playlist[i].volume)
928     {
929       deallocate_voice(playlist[i].voice);
930       PlaylistRemoveSound(i);
931     }
932   }
933
934   if (snd_ctrl.active)
935     SoundServer_InsertNewSound(snd_ctrl);
936 }
937 #endif /* PLATFORM_MSDOS */
938
939 #if 0
940 #if defined(TARGET_SDL)
941 static void sound_handler_SDL(struct SoundControl snd_ctrl)
942 {
943   /* copy sound_handler() here ... */
944 }
945 #endif /* TARGET_SDL */
946 #endif
947
948 #if !defined(PLATFORM_WIN32)
949 static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
950 {
951   SoundInfo *snd_info;
952   int i, k;
953
954 #if 0
955   printf("NEW SOUND %d HAS ARRIVED [%d]\n", snd_ctrl.nr, num_sounds);
956 #endif
957
958   if (IS_MUSIC(snd_ctrl))
959     snd_ctrl.nr = snd_ctrl.nr % num_music;
960   else if (snd_ctrl.nr >= num_sounds)
961     return;
962
963   snd_info = (IS_MUSIC(snd_ctrl) ? Music[snd_ctrl.nr] : Sound[snd_ctrl.nr]);
964   if (snd_info == NULL)
965   {
966 #if 0
967     printf("sound/music %d undefined\n", snd_ctrl.nr);
968 #endif
969     return;
970   }
971
972 #if 0
973   printf("-> %d\n", playing_sounds);
974 #endif
975
976   if (playing_sounds == audio.num_channels)
977   {
978     for (i=0; i<audio.num_channels; i++)
979     {
980       if (playlist[i].data_ptr == NULL)
981       {
982 #if 1
983         printf("THIS SHOULD NEVER HAPPEN! [%d]\n", i);
984 #endif
985
986         PlaylistRemoveSound(i);
987       }
988     }
989   }
990
991   /* if playlist is full, remove oldest sound */
992   if (playing_sounds == audio.num_channels)
993   {
994     int longest = 0, longest_nr = 0;
995
996     for (i=audio.first_sound_channel; i<audio.num_channels; i++)
997     {
998 #if !defined(PLATFORM_MSDOS)
999       int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
1000 #else
1001       int actual = playlist[i].playingpos;
1002 #endif
1003
1004       if (!IS_LOOP(playlist[i]) && actual > longest)
1005       {
1006         longest = actual;
1007         longest_nr = i;
1008       }
1009     }
1010 #if defined(PLATFORM_MSDOS)
1011     voice_set_volume(playlist[longest_nr].voice, 0);
1012     deallocate_voice(playlist[longest_nr].voice);
1013 #endif
1014     PlaylistRemoveSound(longest_nr);
1015   }
1016
1017   /* check if sound is already being played (and how often) */
1018   for (k=0, i=audio.first_sound_channel; i<audio.num_channels; i++)
1019     if (playlist[i].nr == snd_ctrl.nr)
1020       k++;
1021
1022   /* restart loop sounds only if they are just fading out */
1023   if (k >= 1 && IS_LOOP(snd_ctrl))
1024   {
1025     for(i=audio.first_sound_channel; i<audio.num_channels; i++)
1026     {
1027       if (playlist[i].nr == snd_ctrl.nr && IS_FADING(playlist[i]))
1028       {
1029         playlist[i].state &= ~SND_CTRL_FADE;
1030         playlist[i].volume = PSND_MAX_VOLUME;
1031 #if defined(PLATFORM_MSDOS)
1032         playlist[i].state |= SND_CTRL_LOOP;
1033         voice_stop_volumeramp(playlist[i].voice);
1034         voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
1035 #endif
1036       }
1037     }
1038
1039     return;
1040   }
1041
1042   /* don't play sound more than n times simultaneously (with n == 2 for now) */
1043   if (k >= 2)
1044   {
1045     int longest = 0, longest_nr = 0;
1046
1047     /* look for oldest equal sound */
1048     for(i=audio.first_sound_channel; i<audio.num_channels; i++)
1049     {
1050       int actual;
1051
1052       if (!playlist[i].active || playlist[i].nr != snd_ctrl.nr)
1053         continue;
1054
1055 #if !defined(PLATFORM_MSDOS)
1056       actual = 100 * playlist[i].playingpos / playlist[i].data_len;
1057 #else
1058       actual = playlist[i].playingpos;
1059 #endif
1060       if (actual >= longest)
1061       {
1062         longest = actual;
1063         longest_nr = i;
1064       }
1065     }
1066
1067 #if defined(PLATFORM_MSDOS)
1068     voice_set_volume(playlist[longest_nr].voice, 0);
1069     deallocate_voice(playlist[longest_nr].voice);
1070 #endif
1071     PlaylistRemoveSound(longest_nr);
1072   }
1073
1074   /* add new sound to playlist */
1075   for(i=0; i<audio.num_channels; i++)
1076   {
1077 #if 0
1078     printf("CHECKING CHANNEL %d FOR SOUND %d ...\n", i, snd_ctrl.nr);
1079 #endif
1080
1081     /*
1082     if (!playlist[i].active ||
1083         (IS_MUSIC(snd_ctrl) && i == audio.music_channel))
1084     */
1085     if ((i == audio.music_channel && IS_MUSIC(snd_ctrl)) ||
1086         (i != audio.music_channel && !playlist[i].active))
1087     {
1088       snd_ctrl.data_ptr = snd_info->data_ptr;
1089       snd_ctrl.data_len = snd_info->data_len;
1090       snd_ctrl.format   = snd_info->format;
1091
1092       snd_ctrl.playingpos = 0;
1093       snd_ctrl.playingtime = 0;
1094
1095 #if 1
1096       if (snd_info->data_len == 0)
1097       {
1098         printf("THIS SHOULD NEVER HAPPEN! [snd_info->data_len == 0]\n");
1099       }
1100 #endif
1101
1102 #if 1
1103       if (IS_MUSIC(snd_ctrl) && i == audio.music_channel && playlist[i].active)
1104       {
1105         printf("THIS SHOULD NEVER HAPPEN! [adding music twice]\n");
1106
1107 #if 1
1108         PlaylistRemoveSound(i);
1109 #endif
1110       }
1111 #endif
1112
1113       playlist[i] = snd_ctrl;
1114       playing_sounds++;
1115
1116 #if 0
1117       printf("NEW SOUND %d ADDED TO PLAYLIST\n", snd_ctrl.nr);
1118 #endif
1119
1120 #if defined(PLATFORM_MSDOS)
1121       playlist[i].voice = allocate_voice((SAMPLE *)playlist[i].data_ptr);
1122
1123       if (snd_ctrl.loop)
1124         voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
1125
1126       voice_set_volume(playlist[i].voice, snd_ctrl.volume);
1127       voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
1128       voice_start(playlist[i].voice);       
1129 #endif
1130       break;
1131     }
1132   }
1133 }
1134 #endif /* !PLATFORM_WIN32 */
1135
1136 /*
1137 void SoundServer_FadeSound(int nr)
1138 {
1139   int i;
1140
1141   if (!playing_sounds)
1142     return;
1143
1144   for(i=0;i<audio.num_channels;i++)
1145     if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
1146       playlist[i].fade_sound = TRUE;
1147 }
1148 */
1149
1150 #if !defined(PLATFORM_WIN32)
1151 #if defined(PLATFORM_MSDOS)
1152 static void SoundServer_StopSound(struct SoundControl snd_ctrl)
1153 {
1154   int nr = snd_ctrl.nr;
1155   int i;
1156
1157   if (!playing_sounds)
1158     return;
1159
1160   for(i=0; i<audio.num_channels; i++)
1161   {
1162     if ((i == audio.music_channel && snd_ctrl.music) ||
1163         (i != audio.music_channel && playlist[i].nr == nr))
1164     {
1165 #if defined(PLATFORM_MSDOS)
1166       voice_set_volume(playlist[i].voice, 0);
1167       deallocate_voice(playlist[i].voice);
1168 #endif
1169       PlaylistRemoveSound(i);
1170     }
1171   }
1172
1173 #if !defined(PLATFORM_MSDOS)
1174   if (!playing_sounds)
1175     close(audio.device_fd);
1176 #endif
1177 }
1178
1179 static void SoundServer_StopAllSounds()
1180 {
1181   int i;
1182
1183   for(i=0; i<audio.num_channels; i++)
1184   {
1185 #if defined(PLATFORM_MSDOS)
1186     voice_set_volume(playlist[i].voice, 0);
1187     deallocate_voice(playlist[i].voice);
1188 #endif
1189     PlaylistRemoveSound(i);
1190   }
1191   playing_sounds = 0;
1192
1193 #if !defined(PLATFORM_MSDOS)
1194   close(audio.device_fd);
1195 #endif
1196 }
1197 #endif /* PLATFORM_MSDOS */
1198 #endif /* !PLATFORM_WIN32 */
1199
1200
1201 /* ------------------------------------------------------------------------- */
1202 /* platform dependant audio initialization code                              */
1203 /* ------------------------------------------------------------------------- */
1204
1205 #if defined(AUDIO_LINUX_IOCTL)
1206 static void InitAudioDevice_Linux(struct AudioFormatInfo *afmt)
1207 {
1208   /* "ioctl()" expects pointer to 'int' value for stereo flag
1209      (boolean is defined as 'char', which will not work here) */
1210   unsigned int fragment_spec = 0;
1211   int fragment_size_query;
1212   int stereo = TRUE;
1213   struct
1214   {
1215     int format_ioctl;
1216     int format_result;
1217   }
1218   formats[] =
1219   {
1220     /* supported audio format in preferred order */
1221     { AFMT_S16_LE,      AUDIO_FORMAT_S16 | AUDIO_FORMAT_LE },
1222     { AFMT_S16_BE,      AUDIO_FORMAT_S16 | AUDIO_FORMAT_BE },
1223     { AFMT_U8,          AUDIO_FORMAT_U8                    },
1224     { -1,               -1 }
1225   };
1226   int i;
1227
1228   /* determine logarithm (log2) of the fragment size */
1229   while ((1 << fragment_spec) < afmt->fragment_size)
1230     fragment_spec++;
1231
1232   /* use two fragments (play one fragment, prepare the other);
1233      one fragment would result in interrupted audio output, more
1234      than two fragments would raise audio output latency to much */
1235   fragment_spec |= 0x00020000;
1236
1237   /* Example for fragment specification:
1238      - 2 buffers / 512 bytes (giving 1/16 second resolution for 8 kHz)
1239      - (with stereo the effective buffer size will shrink to 256)
1240      => fragment_size = 0x00020009 */
1241
1242   if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0)
1243     Error(ERR_EXIT_SOUND_SERVER,
1244           "cannot set fragment size of /dev/dsp -- no sounds");
1245
1246   i = 0;
1247   afmt->format = 0;
1248   while (formats[i].format_result != -1)
1249   {
1250     unsigned int audio_format = formats[i].format_ioctl;
1251     if (ioctl(audio.device_fd, SNDCTL_DSP_SETFMT, &audio_format) == 0)
1252     {
1253       afmt->format = formats[i].format_result;
1254       break;
1255     }
1256   }
1257
1258   if (afmt->format == 0)        /* no supported audio format found */
1259     Error(ERR_EXIT_SOUND_SERVER,
1260           "cannot set audio format of /dev/dsp -- no sounds");
1261
1262   /* try if we can use stereo sound */
1263   afmt->stereo = TRUE;
1264   if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
1265     afmt->stereo = FALSE;
1266
1267   if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &afmt->sample_rate) < 0)
1268     Error(ERR_EXIT_SOUND_SERVER,
1269           "cannot set sample rate of /dev/dsp -- no sounds");
1270
1271   /* get the real fragmentation size; this should return 512 */
1272   if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size_query) < 0)
1273     Error(ERR_EXIT_SOUND_SERVER,
1274           "cannot get fragment size of /dev/dsp -- no sounds");
1275   if (fragment_size_query != afmt->fragment_size)
1276     Error(ERR_EXIT_SOUND_SERVER,
1277           "cannot set fragment size of /dev/dsp -- no sounds");
1278 }
1279 #endif  /* AUDIO_LINUX_IOCTL */
1280
1281 #if defined(PLATFORM_NETBSD)
1282 static void InitAudioDevice_NetBSD(struct AudioFormatInfo *afmt)
1283 {
1284   audio_info_t a_info;
1285   boolean stereo = TRUE;
1286
1287   AUDIO_INITINFO(&a_info);
1288   a_info.play.encoding = AUDIO_ENCODING_LINEAR8;
1289   a_info.play.precision = 8;
1290   a_info.play.channels = 2;
1291   a_info.play.sample_rate = sample_rate;
1292   a_info.blocksize = fragment_size;
1293
1294   afmt->format = AUDIO_FORMAT_U8;
1295   afmt->stereo = TRUE;
1296
1297   if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
1298   {
1299     /* try to disable stereo */
1300     a_info.play.channels = 1;
1301
1302     afmt->stereo = FALSE;
1303
1304     if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
1305       Error(ERR_EXIT_SOUND_SERVER,
1306             "cannot set sample rate of /dev/audio -- no sounds");
1307   }
1308 }
1309 #endif /* PLATFORM_NETBSD */
1310
1311 #if defined(PLATFORM_HPUX)
1312 static void InitAudioDevice_HPUX(struct AudioFormatInfo *afmt)
1313 {
1314   struct audio_describe ainfo;
1315   int audio_ctl;
1316
1317   audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
1318   if (audio_ctl == -1)
1319     Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl -- no sounds");
1320
1321   if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
1322     Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds");
1323
1324   if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
1325     Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds");
1326
1327   ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
1328   ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
1329
1330   afmt->format = AUDIO_FORMAT_U8;
1331   afmt->stereo = FALSE;
1332   afmt->sample_rate = 8000;
1333
1334   close(audio_ctl);
1335 }
1336 #endif /* PLATFORM_HPUX */
1337
1338 #if defined(PLATFORM_UNIX)
1339 static void InitAudioDevice(struct AudioFormatInfo *afmt)
1340 {
1341 #if defined(AUDIO_LINUX_IOCTL)
1342   InitAudioDevice_Linux(afmt);
1343 #elif defined(PLATFORM_NETBSD)
1344   InitAudioDevice_NetBSD(afmt);
1345 #elif defined(PLATFORM_HPUX)
1346   InitAudioDevice_HPUX(afmt);
1347 #else
1348   /* generic /dev/audio stuff might be placed here */
1349 #endif
1350 }
1351 #endif /* PLATFORM_UNIX */
1352
1353 #if defined(PLATFORM_UNIX) && !defined(AUDIO_STREAMING_DSP)
1354
1355 /* these two are stolen from "sox"... :) */
1356
1357 /*
1358 ** This routine converts from linear to ulaw.
1359 **
1360 ** Craig Reese: IDA/Supercomputing Research Center
1361 ** Joe Campbell: Department of Defense
1362 ** 29 September 1989
1363 **
1364 ** References:
1365 ** 1) CCITT Recommendation G.711  (very difficult to follow)
1366 ** 2) "A New Digital Technique for Implementation of Any
1367 **     Continuous PCM Companding Law," Villeret, Michel,
1368 **     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
1369 **     1973, pg. 11.12-11.17
1370 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
1371 **     for Analog-to_Digital Conversion Techniques,"
1372 **     17 February 1987
1373 **
1374 ** Input: Signed 16 bit linear sample
1375 ** Output: 8 bit ulaw sample
1376 */
1377
1378 #define ZEROTRAP    /* turn on the trap as per the MIL-STD */
1379 #define BIAS 0x84   /* define the add-in bias for 16 bit samples */
1380 #define CLIP 32635
1381
1382 static unsigned char linear_to_ulaw(int sample)
1383 {
1384   static int exp_lut[256] =
1385   {
1386     0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
1387     4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
1388     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
1389     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
1390     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1391     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1392     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1393     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1394     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1395     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1396     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1397     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1398     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1399     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1400     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1401     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
1402   };
1403
1404   int sign, exponent, mantissa;
1405   unsigned char ulawbyte;
1406
1407   /* Get the sample into sign-magnitude. */
1408   sign = (sample >> 8) & 0x80;          /* set aside the sign */
1409   if (sign != 0)
1410     sample = -sample;                   /* get magnitude */
1411   if (sample > CLIP)
1412     sample = CLIP;                      /* clip the magnitude */
1413
1414   /* Convert from 16 bit linear to ulaw. */
1415   sample = sample + BIAS;
1416   exponent = exp_lut[( sample >> 7 ) & 0xFF];
1417   mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
1418   ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
1419 #ifdef ZEROTRAP
1420   if (ulawbyte == 0)
1421     ulawbyte = 0x02;                    /* optional CCITT trap */
1422 #endif
1423
1424   return(ulawbyte);
1425 }
1426
1427 /*
1428 ** This routine converts from ulaw to 16 bit linear.
1429 **
1430 ** Craig Reese: IDA/Supercomputing Research Center
1431 ** 29 September 1989
1432 **
1433 ** References:
1434 ** 1) CCITT Recommendation G.711  (very difficult to follow)
1435 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
1436 **     for Analog-to_Digital Conversion Techniques,"
1437 **     17 February 1987
1438 **
1439 ** Input: 8 bit ulaw sample
1440 ** Output: signed 16 bit linear sample
1441 */
1442
1443 static int ulaw_to_linear(unsigned char ulawbyte)
1444 {
1445   static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
1446   int sign, exponent, mantissa, sample;
1447
1448   ulawbyte = ~ ulawbyte;
1449   sign = ( ulawbyte & 0x80 );
1450   exponent = ( ulawbyte >> 4 ) & 0x07;
1451   mantissa = ulawbyte & 0x0F;
1452   sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
1453   if (sign != 0)
1454     sample = -sample;
1455
1456   return(sample);
1457 }
1458 #endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */
1459
1460
1461 /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS            */
1462 /* ========================================================================= */
1463 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS                          */
1464
1465 #define CHUNK_ID_LEN            4       /* IFF style chunk id length */
1466 #define WAV_HEADER_SIZE         16      /* size of WAV file header */
1467
1468 static SoundInfo *Load_WAV(char *filename)
1469 {
1470   SoundInfo *snd_info;
1471 #if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS)
1472   byte sound_header_buffer[WAV_HEADER_SIZE];
1473   char chunk_name[CHUNK_ID_LEN + 1];
1474   int chunk_size;
1475   FILE *file;
1476   int i;
1477 #endif
1478
1479   if (!audio.sound_available)
1480     return NULL;
1481
1482 #if 0
1483   printf("loading WAV file '%s'\n", filename);
1484 #endif
1485
1486   snd_info = checked_calloc(sizeof(SoundInfo));
1487
1488 #if defined(TARGET_SDL)
1489
1490   if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
1491   {
1492     Error(ERR_WARN, "cannot read sound file '%s'", filename);
1493     free(snd_info);
1494     return NULL;
1495   }
1496
1497 #elif defined(TARGET_ALLEGRO)
1498
1499   if ((snd_info->data_ptr = load_sample(filename)) == NULL)
1500   {
1501     Error(ERR_WARN, "cannot read sound file '%s'", filename);
1502     free(snd_info);
1503     return NULL;
1504   }
1505
1506 #else   /* PLATFORM_UNIX */
1507
1508   if ((file = fopen(filename, MODE_READ)) == NULL)
1509   {
1510     Error(ERR_WARN, "cannot open sound file '%s'", filename);
1511     free(snd_info);
1512     return NULL;
1513   }
1514
1515   /* read chunk id "RIFF" */
1516   getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
1517   if (strcmp(chunk_name, "RIFF") != 0)
1518   {
1519     Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
1520     fclose(file);
1521     free(snd_info);
1522     return NULL;
1523   }
1524
1525   /* read "RIFF" type id "WAVE" */
1526   getFileChunk(file, chunk_name, NULL, BYTE_ORDER_LITTLE_ENDIAN);
1527   if (strcmp(chunk_name, "WAVE") != 0)
1528   {
1529     Error(ERR_WARN, "missing 'WAVE' type ID of sound file '%s'", filename);
1530     fclose(file);
1531     free(snd_info);
1532     return NULL;
1533   }
1534
1535   while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN))
1536   {
1537     if (strcmp(chunk_name, "fmt ") == 0)
1538     {
1539       /* read header information */
1540       for (i=0; i < MIN(chunk_size, WAV_HEADER_SIZE); i++)
1541         sound_header_buffer[i] = fgetc(file);
1542
1543       if (chunk_size > WAV_HEADER_SIZE)
1544         ReadUnusedBytesFromFile(file, chunk_size - WAV_HEADER_SIZE);
1545     }
1546     else if (strcmp(chunk_name, "data") == 0)
1547     {
1548       snd_info->data_len = chunk_size;
1549       snd_info->data_ptr = checked_malloc(snd_info->data_len);
1550
1551       /* read sound data */
1552       if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
1553           snd_info->data_len)
1554       {
1555         Error(ERR_WARN,"cannot read 'data' chunk of sound file '%s'",filename);
1556         fclose(file);
1557         free(snd_info->data_ptr);
1558         free(snd_info);
1559         return NULL;
1560       }
1561
1562       /* check for odd number of sample bytes (data chunk is word aligned) */
1563       if ((chunk_size % 2) == 1)
1564         ReadUnusedBytesFromFile(file, 1);
1565     }
1566     else        /* unknown chunk -- ignore */
1567       ReadUnusedBytesFromFile(file, chunk_size);
1568   }
1569
1570   fclose(file);
1571
1572   if (snd_info->data_ptr == NULL)
1573   {
1574     Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
1575     free(snd_info);
1576     return NULL;
1577   }
1578
1579   snd_info->format = AUDIO_FORMAT_U8;
1580
1581 #endif  /* PLATFORM_UNIX */
1582
1583   snd_info->type = SND_TYPE_WAV;
1584   snd_info->source_filename = getStringCopy(filename);
1585
1586   return snd_info;
1587 }
1588
1589 static void deleteSoundEntry(SoundInfo **snd_info)
1590 {
1591   if (*snd_info)
1592   {
1593     char *filename = (*snd_info)->source_filename;
1594
1595 #if 0
1596     printf("[decrementing reference counter of sound '%s']\n", filename);
1597 #endif
1598
1599     if (--(*snd_info)->num_references <= 0)
1600     {
1601 #if 0
1602       printf("[deleting sound '%s']\n", filename);
1603 #endif
1604
1605       /*
1606       FreeSound(*snd_info);
1607       */
1608       deleteNodeFromList(&SoundFileList, filename, FreeSound);
1609     }
1610
1611     *snd_info = NULL;
1612   }
1613 }
1614
1615 static void replaceSoundEntry(SoundInfo **snd_info, char *filename)
1616 {
1617   ListNode *node;
1618
1619   /* check if the old and the new sound file are the same */
1620   if (*snd_info && strcmp((*snd_info)->source_filename, filename) == 0)
1621   {
1622     /* The old and new sound are the same (have the same filename and path).
1623        This usually means that this sound does not exist in this sound set
1624        and a fallback to the existing sound is done. */
1625
1626 #if 0
1627     printf("[sound '%s' already exists (same list entry)]\n", filename);
1628 #endif
1629
1630     return;
1631   }
1632
1633   /* delete existing sound file entry */
1634   deleteSoundEntry(snd_info);
1635
1636   /* check if the new sound file already exists in the list of sounds */
1637   if ((node = getNodeFromKey(SoundFileList, filename)) != NULL)
1638   {
1639 #if 0
1640       printf("[sound '%s' already exists (other list entry)]\n", filename);
1641 #endif
1642
1643       *snd_info = (SoundInfo *)node->content;
1644       (*snd_info)->num_references++;
1645   }
1646   else if ((*snd_info = Load_WAV(filename)) != NULL)    /* load new sound */
1647   {
1648     (*snd_info)->num_references = 1;
1649     addNodeToList(&SoundFileList, (*snd_info)->source_filename, *snd_info);
1650   }
1651 }
1652
1653 static void LoadCustomSound(SoundInfo **snd_info, char *basename)
1654 {
1655   char *filename = getCustomSoundFilename(basename);
1656
1657   if (strcmp(basename, SND_FILE_UNDEFINED) == 0)
1658   {
1659     deleteSoundEntry(snd_info);
1660     return;
1661   }
1662
1663   if (filename == NULL)
1664   {
1665     Error(ERR_WARN, "cannot find sound file '%s'", basename);
1666     return;
1667   }
1668
1669   replaceSoundEntry(snd_info, filename);
1670 }
1671
1672 void InitSoundList(struct SoundEffectInfo *sounds_list, int num_list_entries)
1673 {
1674   if (Sound == NULL)
1675     Sound = checked_calloc(num_list_entries * sizeof(SoundInfo *));
1676
1677   sound_effect = sounds_list;
1678   num_sounds = num_list_entries;
1679 }
1680
1681 void LoadSoundToList(char *basename, int list_pos)
1682 {
1683   if (Sound == NULL || list_pos >= num_sounds)
1684     return;
1685
1686 #if 0
1687   printf("loading sound '%s' ...  [%d]\n",
1688          basename, getNumNodes(SoundFileList));
1689 #endif
1690
1691   LoadCustomSound(&Sound[list_pos], basename);
1692
1693 #if 0
1694   printf("loading sound '%s' done [%d]\n",
1695          basename, getNumNodes(SoundFileList));
1696 #endif
1697 }
1698
1699 static MusicInfo *Load_MOD(char *filename)
1700 {
1701 #if defined(TARGET_SDL)
1702   MusicInfo *mod_info;
1703
1704   if (!audio.sound_available)
1705     return NULL;
1706
1707   mod_info = checked_calloc(sizeof(MusicInfo));
1708
1709   if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
1710   {
1711     Error(ERR_WARN, "cannot read music file '%s'", filename);
1712     free(mod_info);
1713     return NULL;
1714   }
1715
1716   mod_info->type = MUS_TYPE_MOD;
1717   mod_info->source_filename = getStringCopy(filename);
1718
1719   return mod_info;
1720 #else
1721   return NULL;
1722 #endif
1723 }
1724
1725 void LoadCustomMusic(void)
1726 {
1727   char *music_directory = getCustomMusicDirectory();
1728   DIR *dir;
1729   struct dirent *dir_entry;
1730
1731   if (!audio.sound_available)
1732     return;
1733
1734   if ((dir = opendir(music_directory)) == NULL)
1735   {
1736     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
1737     audio.music_available = FALSE;
1738     return;
1739   }
1740
1741   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
1742   {
1743     char *basename = dir_entry->d_name;
1744     char *filename = getPath2(music_directory, basename);
1745     MusicInfo *mus_info = NULL;
1746
1747     if (FileIsSound(basename))
1748       mus_info = Load_WAV(filename);
1749     else if (FileIsMusic(basename))
1750       mus_info = Load_MOD(filename);
1751
1752     free(filename);
1753
1754     if (mus_info)
1755     {
1756       num_music++;
1757       Music = checked_realloc(Music, num_music * sizeof(MusicInfo *));
1758       Music[num_music -1] = mus_info;
1759     }
1760   }
1761
1762   closedir(dir);
1763
1764   if (num_music == 0)
1765     Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
1766           music_directory);
1767 }
1768
1769 void PlayMusic(int nr)
1770 {
1771   if (!audio.music_available)
1772     return;
1773
1774 #if defined(TARGET_SDL)
1775
1776   nr = nr % num_music;
1777
1778   if (Music[nr]->type == MUS_TYPE_MOD)
1779   {
1780     Mix_PlayMusic(Music[nr]->data_ptr, -1);
1781     Mix_VolumeMusic(SOUND_MAX_VOLUME);  /* must be _after_ Mix_PlayMusic()! */
1782   }
1783   else                          /* play WAV music loop */
1784   {
1785     Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
1786     Mix_PlayChannel(audio.music_channel, Music[nr]->data_ptr, -1);
1787   }
1788
1789 #else
1790
1791   PlaySoundMusic(nr);
1792
1793 #endif
1794 }
1795
1796 void PlaySound(int nr)
1797 {
1798   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, SND_CTRL_PLAY_SOUND);
1799 }
1800
1801 void PlaySoundStereo(int nr, int stereo)
1802 {
1803   PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, SND_CTRL_PLAY_SOUND);
1804 }
1805
1806 void PlaySoundLoop(int nr)
1807 {
1808   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, SND_CTRL_PLAY_LOOP);
1809 }
1810
1811 void PlaySoundMusic(int nr)
1812 {
1813   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, SND_CTRL_PLAY_MUSIC);
1814 }
1815
1816 void PlaySoundExt(int nr, int volume, int stereo, int state)
1817 {
1818   struct SoundControl snd_ctrl;
1819
1820   if (!audio.sound_available ||
1821       !audio.sound_enabled ||
1822       audio.sound_deactivated)
1823     return;
1824
1825   if (volume < PSND_MIN_VOLUME)
1826     volume = PSND_MIN_VOLUME;
1827   else if (volume > PSND_MAX_VOLUME)
1828     volume = PSND_MAX_VOLUME;
1829
1830   if (stereo < PSND_MAX_LEFT)
1831     stereo = PSND_MAX_LEFT;
1832   else if (stereo > PSND_MAX_RIGHT)
1833     stereo = PSND_MAX_RIGHT;
1834
1835   snd_ctrl.active = TRUE;
1836   snd_ctrl.nr     = nr;
1837   snd_ctrl.volume = volume;
1838   snd_ctrl.stereo = stereo;
1839   snd_ctrl.state  = state;
1840
1841 #if defined(TARGET_SDL)
1842   if (Sound[nr])
1843   {
1844     Mix_Volume(-1, SOUND_MAX_VOLUME);
1845     Mix_PlayChannel(-1, Sound[nr]->data_ptr, (state & SND_CTRL_LOOP ? -1 : 0));
1846   }
1847 #elif defined(PLATFORM_UNIX)
1848   if (audio.soundserver_pid == 0)       /* we are child process */
1849     return;
1850
1851   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1852   {
1853     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1854     audio.sound_available = audio.sound_enabled = FALSE;
1855     return;
1856   }
1857 #elif defined(PLATFORM_MSDOS)
1858   sound_handler(snd_ctrl);
1859 #endif
1860 }
1861
1862 void FadeMusic(void)
1863 {
1864   if (!audio.sound_available)
1865     return;
1866
1867 #if defined(TARGET_SDL)
1868   Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1869   Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
1870 #else
1871   StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
1872 #endif
1873 }
1874
1875 void FadeSound(int nr)
1876 {
1877   StopSoundExt(nr, SND_CTRL_FADE_SOUND);
1878 }
1879
1880 void FadeSounds()
1881 {
1882   FadeMusic();
1883   StopSoundExt(-1, SND_CTRL_FADE_ALL);
1884 }
1885
1886 void StopMusic(void)
1887 {
1888 #if defined(TARGET_SDL)
1889   if (!audio.sound_available)
1890     return;
1891
1892   Mix_HaltMusic();
1893   Mix_HaltChannel(audio.music_channel);
1894 #else
1895   StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
1896 #endif
1897 }
1898
1899 void StopSound(int nr)
1900 {
1901   StopSoundExt(nr, SND_CTRL_STOP_SOUND);
1902 }
1903
1904 void StopSounds()
1905 {
1906   StopMusic();
1907   StopSoundExt(-1, SND_CTRL_STOP_ALL);
1908 }
1909
1910 void StopSoundExt(int nr, int state)
1911 {
1912   struct SoundControl snd_ctrl;
1913
1914   if (!audio.sound_available)
1915     return;
1916
1917   snd_ctrl.active = FALSE;
1918   snd_ctrl.nr     = nr;
1919   snd_ctrl.state  = state;
1920
1921 #if defined(TARGET_SDL)
1922
1923   if (state & SND_CTRL_FADE)
1924   {
1925     int i;
1926
1927     /*
1928     for (i=audio.first_sound_channel; i<audio.num_channels; i++)
1929     */
1930
1931     for (i=0; i<audio.channels; i++)
1932       if (i != audio.music_channel || snd_ctrl.music)
1933         Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
1934     if (state & SND_CTRL_MUSIC)
1935       Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1936   }
1937   else
1938   {
1939     int i;
1940
1941     for (i=0; i<audio.channels; i++)
1942       if (i != audio.music_channel || snd_ctrl.music)
1943         Mix_HaltChannel(i);
1944     if (state & SND_CTRL_MUSIC)
1945       Mix_HaltMusic();
1946   }
1947
1948 #elif !defined(PLATFORM_MSDOS)
1949
1950   if (audio.soundserver_pid == 0)       /* we are child process */
1951     return;
1952
1953   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1954   {
1955     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1956     audio.sound_available = audio.sound_enabled = FALSE;
1957     return;
1958   }
1959 #else /* PLATFORM_MSDOS */
1960   sound_handler(snd_ctrl);
1961 #endif
1962 }
1963
1964 ListNode *newListNode()
1965 {
1966   return checked_calloc(sizeof(ListNode));
1967 }
1968
1969 void addNodeToList(ListNode **node_first, char *key, void *content)
1970 {
1971   ListNode *node_new = newListNode();
1972
1973 #if 0
1974   printf("LIST: adding node with key '%s'\n", key);
1975 #endif
1976
1977   node_new->key = getStringCopy(key);
1978   node_new->content = content;
1979   node_new->next = *node_first;
1980   *node_first = node_new;
1981 }
1982
1983 void deleteNodeFromList(ListNode **node_first, char *key,
1984                         void (*destructor_function)(void *))
1985 {
1986   if (node_first == NULL || *node_first == NULL)
1987     return;
1988
1989 #if 0
1990   printf("[CHECKING LIST KEY '%s' == '%s']\n",
1991          (*node_first)->key, key);
1992 #endif
1993
1994   if (strcmp((*node_first)->key, key) == 0)
1995   {
1996 #if 0
1997     printf("[DELETING LIST ENTRY]\n");
1998 #endif
1999
2000     free((*node_first)->key);
2001     if (destructor_function)
2002       destructor_function((*node_first)->content);
2003     *node_first = (*node_first)->next;
2004   }
2005   else
2006     deleteNodeFromList(&(*node_first)->next, key, destructor_function);
2007 }
2008
2009 ListNode *getNodeFromKey(ListNode *node_first, char *key)
2010 {
2011   if (node_first == NULL)
2012     return NULL;
2013
2014   if (strcmp(node_first->key, key) == 0)
2015     return node_first;
2016   else
2017     return getNodeFromKey(node_first->next, key);
2018 }
2019
2020 int getNumNodes(ListNode *node_first)
2021 {
2022   return (node_first ? 1 + getNumNodes(node_first->next) : 0);
2023 }
2024
2025 void dumpList(ListNode *node_first)
2026 {
2027   ListNode *node = node_first;
2028
2029   while (node)
2030   {
2031     printf("['%s' (%d)]\n", node->key,
2032            ((SoundInfo *)node->content)->num_references);
2033     node = node->next;
2034   }
2035
2036   printf("[%d nodes]\n", getNumNodes(node_first));
2037 }
2038
2039 static void LoadSoundsInfo()
2040 {
2041   char *filename = getCustomSoundConfigFilename();
2042   struct SetupFileList *setup_file_list;
2043   int i;
2044
2045   /* always start with reliable default values */
2046   for (i=0; i<num_sounds; i++)
2047     sound_effect[i].filename = NULL;
2048
2049   if (filename == NULL)
2050     return;
2051
2052   if ((setup_file_list = loadSetupFileList(filename)))
2053   {
2054     for (i=0; i<num_sounds; i++)
2055       sound_effect[i].filename =
2056         getStringCopy(getTokenValue(setup_file_list, sound_effect[i].text));
2057
2058     freeSetupFileList(setup_file_list);
2059
2060 #if 1
2061     for (i=0; i<num_sounds; i++)
2062     {
2063       printf("'%s' ", sound_effect[i].text);
2064       if (sound_effect[i].filename)
2065         printf("-> '%s'\n", sound_effect[i].filename);
2066       else
2067         printf("-> UNDEFINED [-> '%s']\n", sound_effect[i].default_filename);
2068     }
2069 #endif
2070   }
2071 }
2072
2073 static void ReloadCustomSounds()
2074 {
2075   int i;
2076
2077 #if 0
2078   printf("DEBUG: reloading sounds '%s' ...\n", artwork.sounds_set_current);
2079 #endif
2080
2081   LoadSoundsInfo();
2082
2083 #if 0
2084   printf("DEBUG: reloading %d sounds ...\n", num_sounds);
2085 #endif
2086
2087   for(i=0; i<num_sounds; i++)
2088   {
2089     if (sound_effect[i].filename)
2090       LoadSoundToList(sound_effect[i].filename, i);
2091     else
2092       LoadSoundToList(sound_effect[i].default_filename, i);
2093   }
2094
2095   /*
2096   printf("list size == %d\n", getNumNodes(SoundFileList));
2097   */
2098
2099 #if 0
2100   dumpList(SoundFileList);
2101 #endif
2102 }
2103
2104 static void ReloadCustomMusic()
2105 {
2106 #if 0
2107   printf("DEBUG: reloading music '%s' ...\n", artwork.music_set_current);
2108 #endif
2109
2110   FreeAllMusic();
2111
2112   LoadCustomMusic();
2113 }
2114
2115 static void InitReloadSoundsOrMusic(char *set_name, int type)
2116 {
2117   if (!audio.sound_available)
2118     return;
2119
2120 #if defined(TARGET_SDL) || defined(TARGET_ALLEGRO)
2121   if (type == SND_CTRL_RELOAD_SOUNDS)
2122     ReloadCustomSounds();
2123   else
2124     ReloadCustomMusic();
2125 #elif defined(PLATFORM_UNIX)
2126   if (audio.soundserver_pid == 0)       /* we are child process */
2127     return;
2128
2129   if (leveldir_current == NULL)         /* should never happen */
2130     Error(ERR_EXIT, "leveldir_current == NULL");
2131
2132 #if 1
2133   WriteReloadInfoToPipe(set_name, type);
2134 #else
2135
2136   snd_ctrl.active = FALSE;
2137   snd_ctrl.state = type;
2138   snd_ctrl.data_len = strlen(set_name) + 1;
2139
2140   if (write(audio.soundserver_pipe[1], &snd_ctrl,
2141             sizeof(snd_ctrl)) < 0 ||
2142       write(audio.soundserver_pipe[1], set_name,
2143             snd_ctrl.data_len) < 0 ||
2144       write(audio.soundserver_pipe[1], leveldir_current,
2145             sizeof(TreeInfo)) < 0 ||
2146       write(audio.soundserver_pipe[1], ti,
2147             sizeof(TreeInfo)) < 0 ||
2148       write(audio.soundserver_pipe[1], &str_size1,
2149             sizeof(unsigned long)) < 0 ||
2150       write(audio.soundserver_pipe[1], &str_size2,
2151             sizeof(unsigned long)) < 0 ||
2152       write(audio.soundserver_pipe[1], &str_size3,
2153             sizeof(unsigned long)) < 0 ||
2154       write(audio.soundserver_pipe[1], leveldir_current->fullpath,
2155             str_size1) < 0 ||
2156       write(audio.soundserver_pipe[1], ti->basepath,
2157             str_size2) < 0 ||
2158       write(audio.soundserver_pipe[1], ti->fullpath,
2159             str_size3) < 0)
2160   {
2161     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
2162     audio.sound_available = audio.sound_enabled = FALSE;
2163     return;
2164   }
2165 #endif
2166
2167 #endif
2168 }
2169
2170 void InitReloadSounds(char *set_name)
2171 {
2172   InitReloadSoundsOrMusic(set_name, SND_CTRL_RELOAD_SOUNDS);
2173 }
2174
2175 void InitReloadMusic(char *set_name)
2176 {
2177   InitReloadSoundsOrMusic(set_name, SND_CTRL_RELOAD_MUSIC);
2178 }
2179
2180 void FreeSound(void *ptr)
2181 {
2182   SoundInfo *sound = (SoundInfo *)ptr;
2183
2184   if (sound == NULL)
2185     return;
2186
2187   if (sound->data_ptr)
2188   {
2189 #if defined(TARGET_SDL)
2190     Mix_FreeChunk(sound->data_ptr);
2191 #elif defined(TARGET_ALLEGRO)
2192     destroy_sample(sound->data_ptr);
2193 #else   /* PLATFORM_UNIX */
2194     free(sound->data_ptr);
2195 #endif
2196   }
2197
2198   if (sound->source_filename)
2199     free(sound->source_filename);
2200
2201   free(sound);
2202 }
2203
2204 void FreeMusic(MusicInfo *music)
2205 {
2206   if (music == NULL)
2207     return;
2208
2209   if (music->data_ptr)
2210   {
2211 #if defined(TARGET_SDL)
2212     if (music->type == MUS_TYPE_MOD)
2213       Mix_FreeMusic(music->data_ptr);
2214     else
2215       Mix_FreeChunk(music->data_ptr);
2216 #elif defined(TARGET_ALLEGRO)
2217     destroy_sample(music->data_ptr);
2218 #else   /* PLATFORM_UNIX */
2219     free(music->data_ptr);
2220 #endif
2221   }
2222
2223   free(music);
2224 }
2225
2226 void FreeAllSounds()
2227 {
2228   int i;
2229
2230   if (Sound == NULL)
2231     return;
2232
2233   printf("%s: FREEING SOUNDS ...\n",
2234          audio.soundserver_pid == 0 ? "CHILD" : "PARENT");
2235
2236   for(i=0; i<num_sounds; i++)
2237     deleteSoundEntry(&Sound[i]);
2238   /*
2239     FreeSound(Sound[i]);
2240   */
2241
2242   printf("%s: FREEING SOUNDS -- DONE\n",
2243          audio.soundserver_pid == 0 ? "CHILD" : "PARENT");
2244
2245   free(Sound);
2246
2247   Sound = NULL;
2248   num_sounds = 0;
2249 }
2250
2251 void FreeAllMusic()
2252 {
2253   int i;
2254
2255   if (Music == NULL)
2256     return;
2257
2258   for(i=0; i<num_music; i++)
2259     FreeMusic(Music[i]);
2260
2261   free(Music);
2262
2263   Music = NULL;
2264   num_music = 0;
2265 }
2266
2267 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS                          */
2268 /* ========================================================================= */