X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fsound.c;h=d10f0f2b7f94a6f3f286602e9f45eb7b3e59eba9;hp=1cf7e5f1baeaa86cce0188ce2676d73132c0d28e;hb=bcb3453f710b95ec98b188b95574bea9ab336e96;hpb=3d07b68a314ce189f207e42d95f786979662410d diff --git a/src/libgame/sound.c b/src/libgame/sound.c index 1cf7e5f1..d10f0f2b 100644 --- a/src/libgame/sound.c +++ b/src/libgame/sound.c @@ -1,29 +1,38 @@ /*********************************************************** -* Rocks'n'Diamonds -- McDuffin Strikes Back! * +* Artsoft Retro-Game Library * *----------------------------------------------------------* -* (c) 1995-98 Artsoft Entertainment * -* Holger Schemel * -* Oststrasse 11a * -* 33604 Bielefeld * -* phone: ++49 +521 290471 * -* email: aeglos@valinor.owl.de * +* (c) 1994-2001 Artsoft Entertainment * +* Holger Schemel * +* Detmolder Strasse 189 * +* 33604 Bielefeld * +* Germany * +* e-mail: info@artsoft.org * *----------------------------------------------------------* -* sound.c * +* sound.c * ***********************************************************/ +#include #include #include #include +#include +#include +#include "system.h" #include "sound.h" #include "misc.h" -static int num_sounds = 0; +static int num_sounds = 0, num_music = 0; static struct SampleInfo *Sound = NULL; +#if defined(TARGET_SDL) +static int num_mods = 0; +static struct SampleInfo *Mod = NULL; +#endif -/*** THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/ +/* ========================================================================= */ +/* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */ static int playing_sounds = 0; static struct SoundControl playlist[MAX_SOUNDS_PLAYING]; @@ -51,18 +60,20 @@ static unsigned char linear_to_ulaw(int); static int ulaw_to_linear(unsigned char); #endif -#if defined(PLATFORM_HPUX) -static void HPUX_Audio_Control(); -#endif - -#if defined(PLATFORM_MSDOS) +#if defined(AUDIO_LINUX_IOCTL) +static boolean InitAudioDevice_Linux(); +#elif defined(PLATFORM_NETBSD) +static boolean InitAudioDevice_NetBSD(); +#elif defined(PLATFORM_HPUX) +static boolean InitAudioDevice_HPUX(); +#elif defined(PLATFORM_MSDOS) static void SoundServer_InsertNewSound(struct SoundControl); static void SoundServer_StopSound(int); static void SoundServer_StopAllSounds(); #endif #if defined(PLATFORM_UNIX) -int OpenAudioDevice(char *audio_device_name) +static int OpenAudioDevice(char *audio_device_name) { int audio_fd; @@ -81,7 +92,7 @@ int OpenAudioDevice(char *audio_device_name) return audio_fd; } -void UnixOpenAudio(struct AudioSystemInfo *audio) +static boolean TestAudioDevices(void) { static char *audio_device_name[] = { @@ -98,51 +109,109 @@ void UnixOpenAudio(struct AudioSystemInfo *audio) if (audio_fd < 0) { - Error(ERR_WARN, "cannot open audio device - no sound"); - return; + Error(ERR_WARN, "cannot open audio device -- no sound"); + return FALSE; } close(audio_fd); - audio->device_name = audio_device_name[i]; - audio->sound_available = TRUE; - audio->sound_enabled = TRUE; + audio.device_name = audio_device_name[i]; + + return TRUE; +} + +#if !defined(TARGET_SDL) +static boolean ForkAudioProcess(void) +{ + if (pipe(audio.soundserver_pipe) < 0) + { + Error(ERR_WARN, "cannot create pipe -- no sounds"); + return FALSE; + } + + if ((audio.soundserver_pid = fork()) < 0) + { + Error(ERR_WARN, "cannot create sound server process -- no sounds"); + return FALSE; + } + + if (audio.soundserver_pid == 0) /* we are child */ + { + SoundServer(); + + /* never reached */ + exit(0); + } + else /* we are parent */ + close(audio.soundserver_pipe[0]); /* no reading from pipe needed */ + + return TRUE; +} +#endif + +void UnixOpenAudio(void) +{ + if (!TestAudioDevices()) + return; + + audio.sound_available = TRUE; + audio.sound_enabled = TRUE; #if defined(AUDIO_STREAMING_DSP) - audio->loops_available = TRUE; + audio.music_available = TRUE; + audio.loops_available = TRUE; #endif } -void UnixCloseAudio(struct AudioSystemInfo *audio) +void UnixCloseAudio(void) { - if (audio->device_fd) - close(audio->device_fd); -} + if (audio.device_fd) + close(audio.device_fd); + if (audio.soundserver_pid) + kill(audio.soundserver_pid, SIGTERM); +} #endif /* PLATFORM_UNIX */ -void SoundServer() +void InitPlaylist(void) { int i; + + for(i=0;i= 0) { if (!playing_sounds) /* we just opened the audio device */ { - /* 2 buffers / 512 bytes, giving 1/16 second resolution */ - /* (with stereo the effective buffer size will shrink to 256) */ - fragment_size = 0x00020009; - - if (ioctl(audio.device_fd,SNDCTL_DSP_SETFRAGMENT,&fragment_size) < 0) - Error(ERR_EXIT_SOUND_SERVER, - "cannot set fragment size of /dev/dsp - no sounds"); - - /* try if we can use stereo sound */ - if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0) - { -#ifdef DEBUG - static boolean reported = FALSE; - - if (!reported) - { - Error(ERR_RETURN, "cannot get stereo sound on /dev/dsp"); - reported = TRUE; - } +#if defined(AUDIO_LINUX_IOCTL) + stereo = InitAudioDevice_Linux(fragment_size, sample_rate); +#elif defined(PLATFORM_NETBSD) + stereo = InitAudioDevice_NetBSD(fragment_size, sample_rate); #endif - stereo = FALSE; - } - - if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &sample_rate) < 0) - Error(ERR_EXIT_SOUND_SERVER, - "cannot set sample rate of /dev/dsp - no sounds"); - - /* get the real fragmentation size; this should return 512 */ - if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE,&fragment_size) < 0) - Error(ERR_EXIT_SOUND_SERVER, - "cannot get fragment size of /dev/dsp - no sounds"); - max_sample_size = fragment_size / (stereo ? 2 : 1); } @@ -262,7 +298,7 @@ void SoundServer() FD_SET(audio.soundserver_pipe[0], &sound_fdset); /* first clear the last premixing buffer */ - memset(premix_last_buffer,0,fragment_size*sizeof(int)); + memset(premix_last_buffer, 0, fragment_size * sizeof(int)); for(i=0;i=PSND_MAX_VOLUME/10) - playlist[i].volume-=PSND_MAX_VOLUME/20; + playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD) + playlist[i].volume -= SOUND_FADING_VOLUME_STEP; /* adjust volume of actual sound sample */ if (playlist[i].volume != PSND_MAX_VOLUME) @@ -337,7 +373,7 @@ void SoundServer() playing_sounds--; } } - else if (playlist[i].volume <= PSND_MAX_VOLUME/10) + else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD) { playlist[i] = emptySoundControl; playing_sounds--; @@ -345,7 +381,7 @@ void SoundServer() } /* put last mixing buffer to final playing buffer */ - for(i=0;i fragment_size = 0x00020009 */ + + if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0) + Error(ERR_EXIT_SOUND_SERVER, + "cannot set fragment size of /dev/dsp -- no sounds"); + + /* try if we can use stereo sound */ + if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0) + { +#ifdef DEBUG + static boolean reported = FALSE; + + if (!reported) + { + Error(ERR_RETURN, "cannot get stereo sound on /dev/dsp"); + reported = TRUE; + } +#endif + stereo = FALSE; + } + + if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &sample_rate) < 0) + Error(ERR_EXIT_SOUND_SERVER, + "cannot set sample rate of /dev/dsp -- no sounds"); + + /* get the real fragmentation size; this should return 512 */ + if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size) < 0) + Error(ERR_EXIT_SOUND_SERVER, + "cannot get fragment size of /dev/dsp -- no sounds"); + + return (boolean)stereo; +} +#endif /* AUDIO_LINUX_IOCTL */ + +#if defined(PLATFORM_NETBSD) +static boolean InitAudioDevice_NetBSD(long fragment_size, int sample_rate) +{ + audio_info_t a_info; + boolean stereo = TRUE; + + AUDIO_INITINFO(&a_info); + a_info.play.encoding = AUDIO_ENCODING_LINEAR8; + a_info.play.precision = 8; + a_info.play.channels = 2; + a_info.play.sample_rate = sample_rate; + a_info.blocksize = fragment_size; + + if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0) + { + /* try to disable stereo */ + a_info.play.channels = 1; + stereo = FALSE; + + if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0) + Error(ERR_EXIT_SOUND_SERVER, + "cannot set sample rate of /dev/audio -- no sounds"); + } + + return stereo; +} +#endif /* PLATFORM_NETBSD */ + #if defined(PLATFORM_HPUX) -static void HPUX_Audio_Control() +static boolean InitAudioDevice_HPUX() { struct audio_describe ainfo; int audio_ctl; audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY); if (audio_ctl == -1) - Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl - no sounds"); + Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl -- no sounds"); if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1) - Error(ERR_EXIT_SOUND_SERVER, "no audio info - no sounds"); + Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds"); if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1) - Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available - no sounds"); + Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds"); ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1); ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000); close(audio_ctl); + + return TRUE; /* to provide common interface for InitAudioDevice_...() */ } #endif /* PLATFORM_HPUX */ @@ -785,67 +905,64 @@ static int ulaw_to_linear(unsigned char ulawbyte) } #endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */ -/*** THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/ -/*===========================================================================*/ +/* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */ +/* ========================================================================= */ +/* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */ -/*** THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS ***/ - -void AllocSoundArray(int num) -{ - num_sounds = num; - Sound = checked_calloc(num_sounds * sizeof(struct SampleInfo)); -} #define CHUNK_ID_LEN 4 /* IFF style chunk id length */ #define WAV_HEADER_SIZE 20 /* size of WAV file header */ -boolean LoadSound(int sound_nr, char *sound_name) +static boolean LoadSoundExt(char *sound_name, boolean is_music) { - struct SampleInfo *snd_info = &Sound[sound_nr]; - char filename[256]; - char *sound_ext = "wav"; -#if !defined(TARGET_SDL) -#if !defined(PLATFORM_MSDOS) + struct SampleInfo *snd_info; + char *filename; +#if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS) byte sound_header_buffer[WAV_HEADER_SIZE]; char chunk[CHUNK_ID_LEN + 1]; - int chunk_length, dummy; + int chunk_size, dummy; FILE *file; int i; #endif -#endif + if (!audio.sound_available) + return FALSE; + + num_sounds++; + Sound = checked_realloc(Sound, num_sounds * sizeof(struct SampleInfo)); + + snd_info = &Sound[num_sounds - 1]; snd_info->name = sound_name; - sprintf(filename, "%s/%s/%s.%s", - options.ro_base_directory, SOUNDS_DIRECTORY, - snd_info->name, sound_ext); + filename = getPath2((is_music ? options.music_directory : + options.sounds_directory), snd_info->name); #if defined(TARGET_SDL) - snd_info->mix_chunk = Mix_LoadWAV(filename); - if (snd_info->mix_chunk == NULL) + if ((snd_info->mix_chunk = Mix_LoadWAV(filename)) == NULL) { - Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename); + Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename); + free(filename); return FALSE; } -#else /* !TARGET_SDL */ - -#if !defined(PLATFORM_MSDOS) +#elif defined(PLATFORM_UNIX) - if ((file = fopen(filename, "r")) == NULL) + if ((file = fopen(filename, MODE_READ)) == NULL) { - Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename); + Error(ERR_WARN, "cannot open sound file '%s' -- no sounds", filename); + free(filename); return FALSE; } /* read chunk "RIFF" */ - getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_LITTLE_ENDIAN); + getFileChunk(file, chunk, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN); if (strcmp(chunk, "RIFF") != 0) { Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename); fclose(file); + free(filename); return FALSE; } @@ -855,6 +972,7 @@ boolean LoadSound(int sound_nr, char *sound_name) { Error(ERR_WARN, "missing 'WAVE' chunk of sound file '%s'", filename); fclose(file); + free(filename); return FALSE; } @@ -863,23 +981,25 @@ boolean LoadSound(int sound_nr, char *sound_name) sound_header_buffer[i] = fgetc(file); /* read chunk "data" */ - getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_LITTLE_ENDIAN); + getFileChunk(file, chunk, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN); if (strcmp(chunk, "data") != 0) { Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename); fclose(file); + free(filename); return FALSE; } - snd_info->data_len = chunk_length; + snd_info->data_len = chunk_size; snd_info->data_ptr = checked_malloc(snd_info->data_len); /* read sound data */ if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) != snd_info->data_len) { - Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename); + Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename); fclose(file); + free(filename); return FALSE; } @@ -893,14 +1013,116 @@ boolean LoadSound(int sound_nr, char *sound_name) snd_info->sample_ptr = load_sample(filename); if (!snd_info->sample_ptr) { - Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename); + Error(ERR_WARN, "cannot read sound file '%s' -- no sounds", filename); return FALSE; } -#endif /* PLATFORM_MSDOS */ -#endif /* !TARGET_SDL */ +#endif + + free(filename); + + return TRUE; +} + +boolean LoadSound(char *sound_name) +{ + return LoadSoundExt(sound_name, FALSE); +} + +boolean LoadMod(char *mod_name) +{ +#if defined(TARGET_SDL) + struct SampleInfo *mod_info; + char *filename; + + num_mods++; + Mod = checked_realloc(Mod, num_mods * sizeof(struct SampleInfo)); + + mod_info = &Mod[num_mods - 1]; + mod_info->name = mod_name; + + filename = getPath2(options.music_directory, mod_info->name); + + if ((mod_info->mix_music = Mix_LoadMUS(filename)) == NULL) + { + Error(ERR_WARN, "cannot read music file '%s' -- no music", filename); + free(filename); + return FALSE; + } + + free(filename); return TRUE; +#else + return FALSE; +#endif +} + +int LoadMusic(void) +{ + DIR *dir; + struct dirent *dir_entry; + int num_wav_music = 0; + int num_mod_music = 0; + + if (!audio.sound_available) + return 0; + + if ((dir = opendir(options.music_directory)) == NULL) + { + Error(ERR_WARN, "cannot read music directory '%s'", + options.music_directory); + audio.music_available = FALSE; + return 0; + } + + while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ + { + char *filename = dir_entry->d_name; + + if (FileIsSound(filename) && LoadSoundExt(filename, TRUE)) + num_wav_music++; + else if (FileIsMusic(filename) && LoadMod(filename)) + num_mod_music++; + } + + closedir(dir); + + if (num_wav_music == 0 && num_mod_music == 0) + Error(ERR_WARN, "cannot find any valid music files in directory '%s'", + options.music_directory); + + num_music = (num_mod_music > 0 ? num_mod_music : num_wav_music); + + audio.mods_available = (num_mod_music > 0); + audio.music_available = (num_music > 0); + + return num_music; +} + +void PlayMusic(int nr) +{ + if (!audio.music_available) + return; + + if (!audio.mods_available) + nr = num_sounds - num_music + nr; + +#if defined(TARGET_SDL) + if (audio.mods_available) /* play MOD music */ + { + Mix_PlayMusic(Mod[nr].mix_music, -1); + Mix_VolumeMusic(SOUND_MAX_VOLUME); /* must be _after_ Mix_PlayMusic()! */ + } + else /* play WAV music loop */ + { + Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME); + Mix_PlayChannel(audio.music_channel, Sound[nr].mix_chunk, -1); + } +#else + audio.music_nr = nr; + PlaySoundLoop(nr); +#endif } void PlaySound(int nr) @@ -944,23 +1166,32 @@ void PlaySoundExt(int nr, int volume, int stereo, boolean loop) snd_ctrl.data_len = Sound[nr].data_len; #if defined(TARGET_SDL) - - Mix_Volume(-1, SDL_MIX_MAXVOLUME / 4); - Mix_VolumeMusic(SDL_MIX_MAXVOLUME / 4); - + Mix_Volume(-1, SOUND_MAX_VOLUME); Mix_PlayChannel(-1, Sound[nr].mix_chunk, (loop ? -1 : 0)); - -#else -#if !defined(PLATFORM_MSDOS) +#elif defined(PLATFORM_UNIX) if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0) { - Error(ERR_WARN, "cannot pipe to child process - no sounds"); + Error(ERR_WARN, "cannot pipe to child process -- no sounds"); audio.sound_available = audio.sound_enabled = FALSE; return; } -#else +#elif defined(PLATFORM_MSDOS) sound_handler(snd_ctrl); #endif +} + +void FadeMusic(void) +{ +#if defined(TARGET_SDL) + if (!audio.sound_available) + return; + + if (audio.mods_available) + Mix_FadeOutMusic(SOUND_FADING_INTERVAL); + else + Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL); +#else + FadeSound(audio.music_nr); #endif } @@ -971,9 +1202,25 @@ void FadeSound(int nr) void FadeSounds() { + FadeMusic(); StopSoundExt(-1, SSND_FADE_ALL_SOUNDS); } +void StopMusic(void) +{ +#if defined(TARGET_SDL) + if (!audio.sound_available) + return; + + if (audio.mods_available) + Mix_HaltMusic(); + else + Mix_HaltChannel(audio.music_channel); +#else + StopSound(audio.music_nr); +#endif +} + void StopSound(int nr) { StopSoundExt(nr, SSND_STOP_SOUND); @@ -1006,20 +1253,30 @@ void StopSoundExt(int nr, int method) if (SSND_FADING(method)) { - Mix_FadeOutChannel(-1, 1000); - Mix_FadeOutMusic(1000); + int i; + + for (i=0; i