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: 29726 $
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