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