/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_WaveSoundPlayer.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include namespace nw { namespace snd { namespace internal { namespace driver { /* ======================================================================== public function ======================================================================== */ /*---------------------------------------------------------------------------* Name: WaveSoundPlayer Description: コンストラクタ Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ WaveSoundPlayer::WaveSoundPlayer() { } void WaveSoundPlayer::Initialize() { BasicSoundPlayer::Initialize(); m_ReleasePriorityFixFlag = false; m_PanRange = 1.0f; m_Priority = DEFAULT_PRIORITY; m_pCallback = NULL; m_CallbackData = 0; m_pWaveSoundData = NULL; m_WaveSoundIndex = -1; m_WaveSoundInfo.pitch = 1.0f; m_WaveSoundInfo.pan = 64; m_WaveSoundInfo.surroundPan = 0; for ( int i = 0; i < AUX_BUS_NUM; i++ ) { m_WaveSoundInfo.fxSend[ i ] = 0; } m_WaveSoundInfo.mainSend = 127; m_LfoParam.Initialize(); m_WavePlayFlag = false; m_pChannel = NULL; } void WaveSoundPlayer::Finalize() { // 無効化リストから削除 if ( m_ActiveFlag ) { DisposeCallbackManager::GetInstance().UnregisterDisposeCallback( this ); m_ActiveFlag = false; } // チャンネル解放 CloseChannel(); BasicSoundPlayer::Finalize(); } /*---------------------------------------------------------------------------* Name: Prepare Description: ウェーブサウンドの再生準備を行います Arguments: playerNo - プレイヤー番号 seqBase - シーケンスデータベースアドレス seqOffset - シーケンスデータオフセット bank_p - バンクポインタ Returns: None. *---------------------------------------------------------------------------*/ bool WaveSoundPlayer::Prepare( const void* waveSoundBase, int index, StartOffsetType startOffsetType, int startOffset, const WaveSoundCallback* callback, u32 callbackData ) { //----------------------------------------------------------------------------- // 再生中シーケンスの停止 if ( m_ActiveFlag ) { FinishPlayer(); } //----------------------------------------------------------------------------- // プレイヤー初期化 m_pCallback = callback; m_CallbackData = callbackData; //----------------------------------------------------------------------------- // データ開始 m_pWaveSoundData = waveSoundBase; m_WaveSoundIndex = index; m_StartOffsetType = startOffsetType; m_StartOffset = startOffset; // 無効化リストに追加 DisposeCallbackManager::GetInstance().RegisterDisposeCallback( this ); // シーケンス準備完了 m_ActiveFlag = true; return true; } /*---------------------------------------------------------------------------* Name: Start Description: シーケンスをスタートします Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void WaveSoundPlayer::Start() { // プレイヤーリストに追加 SoundThread::GetInstance().RegisterPlayerCallback( this ); m_StartedFlag = true; } /*---------------------------------------------------------------------------* Name: Stop Description: シーケンスを止めます Arguments: playerNo - プレイヤー番号 Returns: None. *---------------------------------------------------------------------------*/ void WaveSoundPlayer::Stop() { FinishPlayer(); } /*---------------------------------------------------------------------------* Name: Pause Description: シーケンスを一時停止または再開します Arguments: playerNo - プレイヤー番号 flag - trueで一時停止、falseで再開します Returns: None. *---------------------------------------------------------------------------*/ void WaveSoundPlayer::Pause( bool flag ) { m_PauseFlag = static_cast( flag ); // チャンネルを一時停止 if ( IsChannelActive() ) { if ( m_pChannel->IsPause() != flag ) { m_pChannel->Pause( flag ); } } } /*---------------------------------------------------------------------------* Name: SetPanRange Description: パンレンジの変更 Arguments: panRange - パンレンジ Returns: なし *---------------------------------------------------------------------------*/ void WaveSoundPlayer::SetPanRange( float panRange ) { m_PanRange = panRange; } /*---------------------------------------------------------------------------* Name: SetChannelPriority Description: チャンネルプライオリティの変更 Arguments: prio - プライオリティ Returns: なし *---------------------------------------------------------------------------*/ void WaveSoundPlayer::SetChannelPriority( int priority ) { NW_MINMAX_ASSERT( priority, 0, 127 ); m_Priority = static_cast( priority ); } void WaveSoundPlayer::SetReleasePriorityFix( bool fix ) { m_ReleasePriorityFixFlag = fix; } /*---------------------------------------------------------------------------* Name: InvalidateData Description: 指定シーケンスデータを使用しているシーケンスを無効化します Arguments: start - シーケンスデータ開始アドレス end - シーケンスデータ終了アドレス Returns: None. *---------------------------------------------------------------------------*/ void WaveSoundPlayer::InvalidateData( const void* start, const void* end ) { if ( m_ActiveFlag ) { const void* current = GetWaveSoundDataAddress(); if ( start <= current && current <= end ) { FinishPlayer(); } } } /*---------------------------------------------------------------------------* Name: FinishPlayer Description: プレイヤーの完了処理を行います。 Arguments: player : プレイヤーポインタ Returns: None *---------------------------------------------------------------------------*/ void WaveSoundPlayer::FinishPlayer() { // プレイヤーリストから削除 if ( m_StartedFlag ) { SoundThread::GetInstance().UnregisterPlayerCallback( this ); m_StartedFlag = false; } } /*---------------------------------------------------------------------------* Name: ReadWaveSoundDataInfo Description: ウェーブサウンドデータの情報取得 Arguments: info - ウェーブサウンドデータ情報構造体 Returns: 現在の再生しているウェーブサウンドデータの情報を取得する *---------------------------------------------------------------------------*/ bool WaveSoundPlayer::ReadWaveSoundDataInfo( WaveSoundDataInfo* info ) const { WaveSoundInfo waveSoundInfo; // 現状、データは格納されるが本関数では利用されない WaveInfo waveInfo; WaveSoundNoteInfo noteInfo; // 現状、データは格納されるが本関数では利用されない WaveSoundCallbackArg arg = { m_pWaveSoundData, m_WaveSoundIndex, 0, m_CallbackData, GetPlayerHeapDataManager() }; bool result = m_pCallback->GetWaveSoundData( &waveSoundInfo, ¬eInfo, &waveInfo, arg ); if ( result ) { info->loopFlag = ( waveInfo.loopFlag != 0 ); info->sampleRate = static_cast( waveInfo.sampleRate ); info->loopStart = waveInfo.loopStartFrame; info->loopEnd = waveInfo.loopEndFrame; } return result; } /*---------------------------------------------------------------------------* Name: GetPlaySamplePosition Description: 現在の再生位置の取得 Arguments: なし Returns: 現在の再生位置をサンプル単位で返す 再生していない場合は、負の値を返す *---------------------------------------------------------------------------*/ s32 WaveSoundPlayer::GetPlaySamplePosition() const { if ( m_pChannel == NULL ) return -1; return static_cast( m_pChannel->GetCurrentPlayingSample() ); } /*---------------------------------------------------------------------------* Name: Update Description: シーケンスのフレーム処理を行います Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void WaveSoundPlayer::Update() { NW_ASSERT( m_ActiveFlag ); if ( ! m_ActiveFlag ) return; if ( ! m_StartedFlag ) return; if ( ! m_PauseFlag ) { // 波形終端終了チェック if ( ( m_WavePlayFlag ) && ( m_pChannel == NULL ) ) { m_FinishFlag = true; FinishPlayer(); return; } // 波形再生 if ( ! m_WavePlayFlag ) { if ( ! StartChannel( m_pCallback, m_CallbackData ) ) { FinishPlayer(); return; } } } UpdateChannel(); } /*---------------------------------------------------------------------------* Name: StartChannel Description: トラックのシーケンス処理を進めます Arguments: Returns: シーケンス継続時には0を、完了時にはー1を返します *---------------------------------------------------------------------------*/ bool WaveSoundPlayer::StartChannel( const WaveSoundCallback* callback, u32 callbackData ) { const int priority = GetChannelPriority() + DEFAULT_PRIORITY; WaveInfo waveInfo; WaveSoundNoteInfo noteInfo; // 現在の実装では使用されない。 // 「マルチトラックウェーブサウンド」的な拡張を想定。 WaveSoundCallbackArg arg = { m_pWaveSoundData, m_WaveSoundIndex, 0, callbackData, GetPlayerHeapDataManager() }; bool result = callback->GetWaveSoundData( &m_WaveSoundInfo, ¬eInfo, &waveInfo, arg ); if ( ! result ) return false; // 開始オフセット u32 startOffsetSamples = 0; if ( m_StartOffsetType == START_OFFSET_TYPE_SAMPLE ) { startOffsetSamples = static_cast( m_StartOffset ); } else if ( m_StartOffsetType == START_OFFSET_TYPE_MILLISEC ) { startOffsetSamples = static_cast( static_cast( m_StartOffset ) * waveInfo.sampleRate / 1000 ); } // 開始オフセットが範囲外なので再生せずに終了 if ( startOffsetSamples > waveInfo.loopEndFrame ) return false; Channel* channel; channel = Channel::AllocChannel( ut::Min( static_cast( waveInfo.channelCount ), 2 ), priority, ChannelCallbackFunc, reinterpret_cast( this ) ); // 鳴らせなかったらエラーでサウンド終了 if ( channel == NULL ) return false; // エンベロープ設定 channel->SetAttack( m_WaveSoundInfo.adshr.attack ); channel->SetHold( m_WaveSoundInfo.adshr.hold ); channel->SetDecay( m_WaveSoundInfo.adshr.decay ); channel->SetSustain( m_WaveSoundInfo.adshr.sustain ); channel->SetRelease( m_WaveSoundInfo.adshr.release ); channel->SetReleasePriorityFix( m_ReleasePriorityFixFlag ); channel->SetFrontBypass( IsFrontBypass() ); channel->Start( waveInfo, -1, startOffsetSamples ); // チャンネルリストへの結合 m_pChannel = channel; m_WavePlayFlag = true; return true; } /*---------------------------------------------------------------------------* Name: CloseChannel Description: チャンネルを閉じます Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void WaveSoundPlayer::CloseChannel() { // Release if ( IsChannelActive() ) { UpdateChannel(); m_pChannel->Release(); } // Free if ( m_pChannel != NULL ) { Channel::FreeChannel( m_pChannel ); } m_pChannel = NULL; } /*---------------------------------------------------------------------------* Name: UpdateChannel Description: トラックが保持しているチャンネルのパラメータを更新します Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void WaveSoundPlayer::UpdateChannel() { if ( m_pChannel == NULL ) return; // volume float volume = 1.0f; volume *= GetVolume(); float pitchRatio = 1.0f; pitchRatio *= GetPitch(); pitchRatio *= m_WaveSoundInfo.pitch; // pan float pan = 0.0f; if ( m_WaveSoundInfo.pan <= 1 ) // panの1と2は同じ値 { pan += static_cast( static_cast( m_WaveSoundInfo.pan ) - 63 ) / 63.0f; } else { pan += static_cast( static_cast( m_WaveSoundInfo.pan ) - 64 ) / 63.0f; } pan *= GetPanRange(); pan += GetPan(); // surround pan f32 surroundPan = 0.0f; if ( m_WaveSoundInfo.surroundPan <= 63 ) { surroundPan += static_cast( m_WaveSoundInfo.surroundPan ) / 63.0f; } else { surroundPan += static_cast( m_WaveSoundInfo.surroundPan + 1 ) / 64.0f; // NOTE: y = (1/64) * x + 1/64 = (x/64) + (1/64) = (x+1)/64 } surroundPan += GetSurroundPan(); // lpf freq float lpfFreq = 0.0f; lpfFreq += GetLpfFreq(); // biquad filter int biquadType = GetBiquadFilterType(); float biquadValue = GetBiquadFilterValue(); // main send float mainSend = 0.0f; mainSend += static_cast( m_WaveSoundInfo.mainSend ) / 127.0f - 1.0f; mainSend += GetMainSend(); // fx send float fxSend[ AUX_BUS_NUM ]; u8 infoSend[ AUX_BUS_NUM ]; for ( int i = 0; i < AUX_BUS_NUM; i++ ) { infoSend[ i ] = m_WaveSoundInfo.fxSend[ i ]; } for ( int i=0; i( infoSend[i] ) / 127.0f; fxSend[ i ] += GetFxSend( static_cast( i ) ); } // set channel params of track m_pChannel->SetPanMode( GetPanMode() ); m_pChannel->SetPanCurve( GetPanCurve() ); m_pChannel->SetUserVolume( volume ); m_pChannel->SetUserPitchRatio( pitchRatio ); m_pChannel->SetUserPan( pan ); m_pChannel->SetUserLpfFreq( lpfFreq ); m_pChannel->SetBiquadFilter( biquadType, biquadValue ); m_pChannel->SetMainSend( mainSend ); for ( int i=0; i( i ); m_pChannel->SetFxSend( bus, fxSend[ i ] ); } m_pChannel->SetUserSurroundPan( surroundPan ); m_pChannel->SetLfoParam( m_LfoParam ); } /*---------------------------------------------------------------------------* Name: ChannelCallbackFunc Description: チャンネルから呼びだされるコールバック関数 Arguments: dropChannel - チャンネルポインタ status - チャンネルコールバックステータス userData - トラックポインタを格納したコールバックユーザーデータ Returns: None. *---------------------------------------------------------------------------*/ void WaveSoundPlayer::ChannelCallbackFunc( Channel* dropChannel, Channel::ChannelCallbackStatus status, u32 userData ) { WaveSoundPlayer* player = reinterpret_cast( userData ); NW_NULL_ASSERT( dropChannel ); NW_NULL_ASSERT( player ); NW_ASSERT( dropChannel == player->m_pChannel ); if ( status == Channel::CALLBACK_STATUS_FINISH ) { Channel::FreeChannel( dropChannel ); } // チャンネル参照の切断 player->m_pChannel = NULL; } } // namespace nw::snd::internal::driver } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw