1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_HardwareChannelManager.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: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #include "precompiled.h"
19 #include <nw/snd/snd_HardwareChannelManager.h>
20 #include <nw/snd/snd_HardwareChannel.h>
21 
22 #include <new>
23 
24 #include NW_SND_ADAPTIVE_SOURCE( HardwareChannelManager )
25 
26 namespace nw {
27 namespace snd {
28 namespace internal {
29 namespace driver {
30 
GetInstance()31 HardwareChannelManager& HardwareChannelManager::GetInstance()
32 {
33     static HardwareChannelManager instance;
34     return instance;
35 }
36 
HardwareChannelManager()37 HardwareChannelManager::HardwareChannelManager()
38 : m_IsInitialized( false )
39 {
40 }
41 
GetRequiredMemSize(int hardwareChannelCount)42 unsigned long HardwareChannelManager::GetRequiredMemSize( int hardwareChannelCount )
43 {
44     return sizeof( HardwareChannel )
45             * ( hardwareChannelCount + CHANNEL_COUNT_MARGIN );
46 }
47 
Initialize(void * mem,unsigned long memSize)48 void HardwareChannelManager::Initialize( void* mem, unsigned long memSize )
49 {
50     if ( m_IsInitialized ) return;
51 
52     OnInitialize();
53 
54     m_HardwareChannelCount = static_cast<int>( memSize / sizeof( HardwareChannel ) );
55 
56     u8* ptr = reinterpret_cast<u8*>( mem );
57 
58     for ( int i = 0; i < m_HardwareChannelCount; i++ )
59     {
60         m_FreeList.PushBack( new( ptr ) HardwareChannel() );
61         ptr += sizeof( HardwareChannel );
62     }
63     NW_ASSERT( ptr <= reinterpret_cast<u8*>( mem ) + memSize );
64     m_IsInitialized = true;
65 
66     return;
67 }
68 
Finalize()69 void HardwareChannelManager::Finalize()
70 {
71     if ( ! m_IsInitialized ) return;
72 
73     // 全てのボイスを止める
74     while ( ! m_ActiveList.IsEmpty() )
75     {
76         HardwareChannel& channel = m_ActiveList.GetFront();
77         m_ActiveList.PopFront();
78         if ( channel.IsAvailable() )
79         {
80             channel.Stop();
81             if ( channel.m_Callback != NULL )
82             {
83                 channel.m_Callback(
84                     &channel,
85                     HardwareChannel::CALLBACK_STATUS_CANCEL,
86                     channel.m_pCallbackData
87                 );
88             }
89             FreeHardwareChannel( &channel );
90         }
91     }
92 
93     // TODO: コード整理(コードの重複)
94     while ( ! m_FreeReservedList.IsEmpty() )
95     {
96         HardwareChannel& channel = m_FreeReservedList.GetFront();
97         m_ActiveList.PopFront();
98         if ( channel.IsAvailable() )
99         {
100             channel.Stop();
101             if ( channel.m_Callback != NULL )
102             {
103                 channel.m_Callback(
104                     &channel,
105                     HardwareChannel::CALLBACK_STATUS_CANCEL,
106                     channel.m_pCallbackData
107                 );
108             }
109             FreeHardwareChannel( &channel );
110         }
111     }
112 
113     // ボイスをリストから削除
114     while ( ! m_FreeList.IsEmpty() )
115     {
116         HardwareChannel& voice = m_FreeList.GetFront();
117         m_FreeList.PopFront();
118         voice.~HardwareChannel(); // デストラクタ呼び出し
119     }
120 
121     m_IsInitialized = false;
122 }
123 
ReserveForFreeHardwareChannel(HardwareChannel * pChannel)124 void HardwareChannelManager::ReserveForFreeHardwareChannel( HardwareChannel* pChannel )
125 {
126     NW_NULL_ASSERT( pChannel );
127     pChannel->m_IsReserveForFree = true;
128     ReserveForFree( pChannel );
129 }
130 
FreeAllReservedHardwareChannel()131 void HardwareChannelManager::FreeAllReservedHardwareChannel()
132 {
133     while ( !m_FreeReservedList.IsEmpty() )
134     {
135         HardwareChannel& channel = m_FreeReservedList.GetFront();
136 
137         if ( channel.m_Callback != NULL )
138         {
139             channel.m_Callback(
140                 &channel,
141                 HardwareChannel::CALLBACK_STATUS_DROP_DSP,
142                 channel.m_pCallbackData
143             );
144         }
145 
146         HardwareChannelManager::GetInstance().FreeHardwareChannel( &channel );
147     }
148 }
149 
150 // TODO-continue: アロックできない
Alloc()151 HardwareChannel* HardwareChannelManager::Alloc()
152 {
153     // HardwareChannel インスタンスの枯渇をさけるため、
154     // 解放予約ボイスの解放処理を行う
155     // 割り込み禁止期間が長くなるが、やむを得ない
156     FreeAllReservedHardwareChannel();
157 
158     if ( m_FreeList.IsEmpty() )
159     {
160         return NULL;
161     }
162 
163     HardwareChannel* ptr = &m_FreeList.GetFront();
164     m_FreeList.PopFront();
165 
166     // コンストラクタ呼び出し
167     HardwareChannel* pChannel = new( ptr )HardwareChannel();
168     m_ActiveList.PushBack( ptr );
169 
170     return pChannel;
171 }
172 
Free(HardwareChannel * pChannel)173 void HardwareChannelManager::Free( HardwareChannel* pChannel )
174 {
175     NW_NULL_ASSERT( pChannel );
176 
177     pChannel->~HardwareChannel();
178 
179     {
180         if ( pChannel->m_IsReserveForFree )
181         {
182             m_FreeReservedList.Erase( pChannel );
183         }
184         else
185         {
186             m_ActiveList.Erase( pChannel );
187         }
188         m_FreeList.PushBack( pChannel );
189     }
190 }
191 
ReserveForFree(HardwareChannel * pChannel)192 void HardwareChannelManager::ReserveForFree( HardwareChannel* pChannel )
193 {
194     NW_ASSERT( pChannel );
195 
196     m_ActiveList.Erase( pChannel );
197     m_FreeReservedList.PushBack( pChannel );
198 }
199 
200 } // namespace nw::snd::internal::driver
201 } // namespace nw::snd::internal
202 } // namespace nw::snd
203 } // namespace nw
204