2006-04-13 22:35:56 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
#include "i_musicinterns.h"
|
|
|
|
#include "templates.h"
|
|
|
|
#include "c_cvars.h"
|
|
|
|
#include "doomdef.h"
|
|
|
|
|
|
|
|
struct XID6Tag
|
|
|
|
{
|
|
|
|
BYTE ID;
|
|
|
|
BYTE Type;
|
|
|
|
WORD Value;
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_CVAR (Int, spc_frequency, 32000, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
{
|
|
|
|
if (spc_frequency < 8000)
|
|
|
|
{
|
|
|
|
spc_frequency = 8000;
|
|
|
|
}
|
|
|
|
else if (spc_frequency > 65535)
|
|
|
|
{
|
|
|
|
spc_frequency = 65535;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-14 12:58:52 +00:00
|
|
|
SPCSong::SPCSong (FILE *iofile, char * musiccache, int len)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if (!LoadEmu ())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-04-14 12:58:52 +00:00
|
|
|
FileReader * file;
|
|
|
|
|
|
|
|
if (iofile != NULL) file = new FileReader(iofile, len);
|
|
|
|
else file = new MemoryReader(musiccache, len);
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
// 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 ();
|
2006-04-14 12:58:52 +00:00
|
|
|
delete file;
|
2006-02-24 04:48:15 +00:00
|
|
|
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));
|
|
|
|
|
|
|
|
BYTE spcfile[66048];
|
|
|
|
|
2006-04-14 12:58:52 +00:00
|
|
|
file->Read (spcfile, 66048);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (LoadSPCFile != 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]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Search for amplification tag in extended ID666 info
|
|
|
|
if (len > 66056)
|
|
|
|
{
|
|
|
|
DWORD id;
|
|
|
|
|
2006-04-14 12:58:52 +00:00
|
|
|
file->Read (&id, 4);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (id == MAKE_ID('x','i','d','6'))
|
|
|
|
{
|
|
|
|
DWORD size;
|
|
|
|
|
2006-04-14 12:58:52 +00:00
|
|
|
(*file) >> size;
|
2006-02-24 04:48:15 +00:00
|
|
|
DWORD pos = 66056;
|
|
|
|
|
|
|
|
while (pos < size)
|
|
|
|
{
|
|
|
|
XID6Tag tag;
|
|
|
|
|
2006-04-14 12:58:52 +00:00
|
|
|
file->Read (&tag, 4);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (tag.Type == 0)
|
|
|
|
{
|
|
|
|
// Don't care about these
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pos + LittleShort(tag.Value) <= size)
|
|
|
|
{
|
|
|
|
if (tag.Type == 4 && tag.ID == 0x36)
|
|
|
|
{
|
|
|
|
DWORD amp;
|
2006-04-14 12:58:52 +00:00
|
|
|
(*file) >> amp;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (APUVersion < 98)
|
|
|
|
{
|
|
|
|
amp >>= 12;
|
|
|
|
}
|
|
|
|
SetDSPAmp (amp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-04-14 12:58:52 +00:00
|
|
|
file->Seek (LittleShort(tag.Value), SEEK_CUR);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-04-14 12:58:52 +00:00
|
|
|
delete file;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SPCSong::~SPCSong ()
|
|
|
|
{
|
|
|
|
Stop ();
|
|
|
|
CloseEmu ();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SPCSong::IsValid () const
|
|
|
|
{
|
|
|
|
return HandleAPU != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SPCSong::IsPlaying ()
|
|
|
|
{
|
|
|
|
return m_Status == STATE_Playing;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SPCSong::Play (bool looping)
|
|
|
|
{
|
|
|
|
m_Status = STATE_Stopped;
|
|
|
|
m_Looping = true;
|
|
|
|
|
VERY IMPORTANT NOTE FOR ANYBODY BUILDING FROM THE TRUNK: This commit adds support
for FMOD Ex while at the same time removing support for FMOD 3. Be sure to update
your SDKs. GCC users, be sure to do a "make cleandep && make clean" before
building, or you will likely get inexplicable errors.
- Fixed: If you wanted to make cleandep with MinGW, you had to specifically
specify Makefile.mingw as the makefile to use.
- Added a normalizer to the OPL synth. It helped bring up the volume a little,
but not nearly as much as I would have liked.
- Removed MIDI Mapper references. It doesn't work with the stream API, and
it doesn't really exist on NT kernels, either.
- Reworked music volume: Except for MIDI, all music volume is controlled
through GSnd and not at the individual song level.
- Removed the mididevice global variable.
- Removed snd_midivolume. Now that all music uses a linear volume scale,
there's no need for two separate music volume controls.
- Increased snd_samplerate default up to 48000.
- Added snd_format, defaulting to "PCM-16".
- Added snd_speakermode, defaulting to "Auto".
- Replaced snd_fpu with snd_resampler, defaulting to "Linear".
- Bumped the snd_channels default up from a pitiful 12 to 32.
- Changed snd_3d default to true. The new cvar snd_hw3d determines if
hardware 3D support is used and default to false.
- Removed the libFLAC source, since FMOD Ex has native FLAC support.
- Removed the altsound code, since it was terribly gimped in comparison to
the FMOD code. It's original purpose was to have been as a springboard for
writing a non-FMOD sound system for Unix-y systems, but that never
happened.
- Finished preliminary FMOD Ex support.
SVN r789 (trunk)
2008-03-09 03:13:49 +00:00
|
|
|
if (m_Stream->Play (true, snd_musicvolume, false))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
m_Status = STATE_Playing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2006-04-13 22:35:56 +00:00
|
|
|
|
|
|
|
#endif
|