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