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