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