2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2018 Masanao Izumo <iz@onicos.co.jp>
4 Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
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.
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.
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
20 The Tcl/Tk interface for Timidity
21 written by Takashi Iwai (iwai@dragon.mm.t.u-tokyo.ac.jp)
23 Most of the following codes are derived from both motif_ctl.c
24 and motif_pipe.c. The communication between Tk program and
25 timidity is established by a pipe stream as in Motif interface.
26 On the contrast to motif, the stdin and stdout are assigned
27 as pipe i/o in Tk interface.
33 #endif /* HAVE_CONFIG_H */
39 #include <sys/types.h>
40 #include <sys/ioctl.h>
56 #include "miditrace.h"
60 #define TKPROGPATH PKGLIBDIR "/tkmidity.tcl"
61 #endif /* TKPROGPATH */
63 #if (TCL_MAJOR_VERSION < 8)
64 #define Tcl_GetStringResult(interp) (interp->result)
67 static void ctl_refresh(void);
68 static void ctl_total_time(int tt);
69 static void ctl_master_volume(int mv);
70 static void ctl_file_name(const char *name);
71 static void ctl_current_time(int secs, int v);
72 static void ctl_program(int ch, int val);
73 static void ctl_volume(int channel, int val);
74 static void ctl_expression(int channel, int val);
75 static void ctl_panning(int channel, int val);
76 static void ctl_sustain(int channel, int val);
77 static void ctl_pitch_bend(int channel, int val);
78 static void ctl_lyric(int lyricid);
79 static void ctl_reset(void);
80 static int ctl_open(int using_stdin, int using_stdout);
81 static void ctl_close(void);
82 static int ctl_read(ptr_size_t *valp);
83 static int cmsg(int type, int verbosity_level, const char *fmt, ...);
84 static int ctl_pass_playing_list(int number_of_files, char *list_of_files[]);
85 static int ctl_blocking_read(ptr_size_t *valp);
86 static void ctl_note(int status, int ch, int note, int vel);
87 static void ctl_event(CtlEvent *e);
89 static void k_pipe_printf(const char *fmt, ...);
90 static void k_pipe_puts(char *str);
91 static int k_pipe_gets(char *str, int maxlen);
92 static void k_pipe_open(void);
93 static void k_pipe_error(char *st);
94 static int k_pipe_read_ready(void);
96 static int AppInit(Tcl_Interp *interp);
97 static int ExitAll(ClientData clientData, Tcl_Interp *interp,
98 int argc, char *argv[]);
99 static int TraceCreate(ClientData clientData, Tcl_Interp *interp,
100 int argc, char *argv[]);
101 static int TraceUpdate(ClientData clientData, Tcl_Interp *interp,
102 int argc, char *argv[]);
103 static int TraceReset(ClientData clientData, Tcl_Interp *interp,
104 int argc, char *argv[]);
105 static void trace_volume(int ch, int val);
106 static void trace_panning(int ch, int val);
107 static void trace_prog_init(int ch);
108 static void trace_prog(int ch, int val);
109 static void trace_bank(int ch, int val);
110 static void trace_sustain(int ch, int val);
112 static void get_child(int sig);
113 static void shm_alloc(void);
114 static void shm_free(int sig);
116 static void start_panel(void);
118 #define MAX_TK_MIDI_CHANNELS 32
124 int32 last_time, cur_time;
126 char v_flags[MAX_TK_MIDI_CHANNELS];
127 int16 cnote[MAX_TK_MIDI_CHANNELS];
128 int16 cvel[MAX_TK_MIDI_CHANNELS];
129 int16 ctotal[MAX_TK_MIDI_CHANNELS];
131 char c_flags[MAX_TK_MIDI_CHANNELS];
132 Channel channel[MAX_TK_MIDI_CHANNELS];
137 /**********************************************/
139 #define ctl tk_control_mode
143 "Tcl/Tk interface", 'k',
149 ctl_pass_playing_list,
156 static uint32 cuepoint = 0;
157 static int cuepoint_pending = 0;
159 #define FLAG_NOTE_OFF 1
160 #define FLAG_NOTE_ON 2
167 static VOLATILE PanelInfo *Panel;
168 static VOLATILE int child_killed = 0;
170 static int shmid; /* shared memory id */
171 static int semid; /* semaphore id */
173 static int pipeAppli[2], pipePanel[2]; /* Pipe for communication with Tcl/Tk process */
174 static int fpip_in, fpip_out; /* in and out depends in which process we are */
175 static int child_pid; /* Pid for child process */
177 /***********************************************************************/
178 /* semaphore utilities */
179 /***********************************************************************/
180 static void semaphore_P(int sid)
187 if (semop(sid, &sb, 1) == -1)
191 static void semaphore_V(int sid)
198 if (semop(sid, &sb, 1) == -1)
202 /***********************************************************************/
203 /* Put controls on the pipe */
204 /***********************************************************************/
206 static int cmsg(int type, int verbosity_level, const char *fmt, ...)
209 #define TOO_LONG 2000
212 if ((type == CMSG_TEXT || type == CMSG_INFO || type == CMSG_WARNING) &&
213 ctl.verbosity < verbosity_level)
217 //if (strlen(fmt) > TOO_LONG)
218 // fmt[TOO_LONG] = 0;
220 vfprintf(stderr, fmt, ap);
221 fprintf(stderr, "\n");
222 } else if (type == CMSG_ERROR) {
224 vsnprintf(local, ARRAY_SIZE(local), fmt, ap);
225 k_pipe_printf("CERR %d", type);
227 while (ctl_blocking_read(&val) != RC_NEXT)
230 vsnprintf(local, ARRAY_SIZE(local), fmt, ap);
231 k_pipe_printf("CMSG %d", type);
238 static void ctl_refresh(void)
242 static void ctl_total_time(int tt)
244 int centisecs = tt / (play_mode->rate / 100);
245 k_pipe_printf("TIME %d", centisecs);
246 ctl_current_time(0, 0);
249 static void ctl_master_volume(int mv)
251 k_pipe_printf("MVOL %d", mv);
254 static void ctl_file_name(const char *name)
256 k_pipe_printf("FILE %s", name);
259 static void ctl_current_time(int secs, int v)
261 Panel->cur_time = secs;
264 static void ctl_channel_note(int ch, int note, int vel)
267 if (note == Panel->cnote[ch])
268 Panel->v_flags[ch] = FLAG_NOTE_OFF;
270 } else if (vel > Panel->cvel[ch]) {
271 Panel->cvel[ch] = vel;
272 Panel->cnote[ch] = note;
273 Panel->ctotal[ch] = vel * Panel->channel[ch].volume *
274 Panel->channel[ch].expression / (127 * 127);
275 Panel->v_flags[ch] = FLAG_NOTE_ON;
279 static void ctl_note(int status, int ch, int note, int vel)
281 if (!ctl.trace_playing)
284 if (ch < 0 || ch >= MAX_TK_MIDI_CHANNELS) return;
286 if (status != VOICE_ON)
289 ctl_channel_note(ch, note, vel);
293 static void ctl_program(int ch, int val)
295 if (ch >= MAX_TK_MIDI_CHANNELS)
297 if (!ctl.trace_playing)
299 if (ch < 0 || ch >= MAX_TK_MIDI_CHANNELS) return;
300 if (channel[ch].special_sample)
301 val = channel[ch].special_sample;
306 Panel->channel[ch].program = val;
307 Panel->c_flags[ch] |= FLAG_PROG;
311 static void ctl_volume(int ch, int val)
313 if (ch >= MAX_TK_MIDI_CHANNELS)
315 if (!ctl.trace_playing)
318 Panel->channel[ch].volume = val;
319 ctl_channel_note(ch, Panel->cnote[ch], Panel->cvel[ch]);
323 static void ctl_expression(int ch, int val)
325 if (ch >= MAX_TK_MIDI_CHANNELS)
327 if (!ctl.trace_playing)
330 Panel->channel[ch].expression = val;
331 ctl_channel_note(ch, Panel->cnote[ch], Panel->cvel[ch]);
335 static void ctl_panning(int ch, int val)
337 if (ch >= MAX_TK_MIDI_CHANNELS)
339 if (!ctl.trace_playing)
342 Panel->channel[ch].panning = val;
343 Panel->c_flags[ch] |= FLAG_PAN;
347 static void ctl_sustain(int ch, int val)
349 if (ch >= MAX_TK_MIDI_CHANNELS)
351 if (!ctl.trace_playing)
354 Panel->channel[ch].sustain = val;
355 Panel->c_flags[ch] |= FLAG_SUST;
360 static void ctl_pitch_bend(int channel, int val)
363 if (ch >= MAX_TK_MIDI_CHANNELS)
365 if (!ctl.trace_playing)
368 Panel->channel[ch].pitch_bend = val;
369 Panel->c_flags[ch] |= FLAG_BENDT;
374 static void ctl_lyric(int lyricid)
378 lyric = event2string(lyricid);
381 if (lyric[0] == ME_KARAOKE_LYRIC)
383 if (lyric[1] == '/' || lyric[1] == '\\')
385 k_pipe_printf("CMSG %d", CMSG_TEXT);
387 k_pipe_printf("LYRC %d", CMSG_TEXT);
388 k_pipe_printf("%s", lyric + 2);
390 else if (lyric[1] == '@')
394 k_pipe_printf("CMSG %d", CMSG_TEXT);
395 k_pipe_printf("Language: %s", lyric + 3);
397 else if (lyric[2] == 'T')
399 k_pipe_printf("CMSG %d", CMSG_TEXT);
400 k_pipe_printf("Title: %s", lyric + 3);
404 k_pipe_printf("CMSG %d", CMSG_TEXT);
405 k_pipe_printf("%s", lyric + 1);
410 k_pipe_printf("LYRC %d", CMSG_TEXT);
411 k_pipe_printf("%s", lyric + 1);
416 k_pipe_printf("CMSG %d", CMSG_TEXT);
417 k_pipe_printf("%s", lyric + 1);
422 static void ctl_reset(void)
426 if (!ctl.trace_playing)
428 k_pipe_printf("RSET %d", ctl.trace_playing);
432 Panel->wait_reset = 1;
433 k_pipe_printf("RSET %d", ctl.trace_playing);
435 while (Panel->wait_reset)
436 VOLATILE_TOUCH(Panel->wait_reset);
438 if (!ctl.trace_playing)
440 for (i = 0; i < MAX_TK_MIDI_CHANNELS; i++) {
441 if (ISDRUMCHANNEL(i))
442 ctl_program(i, channel[i].bank);
444 ctl_program(i, channel[i].program);
445 ctl_volume(i, channel[i].volume);
446 ctl_expression(i, channel[i].expression);
447 ctl_panning(i, channel[i].panning);
448 ctl_sustain(i, channel[i].sustain);
449 if (channel[i].pitchbend == 0x2000 &&
450 channel[i].mod.val > 0)
451 ctl_pitch_bend(i, -1);
453 ctl_pitch_bend(i, channel[i].pitchbend);
454 ctl_channel_note(i, Panel->cnote[i], 0);
458 /***********************************************************************/
459 /* OPEN THE CONNECTION */
460 /***********************************************************************/
462 static int ctl_open(int using_stdin, int using_stdout)
470 signal(SIGCHLD, get_child);
471 signal(SIGTERM, shm_free);
472 signal(SIGINT, shm_free);
473 signal(SIGHUP, shm_free);
479 /* Tells the window to disapear */
480 static void ctl_close(void)
483 kill(child_pid, SIGTERM);
491 * Read information coming from the window in a BLOCKING way
494 /* commands are: PREV, NEXT, QUIT, STOP, LOAD, JUMP, VOLM */
496 static int ctl_blocking_read(ptr_size_t *valp)
498 char buf[8192], *tok, *arg;
500 int new_centiseconds;
501 char *args[64], **files;
504 k_pipe_gets(buf, sizeof(buf) - 1);
505 tok = strtok(buf, " ");
507 for (;;)/* Loop after pause sleeping to treat other buttons! */
511 if ((arg = strtok(NULL, " ")) != NULL) {
512 new_volume = atoi(arg);
513 *valp = new_volume - output_amplification;
514 return RC_CHANGE_VOLUME;
519 if ((arg = strtok(NULL, " ")) != NULL) {
520 new_centiseconds = atoi(arg);
521 *valp = new_centiseconds * (play_mode->rate / 100);
536 /*return RC_REALLY_PREVIOUS;*/
543 *valp = play_mode->rate;
547 *valp = play_mode->rate;
551 k_pipe_gets(buf, sizeof(buf) - 1);
552 args[i++] = strtok(buf, " ");
553 while ((args[i++] = strtok(NULL, " ")) != NULL);
555 files = expand_file_archives(args, &nfiles);
556 k_pipe_printf("ALST %d", nfiles);
557 for (i = 0; i < nfiles; i++)
558 k_pipe_puts(files[i]);
564 return RC_TOGGLE_PAUSE;
567 fprintf(stderr, "UNKNOWN RC_MESSAGE `%s'\n", tok);
575 * Read information coming from the window in a non blocking way
577 static int ctl_read(ptr_size_t *valp)
581 if (cuepoint_pending) {
583 cuepoint_pending = 0;
587 /* We don't wan't to lock on reading */
588 num = k_pipe_read_ready();
593 return(ctl_blocking_read(valp));
596 static int ctl_pass_playing_list(int number_of_files, char *list_of_files[])
603 /* Pass the list to the interface */
604 k_pipe_printf("LIST %d", number_of_files);
605 for (i = 0; i < number_of_files; i++)
606 k_pipe_puts(list_of_files[i]);
608 /* Ask the interface for a filename to play -> begin to play automatically */
609 /*k_pipe_puts("NEXT");*/
610 command = ctl_blocking_read(&val);
615 if (command == RC_LOAD_FILE)
617 /* Read a LoadFile command */
618 k_pipe_gets(local, sizeof(local) - 1);
619 command = play_midi_file(local);
623 if (command == RC_QUIT) {
625 k_pipe_gets(local, sizeof(local) - 1);
628 /* only stop playing..*/
630 if (command == RC_CHANGE_VOLUME) /* init volume */
631 output_amplification += val;
641 case RC_REALLY_PREVIOUS:
652 command = ctl_blocking_read(&val);
659 /* open pipe and fork child process */
660 static void k_pipe_open(void)
664 res = pipe(pipeAppli);
665 if (res != 0) k_pipe_error("PIPE_APPLI CREATION");
667 res = pipe(pipePanel);
668 if (res != 0) k_pipe_error("PIPE_PANEL CREATION");
670 if ((child_pid = fork()) == 0) {
675 /* redirect to stdin/out */
676 dup2(pipePanel[0], fileno(stdin));
678 dup2(pipeAppli[1], fileno(stdout));
684 fpip_in = pipeAppli[0];
685 fpip_out = pipePanel[1];
691 #include <sys/time.h>
695 #include <sys/filio.h>
698 static int k_pipe_read_ready(void)
703 struct timeval timeout;
706 FD_SET(fpip_in, &fds);
707 timeout.tv_sec = timeout.tv_usec = 0;
709 if ((cnt = select(fpip_in + 1, &fds, NULL, NULL, &timeout)) < 0)
715 return cnt > 0 && FD_ISSET(fpip_in, &fds) != 0;
719 if (ioctl(fpip_in, FIONREAD, &num) < 0) /* see how many chars in buffer. */
721 perror("ioctl: FIONREAD");
729 /***********************************************************************/
730 /* PIPE COMUNICATION */
731 /***********************************************************************/
733 static void k_pipe_error(char *st)
735 fprintf(stderr, "CONNECTION PROBLEM WITH TCL/TK PROCESS IN %s BECAUSE:%s\n",
742 static void k_pipe_printf(const char *fmt, ...)
747 vsnprintf(buf, sizeof(buf), fmt, ap);
751 static int line_strlen(char *str)
756 while (*str && *str != '\r' && *str != '\n') {
763 static void k_pipe_puts(char *str)
767 len = line_strlen(str);
768 ssize_t dummy = write(fpip_out, str, len);
769 dummy = write(fpip_out, &lf, 1);
773 int k_pipe_gets(char *str, int maxlen)
775 /* blocking reading */
779 /* at least 5 letters (4+\n) command */
781 for (p = str; len < maxlen - 1; p++) {
782 ssize_t dummy = read(fpip_in, p, 1);
793 /*----------------------------------------------------------------
794 * shared memory handling
795 *----------------------------------------------------------------*/
798 static void get_child(int sig)
803 static void shm_alloc(void)
805 shmid = shmget(IPC_PRIVATE, sizeof(PanelInfo),
808 fprintf(stderr, "can't allocate shared memory\n");
812 semid = semget(IPC_PRIVATE, 1, IPC_CREAT|0600);
815 shmctl(shmid, IPC_RMID, NULL);
819 /* bin semaphore: only call once at first */
822 Panel = (PanelInfo*) shmat(shmid, 0, 0);
823 Panel->reset_panel = 0;
824 Panel->multi_part = 0;
825 Panel->wait_reset = 0;
829 static void shm_free(int sig)
832 #if defined(HAVE_UNION_SEMUN)
834 #else /* Solaris 2.x, BSDI, OSF/1, HPUX */
838 kill(child_pid, SIGTERM);
839 while (wait(&status) != child_pid)
841 memset(&dmy, 0, sizeof(dmy)); /* Shut compiler warning up :-) */
842 semctl(semid, 0, IPC_RMID, dmy);
843 shmctl(shmid, IPC_RMID, NULL);
844 shmdt((char*) Panel);
849 /*----------------------------------------------------------------
850 * start Tk window panel
851 *----------------------------------------------------------------*/
853 static void start_panel(void)
860 argv[argc++] = TKPROGPATH;
862 if (ctl.trace_playing) {
863 argv[argc++] = "-mode";
864 argv[argc++] = "trace";
867 /* call Tk main routine */
868 Tk_Main(argc, argv, AppInit);
874 /*----------------------------------------------------------------
875 * initialize Tcl application
876 *----------------------------------------------------------------*/
878 static Tcl_Interp *my_interp;
880 static int AppInit(Tcl_Interp *interp)
882 #include "bitmaps/back.xbm"
883 #include "bitmaps/fwrd.xbm"
884 #include "bitmaps/next.xbm"
885 #include "bitmaps/pause.xbm"
886 #include "bitmaps/play.xbm"
887 #include "bitmaps/prev.xbm"
888 #include "bitmaps/quit.xbm"
889 #include "bitmaps/stop.xbm"
890 #include "bitmaps/timidity.xbm"
892 #define DefineBitmap(Bitmap) do { \
893 Tk_DefineBitmap (interp, Tk_GetUid(#Bitmap), Bitmap##_bits, \
894 Bitmap##_width, Bitmap##_height); \
899 if (Tcl_Init(interp) == TCL_ERROR) {
902 if (Tk_Init(interp) == TCL_ERROR) {
906 Tcl_CreateCommand(interp, "TraceCreate", (Tcl_CmdProc*) TraceCreate,
907 (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
908 Tcl_CreateCommand(interp, "TraceUpdate", (Tcl_CmdProc*) TraceUpdate,
909 (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
910 Tcl_CreateCommand(interp, "TraceReset", (Tcl_CmdProc*) TraceReset,
911 (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
912 Tcl_CreateCommand(interp, "ExitAll", (Tcl_CmdProc*) ExitAll,
913 (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
914 Tcl_CreateCommand(interp, "TraceUpdate", (Tcl_CmdProc*) TraceUpdate,
915 (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
925 DefineBitmap(timidity);
932 static int ExitAll(ClientData clientData, Tcl_Interp *interp,
933 int argc, char *argv[])
935 /* window is killed; kill the parent process, too */
936 kill(getppid(), SIGTERM);
942 /* evaluate Tcl script */
943 static const char *v_eval(const char *fmt, ...)
948 vsnprintf(buf, sizeof(buf), fmt, ap);
949 Tcl_Eval(my_interp, buf);
951 return Tcl_GetStringResult(my_interp);
954 static const char *v_get2(const char *v1, const char *v2)
956 return Tcl_GetVar2(my_interp, v1, v2, 0);
960 /*----------------------------------------------------------------
961 * update Tcl timer / trace window
962 *----------------------------------------------------------------*/
964 #define FRAME_WIN ".body.trace"
965 #define CANVAS_WIN FRAME_WIN ".c"
969 #define WIN_WID (BAR_WID * 16)
970 #define WIN_HGT (BAR_HGT + 11 + 17)
971 #define BAR_HALF_HGT (WIN_HGT / 2 - 11 - 17)
975 static int TraceCreate(ClientData clientData, Tcl_Interp *interp,
976 int argc, char *argv[])
979 v_eval("frame %s -bg black", FRAME_WIN);
980 v_eval("canvas %s -width %d -height %d -bd 0 -bg black "
981 "-highlightthickness 0",
982 CANVAS_WIN, WIN_WID, WIN_HGT);
983 v_eval("pack %s -side top -fill x", CANVAS_WIN);
984 for (i = 0; i < 32; i++) {
986 v_eval("%s create text 0 0 -anchor n -fill white -text 00 "
987 "-tags prog%d", CANVAS_WIN, i);
988 v_eval("%s create poly 0 0 0 0 0 0 -fill yellow -tags pos%d",
990 color = (ISDRUMCHANNEL(i) || i == 25) ? "red" : "green";
991 v_eval("%s create rect 0 0 0 0 -fill %s -tags bar%d "
992 "-outline \"\"", CANVAS_WIN, color, i);
994 v_eval("set Stat(TimerId) -1");
995 v_eval("TraceReset");
999 static void trace_bank(int ch, int val)
1001 v_eval("%s itemconfigure bar%d -fill %s",
1003 (val == 128 ? "red" : "green"));
1006 static void trace_prog(int ch, int val)
1008 v_eval("%s itemconfigure prog%d -text %02X",
1009 CANVAS_WIN, ch, val);
1012 static void trace_sustain(int ch, int val)
1014 v_eval("%s itemconfigure prog%d -fill %s",
1016 (val == 127 ? "green" : "white"));
1019 static void trace_prog_init(int ch)
1021 int item, yofs, bar, x, y;
1025 bar = Panel->multi_part ? BAR_HALF_HGT : BAR_HGT;
1029 if (!Panel->multi_part)
1032 x = ch * BAR_WID + BAR_WID / 2;
1033 y = bar + 11 + yofs;
1034 v_eval("%s coords prog%d %d %d", CANVAS_WIN, item, x, y);
1037 static void trace_volume(int ch, int val)
1039 int item, bar, yofs, x1, y1, x2, y2;
1042 bar = Panel->multi_part ? BAR_HALF_HGT : BAR_HGT;
1046 if (!Panel->multi_part)
1050 y1 = bar - 1 + yofs;
1051 x2 = x1 + BAR_WID - 1;
1052 y2 = y1 - bar * val / 127;
1053 v_eval("%s coords bar%d %d %d %d %d", CANVAS_WIN,
1054 item, x1, y1, x2, y2);
1057 static void trace_panning(int ch, int val)
1059 int item, bar, yofs;
1063 v_eval("%s coords pos%d -1 0 -1 0 -1 0", CANVAS_WIN, ch);
1069 bar = Panel->multi_part ? BAR_HALF_HGT : BAR_HGT;
1073 if (!Panel->multi_part)
1078 ap = BAR_WID * val / 127;
1079 bp = BAR_WID - ap - 1;
1080 v_eval("%s coords pos%d %d %d %d %d %d %d", CANVAS_WIN, item,
1081 ap + x, bar + 5 + yofs,
1082 bp + x, bar + 1 + yofs,
1083 bp + x, bar + 9 + yofs);
1087 static int TraceReset(ClientData clientData, Tcl_Interp *interp,
1088 int argc, char *argv[])
1093 for (i = 0; i < 32; i++) {
1095 trace_panning(i, -1);
1098 trace_sustain(i, 0);
1099 Panel->ctotal[i] = 0;
1101 Panel->v_flags[i] = 0;
1102 Panel->c_flags[i] = 0;
1105 Panel->wait_reset = 0;
1111 #define DELTA_VEL 32
1113 static void update_notes(void)
1117 imax = Panel->multi_part ? 32 : 16;
1118 for (i = 0; i < imax; i++) {
1119 if (Panel->v_flags[i]) {
1120 if (Panel->v_flags[i] == FLAG_NOTE_OFF) {
1121 Panel->ctotal[i] -= DELTA_VEL;
1122 if (Panel->ctotal[i] <= 0) {
1123 Panel->ctotal[i] = 0;
1124 Panel->v_flags[i] = 0;
1127 Panel->v_flags[i] = 0;
1129 trace_volume(i, Panel->ctotal[i]);
1132 if (Panel->c_flags[i]) {
1133 if (Panel->c_flags[i] & FLAG_PAN)
1134 trace_panning(i, Panel->channel[i].panning);
1135 if (Panel->c_flags[i] & FLAG_BANK)
1136 trace_bank(i, Panel->channel[i].bank);
1137 if (Panel->c_flags[i] & FLAG_PROG)
1138 trace_prog(i, Panel->channel[i].program);
1139 if (Panel->c_flags[i] & FLAG_SUST)
1140 trace_sustain(i, Panel->channel[i].sustain);
1141 Panel->c_flags[i] = 0;
1148 static int TraceUpdate(ClientData clientData, Tcl_Interp *interp,
1149 int argc, char *argv[])
1151 const char *playing = v_get2("Stat", "Playing");
1152 if (playing && *playing != '0') {
1153 if (Panel->reset_panel) {
1154 v_eval("TraceReset");
1155 Panel->reset_panel = 0;
1157 if (Panel->last_time != Panel->cur_time) {
1158 v_eval("SetTime %d", Panel->cur_time);
1159 Panel->last_time = Panel->cur_time;
1161 if (ctl.trace_playing)
1164 v_eval("set Stat(TimerId) [after 50 TraceUpdate]");
1168 static void ctl_event(CtlEvent *e)
1172 case CTLE_NOW_LOADING:
1173 ctl_file_name((char*) e->v1);
1175 case CTLE_LOADING_DONE:
1177 case CTLE_PLAY_START:
1178 ctl_total_time((int) e->v1);
1184 cuepoint_pending = 1;
1188 case CTLE_METRONOME:
1190 case CTLE_CURRENT_TIME:
1191 ctl_current_time((int) e->v1, (int) e->v2);
1194 ctl_note((int) e->v1, (int) e->v2, (int) e->v3, (int) e->v4);
1196 case CTLE_MASTER_VOLUME:
1197 ctl_master_volume((int) e->v1);
1200 ctl_program((int) e->v1, (int) e->v2);
1203 ctl_volume((int) e->v1, (int) e->v2);
1205 case CTLE_EXPRESSION:
1206 ctl_expression((int) e->v1, (int) e->v2);
1209 ctl_panning((int) e->v1, (int) e->v2);
1212 ctl_sustain((int) e->v1, (int) e->v2);
1214 case CTLE_PITCH_BEND:
1215 ctl_pitch_bend((int) e->v1, (int) e->v2);
1217 case CTLE_MOD_WHEEL:
1218 ctl_pitch_bend((int) e->v1, e->v2 ? -1 : 0x2000);
1220 case CTLE_CHORUS_EFFECT:
1222 case CTLE_REVERB_EFFECT:
1225 ctl_lyric((int) e->v1);
1237 * interface_<id>_loader();
1239 ControlMode *interface_k_loader(void)