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