1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: snd_SoundSystem.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: 32385 $
16 *---------------------------------------------------------------------------*/
17
18 #include "precompiled.h"
19
20 #include <nw/snd/snd_SoundSystem.h>
21
22
23 #ifdef NW_PLATFORM_CTRWIN
24 #include <nw/snd/snd_HardwareChannel.h>
25 #include <nw/snd/snd_HardwareChannelManager.h>
26 #endif
27 #include <nw/snd/snd_Voice.h>
28 #include <nw/snd/snd_Channel.h>
29 #include <nw/snd/snd_ChannelManager.h>
30 #include <nw/snd/snd_DriverCommandManager.h>
31 #include <nw/snd/snd_SequenceSoundPlayer.h>
32 #include <nw/snd/snd_TaskManager.h>
33
34 namespace nw {
35 namespace snd {
36
37 internal::ThreadStack SoundSystem::s_LoadThreadStack;
38 bool SoundSystem::s_AutoCreateSoundThreadFlag = false;
39 bool SoundSystem::s_IsInitialized = false;
40 bool SoundSystem::s_IsStreamLoadWait = false;
41 bool SoundSystem::s_IsEnterSleep = false;
42 bool SoundSystem::s_IsInitializedDriverCommandManager = false;
43
44 #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD )
45 // このバージョンからサウンドスレッド用の ThreadStack は不要
46 #else
47 internal::ThreadStack SoundSystem::s_SoundThreadStack;
48 #endif
49
50 int SoundSystem::s_MaxVoiceCount = NN_SND_VOICE_NUM;
51
GetRequiredMemSize(const SoundSystemParam & param)52 size_t SoundSystem::GetRequiredMemSize( const SoundSystemParam& param )
53 {
54 NW_ASSERT( param.soundThreadStackSize % 8 == 0 );
55 NW_ASSERT( param.taskThreadStackSize % 8 == 0 );
56 NW_MINMAX_ASSERT( param.soundThreadCoreNo, 0, 1 );
57
58 size_t result =
59 detail_GetRequiredDriverCommandManagerMemSize( param )
60 + param.taskThreadStackSize
61 #ifdef NW_PLATFORM_CTRWIN
62 + internal::driver::HardwareChannelManager::GetInstance().GetRequiredMemSize(
63 s_MaxVoiceCount )
64 #endif
65 + internal::driver::VoiceManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount )
66 + internal::driver::ChannelManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount );
67
68 if ( param.autoCreateSoundThread == true )
69 {
70 result += param.soundThreadStackSize;
71 }
72
73 #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD )
74 if ( param.soundThreadCoreNo == 1 )
75 {
76 // nn::snd::StartUserSoundThread 用のスタックサイズは、StartSoundThread と同じとする
77 result += param.soundThreadStackSize;
78 }
79 #endif
80
81 return result;
82 }
83
detail_GetRequiredDriverCommandManagerMemSize(const SoundSystemParam & param)84 size_t SoundSystem::detail_GetRequiredDriverCommandManagerMemSize(
85 const SoundSystemParam& param )
86 {
87 NW_ASSERT( param.soundThreadCommandBufferSize % 4 == 0 );
88 NW_ASSERT( param.taskThreadCommandBufferSize % 4 == 0 );
89
90 size_t result =
91 param.soundThreadCommandBufferSize
92 + param.taskThreadCommandBufferSize;
93
94 return result;
95 }
96
detail_InitializeDriverCommandManager(const SoundSystemParam & param,uptr workMem,size_t workMemSize)97 void SoundSystem::detail_InitializeDriverCommandManager(
98 const SoundSystemParam& param,
99 uptr workMem,
100 size_t workMemSize )
101 {
102 if ( s_IsInitializedDriverCommandManager )
103 {
104 return;
105 }
106
107 NW_UNUSED_VARIABLE( workMemSize );
108 NW_ASSERTMSG( workMemSize >= detail_GetRequiredDriverCommandManagerMemSize( param ),
109 "workMemSize(%X) >= RequiredMemSize(%X)",
110 workMemSize, detail_GetRequiredDriverCommandManagerMemSize( param ) );
111
112 uptr ptr = workMem;
113
114 // コマンドバッファ初期化
115 uptr soundThreadCommandBufferPtr = ptr;
116 ptr += param.soundThreadCommandBufferSize;
117
118 uptr taskThreadCommandBufferPtr = ptr;
119 ptr += param.taskThreadCommandBufferSize;
120
121 internal::DriverCommandManager::GetInstance().Initialize(
122 reinterpret_cast<void*>( soundThreadCommandBufferPtr ),
123 param.soundThreadCommandBufferSize
124 );
125 internal::DriverCommandManager::GetInstanceForTaskThread().Initialize(
126 reinterpret_cast<void*>( taskThreadCommandBufferPtr ),
127 param.taskThreadCommandBufferSize
128 );
129
130 s_IsInitializedDriverCommandManager = true;
131 }
132
Initialize(const SoundSystemParam & param,uptr workMem,size_t workMemSize)133 void SoundSystem::Initialize(
134 const SoundSystemParam& param,
135 uptr workMem,
136 size_t workMemSize )
137 {
138 NW_UNUSED_VARIABLE( workMemSize );
139 NW_ASSERTMSG( workMemSize >= GetRequiredMemSize( param ),
140 "workMemSize(%X) >= RequiredMemSize(%X)",
141 workMemSize, GetRequiredMemSize( param ) );
142 NW_MINMAX_ASSERT( param.soundThreadCoreNo, 0, 1 );
143
144 // 多重初期化チェック
145 if ( s_IsInitialized )
146 {
147 return;
148 }
149
150 bool result;
151 NW_UNUSED_VARIABLE(result);
152
153 // SDK 関連初期化
154 internal::driver::HardwareManager::GetInstance().Initialize();
155
156 uptr ptr = workMem;
157
158 if ( s_IsInitializedDriverCommandManager == false )
159 {
160 size_t workMemSizeForDriverCommandManager =
161 detail_GetRequiredDriverCommandManagerMemSize( param );
162 detail_InitializeDriverCommandManager(
163 param,
164 ptr,
165 workMemSizeForDriverCommandManager );
166 ptr += workMemSizeForDriverCommandManager;
167 }
168
169 // nw::snd サウンドスレッドの準備
170 uptr soundThreadStackPtr = NULL;
171 #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD )
172 uptr userSoundThreadStackPtr = NULL;
173 if ( param.autoCreateSoundThread )
174 {
175 soundThreadStackPtr = ptr;
176 ptr += param.soundThreadStackSize;
177 if ( param.soundThreadCoreNo == 1 )
178 {
179 userSoundThreadStackPtr = ptr;
180 ptr += param.soundThreadStackSize; // 通常サウンドスレッドのスタックサイズを流用
181 }
182 }
183 #else
184 if ( param.autoCreateSoundThread )
185 {
186 soundThreadStackPtr = ptr;
187 ptr += param.soundThreadStackSize;
188 s_SoundThreadStack.Initialize( soundThreadStackPtr, param.soundThreadStackSize );
189 }
190 #endif
191 internal::driver::SoundThread::GetInstance().Initialize();
192
193 // nw::snd サウンドデータロードスレッドの準備
194 uptr loadThreadStackPtr = ptr;
195 ptr += param.taskThreadStackSize;
196 internal::TaskManager::GetInstance().Initialize();
197 s_LoadThreadStack.Initialize( loadThreadStackPtr, param.taskThreadStackSize );
198
199 #ifdef NW_PLATFORM_CTRWIN
200 // HardwareChannelManager初期化
201 uptr axVoiceWork = ptr;
202 ptr += internal::driver::HardwareChannelManager::GetInstance().GetRequiredMemSize(
203 s_MaxVoiceCount );
204 internal::driver::HardwareChannelManager::GetInstance().Initialize(
205 reinterpret_cast<void*>( axVoiceWork ),
206 internal::driver::HardwareChannelManager::GetInstance().GetRequiredMemSize(
207 s_MaxVoiceCount )
208 );
209 #endif
210
211 // VoiceManager初期化
212 uptr voiceWork = ptr;
213 ptr += internal::driver::VoiceManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount );
214 internal::driver::VoiceManager::GetInstance().Initialize(
215 reinterpret_cast<void*>( voiceWork ),
216 internal::driver::VoiceManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount )
217 );
218
219 // ChannelManager初期化
220 uptr channelWork = ptr;
221 ptr += internal::driver::ChannelManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount );
222 internal::driver::ChannelManager::GetInstance().Initialize(
223 reinterpret_cast<void*>( channelWork ),
224 internal::driver::ChannelManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount )
225 );
226
227 NW_ASSERT( ptr <= workMem + workMemSize );
228
229 // SequenceSoundPlayer初期化
230 internal::driver::SequenceSoundPlayer::InitSequenceSoundPlayer();
231
232
233 // データロードスレッド起動
234 result = internal::TaskThread::GetInstance().Create( param.taskThreadPriority, s_LoadThreadStack );
235 NW_ASSERT( result );
236
237 // サウンドスレッド起動
238 if ( param.autoCreateSoundThread )
239 {
240 #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD )
241 #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD2 )
242 result = internal::driver::SoundThread::GetInstance().CreateSoundThread(
243 soundThreadStackPtr,
244 param.soundThreadStackSize,
245 param.soundThreadPriority,
246
247 userSoundThreadStackPtr,
248 param.soundThreadStackSize,
249 param.soundThreadPriority,
250
251 param.soundThreadCoreNo,
252 param.enableGetSoundThreadTick );
253
254 NW_ASSERT( result );
255 #else
256 result = internal::driver::SoundThread::GetInstance().CreateSoundThread(
257 soundThreadStackPtr,
258 param.soundThreadStackSize,
259 param.soundThreadPriority,
260 param.soundThreadCoreNo,
261 param.enableGetSoundThreadTick );
262 NW_ASSERT( result );
263 if ( param.soundThreadCoreNo == 1 )
264 {
265 result = internal::driver::SoundThread::GetInstance().CreateUserSoundThread(
266 userSoundThreadStackPtr,
267 param.soundThreadStackSize, // StartSoundThread と同じスタックサイズとする
268 param.soundThreadPriority ); // StartSoundThread の優先度を流用する
269 NW_ASSERT( result );
270 }
271 #endif
272 #else
273 result = internal::driver::SoundThread::GetInstance().Create(
274 param.soundThreadPriority,
275 s_SoundThreadStack,
276 param.soundThreadCoreNo,
277 param.enableGetSoundThreadTick );
278 NW_ASSERT( result );
279 #endif
280 }
281
282 s_AutoCreateSoundThreadFlag = param.autoCreateSoundThread;
283 s_IsInitialized = true;
284 }
285
Finalize()286 void SoundSystem::Finalize()
287 {
288 if ( ! s_IsInitialized )
289 {
290 return;
291 }
292
293 // データロードスレッド終了
294 internal::TaskManager::GetInstance().CancelAllTask();
295 internal::TaskThread::GetInstance().Destroy();
296 internal::TaskManager::GetInstance().Finalize();
297
298 // サウンドスレッド停止
299 internal::driver::SoundThread::GetInstance().Destroy();
300
301 // 各種マネージャー破棄
302 internal::driver::ChannelManager::GetInstance().Finalize();
303
304 internal::driver::VoiceManager::GetInstance().Finalize();
305
306 #ifdef NW_PLATFORM_CTRWIN
307 internal::driver::HardwareChannelManager::GetInstance().Finalize();
308 #endif
309
310 internal::driver::HardwareManager::GetInstance().Finalize();
311
312 #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD )
313 // なにもしない
314 #else
315 s_SoundThreadStack.Finalize();
316 #endif
317 s_LoadThreadStack.Finalize();
318
319 // サウンドスレッド終了
320 internal::driver::SoundThread::GetInstance().Finalize();
321
322 internal::DriverCommandManager::GetInstance().Finalize();
323 internal::DriverCommandManager::GetInstanceForTaskThread().Finalize();
324 s_IsInitializedDriverCommandManager = false;
325
326 s_IsInitialized = false;
327 }
328
IsInitialized()329 bool SoundSystem::IsInitialized()
330 {
331 return s_IsInitialized;
332 }
333
334 #if 0
335 /*---------------------------------------------------------------------------*
336 Name: WaitForResetReady
337
338 Description: リセット準備の完了を待つ
339
340 Arguments: 無し
341
342 Returns: 無し
343 *---------------------------------------------------------------------------*/
344 void SoundSystem::WaitForResetReady()
345 {
346 if ( ! s_IsInitialized ) return;
347
348 #ifdef NW_PLATFORM_CTRWIN
349 OSTick tick = OS_GetTick();
350 #else
351 nn::os::Tick tick = nn::os::Tick::GetSystemCurrent();
352 #endif
353
354 while( ! internal::driver::HardwareManager::GetInstance().IsResetReady() )
355 {
356 #ifdef NW_PLATFORM_CTRWIN
357 s64 seconds = OS_TicksToSeconds( OS_DiffTick( OS_GetTick(), tick ) );
358 #else
359 s64 seconds = static_cast<nn::fnd::TimeSpan>(
360 nn::os::Tick::GetSystemCurrent() - tick ).GetSeconds();
361 #endif
362 if ( seconds > 0 )
363 {
364 NW_WARNING( false, "SoundSystem::WaitForResetReady is TIME OUT.\n" );
365 break;
366 }
367 }
368 }
369 #endif
370
AppendEffect(AuxBus bus,FxBase * effect)371 bool SoundSystem::AppendEffect( AuxBus bus, FxBase* effect )
372 {
373 NW_NULL_ASSERT( effect );
374
375 if ( ! effect->Initialize() )
376 {
377 return false;
378 }
379
380 internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance();
381
382 internal::DriverCommandEffect* command =
383 cmdmgr.AllocCommand<internal::DriverCommandEffect>();
384 command->id = internal::DRIVER_COMMAND_APPEND_EFFECT;
385 command->bus = bus;
386 command->effect = effect;
387 cmdmgr.PushCommand(command);
388
389 return true;
390 }
391
ClearEffect(AuxBus bus,int fadeTimes)392 void SoundSystem::ClearEffect( AuxBus bus, int fadeTimes )
393 {
394 internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance();
395
396 internal::DriverCommandEffect* command =
397 cmdmgr.AllocCommand<internal::DriverCommandEffect>();
398 command->id = internal::DRIVER_COMMAND_CLEAR_EFFECT;
399 command->bus = bus;
400 command->fadeTimes = fadeTimes;
401 cmdmgr.PushCommand(command);
402
403 u32 tag = cmdmgr.FlushCommand( true );
404 cmdmgr.WaitCommandReply( tag );
405 }
406
407 #ifdef NW_SND_AVAILABLE_NN_EFFECT
AppendEffect(AuxBus bus,nn::snd::FxDelay * fxDelay)408 bool SoundSystem::AppendEffect( AuxBus bus, nn::snd::FxDelay* fxDelay )
409 {
410 internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance();
411
412 internal::DriverCommandEffectSdkDelay* command =
413 cmdmgr.AllocCommand<internal::DriverCommandEffectSdkDelay>();
414 command->id = internal::DRIVER_COMMAND_APPEND_EFFECT_SDK_DELAY;
415 command->bus = bus;
416 command->effect = fxDelay;
417 cmdmgr.PushCommand(command);
418
419 return true;
420 }
421
AppendEffect(AuxBus bus,nn::snd::FxReverb * fxReverb)422 bool SoundSystem::AppendEffect( AuxBus bus, nn::snd::FxReverb* fxReverb )
423 {
424 internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance();
425
426 internal::DriverCommandEffectSdkReverb* command =
427 cmdmgr.AllocCommand<internal::DriverCommandEffectSdkReverb>();
428 command->id = internal::DRIVER_COMMAND_APPEND_EFFECT_SDK_REVERB;
429 command->bus = bus;
430 command->effect = fxReverb;
431 cmdmgr.PushCommand(command);
432
433 return true;
434 }
435 #endif
436
437 } // namespace nw::snd
438 } // namespace nw
439
440