Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/fluidsynth/src/utils/fluid_conv.c
4396 views
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
47
fluid_ct2hz_real(fluid_real_t cents)
48
{
49
if(FLUID_UNLIKELY(cents < 0))
50
{
51
return fluid_act2hz(cents);
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
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
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(FLUID_UNLIKELY(cb < 0))
115
{
116
/* Issue #1374: it seems that by using modLfoToVolEnv, the attenuation can become negative and
117
* therefore the signal needs to be amplified.
118
* In such a rare case, calculate the attenuation on the fly.
119
*
120
* This behavior is backed by the spec saying:
121
* modLfoToVolume: "A positive number indicates a positive LFO excursion increases volume;
122
* a negative number indicates a positive excursion decreases volume.
123
* [...] For example, a value of 100 indicates that the volume will first rise ten dB, then fall ten dB."
124
*
125
* And in order to rise, a negative attenuation must be permitted.
126
*/
127
return FLUID_POW(10.0f, cb / -200.0f);
128
}
129
130
if(cb >= FLUID_CB_AMP_SIZE)
131
{
132
return 0.0;
133
}
134
135
return fluid_cb2amp_tab[(int) cb];
136
}
137
138
/*
139
* fluid_tc2sec_delay
140
*/
141
fluid_real_t
142
fluid_tc2sec_delay(fluid_real_t tc)
143
{
144
/* SF2.01 section 8.1.2 items 21, 23, 25, 33
145
* SF2.01 section 8.1.3 items 21, 23, 25, 33
146
*
147
* The most negative number indicates a delay of 0. Range is limited
148
* from -12000 to 5000 */
149
if(tc <= -32768.0f)
150
{
151
return (fluid_real_t) 0.0f;
152
};
153
154
if(tc < -12000.f)
155
{
156
tc = (fluid_real_t) -12000.0f;
157
}
158
159
if(tc > 5000.0f)
160
{
161
tc = (fluid_real_t) 5000.0f;
162
}
163
164
return fluid_tc2sec(tc);
165
}
166
167
/*
168
* fluid_tc2sec_attack
169
*/
170
fluid_real_t
171
fluid_tc2sec_attack(fluid_real_t tc)
172
{
173
/* SF2.01 section 8.1.2 items 26, 34
174
* SF2.01 section 8.1.3 items 26, 34
175
* The most negative number indicates a delay of 0
176
* Range is limited from -12000 to 8000 */
177
if(tc <= -32768.f)
178
{
179
return (fluid_real_t) 0.f;
180
};
181
182
if(tc < -12000.f)
183
{
184
tc = (fluid_real_t) -12000.f;
185
};
186
187
if(tc > 8000.f)
188
{
189
tc = (fluid_real_t) 8000.f;
190
};
191
192
return fluid_tc2sec(tc);
193
}
194
195
/*
196
* fluid_tc2sec
197
*/
198
fluid_real_t
199
fluid_tc2sec(fluid_real_t tc)
200
{
201
/* No range checking here! */
202
return FLUID_POW(2.f, tc / 1200.f);
203
}
204
205
/*
206
* fluid_sec2tc
207
*
208
* seconds to timecents
209
*/
210
fluid_real_t
211
fluid_sec2tc(fluid_real_t sec)
212
{
213
fluid_real_t res;
214
if(sec < 0)
215
{
216
// would require a complex solution of fluid_tc2sec(), but this is real-only
217
return -32768.f;
218
}
219
220
res = (1200.f / M_LN2) * FLUID_LOGF(sec);
221
if(res < -32768.f)
222
{
223
res = -32768.f;
224
}
225
return res;
226
}
227
228
/*
229
* fluid_tc2sec_release
230
*/
231
fluid_real_t
232
fluid_tc2sec_release(fluid_real_t tc)
233
{
234
/* SF2.01 section 8.1.2 items 30, 38
235
* SF2.01 section 8.1.3 items 30, 38
236
* No 'most negative number' rule here!
237
* Range is limited from -12000 to 8000 */
238
if(tc <= -32768.f)
239
{
240
return (fluid_real_t) 0.f;
241
};
242
243
if(tc < -12000.f)
244
{
245
tc = (fluid_real_t) -12000.f;
246
};
247
248
if(tc > 8000.f)
249
{
250
tc = (fluid_real_t) 8000.f;
251
};
252
253
return fluid_tc2sec(tc);
254
}
255
256
/**
257
* The inverse operation, converting from Hertz to cents
258
*/
259
fluid_real_t fluid_hz2ct(fluid_real_t f)
260
{
261
return 6900.f + (1200.f / FLUID_M_LN2) * FLUID_LOGF(f / 440.0f);
262
}
263
264
/*
265
* fluid_act2hz
266
*
267
* Convert from absolute cents to Hertz
268
*/
269
double
270
fluid_act2hz(double c)
271
{
272
// do not use FLUID_POW, otherwise the unit tests will fail when compiled in single precision
273
return 8.1757989156437073336828122976032719176391831357 * pow(2.f, c / 1200.f);
274
}
275
276
/*
277
* fluid_pan
278
*/
279
fluid_real_t
280
fluid_pan(fluid_real_t c, int left)
281
{
282
if(left)
283
{
284
c = -c;
285
}
286
287
if(c <= -500.f)
288
{
289
return (fluid_real_t) 0.f;
290
}
291
else if(c >= 500.f)
292
{
293
return (fluid_real_t) 1.f;
294
}
295
else
296
{
297
return fluid_pan_tab[(int)(c) + 500];
298
}
299
}
300
301
/*
302
* Return the amount of attenuation based on the balance for the specified
303
* channel. If balance is negative (turned toward left channel, only the right
304
* channel is attenuated. If balance is positive, only the left channel is
305
* attenuated.
306
*
307
* @params balance left/right balance, range [-960;960] in absolute centibels
308
* @return amount of attenuation [0.0;1.0]
309
*/
310
fluid_real_t fluid_balance(fluid_real_t balance, int left)
311
{
312
/* This is the most common case */
313
if(balance == 0.f)
314
{
315
return 1.0f;
316
}
317
318
if((left && balance < 0.f) || (!left && balance > 0.f))
319
{
320
return 1.0f;
321
}
322
323
if(balance < 0.f)
324
{
325
balance = -balance;
326
}
327
328
return fluid_cb2amp(balance);
329
}
330
331
/*
332
* fluid_concave
333
*/
334
fluid_real_t
335
fluid_concave(fluid_real_t val)
336
{
337
int ival = (int)val;
338
if(val < 0.f)
339
{
340
return 0.f;
341
}
342
else if (ival >= FLUID_VEL_CB_SIZE - 1)
343
{
344
return fluid_concave_tab[FLUID_VEL_CB_SIZE - 1];
345
}
346
347
return fluid_concave_tab[ival] + (fluid_concave_tab[ival + 1] - fluid_concave_tab[ival]) * (val - ival);
348
}
349
350
/*
351
* fluid_convex
352
*/
353
fluid_real_t
354
fluid_convex(fluid_real_t val)
355
{
356
int ival = (int)val;
357
if(val < 0.f)
358
{
359
return 0.f;
360
}
361
else if (ival >= FLUID_VEL_CB_SIZE - 1)
362
{
363
return fluid_convex_tab[FLUID_VEL_CB_SIZE - 1];
364
}
365
366
// interpolation between convex steps: fixes bad sounds with modenv and filter cutoff
367
return fluid_convex_tab[ival] + (fluid_convex_tab[ival + 1] - fluid_convex_tab[ival]) * (val - ival);
368
}
369
370