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