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