1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_CurveAdshr.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: 13145 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/snd/snd_CurveAdshr.h>
19 #include <nw/assert.h>
20 
21 namespace nw {
22 namespace snd {
23 namespace internal {
24 
25 const float CurveAdshr::VOLUME_INIT = -90.4f;
26 
27 //  squareスケール -> デシベル 変換テーブル
28 
29 const s16 CurveAdshr::DecibelSquareTable[ DECIBEL_SQUARE_TABLE_SIZE ] =
30 {
31     -723, -722, -721, -651, -601, -562, -530, -503,
32     -480, -460, -442, -425, -410, -396, -383, -371,
33     -360, -349, -339, -330, -321, -313, -305, -297,
34     -289, -282, -276, -269, -263, -257, -251, -245,
35     -239, -234, -229, -224, -219, -214, -210, -205,
36     -201, -196, -192, -188, -184, -180, -176, -173,
37     -169, -165, -162, -158, -155, -152, -149, -145,
38     -142, -139, -136, -133, -130, -127, -125, -122,
39     -119, -116, -114, -111, -109, -106, -103, -101,
40      -99,  -96,  -94,  -91,  -89,  -87,  -85,  -82,
41      -80,  -78,  -76,  -74,  -72,  -70,  -68,  -66,
42      -64,  -62,  -60,  -58,  -56,  -54,  -52,  -50,
43      -49,  -47,  -45,  -43,  -42,  -40,  -38,  -36,
44      -35,  -33,  -31,  -30,  -28,  -27,  -25,  -23,
45      -22,  -20,  -19,  -17,  -16,  -14,  -13,  -11,
46      -10,   -8,   -7,   -6,   -4,   -3,   -1,    0
47 };
48 
49 
50 /* ========================================================================
51         public function
52    ======================================================================== */
53 
54 /*---------------------------------------------------------------------------*
55   Name:         CurveAdshr
56 
57   Description:  コンストラクタ
58 
59   Arguments:    なし
60 
61   Returns:      なし
62  *---------------------------------------------------------------------------*/
CurveAdshr()63 CurveAdshr::CurveAdshr()
64 {
65     Initialize();
66 }
67 
68 /*---------------------------------------------------------------------------*
69   Name:         Init
70 
71   Description:  エンベロープジェネレータのパラメータを初期化します
72 
73   Arguments:    なし
74 
75   Returns:      なし
76  *---------------------------------------------------------------------------*/
Initialize(float initDecibel)77 void CurveAdshr::Initialize( float initDecibel )
78 {
79     SetAttack( ATTACK_INIT );
80     SetHold( HOLD_INIT );
81     SetDecay( DECAY_INIT );
82     SetSustain( SUSTAIN_INIT );
83     SetRelease( RELEASE_INIT );
84 
85     Reset( initDecibel );
86 }
87 
88 /*---------------------------------------------------------------------------*
89   Name:         Reset
90 
91   Description:  エンベロープジェネレータをリセットします
92 
93   Arguments:    なし
94 
95   Returns:      なし
96  *---------------------------------------------------------------------------*/
Reset(float initDecibel)97 void CurveAdshr::Reset( float initDecibel )
98 {
99     m_Value = initDecibel * 10.0f;
100     m_Status = STATUS_ATTACK;
101 }
102 
103 /*---------------------------------------------------------------------------*
104   Name:         GetValue
105 
106   Description:  現在値を取得します
107 
108   Arguments:    なし
109 
110   Returns:      現在値
111  *---------------------------------------------------------------------------*/
GetValue() const112 f32  CurveAdshr::GetValue() const
113 {
114     // アタックの速度が最大の時は、音量0から始まらず最大の音量を返す
115     if ( ( m_Status == STATUS_ATTACK ) && ( m_Attack == 0.0f ) )
116     {
117         return 0.0f;
118     }
119 
120     return m_Value/10.0f;
121 }
122 
123 /*---------------------------------------------------------------------------*
124   Name:         Update
125 
126   Description:  エンベロープを更新します
127 
128   Arguments:    msec - 更新時間
129 
130   Returns:      なし
131  *---------------------------------------------------------------------------*/
Update(int msec)132 void CurveAdshr::Update( int msec )
133 {
134     switch ( m_Status )
135     {
136     case STATUS_ATTACK:
137     {
138         while( msec > 0 )
139         {
140             m_Value *= m_Attack;
141             msec--;
142 
143             if ( m_Value > - 1.0f / 32.0f )
144             {
145                 m_Value = 0.0f;
146                 m_Status = STATUS_HOLD;
147                 m_HoldCounter = m_Hold;
148                 break;
149             }
150         }
151         break;
152     }
153 
154     case STATUS_HOLD:
155     {
156         if ( msec < m_HoldCounter )
157         {
158             m_HoldCounter -= msec;
159         }
160         else
161         {
162             msec -= m_HoldCounter;
163             m_HoldCounter = 0;
164             m_Status = STATUS_DECAY;
165         }
166         if ( m_Status != STATUS_DECAY ) break;
167         // continue;
168     }
169 
170     case STATUS_DECAY:
171     {
172         const f32 sustainDecay =
173             CalcDecibelSquare( m_Sustain );
174 
175         m_Value -= m_Decay * msec;
176         if ( m_Value < sustainDecay )
177         {
178             m_Value = sustainDecay;
179             m_Status = STATUS_SUSTAIN;
180         }
181         break;
182     }
183 
184     case STATUS_SUSTAIN:
185         // do Nothing
186         break;
187 
188     case STATUS_RELEASE:
189         m_Value -= m_Release * msec;
190         break;
191     }
192 }
193 
194 /*---------------------------------------------------------------------------*
195   Name:         SetChannelAttack
196 
197   Description:  エンベロープのアタックを設定します
198 
199   Arguments:    attack - アタック値
200 
201   Returns:      None.
202  *---------------------------------------------------------------------------*/
SetAttack(int attack)203 void CurveAdshr::SetAttack( int attack )
204 {
205     /*----------------------------------------------------------
206     以下の計算式をテーブルにして最適化
207 
208     static const u8 attackTable[ 127 - 109 + 1 ] = {
209         0, 1, 5, 14, 26, 38, 51, 63, 73, 84,
210         92, 100, 109, 116, 123, 127, 132, 137, 143
211     };
212 
213     NW_MINMAX_ASSERT( attack, 0, 127 );
214 
215     double x;
216     if ( attack < 109 ) {
217         x  = 255 - attack;
218     }
219     else {
220         x = attackTable[ 127 - attack ];
221     }
222     x /= 256.0f;
223     x = std::pow( x, 1.0/5 );
224 
225     m_Attack = static_cast<f32>(x);
226     ----------------------------------------------------------*/
227 
228     static const float attackTable[ 128 ] = {
229         0.9992175f, 0.9984326f, 0.9976452f, 0.9968553f,
230         0.9960629f, 0.9952679f, 0.9944704f, 0.9936704f,
231         0.9928677f, 0.9920625f, 0.9912546f, 0.9904441f,
232         0.9896309f, 0.9888151f, 0.9879965f, 0.9871752f,
233         0.9863512f, 0.9855244f, 0.9846949f, 0.9838625f,
234         0.9830273f, 0.9821893f, 0.9813483f, 0.9805045f,
235         0.9796578f, 0.9788081f, 0.9779555f, 0.9770999f,
236         0.9762413f, 0.9753797f, 0.9745150f, 0.9736472f,
237         0.9727763f, 0.9719023f, 0.9710251f, 0.9701448f,
238         0.9692612f, 0.9683744f, 0.9674844f, 0.9665910f,
239         0.9656944f, 0.9647944f, 0.9638910f, 0.9629842f,
240         0.9620740f, 0.9611604f, 0.9602433f, 0.9593226f,
241         0.9583984f, 0.9574706f, 0.9565392f, 0.9556042f,
242         0.9546655f, 0.9537231f, 0.9527769f, 0.9518270f,
243         0.9508732f, 0.9499157f, 0.9489542f, 0.9479888f,
244         0.9470195f, 0.9460462f, 0.9450689f, 0.9440875f,
245         0.9431020f, 0.9421124f, 0.9411186f, 0.9401206f,
246         0.9391184f, 0.9381118f, 0.9371009f, 0.9360856f,
247         0.9350659f, 0.9340417f, 0.9330131f, 0.9319798f,
248         0.9309420f, 0.9298995f, 0.9288523f, 0.9278004f,
249         0.9267436f, 0.9256821f, 0.9246156f, 0.9235442f,
250         0.9224678f, 0.9213864f, 0.9202998f, 0.9192081f,
251         0.9181112f, 0.9170091f, 0.9159016f, 0.9147887f,
252         0.9136703f, 0.9125465f, 0.9114171f, 0.9102821f,
253         0.9091414f, 0.9079949f, 0.9068427f, 0.9056845f,
254         0.9045204f, 0.9033502f, 0.9021740f, 0.9009916f,
255         0.8998029f, 0.8986080f, 0.8974066f, 0.8961988f,
256         0.8949844f, 0.8900599f, 0.8824622f, 0.8759247f,
257         0.8691861f, 0.8636406f, 0.8535788f, 0.8430189f,
258         0.8286135f, 0.8149099f, 0.8002172f, 0.7780663f,
259         0.7554750f, 0.7242125f, 0.6828239f, 0.6329169f,
260         0.5592135f, 0.4551411f, 0.3298770f, 0.0000000f
261     };
262 
263     NW_MINMAX_ASSERT( attack, 0, 127 );
264     m_Attack = attackTable[ attack ];
265 }
266 
267 /*---------------------------------------------------------------------------*
268   Name:         SetSustain
269 
270   Description:  エンベロープのサステインを設定します
271 
272   Arguments:    hold - ホールド値
273 
274   Returns:      None.
275  *---------------------------------------------------------------------------*/
SetHold(int hold)276 void CurveAdshr::SetHold( int hold )
277 {
278     NW_MINMAX_ASSERT( hold, 0, 127 );
279 
280     m_Hold = static_cast<u16>( (hold+1)*(hold+1)/4 );
281 }
282 
283 /*---------------------------------------------------------------------------*
284   Name:         SetDecay
285 
286   Description:  エンベロープのディケイを設定します
287 
288   Arguments:    decay - ディケイ値
289 
290   Returns:      None.
291  *---------------------------------------------------------------------------*/
SetDecay(int decay)292 void CurveAdshr::SetDecay( int decay )
293 {
294     NW_MINMAX_ASSERT( decay, 0, 127 );
295 
296     m_Decay = CalcRelease( decay );
297 }
298 
299 /*---------------------------------------------------------------------------*
300   Name:         SetSustain
301 
302   Description:  エンベロープのサステインを設定します
303 
304   Arguments:    sustain - サステイン値
305 
306   Returns:      None.
307  *---------------------------------------------------------------------------*/
SetSustain(int sustain)308 void CurveAdshr::SetSustain( int sustain )
309 {
310     NW_MINMAX_ASSERT( sustain, 0, 127 );
311 
312     m_Sustain = static_cast<u8>( sustain );
313 }
314 
315 /*---------------------------------------------------------------------------*
316   Name:         SetRelease
317 
318   Description:  エンベロープのリリースを設定します
319 
320   Arguments:    release - リリース値
321 
322   Returns:      None.
323  *---------------------------------------------------------------------------*/
SetRelease(int release)324 void CurveAdshr::SetRelease( int release )
325 {
326     NW_MINMAX_ASSERT( release, 0, 127 );
327 
328     m_Release = CalcRelease( release );
329 }
330 
331 /* ========================================================================
332         private function
333    ======================================================================== */
334 
CalcRelease(int release)335 f32 CurveAdshr::CalcRelease( int release )
336 {
337     NW_MINMAX_ASSERT( release, 0, 127 );
338 
339     if ( release == 127 ) return 65535.0f;
340     if ( release == 126 ) return 120 / 5.0f;
341 
342     if ( release < 50 ) {
343         return ( ( release << 1 ) + 1 ) / 128.0f / 5.0f;
344     }
345     else {
346         return ( 60.0f / ( 126 - release ) ) / 5.0f;
347     }
348 }
349 
CalcDecibelSquare(int scale)350 s16 CurveAdshr::CalcDecibelSquare( int scale )
351 {
352     NW_MINMAX_ASSERT( scale, 0, CALC_DECIBEL_SCALE_MAX );
353     return DecibelSquareTable[ scale ];
354 }
355 
356 
357 } // namespace nw::snd::internal
358 } // namespace nw::snd
359 } // namespace nw
360 
361