Timing is correct now! Forgot to update samples_per_tick when parsing the 0xf effect.
[pineappletracker.git] / gui.c
blob964fe2877e1cb78c0f90654c4396a35dcef06aa8
1 /* vi:set ts=8 sts=8 sw=8 noexpandtab: */
3 /* welcome to gui.c, enjoy your stay 8-) */
5 #include "pineapple.h"
6 #include "filetypes.h"
7 #include "gui.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <math.h>
13 #include <curses.h>
14 #include <unistd.h>
15 #include <ctype.h>
17 #ifndef WINDOWS
18 #include <err.h>
19 #endif
22 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
23 \\\ local vars .\
24 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
25 char *dispmesg = "";
27 static char *notenames[] = {"C-", "C#", "D-", "D#", "E-", "F-", "F#",
28 "G-", "G#", "A-", "A#", "H-"};
30 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
31 \\\ local functions .\
32 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
33 int _char2int(char ch);
34 void _display(void);
36 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
37 \\\ end local declarations .\
38 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
40 char cmdstr[500] = "";
42 int disptick = 0;
43 int currmode = PM_NORMAL;
44 int octave = 4;
45 int songlen = 1;
46 int tracklen = TRACKLEN;
47 int currtrack = 1;
48 int currinstr = 1;
49 int currtab = 0;
50 int saved = 1;
52 int step = 1;
54 int cmdrepeat = 0;
55 int cmdrepeatnum = 1;
56 int lastrepeat = 1;
58 // 0 is like a blank command
59 char *validcmds = "0dfi@smtvw~+=*";
61 /*char *keymap[2] = {
62 ";oqejkixdbhmwnvsz",
63 "'2,3.p5y6f7gc9r0l/="
64 };*/
66 char *keymap[2] = {
67 "zsxdcvgbhnjm,l.;/",
68 "q2w3er5t6y7ui9o0p"
71 /* hexinc and hexdec wrap around */
72 int hexinc(int x){
73 return (x >= 0 && x <= 14)? x+1 : 0;
75 int hexdec(int x){
76 return (x >= 1 && x <= 15)? x-1 : 15;
79 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
80 \\\ < int _char2int(char) > .|
81 /// .\
82 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
83 int _char2int(char ch){
84 if(isdigit(ch)){
85 return (int)ch - '0';
87 return -1;
90 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
91 \\\ < int freqkey(int) > .|
92 /// Calculates the frequency of key c. .\
93 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
94 int freqkey(int c){
95 char *s;
96 int f = -1;
98 if(c == '-' || c == KEY_DC) return 0;
99 if(c > 0 && c < 256){
100 s = strchr(keymap[0], c);
101 if(s){
102 f = (s - (keymap[0])) + octave * 12 + 1;
103 }else{
104 s = strchr(keymap[1], c);
105 if(s){
106 f = (s - (keymap[1])) + octave * 12 + 12 + 1;
110 if(f > 12 * 9 + 1) return -1;
111 return f;
114 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
115 \\\ < void initsonglines() > .|
116 /// . .\
117 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
118 void initsonglines(void){
119 for(int i=0; i < songlen; i++){
120 memmove(&tune->sng[i + 0], &tune->sng[i + 1], sizeof(struct songline) * (songlen - i - 1));
121 if(i < 4){
122 tune->sng[0].track[i] = 0x00;
123 tune->sng[0].transp[i] = 0x00;
126 songlen = 1;
129 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
130 \\\ < void inittracks() > .\
131 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
132 void inittracks(void){
133 for(int i=0; i < 256; i++){
134 for(int j=0; j < TRACKLEN; j++){
135 tune->trk[i].line[j].note = 0x00;
136 tune->trk[i].line[j].instr = 0x00;
137 for(int k=0; k < 2; k++){
138 tune->trk[i].line[j].cmd[k] = 0x0000;
139 tune->trk[i].line[j].param[k] = 0x0000;
145 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
146 \\\ < void initinstrs() > .\
147 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
148 void initinstrs(void){
149 for(int i=1; i < 256; i++){
150 instrument[i].length = 1;
151 instrument[i].line[0].cmd = '0';
152 instrument[i].line[0].param = 0;
156 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
157 \\\ < void readsong(int,int,u8) > .\
158 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
159 void readsong(int pos, int ch, u8 *dest){
160 dest[0] = tune->sng[pos].track[ch];
161 dest[1] = tune->sng[pos].transp[ch];
165 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
166 \\\ < void readinstr(int,int,u8) > .\
167 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
168 void readinstr(int num, int pos, u8 *il){
169 if(pos >= instrument[num].length){
170 il[0] = 0;
171 il[1] = 0;
172 }else{
173 il[0] = instrument[num].line[pos].cmd;
174 il[1] = instrument[num].line[pos].param;
178 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
179 \\\ < void exitgui() > .|
180 /// Exits the gui. .\
181 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
182 void exitgui(){
183 endwin();
186 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
187 \\\ < void initgui() > .|
188 /// Initializes the gui. .\
189 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
190 void initgui(){
191 initscr();
193 //if(setlocale(LC_CTYPE,"en_US.utf8") != NULL){
194 // setdisplay("UTF-8 enabled!");
197 // don't send newline on Enter key, and don't echo chars to the screen.
198 nonl();
199 noecho();
201 // make sure behaviour for special keys like ^H isn't overridden
202 keypad(stdscr, FALSE);
204 nodelay(stdscr, TRUE);
206 //initinstrs();
208 atexit(exitgui);
211 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
212 \\\ < void handleinput() > .|
213 /// Main input loop. .\
214 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
215 void handleinput(void){
216 int c;
218 //if(currmode == PM_NORMAL){
219 if((c = getch()) != ERR){
221 // Repeat
222 if(isdigit(c)){
223 if(!cmdrepeat){
224 cmdrepeat = 1;
225 cmdrepeatnum = _char2int(c);
226 }else{
227 cmdrepeatnum = (cmdrepeatnum*10) + _char2int(c);
229 }else{
230 normalmode(c);
235 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
236 \\\ < char nextchar() > .|
237 /// Wait for the next keyboard char and return it. .\
238 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
239 char nextchar(void){
240 char ch;
241 ch = getch();
242 while (ch == ERR){
243 ch = getch();
244 if(ch != ERR )
245 return ch;
247 return ch;
250 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
251 \\\ < void setdisplay(char*) > .|
252 /// Sets a message to be popped up for a while. .\
253 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
254 void setdisplay(char *str){
255 disptick = 350;
256 dispmesg = str;
259 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
260 \\\ < void drawgui() > .|
261 /// Draw all text and graphix to the screen. .\
262 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
263 void drawgui(){
264 char buf[1024];
265 int lines = LINES;
266 int songcols[] = {0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21, 22};
267 int trackcols[] = {0, 2, 4, 5, 7, 8, 9, 11, 12, 13};
268 int instrcols[] = {0, 2, 3};
269 u8 tempo;
271 erase();
272 attrset(A_UNDERLINE);
273 mvaddstr(0, 0, "PINEAPPLEtRACKER");
274 attrset(A_NORMAL);
276 // display track num
277 mvaddch(0, 31, ACS_ULCORNER);
278 snprintf(buf, sizeof(buf), "%02x{}", currtrack);
279 mvaddstr(0, 32, buf);
280 drawtracked(29, 1, lines - 2);
282 // display instrument num
283 mvaddch(0, 51, ACS_ULCORNER);
284 snprintf(buf, sizeof(buf), "%02x[]", currinstr);
285 mvaddstr(0, 52, buf);
286 drawinstred(49, 1, lines - 2);
288 mvaddstr(1, 0, "Song");
289 drawsonged(0, 1, lines - 2);
291 // just a wild guess here..
292 tempo = callbacktime * (-1) + 300;
293 // display tempo
294 mvaddch(0, 17, ACS_DEGREE);
295 snprintf(buf, sizeof(buf), "%d()", tempo);
296 mvaddstr(0, 18, buf);
298 // display octave
299 mvaddch(0, 24, ACS_PI);
300 snprintf(buf, sizeof(buf), "%d<>", octave);
301 mvaddstr(0, 25, buf);
303 // display step amount
304 mvaddstr(0, 60, "step -=");
305 snprintf(buf, sizeof(buf), "%0x", step);
306 mvaddstr(0, 68, buf);
308 // display comment
309 mvaddstr(2, 60, "comment:");
310 snprintf(buf, sizeof(buf), "%s", comment);
311 mvaddstr(3, 60, buf);
313 if(currmode == PM_NORMAL){
314 mvaddstr(getmaxy(stdscr)-1, 0, filename);
315 if(!saved && currmode != PM_INSERT){
316 addstr(" [+]");
317 infinitemsg = NULL;
321 if(disptick > 0){
322 _display();
323 disptick--;
326 if(currmode == PM_INSERT){
327 infinitemsg = NULL;
329 move(getmaxy(stdscr)-1,0);
330 clrtoeol();
331 mvaddstr(getmaxy(stdscr)-1, 0, "-- INSERT --");
332 }else if(currmode == PM_VISUAL){
333 infinitemsg = NULL;
335 move(getmaxy(stdscr)-1,0);
336 clrtoeol();
337 mvaddstr(getmaxy(stdscr)-1, 0, "-- VISUAL --");
338 }else if(currmode == PM_VISUALLINE){
339 infinitemsg = NULL;
341 move(getmaxy(stdscr)-1,0);
342 clrtoeol();
343 mvaddstr(getmaxy(stdscr)-1, 0, "-- VISUAL LINE --");
344 }else if(currmode == PM_JAMMER){
345 infinitemsg = NULL;
347 move(getmaxy(stdscr)-1,0);
348 clrtoeol();
349 mvaddstr(getmaxy(stdscr)-1, 0, "-- JAMMER --");
350 }else if(currmode == PM_CMDLINE){
351 infinitemsg = NULL;
353 move(getmaxy(stdscr)-1,0);
354 clrtoeol();
355 mvaddstr(getmaxy(stdscr) - 1, 0, cmdstr);
356 }else if(infinitemsg != NULL){
357 move(getmaxy(stdscr)-1,0);
358 clrtoeol();
359 mvaddstr(getmaxy(stdscr) - 1, 0, infinitemsg);
362 switch(currtab){
363 case 0:
364 move(1 + songy - songoffs, 0 + 4 + songcols[songx]);
365 break;
366 case 1:
367 move(1 + tracky - trackoffs, 29 + 4 + trackcols[trackx]);
368 break;
369 case 2:
370 move(1 + instry - instroffs, 49 + 4 + instrcols[instrx]);
371 break;
374 refresh();
376 if(disptick > 0){
377 disptick--;
381 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
382 \\\ < void *spin_input(void *) > .|
383 /// Pass this function to a thread to get the next key without blocking the .\
384 \\\ the gui. .\
385 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
386 /*void *spin_input(void *tid){
387 for(;;){
388 handleinput();
389 msleep(500);
393 void *spin_gui(void *tid){
394 for(;;){
395 drawgui();
396 msleep(50000);
400 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
401 \\\ < void eventloop() > .|
402 /// Main event loop .\
403 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
404 void eventloop(void){
405 #ifndef WINDOWS
406 ESCDELAY = 50;
407 #endif
408 for(;;){
409 drawgui();
410 handleinput();
414 //--------------------------------------------------------------------------\\
415 // this is when i tried to make separate threads for the screen and the
416 // input
417 //--------------------------------------------------------------------------//
418 //TODO: figure out a method where we don't have to use usleep()... the
419 // screen also jitters sometimes
420 /*void eventloop(void){
421 int rc;
422 pthread_t inputthread;
423 pthread_t guithread;
424 pthread_attr_t attr;
426 // make it detached ... we won't need to join it
427 pthread_attr_init(&attr);
428 pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
430 rc = pthread_create(&inputthread,&attr,spin_input,(void *)0);
431 if(rc)
432 setdisplay("Uh oh!!! thread please");
434 rc = pthread_create(&guithread,&attr,spin_gui,(void *)0);
436 #ifndef WINDOWS
437 // don't treat the escape key like a meta key
438 ESCDELAY = 50;
439 #endif
441 for(;;){
442 msleep(1000);
446 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
447 \\\ Internal functions .\
448 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
450 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
451 \\\ < void _display() > .|
452 /// Display dispmesg in the center of the screen. .\
453 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
454 void _display(void){
455 int cx = (getmaxx(stdscr)/2)-(strlen(dispmesg)/2)-1;
456 int cy = getmaxy(stdscr)/2;
458 mvaddch(cy-1, cx, ACS_ULCORNER);
459 for(int i=cx+1; i<cx+strlen(dispmesg)+1; i++)
460 mvaddch(cy-1, i, ACS_HLINE);
461 mvaddch(cy-1, cx+strlen(dispmesg)+1, ACS_URCORNER);
463 mvaddch(cy, cx, ACS_VLINE);
464 mvaddstr(cy, cx+1, dispmesg);
465 mvaddch(cy, cx+strlen(dispmesg)+1, ACS_VLINE);
467 mvaddch(cy+1, cx, ACS_LLCORNER);
468 for(int i=cx+1; i<cx+strlen(dispmesg)+1; i++)
469 mvaddch(cy+1, i, ACS_HLINE);
470 mvaddch(cy+1, cx+strlen(dispmesg)+1, ACS_LRCORNER);
473 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
474 \\\ < void drawsonged(int,int,int) > .|
475 /// Draws the song editor. .\
476 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
477 void drawsonged(int x, int y, int height){
478 int i, j;
479 char buf[1024];
480 //NODE *match;
482 if(songy < songoffs) songoffs = songy;
483 if(songy >= songoffs + height) songoffs = songy - height + 1;
485 for(i = 0; i < tune->songlen; i++){
486 if(i >= songoffs && i - songoffs < height){
487 move(y + i - songoffs, x + 0);
488 if(i == songy) attrset(A_BOLD);
490 snprintf(buf, sizeof(buf), "%02x", i);
492 if(i == 0){ addch(ACS_ULCORNER); }
493 else if(i == tune->songlen-1){ addch(ACS_LLCORNER); }
494 else if(i%4 == 0){ addch(ACS_LTEE); }
495 else if(i < tune->songlen-1){ addch(ACS_VLINE); }
496 addch(' ');
498 // should this line be highlighted?
499 //if( (match = list_contains(highlightlines, findu8, &i)) ){
500 if( currtab == 0 && currmode == PM_VISUALLINE &&
501 ((i <= highlight_firstline && i >= highlight_lastline)
502 || (i >= highlight_firstline && i <= highlight_lastline)) ){
503 attrset(A_REVERSE);
506 addstr(buf);
507 for(j = 0; j < 4; j++){
508 snprintf(buf, sizeof(buf), "%02x:%02x", tune->sng[i].track[j], tune->sng[i].transp[j]);
509 addstr(buf);
510 if(j != 3) addch(' ');
512 if(tune->type == LFT){
513 if(playsong && tune->songpos == (i+1)){
514 attrset(A_STANDOUT);
515 addch('*');
517 }else if(tune->type == AHX){
518 if(playsong && tune->songpos == (i)){
519 attrset(A_STANDOUT);
520 addch('*');
523 attrset(A_NORMAL);
528 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
529 \\\ < void drawtracked(int,int,int) > .|
530 /// Draws the track editor. .\
531 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
532 void drawtracked(int x, int y, int height){
533 u8 i, j;
534 char buf[1024];
536 if(tracky < trackoffs) trackoffs = tracky;
537 if(tracky >= trackoffs + height) trackoffs = tracky - height + 1;
539 for(i = 0; i < tune->tracklen; i++){
540 if(i >= trackoffs && i - trackoffs < height){
541 move(y + i - trackoffs, x + 0);
542 if(i == tracky) attrset(A_BOLD);
544 snprintf(buf, sizeof(buf), "%02x", i);
545 addstr(buf);
547 if(i == 0){ addch(ACS_LLCORNER); }
548 else if(i == 1){ addch(ACS_ULCORNER); }
549 else if(i == tune->tracklen-1){ addch(ACS_LLCORNER); }
550 else if(i%4 == 0){ addch(ACS_LTEE); }
551 else if(i < tune->tracklen-1){ addch(ACS_VLINE); }
552 addch(' ');
554 // should this line be highlighted?
555 //if( (match = list_contains(highlightlines, findu8, &i)) ){
556 if(currtab == 1 && currmode == PM_VISUALLINE
557 && ((i <= highlight_firstline && i >= highlight_lastline)
558 || (i >= highlight_firstline && i <= highlight_lastline)) ){
559 attrset(A_REVERSE);
562 if (currtab == 1 && currmode == PM_VISUAL)
563 attrset(A_REVERSE);
565 if(tune->trk[currtrack].line[i].note){
566 snprintf(buf, sizeof(buf), "%s%d",
567 notenames[(tune->trk[currtrack].line[i].note - 1) % 12],
568 (tune->trk[currtrack].line[i].note - 1) / 12);
569 }else{
570 snprintf(buf, sizeof(buf), "---");
572 addstr(buf);
573 snprintf(buf, sizeof(buf), " %02x", tune->trk[currtrack].line[i].instr);
574 addstr(buf);
575 for(j = 0; j < 2; j++){
576 if(tune->trk[currtrack].line[i].cmd[j]){
577 //this is pretty dumb just checking the type, we can probably
578 //do something better like make cmd more generic somehow...
579 if(tune->type == LFT) {
580 snprintf(buf, sizeof(buf), " %c%02x",
581 tune->trk[currtrack].line[i].cmd[j],
582 tune->trk[currtrack].line[i].param[j]);
583 }else if(tune->type == AHX) {
584 snprintf(buf, sizeof(buf), " %02x%02x",
585 tune->trk[currtrack].line[i].cmd[j],
586 tune->trk[currtrack].line[i].param[j]);
588 }else{
589 snprintf(buf, sizeof(buf), " ...");
591 addstr(buf);
593 if(playtrack && ((i + 1) % tune->tracklen) == trackpos){
594 attrset(A_STANDOUT);
595 addch('*');
597 attrset(A_NORMAL);
602 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
603 \\\ < void drawinstred(int,int,int) > .|
604 /// Draws the instrument editor. .\
605 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
606 void drawinstred(int x, int y, int height){
607 u8 i;
608 char buf[1024];
610 if(instry >= instrument[currinstr].length) instry = instrument[currinstr].length - 1;
612 if(instry < instroffs) instroffs = instry;
613 if(instry >= instroffs + height) instroffs = instry - height + 1;
615 for(i = 0; i < instrument[currinstr].length; i++){
616 if(i >= instroffs && i - instroffs < height){
617 move(y + i - instroffs, x + 0);
618 if(i == instry) attrset(A_BOLD);
620 snprintf(buf, sizeof(buf), "%02x", i);
621 addstr(buf);
623 if(i == 0){ addch(ACS_LLCORNER); }
624 else if(i == 1){ addch(ACS_ULCORNER); }
625 else if(i == instrument[currinstr].length-1){ addch(ACS_LLCORNER); }
626 else if(i < instrument[currinstr].length-1){ addch(ACS_VLINE); }
627 addch(' ');
629 // should this line be highlighted?
630 //if( (match = list_contains(highlightlines, findu8, &i)) ){
631 if( currtab == 2 && currmode == PM_VISUALLINE &&
632 ((i <= highlight_firstline && i >= highlight_lastline)
633 || (i >= highlight_firstline && i <= highlight_lastline)) ){
634 attrset(A_REVERSE);
637 snprintf(buf, sizeof(buf), "%c ", instrument[currinstr].line[i].cmd);
638 addstr(buf);
639 if(instrument[currinstr].line[i].cmd == '+' || instrument[currinstr].line[i].cmd == '='){
640 if(instrument[currinstr].line[i].param){
641 snprintf(buf, sizeof(buf), "%s%d",
642 notenames[(instrument[currinstr].line[i].param - 1) % 12],
643 (instrument[currinstr].line[i].param - 1) / 12);
644 }else{
645 snprintf(buf, sizeof(buf), "---");
647 }else{
648 snprintf(buf, sizeof(buf), "%02x", instrument[currinstr].line[i].param);
650 addstr(buf);
651 attrset(A_NORMAL);