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