#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::ParseXML(tinyxml2::XMLElement* reader) { ZResource::ParseXML(reader); auto t = reader->Name(); auto child = reader->FirstChildElement(); while (child != nullptr) { int bp = 0; if (std::string(child->Value()) == "Sequences") { auto seqChild = child->FirstChildElement(); while (seqChild != nullptr) { if (std::string(seqChild->Value()) == "Sequence") { seqNames.push_back(seqChild->Attribute("Name")); } seqChild = seqChild->NextSiblingElement(); } } if (std::string(child->Value()) == "Samples") { int bankId = child->IntAttribute("Bank", 0); auto sampChild = child->FirstChildElement(); while (sampChild != nullptr) { if (std::string(sampChild->Value()) == "Sample") { auto atStr = sampChild->FirstChildElement()->Attribute("At"); sampleOffsets[bankId][StringHelper::StrToL(atStr, 16)] = sampChild->Attribute("Name"); } sampChild = sampChild->NextSiblingElement(); } } child = child->NextSiblingElement(); } } void ZAudio::DecodeADPCMSample(SampleEntry* sample) { int16_t buffer[1024 * 128]; int16_t* out = &buffer[0]; } std::vector ZAudio::ParseEnvelopeData(std::vector audioBank, std::vector audioTable, int envelopeOffset, int baseOffset) { std::vector result; 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 audioBank, std::vector audioTable, AudioTableEntry audioSampleBankEntry, int bankIndex, int soundFontOffset, int baseOffset) { SoundFontEntry* soundFont = new SoundFontEntry(); soundFont->sampleEntry = ParseSampleEntry( audioBank, audioTable, audioSampleBankEntry, bankIndex, BitConverter::ToInt32BE(audioBank, soundFontOffset + 0) + baseOffset, baseOffset); soundFont->tuning = BitConverter::ToFloatBE(audioBank, soundFontOffset + 4); return soundFont; } SampleEntry* ZAudio::ParseSampleEntry(std::vector audioBank, std::vector audioTable, AudioTableEntry audioSampleBankEntry, int bankIndex, int sampleOffset, int baseOffset) { int sampleDataOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 4) + audioSampleBankEntry.ptr; if (samples.find(sampleOffset) == samples.end()) { SampleEntry* sample = new SampleEntry(); sample->bankId = bankIndex; 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(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))); } sample->sampleDataOffset = sampleDataOffset; sample->fileName = StringHelper::Sprintf("audio/samples/sample_%08X", sampleOffset); samples[sampleOffset] = sample; return sample; } else { return samples[sampleOffset]; } } std::vector ZAudio::ParseAudioTable(std::vector codeData, int baseOffset) { std::vector 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 codeData, std::vector audioTable, std::vector 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], 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); 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], 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], sampleBankId1, currentOffset + 8, ptr); if (BitConverter::ToInt32BE(codeData, currentOffset + 16) != 0) instrument.normalNotesSound = ParseSoundFontEntry( codeData, audioTable, audioSampleBank[sampleBankId1], sampleBankId1, currentOffset + 16, ptr); if (BitConverter::ToInt32BE(codeData, currentOffset + 24) != 0 && instrument.normalRangeHi != 0x7F) instrument.highNotesSound = ParseSoundFontEntry( codeData, audioTable, audioSampleBank[sampleBankId1], sampleBankId1, currentOffset + 24, ptr); } entry.instruments.push_back(instrument); } } void ZAudio::ParseRawData() { ZResource::ParseRawData(); std::vector codeData; std::vector audioTableData; std::vector audioBankData; std::vector 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"); //codeData = File::ReadAllBytes("baserom/code_ntsc"); //audioTableData = File::ReadAllBytes("baserom/Audiotable_ntsc"); //audioSeqData = File::ReadAllBytes("baserom/Audioseq_ntsc"); //audioBankData = File::ReadAllBytes("baserom/Audiobank_ntsc"); // TABLE PARSING // GC PAL //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 gSequenceFontTableOffset = 0x1384E0; // OTRTODO: Make this an XML Param // NMQ DBG ROM //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 //int gSequenceFontTableOffset = 0x138500; // OTRTODO: Make this an XML Param // NTSC 1.0 int gSoundFontTableOffset = 0x1026A0; // OTRTODO: Make this an XML Param int gSequenceTableOffset = 0x102AD0; // OTRTODO: Make this an XML Param int gSampleBankTableOffset = 0x1031C0; // OTRTODO: Make this an XML Param int gSequenceFontTableOffset = 0x102910; // OTRTODO: Make this an XML Param soundFontTable = ParseAudioTable(codeData, gSoundFontTableOffset); sequenceTable = ParseAudioTable(codeData, gSequenceTableOffset); sampleBankTable = ParseAudioTable(codeData, gSampleBankTableOffset); // SEQEUNCE FONT TABLE PARSING for (int i = 0; i < sequenceTable.size(); i++) { uint16_t idx = BitConverter::ToUInt16BE(codeData, gSequenceFontTableOffset + (i * 2)); uint8_t numFonts = codeData[gSequenceFontTableOffset + (idx++)]; std::vector fontIds; for (int j = 0; j < numFonts; j++) { uint8_t fontId = codeData[gSequenceFontTableOffset + (idx++)]; fontIds.push_back(fontId); } fontIndices.push_back(fontIds); } // SAMPLE/FONT PARSING for (int i = 0; i < soundFontTable.size(); i++) { ParseSoundFont(audioBankData, audioTableData, sampleBankTable, soundFontTable[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 seqVec = std::vector(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; }