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