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