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