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)
363 int fragment_size = afmt.fragment_size;
364 int sample_bytes = (afmt.format & AUDIO_FORMAT_U8 ? 1 : 2);
365 boolean stereo = afmt.stereo;
367 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
369 max_sample_size = fragment_size / ((stereo ? 2 : 1) * sample_bytes);
371 /* first clear the last premixing buffer */
372 memset(premix_last_buffer, 0,
373 max_sample_size * (stereo ? 2 : 1) * sizeof(long));
375 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
379 if (!playlist[i].active)
382 /* get pointer and size of the actual sound sample */
383 sample_ptr = (short *)playlist[i].data_ptr +playlist[i].playingpos;
384 sample_size = MIN(max_sample_size,
385 playlist[i].data_len - playlist[i].playingpos);
386 playlist[i].playingpos += sample_size;
388 /* fill the first mixing buffer with original sample */
389 memcpy(premix_first_buffer, sample_ptr,
390 sample_size * sizeof(short));
392 /* are we about to restart a looping sound? */
393 if (playlist[i].loop && sample_size < max_sample_size)
395 playlist[i].playingpos = max_sample_size - sample_size;
396 memcpy(premix_first_buffer + sample_size * sizeof(short),
397 playlist[i].data_ptr,
398 (max_sample_size - sample_size) * sizeof(short));
399 sample_size = max_sample_size;
402 /* decrease volume if sound is fading out */
403 if (playlist[i].fade_sound &&
404 playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
405 playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
407 /* adjust volume of actual sound sample */
408 if (playlist[i].volume != PSND_MAX_VOLUME)
409 for(j=0; j<sample_size; j++)
410 premix_first_buffer[j] =
411 (playlist[i].volume * (long)premix_first_buffer[j])
412 >> PSND_MAX_VOLUME_BITS;
414 /* fill the last mixing buffer with stereo or mono sound */
417 int middle_pos = PSND_MAX_LEFT2RIGHT / 2;
418 int left_volume = stereo_volume[middle_pos + playlist[i].stereo];
419 int right_volume= stereo_volume[middle_pos - playlist[i].stereo];
421 for(j=0; j<sample_size; j++)
423 premix_left_buffer[j] =
424 (left_volume * premix_first_buffer[j])
425 >> PSND_MAX_LEFT2RIGHT_BITS;
426 premix_right_buffer[j] =
427 (right_volume * premix_first_buffer[j])
428 >> PSND_MAX_LEFT2RIGHT_BITS;
430 premix_last_buffer[2 * j + 0] += premix_left_buffer[j];
431 premix_last_buffer[2 * j + 1] += premix_right_buffer[j];
436 for(j=0; j<sample_size; j++)
437 premix_last_buffer[j] += premix_first_buffer[j];
440 /* delete completed sound entries from the playlist */
441 if (playlist[i].playingpos >= playlist[i].data_len)
443 if (playlist[i].loop)
444 playlist[i].playingpos = 0;
447 playlist[i] = emptySoundControl;
451 else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
453 playlist[i] = emptySoundControl;
458 /* prepare final playing buffer according to system audio format */
459 for(i=0; i<max_sample_size * (stereo ? 2 : 1); i++)
461 /* cut off at 17 bit value */
462 if (premix_last_buffer[i] < -65535)
463 premix_last_buffer[i] = -65535;
464 else if (premix_last_buffer[i] > 65535)
465 premix_last_buffer[i] = 65535;
467 /* shift to 16 bit value */
468 premix_last_buffer[i] >>= 1;
470 if (afmt.format & AUDIO_FORMAT_U8)
472 playing_buffer[i] = (premix_last_buffer[i] >> 8) ^ 0x80;
474 else if (afmt.format & AUDIO_FORMAT_LE) /* 16 bit */
476 playing_buffer[2 * i + 0] = premix_last_buffer[i] & 0xff;
477 playing_buffer[2 * i + 1] = premix_last_buffer[i] >> 8;
479 else /* big endian */
481 playing_buffer[2 * i + 0] = premix_last_buffer[i] >> 8;
482 playing_buffer[2 * i + 1] = premix_last_buffer[i] & 0xff;
486 /* finally play the sound fragment */
487 write(audio.device_fd, playing_buffer, fragment_size);
490 /* if no sounds playing, free device for other sound programs */
492 close(audio.device_fd);
496 #else /* !AUDIO_STREAMING_DSP */
498 if (snd_ctrl.active && !snd_ctrl.loop)
500 struct timeval delay = { 0, 0 };
502 long sample_size, max_sample_size = SND_BLOCKSIZE;
503 long sample_rate = 8000; /* standard "/dev/audio" sampling rate */
504 int wait_percent = 90; /* wait 90% of the real playing time */
507 if ((audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
511 while (playing_sounds &&
512 select(audio.soundserver_pipe[0] + 1,
513 &sound_fdset, NULL, NULL, &delay) < 1)
515 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
517 /* get pointer and size of the actual sound sample */
518 sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos;
520 MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos);
521 snd_ctrl.playingpos += sample_size;
523 /* fill the first mixing buffer with original sample */
524 memcpy(premix_first_buffer,sample_ptr,sample_size);
526 /* adjust volume of actual sound sample */
527 if (snd_ctrl.volume != PSND_MAX_VOLUME)
528 for(i=0;i<sample_size;i++)
529 premix_first_buffer[i] =
530 (snd_ctrl.volume * (int)premix_first_buffer[i])
531 >> PSND_MAX_VOLUME_BITS;
533 for(i=0;i<sample_size;i++)
535 linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
537 if (snd_ctrl.playingpos >= snd_ctrl.data_len)
540 /* finally play the sound fragment */
541 write(audio.device_fd,playing_buffer,sample_size);
544 delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
546 close(audio.device_fd);
549 #endif /* !AUDIO_STREAMING_DSP */
552 #endif /* PLATFORM_UNIX */
554 #if defined(PLATFORM_MSDOS)
555 static void sound_handler(struct SoundControl snd_ctrl)
559 if (snd_ctrl.fade_sound)
564 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
565 if ((snd_ctrl.stop_all_sounds ||
566 (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr) ||
567 (i == audio.music_channel && snd_ctrl.music)) &&
568 !playlist[i].fade_sound)
570 playlist[i].fade_sound = TRUE;
571 if (voice_check(playlist[i].voice))
572 voice_ramp_volume(playlist[i].voice, 1000, 0);
573 playlist[i].loop = PSND_NO_LOOP;
576 else if (snd_ctrl.stop_all_sounds)
580 SoundServer_StopAllSounds();
582 else if (snd_ctrl.stop_sound)
586 SoundServer_StopSound(snd_ctrl);
589 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
591 if (!playlist[i].active || playlist[i].loop)
594 playlist[i].playingpos = voice_get_position(playlist[i].voice);
595 playlist[i].volume = voice_get_volume(playlist[i].voice);
596 if (playlist[i].playingpos == -1 || !playlist[i].volume)
598 deallocate_voice(playlist[i].voice);
599 playlist[i] = emptySoundControl;
605 SoundServer_InsertNewSound(snd_ctrl);
607 #endif /* PLATFORM_MSDOS */
609 #if !defined(PLATFORM_WIN32)
610 static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
615 snd_ctrl.nr = snd_ctrl.nr % num_music;
617 /* if playlist is full, remove oldest sound */
618 if (playing_sounds == MAX_SOUNDS_PLAYING)
620 int longest = 0, longest_nr = 0;
622 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
624 #if !defined(PLATFORM_MSDOS)
625 int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
627 int actual = playlist[i].playingpos;
630 if (i != audio.music_channel && !playlist[i].loop && actual > longest)
636 #if defined(PLATFORM_MSDOS)
637 voice_set_volume(playlist[longest_nr].voice, 0);
638 deallocate_voice(playlist[longest_nr].voice);
640 playlist[longest_nr] = emptySoundControl;
644 /* check if sound is already being played (and how often) */
645 for (k=0,i=0; i<MAX_SOUNDS_PLAYING; i++)
646 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr)
649 /* restart loop sounds only if they are just fading out */
650 if (k >= 1 && snd_ctrl.loop)
652 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
654 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr &&
655 playlist[i].fade_sound)
657 playlist[i].fade_sound = FALSE;
658 playlist[i].volume = PSND_MAX_VOLUME;
659 #if defined(PLATFORM_MSDOS)
660 playlist[i].loop = PSND_LOOP;
661 voice_stop_volumeramp(playlist[i].voice);
662 voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
670 /* don't play sound more than n times simultaneously (with n == 2 for now) */
673 int longest = 0, longest_nr = 0;
675 /* look for oldest equal sound */
676 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
680 if (!playlist[i].active ||
681 i == audio.music_channel ||
682 playlist[i].nr != snd_ctrl.nr)
685 #if !defined(PLATFORM_MSDOS)
686 actual = 100 * playlist[i].playingpos / playlist[i].data_len;
688 actual = playlist[i].playingpos;
690 if (actual >= longest)
697 #if defined(PLATFORM_MSDOS)
698 voice_set_volume(playlist[longest_nr].voice, 0);
699 deallocate_voice(playlist[longest_nr].voice);
701 playlist[longest_nr] = emptySoundControl;
705 /* add new sound to playlist */
706 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
708 if (!playlist[i].active ||
709 (snd_ctrl.music && i == audio.music_channel))
711 SoundInfo *snd_info =
712 (snd_ctrl.music ? Music[snd_ctrl.nr] : Sound[snd_ctrl.nr]);
714 snd_ctrl.data_ptr = snd_info->data_ptr;
715 snd_ctrl.data_len = snd_info->data_len;
717 playlist[i] = snd_ctrl;
720 #if defined(PLATFORM_MSDOS)
721 playlist[i].voice = allocate_voice((SAMPLE *)playlist[i].data_ptr);
724 voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
726 voice_set_volume(playlist[i].voice, snd_ctrl.volume);
727 voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
728 voice_start(playlist[i].voice);
734 #endif /* !PLATFORM_WIN32 */
737 void SoundServer_FadeSound(int nr)
744 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
745 if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
746 playlist[i].fade_sound = TRUE;
750 #if !defined(PLATFORM_WIN32)
751 #if defined(PLATFORM_MSDOS)
752 static void SoundServer_StopSound(struct SoundControl snd_ctrl)
754 int nr = snd_ctrl.nr;
760 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
762 if ((i == audio.music_channel && snd_ctrl.music) ||
763 (i != audio.music_channel && playlist[i].nr == nr))
765 #if defined(PLATFORM_MSDOS)
766 voice_set_volume(playlist[i].voice, 0);
767 deallocate_voice(playlist[i].voice);
769 playlist[i] = emptySoundControl;
774 #if !defined(PLATFORM_MSDOS)
776 close(audio.device_fd);
780 static void SoundServer_StopAllSounds()
784 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
786 #if defined(PLATFORM_MSDOS)
787 voice_set_volume(playlist[i].voice, 0);
788 deallocate_voice(playlist[i].voice);
790 playlist[i]=emptySoundControl;
794 #if !defined(PLATFORM_MSDOS)
795 close(audio.device_fd);
798 #endif /* PLATFORM_MSDOS */
799 #endif /* !PLATFORM_WIN32 */
802 /* ------------------------------------------------------------------------- */
803 /* platform dependant audio initialization code */
804 /* ------------------------------------------------------------------------- */
806 #if defined(AUDIO_LINUX_IOCTL)
807 static void InitAudioDevice_Linux(struct AudioFormatInfo *afmt)
809 /* "ioctl()" expects pointer to 'int' value for stereo flag
810 (boolean is defined as 'char', which will not work here) */
811 unsigned int fragment_spec = 0;
812 int fragment_size_query;
821 /* supported audio format in preferred order */
822 { AFMT_S16_LE, AUDIO_FORMAT_S16 | AUDIO_FORMAT_LE },
823 { AFMT_S16_BE, AUDIO_FORMAT_S16 | AUDIO_FORMAT_BE },
824 { AFMT_U8, AUDIO_FORMAT_U8 },
829 /* determine logarithm (log2) of the fragment size */
830 while ((1 << fragment_spec) < afmt->fragment_size)
833 /* use two fragments (play one fragment, prepare the other);
834 one fragment would result in interrupted audio output, more
835 than two fragments would raise audio output latency to much */
836 fragment_spec |= 0x00020000;
838 /* Example for fragment specification:
839 - 2 buffers / 512 bytes (giving 1/16 second resolution for 8 kHz)
840 - (with stereo the effective buffer size will shrink to 256)
841 => fragment_size = 0x00020009 */
843 if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0)
844 Error(ERR_EXIT_SOUND_SERVER,
845 "cannot set fragment size of /dev/dsp -- no sounds");
849 while (formats[i].format_result != -1)
851 unsigned int audio_format = formats[i].format_ioctl;
852 if (ioctl(audio.device_fd, SNDCTL_DSP_SETFMT, &audio_format) == 0)
854 afmt->format = formats[i].format_result;
859 if (afmt->format == 0) /* no supported audio format found */
860 Error(ERR_EXIT_SOUND_SERVER,
861 "cannot set audio format of /dev/dsp -- no sounds");
863 /* try if we can use stereo sound */
865 if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
866 afmt->stereo = FALSE;
868 if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &afmt->sample_rate) < 0)
869 Error(ERR_EXIT_SOUND_SERVER,
870 "cannot set sample rate of /dev/dsp -- no sounds");
872 /* get the real fragmentation size; this should return 512 */
873 if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size_query) < 0)
874 Error(ERR_EXIT_SOUND_SERVER,
875 "cannot get fragment size of /dev/dsp -- no sounds");
876 if (fragment_size_query != afmt->fragment_size)
877 Error(ERR_EXIT_SOUND_SERVER,
878 "cannot set fragment size of /dev/dsp -- no sounds");
880 #endif /* AUDIO_LINUX_IOCTL */
882 #if defined(PLATFORM_NETBSD)
883 static void InitAudioDevice_NetBSD(struct AudioFormatInfo *afmt)
886 boolean stereo = TRUE;
888 AUDIO_INITINFO(&a_info);
889 a_info.play.encoding = AUDIO_ENCODING_LINEAR8;
890 a_info.play.precision = 8;
891 a_info.play.channels = 2;
892 a_info.play.sample_rate = sample_rate;
893 a_info.blocksize = fragment_size;
895 afmt->format = AUDIO_FORMAT_U8;
898 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
900 /* try to disable stereo */
901 a_info.play.channels = 1;
903 afmt->stereo = FALSE;
905 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
906 Error(ERR_EXIT_SOUND_SERVER,
907 "cannot set sample rate of /dev/audio -- no sounds");
910 #endif /* PLATFORM_NETBSD */
912 #if defined(PLATFORM_HPUX)
913 static void InitAudioDevice_HPUX(struct AudioFormatInfo *afmt)
915 struct audio_describe ainfo;
918 audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
920 Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl -- no sounds");
922 if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
923 Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds");
925 if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
926 Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds");
928 ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
929 ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
931 afmt->format = AUDIO_FORMAT_U8;
932 afmt->stereo = FALSE;
933 afmt->sample_rate = 8000;
937 #endif /* PLATFORM_HPUX */
939 #if defined(PLATFORM_UNIX)
940 static void InitAudioDevice_DSP(struct AudioFormatInfo *afmt)
942 #if defined(AUDIO_LINUX_IOCTL)
943 InitAudioDevice_Linux(afmt);
944 #elif defined(PLATFORM_NETBSD)
945 InitAudioDevice_NetBSD(afmt);
946 #elif defined(PLATFORM_HPUX)
947 InitAudioDevice_HPUX(afmt);
950 #endif /* PLATFORM_UNIX */
952 #if defined(PLATFORM_UNIX) && !defined(AUDIO_STREAMING_DSP)
954 /* these two are stolen from "sox"... :) */
957 ** This routine converts from linear to ulaw.
959 ** Craig Reese: IDA/Supercomputing Research Center
960 ** Joe Campbell: Department of Defense
964 ** 1) CCITT Recommendation G.711 (very difficult to follow)
965 ** 2) "A New Digital Technique for Implementation of Any
966 ** Continuous PCM Companding Law," Villeret, Michel,
967 ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
968 ** 1973, pg. 11.12-11.17
969 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
970 ** for Analog-to_Digital Conversion Techniques,"
973 ** Input: Signed 16 bit linear sample
974 ** Output: 8 bit ulaw sample
977 #define ZEROTRAP /* turn on the trap as per the MIL-STD */
978 #define BIAS 0x84 /* define the add-in bias for 16 bit samples */
981 static unsigned char linear_to_ulaw(int sample)
983 static int exp_lut[256] =
985 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
986 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
987 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
988 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
989 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
990 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
991 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
992 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
993 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
994 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
995 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
996 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
997 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
998 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
999 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1000 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
1003 int sign, exponent, mantissa;
1004 unsigned char ulawbyte;
1006 /* Get the sample into sign-magnitude. */
1007 sign = (sample >> 8) & 0x80; /* set aside the sign */
1009 sample = -sample; /* get magnitude */
1011 sample = CLIP; /* clip the magnitude */
1013 /* Convert from 16 bit linear to ulaw. */
1014 sample = sample + BIAS;
1015 exponent = exp_lut[( sample >> 7 ) & 0xFF];
1016 mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
1017 ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
1020 ulawbyte = 0x02; /* optional CCITT trap */
1027 ** This routine converts from ulaw to 16 bit linear.
1029 ** Craig Reese: IDA/Supercomputing Research Center
1030 ** 29 September 1989
1033 ** 1) CCITT Recommendation G.711 (very difficult to follow)
1034 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
1035 ** for Analog-to_Digital Conversion Techniques,"
1038 ** Input: 8 bit ulaw sample
1039 ** Output: signed 16 bit linear sample
1042 static int ulaw_to_linear(unsigned char ulawbyte)
1044 static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
1045 int sign, exponent, mantissa, sample;
1047 ulawbyte = ~ ulawbyte;
1048 sign = ( ulawbyte & 0x80 );
1049 exponent = ( ulawbyte >> 4 ) & 0x07;
1050 mantissa = ulawbyte & 0x0F;
1051 sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
1057 #endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */
1060 /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
1061 /* ========================================================================= */
1062 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */
1064 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
1065 #define WAV_HEADER_SIZE 16 /* size of WAV file header */
1067 static SoundInfo *Load_WAV(char *filename)
1069 SoundInfo *snd_info;
1070 #if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS)
1071 byte sound_header_buffer[WAV_HEADER_SIZE];
1072 char chunk_name[CHUNK_ID_LEN + 1];
1079 if (!audio.sound_available)
1082 snd_info = checked_calloc(sizeof(SoundInfo));
1084 #if defined(TARGET_SDL)
1086 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
1088 Error(ERR_WARN, "cannot read sound file '%s'", filename);
1093 #elif defined(TARGET_ALLEGRO)
1095 if ((snd_info->data_ptr = load_sample(filename)) == NULL)
1097 Error(ERR_WARN, "cannot read sound file '%s'", filename);
1102 #else /* PLATFORM_UNIX */
1104 if ((file = fopen(filename, MODE_READ)) == NULL)
1106 Error(ERR_WARN, "cannot open sound file '%s'", filename);
1111 /* read chunk id "RIFF" */
1112 getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
1113 if (strcmp(chunk_name, "RIFF") != 0)
1115 Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
1121 /* read "RIFF" type id "WAVE" */
1122 getFileChunk(file, chunk_name, NULL, BYTE_ORDER_LITTLE_ENDIAN);
1123 if (strcmp(chunk_name, "WAVE") != 0)
1125 Error(ERR_WARN, "missing 'WAVE' type ID of sound file '%s'", filename);
1131 while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN))
1133 if (strcmp(chunk_name, "fmt ") == 0)
1135 /* read header information */
1136 for (i=0; i < MIN(chunk_size, WAV_HEADER_SIZE); i++)
1137 sound_header_buffer[i] = fgetc(file);
1139 if (chunk_size > WAV_HEADER_SIZE)
1140 ReadUnusedBytesFromFile(file, chunk_size - WAV_HEADER_SIZE);
1142 else if (strcmp(chunk_name, "data") == 0)
1144 snd_info->data_len = chunk_size;
1145 snd_info->data_ptr = checked_malloc(snd_info->data_len);
1147 /* read sound data */
1148 if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
1151 Error(ERR_WARN,"cannot read 'data' chunk of sound file '%s'",filename);
1153 free(snd_info->data_ptr);
1158 /* check for odd number of sample bytes (data chunk is word aligned) */
1159 if ((chunk_size % 2) == 1)
1160 ReadUnusedBytesFromFile(file, 1);
1162 else /* unknown chunk -- ignore */
1163 ReadUnusedBytesFromFile(file, chunk_size);
1168 if (snd_info->data_ptr == NULL)
1170 Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
1175 /* convert unsigned 8 bit sample data to signed 16 bit sample data */
1177 data_ptr = checked_malloc(snd_info->data_len * sizeof(short));
1179 for (i=0; i<snd_info->data_len; i++)
1180 data_ptr[i] = ((short)(((byte *)snd_info->data_ptr)[i] ^ 0x80)) << 8;
1182 free(snd_info->data_ptr);
1183 snd_info->data_ptr = data_ptr;
1185 #endif /* PLATFORM_UNIX */
1187 snd_info->type = SND_TYPE_WAV;
1188 snd_info->source_filename = getStringCopy(filename);
1193 SoundInfo *LoadCustomSound(char *basename)
1195 char *filename = getCustomSoundFilename(basename);
1197 if (filename == NULL)
1199 Error(ERR_WARN, "cannot find sound file '%s'", basename);
1203 return Load_WAV(filename);
1206 void InitSoundList(int num_list_entries)
1208 Sound = checked_calloc(num_list_entries * sizeof(SoundInfo *));
1209 num_sounds = num_list_entries;
1212 void LoadSoundToList(char *basename, int list_pos)
1214 if (Sound == NULL || list_pos >= num_sounds)
1217 if (Sound[list_pos])
1218 FreeSound(Sound[list_pos]);
1220 Sound[list_pos] = LoadCustomSound(basename);
1223 static MusicInfo *Load_MOD(char *filename)
1225 #if defined(TARGET_SDL)
1226 MusicInfo *mod_info;
1228 if (!audio.sound_available)
1231 mod_info = checked_calloc(sizeof(MusicInfo));
1233 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
1235 Error(ERR_WARN, "cannot read music file '%s'", filename);
1240 mod_info->type = MUS_TYPE_MOD;
1241 mod_info->source_filename = getStringCopy(filename);
1249 void LoadCustomMusic(void)
1251 char *music_directory = getCustomMusicDirectory();
1253 struct dirent *dir_entry;
1255 if (!audio.sound_available)
1258 if ((dir = opendir(music_directory)) == NULL)
1260 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
1261 audio.music_available = FALSE;
1265 while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
1267 char *basename = dir_entry->d_name;
1268 char *filename = getPath2(music_directory, basename);
1269 MusicInfo *mus_info = NULL;
1271 if (FileIsSound(basename))
1272 mus_info = Load_WAV(filename);
1273 else if (FileIsMusic(basename))
1274 mus_info = Load_MOD(filename);
1281 Music = checked_realloc(Music, num_music * sizeof(MusicInfo *));
1282 Music[num_music -1] = mus_info;
1289 Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
1293 void PlayMusic(int nr)
1295 if (!audio.music_available)
1298 #if defined(TARGET_SDL)
1300 nr = nr % num_music;
1302 if (Music[nr]->type == MUS_TYPE_MOD)
1304 Mix_PlayMusic(Music[nr]->data_ptr, -1);
1305 Mix_VolumeMusic(SOUND_MAX_VOLUME); /* must be _after_ Mix_PlayMusic()! */
1307 else /* play WAV music loop */
1309 Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
1310 Mix_PlayChannel(audio.music_channel, Music[nr]->data_ptr, -1);
1320 void PlaySound(int nr)
1322 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
1325 void PlaySoundStereo(int nr, int stereo)
1327 PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
1330 void PlaySoundLoop(int nr)
1332 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
1335 void PlaySoundMusic(int nr)
1337 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_MUSIC);
1340 void PlaySoundExt(int nr, int volume, int stereo, boolean loop_type)
1342 struct SoundControl snd_ctrl = emptySoundControl;
1344 if (!audio.sound_available ||
1345 !audio.sound_enabled ||
1346 audio.sound_deactivated)
1349 if (volume < PSND_MIN_VOLUME)
1350 volume = PSND_MIN_VOLUME;
1351 else if (volume > PSND_MAX_VOLUME)
1352 volume = PSND_MAX_VOLUME;
1354 if (stereo < PSND_MAX_LEFT)
1355 stereo = PSND_MAX_LEFT;
1356 else if (stereo > PSND_MAX_RIGHT)
1357 stereo = PSND_MAX_RIGHT;
1360 snd_ctrl.volume = volume;
1361 snd_ctrl.stereo = stereo;
1362 snd_ctrl.loop = (loop_type != PSND_NO_LOOP);
1363 snd_ctrl.music = (loop_type == PSND_MUSIC);
1364 snd_ctrl.active = TRUE;
1367 /* now only used internally in sound server child process */
1368 snd_ctrl.data_ptr = Sound[nr].data_ptr;
1369 snd_ctrl.data_len = Sound[nr].data_len;
1372 #if defined(TARGET_SDL)
1373 Mix_Volume(-1, SOUND_MAX_VOLUME);
1374 Mix_PlayChannel(-1, Sound[nr]->data_ptr, (loop_type ? -1 : 0));
1375 #elif defined(PLATFORM_UNIX)
1376 if (audio.soundserver_pid == 0) /* we are child process */
1379 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1381 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1382 audio.sound_available = audio.sound_enabled = FALSE;
1385 #elif defined(PLATFORM_MSDOS)
1386 sound_handler(snd_ctrl);
1390 void FadeMusic(void)
1392 if (!audio.sound_available)
1395 #if defined(TARGET_SDL)
1396 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1397 Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
1399 StopSoundExt(-1, SSND_FADE_MUSIC);
1403 void FadeSound(int nr)
1405 StopSoundExt(nr, SSND_FADE_SOUND);
1411 StopSoundExt(-1, SSND_FADE_ALL);
1414 void StopMusic(void)
1416 #if defined(TARGET_SDL)
1417 if (!audio.sound_available)
1421 Mix_HaltChannel(audio.music_channel);
1423 StopSoundExt(-1, SSND_STOP_MUSIC);
1427 void StopSound(int nr)
1429 StopSoundExt(nr, SSND_STOP_SOUND);
1434 StopSoundExt(-1, SSND_STOP_ALL);
1437 void StopSoundExt(int nr, int method)
1439 struct SoundControl snd_ctrl = emptySoundControl;
1441 if (!audio.sound_available)
1444 if (method & SSND_FADING)
1445 snd_ctrl.fade_sound = TRUE;
1447 if (method & SSND_ALL)
1448 snd_ctrl.stop_all_sounds = TRUE;
1451 snd_ctrl.stop_sound = TRUE;
1455 if (method & SSND_MUSIC)
1456 snd_ctrl.music = TRUE;
1458 #if defined(TARGET_SDL)
1460 if (method & SSND_FADING)
1464 for (i=0; i<audio.channels; i++)
1465 if (i != audio.music_channel || snd_ctrl.music)
1466 Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
1468 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1474 for (i=0; i<audio.channels; i++)
1475 if (i != audio.music_channel || snd_ctrl.music)
1481 #elif !defined(PLATFORM_MSDOS)
1483 if (audio.soundserver_pid == 0) /* we are child process */
1486 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1488 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1489 audio.sound_available = audio.sound_enabled = FALSE;
1493 sound_handler(snd_ctrl);
1497 static void InitReloadSoundsOrMusic(char *set_name, int type)
1499 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
1500 struct SoundControl snd_ctrl = emptySoundControl;
1502 (type == SND_RELOAD_SOUNDS ? artwork.snd_current : artwork.mus_current);
1503 unsigned long str_size1 = strlen(leveldir_current->fullpath) + 1;
1504 unsigned long str_size2 = strlen(ti->basepath) + 1;
1505 unsigned long str_size3 = strlen(ti->fullpath) + 1;
1508 if (!audio.sound_available)
1511 #if defined(TARGET_SDL) || defined(TARGET_ALLEGRO)
1512 if (type == SND_RELOAD_SOUNDS)
1513 audio.func_reload_sounds();
1515 audio.func_reload_music();
1516 #elif defined(PLATFORM_UNIX)
1517 if (audio.soundserver_pid == 0) /* we are child process */
1520 if (leveldir_current == NULL) /* should never happen */
1521 Error(ERR_EXIT, "leveldir_current == NULL");
1523 snd_ctrl.reload_sounds = (type == SND_RELOAD_SOUNDS);
1524 snd_ctrl.reload_music = (type == SND_RELOAD_MUSIC);
1525 snd_ctrl.data_len = strlen(set_name) + 1;
1527 if (write(audio.soundserver_pipe[1], &snd_ctrl,
1528 sizeof(snd_ctrl)) < 0 ||
1529 write(audio.soundserver_pipe[1], set_name,
1530 snd_ctrl.data_len) < 0 ||
1531 write(audio.soundserver_pipe[1], leveldir_current,
1532 sizeof(TreeInfo)) < 0 ||
1533 write(audio.soundserver_pipe[1], ti,
1534 sizeof(TreeInfo)) < 0 ||
1535 write(audio.soundserver_pipe[1], &str_size1,
1536 sizeof(unsigned long)) < 0 ||
1537 write(audio.soundserver_pipe[1], &str_size2,
1538 sizeof(unsigned long)) < 0 ||
1539 write(audio.soundserver_pipe[1], &str_size3,
1540 sizeof(unsigned long)) < 0 ||
1541 write(audio.soundserver_pipe[1], leveldir_current->fullpath,
1543 write(audio.soundserver_pipe[1], ti->basepath,
1545 write(audio.soundserver_pipe[1], ti->fullpath,
1548 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1549 audio.sound_available = audio.sound_enabled = FALSE;
1555 void InitReloadSounds(char *set_name)
1557 InitReloadSoundsOrMusic(set_name, SND_RELOAD_SOUNDS);
1560 void InitReloadMusic(char *set_name)
1562 InitReloadSoundsOrMusic(set_name, SND_RELOAD_MUSIC);
1565 void FreeSound(SoundInfo *sound)
1570 if (sound->data_ptr)
1572 #if defined(TARGET_SDL)
1573 Mix_FreeChunk(sound->data_ptr);
1574 #elif defined(TARGET_ALLEGRO)
1575 destroy_sample(sound->data_ptr);
1576 #else /* PLATFORM_UNIX */
1577 free(sound->data_ptr);
1584 void FreeMusic(MusicInfo *music)
1589 if (music->data_ptr)
1591 #if defined(TARGET_SDL)
1592 if (music->type == MUS_TYPE_MOD)
1593 Mix_FreeMusic(music->data_ptr);
1595 Mix_FreeChunk(music->data_ptr);
1596 #elif defined(TARGET_ALLEGRO)
1597 destroy_sample(music->data_ptr);
1598 #else /* PLATFORM_UNIX */
1599 free(music->data_ptr);
1606 void FreeAllSounds()
1613 for(i=0; i<num_sounds; i++)
1614 FreeSound(Sound[i]);
1629 for(i=0; i<num_music; i++)
1630 FreeMusic(Music[i]);
1638 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
1639 /* ========================================================================= */