1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_SoundPlayer.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: 22340 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/snd/snd_SoundPlayer.h>
19 
20 #include <nw/snd/snd_SoundThread.h>
21 
22 namespace nw {
23 namespace snd {
24 
25 /* ========================================================================
26         public function
27    ======================================================================== */
28 
29 /*---------------------------------------------------------------------------*
30   Name:         SoundPlayer
31 
32   Description:  コンストラクタ
33 
34   Arguments:    None.
35 
36   Returns:      None.
37  *---------------------------------------------------------------------------*/
SoundPlayer()38 SoundPlayer::SoundPlayer()
39 : m_PlayableCount( 1 ),
40   m_PlayableLimit( INT_MAX ),
41   m_Volume( 1.0f ),
42   m_LpfFreq( 0.0f ),
43   m_BiquadType( BIQUAD_FILTER_TYPE_NONE ),
44   m_BiquadValue( 0.0f ),
45   m_MainSend( 0.0f )
46 {
47     for ( int i=0; i<AUX_BUS_NUM; i++ )
48     {
49         m_FxSend[i] = 0.0f;
50     }
51 }
52 
53 /*---------------------------------------------------------------------------*
54   Name:         ~SoundPlayer
55 
56   Description:  デストラクタ
57 
58   Arguments:    None.
59 
60   Returns:      None.
61  *---------------------------------------------------------------------------*/
~SoundPlayer()62 SoundPlayer::~SoundPlayer()
63 {
64     StopAllSound( 0 );
65 }
66 
67 /*---------------------------------------------------------------------------*
68   Name:         Update
69 
70   Description:  プレイヤーのフレーム処理を更新する
71 
72   Arguments:    None.
73 
74   Returns:      None.
75  *---------------------------------------------------------------------------*/
Update()76 void SoundPlayer::Update()
77 {
78     for ( SoundList::Iterator itr = m_SoundList.GetBeginIter();
79           itr != m_SoundList.GetEndIter();
80         )
81     {
82         SoundList::Iterator curItr = itr++;
83         curItr->Update();
84     }
85 
86     // プライオリティリストを整列しなおす
87     detail_SortPriorityList();
88 }
89 
90 /*---------------------------------------------------------------------------*
91   Name:         StopAllSound
92 
93   Description:  全てのサウンドを停止する
94 
95   Arguments:    fadeFrames - フェードアウトフレーム数
96 
97   Returns:      None.
98  *---------------------------------------------------------------------------*/
StopAllSound(int fadeFrames)99 void SoundPlayer::StopAllSound( int fadeFrames )
100 {
101     for ( SoundList::Iterator itr = m_SoundList.GetBeginIter();
102           itr != m_SoundList.GetEndIter();
103         )
104     {
105         SoundList::Iterator curItr = itr++;
106         curItr->Stop( fadeFrames );
107     }
108 }
109 
110 /*---------------------------------------------------------------------------*
111   Name:         PauseAllSound
112 
113   Description:  全てのサウンドを一時停止または再開する
114 
115   Arguments:    flag       - 一時停止か再開か
116                 fadeFrames - フェードフレーム数
117 
118   Returns:      None.
119  *---------------------------------------------------------------------------*/
PauseAllSound(bool flag,int fadeFrames)120 void SoundPlayer::PauseAllSound( bool flag, int fadeFrames )
121 {
122     for ( SoundList::Iterator itr = m_SoundList.GetBeginIter();
123           itr != m_SoundList.GetEndIter();
124         )
125     {
126         SoundList::Iterator curItr = itr++;
127         curItr->Pause( flag, fadeFrames );
128     }
129 }
130 
131 /*---------------------------------------------------------------------------*
132   Name:         SetVolume
133 
134   Description:  音量を変更
135 
136   Arguments:    volume - 音量
137 
138   Returns:      None.
139  *---------------------------------------------------------------------------*/
SetVolume(float volume)140 void SoundPlayer::SetVolume( float volume )
141 {
142     NW_ASSERT( volume >= 0.0f );
143     if ( volume < 0.0f ) volume = 0.0f;
144     m_Volume = volume;
145 }
146 
147 /*---------------------------------------------------------------------------*
148   Name:         SetLpfFreq
149 
150   Description:  ローパスフィルタの周波数変更
151 
152   Arguments:    lpfFreq - ローパスフィルタの周波数値
153 
154   Returns:      なし
155  *---------------------------------------------------------------------------*/
SetLpfFreq(float lpfFreq)156 void SoundPlayer::SetLpfFreq( float lpfFreq )
157 {
158     m_LpfFreq = lpfFreq;
159 }
160 
161 /*---------------------------------------------------------------------------*
162   Name:         SetBiquadFilter
163 
164   Description:  Biquadフィルタの設定
165 
166   Arguments:    type  - フィルタの種類 (0 - 127)
167                 value - フィルタの値 (0.0f - 1.0f)
168 
169   Returns:      なし
170  *---------------------------------------------------------------------------*/
SetBiquadFilter(int type,float value)171 void SoundPlayer::SetBiquadFilter( int type, float value )
172 {
173     m_BiquadType = type;
174     m_BiquadValue = value;
175 }
176 
177 /*---------------------------------------------------------------------------*
178   Name:         SetMainSend
179 
180   Description:  メインセンドバスに送る音量を変更する
181 
182   Arguments:    send - 音量
183 
184   Returns:      None.
185  *---------------------------------------------------------------------------*/
SetMainSend(float send)186 void SoundPlayer::SetMainSend( float send )
187 {
188     m_MainSend = send;
189 }
190 
191 /*---------------------------------------------------------------------------*
192   Name:         SetFxSend
193 
194   Description:  エフェクトセンドバスに送る音量を変更する
195 
196   Arguments:    bus - センドバス
197                 send - 音量
198 
199   Returns:      None.
200  *---------------------------------------------------------------------------*/
SetFxSend(AuxBus bus,float send)201 void SoundPlayer::SetFxSend( AuxBus bus, float send )
202 {
203     NW_MINMAXLT_ASSERT( bus, 0, AUX_BUS_NUM );
204     m_FxSend[bus] = send;
205 }
206 /*---------------------------------------------------------------------------*
207   Name:         RemoveSoundList
208 
209   Description:  サウンドをプレイヤーリストから削除する
210 
211   Arguments:    pSound - シーケンスサウンド
212 
213   Returns:      None.
214  *---------------------------------------------------------------------------*/
RemoveSoundList(internal::BasicSound * pSound)215 void SoundPlayer::RemoveSoundList( internal::BasicSound* pSound )
216 {
217     // 再生リストから削除する
218     m_SoundList.Erase( pSound );
219     pSound->DetachSoundPlayer( this );
220 }
221 
222 /*---------------------------------------------------------------------------*
223   Name:         InsertPriorityList
224 
225   Description:  サウンドをプライオリティリストへ追加
226 
227   Arguments:    pSound - 追加するサウンド
228 
229   Returns:      None.
230   *---------------------------------------------------------------------------*/
InsertPriorityList(internal::BasicSound * pSound)231 void SoundPlayer::InsertPriorityList( internal::BasicSound* pSound )
232 {
233     PriorityList::Iterator itr = m_PriorityList.GetBeginIter();
234     while ( itr != m_PriorityList.GetEndIter() )
235     {
236         if ( pSound->CalcCurrentPlayerPriority() < itr->CalcCurrentPlayerPriority() ) break;
237         (void)++itr;
238     }
239     m_PriorityList.Insert( itr, pSound );
240 }
241 
242 /*---------------------------------------------------------------------------*
243   Name:         RemovePriorityList
244 
245   Description:  サウンドをプライオリティリストから削除
246 
247   Arguments:    pSound - 削除するサウンド
248 
249   Returns:      None.
250   *---------------------------------------------------------------------------*/
RemovePriorityList(internal::BasicSound * pSound)251 void SoundPlayer::RemovePriorityList( internal::BasicSound* pSound )
252 {
253     m_PriorityList.Erase( pSound );
254 }
255 
256 /*---------------------------------------------------------------------------*
257   Name:         detail_SortPriorityList
258 
259   Description:  指定したサウンドのプライオリティ順序を並び替える
260 
261   Arguments:    pSound - 並び替えるサウンド
262 
263   Returns:      None.
264   *---------------------------------------------------------------------------*/
detail_SortPriorityList(internal::BasicSound * pSound)265 void SoundPlayer::detail_SortPriorityList( internal::BasicSound* pSound )
266 {
267     RemovePriorityList( pSound );
268     InsertPriorityList( pSound );
269 }
270 
271 /*---------------------------------------------------------------------------*
272   Name:         detail_SortPriorityList
273 
274   Description:  全サウンドのプライオリティ順序を並び替える
275 
276   Arguments:    None.
277 
278   Returns:      None.
279   *---------------------------------------------------------------------------*/
detail_SortPriorityList()280 void SoundPlayer::detail_SortPriorityList()
281 {
282     if ( m_PriorityList.GetSize() < 2 ) return;
283 
284     static const int TMP_NUM = internal::BasicSound::PRIORITY_MAX - internal::BasicSound::PRIORITY_MIN + 1;
285     static PriorityList tmplist[ TMP_NUM ]; // notice: large stack
286 #ifdef NW_DEBUG
287     for ( int i=0; i<TMP_NUM; i++ ) NW_ASSERT( tmplist[i].IsEmpty() );
288 #endif
289 
290     while ( !m_PriorityList.IsEmpty() )
291     {
292         internal::BasicSound& front = m_PriorityList.GetFront();
293         m_PriorityList.PopFront();
294         tmplist[ front.CalcCurrentPlayerPriority() ].PushBack( &front );
295     }
296     for ( int i=0; i<TMP_NUM; i++ )
297     {
298         while ( !tmplist[i].IsEmpty() )
299         {
300             internal::BasicSound& front = tmplist[i].GetFront();
301             tmplist[i].PopFront();
302             m_PriorityList.PushBack( &front );
303         }
304     }
305 }
306 
307 /*---------------------------------------------------------------------------*
308   Name:         detail_AppendSound
309 
310   Description:  サウンドをサウンドプレイヤーに登録する
311 
312   Arguments:    pSound - サウンド
313 
314   Returns:      登録できたらtrue
315  *---------------------------------------------------------------------------*/
detail_AppendSound(internal::BasicSound * pSound)316 bool SoundPlayer::detail_AppendSound( internal::BasicSound* pSound )
317 {
318     NW_NULL_ASSERT( pSound );
319 
320     int allocPriority = pSound->CalcCurrentPlayerPriority();
321 
322     // 最大同時再生数のチェック
323     if ( GetPlayableSoundCount() == 0 ) return false;
324     while ( GetPlayingSoundCount() >= GetPlayableSoundCount() )
325     {
326         internal::BasicSound* dropSound = GetLowestPrioritySound();
327         if ( dropSound == NULL ) return false;
328         if ( allocPriority < dropSound->CalcCurrentPlayerPriority() ) return false;
329         dropSound->Finalize();
330     }
331 
332     // リストへ登録
333     m_SoundList.PushBack( pSound );
334     InsertPriorityList( pSound );
335 
336     pSound->AttachSoundPlayer( this );
337 
338     return true;
339 }
340 
341 /*---------------------------------------------------------------------------*
342   Name:         detail_RemoveSound
343 
344   Description:  サウンドをサウンドプレイヤーから削除する
345 
346   Arguments:    pSound - 削除するサウンド
347 
348   Returns:      None.
349   *---------------------------------------------------------------------------*/
detail_RemoveSound(internal::BasicSound * pSound)350 void SoundPlayer::detail_RemoveSound( internal::BasicSound* pSound )
351 {
352     RemovePriorityList( pSound );
353     RemoveSoundList( pSound );
354 }
355 
356 /*---------------------------------------------------------------------------*
357   Name:         SetPlayableSoundCount
358 
359   Description:  同時再生数を設定
360 
361   Arguments:    count - 同時再生数
362 
363   Returns:      None.
364  *---------------------------------------------------------------------------*/
SetPlayableSoundCount(int count)365 void SoundPlayer::SetPlayableSoundCount( int count )
366 {
367     NW_ASSERT( count >= 0 );
368 
369     // プレイヤーヒープ使用時の上限
370     NW_WARNING( count <= m_PlayableLimit, "playable sound count is over limit." );
371     count = ut::Clamp( count, 0, m_PlayableLimit );
372 
373     m_PlayableCount = count;
374 
375     // 新しく設定された同時再生数を越えるサウンドを終了する
376     while ( GetPlayingSoundCount() > GetPlayableSoundCount() )
377     {
378         internal::BasicSound* dropSound = GetLowestPrioritySound();
379         NW_NULL_ASSERT( dropSound );
380         dropSound->Finalize();
381     }
382 }
383 
384 /*---------------------------------------------------------------------------*
385   Name:         detail_SetPlayableSoundLimit
386 
387   Description:
388 
389   Arguments:    None.
390 
391   Returns:      None.
392   *---------------------------------------------------------------------------*/
detail_SetPlayableSoundLimit(int limit)393 void SoundPlayer::detail_SetPlayableSoundLimit( int limit )
394 {
395     NW_ASSERT( limit >= 0 );
396 
397     m_PlayableLimit = limit;
398 }
399 
400 /*---------------------------------------------------------------------------*
401   Name:         detail_CanPlaySound
402 
403   Description:  指定したプライオリティのサウンドを再生できるかどうかを調べる
404 
405   Arguments:    startPriority - プライオリティ
406 
407   Returns:      再生可能ならtrue
408  *---------------------------------------------------------------------------*/
detail_CanPlaySound(int startPriority)409 bool SoundPlayer::detail_CanPlaySound( int startPriority )
410 {
411     // プレイヤー毎の最大同時再生数のチェック
412     if ( GetPlayableSoundCount() == 0 ) return false;
413     if ( GetPlayingSoundCount() >= GetPlayableSoundCount() )
414     {
415         internal::BasicSound* dropSound = GetLowestPrioritySound();
416         if ( dropSound == NULL ) return false;
417         if ( startPriority < dropSound->CalcCurrentPlayerPriority() ) return false;
418     }
419 
420     return true;
421 }
422 
423 /*---------------------------------------------------------------------------*
424   Name:         detail_AppendPlayerHeap
425 
426   Description:  プレイヤーヒープを追加
427 
428   Arguments:    heap - 追加するプレイヤーヒープ
429 
430   Returns:      None.
431  *---------------------------------------------------------------------------*/
detail_AppendPlayerHeap(internal::PlayerHeap * pHeap)432 void SoundPlayer::detail_AppendPlayerHeap( internal::PlayerHeap* pHeap )
433 {
434     NW_NULL_ASSERT( pHeap );
435 
436     pHeap->AttachSoundPlayer( this );
437     m_PlayerHeapList.PushBack( pHeap );
438 }
439 
440 /*---------------------------------------------------------------------------*
441   Name:         detail_RemovePlayerHeap
442 
443   Description:  プレイヤーヒープの削除
444 
445   Arguments:    heap - 削除するプレイヤーヒープ
446 
447   Returns:      None.
448   *---------------------------------------------------------------------------*/
detail_RemovePlayerHeap(internal::PlayerHeap * pHeap)449 void SoundPlayer::detail_RemovePlayerHeap( internal::PlayerHeap* pHeap )
450 {
451     m_PlayerHeapList.Erase( pHeap );
452 }
453 
454 /*---------------------------------------------------------------------------*
455   Name:         detail_AllocPlayerHeap
456 
457   Description:  プレイヤーヒープの確保
458 
459   Arguments:    sound - プレイヤーヒープを使用するサウンド
460 
461   Returns:      確保したヒープ
462  *---------------------------------------------------------------------------*/
463 internal::PlayerHeap*
detail_AllocPlayerHeap(internal::BasicSound * pSound)464 SoundPlayer::detail_AllocPlayerHeap( internal::BasicSound* pSound )
465 {
466     NW_NULL_ASSERT( pSound );
467 
468     // プレイヤーヒープの確保
469     if ( m_PlayerHeapList.IsEmpty() ) return NULL;
470     internal::PlayerHeap& playerHeap = m_PlayerHeapList.GetFront();
471     m_PlayerHeapList.PopFront();
472 
473     // プレイヤーヒープとサウンドの結合
474     playerHeap.AttachSound( pSound );
475     pSound->AttachPlayerHeap( &playerHeap );
476 
477     // プレイヤーヒープ初期化
478     playerHeap.Clear();
479 
480     return &playerHeap;
481 }
482 
483 /*---------------------------------------------------------------------------*
484   Name:         detail_FreePlayerHeap
485 
486   Description:  プレイヤーヒープの解放
487 
488   Arguments:    sound - プレイヤーヒープを解放するサウンド
489 
490   Returns:      None.
491  *---------------------------------------------------------------------------*/
detail_FreePlayerHeap(internal::BasicSound * pSound)492 void SoundPlayer::detail_FreePlayerHeap( internal::BasicSound* pSound )
493 {
494     NW_NULL_ASSERT( pSound );
495 
496     internal::PlayerHeap* pHeap = pSound->GetPlayerHeap();
497     if ( pHeap == NULL ) return;
498 
499     // プレイヤーヒープとサウンドの切断
500     pHeap->DetachSound( pSound );
501     pSound->DetachPlayerHeap( pHeap );
502 
503     // プレイヤーヒープの解放
504     m_PlayerHeapList.PushBack( pHeap );
505 }
506 
507 } // namespace nw::snd
508 } // namespace nw
509 
510