rnd-19990205-1
[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 #ifndef MSDOS
712 static unsigned long be2long(unsigned long *be) /* big-endian -> longword */
713 {
714   unsigned char *ptr = (unsigned char *)be;
715
716   return(ptr[0]<<24 | ptr[1]<<16 | ptr[2]<<8 | ptr[3]);
717 }
718
719 static unsigned long le2long(unsigned long *be) /* little-endian -> longword */
720 {
721   unsigned char *ptr = (unsigned char *)be;
722
723   return(ptr[3]<<24 | ptr[2]<<16 | ptr[1]<<8 | ptr[0]);
724 }
725 #endif /* !MSDOS */
726
727 boolean LoadSound(struct SoundInfo *snd_info)
728 {
729   char filename[256];
730   char *sound_ext = "wav";
731 #ifndef MSDOS
732   struct SoundHeader_WAV *sound_header;
733   FILE *file;
734   int i;
735 #endif
736
737   sprintf(filename, "%s/%s/%s.%s",
738           options.base_directory, SOUNDS_DIRECTORY, snd_info->name, sound_ext);
739
740 #ifndef MSDOS
741
742   if ((file = fopen(filename, "r")) == NULL)
743   {
744     Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename);
745     return(FALSE);
746   }
747
748   if (fseek(file, 0, SEEK_END) < 0)
749   {
750     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
751     fclose(file);
752     return(FALSE);
753   }
754
755   snd_info->file_len = ftell(file);
756   rewind(file);
757
758   snd_info->file_ptr = checked_malloc(snd_info->file_len);
759
760   if (fread(snd_info->file_ptr, 1, snd_info->file_len, file) !=
761       snd_info->file_len)
762   {
763     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
764     fclose(file);
765     return(FALSE);
766   }
767
768   fclose(file);
769
770   sound_header = (struct SoundHeader_WAV *)snd_info->file_ptr;
771
772   if (strncmp(sound_header->magic_RIFF, "RIFF", 4) ||
773       snd_info->file_len != le2long(&sound_header->header_size) + 8 ||
774       strncmp(sound_header->magic_WAVE, "WAVE", 4) ||
775       strncmp(sound_header->magic_DATA, "data", 4) ||
776       snd_info->file_len != le2long(&sound_header->data_size) + 44)
777   {
778     Error(ERR_WARN, "'%s' is not a RIFF/WAVE file or broken - no sounds",
779           filename);
780     return(FALSE);
781   }
782
783   snd_info->data_ptr = snd_info->file_ptr + 44;
784   snd_info->data_len = le2long(&sound_header->data_size);
785
786   for (i=0; i<snd_info->data_len; i++)
787     snd_info->data_ptr[i] = snd_info->data_ptr[i]^0x80;
788
789 #else /* MSDOS */
790
791   snd_info->sample_ptr = load_sample(filename);
792   if (!snd_info->sample_ptr)
793   {
794     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
795     return(FALSE);
796   }
797
798 #endif /* MSDOS */
799
800   return(TRUE);
801 }
802
803 boolean LoadSound_8SVX(struct SoundInfo *snd_info)
804 {
805   char filename[256];
806 #ifndef MSDOS
807   struct SoundHeader_8SVX *sound_header;
808   FILE *file;
809   char *ptr;
810   char *sound_ext = "8svx";
811 #else
812   char *sound_ext = "wav";
813 #endif
814
815   sprintf(filename, "%s/%s/%s.%s",
816           options.base_directory, SOUNDS_DIRECTORY, snd_info->name, sound_ext);
817
818 #ifndef MSDOS
819   if (!(file=fopen(filename,"r")))
820   {
821     Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename);
822     return(FALSE);
823   }
824
825   if (fseek(file,0,SEEK_END)<0)
826   {
827     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
828     fclose(file);
829     return(FALSE);
830   }
831
832   snd_info->file_len = ftell(file);
833   rewind(file);
834
835   if (!(snd_info->file_ptr=malloc(snd_info->file_len)))
836   {
837     Error(ERR_WARN, "out of memory (this shouldn't happen :) - no sounds");
838     fclose(file);
839     return(FALSE);
840   }
841
842   if (fread(snd_info->file_ptr,1,snd_info->file_len,file)!=snd_info->file_len)
843   {
844     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
845     fclose(file);
846     return(FALSE);
847   }
848
849   fclose(file);
850
851   sound_header = (struct SoundHeader_8SVX *)snd_info->file_ptr;
852
853   if (strncmp(sound_header->magic_FORM,"FORM",4) ||
854       snd_info->file_len != be2long(&sound_header->chunk_size)+8 ||
855       strncmp(sound_header->magic_8SVX,"8SVX",4))
856   {
857     Error(ERR_WARN, "'%s' is not an IFF/8SVX file or broken - no sounds",
858           filename);
859     return(FALSE);
860   }
861
862   ptr = (char *)snd_info->file_ptr + 12;
863
864   while(ptr < (char *)(snd_info->file_ptr + snd_info->file_len))
865   {
866     if (!strncmp(ptr,"VHDR",4))
867     {
868       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
869       continue;
870     }
871     else if (!strncmp(ptr,"ANNO",4))
872     {
873       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
874       continue;
875     }
876     else if (!strncmp(ptr,"CHAN",4))
877     {
878       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
879       continue;
880     }
881     else if (!strncmp(ptr,"BODY",4))
882     {
883       snd_info->data_ptr = (byte *)ptr + 8;
884       snd_info->data_len = be2long((unsigned long *)(ptr + 4));
885       return(TRUE);
886     }
887     else
888     {
889       /* other chunk not recognized here */
890       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
891       continue;
892     }
893   }
894
895   return(FALSE);
896 #else /* MSDOS */
897   snd_info->sample_ptr = load_sample(filename);
898   if(!snd_info->sample_ptr)
899   {
900     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
901     return(FALSE);
902   }
903   return(TRUE);
904 #endif /* MSDOS */
905 }
906
907 void PlaySound(int nr)
908 {
909   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
910 }
911
912 void PlaySoundStereo(int nr, int stereo)
913 {
914   PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
915 }
916
917 void PlaySoundLoop(int nr)
918 {
919   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
920 }
921
922 void PlaySoundExt(int nr, int volume, int stereo, boolean loop)
923 {
924   struct SoundControl snd_ctrl = emptySoundControl;
925
926   if (sound_status==SOUND_OFF || !setup.sound)
927     return;
928
929   if (volume<PSND_MIN_VOLUME)
930     volume = PSND_MIN_VOLUME;
931   else if (volume>PSND_MAX_VOLUME)
932     volume = PSND_MAX_VOLUME;
933
934   if (stereo<PSND_MAX_LEFT)
935     stereo = PSND_MAX_LEFT;
936   else if (stereo>PSND_MAX_RIGHT)
937     stereo = PSND_MAX_RIGHT;
938
939   snd_ctrl.nr           = nr;
940   snd_ctrl.volume       = volume;
941   snd_ctrl.stereo       = stereo;
942   snd_ctrl.loop         = loop;
943   snd_ctrl.active       = TRUE;
944   snd_ctrl.data_ptr     = Sound[nr].data_ptr;
945   snd_ctrl.data_len     = Sound[nr].data_len;
946
947 #ifndef MSDOS
948   if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
949   {
950     Error(ERR_WARN, "cannot pipe to child process - no sounds");
951     sound_status = SOUND_OFF;
952     return;
953   }
954 #else
955   sound_handler(snd_ctrl);
956 #endif
957 }
958
959 void FadeSound(int nr)
960 {
961   StopSoundExt(nr, SSND_FADE_SOUND);
962 }
963
964 void FadeSounds()
965 {
966   StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
967 }
968
969 void StopSound(int nr)
970 {
971   StopSoundExt(nr, SSND_STOP_SOUND);
972 }
973
974 void StopSounds()
975 {
976   StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
977 }
978
979 void StopSoundExt(int nr, int method)
980 {
981   struct SoundControl snd_ctrl = emptySoundControl;
982
983   if (sound_status==SOUND_OFF)
984     return;
985
986   if (SSND_FADING(method))
987     snd_ctrl.fade_sound = TRUE;
988
989   if (SSND_ALL(method))
990     snd_ctrl.stop_all_sounds = TRUE;
991   else
992   {
993     snd_ctrl.nr = nr;
994     snd_ctrl.stop_sound = TRUE;
995   }
996
997 #ifndef MSDOS
998   if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
999   {
1000     Error(ERR_WARN, "cannot pipe to child process - no sounds");
1001     sound_status = SOUND_OFF;
1002     return;
1003   }
1004 #else
1005   sound_handler(snd_ctrl);
1006 #endif
1007 }
1008
1009 void FreeSounds(int max)
1010 {
1011   int i;
1012
1013   if (sound_status==SOUND_OFF)
1014     return;
1015
1016   for(i=0;i<max;i++)
1017 #ifndef MSDOS
1018     free(Sound[i].file_ptr);
1019 #else
1020     destroy_sample(Sound[i].sample_ptr);
1021 #endif
1022 }
1023
1024 /*** THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS ***/