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