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