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