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 }