#include "nw4r/snd/snd_SoundArchiveFile.h" /* Original source: * kiwi515/ogws * src/nw4r/snd/snd_SoundArchiveFile.cpp */ /******************************************************************************* * headers */ #include #include #include "common.h" #include "nw4r/snd/snd_global.h" #include "nw4r/snd/snd_SoundArchive.h" #include "nw4r/snd/snd_Util.h" #include "nw4r/ut/ut_binaryFileFormat.h" // ut::BinaryFileHeader #include "nw4r/ut/ut_algorithm.h" // ut::AddOffsetToPtr #include /******************************************************************************* * functions */ namespace nw4r { namespace snd { namespace detail { SoundArchiveFileReader::SoundArchiveFileReader() : mInfo (nullptr), mStringBase (nullptr), mStringTable (nullptr), mStringTreeSound (nullptr), mStringTreePlayer (nullptr), mStringTreeGroup (nullptr), mStringTreeBank (nullptr) { } void SoundArchiveFileReader::Init(void const *soundArchiveData) { NW4RAssertPointerNonnull_Line(50, soundArchiveData); if (IsValidFileHeader(soundArchiveData)) { mHeader = *static_cast( soundArchiveData); } } bool SoundArchiveFileReader::IsValidFileHeader(void const *soundArchiveData) { ut::BinaryFileHeader const *fileHeader = static_cast(soundArchiveData); NW4RAssertMessage_Line( 75, fileHeader->signature == SoundArchiveFile::SIGNATURE_FILE, "invalid file signature. sound archive data is not available."); if (fileHeader->signature != SoundArchiveFile::SIGNATURE_FILE) return false; NW4RAssertMessage_Line( 83, fileHeader->version >= NW4R_FILE_VERSION(1, 0), "sound archive file is not supported version.\n" " please reconvert file using new version tools.\n"); if (fileHeader->version < NW4R_FILE_VERSION(1, 0)) return false; NW4RAssertMessage_Line( 89, fileHeader->version <= SoundArchiveFile::FILE_VERSION, "sound archive file is not supported version.\n" " please reconvert file using new version tools.\n"); if (fileHeader->version > SoundArchiveFile::FILE_VERSION) return false; return true; } void SoundArchiveFileReader::SetStringChunk(void const *stringChunk, u32 stringChunkSize ATTR_UNUSED) { NW4RAssertPointerNonnull_Line(99, stringChunk); SoundArchiveFile::SymbolBlock const *symbolBlock = static_cast(stringChunk); NW4RAssert_Line(102, symbolBlock->blockHeader.kind == SoundArchiveFile::SIGNATURE_SYMB_BLOCK); SoundArchiveFile::StringBlock const *stringBlock = &symbolBlock->stringBlock; mStringBase = stringBlock; mStringTable = static_cast( GetPtrConst(mStringBase, stringBlock->stringChunk.tableOffset)); mStringTreeSound = static_cast( GetPtrConst(mStringBase, stringBlock->stringChunk.soundTreeOffset)); mStringTreePlayer = static_cast( GetPtrConst(mStringBase, stringBlock->stringChunk.playerTreeOffset)); mStringTreeGroup = static_cast( GetPtrConst(mStringBase, stringBlock->stringChunk.groupTreeOffset)); mStringTreeBank = static_cast( GetPtrConst(mStringBase, stringBlock->stringChunk.bankTreeOffset)); } void SoundArchiveFileReader::SetInfoChunk(void const *infoChunk, u32 infoChunkSize ATTR_UNUSED) { NW4RAssertPointerNonnull_Line(123, infoChunk); SoundArchiveFile::InfoBlock const *infoBlock = static_cast(infoChunk); NW4RAssert_Line(126, infoBlock->blockHeader.kind == SoundArchiveFile::SIGNATURE_INFO_BLOCK); mInfo = &infoBlock->info; } SoundArchive::SoundType SoundArchiveFileReader::GetSoundType(u32 soundId) const { SoundArchiveFile::SoundType soundType; SoundArchiveFile::SoundCommonInfoTable const *table = Util::GetDataRefAddress0(mInfo->soundTableRef, mInfo); if (!table) return SoundArchive::SOUND_TYPE_INVALID; if (soundId >= table->count) return SoundArchive::SOUND_TYPE_INVALID; if (GetVersion() >= NW4R_FILE_VERSION(1, 1)) { SoundArchiveFile::SoundCommonInfo const *soundCommonInfo = Util::GetDataRefAddress0(table->item[soundId], mInfo); if (!soundCommonInfo) return SoundArchive::SOUND_TYPE_INVALID; soundType = static_cast( soundCommonInfo->soundType); } else { soundType = static_cast( table->item[soundId].dataType); } switch (soundType) { case SoundArchiveFile::SOUND_TYPE_SEQ: return SoundArchive::SOUND_TYPE_SEQ; case SoundArchiveFile::SOUND_TYPE_STRM: return SoundArchive::SOUND_TYPE_STRM; case SoundArchiveFile::SOUND_TYPE_WAVE: return SoundArchive::SOUND_TYPE_WAVE; default: return SoundArchive::SOUND_TYPE_INVALID; } } bool SoundArchiveFileReader::ReadSoundInfo(u32 soundId, SoundArchive::SoundInfo *info) const { SoundArchiveFile::SoundCommonInfo const *src = impl_GetSoundInfo(soundId); if (!src) return false; info->fileId = src->fileId; info->playerId = src->playerId; info->actorPlayerId = src->actorPlayerId; info->playerPriority = src->playerPriority; info->volume = src->volume; info->remoteFilter = src->remoteFilter; if (GetVersion() >= NW4R_FILE_VERSION(1, 2)) { info->panMode = static_cast(src->panMode); info->panCurve = static_cast(src->panCurve); } else { info->panMode = PAN_MODE_BALANCE; info->panCurve = PAN_CURVE_SQRT; } return true; } #if 0 /* SoundArchiveFileReader::ReadSound3DParam * ([R89JEL]:/bin/RVL/Debug/mainD.MAP:14110) */ DECOMP_FORCE(Util::GetDataRefAddress0( *(Util::DataRef *)(nullptr), nullptr)); #endif bool SoundArchiveFileReader::ReadSound3DParam(u32 soundId, SoundArchive::Sound3DParam *param) const { SoundArchiveFile::SoundCommonInfo const *src = impl_GetSoundInfo(soundId); if (!src) return false; SoundArchiveFile::Sound3DParam const *arParam = Util::GetDataRefAddress0(src->param3dRef, mInfo); if (!arParam) return false; param->flags = arParam->flags; param->decayCurve = arParam->decayCurve; param->decayRatio = arParam->decayRatio; param->field_0x06 = arParam->field_0x06; return true; } bool SoundArchiveFileReader::ReadSeqSoundInfo( u32 soundId, SoundArchive::SeqSoundInfo *info) const { SoundArchiveFile::SeqSoundInfo const *src = impl_GetSeqSoundInfo(soundId); if (!src) return false; info->dataOffset = src->dataOffset; info->bankId = src->bankId; info->channelPriority = src->channelPriority; info->allocTrack = src->allocTrack; if (GetVersion() >= NW4R_FILE_VERSION(1, 3)) info->releasePriorityFixFlag = src->releasePriorityFix; else info->releasePriorityFixFlag = false; return true; } bool SoundArchiveFileReader::ReadStrmSoundInfo( u32 soundId, SoundArchive::StrmSoundInfo *info) const { SoundArchiveFile::StrmSoundInfo const *src = impl_GetStrmSoundInfo(soundId); if (!src) return false; info->startPosition = src->startPosition; info->allocTrackFlag = src->allocTrackFlag; if (GetVersion() >= NW4R_FILE_VERSION(1, 4)) { info->allocChannelCount = src->allocChannelCount; } else { info->allocChannelCount = 0; // is this meant to be src->allocTrackFlag? for (u16 bitflag = src->allocChannelCount; bitflag; bitflag >>= 1) { if (bitflag & 1) info->allocChannelCount++; else if (bitflag) return false; } } return true; } bool SoundArchiveFileReader::ReadWaveSoundInfo( u32 soundId, SoundArchive::WaveSoundInfo *info) const { SoundArchiveFile::WaveSoundInfo const *src = impl_GetWaveSoundInfo(soundId); if (!src) return false; info->subNo = src->subNo; info->channelPriority = src->channelPriority; if (GetVersion() >= NW4R_FILE_VERSION(1, 3)) info->releasePriorityFixFlag = src->releasePriorityFix; else info->releasePriorityFixFlag = false; return true; } bool SoundArchiveFileReader::ReadBankInfo(u32 bankId, SoundArchive::BankInfo *info) const { SoundArchiveFile::BankInfo const *src = impl_GetBankInfo(bankId); if (!src) return false; info->fileId = src->fileId; return true; } bool SoundArchiveFileReader::ReadPlayerInfo( u32 playerId, SoundArchive::PlayerInfo *info) const { SoundArchiveFile::PlayerInfo const *src = impl_GetPlayerInfo(playerId); if (!src) return false; info->playableSoundCount = src->playableSoundCount; info->heapSize = src->heapSize; return true; } bool SoundArchiveFileReader::ReadGroupInfo(u32 groupId, SoundArchive::GroupInfo *info) const { SoundArchiveFile::GroupInfo const *src = impl_GetGroupInfo(groupId); if (!src) return false; SoundArchiveFile::GroupItemInfoTable const *itemTable = Util::GetDataRefAddress0(src->itemTableRef, mInfo); if (!itemTable) return false; info->extFilePath = Util::GetDataRefAddress0(src->extFilePathRef, mInfo); info->offset = src->offset; info->size = src->size; info->waveDataOffset = src->waveDataOffset; info->waveDataSize = src->waveDataSize; info->itemCount = itemTable->count; return true; } bool SoundArchiveFileReader::ReadGroupItemInfo( u32 groupId, u32 index, SoundArchive::GroupItemInfo *info) const { SoundArchiveFile::GroupInfo const *groupInfo = impl_GetGroupInfo(groupId); if (!groupInfo) return false; SoundArchiveFile::GroupItemInfoTable const *itemTable = Util::GetDataRefAddress0(groupInfo->itemTableRef, mInfo); if (!itemTable) return false; if (index >= itemTable->count) return false; SoundArchiveFile::GroupItemInfo const *src = Util::GetDataRefAddress0(itemTable->item[index], mInfo); if (!src) return false; info->fileId = src->fileId; info->offset = src->offset; info->size = src->size; info->waveDataOffset = src->waveDataOffset; info->waveDataSize = src->waveDataSize; return true; } bool SoundArchiveFileReader::ReadSoundArchivePlayerInfo( SoundArchive::SoundArchivePlayerInfo *info) const { SoundArchiveFile::SoundArchivePlayerInfo const *src = Util::GetDataRefAddress0(mInfo->soundArchivePlayerInfoRef, mInfo); // ERRATUM: checks info instead of src like the other functions if (!info) return false; info->seqSoundCount = src->seqSoundCount; info->seqTrackCount = src->seqTrackCount; info->strmSoundCount = src->strmSoundCount; info->strmTrackCount = src->strmTrackCount; info->strmChannelCount = src->strmChannelCount; info->waveSoundCount = src->waveSoundCount; info->waveTrackCount = src->waveTrackCount; return true; } u32 SoundArchiveFileReader::GetSoundStringId(u32 id) const { const SoundArchiveFile::SoundCommonInfo* pInfo = impl_GetSoundInfo(id); if (pInfo == NULL) { return SoundArchive::INVALID_ID; } return pInfo->stringId; } u32 SoundArchiveFileReader::GetPlayerCount() const { SoundArchiveFile::PlayerInfoTable const *table = Util::GetDataRefAddress0(mInfo->playerTableRef, mInfo); if (table == NULL) return false; return table->count; } u32 SoundArchiveFileReader::GetGroupCount() const { SoundArchiveFile::GroupInfoTable const *table = Util::GetDataRefAddress0(mInfo->groupTableRef, mInfo); if (table == NULL) return false; // TODO: why - 1? return table->count - 1; } #if 0 DECOMP_FORCE(Util::GetDataRefAddress0( *(Util::DataRef *)(nullptr), nullptr)); #endif const char* SoundArchiveFileReader::GetSoundLabelString(u32 id) const { return GetString(GetSoundStringId(id)); } u32 SoundArchiveFileReader::GetSoundUserParam(u32 id) const { const SoundArchiveFile::SoundCommonInfo* pInfo = impl_GetSoundInfo(id); if (pInfo == NULL) { return 0; } return pInfo->userParam[0]; } u32 SoundArchiveFileReader::GetFileCount() const { SoundArchiveFile::FileInfoTable const *table = Util::GetDataRefAddress0(mInfo->fileTableRef, mInfo); if (table == NULL) return false; return table->count; } bool SoundArchiveFileReader::ReadFileInfo(u32 fileId, SoundArchive::FileInfo *info) const { SoundArchiveFile::FileInfoTable const *table = Util::GetDataRefAddress0(mInfo->fileTableRef, mInfo); if (!table) return false; if (fileId >= table->count) return false; SoundArchiveFile::FileInfo const *fileInfo = Util::GetDataRefAddress0(table->item[fileId], mInfo); if (!fileInfo) return false; SoundArchiveFile::FilePosTable const *filePosTable = Util::GetDataRefAddress0(fileInfo->filePosTableRef, mInfo); if (!filePosTable) return false; info->fileSize = fileInfo->fileSize; info->waveDataFileSize = fileInfo->waveDataFileSize; info->extFilePath = Util::GetDataRefAddress0(fileInfo->extFilePathRef, mInfo); info->filePosCount = filePosTable->count; return true; } bool SoundArchiveFileReader::ReadFilePos(u32 fileId, u32 index, SoundArchive::FilePos *filePos) const { SoundArchiveFile::FileInfoTable const *table = Util::GetDataRefAddress0(mInfo->fileTableRef, mInfo); if (!table) return false; if (fileId >= table->count) return false; SoundArchiveFile::FileInfo const *fileInfo = Util::GetDataRefAddress0(table->item[fileId], mInfo); if (!fileInfo) return false; SoundArchiveFile::FilePosTable const *filePosTable = Util::GetDataRefAddress0(fileInfo->filePosTableRef, mInfo); if (!filePosTable) return false; if (index >= filePosTable->count) return false; SoundArchive::FilePos const *pos = Util::GetDataRefAddress0(filePosTable->item[index], mInfo); if (!pos) return false; *filePos = *pos; return true; } char const *SoundArchiveFileReader::GetString(u32 id) const { if (id == SoundArchive::INVALID_ID) return nullptr; if (!mStringTable) return nullptr; NW4RAssert_Line(508, id < mStringTable->offsetTable.count); char const *str = static_cast( GetPtrConst(mStringBase, mStringTable->offsetTable.item[id])); return str; } u32 SoundArchiveFileReader::ConvertLabelStringToId( SoundArchiveFile::StringTree const *tree, char const *str) const { if (!tree) return SoundArchive::INVALID_ID; if (tree->rootIdx >= tree->nodeTable.count) return SoundArchive::INVALID_ID; SoundArchiveFile::StringTreeNode const *node = &tree->nodeTable.item[tree->rootIdx]; u32 strlen = std::strlen(str); while (!(node->flags & 1)) { int pos = node->bit >> 3; int bit = node->bit & 7; u32 nodeIdx; if (pos < static_cast(strlen) && (1 << (7 - bit)) & str[pos]) nodeIdx = node->rightIdx; else nodeIdx = node->leftIdx; node = &tree->nodeTable.item[nodeIdx]; } char const *str_cmp = GetString(node->strIdx); if (std::strcmp(str, str_cmp) == 0) return node->id; else return SoundArchive::INVALID_ID; } SoundArchiveFile::SoundCommonInfo const * SoundArchiveFileReader::impl_GetSoundInfo(u32 soundId) const { SoundArchiveFile::SoundCommonInfoTable const *table = Util::GetDataRefAddress0(mInfo->soundTableRef, mInfo); if (!table) return nullptr; if (soundId >= table->count) return nullptr; if (GetVersion() >= NW4R_FILE_VERSION(1, 1)) { return Util::GetDataRefAddress0(table->item[soundId], mInfo); } else { return static_cast( ut::AddOffsetToPtr(mInfo, table->item[soundId].value)); } } bool SoundArchiveFileReader::impl_GetSoundInfoOffset( u32 soundId, SoundArchiveFile::SoundInfoRef *soundInfoRef) const { SoundArchiveFile::SoundCommonInfoTable const *table = Util::GetDataRefAddress0(mInfo->soundTableRef, mInfo); if (!table) return false; if (soundId >= table->count) return false; if (GetVersion() >= NW4R_FILE_VERSION(1, 1)) { SoundArchiveFile::SoundCommonInfo const *soundCommonInfo = Util::GetDataRefAddress0(table->item[soundId], mInfo); if (!soundCommonInfo) return false; *soundInfoRef = soundCommonInfo->soundInfoRef; return true; } else { SoundArchiveFile::SoundInfoRef ref; // TODO (from ogws): Why is 28 added to value? ref.refType = table->item[soundId].refType; ref.dataType = table->item[soundId].dataType; ref.value = table->item[soundId].value + 28; *soundInfoRef = ref; return true; } } SoundArchiveFile::SeqSoundInfo const * SoundArchiveFileReader::impl_GetSeqSoundInfo(u32 soundId) const { if (GetSoundType(soundId) != SoundArchive::SOUND_TYPE_SEQ) return nullptr; SoundArchiveFile::SoundInfoRef dataRef; bool result = impl_GetSoundInfoOffset(soundId, &dataRef); if (!result) return nullptr; return Util::GetDataRefAddress1(dataRef, mInfo); } SoundArchiveFile::StrmSoundInfo const * SoundArchiveFileReader::impl_GetStrmSoundInfo(u32 soundId) const { if (GetSoundType(soundId) != SoundArchive::SOUND_TYPE_STRM) return nullptr; SoundArchiveFile::SoundInfoRef dataRef; bool result = impl_GetSoundInfoOffset(soundId, &dataRef); if (!result) return nullptr; return Util::GetDataRefAddress2(dataRef, mInfo); } SoundArchiveFile::WaveSoundInfo const * SoundArchiveFileReader::impl_GetWaveSoundInfo(u32 soundId) const { if (GetSoundType(soundId) != SoundArchive::SOUND_TYPE_WAVE) return nullptr; SoundArchiveFile::SoundInfoRef dataRef; bool result = impl_GetSoundInfoOffset(soundId, &dataRef); if (!result) return nullptr; return Util::GetDataRefAddress3(dataRef, mInfo); } SoundArchiveFile::BankInfo const *SoundArchiveFileReader::impl_GetBankInfo( u32 bankId) const { SoundArchiveFile::BankInfoTable const *table = Util::GetDataRefAddress0(mInfo->bankTableRef, mInfo); if (!table) return nullptr; if (bankId >= table->count) return nullptr; return Util::GetDataRefAddress0(table->item[bankId], mInfo); } SoundArchiveFile::PlayerInfo const *SoundArchiveFileReader::impl_GetPlayerInfo( u32 playerId) const { SoundArchiveFile::PlayerInfoTable const *table = Util::GetDataRefAddress0(mInfo->playerTableRef, mInfo); if (!table) return nullptr; if (playerId >= table->count) return nullptr; return Util::GetDataRefAddress0(table->item[playerId], mInfo); } SoundArchiveFile::GroupInfo const *SoundArchiveFileReader::impl_GetGroupInfo( u32 groupId) const { SoundArchiveFile::GroupInfoTable const *table = Util::GetDataRefAddress0(mInfo->groupTableRef, mInfo); if (!table) return nullptr; if (groupId >= table->count) return nullptr; return Util::GetDataRefAddress0(table->item[groupId], mInfo); } }}} // namespace nw4r::snd::detail