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