/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_SoundArchiveLoader.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 28259 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include // #define NW_SND_DEBUG_PRINT_ENABLE #ifdef NW_SND_DEBUG_PRINT_ENABLE #include #endif namespace nw { namespace snd { namespace internal { namespace { const u32 REQUIRED_SIZE_FOR_LOAD_WARC_FILE_HEADER = NW_SND_ROUND_UP_32B( sizeof( internal::WaveArchiveFile::FileHeader ) + 32 ); // 32 バイトごとに読むため class FileStreamHandle { public: FileStreamHandle( io::FileStream* stream ) : m_pStream( stream ) { } ~FileStreamHandle() { if ( m_pStream != NULL ) m_pStream->Close(); } io::FileStream* GetFileStream() { return m_pStream; } io::FileStream* operator->() { return m_pStream; } operator bool() const { return m_pStream != NULL; } private: io::FileStream* m_pStream; }; } // anonymous namespace /*---------------------------------------------------------------------------* Name: SoundArchiveLoader Description: コンストラクタ Arguments: arc - ローダで使用するサウンドアーカイブ Returns: なし *---------------------------------------------------------------------------*/ SoundArchiveLoader::SoundArchiveLoader() : m_pSoundArchive( NULL ) { } /*---------------------------------------------------------------------------* Name: SoundArchiveLoader Description: デストラクタ Arguments: なし Returns: なし *---------------------------------------------------------------------------*/ SoundArchiveLoader::~SoundArchiveLoader() { m_pSoundArchive = NULL; } void SoundArchiveLoader::SetSoundArchive( const SoundArchive* arc ) { m_pSoundArchive = arc; } /*---------------------------------------------------------------------------* Name: IsAvailable Description: サウンドアーカイブプレイヤーが利用可能かどうかを調べる Arguments: 無し Returns: 利用可能かどうかを返す *---------------------------------------------------------------------------*/ bool SoundArchiveLoader::IsAvailable() const { if ( m_pSoundArchive == NULL ) { return false; } if ( ! m_pSoundArchive->IsAvailable() ) { return false; } return true; } bool SoundArchiveLoader::LoadData( SoundArchive::ItemId itemId, SoundMemoryAllocatable* pAllocator, u32 loadFlag, size_t loadBlockSize ) { NW_NULL_ASSERT( m_pSoundArchive ); NW_ALIGN32_ASSERT( loadBlockSize ); if ( ! IsAvailable() ) { return false; } if ( itemId == SoundArchive::INVALID_ID ) { return false; } if ( pAllocator == NULL ) { return false; } switch ( internal::Util::GetItemType( itemId ) ) { case internal::ItemType_Sound: switch ( m_pSoundArchive->GetSoundType( itemId ) ) { case SoundArchive::SOUND_TYPE_SEQ: return LoadSequenceSound( itemId, pAllocator, loadFlag, loadBlockSize ); case SoundArchive::SOUND_TYPE_WAVE: return LoadWaveSound( itemId, pAllocator, loadFlag, loadBlockSize ); case SoundArchive::SOUND_TYPE_STRM: default: return false; } case internal::ItemType_Bank: return LoadBank( itemId, pAllocator, loadFlag, loadBlockSize ); case internal::ItemType_WaveArchive: return LoadWaveArchive( itemId, pAllocator, loadFlag, loadBlockSize ); case internal::ItemType_Group: return LoadGroup( itemId, pAllocator, loadBlockSize ); case internal::ItemType_SoundGroup: return LoadSoundGroup( itemId, pAllocator, loadFlag, loadBlockSize ); case internal::ItemType_Player: default: return false; } } bool SoundArchiveLoader::LoadData( const char* pItemName, SoundMemoryAllocatable* pAllocator, u32 loadFlag, size_t loadBlockSize ) { NW_NULL_ASSERT( m_pSoundArchive ); SoundArchive::ItemId id = m_pSoundArchive->GetItemId( pItemName ); return LoadData( id, pAllocator, loadFlag, loadBlockSize ); } const void* SoundArchiveLoader::LoadImpl( SoundArchive::FileId fileId, SoundMemoryAllocatable* pAllocator, size_t loadBlockSize, bool needDeviceMemory ) { NW_NULL_ASSERT( m_pSoundArchive ); NW_UNUSED_VARIABLE( loadBlockSize ); const void* fileAddress = GetFileAddressImpl( fileId ); // 未ロードの場合 if ( fileAddress == NULL ) { fileAddress = LoadFile( fileId, pAllocator, loadBlockSize, needDeviceMemory ); if ( fileAddress == NULL ) { return NULL; // ロード失敗 } else { SetFileAddressToTable( fileId, fileAddress ); return fileAddress; } } // ロード済みだった場合 else { return fileAddress; } } bool SoundArchiveLoader::LoadSequenceSound( SoundArchive::ItemId soundId, SoundMemoryAllocatable* pAllocator, u32 loadFlag, size_t loadBlockSize ) { if ( loadFlag & LOAD_SEQ ) { u32 fileId = m_pSoundArchive->GetItemFileId( soundId ); const void* pFile = LoadImpl( fileId, pAllocator, loadBlockSize ); if ( pFile == NULL ) { return false; // ロード失敗 } } if ( loadFlag & LOAD_BANK || loadFlag & LOAD_WARC ) { SoundArchive::SequenceSoundInfo info; if ( ! m_pSoundArchive->ReadSequenceSoundInfo( soundId, &info ) ) { return false; // INFO ブロックからシーケンスサウンド情報が得られなかった } for ( int i = 0; i < SoundArchive::SEQ_BANK_MAX; i++ ) { u32 bankId = info.bankIds[ i ]; if ( bankId != SoundArchive::INVALID_ID ) { if ( ! LoadBank( bankId, pAllocator, loadFlag, loadBlockSize ) ) { return false; } } } } return true; } bool SoundArchiveLoader::LoadWaveSound( SoundArchive::ItemId soundId, SoundMemoryAllocatable* pAllocator, u32 loadFlag, size_t loadBlockSize, SoundArchive::ItemId waveSoundSetId ) { u32 wsdFileId = m_pSoundArchive->GetItemFileId( soundId ); if ( loadFlag & LOAD_WSD ) { const void* pFile = LoadImpl( wsdFileId, pAllocator, loadBlockSize ); if ( pFile == NULL ) { return false; // ロード失敗 } } if ( loadFlag & LOAD_WARC ) { const void* pWsdFile = GetFileAddressImpl( wsdFileId ); // ウェーブサウンドセットファイルがロード済みなら、 // 必要に応じて個別ロードを行う if ( pWsdFile != NULL ) { // bcwsd 内でのインデックス取得 u32 index; { SoundArchive::WaveSoundInfo info; if ( ! m_pSoundArchive->detail_ReadWaveSoundInfo( soundId, &info ) ) { return false; // WaveSoundInfo 取得失敗 } index = info.index; } // 関連する波形アーカイブ ID を取得 u32 warcId = SoundArchive::INVALID_ID; u32 waveIndex; { internal::WaveSoundFileReader reader( pWsdFile ); internal::WaveSoundNoteInfo info; if ( ! reader.ReadNoteInfo( &info, index, 0 ) ) { return false; // NoteInfo 取得失敗 } warcId = info.waveArchiveId; waveIndex = info.waveIndex; } // ロード if ( ! LoadWaveArchiveImpl( warcId, waveIndex, pAllocator, loadFlag, loadBlockSize ) ) { return false; } } // 未ロードの場合は、一括ロードのみ行う else { SoundArchive::ItemId itemId; if ( waveSoundSetId != SoundArchive::INVALID_ID ) { itemId = waveSoundSetId; /* ウェーブサウンド ID → ウェーブサウンドセット ID への変換は 時間がかかるので、あらかじめ waveSoundSetId を渡してもらえる場合は これを利用する */ } else { itemId = soundId; } const internal::Util::Table* pWarcIdTable = m_pSoundArchive->detail_GetWaveArchiveIdTable( itemId ); NW_NULL_ASSERT( pWarcIdTable ); for ( u32 i = 0; i < pWarcIdTable->count; i++ ) { if ( ! LoadWaveArchive( pWarcIdTable->item[ i ], pAllocator, loadFlag, loadBlockSize ) ) { return false; } } } } return true; } bool SoundArchiveLoader::LoadBank( SoundArchive::ItemId bankId, SoundMemoryAllocatable* pAllocator, u32 loadFlag, size_t loadBlockSize ) { u32 bankFileId = m_pSoundArchive->GetItemFileId( bankId ); if ( loadFlag & LOAD_BANK ) { const void* pFile = LoadImpl( bankFileId, pAllocator, loadBlockSize ); if ( pFile == NULL ) { return false; // ロード失敗 } } if ( loadFlag & LOAD_WARC ) { const void* pFile = GetFileAddressImpl( bankFileId ); // バンクがロード済みなら、必要に応じて個別ロードを行う if ( pFile != NULL ) { internal::BankFileReader reader( pFile ); const internal::Util::WaveIdTable& table = reader.GetWaveIdTable(); for ( u32 i = 0; i < table.GetCount(); i++ ) { const internal::Util::WaveId& waveId = table.GetWaveId( i ); if ( ! LoadWaveArchiveImpl( waveId.waveArchiveId, waveId.waveIndex, pAllocator, loadFlag, loadBlockSize ) ) { return false; } } } // バンクが未ロードの場合は、一括ロードのみ行う else { const internal::Util::Table* pWarcIdTable = m_pSoundArchive->detail_GetWaveArchiveIdTable( bankId ); NW_NULL_ASSERT( pWarcIdTable ); for ( u32 i = 0; i < pWarcIdTable->count; i++ ) { if ( ! LoadWaveArchive( pWarcIdTable->item[ i ], pAllocator, loadFlag, loadBlockSize ) ) { return false; } } } } return true; } bool SoundArchiveLoader::LoadWaveArchiveImpl( SoundArchive::ItemId warcId, u32 waveIndex, SoundMemoryAllocatable* pAllocator, u32 loadFlag, size_t loadBlockSize ) { SoundArchive::WaveArchiveInfo info; if ( ! m_pSoundArchive->ReadWaveArchiveInfo( warcId, &info ) ) { return false; } if ( info.isLoadIndividual ) { // 波形のロード if ( ! LoadIndividualWave( warcId, waveIndex, pAllocator, loadBlockSize ) ) { return false; } } else { if ( ! LoadWaveArchive( warcId, pAllocator, loadFlag, loadBlockSize ) ) { return false; } } return true; } // 波形アーカイブの一括ロード bool SoundArchiveLoader::LoadWaveArchive( SoundArchive::ItemId warcId, SoundMemoryAllocatable* pAllocator, u32 loadFlag, size_t loadBlockSize ) { if ( loadFlag & LOAD_WARC ) { u32 fileId = m_pSoundArchive->GetItemFileId( warcId ); // 要デバイスメモリ const void* pFile = LoadImpl( fileId, pAllocator, loadBlockSize, true ); if ( pFile == NULL ) { return false; // ロード失敗 } } return true; } const void* SoundArchiveLoader::LoadWaveArchiveTable( SoundArchive::ItemId warcId, SoundMemoryAllocatable* pAllocator, size_t loadBlockSize ) { u32 fileId = m_pSoundArchive->GetItemFileId( warcId ); const void* pWaveArchiveFile = GetFileAddressFromTable( fileId ); if ( pWaveArchiveFile != NULL ) { return pWaveArchiveFile; } // 波形ファイル数 u32 waveCount; { SoundArchive::WaveArchiveInfo info; if ( ! m_pSoundArchive->ReadWaveArchiveInfo( warcId, &info ) ) { return NULL; } if ( info.waveCount <= 0 ) { return NULL; } waveCount = info.waveCount; } // ファイルブロック手前までのオフセット u32 fileBlockOffset; { u8 pBuffer[ REQUIRED_SIZE_FOR_LOAD_WARC_FILE_HEADER ]; u8* pAlignedBuffer = reinterpret_cast( ut::RoundUp( pBuffer, 32 ) ); s32 readSize = ReadFile( fileId, pAlignedBuffer, sizeof(internal::WaveArchiveFile::FileHeader), 0, loadBlockSize ); if ( readSize != sizeof(internal::WaveArchiveFile::FileHeader) ) { return NULL; } const internal::WaveArchiveFile::FileHeader* pHeader = reinterpret_cast( pAlignedBuffer ); fileBlockOffset = pHeader->GetFileBlockOffset(); u32 infoBlockOffset = pHeader->GetInfoBlockOffset(); if ( infoBlockOffset > fileBlockOffset ) { return NULL; // INFO ブロック → FILE ブロックの順に並んでいる必要がある } } // ロード用テーブルを含めたヒープサイズ const u32 REQUIRED_SIZE = fileBlockOffset + waveCount * sizeof( u32 ) + sizeof( internal::WaveArchiveFileReader::SIGNATURE_WARC_TABLE ); void* buffer = pAllocator->Alloc( REQUIRED_SIZE ); if ( ! internal::Util::IsDeviceMemory( reinterpret_cast(buffer), REQUIRED_SIZE ) ) { NW_ASSERTMSG( false, "buffer, buffer + REQUIRED_SIZE is not Device Memory."); return NULL; } { s32 readSize = ReadFile( fileId, buffer, fileBlockOffset, 0, loadBlockSize ); if ( readSize != fileBlockOffset ) { return NULL; } } internal::WaveArchiveFileReader reader( buffer, true ); // テーブル頭につけるシグニチャ std::memcpy( ut::AddOffsetToPtr( buffer, fileBlockOffset ), &internal::WaveArchiveFileReader::SIGNATURE_WARC_TABLE, sizeof( internal::WaveArchiveFileReader::SIGNATURE_WARC_TABLE ) ); reader.InitializeFileTable(); SetFileAddressToTable( fileId, buffer ); return buffer; } bool SoundArchiveLoader::LoadIndividualWave( SoundArchive::ItemId warcId, u32 waveIndex, SoundMemoryAllocatable* pAllocator, size_t loadBlockSize ) { NW_UNUSED_VARIABLE( loadBlockSize ); // (ロードされている) 波形アーカイブファイル取得 u32 fileId = m_pSoundArchive->GetItemFileId( warcId ); const void* pWaveArchiveFile = GetFileAddressFromTable( fileId ); if ( pWaveArchiveFile == NULL ) { pWaveArchiveFile = LoadWaveArchiveTable( warcId, pAllocator, loadBlockSize ); if ( pWaveArchiveFile == NULL ) { return false; } } internal::WaveArchiveFileReader reader( pWaveArchiveFile, true ); // TODO: reader に対して IsLoaded のようなメソッドを呼ぶのは、少し気持ち悪い。 // 波形アーカイブファイルのロード周りの機能は、 // WaveArchiveFileReader から切り分けたほうがいいかもしれない。 if ( reader.IsLoaded( waveIndex ) ) { return true; } const size_t WAVE_FILE_SIZE = reader.GetWaveFileSize( waveIndex ); const size_t REQUIRED_SIZE = WAVE_FILE_SIZE + sizeof(IndividualWaveInfo); void* buffer = pAllocator->Alloc( REQUIRED_SIZE ); if ( ! internal::Util::IsDeviceMemory( reinterpret_cast(buffer), REQUIRED_SIZE ) ) { NW_ASSERTMSG( false, "buffer, buffer + REQUIRED_SIZE is not Device Memory."); return false; } // 個別ロード用の情報書き込み { IndividualWaveInfo iWavInfo( fileId, waveIndex ); std::memcpy( buffer, &iWavInfo, sizeof(IndividualWaveInfo) ); } // 個別ロード波形のロード { void* loadingAddress = ut::AddOffsetToPtr( buffer, sizeof(IndividualWaveInfo) ); s32 readSize = ReadFile( fileId, loadingAddress, WAVE_FILE_SIZE, reader.GetWaveFileOffsetFromFileHead( waveIndex ), loadBlockSize ); if ( readSize != WAVE_FILE_SIZE ) { return false; } // NN_LOG("[%s] warc[%08X](%s) wIdx(%d)\n", // __FUNCTION__, // warcId, // m_pSoundArchive->GetItemLabel(warcId), // waveIndex ); reader.SetWaveFile( waveIndex, loadingAddress ); #ifdef NW_PLATFORM_CTR nn::snd::FlushDataCache( reinterpret_cast(loadingAddress), WAVE_FILE_SIZE ); #endif } return true; } // グループ内の埋め込みアイテムをロード済みファイルテーブルに登録し、 // リンクアイテムをロードする。 bool SoundArchiveLoader::PostProcessForLoadedGroupFile( const void* pGroupFile, SoundMemoryAllocatable* pAllocator, size_t loadBlockSize ) { internal::GroupFileReader reader( pGroupFile ); bool isLinkGroup = false; u32 groupItemCount = reader.GetGroupItemCount(); for ( u32 i = 0; i < groupItemCount; i++ ) { internal::GroupItemLocationInfo info; if ( ! reader.ReadGroupItemLocationInfo( &info, i ) ) { return false; // ファイル位置情報取得失敗 } // 埋め込みアイテム if ( info.address != NULL ) { SetFileAddressToTable( info.fileId, info.address ); } else { // 0 個目のアイテムが埋め込みかどうかで、グループ全体が埋め込みかどうかを判断 if ( i == 0 ) { isLinkGroup = true; break; } } } if ( isLinkGroup ) { u32 groupItemInfoExCount = reader.GetGroupItemExCount(); for ( u32 i = 0; i < groupItemInfoExCount; i++ ) { GroupFile::GroupItemInfoEx infoEx; if ( reader.ReadGroupItemInfoEx( &infoEx, i ) ) { if ( ! LoadData( infoEx.itemId, pAllocator, infoEx.loadFlag, loadBlockSize ) ) { return false; } } } } // 埋め込みかつ、個別ロードの波形アーカイブが入っている場合は、 // 波形アーカイブテーブルを生成しないと、当該波形アーカイブの波形を使ったサウンド再生ができない else { u32 groupItemInfoExCount = reader.GetGroupItemExCount(); for ( u32 i = 0; i < groupItemInfoExCount; i++ ) { GroupFile::GroupItemInfoEx infoEx; if ( reader.ReadGroupItemInfoEx( &infoEx, i ) ) { // infoEx.itemId - infoEx.loadFlag の組み合わせから波形アーカイブを見つける if ( ! ( infoEx.loadFlag && LOAD_WARC ) ) { continue; } switch ( Util::GetItemType( infoEx.itemId ) ) { case ItemType_Sound: switch ( m_pSoundArchive->GetSoundType( infoEx.itemId ) ) { case SoundArchive::SOUND_TYPE_SEQ: SetWaveArchiveTableWithSeqInEmbeddedGroup( infoEx.itemId, pAllocator ); break; #if 0 // 現状、グループのアイテムとして、直接ウェーブサウンドを指定できない case SoundArchive::SOUND_TYPE_WAVE: SetWaveArchiveTableWithWsdInEmbeddedGroup( infoEx.itemId, pAllocator ); break; #endif } break; case ItemType_Bank: SetWaveArchiveTableWithBankInEmbeddedGroup( infoEx.itemId, pAllocator ); break; case ItemType_SoundGroup: { SoundArchive::SoundGroupInfo info; if ( ! m_pSoundArchive->detail_ReadSoundGroupInfo( infoEx.itemId, &info ) ) { continue; } switch ( m_pSoundArchive->GetSoundType( info.startId ) ) { case SoundArchive::SOUND_TYPE_SEQ: for ( u32 id = info.startId; id <= info.endId; id++ ) { SetWaveArchiveTableWithSeqInEmbeddedGroup( id, pAllocator ); } break; case SoundArchive::SOUND_TYPE_WAVE: // ウェーブサウンドはすべて同じ波形アーカイブを指すため、 // startId のもののみ評価する SetWaveArchiveTableWithWsdInEmbeddedGroup( info.startId, pAllocator ); break; } } break; } } } } return true; } // 埋め込みグループ内の個別ロード波形アーカイブに対して、テーブルを作成する void SoundArchiveLoader::SetWaveArchiveTableWithSeqInEmbeddedGroup( SoundArchive::ItemId seqId, SoundMemoryAllocatable* pAllocator ) { SoundArchive::SequenceSoundInfo info; if ( ! m_pSoundArchive->ReadSequenceSoundInfo( seqId, &info ) ) { return; } for ( int i = 0; i < SoundArchive::SEQ_BANK_MAX; i++ ) { SetWaveArchiveTableWithBankInEmbeddedGroup( info.bankIds[i], pAllocator ); } } void SoundArchiveLoader::SetWaveArchiveTableWithBankInEmbeddedGroup( SoundArchive::ItemId bankId, SoundMemoryAllocatable* pAllocator ) { if ( bankId == SoundArchive::INVALID_ID ) { return; } // 波形アーカイブ ID を調べる SoundArchive::BankInfo bankInfo; if ( ! m_pSoundArchive->ReadBankInfo( bankId, &bankInfo ) ) { return; } const void* bankFile = GetFileAddressFromTable( bankInfo.fileId ); if ( bankFile == NULL ) { return; } BankFileReader bankReader( bankFile ); const Util::WaveIdTable& table = bankReader.GetWaveIdTable(); if ( table.GetCount() <= 0 ) { return; } SoundArchive::ItemId warcId = table.GetWaveId( 0U ).waveArchiveId; SetWaveArchiveTableInEmbeddedGroupImpl( warcId, pAllocator ); } void SoundArchiveLoader::SetWaveArchiveTableWithWsdInEmbeddedGroup( SoundArchive::ItemId wsdId, SoundMemoryAllocatable* pAllocator ) { if ( wsdId == SoundArchive::INVALID_ID ) { return; } // 波形アーカイブ ID を調べる SoundArchive::SoundInfo soundInfo; if ( ! m_pSoundArchive->ReadSoundInfo( wsdId, &soundInfo ) ) { return; } SoundArchive::WaveSoundInfo wsdInfo; if ( ! m_pSoundArchive->detail_ReadWaveSoundInfo( wsdId, &wsdInfo ) ) { return; } const void* wsdFile = GetFileAddressFromTable( soundInfo.fileId ); if ( wsdFile == NULL ) { return; } WaveSoundFileReader reader( wsdFile ); WaveSoundNoteInfo noteInfo; if ( ! reader.ReadNoteInfo( ¬eInfo, wsdInfo.index, 0 ) ) { return; } SetWaveArchiveTableInEmbeddedGroupImpl( noteInfo.waveArchiveId, pAllocator ); } void SoundArchiveLoader::SetWaveArchiveTableInEmbeddedGroupImpl( SoundArchive::ItemId warcId, SoundMemoryAllocatable* pAllocator ) { // 当該波形アーカイブが個別ロード OFF なら処理しない SoundArchive::WaveArchiveInfo info; if ( ! m_pSoundArchive->ReadWaveArchiveInfo( warcId, &info ) ) { return; } if ( ! info.isLoadIndividual ) { return; } const void* warcFile = GetFileAddressFromTable( info.fileId ); WaveArchiveFileReader loadedFileReader( warcFile, false ); // すでにテーブル作成済みの場合は、処理しない if ( loadedFileReader.HasIndividualLoadTable() ) { return; } // ファイルブロック手前までのオフセット取得 u32 fileBlockOffset = reinterpret_cast( warcFile )->GetFileBlockOffset(); const u32 REQUIRED_TABLE_SIZE = fileBlockOffset + info.waveCount * sizeof(u32) + sizeof( WaveArchiveFileReader::SIGNATURE_WARC_TABLE ); // ファイルテーブル用のバッファを確保 void* buffer = pAllocator->Alloc( REQUIRED_TABLE_SIZE ); if ( buffer == NULL ) { return; } // ロード済みの波形アーカイブヘッダーをコピー std::memcpy( buffer, warcFile, fileBlockOffset ); // テーブルのシグニチャ書き込み std::memcpy( ut::AddOffsetToPtr( buffer, fileBlockOffset ), &WaveArchiveFileReader::SIGNATURE_WARC_TABLE, sizeof( WaveArchiveFileReader::SIGNATURE_WARC_TABLE ) ); WaveArchiveFileReader reader( buffer, true ); reader.InitializeFileTable(); // 波形アーカイブ中のすべての波形エントリを、テーブル上に書き出す for ( u32 i = 0; i < info.waveCount; i++ ) { reader.SetWaveFile( i, loadedFileReader.GetWaveFile( i ) ); } // ロードテーブル上のエントリは今回作ったテーブルのものに差し替える SetFileAddressToTable( info.fileId, buffer ); } bool SoundArchiveLoader::LoadGroup( SoundArchive::ItemId groupId, SoundMemoryAllocatable* pAllocator, size_t loadBlockSize ) { // グループファイルのロード const void* pGroupFile = NULL; { u32 fileId = m_pSoundArchive->GetItemFileId( groupId ); // NOTE: グループ内の埋め込みアイテムが、デバイスメモリにおくべきかどうかは判断できない。 // そのため、つねに LoadImpl の bool needDeviceMemory は true にしておく。 pGroupFile = LoadImpl( fileId, pAllocator, loadBlockSize, true ); if ( pGroupFile == NULL ) { return false; // ロード失敗 } #ifdef NW_SND_DEBUG_PRINT_ENABLE { GroupFileReader reader( pGroupFile ); NN_LOG("*** GroupItemLocatioInfo ***\n"); for ( u32 i = 0; i < reader.GetGroupItemCount(); i++ ) { GroupItemLocationInfo info; if ( reader.ReadGroupItemLocationInfo( &info, i ) ) { NN_LOG(" [%3d] fileId(%08x) addr(%p)\n", i, info.fileId, info.address ); } } NN_LOG("*** GroupItemInfoEx ***\n"); for ( u32 i = 0; i < reader.GetGroupItemExCount(); i++ ) { GroupFile::GroupItemInfoEx infoEx; if ( reader.ReadGroupItemInfoEx( &infoEx, i ) ) { NN_LOG(" [%3d] itemId(%08x) loadFlag(%08x)\n", i, infoEx.itemId, infoEx.loadFlag ); } } } #endif } return PostProcessForLoadedGroupFile( pGroupFile, pAllocator ); } bool SoundArchiveLoader::LoadSoundGroup( SoundArchive::ItemId soundGroupId, SoundMemoryAllocatable* pAllocator, u32 loadFlag, size_t loadBlockSize ) { // SoundGroupInfo 取得 SoundArchive::SoundGroupInfo info; if ( ! m_pSoundArchive->detail_ReadSoundGroupInfo( soundGroupId, &info ) ) { return false; } // info.startId と info.endId の SoundType は同一であることが保障されている。 switch ( m_pSoundArchive->GetSoundType( info.startId ) ) { case SoundArchive::SOUND_TYPE_SEQ: for ( u32 id = info.startId; id <= info.endId; id++ ) { if ( ! LoadSequenceSound( id, pAllocator, loadFlag, loadBlockSize ) ) { return false; } } break; case SoundArchive::SOUND_TYPE_WAVE: for ( u32 id = info.startId; id <= info.endId; id++ ) { if ( ! LoadWaveSound( id, pAllocator, loadFlag, loadBlockSize, soundGroupId ) ) { return false; } } break; } #if 0 // TODO: パフォーマンスが気になる場合は、loadFlag と照らし合わせて、 // 下記のようにする。 // if ( ( loadFlag == LOAD_SEQ ) || ( loadFlag == LOAD_WSD ) ) { // SoundGroupInfo の fileIds を順番にロード // ... } #endif return true; } /*---------------------------------------------------------------------------* Name: ReadFile Description: サウンドアーカイブ内のファイルの一部をメモリ上に読み出します。 ID が fileId のファイルの offset バイト目から size だけ読み出します。 Arguments: fileId - サウンドアーカイブ内のファイル ID です。 buffer - ロードするバッファの先頭アドレスです。 size - 読み出すサイズです。 offset - ファイル「ファイル ID」の先頭からのオフセットです。 Returns: 読み込んだサイズを返します。 失敗したときは、-1 を返します。 *---------------------------------------------------------------------------*/ s32 SoundArchiveLoader::ReadFile( SoundArchive::FileId fileId, void* buffer, size_t size, s32 offset, size_t loadBlockSize ) { FileStreamHandle stream = const_cast(m_pSoundArchive)->detail_OpenFileStream( fileId, m_StreamArea, sizeof(m_StreamArea) ); if ( ! stream ) { return -1; } if ( ! stream->CanSeek() || ! stream->CanRead() ) { return -1; } stream->Seek( offset, io::FILE_STREAM_SEEK_BEGIN ); if ( loadBlockSize == 0 ) { // 一括ロード s32 readByte = stream->Read( buffer, ut::RoundUp( static_cast( size ), 32 ) ); if ( readByte < 0 ) { return -1; } } else { // 分割ロード u8* ptr = reinterpret_cast( buffer ); u32 restSize = size; while ( restSize > 0 ) { u32 curReadingSize = ut::RoundUp( ut::Min( loadBlockSize, restSize ), 32 ); s32 readByte = stream->Read( ptr, curReadingSize ); if ( readByte < 0 ) { return -1; } if ( restSize > readByte ) { restSize -= readByte; ptr += readByte; } else { restSize = 0; } } } return size; } /*---------------------------------------------------------------------------* Name: LoadFile Description: サウンドアーカイブ内のファイルをロードします。 Arguments: fileId - サウンドアーカイブ内のファイル ID です。 allocator - ファイルを格納するメモリを確保するアロケータです。 loadBlockSize - 分割ロード時、1回の Read で読み取るサイズ。 0 だと一括ロードする。 needDeviceMemory - デバイスメモリへのロードが必要かどうかのフラグです。 Returns: ロードしたメモリアドレス ロード失敗時には NULL を返す *---------------------------------------------------------------------------*/ void* SoundArchiveLoader::LoadFile( SoundArchive::FileId fileId, SoundMemoryAllocatable* allocator, size_t loadBlockSize, bool needDeviceMemory ) { NW_NULL_ASSERT( allocator ); NW_NULL_ASSERT( m_pSoundArchive ); SoundArchive::FileInfo fileInfo; if ( ! m_pSoundArchive->detail_ReadFileInfo( fileId, &fileInfo ) ) { return NULL; } u32 fileSize = fileInfo.fileSize; if ( fileSize == 0 ) { return NULL; } void* buffer = allocator->Alloc( fileSize ); if ( buffer == NULL ) { return NULL; } if ( needDeviceMemory ) { if ( ! Util::IsDeviceMemory( reinterpret_cast(buffer), fileSize ) ) { NW_ASSERTMSG( false, "buffer, buffer + fileSize is not Device Memory."); return false; } } if ( ReadFile( fileId, buffer, (s32)fileSize, 0, loadBlockSize ) != fileSize ) { return NULL; } #ifdef NW_PLATFORM_CTR nn::snd::FlushDataCache( reinterpret_cast(buffer), fileSize ); #endif return buffer; } bool SoundArchiveLoader::IsDataLoaded( const char* pItemName, u32 loadFlag ) const { NW_NULL_ASSERT( m_pSoundArchive ); SoundArchive::ItemId id = m_pSoundArchive->GetItemId( pItemName ); return IsDataLoaded( id, loadFlag ); } bool SoundArchiveLoader::IsDataLoaded( SoundArchive::ItemId itemId, u32 loadFlag ) const { if ( ! IsAvailable() ) { return false; } if ( itemId == SoundArchive::INVALID_ID ) { return false; } switch ( internal::Util::GetItemType( itemId ) ) { case internal::ItemType_Sound: switch ( m_pSoundArchive->GetSoundType( itemId ) ) { case SoundArchive::SOUND_TYPE_SEQ: return IsSequenceSoundDataLoaded( itemId, loadFlag ); case SoundArchive::SOUND_TYPE_WAVE: return IsWaveSoundDataLoaded( itemId, loadFlag ); case SoundArchive::SOUND_TYPE_STRM: default: return false; } case internal::ItemType_Bank: return IsBankDataLoaded( itemId, loadFlag ); case internal::ItemType_WaveArchive: return IsWaveArchiveDataLoaded( itemId, SoundArchive::INVALID_ID ); case internal::ItemType_Group: return IsGroupDataLoaded( itemId ); case internal::ItemType_SoundGroup: return IsSoundGroupDataLoaded( itemId, loadFlag ); case internal::ItemType_Player: default: return false; } } bool SoundArchiveLoader::IsSequenceSoundDataLoaded( SoundArchive::ItemId itemId, u32 loadFlag ) const { if ( loadFlag & LOAD_SEQ ) { u32 fileId = m_pSoundArchive->GetItemFileId( itemId ); if ( GetFileAddressImpl( fileId ) == NULL ) { return false; } } if ( loadFlag & LOAD_BANK || loadFlag & LOAD_WARC ) { SoundArchive::SequenceSoundInfo info; if ( ! m_pSoundArchive->ReadSequenceSoundInfo( itemId, &info ) ) { return false; } for ( int i = 0; i < SoundArchive::SEQ_BANK_MAX; i++ ) { u32 bankId = info.bankIds[i]; if ( bankId != SoundArchive::INVALID_ID ) { if ( ! IsBankDataLoaded( bankId, loadFlag ) ) { return false; } } } } return true; } bool SoundArchiveLoader::IsWaveSoundDataLoaded( SoundArchive::ItemId itemId, u32 loadFlag ) const { const void* pWsdFile = NULL; { u32 wsdFileId = m_pSoundArchive->GetItemFileId( itemId ); pWsdFile = GetFileAddressImpl( wsdFileId ); } if ( (loadFlag & LOAD_WSD) || (loadFlag & LOAD_WARC) ) { if ( pWsdFile == NULL ) { return false; } } if ( loadFlag & LOAD_WARC ) { u32 index; // bcwsd 内のインデックス { SoundArchive::WaveSoundInfo info; if ( ! m_pSoundArchive->detail_ReadWaveSoundInfo( itemId, &info ) ) { return false; } index = info.index; } u32 warcId; u32 waveIndex; { internal::WaveSoundFileReader reader( pWsdFile ); internal::WaveSoundNoteInfo info; if ( ! reader.ReadNoteInfo( &info, index, 0 ) ) { return false; } warcId = info.waveArchiveId; waveIndex = info.waveIndex; } if ( ! IsWaveArchiveDataLoaded( warcId, waveIndex ) ) { return false; } } return true; } bool SoundArchiveLoader::IsBankDataLoaded( SoundArchive::ItemId itemId, u32 loadFlag ) const { const void* pBankFile = NULL; { u32 fileId = m_pSoundArchive->GetItemFileId( itemId ); pBankFile = GetFileAddressImpl( fileId ); } if ( (loadFlag & LOAD_BANK) || (loadFlag & LOAD_WARC) ) { if ( pBankFile == NULL ) { return false; } } if ( loadFlag & LOAD_WARC ) { internal::BankFileReader reader( pBankFile ); const internal::Util::WaveIdTable& table = reader.GetWaveIdTable(); for ( u32 i = 0; i < table.GetCount(); i++ ) { const internal::Util::WaveId& waveId = table.GetWaveId( i ); u32 warcId = waveId.waveArchiveId; u32 waveIndex = waveId.waveIndex; if ( ! IsWaveArchiveDataLoaded( warcId, waveIndex ) ) { return false; } } } return true; } // LOAD_WARC が有効なだけ呼ばれるので、u32 loadFlag は必要ない。 bool SoundArchiveLoader::IsWaveArchiveDataLoaded( SoundArchive::ItemId itemId, u32 waveIndex ) const { const void* pWarcFile = NULL; { u32 fileId = m_pSoundArchive->GetItemFileId( itemId ); pWarcFile = GetFileAddressImpl( fileId ); } if ( pWarcFile == NULL ) { return false; } SoundArchive::WaveArchiveInfo info; if ( ! m_pSoundArchive->ReadWaveArchiveInfo( itemId, &info ) ) { return false; } if ( info.isLoadIndividual == true ) { internal::WaveArchiveFileReader reader( pWarcFile, true ); if ( waveIndex != SoundArchive::INVALID_ID ) { if ( ! reader.IsLoaded( waveIndex ) ) { return false; } } else { // 波形アーカイブのみのロード確認 and 個別ロード時は、全部確認 u32 waveCount = reader.GetWaveFileCount(); for ( u32 i = 0; i < waveCount; i++ ) { if ( ! reader.IsLoaded( i ) ) { return false; } } } } return true; } // 中身がなにか分からないので u32 loadFlag は必要ない bool SoundArchiveLoader::IsGroupDataLoaded( SoundArchive::ItemId itemId ) const { u32 fileId = m_pSoundArchive->GetItemFileId( itemId ); if ( GetFileAddressImpl( fileId ) == NULL ) { return false; } return true; } bool SoundArchiveLoader::IsSoundGroupDataLoaded( SoundArchive::ItemId itemId, u32 loadFlag ) const { SoundArchive::SoundGroupInfo info; if ( ! m_pSoundArchive->detail_ReadSoundGroupInfo( itemId, &info ) ) { return false; } switch ( m_pSoundArchive->GetSoundType( info.startId ) ) { case SoundArchive::SOUND_TYPE_SEQ: for ( u32 id = info.startId; id <= info.endId; id++ ) { if ( ! IsSequenceSoundDataLoaded( id, loadFlag ) ) { return false; } } break; case SoundArchive::SOUND_TYPE_WAVE: for ( u32 id = info.startId; id <= info.endId; id++ ) { if ( ! IsWaveSoundDataLoaded( id, loadFlag ) ) { return false; } } break; } return true; } const void* SoundArchiveLoader::GetFileAddressFromSoundArchive( SoundArchive::FileId fileId ) const { if ( m_pSoundArchive == NULL ) { return NULL; } return m_pSoundArchive->detail_GetFileAddress( fileId ); } const void* SoundArchiveLoader::detail_GetFileAddressByItemId( SoundArchive::ItemId itemId ) const { if ( m_pSoundArchive == NULL ) { return NULL; } SoundArchive::FileId fileId = SoundArchive::INVALID_ID; const void* result = NULL; switch ( Util::GetItemType( itemId ) ) { case ItemType_Sound: { SoundArchive::SoundInfo info; m_pSoundArchive->ReadSoundInfo( itemId, &info ); fileId = info.fileId; } break; case ItemType_Bank: { SoundArchive::BankInfo info; m_pSoundArchive->ReadBankInfo( itemId, &info ); fileId = info.fileId; } break; case ItemType_WaveArchive: { SoundArchive::WaveArchiveInfo info; m_pSoundArchive->ReadWaveArchiveInfo( itemId, &info ); fileId = info.fileId; } break; case ItemType_Group: { SoundArchive::GroupInfo info; m_pSoundArchive->detail_ReadGroupInfo( itemId, &info ); fileId = info.fileId; } break; default: NW_ASSERTMSG( false, "invalid itemId(%08x)\n", itemId ); break; } if ( fileId != SoundArchive::INVALID_ID ) { result = GetFileAddressImpl( fileId ); } return result; } // 当該バンクに必要な波形をロード bool SoundArchiveLoader::detail_LoadWaveArchiveByBankFile( const void* bankFile, SoundMemoryAllocatable* pAllocator ) { if ( bankFile == NULL ) { return false; } // 当該バンクに必要な波形のみロード internal::BankFileReader reader( bankFile ); const internal::Util::WaveIdTable& table = reader.GetWaveIdTable(); for ( u32 i = 0; i < table.GetCount(); i++ ) { const internal::Util::WaveId& waveId = table.GetWaveId( i ); if ( ! LoadWaveArchiveImpl( waveId.waveArchiveId, waveId.waveIndex, pAllocator, LOAD_WARC ) ) { return false; } } return true; } // 当該ウェーブサウンド1つに必要な波形をロード bool SoundArchiveLoader::detail_LoadWaveArchiveByWaveSoundFile( const void* wsdFile, s32 wsdIndex, SoundMemoryAllocatable* pAllocator ) { if ( wsdFile == NULL ) { return false; } // wsdFile, wsdIndex から必要な波形アーカイブ ID および、波形インデックスを取得 u32 warcId = SoundArchive::INVALID_ID; u32 waveIndex; { internal::WaveSoundFileReader reader( wsdFile ); internal::WaveSoundNoteInfo info; if ( ! reader.ReadNoteInfo( &info, wsdIndex, 0 ) ) { return false; } warcId = info.waveArchiveId; waveIndex = info.waveIndex; } if ( ! LoadWaveArchiveImpl( // 波形アーカイブの個別ロードフラグが ON なら、個別ロードされる warcId, waveIndex, pAllocator, LOAD_WARC ) ) { return false; } return true; } } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw