1 /*
2 
3     TiMidity -- Experimental MIDI to WAVE converter
4     Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
19 
20 */
21 #include "pent_include.h"
22 
23 #ifdef USE_TIMIDITY_MIDI
24 
25 #include <cstdio>
26 #include <cstdlib>
27 #include <cstring>
28 #include <vector>
29 
30 using std::vector;
31 
32 #include "SDL.h"
33 #include "timidity.h"
34 #include "timidity_common.h"
35 #include "timidity_instrum.h"
36 #include "timidity_playmidi.h"
37 #include "timidity_readmidi.h"
38 #include "timidity_output.h"
39 #include "timidity_controls.h"
40 #include "timidity_tables.h"
41 
42 // we want to use Pentagram's config
43 #include "Configuration.h"
44 
45 #ifdef NS_TIMIDITY
46 namespace NS_TIMIDITY {
47 #endif
48 
49 void (*s32tobuf)(void *dp, sint32 *lp, sint32 c);
50 int free_instruments_afterwards=0;
51 static char def_instr_name[256]="";
52 
53 int AUDIO_BUFFER_SIZE;
54 sample_t *resample_buffer=nullptr;
55 sint32 *common_buffer=nullptr;
56 
57 #define MAXWORDS 10u
58 
read_config_file(const char * name)59 static int read_config_file(const char *name)
60 {
61 	FILE *fp;
62 	char tmp[1024];
63 	vector<char*> w;
64 	w.reserve(MAXWORDS);
65 	ToneBank *bank=nullptr;
66 	int line=0;
67 	static int rcf_count=0;
68 
69 	if (rcf_count>50)
70 	{
71 		ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
72 		          "Probable source loop in configuration files");
73 		return -1;
74 	}
75 
76 	if (!(fp=open_file(name, 1, OF_VERBOSE)))
77 		return -1;
78 
79 	while (fgets(tmp, sizeof(tmp), fp))
80 	{
81 		line++;
82 		w.clear();
83 		w.push_back(strtok(tmp, " \t\r\n\240"));
84 		if (!w[0] || (*w[0]=='#')) continue;
85 		while (w.back() && w.size() < MAXWORDS)
86 			w.push_back(strtok(nullptr," \t\r\n\240"));
87 		if (!strcmp(w[0], "dir"))
88 		{
89 			if (w.size() < 2)
90 			{
91 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
92 				          "%s: line %d: No directory given\n", name, line);
93 				close_file(fp);
94 				return -2;
95 			}
96 			for (unsigned i=1; i<w.size(); i++)
97 				add_to_pathlist(w[i]);
98 		}
99 		else if (!strcmp(w[0], "source"))
100 		{
101 			if (w.size() < 2)
102 			{
103 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
104 				          "%s: line %d: No file name given\n", name, line);
105 				close_file(fp);
106 				return -2;
107 			}
108 			for (unsigned i=1; i<w.size(); i++)
109 			{
110 				rcf_count++;
111 				read_config_file(w[i]);
112 				rcf_count--;
113 			}
114 		}
115 		else if (!strcmp(w[0], "default"))
116 		{
117 			if (w.size() != 2)
118 			{
119 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
120 				          "%s: line %d: Must specify exactly one patch name\n",
121 				          name, line);
122 				close_file(fp);
123 				return -2;
124 			}
125 			strncpy(def_instr_name, w[1], 255);
126 			def_instr_name[255]='\0';
127 		}
128 		else if (!strcmp(w[0], "drumset"))
129 		{
130 			if (w.size() < 2)
131 			{
132 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
133 				          "%s: line %d: No drum set number given\n",
134 				          name, line);
135 				close_file(fp);
136 				return -2;
137 			}
138 			int i=atoi(w[1]);
139 			if (i<0 || i>127)
140 			{
141 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
142 				          "%s: line %d: Drum set must be between 0 and 127\n",
143 				          name, line);
144 				close_file(fp);
145 				return -2;
146 			}
147 			if (!drumset[i])
148 			{
149 				drumset[i]=safe_Malloc<ToneBank>();
150 				memset(drumset[i], 0, sizeof(ToneBank));
151 			}
152 			bank=drumset[i];
153 		}
154 		else if (!strcmp(w[0], "bank"))
155 		{
156 			if (w.size() < 2)
157 			{
158 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
159 				          "%s: line %d: No bank number given\n",
160 				          name, line);
161 				close_file(fp);
162 				return -2;
163 			}
164 			int i=atoi(w[1]);
165 			if (i<0 || i>127)
166 			{
167 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
168 				          "%s: line %d: Tone bank must be between 0 and 127\n",
169 				          name, line);
170 				close_file(fp);
171 				return -2;
172 			}
173 			if (!tonebank[i])
174 			{
175 				tonebank[i]=safe_Malloc<ToneBank>();
176 				memset(tonebank[i], 0, sizeof(ToneBank));
177 			}
178 			bank=tonebank[i];
179 		}
180 		else {
181 			if ((w.size() < 2) || !std::isdigit(static_cast<unsigned char>(*w[0])))
182 			{
183 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
184 				          "%s: line %d: syntax error\n", name, line);
185 				close_file(fp);
186 				return -2;
187 			}
188 			int i=atoi(w[0]);
189 			if (i<0 || i>127)
190 			{
191 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
192 				          "%s: line %d: Program must be between 0 and 127\n",
193 				          name, line);
194 				close_file(fp);
195 				return -2;
196 			}
197 			if (!bank)
198 			{
199 				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
200 				          "%s: line %d: Must specify tone bank or drum set "
201 				          "before assignment\n",
202 				          name, line);
203 				close_file(fp);
204 				return -2;
205 			}
206 			if (bank->tone[i].name)
207 				free(bank->tone[i].name);
208 			strcpy((bank->tone[i].name=safe_Malloc<char>(strlen(w[1])+1)),w[1]);
209 			bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan=
210 				bank->tone[i].strip_loop=bank->tone[i].strip_envelope=
211 				bank->tone[i].strip_tail=-1;
212 
213 			for (unsigned j=2; j<w.size(); j++)
214 			{
215 				char *cp = strchr(w[j], '=');
216 				if (!cp)
217 				{
218 					ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: line %d: bad patch option %s\n",
219 					          name, line, w[j]);
220 					close_file(fp);
221 					return -2;
222 				}
223 				*cp++=0;
224 				if (!strcmp(w[j], "amp"))
225 				{
226 					int k=atoi(cp);
227 					if ((k<0 || k>MAX_AMPLIFICATION) || !std::isdigit(static_cast<unsigned char>(*cp)))
228 					{
229 						ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
230 						          "%s: line %d: amplification must be between "
231 						          "0 and %d\n", name, line, MAX_AMPLIFICATION);
232 						close_file(fp);
233 						return -2;
234 					}
235 					bank->tone[i].amp=k;
236 				}
237 				else if (!strcmp(w[j], "note"))
238 				{
239 					int k=atoi(cp);
240 					if ((k<0 || k>127) || !std::isdigit(static_cast<unsigned char>(*cp)))
241 					{
242 						ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
243 						          "%s: line %d: note must be between 0 and 127\n",
244 						          name, line);
245 						close_file(fp);
246 						return -2;
247 					}
248 					bank->tone[i].note=k;
249 				}
250 				else if (!strcmp(w[j], "pan"))
251 				{
252 					int k;
253 					if (!strcmp(cp, "center"))
254 						k=64;
255 					else if (!strcmp(cp, "left"))
256 						k=0;
257 					else if (!strcmp(cp, "right"))
258 						k=127;
259 					else
260 						k=((atoi(cp)+100) * 100) / 157;
261 					if ((k<0 || k>127) ||
262 					    (k==0 && *cp!='-' && !std::isdigit(static_cast<unsigned char>(*cp))))
263 					{
264 						ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
265 						          "%s: line %d: panning must be left, right, "
266 						          "center, or between -100 and 100\n",
267 						          name, line);
268 						close_file(fp);
269 						return -2;
270 					}
271 					bank->tone[i].pan=k;
272 				}
273 				else if (!strcmp(w[j], "keep"))
274 				{
275 					if (!strcmp(cp, "env"))
276 						bank->tone[i].strip_envelope=0;
277 					else if (!strcmp(cp, "loop"))
278 						bank->tone[i].strip_loop=0;
279 					else
280 					{
281 						ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
282 						          "%s: line %d: keep must be env or loop\n", name, line);
283 						close_file(fp);
284 						return -2;
285 					}
286 				}
287 				else if (!strcmp(w[j], "strip"))
288 				{
289 					if (!strcmp(cp, "env"))
290 						bank->tone[i].strip_envelope=1;
291 					else if (!strcmp(cp, "loop"))
292 						bank->tone[i].strip_loop=1;
293 					else if (!strcmp(cp, "tail"))
294 						bank->tone[i].strip_tail=1;
295 					else
296 					{
297 						ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
298 						          "%s: line %d: strip must be env, loop, or tail\n",
299 						          name, line);
300 						close_file(fp);
301 						return -2;
302 					}
303 				}
304 				else
305 				{
306 					ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: line %d: bad patch option %s\n",
307 					          name, line, w[j]);
308 					close_file(fp);
309 					return -2;
310 				}
311 			}
312 		}
313 	}
314 	if (ferror(fp))
315 	{
316 		ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't read from %s\n", name);
317 		close_file(fp);
318 		return -2;
319 	}
320 	close_file(fp);
321 	return 0;
322 }
323 
Timidity_Init_Simple(int rate,int samples,sint32 encoding)324 int Timidity_Init_Simple(int rate, int samples, sint32 encoding)
325 {
326 	std::string configfile;
327 	/* see if the pentagram config file specifies an alternate timidity.cfg */
328 	config->value("config/audio/midi/timiditycfg", configfile, CONFIG_FILE);
329 
330 	if (read_config_file(configfile.c_str())<0) {
331 		return -1;
332 	}
333 
334 	/* Check to see if the encoding is 'valid' */
335 
336 	// Only 16 bit can be byte swapped
337 	if ((encoding & PE_BYTESWAP) && !(encoding & PE_16BIT))
338 		return -1;
339 
340 	// u-Law can only be mono or stereo
341 	if ((encoding & PE_ULAW) && (encoding & ~(PE_ULAW|PE_MONO)))
342 		return -1;
343 
344 	/* Set play mode parameters */
345 	play_mode->rate = rate;
346 	play_mode->encoding = encoding;
347 	switch (play_mode->encoding) {
348 		case 0:
349 		case PE_MONO:
350 			s32tobuf = s32tou8;
351 			break;
352 
353 		case PE_SIGNED:
354 		case PE_SIGNED|PE_MONO:
355 			s32tobuf = s32tos8;
356 			break;
357 
358 		case PE_ULAW:
359 		case PE_ULAW|PE_MONO:
360 			s32tobuf = s32toulaw;
361 			break;
362 
363 		case PE_16BIT:
364 		case PE_16BIT|PE_MONO:
365 			s32tobuf = s32tou16;
366 			break;
367 
368 		case PE_16BIT|PE_SIGNED:
369 		case PE_16BIT|PE_SIGNED|PE_MONO:
370 			s32tobuf = s32tos16;
371 			break;
372 
373 		case PE_BYTESWAP|PE_16BIT:
374 		case PE_BYTESWAP|PE_16BIT|PE_MONO:
375 			s32tobuf = s32tou16x;
376 			break;
377 
378 		case PE_BYTESWAP|PE_16BIT|PE_SIGNED:
379 		case PE_BYTESWAP|PE_16BIT|PE_SIGNED|PE_MONO:
380 			s32tobuf = s32tos16x;
381 			break;
382 
383 		default:
384 			ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Unsupported audio format");
385 			return -1;
386 	}
387 
388 	AUDIO_BUFFER_SIZE = samples;
389 
390 	/* Allocate memory for mixing (WARNING:  Memory leak!) */
391 	resample_buffer = safe_Malloc<sample_t>(AUDIO_BUFFER_SIZE);
392 	common_buffer = safe_Malloc<sint32>(AUDIO_BUFFER_SIZE*2);
393 
394 	init_tables();
395 
396 	if (ctl->open(0, 0)) {
397 		ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Couldn't open %s\n", ctl->id_name);
398 		return -1;
399 	}
400 
401 	if (!control_ratio) {
402 		control_ratio = play_mode->rate / CONTROLS_PER_SECOND;
403 		if(control_ratio<1)
404 			control_ratio=1;
405 		else if (control_ratio > MAX_CONTROL_RATIO)
406 			control_ratio=MAX_CONTROL_RATIO;
407 	}
408 	if (*def_instr_name)
409 		set_default_instrument(def_instr_name);
410 	return 0;
411 }
412 
Timidity_DeInit()413 void Timidity_DeInit()
414 {
415 	free_instruments();
416 
417 	free(resample_buffer);
418 	resample_buffer = nullptr;
419 
420 	free(common_buffer);
421 	common_buffer = nullptr;
422 }
423 
424 
425 char timidity_error[1024] = "";
Timidity_Error()426 char *Timidity_Error()
427 {
428 	return timidity_error;
429 }
430 
431 #ifdef NS_TIMIDITY
432 }
433 #endif
434 
435 #endif //USE_TIMIDITY_MIDI
436 
437 
438