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