rnd-20020315-2-src
[rocksndiamonds.git] / src / libgame / sound.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * sound.c                                                  *
12 ***********************************************************/
13
14 #include <string.h>
15 #include <sys/time.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <dirent.h>
19 #include <signal.h>
20
21 #include "system.h"
22 #include "sound.h"
23 #include "misc.h"
24
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       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[256];
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   sprintf(filename, "%s/%s/%s", options.ro_base_directory,
939           (is_music ? MUSIC_DIRECTORY : 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     return FALSE;
947   }
948
949 #elif defined(PLATFORM_UNIX)
950
951   if ((file = fopen(filename, MODE_READ)) == NULL)
952   {
953     Error(ERR_WARN, "cannot open sound file '%s' -- no sounds", filename);
954     return FALSE;
955   }
956
957   /* read chunk "RIFF" */
958   getFileChunk(file, chunk, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
959   if (strcmp(chunk, "RIFF") != 0)
960   {
961     Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
962     fclose(file);
963     return FALSE;
964   }
965
966   /* read chunk "WAVE" */
967   getFileChunk(file, chunk, &dummy, BYTE_ORDER_LITTLE_ENDIAN);
968   if (strcmp(chunk, "WAVE") != 0)
969   {
970     Error(ERR_WARN, "missing 'WAVE' chunk of sound file '%s'", filename);
971     fclose(file);
972     return FALSE;
973   }
974
975   /* read header information */
976   for (i=0; i<WAV_HEADER_SIZE; i++)
977     sound_header_buffer[i] = fgetc(file);
978
979   /* read chunk "data" */
980   getFileChunk(file, chunk, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
981   if (strcmp(chunk, "data") != 0)
982   {
983     Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
984     fclose(file);
985     return FALSE;
986   }
987
988   snd_info->data_len = chunk_size;
989   snd_info->data_ptr = checked_malloc(snd_info->data_len);
990
991   /* read sound data */
992   if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
993       snd_info->data_len)
994   {
995     Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename);
996     fclose(file);
997     return FALSE;
998   }
999
1000   fclose(file);
1001
1002   for (i=0; i<snd_info->data_len; i++)
1003     snd_info->data_ptr[i] = snd_info->data_ptr[i] ^ 0x80;
1004
1005 #else /* PLATFORM_MSDOS */
1006
1007   snd_info->sample_ptr = load_sample(filename);
1008   if (!snd_info->sample_ptr)
1009   {
1010     Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename);
1011     return FALSE;
1012   }
1013
1014 #endif
1015
1016   return TRUE;
1017 }
1018
1019 boolean LoadSound(char *sound_name)
1020 {
1021   return LoadSoundExt(sound_name, FALSE);
1022 }
1023
1024 boolean LoadMod(char *mod_name)
1025 {
1026 #if defined(TARGET_SDL)
1027   struct SampleInfo *mod_info;
1028   char filename[256];
1029
1030   num_mods++;
1031   Mod = checked_realloc(Mod, num_mods * sizeof(struct SampleInfo));
1032
1033   mod_info = &Mod[num_mods - 1];
1034   mod_info->name = mod_name;
1035
1036   sprintf(filename, "%s/%s/%s", options.ro_base_directory,
1037           MUSIC_DIRECTORY, mod_info->name);
1038
1039   if ((mod_info->mix_music = Mix_LoadMUS(filename)) == NULL)
1040   {
1041     Error(ERR_WARN, "cannot read music file '%s' -- no music", filename);
1042     return FALSE;
1043   }
1044
1045   return TRUE;
1046 #else
1047   return FALSE;
1048 #endif
1049 }
1050
1051 int LoadMusic(void)
1052 {
1053   DIR *dir;
1054   struct dirent *dir_entry;
1055   char *music_directory = getPath2(options.ro_base_directory, MUSIC_DIRECTORY);
1056   int num_wav_music = 0;
1057   int num_mod_music = 0;
1058
1059   if (!audio.sound_available)
1060     return 0;
1061
1062   if ((dir = opendir(music_directory)) == NULL)
1063   {
1064     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
1065     audio.music_available = FALSE;
1066     free(music_directory);
1067     return 0;
1068   }
1069
1070   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
1071   {
1072     char *filename = dir_entry->d_name;
1073
1074     if (strlen(filename) > 4 &&
1075         strcmp(&filename[strlen(filename) - 4], ".wav") == 0)
1076     {
1077       if (LoadSoundExt(filename, TRUE))
1078         num_wav_music++;
1079     }
1080     else if (strlen(filename) > 4 &&
1081              (strcmp(&filename[strlen(filename) - 4], ".mod") == 0 ||
1082               strcmp(&filename[strlen(filename) - 4], ".MOD") == 0 ||
1083               strncmp(filename, "mod.", 4) == 0 ||
1084               strncmp(filename, "MOD.", 4) == 0))
1085     {
1086       if (LoadMod(filename))
1087         num_mod_music++;
1088     }
1089   }
1090
1091   closedir(dir);
1092
1093   if (num_wav_music == 0 && num_mod_music == 0)
1094     Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
1095           music_directory);
1096
1097   free(music_directory);
1098
1099   num_music = (num_mod_music > 0 ? num_mod_music : num_wav_music);
1100
1101   audio.mods_available = (num_mod_music > 0);
1102   audio.music_available = (num_music > 0);
1103
1104   return num_music;
1105 }
1106
1107 void PlayMusic(int nr)
1108 {
1109   if (!audio.music_available)
1110     return;
1111
1112   if (!audio.mods_available)
1113     nr = num_sounds - num_music + nr;
1114
1115 #if defined(TARGET_SDL)
1116   if (audio.mods_available)     /* play MOD music */
1117   {
1118     Mix_PlayMusic(Mod[nr].mix_music, -1);
1119     Mix_VolumeMusic(SOUND_MAX_VOLUME);  /* must be _after_ Mix_PlayMusic()! */
1120   }
1121   else                          /* play WAV music loop */
1122   {
1123     Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
1124     Mix_PlayChannel(audio.music_channel, Sound[nr].mix_chunk, -1);
1125   }
1126 #else
1127   audio.music_nr = nr;
1128   PlaySoundLoop(nr);
1129 #endif
1130 }
1131
1132 void PlaySound(int nr)
1133 {
1134   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
1135 }
1136
1137 void PlaySoundStereo(int nr, int stereo)
1138 {
1139   PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
1140 }
1141
1142 void PlaySoundLoop(int nr)
1143 {
1144   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
1145 }
1146
1147 void PlaySoundExt(int nr, int volume, int stereo, boolean loop)
1148 {
1149   struct SoundControl snd_ctrl = emptySoundControl;
1150
1151   if (!audio.sound_available || !audio.sound_enabled)
1152     return;
1153
1154   if (volume<PSND_MIN_VOLUME)
1155     volume = PSND_MIN_VOLUME;
1156   else if (volume>PSND_MAX_VOLUME)
1157     volume = PSND_MAX_VOLUME;
1158
1159   if (stereo<PSND_MAX_LEFT)
1160     stereo = PSND_MAX_LEFT;
1161   else if (stereo>PSND_MAX_RIGHT)
1162     stereo = PSND_MAX_RIGHT;
1163
1164   snd_ctrl.nr           = nr;
1165   snd_ctrl.volume       = volume;
1166   snd_ctrl.stereo       = stereo;
1167   snd_ctrl.loop         = loop;
1168   snd_ctrl.active       = TRUE;
1169   snd_ctrl.data_ptr     = Sound[nr].data_ptr;
1170   snd_ctrl.data_len     = Sound[nr].data_len;
1171
1172 #if defined(TARGET_SDL)
1173   Mix_Volume(-1, SOUND_MAX_VOLUME);
1174   Mix_PlayChannel(-1, Sound[nr].mix_chunk, (loop ? -1 : 0));
1175 #elif defined(PLATFORM_UNIX)
1176   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1177   {
1178     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1179     audio.sound_available = audio.sound_enabled = FALSE;
1180     return;
1181   }
1182 #elif defined(PLATFORM_MSDOS)
1183   sound_handler(snd_ctrl);
1184 #endif
1185 }
1186
1187 void FadeMusic(void)
1188 {
1189 #if defined(TARGET_SDL)
1190   if (!audio.sound_available)
1191     return;
1192
1193   if (audio.mods_available)
1194     Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1195   else
1196     Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
1197 #else
1198   FadeSound(audio.music_nr);
1199 #endif
1200 }
1201
1202 void FadeSound(int nr)
1203 {
1204   StopSoundExt(nr, SSND_FADE_SOUND);
1205 }
1206
1207 void FadeSounds()
1208 {
1209   FadeMusic();
1210   StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
1211 }
1212
1213 void StopMusic(void)
1214 {
1215 #if defined(TARGET_SDL)
1216   if (audio.mods_available)
1217     Mix_HaltMusic();
1218   else
1219     Mix_HaltChannel(audio.music_channel);
1220 #else
1221   StopSound(audio.music_nr);
1222 #endif
1223 }
1224
1225 void StopSound(int nr)
1226 {
1227   StopSoundExt(nr, SSND_STOP_SOUND);
1228 }
1229
1230 void StopSounds()
1231 {
1232   StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
1233 }
1234
1235 void StopSoundExt(int nr, int method)
1236 {
1237   struct SoundControl snd_ctrl = emptySoundControl;
1238
1239   if (!audio.sound_available)
1240     return;
1241
1242   if (SSND_FADING(method))
1243     snd_ctrl.fade_sound = TRUE;
1244
1245   if (SSND_ALL(method))
1246     snd_ctrl.stop_all_sounds = TRUE;
1247   else
1248   {
1249     snd_ctrl.nr = nr;
1250     snd_ctrl.stop_sound = TRUE;
1251   }
1252
1253 #if defined(TARGET_SDL)
1254
1255   if (SSND_FADING(method))
1256   {
1257     int i;
1258
1259     for (i=0; i<audio.channels; i++)
1260       if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
1261         Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
1262     if (snd_ctrl.stop_all_sounds)
1263       Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1264   }
1265   else
1266   {
1267     int i;
1268
1269     for (i=0; i<audio.channels; i++)
1270       if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
1271         Mix_HaltChannel(i);
1272     if (snd_ctrl.stop_all_sounds)
1273       Mix_HaltMusic();
1274   }
1275
1276 #else
1277 #if !defined(PLATFORM_MSDOS)
1278   if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1279   {
1280     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1281     audio.sound_available = audio.sound_enabled = FALSE;
1282     return;
1283   }
1284 #else
1285   sound_handler(snd_ctrl);
1286 #endif
1287 #endif
1288 }
1289
1290 void FreeSounds(int num_sounds)
1291 {
1292   int i;
1293
1294   if (!audio.sound_available)
1295     return;
1296
1297   for(i=0; i<num_sounds; i++)
1298 #if defined(TARGET_SDL)
1299     free(Sound[i].mix_chunk);
1300 #elif !defined(PLATFORM_MSDOS)
1301     free(Sound[i].data_ptr);
1302 #else
1303     destroy_sample(Sound[i].sample_ptr);
1304 #endif
1305 }
1306
1307 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS                          */
1308 /* ========================================================================= */