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