/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_FrameHeap.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: 27749 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include #include #include #include #include namespace nw { namespace snd { namespace internal { namespace { u32 GetWaveArchiveId( u32 fileId, const SoundArchive& arc ) { for ( u32 j = 0; j < arc.GetWaveArchiveCount(); j++ ) { SoundArchive::WaveArchiveInfo info; SoundArchive::ItemId id = Util::GetMaskedItemId( j, ItemType_WaveArchive ); if ( arc.ReadWaveArchiveInfo( id, &info ) ) { if ( info.fileId == fileId ) { return id; } } } return SoundArchive::INVALID_ID; } } // anonymous namespace /* ======================================================================== member function ======================================================================== */ /*---------------------------------------------------------------------------* Name: FrameHeap Description: コンストラクタ Arguments: なし Returns: なし *---------------------------------------------------------------------------*/ FrameHeap::FrameHeap() : m_pHeap( NULL ) { } /*---------------------------------------------------------------------------* Name: ~FrameHeap Description: デストラクタ Arguments: なし Returns: なし *---------------------------------------------------------------------------*/ FrameHeap::~FrameHeap() { if ( IsValid() ) { Destroy(); } } /*---------------------------------------------------------------------------* Name: Create Description: ヒープを作成 Arguments: startAddress - 開始アドレス size - メモリサイズ Returns: ヒープハンドル *---------------------------------------------------------------------------*/ bool FrameHeap::Create( void* startAddress, u32 size ) { NW_NULL_ASSERT( startAddress ); if ( IsValid() ) { Destroy(); } void* endAddress = static_cast( startAddress ) + size; startAddress = ut::RoundUp( startAddress, 4 ); // Heap align if ( startAddress > endAddress ) return false; size = static_cast( static_cast( endAddress ) - static_cast( startAddress ) ); m_pHeap = ut::FrameHeap::Create( startAddress, size ); if ( m_pHeap == NULL ) return false; // ベースセクションの作成 if ( ! NewSection() ) return false; return true; } /*---------------------------------------------------------------------------* Name: Destroy Description: ヒープを破棄します Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void FrameHeap::Destroy() { if ( IsValid() ) { // セクションの破棄 ClearSection(); // ヒープのクリア m_pHeap->Free( ut::FrameHeap::FREE_ALL ); // ヒープの破棄 m_pHeap->Destroy(); m_pHeap = NULL; } } /*---------------------------------------------------------------------------* Name: Clear Description: ヒープを作成時の状態に戻す Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void FrameHeap::Clear() { NW_ASSERT( IsValid() ); // セクションの破棄 ClearSection(); // ヒープのクリア m_pHeap->Free( ut::FrameHeap::FREE_ALL ); // ベースセクションの作成 bool result = NewSection(); NW_ASSERTMSG( result, "FrameHeap::Clear(): NewSection is Failed"); } /*---------------------------------------------------------------------------* Name: Alloc Description: ヒープからメモリを確保 Arguments: size - メモリサイズ callback - メモリが破棄されたときに呼びだされるコールバック関数 callbackArg - コールバック引数 Returns: 確保したメモリへのポインタ *---------------------------------------------------------------------------*/ void* FrameHeap::Alloc( u32 size, FrameHeap::DisposeCallback callback, void* callbackArg ) { NW_ASSERT( IsValid() ); const unsigned long blockSize = ut::RoundUp( sizeof(Block), HEAP_ALIGN ); void* mem = m_pHeap->Alloc( blockSize + ut::RoundUp( size, HEAP_ALIGN ), HEAP_ALIGN ); if ( mem == NULL ) return NULL; void* buffer = ut::AddOffsetToPtr( mem, blockSize ); NW_ASSERTMSG( ( reinterpret_cast(buffer) & 0x1f ) == 0, "FrameHeap::Alloc: Internal Error" ); Block* block = new ( mem ) Block( buffer, size, callback, callbackArg ); m_SectionList.GetBack().AppendBlock( block ); return buffer; } /*---------------------------------------------------------------------------* Name: SaveState Description: ヒープの状態を保存 Arguments: None. Returns: 保存した階層レベルを返す 失敗時には、-1 *---------------------------------------------------------------------------*/ int FrameHeap::SaveState() { NW_ASSERT( IsValid() ); if ( ! m_pHeap->RecordState( m_SectionList.GetSize() ) ) { return -1; } if ( ! NewSection() ) { int result = m_pHeap->FreeByState( 0 ); NW_ASSERTMSG( result, "FrameHeap::SaveState(): ut::FrameHeap::FreeByState is Failed"); return -1; } return static_cast( m_SectionList.GetSize() ) - 1; } /*---------------------------------------------------------------------------* Name: LoadState Description: ヒープの状態を戻す Arguments: level - 階層レベル Returns: None. *---------------------------------------------------------------------------*/ void FrameHeap::LoadState( int level ) { NW_ASSERT( IsValid() ); NW_MINMAXLT_ASSERT( level, 0, static_cast( m_SectionList.GetSize() ) ); if ( level == 0 ) { Clear(); return; } while( level < static_cast( m_SectionList.GetSize() ) ) { // get latest section Section& section = m_SectionList.GetBack(); // call dispose callback section.~Section(); // セクションリストからの削除 m_SectionList.Erase( §ion ); } // ヒープ状態を復元 int result = m_pHeap->FreeByState( static_cast( level ) ); NW_UNUSED_VARIABLE( result ); NW_ASSERTMSG( result, "FrameHeap::LoadState(): ut::FrameHeap::FreeByState is Failed"); // 再度記録 result = m_pHeap->RecordState( m_SectionList.GetSize() ); NW_ASSERTMSG( result, "FrameHeap::LoadState(): ut::FrameHea::RecordState is Failed"); // セクションの作成 bool result2 = NewSection(); NW_ASSERTMSG( result2, "FrameHeap::LoadState(): NewSection is Failed"); } /*---------------------------------------------------------------------------* Name: GetCurrentLevel Description: ヒープの現在の階層レベルを取得 Arguments: None. Returns: 現在の階層レベル *---------------------------------------------------------------------------*/ int FrameHeap::GetCurrentLevel() const { NW_ASSERT( IsValid() ); return static_cast( m_SectionList.GetSize() ) - 1; } /*---------------------------------------------------------------------------* Name: GetSize Description: ヒープの容量を取得 Arguments: None. Returns: ヒープの容量 *---------------------------------------------------------------------------*/ u32 FrameHeap::GetSize() const { NW_ASSERT( IsValid() ); return static_cast( static_cast( m_pHeap->GetHeapEndAddress() ) - static_cast( m_pHeap->GetHeapStartAddress() ) ); } /*---------------------------------------------------------------------------* Name: GetFreeSize Description: ヒープの空き容量を取得 Arguments: None. Returns: 空き容量 *---------------------------------------------------------------------------*/ u32 FrameHeap::GetFreeSize() const { NW_ASSERT( IsValid() ); u32 size = m_pHeap->GetAllocatableSize( HEAP_ALIGN ); if ( size < sizeof( Block ) ) return 0; size -= sizeof( Block ); size &= ~(HEAP_ALIGN-1); return size; } /*---------------------------------------------------------------------------* Name: NewSection Description: 新しいセクションを作成 Arguments: None. Returns: 成功したかどうか *---------------------------------------------------------------------------*/ bool FrameHeap::NewSection() { // new HeapSection void* buffer = m_pHeap->Alloc( sizeof( Section ) ); if ( buffer == NULL ) return false; Section* section = new( buffer ) Section(); m_SectionList.PushBack( section ); return true; } /*---------------------------------------------------------------------------* Name: ClearSection Description: セクションを全て破棄する Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void FrameHeap::ClearSection() { // セクションの破棄 while ( !m_SectionList.IsEmpty() ) { Section& section = m_SectionList.GetBack(); // コールバックの呼び出し section.~Section(); // セクションリストからの削除 m_SectionList.Erase( §ion ); } } void FrameHeap::Dump( nw::snd::SoundDataManager& mgr, nw::snd::SoundArchive& arc ) { int i = 0; for ( SectionList::Iterator itr = m_SectionList.GetBeginIter(); itr != m_SectionList.GetEndIter(); ) { SectionList::Iterator curItr = itr++; NN_LOG("section[%d]\n", i++ ); curItr->Dump( mgr, arc ); } } /* ======================================================================== FrameHeap::Section class member function ======================================================================== */ FrameHeap::Section::~Section() { // コールバックを登録逆順に呼びだし BlockList::Iterator itr = m_BlockList.GetEndIter(); while ( itr != m_BlockList.GetBeginIter() ) { (void)--itr; itr->~Block(); } } void FrameHeap::Section::Dump( nw::snd::SoundDataManager& mgr, nw::snd::SoundArchive& arc ) { int i = 0; for ( BlockList::Iterator itr = m_BlockList.GetBeginIter(); itr != m_BlockList.GetEndIter(); ) { BlockList::Iterator curItr = itr++; const void* ptr = curItr->GetBufferAddr(); u32 sign = *reinterpret_cast(ptr); char signature[5]; signature[4] = '\0'; std::memcpy( signature, &sign, 4 ); u32 fileId = mgr.detail_GetFileIdFromTable( ptr ); SoundArchive::ItemId itemId = SoundArchive::INVALID_ID; u32 waveIndex = 0xffffffff; switch ( sign ) { case BankFileReader::SIGNATURE_FILE: for ( u32 j = 0; j < arc.GetBankCount(); j++ ) { SoundArchive::BankInfo info; SoundArchive::ItemId id = Util::GetMaskedItemId( j, ItemType_Bank ); if ( arc.ReadBankInfo( id, &info ) ) { if ( info.fileId == fileId ) { itemId = id; break; } } } break; case GroupFileReader::SIGNATURE_FILE: for ( u32 j = 0; j < arc.GetGroupCount(); j++ ) { SoundArchive::GroupInfo info; SoundArchive::ItemId id = Util::GetMaskedItemId( j, ItemType_Group ); if ( arc.detail_ReadGroupInfo( id, &info ) ) { if ( info.fileId == fileId ) { itemId = id; break; } } } break; case SequenceSoundFileReader::SIGNATURE_FILE: case WaveSoundFileReader::SIGNATURE_FILE: for ( u32 j = 0; j < arc.GetSoundCount(); j++ ) { SoundArchive::SoundInfo info; SoundArchive::ItemId id = Util::GetMaskedItemId( j, ItemType_Sound ); if ( arc.ReadSoundInfo( id, &info ) ) { if ( info.fileId == fileId ) { itemId = id; break; } } } break; case WaveArchiveFileReader::SIGNATURE_FILE: itemId = GetWaveArchiveId( fileId, arc ); break; // 個別ロードの波形 case SoundDataManager::SIGNATURE_INDIVIDUAL_WAVE: { const u32* pU32Array = reinterpret_cast(ptr); fileId = pU32Array[1]; waveIndex = pU32Array[2]; itemId = GetWaveArchiveId( fileId, arc ); } break; default: itemId = SoundArchive::INVALID_ID; break; } const char* pItemLabel = arc.GetItemLabel( itemId ); if ( pItemLabel != NULL ) { NN_LOG(" block[%d] 0x%08X [%s] fileId(%6d) itemId(%08X) [%s]", i++, ptr, signature, fileId, itemId, pItemLabel ); } else { NN_LOG(" block[%d] 0x%08X [%s] fileId(%6d) itemId(%08X) [(anonymous)]", i++, ptr, signature, fileId, itemId ); } if ( waveIndex != 0xffffffff ) { NN_LOG("(%d)\n", waveIndex ); } else { NN_LOG("\n"); } } } } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw