Audio decompiled and WIP custom sample support

This commit is contained in:
Nicholas Estelami
2022-06-01 13:06:32 -04:00
parent 5fcddaa066
commit b8c9f7f1ce
44 changed files with 2384 additions and 167 deletions

View File

@@ -142,7 +142,7 @@ namespace Ship {
return FileToLoad;
}
bool Archive::AddFile(const std::string& path, uintptr_t fileData, DWORD dwFileSize) {
bool Archive::AddFile(const std::string& oPath, uintptr_t fileData, DWORD dwFileSize) {
HANDLE hFile;
#ifdef _WIN32
SYSTEMTIME sysTime;
@@ -154,6 +154,11 @@ namespace Ship {
time_t stupidHack;
time(&stupidHack);
#endif
std::string path = oPath;
StringHelper::ReplaceOriginal(path, "\\", "/");
if (!SFileCreateFile(mainMPQ, path.c_str(), stupidHack, dwFileSize, 0, MPQ_FILE_COMPRESS, &hFile)) {
SPDLOG_ERROR("({}) Failed to create file of {} bytes {} in archive {}", GetLastError(), dwFileSize, path.c_str(), MainPath.c_str());
return false;

View File

@@ -67,6 +67,7 @@ namespace Ship
TextureAnimationParams,
Vector,
Vertex,
Audio
};
class ArrayV0 : public ResourceFile

View File

@@ -0,0 +1,168 @@
#include "Audio.h"
namespace Ship
{
void AudioSampleV1::ParseFileBinary(BinaryReader* reader, Resource* res)
{
AudioSample* entry = (AudioSample*)res;
ResourceFile::ParseFileBinary(reader, res);
entry->codec = reader->ReadByte();
entry->medium = reader->ReadByte();
entry->unk_bit26 = reader->ReadByte();
entry->unk_bit25 = reader->ReadByte();
int dataSize = reader->ReadInt32();
for (size_t i = 0; i < dataSize; i++)
entry->data.push_back(reader->ReadUByte());
entry->loop.start = reader->ReadUInt32();
entry->loop.end = reader->ReadUInt32();
entry->loop.count = reader->ReadUInt32();
int loopStateCnt = reader->ReadUInt32();
for (size_t i = 0; i < loopStateCnt; i++)
entry->loop.states.push_back(reader->ReadInt16());
entry->book.order = reader->ReadInt32();
entry->book.npredictors = reader->ReadInt32();
int bookSize = reader->ReadInt32();
for (size_t i = 0; i < bookSize; i++)
entry->book.books.push_back(reader->ReadInt16());
}
void AudioSoundFontV1::ParseFileBinary(BinaryReader* reader, Resource* res)
{
AudioSoundFont* soundFont = (AudioSoundFont*)res;
ResourceFile::ParseFileBinary(reader, res);
soundFont->medium = reader->ReadByte();
soundFont->cachePolicy = reader->ReadByte();
soundFont->data1 = reader->ReadInt16();
soundFont->data2 = reader->ReadInt16();
soundFont->data3 = reader->ReadInt16();
int drumCnt = reader->ReadInt32();
int instrumentCnt = reader->ReadInt32();
int sfxCnt = reader->ReadInt32();
for (int i = 0; i < drumCnt; i++)
{
DrumEntry drum;
drum.releaseRate = reader->ReadUByte();
drum.pan = reader->ReadUByte();
drum.loaded = reader->ReadUByte();
drum.env = ReadEnvelopeData(reader);
bool hasSample = reader->ReadByte();
drum.offset = reader->ReadInt32();
drum.tuning = reader->ReadSingle();
soundFont->drums.push_back(drum);
}
for (int i = 0; i < instrumentCnt; i++)
{
InstrumentEntry entry;
entry.isValidEntry = reader->ReadByte();
entry.loaded = reader->ReadByte();
entry.normalRangeLo = reader->ReadByte();
entry.normalRangeHi = reader->ReadByte();
entry.releaseRate = reader->ReadByte();
entry.env = ReadEnvelopeData(reader);
{
bool hasSFEntry = reader->ReadByte();
if (hasSFEntry)
{
entry.lowNotesSound = new SoundFontEntry();
bool hasSampleRef = reader->ReadByte();
entry.lowNotesSound->sampleOffset = reader->ReadInt32();
entry.lowNotesSound->tuning = reader->ReadSingle();
}
}
{
bool hasSFEntry = reader->ReadByte();
if (hasSFEntry)
{
entry.normalNotesSound = new SoundFontEntry();
bool hasSampleRef = reader->ReadByte();
entry.normalNotesSound->sampleOffset = reader->ReadInt32();
entry.normalNotesSound->tuning = reader->ReadSingle();
}
}
{
bool hasSFEntry = reader->ReadByte();
if (hasSFEntry)
{
entry.highNotesSound = new SoundFontEntry();
bool hasSampleRef = reader->ReadByte();
entry.highNotesSound->sampleOffset = reader->ReadInt32();
entry.highNotesSound->tuning = reader->ReadSingle();
}
}
soundFont->instruments.push_back(entry);
}
for (int i = 0; i < sfxCnt; i++)
{
SoundFontEntry* entry = new SoundFontEntry();
bool hasSFEntry = reader->ReadByte();
if (hasSFEntry)
{
bool hasSampleRef = reader->ReadByte();
entry->sampleOffset = reader->ReadInt32();
entry->tuning = reader->ReadSingle();
}
soundFont->soundEffects.push_back(entry);
}
}
std::vector<AdsrEnvelope*> AudioSoundFontV1::ReadEnvelopeData(BinaryReader* reader)
{
std::vector<AdsrEnvelope*> envelopes;
int envelopeCnt = reader->ReadInt32();
for (int i = 0; i < envelopeCnt; i++)
{
AdsrEnvelope* env = new AdsrEnvelope();
env->delay = reader->ReadInt16();
env->arg = reader->ReadInt16();
envelopes.push_back(env);
}
return envelopes;
}
void AudioV1::ParseFileBinary(BinaryReader* reader, Resource* res)
{
Audio* audio = (Audio*)res;
ResourceFile::ParseFileBinary(reader, res);
//int sampleCnt = reader->ReadInt32();
//for (size_t i = 0; i < sampleCnt; i++)
//audio->samples.push_back(ReadSampleEntry(reader));
}
}

View File

@@ -0,0 +1,120 @@
#pragma once
#include "Resource.h"
#include <vector>
#include <map>
namespace Ship
{
struct AdsrEnvelope
{
int16_t delay;
int16_t arg;
};
struct AdpcmBook
{
/* 0x00 */ int32_t order;
/* 0x04 */ int32_t npredictors;
/* 0x08 */ std::vector<int16_t> books; // size 8 * order * npredictors. 8-byte aligned
};
struct AdpcmLoop
{
/* 0x00 */ uint32_t start;
/* 0x04 */ uint32_t end;
/* 0x08 */ uint32_t count;
///* 0x10 */ int16_t state[16]; // only exists if count != 0. 8-byte aligned
/* 0x10 */ std::vector<int16_t> states;
};
struct SoundFontEntry
{
//SampleEntry* sampleEntry = nullptr;
uint32_t sampleOffset;
float tuning;
};
struct DrumEntry
{
uint8_t releaseRate;
uint8_t pan;
uint8_t loaded;
uint32_t offset;
float tuning;
std::vector<AdsrEnvelope*> env;
//SampleEntry* sample = nullptr;
};
struct InstrumentEntry
{
bool isValidEntry;
uint8_t loaded;
uint8_t normalRangeLo;
uint8_t normalRangeHi;
uint8_t releaseRate;
std::vector<AdsrEnvelope*> env;
SoundFontEntry* lowNotesSound = nullptr;
SoundFontEntry* normalNotesSound = nullptr;
SoundFontEntry* highNotesSound = nullptr;
};
class AudioSoundFontV1 : public ResourceFile
{
public:
void ParseFileBinary(BinaryReader* reader, Resource* res) override;
static std::vector<AdsrEnvelope*> ReadEnvelopeData(BinaryReader* reader);
};
class AudioSampleV1 : public ResourceFile
{
public:
void ParseFileBinary(BinaryReader* reader, Resource* res) override;
};
class AudioV1 : public ResourceFile
{
public:
void ParseFileBinary(BinaryReader* reader, Resource* res) override;
};
struct AudioSoundFont : public Resource
{
public:
uint32_t ptr;
uint32_t size;
uint8_t medium;
uint8_t cachePolicy;
uint16_t data1;
uint16_t data2;
uint16_t data3;
std::vector<DrumEntry> drums;
std::vector<SoundFontEntry*> soundEffects;
std::vector<InstrumentEntry> instruments;
};
class AudioSample : public Resource
{
public:
uint8_t codec;
uint8_t medium;
uint8_t unk_bit26;
uint8_t unk_bit25;
std::vector<uint8_t> data;
AdpcmLoop loop;
AdpcmBook book;
};
class Audio : public Resource
{
public:
//std::vector<AudioTableEntry> soundFontTable;
//std::vector<AudioTableEntry> sequenceTable;
//std::vector<AudioTableEntry> sampleBankTable;
//std::vector<char*> sequences;
//std::vector<SampleEntry*> samples;
};
}

View File

@@ -16,6 +16,4 @@ void Ship::CutsceneV0::ParseFileBinary(BinaryReader* reader, Resource* res)
cs->commands.push_back(data);
}
//int bp = 0;
}

View File

@@ -0,0 +1,69 @@
#include "AudioFactory.h"
namespace Ship
{
Audio* AudioFactory::ReadAudio(BinaryReader* reader)
{
Audio* audio = new Audio();
Version version = (Version)reader->ReadUInt32();
switch (version)
{
case Version::Roy:
{
AudioV1 audioFac = AudioV1();
audioFac.ParseFileBinary(reader, audio);
}
break;
default:
// VERSION NOT SUPPORTED
break;
}
return audio;
}
AudioSample* AudioSampleFactory::ReadAudioSample(BinaryReader* reader)
{
AudioSample* audioSample = new AudioSample();
Version version = (Version)reader->ReadUInt32();
switch (version)
{
case Version::Deckard: // OTRTODO: Remove this line after we merge in that refactor
case Version::Roy:
{
AudioSampleV1 audioSampleFac = AudioSampleV1();
audioSampleFac.ParseFileBinary(reader, audioSample);
}
break;
default:
// VERSION NOT SUPPORTED
break;
}
return audioSample;
}
AudioSoundFont* AudioSoundFontFactory::ReadAudioSoundFont(BinaryReader* reader)
{
AudioSoundFont* audioSF = new AudioSoundFont();
Version version = (Version)reader->ReadUInt32();
switch (version)
{
case Version::Deckard: // OTRTODO: Remove this line after we merge in that refactor
case Version::Roy:
{
AudioSoundFontV1 audioSFFac = AudioSoundFontV1();
audioSFFac.ParseFileBinary(reader, audioSF);
}
break;
default:
// VERSION NOT SUPPORTED
break;
}
return audioSF;
}
};

View File

@@ -0,0 +1,23 @@
#include "../Audio.h"
#include "Utils/BinaryReader.h"
namespace Ship
{
class AudioFactory
{
public:
static Audio* ReadAudio(BinaryReader* reader);
};
class AudioSampleFactory
{
public:
static AudioSample* ReadAudioSample(BinaryReader* reader);
};
class AudioSoundFontFactory
{
public:
static AudioSoundFont* ReadAudioSoundFont(BinaryReader* reader);
};
}

View File

@@ -15,6 +15,7 @@
#include "TextureFactory.h"
#include "BlobFactory.h"
#include "MtxFactory.h"
#include "AudioFactory.h"
#include <Utils/MemoryStream.h>
namespace Ship
@@ -84,6 +85,15 @@ namespace Ship
case ResourceType::Matrix:
result = MtxFactory::ReadMtx(reader.get());
break;
case ResourceType::Audio:
result = AudioFactory::ReadAudio(reader.get());
break;
case ResourceType::AudioSample:
result = AudioSampleFactory::ReadAudioSample(reader.get());
break;
case ResourceType::AudioSoundFont:
result = AudioSoundFontFactory::ReadAudioSoundFont(reader.get());
break;
default:
// RESOURCE TYPE NOT SUPPORTED
break;

View File

@@ -30,6 +30,9 @@ namespace Ship
Array = 0x4F415252, // OARR
Text = 0x4F545854, // OTXT
Blob = 0x4F424C42, // OBLB
Audio = 'OAUD',
AudioSample = 'OSMP',
AudioSoundFont = 'OSFT',
};
enum class DataType

View File

@@ -253,9 +253,11 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Audio.cpp" />
<ClCompile Include="Blob.cpp" />
<ClCompile Include="Cvar.cpp" />
<ClCompile Include="Environment.cpp" />
<ClCompile Include="Factories\AudioFactory.cpp" />
<ClCompile Include="GameOverlay.cpp" />
<ClCompile Include="GameSettings.cpp" />
<ClCompile Include="Lib\ImGui\backends\imgui_impl_dx11.cpp" />
@@ -340,10 +342,12 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="abi.h" />
<ClInclude Include="Audio.h" />
<ClInclude Include="AudioPlayer.h" />
<ClInclude Include="Blob.h" />
<ClInclude Include="Cvar.h" />
<ClInclude Include="Environment.h" />
<ClInclude Include="Factories\AudioFactory.h" />
<ClInclude Include="GameOverlay.h" />
<ClInclude Include="GameSettings.h" />
<ClInclude Include="GameVersions.h" />

View File

@@ -345,6 +345,12 @@
<ClCompile Include="GameOverlay.cpp">
<Filter>Source Files\CustomImpl\Overlay</Filter>
</ClCompile>
<ClCompile Include="Audio.cpp">
<Filter>Source Files\Resources\Files</Filter>
</ClCompile>
<ClCompile Include="Factories\AudioFactory.cpp">
<Filter>Source Files\Resources\Factories</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Lib\tinyxml2\tinyxml2.h">
@@ -638,5 +644,11 @@
<ClInclude Include="GameOverlay.h">
<Filter>Source Files\CustomImpl\Overlay</Filter>
</ClInclude>
<ClInclude Include="Audio.h">
<Filter>Header Files\Resources\Files</Filter>
</ClInclude>
<ClInclude Include="Factories\AudioFactory.h">
<Filter>Header Files\Resources\Factories</Filter>
</ClInclude>
</ItemGroup>
</Project>