1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: snd_WaveSoundPlayer.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: 24222 $
14 *---------------------------------------------------------------------------*/
15
16 #include "precompiled.h"
17
18 #include <nw/snd/snd_WaveSoundPlayer.h>
19 #include <nw/snd/snd_DisposeCallbackManager.h>
20
21 namespace nw {
22 namespace snd {
23 namespace internal {
24 namespace driver {
25
26 /* ========================================================================
27 public function
28 ======================================================================== */
29
30 /*---------------------------------------------------------------------------*
31 Name: WaveSoundPlayer
32
33 Description: コンストラクタ
34
35 Arguments: None.
36
37 Returns: None.
38 *---------------------------------------------------------------------------*/
WaveSoundPlayer()39 WaveSoundPlayer::WaveSoundPlayer()
40 {
41 }
42
Initialize()43 void WaveSoundPlayer::Initialize()
44 {
45 BasicSoundPlayer::Initialize();
46
47 m_ReleasePriorityFixFlag = false;
48 m_PanRange = 1.0f;
49
50 m_Priority = DEFAULT_PRIORITY;
51 m_pCallback = NULL;
52 m_CallbackData = 0;
53
54
55 m_pWaveSoundData = NULL;
56 m_WaveSoundIndex = -1;
57
58 m_WaveSoundInfo.pitch = 1.0f;
59 m_WaveSoundInfo.pan = 64;
60 m_WaveSoundInfo.surroundPan = 0;
61 for ( int i = 0; i < AUX_BUS_NUM; i++ )
62 {
63 m_WaveSoundInfo.fxSend[ i ] = 0;
64 }
65 m_WaveSoundInfo.mainSend = 127;
66
67 m_LfoParam.Initialize();
68
69 m_WavePlayFlag = false;
70
71 m_pChannel = NULL;
72 }
73
Finalize()74 void WaveSoundPlayer::Finalize()
75 {
76 // 無効化リストから削除
77 if ( m_ActiveFlag )
78 {
79 DisposeCallbackManager::GetInstance().UnregisterDisposeCallback( this );
80 m_ActiveFlag = false;
81 }
82
83 // チャンネル解放
84 CloseChannel();
85
86 BasicSoundPlayer::Finalize();
87 }
88
89 /*---------------------------------------------------------------------------*
90 Name: Prepare
91
92 Description: ウェーブサウンドの再生準備を行います
93
94 Arguments: playerNo - プレイヤー番号
95 seqBase - シーケンスデータベースアドレス
96 seqOffset - シーケンスデータオフセット
97 bank_p - バンクポインタ
98
99 Returns: None.
100 *---------------------------------------------------------------------------*/
Prepare(const void * waveSoundBase,int index,StartOffsetType startOffsetType,int startOffset,const WaveSoundCallback * callback,u32 callbackData)101 bool WaveSoundPlayer::Prepare(
102 const void* waveSoundBase,
103 int index,
104 StartOffsetType startOffsetType,
105 int startOffset,
106 const WaveSoundCallback* callback,
107 u32 callbackData
108 )
109 {
110 //-----------------------------------------------------------------------------
111 // 再生中シーケンスの停止
112 if ( m_ActiveFlag )
113 {
114 FinishPlayer();
115 }
116
117 //-----------------------------------------------------------------------------
118 // プレイヤー初期化
119 m_pCallback = callback;
120 m_CallbackData = callbackData;
121
122 //-----------------------------------------------------------------------------
123 // データ開始
124 m_pWaveSoundData = waveSoundBase;
125 m_WaveSoundIndex = index;
126 m_StartOffsetType = startOffsetType;
127 m_StartOffset = startOffset;
128
129 // 無効化リストに追加
130 DisposeCallbackManager::GetInstance().RegisterDisposeCallback( this );
131
132 // シーケンス準備完了
133 m_ActiveFlag = true;
134
135 return true;
136 }
137
138 /*---------------------------------------------------------------------------*
139 Name: Start
140
141 Description: シーケンスをスタートします
142
143 Arguments: None.
144
145 Returns: None.
146 *---------------------------------------------------------------------------*/
Start()147 void WaveSoundPlayer::Start()
148 {
149 // プレイヤーリストに追加
150 SoundThread::GetInstance().RegisterPlayerCallback( this );
151
152 m_StartedFlag = true;
153 }
154
155 /*---------------------------------------------------------------------------*
156 Name: Stop
157
158 Description: シーケンスを止めます
159
160 Arguments: playerNo - プレイヤー番号
161
162 Returns: None.
163 *---------------------------------------------------------------------------*/
Stop()164 void WaveSoundPlayer::Stop()
165 {
166 FinishPlayer();
167 }
168
169 /*---------------------------------------------------------------------------*
170 Name: Pause
171
172 Description: シーケンスを一時停止または再開します
173
174 Arguments: playerNo - プレイヤー番号
175 flag - trueで一時停止、falseで再開します
176
177 Returns: None.
178 *---------------------------------------------------------------------------*/
Pause(bool flag)179 void WaveSoundPlayer::Pause( bool flag )
180 {
181 m_PauseFlag = static_cast<u8>( flag );
182
183 // チャンネルを一時停止
184 if ( IsChannelActive() )
185 {
186 if ( m_pChannel->IsPause() != flag )
187 {
188 m_pChannel->Pause( flag );
189 }
190 }
191 }
192
193 /*---------------------------------------------------------------------------*
194 Name: SetPanRange
195
196 Description: パンレンジの変更
197
198 Arguments: panRange - パンレンジ
199
200 Returns: なし
201 *---------------------------------------------------------------------------*/
SetPanRange(float panRange)202 void WaveSoundPlayer::SetPanRange( float panRange )
203 {
204 m_PanRange = panRange;
205 }
206
207 /*---------------------------------------------------------------------------*
208 Name: SetChannelPriority
209
210 Description: チャンネルプライオリティの変更
211
212 Arguments: prio - プライオリティ
213
214 Returns: なし
215 *---------------------------------------------------------------------------*/
SetChannelPriority(int priority)216 void WaveSoundPlayer::SetChannelPriority( int priority )
217 {
218 NW_MINMAX_ASSERT( priority, 0, 127 );
219 m_Priority = static_cast<u8>( priority );
220 }
221
SetReleasePriorityFix(bool fix)222 void WaveSoundPlayer::SetReleasePriorityFix( bool fix )
223 {
224 m_ReleasePriorityFixFlag = fix;
225 }
226
227 /*---------------------------------------------------------------------------*
228 Name: InvalidateData
229
230 Description: 指定シーケンスデータを使用しているシーケンスを無効化します
231
232 Arguments: start - シーケンスデータ開始アドレス
233 end - シーケンスデータ終了アドレス
234
235 Returns: None.
236 *---------------------------------------------------------------------------*/
InvalidateData(const void * start,const void * end)237 void WaveSoundPlayer::InvalidateData( const void* start, const void* end )
238 {
239 if ( m_ActiveFlag )
240 {
241 const void* current = GetWaveSoundDataAddress();
242 if ( start <= current && current <= end )
243 {
244 FinishPlayer();
245 }
246 }
247 }
248
249 /*---------------------------------------------------------------------------*
250 Name: FinishPlayer
251
252 Description: プレイヤーの完了処理を行います。
253
254 Arguments: player : プレイヤーポインタ
255
256 Returns: None
257 *---------------------------------------------------------------------------*/
FinishPlayer()258 void WaveSoundPlayer::FinishPlayer()
259 {
260 // プレイヤーリストから削除
261 if ( m_StartedFlag )
262 {
263 SoundThread::GetInstance().UnregisterPlayerCallback( this );
264 m_StartedFlag = false;
265 }
266 }
267
268 /*---------------------------------------------------------------------------*
269 Name: ReadWaveSoundDataInfo
270
271 Description: ウェーブサウンドデータの情報取得
272
273 Arguments: info - ウェーブサウンドデータ情報構造体
274
275 Returns: 現在の再生しているウェーブサウンドデータの情報を取得する
276 *---------------------------------------------------------------------------*/
ReadWaveSoundDataInfo(WaveSoundDataInfo * info) const277 bool WaveSoundPlayer::ReadWaveSoundDataInfo( WaveSoundDataInfo* info ) const
278 {
279 WaveSoundInfo waveSoundInfo; // 現状、データは格納されるが本関数では利用されない
280 WaveInfo waveInfo;
281 WaveSoundNoteInfo noteInfo; // 現状、データは格納されるが本関数では利用されない
282 bool result = m_pCallback->GetWaveSoundData(
283 &waveSoundInfo,
284 ¬eInfo,
285 &waveInfo,
286 m_pWaveSoundData,
287 m_WaveSoundIndex,
288 0,
289 m_CallbackData
290 );
291
292 if ( result )
293 {
294 info->loopFlag = ( waveInfo.loopFlag != 0 );
295 info->sampleRate = static_cast<int>( waveInfo.sampleRate );
296 info->loopStart = waveInfo.loopStartFrame;
297 info->loopEnd = waveInfo.loopEndFrame;
298 }
299
300 return result;
301 }
302
303 /*---------------------------------------------------------------------------*
304 Name: GetPlaySamplePosition
305
306 Description: 現在の再生位置の取得
307
308 Arguments: なし
309
310 Returns: 現在の再生位置をサンプル単位で返す
311 再生していない場合は、負の値を返す
312 *---------------------------------------------------------------------------*/
GetPlaySamplePosition() const313 s32 WaveSoundPlayer::GetPlaySamplePosition() const
314 {
315 if ( m_pChannel == NULL ) return -1;
316
317 return static_cast<s32>( m_pChannel->GetCurrentPlayingSample() );
318 }
319
320 /*---------------------------------------------------------------------------*
321 Name: Update
322
323 Description: シーケンスのフレーム処理を行います
324
325 Arguments: None.
326
327 Returns: None.
328 *---------------------------------------------------------------------------*/
Update()329 void WaveSoundPlayer::Update()
330 {
331 NW_ASSERT( m_ActiveFlag );
332 if ( ! m_ActiveFlag ) return;
333 if ( ! m_StartedFlag ) return;
334
335 if ( ! m_PauseFlag )
336 {
337 // 波形終端終了チェック
338 if ( ( m_WavePlayFlag ) && ( m_pChannel == NULL ) )
339 {
340 m_FinishFlag = true;
341 FinishPlayer();
342 return;
343 }
344
345 // 波形再生
346 if ( ! m_WavePlayFlag )
347 {
348 if ( ! StartChannel( m_pCallback, m_CallbackData ) )
349 {
350 FinishPlayer();
351 return;
352 }
353 }
354 }
355
356 UpdateChannel();
357 }
358
359 /*---------------------------------------------------------------------------*
360 Name: StartChannel
361
362 Description: トラックのシーケンス処理を進めます
363
364 Arguments:
365
366 Returns: シーケンス継続時には0を、完了時にはー1を返します
367 *---------------------------------------------------------------------------*/
StartChannel(const WaveSoundCallback * callback,u32 callbackData)368 bool WaveSoundPlayer::StartChannel( const WaveSoundCallback* callback, u32 callbackData )
369 {
370 const int priority = GetChannelPriority() + DEFAULT_PRIORITY;
371
372 WaveInfo waveInfo;
373 WaveSoundNoteInfo noteInfo; // 現在の実装では使用されない。
374 // 「マルチトラックウェーブサウンド」的な拡張を想定。
375 bool result = callback->GetWaveSoundData(
376 &m_WaveSoundInfo,
377 ¬eInfo,
378 &waveInfo,
379 m_pWaveSoundData,
380 m_WaveSoundIndex,
381 0,
382 callbackData
383 );
384 if ( ! result ) return false;
385
386 // 開始オフセット
387 u32 startOffsetSamples = 0;
388 if ( m_StartOffsetType == START_OFFSET_TYPE_SAMPLE )
389 {
390 startOffsetSamples = static_cast<u32>( m_StartOffset );
391 }
392 else if ( m_StartOffsetType == START_OFFSET_TYPE_MILLISEC )
393 {
394 startOffsetSamples = static_cast<u32>(
395 static_cast<s64>( m_StartOffset ) * waveInfo.sampleRate / 1000
396 );
397 }
398
399 // 開始オフセットが範囲外なので再生せずに終了
400 if ( startOffsetSamples > waveInfo.loopEndFrame ) return false;
401
402 Channel* channel;
403 channel = Channel::AllocChannel(
404 ut::Min( static_cast<int>( waveInfo.channelCount ), 2 ),
405 priority,
406 ChannelCallbackFunc,
407 reinterpret_cast<u32>( this )
408 );
409
410 // 鳴らせなかったらエラーでサウンド終了
411 if ( channel == NULL ) return false;
412
413 // エンベロープ設定
414 channel->SetAttack( m_WaveSoundInfo.adshr.attack );
415 channel->SetHold( m_WaveSoundInfo.adshr.hold );
416 channel->SetDecay( m_WaveSoundInfo.adshr.decay );
417 channel->SetSustain( m_WaveSoundInfo.adshr.sustain );
418 channel->SetRelease( m_WaveSoundInfo.adshr.release );
419
420 channel->SetReleasePriorityFix( m_ReleasePriorityFixFlag );
421 channel->SetFrontBypass( IsFrontBypass() );
422
423 channel->Start( waveInfo, -1, startOffsetSamples );
424
425 // チャンネルリストへの結合
426 m_pChannel = channel;
427
428 m_WavePlayFlag = true;
429
430 return true;
431 }
432
433 /*---------------------------------------------------------------------------*
434 Name: CloseChannel
435
436 Description: チャンネルを閉じます
437
438 Arguments: None.
439
440 Returns: None.
441 *---------------------------------------------------------------------------*/
CloseChannel()442 void WaveSoundPlayer::CloseChannel()
443 {
444 // Release
445 if ( IsChannelActive() )
446 {
447 UpdateChannel();
448 m_pChannel->Release();
449 }
450
451 // Free
452 if ( m_pChannel != NULL )
453 {
454 Channel::FreeChannel( m_pChannel );
455 }
456 m_pChannel = NULL;
457 }
458
459 /*---------------------------------------------------------------------------*
460 Name: UpdateChannel
461
462 Description: トラックが保持しているチャンネルのパラメータを更新します
463
464 Arguments: None.
465
466 Returns: None.
467 *---------------------------------------------------------------------------*/
UpdateChannel()468 void WaveSoundPlayer::UpdateChannel()
469 {
470 if ( m_pChannel == NULL ) return;
471
472 // volume
473 float volume = 1.0f;
474 volume *= GetVolume();
475
476 float pitchRatio = 1.0f;
477 pitchRatio *= GetPitch();
478 pitchRatio *= m_WaveSoundInfo.pitch;
479
480 // pan
481 float pan = 0.0f;
482 if ( m_WaveSoundInfo.pan <= 1 ) // panの1と2は同じ値
483 {
484 pan += static_cast<f32>( static_cast<int>( m_WaveSoundInfo.pan ) - 63 ) / 63.0f;
485 }
486 else
487 {
488 pan += static_cast<f32>( static_cast<int>( m_WaveSoundInfo.pan ) - 64 ) / 63.0f;
489 }
490 pan *= GetPanRange();
491 pan += GetPan();
492
493 // surround pan
494 f32 surroundPan = 0.0f;
495 if ( m_WaveSoundInfo.surroundPan <= 63 )
496 {
497 surroundPan += static_cast<f32>( m_WaveSoundInfo.surroundPan ) / 63.0f;
498 }
499 else
500 {
501 surroundPan += static_cast<f32>( m_WaveSoundInfo.surroundPan + 1 ) / 64.0f;
502 // NOTE: y = (1/64) * x + 1/64 = (x/64) + (1/64) = (x+1)/64
503 }
504 surroundPan += GetSurroundPan();
505
506 // lpf freq
507 float lpfFreq = 0.0f;
508 lpfFreq += GetLpfFreq();
509
510 // biquad filter
511 int biquadType = GetBiquadFilterType();
512 float biquadValue = GetBiquadFilterValue();
513
514 // main send
515 float mainSend = 0.0f;
516 mainSend += static_cast<float>( m_WaveSoundInfo.mainSend ) / 127.0f - 1.0f;
517 mainSend += GetMainSend();
518
519 // fx send
520 float fxSend[ AUX_BUS_NUM ];
521 u8 infoSend[ AUX_BUS_NUM ];
522 for ( int i = 0; i < AUX_BUS_NUM; i++ )
523 {
524 infoSend[ i ] = m_WaveSoundInfo.fxSend[ i ];
525 }
526 for ( int i=0; i<AUX_BUS_NUM; i++ )
527 {
528 fxSend[ i ] = 0.0f;
529 fxSend[ i ] += static_cast<float>( infoSend[i] ) / 127.0f;
530 fxSend[ i ] += GetFxSend( static_cast<AuxBus>( i ) );
531 }
532
533 // set channel params of track
534 m_pChannel->SetPanMode( GetPanMode() );
535 m_pChannel->SetPanCurve( GetPanCurve() );
536
537 m_pChannel->SetUserVolume( volume );
538 m_pChannel->SetUserPitchRatio( pitchRatio );
539 m_pChannel->SetUserPan( pan );
540 m_pChannel->SetUserLpfFreq( lpfFreq );
541 m_pChannel->SetBiquadFilter( biquadType, biquadValue );
542 m_pChannel->SetMainSend( mainSend );
543 for ( int i=0; i<AUX_BUS_NUM; i++ )
544 {
545 AuxBus bus = static_cast<AuxBus>( i );
546 m_pChannel->SetFxSend( bus, fxSend[ i ] );
547 }
548 m_pChannel->SetUserSurroundPan( surroundPan );
549
550 m_pChannel->SetLfoParam( m_LfoParam );
551 }
552
553 /*---------------------------------------------------------------------------*
554 Name: ChannelCallbackFunc
555
556 Description: チャンネルから呼びだされるコールバック関数
557
558 Arguments: dropChannel - チャンネルポインタ
559 status - チャンネルコールバックステータス
560 userData - トラックポインタを格納したコールバックユーザーデータ
561
562 Returns: None.
563 *---------------------------------------------------------------------------*/
ChannelCallbackFunc(Channel * dropChannel,Channel::ChannelCallbackStatus status,u32 userData)564 void WaveSoundPlayer::ChannelCallbackFunc(
565 Channel* dropChannel,
566 Channel::ChannelCallbackStatus status,
567 u32 userData
568 )
569 {
570 WaveSoundPlayer* player = reinterpret_cast<WaveSoundPlayer*>( userData );
571
572 NW_NULL_ASSERT( dropChannel );
573 NW_NULL_ASSERT( player );
574 NW_ASSERT( dropChannel == player->m_pChannel );
575
576 if ( status == Channel::CALLBACK_STATUS_FINISH )
577 {
578 Channel::FreeChannel( dropChannel );
579 }
580
581 // チャンネル参照の切断
582 player->m_pChannel = NULL;
583 }
584
585 } // namespace nw::snd::internal::driver
586 } // namespace nw::snd::internal
587 } // namespace nw::snd
588 } // namespace nw
589
590