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
This commit is contained in:
Simon Howard 2007-06-17 18:40:02 +00:00
parent 5fc7913741
commit beab4eb58b
15 changed files with 746 additions and 577 deletions

View file

@ -29,6 +29,7 @@
#include "config.h" #include "config.h"
#include "pcsound.h" #include "pcsound.h"
#include "pcsound_internal.h"
#ifdef _WIN32 #ifdef _WIN32
extern pcsound_driver_t pcsound_win32_driver; extern pcsound_driver_t pcsound_win32_driver;
@ -54,6 +55,13 @@ static pcsound_driver_t *drivers[] =
static pcsound_driver_t *pcsound_driver = NULL; 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) int PCSound_Init(pcsound_callback_func callback_func)
{ {
char *driver_name; char *driver_name;

View file

@ -26,22 +26,21 @@
#ifndef PCSOUND_H #ifndef PCSOUND_H
#define 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 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 // Initialise the PC speaker subsystem. The given function is called
{ // periodically to request more sound data to play.
char *name;
pcsound_init_func init_func;
pcsound_shutdown_func shutdown_func;
};
int PCSound_Init(pcsound_callback_func callback_func); int PCSound_Init(pcsound_callback_func callback_func);
// Shut down the PC speaker subsystem.
void PCSound_Shutdown(void); 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 */ #endif /* #ifndef PCSOUND_H */

View file

@ -19,22 +19,29 @@
// 02111-1307, USA. // 02111-1307, USA.
// //
// DESCRIPTION: // DESCRIPTION:
// System interface for PC speaker sound. // PC speaker interface.
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifndef __I_PCSOUND_H__ #ifndef PCSOUND_INTERNAL_H
#define __I_PCSOUND_H__ #define PCSOUND_INTERNAL_H
int I_PCS_StartSound(int id, #include "pcsound.h"
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__ */ #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 */

View file

@ -40,6 +40,7 @@
#include "SDL_thread.h" #include "SDL_thread.h"
#include "pcsound.h" #include "pcsound.h"
#include "pcsound_internal.h"
#define CONSOLE_DEVICE "/dev/console" #define CONSOLE_DEVICE "/dev/console"

View file

@ -30,9 +30,17 @@
#include "SDL_mixer.h" #include "SDL_mixer.h"
#include "pcsound.h" #include "pcsound.h"
#include "pcsound_internal.h"
#define SQUARE_WAVE_AMP 0x2000 #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; static pcsound_callback_func callback;
// Output sound format // 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) static int PCSound_SDL_Init(pcsound_callback_func callback_func)
{ {
// Check that SDL_mixer has been opened already // Check if SDL_mixer has been opened already
// If not, fail // 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 // Only supports AUDIO_S16SYS
if (mixing_format != AUDIO_S16SYS || mixing_channels != 2) if (mixing_format != AUDIO_S16SYS || mixing_channels != 2)
@ -154,6 +203,8 @@ static int PCSound_SDL_Init(pcsound_callback_func callback_func)
fprintf(stderr, fprintf(stderr,
"PCSound_SDL only supports native signed 16-bit LSB, " "PCSound_SDL only supports native signed 16-bit LSB, "
"stereo format!\n"); "stereo format!\n");
PCSound_SDL_Shutdown();
return 0; return 0;
} }
@ -166,10 +217,6 @@ static int PCSound_SDL_Init(pcsound_callback_func callback_func)
return 1; return 1;
} }
static void PCSound_SDL_Shutdown(void)
{
}
pcsound_driver_t pcsound_sdl_driver = pcsound_driver_t pcsound_sdl_driver =
{ {
"SDL", "SDL",

View file

@ -29,6 +29,7 @@
#include <windows.h> #include <windows.h>
#include "pcsound.h" #include "pcsound.h"
#include "pcsound_internal.h"
static SDL_Thread *sound_thread_handle; static SDL_Thread *sound_thread_handle;
static int sound_thread_running; static int sound_thread_running;

View file

@ -95,6 +95,7 @@ r_sky.c r_sky.h \
r_state.h \ r_state.h \
r_things.c r_things.h \ r_things.c r_things.h \
sounds.c sounds.h \ sounds.c sounds.h \
s_sound.c s_sound.h \
st_lib.c st_lib.h \ st_lib.c st_lib.h \
st_stuff.c st_stuff.h \ st_stuff.c st_stuff.h \
tables.c tables.h \ tables.c tables.h \
@ -146,9 +147,9 @@ w_merge.c w_merge.h
FEATURE_SOUND_SOURCE_FILES = \ FEATURE_SOUND_SOURCE_FILES = \
i_pcsound.c i_pcsound.h \ i_pcsound.c i_pcsound.h \
i_sound.c i_sound.h \ i_sdlsound.c \
mus2mid.c mus2mid.h \ i_sdlmusic.c i_music.h \
s_sound.c s_sound.h mus2mid.c mus2mid.h
SOURCE_FILES = $(MAIN_SOURCE_FILES) \ SOURCE_FILES = $(MAIN_SOURCE_FILES) \
$(FEATURE_DEHACKED_SOURCE_FILES) \ $(FEATURE_DEHACKED_SOURCE_FILES) \

View file

@ -59,7 +59,6 @@
#include "p_saveg.h" #include "p_saveg.h"
#include "i_system.h" #include "i_system.h"
#include "i_sound.h"
#include "i_timer.h" #include "i_timer.h"
#include "i_video.h" #include "i_video.h"

View file

@ -68,15 +68,7 @@ static void *DEH_SoundStart(deh_context_t *context, char *line)
"in Vanilla dehacked.", sound_number); "in Vanilla dehacked.", sound_number);
} }
#ifdef FEATURE_SOUND
return &S_sfx[sound_number]; return &S_sfx[sound_number];
#else
return NULL;
#endif
} }
static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag) static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag)

View file

@ -21,7 +21,7 @@
// //
// //
// DESCRIPTION: // DESCRIPTION:
// System interface, sound. // System interface, music.
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -32,59 +32,7 @@
#include "doomstat.h" #include "doomstat.h"
#include "sounds.h" #include "sounds.h"
#include "s_sound.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 // MUSIC I/O
@ -125,3 +73,4 @@ boolean I_QrySongPlaying(void *handle);
#endif #endif

View file

@ -28,8 +28,8 @@
#include "doomdef.h" #include "doomdef.h"
#include "doomtype.h" #include "doomtype.h"
#include "i_pcsound.h" #include "deh_main.h"
#include "i_sound.h" #include "s_sound.h"
#include "sounds.h" #include "sounds.h"
#include "w_wad.h" #include "w_wad.h"
@ -62,7 +62,7 @@ static float frequencies[] = {
#define NUM_FREQUENCIES (sizeof(frequencies) / sizeof(*frequencies)) #define NUM_FREQUENCIES (sizeof(frequencies) / sizeof(*frequencies))
void PCSCallbackFunc(int *duration, int *freq) static void PCSCallbackFunc(int *duration, int *freq)
{ {
int tone; int tone;
@ -144,12 +144,10 @@ static boolean CachePCSLump(int sound_id)
return true; return true;
} }
int I_PCS_StartSound(int id, static int I_PCS_StartSound(int id,
int channel, int channel,
int vol, int vol,
int sep, int sep)
int pitch,
int priority)
{ {
int result; 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) if (!pcs_initialised)
{ {
@ -214,7 +212,22 @@ void I_PCS_StopSound(int handle)
SDL_UnlockMutex(sound_lock); 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) if (!pcs_initialised)
{ {
@ -229,10 +242,58 @@ int I_PCS_SoundIsPlaying(int handle)
return current_sound_lump != NULL && current_sound_remaining > 0; 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); 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,
};

317
src/i_sdlmusic.c Normal file
View file

@ -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();
}

View file

@ -30,35 +30,17 @@
#include "SDL.h" #include "SDL.h"
#include "SDL_mixer.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 "deh_main.h"
#include "s_sound.h" #include "s_sound.h"
#include "m_argv.h" #include "m_argv.h"
#include "m_misc.h"
#include "w_wad.h" #include "w_wad.h"
#include "z_zone.h"
#include "doomdef.h" #include "doomdef.h"
#define NUM_CHANNELS 16 #define NUM_CHANNELS 16
#define MAXMIDLENGTH (96 * 1024)
static boolean nosfxparm;
static boolean nomusicparm;
static boolean sound_initialised = false; static boolean sound_initialised = false;
static boolean music_initialised = false;
static Mix_Chunk sound_chunks[NUMSFX]; static Mix_Chunk sound_chunks[NUMSFX];
static int channels_playing[NUM_CHANNELS]; static int channels_playing[NUM_CHANNELS];
@ -67,19 +49,19 @@ static int mixer_freq;
static Uint16 mixer_format; static Uint16 mixer_format;
static int mixer_channels; static int mixer_channels;
int snd_samplerate = MIX_DEFAULT_FREQUENCY;
// When a sound stops, check if it is still playing. If it is not, // 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 // we can mark the sound data as CACHE to be freed back for other
// means. // means.
void ReleaseSoundOnChannel(int channel) static void ReleaseSoundOnChannel(int channel)
{ {
int i; int i;
int id = channels_playing[channel]; int id = channels_playing[channel];
if (!id) if (!id)
{
return; return;
}
channels_playing[channel] = sfx_None; channels_playing[channel] = sfx_None;
@ -265,27 +247,31 @@ static Mix_Chunk *GetSFXChunk(int sound_id)
// for a given SFX name. // for a given SFX name.
// //
int I_GetSfxLumpNum(sfxinfo_t* sfx) static int I_SDL_GetSfxLumpNum(sfxinfo_t* sfx)
{ {
char namebuf[9]; char namebuf[9];
char *prefix;
// Different prefix for PC speaker sound effects. sprintf(namebuf, "ds%s", DEH_String(sfx->name));
if (snd_sfxdevice == SNDDEVICE_PCSPEAKER)
{
prefix = "dp";
}
else
{
prefix = "ds";
}
sprintf(namebuf, "%s%s", prefix, DEH_String(sfx->name));
return W_GetNumForName(namebuf); 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 // Starting a sound means adding it
// to the current list of active sounds // 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. // is set, but currently not used by mixing.
// //
int static int I_SDL_StartSound(int id, int channel, int vol, int sep)
I_StartSound
( int id,
int channel,
int vol,
int sep,
int pitch,
int priority )
{ {
Mix_Chunk *chunk; Mix_Chunk *chunk;
if (!sound_initialised) 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 // Release a sound effect if there is already one playing
@ -340,22 +316,18 @@ I_StartSound
// set separation, etc. // set separation, etc.
I_UpdateSoundParams(channel, vol, sep, pitch); I_SDL_UpdateSoundParams(channel, vol, sep);
return channel; return channel;
} }
void I_StopSound (int handle) static void I_SDL_StopSound (int handle)
{ {
if (!sound_initialised) if (!sound_initialised)
return;
if (snd_sfxdevice == SNDDEVICE_PCSPEAKER)
{ {
I_PCS_StopSound(handle);
return; return;
} }
Mix_HaltChannel(handle); Mix_HaltChannel(handle);
// Sound data is no longer needed; release the // 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) if (handle < 0)
{
return false; return false;
}
if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) return Mix_Playing(handle);
{
return I_PCS_SoundIsPlaying(handle);
}
else
{
return Mix_Playing(handle);
}
} }
// //
// Periodically called to update the sound system // Periodically called to update the sound system
// //
void I_UpdateSound( void ) static void I_SDL_UpdateSound(void)
{ {
int i; int i;
if (!sound_initialised)
return;
if (snd_sfxdevice == SNDDEVICE_PCSPEAKER)
{
return;
}
// Check all channels to see if a sound has finished // Check all channels to see if a sound has finished
for (i=0; i<NUM_CHANNELS; ++i) 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, // Sound has finished playing on this channel,
// but sound data has not been released to cache // but sound data has not been released to cache
@ -416,65 +369,20 @@ void I_UpdateSound( void )
} }
} }
static void I_SDL_ShutdownSound(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;
if (!sound_initialised) if (!sound_initialised)
return;
if (snd_sfxdevice == SNDDEVICE_PCSPEAKER)
{ {
return; 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(); Mix_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO); SDL_QuitSubSystem(SDL_INIT_AUDIO);
sound_initialised = false; sound_initialised = false;
music_initialised = false;
} }
static boolean I_SDL_InitSound()
void
I_InitSound()
{ {
int i; int i;
@ -490,75 +398,16 @@ I_InitSound()
channels_playing[i] = sfx_None; 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) if (SDL_Init(SDL_INIT_AUDIO) < 0)
{ {
fprintf(stderr, "Unable to set up sound.\n"); fprintf(stderr, "Unable to set up sound.\n");
return; return false;
} }
if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0) if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0)
{ {
fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError()); fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError());
return; return false;
} }
Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels); Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels);
@ -567,201 +416,32 @@ I_InitSound()
SDL_PauseAudio(0); SDL_PauseAudio(0);
// If we are using the PC speaker, we now need to initialise it. sound_initialised = true;
if (snd_sfxdevice == SNDDEVICE_PCSPEAKER) return true;
{
I_PCS_InitSound();
}
if (!nomusicparm)
music_initialised = true;
if (!nosfxparm)
sound_initialised = true;
} }
static snddevice_t sound_sdl_devices[] =
//
// 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; SNDDEVICE_SB,
SNDDEVICE_PAS,
SNDDEVICE_GUS,
SNDDEVICE_WAVEBLASTER,
SNDDEVICE_SOUNDCANVAS,
SNDDEVICE_AWE32,
};
if (musicpaused) sound_module_t sound_sdl_module =
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. sound_sdl_devices,
currentMusicVolume = volume; sizeof(sound_sdl_devices) / sizeof(*sound_sdl_devices),
I_SDL_InitSound,
UpdateMusicVolume(); I_SDL_ShutdownSound,
} I_SDL_GetSfxLumpNum,
I_SDL_UpdateSound,
void I_PlaySong(void *handle, int looping) I_SDL_UpdateSoundParams,
{ I_SDL_StartSound,
Mix_Music *music = (Mix_Music *) handle; I_SDL_StopSound,
int loops; I_SDL_SoundIsPlaying,
};
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();
}

View file

@ -26,20 +26,24 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "i_music.h"
#include "i_system.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 "sounds.h"
#include "s_sound.h" #include "s_sound.h"
#include "deh_main.h"
#include "z_zone.h"
#include "m_random.h" #include "m_random.h"
#include "w_wad.h" #include "m_argv.h"
#include "doomdef.h"
#include "p_local.h" #include "p_local.h"
#include "w_wad.h"
#include "doomstat.h" #include "z_zone.h"
// when to clip out sounds // when to clip out sounds
// Does not fit the large outdoor areas. // Does not fit the large outdoor areas.
@ -74,10 +78,6 @@
#define DEFAULT_MUSIC_DEVICE SNDDEVICE_NONE #define DEFAULT_MUSIC_DEVICE SNDDEVICE_NONE
#endif #endif
int snd_musicdevice = DEFAULT_MUSIC_DEVICE;
int snd_sfxdevice = SNDDEVICE_SB;
typedef struct typedef struct
{ {
// sound information (if null, channel avail.) // sound information (if null, channel avail.)
@ -91,6 +91,9 @@ typedef struct
} channel_t; } channel_t;
// Low-level sound module we are using
static sound_module_t *sound_module;
// The set of channels available // The set of channels available
@ -105,6 +108,10 @@ int sfxVolume = 8;
int musicVolume = 8; int musicVolume = 8;
// Sound sample rate to use for digital output (Hz)
int snd_samplerate = 22050;
// Internal volume level, ranging from 0-127 // Internal volume level, ranging from 0-127
static int snd_SfxVolume; static int snd_SfxVolume;
@ -121,6 +128,81 @@ static musicinfo_t *mus_playing = NULL;
int numChannels = 8; 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 // Initializes sound stuff, including volume
// Sets channels, SFX and music volume, // Sets channels, SFX and music volume,
@ -131,7 +213,20 @@ void S_Init(int sfxVolume, int musicVolume)
{ {
int i; 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_SetSfxVolume(sfxVolume);
S_SetMusicVolume(musicVolume); S_SetMusicVolume(musicVolume);
@ -159,7 +254,12 @@ void S_Init(int sfxVolume, int musicVolume)
void S_Shutdown(void) void S_Shutdown(void)
{ {
I_ShutdownSound(); if (sound_module != NULL)
{
sound_module->Shutdown();
}
I_ShutdownMusic();
} }
static void S_StopChannel(int cnum) static void S_StopChannel(int cnum)
@ -172,9 +272,13 @@ static void S_StopChannel(int cnum)
if (c->sfxinfo) if (c->sfxinfo)
{ {
// stop the sound playing // 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 // check to see if other channels are playing the sound
@ -228,15 +332,15 @@ void S_Start(void)
{ {
// Song - Who? - Where? // Song - Who? - Where?
mus_e3m4, // American e4m1 mus_e3m4, // American e4m1
mus_e3m2, // Romero e4m2 mus_e3m2, // Romero e4m2
mus_e3m3, // Shawn e4m3 mus_e3m3, // Shawn e4m3
mus_e1m5, // American e4m4 mus_e1m5, // American e4m4
mus_e2m7, // Tim e4m5 mus_e2m7, // Tim e4m5
mus_e2m4, // Romero e4m6 mus_e2m4, // Romero e4m6
mus_e2m6, // J.Anderson e4m7 CHIRON.WAD mus_e2m6, // J.Anderson e4m7 CHIRON.WAD
mus_e2m5, // Shawn e4m8 mus_e2m5, // Shawn e4m8
mus_e1m9 // Tim e4m9 mus_e1m9, // Tim e4m9
}; };
if (gameepisode < 4) 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. // from the norm of a sound effect to be played.
// If the sound is not audible, returns a 0. // If the sound is not audible, returns a 0.
// Otherwise, modifies parameters and returns 1. // Otherwise, modifies parameters and returns 1.
// //
static int S_AdjustSoundParams(mobj_t *listener, mobj_t *source, 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 approx_dist;
fixed_t adx; fixed_t adx;
@ -406,7 +510,6 @@ void S_StartSound(void *origin_p, int sfx_id)
mobj_t *origin; mobj_t *origin;
int rc; int rc;
int sep; int sep;
int pitch;
int priority; int priority;
int cnum; int cnum;
int volume; int volume;
@ -425,7 +528,6 @@ void S_StartSound(void *origin_p, int sfx_id)
// Initialize sound parameters // Initialize sound parameters
if (sfx->link) if (sfx->link)
{ {
pitch = sfx->pitch;
priority = sfx->priority; priority = sfx->priority;
volume += sfx->volume; volume += sfx->volume;
@ -441,7 +543,6 @@ void S_StartSound(void *origin_p, int sfx_id)
} }
else else
{ {
pitch = NORM_PITCH;
priority = NORM_PRIORITY; priority = NORM_PRIORITY;
} }
@ -453,8 +554,7 @@ void S_StartSound(void *origin_p, int sfx_id)
rc = S_AdjustSoundParams(players[consoleplayer].mo, rc = S_AdjustSoundParams(players[consoleplayer].mo,
origin, origin,
&volume, &volume,
&sep, &sep);
&pitch);
if (origin->x == players[consoleplayer].mo->x if (origin->x == players[consoleplayer].mo->x
&& origin->y == players[consoleplayer].mo->y) && origin->y == players[consoleplayer].mo->y)
@ -472,36 +572,6 @@ void S_StartSound(void *origin_p, int sfx_id)
sep = NORM_SEP; 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 // kill old sound
S_StopSound(origin); S_StopSound(origin);
@ -513,32 +583,29 @@ void S_StartSound(void *origin_p, int sfx_id)
return; 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 // increase the usefulness
if (sfx->usefulness++ < 0) if (sfx->usefulness++ < 0)
{ {
sfx->usefulness = 1; sfx->usefulness = 1;
} }
// Assigns the handle to one of the channels in the if (sound_module != NULL)
// mix/output buffer. {
channels[cnum].handle = I_StartSound(sfx_id, // Get lumpnum if necessary
cnum,
volume, if (sfx->lumpnum < 0)
sep, {
pitch, sfx->lumpnum = sound_module->GetSfxLumpNum(sfx);
priority); }
// 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 cnum;
int volume; int volume;
int sep; int sep;
int pitch;
sfxinfo_t* sfx; sfxinfo_t* sfx;
channel_t* c; channel_t* c;
@ -584,16 +650,14 @@ void S_UpdateSounds(mobj_t *listener)
if (c->sfxinfo) if (c->sfxinfo)
{ {
if (I_SoundIsPlaying(c->handle)) if (sound_module != NULL && sound_module->SoundIsPlaying(c->handle))
{ {
// initialize parameters // initialize parameters
volume = snd_SfxVolume; volume = snd_SfxVolume;
pitch = NORM_PITCH;
sep = NORM_SEP; sep = NORM_SEP;
if (sfx->link) if (sfx->link)
{ {
pitch = sfx->pitch;
volume += sfx->volume; volume += sfx->volume;
if (volume < 1) if (volume < 1)
{ {
@ -613,8 +677,7 @@ void S_UpdateSounds(mobj_t *listener)
audible = S_AdjustSoundParams(listener, audible = S_AdjustSoundParams(listener,
c->origin, c->origin,
&volume, &volume,
&sep, &sep);
&pitch);
if (!audible) if (!audible)
{ {
@ -622,7 +685,7 @@ void S_UpdateSounds(mobj_t *listener)
} }
else else
{ {
I_UpdateSoundParams(c->handle, volume, sep, pitch); sound_module->UpdateSoundParams(c->handle, volume, sep);
} }
} }
} }

View file

@ -28,6 +28,8 @@
#ifndef __S_SOUND__ #ifndef __S_SOUND__
#define __S_SOUND__ #define __S_SOUND__
#include "p_mobj.h"
#include "sounds.h"
typedef enum typedef enum
{ {
@ -43,8 +45,50 @@ typedef enum
SNDDEVICE_AWE32 = 9, SNDDEVICE_AWE32 = 9,
} snddevice_t; } 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_sfxdevice;
extern int snd_musicdevice; extern int snd_musicdevice;
extern int snd_samplerate;
// //
// Initializes sound stuff, including volume // Initializes sound stuff, including volume