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 Library General Public License
7 * as published by the Free Software Foundation; either version 2 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 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 * 02111-1307, USA
19 */
20
21#include "fluid_conv.h"
22
23
24/* conversion tables */
25fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
26fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
27fluid_real_t fluid_atten2amp_tab[FLUID_ATTEN_AMP_SIZE];
28fluid_real_t fluid_posbp_tab[128];
29fluid_real_t fluid_concave_tab[128];
30fluid_real_t fluid_convex_tab[128];
31fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
32
33/*
34 * void fluid_synth_init
35 *
36 * Does all the initialization for this module.
37 */
38void
39fluid_conversion_config(void)
40{
41  int i;
42  double x;
43
44  for (i = 0; i < FLUID_CENTS_HZ_SIZE; i++) {
45    fluid_ct2hz_tab[i] = (fluid_real_t) pow(2.0, (double) i / 1200.0);
46  }
47
48  /* centibels to amplitude conversion
49   * Note: SF2.01 section 8.1.3: Initial attenuation range is
50   * between 0 and 144 dB. Therefore a negative attenuation is
51   * not allowed.
52   */
53  for (i = 0; i < FLUID_CB_AMP_SIZE; i++) {
54    fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
55  }
56
57  /* NOTE: EMU8k and EMU10k devices don't conform to the SoundFont
58   * specification in regards to volume attenuation.  The below calculation
59   * is an approx. equation for generating a table equivelant to the
60   * cb_to_amp_table[] in tables.c of the TiMidity++ source, which I'm told
61   * was generated from device testing.  By the spec this should be centibels.
62   */
63  for (i = 0; i < FLUID_ATTEN_AMP_SIZE; i++) {
64    fluid_atten2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / FLUID_ATTEN_POWER_FACTOR);
65  }
66
67  /* initialize the conversion tables (see fluid_mod.c
68     fluid_mod_get_value cases 4 and 8) */
69
70  /* concave unipolar positive transform curve */
71  fluid_concave_tab[0] = 0.0;
72  fluid_concave_tab[127] = 1.0;
73
74  /* convex unipolar positive transform curve */
75  fluid_convex_tab[0] = 0;
76  fluid_convex_tab[127] = 1.0;
77  x = log10(128.0 / 127.0);
78
79  /* There seems to be an error in the specs. The equations are
80     implemented according to the pictures on SF2.01 page 73. */
81
82  for (i = 1; i < 127; i++) {
83    x = -20.0 / 96.0 * log((i * i) / (127.0 * 127.0)) / log(10.0);
84    fluid_convex_tab[i] = (fluid_real_t) (1.0 - x);
85    fluid_concave_tab[127 - i] = (fluid_real_t) x;
86  }
87
88  /* initialize the pan conversion table */
89  x = PI / 2.0 / (FLUID_PAN_SIZE - 1.0);
90  for (i = 0; i < FLUID_PAN_SIZE; i++) {
91    fluid_pan_tab[i] = (fluid_real_t) sin(i * x);
92  }
93}
94
95/*
96 * fluid_ct2hz
97 */
98fluid_real_t
99fluid_ct2hz_real(fluid_real_t cents)
100{
101  if (cents < 0)
102    return (fluid_real_t) 1.0;
103  else if (cents < 900) {
104    return (fluid_real_t) 6.875 * fluid_ct2hz_tab[(int) (cents + 300)];
105  } else if (cents < 2100) {
106    return (fluid_real_t) 13.75 * fluid_ct2hz_tab[(int) (cents - 900)];
107  } else if (cents < 3300) {
108    return (fluid_real_t) 27.5 * fluid_ct2hz_tab[(int) (cents - 2100)];
109  } else if (cents < 4500) {
110    return (fluid_real_t) 55.0 * fluid_ct2hz_tab[(int) (cents - 3300)];
111  } else if (cents < 5700) {
112    return (fluid_real_t) 110.0 * fluid_ct2hz_tab[(int) (cents - 4500)];
113  } else if (cents < 6900) {
114    return (fluid_real_t) 220.0 * fluid_ct2hz_tab[(int) (cents - 5700)];
115  } else if (cents < 8100) {
116    return (fluid_real_t) 440.0 * fluid_ct2hz_tab[(int) (cents - 6900)];
117  } else if (cents < 9300) {
118    return (fluid_real_t) 880.0 * fluid_ct2hz_tab[(int) (cents - 8100)];
119  } else if (cents < 10500) {
120    return (fluid_real_t) 1760.0 * fluid_ct2hz_tab[(int) (cents - 9300)];
121  } else if (cents < 11700) {
122    return (fluid_real_t) 3520.0 * fluid_ct2hz_tab[(int) (cents - 10500)];
123  } else if (cents < 12900) {
124    return (fluid_real_t) 7040.0 * fluid_ct2hz_tab[(int) (cents - 11700)];
125  } else if (cents < 14100) {
126    return (fluid_real_t) 14080.0 * fluid_ct2hz_tab[(int) (cents - 12900)];
127  } else {
128    return (fluid_real_t) 1.0; /* some loony trying to make you deaf */
129  }
130}
131
132/*
133 * fluid_ct2hz
134 */
135fluid_real_t
136fluid_ct2hz(fluid_real_t cents)
137{
138  /* Filter fc limit: SF2.01 page 48 # 8 */
139  if (cents >= 13500){
140    cents = 13500;             /* 20 kHz */
141  } else if (cents < 1500){
142    cents = 1500;              /* 20 Hz */
143  }
144  return fluid_ct2hz_real(cents);
145}
146
147/*
148 * fluid_cb2amp
149 *
150 * in: a value between 0 and 960, 0 is no attenuation
151 * out: a value between 1 and 0
152 */
153fluid_real_t
154fluid_cb2amp(fluid_real_t cb)
155{
156  /*
157   * cb: an attenuation in 'centibels' (1/10 dB)
158   * SF2.01 page 49 # 48 limits it to 144 dB.
159   * 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit.
160   */
161
162  /* minimum attenuation: 0 dB */
163  if (cb < 0) {
164    return 1.0;
165  }
166  if (cb >= FLUID_CB_AMP_SIZE) {
167    return 0.0;
168  }
169  return fluid_cb2amp_tab[(int) cb];
170}
171
172/*
173 * fluid_atten2amp
174 *
175 * in: a value between 0 and 1440, 0 is no attenuation
176 * out: a value between 1 and 0
177 *
178 * Note: Volume attenuation is supposed to be centibels but EMU8k/10k don't
179 * follow this.  Thats the reason for separate fluid_cb2amp and fluid_atten2amp.
180 */
181fluid_real_t
182fluid_atten2amp(fluid_real_t atten)
183{
184  if (atten < 0) return 1.0;
185  else if (atten >= FLUID_ATTEN_AMP_SIZE) return 0.0;
186  else return fluid_atten2amp_tab[(int) atten];
187}
188
189/*
190 * fluid_tc2sec_delay
191 */
192fluid_real_t
193fluid_tc2sec_delay(fluid_real_t tc)
194{
195  /* SF2.01 section 8.1.2 items 21, 23, 25, 33
196   * SF2.01 section 8.1.3 items 21, 23, 25, 33
197   *
198   * The most negative number indicates a delay of 0. Range is limited
199   * from -12000 to 5000 */
200  if (tc <= -32768.0f) {
201	  return (fluid_real_t) 0.0f;
202  };
203  if (tc < -12000.) {
204	  tc = (fluid_real_t) -12000.0f;
205  }
206  if (tc > 5000.0f) {
207	  tc = (fluid_real_t) 5000.0f;
208  }
209  return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
210}
211
212/*
213 * fluid_tc2sec_attack
214 */
215fluid_real_t
216fluid_tc2sec_attack(fluid_real_t tc)
217{
218  /* SF2.01 section 8.1.2 items 26, 34
219   * SF2.01 section 8.1.3 items 26, 34
220   * The most negative number indicates a delay of 0
221   * Range is limited from -12000 to 8000 */
222  if (tc<=-32768.){return (fluid_real_t) 0.0;};
223  if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
224  if (tc>8000.){tc=(fluid_real_t) 8000.0;};
225  return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
226}
227
228/*
229 * fluid_tc2sec
230 */
231fluid_real_t
232fluid_tc2sec(fluid_real_t tc)
233{
234  /* No range checking here! */
235  return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
236}
237
238/*
239 * fluid_tc2sec_release
240 */
241fluid_real_t
242fluid_tc2sec_release(fluid_real_t tc)
243{
244  /* SF2.01 section 8.1.2 items 30, 38
245   * SF2.01 section 8.1.3 items 30, 38
246   * No 'most negative number' rule here!
247   * Range is limited from -12000 to 8000 */
248  if (tc<=-32768.){return (fluid_real_t) 0.0;};
249  if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
250  if (tc>8000.){tc=(fluid_real_t) 8000.0;};
251  return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
252}
253
254/*
255 * fluid_act2hz
256 *
257 * Convert from absolute cents to Hertz
258 */
259fluid_real_t
260fluid_act2hz(fluid_real_t c)
261{
262  return (fluid_real_t) (8.176 * pow(2.0, (double) c / 1200.0));
263}
264
265/*
266 * fluid_hz2ct
267 *
268 * Convert from Hertz to cents
269 */
270fluid_real_t
271fluid_hz2ct(fluid_real_t f)
272{
273  return (fluid_real_t) (6900 + 1200 * log(f / 440.0) / log(2.0));
274}
275
276/*
277 * fluid_pan
278 */
279fluid_real_t
280fluid_pan(fluid_real_t c, int left)
281{
282  if (left) {
283    c = -c;
284  }
285  if (c < -500) {
286    return (fluid_real_t) 0.0;
287  } else if (c > 500) {
288    return (fluid_real_t) 1.0;
289  } else {
290    return fluid_pan_tab[(int) (c + 500)];
291  }
292}
293
294/*
295 * fluid_concave
296 */
297fluid_real_t
298fluid_concave(fluid_real_t val)
299{
300  if (val < 0) {
301    return 0;
302  } else if (val > 127) {
303    return 1;
304  }
305  return fluid_concave_tab[(int) val];
306}
307
308/*
309 * fluid_convex
310 */
311fluid_real_t
312fluid_convex(fluid_real_t val)
313{
314  if (val < 0) {
315    return 0;
316  } else if (val > 127) {
317    return 1;
318  }
319  return fluid_convex_tab[(int) val];
320}
321