mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-11 07:12:16 +00:00
Use a FileReader to handle music resources and audio decoding
Instead of the previous method where there'd be a filename and offset, and/or a memory pointer, this uses a class to access resource data regardless of its underlying form.
This commit is contained in:
parent
075c5d872d
commit
0017e1e6e8
29 changed files with 550 additions and 849 deletions
|
@ -527,3 +527,59 @@ char *MemoryReader::Gets(char *strbuf, int len)
|
|||
{
|
||||
return GetsFromBuffer(bufptr, strbuf, len);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// MemoryArrayReader
|
||||
//
|
||||
// reads data from an array of memory
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
MemoryArrayReader::MemoryArrayReader (const char *buffer, long length)
|
||||
{
|
||||
buf.Resize(length);
|
||||
memcpy(&buf[0], buffer, length);
|
||||
Length=length;
|
||||
FilePos=0;
|
||||
}
|
||||
|
||||
MemoryArrayReader::~MemoryArrayReader ()
|
||||
{
|
||||
}
|
||||
|
||||
long MemoryArrayReader::Tell () const
|
||||
{
|
||||
return FilePos;
|
||||
}
|
||||
|
||||
long MemoryArrayReader::Seek (long offset, int origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
offset+=FilePos;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
offset+=Length;
|
||||
break;
|
||||
|
||||
}
|
||||
FilePos=clamp<long>(offset,0,Length-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long MemoryArrayReader::Read (void *buffer, long len)
|
||||
{
|
||||
if (len>Length-FilePos) len=Length-FilePos;
|
||||
if (len<0) len=0;
|
||||
memcpy(buffer,&buf[FilePos],len);
|
||||
FilePos+=len;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *MemoryArrayReader::Gets(char *strbuf, int len)
|
||||
{
|
||||
return GetsFromBuffer((char*)&buf[0], strbuf, len);
|
||||
}
|
||||
|
|
18
src/files.h
18
src/files.h
|
@ -335,6 +335,24 @@ protected:
|
|||
const char * bufptr;
|
||||
};
|
||||
|
||||
class MemoryArrayReader : public FileReader
|
||||
{
|
||||
public:
|
||||
MemoryArrayReader (const char *buffer, long length);
|
||||
~MemoryArrayReader ();
|
||||
|
||||
virtual long Tell () const;
|
||||
virtual long Seek (long offset, int origin);
|
||||
virtual long Read (void *buffer, long len);
|
||||
virtual char *Gets(char *strbuf, int len);
|
||||
virtual const char *GetBuffer() const { return (char*)&buf[0]; }
|
||||
TArray<BYTE> &GetArray() { return buf; }
|
||||
|
||||
void UpdateLength() { Length = buf.Size(); }
|
||||
|
||||
protected:
|
||||
TArray<BYTE> buf;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -52,29 +52,22 @@ void OPLmusicBlock::Restart()
|
|||
LastOffset = 0;
|
||||
}
|
||||
|
||||
OPLmusicFile::OPLmusicFile (FILE *file, BYTE *musiccache, int len)
|
||||
: ScoreLen (len)
|
||||
OPLmusicFile::OPLmusicFile (FileReader *reader)
|
||||
: ScoreLen (reader->GetLength())
|
||||
{
|
||||
if (io == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
scoredata = new BYTE[len];
|
||||
scoredata = new BYTE[ScoreLen];
|
||||
|
||||
if (file)
|
||||
{
|
||||
if (fread (scoredata, 1, len, file) != (size_t)len)
|
||||
{
|
||||
fail: delete[] scoredata;
|
||||
scoredata = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(scoredata, &musiccache[0], len);
|
||||
}
|
||||
if (reader->Read(scoredata, ScoreLen) != ScoreLen)
|
||||
{
|
||||
fail: delete[] scoredata;
|
||||
scoredata = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == (NumChips = io->OPLinit(NumChips)))
|
||||
{
|
||||
|
@ -100,7 +93,7 @@ fail: delete[] scoredata;
|
|||
{
|
||||
RawPlayer = DosBox1;
|
||||
SamplesPerTick = OPL_SAMPLE_RATE / 1000;
|
||||
ScoreLen = MIN<int>(len - 24, LittleLong(((DWORD *)scoredata)[4])) + 24;
|
||||
ScoreLen = MIN<int>(ScoreLen - 24, LittleLong(((DWORD *)scoredata)[4])) + 24;
|
||||
}
|
||||
else if (((DWORD *)scoredata)[2] == MAKE_ID(2,0,0,0))
|
||||
{
|
||||
|
@ -120,7 +113,7 @@ fail: delete[] scoredata;
|
|||
RawPlayer = DosBox2;
|
||||
SamplesPerTick = OPL_SAMPLE_RATE / 1000;
|
||||
int headersize = 0x1A + scoredata[0x19];
|
||||
ScoreLen = MIN<int>(len - headersize, LittleLong(((DWORD *)scoredata)[3]) * 2) + headersize;
|
||||
ScoreLen = MIN<int>(ScoreLen - headersize, LittleLong(((DWORD *)scoredata)[3]) * 2) + headersize;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -29,7 +29,7 @@ protected:
|
|||
class OPLmusicFile : public OPLmusicBlock
|
||||
{
|
||||
public:
|
||||
OPLmusicFile(FILE *file, BYTE *musiccache, int len);
|
||||
OPLmusicFile(FileReader *reader);
|
||||
OPLmusicFile(const OPLmusicFile *source, const char *filename);
|
||||
virtual ~OPLmusicFile();
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <io.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
|
||||
#include "i_system.h"
|
||||
#include "i_sound.h"
|
||||
|
@ -2435,7 +2436,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
|||
else
|
||||
{
|
||||
int lumpnum = -1;
|
||||
int offset = 0, length = 0;
|
||||
int length = 0;
|
||||
int device = MDEV_DEFAULT;
|
||||
MusInfo *handle = NULL;
|
||||
FName musicasname = musicname;
|
||||
|
@ -2456,6 +2457,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
|||
musicname += 7;
|
||||
}
|
||||
|
||||
std::auto_ptr<FileReader> reader;
|
||||
if (!FileExists (musicname))
|
||||
{
|
||||
if ((lumpnum = Wads.CheckNumForFullName (musicname, true, ns_music)) == -1)
|
||||
|
@ -2485,8 +2487,6 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
|||
// shut down old music before reallocating and overwriting the cache!
|
||||
S_StopMusic (true);
|
||||
|
||||
offset = -1; // this tells the low level code that the music
|
||||
// is being used from memory
|
||||
length = Wads.LumpLength (lumpnum);
|
||||
if (length == 0)
|
||||
{
|
||||
|
@ -2494,15 +2494,16 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
|||
}
|
||||
musiccache.Resize(length);
|
||||
Wads.ReadLump(lumpnum, &musiccache[0]);
|
||||
|
||||
reader.reset(new MemoryReader((const char*)&musiccache[0], musiccache.Size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = Wads.GetLumpOffset (lumpnum);
|
||||
length = Wads.LumpLength (lumpnum);
|
||||
if (length == 0)
|
||||
if (Wads.LumpLength (lumpnum) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
reader.reset(Wads.ReopenLumpNum(lumpnum));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2525,15 +2526,9 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
|||
{
|
||||
mus_playing.handle = handle;
|
||||
}
|
||||
else if (offset != -1)
|
||||
{
|
||||
mus_playing.handle = I_RegisterSong (lumpnum != -1 ?
|
||||
Wads.GetWadFullName (Wads.GetLumpFile (lumpnum)) :
|
||||
musicname, NULL, offset, length, device);
|
||||
}
|
||||
else
|
||||
{
|
||||
mus_playing.handle = I_RegisterSong (NULL, &musiccache[0], -1, length, device);
|
||||
mus_playing.handle = I_RegisterSong (reader, device);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ extern HWND Window;
|
|||
#include "v_palette.h"
|
||||
#include "cmdlib.h"
|
||||
#include "s_sound.h"
|
||||
#include "files.h"
|
||||
|
||||
#if FMOD_VERSION > 0x42899 && FMOD_VERSION < 0x43600
|
||||
#error You are trying to compile with an unsupported version of FMOD.
|
||||
|
@ -310,6 +311,13 @@ public:
|
|||
SetStream(stream);
|
||||
}
|
||||
|
||||
FMODStreamCapsule(FMOD::Sound *stream, FMODSoundRenderer *owner, std::auto_ptr<FileReader> reader)
|
||||
: Owner(owner), Stream(NULL), Channel(NULL),
|
||||
UserData(NULL), Callback(NULL), Reader(reader), Ended(false)
|
||||
{
|
||||
SetStream(stream);
|
||||
}
|
||||
|
||||
FMODStreamCapsule(void *udata, SoundStreamCallback callback, FMODSoundRenderer *owner)
|
||||
: Owner(owner), Stream(NULL), Channel(NULL),
|
||||
UserData(udata), Callback(callback), Ended(false)
|
||||
|
@ -594,6 +602,7 @@ private:
|
|||
FMOD::Channel *Channel;
|
||||
void *UserData;
|
||||
SoundStreamCallback Callback;
|
||||
std::auto_ptr<FileReader> Reader;
|
||||
FString URL;
|
||||
bool Ended;
|
||||
bool JustStarted;
|
||||
|
@ -1600,83 +1609,173 @@ static void SetCustomLoopPts(FMOD::Sound *sound)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMODSoundRenderer :: OpenStream
|
||||
// open_reader_callback
|
||||
// close_reader_callback
|
||||
// read_reader_callback
|
||||
// seek_reader_callback
|
||||
//
|
||||
// Creates a streaming sound from a file on disk.
|
||||
// FMOD_CREATESOUNDEXINFO callbacks to handle reading resource data from a
|
||||
// FileReader.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int flags, int offset, int length)
|
||||
static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata)
|
||||
{
|
||||
FMOD_MODE mode;
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
FMOD::Sound *stream;
|
||||
FMOD_RESULT result;
|
||||
bool url;
|
||||
FString patches;
|
||||
char *endptr = NULL;
|
||||
QWORD val = strtoull(name, &endptr, 0);
|
||||
if(!endptr || *endptr != '\0')
|
||||
{
|
||||
Printf("Invalid name in callback: %s\n", name);
|
||||
return FMOD_ERR_FILE_NOTFOUND;
|
||||
}
|
||||
|
||||
InitCreateSoundExInfo(&exinfo);
|
||||
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
|
||||
if (flags & SoundStream::Loop)
|
||||
{
|
||||
mode |= FMOD_LOOP_NORMAL;
|
||||
}
|
||||
if (offset == -1)
|
||||
{
|
||||
mode |= FMOD_OPENMEMORY;
|
||||
offset = 0;
|
||||
}
|
||||
exinfo.length = length;
|
||||
exinfo.fileoffset = offset;
|
||||
if ((*snd_midipatchset)[0] != '\0')
|
||||
{
|
||||
FileReader *reader = reinterpret_cast<FileReader*>((uintptr_t)val);
|
||||
*filesize = reader->GetLength();
|
||||
*handle = reader;
|
||||
*userdata = reader;
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
static FMOD_RESULT F_CALLBACK close_reader_callback(void *handle, void *userdata)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
static FMOD_RESULT F_CALLBACK read_reader_callback(void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata)
|
||||
{
|
||||
FileReader *reader = reinterpret_cast<FileReader*>(handle);
|
||||
*bytesread = reader->Read(buffer, sizebytes);
|
||||
if(*bytesread > 0) return FMOD_OK;
|
||||
return FMOD_ERR_FILE_EOF;
|
||||
}
|
||||
|
||||
static FMOD_RESULT F_CALLBACK seek_reader_callback(void *handle, unsigned int pos, void *userdata)
|
||||
{
|
||||
FileReader *reader = reinterpret_cast<FileReader*>(handle);
|
||||
if(reader->Seek(pos, SEEK_SET) == 0)
|
||||
return FMOD_OK;
|
||||
return FMOD_ERR_FILE_COULDNOTSEEK;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMODSoundRenderer :: OpenStream
|
||||
//
|
||||
// Creates a streaming sound from a FileReader.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
SoundStream *FMODSoundRenderer::OpenStream(std::auto_ptr<FileReader> reader, int flags)
|
||||
{
|
||||
FMOD_MODE mode;
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
FMOD::Sound *stream;
|
||||
FMOD_RESULT result;
|
||||
FString patches;
|
||||
FString name;
|
||||
|
||||
InitCreateSoundExInfo(&exinfo);
|
||||
exinfo.useropen = open_reader_callback;
|
||||
exinfo.userclose = close_reader_callback;
|
||||
exinfo.userread = read_reader_callback;
|
||||
exinfo.userseek = seek_reader_callback;
|
||||
|
||||
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
|
||||
if(flags & SoundStream::Loop)
|
||||
mode |= FMOD_LOOP_NORMAL;
|
||||
if((*snd_midipatchset)[0] != '\0')
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// If the path does not contain any path separators, automatically
|
||||
// prepend $PROGDIR to the path.
|
||||
if (strcspn(snd_midipatchset, ":/\\") == strlen(snd_midipatchset))
|
||||
{
|
||||
patches << "$PROGDIR/" << snd_midipatchset;
|
||||
patches = NicePath(patches);
|
||||
}
|
||||
else
|
||||
// If the path does not contain any path separators, automatically
|
||||
// prepend $PROGDIR to the path.
|
||||
if (strcspn(snd_midipatchset, ":/\\") == strlen(snd_midipatchset))
|
||||
{
|
||||
patches << "$PROGDIR/" << snd_midipatchset;
|
||||
patches = NicePath(patches);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
patches = NicePath(snd_midipatchset);
|
||||
}
|
||||
exinfo.dlsname = patches;
|
||||
}
|
||||
{
|
||||
patches = NicePath(snd_midipatchset);
|
||||
}
|
||||
exinfo.dlsname = patches;
|
||||
}
|
||||
|
||||
url = (offset == 0 && length == 0 && strstr(filename_or_data, "://") > filename_or_data);
|
||||
if (url)
|
||||
{
|
||||
// Use a larger buffer for URLs so that it's less likely to be effected
|
||||
// by hiccups in the data rate from the remote server.
|
||||
Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES);
|
||||
}
|
||||
result = Sys->createSound(filename_or_data, mode, &exinfo, &stream);
|
||||
if (url)
|
||||
{
|
||||
// Restore standard buffer size.
|
||||
Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES);
|
||||
}
|
||||
if (result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL)
|
||||
{
|
||||
// FMOD_ERR_FORMAT could refer to either the main sound file or
|
||||
// to the DLS instrument set. Try again without special DLS
|
||||
// instruments to see if that lets it succeed.
|
||||
exinfo.dlsname = NULL;
|
||||
result = Sys->createSound(filename_or_data, mode, &exinfo, &stream);
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
Printf("%s is an unsupported format.\n", *snd_midipatchset);
|
||||
}
|
||||
}
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
SetCustomLoopPts(stream);
|
||||
return new FMODStreamCapsule(stream, this, url ? filename_or_data : NULL);
|
||||
}
|
||||
return NULL;
|
||||
name.Format("0x%I64x", (QWORD)reader.get());
|
||||
result = Sys->createSound(name, mode, &exinfo, &stream);
|
||||
if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL)
|
||||
{
|
||||
// FMOD_ERR_FORMAT could refer to either the main sound file or
|
||||
// to the DLS instrument set. Try again without special DLS
|
||||
// instruments to see if that lets it succeed.
|
||||
exinfo.dlsname = NULL;
|
||||
result = Sys->createSound(name, mode, &exinfo, &stream);
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
Printf("%s is an unsupported format.\n", *snd_midipatchset);
|
||||
}
|
||||
}
|
||||
if(result != FMOD_OK)
|
||||
return NULL;
|
||||
|
||||
SetCustomLoopPts(stream);
|
||||
return new FMODStreamCapsule(stream, this, reader);
|
||||
}
|
||||
|
||||
SoundStream *FMODSoundRenderer::OpenStream(const char *url, int flags)
|
||||
{
|
||||
FMOD_MODE mode;
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
FMOD::Sound *stream;
|
||||
FMOD_RESULT result;
|
||||
FString patches;
|
||||
|
||||
InitCreateSoundExInfo(&exinfo);
|
||||
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
|
||||
if(flags & SoundStream::Loop)
|
||||
mode |= FMOD_LOOP_NORMAL;
|
||||
if((*snd_midipatchset)[0] != '\0')
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// If the path does not contain any path separators, automatically
|
||||
// prepend $PROGDIR to the path.
|
||||
if (strcspn(snd_midipatchset, ":/\\") == strlen(snd_midipatchset))
|
||||
{
|
||||
patches << "$PROGDIR/" << snd_midipatchset;
|
||||
patches = NicePath(patches);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
patches = NicePath(snd_midipatchset);
|
||||
}
|
||||
exinfo.dlsname = patches;
|
||||
}
|
||||
|
||||
// Use a larger buffer for URLs so that it's less likely to be effected
|
||||
// by hiccups in the data rate from the remote server.
|
||||
Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES);
|
||||
|
||||
result = Sys->createSound(url, mode, &exinfo, &stream);
|
||||
if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL)
|
||||
{
|
||||
exinfo.dlsname = NULL;
|
||||
result = Sys->createSound(url, mode, &exinfo, &stream);
|
||||
if(result == FMOD_OK)
|
||||
{
|
||||
Printf("%s is an unsupported format.\n", *snd_midipatchset);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore standard buffer size.
|
||||
Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES);
|
||||
|
||||
if(result != FMOD_OK)
|
||||
return NULL;
|
||||
|
||||
SetCustomLoopPts(stream);
|
||||
return new FMODStreamCapsule(stream, this, url);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -24,9 +24,8 @@ public:
|
|||
|
||||
// Streaming sounds.
|
||||
SoundStream *CreateStream (SoundStreamCallback callback, int buffsamples, int flags, int samplerate, void *userdata);
|
||||
SoundStream *OpenStream (const char *filename, int flags, int offset, int length);
|
||||
long PlayStream (SoundStream *stream, int volume);
|
||||
void StopStream (SoundStream *stream);
|
||||
SoundStream *OpenStream (std::auto_ptr<FileReader> reader, int flags);
|
||||
SoundStream *OpenStream (const char *url, int flags);
|
||||
|
||||
// Starts a sound.
|
||||
FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan);
|
||||
|
|
|
@ -100,7 +100,7 @@ EXTERN_CVAR (Int, snd_mididevice)
|
|||
|
||||
static bool MusicDown = true;
|
||||
|
||||
static BYTE *ungzip(BYTE *data, int *size);
|
||||
static bool ungzip(BYTE *data, int size, TArray<BYTE> &newdata);
|
||||
|
||||
MusInfo *currSong;
|
||||
int nomusic = 0;
|
||||
|
@ -302,21 +302,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static MIDIStreamer *CreateMIDIStreamer(FILE *file, BYTE *musiccache, int len, EMidiDevice devtype, EMIDIType miditype)
|
||||
static MIDIStreamer *CreateMIDIStreamer(std::auto_ptr<FileReader> &reader, EMidiDevice devtype, EMIDIType miditype)
|
||||
{
|
||||
switch (miditype)
|
||||
{
|
||||
case MIDI_MUS:
|
||||
return new MUSSong2(file, musiccache, len, devtype);
|
||||
return new MUSSong2(reader, devtype);
|
||||
|
||||
case MIDI_MIDI:
|
||||
return new MIDISong2(file, musiccache, len, devtype);
|
||||
return new MIDISong2(reader, devtype);
|
||||
|
||||
case MIDI_HMI:
|
||||
return new HMISong(file, musiccache, len, devtype);
|
||||
return new HMISong(reader, devtype);
|
||||
|
||||
case MIDI_XMI:
|
||||
return new XMISong(file, musiccache, len, devtype);
|
||||
return new XMISong(reader, devtype);
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
|
@ -378,13 +378,11 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int len, int device)
|
||||
MusInfo *I_RegisterSong (std::auto_ptr<FileReader> reader, int device)
|
||||
{
|
||||
FILE *file;
|
||||
MusInfo *info = NULL;
|
||||
const char *fmt;
|
||||
DWORD id[32/4];
|
||||
BYTE *ungzipped;
|
||||
int i;
|
||||
|
||||
if (nomusic)
|
||||
|
@ -392,47 +390,10 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (offset != -1)
|
||||
{
|
||||
file = fopen (filename, "rb");
|
||||
if (file == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0 && offset == 0)
|
||||
{
|
||||
fseek (file, 0, SEEK_END);
|
||||
len = ftell (file);
|
||||
fseek (file, 0, SEEK_SET);
|
||||
}
|
||||
else
|
||||
{
|
||||
fseek (file, offset, SEEK_SET);
|
||||
}
|
||||
if (len < 32)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (fread (id, 4, 32/4, file) != 32/4)
|
||||
{
|
||||
fclose (file);
|
||||
return 0;
|
||||
}
|
||||
fseek (file, -32, SEEK_CUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
file = NULL;
|
||||
if (len < 32)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < 32/4; ++i)
|
||||
{
|
||||
id[i] = ((DWORD *)musiccache)[i];
|
||||
}
|
||||
}
|
||||
if(reader->Read(id, 32) != 32 || reader->Seek(-32, SEEK_CUR) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_FMOD
|
||||
|
@ -440,39 +401,34 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
|
|||
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[0] & 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;
|
||||
for (i = 0; i < 32/4; ++i)
|
||||
{
|
||||
id[i] = ((DWORD *)musiccache)[i];
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
if ((id[0] & MAKE_ID(255,255,255,0)) == GZIP_ID)
|
||||
{
|
||||
int len = reader->GetLength();
|
||||
BYTE *gzipped = new BYTE[len];
|
||||
if (reader->Read(gzipped, len) != len)
|
||||
{
|
||||
delete[] gzipped;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::auto_ptr<MemoryArrayReader> reader2(new MemoryArrayReader(NULL, 0));
|
||||
if(!ungzip(gzipped, len, reader2->GetArray()))
|
||||
{
|
||||
delete[] gzipped;
|
||||
return 0;
|
||||
}
|
||||
delete[] gzipped;
|
||||
reader2->UpdateLength();
|
||||
|
||||
reader.reset(reader2.release());
|
||||
if(reader->Read(id, 32) != 32 || reader->Seek(-32, SEEK_CUR) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
|
||||
if (miditype != MIDI_NOTMIDI)
|
||||
|
@ -480,7 +436,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
|
|||
EMidiDevice devtype = (EMidiDevice)device;
|
||||
|
||||
retry_as_fmod:
|
||||
info = CreateMIDIStreamer(file, musiccache, len, devtype, miditype);
|
||||
info = CreateMIDIStreamer(reader, devtype, miditype);
|
||||
if (info != NULL && !info->IsValid())
|
||||
{
|
||||
delete info;
|
||||
|
@ -494,7 +450,7 @@ retry_as_fmod:
|
|||
#ifdef _WIN32
|
||||
if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0)
|
||||
{
|
||||
info = CreateMIDIStreamer(file, musiccache, len, MDEV_MMAPI, miditype);
|
||||
info = CreateMIDIStreamer(reader, MDEV_MMAPI, miditype);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -505,74 +461,57 @@ retry_as_fmod:
|
|||
(id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL
|
||||
(id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF
|
||||
{
|
||||
info = new OPLMUSSong (file, musiccache, len);
|
||||
info = new OPLMUSSong (reader);
|
||||
}
|
||||
// Check for game music
|
||||
else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0')
|
||||
{
|
||||
info = GME_OpenSong(file, musiccache, len, fmt);
|
||||
info = GME_OpenSong(reader, fmt);
|
||||
}
|
||||
// Check for module formats
|
||||
else
|
||||
{
|
||||
info = MOD_OpenSong(file, musiccache, len);
|
||||
info = MOD_OpenSong(reader);
|
||||
}
|
||||
|
||||
if (info == NULL)
|
||||
{
|
||||
// Check for CDDA "format"
|
||||
if (id[0] == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24)))
|
||||
{
|
||||
if (file != NULL)
|
||||
{
|
||||
DWORD subid;
|
||||
if (info == NULL)
|
||||
{
|
||||
// Check for CDDA "format"
|
||||
if (id[0] == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24)))
|
||||
{
|
||||
DWORD subid;
|
||||
|
||||
fseek (file, 8, SEEK_CUR);
|
||||
if (fread (&subid, 4, 1, file) != 1)
|
||||
{
|
||||
fclose (file);
|
||||
return 0;
|
||||
}
|
||||
fseek (file, -12, SEEK_CUR);
|
||||
reader->Seek(8, SEEK_CUR);
|
||||
if (reader->Read (&subid, 4) != 4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
reader->Seek(-12, SEEK_CUR);
|
||||
|
||||
if (subid == (('C')|(('D')<<8)|(('D')<<16)|(('A')<<24)))
|
||||
{
|
||||
// This is a CDDA file
|
||||
info = new CDDAFile (file, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (subid == (('C')|(('D')<<8)|(('D')<<16)|(('A')<<24)))
|
||||
{
|
||||
// This is a CDDA file
|
||||
info = new CDDAFile (reader);
|
||||
}
|
||||
}
|
||||
|
||||
// no FMOD => no modules/streams
|
||||
// 1024 bytes is an arbitrary restriction. It's assumed that anything
|
||||
// smaller than this can't possibly be a valid music file if it hasn't
|
||||
// been identified already, so don't even bother trying to load it.
|
||||
// Of course MIDIs shorter than 1024 bytes should pass.
|
||||
if (info == NULL && (len >= 1024 || id[0] == MAKE_ID('M','T','h','d')))
|
||||
{
|
||||
// Let FMOD figure out what it is.
|
||||
if (file != NULL)
|
||||
{
|
||||
fclose (file);
|
||||
file = NULL;
|
||||
}
|
||||
info = new StreamSong (offset >= 0 ? filename : (const char *)musiccache, offset, len);
|
||||
}
|
||||
}
|
||||
// no FMOD => no modules/streams
|
||||
// 1024 bytes is an arbitrary restriction. It's assumed that anything
|
||||
// smaller than this can't possibly be a valid music file if it hasn't
|
||||
// been identified already, so don't even bother trying to load it.
|
||||
// Of course MIDIs shorter than 1024 bytes should pass.
|
||||
if (info == NULL && (reader->GetLength() >= 1024 || id[0] == MAKE_ID('M','T','h','d')))
|
||||
{
|
||||
// Let FMOD figure out what it is.
|
||||
info = new StreamSong (reader);
|
||||
}
|
||||
}
|
||||
|
||||
if (info && !info->IsValid ())
|
||||
{
|
||||
delete info;
|
||||
info = NULL;
|
||||
}
|
||||
if (file != NULL)
|
||||
{
|
||||
fclose (file);
|
||||
}
|
||||
if (ungzipped != NULL)
|
||||
{
|
||||
delete[] ungzipped;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
@ -606,7 +545,7 @@ MusInfo *I_RegisterURLSong (const char *url)
|
|||
{
|
||||
StreamSong *song;
|
||||
|
||||
song = new StreamSong(url, 0, 0);
|
||||
song = new StreamSong(url);
|
||||
if (song->IsValid())
|
||||
{
|
||||
return song;
|
||||
|
@ -624,13 +563,12 @@ MusInfo *I_RegisterURLSong (const char *url)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
BYTE *ungzip(BYTE *data, int *complen)
|
||||
static bool ungzip(BYTE *data, int complen, TArray<BYTE> &newdata)
|
||||
{
|
||||
const BYTE *max = data + *complen - 8;
|
||||
const BYTE *max = data + complen - 8;
|
||||
const BYTE *compstart = data + 10;
|
||||
BYTE flags = data[3];
|
||||
unsigned isize;
|
||||
BYTE *newdata;
|
||||
z_stream stream;
|
||||
int err;
|
||||
|
||||
|
@ -659,16 +597,16 @@ BYTE *ungzip(BYTE *data, int *complen)
|
|||
}
|
||||
if (compstart >= max - 1)
|
||||
{
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decompress
|
||||
isize = LittleLong(*(DWORD *)(data + *complen - 4));
|
||||
newdata = new BYTE[isize];
|
||||
isize = LittleLong(*(DWORD *)(data + complen - 4));
|
||||
newdata.Resize(isize);
|
||||
|
||||
stream.next_in = (Bytef *)compstart;
|
||||
stream.avail_in = (uInt)(max - compstart);
|
||||
stream.next_out = newdata;
|
||||
stream.next_out = &newdata[0];
|
||||
stream.avail_out = isize;
|
||||
stream.zalloc = (alloc_func)0;
|
||||
stream.zfree = (free_func)0;
|
||||
|
@ -676,25 +614,20 @@ BYTE *ungzip(BYTE *data, int *complen)
|
|||
err = inflateInit2(&stream, -MAX_WBITS);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
delete[] newdata;
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
err = inflate(&stream, Z_FINISH);
|
||||
if (err != Z_STREAM_END)
|
||||
{
|
||||
inflateEnd(&stream);
|
||||
delete[] newdata;
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
err = inflateEnd(&stream);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
delete[] newdata;
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
*complen = isize;
|
||||
return newdata;
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#ifndef __I_MUSIC_H__
|
||||
#define __I_MUSIC_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "doomdef.h"
|
||||
|
||||
class FileReader;
|
||||
|
@ -52,7 +54,7 @@ void I_SetMusicVolume (float volume);
|
|||
|
||||
// Registers a song handle to song data.
|
||||
class MusInfo;
|
||||
MusInfo *I_RegisterSong (const char *file, BYTE *musiccache, int offset, int length, int device);
|
||||
MusInfo *I_RegisterSong (std::auto_ptr<FileReader> reader, int device);
|
||||
MusInfo *I_RegisterCDSong (int track, int cdid = 0);
|
||||
MusInfo *I_RegisterURLSong (const char *url);
|
||||
|
||||
|
|
|
@ -501,7 +501,7 @@ protected:
|
|||
class MUSSong2 : public MIDIStreamer
|
||||
{
|
||||
public:
|
||||
MUSSong2(FILE *file, BYTE *musiccache, int length, EMidiDevice type);
|
||||
MUSSong2(std::auto_ptr<FileReader> reader, EMidiDevice type);
|
||||
~MUSSong2();
|
||||
|
||||
MusInfo *GetOPLDumper(const char *filename);
|
||||
|
@ -527,7 +527,7 @@ protected:
|
|||
class MIDISong2 : public MIDIStreamer
|
||||
{
|
||||
public:
|
||||
MIDISong2(FILE *file, BYTE *musiccache, int length, EMidiDevice type);
|
||||
MIDISong2(std::auto_ptr<FileReader> reader, EMidiDevice type);
|
||||
~MIDISong2();
|
||||
|
||||
MusInfo *GetOPLDumper(const char *filename);
|
||||
|
@ -584,7 +584,7 @@ protected:
|
|||
class HMISong : public MIDIStreamer
|
||||
{
|
||||
public:
|
||||
HMISong(FILE *file, BYTE *musiccache, int length, EMidiDevice type);
|
||||
HMISong(std::auto_ptr<FileReader> reader, EMidiDevice type);
|
||||
~HMISong();
|
||||
|
||||
MusInfo *GetOPLDumper(const char *filename);
|
||||
|
@ -627,7 +627,7 @@ protected:
|
|||
class XMISong : public MIDIStreamer
|
||||
{
|
||||
public:
|
||||
XMISong(FILE *file, BYTE *musiccache, int length, EMidiDevice type);
|
||||
XMISong(std::auto_ptr<FileReader> reader, EMidiDevice type);
|
||||
~XMISong();
|
||||
|
||||
MusInfo *GetOPLDumper(const char *filename);
|
||||
|
@ -666,7 +666,8 @@ protected:
|
|||
class StreamSong : public MusInfo
|
||||
{
|
||||
public:
|
||||
StreamSong (const char *file, int offset, int length);
|
||||
StreamSong (std::auto_ptr<FileReader> reader);
|
||||
StreamSong (const char *url);
|
||||
~StreamSong ();
|
||||
void Play (bool looping, int subsong);
|
||||
void Pause ();
|
||||
|
@ -689,7 +690,7 @@ protected:
|
|||
class OPLMUSSong : public StreamSong
|
||||
{
|
||||
public:
|
||||
OPLMUSSong (FILE *file, BYTE *musiccache, int length);
|
||||
OPLMUSSong (std::auto_ptr<FileReader> reader);
|
||||
~OPLMUSSong ();
|
||||
void Play (bool looping, int subsong);
|
||||
bool IsPlaying ();
|
||||
|
@ -738,17 +739,17 @@ protected:
|
|||
class CDDAFile : public CDSong
|
||||
{
|
||||
public:
|
||||
CDDAFile (FILE *file, int length);
|
||||
CDDAFile (std::auto_ptr<FileReader> reader);
|
||||
};
|
||||
|
||||
// Module played via foo_dumb -----------------------------------------------
|
||||
|
||||
MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int len);
|
||||
MusInfo *MOD_OpenSong(std::auto_ptr<FileReader> &reader);
|
||||
|
||||
// Music played via Game Music Emu ------------------------------------------
|
||||
|
||||
const char *GME_CheckFormat(uint32 header);
|
||||
MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt);
|
||||
MusInfo *GME_OpenSong(std::auto_ptr<FileReader> &reader, const char *fmt);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ public:
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
SoundStream *OpenStream (const char *filename, int flags, int offset, int length)
|
||||
SoundStream *OpenStream (std::auto_ptr<FileReader> reader, int flags)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -344,12 +344,13 @@ FString SoundRenderer::GatherStats ()
|
|||
|
||||
short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType ctype)
|
||||
{
|
||||
MemoryReader reader((const char*)coded, sizebytes);
|
||||
short *samples = (short*)calloc(1, outlen);
|
||||
ChannelConfig chans;
|
||||
SampleType type;
|
||||
int srate;
|
||||
|
||||
std::auto_ptr<SoundDecoder> decoder(CreateDecoder((const BYTE*)coded, sizebytes));
|
||||
std::auto_ptr<SoundDecoder> decoder(CreateDecoder(&reader));
|
||||
if(!decoder.get()) return samples;
|
||||
|
||||
decoder->getInfo(&srate, &chans, &type);
|
||||
|
@ -540,44 +541,30 @@ SoundHandle SoundRenderer::LoadSoundVoc(BYTE *sfxdata, int length)
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length)
|
||||
SoundStream *SoundRenderer::OpenStream(const char *url, int flags)
|
||||
{
|
||||
SoundDecoder *decoder = NULL;
|
||||
#ifdef HAVE_MPG123
|
||||
decoder = new MPG123Decoder;
|
||||
if(decoder->open((const char*)sfxdata, length))
|
||||
return decoder;
|
||||
|
||||
delete decoder;
|
||||
decoder = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_SNDFILE
|
||||
decoder = new SndFileDecoder;
|
||||
if(decoder->open((const char*)sfxdata, length))
|
||||
return decoder;
|
||||
|
||||
delete decoder;
|
||||
decoder = NULL;
|
||||
#endif
|
||||
return decoder;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SoundDecoder* SoundRenderer::CreateDecoder(const char *fname, int offset, int length)
|
||||
SoundDecoder *SoundRenderer::CreateDecoder(FileReader *reader)
|
||||
{
|
||||
SoundDecoder *decoder = NULL;
|
||||
int pos = reader->Tell();
|
||||
|
||||
#ifdef HAVE_MPG123
|
||||
decoder = new MPG123Decoder;
|
||||
if(decoder->open(fname, offset, length))
|
||||
if(decoder->open(reader))
|
||||
return decoder;
|
||||
reader->Seek(pos, SEEK_SET);
|
||||
|
||||
delete decoder;
|
||||
decoder = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_SNDFILE
|
||||
decoder = new SndFileDecoder;
|
||||
if(decoder->open(fname, offset, length))
|
||||
if(decoder->open(reader))
|
||||
return decoder;
|
||||
reader->Seek(pos, SEEK_SET);
|
||||
|
||||
delete decoder;
|
||||
decoder = NULL;
|
||||
|
|
|
@ -35,9 +35,13 @@
|
|||
#ifndef __I_SOUND__
|
||||
#define __I_SOUND__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "i_soundinternal.h"
|
||||
|
||||
class FileReader;
|
||||
|
||||
enum ECodecType
|
||||
{
|
||||
CODEC_Unknown,
|
||||
|
@ -103,7 +107,8 @@ public:
|
|||
|
||||
// Streaming sounds.
|
||||
virtual SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) = 0;
|
||||
virtual SoundStream *OpenStream (const char *filename, int flags, int offset, int length) = 0;
|
||||
virtual SoundStream *OpenStream (std::auto_ptr<FileReader> reader, int flags) = 0;
|
||||
virtual SoundStream *OpenStream (const char *url, int flags);
|
||||
|
||||
// Starts a sound.
|
||||
virtual FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) = 0;
|
||||
|
@ -154,8 +159,7 @@ public:
|
|||
virtual void DrawWaveDebug(int mode);
|
||||
|
||||
protected:
|
||||
virtual SoundDecoder *CreateDecoder(const BYTE *sfxdata, int length);
|
||||
virtual SoundDecoder *CreateDecoder(const char *fname, int offset, int length);
|
||||
virtual SoundDecoder *CreateDecoder(FileReader *reader);
|
||||
};
|
||||
|
||||
extern SoundRenderer *GSnd;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "basictypes.h"
|
||||
#include "vectors.h"
|
||||
|
||||
class FileReader;
|
||||
|
||||
// For convenience, this structure matches FMOD_REVERB_PROPERTIES.
|
||||
// Since I can't very well #include system-specific stuff in the
|
||||
// main game files, I duplicate it here.
|
||||
|
@ -129,8 +131,7 @@ struct SoundDecoder
|
|||
virtual ~SoundDecoder() { }
|
||||
|
||||
protected:
|
||||
virtual bool open(const char *data, size_t length) = 0;
|
||||
virtual bool open(const char *fname, size_t offset, size_t length) = 0;
|
||||
virtual bool open(FileReader *reader) = 0;
|
||||
friend class SoundRenderer;
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "mpg123_decoder.h"
|
||||
#include "files.h"
|
||||
|
||||
#ifdef HAVE_MPG123
|
||||
static bool inited = false;
|
||||
|
@ -7,99 +8,30 @@ static bool inited = false;
|
|||
off_t MPG123Decoder::file_lseek(void *handle, off_t offset, int whence)
|
||||
{
|
||||
MPG123Decoder *self = reinterpret_cast<MPG123Decoder*>(handle);
|
||||
FileReader *reader = self->Reader;
|
||||
|
||||
long cur = ftell(self->File);
|
||||
if(cur < 0) return -1;
|
||||
|
||||
switch(whence)
|
||||
if(whence == SEEK_SET)
|
||||
offset += self->StartOffset;
|
||||
else if(whence == SEEK_CUR)
|
||||
{
|
||||
case SEEK_SET:
|
||||
if(offset < 0 || offset > (off_t)self->FileLength)
|
||||
return -1;
|
||||
cur = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
cur -= self->FileOffset;
|
||||
if((offset > 0 && (off_t)(self->FileLength-cur) < offset) ||
|
||||
(offset < 0 && (off_t)cur < -offset))
|
||||
return -1;
|
||||
cur += offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
if(offset > 0 || -offset > (off_t)self->FileLength)
|
||||
return -1;
|
||||
cur = self->FileLength + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
if(offset < 0 && reader->Tell()+offset < self->StartOffset)
|
||||
return -1;
|
||||
}
|
||||
else if(whence == SEEK_END)
|
||||
{
|
||||
if(offset < 0 && reader->GetLength()+offset < self->StartOffset)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(fseek(self->File, cur + self->FileOffset, SEEK_SET) != 0)
|
||||
if(reader->Seek(offset, whence) != 0)
|
||||
return -1;
|
||||
return cur;
|
||||
return reader->Tell() - self->StartOffset;
|
||||
}
|
||||
|
||||
ssize_t MPG123Decoder::file_read(void *handle, void *buffer, size_t bytes)
|
||||
{
|
||||
MPG123Decoder *self = reinterpret_cast<MPG123Decoder*>(handle);
|
||||
|
||||
long cur = ftell(self->File);
|
||||
if(cur < 0) return -1;
|
||||
|
||||
cur -= self->FileOffset;
|
||||
if(bytes > (size_t)(self->FileLength-cur))
|
||||
bytes = self->FileLength-cur;
|
||||
|
||||
return fread(buffer, 1, bytes, self->File);
|
||||
}
|
||||
|
||||
|
||||
off_t MPG123Decoder::mem_lseek(void *handle, off_t offset, int whence)
|
||||
{
|
||||
MPG123Decoder *self = reinterpret_cast<MPG123Decoder*>(handle);
|
||||
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
if(offset < 0 || offset > (off_t)self->MemLength)
|
||||
return -1;
|
||||
self->MemPos = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
if((offset > 0 && (off_t)(self->MemLength-self->MemPos) < offset) ||
|
||||
(offset < 0 && (off_t)self->MemPos < -offset))
|
||||
return -1;
|
||||
self->MemPos += offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
if(offset > 0 || -offset > (off_t)self->MemLength)
|
||||
return -1;
|
||||
self->MemPos = self->MemLength + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return self->MemPos;
|
||||
}
|
||||
|
||||
ssize_t MPG123Decoder::mem_read(void *handle, void *buffer, size_t bytes)
|
||||
{
|
||||
MPG123Decoder *self = reinterpret_cast<MPG123Decoder*>(handle);
|
||||
|
||||
if(bytes > self->MemLength-self->MemPos)
|
||||
bytes = self->MemLength-self->MemPos;
|
||||
|
||||
memcpy(buffer, self->MemData+self->MemPos, bytes);
|
||||
self->MemPos += bytes;
|
||||
|
||||
return bytes;
|
||||
FileReader *reader = reinterpret_cast<MPG123Decoder*>(handle)->Reader;
|
||||
return reader->Read(buffer, bytes);
|
||||
}
|
||||
|
||||
|
||||
|
@ -111,12 +43,9 @@ MPG123Decoder::~MPG123Decoder()
|
|||
mpg123_delete(MPG123);
|
||||
MPG123 = 0;
|
||||
}
|
||||
if(File)
|
||||
fclose(File);
|
||||
File = 0;
|
||||
}
|
||||
|
||||
bool MPG123Decoder::open(const char *data, size_t length)
|
||||
bool MPG123Decoder::open(FileReader *reader)
|
||||
{
|
||||
if(!inited)
|
||||
{
|
||||
|
@ -125,91 +54,14 @@ bool MPG123Decoder::open(const char *data, size_t length)
|
|||
inited = true;
|
||||
}
|
||||
|
||||
// Check for ID3 tags and skip them
|
||||
if(length > 10 && memcmp(data, "ID3", 3) == 0 &&
|
||||
(BYTE)data[3] <= 4 && (BYTE)data[4] != 0xff &&
|
||||
(data[5]&0x0f) == 0 && (data[6]&0x80) == 0 &&
|
||||
(data[7]&0x80) == 0 && (data[8]&0x80) == 0 &&
|
||||
(data[9]&0x80) == 0)
|
||||
{
|
||||
// ID3v2
|
||||
int start_offset;
|
||||
start_offset = (data[6]<<21) | (data[7]<<14) |
|
||||
(data[8]<< 7) | (data[9] );
|
||||
start_offset += ((data[5]&0x10) ? 20 : 10);
|
||||
length -= start_offset;
|
||||
data += start_offset;
|
||||
}
|
||||
|
||||
if(length > 128 && memcmp(data+length-128, "TAG", 3) == 0) // ID3v1
|
||||
length -= 128;
|
||||
|
||||
// Check for a frame header
|
||||
bool frame_ok = false;
|
||||
if(length > 3)
|
||||
{
|
||||
if((BYTE)data[0] == 0xff &&
|
||||
((data[1]&0xfe) == 0xfa/*MPEG-1*/ || (data[1]&0xfe) == 0xf2/*MPEG-2*/))
|
||||
{
|
||||
int brate_idx = (data[2]>>4) & 0x0f;
|
||||
int srate_idx = (data[2]>>2) & 0x03;
|
||||
if(brate_idx != 0 && brate_idx != 15 && srate_idx != 3)
|
||||
frame_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(frame_ok)
|
||||
{
|
||||
MemData = data;
|
||||
MemPos = 0;
|
||||
MemLength = length;
|
||||
|
||||
MPG123 = mpg123_new(NULL, NULL);
|
||||
if(mpg123_replace_reader_handle(MPG123, mem_read, mem_lseek, NULL) == MPG123_OK &&
|
||||
mpg123_open_handle(MPG123, this) == MPG123_OK)
|
||||
{
|
||||
int enc, channels;
|
||||
long srate;
|
||||
|
||||
if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK)
|
||||
{
|
||||
if((channels == 1 || channels == 2) && srate > 0 &&
|
||||
mpg123_format_none(MPG123) == MPG123_OK &&
|
||||
mpg123_format(MPG123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK)
|
||||
{
|
||||
// All OK
|
||||
Done = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mpg123_close(MPG123);
|
||||
}
|
||||
mpg123_delete(MPG123);
|
||||
MPG123 = 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MPG123Decoder::open(const char *fname, size_t offset, size_t length)
|
||||
{
|
||||
if(!inited)
|
||||
{
|
||||
if(mpg123_init() != MPG123_OK)
|
||||
return false;
|
||||
inited = true;
|
||||
}
|
||||
|
||||
FileLength = length;
|
||||
FileOffset = offset;
|
||||
File = fopen(fname, "rb");
|
||||
if(!File || fseek(File, FileOffset, SEEK_SET) != 0)
|
||||
return false;
|
||||
Reader = reader;
|
||||
StartOffset = 0;
|
||||
|
||||
char data[10];
|
||||
if(file_read(this, data, 10) != 10)
|
||||
return false;
|
||||
|
||||
int start_offset = 0;
|
||||
// Check for ID3 tags and skip them
|
||||
if(memcmp(data, "ID3", 3) == 0 &&
|
||||
(BYTE)data[3] <= 4 && (BYTE)data[4] != 0xff &&
|
||||
|
@ -218,25 +70,18 @@ bool MPG123Decoder::open(const char *fname, size_t offset, size_t length)
|
|||
(data[9]&0x80) == 0)
|
||||
{
|
||||
// ID3v2
|
||||
int start_offset;
|
||||
start_offset = (data[6]<<21) | (data[7]<<14) |
|
||||
(data[8]<< 7) | (data[9] );
|
||||
start_offset += ((data[5]&0x10) ? 20 : 10);
|
||||
offset += start_offset;
|
||||
length -= start_offset;
|
||||
}
|
||||
|
||||
if(file_lseek(this, -128, SEEK_END) > 0 && memcmp(data, "TAG", 3) == 0) // ID3v1
|
||||
length -= 128;
|
||||
|
||||
FileLength = length;
|
||||
FileOffset = offset;
|
||||
StartOffset = start_offset;
|
||||
if(file_lseek(this, 0, SEEK_SET) != 0)
|
||||
return false;
|
||||
|
||||
// Check for a frame header
|
||||
bool frame_ok = false;
|
||||
if(file_read(this, data, 3) != 3)
|
||||
if(file_read(this, data, 3) == 3)
|
||||
{
|
||||
if((BYTE)data[0] == 0xff &&
|
||||
((data[1]&0xfe) == 0xfa/*MPEG-1*/ || (data[1]&0xfe) == 0xf2/*MPEG-2*/))
|
||||
|
|
|
@ -15,29 +15,21 @@ struct MPG123Decoder : public SoundDecoder
|
|||
virtual bool seek(size_t ms_offset);
|
||||
virtual size_t getSampleOffset();
|
||||
|
||||
MPG123Decoder() : MPG123(0), File(0) { }
|
||||
MPG123Decoder() : MPG123(0) { }
|
||||
virtual ~MPG123Decoder();
|
||||
|
||||
protected:
|
||||
virtual bool open(const char *data, size_t length);
|
||||
virtual bool open(const char *fname, size_t offset, size_t length);
|
||||
virtual bool open(FileReader *reader);
|
||||
|
||||
private:
|
||||
mpg123_handle *MPG123;
|
||||
bool Done;
|
||||
|
||||
FILE *File;
|
||||
size_t FileLength;
|
||||
size_t FileOffset;
|
||||
FileReader *Reader;
|
||||
int StartOffset;
|
||||
static off_t file_lseek(void *handle, off_t offset, int whence);
|
||||
static ssize_t file_read(void *handle, void *buffer, size_t bytes);
|
||||
|
||||
const char *MemData;
|
||||
size_t MemLength;
|
||||
size_t MemPos;
|
||||
static off_t mem_lseek(void *handle, off_t offset, int whence);
|
||||
static ssize_t mem_read(void *handle, void *buffer, size_t bytes);
|
||||
|
||||
// Make non-copyable
|
||||
MPG123Decoder(const MPG123Decoder &rhs);
|
||||
MPG123Decoder& operator=(const MPG123Decoder &rhs);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "i_musicinterns.h"
|
||||
#include "i_cd.h"
|
||||
#include "files.h"
|
||||
|
||||
void CDSong::Play (bool looping, int subsong)
|
||||
{
|
||||
|
@ -78,31 +79,31 @@ bool CDSong::IsPlaying ()
|
|||
return m_Status != STATE_Stopped;
|
||||
}
|
||||
|
||||
CDDAFile::CDDAFile (FILE *file, int length)
|
||||
CDDAFile::CDDAFile (std::auto_ptr<FileReader> reader)
|
||||
: CDSong ()
|
||||
{
|
||||
DWORD chunk;
|
||||
WORD track;
|
||||
DWORD discid;
|
||||
long endpos = ftell (file) + length - 8;
|
||||
long endpos = reader->Tell() + reader->GetLength() - 8;
|
||||
|
||||
// I_RegisterSong already identified this as a CDDA file, so we
|
||||
// just need to check the contents we're interested in.
|
||||
fseek (file, 12, SEEK_CUR);
|
||||
reader->Seek(12, SEEK_CUR);
|
||||
|
||||
while (ftell (file) < endpos)
|
||||
while (reader->Tell() < endpos)
|
||||
{
|
||||
fread (&chunk, 4, 1, file);
|
||||
reader->Read(&chunk, 4);
|
||||
if (chunk != (('f')|(('m')<<8)|(('t')<<16)|((' ')<<24)))
|
||||
{
|
||||
fread (&chunk, 4, 1, file);
|
||||
fseek (file, chunk, SEEK_CUR);
|
||||
reader->Read(&chunk, 4);
|
||||
reader->Seek(chunk, SEEK_CUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
fseek (file, 6, SEEK_CUR);
|
||||
fread (&track, 2, 1, file);
|
||||
fread (&discid, 4, 1, file);
|
||||
reader->Seek(6, SEEK_CUR);
|
||||
reader->Read(&track, 2);
|
||||
reader->Read(&discid, 4);
|
||||
|
||||
if (CD_InitID (discid) && CD_CheckTrack (track))
|
||||
{
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "c_cvars.h"
|
||||
#include "i_sound.h"
|
||||
#include "i_system.h"
|
||||
#include "files.h"
|
||||
|
||||
#undef CDECL // w32api's windef.h defines this
|
||||
#include "../dumb/include/dumb.h"
|
||||
|
@ -512,31 +513,24 @@ static DUMBFILE_SYSTEM mem_dfs = {
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, FILE *file, BYTE *musiccache, int lenhave, int lenfull)
|
||||
DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, std::auto_ptr<FileReader> &reader, int lenhave, int lenfull)
|
||||
{
|
||||
filestate->size = lenfull;
|
||||
filestate->offset = 0;
|
||||
if (lenhave >= lenfull)
|
||||
{
|
||||
filestate->ptr = (BYTE *)start;
|
||||
return dumbfile_open_ex(filestate, &mem_dfs);
|
||||
}
|
||||
if (musiccache != NULL)
|
||||
{
|
||||
filestate->ptr = (BYTE *)musiccache;
|
||||
}
|
||||
else
|
||||
{
|
||||
BYTE *mem = new BYTE[lenfull];
|
||||
memcpy(mem, start, lenhave);
|
||||
if (fread(mem + lenhave, 1, lenfull - lenhave, file) != (size_t)(lenfull - lenhave))
|
||||
{
|
||||
delete[] mem;
|
||||
return NULL;
|
||||
}
|
||||
filestate->ptr = mem;
|
||||
}
|
||||
return dumbfile_open_ex(filestate, &mem_dfs);
|
||||
else
|
||||
{
|
||||
BYTE *mem = new BYTE[lenfull];
|
||||
memcpy(mem, start, lenhave);
|
||||
if (reader->Read(mem + lenhave, lenfull - lenhave) != (lenfull - lenhave))
|
||||
{
|
||||
delete[] mem;
|
||||
return NULL;
|
||||
}
|
||||
filestate->ptr = mem;
|
||||
}
|
||||
return dumbfile_open_ex(filestate, &mem_dfs);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -856,7 +850,7 @@ static void MOD_SetAutoChip(DUH *duh)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
||||
MusInfo *MOD_OpenSong(std::auto_ptr<FileReader> &reader)
|
||||
{
|
||||
DUH *duh = 0;
|
||||
int headsize;
|
||||
|
@ -880,40 +874,36 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
|||
|
||||
atterm(dumb_exit);
|
||||
|
||||
int size = reader->GetLength();
|
||||
fpos = reader->Tell();
|
||||
|
||||
filestate.ptr = start;
|
||||
filestate.offset = 0;
|
||||
headsize = MIN((int)sizeof(start), size);
|
||||
if (musiccache != NULL)
|
||||
{
|
||||
memcpy(start, musiccache, headsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpos = ftell(file);
|
||||
if ((size_t)headsize != fread(start, 1, headsize, file))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (headsize != reader->Read(start, headsize))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size >= 4 && dstart[0] == MAKE_ID('I','M','P','M'))
|
||||
{
|
||||
is_it = true;
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_it_quick(f);
|
||||
}
|
||||
}
|
||||
else if (size >= 17 && !memcmp(start, "Extended Module: ", 17))
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_xm_quick(f);
|
||||
}
|
||||
}
|
||||
else if (size >= 0x30 && dstart[11] == MAKE_ID('S','C','R','M'))
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_s3m_quick(f);
|
||||
}
|
||||
|
@ -924,7 +914,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
|||
!memcmp( &start[20], "BMOD2STM", 8 ) ||
|
||||
!memcmp( &start[20], "WUZAMOD!", 8 ) ) )
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_stm_quick(f);
|
||||
}
|
||||
|
@ -933,21 +923,21 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
|||
((start[0] == 0x69 && start[1] == 0x66) ||
|
||||
(start[0] == 0x4A && start[1] == 0x4E)))
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_669_quick(f);
|
||||
}
|
||||
}
|
||||
else if (size >= 0x30 && dstart[11] == MAKE_ID('P','T','M','F'))
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_ptm_quick(f);
|
||||
}
|
||||
}
|
||||
else if (size >= 4 && dstart[0] == MAKE_ID('P','S','M',' '))
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_psm_quick(f, 0/*start_order*/);
|
||||
/*start_order = 0;*/
|
||||
|
@ -955,14 +945,14 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
|||
}
|
||||
else if (size >= 4 && dstart[0] == (DWORD)MAKE_ID('P','S','M',254))
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_old_psm_quick(f);
|
||||
}
|
||||
}
|
||||
else if (size >= 3 && start[0] == 'M' && start[1] == 'T' && start[2] == 'M')
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_mtm_quick(f);
|
||||
}
|
||||
|
@ -972,7 +962,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
|||
dstart[2] == MAKE_ID('A','M',' ',' ') ||
|
||||
dstart[2] == MAKE_ID('A','M','F','F')))
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_riff_quick(f);
|
||||
}
|
||||
|
@ -981,7 +971,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
|||
!memcmp( start, "ASYLUM Music Format", 19 ) &&
|
||||
!memcmp( start + 19, " V1.0", 5 ) )
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_asy_quick(f);
|
||||
}
|
||||
|
@ -990,7 +980,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
|||
dstart[0] == MAKE_ID('O','K','T','A') &&
|
||||
dstart[1] == MAKE_ID('S','O','N','G'))
|
||||
{
|
||||
if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
duh = dumb_read_okt_quick(f);
|
||||
}
|
||||
|
@ -1001,12 +991,9 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
|||
is_dos = false;
|
||||
if (filestate.ptr == (BYTE *)start)
|
||||
{
|
||||
if (!(f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size)))
|
||||
if (!(f = dumb_read_allfile(&filestate, start, reader, headsize, size)))
|
||||
{
|
||||
if (file != NULL)
|
||||
{
|
||||
fseek(file, fpos, SEEK_SET);
|
||||
}
|
||||
reader->Seek(fpos, SEEK_SET);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1053,15 +1040,13 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size)
|
|||
else
|
||||
{
|
||||
// Reposition file pointer for other codecs to do their checks.
|
||||
if (file != NULL)
|
||||
{
|
||||
fseek(file, fpos, SEEK_SET);
|
||||
}
|
||||
reader->Seek(fpos, SEEK_SET);
|
||||
}
|
||||
if (filestate.ptr != (BYTE *)start && filestate.ptr != musiccache)
|
||||
if (filestate.ptr != (BYTE *)start)
|
||||
{
|
||||
delete[] const_cast<BYTE *>(filestate.ptr);
|
||||
}
|
||||
if(state) reader.reset();
|
||||
return state;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "critsec.h"
|
||||
#include <gme/gme.h>
|
||||
#include "v_text.h"
|
||||
#include "files.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -104,7 +105,7 @@ const char *GME_CheckFormat(uint32 id)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt)
|
||||
MusInfo *GME_OpenSong(std::auto_ptr<FileReader> &reader, const char *fmt)
|
||||
{
|
||||
gme_type_t type;
|
||||
gme_err_t err;
|
||||
|
@ -123,31 +124,29 @@ MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt)
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
int fpos = reader->Tell();
|
||||
int len = reader->GetLength();
|
||||
song = new BYTE[len];
|
||||
if (reader->Read(song, len) != len)
|
||||
{
|
||||
delete[] song;
|
||||
gme_delete(emu);
|
||||
reader->Seek(fpos, SEEK_SET);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = gme_load_data(emu, song, len);
|
||||
if (song != musiccache)
|
||||
{
|
||||
delete[] song;
|
||||
}
|
||||
delete[] song;
|
||||
|
||||
if (err != NULL)
|
||||
{
|
||||
Printf("Failed loading song: %s\n", err);
|
||||
gme_delete(emu);
|
||||
reader->Seek(fpos, SEEK_SET);
|
||||
return NULL;
|
||||
}
|
||||
reader.reset();
|
||||
return new GMESong(emu, sample_rate);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "m_swap.h"
|
||||
#include "files.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -127,7 +128,7 @@ extern char MIDI_CommonLengths[15];
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
||||
HMISong::HMISong (std::auto_ptr<FileReader> reader, EMidiDevice type)
|
||||
: MIDIStreamer(type), MusHeader(0), Tracks(0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
@ -136,6 +137,7 @@ HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
int len = reader->GetLength();
|
||||
if (len < 0x100)
|
||||
{ // Way too small to be HMI.
|
||||
return;
|
||||
|
@ -143,15 +145,8 @@ HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
MusHeader = new BYTE[len];
|
||||
SongLen = len;
|
||||
NumTracks = 0;
|
||||
if (file != NULL)
|
||||
{
|
||||
if (fread(MusHeader, 1, len, file) != (size_t)len)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(MusHeader, musiccache, len);
|
||||
}
|
||||
if (reader->Read(MusHeader, len) != len)
|
||||
return;
|
||||
|
||||
// Do some validation of the MIDI file
|
||||
if (memcmp(MusHeader, HMI_SONG_MAGIC, sizeof(HMI_SONG_MAGIC)) == 0)
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "m_swap.h"
|
||||
#include "files.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -91,7 +92,7 @@ static const BYTE CtrlTranslate[15] =
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
||||
MUSSong2::MUSSong2 (std::auto_ptr<FileReader> reader, EMidiDevice type)
|
||||
: MIDIStreamer(type), MusHeader(0), MusBuffer(0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
@ -104,11 +105,7 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
BYTE front[32];
|
||||
int start;
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
memcpy(front, musiccache, sizeof(front));
|
||||
}
|
||||
else if (fread(front, 1, sizeof(front), file) != sizeof(front))
|
||||
if (reader->Read(front, sizeof(front)) != sizeof(front))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -124,24 +121,17 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
}
|
||||
|
||||
// Read the remainder of the song.
|
||||
len = int(len - start);
|
||||
int len = int(reader->GetLength() - start);
|
||||
if (len < (int)sizeof(MusHeader))
|
||||
{ // It's too short.
|
||||
return;
|
||||
}
|
||||
MusHeader = (MUSHeader *)new BYTE[len];
|
||||
if (file == NULL)
|
||||
{
|
||||
memcpy(MusHeader, musiccache + start, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(MusHeader, front + start, sizeof(front) - start);
|
||||
if (fread((BYTE *)MusHeader + sizeof(front) - start, 1, len - (sizeof(front) - start), file) != (size_t)(len - (32 - start)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
memcpy(MusHeader, front + start, sizeof(front) - start);
|
||||
if (reader->Read((BYTE *)MusHeader + sizeof(front) - start, len - (sizeof(front) - start)) != (len - (32 - start)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Do some validation of the MUS file.
|
||||
if (LittleShort(MusHeader->NumChans) > 15)
|
||||
|
|
|
@ -22,11 +22,11 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
|
||||
CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
OPLMUSSong::OPLMUSSong (FILE *file, BYTE *musiccache, int len)
|
||||
OPLMUSSong::OPLMUSSong (std::auto_ptr<FileReader> reader)
|
||||
{
|
||||
int samples = int(OPL_SAMPLE_RATE / 14);
|
||||
|
||||
Music = new OPLmusicFile (file, musiccache, len);
|
||||
Music = new OPLmusicFile (reader.get());
|
||||
|
||||
m_Stream = GSnd->CreateStream (FillStream, samples*4,
|
||||
(opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "m_swap.h"
|
||||
#include "files.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -253,10 +254,12 @@ int FMODMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), v
|
|||
|
||||
bool FMODMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
|
||||
{
|
||||
TArray<BYTE> midi;
|
||||
std::auto_ptr<MemoryArrayReader> reader(new MemoryArrayReader(NULL, 0));
|
||||
song->CreateSMF(reader->GetArray(), looping ? 0 : 1);
|
||||
reader->UpdateLength();
|
||||
|
||||
song->CreateSMF(midi, looping ? 0 : 1);
|
||||
bLooping = looping;
|
||||
Stream = GSnd->OpenStream((char *)&midi[0], looping ? SoundStream::Loop : 0, -1, midi.Size());
|
||||
return false;
|
||||
bLooping = looping;
|
||||
Stream = GSnd->OpenStream(std::auto_ptr<FileReader>(reader.release()),
|
||||
looping ? SoundStream::Loop : 0);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "m_swap.h"
|
||||
#include "files.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -101,7 +102,7 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
||||
MIDISong2::MIDISong2 (std::auto_ptr<FileReader> reader, EMidiDevice type)
|
||||
: MIDIStreamer(type), MusHeader(0), Tracks(0)
|
||||
{
|
||||
int p;
|
||||
|
@ -113,17 +114,10 @@ MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
MusHeader = new BYTE[len];
|
||||
SongLen = len;
|
||||
if (file != NULL)
|
||||
{
|
||||
if (fread(MusHeader, 1, len, file) != (size_t)len)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(MusHeader, musiccache, len);
|
||||
}
|
||||
SongLen = reader->GetLength();
|
||||
MusHeader = new BYTE[SongLen];
|
||||
if (reader->Read(MusHeader, SongLen) != SongLen)
|
||||
return;
|
||||
|
||||
// Do some validation of the MIDI file
|
||||
if (MusHeader[4] != 0 || MusHeader[5] != 0 || MusHeader[6] != 0 || MusHeader[7] != 6)
|
||||
|
@ -153,7 +147,7 @@ MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
Tracks = new TrackInfo[NumTracks];
|
||||
|
||||
// Gather information about each track
|
||||
for (i = 0, p = 14; i < NumTracks && p < len + 8; ++i)
|
||||
for (i = 0, p = 14; i < NumTracks && p < SongLen + 8; ++i)
|
||||
{
|
||||
DWORD chunkLen =
|
||||
(MusHeader[p+4]<<24) |
|
||||
|
@ -161,9 +155,9 @@ MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
(MusHeader[p+6]<<8) |
|
||||
(MusHeader[p+7]);
|
||||
|
||||
if (chunkLen + p + 8 > (DWORD)len)
|
||||
if (chunkLen + p + 8 > (DWORD)SongLen)
|
||||
{ // Track too long, so truncate it
|
||||
chunkLen = len - p - 8;
|
||||
chunkLen = SongLen - p - 8;
|
||||
}
|
||||
|
||||
if (MusHeader[p+0] == 'M' &&
|
||||
|
|
|
@ -52,9 +52,14 @@ StreamSong::~StreamSong ()
|
|||
}
|
||||
}
|
||||
|
||||
StreamSong::StreamSong (const char *filename_or_data, int offset, int len)
|
||||
StreamSong::StreamSong (std::auto_ptr<FileReader> reader)
|
||||
{
|
||||
m_Stream = GSnd->OpenStream (filename_or_data, SoundStream::Loop, offset, len);
|
||||
m_Stream = GSnd->OpenStream (reader, SoundStream::Loop);
|
||||
}
|
||||
|
||||
StreamSong::StreamSong (const char *url)
|
||||
{
|
||||
m_Stream = GSnd->OpenStream (url, SoundStream::Loop);
|
||||
}
|
||||
|
||||
bool StreamSong::IsPlaying ()
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "m_swap.h"
|
||||
#include "files.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -107,7 +108,7 @@ extern char MIDI_CommonLengths[15];
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
||||
XMISong::XMISong (std::auto_ptr<FileReader> reader, EMidiDevice type)
|
||||
: MIDIStreamer(type), MusHeader(0), Songs(0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
@ -116,20 +117,13 @@ XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
MusHeader = new BYTE[len];
|
||||
SongLen = len;
|
||||
if (file != NULL)
|
||||
{
|
||||
if (fread(MusHeader, 1, len, file) != (size_t)len)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(MusHeader, musiccache, len);
|
||||
}
|
||||
SongLen = reader->GetLength();
|
||||
MusHeader = new BYTE[SongLen];
|
||||
if (reader->Read(MusHeader, SongLen) != SongLen)
|
||||
return;
|
||||
|
||||
// Find all the songs in this file.
|
||||
NumSongs = FindXMIDforms(MusHeader, len, NULL);
|
||||
NumSongs = FindXMIDforms(MusHeader, SongLen, NULL);
|
||||
if (NumSongs == 0)
|
||||
{
|
||||
return;
|
||||
|
@ -147,7 +141,7 @@ XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
|
||||
Songs = new TrackInfo[NumSongs];
|
||||
memset(Songs, 0, sizeof(*Songs) * NumSongs);
|
||||
FindXMIDforms(MusHeader, len, Songs);
|
||||
FindXMIDforms(MusHeader, SongLen, Songs);
|
||||
CurrSong = Songs;
|
||||
DPrintf("XMI song count: %d\n", NumSongs);
|
||||
}
|
||||
|
|
|
@ -156,6 +156,7 @@ class OpenALSoundStream : public SoundStream
|
|||
ALfloat Volume;
|
||||
|
||||
|
||||
std::auto_ptr<FileReader> Reader;
|
||||
std::vector<BYTE> DecoderData;
|
||||
std::auto_ptr<SoundDecoder> Decoder;
|
||||
static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user)
|
||||
|
@ -440,54 +441,13 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Init(const char *fname, int offset, int length, bool loop)
|
||||
bool Init(std::auto_ptr<FileReader> reader, bool loop)
|
||||
{
|
||||
if(!SetupSource())
|
||||
return false;
|
||||
|
||||
Decoder.reset(Renderer->CreateDecoder(fname, offset, length));
|
||||
if(!Decoder.get()) return false;
|
||||
|
||||
Callback = DecoderCallback;
|
||||
UserData = NULL;
|
||||
Format = AL_NONE;
|
||||
|
||||
ChannelConfig chans;
|
||||
SampleType type;
|
||||
int srate;
|
||||
|
||||
Decoder->getInfo(&srate, &chans, &type);
|
||||
if(chans == ChannelConfig_Mono)
|
||||
{
|
||||
if(type == SampleType_UInt8) Format = AL_FORMAT_MONO8;
|
||||
if(type == SampleType_Int16) Format = AL_FORMAT_MONO16;
|
||||
}
|
||||
if(chans == ChannelConfig_Stereo)
|
||||
{
|
||||
if(type == SampleType_UInt8) Format = AL_FORMAT_STEREO8;
|
||||
if(type == SampleType_Int16) Format = AL_FORMAT_STEREO16;
|
||||
}
|
||||
|
||||
if(Format == AL_NONE)
|
||||
{
|
||||
Printf("Unsupported audio format (0x%x / 0x%x)\n", chans, type);
|
||||
return false;
|
||||
}
|
||||
SampleRate = srate;
|
||||
Looping = loop;
|
||||
|
||||
Data.resize((size_t)(0.2 * SampleRate) * 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Init(const BYTE *data, int length, bool loop)
|
||||
{
|
||||
if(!SetupSource())
|
||||
return false;
|
||||
|
||||
DecoderData.insert(DecoderData.end(), data, data+length);
|
||||
Decoder.reset(Renderer->CreateDecoder(&DecoderData[0], DecoderData.size()));
|
||||
Reader = reader;
|
||||
Decoder.reset(Renderer->CreateDecoder(Reader.get()));
|
||||
if(!Decoder.get()) return false;
|
||||
|
||||
Callback = DecoderCallback;
|
||||
|
@ -949,12 +909,13 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre
|
|||
SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length)
|
||||
{
|
||||
SoundHandle retval = { NULL };
|
||||
MemoryReader reader((const char*)sfxdata, length);
|
||||
ALenum format = AL_NONE;
|
||||
ChannelConfig chans;
|
||||
SampleType type;
|
||||
int srate;
|
||||
|
||||
std::auto_ptr<SoundDecoder> decoder(CreateDecoder(sfxdata, length));
|
||||
std::auto_ptr<SoundDecoder> decoder(CreateDecoder(&reader));
|
||||
if(!decoder.get()) return retval;
|
||||
|
||||
decoder->getInfo(&srate, &chans, &type);
|
||||
|
@ -1031,15 +992,12 @@ SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int
|
|||
return stream.release();
|
||||
}
|
||||
|
||||
SoundStream *OpenALSoundRenderer::OpenStream(const char *filename, int flags, int offset, int length)
|
||||
SoundStream *OpenALSoundRenderer::OpenStream(std::auto_ptr<FileReader> reader, int flags)
|
||||
{
|
||||
std::auto_ptr<OpenALSoundStream> stream(new OpenALSoundStream(this));
|
||||
|
||||
bool loop = (flags&SoundStream::Loop);
|
||||
bool ok = ((offset == -1) ? stream->Init((const BYTE*)filename, length, loop) :
|
||||
stream->Init(filename, offset, length, loop));
|
||||
if(ok == false)
|
||||
return NULL;
|
||||
bool ok = stream->Init(reader, (flags&SoundStream::Loop));
|
||||
if(ok == false) return NULL;
|
||||
|
||||
return stream.release();
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
|
||||
// Streaming sounds.
|
||||
virtual SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata);
|
||||
virtual SoundStream *OpenStream(const char *filename, int flags, int offset, int length);
|
||||
virtual SoundStream *OpenStream(std::auto_ptr<FileReader> reader, int flags);
|
||||
|
||||
// Starts a sound.
|
||||
virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan);
|
||||
|
|
|
@ -1,62 +1,26 @@
|
|||
#include "sndfile_decoder.h"
|
||||
#include "files.h"
|
||||
|
||||
#ifdef HAVE_SNDFILE
|
||||
sf_count_t SndFileDecoder::file_get_filelen(void *user_data)
|
||||
{
|
||||
SndFileDecoder *self = reinterpret_cast<SndFileDecoder*>(user_data);
|
||||
return self->FileLength;
|
||||
FileReader *reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
return reader->GetLength();
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::file_seek(sf_count_t offset, int whence, void *user_data)
|
||||
{
|
||||
SndFileDecoder *self = reinterpret_cast<SndFileDecoder*>(user_data);
|
||||
FileReader *reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
|
||||
long cur = ftell(self->File);
|
||||
if(cur < 0) return -1;
|
||||
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
if(offset < 0 || offset > (sf_count_t)self->FileLength)
|
||||
return -1;
|
||||
cur = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
cur -= self->FileOffset;
|
||||
if((offset > 0 && (sf_count_t)(self->FileLength-cur) < offset) ||
|
||||
(offset < 0 && (sf_count_t)cur < -offset))
|
||||
return -1;
|
||||
cur += offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
if(offset > 0 || -offset > (sf_count_t)self->FileLength)
|
||||
return -1;
|
||||
cur = self->FileLength + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(fseek(self->File, cur + self->FileOffset, SEEK_SET) != 0)
|
||||
if(reader->Seek(offset, whence) != 0)
|
||||
return -1;
|
||||
return cur;
|
||||
return reader->Tell();
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::file_read(void *ptr, sf_count_t count, void *user_data)
|
||||
{
|
||||
SndFileDecoder *self = reinterpret_cast<SndFileDecoder*>(user_data);
|
||||
|
||||
long cur = ftell(self->File);
|
||||
if(cur < 0) return -1;
|
||||
|
||||
cur -= self->FileOffset;
|
||||
if(count > (sf_count_t)(self->FileLength-cur))
|
||||
count = self->FileLength-cur;
|
||||
|
||||
return fread(ptr, 1, count, self->File);
|
||||
FileReader *reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
return reader->Read(ptr, count);
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *user_data)
|
||||
|
@ -66,75 +30,8 @@ sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *u
|
|||
|
||||
sf_count_t SndFileDecoder::file_tell(void *user_data)
|
||||
{
|
||||
SndFileDecoder *self = reinterpret_cast<SndFileDecoder*>(user_data);
|
||||
|
||||
long cur = ftell(self->File);
|
||||
if(cur < 0 || (unsigned long)cur < self->FileLength)
|
||||
return -1;
|
||||
return cur - self->FileOffset;
|
||||
}
|
||||
|
||||
|
||||
sf_count_t SndFileDecoder::mem_get_filelen(void *user_data)
|
||||
{
|
||||
SndFileDecoder *self = reinterpret_cast<SndFileDecoder*>(user_data);
|
||||
return self->MemLength;
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::mem_seek(sf_count_t offset, int whence, void *user_data)
|
||||
{
|
||||
SndFileDecoder *self = reinterpret_cast<SndFileDecoder*>(user_data);
|
||||
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
if(offset < 0 || offset > (sf_count_t)self->MemLength)
|
||||
return -1;
|
||||
self->MemPos = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
if((offset > 0 && (sf_count_t)(self->MemLength-self->MemPos) < offset) ||
|
||||
(offset < 0 && (sf_count_t)self->MemPos < -offset))
|
||||
return -1;
|
||||
self->MemPos += offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
if(offset > 0 || -offset > (sf_count_t)self->MemLength)
|
||||
return -1;
|
||||
self->MemPos = self->MemLength + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return self->MemPos;
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::mem_read(void *ptr, sf_count_t count, void *user_data)
|
||||
{
|
||||
SndFileDecoder *self = reinterpret_cast<SndFileDecoder*>(user_data);
|
||||
|
||||
if(count > (sf_count_t)(self->MemLength-self->MemPos))
|
||||
count = self->MemLength-self->MemPos;
|
||||
|
||||
memcpy(ptr, self->MemData+self->MemPos, count);
|
||||
self->MemPos += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::mem_write(const void *ptr, sf_count_t count, void *user_data)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::mem_tell(void *user_data)
|
||||
{
|
||||
SndFileDecoder *self = reinterpret_cast<SndFileDecoder*>(user_data);
|
||||
return self->MemPos;
|
||||
FileReader *reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
return reader->Tell();
|
||||
}
|
||||
|
||||
|
||||
|
@ -143,18 +40,13 @@ SndFileDecoder::~SndFileDecoder()
|
|||
if(SndFile)
|
||||
sf_close(SndFile);
|
||||
SndFile = 0;
|
||||
if(File)
|
||||
fclose(File);
|
||||
File = 0;
|
||||
}
|
||||
|
||||
bool SndFileDecoder::open(const char *data, size_t length)
|
||||
bool SndFileDecoder::open(FileReader *reader)
|
||||
{
|
||||
SF_VIRTUAL_IO sfio = { mem_get_filelen, mem_seek, mem_read, mem_write, mem_tell };
|
||||
SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell };
|
||||
|
||||
MemData = data;
|
||||
MemPos = 0;
|
||||
MemLength = length;
|
||||
Reader = reader;
|
||||
SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this);
|
||||
if(SndFile)
|
||||
{
|
||||
|
@ -168,34 +60,6 @@ bool SndFileDecoder::open(const char *data, size_t length)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SndFileDecoder::open(const char *fname, size_t offset, size_t length)
|
||||
{
|
||||
SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell };
|
||||
|
||||
FileOffset = offset;
|
||||
FileLength = length;
|
||||
File = fopen(fname, "rb");
|
||||
if(File)
|
||||
{
|
||||
if(fseek(File, offset, SEEK_SET) == 0)
|
||||
{
|
||||
SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this);
|
||||
if(SndFile)
|
||||
{
|
||||
if(SndInfo.channels == 1 || SndInfo.channels == 2)
|
||||
return true;
|
||||
|
||||
sf_close(SndFile);
|
||||
SndFile = 0;
|
||||
}
|
||||
}
|
||||
fclose(File);
|
||||
File = 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SndFileDecoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
|
||||
{
|
||||
*samplerate = SndInfo.samplerate;
|
||||
|
|
|
@ -16,35 +16,23 @@ struct SndFileDecoder : public SoundDecoder
|
|||
virtual bool seek(size_t ms_offset);
|
||||
virtual size_t getSampleOffset();
|
||||
|
||||
SndFileDecoder() : SndFile(0), File(0) { }
|
||||
SndFileDecoder() : SndFile(0) { }
|
||||
virtual ~SndFileDecoder();
|
||||
|
||||
protected:
|
||||
virtual bool open(const char *data, size_t length);
|
||||
virtual bool open(const char *fname, size_t offset, size_t length);
|
||||
virtual bool open(FileReader *reader);
|
||||
|
||||
private:
|
||||
SNDFILE *SndFile;
|
||||
SF_INFO SndInfo;
|
||||
|
||||
FILE *File;
|
||||
size_t FileLength;
|
||||
size_t FileOffset;
|
||||
FileReader *Reader;
|
||||
static sf_count_t file_get_filelen(void *user_data);
|
||||
static sf_count_t file_seek(sf_count_t offset, int whence, void *user_data);
|
||||
static sf_count_t file_read(void *ptr, sf_count_t count, void *user_data);
|
||||
static sf_count_t file_write(const void *ptr, sf_count_t count, void *user_data);
|
||||
static sf_count_t file_tell(void *user_data);
|
||||
|
||||
const char *MemData;
|
||||
size_t MemLength;
|
||||
size_t MemPos;
|
||||
static sf_count_t mem_get_filelen(void *user_data);
|
||||
static sf_count_t mem_seek(sf_count_t offset, int whence, void *user_data);
|
||||
static sf_count_t mem_read(void *ptr, sf_count_t count, void *user_data);
|
||||
static sf_count_t mem_write(const void *ptr, sf_count_t count, void *user_data);
|
||||
static sf_count_t mem_tell(void *user_data);
|
||||
|
||||
// Make non-copyable
|
||||
SndFileDecoder(const SndFileDecoder &rhs);
|
||||
SndFileDecoder& operator=(const SndFileDecoder &rhs);
|
||||
|
|
Loading…
Reference in a new issue