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