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