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