- Fixed compilation of i_keyboard.cpp with MinGW, because w32api still doesn't have

everything that was new for XP.
- Swapped snes_spc out for the full Game Music Emu library.

SVN r1631 (trunk)
This commit is contained in:
Randy Heit 2009-06-03 03:05:02 +00:00
commit a8de4fc2da
152 changed files with 28327 additions and 5166 deletions

View file

@ -674,13 +674,13 @@ add_executable( zdoom WIN32
sound/i_sound.cpp
sound/music_cd.cpp
sound/music_dumb.cpp
sound/music_gme.cpp
sound/music_midistream.cpp
sound/music_midi_base.cpp
sound/music_midi_midiout.cpp
sound/music_midi_timidity.cpp
sound/music_mus_midiout.cpp
sound/music_mus_opl.cpp
sound/music_spc.cpp
sound/music_stream.cpp
sound/music_timidity_mididevice.cpp
sound/music_win_mididevice.cpp
@ -726,7 +726,7 @@ add_executable( zdoom WIN32
set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" )
set_source_files_properties( sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" )
target_link_libraries( zdoom ${ZDOOM_LIBS} snes_spc gdtoa dumb lzma )
target_link_libraries( zdoom ${ZDOOM_LIBS} gme gdtoa dumb lzma )
include_directories( .
g_doom
g_heretic
@ -740,7 +740,7 @@ include_directories( .
thingdef
timidity
xlat
../snes_spc/snes_spc
../game-music-emu/gme
../gdtoa
../dumb/include
${CMAKE_BINARY_DIR}/gdtoa

View file

@ -189,7 +189,7 @@ static EIWADType ScanIWAD (const char *iwad)
Check_e2m1
};
int lumpsfound[NUM_CHECKLUMPS];
int i;
size_t i;
memset (lumpsfound, 0, sizeof(lumpsfound));
FResourceFile *iwadfile = FResourceFile::OpenResourceFile(iwad, NULL, true);

View file

@ -52,7 +52,7 @@ void OPLmusicBlock::Restart()
LastOffset = 0;
}
OPLmusicFile::OPLmusicFile (FILE *file, char *musiccache, int len)
OPLmusicFile::OPLmusicFile (FILE *file, BYTE *musiccache, int len)
: ScoreLen (len)
{
if (io == NULL)

View file

@ -28,7 +28,7 @@ protected:
class OPLmusicFile : public OPLmusicBlock
{
public:
OPLmusicFile(FILE *file, char *musiccache, int len);
OPLmusicFile(FILE *file, BYTE *musiccache, int len);
OPLmusicFile(const OPLmusicFile *source, const char *filename);
virtual ~OPLmusicFile();

View file

@ -2231,7 +2231,7 @@ bool S_StartMusic (const char *m_id)
// specified, it will only be played if the specified CD is in a drive.
//==========================================================================
TArray<char> musiccache;
TArray<BYTE> musiccache;
bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
{

View file

@ -78,8 +78,6 @@ struct FEnumList
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
FMOD_RESULT SPC_CreateCodec(FMOD::System *sys);
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
@ -1083,12 +1081,6 @@ bool FMODSoundRenderer::Init()
}
}
result = SPC_CreateCodec(Sys);
if (result != FMOD_OK)
{
Printf(TEXTCOLOR_BLUE" Could not register SPC codec. (Error %d)\n", result);
}
if (FMOD_OK != Sys->getSoftwareFormat(&OutputRate, NULL, NULL, NULL, NULL, NULL))
{
OutputRate = 48000; // Guess, but this should never happen.

View file

@ -73,11 +73,24 @@ extern void ChildSigHandler (int signum);
#include "stats.h"
#include "timidity/timidity.h"
#define GZIP_ID1 31
#define GZIP_ID2 139
#define GZIP_CM 8
#define GZIP_ID MAKE_ID(GZIP_ID1,GZIP_ID2,GZIP_CM,0)
#define GZIP_FTEXT 1
#define GZIP_FHCRC 2
#define GZIP_FEXTRA 4
#define GZIP_FNAME 8
#define GZIP_FCOMMENT 16
EXTERN_CVAR (Int, snd_samplerate)
EXTERN_CVAR (Int, snd_mididevice)
static bool MusicDown = true;
static BYTE *ungzip(BYTE *data, int *size);
MusInfo *currSong;
int nomusic = 0;
float relative_volume = 1.f;
@ -275,11 +288,13 @@ MusInfo *I_RegisterURLSong (const char *url)
return NULL;
}
MusInfo *I_RegisterSong (const char *filename, char *musiccache, int offset, int len, int device)
MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int len, int device)
{
FILE *file;
MusInfo *info = NULL;
DWORD id;
const char *fmt;
BYTE *ungzipped;
if (nomusic)
{
@ -315,14 +330,45 @@ MusInfo *I_RegisterSong (const char *filename, char *musiccache, int offset, int
else
{
file = NULL;
memcpy(&id, &musiccache[0], 4);
id = *(DWORD *)musiccache;
}
#ifndef _WIN32
// non-windows platforms don't support MDEV_MIDI so map to MDEV_FMOD
if (device == MDEV_MMAPI) device = MDEV_FMOD;
if (device == MDEV_MMAPI)
device = MDEV_FMOD;
#endif
// Check for gzip compression. Some formats are expected to have players
// that can handle it, so it simplifies things if we make all songs
// gzippable.
ungzipped = NULL;
if ((id & MAKE_ID(255,255,255,0)) == GZIP_ID)
{
if (offset != -1)
{
BYTE *gzipped = new BYTE[len];
if (fread(gzipped, 1, len, file) != (size_t)len)
{
delete[] gzipped;
fclose(file);
return NULL;
}
ungzipped = ungzip(gzipped, &len);
delete[] gzipped;
}
else
{
ungzipped = ungzip(musiccache, &len);
}
if (ungzipped == NULL)
{
fclose(file);
return NULL;
}
musiccache = ungzipped;
id = *(DWORD *)ungzipped;
}
// Check for MUS format
if (id == MAKE_ID('M','U','S',0x1a))
@ -417,7 +463,7 @@ MusInfo *I_RegisterSong (const char *filename, char *musiccache, int offset, int
- if explicitly selected by $mididevice
- when snd_mididevice is -2 and no midi device is set for the song
FMod:
FMOD:
- if explicitly selected by $mididevice
- when snd_mididevice is -1 and no midi device is set for the song
- as fallback when Timidity failed unless snd_mididevice is >= 0
@ -481,6 +527,11 @@ MusInfo *I_RegisterSong (const char *filename, char *musiccache, int offset, int
info = new OPLMUSSong (file, musiccache, len);
}
}
// Check for game music
else if ((fmt = GME_CheckFormat(id)) != NULL)
{
info = GME_OpenSong(file, musiccache, len, fmt);
}
// Check for module formats
else
{
@ -526,21 +577,23 @@ MusInfo *I_RegisterSong (const char *filename, char *musiccache, int offset, int
fclose (file);
file = NULL;
}
info = new StreamSong (offset >=0 ? filename : musiccache, offset, len);
info = new StreamSong (offset >= 0 ? filename : (const char *)musiccache, offset, len);
}
}
if (info && !info->IsValid ())
{
delete info;
info = NULL;
}
if (file != NULL)
{
fclose (file);
}
if (ungzipped != NULL)
{
delete[] ungzipped;
}
return info;
}
@ -558,6 +611,88 @@ MusInfo *I_RegisterCDSong (int track, int id)
return info;
}
//==========================================================================
//
// ungzip
//
// VGZ files are compressed with gzip, so we need to uncompress them before
// handing them to GME.
//
//==========================================================================
BYTE *ungzip(BYTE *data, int *complen)
{
const BYTE *max = data + *complen - 8;
const BYTE *compstart = data + 10;
BYTE flags = data[3];
unsigned isize;
BYTE *newdata;
z_stream stream;
int err;
// Find start of compressed data stream
if (flags & GZIP_FEXTRA)
{
compstart += 2 + LittleShort(*(WORD *)(data + 10));
}
if (flags & GZIP_FNAME)
{
while (compstart < max && *compstart != 0)
{
compstart++;
}
}
if (flags & GZIP_FCOMMENT)
{
while (compstart < max && *compstart != 0)
{
compstart++;
}
}
if (flags & GZIP_FHCRC)
{
compstart += 2;
}
if (compstart >= max - 1)
{
return NULL;
}
// Decompress
isize = LittleLong(*(DWORD *)(data + *complen - 4));
newdata = new BYTE[isize];
stream.next_in = (Bytef *)compstart;
stream.avail_in = (uInt)(max - compstart);
stream.next_out = newdata;
stream.avail_out = isize;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
err = inflateInit2(&stream, -MAX_WBITS);
if (err != Z_OK)
{
delete[] newdata;
return NULL;
}
err = inflate(&stream, Z_FINISH);
if (err != Z_STREAM_END)
{
inflateEnd(&stream);
delete[] newdata;
return NULL;
}
err = inflateEnd(&stream);
if (err != Z_OK)
{
delete[] newdata;
return NULL;
}
*complen = isize;
return newdata;
}
void I_UpdateMusic()
{
if (currSong != NULL)

View file

@ -55,7 +55,7 @@ void I_ResumeSong (void *handle);
// Registers a song handle to song data.
class MusInfo;
MusInfo *I_RegisterSong (const char *file, char * musiccache, int offset, int length, int device);
MusInfo *I_RegisterSong (const char *file, BYTE *musiccache, int offset, int length, int device);
MusInfo *I_RegisterCDSong (int track, int cdid = 0);
MusInfo *I_RegisterURLSong (const char *url);

View file

@ -343,7 +343,7 @@ protected:
class MUSSong2 : public MIDIStreamer
{
public:
MUSSong2(FILE *file, char *musiccache, int length, EMIDIDevice type);
MUSSong2(FILE *file, BYTE *musiccache, int length, EMIDIDevice type);
~MUSSong2();
MusInfo *GetOPLDumper(const char *filename);
@ -369,7 +369,7 @@ protected:
class MIDISong2 : public MIDIStreamer
{
public:
MIDISong2(FILE *file, char *musiccache, int length, EMIDIDevice type);
MIDISong2(FILE *file, BYTE *musiccache, int length, EMIDIDevice type);
~MIDISong2();
MusInfo *GetOPLDumper(const char *filename);
@ -431,7 +431,7 @@ protected:
class TimiditySong : public StreamSong
{
public:
TimiditySong (FILE *file, char * musiccache, int length);
TimiditySong (FILE *file, BYTE *musiccache, int length);
~TimiditySong ();
void Play (bool looping, int subsong);
void Stop ();
@ -469,7 +469,7 @@ protected:
class OPLMUSSong : public StreamSong
{
public:
OPLMUSSong (FILE *file, char *musiccache, int length);
OPLMUSSong (FILE *file, BYTE *musiccache, int length);
~OPLMUSSong ();
void Play (bool looping, int subsong);
bool IsPlaying ();
@ -524,7 +524,12 @@ public:
// Module played via foo_dumb -----------------------------------------------
MusInfo *MOD_OpenSong(FILE *file, char *musiccache, int len);
MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int len);
// Music played via Game Music Emu ------------------------------------------
const char *GME_CheckFormat(uint32 header);
MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt);
// --------------------------------------------------------------------------

View file

@ -513,7 +513,7 @@ static DUMBFILE_SYSTEM mem_dfs = {
//
//==========================================================================
DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, char *start, FILE *file, char *musiccache, int lenhave, int lenfull)
DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, FILE *file, BYTE *musiccache, int lenhave, int lenfull)
{
filestate->size = lenfull;
filestate->offset = 0;
@ -857,13 +857,13 @@ static void MOD_SetAutoChip(DUH *duh)
//
//==========================================================================
MusInfo *MOD_OpenSong(FILE *file, char *musiccache, int size)
MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
{
DUH *duh = 0;
int headsize;
union
{
char start[64];
BYTE start[64];
DWORD dstart[64/4];
};
dumbfile_mem_status filestate;
@ -881,7 +881,7 @@ MusInfo *MOD_OpenSong(FILE *file, char *musiccache, int size)
atterm(dumb_exit);
filestate.ptr = (BYTE *)start;
filestate.ptr = start;
filestate.offset = 0;
headsize = MIN((int)sizeof(start), size);
if (musiccache != NULL)
@ -921,9 +921,9 @@ MusInfo *MOD_OpenSong(FILE *file, char *musiccache, int size)
}
else if (size >= 1168 &&
/*start[28] == 0x1A &&*/ start[29] == 2 &&
( ! strnicmp( &start[20], "!Scream!", 8 ) ||
! strnicmp( &start[20], "BMOD2STM", 8 ) ||
! strnicmp( &start[20], "WUZAMOD!", 8 ) ) )
( !memcmp( &start[20], "!Scream!", 8 ) ||
!memcmp( &start[20], "BMOD2STM", 8 ) ||
!memcmp( &start[20], "WUZAMOD!", 8 ) ) )
{
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
{
@ -1050,7 +1050,7 @@ MusInfo *MOD_OpenSong(FILE *file, char *musiccache, int size)
fseek(file, fpos, SEEK_SET);
}
}
if (filestate.ptr != (BYTE *)start && filestate.ptr != (BYTE *)musiccache)
if (filestate.ptr != (BYTE *)start && filestate.ptr != musiccache)
{
delete[] const_cast<BYTE *>(filestate.ptr);
}

359
src/sound/music_gme.cpp Normal file
View file

@ -0,0 +1,359 @@
/*
** music_gme.cpp
** General game music player, using Game Music Emu for decoding.
**
**---------------------------------------------------------------------------
** Copyright 2009 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
// Uncomment if you are using the DLL version of GME.
//#define GME_DLL
#define USE_WINDOWS_DWORD
#include "i_musicinterns.h"
#include "c_cvars.h"
#include "critsec.h"
#include "gme.h"
#include "v_text.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
class GMESong : public StreamSong
{
public:
GMESong(Music_Emu *emu, int sample_rate);
~GMESong();
bool SetSubsong(int subsong);
void Play(bool looping, int subsong);
FString GetStats();
protected:
FCriticalSection CritSec;
Music_Emu *Emu;
gme_info_t *TrackInfo;
int SampleRate;
int CurrTrack;
bool StartTrack(int track, bool getcritsec=true);
bool GetTrackInfo();
int CalcSongLength();
static bool Read(SoundStream *stream, void *buff, int len, void *userdata);
};
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
// Currently not used.
CVAR (Float, spc_amp, 1.875f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// CODE --------------------------------------------------------------------
//==========================================================================
//
// GME_CheckFormat
//
//==========================================================================
const char *GME_CheckFormat(uint32 id)
{
return gme_identify_header(&id);
}
//==========================================================================
//
// GME_OpenSong
//
//==========================================================================
MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt)
{
gme_type_t type;
gme_err_t err;
BYTE *song;
Music_Emu *emu;
int sample_rate;
type = gme_identify_extension(fmt);
if (type == NULL)
{
return NULL;
}
sample_rate = (int)GSnd->GetOutputRate();
emu = gme_new_emu(type, sample_rate);
if (emu == NULL)
{
return NULL;
}
if (musiccache != NULL)
{
song = musiccache;
}
else
{
song = new BYTE[len];
if (fread(song, 1, len, file) != (size_t)len)
{
delete[] song;
gme_delete(emu);
return NULL;
}
}
err = gme_load_data(emu, song, len);
if (song != musiccache)
{
delete[] song;
}
if (err != NULL)
{
Printf("Failed loading song: %s\n", err);
gme_delete(emu);
return NULL;
}
return new GMESong(emu, sample_rate);
}
//==========================================================================
//
// GMESong - Constructor
//
//==========================================================================
GMESong::GMESong(Music_Emu *emu, int sample_rate)
{
Emu = emu;
SampleRate = sample_rate;
CurrTrack = 0;
TrackInfo = NULL;
m_Stream = GSnd->CreateStream(Read, 32*1024, 0, sample_rate, this);
}
//==========================================================================
//
// GMESong - Destructor
//
//==========================================================================
GMESong::~GMESong()
{
Stop();
if (m_Stream != NULL)
{
delete m_Stream;
m_Stream = NULL;
}
if (TrackInfo != NULL)
{
gme_free_info(TrackInfo);
}
if (Emu != NULL)
{
gme_delete(Emu);
}
}
//==========================================================================
//
// GMESong :: Play
//
//==========================================================================
void GMESong::Play(bool looping, int track)
{
m_Status = STATE_Stopped;
m_Looping = looping;
if (StartTrack(0) && m_Stream->Play(looping, 1))
{
m_Status = STATE_Playing;
}
}
//==========================================================================
//
// GMESong :: SetSubsong
//
//==========================================================================
bool GMESong::SetSubsong(int track)
{
if (CurrTrack == track)
{
return false;
}
return StartTrack(track);
}
//==========================================================================
//
// GMESong :: StartTrack
//
//==========================================================================
bool GMESong::StartTrack(int track, bool getcritsec)
{
gme_err_t err;
if (getcritsec)
{
CritSec.Enter();
}
err = gme_start_track(Emu, track);
if (getcritsec)
{
CritSec.Leave();
}
if (err != NULL)
{
Printf("Could not start track %d: %s\n", track, err);
return false;
}
CurrTrack = track;
GetTrackInfo();
if (!m_Looping)
{
gme_set_fade(Emu, CalcSongLength());
}
return true;
}
//==========================================================================
//
// GMESong :: GetStats
//
//==========================================================================
FString GMESong::GetStats()
{
FString out;
if (TrackInfo != NULL)
{
int time = gme_tell(Emu);
out.Format(
"Track: " TEXTCOLOR_YELLOW "%d" TEXTCOLOR_NORMAL
" Time:" TEXTCOLOR_YELLOW "%3d:%02d:%03d" TEXTCOLOR_NORMAL
" System: " TEXTCOLOR_YELLOW "%s" TEXTCOLOR_NORMAL,
CurrTrack,
time/60000,
(time/1000) % 60,
time % 1000,
TrackInfo->system);
}
return out;
}
//==========================================================================
//
// GMESong :: GetTrackInfo
//
//==========================================================================
bool GMESong::GetTrackInfo()
{
gme_err_t err;
if (TrackInfo != NULL)
{
gme_free_info(TrackInfo);
TrackInfo = NULL;
}
err = gme_track_info(Emu, &TrackInfo, CurrTrack);
if (err != NULL)
{
Printf("Could not get track %d info: %s\n", CurrTrack, err);
return false;
}
return true;
}
//==========================================================================
//
// GMESong :: CalcSongLength
//
//==========================================================================
int GMESong::CalcSongLength()
{
if (TrackInfo == NULL)
{
return 150000;
}
if (TrackInfo->length > 0)
{
return TrackInfo->length;
}
if (TrackInfo->loop_length > 0)
{
return TrackInfo->intro_length + TrackInfo->loop_length * 2;
}
return 150000;
}
//==========================================================================
//
// GMESong :: Read STATIC
//
//==========================================================================
bool GMESong::Read(SoundStream *stream, void *buff, int len, void *userdata)
{
gme_err_t err;
GMESong *song = (GMESong *)userdata;
song->CritSec.Enter();
if (gme_track_ended(song->Emu))
{
if (song->m_Looping)
{
song->StartTrack(song->CurrTrack, false);
}
else
{
memset(buff, 0, len);
return false;
}
}
err = gme_play(song->Emu, len >> 1, (short *)buff);
song->CritSec.Leave();
return (err == NULL);
}

View file

@ -101,7 +101,7 @@ static BYTE CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
//
//==========================================================================
MIDISong2::MIDISong2 (FILE *file, char *musiccache, int len, EMIDIDevice type)
MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type)
: MIDIStreamer(type), MusHeader(0), Tracks(0)
{
int p;

View file

@ -174,7 +174,7 @@ TimiditySong::~TimiditySong ()
#endif
}
TimiditySong::TimiditySong (FILE *file, char * musiccache, int len)
TimiditySong::TimiditySong (FILE *file, BYTE *musiccache, int len)
: DiskName ("zmid"),
#ifdef _WIN32
ReadWavePipe (INVALID_HANDLE_VALUE), WriteWavePipe (INVALID_HANDLE_VALUE),
@ -212,7 +212,10 @@ TimiditySong::TimiditySong (FILE *file, char * musiccache, int len)
buf = new BYTE[len];
fread (buf, 1, len, file);
}
else buf = (BYTE*)musiccache;
else
{
buf = musiccache;
}
// The file type has already been checked before this class instance was
@ -227,7 +230,7 @@ TimiditySong::TimiditySong (FILE *file, char * musiccache, int len)
success = ProduceMIDI (buf, f);
}
fclose (f);
if (file!=NULL)
if (file != NULL)
{
delete[] buf;
}

View file

@ -89,7 +89,7 @@ static const BYTE CtrlTranslate[15] =
//
//==========================================================================
MUSSong2::MUSSong2 (FILE *file, char *musiccache, int len, EMIDIDevice type)
MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type)
: MIDIStreamer(type), MusHeader(0), MusBuffer(0)
{
#ifdef _WIN32

View file

@ -10,7 +10,7 @@ CUSTOM_CVAR (Bool, opl_onechip, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
}
}
OPLMUSSong::OPLMUSSong (FILE *file, char *musiccache, int len)
OPLMUSSong::OPLMUSSong (FILE *file, BYTE *musiccache, int len)
{
int samples = int(OPL_SAMPLE_RATE / 14);

View file

@ -1,340 +0,0 @@
/*
** music_spc.cpp
** SPC codec for FMOD Ex, using snes_spc for decoding.
**
**---------------------------------------------------------------------------
** Copyright 2008 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include "templates.h"
#include "c_cvars.h"
#include "SNES_SPC.h"
#include "SPC_Filter.h"
#include "fmod_wrap.h"
#include "doomdef.h"
#include "m_swap.h"
#include "m_fixed.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
struct XID6Tag
{
BYTE ID;
BYTE Type;
WORD Value;
};
struct SPCCodecData
{
SNES_SPC *SPC;
SPC_Filter *Filter;
FMOD_CODEC_WAVEFORMAT WaveFormat;
bool bPlayed;
};
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
FMOD_RESULT SPC_CreateCodec(FMOD::System *sys);
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static FMOD_RESULT SPC_DoOpen(FMOD_CODEC_STATE *codec, SPCCodecData *userdata);
static FMOD_RESULT F_CALLBACK SPC_Open(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
static FMOD_RESULT F_CALLBACK SPC_Close(FMOD_CODEC_STATE *codec);
static FMOD_RESULT F_CALLBACK SPC_Read(FMOD_CODEC_STATE *codec, void *buffer, unsigned int size, unsigned int *read);
static FMOD_RESULT F_CALLBACK SPC_SetPosition(FMOD_CODEC_STATE *codec_state, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
EXTERN_CVAR (Int, snd_samplerate)
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CVAR (Float, spc_amp, 1.875f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static FMOD_CODEC_DESCRIPTION SPCCodecDescription = {
"Super Nintendo SPC File",
0x00000001,
1,
FMOD_TIMEUNIT_MS | FMOD_TIMEUNIT_PCM,
SPC_Open,
SPC_Close,
SPC_Read,
NULL,
SPC_SetPosition,
NULL,
NULL,
NULL
};
// CODE --------------------------------------------------------------------
//==========================================================================
//
// SPC_CreateCodec
//
//==========================================================================
FMOD_RESULT SPC_CreateCodec(FMOD::System *sys)
{
return sys->createCodec(&SPCCodecDescription);
}
//==========================================================================
//
// SPC_Open
//
//==========================================================================
static FMOD_RESULT SPC_DoOpen(FMOD_CODEC_STATE *codec, SPCCodecData *userdata)
{
FMOD_RESULT result;
char spcfile[SNES_SPC::spc_file_size];
unsigned int bytesread;
SNES_SPC *spc;
SPC_Filter *filter;
if (codec->filesize < 66048)
{ // Anything smaller than this is definitely not a (valid) SPC.
return FMOD_ERR_FORMAT;
}
result = codec->fileseek(codec->filehandle, 0, 0);
if (result != FMOD_OK)
{
return result;
}
// Check the signature.
result = codec->fileread(codec->filehandle, spcfile, SNES_SPC::signature_size, &bytesread, NULL);
if (result != FMOD_OK || bytesread != SNES_SPC::signature_size ||
memcmp(spcfile, SNES_SPC::signature, SNES_SPC::signature_size) != 0)
{
result = FMOD_ERR_FORMAT;
// If the length is right and this is just a different version, try
// to pretend it's the current one.
if (bytesread == SNES_SPC::signature_size)
{
memcpy(spcfile + 28, SNES_SPC::signature + 28, 7);
if (memcmp(spcfile, SNES_SPC::signature, SNES_SPC::signature_size) == 0)
{
result = FMOD_OK;
}
}
}
if (result != FMOD_OK)
{
return result;
}
// Load the rest of the file.
result = codec->fileread(codec->filehandle, spcfile + SNES_SPC::signature_size,
SNES_SPC::spc_file_size - SNES_SPC::signature_size, &bytesread, NULL);
if (result != FMOD_OK || bytesread < SNES_SPC::spc_min_file_size - SNES_SPC::signature_size)
{
return FMOD_ERR_FILE_BAD;
}
bytesread += SNES_SPC::signature_size;
// Create the SPC.
spc = (userdata != NULL) ? userdata->SPC : new SNES_SPC;
spc->init();
if (spc->load_spc(spcfile, bytesread) != NULL)
{
if (userdata != NULL)
{
delete spc;
}
return FMOD_ERR_FILE_BAD;
}
spc->clear_echo();
// Create the filter.
filter = (userdata != NULL) ? userdata->Filter : new SPC_Filter;
filter->set_gain(int(SPC_Filter::gain_unit * spc_amp));
// Search for amplification tag in extended ID666 info.
if (codec->filesize > SNES_SPC::spc_file_size + 8 && bytesread == SNES_SPC::spc_file_size)
{
DWORD id;
result = codec->fileread(codec->filehandle, &id, 4, &bytesread, NULL);
if (result == FMOD_OK && bytesread == 4 && id == MAKE_ID('x','i','d','6'))
{
DWORD size;
result = codec->fileread(codec->filehandle, &size, 4, &bytesread, NULL);
if (result == FMOD_OK && bytesread == 4)
{
size = LittleLong(size);
DWORD pos = SNES_SPC::spc_file_size + 8;
while (pos < size)
{
XID6Tag tag;
result = codec->fileread(codec->filehandle, &tag, 4, &bytesread, NULL);
if (result != FMOD_OK || bytesread != 4)
{
break;
}
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;
result = codec->fileread(codec->filehandle, &amp, 4, &bytesread, NULL);
if (result == FMOD_OK && bytesread == 4)
{
filter->set_gain(LittleLong(amp) >> 8);
}
break;
}
}
if (FMOD_OK != codec->fileseek(codec->filehandle, pos, NULL))
{
break;
}
}
}
}
}
}
if (userdata == NULL)
{
userdata = new SPCCodecData;
userdata->SPC = spc;
userdata->Filter = filter;
memset(&userdata->WaveFormat, 0, sizeof(userdata->WaveFormat));
userdata->WaveFormat.format = FMOD_SOUND_FORMAT_PCM16;
userdata->WaveFormat.channels = 2;
userdata->WaveFormat.frequency = SNES_SPC::sample_rate;
userdata->WaveFormat.lengthbytes = SNES_SPC::spc_file_size;
userdata->WaveFormat.lengthpcm = ~0u;
userdata->WaveFormat.blockalign = 4;
codec->numsubsounds = 0;
codec->waveformat = &userdata->WaveFormat;
codec->plugindata = userdata;
}
userdata->bPlayed = false;
return FMOD_OK;
}
//==========================================================================
//
// SPC_Open
//
//==========================================================================
static FMOD_RESULT F_CALLBACK SPC_Open(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
{
return SPC_DoOpen(codec, NULL);
}
//==========================================================================
//
// SPC_Close
//
//==========================================================================
static FMOD_RESULT F_CALLBACK SPC_Close(FMOD_CODEC_STATE *codec)
{
SPCCodecData *data = (SPCCodecData *)codec->plugindata;
if (data != NULL)
{
delete data->Filter;
delete data->SPC;
delete data;
}
return FMOD_OK;
}
//==========================================================================
//
// SPC_Read
//
//==========================================================================
static FMOD_RESULT F_CALLBACK SPC_Read(FMOD_CODEC_STATE *codec, void *buffer, unsigned int size, unsigned int *read)
{
SPCCodecData *data = (SPCCodecData *)codec->plugindata;
if (read != NULL)
{
*read = size;
}
data->bPlayed = true;
if (data->SPC->play(size >> 1, (short *)buffer) != NULL)
{
return FMOD_ERR_PLUGIN;
}
data->Filter->run((short *)buffer, size >> 1);
return FMOD_OK;
}
static FMOD_RESULT F_CALLBACK SPC_SetPosition(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
{
SPCCodecData *data = (SPCCodecData *)codec->plugindata;
FMOD_RESULT result;
if (data->bPlayed)
{ // Must reload the file after it's already played something.
result = SPC_DoOpen(codec, data);
if (result != FMOD_OK)
{
return result;
}
}
if (position != 0)
{
if (postype == FMOD_TIMEUNIT_PCM)
{
data->SPC->skip(position * 4);
}
else if (postype == FMOD_TIMEUNIT_MS)
{
data->SPC->skip(Scale(position, SNES_SPC::sample_rate, 1000) * 4);
}
else
{
return FMOD_ERR_UNSUPPORTED;
}
}
return FMOD_OK;
}

View file

@ -21,6 +21,11 @@
#define DINPUT_BUFFERSIZE 32
// Hi, w32api!
#ifndef GET_RAWINPUT_CODE_WPARAM
#define GET_RAWINPUT_CODE_WPARAM(wParam) ((wParam) & 0xff)
#endif
// TYPES -------------------------------------------------------------------
class FDInputKeyboard : public FKeyboard