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