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