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 ***********************************************************/
27 static SoundInfo **Sound = NULL;
28 static MusicInfo **Music = NULL;
29 static int num_sounds = 0, num_music = 0;
32 /* ========================================================================= */
33 /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
35 static int playing_sounds = 0;
36 static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
37 static struct SoundControl emptySoundControl =
39 -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, 0,0, 0,NULL
42 #if defined(PLATFORM_UNIX)
43 static int stereo_volume[PSND_MAX_LEFT2RIGHT+1];
44 static short premix_first_buffer[SND_BLOCKSIZE];
45 #if defined(AUDIO_STREAMING_DSP)
46 static short premix_left_buffer[SND_BLOCKSIZE];
47 static short premix_right_buffer[SND_BLOCKSIZE];
48 static long premix_last_buffer[SND_BLOCKSIZE];
50 static short playing_buffer[SND_BLOCKSIZE];
53 /* forward declaration of internal functions */
54 #if defined(AUDIO_STREAMING_DSP)
55 static void SoundServer_InsertNewSound(struct SoundControl);
56 static boolean InitAudioDevice_DSP(int, int);
57 #elif defined(PLATFORM_HPUX)
58 static boolean InitAudioDevice_HPUX();
59 #elif defined(PLATFORM_UNIX)
60 static unsigned char linear_to_ulaw(int);
61 static int ulaw_to_linear(unsigned char);
62 #elif defined(PLATFORM_MSDOS)
63 static void SoundServer_InsertNewSound(struct SoundControl);
64 static void SoundServer_StopSound(struct SoundControl);
65 static void SoundServer_StopAllSounds();
68 #if defined(PLATFORM_UNIX)
69 static int OpenAudioDevice(char *audio_device_name)
73 /* check if desired audio device is accessible */
74 if (access(audio_device_name, W_OK) != 0)
77 /* try to open audio device in non-blocking mode */
78 if ((audio_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0)
81 /* re-open audio device in blocking mode */
83 audio_fd = open(audio_device_name, O_WRONLY);
88 static boolean TestAudioDevices(void)
90 static char *audio_device_name[] =
98 /* look for available audio devices, starting with preferred ones */
99 for (i=0; i<sizeof(audio_device_name)/sizeof(char *); i++)
100 if ((audio_fd = OpenAudioDevice(audio_device_name[i])) >= 0)
105 Error(ERR_WARN, "cannot open audio device -- no sound");
111 audio.device_name = audio_device_name[i];
116 #if !defined(TARGET_SDL)
117 static boolean ForkAudioProcess(void)
119 if (pipe(audio.soundserver_pipe) < 0)
121 Error(ERR_WARN, "cannot create pipe -- no sounds");
125 if ((audio.soundserver_pid = fork()) < 0)
127 Error(ERR_WARN, "cannot create sound server process -- no sounds");
131 if (audio.soundserver_pid == 0) /* we are child process */
138 else /* we are parent */
139 close(audio.soundserver_pipe[0]); /* no reading from pipe needed */
145 void UnixOpenAudio(void)
147 if (!TestAudioDevices())
150 audio.sound_available = TRUE;
151 audio.sound_enabled = TRUE;
153 #if defined(AUDIO_STREAMING_DSP)
154 audio.music_available = TRUE;
155 audio.loops_available = TRUE;
159 void UnixCloseAudio(void)
162 close(audio.device_fd);
164 if (audio.soundserver_pid > 0) /* we are parent process */
165 kill(audio.soundserver_pid, SIGTERM);
167 #endif /* PLATFORM_UNIX */
169 void InitPlaylist(void)
173 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
174 playlist[i] = emptySoundControl;
178 void StartSoundserver(void)
180 if (!audio.sound_available)
183 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
184 if (!ForkAudioProcess())
185 audio.sound_available = FALSE;
189 #if defined(PLATFORM_UNIX)
190 void SoundServer(void)
194 struct SoundControl snd_ctrl;
197 close(audio.soundserver_pipe[1]); /* no writing into pipe needed */
201 stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
202 for(i=0; i<PSND_MAX_LEFT2RIGHT; i++)
204 (int)sqrt((float)(PSND_MAX_LEFT2RIGHT * PSND_MAX_LEFT2RIGHT - i * i));
206 #if defined(PLATFORM_HPUX)
207 InitAudioDevice_HPUX();
210 FD_ZERO(&sound_fdset);
211 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
213 while(1) /* wait for sound playing commands from client */
215 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
216 select(audio.soundserver_pipe[0] + 1, &sound_fdset, NULL, NULL, NULL);
217 if (!FD_ISSET(audio.soundserver_pipe[0], &sound_fdset))
219 if (read(audio.soundserver_pipe[0], &snd_ctrl, sizeof(snd_ctrl))
221 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
223 if (snd_ctrl.reload_sounds || snd_ctrl.reload_music)
225 char *set_name = checked_malloc(snd_ctrl.data_len);
227 (snd_ctrl.reload_sounds ? &artwork.snd_current : &artwork.mus_current);
228 TreeInfo *ti = *ti_ptr;
229 unsigned long str_size1, str_size2, str_size3;
231 if (leveldir_current == NULL)
232 leveldir_current = checked_calloc(sizeof(TreeInfo));
234 ti = *ti_ptr = checked_calloc(sizeof(TreeInfo));
235 if (leveldir_current->fullpath != NULL)
236 free(leveldir_current->fullpath);
237 if (ti->basepath != NULL)
239 if (ti->fullpath != NULL)
242 if (read(audio.soundserver_pipe[0], set_name,
243 snd_ctrl.data_len) != snd_ctrl.data_len ||
244 read(audio.soundserver_pipe[0], leveldir_current,
245 sizeof(TreeInfo)) != sizeof(TreeInfo) ||
246 read(audio.soundserver_pipe[0], ti,
247 sizeof(TreeInfo)) != sizeof(TreeInfo) ||
248 read(audio.soundserver_pipe[0], &str_size1,
249 sizeof(unsigned long)) != sizeof(unsigned long) ||
250 read(audio.soundserver_pipe[0], &str_size2,
251 sizeof(unsigned long)) != sizeof(unsigned long) ||
252 read(audio.soundserver_pipe[0], &str_size3,
253 sizeof(unsigned long)) != sizeof(unsigned long))
254 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
256 leveldir_current->fullpath = checked_calloc(str_size1);
257 ti->basepath = checked_calloc(str_size2);
258 ti->fullpath = checked_calloc(str_size3);
260 if (read(audio.soundserver_pipe[0], leveldir_current->fullpath,
261 str_size1) != str_size1 ||
262 read(audio.soundserver_pipe[0], ti->basepath,
263 str_size2) != str_size2 ||
264 read(audio.soundserver_pipe[0], ti->fullpath,
265 str_size3) != str_size3)
266 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
270 close(audio.device_fd);
272 if (snd_ctrl.reload_sounds)
274 artwork.sounds_set_current = set_name;
275 audio.func_reload_sounds();
279 artwork.music_set_current = set_name;
280 audio.func_reload_music();
288 #if defined(AUDIO_STREAMING_DSP)
290 if (snd_ctrl.fade_sound)
296 playlist[audio.music_channel].fade_sound = TRUE;
298 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
299 if (snd_ctrl.stop_all_sounds ||
300 (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr))
301 playlist[i].fade_sound = TRUE;
303 else if (snd_ctrl.stop_all_sounds)
308 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
309 playlist[i] = emptySoundControl;
312 close(audio.device_fd);
314 else if (snd_ctrl.stop_sound)
321 playlist[audio.music_channel] = emptySoundControl;
325 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
327 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr)
329 playlist[i] = emptySoundControl;
335 close(audio.device_fd);
338 if (playing_sounds || snd_ctrl.active)
340 if (playing_sounds ||
341 (audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
343 struct timeval delay = { 0, 0 };
344 static int fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
345 int sample_rate = DEFAULT_AUDIO_SAMPLE_RATE;
346 static boolean stereo = TRUE;
348 if (!playing_sounds) /* we just opened the audio device */
349 stereo = InitAudioDevice_DSP(fragment_size, sample_rate);
351 if (snd_ctrl.active) /* new sound has arrived */
352 SoundServer_InsertNewSound(snd_ctrl);
354 while (playing_sounds &&
355 select(audio.soundserver_pipe[0] + 1,
356 &sound_fdset, NULL, NULL, &delay) < 1)
362 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
364 max_sample_size = fragment_size / ((stereo ? 2 : 1) * sizeof(short));
366 /* first clear the last premixing buffer */
367 memset(premix_last_buffer, 0,
368 max_sample_size * (stereo ? 2 : 1) * sizeof(long));
370 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
374 if (!playlist[i].active)
377 /* get pointer and size of the actual sound sample */
378 sample_ptr = (short *)playlist[i].data_ptr +playlist[i].playingpos;
379 sample_size = MIN(max_sample_size,
380 playlist[i].data_len - playlist[i].playingpos);
381 playlist[i].playingpos += sample_size;
383 /* fill the first mixing buffer with original sample */
384 memcpy(premix_first_buffer, sample_ptr,
385 sample_size * sizeof(short));
387 /* are we about to restart a looping sound? */
388 if (playlist[i].loop && sample_size < max_sample_size)
390 playlist[i].playingpos = max_sample_size - sample_size;
391 memcpy(premix_first_buffer + sample_size * sizeof(short),
392 playlist[i].data_ptr,
393 (max_sample_size - sample_size) * sizeof(short));
394 sample_size = max_sample_size;
397 /* decrease volume if sound is fading out */
398 if (playlist[i].fade_sound &&
399 playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
400 playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
402 /* adjust volume of actual sound sample */
403 if (playlist[i].volume != PSND_MAX_VOLUME)
404 for(j=0; j<sample_size; j++)
405 premix_first_buffer[j] =
406 (playlist[i].volume * (long)premix_first_buffer[j])
407 >> PSND_MAX_VOLUME_BITS;
409 /* fill the last mixing buffer with stereo or mono sound */
412 int middle_pos = PSND_MAX_LEFT2RIGHT / 2;
413 int left_volume = stereo_volume[middle_pos + playlist[i].stereo];
414 int right_volume= stereo_volume[middle_pos - playlist[i].stereo];
416 for(j=0; j<sample_size; j++)
418 premix_left_buffer[j] =
419 (left_volume * premix_first_buffer[j])
420 >> PSND_MAX_LEFT2RIGHT_BITS;
421 premix_right_buffer[j] =
422 (right_volume * premix_first_buffer[j])
423 >> PSND_MAX_LEFT2RIGHT_BITS;
425 premix_last_buffer[2 * j + 0] += premix_left_buffer[j];
426 premix_last_buffer[2 * j + 1] += premix_right_buffer[j];
431 for(j=0; j<sample_size; j++)
432 premix_last_buffer[j] += premix_first_buffer[j];
435 /* delete completed sound entries from the playlist */
436 if (playlist[i].playingpos >= playlist[i].data_len)
438 if (playlist[i].loop)
439 playlist[i].playingpos = 0;
442 playlist[i] = emptySoundControl;
446 else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
448 playlist[i] = emptySoundControl;
453 /* put last mixing buffer to final playing buffer */
454 for(i=0; i<max_sample_size * (stereo ? 2 : 1); i++)
456 if (premix_last_buffer[i] < -65535)
457 playing_buffer[i] = -32767;
458 else if (premix_last_buffer[i] > 65535)
459 playing_buffer[i] = 32767;
461 playing_buffer[i] = (short)(premix_last_buffer[i] >> 1);
464 /* finally play the sound fragment */
465 write(audio.device_fd, playing_buffer, fragment_size);
468 /* if no sounds playing, free device for other sound programs */
470 close(audio.device_fd);
474 #else /* !AUDIO_STREAMING_DSP */
476 if (snd_ctrl.active && !snd_ctrl.loop)
478 struct timeval delay = { 0, 0 };
480 long sample_size, max_sample_size = SND_BLOCKSIZE;
481 long sample_rate = 8000; /* standard "/dev/audio" sampling rate */
482 int wait_percent = 90; /* wait 90% of the real playing time */
485 if ((audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
489 while (playing_sounds &&
490 select(audio.soundserver_pipe[0] + 1,
491 &sound_fdset, NULL, NULL, &delay) < 1)
493 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
495 /* get pointer and size of the actual sound sample */
496 sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos;
498 MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos);
499 snd_ctrl.playingpos += sample_size;
501 /* fill the first mixing buffer with original sample */
502 memcpy(premix_first_buffer,sample_ptr,sample_size);
504 /* adjust volume of actual sound sample */
505 if (snd_ctrl.volume != PSND_MAX_VOLUME)
506 for(i=0;i<sample_size;i++)
507 premix_first_buffer[i] =
508 (snd_ctrl.volume * (int)premix_first_buffer[i])
509 >> PSND_MAX_VOLUME_BITS;
511 for(i=0;i<sample_size;i++)
513 linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
515 if (snd_ctrl.playingpos >= snd_ctrl.data_len)
518 /* finally play the sound fragment */
519 write(audio.device_fd,playing_buffer,sample_size);
522 delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
524 close(audio.device_fd);
527 #endif /* !AUDIO_STREAMING_DSP */
530 #endif /* PLATFORM_UNIX */
532 #if defined(PLATFORM_MSDOS)
533 static void sound_handler(struct SoundControl snd_ctrl)
537 if (snd_ctrl.fade_sound)
542 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
543 if ((snd_ctrl.stop_all_sounds ||
544 (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr) ||
545 (i == audio.music_channel && snd_ctrl.music)) &&
546 !playlist[i].fade_sound)
548 playlist[i].fade_sound = TRUE;
549 if (voice_check(playlist[i].voice))
550 voice_ramp_volume(playlist[i].voice, 1000, 0);
551 playlist[i].loop = PSND_NO_LOOP;
554 else if (snd_ctrl.stop_all_sounds)
558 SoundServer_StopAllSounds();
560 else if (snd_ctrl.stop_sound)
564 SoundServer_StopSound(snd_ctrl);
567 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
569 if (!playlist[i].active || playlist[i].loop)
572 playlist[i].playingpos = voice_get_position(playlist[i].voice);
573 playlist[i].volume = voice_get_volume(playlist[i].voice);
574 if (playlist[i].playingpos == -1 || !playlist[i].volume)
576 deallocate_voice(playlist[i].voice);
577 playlist[i] = emptySoundControl;
583 SoundServer_InsertNewSound(snd_ctrl);
585 #endif /* PLATFORM_MSDOS */
587 #if !defined(PLATFORM_WIN32)
588 static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
593 snd_ctrl.nr = snd_ctrl.nr % num_music;
595 /* if playlist is full, remove oldest sound */
596 if (playing_sounds == MAX_SOUNDS_PLAYING)
598 int longest = 0, longest_nr = 0;
600 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
602 #if !defined(PLATFORM_MSDOS)
603 int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
605 int actual = playlist[i].playingpos;
608 if (i != audio.music_channel && !playlist[i].loop && actual > longest)
614 #if defined(PLATFORM_MSDOS)
615 voice_set_volume(playlist[longest_nr].voice, 0);
616 deallocate_voice(playlist[longest_nr].voice);
618 playlist[longest_nr] = emptySoundControl;
622 /* check if sound is already being played (and how often) */
623 for (k=0,i=0; i<MAX_SOUNDS_PLAYING; i++)
624 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr)
627 /* restart loop sounds only if they are just fading out */
628 if (k >= 1 && snd_ctrl.loop)
630 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
632 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr &&
633 playlist[i].fade_sound)
635 playlist[i].fade_sound = FALSE;
636 playlist[i].volume = PSND_MAX_VOLUME;
637 #if defined(PLATFORM_MSDOS)
638 playlist[i].loop = PSND_LOOP;
639 voice_stop_volumeramp(playlist[i].voice);
640 voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
648 /* don't play sound more than n times simultaneously (with n == 2 for now) */
651 int longest = 0, longest_nr = 0;
653 /* look for oldest equal sound */
654 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
658 if (!playlist[i].active ||
659 i == audio.music_channel ||
660 playlist[i].nr != snd_ctrl.nr)
663 #if !defined(PLATFORM_MSDOS)
664 actual = 100 * playlist[i].playingpos / playlist[i].data_len;
666 actual = playlist[i].playingpos;
668 if (actual >= longest)
675 #if defined(PLATFORM_MSDOS)
676 voice_set_volume(playlist[longest_nr].voice, 0);
677 deallocate_voice(playlist[longest_nr].voice);
679 playlist[longest_nr] = emptySoundControl;
683 /* add new sound to playlist */
684 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
686 if (!playlist[i].active ||
687 (snd_ctrl.music && i == audio.music_channel))
689 SoundInfo *snd_info =
690 (snd_ctrl.music ? Music[snd_ctrl.nr] : Sound[snd_ctrl.nr]);
692 snd_ctrl.data_ptr = snd_info->data_ptr;
693 snd_ctrl.data_len = snd_info->data_len;
695 playlist[i] = snd_ctrl;
698 #if defined(PLATFORM_MSDOS)
699 playlist[i].voice = allocate_voice((SAMPLE *)playlist[i].data_ptr);
702 voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
704 voice_set_volume(playlist[i].voice, snd_ctrl.volume);
705 voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
706 voice_start(playlist[i].voice);
712 #endif /* !PLATFORM_WIN32 */
715 void SoundServer_FadeSound(int nr)
722 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
723 if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
724 playlist[i].fade_sound = TRUE;
728 #if !defined(PLATFORM_WIN32)
729 #if defined(PLATFORM_MSDOS)
730 static void SoundServer_StopSound(struct SoundControl snd_ctrl)
732 int nr = snd_ctrl.nr;
738 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
740 if ((i == audio.music_channel && snd_ctrl.music) ||
741 (i != audio.music_channel && playlist[i].nr == nr))
743 #if defined(PLATFORM_MSDOS)
744 voice_set_volume(playlist[i].voice, 0);
745 deallocate_voice(playlist[i].voice);
747 playlist[i] = emptySoundControl;
752 #if !defined(PLATFORM_MSDOS)
754 close(audio.device_fd);
758 static void SoundServer_StopAllSounds()
762 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
764 #if defined(PLATFORM_MSDOS)
765 voice_set_volume(playlist[i].voice, 0);
766 deallocate_voice(playlist[i].voice);
768 playlist[i]=emptySoundControl;
772 #if !defined(PLATFORM_MSDOS)
773 close(audio.device_fd);
776 #endif /* PLATFORM_MSDOS */
777 #endif /* !PLATFORM_WIN32 */
780 /* ------------------------------------------------------------------------- */
781 /* platform dependant audio initialization code */
782 /* ------------------------------------------------------------------------- */
784 #if defined(AUDIO_LINUX_IOCTL)
785 static boolean InitAudioDevice_Linux(int fragment_size, int sample_rate)
787 /* "ioctl()" expects pointer to 'int' value for stereo flag
788 (boolean is defined as 'char', which will not work here) */
789 unsigned int fragment_spec = 0;
790 unsigned int audio_format = 0;
791 int fragment_size_query;
794 /* determine logarithm (log2) of the fragment size */
795 for (fragment_spec=0; (1 << fragment_spec) < fragment_size; fragment_spec++);
797 /* use two fragments (play one fragment, prepare the other);
798 one fragment would result in interrupted audio output, more
799 than two fragments would raise audio output latency to much */
800 fragment_spec |= 0x00020000;
802 /* Example for fragment specification:
803 - 2 buffers / 512 bytes (giving 1/16 second resolution for 8 kHz)
804 - (with stereo the effective buffer size will shrink to 256)
805 => fragment_size = 0x00020009 */
807 if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0)
808 Error(ERR_EXIT_SOUND_SERVER,
809 "cannot set fragment size of /dev/dsp -- no sounds");
811 audio_format = AFMT_S16_LE;
812 if (ioctl(audio.device_fd, SNDCTL_DSP_SETFMT, &audio_format) < 0)
813 Error(ERR_EXIT_SOUND_SERVER,
814 "cannot set audio format of /dev/dsp -- no sounds");
816 /* try if we can use stereo sound */
817 if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
820 static boolean reported = FALSE;
824 Error(ERR_RETURN, "cannot get stereo sound on /dev/dsp");
831 if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &sample_rate) < 0)
832 Error(ERR_EXIT_SOUND_SERVER,
833 "cannot set sample rate of /dev/dsp -- no sounds");
835 /* get the real fragmentation size; this should return 512 */
836 if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size_query) < 0)
837 Error(ERR_EXIT_SOUND_SERVER,
838 "cannot get fragment size of /dev/dsp -- no sounds");
839 if (fragment_size_query != fragment_size)
840 Error(ERR_EXIT_SOUND_SERVER,
841 "cannot set fragment size of /dev/dsp -- no sounds");
843 return (boolean)stereo;
845 #endif /* AUDIO_LINUX_IOCTL */
847 #if defined(PLATFORM_NETBSD)
848 static boolean InitAudioDevice_NetBSD(int fragment_size, int sample_rate)
851 boolean stereo = TRUE;
853 AUDIO_INITINFO(&a_info);
854 a_info.play.encoding = AUDIO_ENCODING_LINEAR8;
855 a_info.play.precision = 8;
856 a_info.play.channels = 2;
857 a_info.play.sample_rate = sample_rate;
858 a_info.blocksize = fragment_size;
860 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
862 /* try to disable stereo */
863 a_info.play.channels = 1;
866 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
867 Error(ERR_EXIT_SOUND_SERVER,
868 "cannot set sample rate of /dev/audio -- no sounds");
873 #endif /* PLATFORM_NETBSD */
875 #if defined(PLATFORM_HPUX)
876 static boolean InitAudioDevice_HPUX()
878 struct audio_describe ainfo;
881 audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
883 Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl -- no sounds");
885 if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
886 Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds");
888 if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
889 Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds");
891 ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
892 ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
896 return TRUE; /* to provide common interface for InitAudioDevice_...() */
898 #endif /* PLATFORM_HPUX */
900 #if defined(PLATFORM_UNIX)
901 static boolean InitAudioDevice_DSP(int fragment_size, int sample_rate)
903 #if defined(AUDIO_LINUX_IOCTL)
904 return InitAudioDevice_Linux(fragment_size, sample_rate);
905 #elif defined(PLATFORM_NETBSD)
906 return InitAudioDevice_NetBSD(fragment_size, sample_rate);
907 #elif defined(PLATFORM_HPUX)
908 return InitAudioDevice_HPUX();
911 #endif /* PLATFORM_UNIX */
913 #if defined(PLATFORM_UNIX) && !defined(AUDIO_STREAMING_DSP)
915 /* these two are stolen from "sox"... :) */
918 ** This routine converts from linear to ulaw.
920 ** Craig Reese: IDA/Supercomputing Research Center
921 ** Joe Campbell: Department of Defense
925 ** 1) CCITT Recommendation G.711 (very difficult to follow)
926 ** 2) "A New Digital Technique for Implementation of Any
927 ** Continuous PCM Companding Law," Villeret, Michel,
928 ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
929 ** 1973, pg. 11.12-11.17
930 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
931 ** for Analog-to_Digital Conversion Techniques,"
934 ** Input: Signed 16 bit linear sample
935 ** Output: 8 bit ulaw sample
938 #define ZEROTRAP /* turn on the trap as per the MIL-STD */
939 #define BIAS 0x84 /* define the add-in bias for 16 bit samples */
942 static unsigned char linear_to_ulaw(int sample)
944 static int exp_lut[256] =
946 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
947 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
948 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
949 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
950 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
951 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
952 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
953 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
954 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
955 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
956 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
957 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
958 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
959 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
960 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
961 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
964 int sign, exponent, mantissa;
965 unsigned char ulawbyte;
967 /* Get the sample into sign-magnitude. */
968 sign = (sample >> 8) & 0x80; /* set aside the sign */
970 sample = -sample; /* get magnitude */
972 sample = CLIP; /* clip the magnitude */
974 /* Convert from 16 bit linear to ulaw. */
975 sample = sample + BIAS;
976 exponent = exp_lut[( sample >> 7 ) & 0xFF];
977 mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
978 ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
981 ulawbyte = 0x02; /* optional CCITT trap */
988 ** This routine converts from ulaw to 16 bit linear.
990 ** Craig Reese: IDA/Supercomputing Research Center
994 ** 1) CCITT Recommendation G.711 (very difficult to follow)
995 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
996 ** for Analog-to_Digital Conversion Techniques,"
999 ** Input: 8 bit ulaw sample
1000 ** Output: signed 16 bit linear sample
1003 static int ulaw_to_linear(unsigned char ulawbyte)
1005 static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
1006 int sign, exponent, mantissa, sample;
1008 ulawbyte = ~ ulawbyte;
1009 sign = ( ulawbyte & 0x80 );
1010 exponent = ( ulawbyte >> 4 ) & 0x07;
1011 mantissa = ulawbyte & 0x0F;
1012 sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
1018 #endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */
1021 /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
1022 /* ========================================================================= */
1023 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */
1025 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
1026 #define WAV_HEADER_SIZE 16 /* size of WAV file header */
1028 static SoundInfo *Load_WAV(char *filename)
1030 SoundInfo *snd_info;
1031 #if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS)
1032 byte sound_header_buffer[WAV_HEADER_SIZE];
1033 char chunk_name[CHUNK_ID_LEN + 1];
1040 if (!audio.sound_available)
1043 snd_info = checked_calloc(sizeof(SoundInfo));
1045 #if defined(TARGET_SDL)
1047 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
1049 Error(ERR_WARN, "cannot read sound file '%s'", filename);
1054 #elif defined(TARGET_ALLEGRO)
1056 if ((snd_info->data_ptr = load_sample(filename)) == NULL)
1058 Error(ERR_WARN, "cannot read sound file '%s'", filename);
1063 #else /* PLATFORM_UNIX */
1065 if ((file = fopen(filename, MODE_READ)) == NULL)
1067 Error(ERR_WARN, "cannot open sound file '%s'", filename);
1072 /* read chunk id "RIFF" */
1073 getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
1074 if (strcmp(chunk_name, "RIFF") != 0)
1076 Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
1082 /* read "RIFF" type id "WAVE" */
1083 getFileChunk(file, chunk_name, NULL, BYTE_ORDER_LITTLE_ENDIAN);
1084 if (strcmp(chunk_name, "WAVE") != 0)
1086 Error(ERR_WARN, "missing 'WAVE' type ID of sound file '%s'", filename);
1092 while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN))
1094 if (strcmp(chunk_name, "fmt ") == 0)
1096 /* read header information */
1097 for (i=0; i < MIN(chunk_size, WAV_HEADER_SIZE); i++)
1098 sound_header_buffer[i] = fgetc(file);
1100 if (chunk_size > WAV_HEADER_SIZE)
1101 ReadUnusedBytesFromFile(file, chunk_size - WAV_HEADER_SIZE);
1103 else if (strcmp(chunk_name, "data") == 0)
1105 snd_info->data_len = chunk_size;
1106 snd_info->data_ptr = checked_malloc(snd_info->data_len);
1108 /* read sound data */
1109 if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
1112 Error(ERR_WARN,"cannot read 'data' chunk of sound file '%s'",filename);
1114 free(snd_info->data_ptr);
1119 /* check for odd number of sample bytes (data chunk is word aligned) */
1120 if ((chunk_size % 2) == 1)
1121 ReadUnusedBytesFromFile(file, 1);
1123 else /* unknown chunk -- ignore */
1124 ReadUnusedBytesFromFile(file, chunk_size);
1129 if (snd_info->data_ptr == NULL)
1131 Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
1136 /* convert unsigned 8 bit sample data to signed 16 bit sample data */
1138 data_ptr = checked_malloc(snd_info->data_len * sizeof(short));
1140 for (i=0; i<snd_info->data_len; i++)
1141 data_ptr[i] = ((short)(((byte *)snd_info->data_ptr)[i] ^ 0x80)) << 8;
1143 free(snd_info->data_ptr);
1144 snd_info->data_ptr = data_ptr;
1146 #endif /* PLATFORM_UNIX */
1148 snd_info->type = SND_TYPE_WAV;
1149 snd_info->source_filename = getStringCopy(filename);
1154 SoundInfo *LoadCustomSound(char *basename)
1156 char *filename = getCustomSoundFilename(basename);
1158 if (filename == NULL)
1160 Error(ERR_WARN, "cannot find sound file '%s'", basename);
1164 return Load_WAV(filename);
1167 void InitSoundList(int num_list_entries)
1169 Sound = checked_calloc(num_list_entries * sizeof(SoundInfo *));
1170 num_sounds = num_list_entries;
1173 void LoadSoundToList(char *basename, int list_pos)
1175 if (Sound == NULL || list_pos >= num_sounds)
1178 if (Sound[list_pos])
1179 FreeSound(Sound[list_pos]);
1181 Sound[list_pos] = LoadCustomSound(basename);
1184 static MusicInfo *Load_MOD(char *filename)
1186 #if defined(TARGET_SDL)
1187 MusicInfo *mod_info;
1189 if (!audio.sound_available)
1192 mod_info = checked_calloc(sizeof(MusicInfo));
1194 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
1196 Error(ERR_WARN, "cannot read music file '%s'", filename);
1201 mod_info->type = MUS_TYPE_MOD;
1202 mod_info->source_filename = getStringCopy(filename);
1210 void LoadCustomMusic(void)
1212 char *music_directory = getCustomMusicDirectory();
1214 struct dirent *dir_entry;
1216 if (!audio.sound_available)
1219 if ((dir = opendir(music_directory)) == NULL)
1221 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
1222 audio.music_available = FALSE;
1226 while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
1228 char *basename = dir_entry->d_name;
1229 char *filename = getPath2(music_directory, basename);
1230 MusicInfo *mus_info = NULL;
1232 if (FileIsSound(basename))
1233 mus_info = Load_WAV(filename);
1234 else if (FileIsMusic(basename))
1235 mus_info = Load_MOD(filename);
1242 Music = checked_realloc(Music, num_music * sizeof(MusicInfo *));
1243 Music[num_music -1] = mus_info;
1250 Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
1254 void PlayMusic(int nr)
1256 if (!audio.music_available)
1259 #if defined(TARGET_SDL)
1261 nr = nr % num_music;
1263 if (Music[nr]->type == MUS_TYPE_MOD)
1265 Mix_PlayMusic(Music[nr]->data_ptr, -1);
1266 Mix_VolumeMusic(SOUND_MAX_VOLUME); /* must be _after_ Mix_PlayMusic()! */
1268 else /* play WAV music loop */
1270 Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
1271 Mix_PlayChannel(audio.music_channel, Music[nr]->data_ptr, -1);
1281 void PlaySound(int nr)
1283 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
1286 void PlaySoundStereo(int nr, int stereo)
1288 PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
1291 void PlaySoundLoop(int nr)
1293 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
1296 void PlaySoundMusic(int nr)
1298 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_MUSIC);
1301 void PlaySoundExt(int nr, int volume, int stereo, boolean loop_type)
1303 struct SoundControl snd_ctrl = emptySoundControl;
1305 if (!audio.sound_available ||
1306 !audio.sound_enabled ||
1307 audio.sound_deactivated)
1310 if (volume < PSND_MIN_VOLUME)
1311 volume = PSND_MIN_VOLUME;
1312 else if (volume > PSND_MAX_VOLUME)
1313 volume = PSND_MAX_VOLUME;
1315 if (stereo < PSND_MAX_LEFT)
1316 stereo = PSND_MAX_LEFT;
1317 else if (stereo > PSND_MAX_RIGHT)
1318 stereo = PSND_MAX_RIGHT;
1321 snd_ctrl.volume = volume;
1322 snd_ctrl.stereo = stereo;
1323 snd_ctrl.loop = (loop_type != PSND_NO_LOOP);
1324 snd_ctrl.music = (loop_type == PSND_MUSIC);
1325 snd_ctrl.active = TRUE;
1328 snd_ctrl.data_ptr = Sound[nr].data_ptr;
1329 snd_ctrl.data_len = Sound[nr].data_len;
1332 #if defined(TARGET_SDL)
1333 Mix_Volume(-1, SOUND_MAX_VOLUME);
1334 Mix_PlayChannel(-1, Sound[nr]->data_ptr, (loop_type ? -1 : 0));
1335 #elif defined(PLATFORM_UNIX)
1336 if (audio.soundserver_pid == 0) /* we are child process */
1339 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1341 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1342 audio.sound_available = audio.sound_enabled = FALSE;
1345 #elif defined(PLATFORM_MSDOS)
1346 sound_handler(snd_ctrl);
1350 void FadeMusic(void)
1352 if (!audio.sound_available)
1355 #if defined(TARGET_SDL)
1356 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1357 Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
1359 StopSoundExt(-1, SSND_FADE_MUSIC);
1363 void FadeSound(int nr)
1365 StopSoundExt(nr, SSND_FADE_SOUND);
1371 StopSoundExt(-1, SSND_FADE_ALL);
1374 void StopMusic(void)
1376 #if defined(TARGET_SDL)
1377 if (!audio.sound_available)
1381 Mix_HaltChannel(audio.music_channel);
1383 StopSoundExt(-1, SSND_STOP_MUSIC);
1387 void StopSound(int nr)
1389 StopSoundExt(nr, SSND_STOP_SOUND);
1394 StopSoundExt(-1, SSND_STOP_ALL);
1397 void StopSoundExt(int nr, int method)
1399 struct SoundControl snd_ctrl = emptySoundControl;
1401 if (!audio.sound_available)
1404 if (method & SSND_FADING)
1405 snd_ctrl.fade_sound = TRUE;
1407 if (method & SSND_ALL)
1408 snd_ctrl.stop_all_sounds = TRUE;
1411 snd_ctrl.stop_sound = TRUE;
1415 if (method & SSND_MUSIC)
1416 snd_ctrl.music = TRUE;
1418 #if defined(TARGET_SDL)
1420 if (method & SSND_FADING)
1424 for (i=0; i<audio.channels; i++)
1425 if (i != audio.music_channel || snd_ctrl.music)
1426 Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
1428 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1434 for (i=0; i<audio.channels; i++)
1435 if (i != audio.music_channel || snd_ctrl.music)
1441 #elif !defined(PLATFORM_MSDOS)
1443 if (audio.soundserver_pid == 0) /* we are child process */
1446 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1448 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1449 audio.sound_available = audio.sound_enabled = FALSE;
1453 sound_handler(snd_ctrl);
1457 static void InitReloadSoundsOrMusic(char *set_name, int type)
1459 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
1460 struct SoundControl snd_ctrl = emptySoundControl;
1462 (type == SND_RELOAD_SOUNDS ? artwork.snd_current : artwork.mus_current);
1463 unsigned long str_size1 = strlen(leveldir_current->fullpath) + 1;
1464 unsigned long str_size2 = strlen(ti->basepath) + 1;
1465 unsigned long str_size3 = strlen(ti->fullpath) + 1;
1468 if (!audio.sound_available)
1471 #if defined(TARGET_SDL) || defined(TARGET_ALLEGRO)
1472 if (type == SND_RELOAD_SOUNDS)
1473 audio.func_reload_sounds();
1475 audio.func_reload_music();
1476 #elif defined(PLATFORM_UNIX)
1477 if (audio.soundserver_pid == 0) /* we are child process */
1480 if (leveldir_current == NULL) /* should never happen */
1481 Error(ERR_EXIT, "leveldir_current == NULL");
1483 snd_ctrl.reload_sounds = (type == SND_RELOAD_SOUNDS);
1484 snd_ctrl.reload_music = (type == SND_RELOAD_MUSIC);
1485 snd_ctrl.data_len = strlen(set_name) + 1;
1487 if (write(audio.soundserver_pipe[1], &snd_ctrl,
1488 sizeof(snd_ctrl)) < 0 ||
1489 write(audio.soundserver_pipe[1], set_name,
1490 snd_ctrl.data_len) < 0 ||
1491 write(audio.soundserver_pipe[1], leveldir_current,
1492 sizeof(TreeInfo)) < 0 ||
1493 write(audio.soundserver_pipe[1], ti,
1494 sizeof(TreeInfo)) < 0 ||
1495 write(audio.soundserver_pipe[1], &str_size1,
1496 sizeof(unsigned long)) < 0 ||
1497 write(audio.soundserver_pipe[1], &str_size2,
1498 sizeof(unsigned long)) < 0 ||
1499 write(audio.soundserver_pipe[1], &str_size3,
1500 sizeof(unsigned long)) < 0 ||
1501 write(audio.soundserver_pipe[1], leveldir_current->fullpath,
1503 write(audio.soundserver_pipe[1], ti->basepath,
1505 write(audio.soundserver_pipe[1], ti->fullpath,
1508 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1509 audio.sound_available = audio.sound_enabled = FALSE;
1515 void InitReloadSounds(char *set_name)
1517 InitReloadSoundsOrMusic(set_name, SND_RELOAD_SOUNDS);
1520 void InitReloadMusic(char *set_name)
1522 InitReloadSoundsOrMusic(set_name, SND_RELOAD_MUSIC);
1525 void FreeSound(SoundInfo *sound)
1530 if (sound->data_ptr)
1532 #if defined(TARGET_SDL)
1533 Mix_FreeChunk(sound->data_ptr);
1534 #elif defined(TARGET_ALLEGRO)
1535 destroy_sample(sound->data_ptr);
1536 #else /* PLATFORM_UNIX */
1537 free(sound->data_ptr);
1544 void FreeMusic(MusicInfo *music)
1549 if (music->data_ptr)
1551 #if defined(TARGET_SDL)
1552 if (music->type == MUS_TYPE_MOD)
1553 Mix_FreeMusic(music->data_ptr);
1555 Mix_FreeChunk(music->data_ptr);
1556 #elif defined(TARGET_ALLEGRO)
1557 destroy_sample(music->data_ptr);
1558 #else /* PLATFORM_UNIX */
1559 free(music->data_ptr);
1566 void FreeAllSounds()
1573 for(i=0; i<num_sounds; i++)
1574 FreeSound(Sound[i]);
1589 for(i=0; i<num_music; i++)
1590 FreeMusic(Music[i]);
1598 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
1599 /* ========================================================================= */