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 emacs_c.c
21 Emacs control mode - written by Masanao Izumo <mo@goice.co.jp>
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif /* HAVE_CONFIG_H */
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32 #ifndef NO_STRING_H
33 #include <string.h>
34 #else
35 #include <strings.h>
36 #endif
37
38 #include "timidity.h"
39 #include "common.h"
40 #include "output.h"
41 #include "controls.h"
42 #include "instrum.h"
43 #include "playmidi.h"
44 #include "miditrace.h"
45
46 /*
47 * miditrace functions
48 *
49 * ctl_current_time
50 * ctl_note
51 * ctl_program
52 * ctl_volume
53 * ctl_expression
54 * ctl_panning
55 * ctl_sustain
56 * ctl_pitch_bend
57 */
58
59 /*
60 * commands:
61 * LIST CMSG TIME MVOL DRUMS FILE CURT NOTE PROG VOL EXP PAN SUS PIT RESET
62 */
63
64 static void ctl_refresh(void);
65 static void ctl_total_time(int tt);
66 static void ctl_master_volume(int mv);
67 static void ctl_file_name(char *name);
68 static void ctl_current_time(int ct, int nv);
69 static void ctl_note(int status, int ch, int note, int vel);
70 static void ctl_program(int ch, int val);
71 static void ctl_volume(int channel, int val);
72 static void ctl_expression(int channel, int val);
73 static void ctl_panning(int channel, int val);
74 static void ctl_sustain(int channel, int val);
75 static void ctl_pitch_bend(int channel, int val);
76 static void ctl_reset(void);
77 static int ctl_open(int using_stdin, int using_stdout);
78 static void ctl_close(void);
79 static int ctl_read(int32 *valp);
80 static int cmsg(int type, int verbosity_level, char *fmt, ...);
81 static int ctl_pass_playing_list(int number_of_files, char *list_of_files[]);
82 static void ctl_event(CtlEvent *e);
83 static int read_ready(void);
84 static int emacs_type = 0; /* 0:emacs, 1:mule, 2:??
85 Note that this variable not used yet.
86 */
87 enum emacs_type_t
88 {
89 ETYPE_OF_EMACS,
90 ETYPE_OF_MULE,
91 ETYPE_OF_OTHER
92 };
93
94 /**********************************/
95 /* export the interface functions */
96
97 #define ctl emacs_control_mode
98
99 ControlMode ctl=
100 {
101 "Emacs interface (invoked from `M-x timidity')", 'e',
102 "emacs",
103 1, 0, 0,
104 0,
105 ctl_open,
106 ctl_close,
107 ctl_pass_playing_list,
108 ctl_read,
109 NULL,
110 cmsg,
111 ctl_event
112 };
113
114 static uint32 cuepoint = 0;
115 static int cuepoint_pending = 0;
116
117 static FILE *outfp;
118
quote_string_out(char * str)119 static void quote_string_out(char *str)
120 {
121 char *s;
122
123 s = NULL;
124 if(emacs_type == ETYPE_OF_MULE)
125 {
126 int len;
127
128 len = SAFE_CONVERT_LENGTH(strlen(str));
129 s = (char *)new_segment(&tmpbuffer, len);
130 code_convert(str, s, len, NULL, "EUC");
131 str = s;
132 }
133
134 while(*str)
135 {
136 if(*str == '\\' || *str == '\"')
137 putc('\\', outfp);
138 putc(*str, outfp);
139 str++;
140 }
141
142 if(s != NULL)
143 reuse_mblock(&tmpbuffer);
144 }
145
146 /*ARGSUSED*/
ctl_open(int using_stdin,int using_stdout)147 static int ctl_open(int using_stdin, int using_stdout)
148 {
149 if(using_stdout)
150 outfp = stderr;
151 else
152 outfp = stdout;
153 ctl.opened = 1;
154 output_text_code = "NOCNV";
155 fprintf(outfp, "(timidity-VERSION \"");
156 quote_string_out(timidity_version);
157 fprintf(outfp, "\")\n");
158 ctl_refresh();
159 return 0;
160 }
161
ctl_close(void)162 static void ctl_close(void)
163 {
164 fflush(outfp);
165 ctl.opened = 0;
166 }
167
ctl_read(int32 * valp)168 static int ctl_read(int32 *valp)
169 {
170 char cmd[BUFSIZ];
171 int n;
172
173 if (cuepoint_pending) {
174 *valp = cuepoint;
175 cuepoint_pending = 0;
176 return RC_FORWARD;
177 }
178 if(read_ready() <= 0)
179 return RC_NONE;
180 if(fgets(cmd, sizeof(cmd), stdin) == NULL)
181 return RC_QUIT; /* Emacs may down */
182 n = atoi(cmd + 1);
183 switch(cmd[0])
184 {
185 case 'L':
186 return RC_LOAD_FILE;
187 case 'V':
188 *valp = 10 * n;
189 return RC_CHANGE_VOLUME;
190 case 'v':
191 *valp = -10 * n;
192 return RC_CHANGE_VOLUME;
193 case '1':
194 case '2':
195 case '3':
196 *valp = cmd[0] - '2';
197 return RC_CHANGE_REV_EFFB;
198 case '4':
199 case '5':
200 case '6':
201 *valp = cmd[0] - '5';
202 return RC_CHANGE_REV_TIME;
203 case 'Q':
204 return RC_QUIT;
205 case 'r':
206 return RC_RESTART;
207 case 'f':
208 *valp = play_mode->rate * n;
209 return RC_FORWARD;
210 case 'b':
211 *valp = play_mode->rate * n;
212 return RC_BACK;
213 case ' ':
214 return RC_TOGGLE_PAUSE;
215 case '+':
216 *valp = n;
217 return RC_KEYUP;
218 case '-':
219 *valp = -n;
220 return RC_KEYDOWN;
221 case '>':
222 *valp = n;
223 return RC_SPEEDUP;
224 case '<':
225 *valp = n;
226 return RC_SPEEDDOWN;
227 case 'O':
228 *valp = n;
229 return RC_VOICEINCR;
230 case 'o':
231 *valp = n;
232 return RC_VOICEDECR;
233 case 'd':
234 *valp = n;
235 return RC_TOGGLE_DRUMCHAN;
236 case 'g':
237 return RC_TOGGLE_SNDSPEC;
238 }
239
240 return RC_NONE;
241 }
242
chomp(char * s)243 static char *chomp(char *s)
244 {
245 int len = strlen(s);
246
247 if(len < 2)
248 {
249 if(len == 0)
250 return s;
251 if(s[0] == '\n' || s[0] == '\r')
252 s[0] = '\0';
253 return s;
254 }
255 if(s[len - 1] == '\n')
256 s[--len] = '\0';
257 if(s[len - 1] == '\r')
258 s[--len] = '\0';
259 return s;
260 }
261
ctl_pass_playing_list(int argc,char * argv[])262 static int ctl_pass_playing_list(int argc, char *argv[])
263 {
264 int i;
265 char cmd[BUFSIZ];
266
267 if(argc > 0)
268 {
269 if(!strcmp(argv[0], "emacs"))
270 {
271 emacs_type = ETYPE_OF_EMACS;
272 argc--; argv++;
273 }
274 else if(!strcmp(argv[0], "mule"))
275 {
276 emacs_type = ETYPE_OF_MULE;
277 argc--; argv++;
278 }
279 else
280 emacs_type = ETYPE_OF_OTHER;
281 }
282
283 if(argc > 0 && !strcmp(argv[0], "debug"))
284 {
285 for(i = 1; i < argc; i++)
286 play_midi_file(argv[i]);
287 return 0;
288 }
289
290 /* Main Loop */
291 for(;;)
292 {
293 int rc;
294
295 if(fgets(cmd, sizeof(cmd), stdin) == NULL)
296 return 0; /* Emacs may down */
297 chomp(cmd);
298 if(!strncmp(cmd, "PLAY", 4))
299 {
300 rc = play_midi_file(cmd + 5);
301 switch(rc)
302 {
303 case RC_TUNE_END:
304 case RC_NEXT:
305 fprintf(outfp, "(timidity-NEXT)\n");
306 ctl_refresh();
307 break;
308 case RC_QUIT:
309 return 0;
310 } /* skipping others command */
311 }
312 else if(!strncmp(cmd, "QUIT", 4))
313 return 0;
314 else
315 continue; /* skipping unknown command */
316 }
317 /*NOTREACHED*/
318 }
319
cmsg(int type,int verbosity_level,char * fmt,...)320 static int cmsg(int type, int verbosity_level, char *fmt, ...)
321 {
322 va_list ap;
323 char buff[BUFSIZ];
324
325 if((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
326 ctl.verbosity < verbosity_level)
327 return 0;
328 va_start(ap, fmt);
329
330 vsprintf(buff, fmt, ap);
331 fprintf(outfp, "(timidity-CMSG %d \"", type);
332 quote_string_out(buff);
333 fprintf(outfp, "\")\n");
334 va_end(ap);
335 ctl_refresh();
336 return 0;
337 }
338
ctl_refresh(void)339 static void ctl_refresh(void)
340 {
341 fflush(stdout);
342 }
343
ctl_total_time(int tt)344 static void ctl_total_time(int tt)
345 {
346 int secs;
347 secs = tt/play_mode->rate;
348 fprintf(outfp, "(timidity-TIME %d)\n", secs);
349 ctl_refresh();
350 }
351
ctl_master_volume(int mv)352 static void ctl_master_volume(int mv)
353 {
354 fprintf(outfp, "(timidity-MVOL %d)\n", mv);
355 ctl_refresh();
356 }
357
ctl_file_name(char * name)358 static void ctl_file_name(char *name)
359 {
360 fprintf(outfp, "(timidity-FILE \"");
361 quote_string_out(name);
362 fprintf(outfp, "\")\n");
363 ctl_refresh();
364 }
365
ctl_current_time(int secs,int v)366 static void ctl_current_time(int secs, int v)
367 {
368 fprintf(outfp, "(timidity-CURT %d %d)\n", secs, v);
369 ctl_refresh();
370 }
371
status_number(int s)372 static int status_number(int s)
373 {
374 switch(s)
375 {
376 case VOICE_FREE:
377 return 0;
378 case VOICE_ON:
379 return 1;
380 case VOICE_SUSTAINED:
381 return 2;
382 case VOICE_OFF:
383 return 3;
384 case VOICE_DIE:
385 return 4;
386 }
387 /* dmy */
388 return 3;
389 }
390
ctl_note(int status,int ch,int note,int vel)391 static void ctl_note(int status, int ch, int note, int vel)
392 {
393 if(ch >= 16)
394 return;
395 if(midi_trace.flush_flag)
396 return;
397 fprintf(outfp, "(timidity-NOTE %d %d %d)\n", ch, note,
398 status_number(status));
399 ctl_refresh();
400 }
401
ctl_program(int ch,int val)402 static void ctl_program(int ch, int val)
403 {
404 if(ch >= 16)
405 return;
406 if(midi_trace.flush_flag)
407 return;
408 if(channel[ch].special_sample)
409 val = channel[ch].special_sample;
410 else
411 val += progbase;
412 fprintf(outfp, "(timidity-PROG %d %d)\n", ch, val);
413 ctl_refresh();
414 }
415
ctl_volume(int ch,int val)416 static void ctl_volume(int ch, int val)
417 {
418 if(ch >= 16)
419 return;
420 if(midi_trace.flush_flag)
421 return;
422 fprintf(outfp, "(timidity-VOL %d %d)\n", ch, (val*100)/127);
423 ctl_refresh();
424 }
425
ctl_expression(int ch,int val)426 static void ctl_expression(int ch, int val)
427 {
428 if(ch >= 16)
429 return;
430 if(midi_trace.flush_flag)
431 return;
432 fprintf(outfp, "(timidity-EXP %d %d)\n", ch, (val*100)/127);
433 ctl_refresh();
434 }
435
ctl_panning(int ch,int val)436 static void ctl_panning(int ch, int val)
437 {
438 if(ch >= 16)
439 return;
440 if(midi_trace.flush_flag)
441 return;
442 fprintf(outfp, "(timidity-PAN %d %d)\n", ch, val);
443 ctl_refresh();
444 }
445
ctl_sustain(int ch,int val)446 static void ctl_sustain(int ch, int val)
447 {
448 if(ch >= 16)
449 return;
450 if(midi_trace.flush_flag)
451 return;
452 fprintf(outfp, "(timidity-SUS %d %d)\n", ch, val);
453 ctl_refresh();
454 }
455
ctl_pitch_bend(int ch,int val)456 static void ctl_pitch_bend(int ch, int val)
457 {
458 if(ch >= 16)
459 return;
460 if(midi_trace.flush_flag)
461 return;
462 fprintf(outfp, "(timidity-PIT %d %d)\n", ch, val);
463 ctl_refresh();
464 }
465
ctl_reset(void)466 static void ctl_reset(void)
467 {
468 int i;
469 uint32 drums;
470
471 /* Note that Emacs is 24 bit integer. */
472 drums = 0;
473 for(i = 0; i < 16; i++)
474 if(ISDRUMCHANNEL(i))
475 drums |= (1u << i);
476 fprintf(outfp, "(timidity-DRUMS %lu)\n", (unsigned long)drums);
477
478 fprintf(outfp, "(timidity-RESET)\n");
479 for(i = 0; i < 16; i++)
480 {
481 if(ISDRUMCHANNEL(i))
482 ctl_program(i, channel[i].bank);
483 else
484 ctl_program(i, channel[i].program);
485 ctl_volume(i, channel[i].volume);
486 ctl_expression(i, channel[i].expression);
487 ctl_panning(i, channel[i].panning);
488 ctl_sustain(i, channel[i].sustain);
489 ctl_pitch_bend(i, channel[i].pitchbend);
490 }
491 ctl_refresh();
492 }
493
494
495 #if defined(sgi)
496 #include <sys/time.h>
497 #include <bstring.h>
498 #endif
499
500 #if defined(SOLARIS) || defined(__FreeBSD__)
501 #include <unistd.h>
502 #include <sys/filio.h>
503 #endif
504
read_ready(void)505 static int read_ready(void)
506 {
507 #if defined(sgi)
508 fd_set fds;
509 int cnt;
510 struct timeval timeout;
511 int fd;
512
513 fd = fileno(stdin);
514
515 FD_ZERO(&fds);
516 FD_SET(fd, &fds);
517 timeout.tv_sec = timeout.tv_usec = 0;
518
519 if((cnt = select(fd + 1, &fds, NULL, NULL, &timeout)) < 0)
520 {
521 fprintf(outfp, "(error \"select system call is failed\")\n");
522 ctl_refresh();
523 return -1;
524 }
525
526 return cnt > 0 && FD_ISSET(fd, &fds) != 0;
527 #else
528 int num;
529 int fd;
530
531 fd = fileno(stdin);
532 if(ioctl(fd, FIONREAD, &num) < 0) /* see how many chars in buffer. */
533 {
534 fprintf(outfp, "(error \"ioctl system call is failed\")\n");
535 ctl_refresh();
536 return -1;
537 }
538 return num;
539 #endif
540 }
541
ctl_event(CtlEvent * e)542 static void ctl_event(CtlEvent *e)
543 {
544 switch(e->type)
545 {
546 case CTLE_NOW_LOADING:
547 ctl_file_name((char *)e->v1);
548 break;
549 case CTLE_LOADING_DONE:
550 break;
551 case CTLE_PLAY_START:
552 ctl_total_time((int)e->v1);
553 break;
554 case CTLE_PLAY_END:
555 break;
556 case CTLE_CUEPOINT:
557 cuepoint = e->v1;
558 cuepoint_pending = 1;
559 break;
560 case CTLE_TEMPO:
561 break;
562 case CTLE_METRONOME:
563 break;
564 case CTLE_CURRENT_TIME:
565 ctl_current_time((int)e->v1, (int)e->v2);
566 break;
567 case CTLE_NOTE:
568 ctl_note((int)e->v1, (int)e->v2, (int)e->v3, (int)e->v4);
569 break;
570 case CTLE_MASTER_VOLUME:
571 ctl_master_volume((int)e->v1);
572 break;
573 case CTLE_PROGRAM:
574 ctl_program((int)e->v1, (int)e->v2);
575 break;
576 case CTLE_VOLUME:
577 ctl_volume((int)e->v1, (int)e->v2);
578 break;
579 case CTLE_EXPRESSION:
580 ctl_expression((int)e->v1, (int)e->v2);
581 break;
582 case CTLE_PANNING:
583 ctl_panning((int)e->v1, (int)e->v2);
584 break;
585 case CTLE_SUSTAIN:
586 ctl_sustain((int)e->v1, (int)e->v2);
587 break;
588 case CTLE_PITCH_BEND:
589 ctl_pitch_bend((int)e->v1, (int)e->v2);
590 break;
591 case CTLE_MOD_WHEEL:
592 ctl_pitch_bend((int)e->v1, e->v2 ? -1 : 0x2000);
593 break;
594 case CTLE_CHORUS_EFFECT:
595 break;
596 case CTLE_REVERB_EFFECT:
597 break;
598 case CTLE_LYRIC:
599 default_ctl_lyric((int)e->v1);
600 break;
601 case CTLE_REFRESH:
602 ctl_refresh();
603 break;
604 case CTLE_RESET:
605 ctl_reset();
606 break;
607 }
608 }
609
610 /*
611 * interface_<id>_loader();
612 */
interface_e_loader(void)613 ControlMode *interface_e_loader(void)
614 {
615 return &ctl;
616 }
617