diff --git a/src/files.cpp b/src/files.cpp index d7dfc2cbe..78936eba9 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -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(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); +} diff --git a/src/files.h b/src/files.h index ebe9665a4..52cda93f5 100644 --- a/src/files.h +++ b/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 &GetArray() { return buf; } + + void UpdateLength() { Length = buf.Size(); } + +protected: + TArray buf; +}; #endif diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index a528c10e2..f9b46a08d 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -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(len - 24, LittleLong(((DWORD *)scoredata)[4])) + 24; + ScoreLen = MIN(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(len - headersize, LittleLong(((DWORD *)scoredata)[3]) * 2) + headersize; + ScoreLen = MIN(ScoreLen - headersize, LittleLong(((DWORD *)scoredata)[3]) * 2) + headersize; } else { diff --git a/src/oplsynth/opl_mus_player.h b/src/oplsynth/opl_mus_player.h index b0eb4b6c8..8e675c5d8 100644 --- a/src/oplsynth/opl_mus_player.h +++ b/src/oplsynth/opl_mus_player.h @@ -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(); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index d1c313967..c84c539ca 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -26,6 +26,7 @@ #include #endif #include +#include #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 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); } } diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 081401300..fa442603e 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -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 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 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((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(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(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 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); } //========================================================================== diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 00b491365..c4c039946 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -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 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); diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 93802c8e8..1067b2b83 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -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 &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 &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 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 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 &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; } //========================================================================== diff --git a/src/sound/i_music.h b/src/sound/i_music.h index d587d3129..5948ceb7c 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -34,6 +34,8 @@ #ifndef __I_MUSIC_H__ #define __I_MUSIC_H__ +#include + #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 reader, int device); MusInfo *I_RegisterCDSong (int track, int cdid = 0); MusInfo *I_RegisterURLSong (const char *url); diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index fa04cfa51..43e52a722 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -501,7 +501,7 @@ protected: class MUSSong2 : public MIDIStreamer { public: - MUSSong2(FILE *file, BYTE *musiccache, int length, EMidiDevice type); + MUSSong2(std::auto_ptr 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 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 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 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 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 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 reader); }; // Module played via foo_dumb ----------------------------------------------- -MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int len); +MusInfo *MOD_OpenSong(std::auto_ptr &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 &reader, const char *fmt); // -------------------------------------------------------------------------- diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index ec2071106..9d45ebc68 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -172,7 +172,7 @@ public: { return NULL; } - SoundStream *OpenStream (const char *filename, int flags, int offset, int length) + SoundStream *OpenStream (std::auto_ptr 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 decoder(CreateDecoder((const BYTE*)coded, sizebytes)); + std::auto_ptr 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; diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index b82ea85aa..29dd947f0 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -35,9 +35,13 @@ #ifndef __I_SOUND__ #define __I_SOUND__ +#include + #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 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; diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 64e065b6e..0a7e8b0e0 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -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: diff --git a/src/sound/mpg123_decoder.cpp b/src/sound/mpg123_decoder.cpp index c3a811b40..63ccb6922 100644 --- a/src/sound/mpg123_decoder.cpp +++ b/src/sound/mpg123_decoder.cpp @@ -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(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(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(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(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(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*/)) diff --git a/src/sound/mpg123_decoder.h b/src/sound/mpg123_decoder.h index 216eae2f9..0d8d2e7ab 100644 --- a/src/sound/mpg123_decoder.h +++ b/src/sound/mpg123_decoder.h @@ -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); diff --git a/src/sound/music_cd.cpp b/src/sound/music_cd.cpp index 5b400ba82..a271d1b22 100644 --- a/src/sound/music_cd.cpp +++ b/src/sound/music_cd.cpp @@ -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 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)) { diff --git a/src/sound/music_dumb.cpp b/src/sound/music_dumb.cpp index 8405228a3..bcacefe40 100644 --- a/src/sound/music_dumb.cpp +++ b/src/sound/music_dumb.cpp @@ -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 &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 &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(filestate.ptr); } + if(state) reader.reset(); return state; } diff --git a/src/sound/music_gme.cpp b/src/sound/music_gme.cpp index 7f017b7d2..7db5110b7 100644 --- a/src/sound/music_gme.cpp +++ b/src/sound/music_gme.cpp @@ -42,6 +42,7 @@ #include "critsec.h" #include #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 &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); } diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index 15b50da87..9df28d634 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -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 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) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index ee84239d6..e7e0894bb 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -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 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) diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index fb0d78df5..c8b694a21 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -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 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); diff --git a/src/sound/music_pseudo_mididevice.cpp b/src/sound/music_pseudo_mididevice.cpp index 6c1c90b4c..ba52f0a08 100644 --- a/src/sound/music_pseudo_mididevice.cpp +++ b/src/sound/music_pseudo_mididevice.cpp @@ -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 midi; + std::auto_ptr 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(reader.release()), + looping ? SoundStream::Loop : 0); + return false; } diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index 6fd51f149..6f73277d3 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -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 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' && diff --git a/src/sound/music_stream.cpp b/src/sound/music_stream.cpp index 72c825a28..1f528c309 100644 --- a/src/sound/music_stream.cpp +++ b/src/sound/music_stream.cpp @@ -52,9 +52,14 @@ StreamSong::~StreamSong () } } -StreamSong::StreamSong (const char *filename_or_data, int offset, int len) +StreamSong::StreamSong (std::auto_ptr 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 () diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index fe1761181..f50e8669d 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -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 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); } diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 8bb4be5bc..706c26ae7 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -156,6 +156,7 @@ class OpenALSoundStream : public SoundStream ALfloat Volume; + std::auto_ptr Reader; std::vector DecoderData; std::auto_ptr 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 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 decoder(CreateDecoder(sfxdata, length)); + std::auto_ptr 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 reader, int flags) { std::auto_ptr 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(); } diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index db559ebb7..f9ff49a6e 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -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 reader, int flags); // Starts a sound. virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan); diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index 534cf343f..922fc8b1c 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -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(user_data); - return self->FileLength; + FileReader *reader = reinterpret_cast(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(user_data); + FileReader *reader = reinterpret_cast(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(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(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(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(user_data); - return self->MemLength; -} - -sf_count_t SndFileDecoder::mem_seek(sf_count_t offset, int whence, void *user_data) -{ - SndFileDecoder *self = reinterpret_cast(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(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(user_data); - return self->MemPos; + FileReader *reader = reinterpret_cast(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; diff --git a/src/sound/sndfile_decoder.h b/src/sound/sndfile_decoder.h index ec59af98f..f329ab876 100644 --- a/src/sound/sndfile_decoder.h +++ b/src/sound/sndfile_decoder.h @@ -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);