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