rnd-20001128-1-src
[rocksndiamonds.git] / src / sound.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  sound.c                                                 *
12 ***********************************************************/
13
14 #include "sound.h"
15 #include "misc.h"
16
17 /*** THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/
18
19 static int playing_sounds = 0;
20 static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
21 static struct SoundControl emptySoundControl =
22 {
23   -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE, 0,0L,0L,NULL
24 };
25
26 #if defined(PLATFORM_UNIX)
27 static int stereo_volume[PSND_MAX_LEFT2RIGHT+1];
28 static char premix_first_buffer[SND_BLOCKSIZE];
29 #ifdef VOXWARE
30 static char premix_left_buffer[SND_BLOCKSIZE];
31 static char premix_right_buffer[SND_BLOCKSIZE];
32 static int premix_last_buffer[SND_BLOCKSIZE];
33 #endif
34 static unsigned char playing_buffer[SND_BLOCKSIZE];
35 #endif
36
37 /* forward declaration of internal functions */
38 #ifdef VOXWARE
39 static void SoundServer_InsertNewSound(struct SoundControl);
40 #else
41 #if defined(PLATFORM_UNIX)
42 static unsigned char linear_to_ulaw(int);
43 static int ulaw_to_linear(unsigned char);
44 #endif
45 #endif
46
47 #ifdef HPUX_AUDIO
48 static void HPUX_Audio_Control();
49 #endif
50
51 #if defined(PLATFORM_MSDOS)
52 static void SoundServer_InsertNewSound(struct SoundControl);
53 static void SoundServer_StopSound(int);
54 static void SoundServer_StopAllSounds();
55 #endif
56
57 #if defined(PLATFORM_UNIX)
58 int OpenAudio(char *audio_device_name)
59 {
60   int audio_fd;
61
62   /* try to open audio device in non-blocking mode */
63   if ((audio_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0)
64     return audio_fd;
65
66   /* re-open audio device in blocking mode */
67   close(audio_fd);
68   audio_fd = open(audio_device_name, O_WRONLY);
69
70   return audio_fd;
71 }
72
73 int CheckAudio(char *audio_device_name)
74 {
75   int audio_fd;
76
77   if (access(audio_device_name, W_OK) != 0)
78   {
79     Error(ERR_WARN, "cannot access audio device - no sound");
80     return SOUND_OFF;
81   }
82
83   if ((audio_fd = OpenAudio(sound_device_name)) < 0)
84   {
85     Error(ERR_WARN, "cannot open audio device - no sound");
86     return SOUND_OFF;
87   }
88
89   close(audio_fd);
90
91   return SOUND_AVAILABLE;
92 }
93
94 boolean UnixInitAudio(void)
95 {
96   return TRUE;
97 }
98 #endif  /* PLATFORM_UNIX */
99
100 void SoundServer()
101 {
102   int i;
103 #if defined(PLATFORM_UNIX)
104   struct SoundControl snd_ctrl;
105   fd_set sound_fdset;
106
107   close(sysinfo.audio_process_pipe[1]); /* no writing into pipe needed */
108 #endif
109
110   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
111     playlist[i] = emptySoundControl;
112   playing_sounds = 0;
113
114 #if defined(PLATFORM_UNIX)
115   stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
116   for(i=0;i<PSND_MAX_LEFT2RIGHT;i++)
117     stereo_volume[i] =
118       (int)sqrt((float)(PSND_MAX_LEFT2RIGHT*PSND_MAX_LEFT2RIGHT-i*i));
119
120 #ifdef HPUX_AUDIO
121   HPUX_Audio_Control();
122 #endif
123
124   FD_ZERO(&sound_fdset); 
125   FD_SET(sysinfo.audio_process_pipe[0], &sound_fdset);
126
127   while(1)      /* wait for sound playing commands from client */
128   {
129     FD_SET(sysinfo.audio_process_pipe[0], &sound_fdset);
130     select(sysinfo.audio_process_pipe[0] + 1, &sound_fdset, NULL, NULL, NULL);
131     if (!FD_ISSET(sysinfo.audio_process_pipe[0], &sound_fdset))
132       continue;
133     if (read(sysinfo.audio_process_pipe[0], &snd_ctrl, sizeof(snd_ctrl))
134         != sizeof(snd_ctrl))
135       Error(ERR_EXIT_SOUND_SERVER, "broken pipe - no sounds");
136
137 #ifdef VOXWARE
138
139     if (snd_ctrl.fade_sound)
140     {
141       if (!playing_sounds)
142         continue;
143
144       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
145         if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
146           playlist[i].fade_sound = TRUE;
147     }
148     else if (snd_ctrl.stop_all_sounds)
149     {
150       if (!playing_sounds)
151         continue;
152
153       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
154         playlist[i]=emptySoundControl;
155       playing_sounds=0;
156
157       close(sysinfo.audio_fd);
158     }
159     else if (snd_ctrl.stop_sound)
160     {
161       if (!playing_sounds)
162         continue;
163
164       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
165         if (playlist[i].nr == snd_ctrl.nr)
166         {
167           playlist[i]=emptySoundControl;
168           playing_sounds--;
169         }
170
171       if (!playing_sounds)
172         close(sysinfo.audio_fd);
173     }
174
175     if (playing_sounds || snd_ctrl.active)
176     {
177       struct timeval delay = { 0, 0 };
178       byte *sample_ptr;
179       long sample_size;
180       static long max_sample_size = 0;
181       static long fragment_size = 0;
182       /* Even if the stereo flag is used as being boolean, it must be
183          defined as an integer, else 'ioctl()' will fail! */
184       int stereo = TRUE;
185 #if 0
186       int sample_rate = 8000;
187 #else
188       int sample_rate = 22050;
189 #endif
190
191       if (playing_sounds ||
192           (sysinfo.audio_fd = OpenAudio(sound_device_name)) >= 0)
193       {
194         if (!playing_sounds)    /* we just opened the audio device */
195         {
196           /* 2 buffers / 512 bytes, giving 1/16 second resolution */
197           /* (with stereo the effective buffer size will shrink to 256) */
198           fragment_size = 0x00020009;
199
200           if (ioctl(sysinfo.audio_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_size)
201               < 0)
202             Error(ERR_EXIT_SOUND_SERVER,
203                   "cannot set fragment size of /dev/dsp - no sounds");
204
205           /* try if we can use stereo sound */
206           if (ioctl(sysinfo.audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
207           {
208 #ifdef DEBUG
209             static boolean reported = FALSE;
210
211             if (!reported)
212             {
213               Error(ERR_RETURN, "cannot get stereo sound on /dev/dsp");
214               reported = TRUE;
215             }
216 #endif
217             stereo = FALSE;
218           }
219
220           if (ioctl(sysinfo.audio_fd, SNDCTL_DSP_SPEED, &sample_rate) < 0)
221             Error(ERR_EXIT_SOUND_SERVER,
222                   "cannot set sample rate of /dev/dsp - no sounds");
223
224           /* get the real fragmentation size; this should return 512 */
225           if (ioctl(sysinfo.audio_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size)
226               < 0)
227             Error(ERR_EXIT_SOUND_SERVER,
228                   "cannot get fragment size of /dev/dsp - no sounds");
229
230           max_sample_size = fragment_size / (stereo ? 2 : 1);
231         }
232
233         if (snd_ctrl.active)    /* new sound has arrived */
234           SoundServer_InsertNewSound(snd_ctrl);
235
236         while(playing_sounds &&
237               select(sysinfo.audio_process_pipe[0] + 1,
238                      &sound_fdset, NULL, NULL, &delay) < 1)
239         {       
240           FD_SET(sysinfo.audio_process_pipe[0], &sound_fdset);
241
242           /* first clear the last premixing buffer */
243           memset(premix_last_buffer,0,fragment_size*sizeof(int));
244
245           for(i=0;i<MAX_SOUNDS_PLAYING;i++)
246           {
247             int j;
248
249             if (!playlist[i].active)
250               continue;
251
252             /* get pointer and size of the actual sound sample */
253             sample_ptr = playlist[i].data_ptr+playlist[i].playingpos;
254             sample_size =
255               MIN(max_sample_size,playlist[i].data_len-playlist[i].playingpos);
256             playlist[i].playingpos += sample_size;
257
258             /* fill the first mixing buffer with original sample */
259             memcpy(premix_first_buffer,sample_ptr,sample_size);
260
261             /* are we about to restart a looping sound? */
262             if (playlist[i].loop && sample_size<max_sample_size)
263             {
264               playlist[i].playingpos = max_sample_size-sample_size;
265               memcpy(premix_first_buffer+sample_size,
266                      playlist[i].data_ptr,max_sample_size-sample_size);
267               sample_size = max_sample_size;
268             }
269
270             /* decrease volume if sound is fading out */
271             if (playlist[i].fade_sound &&
272                 playlist[i].volume>=PSND_MAX_VOLUME/10)
273               playlist[i].volume-=PSND_MAX_VOLUME/20;
274
275             /* adjust volume of actual sound sample */
276             if (playlist[i].volume != PSND_MAX_VOLUME)
277               for(j=0;j<sample_size;j++)
278                 premix_first_buffer[j] =
279                   (playlist[i].volume * (int)premix_first_buffer[j])
280                     >> PSND_MAX_VOLUME_BITS;
281
282             /* fill the last mixing buffer with stereo or mono sound */
283             if (stereo)
284             {
285               int middle_pos = PSND_MAX_LEFT2RIGHT/2;
286               int left_volume = stereo_volume[middle_pos+playlist[i].stereo];
287               int right_volume = stereo_volume[middle_pos-playlist[i].stereo];
288
289               for(j=0;j<sample_size;j++)
290               {
291                 premix_left_buffer[j] =
292                   (left_volume * (int)premix_first_buffer[j])
293                     >> PSND_MAX_LEFT2RIGHT_BITS;
294                 premix_right_buffer[j] =
295                   (right_volume * (int)premix_first_buffer[j])
296                     >> PSND_MAX_LEFT2RIGHT_BITS;
297                 premix_last_buffer[2*j+0] += premix_left_buffer[j];
298                 premix_last_buffer[2*j+1] += premix_right_buffer[j];
299               }
300             }
301             else
302             {
303               for(j=0;j<sample_size;j++)
304                 premix_last_buffer[j] += (int)premix_first_buffer[j];
305             }
306
307             /* delete completed sound entries from the playlist */
308             if (playlist[i].playingpos >= playlist[i].data_len)
309             {
310               if (playlist[i].loop)
311                 playlist[i].playingpos = 0;
312               else
313               {
314                 playlist[i] = emptySoundControl;
315                 playing_sounds--;
316               }
317             }
318             else if (playlist[i].volume <= PSND_MAX_VOLUME/10)
319             {
320               playlist[i] = emptySoundControl;
321               playing_sounds--;
322             }
323           }
324
325           /* put last mixing buffer to final playing buffer */
326           for(i=0;i<fragment_size;i++)
327           {
328             if (premix_last_buffer[i]<-255)
329               playing_buffer[i] = 0;
330             else if (premix_last_buffer[i]>255)
331               playing_buffer[i] = 255;
332             else
333               playing_buffer[i] = (premix_last_buffer[i]>>1)^0x80;
334           }
335
336           /* finally play the sound fragment */
337           write(sysinfo.audio_fd, playing_buffer,fragment_size);
338         }
339
340         /* if no sounds playing, free device for other sound programs */
341         if (!playing_sounds)
342           close(sysinfo.audio_fd);
343       }
344     }
345
346 #else /* !VOXWARE */
347
348     if (snd_ctrl.active && !snd_ctrl.loop)
349     {
350       struct timeval delay = { 0, 0 };
351       byte *sample_ptr;
352       long sample_size, max_sample_size = SND_BLOCKSIZE;
353       long sample_rate = 8000;  /* standard "/dev/audio" sampling rate */
354       int wait_percent = 90;    /* wait 90% of the real playing time */
355       int i;
356
357       if ((sysinfo.audio_fd = OpenAudio(sound_device_name)) >= 0)
358       {
359         playing_sounds = 1;
360
361         while(playing_sounds &&
362               select(sysinfo.audio_process_pipe[0] + 1,
363                      &sound_fdset, NULL, NULL, &delay) < 1)
364         {       
365           FD_SET(sysinfo.audio_process_pipe[0], &sound_fdset);
366
367           /* get pointer and size of the actual sound sample */
368           sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos;
369           sample_size =
370             MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos);
371           snd_ctrl.playingpos += sample_size;
372
373           /* fill the first mixing buffer with original sample */
374           memcpy(premix_first_buffer,sample_ptr,sample_size);
375
376
377           /* adjust volume of actual sound sample */
378           if (snd_ctrl.volume != PSND_MAX_VOLUME)
379             for(i=0;i<sample_size;i++)
380               premix_first_buffer[i] =
381                 (snd_ctrl.volume * (int)premix_first_buffer[i])
382                   >> PSND_MAX_VOLUME_BITS;
383
384           for(i=0;i<sample_size;i++)
385             playing_buffer[i] =
386               linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
387
388           if (snd_ctrl.playingpos >= snd_ctrl.data_len)
389             playing_sounds = 0;
390
391           /* finally play the sound fragment */
392           write(sysinfo.audio_fd,playing_buffer,sample_size);
393
394           delay.tv_sec = 0;
395           delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
396         }
397         close(sysinfo.audio_fd);
398       }
399     }
400
401 #endif /* !VOXWARE */
402
403   }
404
405 #endif /* PLATFORM_UNIX */
406
407 }
408
409 #if defined(PLATFORM_MSDOS)
410 static void sound_handler(struct SoundControl snd_ctrl)
411 {
412   int i;
413
414   if (snd_ctrl.fade_sound)
415   {
416     if (!playing_sounds)
417       return;
418
419     for (i=0; i<MAX_SOUNDS_PLAYING; i++)
420       if ((snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr) &&
421           !playlist[i].fade_sound)
422       {
423         playlist[i].fade_sound = TRUE;
424         if (voice_check(playlist[i].voice))
425           voice_ramp_volume(playlist[i].voice, 1000, 0);
426         playlist[i].loop = PSND_NO_LOOP;
427       }
428   }
429   else if (snd_ctrl.stop_all_sounds)
430   {
431     if (!playing_sounds)
432       return;
433     SoundServer_StopAllSounds();
434   }
435   else if (snd_ctrl.stop_sound)
436   {
437     if (!playing_sounds)
438       return;
439     SoundServer_StopSound(snd_ctrl.nr);
440   }
441
442   for (i=0; i<MAX_SOUNDS_PLAYING; i++)
443   {
444     if (!playlist[i].active || playlist[i].loop)
445       continue;
446
447     playlist[i].playingpos = voice_get_position(playlist[i].voice);
448     playlist[i].volume = voice_get_volume(playlist[i].voice);
449     if (playlist[i].playingpos == -1 || !playlist[i].volume)
450     {
451       deallocate_voice(playlist[i].voice);
452       playlist[i] = emptySoundControl;
453       playing_sounds--;
454     }
455   }
456
457   if (snd_ctrl.active)
458     SoundServer_InsertNewSound(snd_ctrl);
459 }
460 #endif /* PLATFORM_MSDOS */
461
462 #if !defined(PLATFORM_WIN32)
463 static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
464 {
465   int i, k;
466
467   /* if playlist is full, remove oldest sound */
468   if (playing_sounds==MAX_SOUNDS_PLAYING)
469   {
470     int longest=0, longest_nr=0;
471
472     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
473     {
474 #if !defined(PLATFORM_MSDOS)
475       int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
476 #else
477       int actual = playlist[i].playingpos;
478 #endif
479
480       if (!playlist[i].loop && actual>longest)
481       {
482         longest=actual;
483         longest_nr=i;
484       }
485     }
486 #if defined(PLATFORM_MSDOS)
487     voice_set_volume(playlist[longest_nr].voice, 0);
488     deallocate_voice(playlist[longest_nr].voice);
489 #endif
490     playlist[longest_nr] = emptySoundControl;
491     playing_sounds--;
492   }
493
494   /* check if sound is already being played (and how often) */
495   for(k=0,i=0;i<MAX_SOUNDS_PLAYING;i++)
496   {
497     if (playlist[i].nr == snd_ctrl.nr)
498       k++;
499   }
500
501   /* restart loop sounds only if they are just fading out */
502   if (k>=1 && snd_ctrl.loop)
503   {
504     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
505     {
506       if (playlist[i].nr == snd_ctrl.nr && playlist[i].fade_sound)
507       {
508         playlist[i].fade_sound = FALSE;
509         playlist[i].volume = PSND_MAX_VOLUME;
510 #if defined(PLATFORM_MSDOS)
511         playlist[i].loop = PSND_LOOP;
512         voice_stop_volumeramp(playlist[i].voice);
513         voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
514 #endif
515       }
516     }
517     return;
518   }
519
520   /* don't play sound more than n times simultaneously (with n == 2 for now) */
521   if (k>=2)
522   {
523     int longest=0, longest_nr=0;
524
525     /* look for oldest equal sound */
526     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
527     {
528       int actual;
529
530       if (!playlist[i].active || playlist[i].nr != snd_ctrl.nr)
531         continue;
532
533 #if !defined(PLATFORM_MSDOS)
534       actual = 100 * playlist[i].playingpos / playlist[i].data_len;
535 #else
536       actual = playlist[i].playingpos;
537 #endif
538       if (actual>=longest)
539       {
540         longest=actual;
541         longest_nr=i;
542       }
543     }
544
545 #if defined(PLATFORM_MSDOS)
546     voice_set_volume(playlist[longest_nr].voice, 0);
547     deallocate_voice(playlist[longest_nr].voice);
548 #endif
549     playlist[longest_nr] = emptySoundControl;
550     playing_sounds--;
551   }
552
553   /* neuen Sound in Liste packen */
554   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
555   {
556     if (!playlist[i].active)
557     {
558       playlist[i] = snd_ctrl;
559       playing_sounds++;
560
561 #if defined(PLATFORM_MSDOS)
562       playlist[i].voice = allocate_voice(Sound[snd_ctrl.nr].sample_ptr);
563       if(snd_ctrl.loop)
564         voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
565       voice_set_volume(playlist[i].voice, snd_ctrl.volume);
566       voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
567       voice_start(playlist[i].voice);       
568 #endif
569       break;
570     }
571   }
572 }
573 #endif /* !PLATFORM_WIN32 */
574
575 /*
576 void SoundServer_FadeSound(int nr)
577 {
578   int i;
579
580   if (!playing_sounds)
581     return;
582
583   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
584     if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
585       playlist[i].fade_sound = TRUE;
586 }
587 */
588
589 #if !defined(PLATFORM_WIN32)
590 #if defined(PLATFORM_MSDOS)
591 static void SoundServer_StopSound(int nr)
592 {
593   int i;
594
595   if (!playing_sounds)
596     return;
597
598   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
599     if (playlist[i].nr == nr)
600     {
601 #if defined(PLATFORM_MSDOS)
602       voice_set_volume(playlist[i].voice, 0);
603       deallocate_voice(playlist[i].voice);
604 #endif
605       playlist[i] = emptySoundControl;
606       playing_sounds--;
607     }
608
609 #if !defined(PLATFORM_MSDOS)
610   if (!playing_sounds)
611     close(sysinfo.audio_fd);
612 #endif
613 }
614
615 static void SoundServer_StopAllSounds()
616 {
617   int i;
618
619   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
620   {
621 #if defined(PLATFORM_MSDOS)
622     voice_set_volume(playlist[i].voice, 0);
623     deallocate_voice(playlist[i].voice);
624 #endif
625     playlist[i]=emptySoundControl;
626   }
627   playing_sounds = 0;
628
629 #if !defined(PLATFORM_MSDOS)
630   close(sysinfo.audio_fd);
631 #endif
632 }
633 #endif /* PLATFORM_MSDOS */
634 #endif /* !PLATFORM_WIN32 */
635
636 #ifdef HPUX_AUDIO
637 static void HPUX_Audio_Control()
638 {
639   struct audio_describe ainfo;
640   int audio_ctl;
641
642   audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
643   if (audio_ctl == -1)
644     Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl - no sounds");
645
646   if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
647     Error(ERR_EXIT_SOUND_SERVER, "no audio info - no sounds");
648
649   if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
650     Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available - no sounds");
651
652   ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
653   ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
654
655   close(audio_ctl);
656 }
657 #endif /* HPUX_AUDIO */
658
659 #if !defined(VOXWARE) && defined(PLATFORM_UNIX)
660
661 /* these two are stolen from "sox"... :) */
662
663 /*
664 ** This routine converts from linear to ulaw.
665 **
666 ** Craig Reese: IDA/Supercomputing Research Center
667 ** Joe Campbell: Department of Defense
668 ** 29 September 1989
669 **
670 ** References:
671 ** 1) CCITT Recommendation G.711  (very difficult to follow)
672 ** 2) "A New Digital Technique for Implementation of Any
673 **     Continuous PCM Companding Law," Villeret, Michel,
674 **     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
675 **     1973, pg. 11.12-11.17
676 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
677 **     for Analog-to_Digital Conversion Techniques,"
678 **     17 February 1987
679 **
680 ** Input: Signed 16 bit linear sample
681 ** Output: 8 bit ulaw sample
682 */
683
684 #define ZEROTRAP    /* turn on the trap as per the MIL-STD */
685 #define BIAS 0x84   /* define the add-in bias for 16 bit samples */
686 #define CLIP 32635
687
688 static unsigned char linear_to_ulaw(int sample)
689 {
690   static int exp_lut[256] =
691   {
692     0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
693     4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
694     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
695     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
696     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
697     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
698     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
699     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
700     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
701     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
702     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
703     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
704     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
705     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
706     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
707     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
708   };
709
710   int sign, exponent, mantissa;
711   unsigned char ulawbyte;
712
713   /* Get the sample into sign-magnitude. */
714   sign = (sample >> 8) & 0x80;          /* set aside the sign */
715   if (sign != 0)
716     sample = -sample;                   /* get magnitude */
717   if (sample > CLIP)
718     sample = CLIP;                      /* clip the magnitude */
719
720   /* Convert from 16 bit linear to ulaw. */
721   sample = sample + BIAS;
722   exponent = exp_lut[( sample >> 7 ) & 0xFF];
723   mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
724   ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
725 #ifdef ZEROTRAP
726   if (ulawbyte == 0)
727     ulawbyte = 0x02;                    /* optional CCITT trap */
728 #endif
729
730   return(ulawbyte);
731 }
732
733 /*
734 ** This routine converts from ulaw to 16 bit linear.
735 **
736 ** Craig Reese: IDA/Supercomputing Research Center
737 ** 29 September 1989
738 **
739 ** References:
740 ** 1) CCITT Recommendation G.711  (very difficult to follow)
741 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
742 **     for Analog-to_Digital Conversion Techniques,"
743 **     17 February 1987
744 **
745 ** Input: 8 bit ulaw sample
746 ** Output: signed 16 bit linear sample
747 */
748
749 static int ulaw_to_linear(unsigned char ulawbyte)
750 {
751   static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
752   int sign, exponent, mantissa, sample;
753
754   ulawbyte = ~ ulawbyte;
755   sign = ( ulawbyte & 0x80 );
756   exponent = ( ulawbyte >> 4 ) & 0x07;
757   mantissa = ulawbyte & 0x0F;
758   sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
759   if (sign != 0)
760     sample = -sample;
761
762   return(sample);
763 }
764 #endif /* !VOXWARE && PLATFORM_UNIX */
765
766 /*** THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/
767
768 /*===========================================================================*/
769
770 /*** THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS ***/
771
772 #define CHUNK_ID_LEN            4       /* IFF style chunk id length */
773 #define WAV_HEADER_SIZE         20      /* size of WAV file header */
774
775 boolean LoadSound(struct SampleInfo *snd_info)
776 {
777   char filename[256];
778   char *sound_ext = "wav";
779 #if !defined(TARGET_SDL)
780 #if !defined(PLATFORM_MSDOS)
781   byte sound_header_buffer[WAV_HEADER_SIZE];
782   char chunk[CHUNK_ID_LEN + 1];
783   int chunk_length, dummy;
784   FILE *file;
785   int i;
786 #endif
787 #endif
788
789   sprintf(filename, "%s/%s/%s.%s",
790           options.ro_base_directory, SOUNDS_DIRECTORY,
791           snd_info->name, sound_ext);
792
793 #if defined(TARGET_SDL)
794
795   snd_info->mix_chunk = Mix_LoadWAV(filename);
796   if (snd_info->mix_chunk == NULL)
797   {
798     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
799     return FALSE;
800   }
801
802 #else /* !TARGET_SDL */
803
804 #if !defined(PLATFORM_MSDOS)
805
806   if ((file = fopen(filename, "r")) == NULL)
807   {
808     Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename);
809     return FALSE;
810   }
811
812   /* read chunk "RIFF" */
813   getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_LITTLE_ENDIAN);
814   if (strcmp(chunk, "RIFF") != 0)
815   {
816     Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
817     fclose(file);
818     return FALSE;
819   }
820
821   /* read chunk "WAVE" */
822   getFileChunk(file, chunk, &dummy, BYTE_ORDER_LITTLE_ENDIAN);
823   if (strcmp(chunk, "WAVE") != 0)
824   {
825     Error(ERR_WARN, "missing 'WAVE' chunk of sound file '%s'", filename);
826     fclose(file);
827     return FALSE;
828   }
829
830   /* read header information */
831   for (i=0; i<WAV_HEADER_SIZE; i++)
832     sound_header_buffer[i] = fgetc(file);
833
834   /* read chunk "data" */
835   getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_LITTLE_ENDIAN);
836   if (strcmp(chunk, "data") != 0)
837   {
838     Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
839     fclose(file);
840     return FALSE;
841   }
842
843   snd_info->data_len = chunk_length;
844   snd_info->data_ptr = checked_malloc(snd_info->data_len);
845
846   /* read sound data */
847   if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
848       snd_info->data_len)
849   {
850     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
851     fclose(file);
852     return FALSE;
853   }
854
855   fclose(file);
856
857   for (i=0; i<snd_info->data_len; i++)
858     snd_info->data_ptr[i] = snd_info->data_ptr[i] ^ 0x80;
859
860 #else /* PLATFORM_MSDOS */
861
862   snd_info->sample_ptr = load_sample(filename);
863   if (!snd_info->sample_ptr)
864   {
865     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
866     return FALSE;
867   }
868
869 #endif /* PLATFORM_MSDOS */
870 #endif /* !TARGET_SDL */
871
872   return TRUE;
873 }
874
875 void PlaySound(int nr)
876 {
877   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
878 }
879
880 void PlaySoundStereo(int nr, int stereo)
881 {
882   PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
883 }
884
885 void PlaySoundLoop(int nr)
886 {
887   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
888 }
889
890 void PlaySoundExt(int nr, int volume, int stereo, boolean loop)
891 {
892   struct SoundControl snd_ctrl = emptySoundControl;
893
894   if (!sysinfo.audio_available || !setup.sound)
895     return;
896
897   if (volume<PSND_MIN_VOLUME)
898     volume = PSND_MIN_VOLUME;
899   else if (volume>PSND_MAX_VOLUME)
900     volume = PSND_MAX_VOLUME;
901
902   if (stereo<PSND_MAX_LEFT)
903     stereo = PSND_MAX_LEFT;
904   else if (stereo>PSND_MAX_RIGHT)
905     stereo = PSND_MAX_RIGHT;
906
907   snd_ctrl.nr           = nr;
908   snd_ctrl.volume       = volume;
909   snd_ctrl.stereo       = stereo;
910   snd_ctrl.loop         = loop;
911   snd_ctrl.active       = TRUE;
912   snd_ctrl.data_ptr     = Sound[nr].data_ptr;
913   snd_ctrl.data_len     = Sound[nr].data_len;
914
915 #if defined(TARGET_SDL)
916
917   Mix_Volume(-1, SDL_MIX_MAXVOLUME / 4);
918   Mix_VolumeMusic(SDL_MIX_MAXVOLUME / 4);
919
920   Mix_PlayChannel(-1, Sound[nr].mix_chunk, (loop ? -1 : 0));
921
922 #else
923 #if !defined(PLATFORM_MSDOS)
924   if (write(sysinfo.audio_process_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
925   {
926     Error(ERR_WARN, "cannot pipe to child process - no sounds");
927     sysinfo.audio_available = FALSE;
928     return;
929   }
930 #else
931   sound_handler(snd_ctrl);
932 #endif
933 #endif
934 }
935
936 void FadeSound(int nr)
937 {
938   StopSoundExt(nr, SSND_FADE_SOUND);
939 }
940
941 void FadeSounds()
942 {
943   StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
944 }
945
946 void StopSound(int nr)
947 {
948   StopSoundExt(nr, SSND_STOP_SOUND);
949 }
950
951 void StopSounds()
952 {
953   StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
954 }
955
956 void StopSoundExt(int nr, int method)
957 {
958   struct SoundControl snd_ctrl = emptySoundControl;
959
960   if (!sysinfo.audio_available)
961     return;
962
963   if (SSND_FADING(method))
964     snd_ctrl.fade_sound = TRUE;
965
966   if (SSND_ALL(method))
967     snd_ctrl.stop_all_sounds = TRUE;
968   else
969   {
970     snd_ctrl.nr = nr;
971     snd_ctrl.stop_sound = TRUE;
972   }
973
974 #if defined(TARGET_SDL)
975
976   if (SSND_FADING(method))
977   {
978     Mix_FadeOutChannel(-1, 1000);
979     Mix_FadeOutMusic(1000);
980   }
981   else
982   {
983     Mix_HaltChannel(-1);
984     Mix_HaltMusic();
985   }
986
987 #else
988 #if !defined(PLATFORM_MSDOS)
989   if (write(sysinfo.audio_process_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
990   {
991     Error(ERR_WARN, "cannot pipe to child process - no sounds");
992     sysinfo.audio_available = FALSE;
993     return;
994   }
995 #else
996   sound_handler(snd_ctrl);
997 #endif
998 #endif
999 }
1000
1001 void FreeSounds(int num_sounds)
1002 {
1003   int i;
1004
1005   if (!sysinfo.audio_available)
1006     return;
1007
1008   for(i=0; i<num_sounds; i++)
1009 #if !defined(PLATFORM_MSDOS)
1010     free(Sound[i].data_ptr);
1011 #else
1012     destroy_sample(Sound[i].sample_ptr);
1013 #endif
1014 }
1015
1016 /*** THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS ***/