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 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #include <stdlib.h>
30 #include <math.h>
31
32 #include "timidity.h"
33 #include "common.h"
34 #include "controls.h"
35 #include "instrum.h"
36 #include "output.h"
37 #include "playmidi.h"
38 #include "tables.h"
39
40 #define ___QUANTITY_C_
41 #include "quantity.h"
42
43 /*
44 Guide To Add New Unit Types/Units
45
46 append QUANTITY_UNIT_TYPE(<TYPE>)
47 QUANTITY_UNIT_NAME(<UNIT>)
48 ... to enum quantity_units (in quantity.h)
49 append QUANTITY_TYPE_INT/FLOAT(<TYPE>)
50 REGISTER_TYPE_INT/FLOAT("<SUFFIX>", <UNIT>);
51 ...
52 END_QUANTITY_TYPE; to GetQuantityHints()
53 write convert_<TYPE>_NUM(int32/FLOAT_T value, int32 param)
54 convert_<UNIT>(int32/FLOAT_T value, int32 param)
55 ... functions.
56 */
57
58 /*************** conversion functions ***************/
59
convert_DIRECT_INT_NUM(int32 value,int32 param)60 static int32 convert_DIRECT_INT_NUM(int32 value, int32 param)
61 {
62 return value;
63 }
64
convert_DIRECT_FLOAT_NUM(FLOAT_T value,int32 param)65 static FLOAT_T convert_DIRECT_FLOAT_NUM(FLOAT_T value, int32 param)
66 {
67 return value;
68 }
69
70 /* from instrum.c, convert_tremolo_sweep() */
convert_TREMOLO_SWEEP_NUM(int32 value,int32 param)71 static int32 convert_TREMOLO_SWEEP_NUM(int32 value, int32 param)
72 {
73 uint8 sweep = value;
74 if (!sweep)
75 return 0;
76
77 return
78 ((control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
79 (play_mode->rate * sweep);
80 }
81
convert_TREMOLO_SWEEP_MS(int32 value,int32 param)82 static int32 convert_TREMOLO_SWEEP_MS(int32 value, int32 param)
83 {
84 if (value <= 0)
85 return 0;
86 #if SWEEP_SHIFT <= 16
87 return ((uint32)(control_ratio * (1000 >> 2)) << SWEEP_SHIFT) / ((play_mode->rate * value) >> 2);
88 #else
89 #error "overflow"
90 #endif
91 }
92
93 /* from instrum.c, convert_tremolo_rate() */
convert_TREMOLO_RATE_NUM(int32 value,int32 param)94 static int32 convert_TREMOLO_RATE_NUM(int32 value, int32 param)
95 {
96 uint8 rate = value;
97 return
98 ((SINE_CYCLE_LENGTH * control_ratio * rate) << RATE_SHIFT) /
99 (TREMOLO_RATE_TUNING * play_mode->rate);
100 }
101
convert_TREMOLO_RATE_MS(int32 value,int32 param)102 static int32 convert_TREMOLO_RATE_MS(int32 value, int32 param)
103 {
104 #if RATE_SHIFT <= 5
105 return ((SINE_CYCLE_LENGTH * control_ratio * (1000 >> 1)) << RATE_SHIFT) /
106 ((play_mode->rate * (uint32)value) >> 1);
107 #else
108 #error "overflow"
109 #endif
110 }
111
convert_TREMOLO_RATE_HZ(FLOAT_T value,int32 param)112 static FLOAT_T convert_TREMOLO_RATE_HZ(FLOAT_T value, int32 param)
113 {
114 if (value <= 0)
115 return 0;
116 return ((SINE_CYCLE_LENGTH * control_ratio) << RATE_SHIFT) * value / play_mode->rate;
117 }
118
119 /* from instrum.c, convert_vibrato_sweep() */
convert_VIBRATO_SWEEP_NUM(int32 value,int32 vib_control_ratio)120 static int32 convert_VIBRATO_SWEEP_NUM(int32 value, int32 vib_control_ratio)
121 {
122 uint8 sweep = value;
123 if (!sweep)
124 return 0;
125
126 return (int32)(TIM_FSCALE((double) (vib_control_ratio)
127 * SWEEP_TUNING, SWEEP_SHIFT)
128 / (double)(play_mode->rate * sweep));
129
130 /* this was overflowing with seashore.pat
131
132 ((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
133 (play_mode->rate * sweep); */
134 }
135
convert_VIBRATO_SWEEP_MS(int32 value,int32 vib_control_ratio)136 static int32 convert_VIBRATO_SWEEP_MS(int32 value, int32 vib_control_ratio)
137 {
138 if (value <= 0)
139 return 0;
140 return (TIM_FSCALE((double)vib_control_ratio * 1000, SWEEP_SHIFT)
141 / (double)(play_mode->rate * value));
142 }
143
144 /* from instrum.c, to_control() */
convert_VIBRATO_RATE_NUM(int32 control,int32 param)145 static int32 convert_VIBRATO_RATE_NUM(int32 control, int32 param)
146 {
147 return (int32) (0x2000 / pow(2.0, control / 31.0));
148 }
149
convert_VIBRATO_RATE_MS(int32 value,int32 param)150 static int32 convert_VIBRATO_RATE_MS(int32 value, int32 param)
151 {
152 return 1000 * play_mode->rate / ((2 * VIBRATO_SAMPLE_INCREMENTS) * value);
153 }
154
convert_VIBRATO_RATE_HZ(FLOAT_T value,int32 param)155 static FLOAT_T convert_VIBRATO_RATE_HZ(FLOAT_T value, int32 param)
156 {
157 return play_mode->rate / ((2 * VIBRATO_SAMPLE_INCREMENTS) * value);
158 }
159
160 /*************** core functions ***************/
161
162 #define MAX_QUANTITY_UNITS_PER_UNIT_TYPES 8
163
GetQuantityHints(uint16 type,QuantityHint * units)164 static int GetQuantityHints(uint16 type, QuantityHint *units)
165 {
166 QuantityHint *unit;
167
168 unit = units;
169 #define QUANTITY_TYPE_INT(type) \
170 case QUANTITY_UNIT_TYPE(type): REGISTER_TYPE_INT("", type##_NUM)
171 #define QUANTITY_TYPE_FLOAT(type) \
172 case QUANTITY_UNIT_TYPE(type): REGISTER_TYPE_FLOAT("", type##_NUM)
173 #define REGISTER_TYPE_INT(ustr, utype) REGISTER_TYPE_ENTITY_INT(ustr, utype, convert_##utype)
174 #define REGISTER_TYPE_FLOAT(ustr, utype) REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, convert_##utype)
175 #define REGISTER_TYPE_ALIAS_INT(ustr, utype, atype) REGISTER_TYPE_ENTITY_INT(ustr, utype, convert_##atype)
176 #define REGISTER_TYPE_ALIAS_FLOAT(ustr, utype, atype) REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, convert_##atype)
177 #define REGISTER_TYPE_ENTITY_INT(ustr, utype, ucvt) \
178 unit->suffix = ustr, unit->type = type, unit->id = QUANTITY_UNIT_NAME(utype), unit->float_type = 0, unit->convert.i = ucvt, unit++
179 #define REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, ucvt) \
180 unit->suffix = ustr, unit->type = type, unit->id = QUANTITY_UNIT_NAME(utype), unit->float_type = 1, unit->convert.f = ucvt, unit++
181 #define END_QUANTITY_TYPE unit->suffix = NULL; break
182 switch (type)
183 {
184 QUANTITY_TYPE_INT(DIRECT_INT);
185 END_QUANTITY_TYPE;
186 QUANTITY_TYPE_FLOAT(DIRECT_FLOAT);
187 END_QUANTITY_TYPE;
188 QUANTITY_TYPE_INT(TREMOLO_SWEEP);
189 REGISTER_TYPE_INT("ms", TREMOLO_SWEEP_MS);
190 END_QUANTITY_TYPE;
191 QUANTITY_TYPE_INT(TREMOLO_RATE);
192 REGISTER_TYPE_INT("ms", TREMOLO_RATE_MS);
193 REGISTER_TYPE_FLOAT("Hz", TREMOLO_RATE_HZ);
194 END_QUANTITY_TYPE;
195 QUANTITY_TYPE_INT(VIBRATO_RATE);
196 REGISTER_TYPE_INT("ms", VIBRATO_RATE_MS);
197 REGISTER_TYPE_FLOAT("Hz", VIBRATO_RATE_HZ);
198 END_QUANTITY_TYPE;
199 QUANTITY_TYPE_INT(VIBRATO_SWEEP);
200 REGISTER_TYPE_INT("ms", VIBRATO_SWEEP_MS);
201 END_QUANTITY_TYPE;
202 default:
203 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Internal parameter error (%d)", type);
204 return 0;
205 }
206 return 1;
207 }
208
209 /* quantity is unchanged if an error occurred */
number_to_quantity(int32 number_i,const char * suffix_i,FLOAT_T number_f,const char * suffix_f,Quantity * quantity,uint16 type)210 static const char *number_to_quantity(int32 number_i, const char *suffix_i, FLOAT_T number_f, const char *suffix_f, Quantity *quantity, uint16 type)
211 {
212 QuantityHint units[MAX_QUANTITY_UNITS_PER_UNIT_TYPES], *unit;
213
214 if (!GetQuantityHints(type, units))
215 return "Parameter error";
216 unit = units;
217 while(unit->suffix != NULL)
218 {
219 if (suffix_i != NULL && strcmp(suffix_i, unit->suffix) == 0) /* number_i, suffix_i was valid */
220 {
221 quantity->type = unit->type;
222 quantity->unit = unit->id;
223 if (unit->float_type)
224 quantity->value.f = number_i;
225 else
226 quantity->value.i = number_i;
227 return NULL;
228 }
229 else if (suffix_f != NULL && strcmp(suffix_f, unit->suffix) == 0) /* number_f, suffix_f was valid */
230 {
231 if (unit->float_type)
232 {
233 quantity->type = unit->type;
234 quantity->unit = unit->id;
235 quantity->value.f = number_f;
236 return NULL;
237 }
238 else
239 return "integer expected";
240 }
241 unit++;
242 }
243 return "invalid parameter";
244 }
245
string_to_quantity(const char * string,Quantity * quantity,uint16 type)246 const char *string_to_quantity(const char *string, Quantity *quantity, uint16 type)
247 {
248 int32 number_i;
249 FLOAT_T number_f;
250 char *suffix_i, *suffix_f;
251
252 number_i = strtol(string, &suffix_i, 10); /* base == 10 for compatibility with atoi() */
253 if (string == suffix_i) /* doesn't start with valid character */
254 return "Number expected";
255 number_f = strtod(string, &suffix_f);
256 return number_to_quantity(number_i, suffix_i, number_f, suffix_f, quantity, type);
257 }
258
int_to_quantity(int32 number,Quantity * quantity,uint16 type)259 void int_to_quantity(int32 number, Quantity *quantity, uint16 type)
260 {
261 /* pass suffix_f NULL to warn if unit type is float type */
262 if (number_to_quantity(number, "", number, NULL, quantity, type) != NULL) /* error */
263 {
264 quantity->type = QUANTITY_UNIT_TYPE(DIRECT_INT);
265 quantity->unit = QUANTITY_UNIT_NAME(DIRECT_INT_NUM);
266 quantity->value.i = 0;
267 }
268 }
269
float_to_quantity(FLOAT_T number,Quantity * quantity,uint16 type)270 void float_to_quantity(FLOAT_T number, Quantity *quantity, uint16 type)
271 {
272 /* pass suffix_i NULL to warn if unit type is integer type */
273 if (number_to_quantity(number, NULL, number, "", quantity, type) != NULL) /* error */
274 {
275 quantity->type = QUANTITY_UNIT_TYPE(DIRECT_FLOAT);
276 quantity->unit = QUANTITY_UNIT_NAME(DIRECT_FLOAT_NUM);
277 quantity->value.f = 0;
278 }
279 }
280
GetQuantityConvertProc(const Quantity * quantity,QuantityConvertProc * proc)281 static int GetQuantityConvertProc(const Quantity *quantity, QuantityConvertProc *proc)
282 {
283 QuantityHint units[MAX_QUANTITY_UNITS_PER_UNIT_TYPES], *unit;
284
285 if (!GetQuantityHints(quantity->type, units))
286 return -1; /* already warned */
287 unit = units;
288 while(unit->suffix != NULL)
289 {
290 if (quantity->unit == unit->id)
291 {
292 *proc = unit->convert;
293 return unit->float_type;
294 }
295 unit++;
296 }
297 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Internal parameter error");
298 return -1;
299 }
300
quantity_to_int(const Quantity * quantity,int32 param)301 int32 quantity_to_int(const Quantity *quantity, int32 param)
302 {
303 QuantityConvertProc proc;
304
305 switch (GetQuantityConvertProc(quantity, &proc))
306 {
307 case 0:
308 return (*proc.i)(quantity->value.i, param);
309 case 1:
310 return (*proc.f)(quantity->value.f, param);
311 }
312 return 0;
313 }
314
quantity_to_float(const Quantity * quantity,int32 param)315 FLOAT_T quantity_to_float(const Quantity *quantity, int32 param)
316 {
317 QuantityConvertProc proc;
318
319 switch (GetQuantityConvertProc(quantity, &proc))
320 {
321 case 0:
322 return (*proc.i)(quantity->value.i, param);
323 case 1:
324 return (*proc.f)(quantity->value.f, param);
325 }
326 return 0;
327 }
328