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: 27883 $
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 WaveSoundCallbackArg arg =
283 {
284 m_pWaveSoundData,
285 m_WaveSoundIndex,
286 0,
287 m_CallbackData,
288 GetPlayerHeapDataManager()
289 };
290 bool result = m_pCallback->GetWaveSoundData(
291 &waveSoundInfo,
292 ¬eInfo,
293 &waveInfo,
294 arg );
295
296 if ( result )
297 {
298 info->loopFlag = ( waveInfo.loopFlag != 0 );
299 info->sampleRate = static_cast<int>( waveInfo.sampleRate );
300 info->loopStart = waveInfo.loopStartFrame;
301 info->loopEnd = waveInfo.loopEndFrame;
302 }
303
304 return result;
305 }
306
307 /*---------------------------------------------------------------------------*
308 Name: GetPlaySamplePosition
309
310 Description: 現在の再生位置の取得
311
312 Arguments: なし
313
314 Returns: 現在の再生位置をサンプル単位で返す
315 再生していない場合は、負の値を返す
316 *---------------------------------------------------------------------------*/
GetPlaySamplePosition() const317 s32 WaveSoundPlayer::GetPlaySamplePosition() const
318 {
319 if ( m_pChannel == NULL ) return -1;
320
321 return static_cast<s32>( m_pChannel->GetCurrentPlayingSample() );
322 }
323
324 /*---------------------------------------------------------------------------*
325 Name: Update
326
327 Description: シーケンスのフレーム処理を行います
328
329 Arguments: None.
330
331 Returns: None.
332 *---------------------------------------------------------------------------*/
Update()333 void WaveSoundPlayer::Update()
334 {
335 NW_ASSERT( m_ActiveFlag );
336 if ( ! m_ActiveFlag ) return;
337 if ( ! m_StartedFlag ) return;
338
339 if ( ! m_PauseFlag )
340 {
341 // 波形終端終了チェック
342 if ( ( m_WavePlayFlag ) && ( m_pChannel == NULL ) )
343 {
344 m_FinishFlag = true;
345 FinishPlayer();
346 return;
347 }
348
349 // 波形再生
350 if ( ! m_WavePlayFlag )
351 {
352 if ( ! StartChannel( m_pCallback, m_CallbackData ) )
353 {
354 FinishPlayer();
355 return;
356 }
357 }
358 }
359
360 UpdateChannel();
361 }
362
363 /*---------------------------------------------------------------------------*
364 Name: StartChannel
365
366 Description: トラックのシーケンス処理を進めます
367
368 Arguments:
369
370 Returns: シーケンス継続時には0を、完了時にはー1を返します
371 *---------------------------------------------------------------------------*/
StartChannel(const WaveSoundCallback * callback,u32 callbackData)372 bool WaveSoundPlayer::StartChannel( const WaveSoundCallback* callback, u32 callbackData )
373 {
374 const int priority = GetChannelPriority() + DEFAULT_PRIORITY;
375
376 WaveInfo waveInfo;
377 WaveSoundNoteInfo noteInfo; // 現在の実装では使用されない。
378 // 「マルチトラックウェーブサウンド」的な拡張を想定。
379 WaveSoundCallbackArg arg =
380 {
381 m_pWaveSoundData,
382 m_WaveSoundIndex,
383 0,
384 callbackData,
385 GetPlayerHeapDataManager()
386 };
387 bool result = callback->GetWaveSoundData(
388 &m_WaveSoundInfo,
389 ¬eInfo,
390 &waveInfo,
391 arg );
392 if ( ! result ) return false;
393
394 // 開始オフセット
395 u32 startOffsetSamples = 0;
396 if ( m_StartOffsetType == START_OFFSET_TYPE_SAMPLE )
397 {
398 startOffsetSamples = static_cast<u32>( m_StartOffset );
399 }
400 else if ( m_StartOffsetType == START_OFFSET_TYPE_MILLISEC )
401 {
402 startOffsetSamples = static_cast<u32>(
403 static_cast<s64>( m_StartOffset ) * waveInfo.sampleRate / 1000
404 );
405 }
406
407 // 開始オフセットが範囲外なので再生せずに終了
408 if ( startOffsetSamples > waveInfo.loopEndFrame ) return false;
409
410 Channel* channel;
411 channel = Channel::AllocChannel(
412 ut::Min( static_cast<int>( waveInfo.channelCount ), 2 ),
413 priority,
414 ChannelCallbackFunc,
415 reinterpret_cast<u32>( this )
416 );
417
418 // 鳴らせなかったらエラーでサウンド終了
419 if ( channel == NULL ) return false;
420
421 // エンベロープ設定
422 channel->SetAttack( m_WaveSoundInfo.adshr.attack );
423 channel->SetHold( m_WaveSoundInfo.adshr.hold );
424 channel->SetDecay( m_WaveSoundInfo.adshr.decay );
425 channel->SetSustain( m_WaveSoundInfo.adshr.sustain );
426 channel->SetRelease( m_WaveSoundInfo.adshr.release );
427
428 channel->SetReleasePriorityFix( m_ReleasePriorityFixFlag );
429 channel->SetFrontBypass( IsFrontBypass() );
430
431 channel->Start( waveInfo, -1, startOffsetSamples );
432
433 // チャンネルリストへの結合
434 m_pChannel = channel;
435
436 m_WavePlayFlag = true;
437
438 return true;
439 }
440
441 /*---------------------------------------------------------------------------*
442 Name: CloseChannel
443
444 Description: チャンネルを閉じます
445
446 Arguments: None.
447
448 Returns: None.
449 *---------------------------------------------------------------------------*/
CloseChannel()450 void WaveSoundPlayer::CloseChannel()
451 {
452 // Release
453 if ( IsChannelActive() )
454 {
455 UpdateChannel();
456 m_pChannel->Release();
457 }
458
459 // Free
460 if ( m_pChannel != NULL )
461 {
462 Channel::FreeChannel( m_pChannel );
463 }
464 m_pChannel = NULL;
465 }
466
467 /*---------------------------------------------------------------------------*
468 Name: UpdateChannel
469
470 Description: トラックが保持しているチャンネルのパラメータを更新します
471
472 Arguments: None.
473
474 Returns: None.
475 *---------------------------------------------------------------------------*/
UpdateChannel()476 void WaveSoundPlayer::UpdateChannel()
477 {
478 if ( m_pChannel == NULL ) return;
479
480 // volume
481 float volume = 1.0f;
482 volume *= GetVolume();
483
484 float pitchRatio = 1.0f;
485 pitchRatio *= GetPitch();
486 pitchRatio *= m_WaveSoundInfo.pitch;
487
488 // pan
489 float pan = 0.0f;
490 if ( m_WaveSoundInfo.pan <= 1 ) // panの1と2は同じ値
491 {
492 pan += static_cast<f32>( static_cast<int>( m_WaveSoundInfo.pan ) - 63 ) / 63.0f;
493 }
494 else
495 {
496 pan += static_cast<f32>( static_cast<int>( m_WaveSoundInfo.pan ) - 64 ) / 63.0f;
497 }
498 pan *= GetPanRange();
499 pan += GetPan();
500
501 // surround pan
502 f32 surroundPan = 0.0f;
503 if ( m_WaveSoundInfo.surroundPan <= 63 )
504 {
505 surroundPan += static_cast<f32>( m_WaveSoundInfo.surroundPan ) / 63.0f;
506 }
507 else
508 {
509 surroundPan += static_cast<f32>( m_WaveSoundInfo.surroundPan + 1 ) / 64.0f;
510 // NOTE: y = (1/64) * x + 1/64 = (x/64) + (1/64) = (x+1)/64
511 }
512 surroundPan += GetSurroundPan();
513
514 // lpf freq
515 float lpfFreq = 0.0f;
516 lpfFreq += GetLpfFreq();
517
518 // biquad filter
519 int biquadType = GetBiquadFilterType();
520 float biquadValue = GetBiquadFilterValue();
521
522 // main send
523 float mainSend = 0.0f;
524 mainSend += static_cast<float>( m_WaveSoundInfo.mainSend ) / 127.0f - 1.0f;
525 mainSend += GetMainSend();
526
527 // fx send
528 float fxSend[ AUX_BUS_NUM ];
529 u8 infoSend[ AUX_BUS_NUM ];
530 for ( int i = 0; i < AUX_BUS_NUM; i++ )
531 {
532 infoSend[ i ] = m_WaveSoundInfo.fxSend[ i ];
533 }
534 for ( int i=0; i<AUX_BUS_NUM; i++ )
535 {
536 fxSend[ i ] = 0.0f;
537 fxSend[ i ] += static_cast<float>( infoSend[i] ) / 127.0f;
538 fxSend[ i ] += GetFxSend( static_cast<AuxBus>( i ) );
539 }
540
541 // set channel params of track
542 m_pChannel->SetPanMode( GetPanMode() );
543 m_pChannel->SetPanCurve( GetPanCurve() );
544
545 m_pChannel->SetUserVolume( volume );
546 m_pChannel->SetUserPitchRatio( pitchRatio );
547 m_pChannel->SetUserPan( pan );
548 m_pChannel->SetUserLpfFreq( lpfFreq );
549 m_pChannel->SetBiquadFilter( biquadType, biquadValue );
550 m_pChannel->SetMainSend( mainSend );
551 for ( int i=0; i<AUX_BUS_NUM; i++ )
552 {
553 AuxBus bus = static_cast<AuxBus>( i );
554 m_pChannel->SetFxSend( bus, fxSend[ i ] );
555 }
556 m_pChannel->SetUserSurroundPan( surroundPan );
557
558 m_pChannel->SetLfoParam( m_LfoParam );
559 }
560
561 /*---------------------------------------------------------------------------*
562 Name: ChannelCallbackFunc
563
564 Description: チャンネルから呼びだされるコールバック関数
565
566 Arguments: dropChannel - チャンネルポインタ
567 status - チャンネルコールバックステータス
568 userData - トラックポインタを格納したコールバックユーザーデータ
569
570 Returns: None.
571 *---------------------------------------------------------------------------*/
ChannelCallbackFunc(Channel * dropChannel,Channel::ChannelCallbackStatus status,u32 userData)572 void WaveSoundPlayer::ChannelCallbackFunc(
573 Channel* dropChannel,
574 Channel::ChannelCallbackStatus status,
575 u32 userData
576 )
577 {
578 WaveSoundPlayer* player = reinterpret_cast<WaveSoundPlayer*>( userData );
579
580 NW_NULL_ASSERT( dropChannel );
581 NW_NULL_ASSERT( player );
582 NW_ASSERT( dropChannel == player->m_pChannel );
583
584 if ( status == Channel::CALLBACK_STATUS_FINISH )
585 {
586 Channel::FreeChannel( dropChannel );
587 }
588
589 // チャンネル参照の切断
590 player->m_pChannel = NULL;
591 }
592
593 } // namespace nw::snd::internal::driver
594 } // namespace nw::snd::internal
595 } // namespace nw::snd
596 } // namespace nw
597
598