e4ac24cc79c16bea7862ff01f528e0a1a9633aee
[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.%s",
631           options.base_directory, SOUNDS_DIRECTORY, snd_info->name, sound_ext);
632
633 #ifndef MSDOS
634   if (!(file=fopen(filename,"r")))
635   {
636     Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename);
637     return(FALSE);
638   }
639
640   if (fseek(file,0,SEEK_END)<0)
641   {
642     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
643     fclose(file);
644     return(FALSE);
645   }
646
647   snd_info->file_len = ftell(file);
648   rewind(file);
649
650   if (!(snd_info->file_ptr=malloc(snd_info->file_len)))
651   {
652     Error(ERR_WARN, "out of memory (this shouldn't happen :) - no sounds");
653     fclose(file);
654     return(FALSE);
655   }
656
657   if (fread(snd_info->file_ptr,1,snd_info->file_len,file)!=snd_info->file_len)
658   {
659     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
660     fclose(file);
661     return(FALSE);
662   }
663
664   fclose(file);
665
666   sound_header = (struct SoundHeader_8SVX *)snd_info->file_ptr;
667
668   if (strncmp(sound_header->magic_FORM,"FORM",4) ||
669       snd_info->file_len != be2long(&sound_header->chunk_size)+8 ||
670       strncmp(sound_header->magic_8SVX,"8SVX",4))
671   {
672     Error(ERR_WARN, "'%s' is not an IFF/8SVX file or broken - no sounds",
673           filename);
674     return(FALSE);
675   }
676
677   ptr = snd_info->file_ptr + 12;
678
679   while(ptr < (unsigned char *)(snd_info->file_ptr + snd_info->file_len))
680   {
681     if (!strncmp(ptr,"VHDR",4))
682     {
683       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
684       continue;
685     }
686     else if (!strncmp(ptr,"ANNO",4))
687     {
688       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
689       continue;
690     }
691     else if (!strncmp(ptr,"CHAN",4))
692     {
693       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
694       continue;
695     }
696     else if (!strncmp(ptr,"BODY",4))
697     {
698       snd_info->data_ptr = ptr + 8;
699       snd_info->data_len = be2long((unsigned long *)(ptr + 4));
700       return(TRUE);
701     }
702     else
703     {
704       /* other chunk not recognized here */
705       ptr += be2long((unsigned long *)(ptr + 4)) + 8;
706       continue;
707     }
708   }
709
710   return(FALSE);
711 #else
712   snd_info->sample_ptr = load_sample(filename);
713   if(!snd_info->sample_ptr)
714   {
715     Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename);
716     fclose(file);
717     return(FALSE);
718   }
719   return(TRUE);
720 #endif  // von  #ifndef MSDOS
721 }
722
723 void PlaySound(int nr)
724 {
725   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
726 }
727
728 void PlaySoundStereo(int nr, int stereo)
729 {
730   PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
731 }
732
733 void PlaySoundLoop(int nr)
734 {
735   PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
736 }
737
738 void PlaySoundExt(int nr, int volume, int stereo, boolean loop)
739 {
740   struct SoundControl snd_ctrl = emptySoundControl;
741
742   if (sound_status==SOUND_OFF || !setup.sound)
743     return;
744
745   if (volume<PSND_MIN_VOLUME)
746     volume = PSND_MIN_VOLUME;
747   else if (volume>PSND_MAX_VOLUME)
748     volume = PSND_MAX_VOLUME;
749
750   if (stereo<PSND_MAX_LEFT)
751     stereo = PSND_MAX_LEFT;
752   else if (stereo>PSND_MAX_RIGHT)
753     stereo = PSND_MAX_RIGHT;
754
755   snd_ctrl.nr           = nr;
756   snd_ctrl.volume       = volume;
757   snd_ctrl.stereo       = stereo;
758   snd_ctrl.loop         = loop;
759   snd_ctrl.active       = TRUE;
760   snd_ctrl.data_ptr     = Sound[nr].data_ptr;
761   snd_ctrl.data_len     = Sound[nr].data_len;
762
763 #ifndef MSDOS
764   if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
765   {
766     Error(ERR_WARN, "cannot pipe to child process - no sounds");
767     sound_status = SOUND_OFF;
768     return;
769   }
770 #else
771   sound_handler(snd_ctrl);
772 #endif
773 }
774
775 void FadeSound(int nr)
776 {
777   StopSoundExt(nr, SSND_FADE_SOUND);
778 }
779
780 void FadeSounds()
781 {
782   StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
783 }
784
785 void StopSound(int nr)
786 {
787   StopSoundExt(nr, SSND_STOP_SOUND);
788 }
789
790 void StopSounds()
791 {
792   StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
793 }
794
795 void StopSoundExt(int nr, int method)
796 {
797   struct SoundControl snd_ctrl = emptySoundControl;
798
799   if (sound_status==SOUND_OFF)
800     return;
801
802   if (SSND_FADING(method))
803     snd_ctrl.fade_sound = TRUE;
804
805   if (SSND_ALL(method))
806     snd_ctrl.stop_all_sounds = TRUE;
807   else
808   {
809     snd_ctrl.nr = nr;
810     snd_ctrl.stop_sound = TRUE;
811   }
812
813 #ifndef MSDOS
814   if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
815   {
816     Error(ERR_WARN, "cannot pipe to child process - no sounds");
817     sound_status = SOUND_OFF;
818     return;
819   }
820 #else
821   sound_handler(snd_ctrl);
822 #endif
823 }
824
825 void FreeSounds(int max)
826 {
827   int i;
828
829   if (sound_status==SOUND_OFF)
830     return;
831
832   for(i=0;i<max;i++)
833 #ifndef MSDOS
834     free(Sound[i].file_ptr);
835 #else
836     destroy_sample(Sound[i].sample_ptr);
837 #endif
838 }
839
840 /*** THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS ***/