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