1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_Channel.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 
20 #include <nw/snd/snd_Channel.h>
21 #include <nw/snd/snd_Util.h>
22 #include <nw/snd/snd_HardwareManager.h>
23 #include <nw/snd/snd_VoiceManager.h>
24 #include <nw/snd/snd_ChannelManager.h>
25 #include <nw/snd/snd_Global.h>
26 
27 namespace nw {
28 namespace snd {
29 namespace internal {
30 namespace driver {
31 
32 namespace
33 {
GetNwInterpolationTypeFromHardwareManager()34 u8 GetNwInterpolationTypeFromHardwareManager()
35 {
36     u8 result = 0;  // 0: 4点補間, 1: 線形補間, 2: 補間なし
37                     // (BankFile::VelocityRegion に格納されている値と同じ)
38     switch ( HardwareManager::GetInstance().GetSrcType() )
39     {
40     case SRC_TYPE_NONE:
41         result = 2;
42         break;
43     case SRC_TYPE_LINEAR:
44         result = 1;
45         break;
46     case SRC_TYPE_4TAP:
47         // 0 のまま
48         break;
49     }
50 
51     return result;
52 }
53 } // anonymous namespace
54 
55 /* ========================================================================
56         member function
57    ======================================================================== */
58 
59 /*---------------------------------------------------------------------------*
60   Name:         Channel
61 
62   Description:  コンストラクタ
63 
64   Arguments:    None.
65 
66   Returns:      None.
67  *---------------------------------------------------------------------------*/
Channel()68 Channel::Channel()
69 : m_Disposer( this ),
70   m_PauseFlag( 0 ),
71   m_ActiveFlag( false ),
72   m_AllocFlag( false ),
73   m_pVoice( NULL )
74 {
75     DisposeCallbackManager::GetInstance().RegisterDisposeCallback( &m_Disposer );
76 }
77 
78 /*---------------------------------------------------------------------------*
79   Name:         Channel
80 
81   Description:  デストラクタ
82 
83   Arguments:    None.
84 
85   Returns:      None.
86  *---------------------------------------------------------------------------*/
~Channel()87 Channel::~Channel()
88 {
89     DisposeCallbackManager::GetInstance().UnregisterDisposeCallback( &m_Disposer );
90 }
91 
92 /*---------------------------------------------------------------------------*
93   Name:         InitParam
94 
95   Description:  パラメータの初期化
96 
97   Arguments:
98 
99   Returns:      None.
100  *---------------------------------------------------------------------------*/
InitParam(ChannelCallback callback,u32 callbackData)101 void Channel::InitParam( ChannelCallback callback, u32 callbackData )
102 {
103     m_pNextLink = NULL; // ユーザー領域
104 
105     m_Callback     = callback;
106     m_CallbackData = callbackData;
107 
108 //  msync_flag = 0; // NOTE: クリアしてはならない!
109     m_PauseFlag          = false;
110     m_AutoSweep          = true;
111     m_ReleasePriorityFixFlag = false;
112     m_IsIgnoreNoteOff    = false;
113 
114 #ifdef NW_PLATFORM_CTR
115 	m_LoopFlag = false;
116     m_LoopStartFrame = 0;
117 #endif
118 
119     m_Length             = 0;
120     m_Key                = KEY_INIT;
121     m_OriginalKey        = ORIGINAL_KEY_INIT;
122     m_InitVolume         = 1.0f;
123     m_InitPan            = 0.0f;
124     m_InitSurroundPan    = 0.0f;
125     m_Tune               = 1.0f;
126 
127     m_Cent = 0.0f;
128     m_CentPitch = 1.0f;
129 
130     m_UserVolume         = 1.0f;
131     m_UserPitch          = 0.0f;
132     m_UserPitchRatio     = 1.0f;
133     m_UserPan            = 0.0f;
134     m_UserSurroundPan    = 0.0f;
135     m_UserLpfFreq        = 0.0f;
136     m_BiquadType         = BIQUAD_FILTER_TYPE_NONE;
137     m_BiquadValue        = 0.0f;
138     m_MainSend           = 0.0f;
139     for ( int i=0; i<AUX_BUS_NUM; i++ )
140     {
141         m_FxSend[ i ]    = 0.0f;
142     }
143 
144     m_SilenceVolume.InitValue( SILENCE_VOLUME_MAX );
145 
146     m_SweepPitch   = 0.0f;
147     m_SweepLength  = 0;
148     m_SweepCounter = 0;
149 
150     m_CurveAdshr.Initialize();
151     m_Lfo.GetParam().Initialize();
152     m_LfoTarget = LFO_TARGET_PITCH;
153 
154     m_PanMode = PAN_MODE_DUAL;
155     m_PanCurve = PAN_CURVE_SQRT;
156 
157     m_KeyGroupId = 0;
158     m_InterpolationType = GetNwInterpolationTypeFromHardwareManager();
159         // WSD はこの値が反映される。
160         // SEQ は Channel::SetInterpolationType によって設定された値
161         // (インストのベロシティリージョンに書かれた値) が反映される。
162 }
163 
164 // #define NW_SND_CHANNEL_PROFILE
165 #ifdef NW_PLATFORM_CTR
166 #ifdef NW_SND_CHANNEL_PROFILE
167 namespace
168 {
169 nn::os::Tick s_Tick;
170 int s_Count;
171 }
GetTick()172 nn::os::Tick Channel::GetTick()
173 {
174     nn::os::Tick ret = static_cast<nn::os::Tick>( s_Tick / s_Count );
175     s_Tick = nn::os::Tick( 0 );
176     s_Count = 0;
177     return ret;
178 }
179 #else
GetTick()180 nn::os::Tick Channel::GetTick()
181 {
182     return nn::os::Tick( 0 );
183 }
184 #endif
185 #endif
186 
187 /*---------------------------------------------------------------------------*
188   Name:         Update
189 
190   Description:  チャンネルのフレームワーク
191 
192   Arguments:    doPeriodicProc - 周期処理を行うかどうかのフラグ
193 
194   Returns:      None.
195  *---------------------------------------------------------------------------*/
Update(bool doPeriodicProc)196 void Channel::Update( bool doPeriodicProc )
197 {
198     if ( ! m_ActiveFlag ) return;
199 
200 #ifdef NW_SND_CHANNEL_PROFILE
201     nn::os::Tick tick = nn::os::Tick::GetSystemCurrent();
202 #endif
203 
204     if ( m_PauseFlag ) doPeriodicProc = false;
205 
206     // volume
207     m_SilenceVolume.Update();
208     register f32 volume = m_InitVolume * m_UserVolume * m_SilenceVolume.GetValue() / SILENCE_VOLUME_MAX;
209 
210     // 減衰完了チェック
211 #if 0
212     if ( m_CurveAdshr.GetStatus() == CurveAdshr::STATUS_RELEASE )
213     {
214         f32 envelopValue = Util::CalcVolumeRatio( m_CurveAdshr.GetValue() );
215         if ( envelopValue == 0.0f )
216         {
217             Stop();
218             return;
219         }
220     }
221 #else
222     if ( m_CurveAdshr.GetStatus() == CurveAdshr::STATUS_RELEASE &&
223          m_CurveAdshr.GetValue() < -90.4f )
224     {
225         Stop();
226         return;
227     }
228 #endif
229 
230     // pitch
231     f32 cent = m_Key - m_OriginalKey + m_UserPitch + GetSweepValue();
232     if ( m_LfoTarget == LFO_TARGET_PITCH )
233     {
234         cent += m_Lfo.GetValue();
235     }
236 
237     register f32 pitch;
238     if ( cent == m_Cent )
239     {
240         pitch = m_CentPitch;
241     }
242     else
243     {
244         pitch = Util::CalcPitchRatio( static_cast<s32>( cent * ( 1 << Util::PITCH_DIVISION_BIT ) ) );
245         m_Cent = cent;
246         m_CentPitch = pitch;
247     }
248 
249     pitch = pitch * m_Tune * m_UserPitchRatio;
250 
251     // pan
252     f32 pan = m_InitPan + m_UserPan;
253     if ( m_LfoTarget == LFO_TARGET_PAN )
254     {
255         pan += m_Lfo.GetValue();
256     }
257 
258     // surround pan
259     f32 surroundPan = m_InitSurroundPan + m_UserSurroundPan;
260 
261     // カウンタ更新
262     if ( doPeriodicProc )
263     {
264         if ( m_AutoSweep )
265         {
266             UpdateSweep( HardwareManager::SOUND_FRAME_INTERVAL_MSEC );
267         }
268         m_Lfo.Update( HardwareManager::SOUND_FRAME_INTERVAL_MSEC );
269         m_CurveAdshr.Update( HardwareManager::SOUND_FRAME_INTERVAL_MSEC );
270     }
271 
272     // lpf
273     f32 lpfFreq = 1.0f + m_UserLpfFreq;
274 
275     // ボリューム値更新
276 #if 1
277     volume *= Util::CalcVolumeRatio( m_CurveAdshr.GetValue() );
278     if ( m_LfoTarget == LFO_TARGET_VOLUME )
279     {
280         volume *= Util::CalcVolumeRatio( m_Lfo.GetValue() * 6.0f );
281     }
282 #else
283     register f32 decay = m_CurveAdshr.GetValue();
284     if ( m_LfoTarget == LFO_TARGET_VOLUME )
285     {
286         decay += m_Lfo.GetValue() * 6.0f;
287     }
288     volume *= Util::CalcVolumeRatio( decay );
289 #endif
290 
291     if ( m_pVoice != NULL )
292     {
293         m_pVoice->SetVolume( volume );
294         m_pVoice->SetPitch( pitch );
295         m_pVoice->SetPan( pan );
296         m_pVoice->SetSurroundPan( surroundPan );
297 
298         m_pVoice->SetLpfFreq( lpfFreq );
299         m_pVoice->SetBiquadFilter( m_BiquadType, m_BiquadValue );
300 
301         m_pVoice->SetMainSend( m_MainSend );
302         for ( int i=0; i<AUX_BUS_NUM; i++ )
303         {
304             m_pVoice->SetFxSend( static_cast<AuxBus>( i ), m_FxSend[ i ] );
305         }
306     }
307 
308 #ifdef NW_SND_CHANNEL_PROFILE
309     s_Tick += nn::os::Tick::GetSystemCurrent() - tick;
310     s_Count += 1;
311 #endif
312 }
313 
314 /*---------------------------------------------------------------------------*
315   Name:         Start
316 
317   Description:  チャンネルでPCMを再生します
318 
319   Arguments:    wave - 波形情報構造体のポインタ
320                 data - 波形データアドレス
321                 length - 発音長
322 
323   Returns:      成功したかどうか
324  *---------------------------------------------------------------------------*/
Start(const WaveInfo & waveInfo,int length,u32 startOffset)325 void Channel::Start( const WaveInfo& waveInfo, int length, u32 startOffset )
326 {
327     // Channel Param
328     m_Length = length;
329     m_Lfo.Reset();
330     m_CurveAdshr.Reset();
331     m_SweepCounter = 0;
332 
333     m_pVoice->Initialize( waveInfo, startOffset );
334 
335 #ifdef NW_PLATFORM_CTR
336     AppendWaveBuffer( waveInfo );
337 #endif
338 
339     m_pVoice->SetPanMode( m_PanMode );
340     m_pVoice->SetPanCurve( m_PanCurve );
341     m_pVoice->SetInterpolationType( m_InterpolationType );
342 
343     m_pVoice->Start();
344     m_ActiveFlag = true;
345 }
346 
347 #ifdef NW_PLATFORM_CTR
AppendWaveBuffer(const WaveInfo & waveInfo)348 void Channel::AppendWaveBuffer( const WaveInfo& waveInfo )
349 {
350     m_LoopFlag = waveInfo.loopFlag;
351     m_LoopStartFrame = waveInfo.loopStartFrame;
352 
353     u32 loopStartByte = Voice::FrameToByte( m_LoopStartFrame, waveInfo.sampleFormat );
354     u32 loopEndByte = Voice::FrameToByte( waveInfo.loopEndFrame, waveInfo.sampleFormat );
355     // NN_LOG("[Channel] LS %d[fr] %d[byte], LE %d[fr] %d[byte]\n",
356     //         waveInfo.loopStartFrame, loopStartByte,
357     //         waveInfo.loopEndFrame, loopEndByte );
358 
359     const int channelCount = m_pVoice->GetChannelCount();
360     for ( int ch = 0; ch < channelCount; ch++ )
361     {
362         const void* dataAddress = waveInfo.channelParam[ch].dataAddress;
363 
364         nn::snd::AdpcmContext& adpcmContext = m_AdpcmContext[ch];
365         nn::snd::AdpcmContext& adpcmLoopContext = m_AdpcmLoopContext[ch];
366 
367         // ADPCM の場合、コンテキストを生成
368         if ( waveInfo.sampleFormat == SAMPLE_FORMAT_DSP_ADPCM )
369         {
370             const DspAdpcmParam* pParam = &waveInfo.channelParam[ch].adpcmParam;
371 
372             // コンテキスト設定 (nn::snd::Voice が使用するまで SDK ユーザー側で保持)
373             adpcmContext.pred_scale = pParam->predScale;
374             adpcmContext.yn1 = pParam->yn1;
375             adpcmContext.yn2 = pParam->yn2;
376 
377             if ( waveInfo.loopFlag )
378             {
379                 const DspAdpcmLoopParam* pLoopParam = &waveInfo.channelParam[ch].adpcmLoopParam;
380                 adpcmLoopContext.pred_scale = pLoopParam->loopPredScale;
381                 adpcmLoopContext.yn1 = pLoopParam->loopYn1;
382                 adpcmLoopContext.yn2 = pLoopParam->loopYn2;
383             }
384 
385             // 係数設定 (u16 coef[16])
386             nn::snd::AdpcmParam param;
387             for ( int i = 0; i < 16; i++ )
388             {
389                 param.coef[i] = pParam->coef[i];
390                 // NN_LOG("[ADPCM] coef(%d)[0x%04x]\n", i, param.coef[i] );
391             }
392             m_pVoice->SetAdpcmParam( ch, param );
393         }
394 
395         {
396             // |------------------|<---------- loop --------->| のような波形を、
397             //
398             // |<-------------- pBuffer0 -------------------->|
399             //                    |<--------- pBuffer1 ------>| として利用する。
400 
401             // WaveBuffer の登録
402             nn::snd::WaveBuffer* pBuffer0 = &m_WaveBuffer[ch][0];
403             nn::snd::WaveBuffer* pBuffer1 = &m_WaveBuffer[ch][1];
404 
405             nn::snd::InitializeWaveBuffer( pBuffer0 );
406             pBuffer0->bufferAddress = dataAddress;
407             pBuffer0->sampleLength = waveInfo.loopEndFrame;
408             pBuffer0->loopFlag = false;
409             if ( waveInfo.sampleFormat == SAMPLE_FORMAT_DSP_ADPCM )
410             {
411                 pBuffer0->pAdpcmContext = &adpcmContext;
412             }
413             m_pVoice->AppendWaveBuffer( ch, pBuffer0, ! waveInfo.loopFlag );
414 
415             if ( waveInfo.loopFlag )
416             {
417                 nn::snd::InitializeWaveBuffer( pBuffer1 );
418                 pBuffer1->bufferAddress = ut::AddOffsetToPtr( dataAddress, loopStartByte );
419                 pBuffer1->sampleLength = waveInfo.loopEndFrame - m_LoopStartFrame;
420                 pBuffer1->loopFlag = true;
421                 if ( waveInfo.sampleFormat == SAMPLE_FORMAT_DSP_ADPCM )
422                 {
423                     pBuffer1->pAdpcmContext = &adpcmLoopContext;
424                 }
425                 m_pVoice->AppendWaveBuffer( ch, pBuffer1, true );
426             }
427 
428             // NN_LOG("fmt(%d) [0] len(%d) lp(%d) a(%d,%d,%d) [1] len(%d) lp(%d) a(%d,%d,%d)\n",
429             //         waveInfo.sampleFormat,
430             //         pBuffer0->sampleLength, pBuffer0->loopFlag,
431             //         pBuffer0->pAdpcmContext.pred_scale,
432             //         pBuffer0->pAdpcmContext.yn1,
433             //         pBuffer0->pAdpcmContext.yn2,
434             //         pBuffer1->sampleLength, pBuffer1->loopFlag,
435             //         pBuffer1->pAdpcmContext.pred_scale,
436             //         pBuffer1->pAdpcmContext.yn1,
437             //         pBuffer1->pAdpcmContext.yn2 );
438         }
439     }
440 }
441 #endif
442 
443 /*---------------------------------------------------------------------------*
444   Name:         Release
445 
446   Description:  チャンネルをリリース状態にします
447 
448   Arguments:    None.
449 
450   Returns:      None.
451  *---------------------------------------------------------------------------*/
Release()452 void Channel::Release()
453 {
454     if ( m_CurveAdshr.GetStatus() != CurveAdshr::STATUS_RELEASE )
455     {
456         if ( m_pVoice != NULL )
457         {
458             if ( ! m_ReleasePriorityFixFlag )
459             {
460                 m_pVoice->SetPriority( Channel::PRIORITY_RELEASE );
461             }
462         }
463         m_CurveAdshr.SetStatus( CurveAdshr::STATUS_RELEASE );
464     }
465     m_PauseFlag = false;
466 }
467 
468 /*---------------------------------------------------------------------------*
469   Name:         NoteOff
470 
471   Description:  チャンネルをノートオフします
472                 通常はリリース状態になります
473 
474   Arguments:    なし
475 
476   Returns:      なし
477  *---------------------------------------------------------------------------*/
NoteOff()478 void Channel::NoteOff()
479 {
480     if ( m_IsIgnoreNoteOff ) return;
481 
482     Release();
483 }
484 
485 /*---------------------------------------------------------------------------*
486     Name:           Stop
487 
488     Description:    チャンネルを停止します
489 
490     Arguments:      無し
491 
492     Returns:        無し
493  *---------------------------------------------------------------------------*/
Stop()494 void Channel::Stop()
495 {
496     if ( m_pVoice == NULL ) return;
497 
498     m_pVoice->Stop();
499     m_pVoice->Free();
500     m_pVoice = NULL;
501 
502     m_PauseFlag = false;
503     m_ActiveFlag = false;
504 
505     if ( m_Callback != NULL )
506     {
507         m_Callback( this, CALLBACK_STATUS_STOPPED, m_CallbackData );
508     }
509     if ( m_AllocFlag )
510     {
511         m_AllocFlag = false;
512         ChannelManager::GetInstance().Free( this );
513     }
514 }
515 
UpdateSweep(int count)516 void Channel::UpdateSweep( int count )
517 {
518     m_SweepCounter += count;
519     if ( m_SweepCounter > m_SweepLength )
520     {
521         m_SweepCounter = m_SweepLength;
522     }
523 }
524 
SetSweepParam(f32 sweepPitch,int sweepTime,bool autoUpdate)525 void Channel::SetSweepParam( f32 sweepPitch, int sweepTime, bool autoUpdate )
526 {
527     m_SweepPitch = sweepPitch;
528     m_SweepLength = sweepTime;
529     m_AutoSweep = autoUpdate;
530     m_SweepCounter = 0;
531 }
532 
GetSweepValue() const533 f32 Channel::GetSweepValue() const
534 {
535     if ( m_SweepPitch == 0.0f ) return 0.0f;
536     if ( m_SweepCounter >= m_SweepLength ) return 0.0f;
537 
538     f32 sweep = m_SweepPitch;
539     sweep *= m_SweepLength - m_SweepCounter;
540 
541     NW_ASSERT( m_SweepLength != 0 );
542     sweep /= m_SweepLength;
543 
544     return sweep;
545 }
546 
SetBiquadFilter(int type,f32 value)547 void Channel::SetBiquadFilter( int type, f32 value )
548 {
549     m_BiquadType = static_cast<u8>( type );
550     m_BiquadValue = value;
551 }
552 
GetCurrentPlayingSample() const553 u32 Channel::GetCurrentPlayingSample() const
554 {
555     if ( ! m_ActiveFlag ) return 0;
556 
557     NW_NULL_ASSERT( m_pVoice );
558 
559 #ifdef NW_PLATFORM_CTRWIN
560     return m_pVoice->GetCurrentPlayingSample();
561 #else
562     if ( m_LoopFlag && m_WaveBuffer[0][0].status == nn::snd::WaveBuffer::STATUS_DONE )
563     {
564         return m_LoopStartFrame + m_pVoice->GetCurrentPlayingSample();
565     }
566     else
567     {
568         return m_pVoice->GetCurrentPlayingSample();
569     }
570 #endif
571 }
572 
573 /*---------------------------------------------------------------------------*
574     Name:           VoiceCallback
575 
576     Description:    ボイスがドロップされたときに呼ばれる
577 
578     Arguments:      param: ボイスへのポインタ
579 
580     Returns:        none
581  *---------------------------------------------------------------------------*/
VoiceCallbackFunc(Voice * voice,Voice::VoiceCallbackStatus status,void * arg)582 void Channel::VoiceCallbackFunc(
583     Voice* voice,
584     Voice::VoiceCallbackStatus status,
585     void* arg
586 )
587 {
588     NW_NULL_ASSERT( arg );
589 
590     ChannelCallbackStatus chStatus = CALLBACK_STATUS_FINISH;    // 適当な初期化
591     switch ( status )
592     {
593     case Voice::CALLBACK_STATUS_FINISH_WAVE:
594         chStatus = CALLBACK_STATUS_FINISH;
595         voice->Free();
596         break;
597     case Voice::CALLBACK_STATUS_CANCEL:
598         chStatus = CALLBACK_STATUS_CANCEL;
599         voice->Free();
600         break;
601     case Voice::CALLBACK_STATUS_DROP_VOICE:
602         chStatus = CALLBACK_STATUS_DROP;
603         break;
604     case Voice::CALLBACK_STATUS_DROP_DSP:
605         chStatus = CALLBACK_STATUS_DROP;
606         break;
607     }
608 
609     Channel* channel = static_cast<Channel*>( arg );
610 
611     if ( channel->m_Callback != NULL ) {
612         channel->m_Callback( channel, chStatus, channel->m_CallbackData );
613     }
614 
615     channel->m_pVoice = NULL;
616     channel->m_PauseFlag = false;
617     channel->m_ActiveFlag = false;
618 
619     channel->m_AllocFlag = false;
620     ChannelManager::GetInstance().Free( channel );
621 }
622 
623 /*---------------------------------------------------------------------------*
624   Name:         AllocChannel
625 
626   Description:  チャンネルを確保します
627 
628   Arguments:    priority - プライオリティ
629                 callback - チャンネルコールバック関数
630                 callbackData - チャンネルコールバック関数のユーザー引数
631 
632   Returns:      確保したチャンネルのポインタ
633                 確保できなかった場合はNULL
634  *---------------------------------------------------------------------------*/
AllocChannel(int voiceChannelCount,int priority,Channel::ChannelCallback callback,u32 callbackData)635 Channel* Channel::AllocChannel(
636     int voiceChannelCount,
637     int priority,
638     Channel::ChannelCallback callback,
639     u32 callbackData
640 )
641 {
642     NW_MINMAX_ASSERT( priority, 0, 255 );
643 
644     Channel* channel = ChannelManager::GetInstance().Alloc();
645     if ( channel == NULL )
646     {
647         NW_WARNING( channel, "Channel Allocation failed!" );
648         return NULL;
649     }
650     channel->m_AllocFlag = true;
651 
652     // ボイス取得
653     Voice* voice = VoiceManager::GetInstance().AllocVoice(
654         voiceChannelCount,
655         priority,
656         VoiceCallbackFunc,
657         channel
658     );
659     if ( voice == NULL )
660     {
661         ChannelManager::GetInstance().Free( channel );
662         return NULL;
663     }
664 
665     channel->m_pVoice = voice;
666     channel->InitParam( callback, callbackData );
667 
668     return channel;
669 }
670 
671 /*---------------------------------------------------------------------------*
672   Name:         FreeChannel
673 
674   Description:  チャンネルを解放します
675 
676   Arguments:    channel - チャンネルポインタ
677 
678   Returns:      None.
679  *---------------------------------------------------------------------------*/
FreeChannel(Channel * channel)680 void Channel::FreeChannel( Channel* channel )
681 {
682     if ( channel == NULL ) return;
683 
684     channel->m_Callback     = NULL;
685     channel->m_CallbackData = 0;
686 }
687 
InvalidateData(const void * start,const void * end)688 void Channel::Disposer::InvalidateData( const void* start, const void* end )
689 {
690     if ( m_pChannel->m_pVoice == NULL ) return;
691 
692     // 一つでも start, end 内に波形データを含んでいたらボイス停止
693     bool disposeFlag = false;
694     int channelCount = m_pChannel->m_pVoice->GetChannelCount();
695 #ifdef NW_PLATFORM_CTR
696     for ( int channelIndex = 0; channelIndex < channelCount; channelIndex++ )
697     {
698         for ( int waveBufferIndex = 0; waveBufferIndex < WAVE_BUFFER_MAX; waveBufferIndex++ )
699         {
700             const nn::snd::WaveBuffer& waveBuffer =
701                 m_pChannel->m_WaveBuffer[ channelIndex ][ waveBufferIndex ];
702             if ( waveBuffer.status == nn::snd::WaveBuffer::STATUS_FREE ||
703                  waveBuffer.status == nn::snd::WaveBuffer::STATUS_DONE )
704             {
705                 continue;
706             }
707 
708             const void* bufferEnd = ut::AddOffsetToPtr(
709                     waveBuffer.bufferAddress,
710                     Util::GetByteBySample(
711                         waveBuffer.sampleLength,
712                         m_pChannel->m_pVoice->GetFormat() ) );
713 
714             if ( start <= bufferEnd && end >= waveBuffer.bufferAddress )
715             {
716                 disposeFlag = true;
717                 break;
718             }
719         }
720     }
721 #endif
722 
723     if ( disposeFlag )
724     {
725         if ( m_pChannel->m_Callback != NULL ) {
726             m_pChannel->m_Callback( m_pChannel, CALLBACK_STATUS_CANCEL, m_pChannel->m_CallbackData );
727             m_pChannel->m_Callback = NULL;
728         }
729 
730         m_pChannel->Stop();
731     }
732 }
733 
734 
735 } // namespace nw::snd::internal::driver
736 } // namespace nw::snd::internal
737 } // namespace nw::snd
738 } // namespace nw
739 
740