diff options
author | Simon Howard | 2007-06-17 18:40:02 +0000 |
---|---|---|
committer | Simon Howard | 2007-06-17 18:40:02 +0000 |
commit | beab4eb58b667a5883166bd1dd7bc33369a005c7 (patch) | |
tree | a6574cd329b3caea7a600ec6ce9184cc79ffb494 | |
parent | 5fc7913741e9f722e31735baea10f635fc18acce (diff) | |
download | chocolate-doom-beab4eb58b667a5883166bd1dd7bc33369a005c7.tar.gz chocolate-doom-beab4eb58b667a5883166bd1dd7bc33369a005c7.tar.bz2 chocolate-doom-beab4eb58b667a5883166bd1dd7bc33369a005c7.zip |
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
-rw-r--r-- | pcsound/pcsound.c | 8 | ||||
-rw-r--r-- | pcsound/pcsound.h | 21 | ||||
-rw-r--r-- | pcsound/pcsound_internal.h (renamed from src/i_pcsound.h) | 33 | ||||
-rw-r--r-- | pcsound/pcsound_linux.c | 1 | ||||
-rw-r--r-- | pcsound/pcsound_sdl.c | 63 | ||||
-rw-r--r-- | pcsound/pcsound_win32.c | 1 | ||||
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/d_main.c | 1 | ||||
-rw-r--r-- | src/deh_sound.c | 8 | ||||
-rw-r--r-- | src/i_music.h (renamed from src/i_sound.h) | 57 | ||||
-rw-r--r-- | src/i_pcsound.c | 87 | ||||
-rw-r--r-- | src/i_sdlmusic.c | 317 | ||||
-rw-r--r-- | src/i_sdlsound.c (renamed from src/i_sound.c) | 438 | ||||
-rw-r--r-- | src/s_sound.c | 235 | ||||
-rw-r--r-- | src/s_sound.h | 44 |
15 files changed, 745 insertions, 576 deletions
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/src/i_pcsound.h b/pcsound/pcsound_internal.h index 601f4ee5..c5ae90b6 100644 --- a/src/i_pcsound.h +++ b/pcsound/pcsound_internal.h @@ -19,22 +19,29 @@ // 02111-1307, USA. // // DESCRIPTION: -// System interface for PC speaker sound. +// PC speaker interface. // //----------------------------------------------------------------------------- -#ifndef __I_PCSOUND_H__ -#define __I_PCSOUND_H__ +#ifndef PCSOUND_INTERNAL_H +#define PCSOUND_INTERNAL_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); +#include "pcsound.h" -#endif /* #ifndef __I_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 <windows.h> #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_sound.h b/src/i_music.h index ad3852ce..70664c9a 100644 --- a/src/i_sound.h +++ b/src/i_music.h @@ -21,7 +21,7 @@ // // // DESCRIPTION: -// System interface, sound. +// System interface, music. // //----------------------------------------------------------------------------- @@ -32,59 +32,7 @@ #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 ); - +#include "s_sound.h" // // MUSIC I/O @@ -125,3 +73,4 @@ 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_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 <stdio.h> +#include <stdlib.h> +#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_sound.c b/src/i_sdlsound.c index c332c69f..920e74d2 100644 --- a/src/i_sound.c +++ b/src/i_sdlsound.c @@ -30,35 +30,17 @@ #include "SDL.h" #include "SDL_mixer.h" -#ifndef _WIN32 -#include <unistd.h> -#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 "z_zone.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]; @@ -67,19 +49,19 @@ 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) +static void ReleaseSoundOnChannel(int channel) { int i; int id = channels_playing[channel]; if (!id) + { return; + } channels_playing[channel] = sfx_None; @@ -265,27 +247,31 @@ static Mix_Chunk *GetSFXChunk(int sound_id) // for a given SFX name. // -int I_GetSfxLumpNum(sfxinfo_t* sfx) +static int I_SDL_GetSfxLumpNum(sfxinfo_t* sfx) { char namebuf[9]; - char *prefix; - // Different prefix for PC speaker sound effects. + sprintf(namebuf, "ds%s", DEH_String(sfx->name)); + + return W_GetNumForName(namebuf); +} - if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) - { - prefix = "dp"; - } - else +static void I_SDL_UpdateSoundParams(int handle, int vol, int sep) +{ + int left, right; + + if (!sound_initialised) { - prefix = "ds"; + return; } - sprintf(namebuf, "%s%s", prefix, DEH_String(sfx->name)); - - return W_GetNumForName(namebuf); + 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 @@ -299,23 +285,13 @@ int I_GetSfxLumpNum(sfxinfo_t* sfx) // is set, but currently not used by mixing. // -int -I_StartSound -( int id, - int channel, - int vol, - int sep, - int pitch, - int priority ) +static int I_SDL_StartSound(int id, int channel, int vol, int sep) { Mix_Chunk *chunk; if (!sound_initialised) - return 0; - - if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) { - return I_PCS_StartSound(id, channel, vol, sep, pitch, priority); + return -1; } // Release a sound effect if there is already one playing @@ -340,22 +316,18 @@ I_StartSound // set separation, etc. - I_UpdateSoundParams(channel, vol, sep, pitch); + I_SDL_UpdateSoundParams(channel, vol, sep); return channel; } -void I_StopSound (int handle) +static void I_SDL_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 @@ -365,48 +337,29 @@ void I_StopSound (int handle) } -int I_SoundIsPlaying(int handle) +static boolean I_SDL_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); + return false; } -} - - + return Mix_Playing(handle); +} // // Periodically called to update the sound system // -void I_UpdateSound( void ) +static void I_SDL_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<NUM_CHANNELS; ++i) { - if (channels_playing[i] && !I_SoundIsPlaying(i)) + if (channels_playing[i] && !I_SDL_SoundIsPlaying(i)) { // Sound has finished playing on this channel, // but sound data has not been released to cache @@ -416,65 +369,20 @@ void I_UpdateSound( void ) } } - -// -// This would be used to write out the mixbuffer -// during each game loop update. -// Updates sound buffer and audio device at runtime. -// It is called during Timer interrupt with SNDINTR. -// Mixing now done synchronous, and -// only output be done asynchronous? -// -void -I_SubmitSound(void) -{ -} - - - -void -I_UpdateSoundParams -( int handle, - int vol, - int sep, - int pitch) -{ - int left, right; - +static void I_SDL_ShutdownSound(void) +{ if (!sound_initialised) - return; - - if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) { return; } - left = ((254 - sep) * vol) / 127; - right = ((sep) * vol) / 127; - - Mix_SetPanning(handle, left, right); -} - - - - -void I_ShutdownSound(void) -{ - if (!sound_initialised && !music_initialised) - return; - - Mix_HaltMusic(); Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); sound_initialised = false; - music_initialised = false; } - - -void -I_InitSound() +static boolean I_SDL_InitSound() { int i; @@ -490,75 +398,16 @@ I_InitSound() channels_playing[i] = sfx_None; } - //! - // Disable music playback. - // - - nomusicparm = M_CheckParm("-nomusic") > 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; + return false; } if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0) { fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError()); - return; + return false; } Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels); @@ -567,201 +416,32 @@ I_InitSound() 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; + sound_initialised = true; - 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); + return true; } -static boolean ConvertMus(byte *musdata, int len, char *filename) +static snddevice_t sound_sdl_devices[] = { - 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) + SNDDEVICE_SB, + SNDDEVICE_PAS, + SNDDEVICE_GUS, + SNDDEVICE_WAVEBLASTER, + SNDDEVICE_SOUNDCANVAS, + SNDDEVICE_AWE32, +}; + +sound_module_t sound_sdl_module = { - 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(); -} - - + sound_sdl_devices, + sizeof(sound_sdl_devices) / sizeof(*sound_sdl_devices), + I_SDL_InitSound, + I_SDL_ShutdownSound, + I_SDL_GetSfxLumpNum, + I_SDL_UpdateSound, + I_SDL_UpdateSoundParams, + I_SDL_StartSound, + I_SDL_StopSound, + I_SDL_SoundIsPlaying, +}; 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 <stdio.h> #include <stdlib.h> +#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; i<len; ++i) + { + if (device == list[i]) + { + return true; + } + } + + return false; +} + +// Find and initialise a sound_module_t appropriate for the setting +// in snd_sfxdevice. + +static void InitSfxModule(void) +{ + int i; + + sound_module = NULL; + + for (i=0; i<sizeof(sound_modules) / sizeof(*sound_modules); ++i) + { + // Is the sfx device in the list of devices supported by + // this module? + + if (SndDeviceInList(snd_sfxdevice, + sound_modules[i]->sound_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 |