- Removed lots of spc_* cvars that are no longer meaningful and changed

spc_amp from a x.4 fixed point number to a normal float.
- Switched SPC playback from the external SNESAPU.DLL to Blargg's LGPL
  snes_spc library. I've compiled it with the fast DSP rather than the
  highly accurate one, since I didn't notice a meaningful difference between
  the two in my limited testing. In short: SPC playback is now built in to
  ZDoom. You don't need to download anything extra to make it work, and it
  also works on Linux as well as Windows (though building with Linux is
  currently untested).
- Fixed: Stereo separation was calculated very wrongly when in 2D sound mode.


SVN r794 (trunk)
This commit is contained in:
Randy Heit 2008-03-11 22:17:57 +00:00
commit 3bfcc5c09c
48 changed files with 9433 additions and 771 deletions

View file

@ -295,6 +295,16 @@ void FGameConfigFile::DoGlobalSetup ()
vsync->ResetToDefault ();
}
}
if (last < 206)
{ // spc_amp is now a float, not an int.
FBaseCVar *amp = FindCVar ("spc_amp", NULL);
if (amp != NULL)
{
UCVarValue val = amp->GetGenericRep(CVAR_Float);
val.Float /= 16.f;
amp->SetGenericRep(val, CVAR_Float);
}
}
}
}
}

View file

@ -74,10 +74,9 @@
#define NORM_PITCH 128
#define NORM_PRIORITY 64
#define NORM_SEP 0
#define NONE_SEP -2
#define S_PITCH_PERTURB 1
#define S_STEREO_SWING 0.25f
#define S_STEREO_SWING 0.75
/* Sound curve parameters for Doom */
@ -606,7 +605,6 @@ static void S_StartSound (fixed_t *pt, AActor *mover, int channel,
float sep;
int org_id;
fixed_t x, y, z;
angle_t angle;
static int sndcount = 0;
int chan;
@ -653,14 +651,9 @@ static void S_StartSound (fixed_t *pt, AActor *mover, int channel,
if (volume > 1)
volume = 1;
if (attenuation == 0)
if (attenuation <= 0)
{
sep = NONE_SEP;
dist = 0;
}
else if (attenuation < 0)
{
sep = NONE_SEP;
sep = NORM_SEP;
dist = 0;
}
else
@ -836,22 +829,21 @@ static void S_StartSound (fixed_t *pt, AActor *mover, int channel,
if (sep == -3)
{
AActor *listener = players[consoleplayer].camera;
if (listener == NULL)
{
sep = NONE_SEP;
}
else if (dist == 0)
if (listener == NULL || dist == 0)
{
sep = NORM_SEP;
}
else
{
angle = R_PointToAngle2 (listener->x, listener->y, x, y);
if (angle > listener->angle)
angle = angle - listener->angle;
else
angle = angle + (ANGLE_MAX - listener->angle);
sep = NORM_SEP - S_STEREO_SWING * sin((angle >> 1) * M_PI / 2147483648.0);
double angle = atan2(double(y - listener->y), double(x - listener->x));
double listener_angle = (listener->angle >> 1) * (M_PI / 1073741824.0);
if (angle <= listener_angle)
{
angle += 2*M_PI;
}
angle -= listener_angle;
sep = -S_STEREO_SWING * sin(angle);
if (snd_flipstereo)
{
sep = -sep;
@ -1303,7 +1295,6 @@ void S_UpdateSounds (void *listener_p)
fixed_t *listener;
fixed_t x, y;
int i, dist;
angle_t angle;
float vol, sep;
I_UpdateMusic();
@ -1363,12 +1354,15 @@ void S_UpdateSounds (void *listener_p)
vol = SoundCurve[dist] * Channel[i].volume;
if (dist > 0)
{
angle = R_PointToAngle2(listener[0], listener[1], x, y);
if (angle > players[consoleplayer].camera->angle)
angle = angle - players[consoleplayer].camera->angle;
else
angle = angle + (ANGLE_MAX - players[consoleplayer].camera->angle);
sep = NORM_SEP - S_STEREO_SWING * sin((angle >> 1) * M_PI / 2147483648.0);
double angle = atan2(double(y - listener[1]), double(x - listener[0]));
double listener_angle = (players[consoleplayer].camera->angle >> 1) * (M_PI / 1073741824.0);
if (angle <= listener_angle)
{
angle += 2*M_PI;
}
angle -= listener_angle;
sep = -S_STEREO_SWING * sin(angle);
if (snd_flipstereo)
{
sep = -sep;

View file

@ -3,7 +3,7 @@
** System interface for sound; uses fmod.dll
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** Copyright 1998-2008 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without

View file

@ -250,17 +250,10 @@ protected:
int m_LastPos;
};
#ifdef _WIN32
// SPC file, rendered with SNESAPU.DLL and streamed through FMOD ------------
typedef void (__stdcall *SNESAPUInfo_TYPE) (DWORD*, DWORD*, DWORD*);
typedef void (__stdcall *GetAPUData_TYPE) (void**, BYTE**, BYTE**, DWORD**, void**, void**, DWORD**, DWORD**);
typedef void (__stdcall *LoadSPCFile_TYPE) (void*);
typedef void (__stdcall *ResetAPU_TYPE) (DWORD);
typedef void (__stdcall *SetDSPAmp_TYPE) (DWORD);
typedef void (__stdcall *FixAPU_TYPE) (WORD, BYTE, BYTE, BYTE, BYTE, BYTE);
typedef void (__stdcall *SetAPUOpt_TYPE) (DWORD, DWORD, DWORD, DWORD, DWORD, DWORD);
typedef void *(__stdcall *EmuAPU_TYPE) (void *, DWORD, BYTE);
struct SNES_SPC;
struct SPC_Filter;
class SPCSong : public StreamSong
{
@ -272,33 +265,12 @@ public:
bool IsValid () const;
protected:
bool LoadEmu ();
void CloseEmu ();
static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
#ifdef _WIN32
HINSTANCE HandleAPU;
#else
void *HandleAPU;
#endif
int APUVersion;
bool Stereo;
bool Is8Bit;
SNESAPUInfo_TYPE SNESAPUInfo;
GetAPUData_TYPE GetAPUData;
LoadSPCFile_TYPE LoadSPCFile;
ResetAPU_TYPE ResetAPU;
SetDSPAmp_TYPE SetDSPAmp;
FixAPU_TYPE FixAPU;
SetAPUOpt_TYPE SetAPUOpt;
EmuAPU_TYPE EmuAPU;
SNES_SPC *SPC;
SPC_Filter *Filter;
};
#endif
// MIDI file played with Timidity and possibly streamed through FMOD --------
class TimiditySong : public StreamSong

View file

@ -4,6 +4,8 @@
#include "templates.h"
#include "c_cvars.h"
#include "doomdef.h"
#include "SNES_SPC.h"
#include "SPC_Filter.h"
struct XID6Tag
{
@ -14,25 +16,7 @@ struct XID6Tag
EXTERN_CVAR (Int, snd_samplerate)
CVAR (Int, spc_amp, 30, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, spc_8bit, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, spc_stereo, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, spc_lowpass, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, spc_surround, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, spc_oldsamples, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, spc_noecho, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR (Int, spc_quality, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (spc_quality < 0)
{
spc_quality = 0;
}
else if (spc_quality > 3)
{
spc_quality = 3;
}
}
CVAR (Float, spc_amp, 1.875f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR (Int, spc_frequency, 32000, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
@ -40,68 +24,46 @@ CUSTOM_CVAR (Int, spc_frequency, 32000, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
spc_frequency = 8000;
}
else if (spc_frequency > 65535)
else if (spc_frequency > 32000)
{
spc_frequency = 65535;
spc_frequency = 32000;
}
}
SPCSong::SPCSong (FILE *iofile, char * musiccache, int len)
SPCSong::SPCSong (FILE *iofile, char *musiccache, int len)
{
FileReader *file;
if (!LoadEmu ())
if (iofile != NULL)
{
return;
file = new FileReader(iofile, len);
}
else
{
file = new MemoryReader(musiccache, len);
}
FileReader * file;
if (iofile != NULL) file = new FileReader(iofile, len);
else file = new MemoryReader(musiccache, len);
// No sense in using a higher frequency than the final output
int freq = MIN (*spc_frequency, *snd_samplerate);
Is8Bit = spc_8bit;
Stereo = spc_stereo;
m_Stream = GSnd->CreateStream (FillStream, 16384,
(Stereo ? 0 : SoundStream::Mono) |
(Is8Bit ? SoundStream::Bits8 : 0),
freq, this);
if (m_Stream == NULL)
{
Printf (PRINT_BOLD, "Could not create music stream.\n");
CloseEmu ();
delete file;
return;
}
ResetAPU (spc_amp);
SetAPUOpt (~0, Stereo + 1, Is8Bit ? 8 : 16, freq, spc_quality,
(spc_lowpass ? 1 : 0) | (spc_oldsamples ? 2 : 0) | (spc_surround ? 4 : 0) | (spc_noecho ? 16 : 0));
SPC = new SNES_SPC;
SPC->init();
Filter = new SPC_Filter;
BYTE spcfile[66048];
file->Read (spcfile, 66048);
if (LoadSPCFile != NULL)
SPC->load_spc(spcfile, 66048);
SPC->clear_echo();
Filter->set_gain(int(SPC_Filter::gain_unit * spc_amp));
m_Stream = GSnd->CreateStream (FillStream, 16384, 0, freq, this);
if (m_Stream == NULL)
{
LoadSPCFile (spcfile);
}
else
{
void *apuram;
BYTE *extraram;
void *dsp;
GetAPUData (&apuram, &extraram, NULL, NULL, &dsp, NULL, NULL, NULL);
memcpy (apuram, spcfile + 0x100, 65536);
memcpy (dsp, spcfile + 0x10100, 128);
memcpy (extraram, spcfile + 0x101c0, 64);
FixAPU (spcfile[37]+spcfile[38]*256, spcfile[39], spcfile[41], spcfile[40], spcfile[42], spcfile[43]);
Printf (PRINT_BOLD, "Could not create music stream.\n");
delete file;
return;
}
// Search for amplification tag in extended ID666 info
@ -134,11 +96,7 @@ SPCSong::SPCSong (FILE *iofile, char * musiccache, int len)
{
DWORD amp;
(*file) >> amp;
if (APUVersion < 98)
{
amp >>= 12;
}
SetDSPAmp (amp);
Filter->set_gain(amp >> 8);
break;
}
}
@ -152,13 +110,14 @@ SPCSong::SPCSong (FILE *iofile, char * musiccache, int len)
SPCSong::~SPCSong ()
{
Stop ();
CloseEmu ();
Stop();
delete Filter;
delete SPC;
}
bool SPCSong::IsValid () const
{
return HandleAPU != NULL;
return SPC != NULL;
}
bool SPCSong::IsPlaying ()
@ -180,94 +139,9 @@ void SPCSong::Play (bool looping)
bool SPCSong::FillStream (SoundStream *stream, void *buff, int len, void *userdata)
{
SPCSong *song = (SPCSong *)userdata;
song->EmuAPU (buff, len >> (song->Stereo + !song->Is8Bit), 1);
if (song->Is8Bit)
{
BYTE *bytebuff = (BYTE *)buff;
for (int i = 0; i < len; ++i)
{
bytebuff[i] -= 128;
}
}
song->SPC->play(len >> 1, (short *)buff);
song->Filter->run((short *)buff, len >> 1);
return true;
}
bool SPCSong::LoadEmu ()
{
APUVersion = 0;
HandleAPU = LoadLibraryA ("snesapu.dll");
if (HandleAPU == NULL)
{
Printf ("Could not load snesapu.dll\n");
return false;
}
SNESAPUInfo = (SNESAPUInfo_TYPE)GetProcAddress (HandleAPU, "SNESAPUInfo");
if (SNESAPUInfo == NULL)
{
Printf ("This snesapu.dll is too old.\n");
}
else
{
DWORD ver, min, opt;
SNESAPUInfo (&ver, &min, &opt);
if ((min & 0xffff00) >= 0x8500 && (min & 0xffff00) < 0x9800)
{
APUVersion = 85;
}
else if ((min & 0xffff00) == 0x9800)
{
APUVersion = 98;
}
else if ((min & 0xffff00) == 0x11000)
{
APUVersion = 110;
}
else
{
char letters[4];
letters[0] = (char)ver; letters[1] = 0;
letters[2] = (char)min; letters[3] = 0;
Printf ("This snesapu.dll is too new.\nIt is version %lx.%02lx%s and"
"is backward compatible with DLL version %lx.%02lx%s.\n"
"ZDoom is only known to support DLL versions 0.95 - 2.0\n",
(ver>>16) & 255, (ver>>8) & 255, letters,
(min>>16) & 255, (min>>8) & 255, letters+2);
}
if (APUVersion != 0)
{
if (!(GetAPUData = (GetAPUData_TYPE)GetProcAddress (HandleAPU, "GetAPUData")) ||
!(ResetAPU = (ResetAPU_TYPE)GetProcAddress (HandleAPU, "ResetAPU")) ||
!(SetDSPAmp = (SetDSPAmp_TYPE)GetProcAddress (HandleAPU, "SetDSPAmp")) ||
!(FixAPU = (FixAPU_TYPE)GetProcAddress (HandleAPU, "FixAPU")) ||
!(SetAPUOpt = (SetAPUOpt_TYPE)GetProcAddress (HandleAPU, "SetAPUOpt")) ||
!(EmuAPU = (EmuAPU_TYPE)GetProcAddress (HandleAPU, "EmuAPU")))
{
Printf ("Snesapu.dll is missing some functions.\n");
APUVersion = 0;
}
LoadSPCFile = (LoadSPCFile_TYPE)GetProcAddress (HandleAPU, "LoadSPCFile");
}
}
if (APUVersion == 0)
{
FreeLibrary (HandleAPU);
HandleAPU = NULL;
return false;
}
return true;
}
void SPCSong::CloseEmu ()
{
if (HandleAPU != NULL)
{
FreeLibrary (HandleAPU);
HandleAPU = NULL;
}
}
#endif

View file

@ -59,7 +59,7 @@
// Version stored in the ini's [LastRun] section.
// Bump it if you made some configuration change that you want to
// be able to migrate in FGameConfigFile::DoGlobalSetup().
#define LASTRUNVERSION "205"
#define LASTRUNVERSION "206"
// Protocol version used in demos.
// Bump it if you change existing DEM_ commands or add new ones.