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