/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_SoundSystem.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 32385 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #ifdef NW_PLATFORM_CTRWIN #include #include #endif #include #include #include #include #include #include namespace nw { namespace snd { internal::ThreadStack SoundSystem::s_LoadThreadStack; bool SoundSystem::s_AutoCreateSoundThreadFlag = false; bool SoundSystem::s_IsInitialized = false; bool SoundSystem::s_IsStreamLoadWait = false; bool SoundSystem::s_IsEnterSleep = false; bool SoundSystem::s_IsInitializedDriverCommandManager = false; #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD ) // このバージョンからサウンドスレッド用の ThreadStack は不要 #else internal::ThreadStack SoundSystem::s_SoundThreadStack; #endif int SoundSystem::s_MaxVoiceCount = NN_SND_VOICE_NUM; size_t SoundSystem::GetRequiredMemSize( const SoundSystemParam& param ) { NW_ASSERT( param.soundThreadStackSize % 8 == 0 ); NW_ASSERT( param.taskThreadStackSize % 8 == 0 ); NW_MINMAX_ASSERT( param.soundThreadCoreNo, 0, 1 ); size_t result = detail_GetRequiredDriverCommandManagerMemSize( param ) + param.taskThreadStackSize #ifdef NW_PLATFORM_CTRWIN + internal::driver::HardwareChannelManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount ) #endif + internal::driver::VoiceManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount ) + internal::driver::ChannelManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount ); if ( param.autoCreateSoundThread == true ) { result += param.soundThreadStackSize; } #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD ) if ( param.soundThreadCoreNo == 1 ) { // nn::snd::StartUserSoundThread 用のスタックサイズは、StartSoundThread と同じとする result += param.soundThreadStackSize; } #endif return result; } size_t SoundSystem::detail_GetRequiredDriverCommandManagerMemSize( const SoundSystemParam& param ) { NW_ASSERT( param.soundThreadCommandBufferSize % 4 == 0 ); NW_ASSERT( param.taskThreadCommandBufferSize % 4 == 0 ); size_t result = param.soundThreadCommandBufferSize + param.taskThreadCommandBufferSize; return result; } void SoundSystem::detail_InitializeDriverCommandManager( const SoundSystemParam& param, uptr workMem, size_t workMemSize ) { if ( s_IsInitializedDriverCommandManager ) { return; } NW_UNUSED_VARIABLE( workMemSize ); NW_ASSERTMSG( workMemSize >= detail_GetRequiredDriverCommandManagerMemSize( param ), "workMemSize(%X) >= RequiredMemSize(%X)", workMemSize, detail_GetRequiredDriverCommandManagerMemSize( param ) ); uptr ptr = workMem; // コマンドバッファ初期化 uptr soundThreadCommandBufferPtr = ptr; ptr += param.soundThreadCommandBufferSize; uptr taskThreadCommandBufferPtr = ptr; ptr += param.taskThreadCommandBufferSize; internal::DriverCommandManager::GetInstance().Initialize( reinterpret_cast( soundThreadCommandBufferPtr ), param.soundThreadCommandBufferSize ); internal::DriverCommandManager::GetInstanceForTaskThread().Initialize( reinterpret_cast( taskThreadCommandBufferPtr ), param.taskThreadCommandBufferSize ); s_IsInitializedDriverCommandManager = true; } void SoundSystem::Initialize( const SoundSystemParam& param, uptr workMem, size_t workMemSize ) { NW_UNUSED_VARIABLE( workMemSize ); NW_ASSERTMSG( workMemSize >= GetRequiredMemSize( param ), "workMemSize(%X) >= RequiredMemSize(%X)", workMemSize, GetRequiredMemSize( param ) ); NW_MINMAX_ASSERT( param.soundThreadCoreNo, 0, 1 ); // 多重初期化チェック if ( s_IsInitialized ) { return; } bool result; NW_UNUSED_VARIABLE(result); // SDK 関連初期化 internal::driver::HardwareManager::GetInstance().Initialize(); uptr ptr = workMem; if ( s_IsInitializedDriverCommandManager == false ) { size_t workMemSizeForDriverCommandManager = detail_GetRequiredDriverCommandManagerMemSize( param ); detail_InitializeDriverCommandManager( param, ptr, workMemSizeForDriverCommandManager ); ptr += workMemSizeForDriverCommandManager; } // nw::snd サウンドスレッドの準備 uptr soundThreadStackPtr = NULL; #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD ) uptr userSoundThreadStackPtr = NULL; if ( param.autoCreateSoundThread ) { soundThreadStackPtr = ptr; ptr += param.soundThreadStackSize; if ( param.soundThreadCoreNo == 1 ) { userSoundThreadStackPtr = ptr; ptr += param.soundThreadStackSize; // 通常サウンドスレッドのスタックサイズを流用 } } #else if ( param.autoCreateSoundThread ) { soundThreadStackPtr = ptr; ptr += param.soundThreadStackSize; s_SoundThreadStack.Initialize( soundThreadStackPtr, param.soundThreadStackSize ); } #endif internal::driver::SoundThread::GetInstance().Initialize(); // nw::snd サウンドデータロードスレッドの準備 uptr loadThreadStackPtr = ptr; ptr += param.taskThreadStackSize; internal::TaskManager::GetInstance().Initialize(); s_LoadThreadStack.Initialize( loadThreadStackPtr, param.taskThreadStackSize ); #ifdef NW_PLATFORM_CTRWIN // HardwareChannelManager初期化 uptr axVoiceWork = ptr; ptr += internal::driver::HardwareChannelManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount ); internal::driver::HardwareChannelManager::GetInstance().Initialize( reinterpret_cast( axVoiceWork ), internal::driver::HardwareChannelManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount ) ); #endif // VoiceManager初期化 uptr voiceWork = ptr; ptr += internal::driver::VoiceManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount ); internal::driver::VoiceManager::GetInstance().Initialize( reinterpret_cast( voiceWork ), internal::driver::VoiceManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount ) ); // ChannelManager初期化 uptr channelWork = ptr; ptr += internal::driver::ChannelManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount ); internal::driver::ChannelManager::GetInstance().Initialize( reinterpret_cast( channelWork ), internal::driver::ChannelManager::GetInstance().GetRequiredMemSize( s_MaxVoiceCount ) ); NW_ASSERT( ptr <= workMem + workMemSize ); // SequenceSoundPlayer初期化 internal::driver::SequenceSoundPlayer::InitSequenceSoundPlayer(); // データロードスレッド起動 result = internal::TaskThread::GetInstance().Create( param.taskThreadPriority, s_LoadThreadStack ); NW_ASSERT( result ); // サウンドスレッド起動 if ( param.autoCreateSoundThread ) { #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD ) #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD2 ) result = internal::driver::SoundThread::GetInstance().CreateSoundThread( soundThreadStackPtr, param.soundThreadStackSize, param.soundThreadPriority, userSoundThreadStackPtr, param.soundThreadStackSize, param.soundThreadPriority, param.soundThreadCoreNo, param.enableGetSoundThreadTick ); NW_ASSERT( result ); #else result = internal::driver::SoundThread::GetInstance().CreateSoundThread( soundThreadStackPtr, param.soundThreadStackSize, param.soundThreadPriority, param.soundThreadCoreNo, param.enableGetSoundThreadTick ); NW_ASSERT( result ); if ( param.soundThreadCoreNo == 1 ) { result = internal::driver::SoundThread::GetInstance().CreateUserSoundThread( userSoundThreadStackPtr, param.soundThreadStackSize, // StartSoundThread と同じスタックサイズとする param.soundThreadPriority ); // StartSoundThread の優先度を流用する NW_ASSERT( result ); } #endif #else result = internal::driver::SoundThread::GetInstance().Create( param.soundThreadPriority, s_SoundThreadStack, param.soundThreadCoreNo, param.enableGetSoundThreadTick ); NW_ASSERT( result ); #endif } s_AutoCreateSoundThreadFlag = param.autoCreateSoundThread; s_IsInitialized = true; } void SoundSystem::Finalize() { if ( ! s_IsInitialized ) { return; } // データロードスレッド終了 internal::TaskManager::GetInstance().CancelAllTask(); internal::TaskThread::GetInstance().Destroy(); internal::TaskManager::GetInstance().Finalize(); // サウンドスレッド停止 internal::driver::SoundThread::GetInstance().Destroy(); // 各種マネージャー破棄 internal::driver::ChannelManager::GetInstance().Finalize(); internal::driver::VoiceManager::GetInstance().Finalize(); #ifdef NW_PLATFORM_CTRWIN internal::driver::HardwareChannelManager::GetInstance().Finalize(); #endif internal::driver::HardwareManager::GetInstance().Finalize(); #if defined( NW_SND_AVAILABLE_NN_SND_STARTSOUNDTHREAD ) // なにもしない #else s_SoundThreadStack.Finalize(); #endif s_LoadThreadStack.Finalize(); // サウンドスレッド終了 internal::driver::SoundThread::GetInstance().Finalize(); internal::DriverCommandManager::GetInstance().Finalize(); internal::DriverCommandManager::GetInstanceForTaskThread().Finalize(); s_IsInitializedDriverCommandManager = false; s_IsInitialized = false; } bool SoundSystem::IsInitialized() { return s_IsInitialized; } #if 0 /*---------------------------------------------------------------------------* Name: WaitForResetReady Description: リセット準備の完了を待つ Arguments: 無し Returns: 無し *---------------------------------------------------------------------------*/ void SoundSystem::WaitForResetReady() { if ( ! s_IsInitialized ) return; #ifdef NW_PLATFORM_CTRWIN OSTick tick = OS_GetTick(); #else nn::os::Tick tick = nn::os::Tick::GetSystemCurrent(); #endif while( ! internal::driver::HardwareManager::GetInstance().IsResetReady() ) { #ifdef NW_PLATFORM_CTRWIN s64 seconds = OS_TicksToSeconds( OS_DiffTick( OS_GetTick(), tick ) ); #else s64 seconds = static_cast( nn::os::Tick::GetSystemCurrent() - tick ).GetSeconds(); #endif if ( seconds > 0 ) { NW_WARNING( false, "SoundSystem::WaitForResetReady is TIME OUT.\n" ); break; } } } #endif bool SoundSystem::AppendEffect( AuxBus bus, FxBase* effect ) { NW_NULL_ASSERT( effect ); if ( ! effect->Initialize() ) { return false; } internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance(); internal::DriverCommandEffect* command = cmdmgr.AllocCommand(); command->id = internal::DRIVER_COMMAND_APPEND_EFFECT; command->bus = bus; command->effect = effect; cmdmgr.PushCommand(command); return true; } void SoundSystem::ClearEffect( AuxBus bus, int fadeTimes ) { internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance(); internal::DriverCommandEffect* command = cmdmgr.AllocCommand(); command->id = internal::DRIVER_COMMAND_CLEAR_EFFECT; command->bus = bus; command->fadeTimes = fadeTimes; cmdmgr.PushCommand(command); u32 tag = cmdmgr.FlushCommand( true ); cmdmgr.WaitCommandReply( tag ); } #ifdef NW_SND_AVAILABLE_NN_EFFECT bool SoundSystem::AppendEffect( AuxBus bus, nn::snd::FxDelay* fxDelay ) { internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance(); internal::DriverCommandEffectSdkDelay* command = cmdmgr.AllocCommand(); command->id = internal::DRIVER_COMMAND_APPEND_EFFECT_SDK_DELAY; command->bus = bus; command->effect = fxDelay; cmdmgr.PushCommand(command); return true; } bool SoundSystem::AppendEffect( AuxBus bus, nn::snd::FxReverb* fxReverb ) { internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance(); internal::DriverCommandEffectSdkReverb* command = cmdmgr.AllocCommand(); command->id = internal::DRIVER_COMMAND_APPEND_EFFECT_SDK_REVERB; command->bus = bus; command->effect = fxReverb; cmdmgr.PushCommand(command); return true; } #endif } // namespace nw::snd } // namespace nw