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