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