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

@ -341,6 +341,7 @@ build/
ZAPDUtils/build/
ZAPD/BuildInfo.h
baserom/
baserom_ntsc/
*.vtx.inc
*.otr
*.swp

View File

@ -0,0 +1,174 @@
#include "AudioExporter.h"
#include "Main.h"
#include <Animation.h>
#include <Utils/MemoryStream.h>
#include <Globals.h>
#include <Utils/File.h>
#include "DisplayListExporter.h"
void OTRExporter_Audio::WriteSampleEntryReference(SampleEntry* entry, std::map<uint32_t, SampleEntry*> samples, BinaryWriter* writer)
{
writer->Write((uint8_t)(entry != nullptr ? 1 : 0));
uint32_t addr = 0;
for (auto pair : samples)
{
if (pair.second == entry)
{
addr = pair.first;
break;
}
}
writer->Write(addr);
}
void OTRExporter_Audio::WriteSampleEntry(SampleEntry* entry, BinaryWriter* writer)
{
WriteHeader(nullptr, "", writer, Ship::ResourceType::AudioSample);
writer->Write(entry->codec);
writer->Write(entry->medium);
writer->Write(entry->unk_bit26);
writer->Write(entry->unk_bit25);
writer->Write((uint32_t)entry->data.size());
writer->Write((char*)entry->data.data(), entry->data.size());
writer->Write((uint32_t)(entry->loop.start));
writer->Write((uint32_t)(entry->loop.end));
writer->Write((uint32_t)(entry->loop.count));
writer->Write((uint32_t)entry->loop.states.size());
for (int i = 0; i < entry->loop.states.size(); i++)
writer->Write((entry->loop.states[i]));
writer->Write((uint32_t)(entry->book.order));
writer->Write((uint32_t)(entry->book.npredictors));
writer->Write((uint32_t)entry->book.books.size());
for (int i = 0; i < entry->book.books.size(); i++)
writer->Write((entry->book.books[i]));
}
void OTRExporter_Audio::WriteSoundFontEntry(SoundFontEntry* entry, std::map<uint32_t, SampleEntry*> samples, BinaryWriter* writer)
{
writer->Write((uint8_t)(entry != nullptr ? 1 : 0));
if (entry != nullptr)
{
WriteSampleEntryReference(entry->sampleEntry, samples, writer);
writer->Write(entry->tuning);
}
}
void OTRExporter_Audio::WriteEnvData(std::vector<AdsrEnvelope*> envelopes, BinaryWriter* writer)
{
writer->Write((uint32_t)envelopes.size());
for (auto env : envelopes)
{
writer->Write(env->delay);
writer->Write(env->arg);
}
}
void OTRExporter_Audio::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
{
ZAudio* audio = (ZAudio*)res;
WriteHeader(res, outPath, writer, Ship::ResourceType::Audio);
// Write Samples as individual files
for (auto pair : audio->samples)
{
MemoryStream* sampleStream = new MemoryStream();
BinaryWriter sampleWriter = BinaryWriter(sampleStream);
WriteSampleEntry(pair.second, &sampleWriter);
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, StringHelper::Sprintf("samples/sample_%08X", pair.first));
AddFile(fName, sampleStream->ToVector());
}
// Write the samplebank table
//writer->Write((uint32_t)audio->sampleBankTable.size());
//for (size_t i = 0; i < audio->sampleBankTable.size(); i++)
//{
//}
// Write the soundfont table
//writer->Write((uint32_t)audio->soundFontTable.size());
for (size_t i = 0; i < audio->soundFontTable.size(); i++)
{
MemoryStream* fntStream = new MemoryStream();
BinaryWriter fntWriter = BinaryWriter(fntStream);
WriteHeader(nullptr, "", &fntWriter, Ship::ResourceType::AudioSoundFont);
fntWriter.Write(audio->soundFontTable[i].medium);
fntWriter.Write(audio->soundFontTable[i].cachePolicy);
fntWriter.Write(audio->soundFontTable[i].data1);
fntWriter.Write(audio->soundFontTable[i].data2);
fntWriter.Write(audio->soundFontTable[i].data3);
fntWriter.Write((uint32_t)audio->soundFontTable[i].drums.size());
fntWriter.Write((uint32_t)audio->soundFontTable[i].instruments.size());
fntWriter.Write((uint32_t)audio->soundFontTable[i].soundEffects.size());
for (int k = 0; k < audio->soundFontTable[i].drums.size(); k++)
{
fntWriter.Write(audio->soundFontTable[i].drums[k].releaseRate);
fntWriter.Write(audio->soundFontTable[i].drums[k].pan);
fntWriter.Write(audio->soundFontTable[i].drums[k].loaded);
WriteEnvData(audio->soundFontTable[i].drums[k].env, &fntWriter);
WriteSampleEntryReference(audio->soundFontTable[i].drums[k].sample, audio->samples, &fntWriter);
fntWriter.Write(audio->soundFontTable[i].drums[k].tuning);
}
for (int k = 0; k < audio->soundFontTable[i].instruments.size(); k++)
{
fntWriter.Write((uint8_t)audio->soundFontTable[i].instruments[k].isValidInstrument);
fntWriter.Write(audio->soundFontTable[i].instruments[k].loaded);
fntWriter.Write(audio->soundFontTable[i].instruments[k].normalRangeLo);
fntWriter.Write(audio->soundFontTable[i].instruments[k].normalRangeHi);
fntWriter.Write(audio->soundFontTable[i].instruments[k].releaseRate);
WriteEnvData(audio->soundFontTable[i].instruments[k].env, &fntWriter);
WriteSoundFontEntry(audio->soundFontTable[i].instruments[k].lowNotesSound, audio->samples, &fntWriter);
WriteSoundFontEntry(audio->soundFontTable[i].instruments[k].normalNotesSound, audio->samples, &fntWriter);
WriteSoundFontEntry(audio->soundFontTable[i].instruments[k].highNotesSound, audio->samples, &fntWriter);
}
for (int k = 0; k < audio->soundFontTable[i].soundEffects.size(); k++)
{
WriteSoundFontEntry(audio->soundFontTable[i].soundEffects[k], audio->samples, &fntWriter);
}
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, StringHelper::Sprintf("fonts/font_%02X", i));
AddFile(fName, fntStream->ToVector());
}
// Write Sequences
for (int i = 0; i < audio->sequences.size(); i++)
{
auto seq = audio->sequences[i];
MemoryStream* seqStream = new MemoryStream();
BinaryWriter seqWriter = BinaryWriter(seqStream);
seqWriter.Write((uint8_t)audio->sequenceTable[i].medium);
seqWriter.Write((uint8_t)audio->sequenceTable[i].cachePolicy);
seqWriter.Write(seq.data(), seq.size());
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, StringHelper::Sprintf("sequences/seq_%02X", i));
AddFile(fName, seqStream->ToVector());
}
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "ZResource.h"
#include "ZAudio.h"
#include "Exporter.h"
#include <Utils/BinaryWriter.h>
class OTRExporter_Audio : public OTRExporter
{
public:
void WriteSampleEntry(SampleEntry* entry, BinaryWriter* writer);
void WriteSampleEntryReference(SampleEntry* entry, std::map<uint32_t, SampleEntry*> samples, BinaryWriter* writer);
void WriteSoundFontEntry(SoundFontEntry* entry, std::map<uint32_t, SampleEntry*> samples, BinaryWriter* writer);
void WriteEnvData(std::vector<AdsrEnvelope*> envelopes, BinaryWriter* writer);
virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
};

View File

@ -362,18 +362,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
BinaryWriter dlWriter = BinaryWriter(dlStream);
Save(dList->otherDLists[i], outPath, &dlWriter);
#ifdef _DEBUG
//if (otrArchive->HasFile(fName))
//otrArchive->RemoveFile(fName);
#endif
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, dlStream->ToVector());
else
files[fName] = dlStream->ToVector();
//otrArchive->AddFile(fName, (uintptr_t)dlStream->ToVector().data(), dlWriter.GetBaseAddress());
AddFile(fName, dlStream->ToVector());
}
}
else
@ -460,10 +449,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
Save(dList->otherDLists[i], outPath, &dlWriter);
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, dlStream->ToVector());
else
files[fName] = dlStream->ToVector();
AddFile(fName, dlStream->ToVector());
}
}
else
@ -827,10 +813,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
}
}
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, vtxStream->ToVector());
else
files[fName] = vtxStream->ToVector();
AddFile(fName, vtxStream->ToVector());
auto end = std::chrono::steady_clock::now();
size_t diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

View File

@ -15,6 +15,7 @@
#include "TextExporter.h"
#include "BlobExporter.h"
#include "MtxExporter.h"
#include "AudioExporter.h"
#include <Globals.h>
#include <Utils/File.h>
#include <Utils/Directory.h>
@ -26,6 +27,7 @@ std::shared_ptr<Ship::Archive> otrArchive;
BinaryWriter* fileWriter;
std::chrono::steady_clock::time_point fileStart, resStart;
std::map<std::string, std::vector<char>> files;
std::mutex fileMutex;
void InitVersionInfo();
@ -45,7 +47,7 @@ static void ExporterParseFileMode(const std::string& buildMode, ZFileMode& fileM
if (File::Exists(otrFileName))
otrArchive = std::shared_ptr<Ship::Archive>(new Ship::Archive(otrFileName, true));
else
otrArchive = Ship::Archive::CreateArchive(otrFileName, 65536 / 2);
otrArchive = Ship::Archive::CreateArchive(otrFileName, 40000);
auto lst = Directory::ListFiles("Extract");
@ -62,7 +64,7 @@ static void ExporterProgramEnd()
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
{
printf("Generating OTR Archive...\n");
otrArchive = Ship::Archive::CreateArchive(otrFileName, 65536 / 2);
otrArchive = Ship::Archive::CreateArchive(otrFileName, 40000);
for (auto item : files)
{
@ -79,9 +81,9 @@ static void ExporterProgramEnd()
otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], (uintptr_t)fileData.data(), fileData.size());
}
otrArchive->AddFile("Audiobank", (uintptr_t)Globals::Instance->GetBaseromFile("Audiobank").data(), Globals::Instance->GetBaseromFile("Audiobank").size());
otrArchive->AddFile("Audioseq", (uintptr_t)Globals::Instance->GetBaseromFile("Audioseq").data(), Globals::Instance->GetBaseromFile("Audioseq").size());
otrArchive->AddFile("Audiotable", (uintptr_t)Globals::Instance->GetBaseromFile("Audiotable").data(), Globals::Instance->GetBaseromFile("Audiotable").size());
//otrArchive->AddFile("Audiobank", (uintptr_t)Globals::Instance->GetBaseromFile("Audiobank").data(), Globals::Instance->GetBaseromFile("Audiobank").size());
//otrArchive->AddFile("Audioseq", (uintptr_t)Globals::Instance->GetBaseromFile("Audioseq").data(), Globals::Instance->GetBaseromFile("Audioseq").size());
//otrArchive->AddFile("Audiotable", (uintptr_t)Globals::Instance->GetBaseromFile("Audiotable").data(), Globals::Instance->GetBaseromFile("Audiotable").size());
}
}
@ -158,7 +160,10 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer)
fName = StringHelper::Sprintf("%s/%s", oName.c_str(), rName.c_str());
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
{
std::unique_lock Lock(fileMutex);
files[fName] = strem->ToVector();
}
else
File::WriteAllBytes("Extract/" + fName, strem->ToVector());
}
@ -178,6 +183,17 @@ static void ExporterXMLEnd()
{
}
void AddFile(std::string fName, std::vector<char> data)
{
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, data);
else
{
std::unique_lock Lock(fileMutex);
files[fName] = data;
}
}
static void ImportExporters()
{
// In this example we set up a new exporter called "EXAMPLE".
@ -211,6 +227,7 @@ static void ImportExporters()
exporterSet->exporters[ZResourceType::Text] = new OTRExporter_Text();
exporterSet->exporters[ZResourceType::Blob] = new OTRExporter_Blob();
exporterSet->exporters[ZResourceType::Mtx] = new OTRExporter_MtxExporter();
exporterSet->exporters[ZResourceType::Audio] = new OTRExporter_Audio();
Globals::AddExporter("OTR", exporterSet);

View File

@ -3,4 +3,6 @@
#include <Archive.h>
extern std::shared_ptr<Ship::Archive> otrArchive;
extern std::map<std::string, std::vector<char>> files;
extern std::map<std::string, std::vector<char>> files;
void AddFile(std::string fName, std::vector<char> data);

View File

@ -20,6 +20,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="ArrayExporter.h" />
<ClInclude Include="AudioExporter.h" />
<ClInclude Include="BackgroundExporter.h" />
<ClInclude Include="BlobExporter.h" />
<ClInclude Include="CollisionExporter.h" />
@ -44,6 +45,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="ArrayExporter.cpp" />
<ClCompile Include="AudioExporter.cpp" />
<ClCompile Include="BackgroundExporter.cpp" />
<ClCompile Include="BlobExporter.cpp" />
<ClCompile Include="CollisionExporter.cpp" />

View File

@ -81,6 +81,9 @@
<ClInclude Include="VersionInfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AudioExporter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CollisionExporter.cpp">
@ -140,5 +143,8 @@
<ClCompile Include="VersionInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AudioExporter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -453,13 +453,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
OTRExporter_Cutscene cs;
cs.Save(cmdSetCutscenes->cutscenes[0], "", &csWriter);
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + fName, csStream->ToVector());
else
files[fName] = csStream->ToVector();
//std::string fName = OTRExporter_DisplayList::GetPathToRes(res, vtxDecl->varName);
//otrArchive->AddFile(fName, (uintptr_t)csStream->ToVector().data(), csWriter.GetBaseAddress());
AddFile(fName, csStream->ToVector());
}
break;
case RoomCommand::SetPathways:
@ -480,14 +474,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
OTRExporter_Path pathExp;
pathExp.Save(&cmdSetPathways->pathwayList, outPath, &pathWriter);
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract/" + path, pathStream->ToVector());
else
files[path] = pathStream->ToVector();
//otrArchive->AddFile(path, (uintptr_t)pathStream->ToVector().data(), pathWriter.GetBaseAddress());
int bp = 0;
AddFile(path, pathStream->ToVector());
}
}
break;

View File

@ -39,7 +39,7 @@ extern "C" void Audio_SetGameVolume(int player_id, float volume)
extern "C" int ResourceMgr_OTRSigCheck(char* imgData)
{
return 0;
}
void DebugConsole_SaveCVars()

View File

@ -195,6 +195,8 @@
<ClCompile Include="WarningHandler.cpp" />
<ClCompile Include="yaz0\yaz0.cpp" />
<ClCompile Include="ZArray.cpp" />
<ClCompile Include="ZAudio.cpp" />
<ClCompile Include="ZAudioDecode.cpp" />
<ClCompile Include="ZBackground.cpp" />
<ClCompile Include="ZCutsceneMM.cpp" />
<ClCompile Include="ZLimb.cpp" />
@ -288,6 +290,7 @@
<ClInclude Include="yaz0\yaz0.h" />
<ClInclude Include="ZAnimation.h" />
<ClInclude Include="ZArray.h" />
<ClInclude Include="ZAudio.h" />
<ClInclude Include="ZBackground.h" />
<ClInclude Include="ZBlob.h" />
<ClInclude Include="ZCollision.h" />

View File

@ -297,6 +297,12 @@
<ClCompile Include="FileWorker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ZAudio.cpp">
<Filter>Source Files\Z64</Filter>
</ClCompile>
<ClCompile Include="ZAudioDecode.cpp">
<Filter>Source Files\Z64</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ZRoom\ZRoom.h">
@ -569,6 +575,9 @@
<ClInclude Include="ctpl_stl.h">
<Filter>Header Files\Libraries</Filter>
</ClInclude>
<ClInclude Include="ZAudio.h">
<Filter>Header Files\Z64</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="..\SymbolMap_OoTMqDbg.txt">

325
ZAPDTR/ZAPD/ZAudio.cpp Normal file
View File

@ -0,0 +1,325 @@
#include "ZAudio.h"
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/File.h"
#include "Utils/Path.h"
#include "Utils/StringHelper.h"
#include "ZFile.h"
REGISTER_ZFILENODE(Audio, ZAudio);
ZAudio::ZAudio(ZFile* nParent) : ZResource(nParent)
{
//RegisterRequiredAttribute("CodeOffset");
//RegisterOptionalAttribute("LangOffset", "0");
}
void ZAudio::DecodeADPCMSample(SampleEntry* sample)
{
int16_t buffer[1024 * 128];
int16_t* out = &buffer[0];
}
std::vector<AdsrEnvelope*> ZAudio::ParseEnvelopeData(std::vector<uint8_t> audioBank, std::vector<uint8_t> audioTable, int envelopeOffset, int baseOffset)
{
std::vector<AdsrEnvelope*> result;
//bool process = true;
//for (int i = 0; i < 4; i++)
while (true)
{
AdsrEnvelope* env = new AdsrEnvelope();
env->delay = BitConverter::ToInt16BE(audioBank, envelopeOffset + 0);
env->arg = BitConverter::ToInt16BE(audioBank, envelopeOffset + 2);
envelopeOffset += 4;
result.push_back(env);
if (env->delay < 0)
break;
}
return result;
}
SoundFontEntry* ZAudio::ParseSoundFontEntry(std::vector<uint8_t> audioBank,
std::vector<uint8_t> audioTable,
AudioTableEntry audioSampleBankEntry,
int soundFontOffset,
int baseOffset)
{
SoundFontEntry* soundFont = new SoundFontEntry();
soundFont->sampleEntry = ParseSampleEntry(
audioBank, audioTable, audioSampleBankEntry,
BitConverter::ToInt32BE(audioBank, soundFontOffset + 0) + baseOffset, baseOffset);
soundFont->tuning = BitConverter::ToFloatBE(audioBank, soundFontOffset + 4);
return soundFont;
}
SampleEntry* ZAudio::ParseSampleEntry(std::vector<uint8_t> audioBank,
std::vector<uint8_t> audioTable,
AudioTableEntry audioSampleBankEntry,
int sampleOffset,
int baseOffset)
{
int sampleDataOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 4) + audioSampleBankEntry.ptr;
if (samples.find(sampleOffset) == samples.end())
{
SampleEntry* sample = new SampleEntry();
int sampleSize = BitConverter::ToInt32BE(audioBank, sampleOffset + 0) & 0x00FFFFFF;
int loopOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 8) + baseOffset;
int bookOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 12) + baseOffset;
char* sampleData = (char*)malloc(sampleSize);
memcpy(sampleData, audioTable.data() + sampleDataOffset, sampleSize);
sample->data = std::vector<uint8_t>(sampleSize);
memcpy(sample->data.data(), sampleData, sampleSize);
uint32_t origField = (BitConverter::ToUInt32BE(audioBank, sampleOffset + 0));
sample->codec = (origField >> 28) & 0x0F;
sample->medium = (origField >> 24) & 0x03;
sample->unk_bit26 = (origField >> 22) & 0x01;
sample->unk_bit25 = (origField >> 21) & 0x01;
sample->loop.start = BitConverter::ToInt32BE(audioBank, loopOffset + 0);
sample->loop.end = BitConverter::ToInt32BE(audioBank, loopOffset + 4);
sample->loop.count = BitConverter::ToInt32BE(audioBank, loopOffset + 8);
if (sample->loop.count != 0xFFFFFFFF)
{
for (int i = 0; i < sample->loop.count; i++)
{
int16_t state = BitConverter::ToInt16BE(sample->data, loopOffset + 16 + (i * 2));
sample->loop.states.push_back(state);
}
}
sample->book.order = BitConverter::ToInt32BE(audioBank, bookOffset + 0);
sample->book.npredictors = BitConverter::ToInt32BE(audioBank, bookOffset + 4);
for (int i = 0; i < sample->book.npredictors * sample->book.order * 8; i++)
{
sample->book.books.push_back(
BitConverter::ToInt16BE(audioBank, bookOffset + 8 + (i * 2)));
}
samples[sampleOffset] = sample;
return sample;
}
else
{
return samples[sampleOffset];
}
}
std::vector<AudioTableEntry> ZAudio::ParseAudioTable(std::vector<uint8_t> codeData, int baseOffset)
{
std::vector<AudioTableEntry> entries;
int numEntries = BitConverter::ToInt16BE(codeData, baseOffset + 0);
int romAddr = BitConverter::ToInt16BE(codeData, baseOffset + 4);
int currentOffset = baseOffset + 16;
for (int i = 0; i < numEntries; i++)
{
AudioTableEntry entry;
entry.ptr = BitConverter::ToInt32BE(codeData, currentOffset + 0);
entry.size = BitConverter::ToInt32BE(codeData, currentOffset + 4);
entry.medium = codeData[currentOffset + 8];
entry.cachePolicy = codeData[currentOffset + 9];
entry.data1 = BitConverter::ToInt16BE(codeData, currentOffset + 10);
entry.data2 = BitConverter::ToInt16BE(codeData, currentOffset + 12);
entry.data3 = BitConverter::ToInt16BE(codeData, currentOffset + 14);
entries.push_back(entry);
currentOffset += 16;
}
return entries;
}
void ZAudio::ParseSoundFont(std::vector<uint8_t> codeData, std::vector<uint8_t> audioTable,
std::vector<AudioTableEntry> audioSampleBank,
AudioTableEntry& entry)
{
int ptr = entry.ptr;
int size = entry.size;
int sampleBankId1 = (entry.data1 >> 8) & 0xFF;
int sampleBankId2 = (entry.data1) & 0xFF;
int numInstruments = (entry.data2 >> 8) & 0xFF;
int numDrums = entry.data2 & 0xFF;
int numSfx = entry.data3;
int currentOffset = BitConverter::ToInt32BE(codeData, ptr) + ptr;
for (int i = 0; i < numDrums; i++)
{
DrumEntry drum;
int samplePtr = BitConverter::ToInt32BE(codeData, currentOffset);
if (samplePtr != 0)
{
samplePtr += ptr;
drum.sample = ParseSampleEntry(codeData, audioTable, audioSampleBank[sampleBankId1],
BitConverter::ToInt32BE(codeData, samplePtr + 4) + ptr, ptr);
drum.releaseRate = codeData[samplePtr + 0];
drum.pan = codeData[samplePtr + 1];
drum.loaded = codeData[samplePtr + 2];
drum.tuning = BitConverter::ToFloatBE(codeData, samplePtr + 8);
//int sampleDefOffset = BitConverter::ToInt32BE(codeData, samplePtr + 4);
drum.env = ParseEnvelopeData(codeData, audioTable, BitConverter::ToInt32BE(codeData, samplePtr + 12) + ptr, ptr);
}
entry.drums.push_back(drum);
currentOffset += 4;
}
currentOffset = BitConverter::ToInt32BE(codeData, ptr + 4) + ptr;
for (int i = 0; i < numSfx; i++)
{
SoundFontEntry* sfx;
sfx = ParseSoundFontEntry(codeData, audioTable, audioSampleBank[sampleBankId1],
currentOffset, ptr);
entry.soundEffects.push_back(sfx);
currentOffset += 8;
}
for (int i = 0; i < numInstruments; i++)
{
InstrumentEntry instrument;
currentOffset = BitConverter::ToInt32BE(codeData, ptr + 8 + (i * 4));
instrument.isValidInstrument = currentOffset != 0;
if (currentOffset != 0)
{
currentOffset += ptr;
instrument.loaded = codeData[currentOffset + 0];
instrument.normalRangeLo = codeData[currentOffset + 1];
instrument.normalRangeHi = codeData[currentOffset + 2];
instrument.releaseRate = codeData[currentOffset + 3];
instrument.env = ParseEnvelopeData(codeData, audioTable, BitConverter::ToInt32BE(codeData, currentOffset + 4) + ptr, ptr);
if (BitConverter::ToInt32BE(codeData, currentOffset + 8) != 0)
instrument.lowNotesSound = ParseSoundFontEntry(
codeData, audioTable, audioSampleBank[sampleBankId1], currentOffset + 8, ptr);
if (BitConverter::ToInt32BE(codeData, currentOffset + 16) != 0)
instrument.normalNotesSound = ParseSoundFontEntry(
codeData, audioTable, audioSampleBank[sampleBankId1], currentOffset + 16, ptr);
if (BitConverter::ToInt32BE(codeData, currentOffset + 24) != 0 &&
instrument.normalRangeHi != 0x7F)
instrument.highNotesSound = ParseSoundFontEntry(
codeData, audioTable, audioSampleBank[sampleBankId1], currentOffset + 24, ptr);
}
entry.instruments.push_back(instrument);
}
}
void ZAudio::ParseRawData()
{
ZResource::ParseRawData();
std::vector<uint8_t> codeData;
std::vector<uint8_t> audioTableData;
std::vector<uint8_t> audioBankData;
std::vector<uint8_t> audioSeqData;
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
codeData = Globals::Instance->GetBaseromFile("code");
else
codeData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() + "code");
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
audioTableData = Globals::Instance->GetBaseromFile("Audiotable");
else
audioTableData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() + "Audiotable");
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
audioBankData = Globals::Instance->GetBaseromFile("Audiobank");
else
audioBankData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() + "Audiobank");
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
audioSeqData = Globals::Instance->GetBaseromFile("Audioseq");
else
audioSeqData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() +
"Audioseq");
// TABLE PARSING
//int gSoundFontTableOffset = 0x138270; // OTRTODO: Make this an XML Param
//int gSequenceTableOffset = 0x1386A0; // OTRTODO: Make this an XML Param
//int gSampleBankTableOffset = 0x138D90; // OTRTODO: Make this an XML Param
int gSoundFontTableOffset = 0x138290; // OTRTODO: Make this an XML Param
int gSequenceTableOffset = 0x1386C0; // OTRTODO: Make this an XML Param
int gSampleBankTableOffset = 0x138DB0; // OTRTODO: Make this an XML Param
soundFontTable = ParseAudioTable(codeData, gSoundFontTableOffset);
sequenceTable = ParseAudioTable(codeData, gSequenceTableOffset);
sampleBankTable = ParseAudioTable(codeData, gSampleBankTableOffset);
// int gSequenceFontTableOffset = 0x1384E0; // OTRTODO: Make this an XML Param
// SAMPLE/FONT PARSING
for (int i = 0; i < soundFontTable.size(); i++)
{
ParseSoundFont(audioBankData, audioTableData, sampleBankTable, soundFontTable[i]);
}
// SOUNDBANK PARSING
/*for (int i = 0; i < sampleBankTable.size(); i++)
{
}*/
// SEQUENCE PARSING
for (int i = 0; i < sequenceTable.size(); i++)
{
int seqDestIdx = i;
if (sequenceTable[i].size == 0)
seqDestIdx = sequenceTable[i].ptr;
std::vector<char> seqVec = std::vector<char>(sequenceTable[seqDestIdx].size);
memcpy(seqVec.data(), audioSeqData.data() + sequenceTable[seqDestIdx].ptr,
sequenceTable[seqDestIdx].size);
sequences.push_back(seqVec);
}
}
std::string ZAudio::GetSourceTypeName() const
{
return "u8";
}
size_t ZAudio::GetRawDataSize() const
{
return 1;
}
ZResourceType ZAudio::GetResourceType() const
{
return ZResourceType::Audio;
}

122
ZAPDTR/ZAPD/ZAudio.h Normal file
View File

@ -0,0 +1,122 @@
#pragma once
#include "ZResource.h"
#include "tinyxml2.h"
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 SampleEntry
{
uint8_t codec;
uint8_t medium;
uint8_t unk_bit26;
uint8_t unk_bit25;
std::vector<uint8_t> data;
AdpcmLoop loop;
AdpcmBook book;
};
struct SoundFontEntry
{
SampleEntry* sampleEntry = nullptr;
float tuning;
};
struct DrumEntry
{
uint8_t releaseRate;
uint8_t pan;
uint8_t loaded;
uint32_t offset;
float tuning;
std::vector<AdsrEnvelope*> env;
//AdsrEnvelope* env = nullptr;
SampleEntry* sample = nullptr;
};
struct InstrumentEntry
{
bool isValidInstrument;
uint8_t loaded;
uint8_t normalRangeLo;
uint8_t normalRangeHi;
uint8_t releaseRate;
std::vector<AdsrEnvelope*> env;
//AdsrEnvelope* env = nullptr;
SoundFontEntry* lowNotesSound = nullptr;
SoundFontEntry* normalNotesSound = nullptr;
SoundFontEntry* highNotesSound = nullptr;
};
struct AudioTableEntry
{
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 ZAudio : public ZResource
{
public:
std::vector<AudioTableEntry> soundFontTable;
std::vector<AudioTableEntry> sequenceTable;
std::vector<AudioTableEntry> sampleBankTable;
std::vector<std::vector<char>> sequences;
std::map<uint32_t, SampleEntry*> samples;
ZAudio(ZFile* nParent);
void DecodeADPCMSample(SampleEntry* sample);
std::vector<AdsrEnvelope*> ParseEnvelopeData(std::vector<uint8_t> audioBank, std::vector<uint8_t> audioTable,
int envelopeOffset, int baseOffset);
SoundFontEntry* ParseSoundFontEntry(std::vector<uint8_t> audioBank,
std::vector<uint8_t> audioTable,
AudioTableEntry audioSampleBankEntry,
int soundFontOffset,
int baseOffset);
SampleEntry* ParseSampleEntry(std::vector<uint8_t> audioBank, std::vector<uint8_t> audioTable,
AudioTableEntry audioSampleBankEntry,
int sampleOffset, int baseOffset);
std::vector<AudioTableEntry> ParseAudioTable(std::vector<uint8_t> codeData, int baseOffset);
void ParseSoundFont(std::vector<uint8_t> codeData, std::vector<uint8_t> audioTable,
std::vector<AudioTableEntry> audioSampleBank, AudioTableEntry& entry);
void ParseRawData() override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;
size_t GetRawDataSize() const override;
};

View File

@ -0,0 +1,669 @@
/**
* Bruteforcing decoder for converting ADPCM-encoded AIFC into AIFF, in a way
* that roundtrips with vadpcm_enc.
*/
#include <assert.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <unistd.h>
typedef signed char s8;
typedef short s16;
typedef int s32;
typedef long long s64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef float f32;
typedef double f64;
#ifdef _MSC_VER
#define __builtin_bswap16 _byteswap_ushort
#define __builtin_bswap32 _byteswap_ulong
#endif
#define bswap16(x) __builtin_bswap16(x)
#define bswap32(x) __builtin_bswap32(x)
#define BSWAP16(x) x = __builtin_bswap16(x)
#define BSWAP32(x) x = __builtin_bswap32(x)
#define BSWAP16_MANY(x, n) \
for (s32 _i = 0; _i < n; _i++) \
BSWAP16((x)[_i])
#define NORETURN __attribute__((noreturn))
#define UNUSED __attribute__((unused))
typedef struct
{
u32 ckID;
u32 ckSize;
} ChunkHeader;
typedef struct
{
u32 ckID;
u32 ckSize;
u32 formType;
} Chunk;
typedef struct
{
s16 numChannels;
u16 numFramesH;
u16 numFramesL;
s16 sampleSize;
s16 sampleRate[5]; // 80-bit float
u16 compressionTypeH;
u16 compressionTypeL;
} CommonChunk;
typedef struct
{
s16 MarkerID;
u16 positionH;
u16 positionL;
} Marker;
typedef struct
{
s16 playMode;
s16 beginLoop;
s16 endLoop;
} Loop;
typedef struct
{
s8 baseNote;
s8 detune;
s8 lowNote;
s8 highNote;
s8 lowVelocity;
s8 highVelocity;
s16 gain;
Loop sustainLoop;
Loop releaseLoop;
} InstrumentChunk;
typedef struct
{
s32 offset;
s32 blockSize;
} SoundDataChunk;
typedef struct
{
s16 version;
s16 order;
s16 nEntries;
} CodeChunk;
typedef struct
{
u32 start;
u32 end;
u32 count;
s16 state[16];
} ALADPCMloop;
static char usage[] = "input.aifc output.aiff";
static const char *progname, *infilename;
static int framesize = 9;
void fail_parse(const char* fmt, ...)
{
char* formatted = NULL;
va_list ap;
va_start(ap, fmt);
int size = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if (size >= 0)
{
size++;
formatted = (char*)malloc(size);
if (formatted != NULL)
{
va_start(ap, fmt);
size = vsnprintf(formatted, size, fmt, ap);
va_end(ap);
if (size < 0)
{
free(formatted);
formatted = NULL;
}
}
}
if (formatted != NULL)
{
fprintf(stderr, "%s: %s [%s]\n", progname, formatted, infilename);
free(formatted);
}
exit(1);
}
s32 myrand()
{
static u64 state = 1619236481962341ULL;
state *= 3123692312237ULL;
state += 1;
return state >> 33;
}
s16 qsample(f32 x, s32 scale)
{
if (x > 0.0f)
{
return (s16)((x / scale) + 0.4999999);
}
else
{
return (s16)((x / scale) - 0.4999999);
}
}
void clamp_to_s16(f32* in, s32* out)
{
f32 llevel = -0x8000;
f32 ulevel = 0x7fff;
for (s32 i = 0; i < 16; i++)
{
if (in[i] > ulevel)
in[i] = ulevel;
if (in[i] < llevel)
in[i] = llevel;
if (in[i] > 0.0f)
{
out[i] = (s32)(in[i] + 0.5);
}
else
{
out[i] = (s32)(in[i] - 0.5);
}
}
}
s16 clamp_bits(s32 x, s32 bits)
{
s32 lim = 1 << (bits - 1);
if (x < -lim)
return -lim;
if (x > lim - 1)
return lim - 1;
return x;
}
s32 readaifccodebook(FILE* fhandle, s32**** table, s16* order, s16* npredictors)
{
BSWAP16(*order);
BSWAP16(*npredictors);
*table = (s32***)malloc(*npredictors * sizeof(s32**));
for (s32 i = 0; i < *npredictors; i++)
{
(*table)[i] = (s32**)malloc(8 * sizeof(s32*));
for (s32 j = 0; j < 8; j++)
{
(*table)[i][j] = (s32*)malloc((*order + 8) * sizeof(s32));
}
}
for (s32 i = 0; i < *npredictors; i++)
{
s32** table_entry = (*table)[i];
for (s32 j = 0; j < *order; j++)
{
for (s32 k = 0; k < 8; k++)
{
s16 ts = 0;
BSWAP16(ts);
table_entry[k][j] = ts;
}
}
for (s32 k = 1; k < 8; k++)
{
table_entry[k][*order] = table_entry[k - 1][*order - 1];
}
table_entry[0][*order] = 1 << 11;
for (s32 k = 1; k < 8; k++)
{
s32 j = 0;
for (; j < k; j++)
{
table_entry[j][k + *order] = 0;
}
for (; j < 8; j++)
{
table_entry[j][k + *order] = table_entry[j - k][*order];
}
}
}
return 0;
}
ALADPCMloop* readlooppoints(FILE* ifile, s16* nloops)
{
BSWAP16(*nloops);
ALADPCMloop* al = (ALADPCMloop*)malloc(*nloops * sizeof(ALADPCMloop));
for (s32 i = 0; i < *nloops; i++)
{
BSWAP32(al[i].start);
BSWAP32(al[i].end);
BSWAP32(al[i].count);
BSWAP16_MANY(al[i].state, 16);
}
return al;
}
s32 inner_product(s32 length, s32* v1, s32* v2)
{
s32 out = 0;
for (s32 i = 0; i < length; i++)
{
out += v1[i] * v2[i];
}
// Compute "out / 2^11", rounded down.
s32 dout = out / (1 << 11);
s32 fiout = dout * (1 << 11);
return dout - (out - fiout < 0);
}
void my_decodeframe(u8* frame, s32* decompressed, s32* state, s32 order, s32*** coefTable)
{
s32 ix[16];
u8 header = frame[0];
s32 scale = 1 << (header >> 4);
s32 optimalp = header & 0xf;
if (framesize == 5)
{
for (s32 i = 0; i < 16; i += 4)
{
u8 c = frame[1 + i / 4];
ix[i] = c >> 6;
ix[i + 1] = (c >> 4) & 0x3;
ix[i + 2] = (c >> 2) & 0x3;
ix[i + 3] = c & 0x3;
}
}
else
{
for (s32 i = 0; i < 16; i += 2)
{
u8 c = frame[1 + i / 2];
ix[i] = c >> 4;
ix[i + 1] = c & 0xf;
}
}
for (s32 i = 0; i < 16; i++)
{
if (framesize == 5)
{
if (ix[i] >= 2)
ix[i] -= 4;
}
else
{
if (ix[i] >= 8)
ix[i] -= 16;
}
decompressed[i] = ix[i];
ix[i] *= scale;
}
for (s32 j = 0; j < 2; j++)
{
s32 in_vec[16];
if (j == 0)
{
for (s32 i = 0; i < order; i++)
{
in_vec[i] = state[16 - order + i];
}
}
else
{
for (s32 i = 0; i < order; i++)
{
in_vec[i] = state[8 - order + i];
}
}
for (s32 i = 0; i < 8; i++)
{
s32 ind = j * 8 + i;
in_vec[order + i] = ix[ind];
state[ind] = inner_product(order + i, coefTable[optimalp][i], in_vec) + ix[ind];
}
}
}
void get_bounds(s32* in, s32* decompressed, s32 scale, s32* minVals, s32* maxVals)
{
s32 minv, maxv;
if (framesize == 9)
{
minv = -8;
maxv = 7;
}
else
{
minv = -2;
maxv = 1;
}
for (s32 i = 0; i < 16; i++)
{
s32 lo = in[i] - scale / 2;
s32 hi = in[i] + scale / 2;
lo -= scale;
hi += scale;
if (decompressed[i] == minv)
lo -= scale;
else if (decompressed[i] == maxv)
hi += scale;
minVals[i] = lo;
maxVals[i] = hi;
}
}
void write_header(FILE* ofile, const char* id, s32 size)
{
fwrite(id, 4, 1, ofile);
BSWAP32(size);
fwrite(&size, sizeof(s32), 1, ofile);
}
char* OldMain(char* infilename)
{
s16 order = -1;
s16 nloops = 0;
ALADPCMloop* aloops = NULL;
s16 npredictors = -1;
s32*** coefTable = NULL;
s32 state[16];
s32 decompressed[16];
s32 soundPointer = -1;
s32 currPos = 0;
s32 nSamples = 0;
Chunk FormChunk = Chunk();
ChunkHeader Header = ChunkHeader();
CommonChunk CommChunk = CommonChunk();
InstrumentChunk InstChunk;
SoundDataChunk SndDChunk = SoundDataChunk();
FILE* ifile = NULL;
FILE* ofile = NULL;
if ((ifile = fopen(infilename, "rb")) == NULL)
{
fail_parse("AIFF-C file could not be opened");
exit(1);
}
memset(&InstChunk, 0, sizeof(InstChunk));
BSWAP32(FormChunk.ckID);
BSWAP32(FormChunk.formType);
if ((FormChunk.ckID != 0x464f524d) || (FormChunk.formType != 0x41494643))
{ // FORM, AIFC
fail_parse("not an AIFF-C file");
}
for (;;)
{
s32 num = fread(&Header, sizeof(Header), 1, ifile);
u32 ts = 0;
if (num <= 0)
break;
BSWAP32(Header.ckID);
BSWAP32(Header.ckSize);
Header.ckSize++;
Header.ckSize &= ~1;
s32 offset = ftell(ifile);
switch (Header.ckID)
{
case 0x434f4d4d: // COMM
{
BSWAP16(CommChunk.numChannels);
BSWAP16(CommChunk.numFramesH);
BSWAP16(CommChunk.numFramesL);
BSWAP16(CommChunk.sampleSize);
BSWAP16(CommChunk.compressionTypeH);
BSWAP16(CommChunk.compressionTypeL);
s32 cType = (CommChunk.compressionTypeH << 16) + CommChunk.compressionTypeL;
if (cType == 0x56415043 || cType == 0x41445039)
{ // VAPC or ADP9
framesize = 9;
}
else if (cType == 0x41445035)
{ // ADP5
framesize = 5;
}
else if (cType == 0x4850434d)
{ // HPCM
framesize = 16;
}
else
{
char comprType[5] = {
CommChunk.compressionTypeH >> 8, CommChunk.compressionTypeH & 0xFF,
CommChunk.compressionTypeL >> 8, CommChunk.compressionTypeL & 0xFF, 0};
fail_parse("file is of the wrong compression type [got %s (%08x)]", &comprType,
cType);
}
if (CommChunk.numChannels != 1)
{
fail_parse("file contains %d channels, only 1 channel supported",
CommChunk.numChannels);
}
if (CommChunk.sampleSize != 16)
{
fail_parse("file contains %d bit samples, only 16 bit samples supported",
CommChunk.sampleSize);
}
nSamples = (CommChunk.numFramesH << 16) + CommChunk.numFramesL;
// Allow broken input lengths
if (nSamples % 16)
{
nSamples -= (nSamples % 16);
}
if (nSamples % 16 != 0)
{
fail_parse("number of chunks must be a multiple of 16, found %d with remainder %d",
nSamples, nSamples % 16);
}
}
break;
case 0x53534e44: // SSND
BSWAP32(SndDChunk.offset);
BSWAP32(SndDChunk.blockSize);
assert(SndDChunk.offset == 0);
assert(SndDChunk.blockSize == 0);
soundPointer = ftell(ifile);
break;
case 0x4150504c: // APPL
BSWAP32(ts);
if (ts == 0x73746f63)
{ // stoc
u8 len = 0;
if (len == 11)
{
char ChunkName[12];
s16 version;
ChunkName[11] = '\0';
if (strcmp("VADPCMCODES", ChunkName) == 0)
{
BSWAP16(version);
if (version != 1)
{
fail_parse("Unknown codebook chunk version");
}
readaifccodebook(ifile, &coefTable, &order, &npredictors);
}
else if (strcmp("VADPCMLOOPS", ChunkName) == 0)
{
BSWAP16(version);
if (version != 1)
{
fail_parse("Unknown loop chunk version");
}
aloops = readlooppoints(ifile, &nloops);
if (nloops != 1)
{
fail_parse("Only a single loop supported");
}
}
}
}
break;
}
fseek(ifile, offset + Header.ckSize, SEEK_SET);
}
if (coefTable == NULL)
{
fail_parse("Codebook missing from bitstream");
}
for (s32 i = 0; i < order; i++)
{
state[15 - i] = 0;
}
u32 outputBytes = nSamples * sizeof(s16);
u8* outputBuf = (u8*)malloc(outputBytes);
fseek(ifile, soundPointer, SEEK_SET);
s32 fails = 0;
while (currPos < nSamples)
{
u8 input[9];
u8 encoded[9];
s32 lastState[16];
s32 decoded[16];
s16 guess[16];
s16 origGuess[16];
memcpy(lastState, state, sizeof(state));
// Decode for real
my_decodeframe(input, decompressed, state, order, coefTable);
memcpy(decoded, state, sizeof(state));
// Create a guess from that, by clamping to 16 bits
for (s32 i = 0; i < 16; i++)
{
origGuess[i] = clamp_bits(state[i], 16);
}
memcpy(state, decoded, sizeof(state));
memcpy(outputBuf + currPos * 2, decoded, sizeof(decoded));
currPos += 16;
}
if (fails)
{
fprintf(stderr, "%s %d\n", infilename, fails);
}
// Write an incomplete file header. We'll fill in the size later.
fwrite("FORM\0\0\0\0AIFF", 12, 1, ofile);
// Subtract 4 from the COMM size to skip the compression field.
write_header(ofile, "COMM", sizeof(CommonChunk) - 4);
CommChunk.numFramesH = nSamples >> 16;
CommChunk.numFramesL = nSamples & 0xffff;
BSWAP16(CommChunk.numChannels);
BSWAP16(CommChunk.numFramesH);
BSWAP16(CommChunk.numFramesL);
BSWAP16(CommChunk.sampleSize);
fwrite(&CommChunk, sizeof(CommonChunk) - 4, 1, ofile);
if (nloops > 0)
{
s32 startPos = aloops[0].start, endPos = aloops[0].end;
const char* markerNames[2] = {"start", "end"};
Marker markers[2] = {{1, startPos >> 16, startPos & 0xffff},
{2, endPos >> 16, endPos & 0xffff}};
write_header(ofile, "MARK", 2 + 2 * sizeof(Marker) + 1 + 5 + 1 + 3);
s16 numMarkers = bswap16(2);
fwrite(&numMarkers, sizeof(s16), 1, ofile);
for (s32 i = 0; i < 2; i++)
{
u8 len = (u8)strlen(markerNames[i]);
BSWAP16(markers[i].MarkerID);
BSWAP16(markers[i].positionH);
BSWAP16(markers[i].positionL);
fwrite(&markers[i], sizeof(Marker), 1, ofile);
fwrite(&len, 1, 1, ofile);
fwrite(markerNames[i], len, 1, ofile);
}
write_header(ofile, "INST", sizeof(InstrumentChunk));
InstChunk.sustainLoop.playMode = bswap16(1);
InstChunk.sustainLoop.beginLoop = bswap16(1);
InstChunk.sustainLoop.endLoop = bswap16(2);
InstChunk.releaseLoop.playMode = 0;
InstChunk.releaseLoop.beginLoop = 0;
InstChunk.releaseLoop.endLoop = 0;
fwrite(&InstChunk, sizeof(InstrumentChunk), 1, ofile);
}
// Save the coefficient table for use when encoding. Ideally this wouldn't
// be needed and "tabledesign -s 1" would generate the right table, but in
// practice it's difficult to adjust samples to make that happen.
write_header(ofile, "APPL", 4 + 12 + sizeof(CodeChunk) + npredictors * order * 8 * 2);
fwrite("stoc", 4, 1, ofile);
CodeChunk cChunk;
cChunk.version = bswap16(1);
cChunk.order = bswap16(order);
cChunk.nEntries = bswap16(npredictors);
fwrite("\x0bVADPCMCODES", 12, 1, ofile);
fwrite(&cChunk, sizeof(CodeChunk), 1, ofile);
for (s32 i = 0; i < npredictors; i++)
{
for (s32 j = 0; j < order; j++)
{
for (s32 k = 0; k < 8; k++)
{
s16 ts = bswap16(coefTable[i][k][j]);
fwrite(&ts, sizeof(s16), 1, ofile);
}
}
}
write_header(ofile, "SSND", outputBytes + 8);
SndDChunk.offset = 0;
SndDChunk.blockSize = 0;
fwrite(&SndDChunk, sizeof(SoundDataChunk), 1, ofile);
fwrite(outputBuf, outputBytes, 1, ofile);
// Fix the size in the header
s32 fileSize = bswap32(ftell(ofile) - 8);
fseek(ofile, 4, SEEK_SET);
fwrite(&fileSize, 4, 1, ofile);
fclose(ifile);
fclose(ofile);
return 0;
}

View File

@ -50,7 +50,8 @@ enum class ZResourceType
TextureAnimationParams,
Vector,
Vertex,
Text
Text,
Audio
};
class ResourceAttribute

View File

@ -191,6 +191,8 @@ ZRom::ZRom(std::string romPath)
}
else
files[lines[i]] = outData;
//File::WriteAllBytes(StringHelper::Sprintf("baserom/%s", lines[i]), files[lines[i]]);
}
int bp = 0;

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>

View File

@ -0,0 +1,5 @@
<Root>
<File Name="code" OutName="audio" RangeStart="0x0" RangeEnd="0x12CBB0">
<Audio Name="audio" Offset="0x00"/>
</File>
</Root>

View File

@ -0,0 +1,5 @@
<Root>
<File Name="code" OutName="audio" RangeStart="0x0" RangeEnd="0x12CBB0">
<Audio Name="audio" Offset="0x00"/>
</File>
</Root>

View File

@ -30,7 +30,8 @@
#include "ichain.h"
#include "regs.h"
#define AUDIO_HEAP_SIZE 0x38000
//#define AUDIO_HEAP_SIZE 0x38000
#define AUDIO_HEAP_SIZE 0x3800000 // The original audio heap size was too small. The heap would exceed capacity and corrupt everything in its path.
#define SYSTEM_HEAP_SIZE (1024 * 1024 * 4)
#ifdef __cplusplus

View File

@ -120,7 +120,8 @@ typedef struct {
/* 0x08 */ s16 book[1]; // size 8 * order * npredictors. 8-byte aligned
} AdpcmBook; // size >= 0x8
typedef struct {
typedef struct
{
union {
struct {
/* 0x00 */ u32 codec : 4;

View File

@ -36,6 +36,7 @@
#include <Utils/StringHelper.h>
#include <SDL2/SDL_scancode.h>
#include <Audio.h>
OTRGlobals* OTRGlobals::Instance;
@ -57,8 +58,15 @@ extern "C" void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples);
extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len);
extern "C" int AudioPlayer_Buffered(void);
extern "C" int AudioPlayer_GetDesiredBuffered(void);
extern "C" void ResourceMgr_CacheDirectory(const char* resName);
// C->C++ Bridge
extern "C" void OTRAudio_Init()
{
// Precache all our samples, sequences, etc...
ResourceMgr_CacheDirectory("audio");
}
extern "C" void InitOTR() {
OTRGlobals::Instance = new OTRGlobals();
auto t = OTRGlobals::Instance->context->GetResourceManager()->LoadFile("version");
@ -72,6 +80,7 @@ extern "C" void InitOTR() {
clearMtx = (uintptr_t)&gMtxClear;
OTRMessage_Init();
OTRAudio_Init();
DebugConsole_Init();
Debug_Init();
}
@ -530,12 +539,235 @@ extern "C" CollisionHeader* ResourceMgr_LoadColByName(const char* path)
return (CollisionHeader*)colHeader;
}
extern "C" Vtx * ResourceMgr_LoadVtxByName(const char* path)
extern "C" Vtx* ResourceMgr_LoadVtxByName(const char* path)
{
auto res = std::static_pointer_cast<Ship::Array>(OTRGlobals::Instance->context->GetResourceManager()->LoadResource(path));
return (Vtx*)res->vertices.data();
}
extern "C" char* ResourceMgr_LoadSeqByID(int seqID)
{
std::string fmtStr = "audio/sequences/seq_%02X";
return OTRGlobals::Instance->context->GetResourceManager()->LoadFile(StringHelper::Sprintf(fmtStr.c_str(), seqID)).get()->buffer.get();
}
extern "C" int ResourceMgr_GetSeqSizeByID(int seqID)
{
return OTRGlobals::Instance->context->GetResourceManager()
->LoadFile(StringHelper::Sprintf("audio/sequences/seq_%02X", seqID))
.get()
->dwBufferSize;
}
std::map<std::string, SoundFontSample*> cachedCustomSFs;
extern "C" SoundFontSample* ResourceMgr_LoadAudioSample(int romOffset)
{
auto str = StringHelper::Sprintf("audio/samples/sample_%08X", romOffset);
if (cachedCustomSFs.find(str) != cachedCustomSFs.end())
return cachedCustomSFs[str];
// Check if our file is actually a wav...
auto sampleRaw = OTRGlobals::Instance->context->GetResourceManager()->LoadFile(str);
uint32_t* strem = (uint32_t*)sampleRaw->buffer.get();
uint8_t* strem2 = (uint8_t*)strem;
if (strem2[0] == 'R' && strem2[1] == 'I' && strem2[2] == 'F' && strem2[3] == 'F')
{
SoundFontSample* sampleC = (SoundFontSample*)malloc(sizeof(SoundFontSample));
*strem++; // RIFF
*strem++; // size
*strem++; // WAVE
*strem++; // fmt
int fmtChunkSize = *strem++;
// OTRTODO: Make sure wav format is what the audio driver wants!
strem = (uint32_t*)&strem2[0x0C + fmtChunkSize + 8 + 4];
sampleC->size = *strem++;
sampleC->sampleAddr = (uint8_t*)strem;
sampleC->codec = CODEC_S16;
// OTRTODO: Grab loop data from wav
sampleC->loop = (AdpcmLoop*)malloc(sizeof(AdpcmLoop));
sampleC->loop->start = 0;
sampleC->loop->end = sampleC->size / 2;
sampleC->loop->count = 0;
cachedCustomSFs[str] = sampleC;
return sampleC;
}
auto sample = std::static_pointer_cast<Ship::AudioSample>(OTRGlobals::Instance->context->GetResourceManager()->LoadResource(str));
if (sample == nullptr)
return NULL;
if (sample->cachedGameAsset != nullptr)
{
SoundFontSample* sampleC = (SoundFontSample*)sample->cachedGameAsset;
return (SoundFontSample*)sample->cachedGameAsset;
}
else
{
SoundFontSample* sampleC = (SoundFontSample*)malloc(sizeof(SoundFontSample));
sampleC->sampleAddr = sample->data.data();
sampleC->size = sample->data.size();
sampleC->codec = sample->codec;
sampleC->medium = sample->medium;
sampleC->unk_bit26 = sample->unk_bit26;
sampleC->unk_bit25 = sample->unk_bit25;
sampleC->book = (AdpcmBook*)malloc(sizeof(AdpcmBook) + (sample->book.books.size() * sizeof(int16_t)));
sampleC->book->npredictors = sample->book.npredictors;
sampleC->book->order = sample->book.order;
for (int i = 0; i < sample->book.books.size(); i++)
sampleC->book->book[i] = sample->book.books[i];
sampleC->loop = (AdpcmLoop*)malloc(sizeof(AdpcmLoop));
sampleC->loop->start = sample->loop.start;
sampleC->loop->end = sample->loop.end;
sampleC->loop->count = sample->loop.count;
for (int i = 0; i < sample->loop.states.size(); i++)
sampleC->loop->state[i] = sample->loop.states[i];
sample->cachedGameAsset = sampleC;
return sampleC;
}
}
extern "C" SoundFont* ResourceMgr_LoadAudioSoundFont(int fontIndex) {
auto soundFont =
std::static_pointer_cast<Ship::AudioSoundFont>(OTRGlobals::Instance->context->GetResourceManager()->LoadResource(
StringHelper::Sprintf("audio/fonts/font_%02X", fontIndex)));
if (soundFont == nullptr)
return NULL;
if (soundFont->cachedGameAsset != nullptr)
{
return (SoundFont*)soundFont->cachedGameAsset;
}
else
{
SoundFont* soundFontC = (SoundFont*)malloc(sizeof(SoundFont));
soundFontC->numDrums = soundFont->drums.size();
soundFontC->numInstruments = soundFont->instruments.size();
soundFontC->numSfx = soundFont->soundEffects.size();
soundFontC->sampleBankId1 = soundFont->data1 >> 8;
soundFontC->sampleBankId2 = soundFont->data1 & 0xFF;
soundFontC->drums = (Drum**)malloc(sizeof(Drum*) * soundFont->drums.size());
for (int i = 0; i < soundFont->drums.size(); i++)
{
Drum* drum = (Drum*)malloc(sizeof(Drum));
drum->releaseRate = soundFont->drums[i].releaseRate;
drum->pan = soundFont->drums[i].pan;
drum->loaded = 0;
if (soundFont->drums[i].env.size() == 0)
drum->envelope = NULL;
else
{
drum->envelope = (AdsrEnvelope*)malloc(sizeof(AdsrEnvelope) * soundFont->drums[i].env.size());
for (int k = 0; k < soundFont->drums[i].env.size(); k++)
{
drum->envelope[k].delay = BOMSWAP16(soundFont->drums[i].env[k]->delay);
drum->envelope[k].arg = BOMSWAP16(soundFont->drums[i].env[k]->arg);
}
}
drum->sound.sample = ResourceMgr_LoadAudioSample(soundFont->drums[i].offset);
drum->sound.tuning = soundFont->drums[i].tuning;
soundFontC->drums[i] = drum;
}
soundFontC->instruments = (Instrument**)malloc(sizeof(Instrument*) * soundFont->instruments.size());
for (int i = 0; i < soundFont->instruments.size(); i++) {
if (soundFont->instruments[i].isValidEntry)
{
Instrument* inst = (Instrument*)malloc(sizeof(Instrument));
inst->loaded = 0;
inst->releaseRate = soundFont->instruments[i].releaseRate;
inst->normalRangeLo = soundFont->instruments[i].normalRangeLo;
inst->normalRangeHi = soundFont->instruments[i].normalRangeHi;
if (soundFont->instruments[i].env.size() == 0)
inst->envelope = NULL;
else
{
inst->envelope = (AdsrEnvelope*)malloc(sizeof(AdsrEnvelope) * soundFont->instruments[i].env.size());
for (int k = 0; k < soundFont->instruments[i].env.size(); k++)
{
inst->envelope[k].delay = BOMSWAP16(soundFont->instruments[i].env[k]->delay);
inst->envelope[k].arg = BOMSWAP16(soundFont->instruments[i].env[k]->arg);
}
}
if (soundFont->instruments[i].lowNotesSound != nullptr)
{
inst->lowNotesSound.sample =
ResourceMgr_LoadAudioSample(soundFont->instruments[i].lowNotesSound->sampleOffset);
inst->lowNotesSound.tuning = soundFont->instruments[i].lowNotesSound->tuning;
} else {
inst->lowNotesSound.sample = NULL;
inst->lowNotesSound.tuning = 0;
}
if (soundFont->instruments[i].normalNotesSound != nullptr) {
inst->normalNotesSound.sample =
ResourceMgr_LoadAudioSample(soundFont->instruments[i].normalNotesSound->sampleOffset);
inst->normalNotesSound.tuning = soundFont->instruments[i].normalNotesSound->tuning;
} else {
inst->normalNotesSound.sample = NULL;
inst->normalNotesSound.tuning = 0;
}
if (soundFont->instruments[i].highNotesSound != nullptr) {
inst->highNotesSound.sample =
ResourceMgr_LoadAudioSample(soundFont->instruments[i].highNotesSound->sampleOffset);
inst->highNotesSound.tuning = soundFont->instruments[i].highNotesSound->tuning;
} else {
inst->highNotesSound.sample = NULL;
inst->highNotesSound.tuning = 0;
}
soundFontC->instruments[i] = inst;
} else
{
soundFontC->instruments[i] = nullptr;
}
}
soundFontC->soundEffects = (SoundFontSound*)malloc(sizeof(SoundFontSound) * soundFont->soundEffects.size());
for (int i = 0; i < soundFont->soundEffects.size(); i++)
{
soundFontC->soundEffects[i].sample = ResourceMgr_LoadAudioSample(soundFont->soundEffects[i]->sampleOffset);
soundFontC->soundEffects[i].tuning = soundFont->soundEffects[i]->tuning;
}
soundFont->cachedGameAsset = soundFontC;
return soundFontC;
}
}
extern "C" int ResourceMgr_OTRSigCheck(char* imgData)
{
uintptr_t i = (uintptr_t)(imgData);

View File

@ -24,8 +24,8 @@ private:
#endif
#ifndef __cplusplus
void InitOTR();
void Graph_ProcessFrame(void (*run_one_game_iter)(void));
void OTRAudio_Init();
void InitAudio();
void Graph_StartFrame();
void Graph_ProcessGfxCommands(Gfx* commands);
void OTRLogString(const char* src);

View File

@ -445,7 +445,9 @@ void osViExtendVStart(u32 arg0)
}
#if 0
AudioTable gSoundFontTable = { 0 };
#else
AudioTable gSoundFontTable = { 0x0026,
0x0000,
0x00000000,
@ -795,7 +797,11 @@ AudioTable gSoundFontTable = { 0x0026,
},
}
};
#endif
#if 0
AudioTable gSequenceTable = { 0 };
#else
AudioTable gSequenceTable = { 0x006E,
0x0000,
0x00000000,
@ -1585,7 +1591,7 @@ AudioTable gSequenceTable = { 0x006E,
0x0000,
},
{
0x00000028,
0x00000028,
0x00000000,
0x02,
0x02,
@ -1791,9 +1797,12 @@ AudioTable gSequenceTable = { 0x006E,
0x0000,
0x0000,
},
}
};
} };
#endif
#if 0
AudioTable gSampleBankTable = { 0 };
#else
AudioTable gSampleBankTable = { 0x0007,
0x0000,
0x00000000,
@ -1864,7 +1873,9 @@ AudioTable gSampleBankTable = { 0x0007,
},
}
};
#endif
// OTRTODO: Implement This in OTR File
u8 gSequenceFontTable[0x1C0] = {
0xDC,
0x00,

View File

@ -10,6 +10,8 @@ void AudioHeap_DiscardSampleCaches(void);
void AudioHeap_DiscardSampleBank(s32 sampleBankId);
void AudioHeap_DiscardSampleBanks(void);
extern bool gUseLegacySD;
f32 func_800DDE20(f32 arg0) {
return 256.0f * gAudioContext.audioBufferParameters.unkUpdatesPerFrameScaled / arg0;
}
@ -1201,7 +1203,11 @@ void AudioHeap_DiscardSampleCacheEntry(SampleCacheEntry* entry) {
}
}
void AudioHeap_UnapplySampleCache(SampleCacheEntry* entry, SoundFontSample* sample) {
void AudioHeap_UnapplySampleCache(SampleCacheEntry* entry, SoundFontSample* sample)
{
if (!gUseLegacySD)
return;
if (sample != NULL) {
if (sample->sampleAddr == entry->allocatedAddr) {
sample->sampleAddr = entry->sampleAddr;

View File

@ -4,6 +4,7 @@
#include "ultra64.h"
#include "global.h"
#include "soh/OTRGlobals.h"
#define MK_ASYNC_MSG(retData, tableType, id, status) (((retData) << 24) | ((tableType) << 16) | ((id) << 8) | (status))
#define ASYNC_TBLTYPE(v) ((u8)(v >> 16))
@ -37,7 +38,7 @@ void AudioLoad_ProcessAsyncLoads(s32 resetStatus);
void AudioLoad_ProcessAsyncLoadUnkMedium(AudioAsyncLoad* asyncLoad, s32 resetStatus);
void AudioLoad_ProcessAsyncLoad(AudioAsyncLoad* asyncLoad, s32 resetStatus);
void AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo, s32 temporary);
void AudioLoad_RelocateSample(SoundFontSound* sound, SoundFontData* mem, RelocInfo* relocInfo);
void AudioLoad_RelocateSample(SoundFontSound* sound, SoundFontData* mem, RelocInfo* relocInfo, int fontId);
void AudioLoad_DiscardFont(s32 fontId);
u32 AudioLoad_TrySyncLoadSampleBank(u32 sampleBankId, u32* outMedium, s32 noLoad);
void* AudioLoad_SyncLoad(u32 tableType, u32 tableId, s32* didAllocate);
@ -74,6 +75,11 @@ void* sUnusedHandler = NULL;
s32 gAudioContextInitalized = false;
uintptr_t fontStart;
uint32_t fontOffsets[8192];
bool gUseLegacySD = false;
void AudioLoad_DecreaseSampleDmaTtls(void) {
u32 i;
@ -278,8 +284,11 @@ void AudioLoad_InitSampleDmaBuffers(s32 arg0) {
}
s32 AudioLoad_IsFontLoadComplete(s32 fontId) {
return true;
if (fontId == 0xFF) {
return true;
} else if (gAudioContext.fontLoadStatus[fontId] >= 2) {
return true;
} else if (gAudioContext.fontLoadStatus[AudioLoad_GetRealTableIndex(FONT_TABLE, fontId)] >= 2) {
@ -352,6 +361,9 @@ void AudioLoad_InitTable(AudioTable* table, uintptr_t romAddr, u16 unkMediumPara
for (i = 0; i < table->numEntries; i++) {
if ((table->entries[i].size != 0) && (table->entries[i].medium == MEDIUM_CART)) {
if (romAddr == fontStart)
fontOffsets[i] = table->entries[i].romAddr;
table->entries[i].romAddr += romAddr;
}
}
@ -400,7 +412,8 @@ void AudioLoad_SyncLoadSeqParts(s32 seqId, s32 arg1) {
s32 AudioLoad_SyncLoadSample(SoundFontSample* sample, s32 fontId) {
void* sampleAddr;
if (sample->unk_bit25 == 1) {
if (sample->unk_bit25 == 1)
{
if (sample->medium != MEDIUM_RAM) {
sampleAddr = AudioHeap_AllocSampleCache(sample->size, fontId, (void*)sample->sampleAddr, sample->medium,
CACHE_PERSISTENT);
@ -544,7 +557,7 @@ s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) {
s32 numFonts;
s32 fontId;
if (seqId >= gAudioContext.numSequences) {
if (gUseLegacySD && seqId >= gAudioContext.numSequences) {
return 0;
}
@ -556,18 +569,27 @@ s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) {
while (numFonts > 0) {
fontId = gAudioContext.sequenceFontTable[index++];
AudioLoad_SyncLoadFont(fontId);
//if (gUseLegacySD)
AudioLoad_SyncLoadFont(fontId);
numFonts--;
}
seqData = AudioLoad_SyncLoadSeq(seqId);
if (seqData == NULL) {
return 0;
}
AudioSeq_ResetSequencePlayer(seqPlayer);
seqPlayer->seqId = seqId;
seqPlayer->defaultFont = AudioLoad_GetRealTableIndex(FONT_TABLE, fontId);
if (gUseLegacySD)
seqPlayer->defaultFont = AudioLoad_GetRealTableIndex(FONT_TABLE, fontId);
else
seqPlayer->defaultFont = fontId;
seqPlayer->seqData = seqData;
seqPlayer->enabled = 1;
seqPlayer->scriptState.pc = seqData;
@ -633,12 +655,22 @@ SoundFontData* AudioLoad_SyncLoadFont(u32 fontId) {
s32 didAllocate;
RelocInfo relocInfo;
s32 realFontId = AudioLoad_GetRealTableIndex(FONT_TABLE, fontId);
//s32 realFontId = fontId;
if (gAudioContext.fontLoadStatus[realFontId] == 1) {
return NULL;
}
sampleBankId1 = gAudioContext.soundFonts[realFontId].sampleBankId1;
sampleBankId2 = gAudioContext.soundFonts[realFontId].sampleBankId2;
if (!gUseLegacySD) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontId);
sampleBankId1 = sf->sampleBankId1;
sampleBankId2 = sf->sampleBankId2;
} else {
sampleBankId1 = gAudioContext.soundFonts[realFontId].sampleBankId1;
sampleBankId2 = gAudioContext.soundFonts[realFontId].sampleBankId2;
}
relocInfo.sampleBankId1 = sampleBankId1;
relocInfo.sampleBankId2 = sampleBankId2;
@ -681,13 +713,39 @@ void* AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) {
if (ret != NULL) {
*didAllocate = false;
status = 2;
} else {
table = AudioLoad_GetLoadTable(tableType);
size = table->entries[realId].size;
size = ALIGN16(size);
medium = table->entries[id].medium;
cachePolicy = table->entries[id].cachePolicy;
romAddr = table->entries[realId].romAddr;
} else
{
char* seqData = 0;
SoundFont* fnt;
if (!gUseLegacySD && tableType == SEQUENCE_TABLE)
{
seqData = ResourceMgr_LoadSeqByID(id);
size = ResourceMgr_GetSeqSizeByID(id);
size -= 2;
medium = seqData[0];
cachePolicy = seqData[1];
romAddr = 0;
seqData += 2;
}
else if (!gUseLegacySD && tableType == FONT_TABLE)
{
fnt = ResourceMgr_LoadAudioSoundFont(id);
size = sizeof(SoundFont);
medium = 2;
cachePolicy = 0;
romAddr = 0;
}
else
{
table = AudioLoad_GetLoadTable(tableType);
size = table->entries[realId].size;
size = ALIGN16(size);
medium = table->entries[id].medium;
cachePolicy = table->entries[id].cachePolicy;
romAddr = table->entries[realId].romAddr;
}
switch (cachePolicy) {
case 0:
ret = AudioHeap_AllocPermanent(tableType, realId, size);
@ -720,7 +778,14 @@ void* AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) {
if (medium == MEDIUM_UNK) {
AudioLoad_SyncDmaUnkMedium(romAddr, ret, size, (s16)table->unkMediumParam);
} else {
AudioLoad_SyncDma(romAddr, ret, size, medium);
if (!gUseLegacySD && tableType == SEQUENCE_TABLE && seqData != NULL) {
AudioLoad_SyncDma(seqData, ret, size, medium);
} else if (!gUseLegacySD && tableType == FONT_TABLE) {
AudioLoad_SyncDma(fnt, ret, size, medium);
}
else {
AudioLoad_SyncDma(romAddr, ret, size, medium);
}
}
status = cachePolicy == 0 ? 5 : 2;
@ -743,9 +808,16 @@ void* AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) {
return ret;
}
u32 AudioLoad_GetRealTableIndex(s32 tableType, u32 id) {
u32 AudioLoad_GetRealTableIndex(s32 tableType, u32 id)
{
if ((tableType == SEQUENCE_TABLE || tableType == FONT_TABLE) && !gUseLegacySD) {
return id;
}
AudioTable* table = AudioLoad_GetLoadTable(tableType);
// If the size is 0, then this entry actually redirects to another entry.
// The rom address is actually an index into the same table where the "real" data is.
if (table->entries[id].size == 0) {
id = table->entries[id].romAddr;
}
@ -796,29 +868,63 @@ void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo
Drum* drum;
SoundFontSound* sfx;
s32 i;
s32 numDrums = gAudioContext.soundFonts[fontId].numDrums;
s32 numInstruments = gAudioContext.soundFonts[fontId].numInstruments;
s32 numSfx = gAudioContext.soundFonts[fontId].numSfx;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontId);
s32 numDrums = 0;
s32 numInstruments = 0;
s32 numSfx = 0;
if (gUseLegacySD) {
numDrums = gAudioContext.soundFonts[fontId].numDrums;
numInstruments = gAudioContext.soundFonts[fontId].numInstruments;
numSfx = gAudioContext.soundFonts[fontId].numSfx;
} else {
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
numSfx = sf->numSfx;
}
void** ptrs = (void**)mem;
#define BASE_OFFSET(x) (void*)((u32)(x) + (u32)(mem))
reloc2 = ptrs[0];
if (1) {}
if ((reloc2 != 0) && (numDrums != 0)) {
if ((reloc2 != 0 || !gUseLegacySD) && (numDrums != 0))
{
ptrs[0] = BASE_OFFSET(reloc2);
for (i = 0; i < numDrums; i++) {
reloc = ((Drum**)ptrs[0])[i];
for (i = 0; i < numDrums; i++)
{
if (gUseLegacySD)
reloc = ((Drum**)ptrs[0])[i];
if (reloc != 0) {
reloc = BASE_OFFSET(reloc);
if (reloc != 0 || !gUseLegacySD)
{
if (gUseLegacySD)
{
reloc = BASE_OFFSET(reloc);
((Drum**)ptrs[0])[i] = drum = reloc;
}
((Drum**)ptrs[0])[i] = drum = reloc;
if (!drum->loaded) {
AudioLoad_RelocateSample(&drum->sound, mem, relocInfo);
reloc = drum->envelope;
drum->envelope = BASE_OFFSET(reloc);
drum->loaded = 1;
if (!gUseLegacySD)
drum = sf->drums[i];
if (!drum->loaded)
{
if (!gUseLegacySD)
{
AudioLoad_RelocateSample(&sf->drums[i]->sound, mem, relocInfo, fontOffsets[fontId]);
//reloc = drum->envelope;
drum->loaded = 1;
}
else
{
AudioLoad_RelocateSample(&drum->sound, mem, relocInfo, fontOffsets[fontId]);
reloc = drum->envelope;
drum->envelope = BASE_OFFSET(reloc);
drum->loaded = 1;
}
}
}
}
@ -826,39 +932,56 @@ void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo
reloc2 = ptrs[1];
if (1) {}
if ((reloc2 != 0) && (numSfx != 0)) {
if ((reloc2 != 0 || !gUseLegacySD) && (numSfx != 0)) {
ptrs[1] = BASE_OFFSET(reloc2);
for (i = 0; i < numSfx; i++) {
reloc = (SoundFontSound*)ptrs[1] + i;
if (reloc != 0) {
sfx = reloc;
if (sfx->sample != NULL) {
AudioLoad_RelocateSample(sfx, mem, relocInfo);
if (reloc != 0 || !gUseLegacySD)
{
if (!gUseLegacySD) {
AudioLoad_RelocateSample(&sf->soundEffects[i].sample, mem, relocInfo, fontOffsets[fontId]);
} else {
sfx = reloc;
if (sfx->sample != NULL) {
AudioLoad_RelocateSample(sfx, mem, relocInfo, fontOffsets[fontId]);
}
}
}
}
}
if (numInstruments > 0x7E) {
numInstruments = 0x7E;
}
for (i = 2; i <= 2 + numInstruments - 1; i++) {
if (ptrs[i] != NULL) {
int startI = gUseLegacySD ? 2 : 0;
int startEC = gUseLegacySD ? 2 + numInstruments - 1 : numInstruments - 1;
//for (i = 2; i <= 2 + numInstruments - 1; i++) {
for (i = startI; i <= startEC; i++) {
if (!gUseLegacySD || ptrs[i] != NULL)
{
ptrs[i] = BASE_OFFSET(ptrs[i]);
inst = ptrs[i];
if (!inst->loaded) {
if (inst->normalRangeLo != 0) {
AudioLoad_RelocateSample(&inst->lowNotesSound, mem, relocInfo);
if (gUseLegacySD)
inst = ptrs[i];
else
inst = sf->instruments[i];
if (inst != NULL && !inst->loaded) {
if (inst->normalRangeLo != 0)
{
AudioLoad_RelocateSample(&inst->lowNotesSound, mem, relocInfo, fontOffsets[fontId]);
}
AudioLoad_RelocateSample(&inst->normalNotesSound, mem, relocInfo);
AudioLoad_RelocateSample(&inst->normalNotesSound, mem, relocInfo, fontOffsets[fontId]);
if (inst->normalRangeHi != 0x7F) {
AudioLoad_RelocateSample(&inst->highNotesSound, mem, relocInfo);
AudioLoad_RelocateSample(&inst->highNotesSound, mem, relocInfo, fontOffsets[fontId]);
}
reloc = inst->envelope;
inst->envelope = BASE_OFFSET(reloc);
if (gUseLegacySD)
inst->envelope = BASE_OFFSET(reloc);
inst->loaded = 1;
}
}
@ -866,9 +989,11 @@ void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo
#undef BASE_OFFSET
gAudioContext.soundFonts[fontId].drums = ptrs[0];
gAudioContext.soundFonts[fontId].soundEffects = ptrs[1];
gAudioContext.soundFonts[fontId].instruments = (Instrument**)(ptrs + 2);
if (gUseLegacySD) {
gAudioContext.soundFonts[fontId].drums = ptrs[0];
gAudioContext.soundFonts[fontId].soundEffects = ptrs[1];
gAudioContext.soundFonts[fontId].instruments = (Instrument**)(ptrs + 2);
}
}
void AudioLoad_SyncDma(u32 devAddr, u8* addr, size_t size, s32 medium) {
@ -1270,17 +1395,21 @@ void AudioLoad_Init(void* heap, u32 heapSize) {
uintptr_t bankStart = ResourceMgr_LoadFileRaw(_AudiobankSegmentRomStart);
uintptr_t tableStart = ResourceMgr_LoadFileRaw(_AudiotableSegmentRomStart);
fontStart = bankStart;
AudioLoad_InitTable(gAudioContext.sequenceTable, seqStart, 0);
AudioLoad_InitTable(gAudioContext.soundFontTable, bankStart, 0);
AudioLoad_InitTable(gAudioContext.sampleBankTable, tableStart, 0);
numFonts = gAudioContext.soundFontTable->numEntries;
gAudioContext.soundFonts = AudioHeap_Alloc(&gAudioContext.audioInitPool, numFonts * sizeof(SoundFont));
for (i = 0; i < numFonts; i++) {
AudioLoad_InitSoundFontMeta(i);
}
if (gUseLegacySD) {
for (i = 0; i < numFonts; i++) {
AudioLoad_InitSoundFontMeta(i);
}
AudioLoad_InitSwapFont();
AudioLoad_InitSwapFont();
}
if (temp_v0_3 = AudioHeap_Alloc(&gAudioContext.audioInitPool, D_8014A6C4.permanentPoolSize), temp_v0_3 == NULL) {
// cast away const from D_8014A6C4
@ -1454,28 +1583,40 @@ s32 AudioLoad_SlowLoadSeq(s32 seqId, u8* ramAddr, s8* isDone) {
AudioTable* seqTable;
size_t size;
if (seqId >= gAudioContext.numSequences) {
if (gUseLegacySD && seqId >= gAudioContext.numSequences) {
*isDone = 0;
return -1;
}
seqId = AudioLoad_GetRealTableIndex(SEQUENCE_TABLE, seqId);
seqTable = AudioLoad_GetLoadTable(SEQUENCE_TABLE);
slowLoad = &gAudioContext.slowLoads[gAudioContext.slowLoadPos];
if (slowLoad->status == LOAD_STATUS_DONE) {
slowLoad->status = LOAD_STATUS_WAITING;
}
slowLoad->sample.sampleAddr = NULL;
slowLoad->isDone = isDone;
size = seqTable->entries[seqId].size;
size = ALIGN16(size);
if (!gUseLegacySD) {
char* seqData = ResourceMgr_LoadSeqByID(seqId);
size = ResourceMgr_GetSeqSizeByID(seqId) - 2;
slowLoad->curDevAddr = seqData + 2;
slowLoad->medium = seqData[0];
} else {
size = seqTable->entries[seqId].size;
size = ALIGN16(size);
slowLoad->curDevAddr = seqTable->entries[seqId].romAddr;
slowLoad->medium = seqTable->entries[seqId].medium;
}
slowLoad->curRamAddr = ramAddr;
slowLoad->status = LOAD_STATUS_START;
slowLoad->bytesRemaining = size;
slowLoad->ramAddr = ramAddr;
slowLoad->curDevAddr = seqTable->entries[seqId].romAddr;
slowLoad->medium = seqTable->entries[seqId].medium;
slowLoad->seqOrFontId = seqId;
if (slowLoad->medium == MEDIUM_UNK) {
@ -1687,7 +1828,7 @@ void AudioLoad_AsyncDmaUnkMedium(u32 devAddr, void* ramAddr, size_t size, s16 ar
#define RELOC(v, base) (reloc = (void*)((u32)(v) + (u32)(base)))
void AudioLoad_RelocateSample(SoundFontSound* sound, SoundFontData* mem, RelocInfo* relocInfo) {
void AudioLoad_RelocateSample(SoundFontSound* sound, SoundFontData* mem, RelocInfo* relocInfo, int fontId) {
// OTRTODO: This is hack to detect whether or not the sample has been relocated.
size_t maxSoundBankSize = 0x3EB2A0; // sample bank 0 is largest size at 0x3EB2A0
if ((uintptr_t)mem <= maxSoundBankSize) {
@ -1699,32 +1840,58 @@ void AudioLoad_RelocateSample(SoundFontSound* sound, SoundFontData* mem, RelocIn
void* reloc;
// OTRTODO: Seems precarious to assume the RAM is never <= 0x3EB2A0, but it largely works.
if ((uintptr_t)sound->sample < maxSoundBankSize) {
sample = sound->sample = RELOC(sound->sample, mem);
if (sample->size != 0 && sample->unk_bit25 != 1) {
sample->loop = RELOC(sample->loop, mem);
sample->book = RELOC(sample->book, mem);
if ((uintptr_t)sound->sample < maxSoundBankSize || !gUseLegacySD)
{
if (!gUseLegacySD) {
SoundFontSample* sample2 = sound;
// Resolve the sample medium 2-bit bitfield into a real value based on relocInfo.
switch (sample->medium) {
case 0:
sample->sampleAddr = RELOC(sample->sampleAddr, relocInfo->baseAddr1);
sample->medium = relocInfo->medium1;
break;
case 1:
sample->sampleAddr = RELOC(sample->sampleAddr, relocInfo->baseAddr2);
sample->medium = relocInfo->medium2;
break;
case 2:
case 3:
// Invalid? This leaves sample->medium as MEDIUM_CART and MEDIUM_DISK_DRIVE
// respectively, and the sampleAddr unrelocated.
break;
if (sample2->unk_bit25 != 1)
{
//if (sample2->size == 0x5CC8)
//{
// switch (sample2->medium) {
// case 0:
// sample2->medium = relocInfo->medium1;
// break;
// case 1:
// sample2->medium = relocInfo->medium2;
// break;
// }
// sample2->unk_bit25 = 1;
// if (sample2->unk_bit26 && (sample2->medium != MEDIUM_RAM)) {
// // gAudioContext.usedSamples[gAudioContext.numUsedSamples++] = sample2;
// }
//}
}
} else {
sample = sound->sample = RELOC(sound->sample, mem);
sample->unk_bit25 = 1;
if (sample->unk_bit26 && (sample->medium != MEDIUM_RAM)) {
gAudioContext.usedSamples[gAudioContext.numUsedSamples++] = sample;
if (sample->size != 0 && sample->unk_bit25 != 1) {
sample->loop = RELOC(sample->loop, mem);
sample->book = RELOC(sample->book, mem);
// Resolve the sample medium 2-bit bitfield into a real value based on relocInfo.
switch (sample->medium) {
case 0:
sample->sampleAddr = RELOC(sample->sampleAddr, relocInfo->baseAddr1);
sample->medium = relocInfo->medium1;
break;
case 1:
sample->sampleAddr = RELOC(sample->sampleAddr, relocInfo->baseAddr2);
sample->medium = relocInfo->medium2;
break;
case 2:
case 3:
// Invalid? This leaves sample->medium as MEDIUM_CART and MEDIUM_DISK_DRIVE
// respectively, and the sampleAddr unrelocated.
break;
}
sample->unk_bit25 = 1;
if (sample->unk_bit26 && (sample->medium != MEDIUM_RAM)) {
gAudioContext.usedSamples[gAudioContext.numUsedSamples++] = sample;
}
}
}
}
@ -1977,9 +2144,17 @@ void AudioLoad_PreloadSamplesForFont(s32 fontId, s32 async, RelocInfo* relocInfo
gAudioContext.numUsedSamples = 0;
numDrums = gAudioContext.soundFonts[fontId].numDrums;
numInstruments = gAudioContext.soundFonts[fontId].numInstruments;
numSfx = gAudioContext.soundFonts[fontId].numSfx;
if (!gUseLegacySD) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontId);
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
numSfx = sf->numSfx;
} else {
numDrums = gAudioContext.soundFonts[fontId].numDrums;
numInstruments = gAudioContext.soundFonts[fontId].numInstruments;
numSfx = gAudioContext.soundFonts[fontId].numSfx;
}
for (i = 0; i < numInstruments; i++) {
instrument = Audio_GetInstrumentInner(fontId, i);
@ -2024,6 +2199,7 @@ void AudioLoad_PreloadSamplesForFont(s32 fontId, s32 async, RelocInfo* relocInfo
}
sample = gAudioContext.usedSamples[i];
if (sample->medium == MEDIUM_RAM) {
continue;
}
@ -2100,10 +2276,19 @@ void AudioLoad_LoadPermanentSamples(void) {
for (i = 0; i < gAudioContext.permanentPool.count; i++) {
RelocInfo relocInfo;
if (gAudioContext.permanentCache[i].tableType == FONT_TABLE) {
if (gAudioContext.permanentCache[i].tableType == FONT_TABLE)
{
fontId = AudioLoad_GetRealTableIndex(FONT_TABLE, gAudioContext.permanentCache[i].id);
relocInfo.sampleBankId1 = gAudioContext.soundFonts[fontId].sampleBankId1;
relocInfo.sampleBankId2 = gAudioContext.soundFonts[fontId].sampleBankId2;
//fontId = gAudioContext.permanentCache[i].id;
if (!gUseLegacySD) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontId);
relocInfo.sampleBankId1 = sf->sampleBankId1;
relocInfo.sampleBankId2 = sf->sampleBankId2;
} else {
relocInfo.sampleBankId1 = gAudioContext.soundFonts[fontId].sampleBankId1;
relocInfo.sampleBankId2 = gAudioContext.soundFonts[fontId].sampleBankId2;
}
if (relocInfo.sampleBankId1 != 0xFF) {
relocInfo.sampleBankId1 = AudioLoad_GetRealTableIndex(SAMPLE_TABLE, relocInfo.sampleBankId1);

View File

@ -1,6 +1,8 @@
#include "global.h"
#include "Cvar.h"
extern bool gUseLegacySD;
void Audio_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* attrs) {
f32 volRight, volLeft;
s32 smallPanIndex;
@ -307,7 +309,7 @@ SoundFontSound* Audio_InstrumentGetSound(Instrument* instrument, s32 semitone) {
Instrument* Audio_GetInstrumentInner(s32 fontId, s32 instId) {
Instrument* inst;
if (fontId == 0xFF) {
return NULL;
}
@ -317,16 +319,31 @@ Instrument* Audio_GetInstrumentInner(s32 fontId, s32 instId) {
return NULL;
}
if (instId >= gAudioContext.soundFonts[fontId].numInstruments) {
gAudioContext.audioErrorFlags = ((fontId << 8) + instId) + 0x3000000;
return NULL;
int instCnt = 0;
if (gUseLegacySD) {
instCnt = gAudioContext.soundFonts[fontId].numInstruments;
inst = gAudioContext.soundFonts[fontId].instruments[instId];
if (instId >= gAudioContext.soundFonts[fontId].numInstruments)
if (instId >= instCnt) {
gAudioContext.audioErrorFlags = ((fontId << 8) + instId) + 0x3000000;
return NULL;
}
} else {
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontId);
if (instId >= sf->numInstruments)
return NULL;
inst = sf->instruments[instId];
}
inst = gAudioContext.soundFonts[fontId].instruments[instId];
if (inst == NULL) {
gAudioContext.audioErrorFlags = ((fontId << 8) + instId) + 0x1000000;
return inst;
}
return inst;
}
@ -343,12 +360,17 @@ Drum* Audio_GetDrum(s32 fontId, s32 drumId) {
return NULL;
}
if (drumId >= gAudioContext.soundFonts[fontId].numDrums) {
gAudioContext.audioErrorFlags = ((fontId << 8) + drumId) + 0x4000000;
return NULL;
}
if (gUseLegacySD) {
if (drumId >= gAudioContext.soundFonts[fontId].numDrums) {
gAudioContext.audioErrorFlags = ((fontId << 8) + drumId) + 0x4000000;
return NULL;
}
drum = gAudioContext.soundFonts[fontId].drums[drumId];
drum = gAudioContext.soundFonts[fontId].drums[drumId];
} else {
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontId);
drum = sf->drums[drumId];
}
if (drum == NULL) {
gAudioContext.audioErrorFlags = ((fontId << 8) + drumId) + 0x5000000;
@ -369,12 +391,17 @@ SoundFontSound* Audio_GetSfx(s32 fontId, s32 sfxId) {
return NULL;
}
if (sfxId >= gAudioContext.soundFonts[fontId].numSfx) {
gAudioContext.audioErrorFlags = ((fontId << 8) + sfxId) + 0x4000000;
return NULL;
}
if (gUseLegacySD) {
if (sfxId >= gAudioContext.soundFonts[fontId].numSfx) {
gAudioContext.audioErrorFlags = ((fontId << 8) + sfxId) + 0x4000000;
return NULL;
}
sfx = &gAudioContext.soundFonts[fontId].soundEffects[sfxId];
sfx = &gAudioContext.soundFonts[fontId].soundEffects[sfxId];
} else {
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontId);
sfx = &sf->soundEffects[sfxId];
}
if (sfx == NULL) {
gAudioContext.audioErrorFlags = ((fontId << 8) + sfxId) + 0x5000000;

View File

@ -938,8 +938,16 @@ u8 AudioSeq_GetInstrument(SequenceChannel* channel, u8 instId, Instrument** inst
*instOut = NULL;
return 0;
}
adsr->envelope = inst->envelope;
adsr->releaseRate = inst->releaseRate;
if (inst->envelope != NULL)
{
adsr->envelope = inst->envelope;
adsr->releaseRate = (inst->releaseRate);
}
else {
adsr->envelope = gDefaultEnvelope;
}
*instOut = inst;
instId += 2;
return instId;

View File

@ -749,8 +749,10 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
cmd = AudioSynth_LoadWaveSamples(cmd, noteSubEu, synthState, nSamplesToLoad);
noteSamplesDmemAddrBeforeResampling = DMEM_UNCOMPRESSED_NOTE + (synthState->samplePosInt * 2);
synthState->samplePosInt += nSamplesToLoad;
} else {
} else
{
audioFontSample = noteSubEu->sound.soundFontSound->sample;
loopInfo = audioFontSample->loop;
loopEndPos = loopInfo->end;
sampleAddr = audioFontSample->sampleAddr;
@ -822,6 +824,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
noteFinished = true;
}
}
switch (audioFontSample->codec) {
case CODEC_ADPCM:
@ -848,6 +851,9 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
goto skip;
case CODEC_S16:
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted * 2) + 0x20);
AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, ALIGN16(nSamplesToLoad * 2),
audioFontSample->sampleAddr + (synthState->samplePosInt * 2));
flags = A_CONTINUE;
skipBytes = 0;
nSamplesProcessed = samplesLenAdjusted;
@ -860,7 +866,8 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
if (nFramesToDecode != 0) {
frameIndex = (synthState->samplePosInt + skipInitialSamples - nFirstFrameSamplesToIgnore) / 16;
sampleDataOffset = frameIndex * frameSize;
if (audioFontSample->medium == MEDIUM_RAM) {
if (audioFontSample->medium == MEDIUM_RAM)
{
sampleData = (u8*)(sampleDataStart + sampleDataOffset + sampleAddr);
} else if (audioFontSample->medium == MEDIUM_UNK) {
return cmd;
@ -1024,7 +1031,8 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
unk7 = noteSubEu->unk_07;
unkE = noteSubEu->unk_0E;
buf = &synthState->synthesisBuffers->panSamplesBuffer[0x18];
if (unk7 != 0 && noteSubEu->unk_0E != 0) {
if (unk7 != 0 && noteSubEu->unk_0E != 0)
{
AudioSynth_DMemMove(cmd++, DMEM_TEMP, DMEM_SCRATCH2, aiBufLen * 2);
thing = DMEM_SCRATCH2 - unk7;
if (synthState->unk_1A != 0) {

View File

@ -213,11 +213,7 @@ AudioTask* func_800E5000(void) {
task = &gAudioContext.currTask->task.t;
task->type = M_AUDTASK;
task->flags = 0;
//task->ucode_boot = D_801120C0;
task->ucode_boot_size = 0x1000;
//task->ucode_data_size = ((rspAspMainDataEnd - rspAspMainDataStart) * sizeof(u64)) - 1;
//task->ucode = D_801120C0;
//task->ucode_data = rspAspMainDataStart;
task->ucode_size = 0x1000;
task->dram_stack = NULL;
task->dram_stack_size = 0;