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 struct AudioFormatInfo afmt =
37 TRUE, 0, DEFAULT_AUDIO_SAMPLE_RATE, DEFAULT_AUDIO_FRAGMENT_SIZE
40 static int playing_sounds = 0;
41 static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
42 static struct SoundControl emptySoundControl =
44 -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, 0,0, 0,NULL
47 #if defined(PLATFORM_UNIX)
48 static int stereo_volume[PSND_MAX_LEFT2RIGHT + 1];
49 static short premix_first_buffer[SND_BLOCKSIZE];
50 #if defined(AUDIO_STREAMING_DSP)
51 static short premix_left_buffer[SND_BLOCKSIZE];
52 static short premix_right_buffer[SND_BLOCKSIZE];
53 static long premix_last_buffer[SND_BLOCKSIZE];
55 static byte playing_buffer[SND_BLOCKSIZE];
58 /* forward declaration of internal functions */
59 #if defined(AUDIO_STREAMING_DSP)
60 static void SoundServer_InsertNewSound(struct SoundControl);
61 static void InitAudioDevice_DSP(struct AudioFormatInfo *);
62 #elif defined(PLATFORM_HPUX)
63 static void InitAudioDevice_HPUX(struct AudioFormatInfo *);
64 #elif defined(PLATFORM_UNIX)
65 static unsigned char linear_to_ulaw(int);
66 static int ulaw_to_linear(unsigned char);
67 #elif defined(PLATFORM_MSDOS)
68 static void SoundServer_InsertNewSound(struct SoundControl);
69 static void SoundServer_StopSound(struct SoundControl);
70 static void SoundServer_StopAllSounds();
73 #if defined(PLATFORM_UNIX)
74 static int OpenAudioDevice(char *audio_device_name)
78 /* check if desired audio device is accessible */
79 if (access(audio_device_name, W_OK) != 0)
82 /* try to open audio device in non-blocking mode */
83 if ((audio_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0)
86 /* re-open audio device in blocking mode */
88 audio_fd = open(audio_device_name, O_WRONLY);
93 static boolean TestAudioDevices(void)
95 static char *audio_device_name[] =
103 /* look for available audio devices, starting with preferred ones */
104 for (i=0; i<sizeof(audio_device_name)/sizeof(char *); i++)
105 if ((audio_fd = OpenAudioDevice(audio_device_name[i])) >= 0)
110 Error(ERR_WARN, "cannot open audio device -- no sound");
116 audio.device_name = audio_device_name[i];
121 #if !defined(TARGET_SDL)
122 static boolean ForkAudioProcess(void)
124 if (pipe(audio.soundserver_pipe) < 0)
126 Error(ERR_WARN, "cannot create pipe -- no sounds");
130 if ((audio.soundserver_pid = fork()) < 0)
132 Error(ERR_WARN, "cannot create sound server process -- no sounds");
136 if (audio.soundserver_pid == 0) /* we are child process */
143 else /* we are parent */
144 close(audio.soundserver_pipe[0]); /* no reading from pipe needed */
150 void UnixOpenAudio(void)
152 if (!TestAudioDevices())
155 audio.sound_available = TRUE;
156 audio.sound_enabled = TRUE;
158 #if defined(AUDIO_STREAMING_DSP)
159 audio.music_available = TRUE;
160 audio.loops_available = TRUE;
164 void UnixCloseAudio(void)
167 close(audio.device_fd);
169 if (audio.soundserver_pid > 0) /* we are parent process */
170 kill(audio.soundserver_pid, SIGTERM);
172 #endif /* PLATFORM_UNIX */
174 void InitPlaylist(void)
178 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
179 playlist[i] = emptySoundControl;
183 void StartSoundserver(void)
185 if (!audio.sound_available)
188 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
189 if (!ForkAudioProcess())
190 audio.sound_available = FALSE;
194 #if defined(PLATFORM_UNIX)
195 void SoundServer(void)
199 struct SoundControl snd_ctrl;
202 close(audio.soundserver_pipe[1]); /* no writing into pipe needed */
206 stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
207 for(i=0; i<PSND_MAX_LEFT2RIGHT; i++)
209 (int)sqrt((float)(PSND_MAX_LEFT2RIGHT * PSND_MAX_LEFT2RIGHT - i * i));
211 #if defined(PLATFORM_HPUX)
212 InitAudioDevice_HPUX(&afmt);
215 FD_ZERO(&sound_fdset);
216 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
218 while(1) /* wait for sound playing commands from client */
220 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
221 select(audio.soundserver_pipe[0] + 1, &sound_fdset, NULL, NULL, NULL);
222 if (!FD_ISSET(audio.soundserver_pipe[0], &sound_fdset))
224 if (read(audio.soundserver_pipe[0], &snd_ctrl, sizeof(snd_ctrl))
226 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
228 if (snd_ctrl.reload_sounds || snd_ctrl.reload_music)
230 char *set_name = checked_malloc(snd_ctrl.data_len);
232 (snd_ctrl.reload_sounds ? &artwork.snd_current : &artwork.mus_current);
233 TreeInfo *ti = *ti_ptr;
234 unsigned long str_size1, str_size2, str_size3;
236 if (leveldir_current == NULL)
237 leveldir_current = checked_calloc(sizeof(TreeInfo));
239 ti = *ti_ptr = checked_calloc(sizeof(TreeInfo));
240 if (leveldir_current->fullpath != NULL)
241 free(leveldir_current->fullpath);
242 if (ti->basepath != NULL)
244 if (ti->fullpath != NULL)
247 if (read(audio.soundserver_pipe[0], set_name,
248 snd_ctrl.data_len) != snd_ctrl.data_len ||
249 read(audio.soundserver_pipe[0], leveldir_current,
250 sizeof(TreeInfo)) != sizeof(TreeInfo) ||
251 read(audio.soundserver_pipe[0], ti,
252 sizeof(TreeInfo)) != sizeof(TreeInfo) ||
253 read(audio.soundserver_pipe[0], &str_size1,
254 sizeof(unsigned long)) != sizeof(unsigned long) ||
255 read(audio.soundserver_pipe[0], &str_size2,
256 sizeof(unsigned long)) != sizeof(unsigned long) ||
257 read(audio.soundserver_pipe[0], &str_size3,
258 sizeof(unsigned long)) != sizeof(unsigned long))
259 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
261 leveldir_current->fullpath = checked_calloc(str_size1);
262 ti->basepath = checked_calloc(str_size2);
263 ti->fullpath = checked_calloc(str_size3);
265 if (read(audio.soundserver_pipe[0], leveldir_current->fullpath,
266 str_size1) != str_size1 ||
267 read(audio.soundserver_pipe[0], ti->basepath,
268 str_size2) != str_size2 ||
269 read(audio.soundserver_pipe[0], ti->fullpath,
270 str_size3) != str_size3)
271 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
275 close(audio.device_fd);
277 if (snd_ctrl.reload_sounds)
279 artwork.sounds_set_current = set_name;
280 audio.func_reload_sounds();
284 artwork.music_set_current = set_name;
285 audio.func_reload_music();
293 #if defined(AUDIO_STREAMING_DSP)
295 if (snd_ctrl.fade_sound)
301 playlist[audio.music_channel].fade_sound = TRUE;
303 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
304 if (snd_ctrl.stop_all_sounds ||
305 (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr))
306 playlist[i].fade_sound = TRUE;
308 else if (snd_ctrl.stop_all_sounds)
313 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
314 playlist[i] = emptySoundControl;
317 close(audio.device_fd);
319 else if (snd_ctrl.stop_sound)
326 playlist[audio.music_channel] = emptySoundControl;
330 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
332 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr)
334 playlist[i] = emptySoundControl;
340 close(audio.device_fd);
343 if (playing_sounds || snd_ctrl.active)
345 if (playing_sounds ||
346 (audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
348 struct timeval delay = { 0, 0 };
350 if (!playing_sounds) /* we just opened the audio device */
351 InitAudioDevice_DSP(&afmt);
353 if (snd_ctrl.active) /* new sound has arrived */
354 SoundServer_InsertNewSound(snd_ctrl);
356 while (playing_sounds &&
357 select(audio.soundserver_pipe[0] + 1,
358 &sound_fdset, NULL, NULL, &delay) < 1)
361 int fragment_size = afmt.fragment_size;
362 int sample_bytes = (afmt.format & AUDIO_FORMAT_U8 ? 1 : 2);
363 boolean stereo = afmt.stereo;
365 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
367 max_sample_size = fragment_size / ((stereo ? 2 : 1) * sample_bytes);
369 /* first clear the last premixing buffer */
370 memset(premix_last_buffer, 0,
371 max_sample_size * (stereo ? 2 : 1) * sizeof(long));
373 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
381 if (!playlist[i].active)
384 /* pointer, lenght and actual playing position of sound sample */
385 sample_ptr = playlist[i].data_ptr;
386 sample_len = playlist[i].data_len;
387 sample_pos = playlist[i].playingpos;
388 sample_size = MIN(max_sample_size, sample_len - sample_pos);
389 playlist[i].playingpos += sample_size;
391 /* copy original sample to first mixing buffer */
392 if (playlist[i].format == AUDIO_FORMAT_U8)
393 for (j=0; j<sample_size; j++)
394 premix_first_buffer[j] =
395 ((short)(((byte *)sample_ptr)[sample_pos + j] ^ 0x80)) << 8;
396 else /* AUDIO_FORMAT_S16 */
397 for (j=0; j<sample_size; j++)
398 premix_first_buffer[j] =
399 ((short *)sample_ptr)[sample_pos + j];
401 /* are we about to restart a looping sound? */
402 if (playlist[i].loop && sample_size < max_sample_size)
404 while (sample_size < max_sample_size)
406 int restarted_sample_size =
407 MIN(max_sample_size - sample_size, sample_len);
409 if (playlist[i].format == AUDIO_FORMAT_U8)
410 for (j=0; j<restarted_sample_size; j++)
411 premix_first_buffer[sample_size + j] =
412 ((short)(((byte *)sample_ptr)[j] ^ 0x80)) << 8;
414 for (j=0; j<restarted_sample_size; j++)
415 premix_first_buffer[sample_size + j] =
416 ((short *)sample_ptr)[j];
418 playlist[i].playingpos = restarted_sample_size;
419 sample_size += restarted_sample_size;
423 /* decrease volume if sound is fading out */
424 if (playlist[i].fade_sound &&
425 playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
426 playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
428 /* adjust volume of actual sound sample */
429 if (playlist[i].volume != PSND_MAX_VOLUME)
430 for(j=0; j<sample_size; j++)
431 premix_first_buffer[j] =
432 (playlist[i].volume * (long)premix_first_buffer[j])
433 >> PSND_MAX_VOLUME_BITS;
435 /* fill the last mixing buffer with stereo or mono sound */
438 int middle_pos = PSND_MAX_LEFT2RIGHT / 2;
439 int left_volume = stereo_volume[middle_pos + playlist[i].stereo];
440 int right_volume= stereo_volume[middle_pos - playlist[i].stereo];
442 for(j=0; j<sample_size; j++)
444 premix_left_buffer[j] =
445 (left_volume * premix_first_buffer[j])
446 >> PSND_MAX_LEFT2RIGHT_BITS;
447 premix_right_buffer[j] =
448 (right_volume * premix_first_buffer[j])
449 >> PSND_MAX_LEFT2RIGHT_BITS;
451 premix_last_buffer[2 * j + 0] += premix_left_buffer[j];
452 premix_last_buffer[2 * j + 1] += premix_right_buffer[j];
457 for(j=0; j<sample_size; j++)
458 premix_last_buffer[j] += premix_first_buffer[j];
461 /* delete completed sound entries from the playlist */
462 if (playlist[i].playingpos >= playlist[i].data_len)
464 if (playlist[i].loop)
465 playlist[i].playingpos = 0;
468 playlist[i] = emptySoundControl;
472 else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
474 playlist[i] = emptySoundControl;
479 /* prepare final playing buffer according to system audio format */
480 for(i=0; i<max_sample_size * (stereo ? 2 : 1); i++)
482 /* cut off at 17 bit value */
483 if (premix_last_buffer[i] < -65535)
484 premix_last_buffer[i] = -65535;
485 else if (premix_last_buffer[i] > 65535)
486 premix_last_buffer[i] = 65535;
488 /* shift to 16 bit value */
489 premix_last_buffer[i] >>= 1;
491 if (afmt.format & AUDIO_FORMAT_U8)
493 playing_buffer[i] = (premix_last_buffer[i] >> 8) ^ 0x80;
495 else if (afmt.format & AUDIO_FORMAT_LE) /* 16 bit */
497 playing_buffer[2 * i + 0] = premix_last_buffer[i] & 0xff;
498 playing_buffer[2 * i + 1] = premix_last_buffer[i] >> 8;
500 else /* big endian */
502 playing_buffer[2 * i + 0] = premix_last_buffer[i] >> 8;
503 playing_buffer[2 * i + 1] = premix_last_buffer[i] & 0xff;
507 /* finally play the sound fragment */
508 write(audio.device_fd, playing_buffer, fragment_size);
511 /* if no sounds playing, free device for other sound programs */
513 close(audio.device_fd);
517 #else /* !AUDIO_STREAMING_DSP */
519 if (snd_ctrl.active && !snd_ctrl.loop)
521 struct timeval delay = { 0, 0 };
523 long sample_size, max_sample_size = SND_BLOCKSIZE;
524 long sample_rate = 8000; /* standard "/dev/audio" sampling rate */
525 int wait_percent = 90; /* wait 90% of the real playing time */
528 if ((audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
532 while (playing_sounds &&
533 select(audio.soundserver_pipe[0] + 1,
534 &sound_fdset, NULL, NULL, &delay) < 1)
536 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
538 /* get pointer and size of the actual sound sample */
539 sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos;
541 MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos);
542 snd_ctrl.playingpos += sample_size;
544 /* fill the first mixing buffer with original sample */
545 memcpy(premix_first_buffer,sample_ptr,sample_size);
547 /* adjust volume of actual sound sample */
548 if (snd_ctrl.volume != PSND_MAX_VOLUME)
549 for(i=0;i<sample_size;i++)
550 premix_first_buffer[i] =
551 (snd_ctrl.volume * (int)premix_first_buffer[i])
552 >> PSND_MAX_VOLUME_BITS;
554 for(i=0;i<sample_size;i++)
556 linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
558 if (snd_ctrl.playingpos >= snd_ctrl.data_len)
561 /* finally play the sound fragment */
562 write(audio.device_fd,playing_buffer,sample_size);
565 delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
567 close(audio.device_fd);
570 #endif /* !AUDIO_STREAMING_DSP */
573 #endif /* PLATFORM_UNIX */
575 #if defined(PLATFORM_MSDOS)
576 static void sound_handler(struct SoundControl snd_ctrl)
580 if (snd_ctrl.fade_sound)
585 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
586 if ((snd_ctrl.stop_all_sounds ||
587 (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr) ||
588 (i == audio.music_channel && snd_ctrl.music)) &&
589 !playlist[i].fade_sound)
591 playlist[i].fade_sound = TRUE;
592 if (voice_check(playlist[i].voice))
593 voice_ramp_volume(playlist[i].voice, 1000, 0);
594 playlist[i].loop = PSND_NO_LOOP;
597 else if (snd_ctrl.stop_all_sounds)
601 SoundServer_StopAllSounds();
603 else if (snd_ctrl.stop_sound)
607 SoundServer_StopSound(snd_ctrl);
610 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
612 if (!playlist[i].active || playlist[i].loop)
615 playlist[i].playingpos = voice_get_position(playlist[i].voice);
616 playlist[i].volume = voice_get_volume(playlist[i].voice);
617 if (playlist[i].playingpos == -1 || !playlist[i].volume)
619 deallocate_voice(playlist[i].voice);
620 playlist[i] = emptySoundControl;
626 SoundServer_InsertNewSound(snd_ctrl);
628 #endif /* PLATFORM_MSDOS */
630 #if !defined(PLATFORM_WIN32)
631 static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
636 snd_ctrl.nr = snd_ctrl.nr % num_music;
638 /* if playlist is full, remove oldest sound */
639 if (playing_sounds == MAX_SOUNDS_PLAYING)
641 int longest = 0, longest_nr = 0;
643 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
645 #if !defined(PLATFORM_MSDOS)
646 int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
648 int actual = playlist[i].playingpos;
651 if (i != audio.music_channel && !playlist[i].loop && actual > longest)
657 #if defined(PLATFORM_MSDOS)
658 voice_set_volume(playlist[longest_nr].voice, 0);
659 deallocate_voice(playlist[longest_nr].voice);
661 playlist[longest_nr] = emptySoundControl;
665 /* check if sound is already being played (and how often) */
666 for (k=0,i=0; i<MAX_SOUNDS_PLAYING; i++)
667 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr)
670 /* restart loop sounds only if they are just fading out */
671 if (k >= 1 && snd_ctrl.loop)
673 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
675 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr &&
676 playlist[i].fade_sound)
678 playlist[i].fade_sound = FALSE;
679 playlist[i].volume = PSND_MAX_VOLUME;
680 #if defined(PLATFORM_MSDOS)
681 playlist[i].loop = PSND_LOOP;
682 voice_stop_volumeramp(playlist[i].voice);
683 voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
691 /* don't play sound more than n times simultaneously (with n == 2 for now) */
694 int longest = 0, longest_nr = 0;
696 /* look for oldest equal sound */
697 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
701 if (!playlist[i].active ||
702 i == audio.music_channel ||
703 playlist[i].nr != snd_ctrl.nr)
706 #if !defined(PLATFORM_MSDOS)
707 actual = 100 * playlist[i].playingpos / playlist[i].data_len;
709 actual = playlist[i].playingpos;
711 if (actual >= longest)
718 #if defined(PLATFORM_MSDOS)
719 voice_set_volume(playlist[longest_nr].voice, 0);
720 deallocate_voice(playlist[longest_nr].voice);
722 playlist[longest_nr] = emptySoundControl;
726 /* add new sound to playlist */
727 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
729 if (!playlist[i].active ||
730 (snd_ctrl.music && i == audio.music_channel))
732 SoundInfo *snd_info =
733 (snd_ctrl.music ? Music[snd_ctrl.nr] : Sound[snd_ctrl.nr]);
735 snd_ctrl.data_ptr = snd_info->data_ptr;
736 snd_ctrl.data_len = snd_info->data_len;
737 snd_ctrl.format = snd_info->format;
739 playlist[i] = snd_ctrl;
742 #if defined(PLATFORM_MSDOS)
743 playlist[i].voice = allocate_voice((SAMPLE *)playlist[i].data_ptr);
746 voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
748 voice_set_volume(playlist[i].voice, snd_ctrl.volume);
749 voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
750 voice_start(playlist[i].voice);
756 #endif /* !PLATFORM_WIN32 */
759 void SoundServer_FadeSound(int nr)
766 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
767 if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
768 playlist[i].fade_sound = TRUE;
772 #if !defined(PLATFORM_WIN32)
773 #if defined(PLATFORM_MSDOS)
774 static void SoundServer_StopSound(struct SoundControl snd_ctrl)
776 int nr = snd_ctrl.nr;
782 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
784 if ((i == audio.music_channel && snd_ctrl.music) ||
785 (i != audio.music_channel && playlist[i].nr == nr))
787 #if defined(PLATFORM_MSDOS)
788 voice_set_volume(playlist[i].voice, 0);
789 deallocate_voice(playlist[i].voice);
791 playlist[i] = emptySoundControl;
796 #if !defined(PLATFORM_MSDOS)
798 close(audio.device_fd);
802 static void SoundServer_StopAllSounds()
806 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
808 #if defined(PLATFORM_MSDOS)
809 voice_set_volume(playlist[i].voice, 0);
810 deallocate_voice(playlist[i].voice);
812 playlist[i]=emptySoundControl;
816 #if !defined(PLATFORM_MSDOS)
817 close(audio.device_fd);
820 #endif /* PLATFORM_MSDOS */
821 #endif /* !PLATFORM_WIN32 */
824 /* ------------------------------------------------------------------------- */
825 /* platform dependant audio initialization code */
826 /* ------------------------------------------------------------------------- */
828 #if defined(AUDIO_LINUX_IOCTL)
829 static void InitAudioDevice_Linux(struct AudioFormatInfo *afmt)
831 /* "ioctl()" expects pointer to 'int' value for stereo flag
832 (boolean is defined as 'char', which will not work here) */
833 unsigned int fragment_spec = 0;
834 int fragment_size_query;
843 /* supported audio format in preferred order */
844 { AFMT_S16_LE, AUDIO_FORMAT_S16 | AUDIO_FORMAT_LE },
845 { AFMT_S16_BE, AUDIO_FORMAT_S16 | AUDIO_FORMAT_BE },
846 { AFMT_U8, AUDIO_FORMAT_U8 },
851 /* determine logarithm (log2) of the fragment size */
852 while ((1 << fragment_spec) < afmt->fragment_size)
855 /* use two fragments (play one fragment, prepare the other);
856 one fragment would result in interrupted audio output, more
857 than two fragments would raise audio output latency to much */
858 fragment_spec |= 0x00020000;
860 /* Example for fragment specification:
861 - 2 buffers / 512 bytes (giving 1/16 second resolution for 8 kHz)
862 - (with stereo the effective buffer size will shrink to 256)
863 => fragment_size = 0x00020009 */
865 if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0)
866 Error(ERR_EXIT_SOUND_SERVER,
867 "cannot set fragment size of /dev/dsp -- no sounds");
871 while (formats[i].format_result != -1)
873 unsigned int audio_format = formats[i].format_ioctl;
874 if (ioctl(audio.device_fd, SNDCTL_DSP_SETFMT, &audio_format) == 0)
876 afmt->format = formats[i].format_result;
881 if (afmt->format == 0) /* no supported audio format found */
882 Error(ERR_EXIT_SOUND_SERVER,
883 "cannot set audio format of /dev/dsp -- no sounds");
885 /* try if we can use stereo sound */
887 if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
888 afmt->stereo = FALSE;
890 if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &afmt->sample_rate) < 0)
891 Error(ERR_EXIT_SOUND_SERVER,
892 "cannot set sample rate of /dev/dsp -- no sounds");
894 /* get the real fragmentation size; this should return 512 */
895 if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size_query) < 0)
896 Error(ERR_EXIT_SOUND_SERVER,
897 "cannot get fragment size of /dev/dsp -- no sounds");
898 if (fragment_size_query != afmt->fragment_size)
899 Error(ERR_EXIT_SOUND_SERVER,
900 "cannot set fragment size of /dev/dsp -- no sounds");
902 #endif /* AUDIO_LINUX_IOCTL */
904 #if defined(PLATFORM_NETBSD)
905 static void InitAudioDevice_NetBSD(struct AudioFormatInfo *afmt)
908 boolean stereo = TRUE;
910 AUDIO_INITINFO(&a_info);
911 a_info.play.encoding = AUDIO_ENCODING_LINEAR8;
912 a_info.play.precision = 8;
913 a_info.play.channels = 2;
914 a_info.play.sample_rate = sample_rate;
915 a_info.blocksize = fragment_size;
917 afmt->format = AUDIO_FORMAT_U8;
920 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
922 /* try to disable stereo */
923 a_info.play.channels = 1;
925 afmt->stereo = FALSE;
927 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
928 Error(ERR_EXIT_SOUND_SERVER,
929 "cannot set sample rate of /dev/audio -- no sounds");
932 #endif /* PLATFORM_NETBSD */
934 #if defined(PLATFORM_HPUX)
935 static void InitAudioDevice_HPUX(struct AudioFormatInfo *afmt)
937 struct audio_describe ainfo;
940 audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
942 Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl -- no sounds");
944 if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
945 Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds");
947 if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
948 Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds");
950 ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
951 ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
953 afmt->format = AUDIO_FORMAT_U8;
954 afmt->stereo = FALSE;
955 afmt->sample_rate = 8000;
959 #endif /* PLATFORM_HPUX */
961 #if defined(PLATFORM_UNIX)
962 static void InitAudioDevice_DSP(struct AudioFormatInfo *afmt)
964 #if defined(AUDIO_LINUX_IOCTL)
965 InitAudioDevice_Linux(afmt);
966 #elif defined(PLATFORM_NETBSD)
967 InitAudioDevice_NetBSD(afmt);
968 #elif defined(PLATFORM_HPUX)
969 InitAudioDevice_HPUX(afmt);
972 #endif /* PLATFORM_UNIX */
974 #if defined(PLATFORM_UNIX) && !defined(AUDIO_STREAMING_DSP)
976 /* these two are stolen from "sox"... :) */
979 ** This routine converts from linear to ulaw.
981 ** Craig Reese: IDA/Supercomputing Research Center
982 ** Joe Campbell: Department of Defense
986 ** 1) CCITT Recommendation G.711 (very difficult to follow)
987 ** 2) "A New Digital Technique for Implementation of Any
988 ** Continuous PCM Companding Law," Villeret, Michel,
989 ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
990 ** 1973, pg. 11.12-11.17
991 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
992 ** for Analog-to_Digital Conversion Techniques,"
995 ** Input: Signed 16 bit linear sample
996 ** Output: 8 bit ulaw sample
999 #define ZEROTRAP /* turn on the trap as per the MIL-STD */
1000 #define BIAS 0x84 /* define the add-in bias for 16 bit samples */
1003 static unsigned char linear_to_ulaw(int sample)
1005 static int exp_lut[256] =
1007 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
1008 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
1009 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
1010 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
1011 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1012 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1013 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1014 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1015 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1016 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1017 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1018 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1019 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1020 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1021 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1022 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
1025 int sign, exponent, mantissa;
1026 unsigned char ulawbyte;
1028 /* Get the sample into sign-magnitude. */
1029 sign = (sample >> 8) & 0x80; /* set aside the sign */
1031 sample = -sample; /* get magnitude */
1033 sample = CLIP; /* clip the magnitude */
1035 /* Convert from 16 bit linear to ulaw. */
1036 sample = sample + BIAS;
1037 exponent = exp_lut[( sample >> 7 ) & 0xFF];
1038 mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
1039 ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
1042 ulawbyte = 0x02; /* optional CCITT trap */
1049 ** This routine converts from ulaw to 16 bit linear.
1051 ** Craig Reese: IDA/Supercomputing Research Center
1052 ** 29 September 1989
1055 ** 1) CCITT Recommendation G.711 (very difficult to follow)
1056 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
1057 ** for Analog-to_Digital Conversion Techniques,"
1060 ** Input: 8 bit ulaw sample
1061 ** Output: signed 16 bit linear sample
1064 static int ulaw_to_linear(unsigned char ulawbyte)
1066 static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
1067 int sign, exponent, mantissa, sample;
1069 ulawbyte = ~ ulawbyte;
1070 sign = ( ulawbyte & 0x80 );
1071 exponent = ( ulawbyte >> 4 ) & 0x07;
1072 mantissa = ulawbyte & 0x0F;
1073 sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
1079 #endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */
1082 /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
1083 /* ========================================================================= */
1084 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */
1086 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
1087 #define WAV_HEADER_SIZE 16 /* size of WAV file header */
1089 static SoundInfo *Load_WAV(char *filename)
1091 SoundInfo *snd_info;
1092 #if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS)
1093 byte sound_header_buffer[WAV_HEADER_SIZE];
1094 char chunk_name[CHUNK_ID_LEN + 1];
1100 if (!audio.sound_available)
1103 snd_info = checked_calloc(sizeof(SoundInfo));
1105 #if defined(TARGET_SDL)
1107 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
1109 Error(ERR_WARN, "cannot read sound file '%s'", filename);
1114 #elif defined(TARGET_ALLEGRO)
1116 if ((snd_info->data_ptr = load_sample(filename)) == NULL)
1118 Error(ERR_WARN, "cannot read sound file '%s'", filename);
1123 #else /* PLATFORM_UNIX */
1125 if ((file = fopen(filename, MODE_READ)) == NULL)
1127 Error(ERR_WARN, "cannot open sound file '%s'", filename);
1132 /* read chunk id "RIFF" */
1133 getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
1134 if (strcmp(chunk_name, "RIFF") != 0)
1136 Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
1142 /* read "RIFF" type id "WAVE" */
1143 getFileChunk(file, chunk_name, NULL, BYTE_ORDER_LITTLE_ENDIAN);
1144 if (strcmp(chunk_name, "WAVE") != 0)
1146 Error(ERR_WARN, "missing 'WAVE' type ID of sound file '%s'", filename);
1152 while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN))
1154 if (strcmp(chunk_name, "fmt ") == 0)
1156 /* read header information */
1157 for (i=0; i < MIN(chunk_size, WAV_HEADER_SIZE); i++)
1158 sound_header_buffer[i] = fgetc(file);
1160 if (chunk_size > WAV_HEADER_SIZE)
1161 ReadUnusedBytesFromFile(file, chunk_size - WAV_HEADER_SIZE);
1163 else if (strcmp(chunk_name, "data") == 0)
1165 snd_info->data_len = chunk_size;
1166 snd_info->data_ptr = checked_malloc(snd_info->data_len);
1168 /* read sound data */
1169 if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
1172 Error(ERR_WARN,"cannot read 'data' chunk of sound file '%s'",filename);
1174 free(snd_info->data_ptr);
1179 /* check for odd number of sample bytes (data chunk is word aligned) */
1180 if ((chunk_size % 2) == 1)
1181 ReadUnusedBytesFromFile(file, 1);
1183 else /* unknown chunk -- ignore */
1184 ReadUnusedBytesFromFile(file, chunk_size);
1189 if (snd_info->data_ptr == NULL)
1191 Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
1196 snd_info->format = AUDIO_FORMAT_U8;
1198 #endif /* PLATFORM_UNIX */
1200 snd_info->type = SND_TYPE_WAV;
1201 snd_info->source_filename = getStringCopy(filename);
1206 SoundInfo *LoadCustomSound(char *basename)
1208 char *filename = getCustomSoundFilename(basename);
1210 if (filename == NULL)
1212 Error(ERR_WARN, "cannot find sound file '%s'", basename);
1216 return Load_WAV(filename);
1219 void InitSoundList(int num_list_entries)
1221 Sound = checked_calloc(num_list_entries * sizeof(SoundInfo *));
1222 num_sounds = num_list_entries;
1225 void LoadSoundToList(char *basename, int list_pos)
1227 if (Sound == NULL || list_pos >= num_sounds)
1230 if (Sound[list_pos])
1231 FreeSound(Sound[list_pos]);
1233 Sound[list_pos] = LoadCustomSound(basename);
1236 static MusicInfo *Load_MOD(char *filename)
1238 #if defined(TARGET_SDL)
1239 MusicInfo *mod_info;
1241 if (!audio.sound_available)
1244 mod_info = checked_calloc(sizeof(MusicInfo));
1246 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
1248 Error(ERR_WARN, "cannot read music file '%s'", filename);
1253 mod_info->type = MUS_TYPE_MOD;
1254 mod_info->source_filename = getStringCopy(filename);
1262 void LoadCustomMusic(void)
1264 char *music_directory = getCustomMusicDirectory();
1266 struct dirent *dir_entry;
1268 if (!audio.sound_available)
1271 if ((dir = opendir(music_directory)) == NULL)
1273 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
1274 audio.music_available = FALSE;
1278 while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
1280 char *basename = dir_entry->d_name;
1281 char *filename = getPath2(music_directory, basename);
1282 MusicInfo *mus_info = NULL;
1284 if (FileIsSound(basename))
1285 mus_info = Load_WAV(filename);
1286 else if (FileIsMusic(basename))
1287 mus_info = Load_MOD(filename);
1294 Music = checked_realloc(Music, num_music * sizeof(MusicInfo *));
1295 Music[num_music -1] = mus_info;
1302 Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
1306 void PlayMusic(int nr)
1308 if (!audio.music_available)
1311 #if defined(TARGET_SDL)
1313 nr = nr % num_music;
1315 if (Music[nr]->type == MUS_TYPE_MOD)
1317 Mix_PlayMusic(Music[nr]->data_ptr, -1);
1318 Mix_VolumeMusic(SOUND_MAX_VOLUME); /* must be _after_ Mix_PlayMusic()! */
1320 else /* play WAV music loop */
1322 Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
1323 Mix_PlayChannel(audio.music_channel, Music[nr]->data_ptr, -1);
1333 void PlaySound(int nr)
1335 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
1338 void PlaySoundStereo(int nr, int stereo)
1340 PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
1343 void PlaySoundLoop(int nr)
1345 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
1348 void PlaySoundMusic(int nr)
1350 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_MUSIC);
1353 void PlaySoundExt(int nr, int volume, int stereo, boolean loop_type)
1355 struct SoundControl snd_ctrl = emptySoundControl;
1357 if (!audio.sound_available ||
1358 !audio.sound_enabled ||
1359 audio.sound_deactivated)
1362 if (volume < PSND_MIN_VOLUME)
1363 volume = PSND_MIN_VOLUME;
1364 else if (volume > PSND_MAX_VOLUME)
1365 volume = PSND_MAX_VOLUME;
1367 if (stereo < PSND_MAX_LEFT)
1368 stereo = PSND_MAX_LEFT;
1369 else if (stereo > PSND_MAX_RIGHT)
1370 stereo = PSND_MAX_RIGHT;
1373 snd_ctrl.volume = volume;
1374 snd_ctrl.stereo = stereo;
1375 snd_ctrl.loop = (loop_type != PSND_NO_LOOP);
1376 snd_ctrl.music = (loop_type == PSND_MUSIC);
1377 snd_ctrl.active = TRUE;
1380 /* now only used internally in sound server child process */
1381 snd_ctrl.data_ptr = Sound[nr].data_ptr;
1382 snd_ctrl.data_len = Sound[nr].data_len;
1385 #if defined(TARGET_SDL)
1386 Mix_Volume(-1, SOUND_MAX_VOLUME);
1387 Mix_PlayChannel(-1, Sound[nr]->data_ptr, (loop_type ? -1 : 0));
1388 #elif defined(PLATFORM_UNIX)
1389 if (audio.soundserver_pid == 0) /* we are child process */
1392 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1394 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1395 audio.sound_available = audio.sound_enabled = FALSE;
1398 #elif defined(PLATFORM_MSDOS)
1399 sound_handler(snd_ctrl);
1403 void FadeMusic(void)
1405 if (!audio.sound_available)
1408 #if defined(TARGET_SDL)
1409 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1410 Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
1412 StopSoundExt(-1, SSND_FADE_MUSIC);
1416 void FadeSound(int nr)
1418 StopSoundExt(nr, SSND_FADE_SOUND);
1424 StopSoundExt(-1, SSND_FADE_ALL);
1427 void StopMusic(void)
1429 #if defined(TARGET_SDL)
1430 if (!audio.sound_available)
1434 Mix_HaltChannel(audio.music_channel);
1436 StopSoundExt(-1, SSND_STOP_MUSIC);
1440 void StopSound(int nr)
1442 StopSoundExt(nr, SSND_STOP_SOUND);
1447 StopSoundExt(-1, SSND_STOP_ALL);
1450 void StopSoundExt(int nr, int method)
1452 struct SoundControl snd_ctrl = emptySoundControl;
1454 if (!audio.sound_available)
1457 if (method & SSND_FADING)
1458 snd_ctrl.fade_sound = TRUE;
1460 if (method & SSND_ALL)
1461 snd_ctrl.stop_all_sounds = TRUE;
1464 snd_ctrl.stop_sound = TRUE;
1468 if (method & SSND_MUSIC)
1469 snd_ctrl.music = TRUE;
1471 #if defined(TARGET_SDL)
1473 if (method & SSND_FADING)
1477 for (i=0; i<audio.channels; i++)
1478 if (i != audio.music_channel || snd_ctrl.music)
1479 Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
1481 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1487 for (i=0; i<audio.channels; i++)
1488 if (i != audio.music_channel || snd_ctrl.music)
1494 #elif !defined(PLATFORM_MSDOS)
1496 if (audio.soundserver_pid == 0) /* we are child process */
1499 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1501 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1502 audio.sound_available = audio.sound_enabled = FALSE;
1506 sound_handler(snd_ctrl);
1510 static void InitReloadSoundsOrMusic(char *set_name, int type)
1512 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
1513 struct SoundControl snd_ctrl = emptySoundControl;
1515 (type == SND_RELOAD_SOUNDS ? artwork.snd_current : artwork.mus_current);
1516 unsigned long str_size1 = strlen(leveldir_current->fullpath) + 1;
1517 unsigned long str_size2 = strlen(ti->basepath) + 1;
1518 unsigned long str_size3 = strlen(ti->fullpath) + 1;
1521 if (!audio.sound_available)
1524 #if defined(TARGET_SDL) || defined(TARGET_ALLEGRO)
1525 if (type == SND_RELOAD_SOUNDS)
1526 audio.func_reload_sounds();
1528 audio.func_reload_music();
1529 #elif defined(PLATFORM_UNIX)
1530 if (audio.soundserver_pid == 0) /* we are child process */
1533 if (leveldir_current == NULL) /* should never happen */
1534 Error(ERR_EXIT, "leveldir_current == NULL");
1536 snd_ctrl.reload_sounds = (type == SND_RELOAD_SOUNDS);
1537 snd_ctrl.reload_music = (type == SND_RELOAD_MUSIC);
1538 snd_ctrl.data_len = strlen(set_name) + 1;
1540 if (write(audio.soundserver_pipe[1], &snd_ctrl,
1541 sizeof(snd_ctrl)) < 0 ||
1542 write(audio.soundserver_pipe[1], set_name,
1543 snd_ctrl.data_len) < 0 ||
1544 write(audio.soundserver_pipe[1], leveldir_current,
1545 sizeof(TreeInfo)) < 0 ||
1546 write(audio.soundserver_pipe[1], ti,
1547 sizeof(TreeInfo)) < 0 ||
1548 write(audio.soundserver_pipe[1], &str_size1,
1549 sizeof(unsigned long)) < 0 ||
1550 write(audio.soundserver_pipe[1], &str_size2,
1551 sizeof(unsigned long)) < 0 ||
1552 write(audio.soundserver_pipe[1], &str_size3,
1553 sizeof(unsigned long)) < 0 ||
1554 write(audio.soundserver_pipe[1], leveldir_current->fullpath,
1556 write(audio.soundserver_pipe[1], ti->basepath,
1558 write(audio.soundserver_pipe[1], ti->fullpath,
1561 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1562 audio.sound_available = audio.sound_enabled = FALSE;
1568 void InitReloadSounds(char *set_name)
1570 InitReloadSoundsOrMusic(set_name, SND_RELOAD_SOUNDS);
1573 void InitReloadMusic(char *set_name)
1575 InitReloadSoundsOrMusic(set_name, SND_RELOAD_MUSIC);
1578 void FreeSound(SoundInfo *sound)
1583 if (sound->data_ptr)
1585 #if defined(TARGET_SDL)
1586 Mix_FreeChunk(sound->data_ptr);
1587 #elif defined(TARGET_ALLEGRO)
1588 destroy_sample(sound->data_ptr);
1589 #else /* PLATFORM_UNIX */
1590 free(sound->data_ptr);
1597 void FreeMusic(MusicInfo *music)
1602 if (music->data_ptr)
1604 #if defined(TARGET_SDL)
1605 if (music->type == MUS_TYPE_MOD)
1606 Mix_FreeMusic(music->data_ptr);
1608 Mix_FreeChunk(music->data_ptr);
1609 #elif defined(TARGET_ALLEGRO)
1610 destroy_sample(music->data_ptr);
1611 #else /* PLATFORM_UNIX */
1612 free(music->data_ptr);
1619 void FreeAllSounds()
1626 for(i=0; i<num_sounds; i++)
1627 FreeSound(Sound[i]);
1642 for(i=0; i<num_music; i++)
1643 FreeMusic(Music[i]);
1651 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
1652 /* ========================================================================= */