From 114412d5a2ed274839ac3eb68a19898c4b00b4bb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 6 Apr 2010 03:12:32 +0000 Subject: [PATCH] - Search for the MUS header within the first 32 bytes of the song so that the music in diescum.wad works. SVN r2273 (trunk) --- src/sound/fmodsound.cpp | 2 +- src/sound/i_music.cpp | 78 ++++++++++++++++----------------- src/sound/music_mus_midiout.cpp | 77 +++++++++++++++++++++++++------- zdoom.vcproj | 2 +- 4 files changed, 103 insertions(+), 56 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index e167d389f..b9c2f8bc2 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1671,10 +1671,10 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * chan->setReverbProperties(&reverb); } } - chan->setPaused(false); chan->getPriority(&def_priority); FISoundChannel *schan = CommonChannelSetup(chan, reuse_chan); schan->Rolloff = *rolloff; + chan->setPaused(false); return schan; } diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 38e820c8b..6e996bbad 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -84,6 +84,8 @@ extern void ChildSigHandler (int signum); #define GZIP_FNAME 8 #define GZIP_FCOMMENT 16 +extern int MUSHeaderSearch(const BYTE *head, int len); + EXTERN_CVAR (Int, snd_samplerate) EXTERN_CVAR (Int, snd_mididevice) @@ -295,9 +297,14 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int { FILE *file; MusInfo *info = NULL; - DWORD id; + union + { + DWORD id[32/4]; + BYTE idstr[32]; + }; const char *fmt; BYTE *ungzipped; + int i; if (nomusic) { @@ -322,22 +329,32 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int { fseek (file, offset, SEEK_SET); } - - if (fread (&id, 4, 1, file) != 1) + if (len < 32) + { + return 0; + } + if (fread (id, 4, 32/4, file) != 32/4) { fclose (file); return 0; } - fseek (file, -4, SEEK_CUR); + fseek (file, -32, SEEK_CUR); } else { file = NULL; - id = *(DWORD *)musiccache; + if (len < 32) + { + return 0; + } + for (i = 0; i < 32/4; ++i) + { + id[i] = ((DWORD *)musiccache)[i]; + } } #ifndef _WIN32 - // non-windows platforms don't support MDEV_MIDI so map to MDEV_FMOD + // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_FMOD if (device == MDEV_MMAPI) device = MDEV_FMOD; #endif @@ -346,7 +363,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int // that can handle it, so it simplifies things if we make all songs // gzippable. ungzipped = NULL; - if ((id & MAKE_ID(255,255,255,0)) == GZIP_ID) + if ((id[0] & MAKE_ID(255,255,255,0)) == GZIP_ID) { if (offset != -1) { @@ -370,11 +387,15 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int return NULL; } musiccache = ungzipped; - id = *(DWORD *)ungzipped; + for (i = 0; i < 32/4; ++i) + { + id[i] = ((DWORD *)musiccache)[i]; + } } // Check for MUS format - if (id == MAKE_ID('M','U','S',0x1a)) + // Tolerate sloppy wads by searching up to 32 bytes for the header + if (MUSHeaderSearch(idstr, sizeof(idstr)) >= 0) { /* MUS are played as: - OPL: @@ -453,7 +474,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int // Check for MIDI format else { - if (id == MAKE_ID('M','T','h','d')) + if (id[0] == MAKE_ID('M','T','h','d')) { // This is a midi file @@ -502,36 +523,15 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int #endif // _WIN32 } // Check for various raw OPL formats - else if (len >= 12 && - (id == MAKE_ID('R','A','W','A') || // Rdos Raw OPL - id == MAKE_ID('D','B','R','A') || // DosBox Raw OPL - id == MAKE_ID('A','D','L','I'))) // Martin Fernandez's modified IMF + else if ( + (id[0] == MAKE_ID('R','A','W','A') && id[1] == MAKE_ID('D','A','T','A')) || // Rdos Raw OPL + (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 { - DWORD fullsig[2]; - - if (file != NULL) - { - if (fread (fullsig, 4, 2, file) != 2) - { - fclose (file); - return 0; - } - fseek (file, -8, SEEK_CUR); - } - else - { - memcpy(fullsig, musiccache, 8); - } - - if ((fullsig[0] == MAKE_ID('R','A','W','A') && fullsig[1] == MAKE_ID('D','A','T','A')) || - (fullsig[0] == MAKE_ID('D','B','R','A') && fullsig[1] == MAKE_ID('W','O','P','L')) || - (fullsig[0] == MAKE_ID('A','D','L','I') && (fullsig[1] & MAKE_ID(255,255,0,0)) == MAKE_ID('B',1,0,0))) - { - info = new OPLMUSSong (file, musiccache, len); - } + info = new OPLMUSSong (file, musiccache, len); } // Check for game music - else if ((fmt = GME_CheckFormat(id)) != NULL && fmt[0] != '\0') + else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') { info = GME_OpenSong(file, musiccache, len, fmt); } @@ -545,7 +545,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int if (info == NULL) { // Check for CDDA "format" - if (id == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24))) + if (id[0] == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24))) { if (file != NULL) { @@ -572,7 +572,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int // 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 == MAKE_ID('M','T','h','d'))) + if (info == NULL && (len >= 1024 || id[0] == MAKE_ID('M','T','h','d'))) { // Let FMOD figure out what it is. if (file != NULL) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index fcdf704bd..ef6cba16d 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -51,6 +51,8 @@ // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- +int MUSHeaderSearch(const BYTE *head, int len); + // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- @@ -99,32 +101,55 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type) } #endif - MusHeader = (MUSHeader *)new BYTE[len]; - if (file != NULL) + BYTE front[32]; + int start; + + if (file == NULL) { - if (fread(MusHeader, 1, len, file) != (size_t)len) + memcpy(front, musiccache, len); + } + else if (fread(front, 1, 32, file) != 32) + { + return; + } + + // To tolerate sloppy wads (diescum.wad, I'm looking at you), we search + // the first 32 bytes of the file for a signature. My guess is that DMX + // does no validation whatsoever and just assumes it was passed a valid + // MUS file, since where the header is offset affects how it plays. + start = MUSHeaderSearch(front, sizeof(front)); + if (start < 0) + { + return; + } + + // Read the remainder of the song. + len = int(len - start); + if (len < 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, 32 - start); + if (fread((BYTE *)MusHeader + 32 - start, 1, len - (32 - start), file) != (size_t)(len - (32 - start))) { return; } } - else - { - memcpy(MusHeader, musiccache, len); - } - // Do some validation of the MUS file - if (MusHeader->Magic != MAKE_ID('M','U','S','\x1a')) - { - return; - } - + // Do some validation of the MUS file. if (LittleShort(MusHeader->NumChans) > 15) { return; } - MusBuffer = (BYTE *)MusHeader + LittleShort(MusHeader->SongStart); - MaxMusP = MIN (LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart)); + MaxMusP = MIN(LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart)); Division = 140; InitialTempo = 1000000; } @@ -376,3 +401,25 @@ MUSSong2::MUSSong2(const MUSSong2 *original, const char *filename, EMIDIDevice t Division = 140; InitialTempo = 1000000; } + +//========================================================================== +// +// MUSHeaderSearch +// +// Searches for the MUS header within the given memory block, returning +// the offset it was found at, or -1 if not present. +// +//========================================================================== + +int MUSHeaderSearch(const BYTE *head, int len) +{ + len -= 4; + for (int i = 0; i <= len; ++i) + { + if (head[i+0] == 'M' && head[i+1] == 'U' && head[i+2] == 'S' && head[i+3] == 0x1A) + { + return i; + } + } + return -1; +} diff --git a/zdoom.vcproj b/zdoom.vcproj index 2cee5d413..74ab3a9e3 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -318,7 +318,7 @@