1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_SoundInstanceManager.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: 27043 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_SND_SOUND_INSTANCE_MANAGER_H_
17 #define NW_SND_SOUND_INSTANCE_MANAGER_H_
18 
19 #include <nw/ut/ut_LinkList.h>
20 #include <nw/snd/snd_InstancePool.h>
21 #include <nw/snd/snd_BasicSound.h>
22 
23 namespace nw {
24 namespace snd {
25 namespace internal {
26 
27 /* ========================================================================
28         SoundInstanceManager class
29    ======================================================================== */
30 
31 template < typename Sound, typename Player >
32 class SoundInstanceManager
33 {
34     /* ------------------------------------------------------------------------
35             typename definition
36        ------------------------------------------------------------------------ */
37   public:
38     typedef ut::LinkList< Sound, offsetof(Sound,m_PriorityLink)> PriorityList;
39     typedef typename PriorityList::Iterator Iterator;
40 
41     /* ------------------------------------------------------------------------
42             class member
43        ------------------------------------------------------------------------ */
44   public:
SoundInstanceManager()45     SoundInstanceManager()
46     {
47 //        m_CriticalSection.Initialize();
48     }
49 
~SoundInstanceManager()50     ~SoundInstanceManager()
51     {
52 //        m_CriticalSection.Finalize();
53     }
54 
GetRequiredMemSize(int instanceCount)55     unsigned long GetRequiredMemSize( int instanceCount )
56     {
57         return sizeof(Sound) * instanceCount;
58     }
59 
60     /*---------------------------------------------------------------------------*
61       Name:         Create
62 
63       Description:  指定したメモリ領域をインスタンスマネージャに割り当てます
64 
65       Arguments:    buffer - メモリ領域の開始アドレス
66                     size   - メモリ領域のサイズ
67 
68       Returns:      無し
69      *---------------------------------------------------------------------------*/
Create(void * buffer,unsigned long size)70     unsigned long Create( void* buffer, unsigned long size )
71     {
72         NW_NULL_ASSERT( buffer );
73 //		nn::os::CriticalSection::ScopedLock lock(m_CriticalSection);
74 
75         char* ptr = static_cast<char*>(buffer);
76         const unsigned long numObjects = size / sizeof(Sound);
77         for( unsigned long i=0 ;i<numObjects; i++ ){
78             Sound* sound = new( ptr ) Sound( *this );
79             m_FreeList.PushBack( sound );
80             ptr += sizeof(Sound);
81         }
82         return numObjects;
83     }
84 
85     /*---------------------------------------------------------------------------*
86       Name:         Destroy
87 
88       Description:  指定したメモリ領域をインスタンスマネージャから解放します
89                     解放するためにはメモリ領域が Free されている必要があります。
90 
91       Arguments:    buffer - メモリ領域の開始アドレス
92                     size   - メモリ領域のサイズ
93 
94       Returns:      無し
95      *---------------------------------------------------------------------------*/
Destroy(void * buffer,unsigned long size)96     void Destroy( void* buffer, unsigned long size )
97     {
98         NW_NULL_ASSERT( buffer );
99         NW_ASSERT( m_PriorityList.IsEmpty() );
100 
101         (void)buffer;
102         (void)size;
103 
104         m_FreeList.Clear();
105         m_PriorityList.Clear();
106 //		nn::os::CriticalSection::ScopedLock lock(m_CriticalSection);
107     }
108 
109     /*---------------------------------------------------------------------------*
110       Name:         Alloc
111 
112       Description:  インスタンスを確保する
113                     マネージャーからインスタンスを確保します。
114 
115       Arguments:    priority - プライオリティ
116                     ambientPriority - アンビエントプライオリティ
117 
118       Returns:      確保したインスタンス、確保できなければNULL
119      *---------------------------------------------------------------------------*/
Alloc(int priority,int ambientPriority)120     Sound* Alloc( int priority, int ambientPriority )
121     {
122         int allocPriority = priority + ambientPriority;
123         allocPriority = ut::Clamp( allocPriority, BasicSound::PRIORITY_MIN, BasicSound::PRIORITY_MAX );
124 
125 //		nn::os::CriticalSection::ScopedLock lock(m_CriticalSection);
126 
127         Sound* sound = NULL;
128         while( sound == NULL )
129         {
130             if ( ! m_FreeList.IsEmpty() )
131             {
132                 sound = &m_FreeList.GetFront();
133                 m_FreeList.PopFront();
134             }
135             else
136             {
137                 // get lowest priority sound
138                 Sound* lowPrioSound = GetLowestPrioritySound();
139                 if ( lowPrioSound == NULL ) return NULL;
140                 if ( allocPriority < lowPrioSound->CalcCurrentPlayerPriority() ) return NULL;
141 
142 //                m_CriticalSection.Leave();
143 
144                 NW_WARNING(
145                     ! internal::Debug_GetWarningFlag(
146                         internal::Debug_GetDebugWarningFlagFromSoundType(
147                             lowPrioSound->GetSoundType() ) ),
148                     "Sound (id:0x%08x) is stopped for not enough %s sound instance.",
149                     lowPrioSound->GetId(),
150                     internal::Debug_GetSoundTypeString( lowPrioSound->GetSoundType() )
151                 );
152                 lowPrioSound->Stop( 0 );
153 
154 //				m_CriticalSection.Enter();
155             }
156         }
157 
158         sound->Initialize();
159         sound->SetPriority( priority, ambientPriority );
160 
161         InsertPriorityList( sound, allocPriority );
162         return sound;
163     }
164 
165     /*---------------------------------------------------------------------------*
166       Name:         Free
167 
168       Description:  インスタンスをマネージャーに解放する
169                     指定したインスタンスをマネージャーに対して解放します。
170                     解放するインスタンスは、あらかじめ停止されている必要があります。
171 
172       Arguments:    sound - インスタンス
173 
174       Returns:      無し
175      *---------------------------------------------------------------------------*/
Free(Sound * sound)176     void Free( Sound* sound )
177     {
178         NW_NULL_ASSERT( sound );
179 
180 //		nn::os::CriticalSection::ScopedLock lock( m_CriticalSection );
181 
182         RemovePriorityList( sound );
183 
184         sound->Finalize();
185         m_FreeList.PushBack( sound );
186     }
187 
188     /*---------------------------------------------------------------------------*
189       Name:         UpdatePriority
190 
191       Description:  引数に指定したサウンドのプライオリティをプライオリティリストに
192                     反映させる
193 
194       Arguments:    sound - インスタンス
195                     priority - プライオリティ
196 
197       Returns:      無し
198      *---------------------------------------------------------------------------*/
UpdatePriority(Sound * sound,int priority)199     void UpdatePriority( Sound* sound, int priority )
200     {
201 //        nn::os::CriticalSection::ScopedLock lock( m_CriticalSection );
202 
203         RemovePriorityList( sound );
204         InsertPriorityList( sound, priority );
205     }
206 
207     /*---------------------------------------------------------------------------*
208       Name:         SortPriorityList
209 
210       Description:  プライオリティリストをソートする
211 
212       Arguments:    無し
213 
214       Returns:      無し
215      *---------------------------------------------------------------------------*/
SortPriorityList()216     void SortPriorityList()
217     {
218         if ( m_PriorityList.GetSize() < 2 ) return;
219 
220 //        nn::os::CriticalSection::ScopedLock lock( m_CriticalSection );
221 
222         static const int TMP_NUM =
223             internal::BasicSound::PRIORITY_MAX - internal::BasicSound::PRIORITY_MIN + 1;
224         PriorityList tmplist[ TMP_NUM ]; // notice: large stack
225 
226         while ( !m_PriorityList.IsEmpty() )
227         {
228             Sound& front = m_PriorityList.GetFront();
229             m_PriorityList.PopFront();
230             tmplist[ front.CalcCurrentPlayerPriority() ].PushBack( &front );
231         }
232         for ( int i=0; i<TMP_NUM; i++ )
233         {
234             while ( !tmplist[i].IsEmpty() )
235             {
236                 Sound& front = tmplist[i].GetFront();
237                 tmplist[i].PopFront();
238                 m_PriorityList.PushBack( &front );
239             }
240         }
241     }
242 
243     /*---------------------------------------------------------------------------*
244       Name:         GetLowestPrioritySound
245 
246       Description:  最もプライオリティの低いサウンドを取得する
247 
248       Arguments:    なし
249 
250       Returns:
251      *---------------------------------------------------------------------------*/
GetLowestPrioritySound()252     Sound* GetLowestPrioritySound()
253     {
254         if ( m_PriorityList.IsEmpty() ) return NULL;
255         return &m_PriorityList.GetFront();
256     }
257 
258     /*---------------------------------------------------------------------------*
259       Name:         GetActiveCount
260 
261       Description:  現在アクティブなサウンド数を取得する
262 
263       Arguments:    なし
264 
265       Returns:      サウンド数
266      *---------------------------------------------------------------------------*/
GetActiveCount()267     unsigned long GetActiveCount() const
268     {
269         return m_PriorityList.GetSize();
270     }
271 
272     /*---------------------------------------------------------------------------*
273       Name:         GetFreeCount
274 
275       Description:  マネージャーからAlloc可能な残りインスタンス数を取得する
276 
277       Arguments:    無し
278 
279       Returns:      インスタンス数
280      *---------------------------------------------------------------------------*/
GetFreeCount()281     int GetFreeCount() const { return m_FreeList.GetSize(); }
282 
283   private:
InsertPriorityList(Sound * sound,int priority)284     void InsertPriorityList( Sound* sound, int priority )
285     {
286         // プライオリティリストへ追加
287         Iterator itr = m_PriorityList.GetBeginIter();
288         while ( itr != m_PriorityList.GetEndIter() )
289         {
290             if ( priority < itr->CalcCurrentPlayerPriority() ) break;
291             (void)++itr;
292         }
293         m_PriorityList.Insert( itr, sound );
294     }
RemovePriorityList(Sound * sound)295     void RemovePriorityList( Sound* sound ) { m_PriorityList.Erase( sound ); }
296 
297     PriorityList m_PriorityList;
298     PriorityList m_FreeList;
299 //	nn::os::CriticalSection m_CriticalSection;
300 };
301 
302 } // namespace nw::snd::internal
303 } // namespace nw::snd
304 } // namespace nw
305 
306 
307 #endif /* NW_SND_SOUND_INSTANCE_MANAGER_H_ */
308 
309