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