/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_HardwareChannelManager.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: 19566 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include NW_SND_ADAPTIVE_SOURCE( HardwareChannelManager ) namespace nw { namespace snd { namespace internal { namespace driver { HardwareChannelManager& HardwareChannelManager::GetInstance() { static HardwareChannelManager instance; return instance; } HardwareChannelManager::HardwareChannelManager() : m_IsInitialized( false ) { } unsigned long HardwareChannelManager::GetRequiredMemSize( int hardwareChannelCount ) { return sizeof( HardwareChannel ) * ( hardwareChannelCount + CHANNEL_COUNT_MARGIN ); } void HardwareChannelManager::Initialize( void* mem, unsigned long memSize ) { if ( m_IsInitialized ) return; OnInitialize(); m_HardwareChannelCount = static_cast( memSize / sizeof( HardwareChannel ) ); u8* ptr = reinterpret_cast( mem ); for ( int i = 0; i < m_HardwareChannelCount; i++ ) { m_FreeList.PushBack( new( ptr ) HardwareChannel() ); ptr += sizeof( HardwareChannel ); } NW_ASSERT( ptr <= reinterpret_cast( mem ) + memSize ); m_IsInitialized = true; return; } void HardwareChannelManager::Finalize() { if ( ! m_IsInitialized ) return; // 全てのボイスを止める while ( ! m_ActiveList.IsEmpty() ) { HardwareChannel& channel = m_ActiveList.GetFront(); m_ActiveList.PopFront(); if ( channel.IsAvailable() ) { channel.Stop(); if ( channel.m_Callback != NULL ) { channel.m_Callback( &channel, HardwareChannel::CALLBACK_STATUS_CANCEL, channel.m_pCallbackData ); } FreeHardwareChannel( &channel ); } } // TODO: コード整理(コードの重複) while ( ! m_FreeReservedList.IsEmpty() ) { HardwareChannel& channel = m_FreeReservedList.GetFront(); m_ActiveList.PopFront(); if ( channel.IsAvailable() ) { channel.Stop(); if ( channel.m_Callback != NULL ) { channel.m_Callback( &channel, HardwareChannel::CALLBACK_STATUS_CANCEL, channel.m_pCallbackData ); } FreeHardwareChannel( &channel ); } } // ボイスをリストから削除 while ( ! m_FreeList.IsEmpty() ) { HardwareChannel& voice = m_FreeList.GetFront(); m_FreeList.PopFront(); voice.~HardwareChannel(); // デストラクタ呼び出し } m_IsInitialized = false; } void HardwareChannelManager::ReserveForFreeHardwareChannel( HardwareChannel* pChannel ) { NW_NULL_ASSERT( pChannel ); pChannel->m_IsReserveForFree = true; ReserveForFree( pChannel ); } void HardwareChannelManager::FreeAllReservedHardwareChannel() { while ( !m_FreeReservedList.IsEmpty() ) { HardwareChannel& channel = m_FreeReservedList.GetFront(); if ( channel.m_Callback != NULL ) { channel.m_Callback( &channel, HardwareChannel::CALLBACK_STATUS_DROP_DSP, channel.m_pCallbackData ); } HardwareChannelManager::GetInstance().FreeHardwareChannel( &channel ); } } // TODO-continue: アロックできない HardwareChannel* HardwareChannelManager::Alloc() { // HardwareChannel インスタンスの枯渇をさけるため、 // 解放予約ボイスの解放処理を行う // 割り込み禁止期間が長くなるが、やむを得ない FreeAllReservedHardwareChannel(); if ( m_FreeList.IsEmpty() ) { return NULL; } HardwareChannel* ptr = &m_FreeList.GetFront(); m_FreeList.PopFront(); // コンストラクタ呼び出し HardwareChannel* pChannel = new( ptr )HardwareChannel(); m_ActiveList.PushBack( ptr ); return pChannel; } void HardwareChannelManager::Free( HardwareChannel* pChannel ) { NW_NULL_ASSERT( pChannel ); pChannel->~HardwareChannel(); { if ( pChannel->m_IsReserveForFree ) { m_FreeReservedList.Erase( pChannel ); } else { m_ActiveList.Erase( pChannel ); } m_FreeList.PushBack( pChannel ); } } void HardwareChannelManager::ReserveForFree( HardwareChannel* pChannel ) { NW_ASSERT( pChannel ); m_ActiveList.Erase( pChannel ); m_FreeReservedList.PushBack( pChannel ); } } // namespace nw::snd::internal::driver } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw