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