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