1/*---------------------------------------------------------------------------*
2  Project:  NintendoWare
3  File:     snd_HardwareManagerAX.cppi
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: $
16 *---------------------------------------------------------------------------*/
17
18#include "precompiled.h"
19
20#include <nw/snd/snd_HardwareManager.h>
21
22namespace nw {
23namespace snd {
24namespace internal {
25namespace driver {
26
27namespace
28{
29NN_ATTRIBUTE_ALIGN(32) u8 s_ZeroBuffer[ HardwareManager::ZERO_BUFFER_SIZE ];
30const u16 AUX_RETURN_VOLUME_MAX = 0x8000;
31}
32
33//
34// 関数
35//
36/*---------------------------------------------------------------------------*
37    Name:           HardwareManager
38
39    Description:    コンストラクタ
40
41    Arguments:      なし
42
43    Returns:        なし
44 *---------------------------------------------------------------------------*/
45HardwareManager::HardwareManager()
46: m_IsInitialized( false ),
47//  m_UpdateVoicePrioFlag( true ),
48  m_pZeroBufferAddress( NULL ),
49  m_OldAidCallback( NULL ),
50  m_ResetReadyCounter( -1 ),
51  m_OutputMode( OUTPUT_MODE_STEREO ),
52  m_SrcType( SRC_TYPE_4TAP )
53{
54    m_MasterVolume.InitValue( 1.0f );
55    m_VolumeForReset.InitValue( 1.0f );
56
57    for ( int i=0; i<AUX_BUS_NUM; i++ )
58    {
59        m_AuxFadeVolume[ i ].InitValue( 1.0f );
60        m_AuxUserVolume[ i ].InitValue( 1.0f );
61        m_AuxCallback[ i ] = NULL;
62        m_AuxCallbackContext[ i ] = NULL;
63        m_EffectProcessTick[ i ] = 0;
64    }
65}
66
67void* HardwareManager::GetZeroBufferAddress()
68{
69    NW_ASSERTMSG( m_pZeroBufferAddress, "Zero buffer is not created." );
70    return m_pZeroBufferAddress;
71}
72
73void HardwareManager::Initialize()
74{
75    if ( m_IsInitialized ) return;
76
77    // TODO: NW_ASSERTMSG( AI_CheckInit(), "not initialized AI\n" );
78
79    // ゼロバッファ作成
80    (void)std::memset( s_ZeroBuffer, 0, ZERO_BUFFER_SIZE );
81    // TODO: DCFlushRange( s_ZeroBuffer, ZERO_BUFFER_SIZE );
82    m_pZeroBufferAddress = s_ZeroBuffer;
83
84    // AUXコールバック設定
85    // 既に登録されているAUXコールバックを保存する
86    AX_GetAuxACallback( &m_AuxCallback[ AUX_BUS_A ], &m_AuxCallbackContext[ AUX_BUS_A ] );
87    AX_GetAuxBCallback( &m_AuxCallback[ AUX_BUS_B ], &m_AuxCallbackContext[ AUX_BUS_B ] );
88
89    // AXコールバック設定(既に登録されているAXコールバックがあれば保存する)
90    m_PreRegisteredCallback = AX_RegisterCallback( &AxCallbackFunc );
91
92#if 0 // BIQUAD
93    // biquadフィルタテーブル初期化
94    (void)std::memset( sBiquadFilterCallbackTable, 0, sizeof( sBiquadFilterCallbackTable ) );
95    SetBiquadFilterCallback( BIQUAD_FILTER_TYPE_LPF, &sBiquadFilterLpf );
96    SetBiquadFilterCallback( BIQUAD_FILTER_TYPE_HPF, &sBiquadFilterHpf );
97    SetBiquadFilterCallback( BIQUAD_FILTER_TYPE_BPF512, &sBiquadFilterBpf512 );
98    SetBiquadFilterCallback( BIQUAD_FILTER_TYPE_BPF1024, &sBiquadFilterBpf1024 );
99    SetBiquadFilterCallback( BIQUAD_FILTER_TYPE_BPF2048, &sBiquadFilterBpf2048 );
100#endif
101
102    m_IsInitialized = true;
103    m_OutputMode    = OUTPUT_MODE_STEREO;
104}
105
106void HardwareManager::Finalize()
107{
108    if ( !m_IsInitialized ) return;
109
110    // AXコールバックを元に戻す
111    (void)AX_RegisterCallback( m_PreRegisteredCallback );
112
113    // エフェクトクリア
114    for ( int bus = AUX_BUS_A; bus < AUX_BUS_NUM; bus++ )
115    {
116        FinalizeEffect( static_cast<AuxBus>( bus ) );
117    }
118
119    // AXのコールバックを元に戻す
120    AX_RegisterAuxACallback( m_AuxCallback[ AUX_BUS_A ], m_AuxCallbackContext[ AUX_BUS_A ] );
121    AX_RegisterAuxBCallback( m_AuxCallback[ AUX_BUS_B ], m_AuxCallbackContext[ AUX_BUS_B ] );
122    for ( int i=0; i<AUX_BUS_NUM; i++ )
123    {
124        m_AuxCallback[ i ] = NULL;
125        m_AuxCallbackContext[ i ] = NULL;
126    }
127
128    // ゼロバッファへの参照をクリア
129    m_pZeroBufferAddress = NULL;
130
131    m_IsInitialized = false;
132}
133
134void HardwareManager::Update()
135{
136    // ClearEffect のフェード処理。フェードが完了したらエフェクトをクリア
137    for ( int i=0; i<AUX_BUS_NUM; i++ )
138    {
139        bool updateFlag = false;
140        if ( ! m_AuxUserVolume[ i ].IsFinished() )
141        {
142            m_AuxUserVolume[ i ].Update();
143            updateFlag = true;
144        }
145        if ( ! m_AuxFadeVolume[ i ].IsFinished() )
146        {
147            m_AuxFadeVolume[ i ].Update();
148            if ( m_AuxFadeVolume[ i ].IsFinished() )
149            {
150                FinalizeEffect( static_cast<AuxBus>( i ) );
151            }
152            updateFlag = true;
153        }
154
155        if ( updateFlag )
156        {
157            float returnVolumeFloat = 1.0f;
158            returnVolumeFloat *= ut::Clamp( m_AuxUserVolume[ i ].GetValue(), 0.0f, 1.0f );
159            returnVolumeFloat *= ut::Clamp( m_AuxFadeVolume[ i ].GetValue(), 0.0f, 1.0f );
160            u16 returnVolume = static_cast<u16>( returnVolumeFloat * AUX_RETURN_VOLUME_MAX );
161            switch ( i )
162            {
163            case AUX_BUS_A:
164                AX_SetAuxAReturnVolume( returnVolume );
165                break;
166            case AUX_BUS_B:
167                AX_SetAuxBReturnVolume( returnVolume );
168                break;
169            }
170        }
171    }
172
173    // 音量のアップデート
174    if ( ! m_MasterVolume.IsFinished() ) {
175        m_MasterVolume.Update();
176        VoiceManager::GetInstance().UpdateAllVoicesSync( Voice::UPDATE_VE );
177    }
178
179    if ( ! m_VolumeForReset.IsFinished() ) {
180        m_VolumeForReset.Update();
181        VoiceManager::GetInstance().UpdateAllVoicesSync( Voice::UPDATE_VE );
182    }
183
184    {
185        f32 volume = 1.0f;
186        volume *= m_VolumeForReset.GetValue();
187
188        volume = ut::Clamp( volume, 0.0f, 1.0f );
189
190        AX_SetMasterVolume( static_cast<u16>(volume * 0x8000) );
191    }
192}
193    // RVL は計96ch中、マージン16だった
194
195u32 HardwareManager::GetChannelCount() const
196{
197    return AX_GetMaxVoices();
198}
199
200/* ========================================================================
201        リセット前準備
202   ======================================================================== */
203
204void HardwareManager::PrepareReset()
205{
206    if ( m_OldAidCallback != NULL ) return;
207
208    m_VolumeForReset.SetTarget( 0.0f, 3 ); // 3オーディオフレームかけてフェードアウト
209    m_ResetReadyCounter = -1;
210    m_OldAidCallback = ::AI_RegisterDMACallback( AiDmaCallbackFunc );
211}
212
213void HardwareManager::AiDmaCallbackFunc()
214{
215    GetInstance().PrepareResetProc();
216}
217
218void HardwareManager::PrepareResetProc()
219{
220    static bool finishedFlag = false;
221    m_OldAidCallback();
222
223    if ( finishedFlag )
224    {
225        if ( m_ResetReadyCounter < 0 )
226        {
227            AX_SetMaxDspCycles( 0 );
228            m_ResetReadyCounter = 6;
229        }
230    }
231    else if ( m_VolumeForReset.GetValue() == 0.0f )
232    {
233        finishedFlag = true;
234    }
235
236    if ( m_ResetReadyCounter > 0 ) --m_ResetReadyCounter;
237}
238
239bool HardwareManager::IsResetReady() const
240{
241    return m_ResetReadyCounter == 0 ? true : false;
242}
243
244void HardwareManager::AxCallbackFunc()
245{
246    // ユーザーコールバックの呼び出し
247    HardwareCallbackFunc();
248
249    // もともと設定されていたコールバックの呼び出し
250    AXUserCallback callback = GetInstance().m_PreRegisteredCallback;
251    if ( callback != NULL )
252    {
253        callback();
254    }
255}
256
257/*---------------------------------------------------------------------------*
258    Name:           AxCallbackFunc
259
260    Description:    AXコールバックに登録される関数
261
262    Arguments:      なし
263
264    Returns:        なし
265 *---------------------------------------------------------------------------*/
266void HardwareManager::HardwareCallbackFunc()
267{
268    for ( CallbackList::Iterator itr = GetInstance().m_CallbackList.GetBeginIter();
269          itr != GetInstance().m_CallbackList.GetEndIter();
270        )
271    {
272        CallbackList::Iterator curItr = itr++;
273        curItr->callback();
274    }
275}
276
277/*---------------------------------------------------------------------------*
278    Name:           RegisterAxCallback
279
280    Description:    AXコールバックの登録をリストに追加する
281
282    Arguments:      node: AXコールバックリストのノード
283                    callback: AXコールバック関数
284
285    Returns:
286 *---------------------------------------------------------------------------*/
287void HardwareManager::RegisterCallback(
288        CallbackListNode* node,
289        HardwareCallback callback )
290{
291    node->callback = callback;
292    m_CallbackList.PushBack( node );
293}
294
295/*---------------------------------------------------------------------------*
296    Name:           UnregisterAxCallback
297
298    Description:    AXコールバックの登録をリストから削除する
299
300    Arguments:      node: AXコールバックリストのノード
301
302    Returns:
303 *---------------------------------------------------------------------------*/
304void HardwareManager::UnregisterCallback( CallbackListNode* node )
305{
306    m_CallbackList.Erase( node );
307}
308
309} /* namespace nw::snd::internal::driver */
310} /* namespace nw::snd::internal */
311} /* namespace nw::snd */
312} /* namespace nw */
313