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