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