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