1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.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     portmidisyn_c.c - PortMIDI synthesizer interface
21         Copyright (c) 2003 Keishi Suenaga <s_keishi@mutt.freemail.ne.jp>
22 
23     I referenced following sources.
24         alsaseq_c.c - ALSA sequencer server interface
25             Copyright (c) 2000  Takashi Iwai <tiwai@suse.de>
26         readmidi.c
27 
28     DESCRIPTION
29     ===========
30 
31     This interface provides a Portmidi MIDI device interface which receives
32     events and plays it in real-time.  On this mode, TiMidity works
33     purely as software (real-time) MIDI render.
34 
35     For invoking PrtMIDI synthesizer interface, run timidity as folows:
36       % timidity -iP    (interactively select an Input MIDI device)
37     or
38       % timidity -iP 2  (connect to MIDI device No. 2)
39 
40     TiMidity loads instruments dynamically at each time a PRM_CHANGE
41     event is received.  It sometimes causes a noise.
42     If you are using a low power machine, invoke timidity as follows:
43       % timidity -s 11025 -iP       (set sampling freq. to 11025Hz)
44     or
45       % timidity -EFreverb=0 -iP    (disable MIDI reverb effect control)
46 
47     TiMidity keeps all loaded instruments during executing.
48 
49     To use TiMidity as output device, you need a MIDI loopback device.
50     (for windows)
51       I use MIDI Yoke.  It can freely be obtained MIDI-OX site
52       (http://www.midiox.com).
53     (for ALSA)
54       You can easily meke it.  See MIDI router section
55       of Alsa 0.9.0 howto
56       (http://www.suse.de/~mana/alsa090_howto.html#sect05 ).
57 */
58 
59 //#define  USE_PORTMIDI 1
60 //#define USE_GTK_GUI 1
61 
62 #ifdef HAVE_CONFIG_H
63 #include "config.h"
64 #endif /* HAVE_CONFIG_H */
65 
66 
67 #include "rtsyn.h"
68 #ifdef USE_GTK_GUI
69 #include "wsgtk_main.h"
70 #endif
71 
72 #ifndef __W32__
73 #include <stdio.h>
74 #include <termios.h>
75 //#include <term.h>
76 #include <unistd.h>
77 #endif
78 
79 
80 #ifndef __W32__
81 static struct termios initial_settings, new_settings;
82 static int peek_character = -1;
83 #endif
84 
85 extern int volatile stream_max_compute;	// play_event() �� compute_data() �Ōv�Z�������ő厞��
86 int seq_quit=~0;
87 
88 
89 static int ctl_open(int using_stdin, int using_stdout);
90 static void ctl_close(void);
91 static int ctl_read(int32 *valp);
92 static int cmsg(int type, int verbosity_level, char *fmt, ...);
93 static void ctl_event(CtlEvent *e);
94 static int ctl_pass_playing_list(int n, char *args[]);
95 
96 #ifndef __W32__
97 static void init_keybord(void);
98 static void close_keybord(void);
99 static int kbhit(void);
100 static char readch(void);
101 #endif
102 
103 /**********************************/
104 /* export the interface functions */
105 
106 #define ctl portmidisyn_control_mode
107 
108 ControlMode ctl=
109 {
110     "PortMIDI Synthesizer interface", 'P',
111     "portmidisyn",
112     1,0,0,
113     0,
114     ctl_open,
115     ctl_close,
116     ctl_pass_playing_list,
117     ctl_read,
118     NULL,
119     cmsg,
120     ctl_event
121 };
122 
123 static int32 event_time_offset;
124 static FILE *outfp;
125 
126 /*ARGSUSED*/
127 
ctl_open(int using_stdin,int using_stdout)128 static int ctl_open(int using_stdin, int using_stdout)
129 {
130 	ctl.opened = 1;
131 	ctl.flags &= ~(CTLF_LIST_RANDOM|CTLF_LIST_SORT);
132 	if (using_stdout)
133 		outfp = stderr;
134 	else
135 		outfp = stdout;
136 	return 0;
137 }
138 
ctl_close(void)139 static void ctl_close(void)
140 {
141   fflush(outfp);
142   if(seq_quit==0){
143   	rtsyn_synth_stop();
144   	rtsyn_close();
145   	seq_quit=~0;
146   }
147   ctl.opened=0;
148 }
149 
ctl_read(int32 * valp)150 static int ctl_read(int32 *valp)
151 {
152     return RC_NONE;
153 }
154 
155 #ifdef IA_W32G_SYN
156 extern void PutsConsoleWnd(char *str);
157 extern int ConsoleWndFlag;
158 #endif
cmsg(int type,int verbosity_level,char * fmt,...)159 static int cmsg(int type, int verbosity_level, char *fmt, ...)
160 {
161 #ifndef IA_W32G_SYN
162 
163 	va_list ap;
164 
165   if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
166       ctl.verbosity<verbosity_level)
167     return 0;
168   va_start(ap, fmt);
169   if(type == CMSG_WARNING || type == CMSG_ERROR || type == CMSG_FATAL)
170       dumb_error_count++;
171   if (!ctl.opened)
172     {
173       vfprintf(stderr, fmt, ap);
174       fputs(NLS, stderr);
175     }
176   else
177     {
178       vfprintf(outfp, fmt, ap);
179       fputs(NLS, outfp);
180       fflush(outfp);
181     }
182   va_end(ap);
183 
184 #else
185 	if ( !ConsoleWndFlag ) return 0;
186 	{
187     char buffer[1024];
188     va_list ap;
189     va_start(ap, fmt);
190     vsnprintf(buffer, sizeof(buffer), fmt, ap);
191     va_end(ap);
192 
193     if((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
194        ctl.verbosity<verbosity_level)
195 	return 0;
196 //    if(type == CMSG_FATAL)
197 //	w32g_msg_box(buffer, "TiMidity Error", MB_OK);
198     PutsConsoleWnd(buffer);
199     PutsConsoleWnd("\n");
200     return 0;
201 	}
202 #endif
203 
204     return 0;
205 }
206 
ctl_event(CtlEvent * e)207 static void ctl_event(CtlEvent *e)
208 {
209 }
210 
211 static void doit(void);
212 
213 #ifdef IA_W32G_SYN
214 extern void w32g_syn_doit(void);
215 extern int w32g_syn_ctl_pass_playing_list(int n_, char *args_[]);
216 
217 
ctl_pass_playing_list(int n,char * args[])218 static int ctl_pass_playing_list(int n, char *args[])
219 {
220 	return w32g_syn_ctl_pass_playing_list ( n, args );
221 }
222 #endif
223 
224 #ifndef IA_W32G_SYN
ctl_pass_playing_list(int n,char * args[])225 static int ctl_pass_playing_list(int n, char *args[])
226 #else
227 // 0: OK, 2: Require to reset.
228 int ctl_pass_playing_list2(int n, char *args[])
229 #endif
230 {
231 	int i, j,devnum,devok;
232 	unsigned int port=0 ;
233 	int started;
234 	char cbuf[80];
235 
236 rtsyn_get_port_list();
237 
238 #ifndef IA_W32G_SYN
239 	if(n > MAX_PORT ){
240 		printf( "Usage: timidity -iW [Midi interface No s]\n");
241 		return 1;
242 	}
243 #endif
244 
245 	if(n>0){
246 		port=0;
247 		while(port<n && n!=0){
248 			if( (portID[port] = atoi(args[port]))==0 ){
249 				n=0;
250 			}else{
251 				devok=0;
252 				for(i=0;i<rtsyn_nportlist;i++){
253 					sscanf( rtsyn_portlist[i],"%d:%s",&devnum,cbuf);
254 					if(devnum==portID[port]) devok=1;
255 				}
256 				if(devok==0){
257 					n=0;
258 #ifdef IA_W32G_SYN
259 					{
260 						char buff[1024];
261 						sprintf ( buff, "MIDI IN Device ID %d is not available. So set a proper ID for the MIDI port %d and restart.", portID[port], port );
262 						MessageBox ( NULL, buff, "Error", MB_OK );
263 						return 2;
264 					}
265 #endif
266 				}
267 			}
268 		port++;
269 		}
270 	}
271 	if(n==0){
272 		rtsyn_portnumber=0;
273 	}else{
274 		rtsyn_portnumber=port;
275 	}
276 
277 #if !defined(IA_W32G_SYN) && !defined(USE_GTK_GUI)
278 	if(n==0){
279 		char cbuf[80];
280 		printf("Whow many ports do you use?(max %d)\n",MAX_PORT);
281 		do{
282 			if (0==scanf("%u",&rtsyn_portnumber)) scanf("%s",cbuf);
283 		}while(rtsyn_portnumber == 0 ||rtsyn_portnumber > MAX_PORT);
284 		printf("\n");
285 		printf("Opening Device drivers:");
286 		printf("Available Midi Input devices:\n");
287 
288 		for(i=0;i<rtsyn_nportlist;i++){
289 			printf("%s\n",rtsyn_portlist[i]);
290 		}
291 		for(port=0;port<rtsyn_portnumber;port++){
292 			printf("Keyin Input Device Number of port%d\n",port+1);
293 			do{
294 				devok=0;
295 				if (0==scanf("%u",&portID[port])) scanf("%s",cbuf);
296 				for(i=0;i<rtsyn_nportlist;i++){
297 					sscanf( rtsyn_portlist[i],"%d:%s",&devnum,cbuf);
298 					if(devnum==portID[port]) devok=1;
299 				}
300 			}while(devok==0);
301 			printf("\n");
302 		}
303 	}
304 #endif
305 
306 	for(port=0;port<rtsyn_portnumber;port++){
307 		portID[port]=portID[port]-1;
308 	}
309 
310 
311 #if !defined(IA_W32G_SYN) && !defined(USE_GTK_GUI)
312 	printf("TiMidity starting in PortMIDI Synthesizer mode\n");
313 	printf("Usage: timidity -iP [Midi interface No]\n");
314 	printf("\n");
315 	printf("N (Normal mode) M(GM mode) S(GS mode) X(XG mode) \n");
316 	printf("(Only in Normal mode, Mode can be changed by MIDI data)\n");
317 	printf("m(GM reset) s(GS reset) x(XG reset)\n");
318 	printf("\n");
319 	printf("Press 'q' key to stop\n");
320 #endif
321 
322 	rtsyn_init();
323 
324 #ifdef USE_GTK_GUI
325 	twgtk_main();
326 #else
327 #ifdef IA_W32G_SYN
328 	if(0!=rtsyn_synth_start()){
329 		seq_quit=0;
330 		while(seq_quit==0) {
331 			w32g_syn_doit();
332 		}
333 		rtsyn_synth_stop();
334 	}
335 #else
336 	if(0!=rtsyn_synth_start()){
337 		seq_quit=0;
338 		while(seq_quit==0) {
339 			doit();
340 		}
341 		rtsyn_synth_stop();
342 	}
343 #endif /* IA_W32G_SYN */
344 #endif /* USE_GTK_GUI */
345 	rtsyn_close();
346 
347 	return 0;
348 }
349 
350 
351 #ifndef IA_W32G_SYN
352 
353 
354 #ifndef __W32__
init_keybord(void)355 static void init_keybord(void){
356 	tcgetattr(0,&initial_settings);
357 	tcgetattr(0,&new_settings);
358 	new_settings.c_lflag &= ~ICANON;
359 	new_settings.c_lflag &= ~ECHO;
360 	new_settings.c_lflag &= ~ISIG;
361 	new_settings.c_cc[VMIN] = 1;
362 	new_settings.c_cc[VTIME] = 0;
363 	tcsetattr(0, TCSANOW, &new_settings);
364 }
365 
close_keybord(void)366 static void close_keybord(void){
367 	tcsetattr(0, TCSANOW, &initial_settings);
368 }
369 
kbhit(void)370 static int kbhit(void){
371 	char ch;
372 	int nread;
373 
374 	if(peek_character != -1)
375 		return 1;
376 	new_settings.c_cc[VMIN]=0;
377 	tcsetattr(0,TCSANOW, &new_settings);
378 	nread = read(0, &ch, 1);
379 	new_settings.c_cc[VMIN]=1;
380 	tcsetattr(0,TCSANOW, &new_settings);
381 
382 	if(nread == 1) {
383 		peek_character = ch;
384 		return 1;
385 	}
386 	return 0;
387 }
388 
389 
readch(void)390 static char readch(void){
391 	char ch;
392 	if(peek_character != -1){
393 		ch = peek_character;
394 		peek_character = -1;
395 		return ch;
396 	}
397 	read(0,&ch,1);
398 	return ch;
399 }
400 #endif
401 
402 
doit(void)403 static void doit(void)
404 {
405 #ifndef __W32__
406 		init_keybord();
407 #endif
408 
409 	while(seq_quit==0){
410 #if __W32__
411 		if(kbhit()){
412 			switch(getch()){
413 #else
414 		if(kbhit()){
415 			switch(readch()){
416 #endif
417 				case 'Q':
418 				case 'q':
419 					seq_quit=~0;
420 				break;
421 				case 'm':
422 					rtsyn_gm_reset();
423 				break;
424 				case 's':
425 					rtsyn_gs_reset();
426 				break;
427 				case 'x':
428 					rtsyn_xg_reset();
429 				break;
430 				case 'c':
431 					rtsyn_normal_reset();
432 				break;
433 				case 'M':
434 					rtsyn_gm_modeset();
435 				break;
436 				case 'S':
437 					rtsyn_gs_modeset();
438 				break;
439 				case 'X':
440 					rtsyn_xg_modeset();
441 				break;
442 				case 'N':
443 					rtsyn_normal_modeset();
444 				break;
445 			}
446 		}
447 		rtsyn_play_some_data();
448 		rtsyn_play_calculate();
449 		sleep(0);
450 	}
451 #ifndef __W32__
452 	close_keybord();
453 #endif
454 }
455 
456 #endif /* !IA_W32G_SYN */
457 
458 
459 #ifdef IA_W32G_SYN
460 static int winplaymidi_sleep_level = 2;
461 static DWORD winplaymidi_active_start_time = 0;
462 
463 
464 void winplaymidi(void){
465 
466 	if ( winplaymidi_sleep_level < 1 ) {
467 		winplaymidi_sleep_level = 1;
468 	}
469 	if( 0 != rtsyn_buf_check() ){
470 			winplaymidi_sleep_level =0;
471 	}
472 	rtsyn_play_some_data();
473 	if ( winplaymidi_sleep_level == 1 ) {
474 		DWORD ct = GetCurrentTime ();
475 		if ( winplaymidi_active_start_time == 0 || ct < winplaymidi_active_start_time ) {
476 			winplaymidi_active_start_time = ct;
477 		} else if ( ct - winplaymidi_active_start_time > 2000 ) {
478 			winplaymidi_sleep_level = 2;
479 		}
480 	} else if ( winplaymidi_sleep_level == 0 ) {
481 		winplaymidi_active_start_time = 0;
482 	}
483 
484 	rtsyn_play_calculate();
485 
486 	if ( winplaymidi_sleep_level >= 2) {
487 		Sleep ( 100 );
488 	} else if ( winplaymidi_sleep_level > 0 ) {
489 		Sleep ( 1 );
490 	}
491 }
492 #endif
493 
494 
495 /*
496  * interface_<id>_loader();
497  */
498 ControlMode *interface_P_loader(void)
499 {
500     return &ctl;
501 }
502 
503 
504