#include "nw4r/snd/snd_StrmFile.h" /* Original source: * kiwi515/ogws * src/nw4r/snd/snd_StrmFile.cpp */ /******************************************************************************* * headers */ #include "common.h" #include "nw4r/snd/snd_adpcm.h" #include "nw4r/snd/snd_global.h" #include "nw4r/snd/snd_Util.h" #include "nw4r/snd/snd_WaveFile.h" #include "nw4r/ut/ut_binaryFileFormat.h" #include "nw4r/ut/ut_FileStream.h" #include "nw4r/ut/ut_algorithm.h" #include "nw4r/NW4RAssert.hpp" /******************************************************************************* * functions */ namespace nw4r { namespace snd { namespace detail { bool StrmFileReader::IsValidFileHeader(void const *strmData) { NW4RAssertPointerNonnull_Line(42, strmData); ut::BinaryFileHeader const *fileHeader = static_cast(strmData); NW4RAssertMessage_Line( 51, fileHeader->signature == StrmFile::SIGNATURE_FILE, "invalid file signature. strm data is not available."); if (fileHeader->signature != StrmFile::SIGNATURE_FILE) return false; NW4RAssertMessage_Line(59, fileHeader->version >= NW4R_FILE_VERSION(1, 0), "strm 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(65, fileHeader->version <= SUPPORTED_FILE_VERSION, "strm file is not supported version.\n" " please reconvert file using new version tools.\n"); if (fileHeader->version > SUPPORTED_FILE_VERSION) return false; return true; } StrmFileReader::StrmFileReader() : mHeader (nullptr), mHeadBlock (nullptr) { } void StrmFileReader::Setup(void const *strmData) { NW4RAssertPointerNonnull_Line(97, strmData); if (!IsValidFileHeader(strmData)) return; mHeader = static_cast(strmData); mHeadBlock = static_cast( ut::AddOffsetToPtr(mHeader, mHeader->headBlockOffset)); NW4RAssert_Line(106, mHeadBlock->blockHeader.kind == StrmFile::SIGNATURE_HEAD_BLOCK); StrmFile::StrmDataInfo const *info = Util::GetDataRefAddress0( mHeadBlock->refDataHeader, &mHeadBlock->refDataHeader); // definitely could have just used align assert here NW4RAssert_Line(113, info->blockSize % 32 == 0); } int StrmFileReader::GetTrackCount() const { NW4RAssertPointerNonnull_Line(142, mHeader); StrmFile::TrackTable const *trackTable = Util::GetDataRefAddress0( mHeadBlock->refTrackTable, &mHeadBlock->refDataHeader); return trackTable->trackCount; } int StrmFileReader::GetChannelCount() const { NW4RAssertPointerNonnull_Line(163, mHeader); StrmFile::ChannelTable const *channelTable = Util::GetDataRefAddress0( mHeadBlock->refChannelTable, &mHeadBlock->refDataHeader); return channelTable->channelCount; } bool StrmFileReader::ReadStrmInfo(StrmInfo *strmInfo) const { NW4RAssertPointerNonnull_Line(184, mHeader); StrmFile::StrmDataInfo const *info = Util::GetDataRefAddress0( mHeadBlock->refDataHeader, &mHeadBlock->refDataHeader); NW4RAssertAligned_Line(192, info->blockHeaderOffset, 32); NW4RAssertAligned_Line(193, info->blockSize, 32); NW4RAssertAligned_Line(194, info->lastBlockPaddedSize, 32); // clang-format off strmInfo->sampleFormat = GetSampleFormatFromStrmFileFormat(info->format); strmInfo->loopFlag = info->loopFlag; strmInfo->numChannels = info->numChannels; strmInfo->sampleRate = (info->sampleRate24 << 16) + info->sampleRate; strmInfo->blockHeaderOffset = info->blockHeaderOffset; strmInfo->loopStart = info->loopStart; strmInfo->loopEnd = info->loopEnd; strmInfo->dataOffset = info->dataOffset; strmInfo->numBlocks = info->numBlocks; strmInfo->blockSize = info->blockSize; strmInfo->blockSamples = info->blockSamples; strmInfo->lastBlockSize = info->lastBlockSize; strmInfo->lastBlockSamples = info->lastBlockSamples; strmInfo->lastBlockPaddedSize = info->lastBlockPaddedSize; strmInfo->adpcmDataInterval = info->adpcmDataInterval; strmInfo->adpcmDataSize = info->adpcmDataSize; // clang-format on return true; } bool StrmFileReader::ReadStrmTrackInfo(StrmTrackInfo *trackInfo, int trackIndex) const { NW4RAssertPointerNonnull_Line(218, mHeader); StrmFile::TrackTable const *trackTable = Util::GetDataRefAddress0( mHeadBlock->refTrackTable, &mHeadBlock->refDataHeader); if (trackIndex >= trackTable->trackCount) return false; switch (trackTable->trackDataType) { case 0: { StrmFile::TrackInfo const *src = Util::GetDataRefAddress0( trackTable->refTrackHeader[trackIndex], &mHeadBlock->refDataHeader); if (!src) return false; trackInfo->volume = 127; trackInfo->pan = 64; trackInfo->channelCount = src->channelCount; int count = ut::Min(trackInfo->channelCount, 32); for (int i = 0; i < count; i++) trackInfo->channelIndexTable[i] = src->channelIndexTable[i]; } break; case 1: { StrmFile::TrackInfoEx const *src = Util::GetDataRefAddress1( trackTable->refTrackHeader[trackIndex], &mHeadBlock->refDataHeader); if (!src) return false; trackInfo->volume = src->volume; trackInfo->pan = src->pan; trackInfo->channelCount = src->channelCount; int count = ut::Min(trackInfo->channelCount, 32); for (int i = 0; i < count; i++) trackInfo->channelIndexTable[i] = src->channelIndexTable[i]; } break; default: NW4RPanic_Line(268); // return false here for NDEBUG? break; } return true; } bool StrmFileReader::ReadAdpcmInfo(AdpcmParam *adpcmParam, AdpcmLoopParam *adpcmLoopParam, int channelIndex) const { NW4RAssertPointerNonnull_Line(289, mHeader); NW4RAssertPointerNonnull_Line(290, adpcmParam); NW4RAssertPointerNonnull_Line(291, adpcmLoopParam); StrmFile::StrmDataInfo const *info = Util::GetDataRefAddress0( mHeadBlock->refDataHeader, &mHeadBlock->refDataHeader); if (info->format != 2) return false; StrmFile::ChannelTable const *channelTable = Util::GetDataRefAddress0( mHeadBlock->refChannelTable, &mHeadBlock->refDataHeader); if (channelIndex >= channelTable->channelCount) return false; StrmFile::ChannelInfo const *channelInfo = Util::GetDataRefAddress0(channelTable->refChannelHeader[channelIndex], &mHeadBlock->refDataHeader); StrmFile::AdpcmParamSet const *src = Util::GetDataRefAddress0( channelInfo->refAdpcmInfo, &mHeadBlock->refDataHeader); *adpcmParam = src->adpcmParam; *adpcmLoopParam = src->adpcmLoopParam; return true; } SampleFormat StrmFileReader::GetSampleFormatFromStrmFileFormat(u8 format) { switch (format) { case 2: return SAMPLE_FORMAT_DSP_ADPCM; case 1: return SAMPLE_FORMAT_PCM_S16; case 0: return SAMPLE_FORMAT_PCM_S8; default: NW4RPanicMessage_Line(333, "Unknown strm data format %d", format); return SAMPLE_FORMAT_DSP_ADPCM; } } bool StrmFileLoader::LoadFileHeader(void *buffer, u32 size) { byte_t buffer2[32 + ROUND_UP(sizeof(StrmFile::Header), 0x20)]; mStream.Seek(0, ut::FileStream::SEEK_ORIGIN_SET); s32 readSize = mStream.Read(ut::RoundUp(buffer2, 32), ROUND_UP(sizeof(StrmFile::Header), 0x20)); if (readSize != ROUND_UP(sizeof(StrmFile::Header), 0x20)) return false; StrmFile::Header *header = static_cast(ut::RoundUp(buffer2, 32)); StrmFileReader reader; if (!reader.IsValidFileHeader(header)) return false; if (header->adpcBlockOffset > size) return false; u32 loadSize = header->headBlockOffset + header->headBlockSize; mStream.Seek(0, ut::FileStream::SEEK_ORIGIN_SET); readSize = mStream.Read(buffer, loadSize); if (readSize != loadSize) return false; mReader.Setup(buffer); return true; } int StrmFileLoader::GetTrackCount() const { if (!mReader.IsAvailable()) return 0; return mReader.GetTrackCount(); } int StrmFileLoader::GetChannelCount() const { if (!mReader.IsAvailable()) return 0; return mReader.GetChannelCount(); } bool StrmFileLoader::ReadStrmInfo(StrmFileReader::StrmInfo *strmInfo) const { if (!mReader.IsAvailable()) return false; mReader.ReadStrmInfo(strmInfo); return true; } bool StrmFileLoader::ReadStrmTrackInfo(StrmFileReader::StrmTrackInfo *trackInfo, int trackIndex) const { if (!mReader.IsAvailable()) return false; mReader.ReadStrmTrackInfo(trackInfo, trackIndex); return true; } bool StrmFileLoader::ReadAdpcmInfo(AdpcmParam *adpcmParam, AdpcmLoopParam *adpcmLoopParam, int channelIndex) const { if (!mReader.IsAvailable()) return false; mReader.ReadAdpcmInfo(adpcmParam, adpcmLoopParam, channelIndex); return true; } bool StrmFileLoader::ReadAdpcBlockData(u16 *yn1, u16 *yn2, int blockIndex, int channelCount) { if (!mReader.IsAvailable()) return false; s32 readOffset = mReader.GetAdpcBlockOffset() + blockIndex * channelCount * (sizeof(u16) * 2) + sizeof(ut::BinaryBlockHeader); mStream.Seek(readOffset, ut::FileStream::SEEK_ORIGIN_SET); u32 readDataSize = channelCount * (sizeof(u16) * 2); NW4RAssert_Line(499, readDataSize <= 32); ALIGN_DECL(32) u16 buffer[2 * 8]; int readSize = mStream.Read(buffer, sizeof buffer); if (readSize != 32u) return false; for (int i = 0; i < channelCount; i++) { yn1[i] = buffer[i * 2]; yn2[i] = buffer[i * 2 + 1]; } return true; } }}} // namespace nw4r::snd::detail