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     x_trace.c - Trace window drawing for X11 based systems
21         based on code by Yoshishige Arai <ryo2@on.rim.or.jp>
22         modified by Yair Kalvariski <cesium2@gmail.com>
23 */
24 
25 #include "x_trace.h"
26 #include <stdlib.h>
27 #include "timer.h"
28 
29 #ifdef HAVE_LIBXFT
30 #include <X11/Xft/Xft.h>
31 #endif
32 
33 enum {
34   CL_C,		/* column 0 = channel */
35   CL_VE,	/* column 1 = velocity */
36   CL_VO,	/* column 2 = volume */
37   CL_EX,	/* column 3 = expression */
38   CL_PR,	/* column 4 = program */
39   CL_PA,	/* column 5 = panning */
40   CL_PI,	/* column 6 = pitch bend */
41   CL_IN,	/* column 7 = instrument name */
42   KEYBOARD,
43   TCOLUMN,
44   CL_BA = 4,	/* column 5 = bank */
45   CL_BA_MSB,	/* column 6 = bank_lsb */
46   CL_BA_LSB,	/* column 7 = bank_msg */
47   CL_RE,	/* column 8 = reverb */
48   CL_CH,	/* column 9 = chorus */
49   KEYBOARD2,
50   T2COLUMN
51 };
52 
53 #define MAX_GRADIENT_COLUMN CL_CH+1
54 
55 typedef struct {
56   int y;
57   int l;
58 } KeyL;
59 
60 typedef struct {
61   KeyL k[3];
62   int xofs;
63   Pixel col;
64 } ThreeL;
65 
66 typedef struct {
67   const int		col;	/* column number */
68   const char		**cap;	/* caption strings array */
69   const int		*w;  	/* column width array */
70   const int		*ofs;	/* column offset array */
71 } Tplane;
72 
73 typedef struct {
74   GC gradient_gc[MAX_GRADIENT_COLUMN];
75   Pixmap gradient_pixmap[MAX_GRADIENT_COLUMN];
76   Boolean gradient_set[MAX_GRADIENT_COLUMN];
77   XColor x_boxcolor;
78   RGBInfo rgb;
79 } GradData;
80 
81 typedef struct {
82   int is_drum[MAX_TRACE_CHANNELS];
83   int8 c_flags[MAX_TRACE_CHANNELS];
84   int8 v_flags[MAX_TRACE_CHANNELS];
85   int16 cnote[MAX_TRACE_CHANNELS];
86   int16 ctotal[MAX_TRACE_CHANNELS];
87   int16 cvel[MAX_TRACE_CHANNELS];
88   int16 reverb[MAX_TRACE_CHANNELS];
89   Channel channel[MAX_TRACE_CHANNELS];
90   char *inst_name[MAX_TRACE_CHANNELS];
91 
92   unsigned int last_voice, tempo, timeratio, xaw_i_voices;
93   int pitch, poffset;
94   const char *key_cache;
95 
96   Display *disp;
97   Window trace;
98   unsigned int depth, plane, multi_part, visible_channels, voices_width;
99   Pixel barcol[MAX_TRACE_CHANNELS];
100   Pixmap layer[2];
101   GC gcs, gct, gc_xcopy;
102   Boolean g_cursor_is_in;
103   tconfig *cfg;
104   const char *title;
105   GradData *grad;
106 
107 #ifdef HAVE_LIBXFT
108   XftDraw *xft_trace, *xft_trace_foot, *xft_trace_inst;
109   XftFont *trfont, *ttfont;
110   XftColor xft_capcolor, xft_textcolor;
111   Pixmap xft_trace_foot_pixmap, xft_trace_inst_pixmap;
112 #else
113   int foot_width;
114   short title_font_ascent;
115 #endif /* HAVE_LIBXFT */
116 } PanelInfo;
117 
118 #define gcs Panel->gcs
119 #define gct Panel->gct
120 #define gc_xcopy Panel->gc_xcopy
121 #define plane Panel->plane
122 #define layer Panel->layer
123 #define gradient_gc Panel->grad->gradient_gc
124 #define gradient_pixmap Panel->grad->gradient_pixmap
125 #define gradient_set Panel->grad->gradient_set
126 #define grgb Panel->grad->rgb
127 #define x_boxcolor Panel->grad->x_boxcolor
128 
129 #ifdef HAVE_LIBXFT
130 #define trace_font	Panel->trfont
131 #define ttitle_font	Panel->ttfont
132 
133 #define COPY_PIXEL(dest, src) do { \
134   XColor _x_; \
135   _x_.pixel = src; \
136   XQueryColor(disp, DefaultColormap(disp, 0), &_x_); \
137   dest.color.red = _x_.red; dest.color.green = _x_.green; \
138   dest.color.blue = _x_.blue; dest.color.alpha = 0xffff; dest.pixel = src; \
139 } while(0)
140 
141 #ifdef X_HAVE_UTF8_STRING
142 #define TraceDrawStr(x,y,buf,len,color) do { \
143   XftColor xftcolor; \
144   COPY_PIXEL(xftcolor, color); \
145   XftDrawStringUtf8(Panel->xft_trace, &xftcolor, trace_font, \
146                     x, y, (FcChar8 *)buf, len); \
147 } while(0)
148 
149 #define TitleDrawStr(x,y,buf,len,color) do { \
150   XftColor xftcolor; \
151   COPY_PIXEL(xftcolor, color); \
152   XftDrawStringUtf8(Panel->xft_trace, &xftcolor, ttitle_font, \
153                     x, y, (FcChar8 *)buf, len); \
154 } while(0)
155 #else
156 #define TraceDrawStr(x,y,buf,len,color) do { \
157   XftColor xftcolor; \
158   COPY_PIXEL(xftcolor, color); \
159   XftDrawString8(Panel->xft_trace, &xftcolor, trace_font, \
160                  x, y, (FcChar8 *)buf, len);\
161 } while(0)
162 
163 #define TitleDrawStr(x,y,buf,len,color) do { \
164   XftColor xftcolor; \
165   COPY_PIXEL(xftcolor, color); \
166   XftDrawString8(Panel->xft_trace, &xftcolor, ttitle_font, \
167                  x, y, (FcChar8 *)buf, len); \
168 } while(0)
169 #endif /* X_HAVE_UTF8_STRING */
170 
171 #else
172 #define trace_font	Panel->cfg->c_trace_font
173 #define ttitle_font	Panel->cfg->c_title_font
174 
175 #define TraceDrawStr(x,y,buf,len,color) do { \
176   XSetForeground(disp, gct, color); \
177   XmbDrawString(disp, Panel->trace, trace_font, gct, x, y, buf, len); \
178 } while(0)
179 
180 #define TitleDrawStr(x,y,buf,len,color) do { \
181   XSetForeground(disp, gct, color); \
182   XmbDrawString(disp, Panel->trace, ttitle_font, gct, x, y, buf, len); \
183 } while(0)
184 #endif /* HAVE_LIBXFT */
185 
186 static PanelInfo *Panel;
187 static ThreeL *keyG = NULL;
188 
189 static const char *caption[TCOLUMN] =
190 {"ch", "  vel", " vol", "expr", "prog", "pan", "pit", " instrument",
191  "          keyboard"};
192 static const char *caption2[T2COLUMN] =
193 {"ch", "  vel", " vol", "expr", "bnk", "msb", "lsb", "reverb", "chorus",
194  "          keyboard"};
195 
196 static const int BARH_SPACE[TCOLUMN] = {22, 60, 40, 36, 36, 36, 30, 106, 304};
197 #define BARH_OFS0	(TRACE_HOFS)
198 #define BARH_OFS1	(BARH_OFS0+22)
199 #define BARH_OFS2	(BARH_OFS1+60)
200 #define BARH_OFS3	(BARH_OFS2+40)
201 #define BARH_OFS4	(BARH_OFS3+36)
202 #define BARH_OFS5	(BARH_OFS4+36)
203 #define BARH_OFS6	(BARH_OFS5+36)
204 #define BARH_OFS7	(BARH_OFS6+30)
205 #define BARH_OFS8	(BARH_OFS7+106)
206 static const int bar0ofs[TCOLUMN+1] = {BARH_OFS0, BARH_OFS1, BARH_OFS2, BARH_OFS3,
207   BARH_OFS4, BARH_OFS5, BARH_OFS6, BARH_OFS7, BARH_OFS8};
208 
209 static const int BARH2_SPACE[T2COLUMN] = {22, 60, 40, 36, 36, 36, 36, 50,
210                                           50, 304};
211 #define BARH2_OFS0	(TRACE_HOFS)
212 #define BARH2_OFS1	(BARH2_OFS0+22)
213 #define BARH2_OFS2	(BARH2_OFS1+60)
214 #define BARH2_OFS3	(BARH2_OFS2+40)
215 #define BARH2_OFS4	(BARH2_OFS3+36)
216 #define BARH2_OFS5	(BARH2_OFS4+36)
217 #define BARH2_OFS6	(BARH2_OFS5+36)
218 #define BARH2_OFS7	(BARH2_OFS6+36)
219 #define BARH2_OFS8	(BARH2_OFS7+50)
220 #define BARH2_OFS9	(BARH2_OFS8+50)
221 static const int bar1ofs[T2COLUMN+1] = {BARH2_OFS0, BARH2_OFS1, BARH2_OFS2, BARH2_OFS3,
222   BARH2_OFS4, BARH2_OFS5, BARH2_OFS6, BARH2_OFS7, BARH2_OFS8, BARH2_OFS9};
223 
224 static const Tplane pl[] = {
225   {TCOLUMN, caption, BARH_SPACE, bar0ofs},
226   {T2COLUMN, caption2, BARH2_SPACE, bar1ofs},
227 };
228 
229 #define KEY_NUM 111
230 #define BARSCALE2 0.31111	/* velocity scale   (60-4)/180 */
231 #define BARSCALE3 0.28125	/* volume scale     (40-4)/128 */
232 #define BARSCALE4 0.25		/* expression scale (36-4)/128 */
233 #define BARSCALE5 0.359375	/* reverb scale     (50-4)/128 */
234 
235 #define FLAG_NOTE_OFF	1
236 #define FLAG_NOTE_ON	2
237 #define FLAG_BANK	1
238 #define FLAG_PROG	2
239 #define FLAG_PROG_ON	4
240 #define FLAG_PAN	8
241 #define FLAG_SUST	16
242 #define FLAG_BENDT	32
243 
244 #define VISIBLE_CHANNELS Panel->visible_channels
245 #define VISLOW Panel->multi_part
246 #define XAWLIMIT(ch) ((VISLOW <= (ch)) && ((ch) < (VISLOW+VISIBLE_CHANNELS)))
247 
248 #define disp		Panel->disp
249 
250 #define boxcolor	Panel->cfg->box_color
251 #define capcolor	Panel->cfg->caption_color
252 #define chocolor	Panel->cfg->cho_color
253 #define expcolor	Panel->cfg->expr_color
254 #define pancolor	Panel->cfg->pan_color
255 #define playcolor	Panel->cfg->play_color
256 #define revcolor	Panel->cfg->rev_color
257 #define rimcolor	Panel->cfg->rim_color
258 #define suscolor	Panel->cfg->sus_color
259 #define textcolor	Panel->cfg->common_fgcolor
260 #define textbgcolor	Panel->cfg->text_bgcolor
261 #define tracecolor	Panel->cfg->trace_bgcolor
262 #define volcolor	Panel->cfg->volume_color
263 
264 #define gradient_bar	Panel->cfg->gradient_bar
265 #define black		Panel->cfg->black_key_color
266 #define white		Panel->cfg->white_key_color
267 
268 #define trace_height_raw	Panel->cfg->trace_height
269 #define trace_height_nf		(Panel->cfg->trace_height - TRACE_FOOT)
270 #define trace_width		Panel->cfg->trace_width
271 
272 #define UNTITLED_STR	Panel->cfg->untitled
273 /* Privates */
274 
275 static int bitcount(int);
276 static void ctl_channel_note(int, int, int);
277 static void drawBar(int, int, int, int, Pixel);
278 static void drawKeyboardAll(Drawable, GC);
279 static void draw1Note(int, int, int);
280 static void drawProg(int, int, Boolean);
281 static void drawPan(int, int, Boolean);
282 static void draw1Chan(int, int, char);
283 static void drawVol(int, int);
284 static void drawExp(int, int);
285 static void drawPitch(int, int);
286 static void drawInstname(int, char *);
287 static void drawDrumPart(int, int);
288 static void drawBank(int, int, int, int);
289 static void drawReverb(int, int);
290 static void drawChorus(int, int);
291 static void drawFoot(Boolean);
292 static void drawVoices(void);
293 static void drawMute(int, int);
294 static int getdisplayinfo(RGBInfo *);
295 static int sftcount(int *);
296 
bitcount(int d)297 static int bitcount(int d) {
298   int rt = 0;
299 
300   while ((d & 0x01) == 0x01) {
301     d >>= 1;
302     rt++;
303   }
304   return rt;
305 }
306 
sftcount(int * mask)307 static int sftcount(int *mask) {
308   int rt = 0;
309 
310   while ((*mask & 0x01) == 0) {
311     (*mask) >>= 1;
312     rt++;
313   }
314   return rt;
315 }
316 
getdisplayinfo(RGBInfo * rgb)317 static int getdisplayinfo(RGBInfo *rgb) {
318   XWindowAttributes xvi;
319   XGetWindowAttributes(disp, Panel->trace, &xvi);
320 
321   if ((rgb != NULL) && (xvi.depth >= 16)) {
322     rgb->Red_depth = (xvi.visual)->red_mask;
323     rgb->Green_depth = (xvi.visual)->green_mask;
324     rgb->Blue_depth = (xvi.visual)->blue_mask;
325     rgb->Red_sft = sftcount(&(rgb->Red_depth));
326     rgb->Green_sft = sftcount(&(rgb->Green_depth));
327     rgb->Blue_sft = sftcount(&(rgb->Blue_depth));
328     rgb->Red_depth = bitcount(rgb->Red_depth);
329     rgb->Green_depth = bitcount(rgb->Green_depth);
330     rgb->Blue_depth = bitcount(rgb->Blue_depth);
331   }
332   return xvi.depth;
333 }
334 
drawBar(int ch,int len,int xofs,int column,Pixel color)335 static void drawBar(int ch, int len, int xofs, int column, Pixel color) {
336   static Pixel column1color0 = 0;
337 
338   XGCValues gv;
339   int col, i, screen;
340   XColor x_color;
341 
342   ch -= VISLOW;
343   screen = DefaultScreen(disp);
344   if ((16 <= Panel->depth) && (gradient_bar)) {
345     gv.fill_style = FillTiled;
346     gv.fill_rule = WindingRule;
347 
348     if (column < MAX_GRADIENT_COLUMN) {
349       col = column;
350       if (column == 1) {
351         if (gradient_set[0] == 0) {
352           column1color0 = color;
353           col = 0;
354         }
355         else if ((gradient_set[1] == 0) && (column1color0 != color)) {
356           col = 1;
357         }
358         else {
359           if (column1color0 == color) col = 0;
360           else col = 1;
361         }
362       }
363       if (gradient_set[col] == 0) {
364         unsigned long pxl;
365         int r, g, b;
366 
367         gradient_pixmap[col] = XCreatePixmap(disp, Panel->trace,
368                       BARH2_SPACE[column], 1, DefaultDepth(disp, screen));
369         x_color.pixel = color;
370         XQueryColor(disp, DefaultColormap(disp, 0), &x_color);
371         for (i=0;i<BARH2_SPACE[column];i++) {
372           r = x_boxcolor.red +
373             (x_color.red - x_boxcolor.red) * i / BARH2_SPACE[column];
374           g = x_boxcolor.green +
375             (x_color.green - x_boxcolor.green) * i / BARH2_SPACE[column];
376           b = x_boxcolor.blue +
377             (x_color.blue - x_boxcolor.blue) * i / BARH2_SPACE[column];
378           if (r<0) r = 0;
379           if (g<0) g = 0;
380           if (b<0) b = 0;
381           r >>= 8;
382           g >>= 8;
383           b >>= 8;
384           if (r>255) r = 255;
385           if (g>255) g = 255;
386           if (b>255) b = 255;
387           pxl  = (r >> (8-grgb.Red_depth)) << grgb.Red_sft;
388           pxl |= (g >> (8-grgb.Green_depth)) << grgb.Green_sft;
389           pxl |= (b >> (8-grgb.Blue_depth)) << grgb.Blue_sft;
390           XSetForeground(disp, gct, pxl);
391           XDrawPoint(disp, gradient_pixmap[col], gct, i, 0);
392         }
393         gv.tile = gradient_pixmap[col];
394         gradient_gc[col] = XCreateGC(disp, Panel->trace,
395                                      GCFillStyle | GCFillRule | GCTile, &gv);
396         gradient_set[col] = 1;
397       }
398       XSetForeground(disp, gct, boxcolor);
399       XFillRectangle(disp, Panel->trace, gct,
400                      xofs+len+2, CHANNEL_HEIGHT(ch)+2,
401                      pl[plane].w[column] - len -4, BAR_HEIGHT);
402       gv.ts_x_origin = xofs + 2 - BARH2_SPACE[column] + len;
403       XChangeGC(disp, gradient_gc[col], GCTileStipXOrigin, &gv);
404       XFillRectangle(disp, Panel->trace, gradient_gc[col],
405                      xofs+2, CHANNEL_HEIGHT(ch)+2,
406                      len, BAR_HEIGHT);
407     }
408   }
409   else {
410     XSetForeground(disp, gct, boxcolor);
411     XFillRectangle(disp, Panel->trace, gct,
412                    xofs+len+2, CHANNEL_HEIGHT(ch)+2,
413                    pl[plane].w[column] - len - 4, BAR_HEIGHT);
414     XSetForeground(disp, gct, color);
415     XFillRectangle(disp, Panel->trace, gct,
416                    xofs+2, CHANNEL_HEIGHT(ch)+2,
417                    len, BAR_HEIGHT);
418   }
419 }
420 
drawProg(int ch,int val,Boolean do_clean)421 static void drawProg(int ch, int val, Boolean do_clean) {
422   char s[4];
423 
424   ch -= VISLOW;
425   if (do_clean == True) {
426     XSetForeground(disp, gct, boxcolor);
427     XFillRectangle(disp,Panel->trace,gct,
428                    pl[plane].ofs[CL_PR]+2,CHANNEL_HEIGHT(ch)+2,
429                    pl[plane].w[CL_PR]-4,BAR_HEIGHT);
430   }
431   snprintf(s, sizeof(s), "%3d", val);
432   TraceDrawStr(pl[plane].ofs[CL_PR]+5, CHANNEL_HEIGHT(ch)+BAR_HEIGHT-1,
433                s, 3, textcolor);
434 }
435 
drawPan(int ch,int val,Boolean setcolor)436 static void drawPan(int ch, int val, Boolean setcolor) {
437   int ap, bp;
438   int x;
439   XPoint pp[3];
440 
441   if (val < 0) return;
442 
443   ch -= VISLOW;
444   if (setcolor == True) {
445     XSetForeground(disp, gct, boxcolor);
446     XFillRectangle(disp, Panel->trace, gct,
447                    pl[plane].ofs[CL_PA]+2, CHANNEL_HEIGHT(ch)+2,
448                    pl[plane].w[CL_PA]-4, BAR_HEIGHT);
449     XSetForeground(disp, gct, pancolor);
450   }
451   x = pl[plane].ofs[CL_PA] + 3;
452   ap = 31 * val/127;
453   bp = 31 - ap - 1;
454   pp[0].x = ap + x; pp[0].y = 12 + BAR_SPACE*(ch+1);
455   pp[1].x = bp + x; pp[1].y = 8 + BAR_SPACE*(ch+1);
456   pp[2].x = bp + x; pp[2].y = 16 + BAR_SPACE*(ch+1);
457   XFillPolygon(disp, Panel->trace, gct, pp, 3,
458                (int)Nonconvex, (int)CoordModeOrigin);
459 }
460 
draw1Chan(int ch,int val,char cmd)461 static void draw1Chan(int ch, int val, char cmd) {
462   if ((cmd == '*') || (cmd == '&'))
463     drawBar(ch, (int)(val*BARSCALE2), pl[plane].ofs[CL_VE],
464              CL_VE, Panel->barcol[ch]);
465 }
466 
drawVol(int ch,int val)467 static void drawVol(int ch, int val) {
468   drawBar(ch, (int)(val*BARSCALE3), pl[plane].ofs[CL_VO], CL_VO, volcolor);
469 }
470 
drawExp(int ch,int val)471 static void drawExp(int ch, int val) {
472   drawBar(ch, (int)(val*BARSCALE4), pl[plane].ofs[CL_EX], CL_EX, expcolor);
473 }
474 
drawReverb(int ch,int val)475 static void drawReverb(int ch, int val) {
476   drawBar(ch, (int)(val*BARSCALE5), pl[plane].ofs[CL_RE], CL_RE, revcolor);
477 }
478 
drawChorus(int ch,int val)479 static void drawChorus(int ch, int val) {
480   drawBar(ch, (int)(val*BARSCALE5), pl[plane].ofs[CL_CH], CL_CH, chocolor);
481 }
482 
drawPitch(int ch,int val)483 static void drawPitch(int ch, int val) {
484   char *s;
485 
486   ch -= VISLOW;
487   XSetForeground(disp, gct, boxcolor);
488   XFillRectangle(disp,Panel->trace,gct,
489                  pl[plane].ofs[CL_PI]+2,CHANNEL_HEIGHT(ch)+2,
490                  pl[plane].w[CL_PI] -4,BAR_HEIGHT);
491   if (val != 0) {
492     if (val < 0) {
493       s = "=";
494     } else {
495       if (val == 0x2000) s = "*";
496       else if (val > 0x3000) s = ">>";
497       else if (val > 0x2000) s = ">";
498       else if (val > 0x1000) s = "<";
499       else s = "<<";
500     }
501     TraceDrawStr(pl[plane].ofs[CL_PI]+4, CHANNEL_HEIGHT(ch)+16, s, strlen(s),
502                  Panel->barcol[9]);
503   }
504 }
505 
drawDrumPart(int ch,int is_drum)506 static void drawDrumPart(int ch, int is_drum) {
507 
508   if (plane != 0) return;
509   if (is_drum) Panel->barcol[ch] = Panel->cfg->drumvelocity_color;
510   else         Panel->barcol[ch] = Panel->cfg->velocity_color;
511 }
512 
draw1Note(int ch,int note,int flag)513 static void draw1Note(int ch, int note, int flag) {
514   int i, j;
515   XSegment dot[3];
516 
517   j = note - 9;
518   if (j < 0) return;
519   ch -= VISLOW;
520   if (flag == '*') {
521     XSetForeground(disp, gct, playcolor);
522   } else if (flag == '&') {
523     XSetForeground(disp, gct,
524                    ((keyG[j].col == black)?suscolor:Panel->barcol[0]));
525   } else {
526     XSetForeground(disp, gct, keyG[j].col);
527   }
528   for(i=0; i<3; i++) {
529     dot[i].x1 = keyG[j].xofs + i;
530     dot[i].y1 = CHANNEL_HEIGHT(ch) + keyG[j].k[i].y;
531     dot[i].x2 = dot[i].x1;
532     dot[i].y2 = dot[i].y1 + keyG[j].k[i].l;
533   }
534   XDrawSegments(disp, Panel->trace, gct, dot, 3);
535 }
536 
ctl_channel_note(int ch,int note,int velocity)537 static void ctl_channel_note(int ch, int note, int velocity) {
538   if (velocity == 0) {
539     if (note == Panel->cnote[ch])
540       Panel->v_flags[ch] = FLAG_NOTE_OFF;
541     Panel->cvel[ch] = 0;
542   } else if (velocity > Panel->cvel[ch]) {
543     Panel->cvel[ch] = velocity;
544     Panel->cnote[ch] = note;
545     Panel->ctotal[ch] = velocity * Panel->channel[ch].volume *
546       Panel->channel[ch].expression / (127*127);
547     Panel->v_flags[ch] = FLAG_NOTE_ON;
548   }
549 }
550 
drawKeyboardAll(Drawable pix,GC gc)551 static void drawKeyboardAll(Drawable pix, GC gc) {
552   int i, j;
553   XSegment dot[3];
554 
555   XSetForeground(disp, gc, tracecolor);
556   XFillRectangle(disp, pix, gc, 0, 0, BARH_OFS8, BAR_SPACE);
557   XSetForeground(disp, gc, boxcolor);
558   XFillRectangle(disp, pix, gc, BARH_OFS8, 0,
559                  trace_width-BARH_OFS8+1, BAR_SPACE);
560   for(i=0; i<KEY_NUM; i++) {
561     XSetForeground(disp, gc, keyG[i].col);
562     for(j=0; j<3; j++) {
563       dot[j].x1 = keyG[i].xofs + j;
564       dot[j].y1 = keyG[i].k[j].y;
565       dot[j].x2 = dot[j].x1;
566       dot[j].y2 = dot[j].y1 + keyG[i].k[j].l;
567     }
568     XDrawSegments(disp, pix, gc, dot, 3);
569   }
570 }
571 
drawBank(int ch,int bank,int lsb,int msb)572 static void drawBank(int ch, int bank, int lsb, int msb) {
573   char s[4];
574 
575   ch -= VISLOW;
576   XSetForeground(disp, gct, boxcolor);
577   XFillRectangle(disp, Panel->trace, gct,
578                  pl[plane].ofs[CL_BA]+2, CHANNEL_HEIGHT(ch)+2,
579                  pl[plane].w[CL_BA]-4, BAR_HEIGHT);
580   XFillRectangle(disp, Panel->trace, gct,
581                  pl[plane].ofs[CL_BA_MSB]+2, CHANNEL_HEIGHT(ch)+2,
582                  pl[plane].w[CL_BA_MSB]-4, BAR_HEIGHT);
583   XFillRectangle(disp, Panel->trace, gct,
584                  pl[plane].ofs[CL_BA_LSB]+2, CHANNEL_HEIGHT(ch)+2,
585                  pl[plane].w[CL_BA_LSB]-4, BAR_HEIGHT);
586   snprintf(s, sizeof(s), "%3d", bank);
587   TraceDrawStr(pl[plane].ofs[CL_BA]+6, CHANNEL_HEIGHT(ch)+BAR_HEIGHT-1,
588                s, strlen(s), textcolor);
589   snprintf(s, sizeof(s), "%3d", msb);
590   TraceDrawStr(pl[plane].ofs[CL_BA_MSB]+6, CHANNEL_HEIGHT(ch)+BAR_HEIGHT-1,
591                s, strlen(s), textcolor);
592   snprintf(s, sizeof(s), "%3d", lsb);
593   TraceDrawStr(pl[plane].ofs[CL_BA_LSB]+6, CHANNEL_HEIGHT(ch)+BAR_HEIGHT-1,
594                s, strlen(s), textcolor);
595 }
596 
calcPitch(void)597 static const char * calcPitch(void)
598 {
599   int i, pitch;
600   static const char *keysig_name[] = {
601     "Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F ", "C ",
602     "G ", "D ", "A ", "E ", "B ", "F#", "C#", "G#",
603     "D#", "A#"
604   };
605 
606   pitch = Panel->pitch + ((Panel->pitch < 8) ? 7 : -6);
607   if (Panel->poffset > 0)
608     for (i = 0; i < Panel->poffset; i++)
609       pitch += (pitch > 10) ? -5 : 7;
610   else
611     for (i = 0; i < -Panel->poffset; i++)
612       pitch += (pitch < 7) ? 5 : -7;
613 
614   return keysig_name[pitch];
615 }
616 
617 #ifdef HAVE_LIBXFT
drawFoot(Boolean PitchChanged)618 static void drawFoot(Boolean PitchChanged) {
619   char *p, s[4096];
620   int l;
621 
622   if (PitchChanged) Panel->key_cache = calcPitch();
623   if (Panel->pitch < 8) p = "Maj";
624   else p = "Min";
625   l = snprintf(s, sizeof(s),
626                "Voices %3d/%d  Tempo %d/%3d%%  Key %s %s (%+03d)   %s",
627                Panel->last_voice, Panel->xaw_i_voices,
628                Panel->tempo*Panel->timeratio/100, Panel->timeratio,
629                Panel->key_cache, p, Panel->poffset, Panel->title);
630   if (l >= sizeof(s) || (l < 0)) l = sizeof(s) - 1;
631 
632  /*
633   * In the Xft path we draw to a pixmap, and then copy that to screen.
634   * Reason is to avoid "flashing" in the footer, as it tends to change often
635   * (number of voices playing fluctuates) and Xft may be too slow otherwise.
636   */
637   XFillRectangle(disp, Panel->xft_trace_foot_pixmap, gcs, 0, 0,
638                  trace_width, TRACE_FOOT-2);
639 #ifdef X_HAVE_UTF8_STRING
640   XftDrawStringUtf8(Panel->xft_trace_foot, &Panel->xft_capcolor, ttitle_font,
641                     FOOT_HOFS, ttitle_font->ascent, (FcChar8 *)s, l);
642 #else
643   XftDrawString8(Panel->xft_trace_foot, &Panel->xft_capcolor, ttitle_font,
644                  FOOT_HOFS, ttitle_font->ascent, (FcChar8 *)s, l);
645 #endif
646   XCopyArea(disp, (Drawable)Panel->xft_trace_foot_pixmap, (Drawable)Panel->trace,
647             gcs, 0, 0, trace_width, TRACE_FOOT-2, 0, trace_height_nf+2);
648 }
649 
drawVoices(void)650 static void drawVoices(void) {
651   char s[20];
652   int l;
653   XGlyphInfo extents;
654 
655   l = snprintf(s, sizeof(s), "Voices %3d/%d ",
656                Panel->last_voice, Panel->xaw_i_voices);
657   if ((l >= sizeof(s)) || (l < 0)) l = sizeof(s) - 1;
658 #ifdef X_HAVE_UTF8_STRING
659   XftTextExtentsUtf8(disp, ttitle_font, (FcChar8 *)s, l, &extents);
660 #else
661   XftTextExtents8(disp, ttitle_font, (FcChar8 *)s, l, &extents);
662 #endif
663   if (Panel->voices_width < extents.width) {
664     drawFoot(False);
665   } else {
666     XFillRectangle(disp, Panel->xft_trace_foot_pixmap, gcs, 0, 0,
667                    Panel->voices_width, TRACE_FOOT-2);
668 #ifdef X_HAVE_UTF8_STRING
669     XftDrawStringUtf8(Panel->xft_trace_foot, &Panel->xft_capcolor,
670                       ttitle_font, FOOT_HOFS, ttitle_font->ascent,
671                       (FcChar8 *)s, l);
672 #else
673     XftDrawString8(Panel->xft_trace_foot, &Panel->xft_capcolor,
674                    ttitle_font, FOOT_HOFS, ttitle_font->ascent,
675                    (FcChar8 *)s, l);
676 #endif
677     XCopyArea(disp, (Drawable)Panel->xft_trace_foot_pixmap, (Drawable)Panel->trace,
678               gcs, 0, 0, Panel->voices_width, TRACE_FOOT-2, 0, trace_height_nf+2);
679   }
680   Panel->voices_width = extents.width;
681 }
682 
drawInstname(int ch,char * name)683 static void drawInstname(int ch, char *name) {
684   int len;
685 
686   ch -= VISLOW;
687   XSetForeground(disp, gct, boxcolor);
688   XFillRectangle(disp, Panel->xft_trace_inst_pixmap, gct,
689                  0, 0, pl[plane].w[CL_IN]-4, BAR_HEIGHT);
690   len = strlen(name);
691 #ifdef X_HAVE_UTF8_STRING
692   XftDrawStringUtf8(Panel->xft_trace_inst, (Panel->is_drum[ch+VISLOW]) ?
693                     &Panel->xft_capcolor : &Panel->xft_textcolor,
694                     trace_font, 0, trace_font->ascent,
695                     (FcChar8 *)name, len);
696 #else
697   XftDrawString8(Panel->xft_trace_inst, (Panel->is_drum[ch+VISLOW]) ?
698                  &Panel->xft_capcolor : &Panel->xft_textcolor,
699                  trace_font, 0, trace_font->ascent,
700                  (FcChar8 *)name, len);
701 #endif
702   XCopyArea(disp, (Drawable)Panel->xft_trace_inst_pixmap,
703             (Drawable)Panel->trace, gct, 0, 0, pl[plane].w[CL_IN]-4,
704             BAR_HEIGHT, pl[plane].ofs[CL_IN]+2, CHANNEL_HEIGHT(ch)+2);
705 }
706 
707 #else /* HAVE_LIBXFT */
708 
drawFoot(Boolean PitchChanged)709 static void drawFoot(Boolean PitchChanged) {
710   char *p, s[4096];
711   int l, w;
712 
713   if (PitchChanged) Panel->key_cache = calcPitch();
714   if (Panel->pitch < 8) p = "Maj";
715   else p = "Min";
716 
717   l = snprintf(s, sizeof(s),
718                "Voices %3d/%d  Tempo %d/%3d%%  Key %s %s (%+03d)   %s",
719                Panel->last_voice, Panel->xaw_i_voices,
720                Panel->tempo*Panel->timeratio/100, Panel->timeratio,
721                Panel->key_cache, p, Panel->poffset, Panel->title);
722   if (l >= sizeof(s) || (l < 0)) l = sizeof(s) - 1;
723 
724   w = XmbTextEscapement(ttitle_font, s, l);
725   if (w < Panel->foot_width) {
726     XSetForeground(disp, gct, tracecolor);
727     /*
728      * w is reliable enough to detect changes in width used on screen,
729      * but can't be trusted enough to clear only w-Panel->foot_width width.
730      */
731     XFillRectangle(disp, Panel->trace, gct, 0,
732                    trace_height_nf+2, trace_width,
733                    TRACE_FOOT-2);
734     XmbDrawString(disp, Panel->trace, ttitle_font, gcs, 2,
735                   trace_height_nf+Panel->title_font_ascent, s, l);
736   } else {
737     XmbDrawImageString(disp, Panel->trace, ttitle_font, gcs, 2,
738                        trace_height_nf+Panel->title_font_ascent, s, l);
739   }
740   Panel->foot_width = w;
741 }
742 
drawVoices(void)743 static void drawVoices(void) {
744   char s[20];
745   int l, w;
746 
747   l = snprintf(s, sizeof(s), "Voices %3d/%d ",
748                Panel->last_voice, Panel->xaw_i_voices);
749   if ((l >= sizeof(s)) || (l < 0)) l = sizeof(s) - 1;
750   w = XmbTextEscapement(ttitle_font, s, l);
751   if (Panel->voices_width < w) {
752     drawFoot(False);
753   } else {
754     XmbDrawImageString(disp, Panel->trace, ttitle_font, gcs, 2,
755                        trace_height_nf+Panel->title_font_ascent, s, l);
756   }
757   Panel->voices_width = w;
758 }
759 
drawInstname(int ch,char * name)760 static void drawInstname(int ch, char *name) {
761   int len;
762 
763   if (plane != 0) return;
764   ch -= VISLOW;
765   len = strlen(name);
766   XSetForeground(disp, gct, boxcolor);
767   XFillRectangle(disp, Panel->trace, gct,
768                  pl[plane].ofs[CL_IN]+2, CHANNEL_HEIGHT(ch)+2,
769                  pl[plane].w[CL_IN]-4, BAR_HEIGHT);
770   TraceDrawStr(pl[plane].ofs[CL_IN]+4, CHANNEL_HEIGHT(ch)+15,
771                name, len, (Panel->is_drum[ch+VISLOW])?capcolor:textcolor);
772 }
773 #endif /* HAVE_LIBXFT */
774 
drawMute(int ch,int mute)775 static void drawMute(int ch, int mute) {
776   char s[16];
777 
778   if (mute != 0) {
779     SET_CHANNELMASK(channel_mute, ch);
780     if (!XAWLIMIT(ch)) return;
781     /*
782      * If we drew the number using textbgcolor, it would only look clear in
783      * the non-Xft case, since AA may prevent the exact same pixels being used.
784      */
785     XSetForeground(disp, gct, textbgcolor);
786     XFillRectangle(disp, Panel->trace, gct, pl[plane].ofs[CL_C]+2,
787                    CHANNEL_HEIGHT(ch-VISLOW)+2, pl[plane].w[CL_C]-4, BAR_HEIGHT);
788   } else {
789     UNSET_CHANNELMASK(channel_mute, ch);
790     if (!XAWLIMIT(ch)) return;
791     /* timidity internals counts from 0. timidity ui counts from 1 */
792     ch++;
793     snprintf(s, sizeof(s), "%2d", ch);
794     TraceDrawStr(pl[plane].ofs[CL_C]+2, CHANNEL_HEIGHT(ch-VISLOW)-5, s, 2, textcolor);
795   }
796 }
797 
798 /* End of privates */
799 
handleTraceinput(char * local_buf)800 int handleTraceinput(char *local_buf) {
801   char c;
802   int ch, i, n;
803 
804 #define EXTRACT_CH(s,off) do { \
805   ch = atoi(s+off); \
806   local_buf = strchr(s, CH_END_TOKEN) - off; \
807 } while(0)
808 
809   switch (local_buf[0]) {
810   case MT_NOTE:
811     {
812       int note;
813 
814       EXTRACT_CH(local_buf, 1);
815       c = *(local_buf+2);
816       note = (*(local_buf+3) - '0') * 100 + (*(local_buf+4) - '0') * 10 +
817               *(local_buf+5) - '0';
818       n = atoi(local_buf+6);
819       if ((c == '*') || (c == '&')) {
820         Panel->c_flags[ch] |= FLAG_PROG_ON;
821       } else {
822         Panel->c_flags[ch] &= ~FLAG_PROG_ON; n = 0;
823       }
824       ctl_channel_note(ch, note, n);
825       if (!XAWLIMIT(ch)) break;
826       draw1Note(ch, note, c);
827       draw1Chan(ch, Panel->ctotal[ch], c);
828     }
829     break;
830   case MT_UPDATE_TIMER:       /* update timer */
831     {
832       static double last_time = 0;
833       double d, t;
834       Bool need_flush;
835       double delta_time;
836 
837       t = get_current_calender_time();
838       d = t - last_time;
839       if (d > 1) d = 1;
840       delta_time = d / TRACE_UPDATE_TIME;
841       last_time = t;
842       need_flush = False;
843       for(i=0; i<MAX_TRACE_CHANNELS; i++)
844         if (Panel->v_flags[i] != 0) {
845           if (Panel->v_flags[i] == FLAG_NOTE_OFF) {
846             Panel->ctotal[i] -= DELTA_VEL * delta_time;
847             if (Panel->ctotal[i] <= 0) {
848               Panel->ctotal[i] = 0;
849               Panel->v_flags[i] = 0;
850             }
851             if (XAWLIMIT(i)) draw1Chan(i, Panel->ctotal[i], '*');
852             need_flush = True;
853           } else {
854             Panel->v_flags[i] = 0;
855           }
856         }
857       if (need_flush) XFlush(disp);
858     }
859     break;
860   case MT_VOICES:
861     c = *(local_buf+1);
862     n = atoi(local_buf+2);
863     if (c == MTV_TOTAL_VOICES) {
864       if (Panel->xaw_i_voices != n) {
865         Panel->xaw_i_voices = n;
866         drawVoices();
867       }
868     }
869     else
870       if (Panel->last_voice != n) {
871         Panel->last_voice = n;
872         drawVoices();
873       }
874     break;
875   case MT_REDRAW_TRACE:
876     redrawTrace(True);
877     break;
878   case MT_MUTE:
879     EXTRACT_CH(local_buf, 1);
880     n = atoi(local_buf+2);
881     drawMute(ch, n);
882     break;
883   case MT_INST_NAME:
884     EXTRACT_CH(local_buf, 1);
885     strlcpy(Panel->inst_name[ch], (char *)&local_buf[2], INST_NAME_SIZE);
886     if (!XAWLIMIT(ch)) break;
887     drawInstname(ch, Panel->inst_name[ch]);
888     break;
889   case MT_IS_DRUM:
890     EXTRACT_CH(local_buf, 1);
891     Panel->is_drum[ch] = *(local_buf+2) - 'A';
892     if (!XAWLIMIT(ch)) break;
893     drawDrumPart(ch, Panel->is_drum[ch]);
894     break;
895   case MT_PANEL_INFO:
896     c = *(local_buf+1);
897     EXTRACT_CH(local_buf, 2);
898     n = atoi(local_buf+3);
899     switch(c) {
900     case MTP_PANNING:
901       Panel->channel[ch].panning = n;
902       Panel->c_flags[ch] |= FLAG_PAN;
903       if (plane || !XAWLIMIT(ch)) break;
904       drawPan(ch, n, True);
905       break;
906     case MTP_PITCH_BEND:
907       Panel->channel[ch].pitchbend = n;
908       Panel->c_flags[ch] |= FLAG_BENDT;
909       if (plane || !XAWLIMIT(ch)) break;
910       drawPitch(ch, n);
911       break;
912     case MTP_TONEBANK:
913       Panel->channel[ch].bank = n & 0xff;
914       Panel->channel[ch].bank_lsb = (n >> 8) & 0xff;
915       Panel->channel[ch].bank_msb = (n >> 16) & 0xff;
916       if (!plane || (!XAWLIMIT(ch))) break;
917       drawBank(ch, Panel->channel[ch].bank, Panel->channel[ch].bank_lsb,
918                Panel->channel[ch].bank_msb);
919       break;
920     case MTP_REVERB:
921       Panel->reverb[ch] = n;
922       if (!plane || !XAWLIMIT(ch)) break;
923       drawReverb(ch, n);
924       break;
925     case MTP_CHORUS:
926       Panel->channel[ch].chorus_level = n;
927       if (!plane || !XAWLIMIT(ch)) break;
928       drawChorus(ch, n);
929       break;
930     case MTP_SUSTAIN:
931       Panel->channel[ch].sustain = n;
932       Panel->c_flags[ch] |= FLAG_SUST;
933       break;
934     case MTP_PROGRAM:
935       Panel->channel[ch].program = n;
936       Panel->c_flags[ch] |= FLAG_PROG;
937       if (!XAWLIMIT(ch)) break;
938       drawProg(ch, n, True);
939       break;
940     case MTP_EXPRESSION:
941       Panel->channel[ch].expression = n;
942       ctl_channel_note(ch, Panel->cnote[ch], Panel->cvel[ch]);
943       if (!XAWLIMIT(ch)) break;
944       drawExp(ch, n);
945       break;
946     case MTP_VOLUME:
947       Panel->channel[ch].volume = n;
948       ctl_channel_note(ch, Panel->cnote[ch], Panel->cvel[ch]);
949       if (!XAWLIMIT(ch)) break;
950       drawVol(ch, n);
951       break;
952     }
953     break;
954   case MT_TEMPO:
955     i = atoi(local_buf+1);
956     n = (int) (500000/ (double)i * 120 + 0.5);
957     if (Panel->tempo != n) {
958       Panel->tempo = n;
959       drawFoot(False);
960     }
961     break;
962   case MT_RATIO:
963     n = atoi(local_buf+1);
964     if (Panel->timeratio != n) {
965       Panel->timeratio = n;
966       drawFoot(False);
967     }
968     break;
969   case MT_PITCH_OFFSET:
970     n = atoi(local_buf+1);
971     if (Panel->poffset != n) {
972       Panel->poffset = n;
973       drawFoot(True);
974     }
975     break;
976   case MT_PITCH:
977     n = atoi(local_buf+1);
978     if (Panel->pitch != n) {
979       Panel->pitch = n;
980       drawFoot(True);
981     }
982     break;
983   default:
984     return -1;
985   }
986   return 0;
987 }
988 
redrawTrace(Boolean draw)989 void redrawTrace(Boolean draw) {
990   int i;
991   char s[3];
992 
993   for(i=0; i<VISIBLE_CHANNELS; i++) {
994     XGCValues gv;
995 
996     gv.tile = layer[plane];
997     gv.ts_x_origin = 0;
998     gv.ts_y_origin = CHANNEL_HEIGHT(i);
999     XChangeGC(disp, gc_xcopy, GCTile|GCTileStipXOrigin|GCTileStipYOrigin, &gv);
1000     XFillRectangle(disp, Panel->trace, gc_xcopy,
1001                    0, CHANNEL_HEIGHT(i), trace_width, BAR_SPACE);
1002   }
1003   XSetForeground(disp, gct, capcolor);
1004   XDrawLine(disp, Panel->trace, gct, BARH_OFS0, trace_height_nf,
1005             trace_width-1, trace_height_nf);
1006 
1007   for(i=VISLOW+1; i<VISLOW+VISIBLE_CHANNELS+1; i++) {
1008     snprintf(s, sizeof(s), "%2d", i);
1009     if (IS_SET_CHANNELMASK(channel_mute, i-1))
1010       TraceDrawStr(pl[plane].ofs[CL_C]+2, CHANNEL_HEIGHT(i-VISLOW)-5,
1011                    s, 2, textbgcolor);
1012     else
1013       TraceDrawStr(pl[plane].ofs[CL_C]+2, CHANNEL_HEIGHT(i-VISLOW)-5,
1014                    s, 2, textcolor);
1015   }
1016 
1017   if (Panel->g_cursor_is_in) {
1018     XSetForeground(disp, gct, capcolor);
1019     XFillRectangle(disp, Panel->trace, gct, 0, 0, trace_width, TRACE_HEADER);
1020   }
1021   redrawCaption(Panel->g_cursor_is_in);
1022 
1023   drawFoot(True);
1024   if (draw) {
1025     for(i=VISLOW; i<VISLOW+VISIBLE_CHANNELS; i++) {
1026       if ((Panel->ctotal[i] != 0) && (Panel->c_flags[i] & FLAG_PROG_ON))
1027         draw1Chan(i, Panel->ctotal[i], '*');
1028       drawProg(i, Panel->channel[i].program, False);
1029       drawVol(i, Panel->channel[i].volume);
1030       drawExp(i, Panel->channel[i].expression);
1031       if (plane) {
1032         drawBank(i, Panel->channel[i].bank, Panel->channel[i].bank_lsb,
1033                  Panel->channel[i].bank_msb);
1034         drawReverb(i, Panel->reverb[i]);
1035         drawChorus(i, Panel->channel[i].chorus_level);
1036       } else {
1037         drawPitch(i, Panel->channel[i].pitchbend);
1038         drawInstname(i, Panel->inst_name[i]);
1039       }
1040     }
1041     if (!plane) {
1042       XSetForeground(disp, gct, pancolor);
1043       for(i=VISLOW; i<VISLOW+VISIBLE_CHANNELS; i++) {
1044         if (Panel->c_flags[i] & FLAG_PAN)
1045           drawPan(i, Panel->channel[i].panning, False);
1046       }
1047       XSetForeground(disp, gct, textcolor);
1048     }
1049   }
1050 }
1051 
redrawCaption(Boolean cursor_is_in)1052 void redrawCaption(Boolean cursor_is_in) {
1053   const char *p;
1054   int i;
1055 
1056   Panel->g_cursor_is_in = cursor_is_in;
1057   if (cursor_is_in) {
1058     XSetForeground(disp, gct, capcolor);
1059     XFillRectangle(disp, Panel->trace, gct, 0, 0, trace_width, TRACE_HEADER);
1060     XSetBackground(disp, gct, expcolor);
1061     for(i=0; i<pl[plane].col; i++) {
1062       p = pl[plane].cap[i];
1063       TitleDrawStr(pl[plane].ofs[i]+4, BAR_HEIGHT, p, strlen(p), tracecolor);
1064     }
1065   } else {
1066     XSetForeground(disp, gct, tracecolor);
1067     XFillRectangle(disp, Panel->trace, gct, 0, 0, trace_width, TRACE_HEADER);
1068     XSetBackground(disp, gct, tracecolor);
1069     for(i=0; i<pl[plane].col; i++) {
1070       p = pl[plane].cap[i];
1071       TitleDrawStr(pl[plane].ofs[i]+4, BAR_HEIGHT, p, strlen(p), capcolor);
1072     }
1073   }
1074 }
1075 
initStatus(void)1076 void initStatus(void) {
1077   int i;
1078 
1079   for(i=0; i<MAX_TRACE_CHANNELS; i++) {
1080     Panel->c_flags[i] = 0;
1081     Panel->channel[i].bank = 0;
1082     Panel->channel[i].chorus_level = 0;
1083     Panel->channel[i].expression = 0;
1084     Panel->channel[i].panning = -1;
1085     Panel->channel[i].pitchbend = 0;
1086     Panel->channel[i].program = 0;
1087     Panel->channel[i].sustain = 0;
1088     Panel->channel[i].volume = 0;
1089     Panel->cnote[i] = 0;
1090     Panel->cvel[i] = 0;
1091     Panel->ctotal[i] = 0;
1092     Panel->is_drum[i] = 0;
1093     *(Panel->inst_name[i]) = '\0';
1094     Panel->reverb[i] = 0;
1095     Panel->v_flags[i] = 0;
1096   }
1097   Panel->multi_part = 0;
1098   Panel->pitch = 0;
1099   Panel->poffset = 0;
1100   Panel->tempo = 100;
1101   Panel->timeratio = 100;
1102   Panel->last_voice = 0;
1103 }
1104 
scrollTrace(int direction)1105 void scrollTrace(int direction) {
1106   if (direction > 0) {
1107     if (Panel->multi_part < (MAX_TRACE_CHANNELS - 2*VISIBLE_CHANNELS))
1108       Panel->multi_part += VISIBLE_CHANNELS;
1109     else if (Panel->multi_part < (MAX_TRACE_CHANNELS - VISIBLE_CHANNELS))
1110       Panel->multi_part = MAX_TRACE_CHANNELS - VISIBLE_CHANNELS;
1111     else
1112       Panel->multi_part = 0;
1113   } else {
1114     if (Panel->multi_part > VISIBLE_CHANNELS)
1115       Panel->multi_part -= VISIBLE_CHANNELS;
1116     else if (Panel->multi_part > 0)
1117       Panel->multi_part = 0;
1118     else
1119       Panel->multi_part = MAX_TRACE_CHANNELS - VISIBLE_CHANNELS;
1120   }
1121   redrawTrace(True);
1122 }
1123 
toggleTracePlane(Boolean draw)1124 void toggleTracePlane(Boolean draw) {
1125   plane ^= 1;
1126   redrawTrace(draw);
1127 }
1128 
getLowestVisibleChan(void)1129 int getLowestVisibleChan(void) {
1130   return Panel->multi_part;
1131 }
1132 
getVisibleChanNum(void)1133 int getVisibleChanNum(void) {
1134   return Panel->visible_channels;
1135 }
1136 
initTrace(Display * dsp,Window trace,char * title,tconfig * cfg)1137 void initTrace(Display *dsp, Window trace, char *title, tconfig *cfg) {
1138 #ifdef HAVE_LIBXFT
1139   char *font_name;
1140 #else
1141   char **ml;
1142   XFontStruct **fs_list;
1143 #endif
1144   int i, j, k, tmpi, w, screen;
1145   unsigned long gcmask;
1146   XGCValues gv;
1147 
1148   Panel = (PanelInfo *)safe_malloc(sizeof(PanelInfo));
1149   Panel->trace = trace;
1150   if (!strcmp(title, "(null)")) Panel->title = (char *)UNTITLED_STR;
1151   else Panel->title = title;
1152   Panel->cfg = cfg;
1153   plane = 0;
1154   Panel->g_cursor_is_in = False;
1155   disp = dsp;
1156   screen = DefaultScreen(disp);
1157   Panel->key_cache = "C ";
1158   if (gradient_bar) {
1159     Panel->grad = (GradData *)safe_malloc(sizeof(GradData));
1160     Panel->depth = getdisplayinfo(&Panel->grad->rgb);
1161     for (i=0; i<MAX_GRADIENT_COLUMN; i++) gradient_set[i] = 0;
1162     x_boxcolor.pixel = boxcolor;
1163     XQueryColor(disp, DefaultColormap(disp, 0), &x_boxcolor);
1164   } else {
1165     Panel->grad = NULL;
1166     Panel->depth = getdisplayinfo(NULL);
1167   }
1168 
1169   for(i=0; i<MAX_TRACE_CHANNELS; i++) {
1170     if (ISDRUMCHANNEL(i)) {
1171       Panel->is_drum[i] = 1;
1172       Panel->barcol[i] = cfg->drumvelocity_color;
1173     } else {
1174       Panel->barcol[i] = cfg->velocity_color;
1175     }
1176     Panel->inst_name[i] = (char *)safe_malloc(sizeof(char) * INST_NAME_SIZE);
1177   }
1178   initStatus();
1179   Panel->xaw_i_voices = 0;
1180   Panel->visible_channels = (cfg->trace_height - TRACE_HEADER - TRACE_FOOT) /
1181                             BAR_SPACE;
1182   if (Panel->visible_channels > MAX_CHANNELS)
1183     Panel->visible_channels = MAX_CHANNELS;
1184   else if (Panel->visible_channels < 1)
1185     Panel->visible_channels = 1;
1186   /* This prevents empty space between the trace foot and the channel bars. */
1187   cfg->trace_height = Panel->visible_channels * BAR_SPACE +
1188                       TRACE_HEADER + TRACE_FOOT;
1189 
1190   Panel->voices_width = 0;
1191 #ifdef HAVE_LIBXFT
1192   if ((XftInit(NULL) != FcTrue) || (XftInitFtLibrary() != FcTrue)) {
1193     fprintf(stderr, "Xft can't init font library!\n");
1194     exit(1);
1195   }
1196 
1197   font_name = XBaseFontNameListOfFontSet(Panel->cfg->c_title_font);
1198   ttitle_font = XftFontOpenXlfd(disp, screen, font_name);
1199   if (ttitle_font == NULL)
1200     ttitle_font = XftFontOpenName(disp, screen, font_name);
1201   if (ttitle_font == NULL) {
1202     fprintf(stderr, "can't load font %s\n", font_name);
1203     exit(1);
1204   }
1205 
1206   font_name = XBaseFontNameListOfFontSet(Panel->cfg->c_trace_font);
1207   trace_font = XftFontOpenXlfd(disp, screen, font_name);
1208   if (trace_font == NULL)
1209     trace_font = XftFontOpenName(disp, screen, font_name);
1210   if (trace_font == NULL) {
1211     fprintf(stderr, "can't load font %s\n", font_name);
1212     exit(1);
1213   }
1214 
1215   Panel->xft_trace = XftDrawCreate(disp, (Drawable)Panel->trace,
1216                                    DefaultVisual(disp, screen),
1217                                    DefaultColormap(disp, screen));
1218   Panel->xft_trace_foot_pixmap = XCreatePixmap (disp, (Drawable)Panel->trace,
1219                                                 trace_width, TRACE_FOOT-2,
1220                                                 Panel->depth);
1221   Panel->xft_trace_foot = XftDrawCreate(disp,
1222                                         (Drawable)Panel->xft_trace_foot_pixmap,
1223                                         DefaultVisual(disp, screen),
1224                                         DefaultColormap(disp, screen));
1225   Panel->xft_trace_inst_pixmap = XCreatePixmap (disp, (Drawable)Panel->trace,
1226                                                 pl[plane].w[CL_IN]-4,
1227                                                 BAR_HEIGHT, Panel->depth);
1228   Panel->xft_trace_inst = XftDrawCreate(disp,
1229                                         (Drawable)Panel->xft_trace_inst_pixmap,
1230                                         DefaultVisual(disp, screen),
1231                                         DefaultColormap(disp, screen));
1232 
1233   COPY_PIXEL (Panel->xft_capcolor, capcolor);
1234   COPY_PIXEL (Panel->xft_textcolor, textcolor);
1235 
1236   gcmask = GCForeground;
1237   gv.foreground = tracecolor;
1238   gcs = XCreateGC(disp, RootWindow(disp, screen), gcmask, &gv);
1239 #else
1240   Panel->foot_width = trace_width;
1241 
1242   j = XFontsOfFontSet(ttitle_font, &fs_list, &ml);
1243   Panel->title_font_ascent = fs_list[0]->ascent;
1244   for (i=1; i<j; i++) {
1245     if (Panel->title_font_ascent < fs_list[i]->ascent)
1246       Panel->title_font_ascent = fs_list[i]->ascent;
1247   }
1248 
1249   gcmask = GCForeground | GCBackground;
1250   gv.foreground = capcolor;
1251   gv.background = tracecolor;
1252   gv.plane_mask = 1;
1253   gcs = XCreateGC(disp, RootWindow(disp, screen), gcmask, &gv);
1254 #endif /* HAVE_LIBXFT */
1255 
1256   gv.fill_style = FillTiled;
1257   gv.fill_rule = WindingRule;
1258   gc_xcopy = XCreateGC(disp, RootWindow(disp, screen),
1259                        GCFillStyle | GCFillRule, &gv);
1260   gct = XCreateGC(disp, RootWindow(disp, screen), 0, NULL);
1261 
1262   if (keyG == NULL) keyG = (ThreeL *)safe_malloc(sizeof(ThreeL) * KEY_NUM);
1263   for(i=0, j=BARH_OFS8+1; i<KEY_NUM; i++) {
1264     tmpi = i%12;
1265     switch (tmpi) {
1266     case 0:
1267     case 5:
1268     case 10:
1269       keyG[i].k[0].y = 11; keyG[i].k[0].l = 7;
1270       keyG[i].k[1].y = 2; keyG[i].k[1].l = 16;
1271       keyG[i].k[2].y = 11; keyG[i].k[2].l = 7;
1272       keyG[i].col = white;
1273       break;
1274     case 2:
1275     case 7:
1276       keyG[i].k[0].y = 11; keyG[i].k[0].l = 7;
1277       keyG[i].k[1].y = 2; keyG[i].k[1].l = 16;
1278       keyG[i].k[2].y = 2; keyG[i].k[2].l = 16;
1279       keyG[i].col = white;
1280       break;
1281     case 3:
1282     case 8:
1283       j += 2;
1284       keyG[i].k[0].y = 2; keyG[i].k[0].l = 16;
1285       keyG[i].k[1].y = 2; keyG[i].k[1].l = 16;
1286       keyG[i].k[2].y = 11; keyG[i].k[2].l = 7;
1287       keyG[i].col = white;
1288       break;
1289     default:  /* black key */
1290       keyG[i].k[0].y = 2; keyG[i].k[0].l = 8;
1291       keyG[i].k[1].y = 2; keyG[i].k[1].l = 8;
1292       keyG[i].k[2].y = 2; keyG[i].k[2].l = 8;
1293       keyG[i].col = black;
1294       break;
1295     }
1296     keyG[i].xofs = j; j += 2;
1297   }
1298 
1299   /* draw on template pixmaps that includes one channel row */
1300   for(i=0; i<2; i++) {
1301     layer[i] = XCreatePixmap(disp, Panel->trace, trace_width, BAR_SPACE,
1302                              DefaultDepth(disp, screen));
1303     drawKeyboardAll(layer[i], gct);
1304     XSetForeground(disp, gct, capcolor);
1305     XDrawLine(disp, layer[i], gct, 0, 0, trace_width, 0);
1306     XDrawLine(disp, layer[i], gct, 0, 0, 0, BAR_SPACE);
1307     XDrawLine(disp, layer[i], gct, trace_width-1, 0, trace_width-1, BAR_SPACE);
1308 
1309     for(j=0; j < pl[i].col-1; j++) {
1310       tmpi = TRACE_HOFS; w = pl[i].w[j];
1311       for(k=0; k<j; k++) tmpi += pl[i].w[k];
1312       tmpi = pl[i].ofs[j];
1313       XSetForeground(disp, gct, capcolor);
1314       XDrawLine(disp, layer[i], gct, tmpi+w, 0, tmpi+w, BAR_SPACE);
1315       XSetForeground(disp, gct, rimcolor);
1316       XDrawLine(disp, layer[i], gct, tmpi+w-2, 2, tmpi+w-2, BAR_HEIGHT+1);
1317       XDrawLine(disp, layer[i], gct, tmpi+2, BAR_HEIGHT+2, tmpi+w-2,
1318                 BAR_HEIGHT+2);
1319       XSetForeground(disp, gct, j?boxcolor:textbgcolor);
1320       XFillRectangle(disp, layer[i], gct, tmpi+2, 2, w-4, BAR_HEIGHT);
1321     }
1322   }
1323 }
1324 
uninitTrace(void)1325 void uninitTrace(void) {
1326   int i;
1327 
1328   XFreePixmap(disp, layer[0]); XFreePixmap(disp, layer[1]);
1329 #ifdef HAVE_LIBXFT
1330   XftDrawDestroy(Panel->xft_trace);
1331   XftDrawDestroy(Panel->xft_trace_foot);
1332   XftDrawDestroy(Panel->xft_trace_inst);
1333   XFreePixmap(disp, Panel->xft_trace_foot_pixmap);
1334   XFreePixmap(disp, Panel->xft_trace_inst_pixmap);
1335   XftFontClose(disp, ttitle_font);
1336   XftFontClose(disp, trace_font);
1337 #endif
1338   if (Panel->grad != NULL) for (i=0; i<MAX_GRADIENT_COLUMN; i++) {
1339     if (gradient_set[i]) {
1340       XFreePixmap(disp, gradient_pixmap[i]);
1341       XFreeGC(disp, gradient_gc[i]);
1342     }
1343   }
1344   XFreeGC(disp, gcs); XFreeGC(disp, gct); XFreeGC(disp, gc_xcopy);
1345 
1346   for (i=0; i<MAX_TRACE_CHANNELS; i++) free(Panel->inst_name[i]);
1347   free(Panel->grad); free(Panel); free(keyG);
1348 }
1349