rnd-20001216-1-src
[rocksndiamonds.git] / src / libgame / sound.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2000 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
25
26 static int num_sounds = 0, num_music = 0;
27 static struct SampleInfo *Sound = NULL;
28 #if defined(TARGET_SDL)
29 static int num_mods = 0;
30 static struct SampleInfo *Mod = NULL;
31 #endif
32
33
34 /*** THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/
35
36 static int playing_sounds = 0;
37 static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
38 static struct SoundControl emptySoundControl =
39 {
40   -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE, 0,0L,0L,NULL
41 };
42
43 #if defined(PLATFORM_UNIX)
44 static int stereo_volume[PSND_MAX_LEFT2RIGHT+1];
45 static char premix_first_buffer[SND_BLOCKSIZE];
46 #if defined(AUDIO_STREAMING_DSP)
47 static char premix_left_buffer[SND_BLOCKSIZE];
48 static char premix_right_buffer[SND_BLOCKSIZE];
49 static int premix_last_buffer[SND_BLOCKSIZE];
50 #endif
51 static unsigned char playing_buffer[SND_BLOCKSIZE];
52 #endif
53
54 /* forward declaration of internal functions */
55 #if defined(AUDIO_STREAMING_DSP)
56 static void SoundServer_InsertNewSound(struct SoundControl);
57 #elif defined(PLATFORM_UNIX)
58 static unsigned char linear_to_ulaw(int);
59 static int ulaw_to_linear(unsigned char);
60 #endif
61
62 #if defined(PLATFORM_HPUX)
63 static void HPUX_Audio_Control();
64 #endif
65
66 #if defined(PLATFORM_MSDOS)
67 static void SoundServer_InsertNewSound(struct SoundControl);
68 static void SoundServer_StopSound(int);
69 static void SoundServer_StopAllSounds();
70 #endif
71
72 #if defined(PLATFORM_UNIX)
73 static int OpenAudioDevice(char *audio_device_name)
74 {
75   int audio_fd;
76
77   /* check if desired audio device is accessible */
78   if (access(audio_device_name, W_OK) != 0)
79     return -1;
80
81   /* try to open audio device in non-blocking mode */
82   if ((audio_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0)
83     return audio_fd;
84
85   /* re-open audio device in blocking mode */
86   close(audio_fd);
87   audio_fd = open(audio_device_name, O_WRONLY);
88
89   return audio_fd;
90 }
91
92 static boolean TestAudioDevices(void)
93 {
94   static char *audio_device_name[] =
95   {
96     DEVICENAME_DSP,
97     DEVICENAME_AUDIO
98   };
99   int audio_fd = -1;
100   int i;
101
102   /* look for available audio devices, starting with preferred ones */
103   for (i=0; i<sizeof(audio_device_name)/sizeof(char *); i++)
104     if ((audio_fd = OpenAudioDevice(audio_device_name[i])) >= 0)
105       break;
106
107   if (audio_fd < 0)
108   {
109     Error(ERR_WARN, "cannot open audio device - no sound");
110     return FALSE;
111   }
112
113   close(audio_fd);
114
115   audio.device_name = audio_device_name[i];
116
117   return TRUE;
118 }
119
120 static boolean ForkAudioProcess(void)
121 {
122   if (pipe(audio.soundserver_pipe) < 0)
123   {
124     Error(ERR_WARN, "cannot create pipe - no sounds");
125     return FALSE;
126   }
127
128   if ((audio.soundserver_pid = fork()) < 0)
129   {       
130     Error(ERR_WARN, "cannot create sound server process - no sounds");
131     return FALSE;
132   }
133
134   if (audio.soundserver_pid == 0)       /* we are child */
135   {
136     SoundServer();
137
138     /* never reached */
139     exit(0);
140   }
141   else                                  /* we are parent */
142     close(audio.soundserver_pipe[0]); /* no reading from pipe needed */
143
144   return TRUE;
145 }
146
147 void UnixOpenAudio(void)
148 {
149   if (!TestAudioDevices())
150     return;
151
152   audio.sound_available = TRUE;
153   audio.sound_enabled = TRUE;
154
155 #if defined(AUDIO_STREAMING_DSP)
156   audio.music_available = TRUE;
157   audio.loops_available = TRUE;
158 #endif
159 }
160
161 void UnixCloseAudio(void)
162 {
163   if (audio.device_fd)
164     close(audio.device_fd);
165
166   if (audio.soundserver_pid)
167     kill(audio.soundserver_pid, SIGTERM);
168 }
169 #endif  /* PLATFORM_UNIX */
170
171 void InitPlaylist(void)
172 {
173   int i;
174
175   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
176     playlist[i] = emptySoundControl;
177   playing_sounds = 0;
178 }
179
180 void StartSoundserver(void)
181 {
182 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
183   if (!ForkAudioProcess())
184     audio.sound_available = FALSE;
185 #endif
186 }
187
188 #if defined(PLATFORM_UNIX)
189 void SoundServer(void)
190 {
191   int i;
192
193   struct SoundControl snd_ctrl;
194   fd_set sound_fdset;
195
196   close(audio.soundserver_pipe[1]);     /* no writing into pipe needed */
197
198   InitPlaylist();
199
200   stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
201   for(i=0;i<PSND_MAX_LEFT2RIGHT;i++)
202     stereo_volume[i] =
203       (int)sqrt((float)(PSND_MAX_LEFT2RIGHT*PSND_MAX_LEFT2RIGHT-i*i));
204
205 #if defined(PLATFORM_HPUX)
206   HPUX_Audio_Control();
207 #endif
208
209   FD_ZERO(&sound_fdset); 
210   FD_SET(audio.soundserver_pipe[0], &sound_fdset);
211
212   while(1)      /* wait for sound playing commands from client */
213   {
214     FD_SET(audio.soundserver_pipe[0], &sound_fdset);
215     select(audio.soundserver_pipe[0] + 1, &sound_fdset, NULL, NULL, NULL);
216     if (!FD_ISSET(audio.soundserver_pipe[0], &sound_fdset))
217       continue;
218     if (read(audio.soundserver_pipe[0], &snd_ctrl, sizeof(snd_ctrl))
219         != sizeof(snd_ctrl))
220       Error(ERR_EXIT_SOUND_SERVER, "broken pipe - no sounds");
221
222 #if defined(AUDIO_STREAMING_DSP)
223
224     if (snd_ctrl.fade_sound)
225     {
226       if (!playing_sounds)
227         continue;
228
229       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
230         if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
231           playlist[i].fade_sound = TRUE;
232     }
233     else if (snd_ctrl.stop_all_sounds)
234     {
235       if (!playing_sounds)
236         continue;
237
238       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
239         playlist[i]=emptySoundControl;
240       playing_sounds=0;
241
242       close(audio.device_fd);
243     }
244     else if (snd_ctrl.stop_sound)
245     {
246       if (!playing_sounds)
247         continue;
248
249       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
250         if (playlist[i].nr == snd_ctrl.nr)
251         {
252           playlist[i]=emptySoundControl;
253           playing_sounds--;
254         }
255
256       if (!playing_sounds)
257         close(audio.device_fd);
258     }
259
260     if (playing_sounds || snd_ctrl.active)
261     {
262       struct timeval delay = { 0, 0 };
263       byte *sample_ptr;
264       long sample_size;
265       static long max_sample_size = 0;
266       static long fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
267       int sample_rate = DEFAULT_AUDIO_SAMPLE_RATE;
268       int stereo = TRUE;
269       /* 'ioctl()' expects pointer to integer value for stereo flag
270          (boolean is defined as 'char', which will not work here) */
271
272       if (playing_sounds ||
273           (audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
274       {
275         if (!playing_sounds)    /* we just opened the audio device */
276         {
277           unsigned long fragment_spec = 0;
278
279           /* determine logarithm (log2) of the fragment size */
280           for (fragment_spec=0; (1 << fragment_spec) < fragment_size;
281                fragment_spec++);
282
283           /* use two fragments (play one fragment, prepare the other);
284              one fragment would result in interrupted audio output, more
285              than two fragments would raise audio output latency to much */
286           fragment_spec |= 0x00020000;
287
288           /* Example for fragment specification:
289              - 2 buffers / 512 bytes (giving 1/16 second resolution for 8 kHz)
290              - (with stereo the effective buffer size will shrink to 256)
291              => fragment_size = 0x00020009 */
292
293           if (ioctl(audio.device_fd,SNDCTL_DSP_SETFRAGMENT,&fragment_spec) < 0)
294             Error(ERR_EXIT_SOUND_SERVER,
295                   "cannot set fragment size of /dev/dsp - no sounds");
296
297           /* try if we can use stereo sound */
298           if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
299           {
300 #ifdef DEBUG
301             static boolean reported = FALSE;
302
303             if (!reported)
304             {
305               Error(ERR_RETURN, "cannot get stereo sound on /dev/dsp");
306               reported = TRUE;
307             }
308 #endif
309             stereo = FALSE;
310           }
311
312           if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &sample_rate) < 0)
313             Error(ERR_EXIT_SOUND_SERVER,
314                   "cannot set sample rate of /dev/dsp - no sounds");
315
316           /* get the real fragmentation size; this should return 512 */
317           if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE,&fragment_size) < 0)
318             Error(ERR_EXIT_SOUND_SERVER,
319                   "cannot get fragment size of /dev/dsp - no sounds");
320
321           max_sample_size = fragment_size / (stereo ? 2 : 1);
322         }
323
324         if (snd_ctrl.active)    /* new sound has arrived */
325           SoundServer_InsertNewSound(snd_ctrl);
326
327         while(playing_sounds &&
328               select(audio.soundserver_pipe[0] + 1,
329                      &sound_fdset, NULL, NULL, &delay) < 1)
330         {       
331           FD_SET(audio.soundserver_pipe[0], &sound_fdset);
332
333           /* first clear the last premixing buffer */
334           memset(premix_last_buffer, 0, fragment_size * sizeof(int));
335
336           for(i=0;i<MAX_SOUNDS_PLAYING;i++)
337           {
338             int j;
339
340             if (!playlist[i].active)
341               continue;
342
343             /* get pointer and size of the actual sound sample */
344             sample_ptr = playlist[i].data_ptr+playlist[i].playingpos;
345             sample_size =
346               MIN(max_sample_size,playlist[i].data_len-playlist[i].playingpos);
347             playlist[i].playingpos += sample_size;
348
349             /* fill the first mixing buffer with original sample */
350             memcpy(premix_first_buffer,sample_ptr,sample_size);
351
352             /* are we about to restart a looping sound? */
353             if (playlist[i].loop && sample_size<max_sample_size)
354             {
355               playlist[i].playingpos = max_sample_size-sample_size;
356               memcpy(premix_first_buffer+sample_size,
357                      playlist[i].data_ptr,max_sample_size-sample_size);
358               sample_size = max_sample_size;
359             }
360
361             /* decrease volume if sound is fading out */
362             if (playlist[i].fade_sound &&
363                 playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
364               playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
365
366             /* adjust volume of actual sound sample */
367             if (playlist[i].volume != PSND_MAX_VOLUME)
368               for(j=0;j<sample_size;j++)
369                 premix_first_buffer[j] =
370                   (playlist[i].volume * (int)premix_first_buffer[j])
371                     >> PSND_MAX_VOLUME_BITS;
372
373             /* fill the last mixing buffer with stereo or mono sound */
374             if (stereo)
375             {
376               int middle_pos = PSND_MAX_LEFT2RIGHT/2;
377               int left_volume = stereo_volume[middle_pos+playlist[i].stereo];
378               int right_volume = stereo_volume[middle_pos-playlist[i].stereo];
379
380               for(j=0;j<sample_size;j++)
381               {
382                 premix_left_buffer[j] =
383                   (left_volume * (int)premix_first_buffer[j])
384                     >> PSND_MAX_LEFT2RIGHT_BITS;
385                 premix_right_buffer[j] =
386                   (right_volume * (int)premix_first_buffer[j])
387                     >> PSND_MAX_LEFT2RIGHT_BITS;
388                 premix_last_buffer[2*j+0] += premix_left_buffer[j];
389                 premix_last_buffer[2*j+1] += premix_right_buffer[j];
390               }
391             }
392             else
393             {
394               for(j=0;j<sample_size;j++)
395                 premix_last_buffer[j] += (int)premix_first_buffer[j];
396             }
397
398             /* delete completed sound entries from the playlist */
399             if (playlist[i].playingpos >= playlist[i].data_len)
400             {
401               if (playlist[i].loop)
402                 playlist[i].playingpos = 0;
403               else
404               {
405                 playlist[i] = emptySoundControl;
406                 playing_sounds--;
407               }
408             }
409             else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
410             {
411               playlist[i] = emptySoundControl;
412               playing_sounds--;
413             }
414           }
415
416           /* put last mixing buffer to final playing buffer */
417           for(i=0; i<fragment_size; i++)
418           {
419             if (premix_last_buffer[i]<-255)
420               playing_buffer[i] = 0;
421             else if (premix_last_buffer[i]>255)
422               playing_buffer[i] = 255;
423             else
424               playing_buffer[i] = (premix_last_buffer[i]>>1)^0x80;
425           }
426
427           /* finally play the sound fragment */
428           write(audio.device_fd, playing_buffer, fragment_size);
429         }
430
431         /* if no sounds playing, free device for other sound programs */
432         if (!playing_sounds)
433           close(audio.device_fd);
434       }
435     }
436
437 #else /* !AUDIO_STREAMING_DSP */
438
439     if (snd_ctrl.active && !snd_ctrl.loop)
440     {
441       struct timeval delay = { 0, 0 };
442       byte *sample_ptr;
443       long sample_size, max_sample_size = SND_BLOCKSIZE;
444       long sample_rate = 8000;  /* standard "/dev/audio" sampling rate */
445       int wait_percent = 90;    /* wait 90% of the real playing time */
446       int i;
447
448       if ((audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
449       {
450         playing_sounds = 1;
451
452         while(playing_sounds &&
453               select(audio.soundserver_pipe[0] + 1,
454                      &sound_fdset, NULL, NULL, &delay) < 1)
455         {       
456           FD_SET(audio.soundserver_pipe[0], &sound_fdset);
457
458           /* get pointer and size of the actual sound sample */
459           sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos;
460           sample_size =
461             MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos);
462           snd_ctrl.playingpos += sample_size;
463
464           /* fill the first mixing buffer with original sample */
465           memcpy(premix_first_buffer,sample_ptr,sample_size);
466
467
468           /* adjust volume of actual sound sample */
469           if (snd_ctrl.volume != PSND_MAX_VOLUME)
470             for(i=0;i<sample_size;i++)
471               premix_first_buffer[i] =
472                 (snd_ctrl.volume * (int)premix_first_buffer[i])
473                   >> PSND_MAX_VOLUME_BITS;
474
475           for(i=0;i<sample_size;i++)
476             playing_buffer[i] =
477               linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
478
479           if (snd_ctrl.playingpos >= snd_ctrl.data_len)
480             playing_sounds = 0;
481
482           /* finally play the sound fragment */
483           write(audio.device_fd,playing_buffer,sample_size);
484
485           delay.tv_sec = 0;
486           delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
487         }
488         close(audio.device_fd);
489       }
490     }
491 #endif /* !AUDIO_STREAMING_DSP */
492   }
493 }
494 #endif /* PLATFORM_UNIX */
495
496 #if defined(PLATFORM_MSDOS)
497 static void sound_handler(struct SoundControl snd_ctrl)
498 {
499   int i;
500
501   if (snd_ctrl.fade_sound)
502   {
503     if (!playing_sounds)
504       return;
505
506     for (i=0; i<MAX_SOUNDS_PLAYING; i++)
507       if ((snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr) &&
508           !playlist[i].fade_sound)
509       {
510         playlist[i].fade_sound = TRUE;
511         if (voice_check(playlist[i].voice))
512           voice_ramp_volume(playlist[i].voice, 1000, 0);
513         playlist[i].loop = PSND_NO_LOOP;
514       }
515   }
516   else if (snd_ctrl.stop_all_sounds)
517   {
518     if (!playing_sounds)
519       return;
520     SoundServer_StopAllSounds();
521   }
522   else if (snd_ctrl.stop_sound)
523   {
524     if (!playing_sounds)
525       return;
526     SoundServer_StopSound(snd_ctrl.nr);
527   }
528
529   for (i=0; i<MAX_SOUNDS_PLAYING; i++)
530   {
531     if (!playlist[i].active || playlist[i].loop)
532       continue;
533
534     playlist[i].playingpos = voice_get_position(playlist[i].voice);
535     playlist[i].volume = voice_get_volume(playlist[i].voice);
536     if (playlist[i].playingpos == -1 || !playlist[i].volume)
537     {
538       deallocate_voice(playlist[i].voice);
539       playlist[i] = emptySoundControl;
540       playing_sounds--;
541     }
542   }
543
544   if (snd_ctrl.active)
545     SoundServer_InsertNewSound(snd_ctrl);
546 }
547 #endif /* PLATFORM_MSDOS */
548
549 #if !defined(PLATFORM_WIN32)
550 static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
551 {
552   int i, k;
553
554   /* if playlist is full, remove oldest sound */
555   if (playing_sounds==MAX_SOUNDS_PLAYING)
556   {
557     int longest=0, longest_nr=0;
558
559     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
560     {
561 #if !defined(PLATFORM_MSDOS)
562       int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
563 #else
564       int actual = playlist[i].playingpos;
565 #endif
566
567       if (!playlist[i].loop && actual>longest)
568       {
569         longest=actual;
570         longest_nr=i;
571       }
572     }
573 #if defined(PLATFORM_MSDOS)
574     voice_set_volume(playlist[longest_nr].voice, 0);
575     deallocate_voice(playlist[longest_nr].voice);
576 #endif
577     playlist[longest_nr] = emptySoundControl;
578     playing_sounds--;
579   }
580
581   /* check if sound is already being played (and how often) */
582   for(k=0,i=0;i<MAX_SOUNDS_PLAYING;i++)
583   {
584     if (playlist[i].nr == snd_ctrl.nr)
585       k++;
586   }
587
588   /* restart loop sounds only if they are just fading out */
589   if (k>=1 && snd_ctrl.loop)
590   {
591     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
592     {
593       if (playlist[i].nr == snd_ctrl.nr && playlist[i].fade_sound)
594       {
595         playlist[i].fade_sound = FALSE;
596         playlist[i].volume = PSND_MAX_VOLUME;
597 #if defined(PLATFORM_MSDOS)
598         playlist[i].loop = PSND_LOOP;
599         voice_stop_volumeramp(playlist[i].voice);
600         voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
601 #endif
602       }
603     }
604     return;
605   }
606
607   /* don't play sound more than n times simultaneously (with n == 2 for now) */
608   if (k>=2)
609   {
610     int longest=0, longest_nr=0;
611
612     /* look for oldest equal sound */
613     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
614     {
615       int actual;
616
617       if (!playlist[i].active || playlist[i].nr != snd_ctrl.nr)
618         continue;
619
620 #if !defined(PLATFORM_MSDOS)
621       actual = 100 * playlist[i].playingpos / playlist[i].data_len;
622 #else
623       actual = playlist[i].playingpos;
624 #endif
625       if (actual>=longest)
626       {
627         longest=actual;
628         longest_nr=i;
629       }
630     }
631
632 #if defined(PLATFORM_MSDOS)
633     voice_set_volume(playlist[longest_nr].voice, 0);
634     deallocate_voice(playlist[longest_nr].voice);
635 #endif
636     playlist[longest_nr] = emptySoundControl;
637     playing_sounds--;
638   }
639
640   /* neuen Sound in Liste packen */
641   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
642   {
643     if (!playlist[i].active)
644     {
645       playlist[i] = snd_ctrl;
646       playing_sounds++;
647
648 #if defined(PLATFORM_MSDOS)
649       playlist[i].voice = allocate_voice(Sound[snd_ctrl.nr].sample_ptr);
650       if(snd_ctrl.loop)
651         voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
652       voice_set_volume(playlist[i].voice, snd_ctrl.volume);
653       voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
654       voice_start(playlist[i].voice);       
655 #endif
656       break;
657     }
658   }
659 }
660 #endif /* !PLATFORM_WIN32 */
661
662 /*
663 void SoundServer_FadeSound(int nr)
664 {
665   int i;
666
667   if (!playing_sounds)
668     return;
669
670   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
671     if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
672       playlist[i].fade_sound = TRUE;
673 }
674 */
675
676 #if !defined(PLATFORM_WIN32)
677 #if defined(PLATFORM_MSDOS)
678 static void SoundServer_StopSound(int nr)
679 {
680   int i;
681
682   if (!playing_sounds)
683     return;
684
685   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
686     if (playlist[i].nr == nr)
687     {
688 #if defined(PLATFORM_MSDOS)
689       voice_set_volume(playlist[i].voice, 0);
690       deallocate_voice(playlist[i].voice);
691 #endif
692       playlist[i] = emptySoundControl;
693       playing_sounds--;
694     }
695
696 #if !defined(PLATFORM_MSDOS)
697   if (!playing_sounds)
698     close(audio.device_fd);
699 #endif
700 }
701
702 static void SoundServer_StopAllSounds()
703 {
704   int i;
705
706   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
707   {
708 #if defined(PLATFORM_MSDOS)
709     voice_set_volume(playlist[i].voice, 0);
710     deallocate_voice(playlist[i].voice);
711 #endif
712     playlist[i]=emptySoundControl;
713   }
714   playing_sounds = 0;
715
716 #if !defined(PLATFORM_MSDOS)
717   close(audio.device_fd);
718 #endif
719 }
720 #endif /* PLATFORM_MSDOS */
721 #endif /* !PLATFORM_WIN32 */
722
723 #if defined(PLATFORM_HPUX)
724 static void HPUX_Audio_Control()
725 {
726   struct audio_describe ainfo;
727   int audio_ctl;
728
729   audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
730   if (audio_ctl == -1)
731     Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl - no sounds");
732
733   if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
734     Error(ERR_EXIT_SOUND_SERVER, "no audio info - no sounds");
735
736   if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
737     Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available - no sounds");
738
739   ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
740   ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
741
742   close(audio_ctl);
743 }
744 #endif /* PLATFORM_HPUX */
745
746 #if defined(PLATFORM_UNIX) && !defined(AUDIO_STREAMING_DSP)
747
748 /* these two are stolen from "sox"... :) */
749
750 /*
751 ** This routine converts from linear to ulaw.
752 **
753 ** Craig Reese: IDA/Supercomputing Research Center
754 ** Joe Campbell: Department of Defense
755 ** 29 September 1989
756 **
757 ** References:
758 ** 1) CCITT Recommendation G.711  (very difficult to follow)
759 ** 2) "A New Digital Technique for Implementation of Any
760 **     Continuous PCM Companding Law," Villeret, Michel,
761 **     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
762 **     1973, pg. 11.12-11.17
763 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
764 **     for Analog-to_Digital Conversion Techniques,"
765 **     17 February 1987
766 **
767 ** Input: Signed 16 bit linear sample
768 ** Output: 8 bit ulaw sample
769 */
770
771 #define ZEROTRAP    /* turn on the trap as per the MIL-STD */
772 #define BIAS 0x84   /* define the add-in bias for 16 bit samples */
773 #define CLIP 32635
774
775 static unsigned char linear_to_ulaw(int sample)
776 {
777   static int exp_lut[256] =
778   {
779     0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
780     4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
781     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
782     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
783     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
784     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
785     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
786     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
787     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
788     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
789     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
790     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
791     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
792     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
793     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
794     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
795   };
796
797   int sign, exponent, mantissa;
798   unsigned char ulawbyte;
799
800   /* Get the sample into sign-magnitude. */
801   sign = (sample >> 8) & 0x80;          /* set aside the sign */
802   if (sign != 0)
803     sample = -sample;                   /* get magnitude */
804   if (sample > CLIP)
805     sample = CLIP;                      /* clip the magnitude */
806
807   /* Convert from 16 bit linear to ulaw. */
808   sample = sample + BIAS;
809   exponent = exp_lut[( sample >> 7 ) & 0xFF];
810   mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
811   ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
812 #ifdef ZEROTRAP
813   if (ulawbyte == 0)
814     ulawbyte = 0x02;                    /* optional CCITT trap */
815 #endif
816
817   return(ulawbyte);
818 }
819
820 /*
821 ** This routine converts from ulaw to 16 bit linear.
822 **
823 ** Craig Reese: IDA/Supercomputing Research Center
824 ** 29 September 1989
825 **
826 ** References:
827 ** 1) CCITT Recommendation G.711  (very difficult to follow)
828 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
829 **     for Analog-to_Digital Conversion Techniques,"
830 **     17 February 1987
831 **
832 ** Input: 8 bit ulaw sample
833 ** Output: signed 16 bit linear sample
834 */
835
836 static int ulaw_to_linear(unsigned char ulawbyte)
837 {
838   static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
839   int sign, exponent, mantissa, sample;
840
841   ulawbyte = ~ ulawbyte;
842   sign = ( ulawbyte & 0x80 );
843   exponent = ( ulawbyte >> 4 ) & 0x07;
844   mantissa = ulawbyte & 0x0F;
845   sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
846   if (sign != 0)
847     sample = -sample;
848
849   return(sample);
850 }
851 #endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */
852
853 /*** THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/
854
855 /*===========================================================================*/
856
857 /*** THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS ***/
858
859 #define CHUNK_ID_LEN            4       /* IFF style chunk id length */
860 #define WAV_HEADER_SIZE         20      /* size of WAV file header */
861
862 static boolean LoadSoundExt(char *sound_name, boolean is_music)
863 {
864   struct SampleInfo *snd_info;
865   char filename[256];
866 #if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS)
867   byte sound_header_buffer[WAV_HEADER_SIZE];
868   char chunk[CHUNK_ID_LEN + 1];
869   int chunk_length, dummy;
870   FILE *file;
871   int i;
872 #endif
873
874   num_sounds++;
875   Sound = checked_realloc(Sound, num_sounds * sizeof(struct SampleInfo));
876
877   snd_info = &Sound[num_sounds - 1];
878   snd_info->name = sound_name;
879
880   sprintf(filename, "%s/%s/%s", options.ro_base_directory,
881           (is_music ? MUSIC_DIRECTORY : SOUNDS_DIRECTORY), snd_info->name);
882
883 #if defined(TARGET_SDL)
884
885   if ((snd_info->mix_chunk = Mix_LoadWAV(filename)) == NULL)
886   {
887     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
888     return FALSE;
889   }
890
891 #elif defined(PLATFORM_UNIX)
892
893   if ((file = fopen(filename, MODE_READ)) == NULL)
894   {
895     Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename);
896     return FALSE;
897   }
898
899   /* read chunk "RIFF" */
900   getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_LITTLE_ENDIAN);
901   if (strcmp(chunk, "RIFF") != 0)
902   {
903     Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
904     fclose(file);
905     return FALSE;
906   }
907
908   /* read chunk "WAVE" */
909   getFileChunk(file, chunk, &dummy, BYTE_ORDER_LITTLE_ENDIAN);
910   if (strcmp(chunk, "WAVE") != 0)
911   {
912     Error(ERR_WARN, "missing 'WAVE' chunk of sound file '%s'", filename);
913     fclose(file);
914     return FALSE;
915   }
916
917   /* read header information */
918   for (i=0; i<WAV_HEADER_SIZE; i++)
919     sound_header_buffer[i] = fgetc(file);
920
921   /* read chunk "data" */
922   getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_LITTLE_ENDIAN);
923   if (strcmp(chunk, "data") != 0)
924   {
925     Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
926     fclose(file);
927     return FALSE;
928   }
929
930   snd_info->data_len = chunk_length;
931   snd_info->data_ptr = checked_malloc(snd_info->data_len);
932
933   /* read sound data */
934   if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
935       snd_info->data_len)
936   {
937     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
938     fclose(file);
939     return FALSE;
940   }
941
942   fclose(file);
943
944   for (i=0; i<snd_info->data_len; i++)
945     snd_info->data_ptr[i] = snd_info->data_ptr[i] ^ 0x80;
946
947 #else /* PLATFORM_MSDOS */
948
949   snd_info->sample_ptr = load_sample(filename);
950   if (!snd_info->sample_ptr)
951   {
952     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
953     return FALSE;
954   }
955
956 #endif
957
958   return TRUE;
959 }
960
961 boolean LoadSound(char *sound_name)
962 {
963   return LoadSoundExt(sound_name, FALSE);
964 }
965
966 boolean LoadMod(char *mod_name)
967 {
968 #if defined(TARGET_SDL)
969   struct SampleInfo *mod_info;
970   char filename[256];
971
972   num_mods++;
973   Mod = checked_realloc(Mod, num_mods * sizeof(struct SampleInfo));
974
975   mod_info = &Mod[num_mods - 1];
976   mod_info->name = mod_name;
977
978   sprintf(filename, "%s/%s/%s", options.ro_base_directory,
979           MUSIC_DIRECTORY, mod_info->name);
980
981   if ((mod_info->mix_music = Mix_LoadMUS(filename)) == NULL)
982   {
983     Error(ERR_WARN, "cannot read music file '%s' - no music", filename);
984     return FALSE;
985   }
986
987   return TRUE;
988 #else
989   return FALSE;
990 #endif
991 }
992
993 int LoadMusic(void)
994 {
995   DIR *dir;
996   struct dirent *dir_entry;
997   char *music_directory = getPath2(options.ro_base_directory, MUSIC_DIRECTORY);
998   int num_wav_music = 0;
999   int num_mod_music = 0;
1000
1001   if ((dir = opendir(music_directory)) == NULL)
1002   {
1003     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
1004     audio.music_available = FALSE;
1005     free(music_directory);
1006     return 0;
1007   }
1008
1009   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
1010   {
1011     char *filename = dir_entry->d_name;
1012
1013     if (strlen(filename) > 4 &&
1014         strcmp(&filename[strlen(filename) - 4], ".wav") == 0)
1015     {
1016       if (LoadSoundExt(filename, TRUE))
1017         num_wav_music++;
1018     }
1019     else if (strlen(filename) > 4 &&
1020              (strcmp(&filename[strlen(filename) - 4], ".mod") == 0 ||
1021               strcmp(&filename[strlen(filename) - 4], ".MOD") == 0 ||
1022               strncmp(filename, "mod.", 4) == 0 ||
1023               strncmp(filename, "MOD.", 4) == 0))
1024     {
1025       if (LoadMod(filename))
1026         num_mod_music++;
1027     }
1028   }
1029
1030   closedir(dir);
1031
1032   if (num_wav_music == 0 && num_mod_music == 0)
1033     Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
1034           music_directory);
1035
1036   free(music_directory);
1037
1038   num_music = (num_mod_music > 0 ? num_mod_music : num_wav_music);
1039
1040   audio.mods_available = (num_mod_music > 0);
1041   audio.music_available = (num_music > 0);
1042
1043   return num_music;
1044 }
1045
1046 void PlayMusic(int nr)
1047 {
1048   if (!audio.music_available)
1049     return;
1050
1051   if (!audio.mods_available)
1052     nr = num_sounds - num_music + nr;
1053
1054 #if defined(TARGET_SDL)
1055   if (audio.mods_available)     /* play MOD music */
1056   {
1057     Mix_VolumeMusic(SOUND_MAX_VOLUME);
1058     Mix_PlayMusic(Mod[nr].mix_music, -1);
1059   }
1060   else                          /* play WAV music loop */
1061   {
1062     Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
1063     Mix_PlayChannel(audio.music_channel, Sound[nr].mix_chunk, -1);
1064   }
1065 #else
1066   audio.music_nr = nr;
1067   PlaySoundLoop(nr);
1068 #endif
1069 }
1070
1071 void PlaySound(int nr)
1072 {
1073   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
1074 }
1075
1076 void PlaySoundStereo(int nr, int stereo)
1077 {
1078   PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
1079 }
1080
1081 void PlaySoundLoop(int nr)
1082 {
1083   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
1084 }
1085
1086 void PlaySoundExt(int nr, int volume, int stereo, boolean loop)
1087 {
1088   struct SoundControl snd_ctrl = emptySoundControl;
1089
1090   if (!audio.sound_available || !audio.sound_enabled)
1091     return;
1092
1093   if (volume<PSND_MIN_VOLUME)
1094     volume = PSND_MIN_VOLUME;
1095   else if (volume>PSND_MAX_VOLUME)
1096     volume = PSND_MAX_VOLUME;
1097
1098   if (stereo<PSND_MAX_LEFT)
1099     stereo = PSND_MAX_LEFT;
1100   else if (stereo>PSND_MAX_RIGHT)
1101     stereo = PSND_MAX_RIGHT;
1102
1103   snd_ctrl.nr           = nr;
1104   snd_ctrl.volume       = volume;
1105   snd_ctrl.stereo       = stereo;
1106   snd_ctrl.loop         = loop;
1107   snd_ctrl.active       = TRUE;
1108   snd_ctrl.data_ptr     = Sound[nr].data_ptr;
1109   snd_ctrl.data_len     = Sound[nr].data_len;
1110
1111 #if defined(TARGET_SDL)
1112   Mix_Volume(-1, SOUND_MAX_VOLUME);
1113   Mix_PlayChannel(-1, Sound[nr].mix_chunk, (loop ? -1 : 0));
1114 #elif defined(PLATFORM_UNIX)
1115   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1116   {
1117     Error(ERR_WARN, "cannot pipe to child process - no sounds");
1118     audio.sound_available = audio.sound_enabled = FALSE;
1119     return;
1120   }
1121 #elif defined(PLATFORM_MSDOS)
1122   sound_handler(snd_ctrl);
1123 #endif
1124 }
1125
1126 void FadeMusic(void)
1127 {
1128 #if defined(TARGET_SDL)
1129   if (audio.mods_available)
1130     Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1131   else
1132     Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
1133 #else
1134   FadeSound(audio.music_nr);
1135 #endif
1136 }
1137
1138 void FadeSound(int nr)
1139 {
1140   StopSoundExt(nr, SSND_FADE_SOUND);
1141 }
1142
1143 void FadeSounds()
1144 {
1145   StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
1146 }
1147
1148 void StopMusic(void)
1149 {
1150 #if defined(TARGET_SDL)
1151   if (audio.mods_available)
1152     Mix_HaltMusic();
1153   else
1154     Mix_HaltChannel(audio.music_channel);
1155 #else
1156   StopSound(audio.music_nr);
1157 #endif
1158 }
1159
1160 void StopSound(int nr)
1161 {
1162   StopSoundExt(nr, SSND_STOP_SOUND);
1163 }
1164
1165 void StopSounds()
1166 {
1167   StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
1168 }
1169
1170 void StopSoundExt(int nr, int method)
1171 {
1172   struct SoundControl snd_ctrl = emptySoundControl;
1173
1174   if (!audio.sound_available)
1175     return;
1176
1177   if (SSND_FADING(method))
1178     snd_ctrl.fade_sound = TRUE;
1179
1180   if (SSND_ALL(method))
1181     snd_ctrl.stop_all_sounds = TRUE;
1182   else
1183   {
1184     snd_ctrl.nr = nr;
1185     snd_ctrl.stop_sound = TRUE;
1186   }
1187
1188 #if defined(TARGET_SDL)
1189
1190   if (SSND_FADING(method))
1191   {
1192     int i;
1193
1194     for (i=0; i<audio.channels; i++)
1195       if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
1196         Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
1197     if (snd_ctrl.stop_all_sounds)
1198       Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1199   }
1200   else
1201   {
1202     int i;
1203
1204     for (i=0; i<audio.channels; i++)
1205       if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
1206         Mix_HaltChannel(i);
1207     if (snd_ctrl.stop_all_sounds)
1208       Mix_HaltMusic();
1209   }
1210
1211 #else
1212 #if !defined(PLATFORM_MSDOS)
1213   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1214   {
1215     Error(ERR_WARN, "cannot pipe to child process - no sounds");
1216     audio.sound_available = audio.sound_enabled = FALSE;
1217     return;
1218   }
1219 #else
1220   sound_handler(snd_ctrl);
1221 #endif
1222 #endif
1223 }
1224
1225 void FreeSounds(int num_sounds)
1226 {
1227   int i;
1228
1229   if (!audio.sound_available)
1230     return;
1231
1232   for(i=0; i<num_sounds; i++)
1233 #if defined(TARGET_SDL)
1234     free(Sound[i].mix_chunk);
1235 #elif !defined(PLATFORM_MSDOS)
1236     free(Sound[i].data_ptr);
1237 #else
1238     destroy_sample(Sound[i].sample_ptr);
1239 #endif
1240 }
1241
1242 /*** THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS ***/