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