1 /*
2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4 Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 quantity.c
21
22 string -> quantity -> native value convertion
23 by Kentaro Sato <kentaro@ranvis.com>
24 */
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <math.h>
29
30 #include "timidity.h"
31 #include "common.h"
32 #include "instrum.h"
33 #include "tables.h"
34
35 #include "quantity.h"
36
37
38 namespace TimidityPlus
39 {
40 typedef int32_t(*QuantityToIntProc)(int32_t value, int32_t param);
41 typedef double(*QuantityToFloatProc)(double value, int32_t param);
42 typedef union {
43 QuantityToIntProc i;
44 QuantityToFloatProc f;
45 } QuantityConvertProc;
46
47 typedef struct {
48 const char *suffix;
49 uint16_t type, id;
50 int float_type; /* is floating-point type */
51 QuantityConvertProc convert;
52 } QuantityHint;
53
54
55 /*
56 Guide To Add New Unit Types/Units
57
58 append QUANTITY_UNIT_TYPE(<TYPE>)
59 QUANTITY_UNIT_NAME(<UNIT>)
60 ... to enum quantity_units (in quantity.h)
61 append QUANTITY_TYPE_INT/FLOAT(<TYPE>)
62 REGISTER_TYPE_INT/FLOAT("<SUFFIX>", <UNIT>);
63 ...
64 END_QUANTITY_TYPE; to GetQuantityHints()
65 write convert_<TYPE>_NUM(int32_t/double value, int32_t param)
66 convert_<UNIT>(int32_t/double value, int32_t param)
67 ... functions.
68 */
69
70 /*************** conversion functions ***************/
71
convert_DIRECT_INT_NUM(int32_t value,int32_t param)72 static int32_t convert_DIRECT_INT_NUM(int32_t value, int32_t param)
73 {
74 return value;
75 }
76
convert_DIRECT_FLOAT_NUM(double value,int32_t param)77 static double convert_DIRECT_FLOAT_NUM(double value, int32_t param)
78 {
79 return value;
80 }
81
82 /* from instrum.c, convert_tremolo_sweep() */
convert_TREMOLO_SWEEP_NUM(int32_t value,int32_t param)83 static int32_t convert_TREMOLO_SWEEP_NUM(int32_t value, int32_t param)
84 {
85 uint8_t sweep = value;
86 if (!sweep)
87 return 0;
88
89 return
90 ((control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
91 (playback_rate * sweep);
92 }
93
convert_TREMOLO_SWEEP_MS(int32_t value,int32_t param)94 static int32_t convert_TREMOLO_SWEEP_MS(int32_t value, int32_t param)
95 {
96 if (value <= 0)
97 return 0;
98 #if SWEEP_SHIFT <= 16
99 return ((uint32_t)(control_ratio * (1000 >> 2)) << SWEEP_SHIFT) / ((playback_rate * value) >> 2);
100 #else
101 #error "overflow"
102 #endif
103 }
104
105 /* from instrum.c, convert_tremolo_rate() */
convert_TREMOLO_RATE_NUM(int32_t value,int32_t param)106 static int32_t convert_TREMOLO_RATE_NUM(int32_t value, int32_t param)
107 {
108 uint8_t rate = value;
109 return
110 ((SINE_CYCLE_LENGTH * control_ratio * rate) << RATE_SHIFT) /
111 (TREMOLO_RATE_TUNING * playback_rate);
112 }
113
convert_TREMOLO_RATE_MS(int32_t value,int32_t param)114 static int32_t convert_TREMOLO_RATE_MS(int32_t value, int32_t param)
115 {
116 #if RATE_SHIFT <= 5
117 return ((SINE_CYCLE_LENGTH * control_ratio * (1000 >> 1)) << RATE_SHIFT) /
118 ((playback_rate * (uint32_t)value) >> 1);
119 #else
120 #error "overflow"
121 #endif
122 }
123
convert_TREMOLO_RATE_HZ(double value,int32_t param)124 static double convert_TREMOLO_RATE_HZ(double value, int32_t param)
125 {
126 if (value <= 0)
127 return 0;
128 return ((SINE_CYCLE_LENGTH * control_ratio) << RATE_SHIFT) * value / playback_rate;
129 }
130
131 /* from instrum.c, convert_vibrato_sweep() */
convert_VIBRATO_SWEEP_NUM(int32_t value,int32_t vib_control_ratio)132 static int32_t convert_VIBRATO_SWEEP_NUM(int32_t value, int32_t vib_control_ratio)
133 {
134 uint8_t sweep = value;
135 if (!sweep)
136 return 0;
137
138 return (int32_t)(TIM_FSCALE((double) (vib_control_ratio)
139 * SWEEP_TUNING, SWEEP_SHIFT)
140 / (double)(playback_rate * sweep));
141
142 /* this was overflowing with seashore.pat
143
144 ((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
145 (playback_rate * sweep); */
146 }
147
convert_VIBRATO_SWEEP_MS(int32_t value,int32_t vib_control_ratio)148 static int32_t convert_VIBRATO_SWEEP_MS(int32_t value, int32_t vib_control_ratio)
149 {
150 if (value <= 0)
151 return 0;
152 return (TIM_FSCALE((double)vib_control_ratio * 1000, SWEEP_SHIFT)
153 / (double)(playback_rate * value));
154 }
155
156 /* from instrum.c, to_control() */
convert_VIBRATO_RATE_NUM(int32_t control,int32_t param)157 static int32_t convert_VIBRATO_RATE_NUM(int32_t control, int32_t param)
158 {
159 return (int32_t) (0x2000 / pow(2.0, control / 31.0));
160 }
161
convert_VIBRATO_RATE_MS(int32_t value,int32_t param)162 static int32_t convert_VIBRATO_RATE_MS(int32_t value, int32_t param)
163 {
164 return 1000 * playback_rate / ((2 * VIBRATO_SAMPLE_INCREMENTS) * value);
165 }
166
convert_VIBRATO_RATE_HZ(double value,int32_t param)167 static double convert_VIBRATO_RATE_HZ(double value, int32_t param)
168 {
169 return playback_rate / ((2 * VIBRATO_SAMPLE_INCREMENTS) * value);
170 }
171
172 /*************** core functions ***************/
173
174 #define MAX_QUANTITY_UNITS_PER_UNIT_TYPES 8
175
GetQuantityHints(uint16_t type,QuantityHint * units)176 static int GetQuantityHints(uint16_t type, QuantityHint *units)
177 {
178 QuantityHint *unit;
179
180 unit = units;
181 #define QUANTITY_TYPE_INT(type) \
182 case QUANTITY_UNIT_TYPE(type): REGISTER_TYPE_INT("", type##_NUM)
183 #define QUANTITY_TYPE_FLOAT(type) \
184 case QUANTITY_UNIT_TYPE(type): REGISTER_TYPE_FLOAT("", type##_NUM)
185 #define REGISTER_TYPE_INT(ustr, utype) REGISTER_TYPE_ENTITY_INT(ustr, utype, convert_##utype)
186 #define REGISTER_TYPE_FLOAT(ustr, utype) REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, convert_##utype)
187 #define REGISTER_TYPE_ALIAS_INT(ustr, utype, atype) REGISTER_TYPE_ENTITY_INT(ustr, utype, convert_##atype)
188 #define REGISTER_TYPE_ALIAS_FLOAT(ustr, utype, atype) REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, convert_##atype)
189 #define REGISTER_TYPE_ENTITY_INT(ustr, utype, ucvt) \
190 unit->suffix = ustr, unit->type = type, unit->id = QUANTITY_UNIT_NAME(utype), unit->float_type = 0, unit->convert.i = ucvt, unit++
191 #define REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, ucvt) \
192 unit->suffix = ustr, unit->type = type, unit->id = QUANTITY_UNIT_NAME(utype), unit->float_type = 1, unit->convert.f = ucvt, unit++
193 #define END_QUANTITY_TYPE unit->suffix = NULL; break
194 switch (type)
195 {
196 QUANTITY_TYPE_INT(DIRECT_INT);
197 END_QUANTITY_TYPE;
198 QUANTITY_TYPE_FLOAT(DIRECT_FLOAT);
199 END_QUANTITY_TYPE;
200 QUANTITY_TYPE_INT(TREMOLO_SWEEP);
201 REGISTER_TYPE_INT("ms", TREMOLO_SWEEP_MS);
202 END_QUANTITY_TYPE;
203 QUANTITY_TYPE_INT(TREMOLO_RATE);
204 REGISTER_TYPE_INT("ms", TREMOLO_RATE_MS);
205 REGISTER_TYPE_FLOAT("Hz", TREMOLO_RATE_HZ);
206 END_QUANTITY_TYPE;
207 QUANTITY_TYPE_INT(VIBRATO_RATE);
208 REGISTER_TYPE_INT("ms", VIBRATO_RATE_MS);
209 REGISTER_TYPE_FLOAT("Hz", VIBRATO_RATE_HZ);
210 END_QUANTITY_TYPE;
211 QUANTITY_TYPE_INT(VIBRATO_SWEEP);
212 REGISTER_TYPE_INT("ms", VIBRATO_SWEEP_MS);
213 END_QUANTITY_TYPE;
214 default:
215 printMessage(CMSG_ERROR, VERB_NORMAL, "Internal parameter error (%d)", type);
216 return 0;
217 }
218 return 1;
219 }
220
221 /* quantity is unchanged if an error occurred */
number_to_quantity(int32_t number_i,const char * suffix_i,double number_f,const char * suffix_f,Quantity * quantity,uint16_t type)222 static const char *number_to_quantity(int32_t number_i, const char *suffix_i, double number_f, const char *suffix_f, Quantity *quantity, uint16_t type)
223 {
224 QuantityHint units[MAX_QUANTITY_UNITS_PER_UNIT_TYPES], *unit;
225
226 if (!GetQuantityHints(type, units))
227 return "Parameter error";
228 unit = units;
229 while(unit->suffix != NULL)
230 {
231 if (suffix_i != NULL && strcmp(suffix_i, unit->suffix) == 0) /* number_i, suffix_i was valid */
232 {
233 quantity->type = unit->type;
234 quantity->unit = unit->id;
235 if (unit->float_type)
236 quantity->value.f = number_i;
237 else
238 quantity->value.i = number_i;
239 return NULL;
240 }
241 else if (suffix_f != NULL && strcmp(suffix_f, unit->suffix) == 0) /* number_f, suffix_f was valid */
242 {
243 if (unit->float_type)
244 {
245 quantity->type = unit->type;
246 quantity->unit = unit->id;
247 quantity->value.f = number_f;
248 return NULL;
249 }
250 else
251 return "integer expected";
252 }
253 unit++;
254 }
255 return "invalid parameter";
256 }
257
string_to_quantity(const char * string,Quantity * quantity,uint16_t type)258 const char *string_to_quantity(const char *string, Quantity *quantity, uint16_t type)
259 {
260 int32_t number_i;
261 double number_f;
262 char *suffix_i, *suffix_f;
263
264 number_i = strtol(string, &suffix_i, 10); /* base == 10 for compatibility with atoi() */
265 if (string == suffix_i) /* doesn't start with valid character */
266 return "Number expected";
267 number_f = strtod(string, &suffix_f);
268 return number_to_quantity(number_i, suffix_i, number_f, suffix_f, quantity, type);
269 }
270
GetQuantityConvertProc(const Quantity * quantity,QuantityConvertProc * proc)271 static int GetQuantityConvertProc(const Quantity *quantity, QuantityConvertProc *proc)
272 {
273 QuantityHint units[MAX_QUANTITY_UNITS_PER_UNIT_TYPES], *unit;
274
275 if (!GetQuantityHints(quantity->type, units))
276 return -1; /* already warned */
277 unit = units;
278 while(unit->suffix != NULL)
279 {
280 if (quantity->unit == unit->id)
281 {
282 *proc = unit->convert;
283 return unit->float_type;
284 }
285 unit++;
286 }
287 printMessage(CMSG_ERROR, VERB_NORMAL, "Internal parameter error");
288 return -1;
289 }
290
quantity_to_int(const Quantity * quantity,int32_t param)291 int32_t quantity_to_int(const Quantity *quantity, int32_t param)
292 {
293 QuantityConvertProc proc;
294
295 switch (GetQuantityConvertProc(quantity, &proc))
296 {
297 case 0:
298 return (*proc.i)(quantity->value.i, param);
299 case 1:
300 return (*proc.f)(quantity->value.f, param);
301 }
302 return 0;
303 }
304
quantity_to_float(const Quantity * quantity,int32_t param)305 double quantity_to_float(const Quantity *quantity, int32_t param)
306 {
307 QuantityConvertProc proc;
308
309 switch (GetQuantityConvertProc(quantity, &proc))
310 {
311 case 0:
312 return (*proc.i)(quantity->value.i, param);
313 case 1:
314 return (*proc.f)(quantity->value.f, param);
315 }
316 return 0;
317 }
318 }