1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_Voice.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: 27399 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 #include <nw/snd/snd_Voice.h>
18 
19 #include <cstring>              // std::memcpy
20 #include <nw/snd/snd_Util.h>
21 #include <nw/snd/snd_Config.h>
22 #include <nw/snd/snd_VoiceManager.h>
23 #include <nw/snd/snd_HardwareManager.h>
24 
25 #ifdef NW_PLATFORM_CTRWIN
26     #include <nw/snd/snd_HardwareChannel.h>
27     #include <nw/snd/snd_HardwareChannelManager.h>
28 #endif // NW_PLATFORM_CTRWIN
29 
30 
31 namespace nw {
32 namespace snd {
33 namespace internal {
34 namespace driver {
35 
36 namespace
37 {
38 #ifdef NW_DEBUG
39 f32 s_Pan;
40 f32 s_SurroundPan;
41 MixParam s_Mix;
42 #endif
43 
44 #ifdef NW_PLATFORM_CTR
GetSdkInterpolationType(u8 interpolationType)45 nn::snd::InterpolationType GetSdkInterpolationType( u8 interpolationType )
46 {
47     nn::snd::InterpolationType result = nn::snd::INTERPOLATION_TYPE_POLYPHASE;
48 
49     switch ( interpolationType )
50     {
51     case 0:
52         // そのまま
53         break;
54     case 1:
55         result = nn::snd::INTERPOLATION_TYPE_LINEAR;
56         break;
57     case 2:
58         result = nn::snd::INTERPOLATION_TYPE_NONE;
59         break;
60     default:
61         NN_ASSERTMSG( 0, "invalid InterpolationType(%d)\n", interpolationType );
62         break;
63     }
64     return result;
65 }
GetSdkSampleFormat(nw::snd::SampleFormat format)66 nn::snd::SampleFormat GetSdkSampleFormat( nw::snd::SampleFormat format )
67 {
68     nn::snd::SampleFormat result = nn::snd::SAMPLE_FORMAT_PCM16;
69 
70     switch ( format )
71     {
72     case nw::snd::SAMPLE_FORMAT_PCM_S8:
73         result = nn::snd::SAMPLE_FORMAT_PCM8;
74         break;
75     case nw::snd::SAMPLE_FORMAT_PCM_S16:
76         // そのまま
77         break;
78     case nw::snd::SAMPLE_FORMAT_DSP_ADPCM:
79         result = nn::snd::SAMPLE_FORMAT_ADPCM;
80         break;
81 
82     case nw::snd::SAMPLE_FORMAT_PCM_S32:
83         NW_ASSERTMSG( 0, "invalid SampleFormat: nn::snd::SAMPLE_FORMAT_PCM_S32\n");
84         break;
85     case nw::snd::SAMPLE_FORMAT_IMA_ADPCM:
86         result = nn::snd::SAMPLE_FORMAT_PCM16;
87         NW_ASSERTMSG( 0, "invalid SampleFormat: nn::snd::SAMPLE_FORMAT_IMA_ADPCM\n");
88         break;
89     }
90 
91     return result;
92 }
93 
GetNwSampleFormat(nn::snd::SampleFormat format)94 nw::snd::SampleFormat GetNwSampleFormat( nn::snd::SampleFormat format )
95 {
96     nw::snd::SampleFormat result = nw::snd::SAMPLE_FORMAT_PCM_S16;
97 
98     switch ( format )
99     {
100     case nn::snd::SAMPLE_FORMAT_PCM16:
101         // そのまま
102         break;
103     case nn::snd::SAMPLE_FORMAT_PCM8:
104         result = nw::snd::SAMPLE_FORMAT_PCM_S8;
105         break;
106     case nn::snd::SAMPLE_FORMAT_ADPCM:
107         result = nw::snd::SAMPLE_FORMAT_DSP_ADPCM;
108         break;
109     }
110     return result;
111 }
112 
FrameToNibbleAddress(u32 frame)113 u32 FrameToNibbleAddress( u32 frame )
114 {
115     u32 mod = frame % 14;
116     u32 nibbleAddress = ( frame / 14 ) * 16;
117     if ( mod != 0 )
118     {
119         nibbleAddress += ( mod + 2 );
120     }
121 
122     return nibbleAddress;
123 }
124 
125 #endif // NW_PLATFORM_CTR
126 
PanCurveToPanInfo(Util::PanInfo & panInfo,PanCurve curve)127 inline void PanCurveToPanInfo( Util::PanInfo& panInfo, PanCurve curve )
128 {
129     switch ( curve )
130     {
131     case PAN_CURVE_SQRT:
132         panInfo.curve = Util::PAN_CURVE_SQRT;
133         break;
134     case PAN_CURVE_SQRT_0DB:
135         panInfo.curve = Util::PAN_CURVE_SQRT;
136         panInfo.centerZeroFlag = true;
137         break;
138     case PAN_CURVE_SQRT_0DB_CLAMP:
139         panInfo.curve = Util::PAN_CURVE_SQRT;
140         panInfo.centerZeroFlag = true;
141         panInfo.zeroClampFlag = true;
142         break;
143     case PAN_CURVE_SINCOS:
144         panInfo.curve = Util::PAN_CURVE_SINCOS;
145         break;
146     case PAN_CURVE_SINCOS_0DB:
147         panInfo.curve = Util::PAN_CURVE_SINCOS;
148         panInfo.centerZeroFlag = true;
149         break;
150     case PAN_CURVE_SINCOS_0DB_CLAMP:
151         panInfo.curve = Util::PAN_CURVE_SINCOS;
152         panInfo.centerZeroFlag = true;
153         panInfo.zeroClampFlag = true;
154         break;
155     case PAN_CURVE_LINEAR:
156         panInfo.curve = Util::PAN_CURVE_LINEAR;
157         break;
158     case PAN_CURVE_LINEAR_0DB:
159         panInfo.curve = Util::PAN_CURVE_LINEAR;
160         panInfo.centerZeroFlag = true;
161         break;
162     case PAN_CURVE_LINEAR_0DB_CLAMP:
163         panInfo.curve = Util::PAN_CURVE_LINEAR;
164         panInfo.centerZeroFlag = true;
165         panInfo.zeroClampFlag = true;
166         break;
167     default:
168         panInfo.curve = Util::PAN_CURVE_SQRT;
169         break;
170     }
171 }
172 
173 // モノラル・バランス or デュアル用パン計算
CalcPanForMono(f32 & left,f32 & right,const Util::PanInfo & panInfo)174 inline void CalcPanForMono( f32& left, f32& right, const Util::PanInfo& panInfo )
175 {
176     left = right = Util::CalcPanRatio( Voice::PAN_CENTER, panInfo );
177 }
178 
179 // ステレオ or サラウンド・バランス用パン計算
CalcBarancePanForStereo(f32 & left,f32 & right,const f32 & pan,int channelIndex,const Util::PanInfo & panInfo)180 inline void CalcBarancePanForStereo(
181         f32& left, f32& right, const f32& pan, int channelIndex, const Util::PanInfo& panInfo )
182 {
183     if ( channelIndex == 0 )
184     {
185         left = Util::CalcPanRatio( pan, panInfo );
186         right = 0.0f;
187     }
188     else if ( channelIndex == 1 )
189     {
190         left = 0.0f;
191         right = Util::CalcPanRatio( Voice::PAN_CENTER - pan, panInfo );
192     }
193 }
194 
195 // ステレオ or サラウンド用デュアルパン計算
CalcDualPanForStereo(f32 & left,f32 & right,const f32 & pan,const Util::PanInfo & panInfo)196 inline void CalcDualPanForStereo(
197         f32& left, f32& right, const f32& pan, const Util::PanInfo& panInfo )
198 {
199     left = Util::CalcPanRatio( pan, panInfo );
200     right = Util::CalcPanRatio( Voice::PAN_CENTER - pan, panInfo );
201 }
202 
203 // モノラル or ステレオ用サラウンドパン計算
CalcSurroundPanForMono(f32 & front,f32 & rear,const Util::PanInfo & panInfo)204 inline void CalcSurroundPanForMono(
205         f32& front, f32& rear, const Util::PanInfo& panInfo )
206 {
207     front = Util::CalcSurroundPanRatio( Voice::SPAN_FRONT, panInfo );
208     rear = Util::CalcSurroundPanRatio( Voice::SPAN_REAR, panInfo );
209 }
210 
211 // サラウンド用サラウンドパン計算
CalcSurroundPanForSurround(f32 & front,f32 & rear,const f32 & span,const Util::PanInfo & panInfo)212 inline void CalcSurroundPanForSurround(
213         f32& front, f32& rear, const f32& span, const Util::PanInfo& panInfo )
214 {
215     front = Util::CalcSurroundPanRatio( span, panInfo );
216     rear = Util::CalcSurroundPanRatio( Voice::SPAN_REAR - span, panInfo );
217 }
218 
219 } // anonymous namespace
220 
221 
222 // ------------------------------------------------------------------------
223 // 定数
224 const f32 Voice::VOLUME_MIN           = 0.0f;
225 const f32 Voice::VOLUME_DEFAULT       = 1.0f;
226 const f32 Voice::VOLUME_MAX           = 2.0f;
227 
228 const f32 Voice::PAN_LEFT             = -1.0f;
229 const f32 Voice::PAN_CENTER           = 0.0f;
230 const f32 Voice::PAN_RIGHT            = 1.0f;
231 
232 const f32 Voice::SPAN_FRONT           = 0.0f;
233 const f32 Voice::SPAN_CENTER          = 1.0f;
234 const f32 Voice::SPAN_REAR            = 2.0f;
235 
236 const f32 Voice::CUTOFF_FREQ_MIN      = 0.0f;
237 const f32 Voice::CUTOFF_FREQ_MAX      = 1.0f;
238 
239 const f32 Voice::BIQUAD_VALUE_MIN     = 0.0f;
240 const f32 Voice::BIQUAD_VALUE_MAX     = 1.0f;
241 
242 const f32 Voice::SEND_MIN             = 0.0f;
243 const f32 Voice::SEND_MAX             = 1.0f;
244 
245 /* ========================================================================
246         inline function
247    ======================================================================== */
248 
CalcMixVolume(f32 volume)249 inline u16 CalcMixVolume( f32 volume )
250 {
251     if ( volume <= 0.f ) return 0UL;
252 
253     return static_cast<u16>(
254         ut::Min(
255             0x0000ffffUL,
256             static_cast<unsigned long>( volume * 0x8000 )
257         )
258     );
259 }
260 
261 
Voice()262 Voice::Voice()
263 : m_Callback( NULL ),
264   m_IsActive( false ),
265   m_IsStart( false ),
266   m_IsStarted( false ),
267   m_IsPause( false ),
268   m_SyncFlag( 0 )
269 {
270     for ( int channelIndex = 0; channelIndex < CHANNEL_MAX; channelIndex++ )
271     {
272         m_pHardwareChannel[ channelIndex ] = NULL;
273     }
274 }
275 
~Voice()276 Voice::~Voice()
277 {
278     for ( int channelIndex = 0; channelIndex < CHANNEL_MAX; channelIndex++ )
279     {
280         HardwareChannel* pChannel = m_pHardwareChannel[ channelIndex ];
281         if ( pChannel != NULL )
282         {
283 #ifdef NW_PLATFORM_CTRWIN
284             HardwareChannelManager::GetInstance().FreeHardwareChannel( pChannel );
285 #else
286             nn::snd::FreeVoice( pChannel );
287 #endif
288         }
289     }
290 }
291 
292 #ifdef NW_PLATFORM_CTRWIN
Alloc(int channelCount,int priority,Voice::VoiceCallback callback,void * callbackData)293 bool Voice::Alloc(
294     int channelCount,
295     int priority,
296     Voice::VoiceCallback callback,
297     void* callbackData
298 )
299 {
300     NW_MINMAX_ASSERT( channelCount, 1, CHANNEL_MAX );
301     channelCount = ut::Clamp( channelCount, 1, CHANNEL_MAX );
302 
303     NW_ASSERT( ! m_IsActive );
304 
305     // ボイス取得
306     {
307         HardwareChannel* channelTable[ CHANNEL_MAX ];
308 
309         // RVL で、NW 層と SDK 層でのプライオリティ変換のために必要
310         u32 sdkVoicePriority =
311             ( priority == PRIORITY_NODROP ) ? VOICE_PRIORITY_NODROP : VOICE_PRIORITY_USE;
312 
313         // 必要なボイスをまとめて確保する
314         for ( int i = 0 ; i < channelCount; i++ )
315         {
316             HardwareChannel* pSdkVoice = NULL;
317 
318             while( pSdkVoice == NULL )
319             {
320                 pSdkVoice = HardwareChannelManager::GetInstance().AllocHardwareChannel(
321                     sdkVoicePriority,
322                     HardwareChannelCallbackFunc,
323                     this
324                 );
325 
326                 // チャンネルの空きが無い
327                 if ( pSdkVoice == NULL )
328                 {
329                     int dropVoiceCount = VoiceManager::GetInstance().DropLowestPriorityVoice( sdkVoicePriority );
330 
331                     if ( dropVoiceCount == 0 )
332                     {
333                         for ( int j = 0; j < i; j++ )
334                         {
335                             HardwareChannelManager::GetInstance().FreeHardwareChannel(
336                                 channelTable[ j ]
337                             );
338                         }
339                         return false;
340                     }
341                     continue;
342                 }
343             }
344 
345             pSdkVoice->SetPriority( sdkVoicePriority );
346             channelTable[ i ] = pSdkVoice;
347         }
348 
349         // 確保完了 → メンバに設定
350         for ( int channelIndex = 0; channelIndex < channelCount; channelIndex++ )
351         {
352             m_pHardwareChannel[ channelIndex ] = channelTable[ channelIndex ];
353         }
354     }
355 
356     // パラメータ初期化
357     InitParam( channelCount, callback, callbackData );
358     m_IsActive = true;
359 
360     return true;
361 }
362 #else   // ifdef NW_PLATFORM_CTRWIN
Alloc(int channelCount,int priority,Voice::VoiceCallback callback,void * callbackData)363 bool Voice::Alloc(
364     int channelCount,
365     int priority,
366     Voice::VoiceCallback callback,
367     void* callbackData
368 )
369 {
370     NW_MINMAX_ASSERT( channelCount, 1, CHANNEL_MAX );
371     channelCount = ut::Clamp( channelCount, 1, CHANNEL_MAX );
372     m_ChannelCount = 0;
373 
374     NW_ASSERT( ! m_IsActive );
375 
376     u32 sdkVoicePriority = ut::Clamp( priority, 0, nn::snd::VOICE_PRIORITY_NODROP );
377 
378     // ボイス取得
379     m_IsAllocating = true;
380     m_AllocateErrorFlag = false;
381 
382     if ( channelCount == 1 )
383     {
384         HardwareChannel* pSdkVoice = NULL;
385 
386 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
387         pSdkVoice = nn::snd::AllocVoice(
388             sdkVoicePriority,
389             SdkVoiceDropCallbackFunc,
390             reinterpret_cast<uptr>( this ) );
391 #else
392         pSdkVoice = NULL;
393 #endif
394         if ( pSdkVoice == NULL )
395         {
396             return false;
397         }
398         m_pHardwareChannel[ 0 ] = pSdkVoice;
399         m_ChannelCount = 1;
400     }
401     else
402     {
403         // 必要なボイスをまとめて確保する
404         for ( int i = 0 ; i < channelCount; i++ )
405         {
406             HardwareChannel* pSdkVoice = NULL;
407 
408             while ( pSdkVoice == NULL )
409             {
410 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
411                 pSdkVoice = nn::snd::AllocVoice(
412                     sdkVoicePriority,
413                     SdkVoiceDropCallbackFuncMulti,
414                     reinterpret_cast<uptr>( this ) );
415 #else
416                 pSdkVoice = NULL;
417 #endif
418 
419                 // チャンネルの空きが無い
420                 if ( pSdkVoice == NULL )
421                 {
422                     int dropVoiceCount = VoiceManager::GetInstance().DropLowestPriorityVoice( sdkVoicePriority );
423 
424                     if ( dropVoiceCount == 0 )
425                     {
426                         m_AllocateErrorFlag = true;
427                         break;
428                     }
429                     continue;
430                 }
431             }
432             m_pHardwareChannel[ i ] = pSdkVoice;
433             m_ChannelCount += 1;
434         }
435         if ( m_AllocateErrorFlag )
436         {
437             for ( int i = 0; i < m_ChannelCount; i++ )
438             {
439                 if ( m_pHardwareChannel[i] )
440                 {
441 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
442                     nn::snd::FreeVoice( m_pHardwareChannel[i] );
443 #endif
444                 }
445             }
446             return false;
447         }
448     }
449 
450     m_IsAllocating = false;
451 
452     // パラメータ初期化
453     InitParam( channelCount, callback, callbackData );
454     m_IsActive = true;
455 
456     return true;
457 }
458 #endif  // endif NW_PLATFORM_CTRWIN
459 
460 
Free()461 void Voice::Free()
462 {
463     if ( ! m_IsActive ) return;
464 
465     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
466     {
467         HardwareChannel* pChannel = m_pHardwareChannel[ channelIndex ];
468         if ( pChannel != NULL )
469         {
470 #ifdef NW_PLATFORM_CTRWIN
471             HardwareChannelManager::GetInstance().FreeHardwareChannel( pChannel );
472 #else
473     #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
474             nn::snd::FreeVoice( pChannel );
475     #endif
476 #endif
477             m_pHardwareChannel[ channelIndex ] = NULL;
478         }
479     }
480     m_ChannelCount = 0;
481 
482     VoiceManager::GetInstance().FreeVoice( this );
483 
484     m_IsActive = false;
485 }
486 
Initialize(const WaveInfo & waveInfo,u32 startOffset)487 void Voice::Initialize( const WaveInfo& waveInfo, u32 startOffset )
488 {
489 #ifdef NW_PLATFORM_CTR
490     // TODO: 途中再生には未対応
491     NW_UNUSED_VARIABLE( startOffset );
492 #endif
493 
494     m_Format = waveInfo.sampleFormat;
495 
496     // チャンネルパラメータ設定
497     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
498     {
499         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
500         if ( pChannel == NULL ) continue;
501 
502 #ifdef NW_PLATFORM_CTRWIN
503         NW_NULL_ASSERT( waveInfo.channelParam[channelIndex].dataAddress );
504         const void* dataAddr = waveInfo.channelParam[channelIndex].dataAddress;
505 
506         // adpcmInfoをオフセット再生のためにCPUでデコードして書き換える
507         DspAdpcmParam adpcmParam;
508 
509         if ( m_Format == SAMPLE_FORMAT_DSP_ADPCM )
510         {
511             adpcmParam = waveInfo.channelParam[channelIndex].adpcmParam;
512             HardwareChannel::CalcOffsetDspAdpcmParam(
513                 &adpcmParam.predScale,
514                 &adpcmParam.yn1,
515                 &adpcmParam.yn2,
516                 startOffset,
517                 dataAddr,
518                 adpcmParam
519             );
520         }
521         pChannel->Initialize(
522             dataAddr,
523             m_Format,
524             waveInfo.sampleRate
525         );
526 
527         pChannel->SetAddr(
528             waveInfo.loopFlag,
529             dataAddr,
530             startOffset,
531             static_cast<u32>(waveInfo.loopStartFrame),
532             static_cast<u32>(waveInfo.loopEndFrame)
533         );
534 
535         if ( m_Format == SAMPLE_FORMAT_DSP_ADPCM )
536         {
537             pChannel->SetDspAdpcm(
538                 &adpcmParam
539             );
540 
541             pChannel->SetDspAdpcmLoop(
542                 &waveInfo.channelParam[channelIndex].adpcmLoopParam
543             );
544         }
545 
546         pChannel->SetSrcType( SRC_TYPE_4TAP, m_Pitch );
547 
548 #else // NW_PLATFORM_CTRWIN
549 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
550 
551         pChannel->SetChannelCount( 1 );
552         pChannel->SetSampleFormat( GetSdkSampleFormat( m_Format ) );
553         pChannel->SetSampleRate( waveInfo.sampleRate );
554 
555         // Voice::Initialize を呼んだ後に、Voice ユーザー (Channel や StreamTrack) が
556         // WaveBuffer の操作をする必要があります。
557         // NN_LOG("[forSDK] SDKFormat(%d)\n", GetSdkSampleFormat( m_Format ));
558 
559         pChannel->SetInterpolationType(
560             Util::GetInterpolationType( HardwareManager::GetInstance().GetSrcType() ) );
561 #endif
562 #endif // NW_PLATFORM_CTRWIN
563     }
564 
565     m_IsPause    = false;
566     m_IsPausing  = false;
567     m_IsStart    = false;
568     m_IsStarted  = false;
569 }
570 
Start()571 void Voice::Start()
572 {
573     m_IsStart = true;
574     m_IsPause = false;
575 
576     m_SyncFlag |= UPDATE_START;
577 }
578 
Stop()579 void Voice::Stop()
580 {
581     if ( m_IsStarted )
582     {
583         StopAllHardwareChannel();
584         m_IsStarted = false;
585     }
586     m_IsPausing = false;
587     m_IsPause = false;
588     m_IsStart = false;
589 }
590 
StopFinished()591 void Voice::StopFinished()
592 {
593     if ( ! m_IsActive )
594     {
595         return;
596     }
597 
598     // 再生停止チェック
599     if ( m_IsStarted )
600     {
601         if ( IsPlayFinished() )
602         {
603             // 波形停止
604             if ( m_Callback != NULL )
605             {
606                 m_Callback( this, CALLBACK_STATUS_FINISH_WAVE, m_pCallbackData );
607             }
608             m_IsStarted = false;
609             m_IsStart = false;
610         }
611     }
612 }
613 
Pause(bool flag)614 void Voice::Pause( bool flag )
615 {
616     if ( m_IsPause == flag ) return;
617 
618     m_IsPause = flag;
619     m_SyncFlag |= UPDATE_PAUSE;
620 }
621 
Calc()622 void Voice::Calc()
623 {
624     if ( m_IsStart )
625     {
626         // 再生レート
627         if ( m_SyncFlag & UPDATE_SRC )
628         {
629             CalcSrc( false );
630             m_SyncFlag &= ~UPDATE_SRC;
631         }
632 
633         // ボリューム
634         if ( m_SyncFlag & UPDATE_VE )
635         {
636             CalcVe();
637             m_SyncFlag &= ~UPDATE_VE;
638         }
639 
640         // ミックス
641         if ( m_SyncFlag & UPDATE_MIX )
642         {
643             CalcMix();
644             m_SyncFlag &= ~UPDATE_MIX;
645         }
646 
647         // ローパスフィルタ
648         if ( m_SyncFlag & UPDATE_LPF )
649         {
650             CalcLpf();
651             m_SyncFlag &= ~UPDATE_LPF;
652         }
653 
654         // Biquadフィルタ
655         if ( m_SyncFlag & UPDATE_BIQUAD )
656         {
657             CalcBiquadFilter();
658             m_SyncFlag &= ~UPDATE_BIQUAD;
659         }
660     }
661 }
662 
Update()663 void Voice::Update()
664 {
665     if ( ! m_IsActive ) return;
666 
667     // ボイスの再生・停止処理をあとでまとめて行うためのフラグ
668     enum { NONE, RUN, STOP, PAUSE } runFlag = NONE;
669 
670     // 再生開始
671     if ( m_SyncFlag & UPDATE_START )
672     {
673         if ( m_IsStart && !m_IsStarted )
674         {
675             CalcSrc( true );
676             CalcMix();
677             CalcVe();   // マスターボリューム反映
678             runFlag = RUN;
679             m_IsStarted = true;
680 
681             m_SyncFlag &= ~UPDATE_START;
682             m_SyncFlag &= ~UPDATE_SRC;
683             m_SyncFlag &= ~UPDATE_MIX;
684         }
685     }
686 
687     if ( m_IsStarted )
688     {
689         // 一時停止
690         if ( m_SyncFlag & UPDATE_PAUSE )
691         {
692             if ( m_IsStart )
693             {
694                 if ( m_IsPause )
695                 {
696                     runFlag = PAUSE;
697                     m_IsPausing = true;
698                 }
699                 else
700                 {
701                     runFlag = RUN;
702                     m_IsPausing = false;
703                 }
704 
705                 m_SyncFlag &= ~UPDATE_PAUSE;
706             }
707         }
708 
709 #ifdef NW_PLATFORM_CTRWIN
710         // パラメータ設定をsyncさせる
711         SyncHardwareChannel();
712 #endif
713     }
714 
715     // ボイスの再生・停止処理をまとめて行う
716     // 同一フレームで、まだ再生されていないボイスに対して
717     // 再生→停止の処理を行うとデポップが発生するため
718     switch ( runFlag )
719     {
720     case RUN:
721         RunAllHardwareChannel();
722         break;
723     case STOP:
724         StopAllHardwareChannel();
725         break;
726     case PAUSE:
727         PauseAllHardwareChannel();
728     case NONE:
729     default:
730         break;
731     }
732 }
733 
SetVolume(f32 volume)734 void Voice::SetVolume( f32 volume )
735 {
736     if ( volume < VOLUME_MIN ) volume = VOLUME_MIN;
737 
738     if ( volume != m_Volume )
739     {
740         m_Volume = volume;
741         m_SyncFlag |= UPDATE_VE;
742     }
743 }
744 
SetPitch(f32 pitch)745 void Voice::SetPitch( f32 pitch )
746 {
747     if ( pitch != m_Pitch )
748     {
749         m_Pitch = pitch;
750         m_SyncFlag |= UPDATE_SRC;
751     }
752 }
753 
SetPanMode(PanMode panMode)754 void Voice::SetPanMode( PanMode panMode )
755 {
756     if ( panMode != m_PanMode )
757     {
758         m_PanMode = panMode;
759         m_SyncFlag |= UPDATE_MIX;
760     }
761 }
762 
SetPanCurve(PanCurve panCurve)763 void Voice::SetPanCurve( PanCurve panCurve )
764 {
765     if ( panCurve != m_PanCurve )
766     {
767         m_PanCurve = panCurve;
768         m_SyncFlag |= UPDATE_MIX;
769     }
770 }
771 
SetPan(f32 pan)772 void Voice::SetPan( f32 pan )
773 {
774     if ( pan != m_Pan )
775     {
776         m_Pan = pan;
777         m_SyncFlag |= UPDATE_MIX;
778     }
779 }
780 
SetSurroundPan(f32 span)781 void Voice::SetSurroundPan( f32 span )
782 {
783     if ( span != m_SurroundPan )
784     {
785         m_SurroundPan = span;
786         m_SyncFlag |= UPDATE_MIX;
787     }
788 }
789 
790 
SetLpfFreq(f32 lpfFreq)791 void Voice::SetLpfFreq( f32 lpfFreq )
792 {
793     if ( lpfFreq != m_LpfFreq )
794     {
795         m_LpfFreq = lpfFreq;
796         m_SyncFlag |= UPDATE_LPF;
797     }
798 }
799 
SetBiquadFilter(int type,f32 value)800 void Voice::SetBiquadFilter( int type, f32 value )
801 {
802     NW_MINMAX_ASSERT( type, 0, BIQUAD_FILTER_TYPE_USER_MAX );
803     value = ut::Clamp( value, BIQUAD_VALUE_MIN, BIQUAD_VALUE_MAX );
804 
805     bool isUpdate = false;
806 
807     if ( type != m_BiquadType )
808     {
809         m_BiquadType = static_cast<u8>( type );
810         isUpdate = true;
811     }
812 
813     if ( value != m_BiquadValue )
814     {
815         m_BiquadValue = value;
816         isUpdate = true;
817     }
818 
819     if ( isUpdate )
820     {
821         m_SyncFlag |= UPDATE_BIQUAD;
822     }
823 }
824 
SetPriority(int priority)825 void Voice::SetPriority( int priority )
826 {
827     NW_MINMAX_ASSERT( priority, PRIORITY_MIN, PRIORITY_MAX );
828 
829     m_Priority = priority;
830     VoiceManager::GetInstance().ChangeVoicePriority( this );
831 
832     // リリースの場合はUpdateVoicesPriorityではなくここですぐに設定
833     if ( m_Priority == PRIORITY_RELEASE )
834     {
835         for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
836         {
837             HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
838             if ( pChannel != NULL )
839             {
840 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
841                 pChannel->SetPriority( VOICE_PRIORITY_RELEASE );
842 #endif
843             }
844         }
845     }
846 }
847 
SetMainSend(f32 send)848 void Voice::SetMainSend( f32 send )
849 {
850     send += 1.0f;
851     if ( send < SEND_MIN ) send = SEND_MIN;
852 
853     if ( send != m_MainSend )
854     {
855         m_MainSend = send;
856         m_SyncFlag |= UPDATE_MIX;
857     }
858 }
859 
SetFxSend(AuxBus bus,f32 send)860 void Voice::SetFxSend( AuxBus bus, f32 send )
861 {
862     NW_MINMAXLT_ASSERT( bus, AUX_BUS_A, AUX_BUS_A + AUX_BUS_NUM );
863     if ( send < SEND_MIN ) send = SEND_MIN;
864 
865     if ( send != m_FxSend[ bus ] )
866     {
867         m_FxSend[ bus ] = send;
868         m_SyncFlag |= UPDATE_MIX;
869     }
870 }
871 
872 #ifdef NW_PLATFORM_CTRWIN
HardwareChannelCallbackFunc(HardwareChannel * dropVoice,HardwareChannel::HardwareChannelCallbackStatus status,void * callbackData)873 void Voice::HardwareChannelCallbackFunc(
874     HardwareChannel* dropVoice,
875     HardwareChannel::HardwareChannelCallbackStatus status,
876     void* callbackData
877 )
878 {
879     Voice* voice = static_cast<Voice*>( callbackData );
880 
881     NW_NULL_ASSERT( voice );
882 
883     VoiceCallbackStatus voiceStatus = CALLBACK_STATUS_FINISH_WAVE;
884     bool freeDropVoice = false;
885     switch ( status )
886     {
887     case HardwareChannel::CALLBACK_STATUS_CANCEL:
888         voiceStatus = CALLBACK_STATUS_CANCEL;
889         break;
890     case HardwareChannel::CALLBACK_STATUS_DROP_DSP:
891         voiceStatus = CALLBACK_STATUS_DROP_DSP;
892         freeDropVoice = true;
893         break;
894     }
895 
896     // 同じボイスのAXVPBを全て止めて解放
897     for ( int channelIndex = 0; channelIndex < voice->m_ChannelCount; channelIndex++ )
898     {
899         HardwareChannel* pChannel = voice->m_pHardwareChannel[ channelIndex ];
900         if ( pChannel == NULL ) continue;
901         if ( pChannel == dropVoice )
902         {
903             if ( ! freeDropVoice )
904             {
905                 // DROP_DSPの時は解放してはいけない
906                 HardwareChannelManager::GetInstance().FreeHardwareChannel( pChannel );
907             }
908         }
909         else
910         {
911             pChannel->Stop();
912             HardwareChannelManager::GetInstance().FreeHardwareChannel( pChannel );
913         }
914         voice->m_pHardwareChannel[ channelIndex ] = NULL;
915     }
916 
917     voice->m_IsPause = false;
918     voice->m_IsStart = false;
919 
920     voice->m_ChannelCount = 0;
921 
922     if ( freeDropVoice ) {
923         voice->Free();
924     }
925 
926     if ( voice->m_Callback != NULL )
927     {
928         voice->m_Callback( voice, voiceStatus, voice->m_pCallbackData );
929     }
930 }
931 #else
SdkVoiceDropCallbackFunc(nn::snd::Voice * pDropSdkVoice,uptr userArg)932 void Voice::SdkVoiceDropCallbackFunc(
933     nn::snd::Voice* pDropSdkVoice,
934     uptr userArg )
935 {
936     NW_UNUSED_VARIABLE( pDropSdkVoice );
937 
938     Voice* pVoice = reinterpret_cast<Voice*>( userArg );
939     NW_NULL_ASSERT( pVoice );
940 
941     // NOTE: NW4R ではステータス CANCEL / DROP_DSP があったが、NW4C では DROP のみ
942 
943     // 同じ NW4C Voice が持っている SDK Voice を止めて解放
944     NW_ASSERT( pVoice->m_ChannelCount == 1 );
945     NW_ASSERT( pVoice->m_pHardwareChannel[0] == pDropSdkVoice );
946     pVoice->m_pHardwareChannel[0] = NULL;
947 
948     pVoice->m_IsPause = false;
949     pVoice->m_IsStart = false;
950     pVoice->m_ChannelCount = 0;
951 
952     VoiceManager::GetInstance().FreeVoice( pVoice );
953     pVoice->m_IsActive = false;
954 
955     // NW4C Voice のコールバックを呼ぶ (Channel などが設定)
956     if ( pVoice->m_Callback != NULL )
957     {
958         pVoice->m_Callback( pVoice, CALLBACK_STATUS_DROP_DSP, pVoice->m_pCallbackData );
959     }
960 }
SdkVoiceDropCallbackFuncMulti(nn::snd::Voice * pDropSdkVoice,uptr userArg)961 void Voice::SdkVoiceDropCallbackFuncMulti(
962     nn::snd::Voice* pDropSdkVoice,
963     uptr userArg )
964 {
965     Voice* pVoice = reinterpret_cast<Voice*>( userArg );
966     NW_NULL_ASSERT( pVoice );
967 
968     // NOTE: NW4R ではステータス CANCEL / DROP_DSP があったが、NW4C では DROP のみ
969 
970     if ( pVoice->m_IsAllocating )
971     {
972         pVoice->m_AllocateErrorFlag = true;
973         for ( int ch = 0; ch < pVoice->m_ChannelCount; ch++ )
974         {
975             nn::snd::Voice* pSdkVoice = pVoice->m_pHardwareChannel[ch];
976             if ( pSdkVoice == pDropSdkVoice )
977             {
978                 pVoice->m_pHardwareChannel[ch] = NULL;
979                 return;
980             }
981         }
982         NW_ASSERTMSG( false, "invalid allocating voice" );
983     }
984     else
985     {
986         // 同じ NW4C Voice が持っている SDK Voice を止めて解放
987         for ( int ch = 0; ch < pVoice->m_ChannelCount; ch++ )
988         {
989             nn::snd::Voice* pSdkVoice = pVoice->m_pHardwareChannel[ch];
990 
991             if ( pSdkVoice == NULL )
992             {
993                 continue;
994             }
995 
996             if ( pSdkVoice != pDropSdkVoice )
997             {
998             #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
999                 pSdkVoice->SetState( nn::snd::Voice::STATE_STOP );
1000                 nn::snd::FreeVoice( pSdkVoice );
1001             #endif
1002             }
1003 
1004             pVoice->m_pHardwareChannel[ch] = NULL;
1005         }
1006     }
1007 
1008     pVoice->m_IsPause = false;
1009     pVoice->m_IsStart = false;
1010     pVoice->m_ChannelCount = 0;
1011 
1012     VoiceManager::GetInstance().FreeVoice( pVoice );
1013     pVoice->m_IsActive = false;
1014 
1015     // NW4C Voice のコールバックを呼ぶ (Channel などが設定)
1016     if ( pVoice->m_Callback != NULL )
1017     {
1018         pVoice->m_Callback( pVoice, CALLBACK_STATUS_DROP_DSP, pVoice->m_pCallbackData );
1019     }
1020 }
1021 #endif
1022 
1023 
InitParam(int channelCount,Voice::VoiceCallback callback,void * callbackData)1024 void Voice::InitParam(
1025     int channelCount,
1026     Voice::VoiceCallback callback,
1027     void* callbackData
1028 )
1029 {
1030     NW_MINMAX_ASSERT( channelCount, 1, CHANNEL_MAX );
1031 
1032 #ifdef NW_PLATFORM_CTRWIN
1033     m_ChannelCount = channelCount;
1034 #else
1035     // m_ChannelCount は AllocVoice 内で設定される
1036     NW_UNUSED_VARIABLE( channelCount );
1037 #endif
1038 
1039     m_Callback      = callback;
1040     m_pCallbackData = callbackData;
1041     m_SyncFlag      = 0;
1042     m_IsPause       = false;
1043     m_IsPausing     = false;
1044     m_IsStarted     = false;
1045     m_pLastWaveBuffer = NULL;
1046 
1047     // Init Param
1048     m_Volume            = VOLUME_DEFAULT;
1049     m_LpfFreq           = 1.0f;
1050     m_BiquadType        = BIQUAD_FILTER_TYPE_NONE;
1051     m_BiquadValue       = 0.0f;
1052     m_Pan               = PAN_CENTER;
1053     m_SurroundPan       = SPAN_FRONT;
1054     m_MainSend          = SEND_MAX;
1055 
1056     for ( int i = 0; i < AUX_BUS_NUM; i++ )
1057     {
1058         m_FxSend[ i ] = SEND_MIN;
1059     }
1060     m_Pitch             = 1.0f;
1061 
1062     m_PanMode           = PAN_MODE_DUAL;
1063     m_PanCurve          = PAN_CURVE_SQRT;
1064 
1065 
1066     // 子クラスのメソッドを呼ぶ
1067     // OnInitParam();
1068 }
1069 
1070 #ifdef NW_PLATFORM_CTRWIN
SyncHardwareChannel()1071 void Voice::SyncHardwareChannel()
1072 {
1073     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1074     {
1075         if ( m_pHardwareChannel[ channelIndex ] != NULL )
1076         {
1077             m_pHardwareChannel[ channelIndex ]->Sync();
1078         }
1079     }
1080 }
1081 #endif
1082 
CalcSrc(bool initialUpdate)1083 void Voice::CalcSrc( bool initialUpdate )
1084 {
1085     f32 ratio = m_Pitch;
1086 
1087     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1088     {
1089         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1090         if ( pChannel != NULL )
1091         {
1092 #ifdef NW_PLATFORM_CTRWIN
1093             pChannel->SetSrc( ratio, initialUpdate );
1094 #else
1095             NW_UNUSED_VARIABLE( initialUpdate );
1096 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1097             pChannel->SetPitch( ratio );
1098 #endif
1099 #endif
1100 //             NN_LOG("[forSDK] pitch(%4d)\n", (int)( ratio*10000 ));
1101         }
1102     }
1103 }
1104 
CalcVe()1105 void Voice::CalcVe()
1106 {
1107     f32 volume = m_Volume;
1108     volume *= HardwareManager::GetInstance().GetOutputVolume();
1109 
1110     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1111     {
1112         HardwareChannel* pChannel = m_pHardwareChannel[ channelIndex ];
1113         if ( pChannel != NULL )
1114         {
1115 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1116             pChannel->SetVolume( volume );
1117 //            NN_LOG("[forSDK] Vol(%4d)\n", (int)(volume*10000));
1118 #endif
1119         }
1120     }
1121 }
1122 
CalcMix()1123 void Voice::CalcMix()
1124 {
1125     MixParam mix;
1126     std::memset( &mix, 0, sizeof(mix) );
1127 
1128     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1129     {
1130         HardwareChannel* pChannel = m_pHardwareChannel[ channelIndex ];
1131         if ( pChannel == NULL ) continue;
1132         CalcMixParam( channelIndex, &mix );
1133 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1134         pChannel->SetMixParam( mix );
1135 #endif
1136 //        NN_LOG("[forSDK] MIX L(%4d) R(%4d)\n",
1137 //                 (int)( mix.mainBus[0] * 10000 ),
1138 //                 (int)( mix.mainBus[1] * 10000 ) );
1139     }
1140 }
1141 
CalcLpf()1142 void Voice::CalcLpf()
1143 {
1144     u16 freq = Util::CalcLpfFreq( m_LpfFreq );
1145 
1146     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1147     {
1148         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1149         if ( pChannel != NULL )
1150         {
1151         #ifdef NW_PLATFORM_CTRWIN
1152             pChannel->SetLpf( freq );
1153         #else
1154           #ifdef NW_SND_AVAILABLE_NN_BOTH_FILTER
1155             if ( freq >= 16000 )
1156             {
1157                 pChannel->EnableMonoFilter( false );
1158             }
1159             else
1160             {
1161                 pChannel->EnableMonoFilter( true );
1162                 pChannel->SetMonoFilterCoefficients( freq );
1163             }
1164           #endif
1165         #endif
1166         }
1167     }
1168 }
1169 
CalcBiquadFilter()1170 void Voice::CalcBiquadFilter()
1171 {
1172     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1173     {
1174         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1175         if ( pChannel != NULL )
1176         {
1177         #ifdef NW_PLATFORM_CTRWIN
1178             pChannel->SetBiquad( m_BiquadType, m_BiquadValue );
1179         #else
1180             {
1181                 const BiquadFilterCallback* cb =
1182                     HardwareManager::GetInstance().GetBiquadFilterCallback( m_BiquadType );
1183                 if ( cb == NULL )
1184                 {
1185                   #ifdef NW_SND_AVAILABLE_NN_BOTH_FILTER
1186                     pChannel->EnableBiquadFilter( false );
1187                   #else
1188                     pChannel->SetFilterType( nn::snd::FILTER_TYPE_NONE );
1189                   #endif
1190                 }
1191                 else
1192                 {
1193                   #ifdef NW_SND_AVAILABLE_NN_BOTH_FILTER
1194                     if ( m_BiquadValue <= 0.0f )
1195                     {
1196                         pChannel->EnableBiquadFilter( false );
1197                     }
1198                     else
1199                     {
1200                         pChannel->EnableBiquadFilter( true );
1201                         BiquadFilterCallback::Coefficients coef;
1202                         cb->GetCoefficients( m_BiquadType, m_BiquadValue, &coef );
1203                         pChannel->SetBiquadFilterCoefficients( coef );
1204                     }
1205                   #else
1206                     BiquadFilterCallback::Coefficients coef;
1207                     cb->GetCoefficients( m_BiquadType, m_BiquadValue, &coef );
1208 
1209                     pChannel->SetFilterType( nn::snd::FILTER_TYPE_BIQUAD );
1210                     pChannel->SetBiquadFilterCoefficients( &coef );
1211                   #endif
1212                 }
1213             }
1214         #endif
1215         }
1216     }
1217 }
1218 
1219 #ifdef NW_PLATFORM_CTRWIN
CalcMixParam(int channelIndex,nw::snd::internal::MixParam * mix)1220 void Voice::CalcMixParam(
1221         int channelIndex,
1222         nw::snd::internal::MixParam* mix
1223 )
1224 {
1225     NW_NULL_ASSERT( mix );
1226     // NW_NULL_ASSERT( rmtMix );
1227 
1228     f32 mainVolume = 1.0f;
1229     f32 mainSend = m_MainSend;
1230     f32 fxSend[ AUX_BUS_NUM ];
1231     for ( int i = 0; i < AUX_BUS_NUM; i++ )
1232     {
1233         fxSend[ i ] = m_FxSend[ i ];
1234     }
1235 
1236     f32 main = mainVolume * ut::Clamp( mainSend, 0.0f, 1.0f );
1237     f32 fx[ AUX_BUS_NUM ];
1238     for ( int i = 0; i < AUX_BUS_NUM; i++ )
1239     {
1240         fx[ i ] = mainVolume * ut::Clamp( fxSend[ i ], 0.0f, 1.0f );
1241     }
1242 
1243     // ------------------------------------------------------------------------
1244     //  パン設定
1245     f32 left = 0.0f;
1246     f32 right = 0.0f;
1247     f32 lrMixed = 0.0f;
1248     f32 surround = 0.0f;
1249     f32 front = 0.0f;
1250     f32 rear = 0.0f;
1251 
1252     Util::PanInfo panInfo;
1253     PanCurveToPanInfo( panInfo, m_PanCurve );
1254 
1255     if ( ( m_ChannelCount > 1 ) && ( m_PanMode == PAN_MODE_BALANCE ) )
1256     {
1257         // バランスとしてパンを処理する
1258 
1259         f32 pan = m_Pan;
1260         f32 span = m_SurroundPan;
1261 
1262         if ( channelIndex == 0 )
1263         {
1264             left  = Util::CalcPanRatio( pan, panInfo );
1265             right = 0.0f;
1266         }
1267         else if ( channelIndex == 1 )
1268         {
1269             left  = 0.0f;
1270             right = Util::CalcPanRatio( PAN_CENTER - pan, panInfo );
1271         }
1272 
1273         front = Util::CalcSurroundPanRatio( span, panInfo );
1274         rear  = Util::CalcSurroundPanRatio( SPAN_REAR - span, panInfo );
1275     }
1276     else
1277     {
1278         // 通常の定位処理
1279 
1280         f32 voicePan = 0.0f;
1281 
1282         // チャンネルごとにオフセットを与える
1283         if ( m_ChannelCount == 2 )
1284         {
1285             if ( channelIndex == 0 ) voicePan = -1.0f;
1286             if ( channelIndex == 1 ) voicePan = 1.0f;
1287         }
1288 
1289         f32 pan;
1290         // f32 span;        // TODO: PC 版のサラウンドはひとまず後回し
1291         switch ( HardwareManager::GetInstance().GetOutputMode() )
1292         {
1293         // TODO:[SURR] case OUTPUT_MODE_DPL2:
1294         // TODO:[SURR]     TransformDpl2Pan(
1295         // TODO:[SURR]         &pan,
1296         // TODO:[SURR]         &span,
1297         // TODO:[SURR]         m_Pan + voicePan,
1298         // TODO:[SURR]         m_SurroundPan
1299         // TODO:[SURR]     );
1300         // TODO:[SURR]     break;
1301         case OUTPUT_MODE_MONO:
1302         case OUTPUT_MODE_STEREO:
1303         // TODO:[SURR] case OUTPUT_MODE_SURROUND:
1304         default:
1305             pan = m_Pan + voicePan;
1306             // TODO:[SURR] span = m_SurroundPan;
1307             break;
1308         }
1309 
1310         // pan
1311         left  = Util::CalcPanRatio( pan, panInfo );
1312         right = Util::CalcPanRatio( PAN_CENTER - pan, panInfo );
1313 
1314         // TODO:[SURR] front = Util::CalcSurroundPanRatio( span, panInfo );
1315         // TODO:[SURR] rear  = Util::CalcSurroundPanRatio( SPAN_REAR - span, panInfo );
1316     }
1317 
1318     // TODO:[SURR] surround  = Util::CalcVolumeRatio( SURROUND_ATTENUATED_DB );
1319     lrMixed   = ( left + right ) * 0.5f;
1320 
1321 
1322     // -----------------------------------------------------------------
1323     // 構造体にセットする
1324 
1325     // 各チャンネルのボリューム
1326     f32 m_l = 0.0f;           // 左のボリューム
1327     f32 m_r = 0.0f;           // 右のボリューム
1328     f32 auxL[ AUX_BUS_NUM ];  // Aux? の 左ボリューム
1329     f32 auxR[ AUX_BUS_NUM ];  // Aux? の 右ボリューム
1330 
1331     switch ( HardwareManager::GetInstance().GetOutputMode() )
1332     {
1333     case OUTPUT_MODE_STEREO:
1334         m_l  = main * left ;
1335         m_r  = main * right;
1336         for ( int i = 0; i < AUX_BUS_NUM; i++ )
1337         {
1338             auxL[ i ] = fx[ i ] * left;
1339             auxR[ i ] = fx[ i ] * right;
1340         }
1341         // a_l  = fx_a * left ;
1342         // a_r  = fx_a * right;
1343         // a_s  = fx_a * 0.0f;
1344         // b_l  = fx_b * left ;
1345         // b_r  = fx_b * right;
1346         // b_s  = fx_b * 0.0f;
1347         // c_l  = fx_c * left ;
1348         // c_r  = fx_c * right;
1349         // c_s  = fx_c * 0.0f;
1350         break;
1351     case OUTPUT_MODE_MONO:
1352         m_l  = main * lrMixed;
1353         m_r  = main * lrMixed;
1354         for ( int i = 0; i < AUX_BUS_NUM; i++ )
1355         {
1356             auxL[ i ] = fx[ i ] * lrMixed;
1357             auxR[ i ] = fx[ i ] * lrMixed;
1358         }
1359         // a_l  = fx_a * lrMixed;
1360         // a_r  = fx_a * lrMixed;
1361         // a_s  = fx_a * 0.0f;
1362         // b_l  = fx_b * lrMixed;
1363         // b_r  = fx_b * lrMixed;
1364         // b_s  = fx_b * 0.0f;
1365         // c_l  = fx_c * lrMixed;
1366         // c_r  = fx_c * lrMixed;
1367         // c_s  = fx_c * 0.0f;
1368         break;
1369     }
1370 
1371     // 計算された値を、mix構造体に代入する値に変換して代入
1372 	mix->mainBus[nn::snd::CHANNEL_INDEX_FRONT_LEFT]     = CalcMixVolume( m_l );
1373 	mix->mainBus[nn::snd::CHANNEL_INDEX_FRONT_RIGHT]     = CalcMixVolume( m_r );
1374 
1375     mix->auxBusA[nn::snd::CHANNEL_INDEX_FRONT_LEFT] = CalcMixVolume( auxL[ 0 ] );
1376     mix->auxBusA[nn::snd::CHANNEL_INDEX_FRONT_RIGHT] = CalcMixVolume( auxR[ 0 ] );
1377 
1378 	mix->auxBusB[nn::snd::CHANNEL_INDEX_FRONT_LEFT] = CalcMixVolume( auxL[ 1 ] );
1379     mix->auxBusB[nn::snd::CHANNEL_INDEX_FRONT_RIGHT] = CalcMixVolume( auxR[ 1 ] );
1380 }
1381 
1382 #else   // for NW_PLATFORM_CTR
1383 
CalcMixParam(int channelIndex,nw::snd::internal::MixParam * mix)1384 void Voice::CalcMixParam(
1385         int channelIndex,
1386         nw::snd::internal::MixParam* mix
1387 )
1388 {
1389     NW_NULL_ASSERT( mix );
1390 
1391     f32 main = ut::Clamp( m_MainSend, 0.0f, 1.0f );
1392     f32 fx[ AUX_BUS_NUM ];
1393     for ( int i = 0; i < AUX_BUS_NUM; i++ )
1394     {
1395         fx[ i ] = ut::Clamp( m_FxSend[i], 0.0f, 1.0f );
1396     }
1397 
1398     register f32 left, right, front, rear;
1399     left = right = front = rear = 0.0f;
1400 
1401     Util::PanInfo panInfo;
1402     PanCurveToPanInfo( panInfo, m_PanCurve );
1403 
1404     const OutputMode mode = HardwareManager::GetInstance().GetOutputMode();
1405 
1406     // left, right の計算
1407     switch ( mode )
1408     {
1409     case OUTPUT_MODE_MONO:
1410         CalcPanForMono( left, right, panInfo );
1411         break;
1412     case OUTPUT_MODE_STEREO:
1413     case OUTPUT_MODE_SURROUND:
1414         if ( ( m_ChannelCount > 1 ) && ( m_PanMode == PAN_MODE_BALANCE ) )
1415         {
1416             CalcBarancePanForStereo( left, right, m_Pan, channelIndex, panInfo );
1417         }
1418         else
1419         {
1420             register f32 voicePan = m_Pan;
1421             if ( m_ChannelCount == 2 )
1422             {
1423                 if ( channelIndex == 0 ) { voicePan -= 1.0f; }
1424                 if ( channelIndex == 1 ) { voicePan += 1.0f; }
1425             }
1426             CalcDualPanForStereo( left, right, voicePan, panInfo );
1427         }
1428         break;
1429     }
1430 
1431     // front, rear の計算
1432     switch ( mode )
1433     {
1434     case OUTPUT_MODE_MONO:
1435     case OUTPUT_MODE_STEREO:
1436         CalcSurroundPanForMono( front, rear, panInfo );
1437         break;
1438     case OUTPUT_MODE_SURROUND:
1439         CalcSurroundPanForSurround( front, rear, m_SurroundPan, panInfo );
1440         break;
1441     }
1442 
1443     // MixParam の計算
1444     register f32 tmpVol[nn::snd::CHANNEL_INDEX_NUM];
1445     tmpVol[nn::snd::CHANNEL_INDEX_FRONT_LEFT]  = front * left;
1446     tmpVol[nn::snd::CHANNEL_INDEX_FRONT_RIGHT] = front * right;
1447     tmpVol[nn::snd::CHANNEL_INDEX_REAR_LEFT]   = rear * left;
1448     tmpVol[nn::snd::CHANNEL_INDEX_REAR_RIGHT]  = rear * right;
1449 
1450     for ( int i = 0; i < nn::snd::CHANNEL_INDEX_NUM; i++ )
1451     {
1452         mix->mainBus[i] = main * tmpVol[i];
1453         mix->auxBusA[i] = fx[0] * tmpVol[i];
1454         mix->auxBusB[i] = fx[1] * tmpVol[i];
1455     }
1456 #ifdef NW_DEBUG
1457     s_Pan = m_Pan;
1458     s_SurroundPan = m_SurroundPan;
1459     s_Mix = *mix;
1460 #endif
1461     // NN_LOG("Front (%.2f, %.2f)  Rear(%.2f, %.2f)\n",
1462     //         mix->mainBus[0], mix->mainBus[1],
1463     //         mix->mainBus[2], mix->mainBus[3] );
1464 }
1465 #endif   // NW_PLATFORM_CTRWIN
1466 
1467 
RunAllHardwareChannel()1468 void Voice::RunAllHardwareChannel()
1469 {
1470     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1471     {
1472         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1473         if ( pChannel != NULL )
1474         {
1475 #ifdef NW_PLATFORM_CTRWIN
1476             pChannel->Run();
1477 #else
1478 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1479             pChannel->SetState( nn::snd::Voice::STATE_PLAY );
1480 #endif
1481 #endif
1482         }
1483     }
1484 }
1485 
StopAllHardwareChannel()1486 void Voice::StopAllHardwareChannel()
1487 {
1488     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1489     {
1490         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1491         if ( pChannel != NULL )
1492         {
1493 #ifdef NW_PLATFORM_CTRWIN
1494             pChannel->Stop();
1495 #else
1496 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1497             pChannel->SetState( nn::snd::Voice::STATE_STOP );
1498 #endif
1499 #endif
1500         }
1501     }
1502 }
1503 
PauseAllHardwareChannel()1504 void Voice::PauseAllHardwareChannel()
1505 {
1506     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1507     {
1508         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1509         if ( pChannel != NULL )
1510         {
1511 #ifdef NW_PLATFORM_CTRWIN
1512             pChannel->Stop();
1513 #else
1514 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1515             pChannel->SetState( nn::snd::Voice::STATE_PAUSE );
1516 #endif
1517 #endif
1518         }
1519     }
1520 }
1521 
GetHardwareChannel(int channelIndex) const1522 const HardwareChannel* Voice::GetHardwareChannel( int channelIndex ) const
1523 {
1524     NW_ASSERT( channelIndex < CHANNEL_MAX );
1525     return m_pHardwareChannel[ channelIndex ];
1526 }
1527 
UpdateVoicesPriority()1528 void Voice::UpdateVoicesPriority()
1529 {
1530     if ( m_Priority == PRIORITY_RELEASE ) return;
1531 
1532     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1533     {
1534         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1535         if ( pChannel != NULL )
1536         {
1537 #ifdef NW_PLATFORM_CTRWIN
1538             pChannel->SetPriority( VOICE_PRIORITY_USE );
1539 #else
1540             pChannel->SetPriority( m_Priority );
1541 #endif
1542         }
1543     }
1544 }
1545 
GetCurrentPlayingSample() const1546 u32 Voice::GetCurrentPlayingSample() const
1547 {
1548     if ( ! IsActive() ) return 0;
1549 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1550     return m_pHardwareChannel[0]->GetPlayPosition();
1551 #else
1552     return 0;
1553 #endif
1554 }
1555 
1556 
1557 #ifdef NW_PLATFORM_CTRWIN
StopAtPoint(int channelIndex,const void * baseAddress,u32 samples)1558 void Voice::StopAtPoint( int channelIndex, const void* baseAddress, u32 samples )
1559 {
1560     HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1561     if ( pChannel != NULL )
1562     {
1563         pChannel->StopAtPoint( baseAddress, samples );
1564     }
1565 }
1566 
SetLoopFlag(bool loopFlag)1567 void Voice::SetLoopFlag( bool loopFlag )
1568 {
1569     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1570     {
1571         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1572         if ( pChannel != NULL )
1573         {
1574             pChannel->SetLoopFlag( loopFlag );
1575         }
1576     }
1577 }
1578 
SetLoopStart(s32 channelIndex,const void * baseAddress,u32 samples)1579 void Voice::SetLoopStart( s32 channelIndex, const void* baseAddress, u32 samples )
1580 {
1581     HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1582     if ( pChannel != NULL )
1583     {
1584         pChannel->SetLoopStart( baseAddress, samples );
1585     }
1586 }
1587 
SetLoopEnd(s32 channelIndex,const void * baseAddress,u32 samples)1588 void Voice::SetLoopEnd( s32 channelIndex, const void* baseAddress, u32 samples )
1589 {
1590     HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1591     if ( pChannel != NULL )
1592     {
1593         pChannel->SetLoopEnd( baseAddress, samples );
1594     }
1595 }
1596 
SetDspAdpcmLoop(s32 channelIndex,const DspAdpcmLoopParam * param)1597 void Voice::SetDspAdpcmLoop( s32 channelIndex, const DspAdpcmLoopParam* param )
1598 {
1599     HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1600     if ( pChannel != NULL )
1601     {
1602         pChannel->SetDspAdpcmLoop( param );
1603     }
1604 }
1605 #endif // NW_PLATFORM_CTRWIN
1606 
GetFormat() const1607 nw::snd::SampleFormat Voice::GetFormat() const
1608 {
1609     NW_ASSERT( IsActive() );
1610     if ( IsActive() )
1611     {
1612         return m_Format;
1613     }
1614     return SAMPLE_FORMAT_PCM_S16;
1615 }
1616 
IsRun() const1617 bool Voice::IsRun() const
1618 {
1619     if ( IsActive() )
1620     {
1621 #ifdef NW_PLATFORM_CTRWIN
1622         return m_pHardwareChannel[0]->IsPlaying();
1623 #else
1624     #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1625         return ( m_pHardwareChannel[0]->GetState() == nn::snd::Voice::STATE_PLAY );
1626     #endif
1627 #endif
1628     }
1629     return false;
1630 }
1631 
1632 
IsPlayFinished() const1633 bool Voice::IsPlayFinished() const
1634 {
1635     if ( IsActive() )
1636     {
1637 #ifdef NW_PLATFORM_CTRWIN
1638         return m_pHardwareChannel[0]->IsPlayFinished();
1639 #else
1640         if ( m_pLastWaveBuffer == NULL ) return false;
1641         if ( m_pLastWaveBuffer->status == nn::snd::WaveBuffer::STATUS_DONE )
1642         {
1643             return true;
1644         }
1645 #endif
1646     }
1647     return false;
1648 }
1649 
SetFrontBypass(bool isFrontBypass)1650 void Voice::SetFrontBypass( bool isFrontBypass )
1651 {
1652 #ifdef NW_PLATFORM_CTR
1653     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1654     {
1655         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1656         if ( pChannel != NULL )
1657         {
1658             pChannel->SetFrontBypassFlag( isFrontBypass );
1659         }
1660     }
1661 #endif
1662 }
1663 
SetInterpolationType(u8 interpolationType)1664 void Voice::SetInterpolationType( u8 interpolationType )
1665 {
1666 #ifdef NW_PLATFORM_CTR
1667     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1668     {
1669         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1670         if ( pChannel != NULL )
1671         {
1672             pChannel->SetInterpolationType( GetSdkInterpolationType( interpolationType ) );
1673         }
1674     }
1675 #endif
1676 }
1677 
1678 #ifdef NW_PLATFORM_CTR
AppendWaveBuffer(int channelIndex,nn::snd::WaveBuffer * pBuffer,bool lastFlag)1679 void Voice::AppendWaveBuffer(
1680     int channelIndex,
1681     nn::snd::WaveBuffer* pBuffer,
1682     bool lastFlag
1683 )
1684 {
1685     HardwareChannel* pChannel = m_pHardwareChannel[ channelIndex ];
1686 
1687     NW_NULL_ASSERT( pBuffer );
1688     NW_NULL_ASSERT( pChannel );
1689 
1690 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1691     pChannel->AppendWaveBuffer( pBuffer );
1692 //    NN_LOG("[forSDK] WaveBuffer: address(%p) size(%d)\n",
1693 //             pBuffer->bufferAddress, pBuffer->sampleLength );
1694 #endif
1695 
1696     if ( lastFlag )
1697     {
1698         m_pLastWaveBuffer = pBuffer;
1699     }
1700 }
1701 
SetAdpcmParam(int channelIndex,const nn::snd::AdpcmParam & param)1702 void Voice::SetAdpcmParam(
1703         int channelIndex,
1704         const nn::snd::AdpcmParam& param )
1705 {
1706     HardwareChannel* pChannel = m_pHardwareChannel[ channelIndex ];
1707 
1708     NW_NULL_ASSERT( pChannel );
1709 
1710 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1711     pChannel->SetAdpcmParam( param );
1712 #else
1713     NW_UNUSED_VARIABLE( param );
1714 #endif
1715 }
1716 
FrameToByte(u32 sample,nw::snd::SampleFormat format)1717 u32 Voice::FrameToByte( u32 sample, nw::snd::SampleFormat format )
1718 {
1719     switch ( format )
1720     {
1721     case nw::snd::SAMPLE_FORMAT_DSP_ADPCM:
1722         {
1723             return ( FrameToNibbleAddress( sample ) >> 1 );
1724         }
1725     case nw::snd::SAMPLE_FORMAT_PCM_S8:
1726         {
1727             return sample;
1728         }
1729     case nw::snd::SAMPLE_FORMAT_PCM_S16:
1730         {
1731             return ( sample << 1 );
1732         }
1733     default:
1734         NW_ASSERTMSG( false, "Invalid format\n" );
1735         return 0;
1736     }
1737 }
1738 #endif
1739 
1740 #ifdef NW_DEBUG
GetDebugMixParam(f32 & pan,f32 & span,nw::snd::internal::MixParam & mix)1741 void Voice::GetDebugMixParam( f32& pan, f32& span, nw::snd::internal::MixParam& mix )
1742 {
1743     pan = s_Pan;
1744     span = s_SurroundPan;
1745     mix = s_Mix;
1746 }
1747 #endif
1748 
1749 } // namespace nw::snd::internal::driver
1750 } // namespace nw::snd::internal
1751 } // namespace nw::snd
1752 } // namespace nw
1753