/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_CurveAdshr.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. 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. $Revision: 13145 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include namespace nw { namespace snd { namespace internal { const float CurveAdshr::VOLUME_INIT = -90.4f; // squareスケール -> デシベル 変換テーブル const s16 CurveAdshr::DecibelSquareTable[ DECIBEL_SQUARE_TABLE_SIZE ] = { -723, -722, -721, -651, -601, -562, -530, -503, -480, -460, -442, -425, -410, -396, -383, -371, -360, -349, -339, -330, -321, -313, -305, -297, -289, -282, -276, -269, -263, -257, -251, -245, -239, -234, -229, -224, -219, -214, -210, -205, -201, -196, -192, -188, -184, -180, -176, -173, -169, -165, -162, -158, -155, -152, -149, -145, -142, -139, -136, -133, -130, -127, -125, -122, -119, -116, -114, -111, -109, -106, -103, -101, -99, -96, -94, -91, -89, -87, -85, -82, -80, -78, -76, -74, -72, -70, -68, -66, -64, -62, -60, -58, -56, -54, -52, -50, -49, -47, -45, -43, -42, -40, -38, -36, -35, -33, -31, -30, -28, -27, -25, -23, -22, -20, -19, -17, -16, -14, -13, -11, -10, -8, -7, -6, -4, -3, -1, 0 }; /* ======================================================================== public function ======================================================================== */ /*---------------------------------------------------------------------------* Name: CurveAdshr Description: コンストラクタ Arguments: なし Returns: なし *---------------------------------------------------------------------------*/ CurveAdshr::CurveAdshr() { Initialize(); } /*---------------------------------------------------------------------------* Name: Init Description: エンベロープジェネレータのパラメータを初期化します Arguments: なし Returns: なし *---------------------------------------------------------------------------*/ void CurveAdshr::Initialize( float initDecibel ) { SetAttack( ATTACK_INIT ); SetHold( HOLD_INIT ); SetDecay( DECAY_INIT ); SetSustain( SUSTAIN_INIT ); SetRelease( RELEASE_INIT ); Reset( initDecibel ); } /*---------------------------------------------------------------------------* Name: Reset Description: エンベロープジェネレータをリセットします Arguments: なし Returns: なし *---------------------------------------------------------------------------*/ void CurveAdshr::Reset( float initDecibel ) { m_Value = initDecibel * 10.0f; m_Status = STATUS_ATTACK; } /*---------------------------------------------------------------------------* Name: GetValue Description: 現在値を取得します Arguments: なし Returns: 現在値 *---------------------------------------------------------------------------*/ f32 CurveAdshr::GetValue() const { // アタックの速度が最大の時は、音量0から始まらず最大の音量を返す if ( ( m_Status == STATUS_ATTACK ) && ( m_Attack == 0.0f ) ) { return 0.0f; } return m_Value/10.0f; } /*---------------------------------------------------------------------------* Name: Update Description: エンベロープを更新します Arguments: msec - 更新時間 Returns: なし *---------------------------------------------------------------------------*/ void CurveAdshr::Update( int msec ) { switch ( m_Status ) { case STATUS_ATTACK: { while( msec > 0 ) { m_Value *= m_Attack; msec--; if ( m_Value > - 1.0f / 32.0f ) { m_Value = 0.0f; m_Status = STATUS_HOLD; m_HoldCounter = m_Hold; break; } } break; } case STATUS_HOLD: { if ( msec < m_HoldCounter ) { m_HoldCounter -= msec; } else { msec -= m_HoldCounter; m_HoldCounter = 0; m_Status = STATUS_DECAY; } if ( m_Status != STATUS_DECAY ) break; // continue; } case STATUS_DECAY: { const f32 sustainDecay = CalcDecibelSquare( m_Sustain ); m_Value -= m_Decay * msec; if ( m_Value < sustainDecay ) { m_Value = sustainDecay; m_Status = STATUS_SUSTAIN; } break; } case STATUS_SUSTAIN: // do Nothing break; case STATUS_RELEASE: m_Value -= m_Release * msec; break; } } /*---------------------------------------------------------------------------* Name: SetChannelAttack Description: エンベロープのアタックを設定します Arguments: attack - アタック値 Returns: None. *---------------------------------------------------------------------------*/ void CurveAdshr::SetAttack( int attack ) { /*---------------------------------------------------------- 以下の計算式をテーブルにして最適化 static const u8 attackTable[ 127 - 109 + 1 ] = { 0, 1, 5, 14, 26, 38, 51, 63, 73, 84, 92, 100, 109, 116, 123, 127, 132, 137, 143 }; NW_MINMAX_ASSERT( attack, 0, 127 ); double x; if ( attack < 109 ) { x = 255 - attack; } else { x = attackTable[ 127 - attack ]; } x /= 256.0f; x = std::pow( x, 1.0/5 ); m_Attack = static_cast(x); ----------------------------------------------------------*/ static const float attackTable[ 128 ] = { 0.9992175f, 0.9984326f, 0.9976452f, 0.9968553f, 0.9960629f, 0.9952679f, 0.9944704f, 0.9936704f, 0.9928677f, 0.9920625f, 0.9912546f, 0.9904441f, 0.9896309f, 0.9888151f, 0.9879965f, 0.9871752f, 0.9863512f, 0.9855244f, 0.9846949f, 0.9838625f, 0.9830273f, 0.9821893f, 0.9813483f, 0.9805045f, 0.9796578f, 0.9788081f, 0.9779555f, 0.9770999f, 0.9762413f, 0.9753797f, 0.9745150f, 0.9736472f, 0.9727763f, 0.9719023f, 0.9710251f, 0.9701448f, 0.9692612f, 0.9683744f, 0.9674844f, 0.9665910f, 0.9656944f, 0.9647944f, 0.9638910f, 0.9629842f, 0.9620740f, 0.9611604f, 0.9602433f, 0.9593226f, 0.9583984f, 0.9574706f, 0.9565392f, 0.9556042f, 0.9546655f, 0.9537231f, 0.9527769f, 0.9518270f, 0.9508732f, 0.9499157f, 0.9489542f, 0.9479888f, 0.9470195f, 0.9460462f, 0.9450689f, 0.9440875f, 0.9431020f, 0.9421124f, 0.9411186f, 0.9401206f, 0.9391184f, 0.9381118f, 0.9371009f, 0.9360856f, 0.9350659f, 0.9340417f, 0.9330131f, 0.9319798f, 0.9309420f, 0.9298995f, 0.9288523f, 0.9278004f, 0.9267436f, 0.9256821f, 0.9246156f, 0.9235442f, 0.9224678f, 0.9213864f, 0.9202998f, 0.9192081f, 0.9181112f, 0.9170091f, 0.9159016f, 0.9147887f, 0.9136703f, 0.9125465f, 0.9114171f, 0.9102821f, 0.9091414f, 0.9079949f, 0.9068427f, 0.9056845f, 0.9045204f, 0.9033502f, 0.9021740f, 0.9009916f, 0.8998029f, 0.8986080f, 0.8974066f, 0.8961988f, 0.8949844f, 0.8900599f, 0.8824622f, 0.8759247f, 0.8691861f, 0.8636406f, 0.8535788f, 0.8430189f, 0.8286135f, 0.8149099f, 0.8002172f, 0.7780663f, 0.7554750f, 0.7242125f, 0.6828239f, 0.6329169f, 0.5592135f, 0.4551411f, 0.3298770f, 0.0000000f }; NW_MINMAX_ASSERT( attack, 0, 127 ); m_Attack = attackTable[ attack ]; } /*---------------------------------------------------------------------------* Name: SetSustain Description: エンベロープのサステインを設定します Arguments: hold - ホールド値 Returns: None. *---------------------------------------------------------------------------*/ void CurveAdshr::SetHold( int hold ) { NW_MINMAX_ASSERT( hold, 0, 127 ); m_Hold = static_cast( (hold+1)*(hold+1)/4 ); } /*---------------------------------------------------------------------------* Name: SetDecay Description: エンベロープのディケイを設定します Arguments: decay - ディケイ値 Returns: None. *---------------------------------------------------------------------------*/ void CurveAdshr::SetDecay( int decay ) { NW_MINMAX_ASSERT( decay, 0, 127 ); m_Decay = CalcRelease( decay ); } /*---------------------------------------------------------------------------* Name: SetSustain Description: エンベロープのサステインを設定します Arguments: sustain - サステイン値 Returns: None. *---------------------------------------------------------------------------*/ void CurveAdshr::SetSustain( int sustain ) { NW_MINMAX_ASSERT( sustain, 0, 127 ); m_Sustain = static_cast( sustain ); } /*---------------------------------------------------------------------------* Name: SetRelease Description: エンベロープのリリースを設定します Arguments: release - リリース値 Returns: None. *---------------------------------------------------------------------------*/ void CurveAdshr::SetRelease( int release ) { NW_MINMAX_ASSERT( release, 0, 127 ); m_Release = CalcRelease( release ); } /* ======================================================================== private function ======================================================================== */ f32 CurveAdshr::CalcRelease( int release ) { NW_MINMAX_ASSERT( release, 0, 127 ); if ( release == 127 ) return 65535.0f; if ( release == 126 ) return 120 / 5.0f; if ( release < 50 ) { return ( ( release << 1 ) + 1 ) / 128.0f / 5.0f; } else { return ( 60.0f / ( 126 - release ) ) / 5.0f; } } s16 CurveAdshr::CalcDecibelSquare( int scale ) { NW_MINMAX_ASSERT( scale, 0, CALC_DECIBEL_SCALE_MAX ); return DecibelSquareTable[ scale ]; } } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw