516892b5d1e8ff841bf8bf73372f98e7a8d50044
[rocksndiamonds.git] / src / sound.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  ©1995 Artsoft Development                               *
5 *        Holger Schemel                                    *
6 *        33659 Bielefeld-Senne                             *
7 *        Telefon: (0521) 493245                            *
8 *        eMail: aeglos@valinor.owl.de                      *
9 *               aeglos@uni-paderborn.de                    *
10 *               q99492@pbhrzx.uni-paderborn.de             *
11 *----------------------------------------------------------*
12 *  sound.c                                                 *
13 ***********************************************************/
14
15 #include "sound.h"
16 #ifdef MSDOS
17 extern void sound_handler(struct SoundControl);
18 #endif
19
20 /*** THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/
21
22 #ifndef MSDOS
23 static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
24 static struct SoundControl emptySoundControl =
25 {
26   -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE, 0,0L,0L,NULL
27 };
28 static int stereo_volume[PSND_MAX_LEFT2RIGHT+1];
29 static char premix_first_buffer[SND_BLOCKSIZE];
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 static unsigned char playing_buffer[SND_BLOCKSIZE];
34 static int playing_sounds = 0;
35 #else
36 struct SoundControl playlist[MAX_SOUNDS_PLAYING];
37 struct SoundControl emptySoundControl;
38 int playing_sounds;
39 #endif
40
41 void SoundServer()
42 {
43   int i;
44 #ifndef MSDOS
45   struct SoundControl snd_ctrl;
46   fd_set sound_fdset;
47
48   close(sound_pipe[1]);         /* no writing into pipe needed */
49 #endif
50
51   for(i=0;i<MAX_SOUNDS_PLAYING;i++)
52     playlist[i] = emptySoundControl;
53   playing_sounds = 0;
54
55 #ifndef MSDOS
56   stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
57   for(i=0;i<PSND_MAX_LEFT2RIGHT;i++)
58     stereo_volume[i] =
59       (int)sqrt((float)(PSND_MAX_LEFT2RIGHT*PSND_MAX_LEFT2RIGHT-i*i));
60
61 #ifdef HPUX_AUDIO
62   HPUX_Audio_Control();
63 #endif
64
65   FD_ZERO(&sound_fdset); 
66   FD_SET(sound_pipe[0], &sound_fdset);
67
68   for(;;)       /* wait for calls from PlaySound(), StopSound(), ... */
69   {
70     FD_SET(sound_pipe[0], &sound_fdset);
71     select(sound_pipe[0]+1, &sound_fdset, NULL, NULL, NULL);
72     if (!FD_ISSET(sound_pipe[0], &sound_fdset))
73       continue;
74     if (read(sound_pipe[0], &snd_ctrl, sizeof(snd_ctrl)) != sizeof(snd_ctrl))
75     {
76       fprintf(stderr,"%s: broken pipe - no sounds\n",progname);
77       exit(0);
78     }
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       BOOL 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   {
489     fprintf(stderr,"%s: cannot open /dev/audioCtl - no sounds\n",progname);
490     exit(0);
491   }
492
493   if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
494   {
495     fprintf(stderr,"%s: no audio info - no sounds\n",progname);
496     exit(0);
497   }
498
499   if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
500   {
501     fprintf(stderr,"%s: ulaw audio not available - no sounds\n",progname);
502     exit(0);
503   }
504
505   ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
506   ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
507
508   close(audio_ctl);
509 }
510 #endif /* HPUX_AUDIO */
511
512 /* these two are stolen from "sox"... :) */
513
514 /*
515 ** This routine converts from linear to ulaw.
516 **
517 ** Craig Reese: IDA/Supercomputing Research Center
518 ** Joe Campbell: Department of Defense
519 ** 29 September 1989
520 **
521 ** References:
522 ** 1) CCITT Recommendation G.711  (very difficult to follow)
523 ** 2) "A New Digital Technique for Implementation of Any
524 **     Continuous PCM Companding Law," Villeret, Michel,
525 **     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
526 **     1973, pg. 11.12-11.17
527 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
528 **     for Analog-to_Digital Conversion Techniques,"
529 **     17 February 1987
530 **
531 ** Input: Signed 16 bit linear sample
532 ** Output: 8 bit ulaw sample
533 */
534
535 #define ZEROTRAP    /* turn on the trap as per the MIL-STD */
536 #define BIAS 0x84   /* define the add-in bias for 16 bit samples */
537 #define CLIP 32635
538
539 unsigned char linear_to_ulaw(int sample)
540 {
541   static int exp_lut[256] =
542   {
543     0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
544     4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
545     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
546     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
547     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
548     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
549     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
550     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
551     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
552     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
553     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
554     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
555     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
556     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
557     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
558     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
559   };
560
561   int sign, exponent, mantissa;
562   unsigned char ulawbyte;
563
564   /* Get the sample into sign-magnitude. */
565   sign = (sample >> 8) & 0x80;          /* set aside the sign */
566   if (sign != 0)
567     sample = -sample;                   /* get magnitude */
568   if (sample > CLIP)
569     sample = CLIP;                      /* clip the magnitude */
570
571   /* Convert from 16 bit linear to ulaw. */
572   sample = sample + BIAS;
573   exponent = exp_lut[( sample >> 7 ) & 0xFF];
574   mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
575   ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
576 #ifdef ZEROTRAP
577   if (ulawbyte == 0)
578     ulawbyte = 0x02;                    /* optional CCITT trap */
579 #endif
580
581   return(ulawbyte);
582 }
583
584 /*
585 ** This routine converts from ulaw to 16 bit linear.
586 **
587 ** Craig Reese: IDA/Supercomputing Research Center
588 ** 29 September 1989
589 **
590 ** References:
591 ** 1) CCITT Recommendation G.711  (very difficult to follow)
592 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
593 **     for Analog-to_Digital Conversion Techniques,"
594 **     17 February 1987
595 **
596 ** Input: 8 bit ulaw sample
597 ** Output: signed 16 bit linear sample
598 */
599
600 int ulaw_to_linear(unsigned char ulawbyte)
601 {
602   static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
603   int sign, exponent, mantissa, sample;
604
605   ulawbyte = ~ ulawbyte;
606   sign = ( ulawbyte & 0x80 );
607   exponent = ( ulawbyte >> 4 ) & 0x07;
608   mantissa = ulawbyte & 0x0F;
609   sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
610   if (sign != 0)
611     sample = -sample;
612
613   return(sample);
614 }
615
616 /*** THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/
617
618 /*===========================================================================*/
619
620 /*** THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS ***/
621
622 static unsigned long be2long(unsigned long *be) /* big-endian -> longword */
623 {
624   unsigned char *ptr = (unsigned char *)be;
625
626   return(ptr[0]<<24 | ptr[1]<<16 | ptr[2]<<8 | ptr[3]);
627 }
628
629 BOOL LoadSound(struct SoundInfo *snd_info)
630 {
631   FILE *file;
632   char filename[256];
633 #ifndef MSDOS
634   char *sound_ext = "8svx";
635 #else
636   char *sound_ext = "wav";
637 #endif
638   struct SoundHeader_8SVX *sound_header;
639   unsigned char *ptr;
640
641   sprintf(filename,"%s/%s.%s",SND_PATH,snd_info->name,sound_ext);
642
643 #ifndef MSDOS
644   if (!(file=fopen(filename,"r")))
645   {
646     fprintf(stderr,"%s: cannot open sound file '%s' - no sounds\n",
647             progname,filename);
648     return(FALSE);
649   }
650
651   if (fseek(file,0,SEEK_END)<0)
652   {
653     fprintf(stderr,"%s: cannot read sound file '%s' - no sounds\n",
654             progname,filename);
655     fclose(file);
656     return(FALSE);
657   }
658
659   snd_info->file_len = ftell(file);
660   rewind(file);
661
662   if (!(snd_info->file_ptr=malloc(snd_info->file_len)))
663   {
664     fprintf(stderr,"%s: out of memory (this shouldn't happen :) - no sounds\n",
665             progname);
666     fclose(file);
667     return(FALSE);
668   }
669
670   if (fread(snd_info->file_ptr,1,snd_info->file_len,file)!=snd_info->file_len)
671   {
672     fprintf(stderr,"%s: cannot read sound file '%s' - no sounds\n",
673             progname,filename);
674     fclose(file);
675     return(FALSE);
676   }
677
678   fclose(file);
679
680   sound_header = (struct SoundHeader_8SVX *)snd_info->file_ptr;
681
682   if (strncmp(sound_header->magic_FORM,"FORM",4) ||
683       snd_info->file_len != be2long(&sound_header->chunk_size)+8 ||
684       strncmp(sound_header->magic_8SVX,"8SVX",4))
685   {
686     fprintf(stderr,"%s: '%s' is not an IFF/8SVX file or broken- no sounds\n",
687             progname,filename);
688     return(FALSE);
689   }
690
691   ptr = snd_info->file_ptr + 12;
692
693   while(ptr < (unsigned char *)(snd_info->file_ptr + snd_info->file_len))
694   {
695     if (!strncmp(ptr,"VHDR",4))
696     {
697       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
698       continue;
699     }
700     else if (!strncmp(ptr,"ANNO",4))
701     {
702       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
703       continue;
704     }
705     else if (!strncmp(ptr,"CHAN",4))
706     {
707       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
708       continue;
709     }
710     else if (!strncmp(ptr,"BODY",4))
711     {
712       snd_info->data_ptr = ptr + 8;
713       snd_info->data_len = be2long((unsigned long *)(ptr + 4));
714       return(TRUE);
715     }
716     else
717     {
718       /* other chunk not recognized here */
719       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
720       continue;
721     }
722   }
723
724   return(FALSE);
725 #else
726   snd_info->sample_ptr = load_sample(filename);
727   if(!snd_info->sample_ptr)
728   {
729     fprintf(stderr,"%s: cannot read sound file '%s' - no sounds\n",
730             progname,filename);
731     fclose(file);
732     return(FALSE);
733   }
734   return(TRUE);
735 #endif  // von  #ifndef MSDOS
736 }
737
738 void PlaySound(int nr)
739 {
740   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
741 }
742
743 void PlaySoundStereo(int nr, int stereo)
744 {
745   PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
746 }
747
748 void PlaySoundLoop(int nr)
749 {
750   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
751 }
752
753 void PlaySoundExt(int nr, int volume, int stereo, BOOL loop)
754 {
755   struct SoundControl snd_ctrl = emptySoundControl;
756
757   if (sound_status==SOUND_OFF || !sound_on)
758     return;
759
760   if (volume<PSND_MIN_VOLUME)
761     volume = PSND_MIN_VOLUME;
762   else if (volume>PSND_MAX_VOLUME)
763     volume = PSND_MAX_VOLUME;
764
765   if (stereo<PSND_MAX_LEFT)
766     stereo = PSND_MAX_LEFT;
767   else if (stereo>PSND_MAX_RIGHT)
768     stereo = PSND_MAX_RIGHT;
769
770   snd_ctrl.nr           = nr;
771   snd_ctrl.volume       = volume;
772   snd_ctrl.stereo       = stereo;
773   snd_ctrl.loop         = loop;
774   snd_ctrl.active       = TRUE;
775   snd_ctrl.data_ptr     = Sound[nr].data_ptr;
776   snd_ctrl.data_len     = Sound[nr].data_len;
777
778 #ifndef MSDOS
779   if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
780   {
781     fprintf(stderr,"%s: cannot pipe to child process - no sounds\n",progname);
782     sound_status=SOUND_OFF;
783     return;
784   }
785 #else
786   sound_handler(snd_ctrl);
787 #endif
788 }
789
790 void FadeSound(int nr)
791 {
792   StopSoundExt(nr, SSND_FADE_SOUND);
793 }
794
795 void FadeSounds()
796 {
797   StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
798 }
799
800 void StopSound(int nr)
801 {
802   StopSoundExt(nr, SSND_STOP_SOUND);
803 }
804
805 void StopSounds()
806 {
807   StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
808 }
809
810 void StopSoundExt(int nr, int method)
811 {
812   struct SoundControl snd_ctrl = emptySoundControl;
813
814   if (sound_status==SOUND_OFF)
815     return;
816
817   if (SSND_FADING(method))
818     snd_ctrl.fade_sound = TRUE;
819
820   if (SSND_ALL(method))
821     snd_ctrl.stop_all_sounds = TRUE;
822   else
823   {
824     snd_ctrl.nr = nr;
825     snd_ctrl.stop_sound = TRUE;
826   }
827
828 #ifndef MSDOS
829   if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
830   {
831     fprintf(stderr,"%s: cannot pipe to child process - no sounds\n",progname);
832     sound_status=SOUND_OFF;
833     return;
834   }
835 #else
836   sound_handler(snd_ctrl);
837 #endif
838 }
839
840 void FreeSounds(int max)
841 {
842   int i;
843
844   if (sound_status==SOUND_OFF)
845     return;
846
847   for(i=0;i<max;i++)
848 #ifndef MSDOS
849     free(Sound[i].file_ptr);
850 #else
851     destroy_sample(Sound[i].sample_ptr);
852 #endif
853 }
854
855 /*** THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS ***/