1 /*
2  * libInstPatch
3  * Copyright (C) 1999-2014 Element Green <element@elementsofsound.org>
4  *
5  * This program 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; version 2.1
8  * of the License only.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA or on the web at http://www.gnu.org.
19  */
20 /**
21  * SECTION: IpatchUnit_DLS
22  * @short_description: Unit types and conversions for DLS
23  * @see_also:
24  * @stability: Stable
25  */
26 #include <stdio.h>
27 #include <math.h>
28 #include <glib.h>
29 #include <glib-object.h>
30 #include "IpatchUnit_DLS.h"
31 #include "IpatchUnit.h"
32 #include "i18n.h"
33 
34 
35 static void
36 ipatch_unit_dls_percent_to_percent_value(const GValue *src_val,
37         GValue *dest_val);
38 static void
39 ipatch_unit_percent_to_dls_percent_value(const GValue *src_val,
40         GValue *dest_val);
41 static void ipatch_unit_dls_gain_to_decibels_value(const GValue *src_val,
42         GValue *dest_val);
43 static void ipatch_unit_decibels_to_dls_gain_value(const GValue *src_val,
44         GValue *dest_val);
45 static void
46 ipatch_unit_dls_abs_time_to_seconds_value(const GValue *src_val,
47         GValue *dest_val);
48 static void
49 ipatch_unit_seconds_to_dls_abs_time_value(const GValue *src_val,
50         GValue *dest_val);
51 static void
52 ipatch_unit_dls_rel_time_to_time_cents_value(const GValue *src_val,
53         GValue *dest_val);
54 static void
55 ipatch_unit_time_cents_to_dls_rel_time_value(const GValue *src_val,
56         GValue *dest_val);
57 static void
58 ipatch_unit_dls_abs_pitch_to_hertz_value(const GValue *src_val,
59         GValue *dest_val);
60 static void
61 ipatch_unit_hertz_to_dls_abs_pitch_value(const GValue *src_val,
62         GValue *dest_val);
63 static void
64 ipatch_unit_dls_rel_pitch_to_cents_value(const GValue *src_val,
65         GValue *dest_val);
66 static void
67 ipatch_unit_cents_to_dls_rel_pitch_value(const GValue *src_val,
68         GValue *dest_val);
69 
70 /**
71  * _ipatch_unit_dls_init: (skip)
72  */
73 void
_ipatch_unit_dls_init(void)74 _ipatch_unit_dls_init(void)
75 {
76     IpatchUnitInfo *info;
77 
78     info = ipatch_unit_info_new();
79     info->label = NULL;
80     info->descr = NULL;
81     info->value_type = G_TYPE_INT;
82     info->digits = 0;
83 
84     info->id = IPATCH_UNIT_TYPE_DLS_PERCENT;
85     info->name = "DLSPercent";
86     ipatch_unit_register(info);
87 
88     info->id = IPATCH_UNIT_TYPE_DLS_GAIN;
89     info->name = "DLSGain";
90     ipatch_unit_register(info);
91 
92     info->id = IPATCH_UNIT_TYPE_DLS_ABS_TIME;
93     info->name = "DLSAbsTime";
94     ipatch_unit_register(info);
95 
96     info->id = IPATCH_UNIT_TYPE_DLS_REL_TIME;
97     info->name = "DLSRelTime";
98     ipatch_unit_register(info);
99 
100     info->id = IPATCH_UNIT_TYPE_DLS_ABS_PITCH;
101     info->name = "DLSAbsPitch";
102     ipatch_unit_register(info);
103 
104     info->id = IPATCH_UNIT_TYPE_DLS_REL_PITCH;
105     info->name = "DLSRelPitch";
106     ipatch_unit_register(info);
107 
108     ipatch_unit_info_free(info);	/* done with unit info structure, free it */
109 
110     ipatch_unit_conversion_register
111     (IPATCH_UNIT_TYPE_DLS_PERCENT, IPATCH_UNIT_TYPE_PERCENT,
112      ipatch_unit_dls_percent_to_percent_value);
113     ipatch_unit_conversion_register
114     (IPATCH_UNIT_TYPE_PERCENT, IPATCH_UNIT_TYPE_DLS_PERCENT,
115      ipatch_unit_percent_to_dls_percent_value);
116 
117     ipatch_unit_conversion_register
118     (IPATCH_UNIT_TYPE_DLS_GAIN, IPATCH_UNIT_TYPE_DECIBELS,
119      ipatch_unit_dls_gain_to_decibels_value);
120     ipatch_unit_conversion_register
121     (IPATCH_UNIT_TYPE_DECIBELS, IPATCH_UNIT_TYPE_DLS_GAIN,
122      ipatch_unit_decibels_to_dls_gain_value);
123 
124     ipatch_unit_conversion_register
125     (IPATCH_UNIT_TYPE_DLS_ABS_TIME, IPATCH_UNIT_TYPE_SECONDS,
126      ipatch_unit_dls_abs_time_to_seconds_value);
127     ipatch_unit_conversion_register
128     (IPATCH_UNIT_TYPE_SECONDS, IPATCH_UNIT_TYPE_DLS_ABS_TIME,
129      ipatch_unit_seconds_to_dls_abs_time_value);
130 
131     ipatch_unit_conversion_register
132     (IPATCH_UNIT_TYPE_DLS_REL_TIME, IPATCH_UNIT_TYPE_TIME_CENTS,
133      ipatch_unit_dls_rel_time_to_time_cents_value);
134     ipatch_unit_conversion_register
135     (IPATCH_UNIT_TYPE_TIME_CENTS, IPATCH_UNIT_TYPE_DLS_REL_TIME,
136      ipatch_unit_time_cents_to_dls_rel_time_value);
137 
138     ipatch_unit_conversion_register
139     (IPATCH_UNIT_TYPE_DLS_ABS_PITCH, IPATCH_UNIT_TYPE_HERTZ,
140      ipatch_unit_dls_abs_pitch_to_hertz_value);
141     ipatch_unit_conversion_register
142     (IPATCH_UNIT_TYPE_HERTZ, IPATCH_UNIT_TYPE_DLS_ABS_PITCH,
143      ipatch_unit_hertz_to_dls_abs_pitch_value);
144 
145     ipatch_unit_conversion_register
146     (IPATCH_UNIT_TYPE_DLS_REL_PITCH, IPATCH_UNIT_TYPE_CENTS,
147      ipatch_unit_dls_rel_pitch_to_cents_value);
148     ipatch_unit_conversion_register
149     (IPATCH_UNIT_TYPE_CENTS, IPATCH_UNIT_TYPE_DLS_REL_PITCH,
150      ipatch_unit_cents_to_dls_rel_pitch_value);
151 
152 
153     ipatch_unit_class_register_map(IPATCH_UNIT_CLASS_USER,
154                                    IPATCH_UNIT_TYPE_DLS_PERCENT,
155                                    IPATCH_UNIT_TYPE_PERCENT);
156     ipatch_unit_class_register_map(IPATCH_UNIT_CLASS_USER,
157                                    IPATCH_UNIT_TYPE_DLS_GAIN,
158                                    IPATCH_UNIT_TYPE_DECIBELS);
159     ipatch_unit_class_register_map(IPATCH_UNIT_CLASS_USER,
160                                    IPATCH_UNIT_TYPE_DLS_ABS_TIME,
161                                    IPATCH_UNIT_TYPE_SECONDS);
162     ipatch_unit_class_register_map(IPATCH_UNIT_CLASS_USER,
163                                    IPATCH_UNIT_TYPE_DLS_REL_TIME,
164                                    IPATCH_UNIT_TYPE_TIME_CENTS);
165     ipatch_unit_class_register_map(IPATCH_UNIT_CLASS_USER,
166                                    IPATCH_UNIT_TYPE_DLS_ABS_PITCH,
167                                    IPATCH_UNIT_TYPE_HERTZ);
168     ipatch_unit_class_register_map(IPATCH_UNIT_CLASS_USER,
169                                    IPATCH_UNIT_TYPE_DLS_REL_PITCH,
170                                    IPATCH_UNIT_TYPE_CENTS);
171 }
172 
173 /**
174  * ipatch_unit_dls_class_convert:
175  * @src_units: Source unit type ID
176  * @src_val: Source value (type should be compatible with the source unit's
177  *   value type)
178  *
179  * Converts a value to "DLS" units.  DLS units are unit types that
180  * are used by DLS (Downloadable Sounds) patches.  The #IPATCH_UNIT_CLASS_DLS
181  * map is used to lookup the corresponding type to convert to.
182  * Only some types have an associated DLS type.  It is an error to pass a
183  * @src_units type that has no DLS mapping (note that this is contrary to the
184  * behavior of ipatch_unit_user_class_convert()).
185  *
186  * Returns: The value converted to DLS units.
187  */
188 int
ipatch_unit_dls_class_convert(guint16 src_units,const GValue * src_val)189 ipatch_unit_dls_class_convert(guint16 src_units, const GValue *src_val)
190 {
191     IpatchUnitInfo *dest_info;
192     GValue v = { 0 };
193     int retval;
194 
195     g_return_val_if_fail(src_val != NULL, 0);
196 
197     dest_info = ipatch_unit_class_lookup_map(IPATCH_UNIT_CLASS_DLS, src_units);
198     g_return_val_if_fail(dest_info != NULL, 0);
199 
200     g_value_init(&v, G_TYPE_INT);
201     ipatch_unit_convert(src_units, dest_info->id, src_val, &v);
202 
203     retval = g_value_get_int(&v);
204     g_value_unset(&v);	/* probably not needed, for the sake of extra paranoia (TM) */
205 
206     return (retval);
207 }
208 
209 /**
210  * ipatch_unit_dls_percent_to_percent:
211  * @dls_percent: Value in DLS percent units
212  *
213  * Convert value in DLS percent units to percent.
214  *
215  * percent = dls_percent / (10 * 65536)
216  *
217  * Returns: Value in percent
218  */
219 double
ipatch_unit_dls_percent_to_percent(int dls_percent)220 ipatch_unit_dls_percent_to_percent(int dls_percent)
221 {
222     return ((double)dls_percent / 655360.0);
223 }
224 
225 /**
226  * ipatch_unit_percent_to_dls_percent:
227  * @percent: Value in percent
228  *
229  * Convert percent to DLS percent.
230  *
231  * dls_percent = percent * 10 * 65536
232  *
233  * Returns: Converted integer in DLS percent
234  */
235 int
ipatch_unit_percent_to_dls_percent(double percent)236 ipatch_unit_percent_to_dls_percent(double percent)
237 {
238     return (int)(percent * 655360.0 + 0.5);	/* +0.5 for rounding */
239 }
240 
241 /**
242  * ipatch_unit_dls_gain_to_decibels:
243  * @dls_gain: Value in DLS gain units
244  *
245  * Converts a value from DLS gain to decibels.
246  *
247  * dls_gain = 200 * 65536 * log10 (V / v)
248  * decibels = 20 * log10 (V / v)
249  *
250  * Returns: Value converted to decibels
251  */
252 double
ipatch_unit_dls_gain_to_decibels(int dls_gain)253 ipatch_unit_dls_gain_to_decibels(int dls_gain)
254 {
255     return ((double)dls_gain / 655360.0);
256 }
257 
258 /**
259  * ipatch_unit_decibels_to_dls_gain:
260  * @db: Value in decibels
261  *
262  * Converts a value from decibels to DLS gain.
263  * See ipatch_unit_dls_gain_to_decibel()
264  *
265  * Returns: Value converted to DLS gain
266  */
267 int
ipatch_unit_decibels_to_dls_gain(double db)268 ipatch_unit_decibels_to_dls_gain(double db)
269 {
270     return (int)(db * 655360.0 + 0.5);
271 }
272 
273 /**
274  * ipatch_unit_dls_abs_time_to_seconds:
275  * @dls_abs_time: Value in DLS absolute time
276  *
277  * Converts a value from DLS absolute time to seconds.
278  * seconds = 2^(dls_abs_time / (1200 * 65536))
279  *
280  * 0x80000000 is used as a 0 value.
281  *
282  * Returns: Value converted to seconds
283  */
284 double
ipatch_unit_dls_abs_time_to_seconds(gint32 dls_abs_time)285 ipatch_unit_dls_abs_time_to_seconds(gint32 dls_abs_time)
286 {
287     if(dls_abs_time == IPATCH_UNIT_DLS_ABS_TIME_0SECS)
288     {
289         return (0.0);
290     }
291 
292     return (pow(2.0, (double)dls_abs_time / (1200 * 65536)));
293 }
294 
295 /**
296  * ipatch_unit_seconds_to_dls_abs_time:
297  * @seconds: Value in seconds
298  *
299  * Converts a value from seconds to DLS absolute time.
300  * dls_rel_time = 1200 * log2 (seconds) * 65536
301  *
302  * Returns: Value converted to DLS relative time
303  */
304 gint32
ipatch_unit_seconds_to_dls_abs_time(double seconds)305 ipatch_unit_seconds_to_dls_abs_time(double seconds)
306 {
307     if(seconds == 0.0)
308     {
309         return (IPATCH_UNIT_DLS_ABS_TIME_0SECS);
310     }
311 
312     return (gint32)((double)1200.0 * (log(seconds) / log(2.0)) * 65536.0 + 0.5);
313 }
314 
315 /**
316  * ipatch_unit_dls_rel_time_to_time_cents:
317  * @dls_rel_time: Value in DLS relative time
318  *
319  * Converts a value from DLS relative time to time cents.
320  * time_cents = dls_rel_time / 65536
321  *
322  * Returns: Value converted to time cents
323  */
324 double
ipatch_unit_dls_rel_time_to_time_cents(int dls_rel_time)325 ipatch_unit_dls_rel_time_to_time_cents(int dls_rel_time)
326 {
327     return (dls_rel_time / 65536.0);
328 }
329 
330 /**
331  * ipatch_unit_time_cents_to_dls_rel_time:
332  * @time_cents: Value in time cents
333  *
334  * Converts a value from time_cents to DLS relative time.
335  * dls_rel_time = time_cents * 65536
336  *
337  * Returns: Value converted to DLS relative time
338  */
339 int
ipatch_unit_time_cents_to_dls_rel_time(double time_cents)340 ipatch_unit_time_cents_to_dls_rel_time(double time_cents)
341 {
342     return (int)(time_cents * 65536.0 + 0.5);
343 }
344 
345 /**
346  * ipatch_unit_dls_abs_pitch_to_hertz:
347  * @dls_abs_pitch: Value in DLS absolute pitch
348  *
349  * Converts a value from DLS absolute pitch to hertz.
350  * hertz = 440 * 2^((dls_abs_pitch / 65536 - 6900) / 1200)
351  *
352  * Returns: Value converted to hertz
353  */
354 double
ipatch_unit_dls_abs_pitch_to_hertz(int dls_abs_pitch)355 ipatch_unit_dls_abs_pitch_to_hertz(int dls_abs_pitch)
356 {
357     return ((double)440.0 * pow(2.0, (dls_abs_pitch / 65536.0 - 6900.0) / 1200.0));
358 }
359 
360 /**
361  * ipatch_unit_hertz_to_dls_abs_pitch:
362  * @hertz: Value in hertz
363  *
364  * Converts a value from hertz to DLS absolute pitch.
365  * dls_abs_pitch = (1200 * log2(hertz/440) + 6900) * 65536
366  *
367  * Returns: Value converted to DLS absolute pitch
368  */
369 int
ipatch_unit_hertz_to_dls_abs_pitch(double hertz)370 ipatch_unit_hertz_to_dls_abs_pitch(double hertz)
371 {
372     return (int)(((double)1200.0 * (log(hertz / 440.0) / log(2)) + 6900.0) * 65536.0 + 0.5);
373 }
374 
375 /**
376  * ipatch_unit_dls_rel_pitch_to_cents:
377  * @dls_rel_pitch: Value in DLS relative pitch
378  *
379  * Converts a value from DLS relative pitch to cents.
380  * cents = dls_rel_pitch / 65536
381  *
382  * Returns: Value converted to cents
383  */
384 double
ipatch_unit_dls_rel_pitch_to_cents(int dls_rel_pitch)385 ipatch_unit_dls_rel_pitch_to_cents(int dls_rel_pitch)
386 {
387     return ((double)dls_rel_pitch / 65536.0);
388 }
389 
390 /**
391  * ipatch_unit_cents_to_dls_rel_pitch:
392  * @cents: Value in cents
393  *
394  * Converts a value from cents to DLS relative pitch.
395  * dls_rel_pitch = cents * 65536
396  *
397  * Returns: Value converted to DLS relative pitch
398  */
399 int
ipatch_unit_cents_to_dls_rel_pitch(double cents)400 ipatch_unit_cents_to_dls_rel_pitch(double cents)
401 {
402     return (int)(cents * 65536.0 + 0.5);
403 }
404 
405 
406 /* =================================================
407    GValue conversion functions, duplicated for speed
408    ================================================= */
409 
410 
411 static void
ipatch_unit_dls_percent_to_percent_value(const GValue * src_val,GValue * dest_val)412 ipatch_unit_dls_percent_to_percent_value(const GValue *src_val,
413         GValue *dest_val)
414 {
415     int dls_percent = g_value_get_int(src_val);
416     g_value_set_double(dest_val, (double)dls_percent / 655360.0);
417 }
418 
419 static void
ipatch_unit_percent_to_dls_percent_value(const GValue * src_val,GValue * dest_val)420 ipatch_unit_percent_to_dls_percent_value(const GValue *src_val,
421         GValue *dest_val)
422 {
423     double percent = g_value_get_double(src_val);
424     g_value_set_int(dest_val, (gint)(percent * 655360.0 + 0.5));
425 }
426 
427 static void
ipatch_unit_dls_gain_to_decibels_value(const GValue * src_val,GValue * dest_val)428 ipatch_unit_dls_gain_to_decibels_value(const GValue *src_val, GValue *dest_val)
429 {
430     int dls_gain = g_value_get_int(src_val);
431     g_value_set_double(dest_val, (double)dls_gain / 655360.0);
432 }
433 
434 static void
ipatch_unit_decibels_to_dls_gain_value(const GValue * src_val,GValue * dest_val)435 ipatch_unit_decibels_to_dls_gain_value(const GValue *src_val, GValue *dest_val)
436 {
437     double db = g_value_get_double(src_val);
438     g_value_set_int(dest_val, (gint)(db * 655360.0 + 0.5));
439 }
440 
441 static void
ipatch_unit_dls_abs_time_to_seconds_value(const GValue * src_val,GValue * dest_val)442 ipatch_unit_dls_abs_time_to_seconds_value(const GValue *src_val,
443         GValue *dest_val)
444 {
445     int dls_abs_time = g_value_get_int(src_val);
446     double secs;
447 
448     if(dls_abs_time != IPATCH_UNIT_DLS_ABS_TIME_0SECS)
449     {
450         secs = pow(2.0, (double)dls_abs_time / (1200 * 65536));
451     }
452     else
453     {
454         secs = 0.0;
455     }
456 
457     g_value_set_double(dest_val, secs);
458 }
459 
460 static void
ipatch_unit_seconds_to_dls_abs_time_value(const GValue * src_val,GValue * dest_val)461 ipatch_unit_seconds_to_dls_abs_time_value(const GValue *src_val,
462         GValue *dest_val)
463 {
464     double secs = g_value_get_double(src_val);
465     int dls_abs_time;
466 
467     if(secs != 0.0)
468     {
469         dls_abs_time = (int)((double)1200.0 * (log(secs) / log(2.0)) * 65536.0 + 0.5);
470     }
471     else
472     {
473         dls_abs_time = IPATCH_UNIT_DLS_ABS_TIME_0SECS;
474     }
475 
476     g_value_set_int(dest_val, dls_abs_time);
477 }
478 
479 static void
ipatch_unit_dls_rel_time_to_time_cents_value(const GValue * src_val,GValue * dest_val)480 ipatch_unit_dls_rel_time_to_time_cents_value(const GValue *src_val,
481         GValue *dest_val)
482 {
483     int dls_rel_time = g_value_get_int(src_val);
484     g_value_set_double(dest_val, (double)dls_rel_time / 65536.0);
485 }
486 
487 static void
ipatch_unit_time_cents_to_dls_rel_time_value(const GValue * src_val,GValue * dest_val)488 ipatch_unit_time_cents_to_dls_rel_time_value(const GValue *src_val,
489         GValue *dest_val)
490 {
491     double time_cents = g_value_get_double(src_val);
492     g_value_set_int(dest_val, (gint)(time_cents * 65536.0 + 0.5));
493 }
494 
495 static void
ipatch_unit_dls_abs_pitch_to_hertz_value(const GValue * src_val,GValue * dest_val)496 ipatch_unit_dls_abs_pitch_to_hertz_value(const GValue *src_val,
497         GValue *dest_val)
498 {
499     int dls_abs_pitch = g_value_get_int(src_val);
500     g_value_set_double(dest_val, 440.0 * pow(2.0, ((double)dls_abs_pitch
501                        / 65536.0 - 6900.0) / 1200.0));
502 }
503 
504 static void
ipatch_unit_hertz_to_dls_abs_pitch_value(const GValue * src_val,GValue * dest_val)505 ipatch_unit_hertz_to_dls_abs_pitch_value(const GValue *src_val,
506         GValue *dest_val)
507 {
508     double hertz = g_value_get_double(src_val);
509     g_value_set_int(dest_val, (gint)(((double)1200.0 * (log(hertz / 440.0) / log(2))
510                                       + 6900.0) * 65536.0 + 0.5));
511 }
512 
513 static void
ipatch_unit_dls_rel_pitch_to_cents_value(const GValue * src_val,GValue * dest_val)514 ipatch_unit_dls_rel_pitch_to_cents_value(const GValue *src_val,
515         GValue *dest_val)
516 {
517     int dls_rel_pitch = g_value_get_int(src_val);
518     g_value_set_double(dest_val, (double)dls_rel_pitch / 65536.0);
519 }
520 
521 static void
ipatch_unit_cents_to_dls_rel_pitch_value(const GValue * src_val,GValue * dest_val)522 ipatch_unit_cents_to_dls_rel_pitch_value(const GValue *src_val,
523         GValue *dest_val)
524 {
525     double cents = g_value_get_double(src_val);
526     g_value_set_int(dest_val, (gint)(cents * 65536.0 + 0.5));
527 }
528