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