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