Skip to content

Commit

Permalink
Fix for non-functional MP3 based SMFs
Browse files Browse the repository at this point in the history
- Discovered purpose of two uint32 values in SMF header: Roughly Major
and Minor version. Major is always 1, minor is 0 for "proto" (likely
during development) WAV based SMFs that seem unused in game, 2 is for
in-use WAV based SMFs and 2 is for in-use MP3 based SMFs

- Updated the creation/detection of WAV/MP3s and their SMF counterparts
to make use of the above information, the lack of which was preventing
MP3s from working entirely since a minor value of 1 was errantly being
assigned to them
  • Loading branch information
oblivioncth committed Feb 20, 2021
1 parent edeecbc commit 7a9ea3a
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 25 deletions.
35 changes: 22 additions & 13 deletions src/smf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,22 @@ Smf::Smf(QByteArray rawData) : mFileDataF(rawData)
}

//-Class Functions---------------------------------------------------------------------------------------------------
Smf Smf::fromStandard(Wav wavData) { return addSMFHeader(wavData.getFullData()); }
Smf Smf::fromStandard(Mp3 mp3Data) { return addSMFHeader(mp3Data.getFullData()); }
Smf Smf::fromStandard(Wav wavData)
{
QByteArray sig = Qx::ByteArray::RAWFromString(SMF_SIG);
QByteArray maj = Qx::ByteArray::RAWFromPrimitive(MAJ_VER_STD);
QByteArray min = Qx::ByteArray::RAWFromPrimitive(MIN_VER_STD_WAV);

return Smf(sig + maj + min + wavData.getFullData());
}
Smf Smf::fromStandard(Mp3 mp3Data)
{
QByteArray sig = Qx::ByteArray::RAWFromString(SMF_SIG);
QByteArray maj = Qx::ByteArray::RAWFromPrimitive(MAJ_VER_STD);
QByteArray min = Qx::ByteArray::RAWFromPrimitive(MIN_VER_STD_MP3);

return Smf(sig + maj + min + mp3Data.getFullData());
}

//-Instance Functions------------------------------------------------------------------------------------------------
//Private:
Expand All @@ -28,18 +42,18 @@ bool Smf::fileIsValidSMF()

// General
QByteArray smfSigRegion = headers.left(L_SMF_SIG);
QByteArray unkFlagOne = headers.mid(L_SMF_SIG, L_SMF_CMN_FLAGS/2); // Not understood so unused
QByteArray unkFlagTwo = headers.mid(L_SMF_SIG + L_SMF_CMN_FLAGS/2, L_SMF_CMN_FLAGS/2); // Not understood so unused
uint32_t majorVersion = Qx::ByteArray::RAWToPrimitive<uint32_t>(headers.mid(L_SMF_SIG, L_SMF_MAJ_VER)); // So far haven't seen SMF with non-1 here so unused
uint32_t minorVersion = Qx::ByteArray::RAWToPrimitive<uint32_t>(headers.mid(L_SMF_SIG + L_SMF_MAJ_VER, L_SMF_MIN_VER));

if(smfSigRegion == SMF_SIG)
{
// WAV Check
if(toWav().isValid())
if((minorVersion == MIN_VER_STD_PROTO_WAV || minorVersion == MIN_VER_STD_WAV) && toWav().isValid())
{
mType = WAVE;
return true;
}
else if(toMp3().isValid()) // MP3 Check
else if(minorVersion == MIN_VER_STD_MP3 && toMp3().isValid()) // MP3 Check
{
mType = MP3;
return true;
Expand All @@ -50,15 +64,10 @@ bool Smf::fileIsValidSMF()
return false;
}

QByteArray Smf::addSMFHeader(const QByteArray& fileData)
{
return Qx::ByteArray::RAWFromString(Smf::SMF_SIG) + QByteArray(Smf::SMF_CMN_FLAGS, 8) + fileData;
}

//Public:
bool Smf::isValid() { return !mFileDataF.isNull(); }
Smf::Type Smf::getType() { return mType; }
QByteArray Smf::getFullData() { return mFileDataF; }
Wav Smf::toWav() { return Wav(mFileDataF.mid(L_SMF_SIG + L_SMF_CMN_FLAGS)); } // Uses unknown flag values that seem to be common to a huge majority of SMFs
Mp3 Smf::toMp3() { return Mp3(mFileDataF.mid(L_SMF_SIG + L_SMF_CMN_FLAGS)); } // Uses unknown flag values that seem to be common to a huge majority of SMFs
Wav Smf::toWav() { return Wav(mFileDataF.mid(L_SMF_SIG + L_SMF_MAJ_VER + L_SMF_MIN_VER)); }
Mp3 Smf::toMp3() { return Mp3(mFileDataF.mid(L_SMF_SIG + L_SMF_MAJ_VER + L_SMF_MIN_VER)); }

14 changes: 6 additions & 8 deletions src/smf.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ class Smf
static inline const QString FILE_EXT = "smf";
static inline const QString SMF_SIG = "fssm";


static inline const char SMF_CMN_FLAGS[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; //This appears to actually be two back-to-back,
// 32-bit, little-endian values of 1 that may be some kind of count. A few older looking BSCs use 1,0 instead, perhaps its a version tag? Initialized
// using char[] because QByteArray seems to be bugged when using "inline" with null (0x00) characters as part of the array
static inline const uint32_t MAJ_VER_STD = 1;
static inline const uint32_t MIN_VER_STD_PROTO_WAV = 0; // Seems to be in unused/really old SMFs, unused in this app for now
static inline const uint32_t MIN_VER_STD_WAV = 1;
static inline const uint32_t MIN_VER_STD_MP3 = 2;

static const int L_SMF_SIG = 0x04;
static const int L_SMF_CMN_FLAGS = 0x08;
static const int L_SMF_MAJ_VER = 0x04;
static const int L_SMF_MIN_VER = 0x04;

//-Instance Variables--------------------------------------------------------------------------------------------
private:
Expand All @@ -36,9 +37,6 @@ class Smf
Smf(QByteArray rawSMFData);

//-Class Functions-------------------------------------------------------------------------------------------------------
private:
static QByteArray addSMFHeader(const QByteArray& fileData);

public:
static Smf fromStandard(Wav wavData);
static Smf fromStandard(Mp3 mp3Data);
Expand Down
8 changes: 4 additions & 4 deletions src/version.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#ifndef VERSION_H
#define VERSION_H

#define VER_FILEVERSION 0,1,7,0
#define VER_FILEVERSION_STR "0.1.7.0"
#define VER_FILEVERSION 0,1,8,0
#define VER_FILEVERSION_STR "0.1.8.0"

#define VER_PRODUCTVERSION 0,1,7,0
#define VER_PRODUCTVERSION_STR "0.1.7.0"
#define VER_PRODUCTVERSION 0,1,8,0
#define VER_PRODUCTVERSION_STR "0.1.8.0"

#define VER_COMPANYNAME_STR "Obby Apps"
#define VER_FILEDESCRIPTION_STR "BSCWorks (CoH:v14)"
Expand Down

0 comments on commit 7a9ea3a

Please sign in to comment.