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