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