/* MFM -- Mirage FM synthesis a la DX7 psl 3/88 */ #include #include #include #include #include #include #include #include #define PSLSIN /* approximate, but FAST */ #define DATAWIDTH 1024 #define DATAHEIGHT 256 #define MARGIN 4 /* space around data in canvas */ #define VIEWWIDTH (DATAWIDTH+2*MARGIN) #define VIEWHEIGHT (DATAHEIGHT+2*MARGIN) #define SCROLLHEIGHT 20 #define PANELHEIGHT 78 #define BORDER 16 #define MISC 16 #define BPP 256 #define ZERO 0x80 /* Mirage data zero */ #define DSCMAGIC 05504 #define PANELFONT "/usr/lib/fonts/fixedwidthfonts/screen.r.14" #define OUTFILE "mfm.data" #define TMPFILE "/tmp/mfm.tmp" #define WDRFILE "/tmp/mfm.wdr" #define SEQFILE "/tmp/mfm.seq" #define PIX_INV PIX_NOT(PIX_DST) #define PIX_XOR (PIX_DST^PIX_SRC) #define ROP(OX,OY,CX,CY,OP) pw_rop(Dpw,OX,OY,CX-(OX),CY-(OY),OP,0,0,0); #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) /* pixel macros for left border area */ #define D_TO_BP(D) (MARGIN+0xFF-(D)) #define BP_TO_D(P) (MARGIN+0xFF-(P)) /* pixel macros for viewing area */ #define B_TO_PIX(B) (1+(MARGIN*BPP+(B)*Ppp-1)/BPP) #define D_TO_PIX(D) (BORDER+D_TO_BP(D)) #define E_TO_PIX(S) (BORDER+MARGIN+0x7F-(((S)+2)>>2)) #define PIX_TO_B(P) ((((P)-MARGIN)*BPP)/Ppp) #define PIX_TO_D(P) (BORDER+BP_TO_D(P)) #define PIX_TO_E(P) ((BORDER+MARGIN+0x7F-(P))<<2) #define D_TO_NUM(D) ((D)-ZERO) #define NUM_TO_D(N) ((N)+ZERO) typedef unsigned char uchar; #define NUMSCALE 256 struct estr { /* envelope structure */ int num; /* number of points in use */ int disp; /* 0 => not being displayed */ int bpos[NUMSCALE]; /* byte position */ short scale[NUMSCALE]; /* scale * 256 */ } Scale = { 1, 1, { 0, }, { 256, }, }; struct opstr { /* operator settings for FM */ int f; /* freq for op (* 100) */ int g; /* gain for op (* 100) */ struct estr e; /* envelope for op */ }; struct fmpstr { /* entire FM setup */ int pcnt; /* length to generate (256 byte pages) */ int cycs; /* cycles to generate */ int fb; /* feedback (op1) (* 100) */ struct opstr op[2]; /* freqs, gains, & envelopes */ } Fmp = { 16, 16, 0, { 100, 100, { 1, 0, { 0, }, { 256, }, }, }, { 100, 100, { 1, 0, { 0, }, { 256, }, }, }, }; char Oldfile[128]; /* where the data comes from for "read" */ char Flbuf[128]; /* frame label buffer */ uchar *Data; /* pointer to wavesample (malloc) */ int Chan = 2; /* Where the Mirage listens */ int Pcnt = 0; /* data page count */ int Ppp = 16; /* pixels/page (magnification) */ int Tticks = BPP; /* bytes per tickmark (time ticks) */ int Aticks = 64; /* values per tickmark (amplitude ticks) */ int Ramt = 1; /* rotation amount */ int Cbusy = 0; /* semaphore, to hide cursor while busy */ Pixrect *Grey; /* grey texture */ Frame Dframe; /* whole display's frame */ Canvas Dlborder; /* left border */ Canvas Dcanvas; /* waveform area */ Scrollbar Dcsb; /* waveform area's scrollbar */ int Dcwidth, Dcheight; /* width & height of Dcanvas */ Pixwin *Bpw = 0; /* display pixwin for border area (Dborder) */ Pixwin *Dpw = 0; /* display pixwin for waveform area (Dcanvas) */ Panel Controls; /* control panel */ Panel_item Mslide; /* id for magnification slider */ Panel_item Tslide; /* id for time ticks slider */ Panel_item Aslide; /* id for amplitude ticks slider */ Panel_item Rslide; /* id for rotation amount slider */ Panel Fmparms; /* FM control panel */ Panel_item Fpgslide; /* id for FM page count slider */ Panel_item Fcyslide; /* id for FM cycle count slider */ Panel_item Ffbslide; /* id for FM feedback slider */ Panel_item Ff1slide; /* id for FM freq 1 slider */ Panel_item Fg1slide; /* id for FM gain 1 slider */ Panel_item Ff2slide; /* id for FM freq 2 slider */ Panel_item Fg2slide; /* id for FM gain 2 slider */ /* Button 3 menu */ Menu b3mp; #define PLAY 1 #define DUMP 2 #define LOAD 3 #define CONTROLS 4 #define FM 5 #define ROTL 6 #define ROTR 7 #define TRIM 8 #define SCALE 9 #define UNSCALE 10 #define NORMALIZE 11 #define READ 12 #define WRITE 13 #define READDSC 14 #define WRITEDSC 15 #define QUIT 16 #define B3MINIT() b3mp = menu_create( \ MENU_INITIAL_SELECTION, MENU_SELECTED, \ MENU_INITIAL_SELECTION_SELECTED, FALSE, \ MENU_STRINGS, \ "PLAY SEQ", \ "MIRAGE->MFM", \ "MFM->MIRAGE", \ "CONTROLS", \ "FM SYNTH", \ "ROT LEFT", \ "ROT RIGHT", \ "TRIM", \ "SCALE", \ "UNSCALE", \ "NORMALIZE", \ "READ", \ "WRITE", \ "READ DSC", \ "WRITE DSC", \ "QUIT", \ 0, 0) short Grey_bits[] = { 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, }; extern double sin(), cos(), atof(); main(argc, argv) char *argv[]; { extern FILE *sopen(); /****/setbuf(stderr, 0); /* THOSE ASSHOLES! */ while (--argc > 0) { if (argv[argc][0] == '-') { switch (argv[argc][1]) { case 'm': /* magnify */ Ppp = atoi(&argv[argc][2]); if (Ppp < 1 || Ppp > BPP) goto syntax; break; default: goto syntax; } } else if (*Oldfile == 0) sprintf(Oldfile, "%s", argv[argc]); else { syntax: fprintf(stderr, "Usage: %s [-m#] [file]\n", argv[0]); exit(2); } } if (readdata(Oldfile) == 0) /* no file read */ exit(1); Fmp.pcnt = Pcnt; miscinits(); redraw(); window_main_loop(Dframe); exit(0); } redraw() { busy_cursor(); drawdata(); drawticks(); if (Scale.disp) flipenv(&Scale, 0); if (Fmp.op[0].e.disp) flipenv(&Fmp.op[0].e, 0); if (Fmp.op[1].e.disp) flipenv(&Fmp.op[1].e, 0); ready_cursor(); } drawdata() { register int i, x, y, ox, oy, nbytes; i = Dcwidth > VIEWWIDTH? Dcwidth : VIEWWIDTH; pw_writebackground(Dpw, 0, BORDER, i, VIEWHEIGHT, PIX_CLR); if (Dpw) pw_batch_on(Dpw); nbytes = BPP * Pcnt; ox = oy = -1; for (i = 0; i < nbytes; i++) { x = B_TO_PIX(i); y = D_TO_PIX(Data[i] & 0xFF); if (ox >= 0) pw_vector(Dpw, ox, oy, x, y, PIX_SET, 1); ox = x; oy = y; } if (Dpw) pw_batch_off(Dpw); } drawticks() { register int i, x, nbytes, h2; if (Dpw) pw_batch_on(Dpw); nbytes = BPP * Pcnt; i = Dcwidth > VIEWWIDTH? Dcwidth : VIEWWIDTH; pw_writebackground(Dpw, 0, 0, i, BORDER, PIX_CLR); if (Tticks) { for (i = 0; i < nbytes; i += Tticks) { x = B_TO_PIX(i); pw_vector(Dpw, x, 0, x, BORDER - 2, PIX_SRC, 1); } } pw_writebackground(Bpw, 0, 0, BORDER, DATAHEIGHT, PIX_CLR); h2 = D_TO_BP(ZERO); pw_vector(Bpw, 0, h2, BORDER - 2, h2, PIX_INV, 1); if (Aticks) { for (i = Aticks; i < h2; i += Aticks) { pw_vector(Bpw, 0, h2 + i, BORDER - 2, h2 + i, PIX_INV, 1); pw_vector(Bpw, 0, h2 - i, BORDER - 2, h2 - i, PIX_INV, 1); } } if (Dpw) pw_batch_off(Dpw); return(1); } flipenv(ep, flg) /* XOR an envelope line in */ struct estr *ep; { register int i, x, y, ox, oy, nbytes; ep->disp ^= flg; if (ep->num < 1) return; x = B_TO_PIX(ep->bpos[0]); y = E_TO_PIX(ep->scale[0]); nbytes = BPP * Pcnt; pw_vector(Dpw, x - 3, y, x, y - 3, PIX_INV, 1); pw_vector(Dpw, x, y - 3, x + 3, y, PIX_INV, 1); pw_vector(Dpw, x + 3, y, x, y + 3, PIX_INV, 1); pw_vector(Dpw, x, y + 3, x - 3, y, PIX_INV, 1); if (ep->num == 1) pw_vector(Dpw, B_TO_PIX(0), y, B_TO_PIX(nbytes), y, PIX_INV, 1); else { if (ep->bpos[0] > 0) pw_vector(Dpw, B_TO_PIX(0), y, x, y, PIX_INV, 1); for (i = 1; i < ep->num; i++) { ox = x; oy = y; x = B_TO_PIX(ep->bpos[i]); y = E_TO_PIX(ep->scale[i]); pw_vector(Dpw, ox, oy, x, y, PIX_INV, 1); pw_vector(Dpw, x - 3, y, x, y - 3, PIX_INV, 1); pw_vector(Dpw, x, y - 3, x + 3, y, PIX_INV, 1); pw_vector(Dpw, x + 3, y, x, y + 3, PIX_INV, 1); pw_vector(Dpw, x, y + 3, x - 3, y, PIX_INV, 1); } if (ep->bpos[ep->num - 1] < nbytes) pw_vector(Dpw, x, y, B_TO_PIX(nbytes), y, PIX_INV, 1); } } upmisc() /* update misc - canvas size, frame label, etc. */ { sprintf(Flbuf, " MFM %s, %d page%s", Oldfile, Pcnt, Pcnt==1? "" : "s"); window_set(Dframe, FRAME_LABEL, Flbuf, 0); Dcwidth = Ppp * Pcnt; window_set(Dcanvas, CANVAS_WIDTH, Dcwidth, 0); scrollbar_scroll_to(Dcsb, 0); panel_set(Mslide, PANEL_VALUE, Ppp, 0); } miscinits() /* do one-time inits */ { Rect tmp; Cursor cursor; void input(); Pixfont *pfont; if (!(pfont = pf_open(PANELFONT))) pfont = pf_default(); tmp.r_left = 8; tmp.r_top = 8; tmp.r_width = BORDER + VIEWWIDTH; tmp.r_height = BORDER + VIEWHEIGHT + SCROLLHEIGHT + PANELHEIGHT + MISC; Dframe = window_create(NULL, FRAME, FRAME_OPEN_RECT, &tmp, 0); Dlborder = window_create(Dframe, CANVAS, CANVAS_FIXED_IMAGE, TRUE, WIN_X, 0, WIN_Y, BORDER, WIN_WIDTH, BORDER, WIN_HEIGHT, VIEWHEIGHT, 0); Dcsb = scrollbar_create( SCROLL_DIRECTION, SCROLL_HORIZONTAL, SCROLL_PLACEMENT, SCROLL_SOUTH, SCROLL_THICKNESS, SCROLLHEIGHT, 0); Dcwidth = Ppp * Pcnt; Dcanvas = window_create(Dframe, CANVAS, CANVAS_FIXED_IMAGE, TRUE, CANVAS_AUTO_SHRINK, FALSE, WIN_X, BORDER, WIN_Y, 0, WIN_WIDTH, VIEWWIDTH, CANVAS_WIDTH, Dcwidth, WIN_HEIGHT, BORDER + VIEWHEIGHT + SCROLLHEIGHT, CANVAS_HEIGHT, BORDER + VIEWHEIGHT, WIN_HORIZONTAL_SCROLLBAR, Dcsb, WIN_CURSOR, cursor_create( CURSOR_SHOW_CROSSHAIRS, TRUE, 0), WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS, LOC_WINENTER, LOC_WINEXIT, LOC_MOVE, WIN_MOUSE_BUTTONS, 0, WIN_EVENT_PROC, input, 0); Bpw = canvas_pixwin(Dlborder); Dpw = canvas_pixwin(Dcanvas); Grey = mem_point(16, 16, 1, Grey_bits); B3MINIT(); genfmp(pfont); window_set(Fmparms, WIN_SHOW, FALSE, 0); gencntl(pfont); window_set(Controls, WIN_SHOW, TRUE, 0); upmisc(); } gencntl(font) Pixfont *font; { int swidth; void cntlchng(), pinput(); swidth = 258; Controls = window_create(Dframe, PANEL, WIN_X, 0, WIN_Y, BORDER + VIEWHEIGHT + SCROLLHEIGHT + 5, WIN_WIDTH, WIN_EXTEND_TO_EDGE, WIN_HEIGHT, PANELHEIGHT, PANEL_SHOW_MENU, FALSE, PANEL_LABEL_BOLD, TRUE, PANEL_ITEM_X_GAP, 25, PANEL_ITEM_Y_GAP, 12, WIN_EVENT_PROC, pinput, WIN_FONT, font, 0); Mslide = panel_create_item(Controls, PANEL_SLIDER, PANEL_LABEL_STRING, "PIXELS/PAGE", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Ppp, PANEL_MIN_VALUE, 4, PANEL_MAX_VALUE, BPP, PANEL_NOTIFY_PROC, cntlchng, 0); Tslide = panel_create_item(Controls, PANEL_SLIDER, PANEL_LABEL_STRING, " BYTES/TICK", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Tticks, PANEL_MIN_VALUE, 2, PANEL_MAX_VALUE, BPP, PANEL_NOTIFY_PROC, cntlchng, 0); Aslide = panel_create_item(Controls, PANEL_SLIDER, PANEL_LABEL_STRING, "VALUES/TICK", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Aticks, PANEL_MIN_VALUE, 2, PANEL_MAX_VALUE, 128, PANEL_NOTIFY_PROC, cntlchng, 0); Rslide = panel_create_item(Controls, PANEL_SLIDER, PANEL_LABEL_STRING, " ROTATE AMT", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Ramt, PANEL_MIN_VALUE, 1, PANEL_MAX_VALUE, BPP, PANEL_NOTIFY_PROC, cntlchng, 0); window_fit_height(Controls); } genfmp(font) Pixfont *font; { int swidth; void fmpchng(), pinput(); Fmparms = window_create(Dframe, PANEL, WIN_X, 0, WIN_Y, BORDER + VIEWHEIGHT + SCROLLHEIGHT + 5, WIN_WIDTH, WIN_EXTEND_TO_EDGE, WIN_HEIGHT, PANELHEIGHT, PANEL_SHOW_MENU, FALSE, PANEL_LABEL_BOLD, TRUE, PANEL_ITEM_X_GAP, 24, PANEL_ITEM_Y_GAP, 2, WIN_EVENT_PROC, pinput, WIN_FONT, font, 0); swidth = 170; Fpgslide = panel_create_item(Fmparms, PANEL_SLIDER, PANEL_LABEL_STRING, "PAGES", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Fmp.pcnt, PANEL_MIN_VALUE, 1, PANEL_MAX_VALUE, 64, PANEL_NOTIFY_PROC, fmpchng, 0); Fcyslide = panel_create_item(Fmparms, PANEL_SLIDER, PANEL_LABEL_STRING, "CYCLES", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Fmp.cycs, PANEL_MIN_VALUE, 1, PANEL_MAX_VALUE, 64, PANEL_NOTIFY_PROC, fmpchng, 0); Ffbslide = panel_create_item(Fmparms, PANEL_SLIDER, PANEL_LABEL_STRING, "FB", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Fmp.fb, PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, 100, PANEL_NOTIFY_PROC, fmpchng, 0); swidth = 300; Ff1slide = panel_create_item(Fmparms, PANEL_SLIDER, PANEL_LABEL_STRING, "FREQ1", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Fmp.op[0].f, PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, 1200, PANEL_NOTIFY_PROC, fmpchng, 0); Fg1slide = panel_create_item(Fmparms, PANEL_SLIDER, PANEL_LABEL_STRING, " GAIN1", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Fmp.op[0].g, PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, 100, PANEL_NOTIFY_PROC, fmpchng, 0); Ff2slide = panel_create_item(Fmparms, PANEL_SLIDER, PANEL_LABEL_STRING, "FREQ2", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Fmp.op[1].f, PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, 1200, PANEL_NOTIFY_PROC, fmpchng, 0); Fg2slide = panel_create_item(Fmparms, PANEL_SLIDER, PANEL_LABEL_STRING, " GAIN2", PANEL_SLIDER_WIDTH, swidth, PANEL_VALUE, Fmp.op[1].g, PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, 100, PANEL_NOTIFY_PROC, fmpchng, 0); window_fit_height(Fmparms); } void cntlchng(item, value, event) Panel_item item; Event *event; { if (item == Mslide) { if (Ppp != value) { /**** pw_writebackground(Dpw, 0,BORDER, Dcwidth,VIEWHEIGHT, PIX_CLR); ****/ Ppp = value; upmisc(); redraw(); } } else if (item == Tslide) { if (Tticks != value) { Tticks = value; drawticks(); } } else if (item == Aslide) { if (Aticks != value) { Aticks = value; drawticks(); } } else if (item == Rslide) Ramt = value; } void fmpchng(item, value, event) Panel_item item; Event *event; { if (item == Fpgslide) { if (Fmp.pcnt != value) Fmp.pcnt = value; } else if (item == Fcyslide) { if (Fmp.cycs != value) Fmp.cycs = value; } else if (item == Ffbslide) { if (Fmp.fb != value) Fmp.fb = value; } else if (item == Ff1slide) { if (Fmp.op[0].f != value) Fmp.op[0].f = value; } else if (item == Ff2slide) { if (Fmp.op[1].f != value) Fmp.op[1].f = value; } else if (item == Fg1slide) { if (Fmp.op[0].g != value) Fmp.op[0].g = value; } else if (item == Fg2slide) { if (Fmp.op[1].g != value) Fmp.op[1].g = value; } } busy_cursor() { Cursor cursor; if (Cbusy++ == 0) { /****/fprintf(stderr, "busy... "); #ifdef NOTHING_WORKS cursor = window_get(Dframe, WIN_CURSOR); cursor_set(cursor, CURSOR_SHOW_CROSSHAIRS, FALSE, 0); window_set(Dframe, WIN_CURSOR, cursor, 0); /****/window_release_event_lock(Dframe); #endif } return(Cbusy); } ready_cursor() { Cursor cursor; if (--Cbusy <= 0) { /****/fprintf(stderr, "\n"); #ifdef NOTHING_WORKS cursor = window_get(Dframe, WIN_CURSOR); cursor_set(cursor, CURSOR_SHOW_CROSSHAIRS, TRUE, 0); window_set(Dframe, WIN_CURSOR, cursor, 0); #endif Cbusy = 0; } return(Cbusy); } void pinput(window, event, arg) Window window; Event *event; { register int i, change; i = event_id(event); if (i != MS_RIGHT) { window_default_event_proc(window, event, arg); return; } busy_cursor(); change = mouseright(window, event); if (change) redraw(); ready_cursor(); } void input(window, event, arg) Window window; Event *event; { register int i, change; i = event_id(event); if (i != MS_LEFT && i != MS_MIDDLE && i != MS_RIGHT) return; busy_cursor(); change = 0; if (i == MS_LEFT) change = mouseleft(window, event); else if (i == MS_MIDDLE) change = mousemiddle(window, event); else if (i == MS_RIGHT) change = mouseright(window, event); if (change) redraw(); ready_cursor(); } mouseleft(window, event) Window window; Event *event; { char tbuf[64], vbuf[64], abuf[64]; int x, y, byte, val, p, b; Menu m; if (!event_is_down(event)) return(0); x = event_x(event); y = event_y(event); byte = PIX_TO_B(x); val = PIX_TO_D(y); p = byte / BPP; b = byte % BPP; sprintf(tbuf, "%d page%s, %d byte%s", p, p==1? "" : "s", b, b==1? "" : "s"); sprintf(vbuf, "Crosshair: %d", val); sprintf(abuf, "Amplitude: %d", Data[byte]); m = menu_create(MENU_STRINGS, tbuf, vbuf, abuf, 0, 0); menu_show(m, window, event, 0); menu_destroy(m); return(0); } mousemiddle(window, event) Window window; Event *event; { char tbuf[64], vbuf[64]; char tsbuf[64], asbuf[64], dsbuf[64]; char t1buf[64], a1buf[64], d1buf[64]; char t2buf[64], a2buf[64], d2buf[64]; int i, byte, p, b, val, dsi, d1i, d2i; Menu m; if (!event_is_down(event)) return(0); byte = PIX_TO_B(event_x(event)); val = PIX_TO_E(event_y(event)); p = byte / BPP; b = byte % BPP; sprintf(tbuf, "%d page%s, %d byte%s", p, p==1? "" : "s", b, b==1? "" : "s"); sprintf(vbuf, "Data:%d, Scale:%g", Data[byte], val / 256.); m = menu_create(MENU_STRINGS, "ENVELOPE", tbuf, vbuf, 0, 0); dsi = envmenu(m, "SCALING", &Scale, val, byte, tsbuf, asbuf, dsbuf); d1i = envmenu(m, "OP 1", &Fmp.op[0].e, val, byte, t1buf, a1buf, d1buf); d2i = envmenu(m, "OP 2", &Fmp.op[1].e, val, byte, t2buf, a2buf, d2buf); i = (int) menu_show(m, window, event, 0); menu_destroy(m); if (i == (int) tsbuf) flipenv(&Scale, 1); else if (i == (int) asbuf) envadd(&Scale, val, byte); else if (i == (int) dsbuf) envdel(&Scale, dsi); else if (i == (int) t1buf) flipenv(&Fmp.op[0].e, 1); else if (i == (int) a1buf) envadd(&Fmp.op[0].e, val, byte); else if (i == (int) d1buf) envdel(&Fmp.op[0].e, d1i); else if (i == (int) t2buf) flipenv(&Fmp.op[1].e, 1); else if (i == (int) a2buf) envadd(&Fmp.op[1].e, val, byte); else if (i == (int) d2buf) envdel(&Fmp.op[1].e, d2i); return(0); } envmenu(m, name, ep, val, byte, tbuf, abuf, dbuf) Menu m; char *name, *tbuf, *abuf, *dbuf; struct estr *ep; { int i = -1; sprintf(tbuf, "%s: %s envelope?", name, ep->disp? "hide" : "display"); menu_set(m, MENU_STRING_ITEM, tbuf, tbuf, 0); if (ep->disp) { sprintf(abuf, " Add %g @ %d", val / 256., byte); menu_set(m, MENU_STRING_ITEM, abuf, abuf, 0); if (ep->num > 0) { for (i = 0; i < ep->num-1 && byte > ep->bpos[i]; i++); if (i > 0 && ep->bpos[i] - byte > byte - ep->bpos[i-1]) --i; sprintf(dbuf, " delete %g @ %d", ep->scale[i] / 256., ep->bpos[i]); menu_set(m, MENU_STRING_ITEM, dbuf, dbuf, 0); } } return(i); } envadd(ep, val, byte) /* add a new point */ struct estr *ep; { int i, j; flipenv(ep, 1); for (i = 0; i < ep->num && byte > ep->bpos[i]; i++); if (i < ep->num && byte == ep->bpos[i]) { if (val != ep->scale[i]) ep->scale[i] = val; } else if (ep->num >= NUMSCALE) { printf("Too many scale points.\n"); } else { if (i < ep->num) { for (j = ep->num; --j >= i; ) { ep->bpos[j+1] = ep->bpos[j]; ep->scale[j+1] = ep->scale[j]; } } ep->num++; ep->bpos[i] = byte; ep->scale[i] = val; } flipenv(ep, 1); } envdel(ep, i) /* delete old point */ struct estr *ep; { flipenv(ep, 1); for (--ep->num; i < ep->num; i++) { ep->bpos[i] = ep->bpos[i+1]; ep->scale[i] = ep->scale[i+1]; } flipenv(ep, 1); } mouseright(window, event) Window window; Event *event; { register int i, nbytes, change, fh, beg, end; char *fp, *bp, fbuf[128]; uchar buf[BPP]; change = 0; i = (int) menu_show(b3mp, window, event, 0); switch(i) { case PLAY: if (close(open(SEQFILE, 0)) < 0) { if ((fh = creat(SEQFILE, 0644)) < 0) { perror(SEQFILE); break; } else { buf[0] = 0; buf[1] = 0x90 | Chan; buf[2] = i; buf[3] = 0x40; buf[4] = 24; buf[5] = i; buf[6] = 0; for (i = 36; i < 97; i++) { buf[2] = buf[5] = i; write(fh, buf, 7); } close(fh); } } sprintf(buf, "play %s", SEQFILE); system(buf); break; case DUMP: if ((i = creat(WDRFILE, 0644)) < 0) { perror(WDRFILE); break; } buf[0] = SX_CMD; buf[1] = ID_ENSONIQ; buf[2] = ID_MIRAGE; buf[3] = MIR_SXF_REQ_WAVE; buf[4] = SX_EOB; write(i, buf, 5); close(i); strcpy(Oldfile, "/tmp/mfm.dmp"); sprintf(buf, "sxmpu <%s -r15 >%s", WDRFILE, Oldfile); system(buf); readdata(Oldfile); upmisc(); change++; break; case LOAD: if ((i = creat(TMPFILE, 0644)) < 0) { perror(TMPFILE); break; } sprintf(buf, "mirset 26=1 27=1 60=0 61=%d 72=61", Pcnt - 1); system(buf); writedata(i); close(i); sprintf(buf, "sxmpu <%s", TMPFILE); system(buf); fprintf(stderr, "\"%s\" written & sent\n", TMPFILE); break; case FM: change = fm(); break; case ROTL: nbytes = BPP * Pcnt; for (i = 0; i < Ramt; i++) buf[i] = Data[i]; for (i = Ramt; i < nbytes; i++) Data[i - Ramt] = Data[i]; for (i = 0; i < Ramt; i++) Data[nbytes - Ramt + i] = buf[i]; change++; break; case ROTR: nbytes = BPP * Pcnt; for (i = 0; i < Ramt; i++) buf[i] = Data[nbytes - Ramt + i]; for (i = nbytes; --i >= Ramt; ) Data[i] = Data[i - Ramt]; for (i = 0; i < Ramt; i++) Data[i] = buf[i]; change++; break; case TRIM: nbytes = BPP * Pcnt; for (beg = 0; beg < nbytes && Data[beg] == ZERO; beg++); for (end = nbytes; --end > beg && Data[end] == ZERO; ); if (beg > 0) for (i = beg; i < nbytes; i++) Data[i - beg] = Data[i]; Pcnt = (end - beg + BPP - 1) / BPP; upmisc(); change++; break; case SCALE: scale(0); change++; break; case UNSCALE: scale(1); change++; break; case NORMALIZE: nbytes = BPP * Pcnt; { int minv, maxv, den, q; minv = maxv = ZERO; for (i = nbytes; --i >= 0; ) { if (Data[i]) { if (Data[i] < minv) minv = Data[i]; else if (Data[i] > maxv) maxv = Data[i]; } } minv = ZERO - minv; maxv = maxv - ZERO; den = maxv > minv? maxv : minv; /****/fprintf(stderr, "scaling=%g\n", (float) 0x7F / den); if (den < 0x7F) { for (i = nbytes; --i >= 0; ) { if (Data[i] != 0) { q = D_TO_NUM(Data[i]); Data[i] = NUM_TO_D((q * 0x7F) / den); } } change++; } } break; case READ: printf("Filename? [%s] ", Oldfile); if (fgets(fbuf, sizeof fbuf, stdin)) { if (*fbuf && *fbuf != '\n') { for (fp = Oldfile, bp = fbuf; (*fp = *bp++) > ' '; fp++); *fp = '\0'; } readdata(Oldfile); upmisc(); change++; } break; case WRITE: if ((i = creat(OUTFILE, 0644)) < 0) perror(OUTFILE); else { writedata(i); close(i); fprintf(stderr, "\"%s\" written\n", OUTFILE); } break; case READDSC: printf("Filename? [%s] ", Oldfile); if (fgets(fbuf, sizeof fbuf, stdin)) { if (*fbuf && *fbuf != '\n') { for (fp = Oldfile, bp = fbuf; (*fp = *bp++) > ' '; fp++); *fp = '\0'; } readdsc(Oldfile); upmisc(); change++; } break; case WRITEDSC: if ((i = creat(OUTFILE, 0644)) < 0) perror(OUTFILE); else { writedsc(i); close(i); fprintf(stderr, "\"%s\" written in dsc format\n", OUTFILE); } break; case CONTROLS: i = (int) window_get(Controls, WIN_SHOW); window_set(Controls, WIN_SHOW, (TRUE + FALSE) - i, 0); window_set(Fmparms, WIN_SHOW, i, 0); break; case QUIT: quit(); break; } return(change); } scale(unflg) { register int i, d, s, b; int nbytes, lb, hb, db, ls, hs, ds, topb; nbytes = BPP * Pcnt; if (Scale.num < 1) return; if (Scale.num == 1) { s = Scale.scale[0]; s = s? s : 1; for (i = nbytes; --i >= 0; ) { if ((d = Data[i]) == 0) /* don't mess with 0 */ continue; d = D_TO_NUM(d); if (unflg) d = ((d << 8) + (s >> 1)) / s; else d = (d * s + 127) >> 8; d = NUM_TO_D(d); Data[i] = d <= 0? 1 : (d > 0xFF? 0xFF : d); } } else { for (i = 0; i <= Scale.num; i++) { if (i <= 0) { ls = Scale.scale[0]; lb = 0; } else { ls = Scale.scale[i-1]; lb = Scale.bpos[i-1]; if (lb >= nbytes) return; } if (i >= Scale.num) { hs = Scale.scale[Scale.num-1]; hb = 65536; } else { hs = Scale.scale[i]; hb = Scale.bpos[i]; } topb = hb >= nbytes? nbytes : hb; ds = hs - ls; db = hb - lb; if (ls != 256 || ds != 0) { for (b = lb; b < topb; b++) { if ((d = Data[b]) == 0) /* don't mess with 0 */ continue; d = D_TO_NUM(d); s = ls + (ds * (b - lb)) / db; if (s == 0) s = 1; if (unflg) d = ((d << 8) + (s >> 1)) / s; else d = (d * s + 127) >> 8; d = NUM_TO_D(d); Data[b] = d < 0? 1 : (d > 0xFF? 0xFF : d); } } } } } readdata(file) char *file; { register int i, j, nbytes; FILE *ifp; if (file && *file) { if ((ifp = sopen(file, "r")) == NULL) { perror(file); return(0); } } else { ifp = 0; sprintf(Oldfile, "BLANK"); } while (ifp) { /* find wavedata */ while ((i = fgetc(ifp)) != EOF && i != SX_CMD); if (i != SX_CMD) { fprintf(stderr, "no wavedata found in %s\n", file); exit(1); } if (fgetc(ifp) == ID_ENSONIQ && fgetc(ifp) == ID_MIRAGE && fgetc(ifp) == MIR_SXF_DAT_WAVE) break; } if (ifp) { Pcnt = fgetc(ifp); Pcnt += fgetc(ifp) << 4; } else Pcnt = 16; if (Pcnt <= 0 || Pcnt > 256) { fprintf(stderr, "Weird page count; %d\n", Pcnt); exit(1); } nbytes = BPP * Pcnt; if (Data) free(Data); if (!(Data = (uchar *) malloc(nbytes))) { fprintf(stderr, "malloc(%d) failed\n", nbytes); exit(3); } for (i = 0; i < nbytes; i++) { if (ifp) { j = fgetc(ifp); j += fgetc(ifp) << 4; } else j = ZERO; Data[i] = j; } if (ifp) fclose(ifp); Ppp = VIEWWIDTH / Pcnt; return(1); } writedata(fh) { register uchar *dp, *bp; register int csum; uchar buf[2 * BPP]; int p, i; csum = 0; bp = buf; *bp++ = RT_RESET; *bp++ = SX_CMD; *bp++ = ID_ENSONIQ; *bp++ = ID_MIRAGE; *bp++ = MIR_SXF_DAT_WAVE; *bp++ = (Pcnt & 0x0F); *bp++ = (Pcnt >> 4); csum = bp[-2] + bp[-1]; write(fh, buf, bp - buf); dp = Data; for (p = 0; p < Pcnt; p++) { bp = buf; for (i = 0; i < BPP; i++) { *bp = (*dp & 0x0F); csum += *bp++; *bp = (*dp++ & 0xF0) >> 4; csum += *bp++; } write(fh, buf, 512); csum &= 0x7F; } buf[0] = (csum & 0x7F); buf[1] = 0xF7; write(fh, buf, 2); } readdsc(file) char *file; { register int i, j, k, nbytes; char c; long rnbytes; struct stat statb; FILE *ifp; if (file && *file) { if ((ifp = sopen(file, "r")) == NULL) { perror(file); return(0); } } else return(readdata((char *) 0)); j = getc(ifp); k = getc(ifp); if (((k << 8) | j) != DSCMAGIC) { fprintf(stderr, "%s is not a DSC file\n", file); return(0); } if (fstat(fileno(ifp), &statb) < 0) { perror(file); return(0); } rnbytes = (statb.st_size - 2) / 2; /* ignore half of them 16->8 */ Pcnt = (rnbytes + BPP - 1) / BPP; if (Pcnt <= 0 || Pcnt > 256) { fprintf(stderr, "weird size; %d (pages)\n", Pcnt); exit(1); } nbytes = BPP * Pcnt; if (Data) free(Data); if (!(Data = (uchar *) malloc(nbytes))) { fprintf(stderr, "malloc(%d) failed\n", nbytes); exit(3); } for (i = 0; i < nbytes; i++) { if (ifp) { j = fgetc(ifp); /* low byte */ k = fgetc(ifp); /* high byte */ if (j == EOF || k == EOF) { fclose(ifp); ifp = 0; k = ZERO; } else { c = k; /* extend sign */ j = c + ((j & 0x80)? 1 : 0); /* half adjust */ k = j + ZERO; /* move 0 to ZERO */ } } else k = ZERO; Data[i] = (k > 0xFF? 0xFF : (k < 1? 1 : k)); } if (ifp) fclose(ifp); Ppp = VIEWWIDTH / Pcnt; return(1); } writedsc(fh) { register uchar *dp, *bp; uchar buf[2 * BPP]; int p, i; buf[0] = (DSCMAGIC & 0xFF); buf[1] = (DSCMAGIC >> 8); write(fh, buf, 2); dp = Data; for (p = 0; p < Pcnt; p++) { bp = buf; for (i = 0; i < BPP; i++) { *bp++ = 0; *bp++ = *dp++ - ZERO; /* move ZERO to 0 */ } write(fh, buf, bp - buf); } } quit() { while (ready_cursor()); exit(0); /*NOTREACHED*/ } /* ** FM - Simulate FM synthesis ** Simple, 2 operator model psl 3/88 ** +----fb-----+ ** | +------+ | +------+ ** +->| op1 |-+-g1-->| op2 |-g2-> ** f1->| env1 | f2->| env2 | ** +------+ +------+ ** args are: op1 freq, op1 gain, op2 freq, op2 gain, feedback */ #define PI 0x8000 fm() { register int t, nbytes, v, bpc; double w1, w2, ppr, fbg, og1, og2, o1, o2; struct estr *e1, *e2; double env(); extern double ipslsin(); Pcnt = Fmp.pcnt; nbytes = BPP * Pcnt; bpc = nbytes / Fmp.cycs; if (Data) free(Data); if (!(Data = (uchar *) malloc(nbytes))) { fprintf(stderr, "malloc(%d) failed\n", nbytes); return(0); } w1 = (Fmp.op[0].f * 0.02 * PI) / bpc; w2 = (Fmp.op[1].f * 0.02 * PI) / bpc; ppr = PI / 3.1415926535; /* PSLs per radian */ fbg = ppr * Fmp.fb / 100.; og1 = ppr * Fmp.op[0].g / 100.; og2 = 127 * Fmp.op[1].g / 100.; e1 = &Fmp.op[0].e; e2 = &Fmp.op[1].e; o1 = 0.; for (t = 0; t < nbytes; t++) { o2 = ipslsin((int) (w2 * t + og1 * env(e1, t) * o1 + 0.5)); o1 = ipslsin((int) (w1 * t + fbg * o1 + 0.5)); v = ZERO + og2 * env(e2, t) * o2; Data[t] = (v <= 0? 1 : (v > 255? 255 : v)); } Ppp = VIEWWIDTH / Pcnt; strcpy(Oldfile, "FM"); upmisc(); return(1); } double env(ep, t) /* return envelope amplitude at time t */ struct estr *ep; { register int i, ls, lb, ds, db, s; if ((i = ep->num) < 1) return(1.); if (i == 1) return(ep->scale[0] / 256.); for (i = ep->num; --i >= 0 && t < ep->bpos[i]; ); if (i < 0) return(ep->scale[0] / 256.); if (i == ep->num - 1 || t == ep->bpos[i]) return(ep->scale[i] / 256.); ls = ep->scale[i]; ds = ep->scale[i + 1] - ls; lb = ep->bpos[i]; db = ep->bpos[i + 1] - lb; s = ls + (ds * (t - lb) + (db >> 1)) / db; return(s / 256.); }