1 /* FluidSynth - A Software Synthesizer
2  *
3  * Copyright (C) 2003  Peter Hanappe and others.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License
7  * as published by the Free Software Foundation; either version 2.1 of
8  * the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA
19  */
20 
21 #include "fluid_conv.h"
22 #include "fluid_sys.h"
23 #include "fluid_conv_tables.inc.h"
24 
25 /*
26  * Converts absolute cents to Hertz
27  *
28  * As per sfspec section 9.3:
29  *
30  * ABSOLUTE CENTS - An absolute logarithmic measure of frequency based on a
31  * reference of MIDI key number scaled by 100.
32  * A cent is 1/1200 of an octave [which is the twelve hundredth root of two],
33  * and value 6900 is 440 Hz (A-440).
34  *
35  * Implemented below basically is the following:
36  *   440 * 2^((cents-6900)/1200)
37  * = 440 * 2^((int)((cents-6900)/1200)) * 2^(((int)cents-6900)%1200))
38  * = 2^((int)((cents-6900)/1200)) * (440 * 2^(((int)cents-6900)%1200)))
39  *                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40  *                           This second factor is stored in the lookup table.
41  *
42  * The first factor can be implemented with a fast shift when the exponent
43  * is always an int. This is the case when using 440/2^6 Hz rather than 440Hz
44  * reference.
45  */
46 fluid_real_t
fluid_ct2hz_real(fluid_real_t cents)47 fluid_ct2hz_real(fluid_real_t cents)
48 {
49     if(FLUID_UNLIKELY(cents < 0))
50     {
51         return (fluid_real_t) 1.0;
52     }
53     else
54     {
55         unsigned int mult, fac, rem;
56         unsigned int icents = (unsigned int)cents;
57         icents += 300u;
58 
59         // don't use stdlib div() here, it turned out have poor performance
60         fac = icents / 1200u;
61         rem = icents % 1200u;
62 
63         // Think of "mult" as the factor that we multiply (440/2^6)Hz with,
64         // or in other words mult is the "first factor" of the above
65         // functions comment.
66         //
67         // Assuming sizeof(uint)==4 this will give us a maximum range of
68         // 32 * 1200cents - 300cents == 38100 cents == 29,527,900,160 Hz
69         // which is much more than ever needed. For bigger values, just
70         // safely wrap around (the & is just a replacement for the quick
71         // modulo operation % 32).
72         mult = 1u << (fac & (sizeof(mult)*8u - 1u));
73 
74         // don't use ldexp() either (poor performance)
75         return mult * fluid_ct2hz_tab[rem];
76     }
77 }
78 
79 /*
80  * fluid_ct2hz
81  */
82 fluid_real_t
fluid_ct2hz(fluid_real_t cents)83 fluid_ct2hz(fluid_real_t cents)
84 {
85     /* Filter fc limit: SF2.01 page 48 # 8 */
86     if(cents >= 13500)
87     {
88         cents = 13500;             /* 20 kHz */
89     }
90     else if(cents < 1500)
91     {
92         cents = 1500;              /* 20 Hz */
93     }
94 
95     return fluid_ct2hz_real(cents);
96 }
97 
98 /*
99  * fluid_cb2amp
100  *
101  * in: a value between 0 and 1440, 0 is no attenuation
102  * out: a value between 1 and 0
103  */
104 fluid_real_t
fluid_cb2amp(fluid_real_t cb)105 fluid_cb2amp(fluid_real_t cb)
106 {
107     /*
108      * cb: an attenuation in 'centibels' (1/10 dB)
109      * SF2.01 page 49 # 48 limits it to 144 dB.
110      * 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit.
111      */
112 
113     /* minimum attenuation: 0 dB */
114     if(cb < 0)
115     {
116         return 1.0;
117     }
118 
119     if(cb >= FLUID_CB_AMP_SIZE)
120     {
121         return 0.0;
122     }
123 
124     return fluid_cb2amp_tab[(int) cb];
125 }
126 
127 /*
128  * fluid_tc2sec_delay
129  */
130 fluid_real_t
fluid_tc2sec_delay(fluid_real_t tc)131 fluid_tc2sec_delay(fluid_real_t tc)
132 {
133     /* SF2.01 section 8.1.2 items 21, 23, 25, 33
134      * SF2.01 section 8.1.3 items 21, 23, 25, 33
135      *
136      * The most negative number indicates a delay of 0. Range is limited
137      * from -12000 to 5000 */
138     if(tc <= -32768.0f)
139     {
140         return (fluid_real_t) 0.0f;
141     };
142 
143     if(tc < -12000.f)
144     {
145         tc = (fluid_real_t) -12000.0f;
146     }
147 
148     if(tc > 5000.0f)
149     {
150         tc = (fluid_real_t) 5000.0f;
151     }
152 
153     return FLUID_POW(2.f, tc / 1200.f);
154 }
155 
156 /*
157  * fluid_tc2sec_attack
158  */
159 fluid_real_t
fluid_tc2sec_attack(fluid_real_t tc)160 fluid_tc2sec_attack(fluid_real_t tc)
161 {
162     /* SF2.01 section 8.1.2 items 26, 34
163      * SF2.01 section 8.1.3 items 26, 34
164      * The most negative number indicates a delay of 0
165      * Range is limited from -12000 to 8000 */
166     if(tc <= -32768.f)
167     {
168         return (fluid_real_t) 0.f;
169     };
170 
171     if(tc < -12000.f)
172     {
173         tc = (fluid_real_t) -12000.f;
174     };
175 
176     if(tc > 8000.f)
177     {
178         tc = (fluid_real_t) 8000.f;
179     };
180 
181     return FLUID_POW(2.f, tc / 1200.f);
182 }
183 
184 /*
185  * fluid_tc2sec
186  */
187 fluid_real_t
fluid_tc2sec(fluid_real_t tc)188 fluid_tc2sec(fluid_real_t tc)
189 {
190     /* No range checking here! */
191     return FLUID_POW(2.f, tc / 1200.f);
192 }
193 
194 /*
195  * fluid_tc2sec_release
196  */
197 fluid_real_t
fluid_tc2sec_release(fluid_real_t tc)198 fluid_tc2sec_release(fluid_real_t tc)
199 {
200     /* SF2.01 section 8.1.2 items 30, 38
201      * SF2.01 section 8.1.3 items 30, 38
202      * No 'most negative number' rule here!
203      * Range is limited from -12000 to 8000 */
204     if(tc <= -32768.f)
205     {
206         return (fluid_real_t) 0.f;
207     };
208 
209     if(tc < -12000.f)
210     {
211         tc = (fluid_real_t) -12000.f;
212     };
213 
214     if(tc > 8000.f)
215     {
216         tc = (fluid_real_t) 8000.f;
217     };
218 
219     return FLUID_POW(2.f, tc / 1200.f);
220 }
221 
222 /*
223  * fluid_act2hz
224  *
225  * Convert from absolute cents to Hertz
226  *
227  * The inverse operation, converting from Hertz to cents, was unused and implemented as
228  *
229 fluid_hz2ct(fluid_real_t f)
230 {
231     return 6900.f + (1200.f / FLUID_M_LN2) * FLUID_LOGF(f / 440.0f));
232 }
233  */
234 fluid_real_t
fluid_act2hz(fluid_real_t c)235 fluid_act2hz(fluid_real_t c)
236 {
237     return 8.176f * FLUID_POW(2.f, c / 1200.f);
238 }
239 
240 /*
241  * fluid_pan
242  */
243 fluid_real_t
fluid_pan(fluid_real_t c,int left)244 fluid_pan(fluid_real_t c, int left)
245 {
246     if(left)
247     {
248         c = -c;
249     }
250 
251     if(c <= -500.f)
252     {
253         return (fluid_real_t) 0.f;
254     }
255     else if(c >= 500.f)
256     {
257         return (fluid_real_t) 1.f;
258     }
259     else
260     {
261         return fluid_pan_tab[(int)(c) + 500];
262     }
263 }
264 
265 /*
266  * Return the amount of attenuation based on the balance for the specified
267  * channel. If balance is negative (turned toward left channel, only the right
268  * channel is attenuated. If balance is positive, only the left channel is
269  * attenuated.
270  *
271  * @params balance left/right balance, range [-960;960] in absolute centibels
272  * @return amount of attenuation [0.0;1.0]
273  */
fluid_balance(fluid_real_t balance,int left)274 fluid_real_t fluid_balance(fluid_real_t balance, int left)
275 {
276     /* This is the most common case */
277     if(balance == 0.f)
278     {
279         return 1.0f;
280     }
281 
282     if((left && balance < 0.f) || (!left && balance > 0.f))
283     {
284         return 1.0f;
285     }
286 
287     if(balance < 0.f)
288     {
289         balance = -balance;
290     }
291 
292     return fluid_cb2amp(balance);
293 }
294 
295 /*
296  * fluid_concave
297  */
298 fluid_real_t
fluid_concave(fluid_real_t val)299 fluid_concave(fluid_real_t val)
300 {
301     if(val < 0.f)
302     {
303         return 0.f;
304     }
305     else if(val >= (fluid_real_t)FLUID_VEL_CB_SIZE)
306     {
307         return 1.f;
308     }
309 
310     return fluid_concave_tab[(int) val];
311 }
312 
313 /*
314  * fluid_convex
315  */
316 fluid_real_t
fluid_convex(fluid_real_t val)317 fluid_convex(fluid_real_t val)
318 {
319     if(val < 0.f)
320     {
321         return 0.f;
322     }
323     else if(val >= (fluid_real_t)FLUID_VEL_CB_SIZE)
324     {
325         return 1.f;
326     }
327 
328     return fluid_convex_tab[(int) val];
329 }
330 
331