/* CHED -- Sunview version of "ched", MIDI Chart Editor, psl 12/85 */ #include #include #include #include #include #define PIX_INV PIX_NOT(PIX_DST) #define ROP(OX,OY,CX,CY,OP) pw_rop(Dpw,OX,OY,CX-(OX),CY-(OY),OP,0,0,0) #define ROPS(OX,OY,CX,CY,OP,S) pw_rop(Dpw,OX,OY,CX-(OX),CY-(OY),OP,S,0,0) #define TREPL(X,Y,W,H,OP,T) pw_replrop(Dpw,X,Y,W,H,OP,T,((X)&15),((Y)&15)) #define RECTOP(R,OP) ROP((R).o.x,(R).o.y,(R).c.x,(R).c.y,OP) #define RINV(OX,OY,CX,CY) pw_rop(Dpw,OX,OY,CX-(OX),CY-(OY),PIX_INV,0,0,0) #define RECTINV(R) RINV((R).o.x,(R).o.y,(R).c.x,(R).c.y) #define CPM 1000 /* CPM is Clocks Per Moment (arbitrarily a thousand clocks) */ #define MAXCHAN 16 #define MINKEY 0 #define MAXKEY 128 #define KRANGE (MAXKEY - MINKEY) #define MAXVEL 128 #define MAXBL 1024 /* maximum number of TCWMEs */ #define VOLRES 1200 /* maximum display width, pixels */ #define SBHH 16 /* scroll bar half height */ #define MAXCMINK 42 /* always show staves initially */ #define MINCMAXK 78 #define NOTEHH (Ppk >> 1) /* note half height */ #define FONTPATH "/usr/lib/fonts/fixedwidthfonts/screen.r.14" /* values for Mymouse */ #define VUMOUSE 1 #define HSMOUSE 2 #define VSMOUSE 3 #define CAMOUSE 4 /* modes for selpart() */ #define SEL 0 /* just split into selected & unselected */ #define OPEN 1 /* open selected time */ #define CLOSE 2 /* close selected time */ /* dummy file arg for selpart() */ #define NO_FILE ((char *) 0) /* chart area macros -- these depend on Ppm, Ppk, Cmint, & Cmink */ #define CAX_T(X) (1 + Cmint + (((X) - Ca.o.x) * CPM - 1) / Ppm) #define CAT_X(T) (Ca.o.x + (((T) - Cmint) * Ppm) / CPM) /****#define CAX_T(X) (Cmint + (((X) - Ca.o.x) * CPM + Ppm / 2) / Ppm) /****#define CAX_T(X) (Cmint + (((X) - Ca.o.x) * CPM) / Ppm) /****#define CAT_X(T) (Ca.o.x + (((T) - Cmint) * Ppm + CPM / 2) / CPM) /****/ #define CAK_Y(K) (Ca.c.y - ((K) - Cmink) * Ppk) #define CAK_YA(K) (CAK_Y(K) - Ppk + 1) #define CAK_YB(K) (CAK_Y(K) + Ppk - 1) #define CAY_K(Y) (Cmink + (Ca.c.y - (Y) + NOTEHH) / Ppk) #define CAY_KA(Y) (CAY_K(Y) + 1) #define CAY_KB(Y) (CAY_K(Y) - 1) /* horizontal scroll area macros */ #define HSAX_T(X) (1 + Mint + (((X) - Hsa.o.x) * Ranget - 1) / Hspix) #define HSAT_X(T) (Hsa.o.x + (((T) - Mint) * Hspix) / Ranget) #define HSAK_Y(K) (Hsa.o.y + ((MAXKEY - (K)) * 2 * SBHH - 1) / MAXKEY) #define VOLT_I(T) (((T) * Hspix) / Ranget) /* vertical scroll area macros */ #define VSAY_K(Y) (1 + (((Vsa.c.y - (Y)) * KRANGE - 1) / Vspix)) #define VSAK_Y(K) (Vsa.c.y - ((K) * Vspix) / KRANGE) typedef struct point { int x, y; } Point; typedef struct recta { Point o, c; } Recta; char Oldfile[128]; /* where the data comes from for "read" */ char Newfile[128]; /* where the data goes for "write" */ char Workfile[128]; /* where it lives while we work */ char Flbuf[128]; /* frame label buffer */ char *Selfile = "/tmp/chedsel"; /* where the selected piece goes */ char *Playfile = "/tmp/chedplay"; /* where stuff to be played goes */ char *Playcmd = "/usr/psl/MIDI/bin/play"; char *Mergecmd = "/usr/psl/MIDI/bin/merge"; char *Tshiftcmd = "/usr/psl/MIDI/bin/tshift"; int Debug = 0; /* for extra debugging output */ int Dirty = 0; /* changed but unwritten */ int Tgrid = 0; /* grid ticks per bar */ int Mymouse = 0; /* who "owns" the mouse at the moment */ int Veldisp = 0; /* 1=> show velocities, 0=> don't */ int Garbsel = 2; /* 0=>none, 1=>sel, 2=>unsel, 3=>both */ int Barlen = 480; /* MIDI clocks per bar, 0=> use TCWMEs */ int Baroff = -2; /* set to first TCWME (% Barlen) by process() */ int Tempo = 100; /* basis for play -t argument */ int Margin = 10; /* guaranteed empty space around score */ int Ppm; /* pixels per moment (see CPM def) */ int Ppk; /* pixels per note (vertically) */ int Vuwidth; /* spacing for VU meters */ int Playpid = 0; /* >0 ==> something is playing */ int Mink, Maxk; /* min and max+1 key values in input */ int Rangek; /* range of key values in input */ int Cmink, Cmaxk; /* min and max+1 key values to display */ int Crangek; /* range of key values to display */ int Smink, Smaxk; /* min and max+1 key values in selection */ int Skmin, Skmax; /* min and max+1 possible keys in Sel */ int Hspix; /* width of Hsa, pixels */ int Vspix; /* height of Vsa, pixels */ long Mint, Maxt; /* min and max+1 times in input */ long Ranget; /* range of time in input */ long Cmint, Cmaxt; /* min and max+1 times to display */ long Cranget; /* range of time to display */ long Smint, Smaxt; /* min and max+1 times in selection */ long Stmin, Stmax; /* min and max+1 possible times in Sel */ FILE *Tfp; /* slightly preprocessed data */ Recta Da; /* entire drawing area (minus Margin) */ Recta Va; /* VU area */ Recta Ca; /* chart area */ Recta Hsa; /* horizontal scroll area */ Recta Vsa; /* vertical scroll area */ Recta Sel; /* selected area */ Point Csize; /* max width & height of Ca, pixels */ Pixrect *Ltgrey; /* light grey texture */ Pixrect *Grey; /* grey texture */ Pixrect *Dkgrey; /* dark grey texture */ Frame Dframe; /* whole display's frame */ Canvas Dcanvas; /* whole display's canvas */ Pixwin *Dpw = 0; /* whole display pixwin */ Pixfont *Fontp; /* the font we use (almost everywhere) */ int Fontwidth; /* the width of chars in *Fontp */ Panel Controls; /* control panel */ int Cntlshow = FALSE; /* whether to show control panel */ Panel_item Bslide; /* id for clocks/bar slider */ Panel_item Oslide; /* id for offset slider */ Panel_item Gslide; /* id for ticks/bar slider */ Panel_item Tslide; /* id for tempo slider */ Panel_item Mchoic; /* id for vmode choice */ Panel_item Gchoic; /* id for gmode choice */ short Ltgrey_bits[] = { 0x0000, 0x5555, 0x0000, 0xAAAA, 0x0000, 0x5555, 0x0000, 0xAAAA, 0x0000, 0x5555, 0x0000, 0xAAAA, 0x0000, 0x5555, 0x0000, 0xAAAA, }; short Grey_bits[] = { 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, }; short Dkgrey_bits[] = { 0xFFFF, 0x5555, 0xFFFF, 0xAAAA, 0xFFFF, 0x5555, 0xFFFF, 0xAAAA, 0xFFFF, 0x5555, 0xFFFF, 0xAAAA, 0xFFFF, 0x5555, 0xFFFF, 0xAAAA, }; #define C_OFF 0x0000 /* channel is off */ #define C_ON 0x0001 /* channel is on (play & display) */ #define C_GREY 0x0002 /* channel gets highlight (display in grey) */ int Tclefk[] = { 77, 74, 71, 67, 64, }; int Bclefk[] = { 43, 47, 50, 53, 57, }; int Chans[MAXCHAN]; int Key[MAXCHAN][MAXKEY]; int Vel[MAXCHAN][MAXKEY]; int Vol[VOLRES]; /* key velocities (volumes) */ int Kiu[MAXKEY]; /* keys in use (in current data) */ int Barline[MAXBL]; /* where the TCWMEs are */ int Nbl = 0; /* index into MAXBL */ /* Button 2 menu - operations on the selected area */ Menu B2mp; #define PLAY2 1 #define BBOX2 2 #define CUT2 3 #define PASTE2 4 #define GLOM2 5 #define FILTER2 6 #define IPROC2 7 #define INFO2 8 #define ZOOMI2 9 #define ZOOMO2 10 #define WRITE2 11 #define OPEN2 12 #define CLOSE2 13 #define B2MINIT() B2mp = menu_create( \ MENU_INITIAL_SELECTION, MENU_SELECTED, \ MENU_INITIAL_SELECTION_SELECTED, TRUE, \ MENU_STRINGS, \ "PLAY", \ "BBOX", \ "CUT", \ "PASTE", \ "GLOM", \ "FILTER", \ "IPROC", \ "INFO", \ "ZOOM IN", \ "ZOOM OUT", \ "WRITE", \ "OPEN", \ "CLOSE", \ 0, 0) /* Button 2 menu - used when the selected area is empty */ Menu B2emp; #define B2EMINIT() B2emp = menu_create(MENU_STRINGS, \ "No area selected.", \ "Sweep an area with button 1", \ 0, 0) /* Button 3 menu - operations on the entire file */ Menu B3mp; #define PLAY3 1 #define CNTRLS3 2 #define FILTER3 3 #define IPROC3 4 #define READ3 5 #define WRITE3 6 #define QUIT3 7 #define B3MINIT() B3mp = menu_create( \ MENU_INITIAL_SELECTION, MENU_SELECTED, \ MENU_INITIAL_SELECTION_SELECTED, TRUE, \ MENU_STRINGS, \ "PLAY", \ "CONTROLS", \ "FILTER", \ "IPROC", \ "READ", \ "WRITE", \ "QUIT", \ 0, 0) /* Button 3 menu for scroll areas */ Menu B3emp; #define B3EMINIT() B3emp = menu_create(MENU_STRINGS, \ "Use button 1 to sweep a range.", \ "Use button 2 to move the range.", \ 0, 0) static short Chedicon_bits[] = { /* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16 */ 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x8000,0x0000,0x0000,0x0001, 0x8000,0x0000,0x0000,0x0001,0x87FF,0xFFFF,0xFFFF,0xFFC1, 0x8400,0x0000,0x0000,0x0041,0x84EE,0xEEEE,0xEEEE,0xEE41, 0x84EE,0xEEEE,0xEEEE,0xEE41,0x84EE,0xEEEE,0xEEEE,0xEE41, 0x8400,0x0000,0x0000,0x0041,0x87FF,0xFFFF,0xFFFF,0xFFC1, 0x8000,0x0000,0x0000,0x0001,0x8000,0x0000,0x0000,0x0001, 0x8000,0x0000,0x0000,0x0001,0x8000,0x0000,0x0000,0x0001, 0x8000,0x0000,0x0040,0x0001,0x8000,0x0000,0x0040,0x0001, 0x9FFF,0xFFFF,0xFFFF,0xFFF9,0x9401,0x0000,0x2040,0x0011, 0x9401,0x0000,0x2040,0x0011,0x9401,0x0002,0x2040,0x0011, 0x9401,0x0002,0x2040,0x0011,0x9401,0x0002,0x2040,0x0011, 0x9FFF,0xFFFF,0xFFFF,0xFFF9,0x9401,0x0002,0x23C0,0x0011, 0x9401,0x0002,0x26C0,0x0011,0x9401,0x0202,0x2440,0x0011, 0x940F,0x0202,0x26C1,0xF811,0x941F,0x0202,0x23C1,0xF811, 0x9FFF,0xFFFF,0xFFFF,0xFFF9,0x941F,0x021E,0x2040,0x0011, 0x940E,0x023E,0x2040,0x0011,0x9400,0x023E,0x2040,0x0011, 0x9400,0x023E,0x23C0,0x0011,0x9400,0x021C,0x26C0,0x0011, 0x9FFF,0xFFFF,0xFFFF,0xFFF9,0x9400,0x1E00,0x26C0,0x0011, 0x9400,0x3600,0x23C0,0x0011,0x9400,0x2200,0x2040,0x0011, 0x9400,0x3600,0x23C0,0x0011,0x9400,0x1C00,0x26C0,0x0011, 0x9FFF,0xFFFF,0xFFFF,0xFFF9,0x8000,0x0000,0x06C0,0x0001, 0x8000,0x0000,0x0380,0x0001,0x8000,0x0000,0x0000,0x0001, 0xAAAA,0xAAAA,0xAAAA,0xAAA9,0x9555,0x5555,0x5555,0x5555, 0xAAAA,0xAAAA,0xAAAA,0xAAA9,0x9555,0x5555,0x5555,0x5555, 0xAAAA,0x8288,0x8082,0xAAA9,0x9555,0x1111,0x1511,0x5555, 0xAAAA,0x8888,0x8A88,0xAAA9,0x9555,0x1511,0x1511,0x5555, 0xAAAA,0x8A80,0x8288,0xAAA9,0x9555,0x1511,0x1511,0x5555, 0xAAAA,0x8888,0x8A88,0xAAA9,0x9555,0x1111,0x1511,0x5555, 0xAAAA,0x8288,0x8082,0xAAA9,0x9555,0x5555,0x5555,0x5555, 0xAAAA,0xAAAA,0xAAAA,0xAAA9,0x9555,0x5555,0x5555,0x5555, 0xAAAA,0xAAAA,0xAAAA,0xAAA9,0x9555,0x5555,0x5555,0x5555, 0x8000,0x0000,0x0000,0x0001,0xFFFF,0xFFFF,0xFFFF,0xFFFF }; DEFINE_ICON_FROM_IMAGE(Chedicon, Chedicon_bits); static short Vuoff_bits[] = { 0xffff, 0xffff, 0xd557, 0xebeb, 0xdd77, 0xfaab, 0xfd5f, 0xeeab, 0xd757, 0xebab, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, }; static short Vuon_bits[] = { 0xffff, 0xffff, 0xc003, 0xc3c3, 0xcc33, 0xd00b, 0xe017, 0xc023, 0xc043, 0xc183, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, }; static short Vugoff_bits[] = { 0xffff, 0xffff, 0xd557, 0xebeb, 0xdd77, 0xfaab, 0xfd5f, 0xeeab, 0xd757, 0xffff, 0xd113, 0xc447, 0xd113, 0xc447, 0xd113, 0xffff, }; static short Vugon_bits[] = { 0xffff, 0xffff, 0xc003, 0xc3c3, 0xcc33, 0xd00b, 0xe017, 0xc023, 0xc043, 0xffff, 0xd113, 0xc447, 0xd113, 0xc447, 0xd113, 0xffff, }; mpr_static(Vuoff_pr, 16, 16, 1, Vuoff_bits); mpr_static(Vuon_pr, 16, 16, 1, Vuon_bits); mpr_static(Vugoff_pr, 16, 16, 1, Vugoff_bits); mpr_static(Vugon_pr, 16, 16, 1, Vugon_bits); Pixrect *Vupr[] = { &Vuoff_pr, &Vuon_pr, &Vugoff_pr, &Vugon_pr, }; main(argc, argv) char *argv[]; { int barspec; extern FILE *sopen(); /****/setbuf(stderr, 0); barspec = 0; while (--argc > 0) { if (argv[argc][0] == '-') { switch (argv[argc][1]) { case 'B': Barlen = atoi(&argv[argc][2]); break; case 'b': barspec = atoi(&argv[argc][2]); break; case 'd': Debug++; break; case 'm': Margin = atoi(&argv[argc][2]); break; case 't': Tgrid = atoi(&argv[argc][2]); break; default: goto syntax; } } else if (*Oldfile == 0) sprintf(Oldfile, "%s", argv[argc]); else { syntax: fprintf(stderr, "Usage: %s [options] [file]\n", argv[0]); fprintf(stderr, "-B120\tSet bar length to 120 MPU clocks\n"); fprintf(stderr, "-b12\tShow the first 12 bars\n"); fprintf(stderr, "-d\tTurn Debug on\n"); fprintf(stderr, "-m20\tProvide a 20 pixel margin\n"); fprintf(stderr, "-t4\tSet ticks/bar to 4\n"); exit(2); } } if (initfile(Oldfile) == 0) { /* no file read */ Mint = 0; if (Barlen) Maxt = 2 * Barlen; else Maxt = 4 * MPU_CLOCK_PERIOD; Mink = MAXCMINK; Maxk = MINCMAXK; Tfp = 0; } Cmink = min(Mink - 2, MAXCMINK); Cmaxk = max(Maxk + 9, MINCMAXK); Cmint = Mint; Cmaxt = Maxt; if (barspec > 0) { if (Barlen) Cmaxt = Cmint + barspec * Barlen + 1; else if (Nbl >= barspec) Cmaxt = Barline[barspec] + 1; } if (!(Fontp = pf_open(FONTPATH))) Fontp = pf_default(); Fontwidth = Fontp->pf_defaultsize.x; miscinits(); window_main_loop(Dframe); unlink(Workfile); exit(0); } miscinits() /* one-time SunView inits */ { Rect tmp; void resized(), input(); B2MINIT(); B2EMINIT(); B3MINIT(); B3EMINIT(); tmp.r_left = 8; tmp.r_top = 64; tmp.r_width = 1136; /* max width - 16 */ tmp.r_height = 660; /* max height - 240 */ sprintf(Flbuf, "-=[ CHED ]=- src:%s dst:%s", Oldfile, Newfile); Dframe = window_create(NULL, FRAME, FRAME_LABEL, Flbuf, FRAME_ICON, &Chedicon, WIN_FONT, Fontp, FRAME_OPEN_RECT, &tmp, 0); Dcanvas = window_create(Dframe, CANVAS, CANVAS_FIXED_IMAGE, FALSE, CANVAS_RESIZE_PROC, resized, 0); window_set(Dcanvas, WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS, LOC_WINENTER, LOC_WINEXIT, LOC_MOVE, WIN_MOUSE_BUTTONS, 0, 0); /* set the canvas defaults */ /* set non-defaults that we need */ window_set(Dcanvas, WIN_CONSUME_KBD_EVENTS, WIN_ASCII_EVENTS, 0, 0); window_set(Dcanvas, WIN_CONSUME_PICK_EVENTS, LOC_DRAG, 0, 0); window_set(Dcanvas, WIN_EVENT_PROC, input, 0); Dpw = canvas_pixwin(Dcanvas); Ltgrey = mem_point(16, 16, 1, Ltgrey_bits); Grey = mem_point(16, 16, 1, Grey_bits); Dkgrey = mem_point(16, 16, 1, Dkgrey_bits); gencntl(); } gencntl() /* generate control panel; called also to re-generate */ { int swidth, i; void cntlchng(); if (Controls) { window_destroy(Controls); Controls = 0; } i = (int) window_get(Dframe, WIN_WIDTH); if (i > 400) swidth = (i - 375) | 1; else swidth = i / 10; Controls = window_create(Dframe, PANEL, WIN_X, 0, WIN_Y, 0, WIN_WIDTH, WIN_EXTEND_TO_EDGE, WIN_SHOW, Cntlshow, WIN_FONT, Fontp, PANEL_SHOW_MENU, FALSE, PANEL_LABEL_BOLD, TRUE, PANEL_ITEM_X_GAP, 25, 0); i = max(0, Barlen - swidth / 2); Bslide = panel_create_item(Controls, PANEL_SLIDER, PANEL_LABEL_STRING, "CLOX/BAR", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Barlen, PANEL_MIN_VALUE, i, PANEL_MAX_VALUE, i + swidth - 1, PANEL_NOTIFY_PROC, cntlchng, 0); if (Barlen > 0) { Oslide = panel_create_item(Controls, PANEL_SLIDER, PANEL_LABEL_STRING, " OFFSET", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Baroff, PANEL_MIN_VALUE, -1, PANEL_MAX_VALUE, Barlen - 1, PANEL_NOTIFY_PROC, cntlchng, 0); Gslide = panel_create_item(Controls, PANEL_SLIDER, PANEL_LABEL_STRING, "TICKS/BAR ", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Tgrid, PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, 32, PANEL_NOTIFY_PROC, cntlchng, 0); } Tslide = panel_create_item(Controls, PANEL_SLIDER, PANEL_LABEL_STRING, " TEMPO", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Tempo, PANEL_MIN_VALUE, 10, PANEL_MAX_VALUE, 250, PANEL_NOTIFY_PROC, cntlchng, 0); Gchoic = panel_create_item(Controls, PANEL_CHOICE, PANEL_LABEL_STRING, "GMODE", PANEL_LAYOUT, PANEL_VERTICAL, PANEL_ITEM_Y, 4, PANEL_CHOICE_YS, 24, 40, 56, 72, 0, PANEL_MARK_YS, 20, 36, 52, 68, 0, PANEL_CHOICE_STRINGS, "NONE", "SEL", "UNSEL", "BOTH", 0, PANEL_VALUE, Garbsel, PANEL_NOTIFY_PROC, cntlchng, 0); Mchoic = panel_create_item(Controls, PANEL_CHOICE, PANEL_LABEL_STRING, "VMODE", PANEL_LAYOUT, PANEL_VERTICAL, PANEL_ITEM_Y, 4, PANEL_CHOICE_YS, 24, 44, 0, PANEL_MARK_YS, 20, 40, 0, PANEL_CHOICE_STRINGS, "OFF", "ON", 0, PANEL_VALUE, Veldisp, PANEL_NOTIFY_PROC, cntlchng, 0); window_fit_height(Controls); if (Cntlshow) { /* I don't know why this should be necessary */ window_set(Controls, WIN_SHOW, 0, 0); window_set(Controls, WIN_SHOW, Cntlshow, 0); } } void cntlchng(item, value, event) Panel_item item; Event *event; { register int change; change = 0; if (item == Bslide) { if (Barlen != value) { Barlen = value; gencntl(); change++; } } else if (item == Oslide) { if (Baroff != value) { Baroff = value; change++; } } else if (item == Gslide) { if (Tgrid != value) { Tgrid = value; change++; } } else if (item == Tslide) { Tempo = value; } else if (item == Mchoic) { if (Veldisp != value) { Veldisp = value; change++; } } else if (item == Gchoic) Garbsel = value; if (change) redraw(); } void input(window, event, arg) Window window; Event *event; { register int i; i = event_id(event); if (i == MS_LEFT || i == MS_MIDDLE || i == MS_RIGHT || i == LOC_DRAG) mousing(window, event); } initfile(oldfile) char oldfile[]; { int i; FILE *ifp; if (*oldfile) { if ((ifp = sopen(oldfile, "r")) == NULL) { perror(oldfile); return(0); } if (*Newfile == '\0') sprintf(Newfile, "%s.new", oldfile); } else { ifp = stdin; sprintf(Oldfile, "stdin"); if (*Newfile == '\0') sprintf(Newfile, "ched.new"); } sprintf(Flbuf, "-=[ CHED ]=- src:%s dst:%s", Oldfile, Newfile); window_set(Dframe, FRAME_LABEL, Flbuf, 0); sprintf(Workfile, "/tmp/ched%d", getpid()); if ((Tfp = fopen(Workfile, "w")) == (FILE *) NULL) { perror(Workfile); exit(1); } for (i = MAXCHAN; --i >= 0; Chans[i] = C_OFF); copyfile(ifp, Tfp); if (ifp != stdin) fclose(ifp); fclose(Tfp); if ((Tfp = fopen(Workfile, "r")) == (FILE *) NULL) { perror(Workfile); exit(1); } Sel.o.x = Sel.o.y = Sel.c.x = Sel.c.y = 0; Stmin = Stmax = 0; Skmin = Skmax = 0; Baroff = -2; return(1); } copyfile(ifp, ofp) FILE *ifp, *ofp; { register int status, mode, chan; long now; MCMD *mp; Maxk = 0; Mink = 99999; Mint = 0; putmcmd((FILE *) 0, (MCMD *) 0); for (now = 0L; mp = getmcmd(ifp, now); now = putmcmd(ofp, mp)) { status = *mp->cmd; mode = (status & M_CMD_MASK); chan = (status & M_CHAN_MASK); if (mode == CH_KEY_ON || mode == CH_KEY_OFF) { if (mode == CH_KEY_OFF) { /* turn key_off into key_on */ mp->cmd[0] = CH_KEY_ON | chan; mp->cmd[2] = 0; } else if (mp->cmd[2] != 0) { Chans[chan] = C_ON; if (mp->cmd[1] < Mink) Mink = mp->cmd[1]; if (mp->cmd[1] >= Maxk) Maxk = mp->cmd[1] + 1; } } } Maxt = now + 1; Ranget = Maxt - Mint; Rangek = Maxk - Mink; } process(ifp) /* set Baroff to -2 to look for first TCWME */ FILE *ifp; { register int k, v, status, mode; int i, chan, chanmode; long now, start[MAXCHAN][MAXKEY]; MCMD *mp; if (Dpw) pw_batch_on(Dpw); for (i = sizeof Vol / sizeof Vol[0]; --i >= 0; Vol[i] = 0); for (i = sizeof Kiu / sizeof Kiu[0]; --i >= 0; Kiu[i] = 0); for (chan = 0; chan < MAXCHAN; chan++) if (Chans[chan] & C_ON) for (k = Mink; k < Maxk; k++) Key[chan][k] = 0; ROP(Hsa.o.x-1, Hsa.o.y-1, Hsa.c.x+1, Hsa.c.y+1, PIX_SET); ROP(Hsa.o.x+1, Hsa.o.y+1, Hsa.c.x-1, Hsa.c.y-1, PIX_CLR); Nbl = 0; for (now = 0L; mp = getmcmd(ifp, now); ) { now = mp->when; status = mp->cmd[0]; if (status == RT_TCWME) { Barline[Nbl++] = now; if (Baroff == -2) Baroff = now; } mode = (status & M_CMD_MASK); if (mode != CH_KEY_ON) continue; chan = status & M_CHAN_MASK; if (((chanmode = Chans[chan]) & C_ON) == 0) continue; k = mp->cmd[1]; v = mp->cmd[2]; if (v == 0) { /* key-off */ --Key[chan][k]; if (Key[chan][k] < 0) { /* extra note-off */ Key[chan][k] = 0; continue; } if (Key[chan][k] == 0) { /* end of note */ plotnote(start[chan][k], k, now, Vel[chan][k], chanmode); addvol(start[chan][k], now, Vel[chan][k]); } } else { /* key-on */ if (Key[chan][k] != 0) { plotnote(start[chan][k], k, now, Vel[chan][k], chanmode); addvol(start[chan][k], now, Vel[chan][k]); } start[chan][k] = now; Vel[chan][k] = v; Key[chan][k]++; } } for (chan = 0; chan < MAXCHAN; chan++) { /* check notes left on */ if (Chans[chan] & C_ON) { for (k = Cmink; k < Cmaxk; k++) { if (Key[chan][k]) { plotnote(start[chan][k], k, now, Vel[chan][k], chanmode); addvol(start[chan][k], now, Vel[chan][k]); } } } } if (Dpw) pw_batch_off(Dpw); /* for deferred update */ if (Baroff == -2) /* no TCWME found */ Baroff = 0; else if (Barlen > 0) Baroff %= Barlen; } plotnote(bt, k, et, v, chanmode) long bt, et; { int bx, ex, y, dy; if (!Veldisp && (chanmode & C_ON)) { /* draw Hor scrollbar data */ bx = HSAT_X(bt); ex = HSAT_X(et); if (ex == bx) ex++; y = HSAK_Y(k); pw_vector(Dpw, bx, y, ex, y, PIX_SET, 1); } Kiu[k]++; if (et < Mint || Maxt <= bt || k < Mink || Maxk <= k) return; bx = CAT_X(bt); if (bx < Ca.c.x) { bx = max(bx, Ca.o.x); ex = CAT_X(et); if (ex >= Ca.o.x) { if (ex == bx) ex++; y = CAK_Y(k); dy = Veldisp? (v * NOTEHH) / MAXVEL : NOTEHH; if (dy <= 0) dy = 1; if (Ca.o.y < (y + dy) && (y + dy) < Ca.c.y) { y -= dy; if (chanmode & C_GREY) TREPL(bx, y, ex - bx, 2 * dy, PIX_SRC, Grey); else ROP(bx, y, ex, y + 2 * dy, PIX_SET); } } } } addvol(bt, et, v) long bt, et; register int v; { register int i, ei; i = VOLT_I(bt); ei = VOLT_I(et); if (ei == i) ei++; for (; i < ei; i++) { Vol[i] += v; v = (36 * v + 18) / 37; } } drawhs() /* display horiz. scroll area */ { register int i, x, y, dy, maxvol; long t; if (Veldisp) { /* if !Veldisp, data drawn in plotnote() */ maxvol = 0; for (i = 0; i < Hspix; i++) if (Vol[i] > maxvol) maxvol = Vol[i]; maxvol++; y = (Hsa.o.y + Hsa.c.y) >> 1; for (i = 0; i < Hspix; i++) { x = Hsa.o.x + i; dy = (Vol[i] * SBHH) / maxvol; pw_vector(Dpw, x, y + dy, x, y - dy, PIX_INV, 1); } } dy = SBHH / 3; if (Barlen) { /* bar line ticks */ for (t = Baroff + Barlen; t < Maxt; t += Barlen) { x = HSAT_X(t); pw_vector(Dpw, x, Hsa.o.y, x, Hsa.o.y + dy, PIX_INV, 1); pw_vector(Dpw, x, Hsa.c.y, x, Hsa.c.y - dy, PIX_INV, 1); } } else { for (i = 0; i < Nbl; i++) { x = HSAT_X(Barline[i]); pw_vector(Dpw, x, Hsa.o.y, x, Hsa.o.y + dy, PIX_INV, 1); pw_vector(Dpw, x, Hsa.c.y, x, Hsa.c.y - dy, PIX_INV, 1); } } fliphs(); } Recta hsrect() { Recta q; q.o.x = HSAT_X(Cmint); q.o.y = Hsa.o.y; q.c.x = HSAT_X(Cmaxt); q.c.y = Hsa.c.y; return(q); } fliphs() { Recta q; q = hsrect(); RECTINV(q); } drawvs() /* display vert. scroll area */ { register int i, x, y, dx, dy; ROP(Vsa.o.x-1, Vsa.o.y-1, Vsa.c.x+1, Vsa.c.y+1, PIX_SET); ROP(Vsa.o.x+1, Vsa.o.y+1, Vsa.c.x-1, Vsa.c.y-1, PIX_CLR); for (i = 5; --i >= 0; ) { /* horizontal staff lines */ y = VSAK_Y(Tclefk[i]); pw_vector(Dpw, Vsa.o.x, y, Vsa.c.x, y, PIX_INV, 1); y = VSAK_Y(Bclefk[i]); pw_vector(Dpw, Vsa.o.x, y, Vsa.c.x, y, PIX_INV, 1); } x = (Vsa.o.x + Vsa.c.x) / 2; dx = (Vsa.c.x - Vsa.o.x) / 6; dy = (VSAK_Y(0) - VSAK_Y(1)) / 2; for (i = sizeof Kiu / sizeof Kiu[0]; --i >= 0; ) { if (Kiu[i]) { y = VSAK_Y(i); ROP(x - dx, y - dy, x + dx, y + dy, PIX_SET); } } flipvs(); } Recta vsrect() /* generate vertical scroll rectangle */ { Recta q; q.o.x = Vsa.o.x; q.o.y = VSAK_Y(Cmaxk-1)+1; q.c.x = Vsa.c.x; q.c.y = VSAK_Y(Cmink); return(q); } flipvs() { Recta q; q = vsrect(); RECTINV(q); } mousing(window, event) Window window; Event *event; { register int change; if (Mymouse == VUMOUSE /* cursor in VU meter area */ || (Mymouse == 0 && einr(event, Va))) { change = vamouse(window, event); } else if (Mymouse == HSMOUSE /* cursor in horizontal scroll area */ || (Mymouse == 0 && einr(event, Hsa))) { Mymouse = HSMOUSE; change = hsamouse(window, event); } else if (Mymouse == VSMOUSE /* cursor in vertical scroll area */ || (Mymouse == 0 && einr(event, Vsa))) { Mymouse = VSMOUSE; change = vsamouse(window, event); } else if (Mymouse == CAMOUSE /* cursor in chart area */ || Mymouse == 0) { Mymouse = CAMOUSE; change = camouse(window, event); } if (change) redraw(); } einr(e, r) /* true if event e is in rectangle r */ Event *e; Recta r; { register int x, y; x = e->ie_locx; y = e->ie_locy; return (r.o.x <= x && x <= r.c.x && r.o.y <= y && y <= r.c.y); } vamouse(window, event) Window window; Event *event; { register int i, code; if (Mymouse) { if (event_is_up(event)) /* we've already done it */ Mymouse = 0; /* give up the mouse */ } else { /* state changes when button is first pushed */ Mymouse = VUMOUSE; code = event_id(event); if (code != MS_LEFT && code != MS_MIDDLE) return(0); i = (event->ie_locx - Va.o.x) / Vuwidth; if (0 <= i && i < MAXCHAN) { Chans[i] ^= (code == MS_LEFT? C_ON : C_GREY); drawvu(); return(1); } } return(0); } hsamouse(window, event) /* mouse event in horizontal scroll area */ Window window; Event *event; { int id, x, y; long t, q; Recta hsrect(), oldR; static int state, onend, dt; static long lastt, ocmaxt, ocmint; id = event_id(event); oldR = hsrect(); if (state == 0) { /* waiting for button down */ ocmaxt = Cmaxt; ocmint = Cmint; lastt = -1; t = HSAX_T(event_x(event)); if (id == MS_LEFT) { onend = HSAX_T(event_x(event)); Cmaxt = Maxt; Cmint = Mint; uprect(oldR, hsrect()); state = id; } else if (id == MS_MIDDLE) { dt = Cmaxt - Cmint; if (Cmint <= t && t <= Cmaxt) { x = (oldR.o.x + oldR.c.x) >> 1; y = (oldR.o.y + oldR.c.y) >> 1; window_set(window, WIN_MOUSE_XY, x, y, 0); } state = id; } else if (id == MS_RIGHT) menu_show(B3emp, window, event, 0); } else if (id == LOC_DRAG) { if (state == MS_LEFT) { t = HSAX_T(event_x(event)); t = Maxt < t? Maxt : t; t = Mint > t? Mint : t; if (t != lastt) { Cmaxt = onend > t? onend : t; Cmint = onend < t? onend : t; if (Cmaxt == Cmint) { Cmaxt = Maxt; Cmint = Mint; } uprect(oldR, hsrect()); lastt = t; } } else if (state == MS_MIDDLE) { t = HSAX_T(event_x(event)); t = (q = Maxt - dt / 2) < t? q : t; t = (q = Mint + dt / 2) > t? q : t; if (t != lastt) { Cmint = t - dt / 2; Cmaxt = Cmint + dt; uprect(oldR, hsrect()); lastt = t; } } } else if (event_is_up(event)) { /* button up */ state = 0; Mymouse = 0; /* give up the mouse */ return(Cmaxt != ocmaxt || Cmint != ocmint); } return(0); } vsamouse(window, event) /* mouse event in vertical scroll area */ Window window; Event *event; { register int k, id, x, y; Recta vsrect(), oldR; static int state, onend, lastk, dk, ocmaxk, ocmink; id = event_id(event); oldR = vsrect(); if (state == 0) { /* waiting for button down */ ocmaxk = Cmaxk; ocmink = Cmink; lastk = -1; k = VSAY_K(event_y(event)); if (id == MS_LEFT) { onend = k + 1; Cmink = MINKEY; Cmaxk = MAXKEY; uprect(oldR, vsrect()); state = id; } else if (id == MS_MIDDLE) { dk = Crangek; if (Cmink <= k && k <= Cmaxk) { x = (oldR.o.x + oldR.c.x) >> 1; y = (oldR.o.y + oldR.c.y) >> 1; window_set(window, WIN_MOUSE_XY, x, y, 0); } state = id; } else if (id == MS_RIGHT) menu_show(B3emp, window, event, 0); } else if (id == LOC_DRAG) { if (state == MS_LEFT) { k = VSAY_K(event_y(event)); k = max(MINKEY, min(MAXKEY, k)); if (k != lastk) { Cmink = min(onend, k); Cmaxk = max(onend, k); if (Cmaxk == Cmink) { Cmink = MINKEY; Cmaxk = MAXKEY; } uprect(oldR, vsrect()); lastk = k; } } else if (state == MS_MIDDLE) { k = VSAY_K(event_y(event)); k = max(MINKEY + dk / 2, min(MAXKEY - dk / 2, k)); if (k != lastk) { Cmink = k - dk / 2; Cmaxk = Cmink + dk; uprect(oldR, vsrect()); lastk = k; } } } else if (event_is_up(event)) { /* button up */ state = 0; Mymouse = 0; /* give up the mouse */ return(Cmink != ocmink || Cmaxk != ocmaxk); } return(0); } camouse(window, event) /* mouse event in chart area */ Window window; Event *event; { register int i, change; change = 0; i = event_id(event); if ((i == LOC_DRAG && window_get(Dcanvas, WIN_EVENT_STATE, MS_LEFT)) || i == MS_LEFT) selectca(window, event); else if (i == MS_MIDDLE) change = menu2ca(window, event); else if (i == MS_RIGHT) change = menu3ca(window, event); return(change); } selectca(window, event) /* define selected area in chart area */ Window window; Event *event; { register int x, y; static int firstx, firsty, lastx, lasty; Recta old; x = event_x(event); y = event_y(event); if (event_id(event) == MS_LEFT) { if (event_is_down(event)) { /* button down */ RECTINV(Sel); Sel.o.x = Sel.c.x = firstx = lastx = x; Sel.o.y = Sel.c.y = firsty = lasty = y; } else { /* button up */ Stmin = CAX_T(Sel.o.x); Stmax = CAX_T(Sel.c.x) + 1; Skmin = CAY_KA(Sel.c.y); Skmax = CAY_KB(Sel.o.y) + 1; firstx = firsty = lastx = lasty = 0; Mymouse = 0; /* give up the mouse */ } return; } else if (event_id(event) == LOC_DRAG && (x != lastx || y != lasty)) { old = Sel; Sel.o.x = min(firstx, lastx = x); Sel.o.y = min(firsty, lasty = y); Sel.c.x = max(firstx, x); Sel.c.y = max(firsty, y); uprect(old, Sel); } } menu2ca(window, event) Window window; Event *event; { register int i, change; char *file; if (Skmin == Skmax || Stmin == Stmax) { menu_show(B2emp, window, event, 0); return(0); } change = 0; i = (int) menu_show(B2mp, window, event, 0); Mymouse = 0; /* give up the mouse */ RECTINV(Ca); switch(i) { case BBOX2: selpart(NO_FILE, NO_FILE, SEL); /* set Smink, Smint, etc. */ RECTINV(Sel); if (Smint < Smaxt && Smink < Smaxk) { Sel.o.x = CAT_X(Stmin = Smint) - 1; Sel.c.x = CAT_X((Stmax = Smaxt) - 1) + 1; Sel.c.y = CAK_YB(Skmin = Smink); Sel.o.y = CAK_YA((Skmax = Smaxk) - 1); RECTINV(Sel); } else { Sel.o.x = Sel.c.x = Sel.o.y = Sel.c.y = 0; Stmin = Stmax = 0; Skmax = Skmin = 0; } break; case CLOSE2: if (selpart(Selfile, file = "/tmp/chedtmp", CLOSE)) { unlink(Workfile); link(file, Workfile); unlink(file); Dirty++; change = 1; } break; case CUT2: if (selpart(Selfile, file = "/tmp/chedtmp", SEL)) { unlink(Workfile); link(file, Workfile); unlink(file); change = 1; Dirty++; } break; case IPROC2: change = iproc(0); break; case FILTER2: if (change = filter(0)) Dirty++; break; case GLOM2: selpart(Selfile, NO_FILE, SEL); break; case INFO2: RECTINV(Ca); infomenu(window, event); RECTINV(Ca); break; case OPEN2: if (selpart(NO_FILE, file = "/tmp/chedtmp", OPEN)) { unlink(Workfile); link(file, Workfile); unlink(file); change = 1; Dirty++; } break; case PASTE2: if (change = paste(Selfile, Workfile)) Dirty++; break; case PLAY2: change = play(0); break; case WRITE2: change = writefile(0); break; case ZOOMI2: change = zoomin(); break; case ZOOMO2: change = zoomout(); break; } if (change == 0) RECTINV(Ca); return(change); } infomenu(window, event) Window window; Event *event; { char bgc[64], bgq[64], bgb[64]; char edc[64], edq[64], edb[64]; char top[64], bot[64]; int i; double q; Menu m; char *key2name(); m = menu_create(MENU_STRINGS, "SELECTED AREA", 0, 0); sprintf(bgc, "Beg clk: %d", Stmin); menu_set(m, MENU_STRING_ITEM, bgc, 0, 0); sprintf(edc, "End clk: %d", Stmax - 1); menu_set(m, MENU_STRING_ITEM, edc, 0, 0); sprintf(bgq, "Beg beat: %g", Stmin / 120.); menu_set(m, MENU_STRING_ITEM, bgq, 0, 0); sprintf(edq, "End beat: %g", (Stmax - 1) / 120.); menu_set(m, MENU_STRING_ITEM, edq, 0, 0); if (Barlen) { sprintf(bgb, "Beg bar: %g", Stmin / (float) Barlen); menu_set(m, MENU_STRING_ITEM, bgb, 0, 0); sprintf(edb, "End bar: %g", (Stmax - 1) / (float) Barlen); menu_set(m, MENU_STRING_ITEM, edb, 0, 0); } else { /* using TCWME */ for (i = Nbl; --i >= 0 && Barline[i] > Stmin; ); if (i < 0) sprintf(bgb, "Beg bar: <0"); else { q = Stmin - Barline[i]; /* residue */ if (i == Nbl - 1) sprintf(bgb, "Beg bar: %d + %g clocks", i, q); else sprintf(bgb, "Beg bar: %g", i + q / (Barline[i + 1] - Barline[i])); } menu_set(m, MENU_STRING_ITEM, bgb, 0, 0); for (i = Nbl; --i >= 0 && Barline[i] > Stmax - 1; ); if (i < 0) sprintf(edb, "End bar: <0"); else { q = Stmax - 1 - Barline[i]; /* residue */ if (i == Nbl - 1) sprintf(edb, "End bar: %d + %g clocks", i, q); else sprintf(edb, "End bar: %g", i + q / (Barline[i + 1] - Barline[i])); } menu_set(m, MENU_STRING_ITEM, edb, 0, 0); } i = Skmax - 1; sprintf(top, "Top key: %d (X%x) %s", i, i, key2name(i)); menu_set(m, MENU_STRING_ITEM, top, 0, 0); sprintf(bot, "Bot key: %d (X%x) %s", Skmin, Skmin, key2name(Skmin)); menu_set(m, MENU_STRING_ITEM, bot, 0, 0); menu_show(m, window, event, 0); menu_destroy(m); } menu3ca(window, event) Window window; Event *event; { register int i, change; change = 0; i = (int) menu_show(B3mp, window, event, 0); Mymouse = 0; /* give up the mouse */ RECTINV(Ca); switch(i) { case CNTRLS3: RECTINV(Ca); Cntlshow = (TRUE + FALSE) - Cntlshow; window_set(Controls, WIN_SHOW, Cntlshow, 0); RECTINV(Ca); break; case FILTER3: if (change = filter(1)) Dirty++; break; case IPROC3: change = iproc(1); break; case PLAY3: change = play(1); break; case QUIT3: change = quit(); break; case READ3: change = readfile(); break; case WRITE3: change = writefile(1); break; } if (change == 0) RECTINV(Ca); return(change); } play(entire) { register int i; char *file, buf[16]; while (Playpid > 0) if ((i = wait(0)) == -1 || i == Playpid) Playpid = 0; if (entire) file = Workfile; else selpart(file = Playfile, NO_FILE, SEL); sprintf(buf, "-t%d", Tempo); Playpid = forkexec(-1, -1, Playcmd, buf, file, 0, 0, 0); return(0); } quit() { register int i; char buf[32]; if (Dirty) { sprintf(buf, "y"); i = gstring("Unwritten changes! Okay? ", buf, sizeof buf, 10, 10, 300, 25); if (i == 0 || *buf != 'y') return(0); } while (Playpid > 0) if ((i = wait(0)) == -1 || i == Playpid) Playpid = 0; if (Workfile && *Workfile) unlink(Workfile); if (Playfile && *Playfile) unlink(Playfile); if (Selfile && *Selfile) unlink(Selfile); exit(0); /*NOTREACHED*/ } gstring(msg, retbuf, len, x, y, w, h) char *msg, *retbuf; { register char *cp; char buf[512]; printf("%s <%s> ", msg, retbuf); if (fgets(buf, len, stdin)) { for (cp = buf; *cp && *cp != '\n' && *cp != '\r'; cp++); if (cp != buf) { *cp = '\0'; strcpy(retbuf, buf); } return(1); } return(0); } readfile() { char buf[32]; int i, oldbo; if (Dirty) { sprintf(buf, "y"); i = gstring("UNWRITTEN CHANGES! Okay? ", buf, sizeof buf, 10, 10, 300, 25); if (i == 0 || *buf != 'y') return(0); } i = gstring("File: ", Oldfile, sizeof Oldfile, 10, 10, 400, 25); if (i == 0 || *Oldfile == '\0') return(0); oldbo = Baroff; Baroff = -2; if (initfile(Oldfile) == 0) return(0); if (Baroff != oldbo) gencntl(); if (Cmint >= Maxt) Cmint = Mint; if (Maxt < Cmaxt) Cmaxt = Maxt; return(1); } /* Merge "part" (offset by Stmin) and "whole" into "Workfile" */ /* return 1 for success, 0 for failure */ paste(part, whole) char *part, *whole; { char buf[512], *tmp1, *tmp2; int change; FILE *ifp, *tfp; change = 1; /* assume we'll change something */ tmp1 = "/tmp/chedpaste1"; tmp2 = "/tmp/chedpaste2"; ifp = tfp = (FILE *) NULL; sprintf(buf, "%s -c%d <%s >%s; %s %s %s >%s", Tshiftcmd, Stmin, part, tmp1, Mergecmd, whole, tmp1, tmp2); if (system(buf)) { perror(buf); change = 0; } if (change && (ifp = fopen(tmp2, "r")) == (FILE *) NULL) { perror(tmp2); change = 0; } if (change && (tfp = fopen(Workfile, "w")) == (FILE *) NULL) { perror(Workfile); change = 0; } /****/if (change) fprintf(stderr, "about to copy %s to %s\n", tmp2, Workfile); if (change) copyfile(ifp, tfp); if (ifp) fclose(ifp); if (tfp) fclose(tfp); unlink(tmp1); unlink(tmp2); if (!change) fprintf(stderr, "Aborting\n"); return(change); } /* copy selected part of Workfile to selfile, the rest to unselfile */ /* if op is CLOSE, then close up selected time */ /* if op is OPEN, then open up selected time */ /* Return 1 for success, 0 for failure */ selpart(selfile, unselfile, op) char *selfile, *unselfile; { register int k, v, status, mode; unsigned char mbuf[16]; int chan, kmin, kmax, syet, sg, ug; long now, tmin, tmax; FILE *ifp, *sfp, *ufp; MCMD m, *mp; m.cmd = mbuf; if ((ifp = fopen(Workfile, "r")) == NULL) { perror(Workfile); return(0); } if (selfile == NO_FILE) sfp = 0; else if ((sfp = fopen(selfile, "w")) == NULL) { perror(selfile); fclose(ifp); return(0); } if (unselfile == NO_FILE) ufp = 0; else if ((ufp = fopen(unselfile, "w")) == NULL) { perror(unselfile); fclose(ifp); if (sfp) fclose(sfp); return(0); } tmin = Stmin; tmax = Stmax; if (op == CLOSE || op == OPEN) { kmin = MINKEY; kmax = MAXKEY; } else { kmin = Skmin; kmax = Skmax; } Smink = 999; Smaxk = 0; Smint = tmax; Smaxt = tmin; for (chan = 0; chan < MAXCHAN; chan++) /* only check selected notes */ if (Chans[chan] & C_ON) for (k = kmin; k < kmax; k++) Key[chan][k] = 0; syet = 0; if (ufp) iputmcmds(0, ufp, 0L); if (sfp) iputmcmds(1, sfp, tmin); for (now = 0L; mp = getmcmd(ifp, now); ) { now = mp->when; if (now >= tmin && syet == 0) { /* just entered selected time */ if (op != OPEN || sfp) { /* stop/start notes in play */ m.when = tmin; m.len = 3; for (chan = 0; chan < MAXCHAN; chan++) { if (Chans[chan] & C_ON) { m.cmd[0] = CH_KEY_ON | chan; for (k = kmin; k < kmax; k++) { if (Key[chan][k]) { /* already playing */ m.cmd[1] = k; if (ufp) { m.cmd[2] = 0; putmcmds(0, &m); } if (sfp) { m.cmd[2] = Vel[chan][k]; putmcmds(1, &m); } } } } } } if (op == OPEN) now += tmax - tmin; /* open requested space */ if (op == CLOSE) Sonow[0] += tmax - tmin; /* close requested space */ syet = 1; } if (now >= tmax && syet == 1) { /* just left selected time */ if (op != OPEN || sfp) { /* stop/start notes in play */ m.when = tmax; m.len = 3; for (chan = 0; chan < MAXCHAN; chan++) { if (Chans[chan] & C_ON) { m.cmd[0] = CH_KEY_ON | chan; for (k = kmin; k < kmax; k++) { if (Key[chan][k]) { m.cmd[1] = k; if (sfp) { m.cmd[2] = 0; putmcmds(1, &m); } if (ufp) { m.cmd[2] = Vel[chan][k]; putmcmds(0, &m); } } } } } if (sfp) { m.when = tmax; m.len = 1; m.cmd[0] = MPU_NO_OP; putmcmds(1, &m); fclose(sfp); sfp = 0; } } if (!ufp) break; syet = 2; } status = mp->cmd[0]; mode = status & M_CMD_MASK; chan = status & M_CHAN_MASK; /* decide what to do with non-note "garbage" */ sg = (Garbsel & 1) && sfp && (syet == 1); ug = (Garbsel & 2) && ufp; if (mode != CH_KEY_ON) { if (sg) putmcmds(1, mp); if (ug) putmcmds(0, mp); continue; } k = mp->cmd[1]; v = mp->cmd[2]; if (v == 0) { /* key-off */ --Key[chan][k]; if (Key[chan][k] < 0) /* extra note-off */ Key[chan][k] = 0; } else { /* key-on */ Vel[chan][k] = v; Key[chan][k]++; } if (tmin <= now && now < tmax && kmin <= k && k < kmax && (Chans[chan] & C_ON)) { putmcmds(1, mp); if (v == 0) { if (now >= Smaxt) Smaxt = now + 1; } else { if (now < Smint) Smint = now; } if (k < Smink) Smink = k; if (k >= Smaxk) Smaxk = k + 1; } else if (now >= Sonow[0]) /* avoid unplayed Chans during CLOSE */ putmcmds(0, mp); } fclose(ifp); if (sfp) { /* we're still in the selected area */ m.when = now; for (chan = 0; chan < MAXCHAN; chan++) { if (Chans[chan] & C_ON) { m.cmd[0] = CH_KEY_ON | chan; for (k = kmin; k < kmax; k++) { if (Key[chan][k]) { m.cmd[1] = k; putmcmds(1, &m); } } } } fclose(sfp); } if (ufp) fclose(ufp); return(1); } /*VARARGS3*/ forkexec(in, out, p, a1, a2, a3, a4) char *p; { register int pid; switch (pid = fork()) { case -1: perror("fork()"); break; case 0: close(0); if (in >= 0) dup2(0, in); close(1); if (out >= 0) dup2(1, out); execl(p, p, a1, a2, a3, a4); perror(p); exit(1); } return(pid); } writefile(entire) { char *file, buf[512]; int i, ifh, ofh; if (entire) { i = gstring("Write entire file to: ", Newfile, sizeof Newfile, 10, 10, 500, 25); if (i == 0 || *Newfile == '\0') return(0); file = Workfile; Dirty = 0; } else { i = gstring("Write selected area to: ", Newfile, sizeof Newfile, 10, 10, 500, 25); if (i == 0 || *Newfile == '\0') return(0); selpart(file = "/tmp/chedtmp", NO_FILE, SEL); } sprintf(Flbuf, " CHED src:%s dst:%s", Oldfile, Newfile); window_set(Dframe, FRAME_LABEL, Flbuf, 0); if ((ifh = open(file, 0)) < 0) perror(file); else if ((ofh = creat(Newfile, 0644)) < 0) perror(Newfile); else { while ((i = read(ifh, buf, sizeof buf)) > 0) write(ofh, buf, i); close(ofh); } close(ifh); printf("%s written\n", Newfile); return(0); } zoomin() { if (Stmin >= Stmax || Skmin >= Skmax) return(0); Cmint = Stmin - 1; Cmaxt = Stmax + 1; Cmink = Skmin - 1; Cmaxk = Skmax + 1; return(1); } zoomout() { int lx, hx, dx, ly, hy, dy, dy2, omink, omaxk, nmink, nmaxk; long omint, omaxt, nmint, nmaxt; omint = Cmint; omaxt = Cmaxt; omink = Cmink; omaxk = Cmaxk; dx = Sel.c.x - Sel.o.x; if (dx == 0) { Cmint = Mint; Cmaxt = Maxt; } else { lx = Sel.o.x - Vsa.c.x; hx = Sel.c.x - Vsa.c.x; nmint = (omint * hx - omaxt * lx) / dx; nmaxt = nmint + (Csize.x * (omaxt - omint)) / dx; Cmint = nmint < Mint? Mint : nmint; Cmaxt = nmaxt > Maxt? Maxt : nmaxt; } dy = Sel.c.y - Sel.o.y; if (dy == 0) { Cmink = MINKEY; Cmaxk = MAXKEY; } else { ly = Hsa.o.y - Sel.o.y; hy = Hsa.o.y - Sel.c.y; dy2 = dy >> 1; nmink = (omink * ly - omaxk * hy + dy2) / dy; nmaxk = nmink + (Csize.y * (omaxk - omink) + dy2) / dy; Cmink = nmink < MINKEY? MINKEY : nmink; Cmaxk = nmaxk > MAXKEY? MAXKEY : nmaxk; } Stmin = omint; Stmax = omaxt; Skmin = omink; Skmax = omaxk; return(1); } iproc(entire) { char buf[256]; int i; static char cmd[128] = "da"; i = gstring("Command: ", cmd, sizeof cmd, 10, 10, 500, 25); if (i == 0 || *cmd == '\0') return(0); if (entire) { sprintf(buf, "cat %s | %s", Workfile, cmd); if (system(buf)) perror(buf); } else { selpart(Selfile, NO_FILE, SEL); sprintf(buf, "cat %s | %s", Selfile, cmd); if (system(buf)) perror(buf); } return(0); } filter(entire) { char *therest, buf[256]; int i; static char cmd[128]; i = gstring("Command: ", cmd, sizeof cmd, 10, 10, 500, 25); if (i == 0 || *cmd == '\0') return(0); if (entire) { unlink(Selfile); link(Workfile, Selfile); unlink(Workfile); sprintf(buf, "%s <%s >%s", cmd, Selfile, Workfile); if (system(buf)) { perror(buf); unlink(Workfile); link(Selfile, Workfile); unlink(Selfile); } } else { if (!selpart(Selfile, therest = "/tmp/chedtmp", SEL)) return(0); sprintf(buf, "%s <%s >%s", cmd, Selfile, "/tmp/ched2"); if (system(buf)) { perror(buf); return(0); } i = paste("/tmp/ched2", therest); unlink(therest); if (!i) return(0); } return(1); } redraw() /* called whenever resized or cmd changes view */ { if (Tfp) fclose(Tfp); if ((Tfp = fopen(Workfile, "r")) == (FILE *) NULL) { perror(Workfile); exit(1); } cascale(); if (Skmax != Skmin) { Sel.o.x = CAT_X(Stmin); Sel.c.x = CAT_X(Stmax); Sel.o.y = CAK_YA(Skmax); Sel.c.y = CAK_YB(Skmin); } pw_writebackground(Dpw, 0, 0, Da.c.x+Margin, Da.c.y+Margin, PIX_CLR); process(Tfp); drawstaves(); drawhs(); drawvs(); drawvu(); RECTINV(Sel); } void resized(canvas, width, height) Canvas canvas; { if (canvas != Dcanvas) return; /* oops */ Da.o.x = Da.o.y = Margin; Da.c.x = width - Margin; Da.c.y = height - Margin; /* entire display area (-borders) */ Vuwidth = min((Da.c.x - Da.o.x) / MAXCHAN, 20); Va.o.x = (Da.o.x + Da.c.x) / 2 - 8 * Vuwidth; /* VU area */ Va.c.x = Va.o.x + MAXCHAN * Vuwidth; Va.o.y = Da.o.y; Va.c.y = Da.o.y + 20; Hsa = Da; /* horizontal scroll area */ Hsa.o.x += 16; Hsa.o.y = Hsa.c.y - 2 * SBHH - 4; Hspix = Hsa.c.x - Hsa.o.x; Vsa = Da; /* vertical scroll area */ Vsa.c.x = Vsa.o.x + 16; Vsa.c.y = Hsa.o.y; Vspix = Vsa.c.y - Vsa.o.y; gencntl(); redraw(); } cascale() /* calc Csize, Ppm, caoff, etc. when scaling occurs */ { /* after this, CAT_X(), CAY_K(), CAX_T(), etc. are usable */ register int x, y; Ca.o.x = Vsa.c.x + 1; /* maximum chart area rect */ Ca.o.y = Va.c.y + 1; Ca.c.x = Hsa.c.x; Ca.c.y = Hsa.o.y - 1; Csize.x = Ca.c.x - Ca.o.x; /* maximum chart size */ Csize.y = Ca.c.y - Ca.o.y; Cranget = Cmaxt - Cmint; Crangek = Cmaxk - Cmink; Ppm = (Csize.x * CPM) / Cranget; Ppk = Csize.y / Crangek; x = Csize.x - (Cranget * Ppm) / CPM; /* adjust to make both */ y = Csize.y - Crangek * Ppk; /* Ppm and Ppk exact */ Ca.o.x += x / 2; /* center in maximum area */ Ca.o.y += y / 2; Ca.c.x -= x / 2; Ca.c.y -= y / 2; Csize.x = Ca.c.x - Ca.o.x; /* real chart area in use */ Csize.y = Ca.c.y - Ca.o.y; } drawstaves() { register int i, lx, hx, ly, hy; long t, dt; if (Dpw) pw_batch_on(Dpw); lx = CAT_X(Cmint); /* horizontal staff lines */ lx = max(lx, Ca.o.x); hx = CAT_X(Cmaxt); for (i = 5; --i >= 0; ) { ly = CAK_Y(Tclefk[i]); if (Ca.o.y < ly && ly < Ca.c.y) pw_vector(Dpw, lx, ly, hx, ly, PIX_SET, 1); ly = CAK_Y(Bclefk[i]); if (Ca.o.y < ly && ly < Ca.c.y) pw_vector(Dpw, lx, ly, hx, ly, PIX_SET, 1); } ly = Ca.o.y; /* various vertical lines */ hy = Ca.c.y; if (Tgrid && Barlen) { /* grid ticks */ dt = Barlen / Tgrid; for (t = Baroff + dt * ((Mint + dt - 1) / dt); t < Cmaxt; t += dt) { lx = CAT_X(t); if (lx < Ca.o.x) continue; if (lx > Ca.c.x) break; TREPL(lx, ly, 1, hy - ly, PIX_SRC, Ltgrey); } } ly = CAK_Y(Tclefk[0]); hy = CAK_Y(Bclefk[0]); hy = min(hy, Ca.c.y); if (Barlen) { /* vertical staff lines */ dt = Barlen; for (t = Baroff + dt * ((Mint + dt - 1) / dt); t < Cmaxt; t += dt) { lx = CAT_X(t); if (lx > Ca.c.x) break; if (lx >= Ca.o.x) pw_vector(Dpw, lx, ly, lx, hy, PIX_SET, 1); } } else { for (i = 0; i < Nbl; i++) { t = Barline[i]; lx = CAT_X(t) - 1; if (lx > Ca.c.x) break; if (lx >= Ca.o.x) pw_vector(Dpw, lx, ly, lx, hy, PIX_SET, 1); } } if (Dpw) pw_batch_off(Dpw); /* for deferred update */ } drawvu() { register int i, x, y, cxo, cyo; if (Dpw) pw_batch_on(Dpw); x = Va.o.x; y = Va.o.y; cxo = 8 - Fontwidth / 2; cyo = 30; for (i = 0; i < MAXCHAN; i++) { ROPS(x, y, x + 16, y + 16, PIX_SRC, Vupr[Chans[i]]); pw_char(Dpw, x + cxo, y + cyo, PIX_SRC, Fontp, "0123456789ABCDEF"[i]); x += Vuwidth; } if (Dpw) pw_batch_off(Dpw); /* for deferred update */ } uprect(old, new) Recta old, new; { if (new.o.x < old.o.x) { RINV(new.o.x, new.o.y, old.o.x, new.c.y); new.o.x = old.o.x; } else if (old.o.x < new.o.x) { RINV(old.o.x, old.o.y, new.o.x, old.c.y); old.o.x = new.o.x; } if (new.o.y < old.o.y) { RINV(new.o.x, new.o.y, new.c.x, old.o.y); new.o.y = old.o.y; } else if (old.o.y < new.o.y) { RINV(old.o.x, old.o.y, old.c.x, new.o.y); old.o.y = new.o.y; } if (new.c.x > old.c.x) { RINV(old.c.x, new.o.y, new.c.x, new.c.y); new.c.x = old.c.x; } else if (old.c.x > new.c.x) { RINV(new.c.x, old.o.y, old.c.x, old.c.y); old.c.x = new.c.x; } if (new.c.y > old.c.y) { RINV(new.o.x, old.c.y, new.c.x, new.c.y); new.c.y = old.c.y; } else if (old.c.y > new.c.y) { RINV(old.o.x, new.c.y, old.c.x, old.c.y); old.c.y = new.c.y; } }