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