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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19
20 xaw_c.c - XAW Interface from
21 Tomokazu Harada <harada@prince.pe.u-tokyo.ac.jp>
22 Yoshishige Arai <ryo2@on.rim.or.jp>
23 Yair Kalvariski <cesium2@gmail.com>
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #if defined(TIME_WITH_SYS_TIME)
33 #include <sys/time.h>
34 #include <time.h>
35 #elif defined(HAVE_SYS_TIME_H)
36 #include <sys/time.h>
37 #else
38 #include <time.h>
39 #endif /* TIME_WITH_SYS_TIME */
40 #ifndef NO_STRING_H
41 #include <string.h>
42 #else
43 #include <strings.h>
44 #endif /* NO_STRING_H */
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif /* HAVE_UNISTD_H */
48
49 #include "timidity.h"
50 #include "aq.h"
51 #include "common.h"
52 #include "instrum.h"
53 #include "playmidi.h"
54 #include "readmidi.h"
55 #include "output.h"
56 #include "controls.h"
57 #include "miditrace.h"
58 #include "timer.h"
59 #include "xaw.h"
60
61 extern void timidity_init_aq_buff(void); /* From timidity/timidity.c */
62 static int cmsg(int, int, char *, ...);
63 static int ctl_blocking_read(int32 *);
64 static void ctl_close(void);
65 static void ctl_event(CtlEvent *);
66 static int ctl_read(int32 *);
67 static int ctl_open(int, int);
68 static int ctl_pass_playing_list(int, char **);
69 ControlMode *interface_a_loader(void);
70
71 static void a_pipe_open(void);
72 static int a_pipe_ready(void);
73 int a_pipe_read(char *, size_t);
74 int a_pipe_nread(char *, size_t);
75 void a_pipe_sync(void);
76 void a_pipe_write(const char *, ...);
77 static void a_pipe_write_buf(const char *, int);
78 static void a_pipe_write_msg(char *);
79 static void a_pipe_write_msg_nobr(char *);
80 extern void a_start_interface(int);
81
82 static void ctl_current_time(int, int);
83 static void ctl_drumpart(int, int);
84 static void ctl_event(CtlEvent *);
85 static void ctl_expression(int, int);
86 static void ctl_keysig(int);
87 static void ctl_key_offset(int);
88 static void ctl_lyric(int);
89 static void ctl_master_volume(int);
90 static void ctl_max_voices(int);
91 static void ctl_mute(int, int);
92 static void ctl_note(int, int, int, int);
93 static void ctl_panning(int, int);
94 static void ctl_pause(int, int);
95 static void ctl_pitch_bend(int, int);
96 static void ctl_program(int, int, const char *, uint32);
97 static void ctl_reset(void);
98 static void ctl_sustain(int, int);
99 static void ctl_tempo(int);
100 static void ctl_timeratio(int);
101 static void ctl_total_time(int);
102 static void ctl_refresh(void);
103 static void ctl_volume(int, int);
104 static void set_otherinfo(int, int, char);
105 static void shuffle(int, int *);
106 static void query_outputs(void);
107 static void update_indicator(void);
108 static void xaw_add_midi_file(char *);
109 static void xaw_delete_midi_file(int);
110 static void xaw_output_flist(const char *);
111 #define BANKS(ch) (channel[ch].bank | (channel[ch].bank_lsb << 8) | (channel[ch].bank_msb << 16))
112
113 static double indicator_last_update = 0;
114 #define EXITFLG_QUIT 1
115 #define EXITFLG_AUTOQUIT 2
116 static int reverb_type;
117 /*
118 * Unfortunate hack, forced because opt_reverb_control has been overloaded,
119 * and is no longer 0 or 1. Now it's in the range 0..3, so when reenabling
120 * reverb and disabling it, we need to know the original value.
121 */
122 static int exitflag = 0, randomflag = 0, repeatflag = 0, selectflag = 0,
123 current_no = 0, xaw_ready = 0, number_of_files, *file_table;
124 static int pipe_in_fd, pipe_out_fd;
125 static char **list_of_files, **titles;
126 static int active[MAX_XAW_MIDI_CHANNELS];
127 /*
128 * When a midi channel has played a note, this is set to 1. Otherwise, it's 0.
129 * This is used to screen out channels which are not used from the GUI.
130 */
131 extern PlayMode *play_mode, *target_play_mode;
132 static PlayMode *olddpm = NULL;
133
134 /**********************************************/
135 /* export the interface functions */
136
137 #define ctl xaw_control_mode
138
139 ControlMode ctl = {
140 "XAW interface", 'a',
141 "xaw",
142 1,0,0,
143 0,
144 ctl_open,
145 ctl_close,
146 ctl_pass_playing_list,
147 ctl_read,
148 NULL,
149 cmsg,
150 ctl_event
151 };
152
153 static uint32 cuepoint = 0;
154 static int cuepoint_pending = 0;
155
156 static char local_buf[PIPE_LENGTH];
157
158 /***********************************************************************/
159 /* Put controls on the pipe */
160 /***********************************************************************/
161 #define CMSG_MESSAGE 16
162
cmsg(int type,int verbosity_level,char * fmt,...)163 static int cmsg(int type, int verbosity_level, char *fmt, ...) {
164 va_list ap;
165 char *buff;
166 MBlockList pool;
167
168 if (((type == CMSG_TEXT) || (type == CMSG_INFO) || (type == CMSG_WARNING)) &&
169 (ctl.verbosity<verbosity_level))
170 return 0;
171
172 va_start(ap, fmt);
173
174 if (!xaw_ready) {
175 vfprintf(stderr, fmt, ap);
176 fprintf(stderr, NLS);
177 va_end(ap);
178 return 0;
179 }
180
181 init_mblock(&pool);
182 buff = (char *)new_segment(&pool, MIN_MBLOCK_SIZE);
183 vsnprintf(buff, MIN_MBLOCK_SIZE, fmt, ap);
184 a_pipe_write_msg(buff);
185 reuse_mblock(&pool);
186
187 va_end(ap);
188 return 0;
189 }
190
191 /*ARGSUSED*/
192 static void
ctl_current_time(int sec,int v)193 ctl_current_time(int sec, int v) {
194 static int previous_sec = -1, last_v = -1;
195
196 if (sec != previous_sec) {
197 previous_sec = sec;
198 a_pipe_write("%c%d", M_CUR_TIME, sec);
199 }
200 if (!ctl.trace_playing || midi_trace.flush_flag || (v == -1)) return;
201 if (last_v != v) {
202 last_v = v;
203 a_pipe_write("%c%c%d", MT_VOICES, MTV_LAST_VOICES_NUM, v);
204 }
205 }
206
207 static void
ctl_total_time(int tt_i)208 ctl_total_time(int tt_i) {
209 static int last_time = -1;
210
211 ctl_current_time(0, 0);
212 if (last_time != tt_i) {
213 last_time = tt_i;
214 a_pipe_write("%c%d", M_TOTAL_TIME, tt_i);
215 }
216 a_pipe_write("%c%d", M_SET_MODE, play_system_mode);
217 }
218
219 static void
ctl_master_volume(int mv)220 ctl_master_volume(int mv) {
221 a_pipe_write("%c%03d", M_VOLUME, mv);
222 }
223
224 static void
ctl_volume(int ch,int val)225 ctl_volume(int ch, int val) {
226 if ((!ctl.trace_playing) || (ch >= MAX_XAW_MIDI_CHANNELS)) return;
227 a_pipe_write("%c%c%d%c%d", MT_PANEL_INFO, MTP_VOLUME, ch,
228 CH_END_TOKEN, val);
229 }
230
231 static void
ctl_expression(int ch,int val)232 ctl_expression(int ch, int val) {
233 if ((!ctl.trace_playing) || (ch >= MAX_XAW_MIDI_CHANNELS)) return;
234 a_pipe_write("%c%c%d%c%d", MT_PANEL_INFO, MTP_EXPRESSION, ch,
235 CH_END_TOKEN, val);
236 }
237
238 static void
ctl_panning(int ch,int val)239 ctl_panning(int ch, int val) {
240 if ((!ctl.trace_playing) || (ch >= MAX_XAW_MIDI_CHANNELS)) return;
241 a_pipe_write("%c%c%d%c%d", MT_PANEL_INFO, MTP_PANNING, ch,
242 CH_END_TOKEN, val);
243 }
244
245 static void
ctl_sustain(int ch,int val)246 ctl_sustain(int ch, int val) {
247 if ((!ctl.trace_playing) || (ch >= MAX_XAW_MIDI_CHANNELS)) return;
248 a_pipe_write("%c%c%d%c%d", MT_PANEL_INFO, MTP_SUSTAIN, ch,
249 CH_END_TOKEN, val);
250 }
251
252 static void
ctl_pitch_bend(int ch,int val)253 ctl_pitch_bend(int ch, int val) {
254 if ((!ctl.trace_playing) || (ch >= MAX_XAW_MIDI_CHANNELS)) return;
255 a_pipe_write("%c%c%d%c%d", MT_PANEL_INFO, MTP_PITCH_BEND, ch,
256 CH_END_TOKEN, val);
257 }
258
259 #ifdef WIDGET_IS_LABEL_WIDGET
260 static void
ctl_lyric(int lyricid)261 ctl_lyric(int lyricid) {
262 char *lyric;
263 static int lyric_col = 0;
264 static char lyric_buf[PIPE_LENGTH];
265
266 lyric = event2string(lyricid);
267 if (lyric != NULL) {
268 if (lyric[0] == ME_KARAOKE_LYRIC) {
269 if ((lyric[1] == '/') || (lyric[1] == '\\')) {
270 strlcpy(lyric_buf, lyric + 2, sizeof(lyric_buf));
271 a_pipe_write_msg(lyric_buf);
272 lyric_col = strlen(lyric_buf);
273 }
274 else if (lyric[1] == '@') {
275 if (lyric[2] == 'L')
276 snprintf(lyric_buf, sizeof(lyric_buf), "Language: %s", lyric + 3);
277 else if (lyric[2] == 'T')
278 snprintf(lyric_buf, sizeof(lyric_buf), "Title: %s", lyric + 3);
279 else
280 strlcpy(lyric_buf, lyric + 1, sizeof(lyric_buf));
281 a_pipe_write_msg(lyric_buf);
282 lyric_col = 0;
283 }
284 else {
285 strlcpy(lyric_buf + lyric_col, lyric + 1,
286 sizeof(lyric_buf) - lyric_col);
287 a_pipe_write_msg(lyric_buf);
288 lyric_col += strlen(lyric + 1);
289 }
290 }
291 else {
292 lyric_col = 0;
293 a_pipe_write_msg_nobr(lyric + 1);
294 }
295 }
296 }
297 #else
298 static void
ctl_lyric(int lyricid)299 ctl_lyric(int lyricid) {
300 char *lyric;
301
302 lyric = event2string(lyricid);
303 if (lyric != NULL) {
304 if (lyric[0] == ME_KARAOKE_LYRIC) {
305 if ((lyric[1] == '/') || (lyric[1] == '\\')) {
306 lyric[1] = '\n';
307 a_pipe_write_msg_nobr(lyric + 1);
308 }
309 else if (lyric[1] == '@') {
310 if (lyric[2] == 'L')
311 snprintf(local_buf, sizeof(local_buf), "Language: %s", lyric + 3);
312 else if (lyric[2] == 'T')
313 snprintf(local_buf, sizeof(local_buf), "Title: %s", lyric + 3);
314 else
315 strlcpy(local_buf, lyric + 1, sizeof(local_buf));
316 a_pipe_write_msg(local_buf);
317 }
318 else a_pipe_write_msg_nobr(lyric + 1);
319 }
320 else a_pipe_write_msg_nobr(lyric + 1);
321 }
322 }
323 #endif /* WIDGET_IS_LABEL_WIDGET */
324
325 /*ARGSUSED*/
326 static int
ctl_open(int using_stdin,int using_stdout)327 ctl_open(int using_stdin, int using_stdout) {
328 ctl.opened = 1;
329
330 set_trace_loop_hook(update_indicator);
331
332 /* The child process won't come back from this call */
333 a_pipe_open();
334
335 return 0;
336 }
337
338 static void
ctl_close(void)339 ctl_close(void) {
340 if (ctl.opened) {
341 a_pipe_write("%c", M_QUIT);
342 ctl.opened = 0;
343 xaw_ready = 0;
344 }
345 }
346
347 static void
xaw_add_midi_file(char * additional_path)348 xaw_add_midi_file(char *additional_path) {
349 char *files[1], **ret;
350 int i, nfiles, nfit, *local_len = NULL;
351 char *p;
352
353 files[0] = additional_path;
354 nfiles = 1;
355 ret = expand_file_archives(files, &nfiles);
356 if (ret == NULL) return;
357 titles = (char **)safe_realloc(titles,
358 (number_of_files + nfiles) * sizeof(char *));
359 list_of_files = (char **)safe_realloc(list_of_files,
360 (number_of_files + nfiles) * sizeof(char *));
361 if (nfiles > 0) local_len = (int *)safe_malloc(nfiles * sizeof(int));
362 for (i=0, nfit=0;i<nfiles;i++) {
363 if (check_midi_file(ret[i]) >= 0) {
364 p = strrchr(ret[i], '/');
365 if (p == NULL) p = ret[i]; else p++;
366 titles[number_of_files+nfit] =
367 (char *)safe_malloc(sizeof(char) * (strlen(p) + 9));
368 list_of_files[number_of_files + nfit] = safe_strdup(ret[i]);
369 local_len[nfit] = sprintf(titles[number_of_files + nfit],
370 "%d. %s", number_of_files + nfit + 1, p);
371 nfit++;
372 }
373 }
374 if (nfit > 0) {
375 file_table = (int *)safe_realloc(file_table,
376 (number_of_files + nfit) * sizeof(int));
377 for(i = number_of_files; i < number_of_files + nfit; i++)
378 file_table[i] = i;
379 number_of_files += nfit;
380 a_pipe_write("%c%d", M_FILE_LIST, nfit);
381 for (i=0;i<nfit;i++)
382 a_pipe_write_buf(titles[number_of_files - nfit + i], local_len[i]);
383 }
384 free(local_len);
385 free(ret[0]);
386 free(ret);
387 }
388
389 static void
xaw_delete_midi_file(int delete_num)390 xaw_delete_midi_file(int delete_num) {
391 int i;
392 char *p;
393
394 if (delete_num < 0) {
395 for(i=0;i<number_of_files;i++){
396 free(list_of_files[i]);
397 free(titles[i]);
398 }
399 list_of_files = NULL; titles = NULL;
400 file_table = (int *)safe_realloc(file_table, 1*sizeof(int));
401 file_table[0] = 0;
402 number_of_files = 0;
403 current_no = 0;
404 } else {
405 free(titles[delete_num]); titles[delete_num] = NULL;
406 for(i=delete_num; i<number_of_files-1; i++) {
407 list_of_files[i] = list_of_files[i+1];
408 p = strchr(titles[i+1], '.');
409 titles[i] = (char *)safe_realloc(titles[i],
410 strlen(titles[i+1]) * sizeof(char));
411 sprintf(titles[i], "%d%s", i+1, p);
412 }
413 if (number_of_files > 0) number_of_files--;
414 if ((current_no >= delete_num) && (delete_num)) current_no--;
415 }
416 }
417
418 static void
xaw_output_flist(const char * filename)419 xaw_output_flist(const char *filename) {
420 int i;
421 char *temp = safe_strdup(filename);
422
423 a_pipe_write("%c%d %s", M_SAVE_PLAYLIST, number_of_files, temp);
424 free(temp);
425 for(i=0;i<number_of_files;i++) {
426 a_pipe_write("%s", list_of_files[i]);
427 }
428 }
429
430 /*ARGSUSED*/
431 static int
ctl_blocking_read(int32 * valp)432 ctl_blocking_read(int32 *valp) {
433 int n;
434
435 a_pipe_read(local_buf, sizeof(local_buf));
436 for (;;) {
437 switch (local_buf[0]) {
438 case S_ADD_TO_PLAYLIST:
439 xaw_add_midi_file(local_buf + 1);
440 return RC_NONE;
441 case S_DEL_CUR_PLAYLIST:
442 xaw_delete_midi_file(-1);
443 return RC_QUIT;
444 case S_PREV: return RC_REALLY_PREVIOUS;
445 case S_BACK:
446 *valp = (int32)(play_mode->rate * 10);
447 return RC_BACK;
448 case S_SET_CHORUS:
449 n = atoi(local_buf + 1);
450 opt_chorus_control = n;
451 return RC_QUIT;
452 case S_SET_RANDOM:
453 randomflag = atoi(local_buf + 1);
454 return RC_QUIT;
455 case S_DEL_FROM_PLAYLIST:
456 n = atoi(local_buf + 1);
457 xaw_delete_midi_file(n);
458 return RC_NONE;
459 case S_SET_OPTIONS:
460 n = atoi(local_buf + 1);
461 opt_modulation_wheel = n & MODUL_BIT;
462 opt_portamento = n & PORTA_BIT;
463 opt_nrpn_vibrato = n & NRPNV_BIT;
464 opt_reverb_control = !!(n & REVERB_BIT) * reverb_type;
465 opt_channel_pressure = n & CHPRESSURE_BIT;
466 opt_overlap_voice_allow = n & OVERLAPV_BIT;
467 opt_trace_text_meta_event = n & TXTMETA_BIT;
468 return RC_QUIT;
469 case S_PLAY_FILE:
470 selectflag = atoi(local_buf + 1);
471 return RC_QUIT;
472 case S_FWD:
473 *valp = (int32)(play_mode->rate * 10);
474 return RC_FORWARD;
475 case S_TOGGLE_SPEC: return RC_TOGGLE_SNDSPEC;
476 case S_PLAY: return RC_LOAD_FILE;
477 case S_TOGGLE_PAUSE: return RC_TOGGLE_PAUSE;
478 case S_STOP: return RC_QUIT;
479 case S_NEXT: return RC_NEXT;
480 case S_SET_REPEAT:
481 repeatflag = atoi(local_buf + 1);
482 return RC_NONE;
483 case S_SET_TIME:
484 n = atoi(local_buf + 1);
485 *valp = n * play_mode->rate;
486 return RC_JUMP;
487 case S_SET_MUTE:
488 n = atoi(local_buf + 1);
489 *valp = (int32)n;
490 return RC_TOGGLE_MUTE;
491 case S_DEC_VOL:
492 *valp = (int32)1;
493 return RC_VOICEDECR;
494 case S_INC_VOL:
495 *valp = (int32)1;
496 return RC_VOICEINCR;
497 case S_TOGGLE_AUTOQUIT:
498 exitflag ^= EXITFLG_AUTOQUIT;
499 return RC_NONE;
500 case S_SAVE_PLAYLIST:
501 xaw_output_flist(local_buf + 1);
502 return RC_NONE;
503 case S_ENABLE_TRACE:
504 ctl.trace_playing = 1;
505 if (local_buf[1] == ST_RESET) return RC_SYNC_RESTART;
506 return RC_NONE;
507 case S_SET_VOL_BEFORE_PLAYING:
508 n = atoi(local_buf + 1);
509 if (n < 0) n = 0;
510 if (n > MAXVOLUME) n = MAXVOLUME;
511 amplification = n;
512 return RC_NONE;
513 case S_SET_VOL:
514 n = atoi(local_buf + 1);
515 if (n < 0) n = 0;
516 if (n > MAXVOLUME) n = MAXVOLUME;
517 *valp = (int32)(n-amplification);
518 return RC_CHANGE_VOLUME;
519 case S_INC_PITCH:
520 *valp = (int32)1;
521 return RC_KEYUP;
522 case S_DEC_PITCH:
523 *valp = (int32)-1;
524 return RC_KEYDOWN;
525 case S_INC_SPEED:
526 *valp = (int32)1;
527 return RC_SPEEDUP;
528 case S_DEC_SPEED:
529 *valp = (int32)1;
530 return RC_SPEEDDOWN;
531 case S_SET_SOLO:
532 n = atoi(local_buf + 1);
533 *valp = (int32)n;
534 return RC_SOLO_PLAY;
535 case S_SET_RECORDING:
536 if (olddpm == NULL) {
537 PlayMode **ii;
538 char id = *(local_buf + 1), *p;
539
540 target_play_mode = NULL;
541 for (ii = play_mode_list; *ii != NULL; ii++)
542 if ((*ii)->id_character == id)
543 target_play_mode = *ii;
544 if (target_play_mode == NULL) goto z1error;
545 p = strchr(local_buf, ' ');
546 target_play_mode->name = safe_strdup(p + 1);
547 target_play_mode->rate = atoi(local_buf + 2);
548 if (target_play_mode->open_output() == -1) {
549 free(target_play_mode->name);
550 goto z1error;
551 }
552 play_mode->close_output();
553 olddpm = play_mode;
554 /*
555 * playmidi.c won't change play_mode when a file is not played,
556 * so to be certain, we do this ourselves.
557 */
558 play_mode = target_play_mode;
559 /*
560 * Reset aq to match the new output's paramteres.
561 */
562 aq_setup();
563 timidity_init_aq_buff();
564
565 a_pipe_write(CHECKPOST "1");
566 return RC_OUTPUT_CHANGED;
567 }
568 z1error:
569 a_pipe_write(CHECKPOST "1E");
570 return RC_NONE;
571 case S_STOP_RECORDING:
572 if (olddpm != NULL) {
573 play_mode->close_output();
574 if (*(local_buf + 1) == SR_USER_STOP) a_pipe_write(CHECKPOST "2S");
575 target_play_mode = olddpm;
576 if (target_play_mode->open_output() == -1) return RC_NONE;
577 free(play_mode->name);
578 play_mode = target_play_mode;
579 olddpm = NULL;
580 aq_setup();
581 timidity_init_aq_buff();
582
583 return RC_OUTPUT_CHANGED;
584 }
585 return RC_NONE;
586 case S_SET_PLAYMODE:
587 {
588 PlayMode **ii;
589 char id = *(local_buf + 1);
590
591 if (play_mode->id_character == id) goto z3error;
592 if (olddpm != NULL) goto z3error;
593
594 target_play_mode = NULL;
595 for (ii = play_mode_list; *ii != NULL; ii++)
596 if ((*ii)->id_character == id)
597 target_play_mode = *ii;
598 if (target_play_mode == NULL) goto z3error;
599 play_mode->close_output();
600 if (target_play_mode->open_output() == -1) {
601 play_mode->open_output();
602 goto z3error;
603 }
604 play_mode = target_play_mode;
605 a_pipe_write(CHECKPOST "3");
606 return RC_OUTPUT_CHANGED;
607 }
608 z3error:
609 a_pipe_write(CHECKPOST "3E");
610 return RC_NONE;
611 case S_QUIT:
612 free(file_table);
613 for (n=0; n<number_of_files; n++) {
614 free(titles[n]); free(list_of_files[n]);
615 }
616 default : exitflag |= EXITFLG_QUIT; return RC_QUIT;
617 }
618 }
619 }
620
621 static int
ctl_read(int32 * valp)622 ctl_read(int32 *valp) {
623 if (cuepoint_pending) {
624 *valp = cuepoint;
625 cuepoint_pending = 0;
626 return RC_FORWARD;
627 }
628 if (a_pipe_ready() <= 0) return RC_NONE;
629 return ctl_blocking_read(valp);
630 }
631
632 static void
shuffle(int n,int * a)633 shuffle(int n, int *a) {
634 int i, j, tmp;
635
636 for (i=0;i<n;i++) {
637 j = int_rand(n);
638 tmp = a[i];
639 a[i] = a[j];
640 a[j] = tmp;
641 }
642 }
643
644 static void
query_outputs(void)645 query_outputs(void) {
646 PlayMode **ii; unsigned char c;
647
648 for (ii = play_mode_list; *ii != NULL; ii++) {
649 if ((*ii)->flag & PF_FILE_OUTPUT) c = M_FILE_OUTPUT;
650 else c = M_DEVICE_OUTPUT;
651 if (*ii == play_mode) {
652 if (c == M_DEVICE_OUTPUT) c = M_DEVICE_CUR_OUTPUT;
653 else c = M_FILE_CUR_OUTPUT;
654 }
655 a_pipe_write("%c%c %s", c, (*ii)->id_character, (*ii)->id_name);
656 }
657 a_pipe_write(CHECKPOST "0");
658 }
659
660 static int
ctl_pass_playing_list(int init_number_of_files,char ** init_list_of_files)661 ctl_pass_playing_list(int init_number_of_files, char **init_list_of_files) {
662 int command = RC_NONE, i, j;
663 int32 val;
664 char *p;
665
666 for (i=0; i<MAX_XAW_MIDI_CHANNELS; i++) active[i] = 0;
667 reverb_type = opt_reverb_control?opt_reverb_control:DEFAULT_REVERB;
668 /* Wait prepare 'interface' */
669 a_pipe_read(local_buf, sizeof(local_buf));
670 if (strcmp("READY", local_buf)) return 0;
671 xaw_ready = 1;
672
673 a_pipe_write("%c", M_CHECKPOST);
674
675 a_pipe_write("%d",
676 (opt_modulation_wheel<<MODUL_N)
677 | (opt_portamento<<PORTA_N)
678 | (opt_nrpn_vibrato<<NRPNV_N)
679 | (!!(opt_reverb_control)<<REVERB_N)
680 | (opt_channel_pressure<<CHPRESSURE_N)
681 | (opt_overlap_voice_allow<<OVERLAPV_N)
682 | (opt_trace_text_meta_event<<TXTMETA_N));
683 a_pipe_write("%d", opt_chorus_control);
684
685 query_outputs();
686
687 /* Make title string */
688 titles = (char **)safe_malloc(init_number_of_files * sizeof(char *));
689 list_of_files = (char **)safe_malloc(init_number_of_files * sizeof(char *));
690 for (i=0, j=0;i<init_number_of_files;i++) {
691 if (check_midi_file(init_list_of_files[i]) >= 0) {
692 p = strrchr(init_list_of_files[i], '/');
693 if (p == NULL) p = safe_strdup(init_list_of_files[i]);
694 else p++;
695 list_of_files[j] = safe_strdup(init_list_of_files[i]);
696 titles[j] = (char *)safe_malloc(sizeof(char) * (strlen(p) + 9));
697 sprintf(titles[j], "%d. %s", j+1, p);
698 j++;
699 }
700 }
701 number_of_files = j;
702 titles = (char **)safe_realloc(titles, number_of_files * sizeof(char *));
703 list_of_files = (char **)safe_realloc(list_of_files,
704 number_of_files * sizeof(char *));
705
706 /* Send title string */
707 a_pipe_write("%d", number_of_files);
708 for (i=0;i<number_of_files;i++)
709 a_pipe_write("%s", titles[i]);
710
711 /* Make the table of play sequence */
712 file_table = (int *)safe_malloc(number_of_files * sizeof(int));
713 for (i=0;i<number_of_files;i++) file_table[i] = i;
714
715 /* Draw the title of the first file */
716 current_no = 0;
717 if (number_of_files != 0) {
718 a_pipe_write("%c%s", M_TITLE, titles[file_table[0]]);
719 command = ctl_blocking_read(&val);
720 }
721
722 /* Main loop */
723 for (;;) {
724 /* Play file */
725 if ((command == RC_LOAD_FILE) && (number_of_files != 0)) {
726 char *title;
727 a_pipe_write("%c%s", M_LISTITEM, titles[file_table[current_no]]);
728 if ((title = get_midi_title(list_of_files[file_table[current_no]]))
729 == NULL)
730 title = list_of_files[file_table[current_no]];
731 a_pipe_write("%c%s", M_TITLE, title);
732 command = play_midi_file(list_of_files[file_table[current_no]]);
733 } else {
734 if (command == RC_CHANGE_VOLUME) { };
735 if (command == RC_JUMP) { };
736 if (command == RC_TOGGLE_SNDSPEC) { };
737 /* Quit timidity*/
738 if (exitflag & EXITFLG_QUIT) return 0;
739 /* Stop playing */
740 if (command == RC_QUIT) {
741 a_pipe_write("%c00:00", M_TOTAL_TIME);
742 /* Shuffle the table */
743 if (randomflag) {
744 if (number_of_files == 0) {
745 randomflag = 0;
746 continue;
747 }
748 current_no = 0;
749 if (randomflag == 1) {
750 shuffle(number_of_files, file_table);
751 randomflag = 0;
752 command = RC_LOAD_FILE;
753 continue;
754 }
755 randomflag = 0;
756 for (i=0;i<number_of_files;i++) file_table[i] = i;
757 a_pipe_write("%c%s", M_LISTITEM, titles[file_table[current_no]]);
758 }
759 /* Play the selected file */
760 if (selectflag) {
761 for (i=0;i<number_of_files;i++)
762 if (file_table[i] == selectflag-1) break;
763 if (i != number_of_files) current_no = i;
764 selectflag = 0;
765 command = RC_LOAD_FILE;
766 continue;
767 }
768 /* After the all file played */
769 } else if ((command == RC_TUNE_END) || (command == RC_ERROR)) {
770 if (current_no+1 < number_of_files) {
771 if (olddpm != NULL) {
772 command = RC_QUIT;
773 a_pipe_write(CHECKPOST "2");
774 } else {
775 current_no++;
776 command = RC_LOAD_FILE;
777 continue;
778 }
779 } else if (exitflag & EXITFLG_AUTOQUIT) {
780 return 0;
781 /* Repeat */
782 } else if (repeatflag) {
783 current_no = 0;
784 command = RC_LOAD_FILE;
785 continue;
786 /* Off the play button */
787 } else {
788 if (olddpm != NULL) a_pipe_write(CHECKPOST "2");
789 a_pipe_write("%c", M_PLAY_END);
790 }
791 /* Play the next */
792 } else if (command == RC_NEXT) {
793 if (current_no+1 < number_of_files) current_no++;
794 command = RC_LOAD_FILE;
795 continue;
796 /* Play the previous */
797 } else if (command == RC_REALLY_PREVIOUS) {
798 if (current_no > 0) current_no--;
799 command = RC_LOAD_FILE;
800 continue;
801 }
802 command = ctl_blocking_read(&val);
803 }
804 }
805 }
806
807 /* ------ Pipe handlers ----- */
808
809 static void
a_pipe_open(void)810 a_pipe_open(void) {
811 int cont_inter[2], inter_cont[2];
812
813 if ((pipe(cont_inter) < 0) || (pipe(inter_cont) < 0)) exit(1);
814
815 if (fork() == 0) {
816 close(cont_inter[1]);
817 close(inter_cont[0]);
818 pipe_in_fd = cont_inter[0];
819 pipe_out_fd = inter_cont[1];
820 a_start_interface(pipe_in_fd);
821 }
822 close(cont_inter[0]);
823 close(inter_cont[1]);
824 pipe_in_fd = inter_cont[0];
825 pipe_out_fd = cont_inter[1];
826 }
827
828 void
a_pipe_write(const char * fmt,...)829 a_pipe_write(const char *fmt, ...) {
830 static char local_buf[PIPE_LENGTH];
831 int len;
832 va_list ap;
833 ssize_t dummy;
834
835 va_start(ap, fmt);
836 len = vsnprintf(local_buf, sizeof(local_buf), fmt, ap);
837 if ((len < 0) || (len > PIPE_LENGTH))
838 dummy = write(pipe_out_fd, local_buf, PIPE_LENGTH);
839 else
840 dummy = write(pipe_out_fd, local_buf, len);
841 dummy += write(pipe_out_fd, "\n", 1);
842 va_end(ap);
843 }
844
845 static void
a_pipe_write_buf(const char * buf,int len)846 a_pipe_write_buf(const char *buf, int len) {
847 ssize_t dummy;
848 if ((len < 0) || (len > PIPE_LENGTH))
849 dummy = write(pipe_out_fd, buf, PIPE_LENGTH);
850 else
851 dummy = write(pipe_out_fd, buf, len);
852 dummy += write(pipe_out_fd, "\n", 1);
853 }
854
855 static int
a_pipe_ready(void)856 a_pipe_ready(void) {
857 fd_set fds;
858 static struct timeval tv;
859 int cnt;
860
861 FD_ZERO(&fds);
862 FD_SET(pipe_in_fd, &fds);
863 tv.tv_sec = 0;
864 tv.tv_usec = 0;
865 if ((cnt = select(pipe_in_fd+1, &fds, NULL, NULL, &tv)) < 0) return -1;
866 return (cnt > 0) && (FD_ISSET(pipe_in_fd, &fds) != 0);
867 }
868
869 int
a_pipe_read(char * buf,size_t bufsize)870 a_pipe_read(char *buf, size_t bufsize) {
871 size_t i;
872
873 bufsize--;
874 for (i=0;i<bufsize;i++) {
875 ssize_t len = read(pipe_in_fd, buf+i, 1);
876 if (len != 1) {
877 perror("CONNECTION PROBLEM WITH XAW PROCESS");
878 exit(1);
879 }
880 if (buf[i] == '\n') break;
881 }
882 buf[i] = '\0';
883 return 0;
884 }
885
886 int
a_pipe_nread(char * buf,size_t n)887 a_pipe_nread(char *buf, size_t n) {
888 ssize_t i, j = 0;
889
890 if (n <= 0) return 0;
891 while ((i = read(pipe_in_fd, buf + j, n - j)) > 0) j += i;
892 return j;
893 }
894
895 void
a_pipe_sync(void)896 a_pipe_sync(void) {
897 fsync(pipe_out_fd);
898 fsync(pipe_in_fd);
899 usleep(100000);
900 }
901
902 static void
a_pipe_write_msg(char * msg)903 a_pipe_write_msg(char *msg) {
904 size_t msglen;
905 ssize_t dummy;
906 char buf[2 + sizeof(size_t)], *p, *q;
907
908 /* convert '\r' to '\n', but strip '\r' from '\r\n' */
909 p = q = msg;
910 while (*q != '\0') {
911 if (*q != '\r') *p++ = *q++;
912 else if (*(++q) != '\n') *p++ = '\n';
913 }
914 *p = '\0';
915
916 msglen = strlen(msg) + 1; /* +1 for '\n' */
917 buf[0] = M_LYRIC;
918 buf[1] = '\n';
919
920 memcpy(buf + 2, &msglen, sizeof(size_t));
921 dummy = write(pipe_out_fd, buf, sizeof(buf));
922 dummy += write(pipe_out_fd, msg, msglen - 1);
923 dummy += write(pipe_out_fd, "\n", 1);
924 }
925
926 static void
a_pipe_write_msg_nobr(char * msg)927 a_pipe_write_msg_nobr(char *msg) {
928 size_t msglen;
929 ssize_t dummy;
930 char buf[2 + sizeof(size_t)], *p, *q;
931
932 /* convert '\r' to '\n', but strip '\r' from '\r\n' */
933 p = q = msg;
934 while (*q != '\0') {
935 if (*q != '\r') *p++ = *q++;
936 else if (*(++q) != '\n') *p++ = '\n';
937 }
938 *p = '\0';
939
940 msglen = strlen(msg);
941 buf[0] = M_LYRIC;
942 buf[1] = '\n';
943
944 memcpy(buf + 2, &msglen, sizeof(size_t));
945 dummy = write(pipe_out_fd, buf, sizeof(buf));
946 dummy += write(pipe_out_fd, msg, msglen);
947 }
948
949 static void
ctl_note(int status,int ch,int note,int velocity)950 ctl_note(int status, int ch, int note, int velocity) {
951 char c;
952
953 if (ch >= MAX_XAW_MIDI_CHANNELS) return;
954 if(!ctl.trace_playing || midi_trace.flush_flag) return;
955
956 switch (status) {
957 case VOICE_ON:
958 c = '*';
959 break;
960 case VOICE_SUSTAINED:
961 c = '&';
962 break;
963 case VOICE_FREE:
964 case VOICE_DIE:
965 case VOICE_OFF:
966 default:
967 c = '.';
968 break;
969 }
970 a_pipe_write("%c%d%c%c%03d%d", MT_NOTE, ch, CH_END_TOKEN,
971 c, (unsigned char)note, velocity);
972
973 if (active[ch] == 0) {
974 active[ch] = 1;
975 ctl_program(ch, channel[ch].program, channel_instrum_name(ch), BANKS(ch));
976 }
977 }
978
979 static void
ctl_program(int ch,int val,const char * comm,uint32 banks)980 ctl_program(int ch, int val, const char *comm, uint32 banks) {
981 if ((!ctl.trace_playing) || (ch >= MAX_XAW_MIDI_CHANNELS)) return;
982
983 if ((channel[ch].program == DEFAULT_PROGRAM) && (active[ch] == 0) &&
984 (!ISDRUMCHANNEL(ch))) return;
985 active[ch] = 1;
986 if (!IS_CURRENT_MOD_FILE) val += progbase;
987 a_pipe_write("%c%c%d%c%d", MT_PANEL_INFO, MTP_PROGRAM, ch,
988 CH_END_TOKEN, val);
989 a_pipe_write("%c%c%d%c%d", MT_PANEL_INFO, MTP_TONEBANK, ch,
990 CH_END_TOKEN, banks);
991 if (comm != NULL) {
992 a_pipe_write("%c%d%c%s", MT_INST_NAME, ch, CH_END_TOKEN,
993 (!strlen(comm) && (ISDRUMCHANNEL(ch)))? "<drum>":comm);
994 }
995 }
996
997 static void
ctl_drumpart(int ch,int is_drum)998 ctl_drumpart(int ch, int is_drum) {
999 if ((!ctl.trace_playing) || (ch >= MAX_XAW_MIDI_CHANNELS)) return;
1000
1001 a_pipe_write("%c%d%c%c", MT_IS_DRUM, ch, CH_END_TOKEN, is_drum+'A');
1002 }
1003
1004 static void
ctl_pause(int is_paused,int time)1005 ctl_pause(int is_paused, int time) {
1006 if (is_paused) {
1007 a_pipe_write("%c1", M_PAUSE);
1008 } else {
1009 ctl_current_time(time, -1);
1010 a_pipe_write("%c0", M_PAUSE);
1011 }
1012 }
1013
1014 static void
ctl_max_voices(int voices)1015 ctl_max_voices(int voices) {
1016 static int last_voices = -1;
1017
1018 if (last_voices != voices) {
1019 last_voices = voices;
1020 a_pipe_write("%c%c%d", MT_VOICES, MTV_TOTAL_VOICES, voices);
1021 }
1022 }
1023
1024 static void
ctl_event(CtlEvent * e)1025 ctl_event(CtlEvent *e) {
1026 switch(e->type) {
1027 case CTLE_CURRENT_TIME:
1028 ctl_current_time((int)e->v1, (int)e->v2);
1029 break;
1030 case CTLE_NOTE:
1031 ctl_note((int)e->v1, (int)e->v2, (int)e->v3, (int)e->v4);
1032 break;
1033 case CTLE_PLAY_START:
1034 ctl_total_time((int)e->v1 / play_mode->rate);
1035 break;
1036 case CTLE_CUEPOINT:
1037 cuepoint = e->v1;
1038 cuepoint_pending = 1;
1039 break;
1040 case CTLE_TEMPO:
1041 ctl_tempo((int)e->v1);
1042 break;
1043 case CTLE_TIME_RATIO:
1044 ctl_timeratio((int)e->v1);
1045 break;
1046 case CTLE_PROGRAM:
1047 ctl_program((int)e->v1, (int)e->v2, (char *)e->v3, (uint32)e->v4);
1048 break;
1049 case CTLE_DRUMPART:
1050 ctl_drumpart((int)e->v1, (int)e->v2);
1051 break;
1052 case CTLE_VOLUME:
1053 ctl_volume((int)e->v1, (int)e->v2);
1054 break;
1055 case CTLE_EXPRESSION:
1056 ctl_expression((int)e->v1, (int)e->v2);
1057 break;
1058 case CTLE_PANNING:
1059 ctl_panning((int)e->v1, (int)e->v2);
1060 break;
1061 case CTLE_SUSTAIN:
1062 ctl_sustain((int)e->v1, (int)e->v2);
1063 break;
1064 case CTLE_PITCH_BEND:
1065 ctl_pitch_bend((int)e->v1, (int)e->v2);
1066 break;
1067 case CTLE_MOD_WHEEL:
1068 ctl_pitch_bend((int)e->v1, e->v2 ? -1 : 0x2000);
1069 break;
1070 case CTLE_CHORUS_EFFECT:
1071 set_otherinfo((int)e->v1, (int)e->v2, MTP_CHORUS);
1072 break;
1073 case CTLE_REVERB_EFFECT:
1074 set_otherinfo((int)e->v1, (int)e->v2, MTP_REVERB);
1075 break;
1076 case CTLE_LYRIC:
1077 ctl_lyric((int)e->v1);
1078 break;
1079 case CTLE_MASTER_VOLUME:
1080 ctl_master_volume((int)e->v1);
1081 break;
1082 case CTLE_REFRESH:
1083 ctl_refresh();
1084 break;
1085 case CTLE_RESET:
1086 ctl_reset();
1087 break;
1088 case CTLE_MUTE:
1089 ctl_mute((int)e->v1, (int)e->v2);
1090 break;
1091 case CTLE_KEYSIG:
1092 ctl_keysig((int)e->v1);
1093 break;
1094 case CTLE_KEY_OFFSET:
1095 ctl_key_offset((int)e->v1);
1096 break;
1097 case CTLE_PAUSE:
1098 ctl_pause((int)e->v1, (int)e->v2);
1099 break;
1100 case CTLE_MAXVOICES:
1101 ctl_max_voices((int)e->v1);
1102 break;
1103 case CTLE_LOADING_DONE:
1104 a_pipe_write("%c%d", M_LOADING_DONE, (int)e->v2);
1105 break;
1106 #if 0
1107 case CTLE_PLAY_END:
1108 case CTLE_METRONOME:
1109 case CTLE_TEMPER_KEYSIG:
1110 case CTLE_TEMPER_TYPE:
1111 case CTLE_SPEANA:
1112 case CTLE_NOW_LOADING:
1113 case CTLE_GSLCD:
1114 #endif
1115 default:
1116 break;
1117 }
1118 }
1119
1120 static void
ctl_refresh(void)1121 ctl_refresh(void) { }
1122
1123 static void
set_otherinfo(int ch,int val,char c)1124 set_otherinfo(int ch, int val, char c) {
1125 if ((!ctl.trace_playing) || (ch >= MAX_XAW_MIDI_CHANNELS)) return;
1126 a_pipe_write("%c%c%d%c%d", MT_PANEL_INFO, c, ch, CH_END_TOKEN, val);
1127 }
1128
1129 static void
ctl_reset(void)1130 ctl_reset(void) {
1131 int i;
1132
1133 if (!ctl.trace_playing) return;
1134
1135 indicator_last_update = get_current_calender_time();
1136 ctl_tempo((int)current_play_tempo);
1137 ctl_timeratio((int)(100 / midi_time_ratio + 0.5));
1138 ctl_keysig((int)current_keysig);
1139 ctl_key_offset(note_key_offset);
1140 ctl_max_voices(voices);
1141 for (i=0; i<MAX_XAW_MIDI_CHANNELS; i++) {
1142 active[i] = 0;
1143 if (ISDRUMCHANNEL(i)) {
1144 if (opt_reverb_control) set_otherinfo(i, get_reverb_level(i), MTP_REVERB);
1145 } else {
1146 if (opt_reverb_control) set_otherinfo(i, get_reverb_level(i), MTP_REVERB);
1147 if (opt_chorus_control) set_otherinfo(i, get_chorus_level(i), MTP_CHORUS);
1148 }
1149 ctl_program(i, channel[i].program, channel_instrum_name(i), BANKS(i));
1150 ctl_volume(i, channel[i].volume);
1151 ctl_expression(i, channel[i].expression);
1152 ctl_panning(i, channel[i].panning);
1153 ctl_sustain(i, channel[i].sustain);
1154 if ((channel[i].pitchbend == 0x2000) && (channel[i].mod.val > 0))
1155 ctl_pitch_bend(i, -1);
1156 else
1157 ctl_pitch_bend(i, channel[i].pitchbend);
1158 }
1159 a_pipe_write("%c", MT_REDRAW_TRACE);
1160 }
1161
1162 static void
update_indicator(void)1163 update_indicator(void) {
1164 double t, diff;
1165
1166 if (!ctl.trace_playing) return;
1167 t = get_current_calender_time();
1168 diff = t - indicator_last_update;
1169 if (diff > XAW_UPDATE_TIME) {
1170 a_pipe_write("%c", MT_UPDATE_TIMER);
1171 indicator_last_update = t;
1172 }
1173 }
1174
1175 static void
ctl_mute(int ch,int mute)1176 ctl_mute(int ch, int mute) {
1177 if ((!ctl.trace_playing) || (ch >= MAX_XAW_MIDI_CHANNELS)) return;
1178 a_pipe_write("%c%d%c%d", MT_MUTE, ch, CH_END_TOKEN, mute);
1179 return;
1180 }
1181
1182 static void
ctl_tempo(int tempo)1183 ctl_tempo(int tempo) {
1184 a_pipe_write("%c%d", MT_TEMPO, tempo);
1185 return;
1186 }
1187
1188
1189 static void
ctl_timeratio(int ratio)1190 ctl_timeratio(int ratio) {
1191 a_pipe_write("%c%d", MT_RATIO, ratio);
1192 return;
1193 }
1194
1195 static void
ctl_keysig(int keysig)1196 ctl_keysig(int keysig) {
1197 a_pipe_write("%c%d", MT_PITCH, keysig);
1198 return;
1199 }
1200
1201 static void
ctl_key_offset(int offset)1202 ctl_key_offset(int offset) {
1203 a_pipe_write("%c%d", MT_PITCH_OFFSET, offset);
1204 return;
1205 }
1206
1207 /*
1208 * interface_<id>_loader();
1209 */
1210 ControlMode *
interface_a_loader(void)1211 interface_a_loader(void) {
1212 return &ctl;
1213 }
1214