1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: snd_Util.h 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: 32405 $ 16 *---------------------------------------------------------------------------*/ 17 18 #ifndef NW_SND_UTIL_H_ 19 #define NW_SND_UTIL_H_ 20 21 #include <nn/types.h> 22 #include <nn/os.h> // nn::os::GetDeviceMemoryAddress 23 #include <nn/snd.h> 24 #include <nw/ut/ut_BinaryReader.h> // ResU32 など 25 #include <nw/ut/ut_BinaryFileFormat.h> 26 #include <nw/ut/ut_Inlines.h> 27 #include <nw/ut/ut_Preprocessor.h> // NW_DISALLOW_COPY_AND_ASSIGN 28 #include <nw/snd/snd_ItemType.h> 29 #include <nw/snd/snd_Global.h> 30 31 // #define NW_SND_DEBUG_NOUSE_CTRSDK // 有効なときは、nn::snd へのアクセスを遮断 (デバッグ用) 32 33 #define NW_SND_ROUND_UP_32B(x) (((u32)(x) + 32 - 1) & ~(32 - 1)) 34 35 namespace nw { 36 namespace snd { 37 38 class SoundArchive; 39 class SoundArchivePlayer; 40 41 namespace internal { 42 43 class SoundArchiveLoader; 44 class PlayerHeapDataManager; 45 struct LoadItemInfo; 46 47 class Util 48 { 49 public: 50 static const int VOLUME_DB_MIN = -904; // -90.4dB = -inf 51 static const int VOLUME_DB_MAX = 60; // + 6.0dB 52 53 static const int PITCH_DIVISION_BIT = 8; // 半音分解能.(ビット数) 54 static const int PITCH_DIVISION_RANGE = 1 << PITCH_DIVISION_BIT; // 半音分解能. 55 56 // ------------------------------------------------------------------------ 57 // パン設定 58 // static const int PAN_CURVE_NUM = 3; 59 enum PanCurve 60 { 61 PAN_CURVE_SQRT, 62 PAN_CURVE_SINCOS, 63 PAN_CURVE_LINEAR 64 }; 65 struct PanInfo 66 { 67 PanCurve curve; 68 bool centerZeroFlag; // 中央で0dBにするかどうか 69 bool zeroClampFlag; // 0dBを超えたときにClampするかどうか PanInfoPanInfo70 PanInfo() : curve( PAN_CURVE_SQRT ), centerZeroFlag( false ), zeroClampFlag( false ) {} 71 }; 72 73 74 static u16 CalcLpfFreq( f32 scale ); 75 static f32 CalcPanRatio( f32 pan, const PanInfo& info ); 76 static f32 CalcSurroundPanRatio( f32 surroundPan, const PanInfo& info ); 77 78 static f32 CalcPitchRatio( int pitch ); 79 static f32 CalcVolumeRatio( f32 dB ); 80 static u16 CalcRandom(); 81 82 #if 0 83 // デバッグ用 (3D サラウンドモード時の音割れ調整) 84 static f32 SetPanCurveMax( f32 max ); // 設定後の現在値を返す 85 static f32 GetPanCurveMax(); 86 static f32 GetPanCurveMin(); 87 #endif 88 GetInterpolationType(SrcType type)89 static nn::snd::InterpolationType GetInterpolationType( SrcType type ) 90 { 91 nn::snd::InterpolationType interpolationType = nn::snd::INTERPOLATION_TYPE_POLYPHASE; 92 switch ( type ) 93 { 94 case SRC_TYPE_NONE: 95 interpolationType = nn::snd::INTERPOLATION_TYPE_NONE; 96 break; 97 case SRC_TYPE_LINEAR: 98 interpolationType = nn::snd::INTERPOLATION_TYPE_LINEAR; 99 break; 100 case SRC_TYPE_4TAP: 101 default: 102 break; 103 } 104 return interpolationType; 105 } 106 107 static unsigned long GetSampleByByte( unsigned long byte, SampleFormat format ); 108 static unsigned long GetByteBySample( unsigned long sample, SampleFormat format ); 109 110 private: 111 // CalcLpfFreq Table 112 static const int CALC_LPF_FREQ_TABLE_SIZE = 24; 113 static const f32 CALC_LPF_FREQ_INTERCEPT; 114 static const u16 CalcLpfFreqTable[ CALC_LPF_FREQ_TABLE_SIZE ]; 115 116 public: 117 template< typename ITEM_TYPE, typename COUNT_TYPE=nw::ut::ResU32 > 118 struct Table 119 { 120 COUNT_TYPE count; 121 ITEM_TYPE item[ 1 ]; 122 }; 123 124 struct Reference 125 { 126 nw::ut::ResU16 typeId; // snd_ElementType.h で定義されているタイプ 127 u16 padding; 128 nw::ut::ResS32 offset; // INVALID_OFFSET が入っていたら 無効値 129 130 static const s32 INVALID_OFFSET = -1; 131 IsValidTypeIdReference132 NW_INLINE bool IsValidTypeId( u16 validId ) const 133 { 134 if ( validId == typeId ) 135 { 136 return true; 137 } 138 return false; 139 } IsValidOffsetReference140 NW_INLINE bool IsValidOffset() const 141 { 142 if ( offset != INVALID_OFFSET ) 143 { 144 return true; 145 } 146 return false; 147 } 148 }; 149 150 struct ReferenceWithSize : public Reference 151 { 152 nw::ut::ResU32 size; 153 }; 154 155 struct ReferenceTable : public Table<Reference> 156 { GetReferedItemReferenceTable157 const void* GetReferedItem( u32 index ) const 158 { 159 if ( index >= count ) return NULL; 160 return ut::AddOffsetToPtr( this, item[ index ].offset ); 161 } GetReferedItemReferenceTable162 const void* GetReferedItem( u32 index, u16 typeId ) const 163 { 164 if ( index >= count ) return NULL; 165 if ( item[ index ].typeId != typeId ) return NULL; 166 return ut::AddOffsetToPtr( this, item[ index ].offset ); 167 } FindReferedItemByReferenceTable168 const void* FindReferedItemBy( u16 typeId ) const 169 { 170 for ( u32 i = 0; i < count; i++ ) 171 { 172 if ( item[ i ].IsValidTypeId( typeId ) ) 173 { 174 return ut::AddOffsetToPtr( this, item[i].offset ); 175 } 176 } 177 return NULL; 178 } 179 }; 180 181 struct ReferenceWithSizeTable : public Table<ReferenceWithSize> 182 { GetReferedItemReferenceWithSizeTable183 const void* GetReferedItem( u32 index ) const 184 { 185 NW_ASSERT( index < count ); 186 return ut::AddOffsetToPtr( this, item[ index ].offset ); 187 } GetReferedItemByReferenceWithSizeTable188 const void* GetReferedItemBy( u16 typeId ) const 189 { 190 for ( u32 i = 0; i < count; i++ ) 191 { 192 if ( item[ i ].IsValidTypeId( typeId ) ) 193 { 194 return ut::AddOffsetToPtr( this, item[i].offset ); 195 } 196 } 197 return NULL; 198 } GetReferedItemSizeReferenceWithSizeTable199 u32 GetReferedItemSize( u32 index ) const 200 { 201 NW_ASSERT( index < count ); 202 return item[ index ].size; 203 } 204 }; 205 206 // ブロック参照テーブル 207 // (通常の Util::ReferenceTable ではないので、 208 // count やオフセット起点を外からもらう必要がある) 209 struct BlockReferenceTable 210 { 211 // データ 212 ReferenceWithSize item[ 1 ]; 213 214 // アクセサ GetReferedItemByIndexBlockReferenceTable215 NW_INLINE const void* GetReferedItemByIndex( 216 const void* origin, int index, u16 count ) const 217 { 218 NW_UNUSED_VARIABLE(count); 219 NW_ASSERT( index < count ); 220 return ut::AddOffsetToPtr( origin, item[ index ].offset ); 221 } GetReferenceBlockReferenceTable222 NW_INLINE const ReferenceWithSize* GetReference( 223 u16 typeId, u16 count ) const 224 { 225 for ( int i = 0; i < count; i++ ) 226 { 227 if ( item[ i ].IsValidTypeId( typeId ) ) 228 { 229 return &item[ i ]; 230 } 231 } 232 return NULL; 233 } GetReferedItemBlockReferenceTable234 const void* GetReferedItem( const void* origin, u16 typeId, u16 count ) const 235 { 236 const ReferenceWithSize* ref = GetReference( typeId, count ); 237 if ( ref == NULL ) return NULL; 238 if ( ref->offset == 0 ) return NULL; 239 return ut::AddOffsetToPtr( origin, ref->offset ); 240 } GetReferedItemSizeBlockReferenceTable241 u32 GetReferedItemSize( u16 typeId, u16 count ) const 242 { 243 const ReferenceWithSize* ref = GetReference( typeId, count ); 244 if ( ref == NULL ) return 0; 245 return ref->size; 246 } GetReferedItemOffsetBlockReferenceTable247 u32 GetReferedItemOffset( u16 typeId, u16 count ) const 248 { 249 const ReferenceWithSize* ref = GetReference( typeId, count ); 250 if ( ref == NULL ) return 0; 251 return ref->offset; 252 } 253 }; 254 255 // サウンドファイルの共通ヘッダー 256 struct SoundFileHeader 257 { 258 ut::BinaryFileHeader header; 259 BlockReferenceTable blockReferenceTable; 260 GetBlockCountSoundFileHeader261 NW_INLINE s32 GetBlockCount() const { return header.dataBlocks; } 262 263 protected: GetBlockSoundFileHeader264 NW_INLINE const void* GetBlock( u16 typeId ) const 265 { 266 return blockReferenceTable.GetReferedItem( this, typeId, header.dataBlocks ); 267 } GetBlockSizeSoundFileHeader268 NW_INLINE u32 GetBlockSize( u16 typeId ) const 269 { 270 return blockReferenceTable.GetReferedItemSize( typeId, header.dataBlocks ); 271 } GetBlockOffsetSoundFileHeader272 NW_INLINE u32 GetBlockOffset( u16 typeId ) const 273 { 274 return blockReferenceTable.GetReferedItemOffset( typeId, header.dataBlocks ); 275 } 276 }; 277 278 // オプションパラメータ 279 struct BitFlag 280 { 281 nw::ut::ResU32 bitFlag; 282 283 public: 284 // binNumber で指定したビットの指す値を value に格納します。 285 // ビットが false なら false を返します。 GetValueBitFlag286 bool GetValue( u32* value, u32 bitNumber ) const 287 { 288 u32 count = GetTrueCount( bitNumber ); 289 290 // bitNumber 番目のビットが無効だった場合 291 if ( count == 0 ) return false; 292 293 *value = *reinterpret_cast<const nw::ut::ResU32*>( 294 ut::AddOffsetToPtr( this, ( count * sizeof(nw::ut::ResU32) ) ) ); 295 return true; 296 } GetValueF32BitFlag297 bool GetValueF32( f32* value, u32 bitNumber ) const 298 { 299 u32 count = GetTrueCount( bitNumber ); 300 if ( count == 0 ) return false; 301 *value = *reinterpret_cast<const nw::ut::ResF32*>( 302 ut::AddOffsetToPtr( this, ( count * sizeof(nw::ut::ResF32) ) ) ); 303 return true; 304 } 305 306 private: 307 // アクセサ 308 // 309 // bitNumber - 「何」ビット目をチェックしたいか? 0 からスタート。 310 // return - bitNumber ビットが 1 なら、下位から数えていくつめの有効フラグか 311 // を返す。 312 // 313 // 例: カンタンのため、4 bit の bitFlag とする。 314 // bitFlag = 1001 [2進] のとき、 315 // GetTrueCount( 0 ) => 1 316 // GetTrueCount( 1 ) => 0 317 // GetTrueCount( 2 ) => 0 318 // GetTrueCount( 3 ) => 2 319 // GetTrueCount( 4 ) => ASSERT 320 static const int BIT_NUMBER_MAX = 31; GetTrueCountBitFlag321 NW_INLINE u32 GetTrueCount( u32 bitNumber ) const 322 { 323 NW_ASSERT( bitNumber <= BIT_NUMBER_MAX ); 324 325 bool ret = false; // bitNumber ビット目が有効かどうか 326 int count = 0; 327 for ( u32 i = 0; i <= bitNumber; i++ ) 328 { 329 if ( bitFlag & ( 0x1 << i ) ) 330 { 331 count++; 332 if ( i == bitNumber ) 333 { 334 ret = true; 335 } 336 } 337 } 338 339 if ( ret ) 340 { 341 return count; 342 } 343 else 344 { 345 return 0; 346 } 347 } 348 }; 349 350 // BitFlag を扱うときに使う便利関数 DevideBy8bit(u32 value,int index)351 static NW_INLINE u8 DevideBy8bit( u32 value, int index ) 352 { 353 return static_cast<u8>( ( value >> (8*index) ) & 0xff ); 354 } 355 DevideBy16bit(u32 value,int index)356 static NW_INLINE u16 DevideBy16bit( u32 value, int index ) 357 { 358 return static_cast<u16>( ( value >> (16*index) ) & 0xffff ); 359 } 360 361 // ID が warcID の波形アーカイブの index 番目の波形アドレスを返します。 362 // 未ロードの場合、NULL が返ります。 363 static const void* GetWaveFile( 364 u32 waveArchiveId, 365 u32 waveIndex, 366 const SoundArchive& arc, 367 const SoundArchivePlayer& player ); 368 369 static const void* GetWaveFile( 370 u32 waveArchiveId, 371 u32 waveIndex, 372 const SoundArchive& arc, 373 const PlayerHeapDataManager* mgr ); 374 375 static bool IsLoadedWaveArchive( 376 const void* bankFile, 377 const SoundArchive& arc, 378 const SoundArchiveLoader& mgr ); 379 380 static bool IsLoadedWaveArchive( 381 const void* wsdFile, 382 u32 index, // bcwsd 内でいくつめのウェーブサウンドか? 383 const SoundArchive& arc, 384 const SoundArchiveLoader& mgr ); 385 GetItemType(u32 id)386 static NW_INLINE ItemType GetItemType( u32 id ) 387 { 388 // id == SoundArchive::ItemId を想定。 389 // 上位 8 bit がアイテムタイプ (nw::snd::internal::ItemType) に相当する 390 return static_cast<ItemType>( id >> 24 ); 391 } 392 GetItemIndex(u32 id)393 static NW_INLINE u32 GetItemIndex( u32 id ) 394 { 395 // id == SoundArchive::ItemId を想定。 396 // 下位 24 bit がアイテムインデックスに相当する 397 return ( id & 0x00ffffff ); 398 } 399 GetMaskedItemId(u32 id,internal::ItemType type)400 static NW_INLINE u32 GetMaskedItemId( u32 id, internal::ItemType type ) 401 { 402 return ( id | ( type << 24 ) ); 403 } 404 405 struct WaveId 406 { 407 ut::ResU32 waveArchiveId; // 波形アーカイブ ID 408 ut::ResU32 waveIndex; // 波形アーカイブ内インデックス 409 }; 410 411 struct WaveIdTable 412 { 413 // データ 414 Table<WaveId> table; 415 416 // アクセサ GetWaveIdWaveIdTable417 const WaveId* GetWaveId( u32 index ) const 418 { 419 if ( index >= table.count ) 420 { 421 return NULL; 422 } 423 return &table.item[ index ]; 424 } GetCountWaveIdTable425 NW_INLINE u32 GetCount() const { return table.count; } 426 }; 427 428 429 /* 430 継承可能なシングルトンクラス 431 */ 432 template <class CHILD> 433 class Singleton 434 { 435 public: GetInstance()436 static CHILD& GetInstance() 437 { 438 static CHILD instance; 439 return instance; 440 } 441 }; 442 443 // デバッグ用処理時間計測ルーチン (規定回数分ためてプリントします) 444 static void CalcTick(); 445 IsDeviceMemory(uptr memory,size_t size)446 static bool IsDeviceMemory( uptr memory, size_t size ) 447 { 448 #ifdef NW_PLATFORM_CTRWIN 449 return true; 450 #else 451 const uptr head = nn::os::GetDeviceMemoryAddress(); 452 const uptr tail = head + nn::os::GetDeviceMemorySize(); 453 if ( head <= memory && (memory + size) <= tail ) 454 { 455 return true; 456 } 457 return false; 458 #endif 459 } 460 461 class AutoStopWatch 462 { 463 public: 464 #ifdef NW_PLATFORM_CTRWIN AutoStopWatch(OSTick & tick)465 AutoStopWatch( OSTick& tick ) : m_Tick( tick ) 466 { 467 m_TmpTick = OS_GetTick(); 468 } ~AutoStopWatch()469 ~AutoStopWatch() 470 { 471 m_Tick = static_cast<OSTick>( OS_DiffTick( OS_GetTick(), m_TmpTick ) ); 472 } 473 #else 474 AutoStopWatch( nn::os::Tick& tick ) : m_Tick( tick ) 475 { 476 m_TmpTick = nn::os::Tick::GetSystemCurrent(); 477 } 478 ~AutoStopWatch() 479 { 480 m_Tick = nn::os::Tick::GetSystemCurrent() - m_TmpTick; 481 } 482 #endif 483 private: 484 #ifdef NW_PLATFORM_CTRWIN 485 OSTick& m_Tick; 486 OSTick m_TmpTick; 487 #else 488 nn::os::Tick& m_Tick; 489 nn::os::Tick m_TmpTick; 490 #endif 491 }; 492 493 // 負荷計測補助。ピーク値を DEFAULT_HOLD_FRAME だけ保存する。 494 template<typename T> 495 class PeakHoldValue 496 { 497 public: PeakHoldValue()498 PeakHoldValue() : m_CurrentValue(0), m_PeakValue(0) {} Update(T value)499 void Update( T value ) 500 { 501 m_CurrentValue = value; 502 if ( m_PeakHoldCounter > 0 ) 503 { 504 --m_PeakHoldCounter; 505 } 506 if ( m_PeakHoldCounter == 0 ) 507 { 508 m_PeakValue = 0; 509 } 510 if ( m_PeakValue < m_CurrentValue ) 511 { 512 m_PeakValue = m_CurrentValue; 513 m_PeakHoldCounter = DEFAULT_HOLD_FRAME; 514 } 515 } GetValue()516 T GetValue() const { return m_CurrentValue; } GetPeakValue()517 T GetPeakValue() const { return m_PeakValue; } 518 private: 519 static const int DEFAULT_HOLD_FRAME = 20; // NW4R は 75 520 T m_CurrentValue; 521 T m_PeakValue; 522 int m_PeakHoldCounter; 523 }; 524 525 // 負荷計測補助。サウンド再生時は値が揺れやすいので、ヒストグラムをつくることにした。 526 // 全サンプルのうち「負荷○○%以下」におさまっているのは、何%かを出力する。 527 class PerfHistogram 528 { 529 public: 530 // コンストラクタ PerfHistogram()531 PerfHistogram() { Reset(); } 532 533 // 負荷%値の設定 SetLoad(f32 load)534 void SetLoad( f32 load ) 535 { 536 // 異常な値 537 if ( load < 0.0f || load > 100.0f ) 538 { 539 m_IrregularCount += 1; 540 } 541 542 // 最大値更新 543 if ( load > m_MaxLoad ) 544 { 545 m_MaxLoad = load; 546 } 547 548 int loadIndex = static_cast<int>( load ); 549 if ( loadIndex < LOAD_COUNT_NUM ) 550 { 551 m_LoadCount[ loadIndex ] += 1; 552 } 553 m_Count += 1; 554 m_SumLoad += load; 555 } 556 557 // 処理負荷 load % 以下は、全体の何%か? GetPercentage(int load)558 f32 GetPercentage( int load ) 559 { 560 int count = 0; 561 for ( int i = 0; i <= load; i++ ) 562 { 563 count += m_LoadCount[ i ]; 564 } 565 f32 ret = 100.f * count / m_Count; 566 return ret; 567 } 568 569 // 全体の percent %のなかで、最大の処理負荷はいくらか? GetMaxLoadByPercent(f32 percent)570 int GetMaxLoadByPercent( f32 percent ) const 571 { 572 int sum = 0; 573 int maxLoad = 0; 574 for ( int i = 0; i < LOAD_COUNT_NUM; i++ ) 575 { 576 sum += m_LoadCount[ i ]; 577 if ( 100.f * sum / m_Count > percent ) 578 { 579 maxLoad = i; 580 break; 581 } 582 } 583 return maxLoad; 584 } 585 GetAverage()586 f32 GetAverage() const { return m_SumLoad / m_Count; } GetMaxLoad()587 f32 GetMaxLoad() const { return m_MaxLoad; } GetCount()588 int GetCount() const { return m_Count; } GetIrregularCount()589 int GetIrregularCount() const { return m_IrregularCount; } 590 591 // リセット Reset()592 void Reset() 593 { 594 m_MaxLoad = m_SumLoad = 0.0; 595 m_Count = m_IrregularCount = 0; 596 std::memset( m_LoadCount, 0x00, sizeof(m_LoadCount) ); 597 } 598 599 private: 600 static int const LOAD_COUNT_NUM = 101; // 0-100 まで合計 101 個に分ける 601 f32 m_MaxLoad; 602 f32 m_SumLoad; 603 int m_LoadCount[ LOAD_COUNT_NUM ]; 604 int m_Count, m_IrregularCount; 605 }; 606 }; 607 608 609 } // namespace nw::snd::internal 610 } // namespace nw::snd 611 } // namespace nw 612 613 614 #endif /* NW_SND_UTIL_H_ */ 615 616