rocksndiamonds-1.2.0
[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 static void SoundServer_StopSound(int nr)
502 {
503   int i;
504
505   if (!playing_sounds)
506     return;
507
508   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
509     if (playlist[i].nr == nr)
510     {
511 #ifdef MSDOS
512       voice_set_volume(playlist[i].voice, 0);
513       deallocate_voice(playlist[i].voice);
514 #endif
515       playlist[i] = emptySoundControl;
516       playing_sounds--;
517     }
518
519 #ifndef MSDOS
520   if (!playing_sounds)
521     close(sound_device);
522 #endif
523 }
524
525 static void SoundServer_StopAllSounds()
526 {
527   int i;
528
529   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
530   {
531 #ifdef MSDOS
532     voice_set_volume(playlist[i].voice, 0);
533     deallocate_voice(playlist[i].voice);
534 #endif
535     playlist[i]=emptySoundControl;
536   }
537   playing_sounds = 0;
538
539 #ifndef MSDOS
540   close(sound_device);
541 #endif
542 }
543
544 #ifdef HPUX_AUDIO
545 static void HPUX_Audio_Control()
546 {
547   struct audio_describe ainfo;
548   int audio_ctl;
549
550   audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
551   if (audio_ctl == -1)
552     Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl - no sounds");
553
554   if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
555     Error(ERR_EXIT_SOUND_SERVER, "no audio info - no sounds");
556
557   if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
558     Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available - no sounds");
559
560   ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
561   ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
562
563   close(audio_ctl);
564 }
565 #endif /* HPUX_AUDIO */
566
567 /* these two are stolen from "sox"... :) */
568
569 /*
570 ** This routine converts from linear to ulaw.
571 **
572 ** Craig Reese: IDA/Supercomputing Research Center
573 ** Joe Campbell: Department of Defense
574 ** 29 September 1989
575 **
576 ** References:
577 ** 1) CCITT Recommendation G.711  (very difficult to follow)
578 ** 2) "A New Digital Technique for Implementation of Any
579 **     Continuous PCM Companding Law," Villeret, Michel,
580 **     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
581 **     1973, pg. 11.12-11.17
582 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
583 **     for Analog-to_Digital Conversion Techniques,"
584 **     17 February 1987
585 **
586 ** Input: Signed 16 bit linear sample
587 ** Output: 8 bit ulaw sample
588 */
589
590 #define ZEROTRAP    /* turn on the trap as per the MIL-STD */
591 #define BIAS 0x84   /* define the add-in bias for 16 bit samples */
592 #define CLIP 32635
593
594 static unsigned char linear_to_ulaw(int sample)
595 {
596   static int exp_lut[256] =
597   {
598     0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
599     4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
600     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
601     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
602     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
603     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
604     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
605     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
606     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
607     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
608     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
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   };
615
616   int sign, exponent, mantissa;
617   unsigned char ulawbyte;
618
619   /* Get the sample into sign-magnitude. */
620   sign = (sample >> 8) & 0x80;          /* set aside the sign */
621   if (sign != 0)
622     sample = -sample;                   /* get magnitude */
623   if (sample > CLIP)
624     sample = CLIP;                      /* clip the magnitude */
625
626   /* Convert from 16 bit linear to ulaw. */
627   sample = sample + BIAS;
628   exponent = exp_lut[( sample >> 7 ) & 0xFF];
629   mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
630   ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
631 #ifdef ZEROTRAP
632   if (ulawbyte == 0)
633     ulawbyte = 0x02;                    /* optional CCITT trap */
634 #endif
635
636   return(ulawbyte);
637 }
638
639 /*
640 ** This routine converts from ulaw to 16 bit linear.
641 **
642 ** Craig Reese: IDA/Supercomputing Research Center
643 ** 29 September 1989
644 **
645 ** References:
646 ** 1) CCITT Recommendation G.711  (very difficult to follow)
647 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
648 **     for Analog-to_Digital Conversion Techniques,"
649 **     17 February 1987
650 **
651 ** Input: 8 bit ulaw sample
652 ** Output: signed 16 bit linear sample
653 */
654
655 static int ulaw_to_linear(unsigned char ulawbyte)
656 {
657   static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
658   int sign, exponent, mantissa, sample;
659
660   ulawbyte = ~ ulawbyte;
661   sign = ( ulawbyte & 0x80 );
662   exponent = ( ulawbyte >> 4 ) & 0x07;
663   mantissa = ulawbyte & 0x0F;
664   sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
665   if (sign != 0)
666     sample = -sample;
667
668   return(sample);
669 }
670
671 /*** THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/
672
673 /*===========================================================================*/
674
675 /*** THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS ***/
676
677 #ifndef MSDOS
678 static unsigned long be2long(unsigned long *be) /* big-endian -> longword */
679 {
680   unsigned char *ptr = (unsigned char *)be;
681
682   return(ptr[0]<<24 | ptr[1]<<16 | ptr[2]<<8 | ptr[3]);
683 }
684
685 static unsigned long le2long(unsigned long *be) /* little-endian -> longword */
686 {
687   unsigned char *ptr = (unsigned char *)be;
688
689   return(ptr[3]<<24 | ptr[2]<<16 | ptr[1]<<8 | ptr[0]);
690 }
691 #endif /* !MSDOS */
692
693 boolean LoadSound(struct SoundInfo *snd_info)
694 {
695   char filename[256];
696   char *sound_ext = "wav";
697 #ifndef MSDOS
698   struct SoundHeader_WAV *sound_header;
699   FILE *file;
700   int i;
701 #endif
702
703   sprintf(filename, "%s/%s/%s.%s",
704           options.base_directory, SOUNDS_DIRECTORY, snd_info->name, sound_ext);
705
706 #ifndef MSDOS
707
708   if ((file = fopen(filename, "r")) == NULL)
709   {
710     Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename);
711     return(FALSE);
712   }
713
714   if (fseek(file, 0, SEEK_END) < 0)
715   {
716     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
717     fclose(file);
718     return(FALSE);
719   }
720
721   snd_info->file_len = ftell(file);
722   rewind(file);
723
724   snd_info->file_ptr = checked_malloc(snd_info->file_len);
725
726   if (fread(snd_info->file_ptr, 1, snd_info->file_len, file) !=
727       snd_info->file_len)
728   {
729     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
730     fclose(file);
731     return(FALSE);
732   }
733
734   fclose(file);
735
736   sound_header = (struct SoundHeader_WAV *)snd_info->file_ptr;
737
738   if (strncmp(sound_header->magic_RIFF, "RIFF", 4) ||
739       snd_info->file_len != le2long(&sound_header->header_size) + 8 ||
740       strncmp(sound_header->magic_WAVE, "WAVE", 4) ||
741       strncmp(sound_header->magic_DATA, "data", 4) ||
742       snd_info->file_len != le2long(&sound_header->data_size) + 44)
743   {
744     Error(ERR_WARN, "'%s' is not a RIFF/WAVE file or broken - no sounds",
745           filename);
746     return(FALSE);
747   }
748
749   snd_info->data_ptr = snd_info->file_ptr + 44;
750   snd_info->data_len = le2long(&sound_header->data_size);
751
752   for (i=0; i<snd_info->data_len; i++)
753     snd_info->data_ptr[i] = snd_info->data_ptr[i]^0x80;
754
755 #else /* MSDOS */
756
757   snd_info->sample_ptr = load_sample(filename);
758   if (!snd_info->sample_ptr)
759   {
760     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
761     return(FALSE);
762   }
763
764 #endif /* MSDOS */
765
766   return(TRUE);
767 }
768
769 boolean LoadSound_8SVX(struct SoundInfo *snd_info)
770 {
771   char filename[256];
772 #ifndef MSDOS
773   struct SoundHeader_8SVX *sound_header;
774   FILE *file;
775   char *ptr;
776   char *sound_ext = "8svx";
777 #else
778   char *sound_ext = "wav";
779 #endif
780
781   sprintf(filename, "%s/%s/%s.%s",
782           options.base_directory, SOUNDS_DIRECTORY, snd_info->name, sound_ext);
783
784 #ifndef MSDOS
785   if (!(file=fopen(filename,"r")))
786   {
787     Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename);
788     return(FALSE);
789   }
790
791   if (fseek(file,0,SEEK_END)<0)
792   {
793     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
794     fclose(file);
795     return(FALSE);
796   }
797
798   snd_info->file_len = ftell(file);
799   rewind(file);
800
801   if (!(snd_info->file_ptr=malloc(snd_info->file_len)))
802   {
803     Error(ERR_WARN, "out of memory (this shouldn't happen :) - no sounds");
804     fclose(file);
805     return(FALSE);
806   }
807
808   if (fread(snd_info->file_ptr,1,snd_info->file_len,file)!=snd_info->file_len)
809   {
810     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
811     fclose(file);
812     return(FALSE);
813   }
814
815   fclose(file);
816
817   sound_header = (struct SoundHeader_8SVX *)snd_info->file_ptr;
818
819   if (strncmp(sound_header->magic_FORM,"FORM",4) ||
820       snd_info->file_len != be2long(&sound_header->chunk_size)+8 ||
821       strncmp(sound_header->magic_8SVX,"8SVX",4))
822   {
823     Error(ERR_WARN, "'%s' is not an IFF/8SVX file or broken - no sounds",
824           filename);
825     return(FALSE);
826   }
827
828   ptr = (char *)snd_info->file_ptr + 12;
829
830   while(ptr < (char *)(snd_info->file_ptr + snd_info->file_len))
831   {
832     if (!strncmp(ptr,"VHDR",4))
833     {
834       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
835       continue;
836     }
837     else if (!strncmp(ptr,"ANNO",4))
838     {
839       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
840       continue;
841     }
842     else if (!strncmp(ptr,"CHAN",4))
843     {
844       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
845       continue;
846     }
847     else if (!strncmp(ptr,"BODY",4))
848     {
849       snd_info->data_ptr = (byte *)ptr + 8;
850       snd_info->data_len = be2long((unsigned long *)(ptr + 4));
851       return(TRUE);
852     }
853     else
854     {
855       /* other chunk not recognized here */
856       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
857       continue;
858     }
859   }
860
861   return(FALSE);
862 #else /* MSDOS */
863   snd_info->sample_ptr = load_sample(filename);
864   if(!snd_info->sample_ptr)
865   {
866     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
867     return(FALSE);
868   }
869   return(TRUE);
870 #endif /* MSDOS */
871 }
872
873 void PlaySound(int nr)
874 {
875   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
876 }
877
878 void PlaySoundStereo(int nr, int stereo)
879 {
880   PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
881 }
882
883 void PlaySoundLoop(int nr)
884 {
885   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
886 }
887
888 void PlaySoundExt(int nr, int volume, int stereo, boolean loop)
889 {
890   struct SoundControl snd_ctrl = emptySoundControl;
891
892   if (sound_status==SOUND_OFF || !setup.sound)
893     return;
894
895   if (volume<PSND_MIN_VOLUME)
896     volume = PSND_MIN_VOLUME;
897   else if (volume>PSND_MAX_VOLUME)
898     volume = PSND_MAX_VOLUME;
899
900   if (stereo<PSND_MAX_LEFT)
901     stereo = PSND_MAX_LEFT;
902   else if (stereo>PSND_MAX_RIGHT)
903     stereo = PSND_MAX_RIGHT;
904
905   snd_ctrl.nr           = nr;
906   snd_ctrl.volume       = volume;
907   snd_ctrl.stereo       = stereo;
908   snd_ctrl.loop         = loop;
909   snd_ctrl.active       = TRUE;
910   snd_ctrl.data_ptr     = Sound[nr].data_ptr;
911   snd_ctrl.data_len     = Sound[nr].data_len;
912
913 #ifndef MSDOS
914   if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
915   {
916     Error(ERR_WARN, "cannot pipe to child process - no sounds");
917     sound_status = SOUND_OFF;
918     return;
919   }
920 #else
921   sound_handler(snd_ctrl);
922 #endif
923 }
924
925 void FadeSound(int nr)
926 {
927   StopSoundExt(nr, SSND_FADE_SOUND);
928 }
929
930 void FadeSounds()
931 {
932   StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
933 }
934
935 void StopSound(int nr)
936 {
937   StopSoundExt(nr, SSND_STOP_SOUND);
938 }
939
940 void StopSounds()
941 {
942   StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
943 }
944
945 void StopSoundExt(int nr, int method)
946 {
947   struct SoundControl snd_ctrl = emptySoundControl;
948
949   if (sound_status==SOUND_OFF)
950     return;
951
952   if (SSND_FADING(method))
953     snd_ctrl.fade_sound = TRUE;
954
955   if (SSND_ALL(method))
956     snd_ctrl.stop_all_sounds = TRUE;
957   else
958   {
959     snd_ctrl.nr = nr;
960     snd_ctrl.stop_sound = TRUE;
961   }
962
963 #ifndef MSDOS
964   if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
965   {
966     Error(ERR_WARN, "cannot pipe to child process - no sounds");
967     sound_status = SOUND_OFF;
968     return;
969   }
970 #else
971   sound_handler(snd_ctrl);
972 #endif
973 }
974
975 void FreeSounds(int max)
976 {
977   int i;
978
979   if (sound_status==SOUND_OFF)
980     return;
981
982   for(i=0;i<max;i++)
983 #ifndef MSDOS
984     free(Sound[i].file_ptr);
985 #else
986     destroy_sample(Sound[i].sample_ptr);
987 #endif
988 }
989
990 /*** THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS ***/