From beab4eb58b667a5883166bd1dd7bc33369a005c7 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 17 Jun 2007 18:40:02 +0000 Subject: Split i_sound.c into i_sdlsound.c, i_sdlmusic.c, with generic "sound driver" modules, one for PC speaker and one for digital output. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 913 --- pcsound/pcsound.c | 8 + pcsound/pcsound.h | 21 +- pcsound/pcsound_internal.h | 47 +++ pcsound/pcsound_linux.c | 1 + pcsound/pcsound_sdl.c | 63 +++- pcsound/pcsound_win32.c | 1 + src/Makefile.am | 7 +- src/d_main.c | 1 - src/deh_sound.c | 8 - src/i_music.h | 76 +++++ src/i_pcsound.c | 87 ++++- src/i_pcsound.h | 40 --- src/i_sdlmusic.c | 317 +++++++++++++++++++ src/i_sdlsound.c | 447 ++++++++++++++++++++++++++ src/i_sound.c | 767 --------------------------------------------- src/i_sound.h | 127 -------- src/s_sound.c | 235 +++++++++----- src/s_sound.h | 44 +++ 18 files changed, 1233 insertions(+), 1064 deletions(-) create mode 100644 pcsound/pcsound_internal.h create mode 100644 src/i_music.h delete mode 100644 src/i_pcsound.h create mode 100644 src/i_sdlmusic.c create mode 100644 src/i_sdlsound.c delete mode 100644 src/i_sound.c delete mode 100644 src/i_sound.h diff --git a/pcsound/pcsound.c b/pcsound/pcsound.c index 1491ff61..8c739b35 100644 --- a/pcsound/pcsound.c +++ b/pcsound/pcsound.c @@ -29,6 +29,7 @@ #include "config.h" #include "pcsound.h" +#include "pcsound_internal.h" #ifdef _WIN32 extern pcsound_driver_t pcsound_win32_driver; @@ -54,6 +55,13 @@ static pcsound_driver_t *drivers[] = static pcsound_driver_t *pcsound_driver = NULL; +int pcsound_sample_rate; + +void PCSound_SetSampleRate(int rate) +{ + pcsound_sample_rate = rate; +} + int PCSound_Init(pcsound_callback_func callback_func) { char *driver_name; diff --git a/pcsound/pcsound.h b/pcsound/pcsound.h index 12a4ffe9..e64796b8 100644 --- a/pcsound/pcsound.h +++ b/pcsound/pcsound.h @@ -26,22 +26,21 @@ #ifndef PCSOUND_H #define PCSOUND_H -#define PCSOUND_8253_FREQUENCY 1193280 - -typedef struct pcsound_driver_s pcsound_driver_t; typedef void (*pcsound_callback_func)(int *duration, int *frequency); -typedef int (*pcsound_init_func)(pcsound_callback_func callback); -typedef void (*pcsound_shutdown_func)(void); -struct pcsound_driver_s -{ - char *name; - pcsound_init_func init_func; - pcsound_shutdown_func shutdown_func; -}; +// Initialise the PC speaker subsystem. The given function is called +// periodically to request more sound data to play. int PCSound_Init(pcsound_callback_func callback_func); + +// Shut down the PC speaker subsystem. + void PCSound_Shutdown(void); +// Set the preferred output sample rate when emulating a PC speaker. +// This must be called before PCSound_Init. + +void PCSound_SetSampleRate(int rate); + #endif /* #ifndef PCSOUND_H */ diff --git a/pcsound/pcsound_internal.h b/pcsound/pcsound_internal.h new file mode 100644 index 00000000..c5ae90b6 --- /dev/null +++ b/pcsound/pcsound_internal.h @@ -0,0 +1,47 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2007 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// PC speaker interface. +// +//----------------------------------------------------------------------------- + +#ifndef PCSOUND_INTERNAL_H +#define PCSOUND_INTERNAL_H + +#include "pcsound.h" + +#define PCSOUND_8253_FREQUENCY 1193280 + +typedef struct pcsound_driver_s pcsound_driver_t; +typedef int (*pcsound_init_func)(pcsound_callback_func callback); +typedef void (*pcsound_shutdown_func)(void); + +struct pcsound_driver_s +{ + char *name; + pcsound_init_func init_func; + pcsound_shutdown_func shutdown_func; +}; + +extern int pcsound_sample_rate; + +#endif /* #ifndef PCSOUND_INTERNAL_H */ + diff --git a/pcsound/pcsound_linux.c b/pcsound/pcsound_linux.c index 7c1abc7b..02ab47b5 100644 --- a/pcsound/pcsound_linux.c +++ b/pcsound/pcsound_linux.c @@ -40,6 +40,7 @@ #include "SDL_thread.h" #include "pcsound.h" +#include "pcsound_internal.h" #define CONSOLE_DEVICE "/dev/console" diff --git a/pcsound/pcsound_sdl.c b/pcsound/pcsound_sdl.c index 50820394..f862dfa7 100644 --- a/pcsound/pcsound_sdl.c +++ b/pcsound/pcsound_sdl.c @@ -30,9 +30,17 @@ #include "SDL_mixer.h" #include "pcsound.h" +#include "pcsound_internal.h" #define SQUARE_WAVE_AMP 0x2000 +// If true, we initialised SDL and have the responsibility to shut it +// down + +static int sdl_was_initialised = 0; + +// Callback function to invoke when we want new sound data + static pcsound_callback_func callback; // Output sound format @@ -137,16 +145,57 @@ static void PCSound_Mix_Callback(void *udata, Uint8 *stream, int len) } } +static int SDLIsInitialised(void) +{ + int freq, channels; + Uint16 format; + + return Mix_QuerySpec(&freq, &format, &channels); +} + +static void PCSound_SDL_Shutdown(void) +{ + if (sdl_was_initialised) + { + Mix_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + sdl_was_initialised = 0; + } +} + static int PCSound_SDL_Init(pcsound_callback_func callback_func) { - // Check that SDL_mixer has been opened already - // If not, fail + // Check if SDL_mixer has been opened already + // If not, we must initialise it now - if (!Mix_QuerySpec(&mixing_freq, &mixing_format, &mixing_channels)) + if (!SDLIsInitialised()) { - return 0; + if (SDL_Init(SDL_INIT_AUDIO) < 0) + { + fprintf(stderr, "Unable to set up sound.\n"); + return 0; + } + + if (Mix_OpenAudio(pcsound_sample_rate, AUDIO_S16SYS, 2, 1024) < 0) + { + fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError()); + + SDL_QuitSubSystem(SDL_INIT_AUDIO); + return 0; + } + + SDL_PauseAudio(0); + + // When this module shuts down, it has the responsibility to + // shut down SDL. + + sdl_was_initialised = 1; } + // Get the mixer frequency, format and number of channels. + + Mix_QuerySpec(&mixing_freq, &mixing_format, &mixing_channels); + // Only supports AUDIO_S16SYS if (mixing_format != AUDIO_S16SYS || mixing_channels != 2) @@ -154,6 +203,8 @@ static int PCSound_SDL_Init(pcsound_callback_func callback_func) fprintf(stderr, "PCSound_SDL only supports native signed 16-bit LSB, " "stereo format!\n"); + + PCSound_SDL_Shutdown(); return 0; } @@ -166,10 +217,6 @@ static int PCSound_SDL_Init(pcsound_callback_func callback_func) return 1; } -static void PCSound_SDL_Shutdown(void) -{ -} - pcsound_driver_t pcsound_sdl_driver = { "SDL", diff --git a/pcsound/pcsound_win32.c b/pcsound/pcsound_win32.c index 48677d73..7976b444 100644 --- a/pcsound/pcsound_win32.c +++ b/pcsound/pcsound_win32.c @@ -29,6 +29,7 @@ #include #include "pcsound.h" +#include "pcsound_internal.h" static SDL_Thread *sound_thread_handle; static int sound_thread_running; diff --git a/src/Makefile.am b/src/Makefile.am index 75c08c05..031369a7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -95,6 +95,7 @@ r_sky.c r_sky.h \ r_state.h \ r_things.c r_things.h \ sounds.c sounds.h \ +s_sound.c s_sound.h \ st_lib.c st_lib.h \ st_stuff.c st_stuff.h \ tables.c tables.h \ @@ -146,9 +147,9 @@ w_merge.c w_merge.h FEATURE_SOUND_SOURCE_FILES = \ i_pcsound.c i_pcsound.h \ -i_sound.c i_sound.h \ -mus2mid.c mus2mid.h \ -s_sound.c s_sound.h +i_sdlsound.c \ +i_sdlmusic.c i_music.h \ +mus2mid.c mus2mid.h SOURCE_FILES = $(MAIN_SOURCE_FILES) \ $(FEATURE_DEHACKED_SOURCE_FILES) \ diff --git a/src/d_main.c b/src/d_main.c index 65cb6bb9..6981b884 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -59,7 +59,6 @@ #include "p_saveg.h" #include "i_system.h" -#include "i_sound.h" #include "i_timer.h" #include "i_video.h" diff --git a/src/deh_sound.c b/src/deh_sound.c index 7068d94a..761ed069 100644 --- a/src/deh_sound.c +++ b/src/deh_sound.c @@ -68,15 +68,7 @@ static void *DEH_SoundStart(deh_context_t *context, char *line) "in Vanilla dehacked.", sound_number); } -#ifdef FEATURE_SOUND - return &S_sfx[sound_number]; - -#else - - return NULL; - -#endif } static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag) diff --git a/src/i_music.h b/src/i_music.h new file mode 100644 index 00000000..70664c9a --- /dev/null +++ b/src/i_music.h @@ -0,0 +1,76 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// +// DESCRIPTION: +// System interface, music. +// +//----------------------------------------------------------------------------- + +#ifndef __I_SOUND__ +#define __I_SOUND__ + +#include "doomdef.h" + +#include "doomstat.h" +#include "sounds.h" +#include "s_sound.h" + +// +// MUSIC I/O +// + +void I_InitMusic(void); +void I_ShutdownMusic(void); + +// Volume. + +void I_SetMusicVolume(int volume); + +// PAUSE game handling. + +void I_PauseSong(void *handle); +void I_ResumeSong(void *handle); + +// Registers a song handle to song data. + +void *I_RegisterSong(void *data, int length); + +// Called by anything that wishes to start music. +// plays a song, and when the song is done, +// starts playing it again in an endless loop. +// Horrible thing to do, considering. + +void I_PlaySong(void *handle, int looping); + +// Stops a song over 3 seconds. + +void I_StopSong(void *handle); + +// See above (register), then think backwards + +void I_UnRegisterSong(void *handle); + +boolean I_QrySongPlaying(void *handle); + + +#endif + diff --git a/src/i_pcsound.c b/src/i_pcsound.c index 0dced9c1..08ba92e9 100644 --- a/src/i_pcsound.c +++ b/src/i_pcsound.c @@ -28,8 +28,8 @@ #include "doomdef.h" #include "doomtype.h" -#include "i_pcsound.h" -#include "i_sound.h" +#include "deh_main.h" +#include "s_sound.h" #include "sounds.h" #include "w_wad.h" @@ -62,7 +62,7 @@ static float frequencies[] = { #define NUM_FREQUENCIES (sizeof(frequencies) / sizeof(*frequencies)) -void PCSCallbackFunc(int *duration, int *freq) +static void PCSCallbackFunc(int *duration, int *freq) { int tone; @@ -144,12 +144,10 @@ static boolean CachePCSLump(int sound_id) return true; } -int I_PCS_StartSound(int id, - int channel, - int vol, - int sep, - int pitch, - int priority) +static int I_PCS_StartSound(int id, + int channel, + int vol, + int sep) { int result; @@ -192,7 +190,7 @@ int I_PCS_StartSound(int id, } } -void I_PCS_StopSound(int handle) +static void I_PCS_StopSound(int handle) { if (!pcs_initialised) { @@ -214,7 +212,22 @@ void I_PCS_StopSound(int handle) SDL_UnlockMutex(sound_lock); } -int I_PCS_SoundIsPlaying(int handle) +// +// Retrieve the raw data lump index +// for a given SFX name. +// + +static int I_PCS_GetSfxLumpNum(sfxinfo_t* sfx) +{ + char namebuf[9]; + + sprintf(namebuf, "dp%s", DEH_String(sfx->name)); + + return W_GetNumForName(namebuf); +} + + +static boolean I_PCS_SoundIsPlaying(int handle) { if (!pcs_initialised) { @@ -229,10 +242,58 @@ int I_PCS_SoundIsPlaying(int handle) return current_sound_lump != NULL && current_sound_remaining > 0; } -void I_PCS_InitSound(void) +static boolean I_PCS_InitSound(void) { + // Use the sample rate from the configuration file + + PCSound_SetSampleRate(snd_samplerate); + + // Initialise the PC speaker subsystem. + pcs_initialised = PCSound_Init(PCSCallbackFunc); - sound_lock = SDL_CreateMutex(); + if (pcs_initialised) + { + sound_lock = SDL_CreateMutex(); + } + + return pcs_initialised; +} + +static void I_PCS_ShutdownSound(void) +{ + if (pcs_initialised) + { + PCSound_Shutdown(); + } +} + +static void I_PCS_UpdateSound(void) +{ + // no-op. +} + +void I_PCS_UpdateSoundParams(int channel, int vol, int sep) +{ + // no-op. } +static snddevice_t sound_pcsound_devices[] = +{ + SNDDEVICE_PCSPEAKER, +}; + +sound_module_t sound_pcsound_module = +{ + sound_pcsound_devices, + sizeof(sound_pcsound_devices) / sizeof(*sound_pcsound_devices), + I_PCS_InitSound, + I_PCS_ShutdownSound, + I_PCS_GetSfxLumpNum, + I_PCS_UpdateSound, + I_PCS_UpdateSoundParams, + I_PCS_StartSound, + I_PCS_StopSound, + I_PCS_SoundIsPlaying, +}; + diff --git a/src/i_pcsound.h b/src/i_pcsound.h deleted file mode 100644 index 601f4ee5..00000000 --- a/src/i_pcsound.h +++ /dev/null @@ -1,40 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2007 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -// DESCRIPTION: -// System interface for PC speaker sound. -// -//----------------------------------------------------------------------------- - -#ifndef __I_PCSOUND_H__ -#define __I_PCSOUND_H__ - -int I_PCS_StartSound(int id, - int channel, - int vol, - int sep, - int pitch, - int priority); -void I_PCS_StopSound(int handle); -int I_PCS_SoundIsPlaying(int handle); -void I_PCS_InitSound(void); - -#endif /* #ifndef __I_PCSOUND_H__ */ - diff --git a/src/i_sdlmusic.c b/src/i_sdlmusic.c new file mode 100644 index 00000000..d2471578 --- /dev/null +++ b/src/i_sdlmusic.c @@ -0,0 +1,317 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// System interface for music. +// +//----------------------------------------------------------------------------- + + +#include +#include +#include "SDL.h" +#include "SDL_mixer.h" + +#include "doomdef.h" +#include "memio.h" +#include "mus2mid.h" + +#include "deh_main.h" +#include "m_misc.h" +#include "s_sound.h" +#include "w_wad.h" +#include "z_zone.h" + +#define MAXMIDLENGTH (96 * 1024) + +static boolean music_initialised = false; + +// If this is true, this module initialised SDL sound and has the +// responsibility to shut it down + +static boolean sdl_was_initialised = false; + +static boolean musicpaused = false; +static int current_music_volume; + +void I_ShutdownMusic(void) +{ + if (music_initialised) + { + Mix_HaltMusic(); + music_initialised = false; + + if (sdl_was_initialised) + { + Mix_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + sdl_was_initialised = false; + } + } +} + +static boolean SDLIsInitialised(void) +{ + int freq, channels; + Uint16 format; + + return Mix_QuerySpec(&freq, &format, &channels) != 0; +} + +void I_InitMusic() +{ + // When trying to run with music enabled on OSX, display + // a warning message. + +#ifdef __MACOSX__ + printf("\n" + " *** WARNING ***\n" + " Music playback on OSX may cause crashes and\n" + " is disabled by default.\n" + "\n"); +#endif + + // If SDL_mixer is not initialised, we have to initialise it + // and have the responsibility to shut it down later on. + + if (!SDLIsInitialised()) + { + if (SDL_Init(SDL_INIT_AUDIO) < 0) + { + fprintf(stderr, "Unable to set up sound.\n"); + return; + } + + if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0) + { + fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError()); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + return; + } + + SDL_PauseAudio(0); + + sdl_was_initialised = true; + } + + music_initialised = true; +} + +// +// SDL_mixer's native MIDI music playing does not pause properly. +// As a workaround, set the volume to 0 when paused. +// + +static void UpdateMusicVolume(void) +{ + int vol; + + if (musicpaused) + { + vol = 0; + } + else + { + vol = (current_music_volume * MIX_MAX_VOLUME) / 127; + } + + Mix_VolumeMusic(vol); +} + +// MUSIC API - dummy. Some code from DOS version. +void I_SetMusicVolume(int volume) +{ + // Internal state variable. + current_music_volume = volume; + + UpdateMusicVolume(); +} + +void I_PlaySong(void *handle, int looping) +{ + Mix_Music *music = (Mix_Music *) handle; + int loops; + + if (!music_initialised) + { + return; + } + + if (handle == NULL) + { + return; + } + + if (looping) + { + loops = -1; + } + else + { + loops = 1; + } + + Mix_PlayMusic(music, loops); +} + +void I_PauseSong (void *handle) +{ + if (!music_initialised) + { + return; + } + + musicpaused = true; + + UpdateMusicVolume(); +} + +void I_ResumeSong (void *handle) +{ + if (!music_initialised) + { + return; + } + + musicpaused = false; + + UpdateMusicVolume(); +} + +void I_StopSong(void *handle) +{ + if (!music_initialised) + { + return; + } + + Mix_HaltMusic(); +} + +void I_UnRegisterSong(void *handle) +{ + Mix_Music *music = (Mix_Music *) handle; + + if (!music_initialised) + { + return; + } + + if (handle == NULL) + { + return; + } + + Mix_FreeMusic(music); +} + +// Determine whether memory block is a .mid file + +static boolean IsMid(byte *mem, int len) +{ + return len > 4 && !memcmp(mem, "MThd", 4); +} + +static boolean ConvertMus(byte *musdata, int len, char *filename) +{ + MEMFILE *instream; + MEMFILE *outstream; + void *outbuf; + size_t outbuf_len; + int result; + + instream = mem_fopen_read(musdata, len); + outstream = mem_fopen_write(); + + result = mus2mid(instream, outstream); + + if (result == 0) + { + mem_get_buf(outstream, &outbuf, &outbuf_len); + + M_WriteFile(filename, outbuf, outbuf_len); + } + + mem_fclose(instream); + mem_fclose(outstream); + + return result; +} + +void *I_RegisterSong(void *data, int len) +{ + char *filename; + Mix_Music *music; + + if (!music_initialised) + { + return NULL; + } + + // MUS files begin with "MUS" + // Reject anything which doesnt have this signature + + filename = M_TempFile("doom.mid"); + + if (IsMid(data, len) && len < MAXMIDLENGTH) + { + M_WriteFile(filename, data, len); + } + else + { + // Assume a MUS file and try to convert + + ConvertMus(data, len, filename); + } + + // Load the MIDI + + music = Mix_LoadMUS(filename); + + if (music == NULL) + { + // Failed to load + + fprintf(stderr, "Error loading midi: %s\n", Mix_GetError()); + } + + // remove file now + + remove(filename); + + Z_Free(filename); + + return music; +} + +// Is the song playing? +boolean I_QrySongPlaying(void *handle) +{ + if (!music_initialised) + { + return false; + } + + return Mix_PlayingMusic(); +} + + + diff --git a/src/i_sdlsound.c b/src/i_sdlsound.c new file mode 100644 index 00000000..920e74d2 --- /dev/null +++ b/src/i_sdlsound.c @@ -0,0 +1,447 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// System interface for sound. +// +//----------------------------------------------------------------------------- + + +#include +#include +#include "SDL.h" +#include "SDL_mixer.h" + +#include "deh_main.h" +#include "s_sound.h" +#include "m_argv.h" +#include "w_wad.h" +#include "z_zone.h" + +#include "doomdef.h" + +#define NUM_CHANNELS 16 + +static boolean sound_initialised = false; + +static Mix_Chunk sound_chunks[NUMSFX]; +static int channels_playing[NUM_CHANNELS]; + +static int mixer_freq; +static Uint16 mixer_format; +static int mixer_channels; + +// When a sound stops, check if it is still playing. If it is not, +// we can mark the sound data as CACHE to be freed back for other +// means. + +static void ReleaseSoundOnChannel(int channel) +{ + int i; + int id = channels_playing[channel]; + + if (!id) + { + return; + } + + channels_playing[channel] = sfx_None; + + for (i=0; i freq2) + { + return ConvertibleRatio(freq2, freq1); + } + else if ((freq2 % freq1) != 0) + { + // Not in a direct ratio + + return false; + } + else + { + // Check the ratio is a power of 2 + + ratio = freq2 / freq1; + + while ((ratio & 1) == 0) + { + ratio = ratio >> 1; + } + + return ratio == 1; + } +} + +// Generic sound expansion function for any sample rate + +static void ExpandSoundData(byte *data, + int samplerate, + int length, + Mix_Chunk *destination) +{ + SDL_AudioCVT convertor; + + if (samplerate <= mixer_freq + && ConvertibleRatio(samplerate, mixer_freq) + && SDL_BuildAudioCVT(&convertor, + AUDIO_U8, 1, samplerate, + mixer_format, mixer_channels, mixer_freq)) + { + convertor.buf = destination->abuf; + convertor.len = length; + memcpy(convertor.buf, data, length); + + SDL_ConvertAudio(&convertor); + } + else + { + Sint16 *expanded = (Sint16 *) destination->abuf; + int expanded_length; + int expand_ratio; + int i; + + // Generic expansion if conversion does not work: + // + // SDL's audio conversion only works for rate conversions that are + // powers of 2; if the two formats are not in a direct power of 2 + // ratio, do this naive conversion instead. + + // number of samples in the converted sound + + expanded_length = (length * mixer_freq) / samplerate; + expand_ratio = (length << 8) / expanded_length; + + for (i=0; i> 8; + + sample = data[src] | (data[src] << 8); + sample -= 32768; + + // expand 8->16 bits, mono->stereo + + expanded[i * 2] = expanded[i * 2 + 1] = sample; + } + } +} + +// Load and convert a sound effect +// Returns true if successful + +static boolean CacheSFX(int sound) +{ + int lumpnum; + unsigned int lumplen; + int samplerate; + unsigned int length; + unsigned int expanded_length; + byte *data; + + // need to load the sound + + lumpnum = S_sfx[sound].lumpnum; + data = W_CacheLumpNum(lumpnum, PU_STATIC); + lumplen = W_LumpLength(lumpnum); + + // Check the header, and ensure this is a valid sound + + if (lumplen < 8 + || data[0] != 0x03 || data[1] != 0x00) + { + // Invalid sound + + return false; + } + + // 16 bit sample rate field, 32 bit length field + + samplerate = (data[3] << 8) | data[2]; + length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4]; + + // If the header specifies that the length of the sound is greater than + // the length of the lump itself, this is an invalid sound lump + + if (length - 8 > lumplen) + { + return false; + } + + expanded_length = (uint32_t) ((((uint64_t) length) * 4 * mixer_freq) / samplerate); + + sound_chunks[sound].allocated = 1; + sound_chunks[sound].alen = expanded_length; + sound_chunks[sound].abuf + = Z_Malloc(expanded_length, PU_STATIC, &sound_chunks[sound].abuf); + sound_chunks[sound].volume = MIX_MAX_VOLUME; + + ExpandSoundData(data + 8, + samplerate, + length - 8, + &sound_chunks[sound]); + + // don't need the original lump any more + + Z_ChangeTag(data, PU_CACHE); + + return true; +} + +static Mix_Chunk *GetSFXChunk(int sound_id) +{ + if (sound_chunks[sound_id].abuf == NULL) + { + if (!CacheSFX(sound_id)) + return NULL; + } + else + { + // don't free the sound while it is playing! + + Z_ChangeTag(sound_chunks[sound_id].abuf, PU_STATIC); + } + + return &sound_chunks[sound_id]; +} + + +// +// Retrieve the raw data lump index +// for a given SFX name. +// + +static int I_SDL_GetSfxLumpNum(sfxinfo_t* sfx) +{ + char namebuf[9]; + + sprintf(namebuf, "ds%s", DEH_String(sfx->name)); + + return W_GetNumForName(namebuf); +} + +static void I_SDL_UpdateSoundParams(int handle, int vol, int sep) +{ + int left, right; + + if (!sound_initialised) + { + return; + } + + left = ((254 - sep) * vol) / 127; + right = ((sep) * vol) / 127; + + Mix_SetPanning(handle, left, right); +} + + +// +// Starting a sound means adding it +// to the current list of active sounds +// in the internal channels. +// As the SFX info struct contains +// e.g. a pointer to the raw data, +// it is ignored. +// As our sound handling does not handle +// priority, it is ignored. +// Pitching (that is, increased speed of playback) +// is set, but currently not used by mixing. +// + +static int I_SDL_StartSound(int id, int channel, int vol, int sep) +{ + Mix_Chunk *chunk; + + if (!sound_initialised) + { + return -1; + } + + // Release a sound effect if there is already one playing + // on this channel + + ReleaseSoundOnChannel(channel); + + // Get the sound data + + chunk = GetSFXChunk(id); + + if (chunk == NULL) + { + return -1; + } + + // play sound + + Mix_PlayChannelTimed(channel, chunk, 0, -1); + + channels_playing[channel] = id; + + // set separation, etc. + + I_SDL_UpdateSoundParams(channel, vol, sep); + + return channel; +} + +static void I_SDL_StopSound (int handle) +{ + if (!sound_initialised) + { + return; + } + + Mix_HaltChannel(handle); + + // Sound data is no longer needed; release the + // sound data being used for this channel + + ReleaseSoundOnChannel(handle); +} + + +static boolean I_SDL_SoundIsPlaying(int handle) +{ + if (handle < 0) + { + return false; + } + + return Mix_Playing(handle); +} + +// +// Periodically called to update the sound system +// + +static void I_SDL_UpdateSound(void) +{ + int i; + + // Check all channels to see if a sound has finished + + for (i=0; i -#include -#include "SDL.h" -#include "SDL_mixer.h" - -#ifndef _WIN32 -#include -#endif - -#include "memio.h" -#include "mus2mid.h" -#include "z_zone.h" - -#include "i_system.h" -#include "i_pcsound.h" -#include "i_sound.h" -#include "i_swap.h" -#include "deh_main.h" -#include "s_sound.h" -#include "m_argv.h" -#include "m_misc.h" -#include "w_wad.h" - -#include "doomdef.h" - -#define NUM_CHANNELS 16 - -#define MAXMIDLENGTH (96 * 1024) - -static boolean nosfxparm; -static boolean nomusicparm; - -static boolean sound_initialised = false; -static boolean music_initialised = false; - -static Mix_Chunk sound_chunks[NUMSFX]; -static int channels_playing[NUM_CHANNELS]; - -static int mixer_freq; -static Uint16 mixer_format; -static int mixer_channels; - -int snd_samplerate = MIX_DEFAULT_FREQUENCY; - -// When a sound stops, check if it is still playing. If it is not, -// we can mark the sound data as CACHE to be freed back for other -// means. - -void ReleaseSoundOnChannel(int channel) -{ - int i; - int id = channels_playing[channel]; - - if (!id) - return; - - channels_playing[channel] = sfx_None; - - for (i=0; i freq2) - { - return ConvertibleRatio(freq2, freq1); - } - else if ((freq2 % freq1) != 0) - { - // Not in a direct ratio - - return false; - } - else - { - // Check the ratio is a power of 2 - - ratio = freq2 / freq1; - - while ((ratio & 1) == 0) - { - ratio = ratio >> 1; - } - - return ratio == 1; - } -} - -// Generic sound expansion function for any sample rate - -static void ExpandSoundData(byte *data, - int samplerate, - int length, - Mix_Chunk *destination) -{ - SDL_AudioCVT convertor; - - if (samplerate <= mixer_freq - && ConvertibleRatio(samplerate, mixer_freq) - && SDL_BuildAudioCVT(&convertor, - AUDIO_U8, 1, samplerate, - mixer_format, mixer_channels, mixer_freq)) - { - convertor.buf = destination->abuf; - convertor.len = length; - memcpy(convertor.buf, data, length); - - SDL_ConvertAudio(&convertor); - } - else - { - Sint16 *expanded = (Sint16 *) destination->abuf; - int expanded_length; - int expand_ratio; - int i; - - // Generic expansion if conversion does not work: - // - // SDL's audio conversion only works for rate conversions that are - // powers of 2; if the two formats are not in a direct power of 2 - // ratio, do this naive conversion instead. - - // number of samples in the converted sound - - expanded_length = (length * mixer_freq) / samplerate; - expand_ratio = (length << 8) / expanded_length; - - for (i=0; i> 8; - - sample = data[src] | (data[src] << 8); - sample -= 32768; - - // expand 8->16 bits, mono->stereo - - expanded[i * 2] = expanded[i * 2 + 1] = sample; - } - } -} - -// Load and convert a sound effect -// Returns true if successful - -static boolean CacheSFX(int sound) -{ - int lumpnum; - unsigned int lumplen; - int samplerate; - unsigned int length; - unsigned int expanded_length; - byte *data; - - // need to load the sound - - lumpnum = S_sfx[sound].lumpnum; - data = W_CacheLumpNum(lumpnum, PU_STATIC); - lumplen = W_LumpLength(lumpnum); - - // Check the header, and ensure this is a valid sound - - if (lumplen < 8 - || data[0] != 0x03 || data[1] != 0x00) - { - // Invalid sound - - return false; - } - - // 16 bit sample rate field, 32 bit length field - - samplerate = (data[3] << 8) | data[2]; - length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4]; - - // If the header specifies that the length of the sound is greater than - // the length of the lump itself, this is an invalid sound lump - - if (length - 8 > lumplen) - { - return false; - } - - expanded_length = (uint32_t) ((((uint64_t) length) * 4 * mixer_freq) / samplerate); - - sound_chunks[sound].allocated = 1; - sound_chunks[sound].alen = expanded_length; - sound_chunks[sound].abuf - = Z_Malloc(expanded_length, PU_STATIC, &sound_chunks[sound].abuf); - sound_chunks[sound].volume = MIX_MAX_VOLUME; - - ExpandSoundData(data + 8, - samplerate, - length - 8, - &sound_chunks[sound]); - - // don't need the original lump any more - - Z_ChangeTag(data, PU_CACHE); - - return true; -} - -static Mix_Chunk *GetSFXChunk(int sound_id) -{ - if (sound_chunks[sound_id].abuf == NULL) - { - if (!CacheSFX(sound_id)) - return NULL; - } - else - { - // don't free the sound while it is playing! - - Z_ChangeTag(sound_chunks[sound_id].abuf, PU_STATIC); - } - - return &sound_chunks[sound_id]; -} - - -// -// Retrieve the raw data lump index -// for a given SFX name. -// - -int I_GetSfxLumpNum(sfxinfo_t* sfx) -{ - char namebuf[9]; - char *prefix; - - // Different prefix for PC speaker sound effects. - - if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) - { - prefix = "dp"; - } - else - { - prefix = "ds"; - } - - sprintf(namebuf, "%s%s", prefix, DEH_String(sfx->name)); - - return W_GetNumForName(namebuf); -} - -// -// Starting a sound means adding it -// to the current list of active sounds -// in the internal channels. -// As the SFX info struct contains -// e.g. a pointer to the raw data, -// it is ignored. -// As our sound handling does not handle -// priority, it is ignored. -// Pitching (that is, increased speed of playback) -// is set, but currently not used by mixing. -// - -int -I_StartSound -( int id, - int channel, - int vol, - int sep, - int pitch, - int priority ) -{ - Mix_Chunk *chunk; - - if (!sound_initialised) - return 0; - - if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) - { - return I_PCS_StartSound(id, channel, vol, sep, pitch, priority); - } - - // Release a sound effect if there is already one playing - // on this channel - - ReleaseSoundOnChannel(channel); - - // Get the sound data - - chunk = GetSFXChunk(id); - - if (chunk == NULL) - { - return -1; - } - - // play sound - - Mix_PlayChannelTimed(channel, chunk, 0, -1); - - channels_playing[channel] = id; - - // set separation, etc. - - I_UpdateSoundParams(channel, vol, sep, pitch); - - return channel; -} - -void I_StopSound (int handle) -{ - if (!sound_initialised) - return; - - if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) - { - I_PCS_StopSound(handle); - return; - } - - Mix_HaltChannel(handle); - - // Sound data is no longer needed; release the - // sound data being used for this channel - - ReleaseSoundOnChannel(handle); -} - - -int I_SoundIsPlaying(int handle) -{ - if (!sound_initialised) - return false; - - if (handle < 0) - return false; - - if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) - { - return I_PCS_SoundIsPlaying(handle); - } - else - { - return Mix_Playing(handle); - } -} - - - - -// -// Periodically called to update the sound system -// - -void I_UpdateSound( void ) -{ - int i; - - if (!sound_initialised) - return; - - if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) - { - return; - } - - // Check all channels to see if a sound has finished - - for (i=0; i 0; - - if (snd_musicdevice < SNDDEVICE_ADLIB) - { - nomusicparm = true; - } - - //! - // Disable sound effects. - // - - nosfxparm = M_CheckParm("-nosfx") > 0; - - // If the SFX device is 0 (none), then disable sound effects, - // just like if we specified -nosfx. However, we still continue - // with initialising digital sound output even if we are using - // the PC speaker, because we might be using the SDL PC speaker - // emulation. - - if (snd_sfxdevice == SNDDEVICE_NONE) - { - nosfxparm = true; - } - - //! - // Disable sound effects and music. - // - - if (M_CheckParm("-nosound") > 0) - { - nosfxparm = true; - nomusicparm = true; - } - - // When trying to run with music enabled on OSX, display - // a warning message. - -#ifdef __MACOSX__ - if (!nomusicparm) - { - printf("\n" - " *** WARNING ***\n" - " Music playback on OSX may cause crashes and\n" - " is disabled by default.\n" - "\n"); - } -#endif - - // If music or sound is going to play, we need to at least - // initialise SDL - // No sound in screensaver mode. - - if (screensaver_mode || (nomusicparm && nosfxparm)) - return; - - if (SDL_Init(SDL_INIT_AUDIO) < 0) - { - fprintf(stderr, "Unable to set up sound.\n"); - return; - } - - if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0) - { - fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError()); - return; - } - - Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels); - - Mix_AllocateChannels(NUM_CHANNELS); - - SDL_PauseAudio(0); - - // If we are using the PC speaker, we now need to initialise it. - - if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) - { - I_PCS_InitSound(); - } - - if (!nomusicparm) - music_initialised = true; - - if (!nosfxparm) - sound_initialised = true; -} - - - - -// -// MUSIC API. -// - -static boolean musicpaused = false; -static int currentMusicVolume; - -// -// SDL_mixer's native MIDI music playing does not pause properly. -// As a workaround, set the volume to 0 when paused. -// - -static void UpdateMusicVolume(void) -{ - int vol; - - if (musicpaused) - vol = 0; - else - vol = (currentMusicVolume * MIX_MAX_VOLUME) / 127; - - Mix_VolumeMusic(vol); -} - -// MUSIC API - dummy. Some code from DOS version. -void I_SetMusicVolume(int volume) -{ - // Internal state variable. - currentMusicVolume = volume; - - UpdateMusicVolume(); -} - -void I_PlaySong(void *handle, int looping) -{ - Mix_Music *music = (Mix_Music *) handle; - int loops; - - if (!music_initialised) - return; - - if (handle == NULL) - return; - - if (looping) - loops = -1; - else - loops = 1; - - Mix_PlayMusic(music, loops); -} - -void I_PauseSong (void *handle) -{ - if (!music_initialised) - return; - - musicpaused = true; - - UpdateMusicVolume(); -} - -void I_ResumeSong (void *handle) -{ - if (!music_initialised) - return; - - musicpaused = false; - - UpdateMusicVolume(); -} - -void I_StopSong(void *handle) -{ - if (!music_initialised) - return; - - Mix_HaltMusic(); -} - -void I_UnRegisterSong(void *handle) -{ - Mix_Music *music = (Mix_Music *) handle; - - if (!music_initialised) - return; - - if (handle == NULL) - return; - - Mix_FreeMusic(music); -} - -// Determine whether memory block is a .mid file - -static boolean IsMid(byte *mem, int len) -{ - return len > 4 && !memcmp(mem, "MThd", 4); -} - -static boolean ConvertMus(byte *musdata, int len, char *filename) -{ - MEMFILE *instream; - MEMFILE *outstream; - void *outbuf; - size_t outbuf_len; - int result; - - instream = mem_fopen_read(musdata, len); - outstream = mem_fopen_write(); - - result = mus2mid(instream, outstream); - - if (result == 0) - { - mem_get_buf(outstream, &outbuf, &outbuf_len); - - M_WriteFile(filename, outbuf, outbuf_len); - } - - mem_fclose(instream); - mem_fclose(outstream); - - return result; -} - -void *I_RegisterSong(void *data, int len) -{ - char *filename; - Mix_Music *music; - - if (!music_initialised) - return NULL; - - // MUS files begin with "MUS" - // Reject anything which doesnt have this signature - - filename = M_TempFile("doom.mid"); - - if (IsMid(data, len) && len < MAXMIDLENGTH) - { - M_WriteFile(filename, data, len); - } - else - { - // Assume a MUS file and try to convert - - ConvertMus(data, len, filename); - } - - // Load the MIDI - - music = Mix_LoadMUS(filename); - - if (music == NULL) - { - // Failed to load - - fprintf(stderr, "Error loading midi: %s\n", Mix_GetError()); - } - - // remove file now - - remove(filename); - - Z_Free(filename); - - return music; -} - -// Is the song playing? -boolean I_QrySongPlaying(void *handle) -{ - if (!music_initialised) - return false; - - return Mix_PlayingMusic(); -} - - - diff --git a/src/i_sound.h b/src/i_sound.h deleted file mode 100644 index ad3852ce..00000000 --- a/src/i_sound.h +++ /dev/null @@ -1,127 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 1993-1996 Id Software, Inc. -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -// -// DESCRIPTION: -// System interface, sound. -// -//----------------------------------------------------------------------------- - -#ifndef __I_SOUND__ -#define __I_SOUND__ - -#include "doomdef.h" - -#include "doomstat.h" -#include "sounds.h" - - - -// Init at program start... -void I_InitSound(); - -// ... update sound buffer and audio device at runtime... -void I_UpdateSound(void); -void I_SubmitSound(void); - -// ... shut down and relase at program termination. -void I_ShutdownSound(void); - - -// -// SFX I/O -// - -// Initialize channels? -void I_SetChannels(); - -// Get raw data lump index for sound descriptor. -int I_GetSfxLumpNum (sfxinfo_t* sfxinfo ); - - -// Starts a sound in a particular sound channel. -int -I_StartSound -( int id, - int channel, - int vol, - int sep, - int pitch, - int priority ); - - -// Stops a sound channel. -void I_StopSound(int handle); - -// Called by S_*() functions -// to see if a channel is still playing. -// Returns 0 if no longer playing, 1 if playing. -int I_SoundIsPlaying(int handle); - -// Updates the volume, separation, -// and pitch of a sound channel. -void -I_UpdateSoundParams -( int handle, - int vol, - int sep, - int pitch ); - - -// -// MUSIC I/O -// - -void I_InitMusic(void); -void I_ShutdownMusic(void); - -// Volume. - -void I_SetMusicVolume(int volume); - -// PAUSE game handling. - -void I_PauseSong(void *handle); -void I_ResumeSong(void *handle); - -// Registers a song handle to song data. - -void *I_RegisterSong(void *data, int length); - -// Called by anything that wishes to start music. -// plays a song, and when the song is done, -// starts playing it again in an endless loop. -// Horrible thing to do, considering. - -void I_PlaySong(void *handle, int looping); - -// Stops a song over 3 seconds. - -void I_StopSong(void *handle); - -// See above (register), then think backwards - -void I_UnRegisterSong(void *handle); - -boolean I_QrySongPlaying(void *handle); - - -#endif diff --git a/src/s_sound.c b/src/s_sound.c index 1477415e..52462258 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -26,20 +26,24 @@ #include #include +#include "i_music.h" #include "i_system.h" -#include "i_sound.h" + +#include "doomfeatures.h" +#include "deh_main.h" + +#include "doomstat.h" +#include "doomdef.h" + #include "sounds.h" #include "s_sound.h" -#include "deh_main.h" -#include "z_zone.h" #include "m_random.h" -#include "w_wad.h" +#include "m_argv.h" -#include "doomdef.h" #include "p_local.h" - -#include "doomstat.h" +#include "w_wad.h" +#include "z_zone.h" // when to clip out sounds // Does not fit the large outdoor areas. @@ -74,10 +78,6 @@ #define DEFAULT_MUSIC_DEVICE SNDDEVICE_NONE #endif -int snd_musicdevice = DEFAULT_MUSIC_DEVICE; -int snd_sfxdevice = SNDDEVICE_SB; - - typedef struct { // sound information (if null, channel avail.) @@ -91,6 +91,9 @@ typedef struct } channel_t; +// Low-level sound module we are using + +static sound_module_t *sound_module; // The set of channels available @@ -105,6 +108,10 @@ int sfxVolume = 8; int musicVolume = 8; +// Sound sample rate to use for digital output (Hz) + +int snd_samplerate = 22050; + // Internal volume level, ranging from 0-127 static int snd_SfxVolume; @@ -121,6 +128,81 @@ static musicinfo_t *mus_playing = NULL; int numChannels = 8; +int snd_musicdevice = DEFAULT_MUSIC_DEVICE; +int snd_sfxdevice = SNDDEVICE_SB; + +// Sound effect modules + +extern sound_module_t sound_sdl_module; +extern sound_module_t sound_pcsound_module; + +// Compiled-in sound modules: + +static sound_module_t *sound_modules[] = +{ +#ifdef FEATURE_SOUND + &sound_sdl_module, + &sound_pcsound_module, +#endif +}; + +// Check if a sound device is in the given list of devices + +static boolean SndDeviceInList(snddevice_t device, snddevice_t *list, + int len) +{ + int i; + + for (i=0; isound_devices, + sound_modules[i]->num_sound_devices)) + { + // Initialise the module + + if (sound_modules[i]->Init()) + { + sound_module = sound_modules[i]; + return; + } + } + } +} + +// Initialise music according to snd_musicdevice. + +static void InitMusicModule(void) +{ + if (snd_musicdevice >= SNDDEVICE_ADLIB) + { + I_InitMusic(); + } +} + // // Initializes sound stuff, including volume // Sets channels, SFX and music volume, @@ -131,7 +213,20 @@ void S_Init(int sfxVolume, int musicVolume) { int i; - I_InitSound(); + // Initialise the sound and music subsystems. + + if (M_CheckParm("-nosound") <= 0 && !screensaver_mode) + { + if (M_CheckParm("-nosfx") <= 0) + { + InitSfxModule(); + } + + if (M_CheckParm("-nomusic") <= 0) + { + InitMusicModule(); + } + } S_SetSfxVolume(sfxVolume); S_SetMusicVolume(musicVolume); @@ -159,7 +254,12 @@ void S_Init(int sfxVolume, int musicVolume) void S_Shutdown(void) { - I_ShutdownSound(); + if (sound_module != NULL) + { + sound_module->Shutdown(); + } + + I_ShutdownMusic(); } static void S_StopChannel(int cnum) @@ -172,9 +272,13 @@ static void S_StopChannel(int cnum) if (c->sfxinfo) { // stop the sound playing - if (I_SoundIsPlaying(c->handle)) + + if (sound_module != NULL) { - I_StopSound(c->handle); + if (sound_module->SoundIsPlaying(c->handle)) + { + sound_module->StopSound(c->handle); + } } // check to see if other channels are playing the sound @@ -228,15 +332,15 @@ void S_Start(void) { // Song - Who? - Where? - mus_e3m4, // American e4m1 - mus_e3m2, // Romero e4m2 + mus_e3m4, // American e4m1 + mus_e3m2, // Romero e4m2 mus_e3m3, // Shawn e4m3 - mus_e1m5, // American e4m4 - mus_e2m7, // Tim e4m5 - mus_e2m4, // Romero e4m6 - mus_e2m6, // J.Anderson e4m7 CHIRON.WAD + mus_e1m5, // American e4m4 + mus_e2m7, // Tim e4m5 + mus_e2m4, // Romero e4m6 + mus_e2m6, // J.Anderson e4m7 CHIRON.WAD mus_e2m5, // Shawn e4m8 - mus_e1m9 // Tim e4m9 + mus_e1m9, // Tim e4m9 }; if (gameepisode < 4) @@ -326,14 +430,14 @@ static int S_GetChannel(mobj_t *origin, sfxinfo_t *sfxinfo) } // -// Changes volume, stereo-separation, and pitch variables +// Changes volume and stereo-separation variables // from the norm of a sound effect to be played. // If the sound is not audible, returns a 0. // Otherwise, modifies parameters and returns 1. // static int S_AdjustSoundParams(mobj_t *listener, mobj_t *source, - int *vol, int *sep, int *pitch) + int *vol, int *sep) { fixed_t approx_dist; fixed_t adx; @@ -406,7 +510,6 @@ void S_StartSound(void *origin_p, int sfx_id) mobj_t *origin; int rc; int sep; - int pitch; int priority; int cnum; int volume; @@ -425,7 +528,6 @@ void S_StartSound(void *origin_p, int sfx_id) // Initialize sound parameters if (sfx->link) { - pitch = sfx->pitch; priority = sfx->priority; volume += sfx->volume; @@ -441,7 +543,6 @@ void S_StartSound(void *origin_p, int sfx_id) } else { - pitch = NORM_PITCH; priority = NORM_PRIORITY; } @@ -453,8 +554,7 @@ void S_StartSound(void *origin_p, int sfx_id) rc = S_AdjustSoundParams(players[consoleplayer].mo, origin, &volume, - &sep, - &pitch); + &sep); if (origin->x == players[consoleplayer].mo->x && origin->y == players[consoleplayer].mo->y) @@ -472,36 +572,6 @@ void S_StartSound(void *origin_p, int sfx_id) sep = NORM_SEP; } - // hacks to vary the sfx pitches - if (sfx_id >= sfx_sawup - && sfx_id <= sfx_sawhit) - { - pitch += 8 - (M_Random()&15); - - if (pitch < 0) - { - pitch = 0; - } - else if (pitch > 255) - { - pitch = 255; - } - } - else if (sfx_id != sfx_itemup - && sfx_id != sfx_tink) - { - pitch += 16 - (M_Random()&31); - - if (pitch < 0) - { - pitch = 0; - } - else if (pitch > 255) - { - pitch = 255; - } - } - // kill old sound S_StopSound(origin); @@ -513,32 +583,29 @@ void S_StartSound(void *origin_p, int sfx_id) return; } - // - // This is supposed to handle the loading/caching. - // For some odd reason, the caching is done nearly - // each time the sound is needed? - // - - // get lumpnum if necessary - if (sfx->lumpnum < 0) - { - sfx->lumpnum = I_GetSfxLumpNum(sfx); - } - // increase the usefulness if (sfx->usefulness++ < 0) { sfx->usefulness = 1; } - // Assigns the handle to one of the channels in the - // mix/output buffer. - channels[cnum].handle = I_StartSound(sfx_id, - cnum, - volume, - sep, - pitch, - priority); + if (sound_module != NULL) + { + // Get lumpnum if necessary + + if (sfx->lumpnum < 0) + { + sfx->lumpnum = sound_module->GetSfxLumpNum(sfx); + } + + // Assigns the handle to one of the channels in the + // mix/output buffer. + + channels[cnum].handle = sound_module->StartSound(sfx_id, + cnum, + volume, + sep); + } } // @@ -573,7 +640,6 @@ void S_UpdateSounds(mobj_t *listener) int cnum; int volume; int sep; - int pitch; sfxinfo_t* sfx; channel_t* c; @@ -584,16 +650,14 @@ void S_UpdateSounds(mobj_t *listener) if (c->sfxinfo) { - if (I_SoundIsPlaying(c->handle)) + if (sound_module != NULL && sound_module->SoundIsPlaying(c->handle)) { // initialize parameters volume = snd_SfxVolume; - pitch = NORM_PITCH; sep = NORM_SEP; if (sfx->link) { - pitch = sfx->pitch; volume += sfx->volume; if (volume < 1) { @@ -613,8 +677,7 @@ void S_UpdateSounds(mobj_t *listener) audible = S_AdjustSoundParams(listener, c->origin, &volume, - &sep, - &pitch); + &sep); if (!audible) { @@ -622,7 +685,7 @@ void S_UpdateSounds(mobj_t *listener) } else { - I_UpdateSoundParams(c->handle, volume, sep, pitch); + sound_module->UpdateSoundParams(c->handle, volume, sep); } } } diff --git a/src/s_sound.h b/src/s_sound.h index c5460aed..8a5e2c6c 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -28,6 +28,8 @@ #ifndef __S_SOUND__ #define __S_SOUND__ +#include "p_mobj.h" +#include "sounds.h" typedef enum { @@ -43,8 +45,50 @@ typedef enum SNDDEVICE_AWE32 = 9, } snddevice_t; +typedef struct +{ + snddevice_t *sound_devices; + int num_sound_devices; + + // Initialise sound module + // Returns true if successfully initialised + + boolean (*Init)(void); + + // Shutdown sound module + + void (*Shutdown)(void); + + // Returns the lump index of the given sound. + + int (*GetSfxLumpNum)(sfxinfo_t *sfxinfo); + + // Called periodically to update the subsystem. + + void (*Update)(void); + + // Update the sound settings on the given channel. + + void (*UpdateSoundParams)(int channel, int vol, int sep); + + // Start a sound on a given channel. Returns the channel id + // or -1 on failure. + + int (*StartSound)(int id, int channel, int vol, int sep); + + // Stop the sound playing on the given channel. + + void (*StopSound)(int channel); + + // Query if a sound is playing on the given channel + + boolean (*SoundIsPlaying)(int channel); + +} sound_module_t; + extern int snd_sfxdevice; extern int snd_musicdevice; +extern int snd_samplerate; // // Initializes sound stuff, including volume -- cgit v1.2.3