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