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