- 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:
parent
2ab76070c0
commit
a8de4fc2da
152 changed files with 28327 additions and 5166 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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
359
src/sound/music_gme.cpp
Normal 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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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, &, 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue