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