1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
26 static int num_sounds = 0, num_music = 0;
27 static struct SampleInfo *Sound = NULL;
28 #if defined(TARGET_SDL)
29 static int num_mods = 0;
30 static struct SampleInfo *Mod = NULL;
34 /* ========================================================================= */
35 /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
37 static int playing_sounds = 0;
38 static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
39 static struct SoundControl emptySoundControl =
41 -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE, 0,0L,0L,NULL
44 #if defined(PLATFORM_UNIX)
45 static int stereo_volume[PSND_MAX_LEFT2RIGHT+1];
46 static char premix_first_buffer[SND_BLOCKSIZE];
47 #if defined(AUDIO_STREAMING_DSP)
48 static char premix_left_buffer[SND_BLOCKSIZE];
49 static char premix_right_buffer[SND_BLOCKSIZE];
50 static int premix_last_buffer[SND_BLOCKSIZE];
52 static unsigned char playing_buffer[SND_BLOCKSIZE];
55 /* forward declaration of internal functions */
56 #if defined(AUDIO_STREAMING_DSP)
57 static void SoundServer_InsertNewSound(struct SoundControl);
58 #elif defined(PLATFORM_UNIX)
59 static unsigned char linear_to_ulaw(int);
60 static int ulaw_to_linear(unsigned char);
63 #if defined(AUDIO_LINUX_IOCTL)
64 static boolean InitAudioDevice_Linux();
65 #elif defined(PLATFORM_NETBSD)
66 static boolean InitAudioDevice_NetBSD();
67 #elif defined(PLATFORM_HPUX)
68 static boolean InitAudioDevice_HPUX();
69 #elif defined(PLATFORM_MSDOS)
70 static void SoundServer_InsertNewSound(struct SoundControl);
71 static void SoundServer_StopSound(int);
72 static void SoundServer_StopAllSounds();
75 #if defined(PLATFORM_UNIX)
76 static int OpenAudioDevice(char *audio_device_name)
80 /* check if desired audio device is accessible */
81 if (access(audio_device_name, W_OK) != 0)
84 /* try to open audio device in non-blocking mode */
85 if ((audio_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0)
88 /* re-open audio device in blocking mode */
90 audio_fd = open(audio_device_name, O_WRONLY);
95 static boolean TestAudioDevices(void)
97 static char *audio_device_name[] =
105 /* look for available audio devices, starting with preferred ones */
106 for (i=0; i<sizeof(audio_device_name)/sizeof(char *); i++)
107 if ((audio_fd = OpenAudioDevice(audio_device_name[i])) >= 0)
112 Error(ERR_WARN, "cannot open audio device -- no sound");
118 audio.device_name = audio_device_name[i];
123 #if !defined(TARGET_SDL)
124 static boolean ForkAudioProcess(void)
126 if (pipe(audio.soundserver_pipe) < 0)
128 Error(ERR_WARN, "cannot create pipe -- no sounds");
132 if ((audio.soundserver_pid = fork()) < 0)
134 Error(ERR_WARN, "cannot create sound server process -- no sounds");
138 if (audio.soundserver_pid == 0) /* we are child */
145 else /* we are parent */
146 close(audio.soundserver_pipe[0]); /* no reading from pipe needed */
152 void UnixOpenAudio(void)
154 if (!TestAudioDevices())
157 audio.sound_available = TRUE;
158 audio.sound_enabled = TRUE;
160 #if defined(AUDIO_STREAMING_DSP)
161 audio.music_available = TRUE;
162 audio.loops_available = TRUE;
166 void UnixCloseAudio(void)
169 close(audio.device_fd);
171 if (audio.soundserver_pid)
172 kill(audio.soundserver_pid, SIGTERM);
174 #endif /* PLATFORM_UNIX */
176 void InitPlaylist(void)
180 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
181 playlist[i] = emptySoundControl;
185 void StartSoundserver(void)
187 if (!audio.sound_available)
190 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
191 if (!ForkAudioProcess())
192 audio.sound_available = FALSE;
196 #if defined(PLATFORM_UNIX)
197 void SoundServer(void)
201 struct SoundControl snd_ctrl;
204 close(audio.soundserver_pipe[1]); /* no writing into pipe needed */
208 stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
209 for(i=0;i<PSND_MAX_LEFT2RIGHT;i++)
211 (int)sqrt((float)(PSND_MAX_LEFT2RIGHT*PSND_MAX_LEFT2RIGHT-i*i));
213 #if defined(PLATFORM_HPUX)
214 InitAudioDevice_HPUX();
217 FD_ZERO(&sound_fdset);
218 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
220 while(1) /* wait for sound playing commands from client */
222 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
223 select(audio.soundserver_pipe[0] + 1, &sound_fdset, NULL, NULL, NULL);
224 if (!FD_ISSET(audio.soundserver_pipe[0], &sound_fdset))
226 if (read(audio.soundserver_pipe[0], &snd_ctrl, sizeof(snd_ctrl))
228 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
230 #if defined(AUDIO_STREAMING_DSP)
232 if (snd_ctrl.fade_sound)
237 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
238 if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
239 playlist[i].fade_sound = TRUE;
241 else if (snd_ctrl.stop_all_sounds)
246 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
247 playlist[i]=emptySoundControl;
250 close(audio.device_fd);
252 else if (snd_ctrl.stop_sound)
257 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
258 if (playlist[i].nr == snd_ctrl.nr)
260 playlist[i]=emptySoundControl;
265 close(audio.device_fd);
268 if (playing_sounds || snd_ctrl.active)
270 struct timeval delay = { 0, 0 };
273 static long max_sample_size = 0;
274 static long fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
275 int sample_rate = DEFAULT_AUDIO_SAMPLE_RATE;
276 static boolean stereo = TRUE;
278 if (playing_sounds ||
279 (audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
281 if (!playing_sounds) /* we just opened the audio device */
283 #if defined(AUDIO_LINUX_IOCTL)
284 stereo = InitAudioDevice_Linux(fragment_size, sample_rate);
285 #elif defined(PLATFORM_NETBSD)
286 stereo = InitAudioDevice_NetBSD(fragment_size, sample_rate);
288 max_sample_size = fragment_size / (stereo ? 2 : 1);
291 if (snd_ctrl.active) /* new sound has arrived */
292 SoundServer_InsertNewSound(snd_ctrl);
294 while(playing_sounds &&
295 select(audio.soundserver_pipe[0] + 1,
296 &sound_fdset, NULL, NULL, &delay) < 1)
298 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
300 /* first clear the last premixing buffer */
301 memset(premix_last_buffer, 0, fragment_size * sizeof(int));
303 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
307 if (!playlist[i].active)
310 /* get pointer and size of the actual sound sample */
311 sample_ptr = playlist[i].data_ptr+playlist[i].playingpos;
313 MIN(max_sample_size,playlist[i].data_len-playlist[i].playingpos);
314 playlist[i].playingpos += sample_size;
316 /* fill the first mixing buffer with original sample */
317 memcpy(premix_first_buffer,sample_ptr,sample_size);
319 /* are we about to restart a looping sound? */
320 if (playlist[i].loop && sample_size<max_sample_size)
322 playlist[i].playingpos = max_sample_size-sample_size;
323 memcpy(premix_first_buffer+sample_size,
324 playlist[i].data_ptr,max_sample_size-sample_size);
325 sample_size = max_sample_size;
328 /* decrease volume if sound is fading out */
329 if (playlist[i].fade_sound &&
330 playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
331 playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
333 /* adjust volume of actual sound sample */
334 if (playlist[i].volume != PSND_MAX_VOLUME)
335 for(j=0;j<sample_size;j++)
336 premix_first_buffer[j] =
337 (playlist[i].volume * (int)premix_first_buffer[j])
338 >> PSND_MAX_VOLUME_BITS;
340 /* fill the last mixing buffer with stereo or mono sound */
343 int middle_pos = PSND_MAX_LEFT2RIGHT/2;
344 int left_volume = stereo_volume[middle_pos+playlist[i].stereo];
345 int right_volume = stereo_volume[middle_pos-playlist[i].stereo];
347 for(j=0;j<sample_size;j++)
349 premix_left_buffer[j] =
350 (left_volume * (int)premix_first_buffer[j])
351 >> PSND_MAX_LEFT2RIGHT_BITS;
352 premix_right_buffer[j] =
353 (right_volume * (int)premix_first_buffer[j])
354 >> PSND_MAX_LEFT2RIGHT_BITS;
355 premix_last_buffer[2*j+0] += premix_left_buffer[j];
356 premix_last_buffer[2*j+1] += premix_right_buffer[j];
361 for(j=0;j<sample_size;j++)
362 premix_last_buffer[j] += (int)premix_first_buffer[j];
365 /* delete completed sound entries from the playlist */
366 if (playlist[i].playingpos >= playlist[i].data_len)
368 if (playlist[i].loop)
369 playlist[i].playingpos = 0;
372 playlist[i] = emptySoundControl;
376 else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
378 playlist[i] = emptySoundControl;
383 /* put last mixing buffer to final playing buffer */
384 for(i=0; i<fragment_size; i++)
386 if (premix_last_buffer[i]<-255)
387 playing_buffer[i] = 0;
388 else if (premix_last_buffer[i]>255)
389 playing_buffer[i] = 255;
391 playing_buffer[i] = (premix_last_buffer[i]>>1)^0x80;
394 /* finally play the sound fragment */
395 write(audio.device_fd, playing_buffer, fragment_size);
398 /* if no sounds playing, free device for other sound programs */
400 close(audio.device_fd);
404 #else /* !AUDIO_STREAMING_DSP */
406 if (snd_ctrl.active && !snd_ctrl.loop)
408 struct timeval delay = { 0, 0 };
410 long sample_size, max_sample_size = SND_BLOCKSIZE;
411 long sample_rate = 8000; /* standard "/dev/audio" sampling rate */
412 int wait_percent = 90; /* wait 90% of the real playing time */
415 if ((audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
419 while(playing_sounds &&
420 select(audio.soundserver_pipe[0] + 1,
421 &sound_fdset, NULL, NULL, &delay) < 1)
423 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
425 /* get pointer and size of the actual sound sample */
426 sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos;
428 MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos);
429 snd_ctrl.playingpos += sample_size;
431 /* fill the first mixing buffer with original sample */
432 memcpy(premix_first_buffer,sample_ptr,sample_size);
434 /* adjust volume of actual sound sample */
435 if (snd_ctrl.volume != PSND_MAX_VOLUME)
436 for(i=0;i<sample_size;i++)
437 premix_first_buffer[i] =
438 (snd_ctrl.volume * (int)premix_first_buffer[i])
439 >> PSND_MAX_VOLUME_BITS;
441 for(i=0;i<sample_size;i++)
443 linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
445 if (snd_ctrl.playingpos >= snd_ctrl.data_len)
448 /* finally play the sound fragment */
449 write(audio.device_fd,playing_buffer,sample_size);
452 delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
454 close(audio.device_fd);
457 #endif /* !AUDIO_STREAMING_DSP */
460 #endif /* PLATFORM_UNIX */
462 #if defined(PLATFORM_MSDOS)
463 static void sound_handler(struct SoundControl snd_ctrl)
467 if (snd_ctrl.fade_sound)
472 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
473 if ((snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr) &&
474 !playlist[i].fade_sound)
476 playlist[i].fade_sound = TRUE;
477 if (voice_check(playlist[i].voice))
478 voice_ramp_volume(playlist[i].voice, 1000, 0);
479 playlist[i].loop = PSND_NO_LOOP;
482 else if (snd_ctrl.stop_all_sounds)
486 SoundServer_StopAllSounds();
488 else if (snd_ctrl.stop_sound)
492 SoundServer_StopSound(snd_ctrl.nr);
495 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
497 if (!playlist[i].active || playlist[i].loop)
500 playlist[i].playingpos = voice_get_position(playlist[i].voice);
501 playlist[i].volume = voice_get_volume(playlist[i].voice);
502 if (playlist[i].playingpos == -1 || !playlist[i].volume)
504 deallocate_voice(playlist[i].voice);
505 playlist[i] = emptySoundControl;
511 SoundServer_InsertNewSound(snd_ctrl);
513 #endif /* PLATFORM_MSDOS */
515 #if !defined(PLATFORM_WIN32)
516 static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
520 /* if playlist is full, remove oldest sound */
521 if (playing_sounds==MAX_SOUNDS_PLAYING)
523 int longest=0, longest_nr=0;
525 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
527 #if !defined(PLATFORM_MSDOS)
528 int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
530 int actual = playlist[i].playingpos;
533 if (!playlist[i].loop && actual>longest)
539 #if defined(PLATFORM_MSDOS)
540 voice_set_volume(playlist[longest_nr].voice, 0);
541 deallocate_voice(playlist[longest_nr].voice);
543 playlist[longest_nr] = emptySoundControl;
547 /* check if sound is already being played (and how often) */
548 for(k=0,i=0;i<MAX_SOUNDS_PLAYING;i++)
550 if (playlist[i].nr == snd_ctrl.nr)
554 /* restart loop sounds only if they are just fading out */
555 if (k>=1 && snd_ctrl.loop)
557 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
559 if (playlist[i].nr == snd_ctrl.nr && playlist[i].fade_sound)
561 playlist[i].fade_sound = FALSE;
562 playlist[i].volume = PSND_MAX_VOLUME;
563 #if defined(PLATFORM_MSDOS)
564 playlist[i].loop = PSND_LOOP;
565 voice_stop_volumeramp(playlist[i].voice);
566 voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
573 /* don't play sound more than n times simultaneously (with n == 2 for now) */
576 int longest=0, longest_nr=0;
578 /* look for oldest equal sound */
579 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
583 if (!playlist[i].active || playlist[i].nr != snd_ctrl.nr)
586 #if !defined(PLATFORM_MSDOS)
587 actual = 100 * playlist[i].playingpos / playlist[i].data_len;
589 actual = playlist[i].playingpos;
598 #if defined(PLATFORM_MSDOS)
599 voice_set_volume(playlist[longest_nr].voice, 0);
600 deallocate_voice(playlist[longest_nr].voice);
602 playlist[longest_nr] = emptySoundControl;
606 /* neuen Sound in Liste packen */
607 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
609 if (!playlist[i].active)
611 playlist[i] = snd_ctrl;
614 #if defined(PLATFORM_MSDOS)
615 playlist[i].voice = allocate_voice(Sound[snd_ctrl.nr].sample_ptr);
617 voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
618 voice_set_volume(playlist[i].voice, snd_ctrl.volume);
619 voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
620 voice_start(playlist[i].voice);
626 #endif /* !PLATFORM_WIN32 */
629 void SoundServer_FadeSound(int nr)
636 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
637 if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
638 playlist[i].fade_sound = TRUE;
642 #if !defined(PLATFORM_WIN32)
643 #if defined(PLATFORM_MSDOS)
644 static void SoundServer_StopSound(int nr)
651 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
652 if (playlist[i].nr == nr)
654 #if defined(PLATFORM_MSDOS)
655 voice_set_volume(playlist[i].voice, 0);
656 deallocate_voice(playlist[i].voice);
658 playlist[i] = emptySoundControl;
662 #if !defined(PLATFORM_MSDOS)
664 close(audio.device_fd);
668 static void SoundServer_StopAllSounds()
672 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
674 #if defined(PLATFORM_MSDOS)
675 voice_set_volume(playlist[i].voice, 0);
676 deallocate_voice(playlist[i].voice);
678 playlist[i]=emptySoundControl;
682 #if !defined(PLATFORM_MSDOS)
683 close(audio.device_fd);
686 #endif /* PLATFORM_MSDOS */
687 #endif /* !PLATFORM_WIN32 */
690 /* ------------------------------------------------------------------------- */
691 /* platform dependant audio initialization code */
692 /* ------------------------------------------------------------------------- */
694 #if defined(AUDIO_LINUX_IOCTL)
695 static boolean InitAudioDevice_Linux(long fragment_size, int sample_rate)
697 /* "ioctl()" expects pointer to 'int' value for stereo flag
698 (boolean is defined as 'char', which will not work here) */
700 unsigned long fragment_spec = 0;
702 /* determine logarithm (log2) of the fragment size */
703 for (fragment_spec=0; (1 << fragment_spec) < fragment_size;
706 /* use two fragments (play one fragment, prepare the other);
707 one fragment would result in interrupted audio output, more
708 than two fragments would raise audio output latency to much */
709 fragment_spec |= 0x00020000;
711 /* Example for fragment specification:
712 - 2 buffers / 512 bytes (giving 1/16 second resolution for 8 kHz)
713 - (with stereo the effective buffer size will shrink to 256)
714 => fragment_size = 0x00020009 */
716 if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0)
717 Error(ERR_EXIT_SOUND_SERVER,
718 "cannot set fragment size of /dev/dsp -- no sounds");
720 /* try if we can use stereo sound */
721 if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
724 static boolean reported = FALSE;
728 Error(ERR_RETURN, "cannot get stereo sound on /dev/dsp");
735 if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &sample_rate) < 0)
736 Error(ERR_EXIT_SOUND_SERVER,
737 "cannot set sample rate of /dev/dsp -- no sounds");
739 /* get the real fragmentation size; this should return 512 */
740 if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size) < 0)
741 Error(ERR_EXIT_SOUND_SERVER,
742 "cannot get fragment size of /dev/dsp -- no sounds");
744 return (boolean)stereo;
746 #endif /* AUDIO_LINUX_IOCTL */
748 #if defined(PLATFORM_NETBSD)
749 static boolean InitAudioDevice_NetBSD(long fragment_size, int sample_rate)
752 boolean stereo = TRUE;
754 AUDIO_INITINFO(&a_info);
755 a_info.play.encoding = AUDIO_ENCODING_LINEAR8;
756 a_info.play.precision = 8;
757 a_info.play.channels = 2;
758 a_info.play.sample_rate = sample_rate;
759 a_info.blocksize = fragment_size;
761 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
763 /* try to disable stereo */
764 a_info.play.channels = 1;
767 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
768 Error(ERR_EXIT_SOUND_SERVER,
769 "cannot set sample rate of /dev/audio -- no sounds");
774 #endif /* PLATFORM_NETBSD */
776 #if defined(PLATFORM_HPUX)
777 static boolean InitAudioDevice_HPUX()
779 struct audio_describe ainfo;
782 audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
784 Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl -- no sounds");
786 if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
787 Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds");
789 if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
790 Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds");
792 ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
793 ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
797 return TRUE; /* to provide common interface for InitAudioDevice_...() */
799 #endif /* PLATFORM_HPUX */
801 #if defined(PLATFORM_UNIX) && !defined(AUDIO_STREAMING_DSP)
803 /* these two are stolen from "sox"... :) */
806 ** This routine converts from linear to ulaw.
808 ** Craig Reese: IDA/Supercomputing Research Center
809 ** Joe Campbell: Department of Defense
813 ** 1) CCITT Recommendation G.711 (very difficult to follow)
814 ** 2) "A New Digital Technique for Implementation of Any
815 ** Continuous PCM Companding Law," Villeret, Michel,
816 ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
817 ** 1973, pg. 11.12-11.17
818 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
819 ** for Analog-to_Digital Conversion Techniques,"
822 ** Input: Signed 16 bit linear sample
823 ** Output: 8 bit ulaw sample
826 #define ZEROTRAP /* turn on the trap as per the MIL-STD */
827 #define BIAS 0x84 /* define the add-in bias for 16 bit samples */
830 static unsigned char linear_to_ulaw(int sample)
832 static int exp_lut[256] =
834 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
835 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
836 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
837 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
838 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
839 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
840 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
841 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
842 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
843 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
844 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
845 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
846 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
847 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
848 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
849 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
852 int sign, exponent, mantissa;
853 unsigned char ulawbyte;
855 /* Get the sample into sign-magnitude. */
856 sign = (sample >> 8) & 0x80; /* set aside the sign */
858 sample = -sample; /* get magnitude */
860 sample = CLIP; /* clip the magnitude */
862 /* Convert from 16 bit linear to ulaw. */
863 sample = sample + BIAS;
864 exponent = exp_lut[( sample >> 7 ) & 0xFF];
865 mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
866 ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
869 ulawbyte = 0x02; /* optional CCITT trap */
876 ** This routine converts from ulaw to 16 bit linear.
878 ** Craig Reese: IDA/Supercomputing Research Center
882 ** 1) CCITT Recommendation G.711 (very difficult to follow)
883 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
884 ** for Analog-to_Digital Conversion Techniques,"
887 ** Input: 8 bit ulaw sample
888 ** Output: signed 16 bit linear sample
891 static int ulaw_to_linear(unsigned char ulawbyte)
893 static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
894 int sign, exponent, mantissa, sample;
896 ulawbyte = ~ ulawbyte;
897 sign = ( ulawbyte & 0x80 );
898 exponent = ( ulawbyte >> 4 ) & 0x07;
899 mantissa = ulawbyte & 0x0F;
900 sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
906 #endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */
909 /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
910 /* ========================================================================= */
911 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */
914 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
915 #define WAV_HEADER_SIZE 20 /* size of WAV file header */
917 static boolean LoadSoundExt(char *sound_name, boolean is_music)
919 struct SampleInfo *snd_info;
921 #if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS)
922 byte sound_header_buffer[WAV_HEADER_SIZE];
923 char chunk[CHUNK_ID_LEN + 1];
924 int chunk_size, dummy;
929 if (!audio.sound_available)
933 Sound = checked_realloc(Sound, num_sounds * sizeof(struct SampleInfo));
935 snd_info = &Sound[num_sounds - 1];
936 snd_info->name = sound_name;
938 filename = getPath2((is_music ? options.music_directory :
939 options.sounds_directory), snd_info->name);
941 #if defined(TARGET_SDL)
943 if ((snd_info->mix_chunk = Mix_LoadWAV(filename)) == NULL)
945 Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename);
950 #elif defined(PLATFORM_UNIX)
952 if ((file = fopen(filename, MODE_READ)) == NULL)
954 Error(ERR_WARN, "cannot open sound file '%s' -- no sounds", filename);
959 /* read chunk "RIFF" */
960 getFileChunk(file, chunk, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
961 if (strcmp(chunk, "RIFF") != 0)
963 Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
969 /* read chunk "WAVE" */
970 getFileChunk(file, chunk, &dummy, BYTE_ORDER_LITTLE_ENDIAN);
971 if (strcmp(chunk, "WAVE") != 0)
973 Error(ERR_WARN, "missing 'WAVE' chunk of sound file '%s'", filename);
979 /* read header information */
980 for (i=0; i<WAV_HEADER_SIZE; i++)
981 sound_header_buffer[i] = fgetc(file);
983 /* read chunk "data" */
984 getFileChunk(file, chunk, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
985 if (strcmp(chunk, "data") != 0)
987 Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
993 snd_info->data_len = chunk_size;
994 snd_info->data_ptr = checked_malloc(snd_info->data_len);
996 /* read sound data */
997 if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
1000 Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename);
1008 for (i=0; i<snd_info->data_len; i++)
1009 snd_info->data_ptr[i] = snd_info->data_ptr[i] ^ 0x80;
1011 #else /* PLATFORM_MSDOS */
1013 snd_info->sample_ptr = load_sample(filename);
1014 if (!snd_info->sample_ptr)
1016 Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename);
1027 boolean LoadSound(char *sound_name)
1029 return LoadSoundExt(sound_name, FALSE);
1032 boolean LoadMod(char *mod_name)
1034 #if defined(TARGET_SDL)
1035 struct SampleInfo *mod_info;
1039 Mod = checked_realloc(Mod, num_mods * sizeof(struct SampleInfo));
1041 mod_info = &Mod[num_mods - 1];
1042 mod_info->name = mod_name;
1044 filename = getPath2(options.music_directory, mod_info->name);
1046 if ((mod_info->mix_music = Mix_LoadMUS(filename)) == NULL)
1048 Error(ERR_WARN, "cannot read music file '%s' -- no music", filename);
1064 struct dirent *dir_entry;
1065 int num_wav_music = 0;
1066 int num_mod_music = 0;
1068 if (!audio.sound_available)
1071 if ((dir = opendir(options.music_directory)) == NULL)
1073 Error(ERR_WARN, "cannot read music directory '%s'",
1074 options.music_directory);
1075 audio.music_available = FALSE;
1079 while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
1081 char *filename = dir_entry->d_name;
1083 if (FileIsSound(filename) && LoadSoundExt(filename, TRUE))
1085 else if (FileIsMusic(filename) && LoadMod(filename))
1091 if (num_wav_music == 0 && num_mod_music == 0)
1092 Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
1093 options.music_directory);
1095 num_music = (num_mod_music > 0 ? num_mod_music : num_wav_music);
1097 audio.mods_available = (num_mod_music > 0);
1098 audio.music_available = (num_music > 0);
1103 void PlayMusic(int nr)
1105 if (!audio.music_available)
1108 if (!audio.mods_available)
1109 nr = num_sounds - num_music + nr;
1111 #if defined(TARGET_SDL)
1112 if (audio.mods_available) /* play MOD music */
1114 Mix_PlayMusic(Mod[nr].mix_music, -1);
1115 Mix_VolumeMusic(SOUND_MAX_VOLUME); /* must be _after_ Mix_PlayMusic()! */
1117 else /* play WAV music loop */
1119 Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
1120 Mix_PlayChannel(audio.music_channel, Sound[nr].mix_chunk, -1);
1123 audio.music_nr = nr;
1128 void PlaySound(int nr)
1130 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
1133 void PlaySoundStereo(int nr, int stereo)
1135 PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
1138 void PlaySoundLoop(int nr)
1140 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
1143 void PlaySoundExt(int nr, int volume, int stereo, boolean loop)
1145 struct SoundControl snd_ctrl = emptySoundControl;
1147 if (!audio.sound_available || !audio.sound_enabled)
1150 if (volume<PSND_MIN_VOLUME)
1151 volume = PSND_MIN_VOLUME;
1152 else if (volume>PSND_MAX_VOLUME)
1153 volume = PSND_MAX_VOLUME;
1155 if (stereo<PSND_MAX_LEFT)
1156 stereo = PSND_MAX_LEFT;
1157 else if (stereo>PSND_MAX_RIGHT)
1158 stereo = PSND_MAX_RIGHT;
1161 snd_ctrl.volume = volume;
1162 snd_ctrl.stereo = stereo;
1163 snd_ctrl.loop = loop;
1164 snd_ctrl.active = TRUE;
1165 snd_ctrl.data_ptr = Sound[nr].data_ptr;
1166 snd_ctrl.data_len = Sound[nr].data_len;
1168 #if defined(TARGET_SDL)
1169 Mix_Volume(-1, SOUND_MAX_VOLUME);
1170 Mix_PlayChannel(-1, Sound[nr].mix_chunk, (loop ? -1 : 0));
1171 #elif defined(PLATFORM_UNIX)
1172 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1174 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1175 audio.sound_available = audio.sound_enabled = FALSE;
1178 #elif defined(PLATFORM_MSDOS)
1179 sound_handler(snd_ctrl);
1183 void FadeMusic(void)
1185 #if defined(TARGET_SDL)
1186 if (!audio.sound_available)
1189 if (audio.mods_available)
1190 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1192 Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
1194 FadeSound(audio.music_nr);
1198 void FadeSound(int nr)
1200 StopSoundExt(nr, SSND_FADE_SOUND);
1206 StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
1209 void StopMusic(void)
1211 #if defined(TARGET_SDL)
1212 if (!audio.sound_available)
1215 if (audio.mods_available)
1218 Mix_HaltChannel(audio.music_channel);
1220 StopSound(audio.music_nr);
1224 void StopSound(int nr)
1226 StopSoundExt(nr, SSND_STOP_SOUND);
1231 StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
1234 void StopSoundExt(int nr, int method)
1236 struct SoundControl snd_ctrl = emptySoundControl;
1238 if (!audio.sound_available)
1241 if (SSND_FADING(method))
1242 snd_ctrl.fade_sound = TRUE;
1244 if (SSND_ALL(method))
1245 snd_ctrl.stop_all_sounds = TRUE;
1249 snd_ctrl.stop_sound = TRUE;
1252 #if defined(TARGET_SDL)
1254 if (SSND_FADING(method))
1258 for (i=0; i<audio.channels; i++)
1259 if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
1260 Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
1261 if (snd_ctrl.stop_all_sounds)
1262 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1268 for (i=0; i<audio.channels; i++)
1269 if (i != audio.music_channel || snd_ctrl.stop_all_sounds)
1271 if (snd_ctrl.stop_all_sounds)
1276 #if !defined(PLATFORM_MSDOS)
1277 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1279 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1280 audio.sound_available = audio.sound_enabled = FALSE;
1284 sound_handler(snd_ctrl);
1289 void FreeSounds(int num_sounds)
1293 if (!audio.sound_available)
1296 for(i=0; i<num_sounds; i++)
1297 #if defined(TARGET_SDL)
1298 free(Sound[i].mix_chunk);
1299 #elif !defined(PLATFORM_MSDOS)
1300 free(Sound[i].data_ptr);
1302 destroy_sample(Sound[i].sample_ptr);
1306 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
1307 /* ========================================================================= */