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     npsyn_c.c - Windows synthesizer interface
21         Copyright (c) 2007 Keishi Suenaga <s_keishi@yahoo.co.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 Windows 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 Windows synthesizer interface, run timidity as folows:
36       % timidity -iW    (interactively select an Input MIDI device)
37     or
38       % timidity -iW 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 -iW       (set sampling freq. to 11025Hz)
44     or
45       % timidity -EFreverb=0 -iW    (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     I use MIDI Yoke. It can freely be obtained MIDI-OX site
51     (http://www.midiox.com).
52 */
53 
54 //#define  USE_PORTMIDI 1
55 //#define USE_GTK_GUI 1
56 
57 #ifdef HAVE_CONFIG_H
58 #include "config.h"
59 #endif /* HAVE_CONFIG_H */
60 
61 #ifdef __POCC__
62 #include <sys/types.h>
63 #endif
64 
65 #include "rtsyn.h"
66 #ifdef USE_GTK_GUI
67 #include "wsgtk_main.h"
68 #endif
69 
70 #ifndef __W32__
71 #include <stdio.h>
72 #include <termios.h>
73 //#include <term.h>
74 #include <unistd.h>
75 #endif
76 
77 
78 #ifndef __W32__
79 static struct termios initial_settings, new_settings;
80 static int peek_character = -1;
81 #endif
82 
83 extern int volatile stream_max_compute;	// play_event() �� compute_data() �Ōv�Z�������ő厞��
84 static int seq_quit=~0;
85 
86 static int ctl_open(int using_stdin, int using_stdout);
87 static void ctl_close(void);
88 static int ctl_read(int32 *valp);
89 static int cmsg(int type, int verbosity_level, char *fmt, ...);
90 static void ctl_event(CtlEvent *e);
91 static int ctl_pass_playing_list(int n, char *args[]);
92 
93 #ifndef __W32__
94 static void init_keybord(void);
95 static void close_keybord(void);
96 static int kbhit(void);
97 static char readch(void);
98 #endif
99 
100 /**********************************/
101 /* export the interface functions */
102 
103 #define ctl npsyn_control_mode
104 
105 ControlMode ctl=
106 {
107     "Windows Named Pipe Synthesizer interface", 'N',
108     "npsyn",
109     1,0,0,
110     0,
111     ctl_open,
112     ctl_close,
113     ctl_pass_playing_list,
114     ctl_read,
115     NULL,
116     cmsg,
117     ctl_event
118 };
119 
120 static int32 event_time_offset;
121 static FILE *outfp;
122 
123 /*ARGSUSED*/
124 
ctl_open(int using_stdin,int using_stdout)125 static int ctl_open(int using_stdin, int using_stdout)
126 {
127 	ctl.opened = 1;
128 	ctl.flags &= ~(CTLF_LIST_RANDOM|CTLF_LIST_SORT);
129 	if (using_stdout)
130 		outfp = stderr;
131 	else
132 		outfp = stdout;
133 	return 0;
134 }
135 
ctl_close(void)136 static void ctl_close(void)
137 {
138   fflush(outfp);
139   if(seq_quit==0){
140   	rtsyn_np_synth_stop();
141   	rtsyn_close();
142   	seq_quit=~0;
143   }
144   ctl.opened=0;
145 }
146 
ctl_read(int32 * valp)147 static int ctl_read(int32 *valp)
148 {
149     return RC_NONE;
150 }
151 
152 #ifdef IA_W32G_SYN
153 extern void PutsConsoleWnd(char *str);
154 extern int ConsoleWndFlag;
155 #endif
cmsg(int type,int verbosity_level,char * fmt,...)156 static int cmsg(int type, int verbosity_level, char *fmt, ...)
157 {
158 #ifndef WINDRV
159 #ifndef IA_W32G_SYN
160 
161 	va_list ap;
162 
163   if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
164       ctl.verbosity<verbosity_level)
165     return 0;
166   va_start(ap, fmt);
167   if(type == CMSG_WARNING || type == CMSG_ERROR || type == CMSG_FATAL)
168       dumb_error_count++;
169   if (!ctl.opened)
170     {
171       vfprintf(stderr, fmt, ap);
172       fputs(NLS, stderr);
173     }
174   else
175     {
176       vfprintf(outfp, fmt, ap);
177       fputs(NLS, outfp);
178       fflush(outfp);
179     }
180   va_end(ap);
181 
182 #else
183 	if ( !ConsoleWndFlag ) return 0;
184 	{
185     char buffer[1024];
186     va_list ap;
187     va_start(ap, fmt);
188 	vsnprintf(buffer, sizeof(buffer), fmt, ap);
189     va_end(ap);
190 
191     if((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
192        ctl.verbosity<verbosity_level)
193 	return 0;
194 //    if(type == CMSG_FATAL)
195 //	w32g_msg_box(buffer, "TiMidity Error", MB_OK);
196     PutsConsoleWnd(buffer);
197     PutsConsoleWnd("\n");
198     return 0;
199 	}
200 #endif
201 #endif
202     return 0;
203 }
204 
ctl_event(CtlEvent * e)205 static void ctl_event(CtlEvent *e)
206 {
207 }
208 
209 static void doit(void);
210 
211 #ifdef IA_W32G_SYN
212 extern void w32g_syn_doit(void);
213 extern int w32g_syn_ctl_pass_playing_list(int n_, char *args_[]);
214 
215 
ctl_pass_playing_list(int n,char * args[])216 static int ctl_pass_playing_list(int n, char *args[])
217 {
218 	return w32g_syn_ctl_pass_playing_list ( n, args );
219 }
220 #endif
221 
222 #ifndef IA_W32G_SYN
ctl_pass_playing_list(int n,char * args[])223 static int ctl_pass_playing_list(int n, char *args[])
224 #else
225 // 0: OK, 2: Require to reset.
226 int ctl_pass_playing_list2(int n, char *args[])
227 #endif
228 {
229 	if( (n < 1) || (n > 2) ){
230 		ctl.cmsg(CMSG_WARNING, VERB_NORMAL, "Usage: timidity -iN [Named Pipe Name] SampeTimeMode(1 or 0) \n");
231 	 	return 1;
232 	}
233 
234 	rtsyn_np_set_pipe_name(args[0]);
235 	if( n==1 ){
236 		rtsyn_sample_time_mode = 0;
237 	}else{
238 		rtsyn_sample_time_mode = atoi(args[1]);
239 	}
240 
241 #if !defined(IA_W32G_SYN) && !defined(USE_GTK_GUI)
242 	ctl.cmsg(CMSG_WARNING, VERB_NORMAL,
243 		"TiMidity starting in Windows Named Pipe Synthesizer mode\n");
244 	ctl.cmsg(CMSG_WARNING, VERB_NORMAL,
245 		"Usage: timidity -iN [Named Pipe Name] SampeTimeMode(1 or 0) \n");
246 	ctl.cmsg(CMSG_WARNING, VERB_NORMAL, "\n");
247 	ctl.cmsg(CMSG_WARNING, VERB_NORMAL,
248 		"N (Normal mode) M(GM mode) S(GS mode) X(XG mode) \n");
249 	ctl.cmsg(CMSG_WARNING, VERB_NORMAL,
250 		"(Only in Normal mode, Mode can be changed by MIDI data)\n");
251 	ctl.cmsg(CMSG_WARNING, VERB_NORMAL,
252 		"m(GM reset) s(GS reset) x(XG reset)\n");
253 	ctl.cmsg(CMSG_WARNING, VERB_NORMAL,
254 		"\n");
255 	ctl.cmsg(CMSG_WARNING, VERB_NORMAL,
256 		"Press 'q' key to stop\n");
257 
258 #endif
259 
260 	rtsyn_init();
261 
262 #ifdef USE_GTK_GUI
263 	twgtk_main();
264 #else
265 #ifdef IA_W32G_SYN
266 	if(0!=rtsyn_np_synth_start()){
267 		seq_quit=0;
268 		while(seq_quit==0) {
269 			w32g_syn_doit();
270 		}
271 		rtsyn_np_synth_stop();
272 	}
273 #else
274 	if(0!=rtsyn_np_synth_start()){
275 		seq_quit=0;
276 		while(seq_quit==0) {
277 			doit();
278 		}
279 		rtsyn_np_synth_stop();
280 	}
281 #endif /* IA_W32G_SYN */
282 #endif /* USE_GTK_GUI */
283 	rtsyn_close();
284 
285 	return 0;
286 }
287 
288 
289 #ifndef IA_W32G_SYN
290 
291 
292 #ifndef __W32__
init_keybord(void)293 static void init_keybord(void){
294 	tcgetattr(0,&initial_settings);
295 	tcgetattr(0,&new_settings);
296 	new_settings.c_lflag &= ~ICANON;
297 	new_settings.c_lflag &= ~ECHO;
298 	new_settings.c_lflag &= ~ISIG;
299 	new_settings.c_cc[VMIN] = 1;
300 	new_settings.c_cc[VTIME] = 0;
301 	tcsetattr(0, TCSANOW, &new_settings);
302 }
303 
close_keybord(void)304 static void close_keybord(void){
305 	tcsetattr(0, TCSANOW, &initial_settings);
306 }
307 
kbhit(void)308 static int kbhit(void){
309 	char ch;
310 	int nread;
311 
312 	if(peek_character != -1)
313 		return 1;
314 	new_settings.c_cc[VMIN]=0;
315 	tcsetattr(0,TCSANOW, &new_settings);
316 	nread = read(0, &ch, 1);
317 	new_settings.c_cc[VMIN]=1;
318 	tcsetattr(0,TCSANOW, &new_settings);
319 
320 	if(nread == 1) {
321 		peek_character = ch;
322 		return 1;
323 	}
324 	return 0;
325 }
326 
327 
readch(void)328 static char readch(void){
329 	char ch;
330 	if(peek_character != -1){
331 		ch = peek_character;
332 		peek_character = -1;
333 		return ch;
334 	}
335 	read(0,&ch,1);
336 	return ch;
337 }
338 #endif
339 
340 
doit(void)341 static void doit(void)
342 {
343 #ifndef __W32__
344 		init_keybord();
345 #endif
346 
347 	while(seq_quit==0){
348 #ifdef __W32__
349 		if(kbhit()){
350 			switch(getch()){
351 #else
352 		if(kbhit()){
353 			switch(readch()){
354 #endif
355 				case 'Q':
356 				case 'q':
357 					seq_quit=~0;
358 				break;
359 				case 'm':
360 					rtsyn_gm_reset();
361 				break;
362 				case 's':
363 					rtsyn_gs_reset();
364 				break;
365 				case 'x':
366 					rtsyn_xg_reset();
367 				break;
368 				case 'c':
369 					rtsyn_normal_reset();
370 				break;
371 				case 'M':
372 					rtsyn_gm_modeset();
373 				break;
374 				case 'S':
375 					rtsyn_gs_modeset();
376 				break;
377 				case 'X':
378 					rtsyn_xg_modeset();
379 				break;
380 				case 'N':
381 					rtsyn_normal_modeset();
382 				break;
383 			}
384 		}
385 		rtsyn_np_play_some_data();
386 		if(rtsyn_sample_time_mode == 0)
387 			rtsyn_play_calculate();
388 		if(intr) seq_quit=~0;
389 		sleep(1);
390 	}
391 #ifndef __W32__
392 	close_keybord();
393 #endif
394 }
395 
396 #endif /* !IA_W32G_SYN */
397 
398 
399 #ifdef IA_W32G_SYN
400 static int winplaymidi_sleep_level = 2;
401 static DWORD winplaymidi_active_start_time = 0;
402 
403 
404 void winplaymidi(void){
405 
406 	if ( winplaymidi_sleep_level < 1 ) {
407 		winplaymidi_sleep_level = 1;
408 	}
409 	if( 0 != rtsyn_buf_check() ){
410 			winplaymidi_sleep_level =0;
411 	}
412 	rtsyn_np_play_some_data();
413 	if ( winplaymidi_sleep_level == 1 ) {
414 		DWORD ct = GetCurrentTime ();
415 		if ( winplaymidi_active_start_time == 0 || ct < winplaymidi_active_start_time ) {
416 			winplaymidi_active_start_time = ct;
417 		} else if ( ct - winplaymidi_active_start_time > 2000 ) {
418 			winplaymidi_sleep_level = 2;
419 		}
420 	} else if ( winplaymidi_sleep_level == 0 ) {
421 		winplaymidi_active_start_time = 0;
422 	}
423 
424 	rtsyn_play_calculate();
425 
426 	if ( winplaymidi_sleep_level >= 2) {
427 		Sleep ( 100 );
428 	} else if ( winplaymidi_sleep_level > 0 ) {
429 		Sleep ( 1 );
430 	}
431 }
432 #endif
433 
434 
435 /*
436  * interface_<id>_loader();
437  */
438 ControlMode *interface_N_loader(void)
439 {
440     return &ctl;
441 }
442 
443 
444