/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_SoundSystem.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. 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. $Revision: 29727 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #ifdef NW_PLATFORM_CTRWIN #include #include #endif #include #include #include #include #include #include namespace nw { namespace snd { internal::TaskThread SoundSystem::s_TaskThread; internal::ThreadStack SoundSystem::s_LoadThreadStack; bool SoundSystem::s_AutoCreateSoundThreadFlag = false; bool SoundSystem::s_IsInitialized = false; bool SoundSystem::s_IsStreamLoadWait = 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 = param.soundThreadCommandBufferSize + param.taskThreadCommandBufferSize + 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; } 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; } s_IsInitialized = true; bool result; NW_UNUSED_VARIABLE(result); // SDK 関連初期化 internal::driver::HardwareManager::GetInstance().Initialize(); 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 ); // 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 = s_TaskThread.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; } void SoundSystem::Finalize() { if ( ! s_IsInitialized ) { return; } // データロードスレッド終了 internal::TaskManager::GetInstance().CancelAllTask(); s_TaskThread.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_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 nn::snd::ClearEffect( static_cast(bus) ); #endif } #ifdef NW_SND_AVAILABLE_NN_EFFECT bool SoundSystem::AppendEffect( AuxBus bus, nn::snd::FxDelay* fxDelay ) { return nn::snd::SetEffect( static_cast(bus), fxDelay ); } bool SoundSystem::AppendEffect( AuxBus bus, nn::snd::FxReverb* fxReverb ) { return nn::snd::SetEffect( static_cast(bus), fxReverb ); } #endif } // namespace nw::snd } // namespace nw