/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_SoundDataManager.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: 22506 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include #include #include #include namespace nw { namespace snd { namespace { // 個別ロード波形のメモリブロック先頭に置かれる情報 // struct IndividualWaveInfo { // データ u32 signature; u32 fileId; //< 所属する波形アーカイブファイル ID u32 waveIndex; //< 波形アーカイブ内インデックス u32 padding[5]; // メソッド IndividualWaveInfo( u32 id, u32 index ) : signature( SoundDataManager::SIGNATURE_INDIVIDUAL_WAVE ), fileId( id ), waveIndex( index ) {} }; const u32 REQUIRED_SIZE_FOR_LOAD_WARC_FILE_HEADER = NW_SND_ROUND_UP_32B( sizeof( internal::WaveArchiveFile::FileHeader ) + 32 ); // 32 バイトごとに読むため } // anonymous namespace SoundDataManager::SoundDataManager() : m_pFileTable ( NULL ), m_pSoundArchive( NULL ), m_pFileManager( NULL ) { } SoundDataManager::~SoundDataManager() { } size_t SoundDataManager::GetRequiredMemSize( const SoundArchive* arc ) const { NW_NULL_ASSERT( arc ); size_t size = 0; size += ut::RoundUp( sizeof( u32 ) + sizeof( FileAddress ) * arc->detail_GetFileCount(), 4 ); return size; } bool SoundDataManager::Initialize( const SoundArchive* arc, void* buffer, u32 size ) { NW_NULL_ASSERT( arc ); NW_NULL_ASSERT( buffer ); NW_ALIGN4_ASSERT( buffer ); NW_ASSERT( size >= GetRequiredMemSize( arc ) ); void* endp = static_cast(buffer) + size; void* buf = buffer; if ( ! CreateFileAddressTable( arc, &buf, endp ) ) { return false; } NW_ASSERT( static_cast(buf) - static_cast(buffer) == GetRequiredMemSize( arc ) ); m_pSoundArchive = arc; internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance(); internal::DriverCommandDisposeCallback* command = cmdmgr.AllocCommand(); command->id = internal::DRIVER_COMMAND_REGIST_DISPOSE_CALLBACK; command->callback = this; cmdmgr.PushCommand(command); return true; } void SoundDataManager::Finalize() { internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance(); internal::DriverCommandDisposeCallback* command = cmdmgr.AllocCommand(); command->id = internal::DRIVER_COMMAND_UNREGIST_DISPOSE_CALLBACK; command->callback = this; cmdmgr.PushCommand(command); u32 tag = cmdmgr.FlushCommand( true ); cmdmgr.WaitCommandReply( tag ); m_pSoundArchive = NULL; m_pFileManager = NULL; m_pFileTable = NULL; } bool SoundDataManager::CreateFileAddressTable( const SoundArchive* arc, void** buffer, void* endp ) { size_t requiredSize = sizeof( u32 ) + sizeof( FileAddress ) * arc->detail_GetFileCount(); void* ep = ut::RoundUp( ut::AddOffsetToPtr( *buffer, requiredSize ), 4 ); if ( ut::ComparePtr( ep, endp ) > 0 ) { return false; } m_pFileTable = reinterpret_cast< FileTable* >(*buffer); *buffer = ep; m_pFileTable->count = arc->detail_GetFileCount(); for( u32 i = 0 ; i < m_pFileTable->count ; i++ ) { m_pFileTable->item[ i ].address = NULL; } return true; } /*---------------------------------------------------------------------------* Name: IsAvailable Description: サウンドアーカイブプレイヤーが利用可能かどうかを調べる Arguments: 無し Returns: 利用可能かどうかを返す *---------------------------------------------------------------------------*/ bool SoundDataManager::IsAvailable() const { if ( m_pSoundArchive == NULL ) return false; if ( ! m_pSoundArchive->IsAvailable() ) return false; return true; } bool SoundDataManager::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 SoundDataManager::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* SoundDataManager::LoadImpl( SoundArchive::FileId fileId, SoundMemoryAllocatable* pAllocator, size_t loadBlockSize, bool needDeviceMemory ) { NW_NULL_ASSERT( m_pSoundArchive ); NW_UNUSED_VARIABLE( loadBlockSize ); const void* fileAddress = detail_GetFileAddress( fileId ); // 未ロードの場合 if ( fileAddress == NULL ) { internal::SoundArchiveLoader loader( *m_pSoundArchive ); fileAddress = loader.LoadFile( fileId, pAllocator, loadBlockSize, needDeviceMemory ); if ( fileAddress == NULL ) { return NULL; // ロード失敗 } else { SetFileAddress( fileId, fileAddress ); return fileAddress; } } // ロード済みだった場合 else { return fileAddress; } } bool SoundDataManager::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 SoundDataManager::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 = detail_GetFileAddress( 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 SoundDataManager::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 = detail_GetFileAddress( 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 ); u32 warcId = waveId.waveArchiveId; u32 waveIndex = waveId.waveIndex; if ( ! LoadWaveArchiveImpl( warcId, 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 SoundDataManager::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 SoundDataManager::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* SoundDataManager::LoadWaveArchiveTable( SoundArchive::ItemId warcId, SoundMemoryAllocatable* pAllocator, size_t loadBlockSize ) { u32 fileId = m_pSoundArchive->GetItemFileId( warcId ); const void* pWaveArchiveFile = GetFileAddress( 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; } // ファイルブロック手前までのオフセット internal::SoundArchiveLoader loader( *m_pSoundArchive ); u32 fileBlockOffset; { u8 pBuffer[ REQUIRED_SIZE_FOR_LOAD_WARC_FILE_HEADER ]; u8* pAlignedBuffer = reinterpret_cast( ut::RoundUp( pBuffer, 32 ) ); s32 readSize = loader.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 = loader.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(); SetFileAddress( fileId, buffer ); return buffer; } bool SoundDataManager::LoadIndividualWave( SoundArchive::ItemId warcId, u32 waveIndex, SoundMemoryAllocatable* pAllocator, size_t loadBlockSize ) { NW_UNUSED_VARIABLE( loadBlockSize ); // (ロードされている) 波形アーカイブファイル取得 u32 fileId = m_pSoundArchive->GetItemFileId( warcId ); const void* pWaveArchiveFile = GetFileAddress( 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) ); internal::SoundArchiveLoader loader( *m_pSoundArchive ); s32 readSize = loader.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 SoundDataManager::SetGroupItem( const void* pGroupFile, SoundMemoryAllocatable* pAllocator, size_t loadBlockSize ) { internal::GroupFileReader reader( pGroupFile ); for ( u32 i = 0; i < reader.GetGroupItemCount(); i++ ) { internal::GroupItemLocationInfo info; if ( ! reader.ReadGroupItemLocationInfo( &info, i ) ) { return false; // ファイル位置情報取得失敗 } // 埋め込みアイテム if ( info.address != NULL ) { // NN_LOG(" EMBEDDED fileId(%08X) addr(%p)\n", // info.fileId, info.address ); SetFileAddress( info.fileId, info.address ); } // リンクアイテム else { // NN_LOG(" LINK fileId(%08X) addr(%p)\n", // info.fileId, info.address ); if ( pAllocator != NULL ) { // NOTE: リンクアイテムがデバイスメモリにおくべきかどうかは判断できない if ( LoadImpl( info.fileId, pAllocator, loadBlockSize ) == NULL ) { // NN_LOG(" ... load failed\n"); return false; } } } } return true; } bool SoundDataManager::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; // ロード失敗 } } // NN_LOG("[%08X](%-15s)\n", // groupId, m_pSoundArchive->GetItemLabel( groupId ) ); return SetGroupItem( pGroupFile, pAllocator ); } bool SoundDataManager::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: InvalidateData Description: ロードされたデータが破棄されたときにテーブルから削除する Arguments: start - 開始アドレス end - 終了アドレス Returns: None. *---------------------------------------------------------------------------*/ void SoundDataManager::InvalidateData( const void* start, const void* end ) { // ファイルアドレステーブルから破棄 if ( m_pFileTable != NULL ) { for( u32 i = 0 ; i < m_pFileTable->count ; i++ ) { const void* addr = m_pFileTable->item[ i ].address; if ( start <= addr && addr <= end ) { m_pFileTable->item[ i ].address = NULL; } } } if ( ut::GetOffsetFromPtr( start, end ) >= sizeof(IndividualWaveInfo) ) { if ( start != NULL ) { const IndividualWaveInfo* info = reinterpret_cast( start ); if ( info->signature == SoundDataManager::SIGNATURE_INDIVIDUAL_WAVE ) { const void* pWarcTable = GetFileAddress( info->fileId ); if ( pWarcTable != NULL ) { internal::WaveArchiveFileReader reader( pWarcTable, true ); reader.SetWaveFile( info->waveIndex, NULL ); } } } } } /*---------------------------------------------------------------------------* Name: detail_GetFileAddress Description: 記憶させたファイルアドレスを取得 Arguments: fileId - ファイルID Returns: ファイルアドレス *---------------------------------------------------------------------------*/ const void* SoundDataManager::detail_GetFileAddress( SoundArchive::FileId fileId ) const { // 外部のファイルマネージャに問い合わせ if ( m_pFileManager != NULL ) { const void* addr = m_pFileManager->GetFileAddress( fileId ); if ( addr != NULL ) return addr; } // サウンドアーカイブに問い合わせ { const void* addr = m_pSoundArchive->detail_GetFileAddress( fileId ); if ( addr != NULL ) return addr; } // ファイルアドレステーブルを参照 { const void* fileData = GetFileAddress( fileId ); if ( fileData != NULL ) return fileData; } return NULL; } /*---------------------------------------------------------------------------* Name: GetFileAddress Description: 記憶させたファイルアドレスを取得 Arguments: fileId - ファイルID Returns: ファイルアドレス *---------------------------------------------------------------------------*/ const void* SoundDataManager::GetFileAddress( SoundArchive::FileId fileId ) const { if ( m_pFileTable == NULL ) { NW_WARNING( m_pFileTable != NULL, "Failed to SoundDataManager::GetFileAddress because file table is not allocated.\n" ); return NULL; } if ( fileId >= m_pFileTable->count ) return NULL; return m_pFileTable->item[ fileId ].address; } /*---------------------------------------------------------------------------* Name: SetFileAddress Description: ファイルアドレスを記憶 Arguments: fileId - ファイル番号 address - ファイルアドレス Returns: セットする前に書かれていたファイルアドレス *---------------------------------------------------------------------------*/ const void* SoundDataManager::SetFileAddress( SoundArchive::FileId fileId, const void* address ) { if ( m_pFileTable == NULL ) { NW_WARNING( m_pFileTable != NULL, "Failed to SoundDataManager::SetFileAddress because file table is not allocated.\n" ); return NULL; } NW_MINMAXLT_ASSERT( fileId, 0, m_pFileTable->count ); const void* preAddress = m_pFileTable->item[ fileId ].address; m_pFileTable->item[ fileId ].address = address; return preAddress; } // ロード済みファイルテーブルの中から、 // 引数と一致するアドレスを持つファイルのファイル ID を取得する u32 SoundDataManager::detail_GetFileId( const void* address ) const { for ( u32 i = 0; i < m_pSoundArchive->detail_GetFileCount(); i++ ) { if ( address == m_pFileTable->item[i].address ) { return i; } } return SoundArchive::INVALID_ID; } void SoundDataManager::InvalidateSoundData( void* mem, size_t size ) { internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance(); internal::DriverCommandInvalidateData* command = cmdmgr.AllocCommand(); command->id = internal::DRIVER_COMMAND_INVALIDATE_DATA; command->mem = mem; command->size = size; cmdmgr.PushCommand(command); u32 tag = cmdmgr.FlushCommand( true ); cmdmgr.WaitCommandReply( tag ); } bool SoundDataManager::IsDataLoaded( const char* pItemName, u32 loadFlag ) const { NW_NULL_ASSERT( m_pSoundArchive ); SoundArchive::ItemId id = m_pSoundArchive->GetItemId( pItemName ); return IsDataLoaded( id, loadFlag ); } bool SoundDataManager::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 SoundDataManager::IsSequenceSoundDataLoaded( SoundArchive::ItemId itemId, u32 loadFlag ) const { if ( loadFlag & LOAD_SEQ ) { u32 fileId = m_pSoundArchive->GetItemFileId( itemId ); if ( detail_GetFileAddress( 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 SoundDataManager::IsWaveSoundDataLoaded( SoundArchive::ItemId itemId, u32 loadFlag ) const { const void* pWsdFile = NULL; { u32 wsdFileId = m_pSoundArchive->GetItemFileId( itemId ); pWsdFile = detail_GetFileAddress( 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 SoundDataManager::IsBankDataLoaded( SoundArchive::ItemId itemId, u32 loadFlag ) const { const void* pBankFile = NULL; { u32 fileId = m_pSoundArchive->GetItemFileId( itemId ); pBankFile = detail_GetFileAddress( 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 SoundDataManager::IsWaveArchiveDataLoaded( SoundArchive::ItemId itemId, u32 waveIndex ) const { const void* pWarcFile = NULL; { u32 fileId = m_pSoundArchive->GetItemFileId( itemId ); pWarcFile = detail_GetFileAddress( 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 SoundDataManager::IsGroupDataLoaded( SoundArchive::ItemId itemId ) const { u32 fileId = m_pSoundArchive->GetItemFileId( itemId ); if ( detail_GetFileAddress( fileId ) == NULL ) { return false; } return true; } bool SoundDataManager::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; } } // namespace nw::snd } // namespace nw