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: 27401 $
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                             // TODO: const 参照版 API が入ったら、入れ替える
1205                     }
1206                   #else
1207                     BiquadFilterCallback::Coefficients coef;
1208                     cb->GetCoefficients( m_BiquadType, m_BiquadValue, &coef );
1209 
1210                     pChannel->SetFilterType( nn::snd::FILTER_TYPE_BIQUAD );
1211                     pChannel->SetBiquadFilterCoefficients( &coef );
1212                   #endif
1213                 }
1214             }
1215         #endif
1216         }
1217     }
1218 }
1219 
1220 #ifdef NW_PLATFORM_CTRWIN
CalcMixParam(int channelIndex,nw::snd::internal::MixParam * mix)1221 void Voice::CalcMixParam(
1222         int channelIndex,
1223         nw::snd::internal::MixParam* mix
1224 )
1225 {
1226     NW_NULL_ASSERT( mix );
1227     // NW_NULL_ASSERT( rmtMix );
1228 
1229     f32 mainVolume = 1.0f;
1230     f32 mainSend = m_MainSend;
1231     f32 fxSend[ AUX_BUS_NUM ];
1232     for ( int i = 0; i < AUX_BUS_NUM; i++ )
1233     {
1234         fxSend[ i ] = m_FxSend[ i ];
1235     }
1236 
1237     f32 main = mainVolume * ut::Clamp( mainSend, 0.0f, 1.0f );
1238     f32 fx[ AUX_BUS_NUM ];
1239     for ( int i = 0; i < AUX_BUS_NUM; i++ )
1240     {
1241         fx[ i ] = mainVolume * ut::Clamp( fxSend[ i ], 0.0f, 1.0f );
1242     }
1243 
1244     // ------------------------------------------------------------------------
1245     //  パン設定
1246     f32 left = 0.0f;
1247     f32 right = 0.0f;
1248     f32 lrMixed = 0.0f;
1249     f32 surround = 0.0f;
1250     f32 front = 0.0f;
1251     f32 rear = 0.0f;
1252 
1253     Util::PanInfo panInfo;
1254     PanCurveToPanInfo( panInfo, m_PanCurve );
1255 
1256     if ( ( m_ChannelCount > 1 ) && ( m_PanMode == PAN_MODE_BALANCE ) )
1257     {
1258         // バランスとしてパンを処理する
1259 
1260         f32 pan = m_Pan;
1261         f32 span = m_SurroundPan;
1262 
1263         if ( channelIndex == 0 )
1264         {
1265             left  = Util::CalcPanRatio( pan, panInfo );
1266             right = 0.0f;
1267         }
1268         else if ( channelIndex == 1 )
1269         {
1270             left  = 0.0f;
1271             right = Util::CalcPanRatio( PAN_CENTER - pan, panInfo );
1272         }
1273 
1274         front = Util::CalcSurroundPanRatio( span, panInfo );
1275         rear  = Util::CalcSurroundPanRatio( SPAN_REAR - span, panInfo );
1276     }
1277     else
1278     {
1279         // 通常の定位処理
1280 
1281         f32 voicePan = 0.0f;
1282 
1283         // チャンネルごとにオフセットを与える
1284         if ( m_ChannelCount == 2 )
1285         {
1286             if ( channelIndex == 0 ) voicePan = -1.0f;
1287             if ( channelIndex == 1 ) voicePan = 1.0f;
1288         }
1289 
1290         f32 pan;
1291         // f32 span;        // TODO: PC 版のサラウンドはひとまず後回し
1292         switch ( HardwareManager::GetInstance().GetOutputMode() )
1293         {
1294         // TODO:[SURR] case OUTPUT_MODE_DPL2:
1295         // TODO:[SURR]     TransformDpl2Pan(
1296         // TODO:[SURR]         &pan,
1297         // TODO:[SURR]         &span,
1298         // TODO:[SURR]         m_Pan + voicePan,
1299         // TODO:[SURR]         m_SurroundPan
1300         // TODO:[SURR]     );
1301         // TODO:[SURR]     break;
1302         case OUTPUT_MODE_MONO:
1303         case OUTPUT_MODE_STEREO:
1304         // TODO:[SURR] case OUTPUT_MODE_SURROUND:
1305         default:
1306             pan = m_Pan + voicePan;
1307             // TODO:[SURR] span = m_SurroundPan;
1308             break;
1309         }
1310 
1311         // pan
1312         left  = Util::CalcPanRatio( pan, panInfo );
1313         right = Util::CalcPanRatio( PAN_CENTER - pan, panInfo );
1314 
1315         // TODO:[SURR] front = Util::CalcSurroundPanRatio( span, panInfo );
1316         // TODO:[SURR] rear  = Util::CalcSurroundPanRatio( SPAN_REAR - span, panInfo );
1317     }
1318 
1319     // TODO:[SURR] surround  = Util::CalcVolumeRatio( SURROUND_ATTENUATED_DB );
1320     lrMixed   = ( left + right ) * 0.5f;
1321 
1322 
1323     // -----------------------------------------------------------------
1324     // 構造体にセットする
1325 
1326     // 各チャンネルのボリューム
1327     f32 m_l = 0.0f;           // 左のボリューム
1328     f32 m_r = 0.0f;           // 右のボリューム
1329     f32 auxL[ AUX_BUS_NUM ];  // Aux? の 左ボリューム
1330     f32 auxR[ AUX_BUS_NUM ];  // Aux? の 右ボリューム
1331 
1332     switch ( HardwareManager::GetInstance().GetOutputMode() )
1333     {
1334     case OUTPUT_MODE_STEREO:
1335         m_l  = main * left ;
1336         m_r  = main * right;
1337         for ( int i = 0; i < AUX_BUS_NUM; i++ )
1338         {
1339             auxL[ i ] = fx[ i ] * left;
1340             auxR[ i ] = fx[ i ] * right;
1341         }
1342         // a_l  = fx_a * left ;
1343         // a_r  = fx_a * right;
1344         // a_s  = fx_a * 0.0f;
1345         // b_l  = fx_b * left ;
1346         // b_r  = fx_b * right;
1347         // b_s  = fx_b * 0.0f;
1348         // c_l  = fx_c * left ;
1349         // c_r  = fx_c * right;
1350         // c_s  = fx_c * 0.0f;
1351         break;
1352     case OUTPUT_MODE_MONO:
1353         m_l  = main * lrMixed;
1354         m_r  = main * lrMixed;
1355         for ( int i = 0; i < AUX_BUS_NUM; i++ )
1356         {
1357             auxL[ i ] = fx[ i ] * lrMixed;
1358             auxR[ i ] = fx[ i ] * lrMixed;
1359         }
1360         // a_l  = fx_a * lrMixed;
1361         // a_r  = fx_a * lrMixed;
1362         // a_s  = fx_a * 0.0f;
1363         // b_l  = fx_b * lrMixed;
1364         // b_r  = fx_b * lrMixed;
1365         // b_s  = fx_b * 0.0f;
1366         // c_l  = fx_c * lrMixed;
1367         // c_r  = fx_c * lrMixed;
1368         // c_s  = fx_c * 0.0f;
1369         break;
1370     }
1371 
1372     // 計算された値を、mix構造体に代入する値に変換して代入
1373 	mix->mainBus[nn::snd::CHANNEL_INDEX_FRONT_LEFT]     = CalcMixVolume( m_l );
1374 	mix->mainBus[nn::snd::CHANNEL_INDEX_FRONT_RIGHT]     = CalcMixVolume( m_r );
1375 
1376     mix->auxBusA[nn::snd::CHANNEL_INDEX_FRONT_LEFT] = CalcMixVolume( auxL[ 0 ] );
1377     mix->auxBusA[nn::snd::CHANNEL_INDEX_FRONT_RIGHT] = CalcMixVolume( auxR[ 0 ] );
1378 
1379 	mix->auxBusB[nn::snd::CHANNEL_INDEX_FRONT_LEFT] = CalcMixVolume( auxL[ 1 ] );
1380     mix->auxBusB[nn::snd::CHANNEL_INDEX_FRONT_RIGHT] = CalcMixVolume( auxR[ 1 ] );
1381 }
1382 
1383 #else   // for NW_PLATFORM_CTR
1384 
CalcMixParam(int channelIndex,nw::snd::internal::MixParam * mix)1385 void Voice::CalcMixParam(
1386         int channelIndex,
1387         nw::snd::internal::MixParam* mix
1388 )
1389 {
1390     NW_NULL_ASSERT( mix );
1391 
1392     f32 main = ut::Clamp( m_MainSend, 0.0f, 1.0f );
1393     f32 fx[ AUX_BUS_NUM ];
1394     for ( int i = 0; i < AUX_BUS_NUM; i++ )
1395     {
1396         fx[ i ] = ut::Clamp( m_FxSend[i], 0.0f, 1.0f );
1397     }
1398 
1399     register f32 left, right, front, rear;
1400     left = right = front = rear = 0.0f;
1401 
1402     Util::PanInfo panInfo;
1403     PanCurveToPanInfo( panInfo, m_PanCurve );
1404 
1405     const OutputMode mode = HardwareManager::GetInstance().GetOutputMode();
1406 
1407     // left, right の計算
1408     switch ( mode )
1409     {
1410     case OUTPUT_MODE_MONO:
1411         CalcPanForMono( left, right, panInfo );
1412         break;
1413     case OUTPUT_MODE_STEREO:
1414     case OUTPUT_MODE_SURROUND:
1415         if ( ( m_ChannelCount > 1 ) && ( m_PanMode == PAN_MODE_BALANCE ) )
1416         {
1417             CalcBarancePanForStereo( left, right, m_Pan, channelIndex, panInfo );
1418         }
1419         else
1420         {
1421             register f32 voicePan = m_Pan;
1422             if ( m_ChannelCount == 2 )
1423             {
1424                 if ( channelIndex == 0 ) { voicePan -= 1.0f; }
1425                 if ( channelIndex == 1 ) { voicePan += 1.0f; }
1426             }
1427             CalcDualPanForStereo( left, right, voicePan, panInfo );
1428         }
1429         break;
1430     }
1431 
1432     // front, rear の計算
1433     switch ( mode )
1434     {
1435     case OUTPUT_MODE_MONO:
1436     case OUTPUT_MODE_STEREO:
1437         CalcSurroundPanForMono( front, rear, panInfo );
1438         break;
1439     case OUTPUT_MODE_SURROUND:
1440         CalcSurroundPanForSurround( front, rear, m_SurroundPan, panInfo );
1441         break;
1442     }
1443 
1444     // MixParam の計算
1445     register f32 tmpVol[nn::snd::CHANNEL_INDEX_NUM];
1446     tmpVol[nn::snd::CHANNEL_INDEX_FRONT_LEFT]  = front * left;
1447     tmpVol[nn::snd::CHANNEL_INDEX_FRONT_RIGHT] = front * right;
1448     tmpVol[nn::snd::CHANNEL_INDEX_REAR_LEFT]   = rear * left;
1449     tmpVol[nn::snd::CHANNEL_INDEX_REAR_RIGHT]  = rear * right;
1450 
1451     for ( int i = 0; i < nn::snd::CHANNEL_INDEX_NUM; i++ )
1452     {
1453         mix->mainBus[i] = main * tmpVol[i];
1454         mix->auxBusA[i] = fx[0] * tmpVol[i];
1455         mix->auxBusB[i] = fx[1] * tmpVol[i];
1456     }
1457 #ifdef NW_DEBUG
1458     s_Pan = m_Pan;
1459     s_SurroundPan = m_SurroundPan;
1460     s_Mix = *mix;
1461 #endif
1462     // NN_LOG("Front (%.2f, %.2f)  Rear(%.2f, %.2f)\n",
1463     //         mix->mainBus[0], mix->mainBus[1],
1464     //         mix->mainBus[2], mix->mainBus[3] );
1465 }
1466 #endif   // NW_PLATFORM_CTRWIN
1467 
1468 
RunAllHardwareChannel()1469 void Voice::RunAllHardwareChannel()
1470 {
1471     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1472     {
1473         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1474         if ( pChannel != NULL )
1475         {
1476 #ifdef NW_PLATFORM_CTRWIN
1477             pChannel->Run();
1478 #else
1479 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1480             pChannel->SetState( nn::snd::Voice::STATE_PLAY );
1481 #endif
1482 #endif
1483         }
1484     }
1485 }
1486 
StopAllHardwareChannel()1487 void Voice::StopAllHardwareChannel()
1488 {
1489     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1490     {
1491         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1492         if ( pChannel != NULL )
1493         {
1494 #ifdef NW_PLATFORM_CTRWIN
1495             pChannel->Stop();
1496 #else
1497 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1498             pChannel->SetState( nn::snd::Voice::STATE_STOP );
1499 #endif
1500 #endif
1501         }
1502     }
1503 }
1504 
PauseAllHardwareChannel()1505 void Voice::PauseAllHardwareChannel()
1506 {
1507     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1508     {
1509         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1510         if ( pChannel != NULL )
1511         {
1512 #ifdef NW_PLATFORM_CTRWIN
1513             pChannel->Stop();
1514 #else
1515 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1516             pChannel->SetState( nn::snd::Voice::STATE_PAUSE );
1517 #endif
1518 #endif
1519         }
1520     }
1521 }
1522 
GetHardwareChannel(int channelIndex) const1523 const HardwareChannel* Voice::GetHardwareChannel( int channelIndex ) const
1524 {
1525     NW_ASSERT( channelIndex < CHANNEL_MAX );
1526     return m_pHardwareChannel[ channelIndex ];
1527 }
1528 
UpdateVoicesPriority()1529 void Voice::UpdateVoicesPriority()
1530 {
1531     if ( m_Priority == PRIORITY_RELEASE ) return;
1532 
1533     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1534     {
1535         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1536         if ( pChannel != NULL )
1537         {
1538 #ifdef NW_PLATFORM_CTRWIN
1539             pChannel->SetPriority( VOICE_PRIORITY_USE );
1540 #else
1541             pChannel->SetPriority( m_Priority );
1542 #endif
1543         }
1544     }
1545 }
1546 
GetCurrentPlayingSample() const1547 u32 Voice::GetCurrentPlayingSample() const
1548 {
1549     if ( ! IsActive() ) return 0;
1550 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1551     return m_pHardwareChannel[0]->GetPlayPosition();
1552 #else
1553     return 0;
1554 #endif
1555 }
1556 
1557 
1558 #ifdef NW_PLATFORM_CTRWIN
StopAtPoint(int channelIndex,const void * baseAddress,u32 samples)1559 void Voice::StopAtPoint( int channelIndex, const void* baseAddress, u32 samples )
1560 {
1561     HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1562     if ( pChannel != NULL )
1563     {
1564         pChannel->StopAtPoint( baseAddress, samples );
1565     }
1566 }
1567 
SetLoopFlag(bool loopFlag)1568 void Voice::SetLoopFlag( bool loopFlag )
1569 {
1570     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1571     {
1572         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1573         if ( pChannel != NULL )
1574         {
1575             pChannel->SetLoopFlag( loopFlag );
1576         }
1577     }
1578 }
1579 
SetLoopStart(s32 channelIndex,const void * baseAddress,u32 samples)1580 void Voice::SetLoopStart( s32 channelIndex, const void* baseAddress, u32 samples )
1581 {
1582     HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1583     if ( pChannel != NULL )
1584     {
1585         pChannel->SetLoopStart( baseAddress, samples );
1586     }
1587 }
1588 
SetLoopEnd(s32 channelIndex,const void * baseAddress,u32 samples)1589 void Voice::SetLoopEnd( s32 channelIndex, const void* baseAddress, u32 samples )
1590 {
1591     HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1592     if ( pChannel != NULL )
1593     {
1594         pChannel->SetLoopEnd( baseAddress, samples );
1595     }
1596 }
1597 
SetDspAdpcmLoop(s32 channelIndex,const DspAdpcmLoopParam * param)1598 void Voice::SetDspAdpcmLoop( s32 channelIndex, const DspAdpcmLoopParam* param )
1599 {
1600     HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1601     if ( pChannel != NULL )
1602     {
1603         pChannel->SetDspAdpcmLoop( param );
1604     }
1605 }
1606 #endif // NW_PLATFORM_CTRWIN
1607 
GetFormat() const1608 nw::snd::SampleFormat Voice::GetFormat() const
1609 {
1610     NW_ASSERT( IsActive() );
1611     if ( IsActive() )
1612     {
1613         return m_Format;
1614     }
1615     return SAMPLE_FORMAT_PCM_S16;
1616 }
1617 
IsRun() const1618 bool Voice::IsRun() const
1619 {
1620     if ( IsActive() )
1621     {
1622 #ifdef NW_PLATFORM_CTRWIN
1623         return m_pHardwareChannel[0]->IsPlaying();
1624 #else
1625     #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1626         return ( m_pHardwareChannel[0]->GetState() == nn::snd::Voice::STATE_PLAY );
1627     #endif
1628 #endif
1629     }
1630     return false;
1631 }
1632 
1633 
IsPlayFinished() const1634 bool Voice::IsPlayFinished() const
1635 {
1636     if ( IsActive() )
1637     {
1638 #ifdef NW_PLATFORM_CTRWIN
1639         return m_pHardwareChannel[0]->IsPlayFinished();
1640 #else
1641         if ( m_pLastWaveBuffer == NULL ) return false;
1642         if ( m_pLastWaveBuffer->status == nn::snd::WaveBuffer::STATUS_DONE )
1643         {
1644             return true;
1645         }
1646 #endif
1647     }
1648     return false;
1649 }
1650 
SetFrontBypass(bool isFrontBypass)1651 void Voice::SetFrontBypass( bool isFrontBypass )
1652 {
1653 #ifdef NW_PLATFORM_CTR
1654     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1655     {
1656         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1657         if ( pChannel != NULL )
1658         {
1659             pChannel->SetFrontBypassFlag( isFrontBypass );
1660         }
1661     }
1662 #endif
1663 }
1664 
SetInterpolationType(u8 interpolationType)1665 void Voice::SetInterpolationType( u8 interpolationType )
1666 {
1667 #ifdef NW_PLATFORM_CTR
1668     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
1669     {
1670         HardwareChannel* pChannel = m_pHardwareChannel[channelIndex];
1671         if ( pChannel != NULL )
1672         {
1673             pChannel->SetInterpolationType( GetSdkInterpolationType( interpolationType ) );
1674         }
1675     }
1676 #endif
1677 }
1678 
1679 #ifdef NW_PLATFORM_CTR
AppendWaveBuffer(int channelIndex,nn::snd::WaveBuffer * pBuffer,bool lastFlag)1680 void Voice::AppendWaveBuffer(
1681     int channelIndex,
1682     nn::snd::WaveBuffer* pBuffer,
1683     bool lastFlag
1684 )
1685 {
1686     HardwareChannel* pChannel = m_pHardwareChannel[ channelIndex ];
1687 
1688     NW_NULL_ASSERT( pBuffer );
1689     NW_NULL_ASSERT( pChannel );
1690 
1691 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1692     pChannel->AppendWaveBuffer( pBuffer );
1693 //    NN_LOG("[forSDK] WaveBuffer: address(%p) size(%d)\n",
1694 //             pBuffer->bufferAddress, pBuffer->sampleLength );
1695 #endif
1696 
1697     if ( lastFlag )
1698     {
1699         m_pLastWaveBuffer = pBuffer;
1700     }
1701 }
1702 
SetAdpcmParam(int channelIndex,const nn::snd::AdpcmParam & param)1703 void Voice::SetAdpcmParam(
1704         int channelIndex,
1705         const nn::snd::AdpcmParam& param )
1706 {
1707     HardwareChannel* pChannel = m_pHardwareChannel[ channelIndex ];
1708 
1709     NW_NULL_ASSERT( pChannel );
1710 
1711 #ifndef NW_SND_DEBUG_NOUSE_CTRSDK
1712     pChannel->SetAdpcmParam( param );
1713 #else
1714     NW_UNUSED_VARIABLE( param );
1715 #endif
1716 }
1717 
FrameToByte(u32 sample,nw::snd::SampleFormat format)1718 u32 Voice::FrameToByte( u32 sample, nw::snd::SampleFormat format )
1719 {
1720     switch ( format )
1721     {
1722     case nw::snd::SAMPLE_FORMAT_DSP_ADPCM:
1723         {
1724             return ( FrameToNibbleAddress( sample ) >> 1 );
1725         }
1726     case nw::snd::SAMPLE_FORMAT_PCM_S8:
1727         {
1728             return sample;
1729         }
1730     case nw::snd::SAMPLE_FORMAT_PCM_S16:
1731         {
1732             return ( sample << 1 );
1733         }
1734     default:
1735         NW_ASSERTMSG( false, "Invalid format\n" );
1736         return 0;
1737     }
1738 }
1739 #endif
1740 
1741 #ifdef NW_DEBUG
GetDebugMixParam(f32 & pan,f32 & span,nw::snd::internal::MixParam & mix)1742 void Voice::GetDebugMixParam( f32& pan, f32& span, nw::snd::internal::MixParam& mix )
1743 {
1744     pan = s_Pan;
1745     span = s_SurroundPan;
1746     mix = s_Mix;
1747 }
1748 #endif
1749 
1750 } // namespace nw::snd::internal::driver
1751 } // namespace nw::snd::internal
1752 } // namespace nw::snd
1753 } // namespace nw
1754