1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: snd_VoiceManager.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_VoiceManager.h>
21 #include <nw/snd/snd_DisposeCallbackManager.h>
22
23 namespace nw {
24 namespace snd {
25 namespace internal {
26 namespace driver {
27
28 /*---------------------------------------------------------------------------*
29 Name: GetInstance
30
31 Description: シングルトンのインスタンスを取得します
32
33 Arguments: なし
34
35 Returns: なし
36 *---------------------------------------------------------------------------*/
GetInstance()37 VoiceManager& VoiceManager::GetInstance()
38 {
39 static VoiceManager instance;
40 return instance;
41 }
42
43
VoiceManager()44 VoiceManager::VoiceManager()
45 : m_Initialized( false )
46 {
47 }
48
GetRequiredMemSize(int voiceCount)49 size_t VoiceManager::GetRequiredMemSize( int voiceCount )
50 {
51 return sizeof( Voice ) * voiceCount;
52 }
53
Initialize(void * mem,size_t memSize)54 void VoiceManager::Initialize( void* mem, size_t memSize )
55 {
56 if ( m_Initialized ) return;
57
58 int voiceCount = memSize / sizeof( Voice );
59
60 u8* ptr = reinterpret_cast<u8*>( mem );
61 // ボイスをリスト管理
62 for ( int i = 0; i < voiceCount; i++ )
63 {
64 m_FreeVoiceList.PushBack( new( ptr )Voice() );
65 ptr += sizeof( Voice );
66 }
67 NW_ASSERT( ptr <= reinterpret_cast<u8*>( mem ) + memSize );
68
69 m_Initialized = true;
70 }
71
Finalize()72 void VoiceManager::Finalize()
73 {
74 if ( !m_Initialized ) return;
75
76 StopAllVoices();
77
78 // ボイスをリストから削除
79 while ( ! m_FreeVoiceList.IsEmpty() )
80 {
81 Voice& voice = m_FreeVoiceList.GetFront();
82 m_FreeVoiceList.PopFront();
83 voice.~Voice(); // デストラクタ呼び出し
84 }
85
86 m_Initialized = false;
87 }
88
StopAllVoices()89 void VoiceManager::StopAllVoices()
90 {
91 // 再生中のボイスを全てFree
92 while ( ! m_PrioVoiceList.IsEmpty() )
93 {
94 Voice& voice = m_PrioVoiceList.GetFront();
95 voice.Stop();
96 if ( voice.m_Callback != NULL )
97 {
98 voice.m_Callback(
99 &voice,
100 Voice::CALLBACK_STATUS_CANCEL,
101 voice.m_pCallbackData
102 );
103 }
104 voice.Free();
105 }
106 }
107
AllocVoice(int voiceChannelCount,int priority,Voice::VoiceCallback callback,void * callbackData)108 Voice* VoiceManager::AllocVoice(
109 int voiceChannelCount,
110 int priority,
111 Voice::VoiceCallback callback,
112 void* callbackData
113 )
114 {
115 // ボイスが不足している場合にプライオリティが低いボイスを停止させる
116 if ( m_FreeVoiceList.IsEmpty() )
117 {
118 if ( DropLowestPriorityVoice( priority ) == 0 ) return NULL;
119 }
120
121 // フリーリストから空きボイスを取得
122 Voice& voice = m_FreeVoiceList.GetFront();
123
124 if ( ! voice.Alloc( voiceChannelCount, priority, callback, callbackData ) )
125 {
126 return NULL;
127 }
128
129 // プライオリティを設定してボイスリストに追加
130 voice.m_Priority = static_cast<u8>( priority );
131 AppendVoiceList( &voice );
132
133 return &voice;
134 }
135
FreeVoice(Voice * voice)136 void VoiceManager::FreeVoice( Voice* voice )
137 {
138 NW_NULL_ASSERT( voice );
139
140 RemoveVoiceList( voice );
141 }
142
UpdateAllVoices()143 void VoiceManager::UpdateAllVoices()
144 {
145 // 波形の再生が完了したボイスを停止させる
146 for ( VoiceList::Iterator itr = m_PrioVoiceList.GetBeginIter();
147 itr != m_PrioVoiceList.GetEndIter();
148 )
149 {
150 VoiceList::Iterator curItr = itr++;
151 curItr->StopFinished();
152 }
153
154 // すべてのボイスのパラメータ計算
155 for ( VoiceList::Iterator itr = m_PrioVoiceList.GetBeginIter();
156 itr != m_PrioVoiceList.GetEndIter();
157 )
158 {
159 VoiceList::Iterator curItr = itr++;
160 curItr->Calc();
161 }
162
163 // すべてのボイスを更新
164 for ( VoiceList::Iterator itr = m_PrioVoiceList.GetBeginIter();
165 itr != m_PrioVoiceList.GetEndIter();
166 )
167 {
168 VoiceList::Iterator curItr = itr++;
169 curItr->Update();
170 }
171 }
172
AppendVoiceList(Voice * voice)173 void VoiceManager::AppendVoiceList( Voice* voice )
174 {
175 m_FreeVoiceList.Erase( voice );
176
177 // プライオリティリストに挿入、同プライオリティは後着の音を後ろに繋ぐ
178 // 逆順に探索したほうが、同プライオリティの場合に速い。
179 VoiceList::ReverseIterator itr = m_PrioVoiceList.GetBeginReverseIter();
180 while ( itr != m_PrioVoiceList.GetEndReverseIter() )
181 {
182 if ( itr->m_Priority <= voice->m_Priority )
183 {
184 break;
185 }
186 (void)++itr;
187 }
188
189 m_PrioVoiceList.Insert( itr.GetBase(), voice );
190 }
RemoveVoiceList(Voice * voice)191 void VoiceManager::RemoveVoiceList( Voice* voice )
192 {
193 m_PrioVoiceList.Erase( voice );
194 m_FreeVoiceList.PushBack( voice );
195 }
196
ChangeVoicePriority(Voice * voice)197 void VoiceManager::ChangeVoicePriority( Voice* voice )
198 {
199 RemoveVoiceList( voice );
200 AppendVoiceList( voice );
201 UpdateEachVoicePriority(
202 m_PrioVoiceList.GetIteratorFromPointer( voice ),
203 m_PrioVoiceList.GetEndIter()
204 );
205 }
206
UpdateEachVoicePriority(const VoiceList::Iterator & beginItr,const VoiceList::Iterator & endItr)207 void VoiceManager::UpdateEachVoicePriority(
208 const VoiceList::Iterator& beginItr,
209 const VoiceList::Iterator& endItr
210 )
211 {
212 // プライオリティリストの更新
213 for ( VoiceList::Iterator itr = beginItr;
214 itr != endItr;
215 (void)++itr
216 )
217 {
218 // RELEASEよりプライオリティが低いものは再設定しない。
219 if ( itr->GetPriority() <= Voice::PRIORITY_RELEASE ) return;
220
221 // NODROPは変更しない
222 if ( itr->GetPriority() == Voice::PRIORITY_NODROP ) continue;
223
224 itr->UpdateVoicesPriority();
225 }
226 }
227
UpdateAllVoicesSync(u32 syncFlag)228 void VoiceManager::UpdateAllVoicesSync( u32 syncFlag )
229 {
230 for ( VoiceList::Iterator itr = m_PrioVoiceList.GetBeginIter();
231 itr != m_PrioVoiceList.GetEndIter();
232 )
233 {
234 VoiceList::Iterator curItr = itr++;
235 if ( curItr->m_IsActive ) curItr->m_SyncFlag |= syncFlag;
236 }
237 }
238
DropLowestPriorityVoice(int priority)239 int VoiceManager::DropLowestPriorityVoice( int priority )
240 {
241 if ( m_PrioVoiceList.IsEmpty() ) return 0;
242
243 Voice* dropVoice = &m_PrioVoiceList.GetFront();
244 if ( dropVoice->GetPriority() > priority ) return 0;
245
246 // もっとも優先度の低いボイスをDrop
247 int dropCount = dropVoice->GetPhysicalVoiceCount();
248
249 Voice::VoiceCallback callbackFunc = dropVoice->m_Callback;
250 void* callbackData = dropVoice->m_pCallbackData;
251
252 dropVoice->Stop();
253 dropVoice->Free();
254
255 if ( callbackFunc != NULL )
256 {
257 callbackFunc(
258 dropVoice,
259 Voice::CALLBACK_STATUS_DROP_VOICE,
260 callbackData
261 );
262 }
263
264 return dropCount;
265 }
266
GetVoiceCount() const267 int VoiceManager::GetVoiceCount() const
268 {
269 SoundThreadLock lock;
270
271 int voiceCount = 0;
272 for (
273 VoiceList::ConstIterator itr = m_PrioVoiceList.GetBeginIter();
274 itr != m_PrioVoiceList.GetEndIter();
275 (void)++itr
276 )
277 {
278 voiceCount += itr->GetPhysicalVoiceCount();
279 }
280
281 return voiceCount;
282 }
283
GetActiveCount() const284 unsigned long VoiceManager::GetActiveCount() const
285 {
286 SoundThreadLock lock;
287
288 return m_PrioVoiceList.GetSize();
289 }
290
GetFreeCount() const291 unsigned long VoiceManager::GetFreeCount() const
292 {
293 SoundThreadLock lock;
294
295 return m_FreeVoiceList.GetSize();
296 }
297
GetVoiceList() const298 const VoiceManager::VoiceList& VoiceManager::GetVoiceList() const
299 {
300 return m_PrioVoiceList;
301 }
302
303 } // namespace nw::snd::internal::driver
304 } // namespace nw::snd::internal
305 } // namespace nw::snd
306 } // namespace nw
307
308