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