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         &noteInfo,
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         &noteInfo,
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