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