1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_HardwareManager.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: 28272 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 #include <nw/snd/snd_HardwareManager.h>
18 
19 #include <nw/snd/snd_VoiceManager.h>
20 #include <nw/assert.h>
21 #include <cstring>
22 
23 #include NW_SND_ADAPTIVE_SOURCE( HardwareManager )
24 
25 namespace nw {
26 namespace snd {
27 namespace internal {
28 namespace driver {
29 
30 const BiquadFilterLpf     HardwareManager::BIQUAD_FILTER_LPF;
31 const BiquadFilterHpf     HardwareManager::BIQUAD_FILTER_HPF;
32 const BiquadFilterBpf512  HardwareManager::BIQUAD_FILTER_BPF_512;
33 const BiquadFilterBpf1024 HardwareManager::BIQUAD_FILTER_BPF_1024;
34 const BiquadFilterBpf2048 HardwareManager::BIQUAD_FILTER_BPF_2048;
35 
SetOutputMode(OutputMode mode)36 void HardwareManager::SetOutputMode( OutputMode mode )
37 {
38     if ( m_OutputMode == mode ) return;
39 
40     m_OutputMode = mode;
41 
42 #ifdef NW_PLATFORM_CTR
43     switch ( mode )
44     {
45     case OUTPUT_MODE_MONO:
46         nn::snd::SetSoundOutputMode( nn::snd::OUTPUT_MODE_MONO );
47         break;
48     case OUTPUT_MODE_STEREO:
49         nn::snd::SetSoundOutputMode( nn::snd::OUTPUT_MODE_STEREO );
50         break;
51     case OUTPUT_MODE_SURROUND:
52         nn::snd::SetSoundOutputMode( nn::snd::OUTPUT_MODE_3DSURROUND );
53         break;
54     default:
55         NW_ASSERT( false );
56         break;
57     }
58 #endif
59 
60     // コマンドを投げる
61     {
62         DriverCommandManager& cmdmgr = DriverCommandManager::GetInstance();
63         DriverCommandAllVoicesSync* command =
64             cmdmgr.AllocCommand<DriverCommandAllVoicesSync>();
65         command->id = DRIVER_COMMAND_ALLVOICES_SYNC;
66         command->syncFlag = Voice::UPDATE_MIX;
67         cmdmgr.PushCommand(command);
68     }
69 
70     // エフェクトの出力モード変更処理
71     for ( int bus = 0; bus < AUX_BUS_NUM; bus++ )
72     {
73         FxList& list = GetEffectList( static_cast<AuxBus>( bus ) );
74         for ( FxList::Iterator itr = list.GetBeginIter();
75               itr != list.GetEndIter();
76               ++itr )
77         {
78             itr->OnChangeOutputMode();
79         }
80     }
81 }
82 
GetOutputVolume() const83 f32 HardwareManager::GetOutputVolume() const
84 {
85     f32 volume = m_MasterVolume.GetValue();
86     volume *= m_VolumeForReset.GetValue();
87     return volume;
88 }
89 
SetMasterVolume(float volume,int fadeTimes)90 void HardwareManager::SetMasterVolume( float volume, int fadeTimes )
91 {
92     if ( volume < 0.0f ) volume = 0.0f;
93     m_MasterVolume.SetTarget(
94         volume,
95         ( fadeTimes + HardwareManager::SOUND_FRAME_INTERVAL_MSEC - 1 )
96         / SOUND_FRAME_INTERVAL_MSEC
97     );
98 
99     if ( fadeTimes == 0 )
100     {
101         // コマンドを投げる
102         DriverCommandManager& cmdmgr = DriverCommandManager::GetInstance();
103         DriverCommandAllVoicesSync* command =
104             cmdmgr.AllocCommand<DriverCommandAllVoicesSync>();
105         command->id = DRIVER_COMMAND_ALLVOICES_SYNC;
106         command->syncFlag = Voice::UPDATE_VE;
107         cmdmgr.PushCommand(command);
108     }
109 }
110 
111 /* ========================================================================
112         SRC タイプ
113    ======================================================================== */
114 
115 /*---------------------------------------------------------------------------*
116     Name:           SetSrcType
117 
118     Description:    SRC タイプを変更する
119 
120     Arguments:      type: SRC タイプ
121 
122     Returns:        なし
123  *---------------------------------------------------------------------------*/
SetSrcType(SrcType type)124 void HardwareManager::SetSrcType( SrcType type )
125 {
126     if ( m_SrcType == type ) return;
127 
128     m_SrcType = type;
129 
130     // コマンドを投げる
131     {
132         DriverCommandManager& cmdmgr = DriverCommandManager::GetInstance();
133         DriverCommandAllVoicesSync* command =
134             cmdmgr.AllocCommand<DriverCommandAllVoicesSync>();
135         command->id = DRIVER_COMMAND_ALLVOICES_SYNC;
136         command->syncFlag = Voice::UPDATE_SRC;
137         cmdmgr.PushCommand(command);
138     }
139 }
140 
141 /* ========================================================================
142         エフェクト
143    ======================================================================== */
144 
AppendEffect(AuxBus bus,FxBase * pFx)145 bool HardwareManager::AppendEffect( AuxBus bus, FxBase* pFx )
146 {
147     NW_NULL_ASSERT( pFx );
148 
149     if ( ! m_AuxFadeVolume[ bus ].IsFinished() )
150     {
151         FinalizeEffect( bus );
152     }
153 
154     m_AuxFadeVolume[ bus ].SetTarget( 1.0f, 0 );
155 #ifdef NW_PLATFORM_CTRWIN
156     switch ( bus )
157     {
158     case AUX_BUS_A:
159         AX_SetAuxAReturnVolume( AUX_RETURN_VOLUME_MAX );
160         break;
161     case AUX_BUS_B:
162         AX_SetAuxBReturnVolume( AUX_RETURN_VOLUME_MAX );
163         break;
164     }
165 #else
166     nn::snd::SetAuxReturnVolume( static_cast<nn::snd::AuxBusId>(bus), AUX_RETURN_VOLUME_MAX );
167 #endif
168 
169     if ( GetEffectList( bus ).IsEmpty() )
170     {
171 #ifdef NW_PLATFORM_CTRWIN
172         switch ( bus )
173         {
174         case AUX_BUS_A:
175             AX_RegisterAuxACallback( AuxCallbackFunc, reinterpret_cast<void*>( bus ) );
176             break;
177         case AUX_BUS_B:
178             AX_RegisterAuxBCallback( AuxCallbackFunc, reinterpret_cast<void*>( bus ) );
179             break;
180         }
181 #else
182         nn::snd::RegisterAuxCallback(
183                 static_cast<nn::snd::AuxBusId>( bus ),
184                 AuxCallbackFunc,
185                 static_cast<uptr>( bus ) );
186 #endif
187     }
188 
189     GetEffectList( bus ).PushBack( pFx );
190     return true;
191 }
192 
ClearEffect(AuxBus bus,int fadeTimes)193 void HardwareManager::ClearEffect( AuxBus bus , int fadeTimes )
194 {
195     if ( fadeTimes == 0 )
196     {
197         FinalizeEffect( bus );
198 
199         if ( m_AuxFadeVolume[ bus ].IsFinished() )
200         {
201             m_AuxFadeVolume[ bus ].SetTarget( 0.0f, 0 );
202         }
203     }
204     else
205     {
206         m_AuxFadeVolume[ bus ].SetTarget(
207             0.0f,
208             ( fadeTimes + SOUND_FRAME_INTERVAL_MSEC - 1 ) / SOUND_FRAME_INTERVAL_MSEC
209         );
210     }
211 }
212 
FinalizeEffect(AuxBus bus)213 void HardwareManager::FinalizeEffect( AuxBus bus )
214 {
215     FxList& list = GetEffectList( bus );
216     if ( list.IsEmpty() )
217     {
218         return;
219     }
220 
221 #ifdef NW_PLATFORM_CTRWIN
222     switch ( bus )
223     {
224     case AUX_BUS_A:
225         AX_RegisterAuxACallback( NULL, NULL );
226         break;
227     case AUX_BUS_B:
228         AX_RegisterAuxBCallback( NULL, NULL );
229         break;
230   #ifdef NW_PLATFORM_RVL
231     case AUX_C:
232         AX_RegisterAuxCCallback( NULL, NULL );
233         break;
234   #endif
235     }
236     m_EffectProcessTick[ bus ] = 0;
237 #else
238     nn::snd::ClearAuxCallback( static_cast<nn::snd::AuxBusId>( bus ) );
239     m_EffectProcessTick[ bus ] = nn::os::Tick( 0 );
240 #endif
241 
242     for ( FxList::Iterator itr = list.GetBeginIter();
243           itr != list.GetEndIter();
244           ++itr )
245     {
246         itr->Finalize();
247     }
248     list.Clear();
249 }
250 
251 #ifdef NW_PLATFORM_CTRWIN
AuxCallbackFunc(void * data,void * context)252 void HardwareManager::AuxCallbackFunc( void *data, void *context )
253 {
254     AuxBus bus = static_cast<AuxBus>( reinterpret_cast<u32>( context ) );
255     NW_MINMAXLT_ASSERT( bus, AUX_BUS_A, AUX_BUS_A + AUX_BUS_NUM );
256 
257     OSTick tick = OS_GetTick();
258 
259     // バッファ設定
260     void* buffer[4];
261     int numChannels;
262     OutputMode outputMode = GetInstance().GetOutputMode();
263     {
264         AXFX_BUFFERUPDATE* axfxbuf = static_cast<AXFX_BUFFERUPDATE*>( data );
265         numChannels = 3;
266         buffer[0] = axfxbuf->left;
267         buffer[1] = axfxbuf->right;
268         buffer[2] = axfxbuf->surround;
269     }
270 
271     // エフェクト処理
272     for ( FxList::Iterator itr = GetInstance().GetEffectList( bus ).GetBeginIter();
273           itr != GetInstance().GetEffectList( bus ).GetEndIter();
274           (void)++itr
275         )
276     {
277 #if 0
278         itr->UpdateBuffer(
279             numChannels,
280             buffer,
281             FX_BUFFER_SIZE,
282             FX_SAMPLE_FORMAT,
283             static_cast<float>( FX_SAMPLE_RATE ),
284             outputMode
285         );
286 #endif
287     }
288 
289     // 処理時間計測
290     GetInstance().m_EffectProcessTick[ bus ] = static_cast<OSTick>( OS_DiffTick( OS_GetTick(), tick ) );
291 }
292 #else
AuxCallbackFunc(nn::snd::AuxBusData * data,s32 sampleLength,uptr userData)293 void HardwareManager::AuxCallbackFunc(
294         nn::snd::AuxBusData *data,
295         s32 sampleLength,
296         uptr userData )
297 {
298     AuxBus bus = static_cast<AuxBus>( userData );
299     NW_MINMAXLT_ASSERT( bus, AUX_BUS_A, AUX_BUS_A + AUX_BUS_NUM );
300     const size_t FX_BUFFER_SIZE = sizeof(s32) * sampleLength;
301 
302     nn::os::Tick tick = nn::os::Tick::GetSystemCurrent();
303 
304     // バッファ設定
305     int numChannels;
306     OutputMode outputMode = GetInstance().GetOutputMode();
307     switch ( outputMode )
308     {
309     case OUTPUT_MODE_SURROUND:
310         numChannels = 4;
311         break;
312     case OUTPUT_MODE_MONO:
313     case OUTPUT_MODE_STEREO:
314     default:
315         numChannels = 2;
316         break;
317     };
318 
319     // エフェクト処理
320     for ( FxList::Iterator itr = GetInstance().GetEffectList( bus ).GetBeginIter();
321           itr != GetInstance().GetEffectList( bus ).GetEndIter();
322           ++itr )
323     {
324         itr->UpdateBuffer(
325                 numChannels,
326                 data,
327                 sampleLength,
328                 FX_SAMPLE_FORMAT,
329                 static_cast<f32>( FX_SAMPLE_RATE ),
330                 outputMode );
331     }
332     GetInstance().m_EffectProcessTick[ bus ] = nn::os::Tick::GetSystemCurrent() - tick;
333 }
334 #endif
335 
SetBiquadFilterCallback(int type,const BiquadFilterCallback * cb)336 void HardwareManager::SetBiquadFilterCallback( int type, const BiquadFilterCallback* cb )
337 {
338     NW_MINMAX_ASSERT( type, BIQUAD_FILTER_TYPE_NONE, BIQUAD_FILTER_TYPE_USER_MAX );
339 
340     if ( type == BIQUAD_FILTER_TYPE_NONE /* 0 */ )
341     {
342         // 0 番は Biquad フィルタ OFF なので、なにもしない
343         return;
344     }
345 
346     m_BiquadFilterCallbackTable[ type ] = cb;
347 }
348 
349 } // namespace nw::snd::internal:driver
350 } // namespace nw::snd::internal
351 } // namespace nw::snd
352 } // namespace nw
353