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