ref: beab4eb58b667a5883166bd1dd7bc33369a005c7
parent: 5fc7913741e9f722e31735baea10f635fc18acce
author: Simon Howard <fraggle@gmail.com>
date: Sun Jun 17 14:40:02 EDT 2007
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
--- 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;
@@ -53,6 +54,13 @@
};
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)
{
--- 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 */
--- /dev/null
+++ b/pcsound/pcsound_internal.h
@@ -1,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 */
+
--- 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"
--- 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 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 @@
fprintf(stderr,
"PCSound_SDL only supports native signed 16-bit LSB, "
"stereo format!\n");
+
+ PCSound_SDL_Shutdown();
return 0;
}
@@ -164,10 +215,6 @@
Mix_SetPostMix(PCSound_Mix_Callback, NULL);
return 1;
-}
-
-static void PCSound_SDL_Shutdown(void)
-{
}
pcsound_driver_t pcsound_sdl_driver =
--- 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;
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -95,6 +95,7 @@
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 @@
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) \
--- 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"
--- a/src/deh_sound.c
+++ b/src/deh_sound.c
@@ -68,15 +68,7 @@
"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)
--- /dev/null
+++ b/src/i_music.h
@@ -1,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
+
--- 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 @@
#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 @@
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 @@
}
}
-void I_PCS_StopSound(int handle)
+static void I_PCS_StopSound(int handle)
{
if (!pcs_initialised)
{
@@ -214,8 +212,23 @@
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)
{
return false;
@@ -229,10 +242,58 @@
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,
+};
--- a/src/i_pcsound.h
+++ /dev/null
@@ -1,40 +1,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__ */
-
--- /dev/null
+++ b/src/i_sdlmusic.c
@@ -1,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();
+}
+
+
+
--- /dev/null
+++ b/src/i_sdlsound.c
@@ -1,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 <stdio.h>
+#include <stdlib.h>
+#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<NUM_CHANNELS; ++i)
+ {
+ // Playing on this channel? if so, don't release.
+
+ if (channels_playing[i] == id)
+ return;
+ }
+
+ // Not used on any channel, and can be safely released
+
+ Z_ChangeTag(sound_chunks[id].abuf, PU_CACHE);
+}
+
+static boolean ConvertibleRatio(int freq1, int freq2)
+{
+ int ratio;
+
+ if (freq1 > 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<expanded_length; ++i)
+ {
+ Sint16 sample;
+ int src;
+
+ src = (i * expand_ratio) >> 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<NUM_CHANNELS; ++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
+
+ ReleaseSoundOnChannel(i);
+ }
+ }
+}
+
+static void I_SDL_ShutdownSound(void)
+{
+ if (!sound_initialised)
+ {
+ return;
+ }
+
+ Mix_CloseAudio();
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
+
+ sound_initialised = false;
+}
+
+static boolean I_SDL_InitSound()
+{
+ int i;
+
+ // No sounds yet
+
+ for (i=0; i<NUMSFX; ++i)
+ {
+ sound_chunks[i].abuf = NULL;
+ }
+
+ for (i=0; i<NUM_CHANNELS; ++i)
+ {
+ channels_playing[i] = sfx_None;
+ }
+
+ if (SDL_Init(SDL_INIT_AUDIO) < 0)
+ {
+ fprintf(stderr, "Unable to set up sound.\n");
+ return false;
+ }
+
+ if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0)
+ {
+ fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError());
+ return false;
+ }
+
+ Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels);
+
+ Mix_AllocateChannels(NUM_CHANNELS);
+
+ SDL_PauseAudio(0);
+
+ sound_initialised = true;
+
+ return true;
+}
+
+static snddevice_t sound_sdl_devices[] =
+{
+ SNDDEVICE_SB,
+ SNDDEVICE_PAS,
+ SNDDEVICE_GUS,
+ SNDDEVICE_WAVEBLASTER,
+ SNDDEVICE_SOUNDCANVAS,
+ SNDDEVICE_AWE32,
+};
+
+sound_module_t sound_sdl_module =
+{
+ 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,
+};
+
--- a/src/i_sound.c
+++ /dev/null
@@ -1,767 +1,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 for sound.
-//
-//-----------------------------------------------------------------------------
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#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 "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<NUM_CHANNELS; ++i)
- {
- // Playing on this channel? if so, don't release.
-
- if (channels_playing[i] == id)
- return;
- }
-
- // Not used on any channel, and can be safely released
-
- Z_ChangeTag(sound_chunks[id].abuf, PU_CACHE);
-}
-
-static boolean ConvertibleRatio(int freq1, int freq2)
-{
- int ratio;
-
- if (freq1 > 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<expanded_length; ++i)
- {
- Sint16 sample;
- int src;
-
- src = (i * expand_ratio) >> 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<NUM_CHANNELS; ++i)
- {
- if (channels_playing[i] && !I_SoundIsPlaying(i))
- {
- // Sound has finished playing on this channel,
- // but sound data has not been released to cache
-
- ReleaseSoundOnChannel(i);
- }
- }
-}
-
-
-//
-// 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)
- 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()
-{
- int i;
-
- // No sounds yet
-
- for (i=0; i<NUMSFX; ++i)
- {
- sound_chunks[i].abuf = NULL;
- }
-
- for (i=0; i<NUM_CHANNELS; ++i)
- {
- 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;
- }
-
- 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();
-}
-
-
-
--- a/src/i_sound.h
+++ /dev/null
@@ -1,127 +1,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
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -26,21 +26,25 @@
#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 "w_wad.h"
+#include "z_zone.h"
-#include "doomstat.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,7 +91,10 @@
} channel_t;
+// Low-level sound module we are using
+static sound_module_t *sound_module;
+
// The set of channels available
static channel_t *channels;
@@ -105,6 +108,10 @@
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 @@
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,8 +213,21 @@
{
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_Shutdown(void)
{
- I_ShutdownSound();
+ if (sound_module != NULL)
+ {
+ sound_module->Shutdown();
+ }
+
+ I_ShutdownMusic();
}
static void S_StopChannel(int cnum)
@@ -172,9 +272,13 @@
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 @@
{
// 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,7 +430,7 @@
}
//
-// 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.
@@ -333,7 +437,7 @@
//
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 @@
mobj_t *origin;
int rc;
int sep;
- int pitch;
int priority;
int cnum;
int volume;
@@ -425,7 +528,6 @@
// Initialize sound parameters
if (sfx->link)
{
- pitch = sfx->pitch;
priority = sfx->priority;
volume += sfx->volume;
@@ -441,7 +543,6 @@
}
else
{
- pitch = NORM_PITCH;
priority = NORM_PRIORITY;
}
@@ -453,8 +554,7 @@
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 @@
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,18 +583,6 @@
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)
{
@@ -531,14 +589,23 @@
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 @@
int cnum;
int volume;
int sep;
- int pitch;
sfxinfo_t* sfx;
channel_t* c;
@@ -584,16 +650,14 @@
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 @@
audible = S_AdjustSoundParams(listener,
c->origin,
&volume,
- &sep,
- &pitch);
+ &sep);
if (!audible)
{
@@ -622,7 +685,7 @@
}
else
{
- I_UpdateSoundParams(c->handle, volume, sep, pitch);
+ sound_module->UpdateSoundParams(c->handle, volume, sep);
}
}
}
--- 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 @@
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