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( §ion );
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( §ion );
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