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