1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_FrameHeap.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #include "precompiled.h"
19 
20 #include <nw/snd/snd_FrameHeap.h>
21 
22 #include <nw/snd/snd_BankFileReader.h>
23 #include <nw/snd/snd_GroupFileReader.h>
24 #include <nw/snd/snd_SequenceSoundFileReader.h>
25 #include <nw/snd/snd_WaveArchiveFileReader.h>
26 #include <nw/snd/snd_WaveFileReader.h>
27 #include <nw/snd/snd_WaveSoundFileReader.h>
28 #include <nw/snd/snd_Util.h>
29 #include <new>
30 
31 namespace nw {
32 namespace snd {
33 namespace internal {
34 
35 namespace
36 {
GetWaveArchiveId(u32 fileId,const SoundArchive & arc)37 u32 GetWaveArchiveId( u32 fileId, const SoundArchive& arc )
38 {
39     for ( u32 j = 0; j < arc.GetWaveArchiveCount(); j++ )
40     {
41         SoundArchive::WaveArchiveInfo info;
42         SoundArchive::ItemId id =
43             Util::GetMaskedItemId( j, ItemType_WaveArchive );
44         if ( arc.ReadWaveArchiveInfo( id, &info ) )
45         {
46             if ( info.fileId == fileId )
47             {
48                 return id;
49             }
50         }
51     }
52     return SoundArchive::INVALID_ID;
53 }
54 
55 } // anonymous namespace
56 
57 /* ========================================================================
58         member function
59    ======================================================================== */
60 
61 /*---------------------------------------------------------------------------*
62   Name:         FrameHeap
63 
64   Description:  コンストラクタ
65 
66   Arguments:    なし
67 
68   Returns:      なし
69  *---------------------------------------------------------------------------*/
FrameHeap()70 FrameHeap::FrameHeap()
71 : m_pHeap( NULL )
72 {
73 }
74 
75 /*---------------------------------------------------------------------------*
76   Name:         ~FrameHeap
77 
78   Description:  デストラクタ
79 
80   Arguments:    なし
81 
82   Returns:      なし
83  *---------------------------------------------------------------------------*/
~FrameHeap()84 FrameHeap::~FrameHeap()
85 {
86     if ( IsValid() )
87     {
88         Destroy();
89     }
90 }
91 
92 /*---------------------------------------------------------------------------*
93   Name:         Create
94 
95   Description:  ヒープを作成
96 
97   Arguments:    startAddress - 開始アドレス
98                 size         - メモリサイズ
99 
100   Returns:      ヒープハンドル
101  *---------------------------------------------------------------------------*/
Create(void * startAddress,u32 size)102 bool FrameHeap::Create( void* startAddress, u32 size )
103 {
104     NW_NULL_ASSERT( startAddress );
105 
106     if ( IsValid() )
107     {
108         Destroy();
109     }
110 
111     void* endAddress = static_cast<u8*>( startAddress ) + size;
112     startAddress = ut::RoundUp( startAddress, 4 ); // Heap align
113 
114     if ( startAddress > endAddress )
115     {
116         return false;
117     }
118 
119     size = static_cast<u32>( static_cast<u8*>( endAddress ) - static_cast<u8*>( startAddress ) );
120 
121     m_pHeap = ut::FrameHeap::Create( startAddress, size );
122     if ( m_pHeap == NULL )
123     {
124         return false;
125     }
126 
127     // ベースセクションの作成
128     if ( ! NewSection() )
129     {
130         return false;
131     }
132 
133     return true;
134 }
135 
136 /*---------------------------------------------------------------------------*
137   Name:         Destroy
138 
139   Description:  ヒープを破棄します
140 
141   Arguments:    None.
142 
143   Returns:      None.
144  *---------------------------------------------------------------------------*/
Destroy()145 void FrameHeap::Destroy()
146 {
147     if ( IsValid() )
148     {
149         // セクションの破棄
150         ClearSection();
151 
152         // ヒープのクリア
153         m_pHeap->Free( ut::FrameHeap::FREE_ALL );
154 
155         // ヒープの破棄
156         m_pHeap->Destroy();
157 
158         m_pHeap = NULL;
159     }
160 }
161 
162 /*---------------------------------------------------------------------------*
163   Name:         Clear
164 
165   Description:  ヒープを作成時の状態に戻す
166 
167   Arguments:    None.
168 
169   Returns:      None.
170  *---------------------------------------------------------------------------*/
Clear()171 void FrameHeap::Clear()
172 {
173     NW_ASSERT( IsValid() );
174 
175     // セクションの破棄
176     ClearSection();
177 
178     // ヒープのクリア
179     m_pHeap->Free( ut::FrameHeap::FREE_ALL );
180 
181     // ベースセクションの作成
182     bool result = NewSection();
183     NW_ASSERTMSG( result, "FrameHeap::Clear(): NewSection is Failed");
184 }
185 
186 /*---------------------------------------------------------------------------*
187   Name:         Alloc
188 
189   Description:  ヒープからメモリを確保
190 
191   Arguments:    size     - メモリサイズ
192                 callback - メモリが破棄されたときに呼びだされるコールバック関数
193                 callbackArg - コールバック引数
194 
195   Returns:      確保したメモリへのポインタ
196  *---------------------------------------------------------------------------*/
Alloc(u32 size,FrameHeap::DisposeCallback callback,void * callbackArg)197 void* FrameHeap::Alloc( u32 size, FrameHeap::DisposeCallback callback, void* callbackArg )
198 {
199     NW_ASSERT( IsValid() );
200 
201     const unsigned long blockSize = ut::RoundUp( sizeof(Block), HEAP_ALIGN );
202     void* mem = m_pHeap->Alloc(
203         blockSize + ut::RoundUp( size, HEAP_ALIGN ),
204         HEAP_ALIGN
205     );
206     if ( mem == NULL )
207     {
208         return NULL;
209     }
210     void* buffer = ut::AddOffsetToPtr( mem, blockSize );
211     NW_ASSERTMSG( ( reinterpret_cast<IntPtr>(buffer) & 0x1f ) == 0, "FrameHeap::Alloc: Internal Error" );
212 
213     Block* block = new ( mem ) Block( buffer, size, callback, callbackArg );
214 
215     m_SectionList.GetBack().AppendBlock( block );
216 
217     return buffer;
218 }
219 
220 /*---------------------------------------------------------------------------*
221   Name:         SaveState
222 
223   Description:  ヒープの状態を保存
224 
225   Arguments:    None.
226 
227   Returns:      保存した階層レベルを返す
228                 失敗時には、-1
229  *---------------------------------------------------------------------------*/
SaveState()230 int FrameHeap::SaveState()
231 {
232     NW_ASSERT( IsValid() );
233 
234     if ( ! m_pHeap->RecordState( m_SectionList.GetSize() ) )
235     {
236         return -1;
237     }
238 
239     if ( ! NewSection() )
240     {
241         int result = m_pHeap->FreeByState( 0 );
242         NW_ASSERTMSG( result, "FrameHeap::SaveState(): ut::FrameHeap::FreeByState is Failed");
243         return -1;
244     }
245 
246     return static_cast<int>( m_SectionList.GetSize() ) - 1;
247 }
248 
249 /*---------------------------------------------------------------------------*
250   Name:         LoadState
251 
252   Description:  ヒープの状態を戻す
253 
254   Arguments:    level - 階層レベル
255 
256   Returns:      None.
257  *---------------------------------------------------------------------------*/
LoadState(int level)258 void FrameHeap::LoadState( int level )
259 {
260     NW_ASSERT( IsValid() );
261     NW_MINMAXLT_ASSERT( level, 0, static_cast<int>( m_SectionList.GetSize() ) );
262 
263     if ( level == 0 )
264     {
265         Clear();
266         return;
267     }
268     while( level < static_cast<int>( m_SectionList.GetSize() ) )
269     {
270         // get latest section
271         Section& section = m_SectionList.GetBack();
272 
273         // call dispose callback
274         section.~Section();
275 
276         // セクションリストからの削除
277         m_SectionList.Erase( &section );
278     }
279 
280     // ヒープ状態を復元
281     int result = m_pHeap->FreeByState( static_cast<u32>( level ) );
282     NW_UNUSED_VARIABLE( result );
283     NW_ASSERTMSG( result, "FrameHeap::LoadState(): ut::FrameHeap::FreeByState is Failed");
284 
285     // 再度記録
286     result =  m_pHeap->RecordState( m_SectionList.GetSize() );
287     NW_ASSERTMSG( result, "FrameHeap::LoadState(): ut::FrameHea::RecordState is Failed");
288 
289     // セクションの作成
290     bool result2 = NewSection();
291     NW_ASSERTMSG( result2, "FrameHeap::LoadState(): NewSection is Failed");
292 }
293 
294 /*---------------------------------------------------------------------------*
295   Name:         GetCurrentLevel
296 
297   Description:  ヒープの現在の階層レベルを取得
298 
299   Arguments:    None.
300 
301   Returns:      現在の階層レベル
302  *---------------------------------------------------------------------------*/
GetCurrentLevel() const303 int FrameHeap::GetCurrentLevel() const
304 {
305     NW_ASSERT( IsValid() );
306 
307     return static_cast<int>( m_SectionList.GetSize() ) - 1;
308 }
309 
310 /*---------------------------------------------------------------------------*
311   Name:         GetSize
312 
313   Description:  ヒープの容量を取得
314 
315   Arguments:    None.
316 
317   Returns:      ヒープの容量
318  *---------------------------------------------------------------------------*/
GetSize() const319 u32 FrameHeap::GetSize() const
320 {
321     NW_ASSERT( IsValid() );
322 
323     return static_cast<u32>(
324         static_cast<u8*>( m_pHeap->GetHeapEndAddress() ) -
325         static_cast<u8*>( m_pHeap->GetHeapStartAddress() )
326     );
327 }
328 
329 /*---------------------------------------------------------------------------*
330   Name:         GetFreeSize
331 
332   Description:  ヒープの空き容量を取得
333 
334   Arguments:    None.
335 
336   Returns:      空き容量
337  *---------------------------------------------------------------------------*/
GetFreeSize() const338 u32 FrameHeap::GetFreeSize() const
339 {
340     NW_ASSERT( IsValid() );
341 
342     u32 size = m_pHeap->GetAllocatableSize( HEAP_ALIGN );
343 
344     if ( size < sizeof( Block ) )
345     {
346         return 0;
347     }
348     size -= sizeof( Block );
349 
350     size &= ~(HEAP_ALIGN-1);
351 
352     return size;
353 }
354 
355 /*---------------------------------------------------------------------------*
356   Name:         NewSection
357 
358   Description:  新しいセクションを作成
359 
360   Arguments:    None.
361 
362   Returns:      成功したかどうか
363  *---------------------------------------------------------------------------*/
NewSection()364 bool FrameHeap::NewSection()
365 {
366     // new HeapSection
367     void* buffer = m_pHeap->Alloc( sizeof( Section ) );
368     if ( buffer == NULL )
369     {
370         return false;
371     }
372 
373     Section* section = new( buffer ) Section();
374     m_SectionList.PushBack( section );
375     return true;
376 }
377 
378 /*---------------------------------------------------------------------------*
379   Name:         ClearSection
380 
381   Description:  セクションを全て破棄する
382 
383   Arguments:    None.
384 
385   Returns:      None.
386  *---------------------------------------------------------------------------*/
ClearSection()387 void FrameHeap::ClearSection()
388 {
389     // セクションの破棄
390     while ( !m_SectionList.IsEmpty() )
391     {
392         Section& section = m_SectionList.GetBack();
393 
394         // コールバックの呼び出し
395         section.~Section();
396 
397         // セクションリストからの削除
398         m_SectionList.Erase( &section );
399     }
400 }
401 
Dump(nw::snd::SoundDataManager & mgr,nw::snd::SoundArchive & arc)402 void FrameHeap::Dump(
403         nw::snd::SoundDataManager& mgr, nw::snd::SoundArchive& arc )
404 {
405     int i = 0;
406     for ( SectionList::Iterator itr = m_SectionList.GetBeginIter();
407             itr != m_SectionList.GetEndIter(); )
408     {
409         SectionList::Iterator curItr = itr++;
410         NN_LOG("section[%d]\n", i++ );
411         curItr->Dump( mgr, arc );
412     }
413 }
414 
415 /* ========================================================================
416         FrameHeap::Section class member function
417    ======================================================================== */
418 
~Section()419 FrameHeap::Section::~Section()
420 {
421     // コールバックを登録逆順に呼びだし
422     BlockList::Iterator itr = m_BlockList.GetEndIter();
423     while ( itr != m_BlockList.GetBeginIter() )
424     {
425         (void)--itr;
426         itr->~Block();
427     }
428 }
429 
Dump(nw::snd::SoundDataManager & mgr,nw::snd::SoundArchive & arc)430 void FrameHeap::Section::Dump(
431         nw::snd::SoundDataManager& mgr, nw::snd::SoundArchive& arc )
432 {
433     int i = 0;
434     for ( BlockList::Iterator itr = m_BlockList.GetBeginIter();
435             itr != m_BlockList.GetEndIter(); )
436     {
437         BlockList::Iterator curItr = itr++;
438         const void* ptr = curItr->GetBufferAddr();
439 
440         u32 sign = *reinterpret_cast<const u32*>(ptr);
441 
442         char signature[5];
443         signature[4] = '\0';
444         std::memcpy( signature, &sign, 4 );
445 
446         u32 fileId = mgr.detail_GetFileIdFromTable( ptr );
447 
448         SoundArchive::ItemId itemId = SoundArchive::INVALID_ID;
449         u32 waveIndex = 0xffffffff;
450         switch ( sign )
451         {
452         case BankFileReader::SIGNATURE_FILE:
453             for ( u32 j = 0; j < arc.GetBankCount(); j++ )
454             {
455                 SoundArchive::BankInfo info;
456                 SoundArchive::ItemId id =
457                     Util::GetMaskedItemId( j, ItemType_Bank );
458                 if ( arc.ReadBankInfo( id, &info ) )
459                 {
460                     if ( info.fileId == fileId )
461                     {
462                         itemId = id;
463                         break;
464                     }
465                 }
466             }
467             break;
468         case GroupFileReader::SIGNATURE_FILE:
469             for ( u32 j = 0; j < arc.GetGroupCount(); j++ )
470             {
471                 SoundArchive::GroupInfo info;
472                 SoundArchive::ItemId id =
473                     Util::GetMaskedItemId( j, ItemType_Group );
474                 if ( arc.detail_ReadGroupInfo( id, &info ) )
475                 {
476                     if ( info.fileId == fileId )
477                     {
478                         itemId = id;
479                         break;
480                     }
481                 }
482             }
483             break;
484         case SequenceSoundFileReader::SIGNATURE_FILE:
485         case WaveSoundFileReader::SIGNATURE_FILE:
486             for ( u32 j = 0; j < arc.GetSoundCount(); j++ )
487             {
488                 SoundArchive::SoundInfo info;
489                 SoundArchive::ItemId id =
490                     Util::GetMaskedItemId( j, ItemType_Sound );
491                 if ( arc.ReadSoundInfo( id, &info ) )
492                 {
493                     if ( info.fileId == fileId )
494                     {
495                         itemId = id;
496                         break;
497                     }
498                 }
499             }
500             break;
501         case WaveArchiveFileReader::SIGNATURE_FILE:
502             itemId = GetWaveArchiveId( fileId, arc );
503             break;
504         // 個別ロードの波形
505         case SoundDataManager::SIGNATURE_INDIVIDUAL_WAVE:
506             {
507                 const u32* pU32Array = reinterpret_cast<const u32*>(ptr);
508                 fileId = pU32Array[1];
509                 waveIndex = pU32Array[2];
510                 itemId = GetWaveArchiveId( fileId, arc );
511             }
512             break;
513         default:
514             itemId = SoundArchive::INVALID_ID;
515             break;
516         }
517 
518         const char* pItemLabel = arc.GetItemLabel( itemId );
519         if ( pItemLabel != NULL )
520         {
521             NN_LOG("  block[%d] 0x%08X [%s] fileId(%6d) itemId(%08X) [%s]",
522                     i++, ptr, signature, fileId, itemId, pItemLabel );
523         }
524         else
525         {
526             NN_LOG("  block[%d] 0x%08X [%s] fileId(%6d) itemId(%08X) [(anonymous)]",
527                     i++, ptr, signature, fileId, itemId );
528         }
529 
530         if ( waveIndex != 0xffffffff )
531         {
532             NN_LOG("(%d)\n", waveIndex );
533         }
534         else
535         {
536             NN_LOG("\n");
537         }
538     }
539 }
540 
541 } // namespace nw::snd::internal
542 } // namespace nw::snd
543 } // namespace nw
544 
545