Support for loading revised Factor5 N64 ROMs

This commit is contained in:
Jack Andersen 2016-07-18 12:38:28 -10:00
parent 260ec5bb93
commit a048605011
5 changed files with 166 additions and 265 deletions

View File

@ -76,8 +76,8 @@ class AudioGroupProject
std::unique_ptr<SongGroupIndex::PageEntry[]> m_convNormalPages;
std::unique_ptr<SongGroupIndex::PageEntry[]> m_convDrumPages;
std::unique_ptr<std::array<SongGroupIndex::MIDISetup, 16>[]> m_convMidiSetups;
void _allocateConvBuffers(const unsigned char* data, bool absOffs, N64DataTag);
void _allocateConvBuffers(const unsigned char* data, bool absOffs, PCDataTag);
void _allocateConvBuffers(const unsigned char* data, N64DataTag);
void _allocateConvBuffers(const unsigned char* data, PCDataTag);
public:
AudioGroupProject(const unsigned char* data, GCNDataTag);

View File

@ -21,8 +21,7 @@ public:
MetroidPrime2,
RogueSquadronPC,
RogueSquadronN64,
BattleForNabooPC,
BattleForNabooN64,
Factor5N64Rev,
RogueSquadron2,
RogueSquadron3
};

View File

@ -22,10 +22,10 @@ public:
private:
State m_phase = State::Attack; /**< Current envelope state */
double m_attackTime = 0.0; /**< Time of attack in seconds */
double m_attackTime = 0.01; /**< Time of attack in seconds */
double m_decayTime = 0.0; /**< Time of decay in seconds */
double m_sustainFactor = 1.0; /**< Evaluated sustain percentage */
double m_releaseTime = 0.0; /**< Time of release in seconds */
double m_releaseTime = 0.01; /**< Time of release in seconds */
double m_releaseStartFactor = 0.0; /**< Level at whenever release event occurs */
double m_curTime = 0.0; /**< Current time of envelope stage in seconds */
bool m_adsrSet = false;

View File

@ -152,7 +152,7 @@ struct MusyX1MIDISetup
}
};
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool absOffs, N64DataTag)
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, N64DataTag)
{
size_t normPageCount = 0;
size_t drumPageCount = 0;
@ -161,7 +161,7 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
while (group->groupEndOff != 0xffffffff)
{
const unsigned char* subData = absOffs ? data : data + 8;
const unsigned char* subData = data + 8;
GroupHeader header = *group;
header.swapBig();
@ -187,20 +187,16 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
/* MIDI setups */
const uint8_t* setupData = subData + header.midiSetupsOff;
while (*reinterpret_cast<const uint32_t*>(setupData) != 0xffffffff)
const uint8_t* setupEnd = subData + header.groupEndOff;
while (setupData < setupEnd)
{
++midiSetupCount;
setupData += 8 * 16 + 4;
}
}
if (absOffs)
group = reinterpret_cast<const GroupHeader*>(data + header.groupEndOff);
else
{
data += header.groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
data += header.groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
if (normPageCount)
@ -213,7 +209,8 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N64DataTag)
{
_allocateConvBuffers(data, absOffs, N64DataTag{});
if (!absOffs)
_allocateConvBuffers(data, N64DataTag{});
SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get();
SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get();
std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get();
@ -232,42 +229,77 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N6
SongGroupIndex& idx = m_songGroups[header.groupId];
bIdx = &idx;
/* Normal pages */
const MusyX1PageEntry* normEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + header.pageTableOff);
while (normEntries->objId != 0xffff)
if (absOffs)
{
normEntries->setIntoMusyX2(*normPagesBuf);
idx.m_normPages[normEntries->programNo] = normPagesBuf;
++normEntries;
++normPagesBuf;
/* Normal pages */
const SongGroupIndex::PageEntry* normEntries =
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.pageTableOff);
while (normEntries->objId != 0xffff)
{
idx.m_normPages[normEntries->programNo] = normEntries;
++normEntries;
}
/* Drum pages */
const SongGroupIndex::PageEntry* drumEntries =
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.drumTableOff);
while (drumEntries->objId != 0xffff)
{
idx.m_drumPages[drumEntries->programNo] = drumEntries;
++drumEntries;
}
/* MIDI setups */
const uint8_t* setupData = data + header.midiSetupsOff;
const uint8_t* setupEnd = data + header.groupEndOff;
while (setupData < setupEnd)
{
uint16_t songId = SBig(*reinterpret_cast<const uint16_t*>(setupData));
idx.m_midiSetups[songId] =
reinterpret_cast<const std::array<SongGroupIndex::MIDISetup, 16>*>(setupData + 4);
setupData += 5 * 16 + 4;
}
}
/* Drum pages */
const MusyX1PageEntry* drumEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + header.drumTableOff);
while (drumEntries->objId != 0xffff)
else
{
drumEntries->setIntoMusyX2(*drumPagesBuf);
idx.m_drumPages[drumEntries->programNo] = drumPagesBuf;
++drumEntries;
++drumPagesBuf;
}
/* Normal pages */
const MusyX1PageEntry* normEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + header.pageTableOff);
while (normEntries->objId != 0xffff)
{
normEntries->setIntoMusyX2(*normPagesBuf);
idx.m_normPages[normEntries->programNo] = normPagesBuf;
++normEntries;
++normPagesBuf;
}
/* MIDI setups */
const uint8_t* setupData = subData + header.midiSetupsOff;
while (*reinterpret_cast<const uint32_t*>(setupData) != 0xffffffff)
{
uint16_t songId = SBig(*reinterpret_cast<const uint16_t*>(setupData));
const std::array<MusyX1MIDISetup, 16>* midiSetups =
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4);
/* Drum pages */
const MusyX1PageEntry* drumEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + header.drumTableOff);
while (drumEntries->objId != 0xffff)
{
drumEntries->setIntoMusyX2(*drumPagesBuf);
idx.m_drumPages[drumEntries->programNo] = drumPagesBuf;
++drumEntries;
++drumPagesBuf;
}
for (int i = 0; i < 16; ++i)
(*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]);
/* MIDI setups */
const uint8_t* setupData = subData + header.midiSetupsOff;
const uint8_t* setupEnd = subData + header.groupEndOff;
while (setupData < setupEnd)
{
uint16_t songId = SBig(*reinterpret_cast<const uint16_t*>(setupData));
const std::array<MusyX1MIDISetup, 16>* midiSetups =
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4);
idx.m_midiSetups[songId] = midiSetupsBuf;
setupData += 8 * 16 + 4;
++midiSetupsBuf;
for (int i = 0; i < 16; ++i)
(*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]);
idx.m_midiSetups[songId] = midiSetupsBuf;
setupData += 8 * 16 + 4;
++midiSetupsBuf;
}
}
}
else if (header.type == GroupType::SFX)
@ -304,7 +336,7 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N6
}
}
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool absOffs, PCDataTag)
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, PCDataTag)
{
size_t normPageCount = 0;
size_t drumPageCount = 0;
@ -313,7 +345,7 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
while (group->groupEndOff != 0xffffffff)
{
const unsigned char* subData = absOffs ? data : data + 8;
const unsigned char* subData = data + 8;
if (group->type == GroupType::Song)
{
@ -337,20 +369,16 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
/* MIDI setups */
const uint8_t* setupData = subData + group->midiSetupsOff;
while (*reinterpret_cast<const uint32_t*>(setupData) != 0xffffffff)
const uint8_t* setupEnd = subData + group->groupEndOff;
while (setupData < setupEnd)
{
++midiSetupCount;
setupData += 8 * 16 + 4;
}
}
if (absOffs)
group = reinterpret_cast<const GroupHeader*>(data + group->groupEndOff);
else
{
data += group->groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
data += group->groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
if (normPageCount)
@ -363,7 +391,8 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool abs
AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, PCDataTag)
{
_allocateConvBuffers(data, absOffs, PCDataTag{});
if (!absOffs)
_allocateConvBuffers(data, PCDataTag{});
SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get();
SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get();
std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get();
@ -380,42 +409,77 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, PC
SongGroupIndex& idx = m_songGroups[group->groupId];
bIdx = &idx;
/* Normal pages */
const MusyX1PageEntry* normEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + group->pageTableOff);
while (normEntries->objId != 0xffff)
if (absOffs)
{
normEntries->setIntoMusyX2(*normPagesBuf);
idx.m_normPages[normEntries->programNo] = normPagesBuf;
++normEntries;
++normPagesBuf;
/* Normal pages */
const SongGroupIndex::PageEntry* normEntries =
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + group->pageTableOff);
while (normEntries->objId != 0xffff)
{
idx.m_normPages[normEntries->programNo] = normEntries;
++normEntries;
}
/* Drum pages */
const SongGroupIndex::PageEntry* drumEntries =
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + group->drumTableOff);
while (drumEntries->objId != 0xffff)
{
idx.m_drumPages[drumEntries->programNo] = drumEntries;
++drumEntries;
}
/* MIDI setups */
const uint8_t* setupData = data + group->midiSetupsOff;
const uint8_t* setupEnd = data + group->groupEndOff;
while (setupData < setupEnd)
{
uint16_t songId = *reinterpret_cast<const uint16_t*>(setupData);
idx.m_midiSetups[songId] =
reinterpret_cast<const std::array<SongGroupIndex::MIDISetup, 16>*>(setupData + 4);
setupData += 5 * 16 + 4;
}
}
/* Drum pages */
const MusyX1PageEntry* drumEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + group->drumTableOff);
while (drumEntries->objId != 0xffff)
else
{
drumEntries->setIntoMusyX2(*drumPagesBuf);
idx.m_drumPages[drumEntries->programNo] = drumPagesBuf;
++drumEntries;
++drumPagesBuf;
}
/* Normal pages */
const MusyX1PageEntry* normEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + group->pageTableOff);
while (normEntries->objId != 0xffff)
{
normEntries->setIntoMusyX2(*normPagesBuf);
idx.m_normPages[normEntries->programNo] = normPagesBuf;
++normEntries;
++normPagesBuf;
}
/* MIDI setups */
const uint8_t* setupData = subData + group->midiSetupsOff;
while (*reinterpret_cast<const uint32_t*>(setupData) != 0xffffffff)
{
uint16_t songId = *reinterpret_cast<const uint16_t*>(setupData);
const std::array<MusyX1MIDISetup, 16>* midiSetups =
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4);
/* Drum pages */
const MusyX1PageEntry* drumEntries =
reinterpret_cast<const MusyX1PageEntry*>(subData + group->drumTableOff);
while (drumEntries->objId != 0xffff)
{
drumEntries->setIntoMusyX2(*drumPagesBuf);
idx.m_drumPages[drumEntries->programNo] = drumPagesBuf;
++drumEntries;
++drumPagesBuf;
}
for (int i = 0; i < 16; ++i)
(*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]);
/* MIDI setups */
const uint8_t* setupData = subData + group->midiSetupsOff;
const uint8_t* setupEnd = subData + group->groupEndOff;
while (setupData < setupEnd)
{
uint16_t songId = *reinterpret_cast<const uint16_t*>(setupData);
const std::array<MusyX1MIDISetup, 16>* midiSetups =
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4);
idx.m_midiSetups[songId] = midiSetupsBuf;
setupData += 8 * 16 + 4;
++midiSetupsBuf;
for (int i = 0; i < 16; ++i)
(*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]);
idx.m_midiSetups[songId] = midiSetupsBuf;
setupData += 8 * 16 + 4;
++midiSetupsBuf;
}
}
}
else if (group->type == GroupType::SFX)

View File

@ -69,10 +69,8 @@ const SystemChar* ContainerRegistry::TypeToName(Type tp)
return _S("Star Wars - Rogue Squadron (PC)");
case Type::RogueSquadronN64:
return _S("Star Wars - Rogue Squadron (N64)");
case Type::BattleForNabooPC:
return _S("Star Wars Episode I - Battle for Naboo (PC)");
case Type::BattleForNabooN64:
return _S("Star Wars Episode I - Battle for Naboo (N64)");
case Type::Factor5N64Rev:
return _S("Factor5 Revision ROM (N64)");
case Type::RogueSquadron2:
return _S("Star Wars - Rogue Squadron 2 (GCN)");
case Type::RogueSquadron3:
@ -1087,148 +1085,7 @@ static std::vector<std::pair<SystemString, ContainerRegistry::SongData>> LoadRS1
return ret;
}
static bool ValidateBFNPC(FILE* fp)
{
size_t endPos = FileLength(fp);
if (endPos > 100 * 1024 * 1024)
return false;
uint32_t fstOff;
uint32_t fstSz;
if (fread(&fstOff, 1, 4, fp) == 4 && fread(&fstSz, 1, 4, fp) == 4)
{
if (fstOff + fstSz <= endPos)
{
FSeek(fp, fstOff, SEEK_SET);
uint32_t elemCount = fstSz / 32;
std::unique_ptr<RS1FSTEntry[]> entries(new RS1FSTEntry[elemCount]);
fread(entries.get(), fstSz, 1, fp);
uint8_t foundComps = 0;
for (uint32_t i = 0; i < elemCount; ++i)
{
RS1FSTEntry& entry = entries[i];
if (!strncmp("proj", entry.name, 16))
foundComps |= 1;
else if (!strncmp("pool", entry.name, 16))
foundComps |= 2;
else if (!strncmp("sdir", entry.name, 16))
foundComps |= 4;
else if (!strncmp("samp", entry.name, 16))
foundComps |= 8;
}
if (foundComps == 0xf)
return true;
}
}
return false;
}
static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadBFNPC(FILE* fp)
{
std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> ret;
size_t endPos = FileLength(fp);
uint32_t fstOff;
uint32_t fstSz;
if (fread(&fstOff, 1, 4, fp) == 4 && fread(&fstSz, 1, 4, fp) == 4)
{
if (fstOff + fstSz <= endPos)
{
FSeek(fp, fstOff, SEEK_SET);
uint32_t elemCount = fstSz / 32;
std::unique_ptr<RS1FSTEntry[]> entries(new RS1FSTEntry[elemCount]);
fread(entries.get(), fstSz, 1, fp);
std::unique_ptr<uint8_t[]> proj;
size_t projSz = 0;
std::unique_ptr<uint8_t[]> pool;
size_t poolSz = 0;
std::unique_ptr<uint8_t[]> sdir;
size_t sdirSz = 0;
std::unique_ptr<uint8_t[]> samp;
size_t sampSz = 0;
for (uint32_t i = 0; i < elemCount; ++i)
{
RS1FSTEntry& entry = entries[i];
if (!strncmp("proj", entry.name, 16))
{
proj.reset(new uint8_t[entry.decompSz]);
FSeek(fp, entry.offset, SEEK_SET);
fread(proj.get(), 1, entry.decompSz, fp);
projSz = entry.decompSz;
}
else if (!strncmp("pool", entry.name, 16))
{
pool.reset(new uint8_t[entry.decompSz]);
FSeek(fp, entry.offset, SEEK_SET);
fread(pool.get(), 1, entry.decompSz, fp);
poolSz = entry.decompSz;
}
else if (!strncmp("sdir", entry.name, 16))
{
sdir.reset(new uint8_t[entry.decompSz]);
FSeek(fp, entry.offset, SEEK_SET);
fread(sdir.get(), 1, entry.decompSz, fp);
sdirSz = entry.decompSz;
}
else if (!strncmp("samp", entry.name, 16))
{
samp.reset(new uint8_t[entry.decompSz]);
FSeek(fp, entry.offset, SEEK_SET);
fread(samp.get(), 1, entry.decompSz, fp);
sampSz = entry.decompSz;
}
}
ret.emplace_back(_S("Group"),
IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz, sdir.release(),
sdirSz, samp.release(), sampSz, true, PCDataTag{}});
}
}
return ret;
}
static std::vector<std::pair<SystemString, ContainerRegistry::SongData>> LoadBFNPCSongs(FILE* fp)
{
std::vector<std::pair<SystemString, ContainerRegistry::SongData>> ret;
size_t endPos = FileLength(fp);
uint32_t fstOff;
uint32_t fstSz;
if (fread(&fstOff, 1, 4, fp) == 4 && fread(&fstSz, 1, 4, fp) == 4)
{
if (fstOff + fstSz <= endPos)
{
FSeek(fp, fstOff, SEEK_SET);
uint32_t elemCount = fstSz / 32;
std::unique_ptr<RS1FSTEntry[]> entries(new RS1FSTEntry[elemCount]);
fread(entries.get(), fstSz, 1, fp);
for (uint32_t i = 0; i < elemCount; ++i)
{
RS1FSTEntry& entry = entries[i];
if (!strncmp(entry.name, "s_", 2))
{
std::unique_ptr<uint8_t[]> song(new uint8_t[entry.decompSz]);
FSeek(fp, entry.offset, SEEK_SET);
fread(song.get(), 1, entry.decompSz, fp);
SystemString name = StrToSys(entry.name);
ret.emplace_back(name, ContainerRegistry::SongData(std::move(song), entry.decompSz, -1, -1));
}
}
}
}
return ret;
}
static bool ValidateBFNN64(FILE* fp)
static bool ValidateFactor5N64Rev(FILE* fp)
{
size_t endPos = FileLength(fp);
if (endPos > 32 * 1024 * 1024)
@ -1282,7 +1139,7 @@ static bool ValidateBFNN64(FILE* fp)
return false;
}
static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadBFNN64(FILE* fp)
static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadFactor5N64Rev(FILE* fp)
{
std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> ret;
size_t endPos = FileLength(fp);
@ -1393,7 +1250,7 @@ static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadBFNN64(
return ret;
}
static std::vector<std::pair<SystemString, ContainerRegistry::SongData>> LoadBFNN64Songs(FILE* fp)
static std::vector<std::pair<SystemString, ContainerRegistry::SongData>> LoadFactor5N64RevSongs(FILE* fp)
{
std::vector<std::pair<SystemString, ContainerRegistry::SongData>> ret;
size_t endPos = FileLength(fp);
@ -1427,6 +1284,8 @@ static std::vector<std::pair<SystemString, ContainerRegistry::SongData>> LoadBFN
if (!strncmp(ent.name, "s_", 2))
{
long idx = strtol(ent.name + 2, nullptr, 10);
std::unique_ptr<uint8_t[]> song(new uint8_t[ent.decompSz]);
if (ent.compSz == 0xffffffff)
@ -1440,7 +1299,7 @@ static std::vector<std::pair<SystemString, ContainerRegistry::SongData>> LoadBFN
}
SystemString name = StrToSys(ent.name);
ret.emplace_back(name, ContainerRegistry::SongData(std::move(song), ent.decompSz, -1, -1));
ret.emplace_back(name, ContainerRegistry::SongData(std::move(song), ent.decompSz, -1, idx));
}
}
}
@ -2011,16 +1870,10 @@ ContainerRegistry::Type ContainerRegistry::DetectContainerType(const SystemChar*
return Type::RogueSquadronN64;
}
if (ValidateBFNPC(fp))
if (ValidateFactor5N64Rev(fp))
{
fclose(fp);
return Type::BattleForNabooPC;
}
if (ValidateBFNN64(fp))
{
fclose(fp);
return Type::BattleForNabooN64;
return Type::Factor5N64Rev;
}
if (ValidateRS2(fp))
@ -2195,19 +2048,11 @@ std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> ContainerRegistry:
return ret;
}
if (ValidateBFNPC(fp))
if (ValidateFactor5N64Rev(fp))
{
auto ret = LoadBFNPC(fp);
auto ret = LoadFactor5N64Rev(fp);
fclose(fp);
typeOut = Type::BattleForNabooPC;
return ret;
}
if (ValidateBFNN64(fp))
{
auto ret = LoadBFNN64(fp);
fclose(fp);
typeOut = Type::BattleForNabooN64;
typeOut = Type::Factor5N64Rev;
return ret;
}
@ -2282,16 +2127,9 @@ std::vector<std::pair<SystemString, ContainerRegistry::SongData>> ContainerRegis
return ret;
}
if (ValidateBFNPC(fp))
if (ValidateFactor5N64Rev(fp))
{
auto ret = LoadBFNPCSongs(fp);
fclose(fp);
return ret;
}
if (ValidateBFNN64(fp))
{
auto ret = LoadBFNN64Songs(fp);
auto ret = LoadFactor5N64RevSongs(fp);
fclose(fp);
return ret;
}