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