Just some notes and SPEC stuff.
[pineappletracker.git] / modes.c
blob3dd286f242110feec23fa59aae681814bebf1f49
1 /* vi:set syntax= ts=8 sts=8 sw=8 noexpandtab: */
2 /* WARNING: this file is ROSS STYLE */
4 #include "pineapple.h"
5 #include "gui.h"
6 #include "musicchip_file.h"
8 #include <curses.h>
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
14 int f;
15 int tcliplen, icliplen = 0;
16 int lastinsert = 0;
18 int hexdigit(char c){
19 if(c >= '0' && c <= '9') return c - '0';
20 if(c >= 'a' && c <= 'f') return c - 'a' + 10;
21 return -1;
24 int nextfreetrack(){
25 int skiptherest = 0;
27 for(int i = 1; i <= 0xff; i++){
28 for(int j = 0; j < tracklen; j++){
29 if(track[i].line[j].note) skiptherest = 1;
30 for(int k = 0; k < 2; k++){
31 if(track[i].line[j].cmd[k]) skiptherest = 1;
32 if(track[i].line[j].param[k]) skiptherest = 1;
35 // skip the rest of this track?
36 if(skiptherest){
37 skiptherest = 0;
38 break;
41 // this track is free, so return the index
42 if(j == tracklen-1) return i;
46 setdisplay("nextfreetrack() failed somehow..");
47 return -1;
50 int nextfreeinstr(){
51 for(int i = 1; i <= 0xff; i++){
52 if(instrument[i].line[0].cmd == '0')
53 return i;
56 setdisplay("nextfreeinstr() failed somehow..");
57 return -1;
60 void _insertc(int c){
61 int x;
63 x = hexdigit(c);
64 if(x >= 0){
65 if(currtab == 2
66 && instrx > 0
67 && instrument[currinstr].line[instry].cmd != '+'
68 && instrument[currinstr].line[instry].cmd != '='){
69 switch(instrx){
70 case 1: SETHI(instrument[currinstr].line[instry].param, x); break;
71 case 2: SETLO(instrument[currinstr].line[instry].param, x); break;
74 if(currtab == 1 && trackx > 1){
75 switch(trackx){
76 case 2: SETHI(track[currtrack].line[tracky].instr, x); break;
77 case 3: SETLO(track[currtrack].line[tracky].instr, x); break;
78 case 5: if(track[currtrack].line[tracky].cmd[0])
79 SETHI(track[currtrack].line[tracky].param[0], x); break;
80 case 6: if(track[currtrack].line[tracky].cmd[0])
81 SETLO(track[currtrack].line[tracky].param[0], x); break;
82 case 8: if(track[currtrack].line[tracky].cmd[1])
83 SETHI(track[currtrack].line[tracky].param[1], x); break;
84 case 9: if(track[currtrack].line[tracky].cmd[1])
85 SETLO(track[currtrack].line[tracky].param[1], x); break;
88 if(currtab == 0){
89 switch(songx & 3){
90 case 0: SETHI(song[songy].track[songx / 4], x); break;
91 case 1: SETLO(song[songy].track[songx / 4], x); break;
92 case 2: SETHI(song[songy].transp[songx / 4], x); break;
93 case 3: SETLO(song[songy].transp[songx / 4], x); break;
97 x = freqkey(c);
98 if(x >= 0){
99 if(currtab == 2
100 && instrx
101 && (instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '=')){
102 instrument[currinstr].line[instry].param = x;
104 if(currtab == 1 && !trackx){
105 track[currtrack].line[tracky].note = x;
106 if(x){
107 track[currtrack].line[tracky].instr = currinstr;
108 }else{
109 track[currtrack].line[tracky].instr = 0;
111 if(x) iedplonk(x, currinstr);
114 if(currtab == 2 && instrx == 0){
115 if(strchr(validcmds, c))
116 instrument[currinstr].line[instry].cmd = c;
118 if(currtab == 1 && (trackx == 4 || trackx == 7)){
119 if(strchr(validcmds, c)){
120 if(c == '.' || c == '0') c = 0;
121 track[currtrack].line[tracky].cmd[(trackx - 3) / 3] = c;
124 // for repeat
125 lastinsert = c;
128 // isnumber() determines if a string is a number
129 // returns 1 if the given arg is a number, 0 otherwise.
130 // for use with isdigit(), isxdigit(), etc...
131 int isnumber(const char* str, int (*func) (int)){
132 int i = 0;
134 for(;;){
135 if( func(str[i]) ){
136 i++;
137 }else if( str[i]=='\0' ){
138 return 1;
139 }else{
140 return 0;
145 // Converts a hexadecimal string to integer
146 // return values:
147 // 0: conversion successful
148 // 1: string is empty
149 // 2: string has more than 8 bytes
150 // 4: Conversion is in process but abnormally terminated by
151 // illegal hexadecimal character
152 // from http://devpinoy.org/blogs/cvega/archive/2006/06/19/xtoi-hex-to-integer-c-function.aspx
153 int xtoi(const char* xs, unsigned int* result){
154 size_t szlen = strlen(xs);
155 int i, xv, fact;
157 if(szlen > 0){
158 // Converting more than 32bit hexadecimal value?
159 if (szlen>8) return 2; // exit
161 // Begin conversion here
162 *result = 0;
163 fact = 1;
165 // Run until no more character to convert
166 for(i=szlen-1; i>=0 ;i--){
167 if(isxdigit(*(xs+i))){
168 if (*(xs+i)>=97){
169 xv = ( *(xs+i) - 97) + 10;
170 }else if( *(xs+i) >= 65){
171 xv = (*(xs+i) - 65) + 10;
172 }else{
173 xv = *(xs+i) - 48;
175 *result += (xv * fact);
176 fact *= 16;
177 }else{
178 // Conversion was abnormally terminated
179 // by non hexadecimal digit, hence
180 // returning only the converted with
181 // an error value 4 (illegal hex character)
182 return 4;
186 // Nothing to convert
187 return 1;
190 void _parsecmd(char cmd[]){
191 //if(cmd[1] == 'w'){
192 //switch(strcmp(cmd,
193 if(strcmp(cmd, ":w") == 0){
194 savefile(filename);
195 saved = 1;
196 }else if(strcmp(cmd, ":q") == 0){
197 if(!saved){
198 setdisplay("no write since last change! use :q! to override");
199 }else{
200 erase();
201 refresh();
202 endwin();
203 exit(0);
205 }else if(strcmp(cmd, ":q!") == 0){
206 erase();
207 refresh();
208 endwin();
209 exit(0);
210 }else if(strcmp(cmd, ":write") == 0){
211 savefile(filename);
212 saved = 1;
213 }else if(strcmp(cmd, ":wq") == 0){
214 savefile(filename);
215 saved = 1;
216 erase();
217 refresh();
218 endwin();
219 exit(0);
220 }else if(strcmp(cmd, ":quit") == 0){
221 erase();
222 refresh();
223 endwin();
224 exit(0);
225 }else if(cmd[1]=='e' && cmd[2]==' '){
226 // if the file doesn't exist, clear the song
227 if(loadfile(cmd+3)){
228 initsonglines();
229 inittracks();
230 initinstrs();
232 //yucky if statement below.....probably better way to do it
233 // maybe this is better??
234 }else if(!strncmp(cmd+1,"save ",5)){
235 saveinstrument(cmd+6);
236 setdisplay("d-_-b saved ins! d-_-b");
237 }else if(!strncmp(cmd+1,"load ",5)){
238 loadinstrument(cmd+6);
239 setdisplay("d-_-b loaded ins! d-_-b");
240 }else if( isnumber((char *)cmd+1,isxdigit) ){
241 unsigned int goton = 1;
242 xtoi(cmd+1,&goton);
244 switch(currtab){
245 case 0:
246 songy = (goton>songlen)? songlen-1 : goton;
247 break;
248 case 1:
249 currtrack = (goton>0xff)? 0xff : goton;
250 break;
251 case 2:
252 currinstr = (goton>0xff)? 0xff : goton;
253 break;
255 }else if(cmd[1] == 'c' && cmd[2] == ' '){
256 strncpy(comment, cmd+3, sizeof(comment));
257 }else
258 setdisplay("not a tracker command!");
259 return;
262 /* normal mode */
263 void normalmode(int c){
264 int i;
266 // don't save the action for repeat if it's a movement or a repeat, or
267 // something else that doesnt make sense to repeat
268 if(c != 'h' &&
269 c != 'j' &&
270 c != 'k' &&
271 c != 'l' &&
272 c != CTRL('D') &&
273 c != CTRL('U') &&
274 c != CTRL('H') &&
275 c != CTRL('L') &&
276 c != 'H' &&
277 c != 'M' &&
278 c != 'L' &&
279 c != 'g' &&
280 c != 'G' &&
281 c != '.'){
282 lastaction = c;
283 lastrepeatnum = cmdrepeatnum;
286 for(i=0; i<cmdrepeatnum; i++){
287 switch(c){
288 /* add line */
289 case 'a':
290 if(currtab == 2){
291 struct instrument *in = &instrument[currinstr];
293 if(in->length < 256){
294 memmove(&in->line[instry + 2], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
295 instry++;
296 in->length++;
297 in->line[instry].cmd = '0';
298 in->line[instry].param = 0;
300 }else if(currtab == 0){
301 if(songlen < 256){
302 memmove(&song[songy + 2], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
303 songy++;
304 songlen++;
305 memset(&song[songy], 0, sizeof(struct songline));
308 break;
309 case '.':
310 // if the last command was a replace, just insert the last thing
311 // inserted instead of calling insertmode()
312 if(lastaction == 'r')
313 _insertc(lastinsert);
314 else
315 normalmode(lastaction);
316 cmdrepeatnum = lastrepeatnum;
317 break;
318 case KEY_ESCAPE:
319 disptick = 0;
320 jammermode();
321 break;
322 case CTRL('Y'):
323 switch(currtab){
324 case 0:
325 if(songoffs>0){
326 if(songy==getmaxy(stdscr)-3+songoffs)
327 songy--;
328 songoffs--;
330 break;
331 case 1:
332 if(trackoffs>0){
333 if(tracky==getmaxy(stdscr)-3+trackoffs)
334 tracky--;
335 trackoffs--;
337 break;
338 case 2:
339 if(instroffs>0){
340 if(instry==getmaxy(stdscr)-3+instroffs)
341 instry--;
342 instroffs--;
344 break;
346 break;
347 case CTRL('E'):
348 switch(currtab){
349 case 0:
350 if(songy<=songlen-2){
351 if(songy==songoffs)
352 songy++;
353 songoffs++;
355 break;
356 case 1:
357 if(tracky<=tracklen-2){
358 if(tracky==trackoffs)
359 tracky++;
360 trackoffs++;
362 break;
363 case 2:
364 if(instry<=instrument[currinstr].length-2){
365 if(instry==instroffs)
366 instry++;
367 instroffs++;
369 break;
371 break;
372 case 'H':
373 switch(currtab){
374 case 0:
375 songy = songoffs;
376 break;
377 case 1:
378 tracky = trackoffs;
379 break;
380 case 2:
381 instry = instroffs;
382 break;
384 break;
386 // the second cases (to the right of the colon) for M and L
387 // took some serious guesswork, so I'm not sure if they're
388 // correct but they seem to work.
389 case 'M':
390 switch(currtab){
391 case 0:
392 songy = (songlen <= getmaxy(stdscr)-2)?
393 songlen/2
394 : ((getmaxy(stdscr)-6)/2) + songoffs;
395 break;
396 case 1:
397 tracky = (tracklen <= getmaxy(stdscr)-2)?
398 tracklen/2
399 : ((getmaxy(stdscr)-6)/2) + trackoffs;
400 break;
401 case 2:
402 instry = (instrument[currinstr].length <= getmaxy(stdscr)-2)?
403 instrument[currinstr].length/2
404 : ((getmaxy(stdscr)-6)/2) + instroffs;
405 break;
407 break;
408 case 'L':
409 switch(currtab){
410 case 0:
411 songy = (songlen <= getmaxy(stdscr)-2)?
412 songlen-1
413 : getmaxy(stdscr)-3+songoffs;
414 break;
415 case 1:
416 tracky = (tracklen <= getmaxy(stdscr)-2)?
417 tracklen-1
418 : getmaxy(stdscr)-3+trackoffs;
419 break;
420 case 2:
421 instry = (instrument[currinstr].length <= getmaxy(stdscr)-2)?
422 instrument[currinstr].length-1
423 : getmaxy(stdscr)-3+instroffs;
424 break;
426 break;
427 case 'g':
428 if(nextchar() == 'g'){
429 act_mvtop();
431 break;
432 case 'G':
433 act_mvbottom();
434 break;
436 // yank
437 case 'y':
438 c = nextchar();
439 switch(c){
440 case 'y':
441 //tclip = malloc(1);
442 if(currtab == 0){
443 tcliplen = 1;
444 memcpy(&tclip, &song[songy], sizeof(struct songline));
445 }else if(currtab == 1){
446 tcliplen = 1;
447 memcpy(&tclip, &track[currtrack].line[tracky], sizeof(struct trackline));
448 }else if(currtab == 2){
449 icliplen = 1;
450 memcpy(&iclip, &instrument[currinstr].line[instry], sizeof(struct instrline));
452 break;
453 case 'j':
454 //tclip = malloc(2);
455 if(currtab == 0){
456 tcliplen = 2;
457 memcpy(&tclip[0], &song[songy], sizeof(struct songline));
458 act_mvdown();
459 memcpy(&tclip[1], &song[songy], sizeof(struct songline));
460 }else if(currtab == 1){
461 tcliplen = 2;
462 memcpy(&tclip[0], &track[currtrack].line[tracky], sizeof(struct trackline));
463 act_mvdown();
464 memcpy(&tclip[1], &track[currtrack].line[tracky], sizeof(struct trackline));
465 }else if(currtab == 2){
466 icliplen = 2;
467 memcpy(&iclip[0], &instrument[currinstr].line[instry], sizeof(struct instrline));
468 act_mvdown();
469 memcpy(&iclip[1], &instrument[currinstr].line[instry], sizeof(struct instrline));
471 break;
472 case 'k':
473 //tclip = malloc(2);
474 if(currtab == 0){
475 tcliplen = 2;
476 memcpy(&tclip[1], &song[songy], sizeof(struct songline));
477 act_mvup();
478 memcpy(&tclip[0], &song[songy], sizeof(struct songline));
479 }else if(currtab == 1){
480 tcliplen = 2;
481 memcpy(&tclip[1], &track[currtrack].line[tracky], sizeof(struct trackline));
482 act_mvup();
483 memcpy(&tclip[0], &track[currtrack].line[tracky], sizeof(struct trackline));
484 }else if(currtab == 2){
485 icliplen = 2;
486 memcpy(&iclip[1], &instrument[currinstr].line[instry], sizeof(struct instrline));
487 act_mvup();
488 memcpy(&iclip[0], &instrument[currinstr].line[instry], sizeof(struct instrline));
490 break;
492 break;
494 //paste
495 case 'p':
496 if(currtab == 0){
497 if(songlen < 256){
498 for(int i = 0; i < tcliplen; i++){
499 // insert new line
500 memmove(&song[songy + 2], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
501 songy++;
502 songlen++;
503 memset(&song[songy], 0, sizeof(struct songline));
505 // paste to new line
506 memcpy(&song[songy], &tclip[i], sizeof(struct songline));
509 }else if(currtab == 1){
510 for(int i = 0; i < tcliplen; i++){
511 memcpy(&track[currtrack].line[tracky], &tclip[i], sizeof(struct trackline));
512 if(tracky < tracklen-step) tracky += step;
513 else tracky = tracklen-1;
515 }else if(currtab == 2){
516 if(instrument[currinstr].length < 256){
517 // insert new line
518 for(int i = 0; i < icliplen; i++){
519 struct instrument *in = &instrument[currinstr];
521 instry++;
522 memmove(&in->line[instry + 1], &in->line[instry + 0], sizeof(struct instrline) * (in->length - instry));
523 in->length++;
524 in->line[instry].cmd = '0';
525 in->line[instry].param = 0;
527 // paste to new line
528 memcpy(&instrument[currinstr].line[instry], &iclip[i], sizeof(struct instrline));
531 //if(instry < instrument[currinstr].length-1) instry++;
533 break;
535 // copy everything in the current phrase or instrument into the next free one
536 case '^':
537 if(currtab == 1){
538 f = nextfreetrack();
539 memcpy(&track[f], &track[currtrack], sizeof(struct track));
540 currtrack = f;
541 }else if(currtab == 2){
542 f = nextfreeinstr();
543 memcpy(&instrument[f], &instrument[currinstr], sizeof(struct instrument));
544 currinstr = f;
546 break;
548 // TODO: Y and P can be removed after we make visual mode
549 // copy whole phrase or instrument
550 case 'Y':
551 if(currtab == 1){
552 memcpy(&tclip, &track[currtrack], sizeof(struct track));
553 }else if(currtab == 2){
554 memcpy(&iclip, &instrument[currinstr], sizeof(struct instrument));
556 break;
557 // paste whole phrase or instrument
558 case 'P':
559 if(currtab == 1){
560 memcpy(&track[currtrack], &tclip, sizeof(struct track));
561 }else if(currtab == 2){
562 memcpy(&instrument[currinstr], &iclip, sizeof(struct instrument));
564 break;
566 /* delete line */
567 // TODO: clean this SHIT up
568 // TODO: add an ACT_ function for delete
569 case 'd':
570 c = nextchar();
571 switch(c){
572 case 'd':
573 if(currtab == 2){
574 struct instrument *in = &instrument[currinstr];
576 if(in->length > 1){
577 memmove(&in->line[instry + 0], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
578 in->length--;
579 if(instry >= in->length) instry = in->length - 1;
581 }else if(currtab == 0){
582 if(songlen > 1){
583 memmove(&song[songy + 0], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
584 songlen--;
585 if(songy >= songlen) songy = songlen - 1;
588 break;
589 case 'k':
590 if(currtab == 2){
591 struct instrument *in = &instrument[currinstr];
592 instry--;
593 int i;
594 for(i=0; i<2; i++){
595 if(in->length > 1){
596 memmove(&in->line[instry + 0], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
597 in->length--;
598 if(instry >= in->length) instry = in->length - 1;
601 }else if(currtab == 0){
602 songy--;
603 int i;
604 for(i=0; i<2; i++){
605 if(songlen > 1){
606 memmove(&song[songy + 0], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
607 songlen--;
608 if(songy >= songlen) songy = songlen - 1;
612 break;
613 case 'j':
614 if(currtab == 2){
615 struct instrument *in = &instrument[currinstr];
617 int i;
618 for(i=0; i<2; i++){
619 if(in->length > 1){
620 memmove(&in->line[instry + 0], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
621 in->length--;
622 if(instry >= in->length) instry = in->length - 1;
625 }else if(currtab == 0){
626 int i;
627 for(i=0; i<2; i++){
628 if(songlen > 1){
629 memmove(&song[songy + 0], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
630 songlen--;
631 if(songy >= songlen) songy = songlen - 1;
635 break;
637 break;
638 /* undo */
639 case 'u':
640 act_undo();
641 /* Clear */
642 case 'x':
643 act_clronething();
644 break;
645 case 'X':
646 act_clritall();
647 break;
648 case ENTER:
649 if(currtab != 2){
650 if(currtab == 1){
651 silence();
652 startplaytrack(currtrack);
653 }else if(currtab == 0){
654 silence();
655 startplaysong(songy);
658 break;
659 case 'Z':
660 c = nextchar();
661 switch(c){
662 case 'Z':
663 savefile(filename);
664 erase();
665 refresh();
666 endwin();
667 exit(0);
668 break;
669 case 'Q':
670 erase();
671 refresh();
672 endwin();
673 exit(0);
674 break;
676 break;
677 /* Enter command mode */
678 case ':':
679 cmdlinemode();
680 break;
681 case ' ':
682 silence();
683 break;
684 // TODO: make an act_ function for '`'
685 case '`':
686 if(currtab == 0){
687 int t = song[songy].track[songx / 4];
688 if(t) currtrack = t;
689 currtab = 1;
690 if(playtrack){
691 startplaytrack(currtrack);
693 }else if((currtab == 1) && ((trackx == 2) || (trackx == 3))){
694 int i = track[currtrack].line[tracky].instr;
695 if(i) currinstr = i;
696 currtab = 2;
697 } else if(currtab == 1){
698 currtab = 0;
699 }else if(currtab == 2){
700 currtab = 1;
702 break;
703 /* Enter insert mode */
704 case 'i':
705 insertmode();
706 break;
707 /* Enter visual mode */
708 case 'v':
709 visualmode();
710 break;
711 /* Enter visual line mode */
712 case 'V':
713 visuallinemode();
714 break;
715 /* enter jammer mode */
716 case CTRL('A'):
717 jammermode();
718 break;
719 /* Add new line and enter insert mode */
720 case 'o':
721 if(currtab == 2){
722 struct instrument *in = &instrument[currinstr];
724 if(in->length < 256){
725 memmove(&in->line[instry + 2], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
726 instry++;
727 in->length++;
728 in->line[instry].cmd = '0';
729 in->line[instry].param = 0;
731 }else if(currtab == 0){
732 if(songlen < 256){
733 memmove(&song[songy + 2], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
734 songy++;
735 songlen++;
736 memset(&song[songy], 0, sizeof(struct songline));
739 insertmode();
740 break;
741 case 'h':
742 case KEY_LEFT:
743 act_mvleft();
744 break;
745 case 'j':
746 case KEY_DOWN:
747 act_mvdown();
748 break;
749 case 'k':
750 case KEY_UP:
751 act_mvup();
752 break;
753 case 'l':
754 case KEY_RIGHT:
755 act_mvright();
756 break;
757 case '<':
758 if(octave) octave--;
759 break;
760 case '>':
761 if(octave < 8) octave++;
762 break;
763 case '{':
764 if(currtrack > 1) currtrack--;
765 break;
766 case '}':
767 if(currtrack < 255) currtrack++;
768 break;
769 case 'J':
770 if(currtab == 0){
771 if( (songx%4) < 2){
772 act_trackdec();
773 }else{
774 act_transpdec();
776 }else if(currtab == 1){
777 switch(trackx){
778 case 0:
779 act_notedec();
780 break;
781 case 1:
782 act_octavedec();
783 break;
784 case 2:
785 act_instrdec();
786 break;
787 case 3:
788 act_instrdec();
789 break;
790 case 4:
791 act_fxdec();
792 break;
793 case 5:
794 case 6:
795 act_paramdec();
796 break;
797 case 7:
798 act_fxdec();
799 break;
800 case 8:
801 case 9:
802 act_paramdec();
803 break;
804 default:
805 setdisplay("in J");
806 break;
808 }else if(currtab == 2){
809 switch(instrx){
810 case 0:
811 act_fxdec();
812 break;
813 case 1:
814 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
815 act_notedec();
816 }else{
817 act_paramdec();
819 break;
820 case 2:
821 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
822 act_notedec();
823 }else{
824 act_paramdec();
826 break;
829 break;
830 case 'K':
831 if(currtab == 0){
832 if( (songx%4) < 2){
833 act_trackinc();
834 }else{
835 act_transpinc();
837 }else if(currtab == 1){
838 switch(trackx){
839 case 0:
840 act_noteinc();
841 break;
842 case 1:
843 act_octaveinc();
844 break;
845 case 2:
846 act_instrinc();
847 break;
848 case 3:
849 act_instrinc();
850 break;
851 case 4:
852 act_fxinc();
853 break;
854 case 5:
855 case 6:
856 act_paraminc();
857 break;
858 case 7:
859 act_fxinc();
860 break;
861 case 8:
862 case 9:
863 act_paraminc();
864 break;
865 default:
866 setdisplay("in K");
867 break;
869 }else if(currtab == 2){
870 switch(instrx){
871 case 0:
872 act_fxinc();
873 break;
874 case 1:
875 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
876 act_noteinc();
877 }else{
878 act_paraminc();
880 break;
881 case 2:
882 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
883 act_noteinc();
884 }else{
885 act_paraminc();
887 break;
890 break;
891 case CTRL('J'):
892 if(currtab == 2){
893 act_viewinstrdec();
894 }else if(currtab == 1){
895 act_viewtrackdec();
897 break;
898 case CTRL('K'):
899 if(currtab == 2){
900 act_viewinstrinc();
901 }else if(currtab == 1){
902 act_viewtrackinc();
904 break;
905 case '[':
906 act_viewinstrdec();
907 break;
908 case ']':
909 act_viewinstrinc();
910 break;
911 case '(':
912 callbacktime++;
913 break;
914 case ')':
915 callbacktime--;
916 break;
917 case '-':
918 if(step > 0)
919 step--;
920 break;
921 case '=':
922 if(step < 0x0f)
923 step++;
924 break;
925 case CTRL('H'):
926 currtab--;
927 if(currtab < 0)
928 currtab = 2;
929 break;
930 case CTRL('L'):
931 currtab++;
932 currtab %= 3;
933 break;
934 case KEY_TAB:
935 currtab++;
936 currtab %= 3;
937 break;
938 case CTRL('U'):
939 act_bigmvup();
940 break;
941 case CTRL('D'):
942 act_bigmvdown();
943 break;
944 /*case CTRL('P'):
945 vimode = false;
946 break;*/
948 // replace
949 case 'r':
950 _insertc(nextchar());
951 break;
953 default:
954 break;
955 } // end switch
956 } // end for
957 cmdrepeatnum = 1;
958 cmdrepeat = 0;
961 /* vi cmdline mode */
962 void cmdlinemode(void){
963 u16 c;
964 keypad(stdscr, TRUE);
966 currmode = PM_CMDLINE;
967 strncat(cmdstr, ":", 100);
968 for(;;){
969 drawgui();
971 c = nextchar();
972 switch(c){
973 case KEY_ESCAPE:
974 //cmdstr = "";
975 currmode = PM_NORMAL;
976 goto end;
977 case ENTER:
978 _parsecmd(cmdstr);
979 goto end;
980 #ifndef WINDOWS
981 case BACKSPACE:
982 setdisplay("\\o/");
983 cmdstr[strlen(cmdstr)-1] = '\0';
984 break;
985 #endif
986 case '\t':
987 break;
988 default:
989 strncat(cmdstr, &c, 50);
990 break;
993 end:
994 strcpy(cmdstr, "");
995 keypad(stdscr, FALSE);
996 return;
999 /* vi insert mode */
1000 void insertmode(void){
1001 int c;
1002 currmode = PM_INSERT;
1003 drawgui();
1004 for(;;){
1005 if((c = getch()) != ERR) switch(c){
1006 case KEY_ESCAPE:
1007 currmode = PM_NORMAL;
1008 guiloop();
1009 case 'h':
1010 case KEY_LEFT:
1011 act_mvleft();
1012 break;
1013 case 'j':
1014 case KEY_DOWN:
1015 act_mvdown();
1016 break;
1017 case 'k':
1018 case KEY_UP:
1019 act_mvup();
1020 break;
1021 case 'l':
1022 case KEY_RIGHT:
1023 act_mvright();
1024 break;
1025 /* change octave */
1026 case '<':
1027 if(octave) octave--;
1028 break;
1029 case '>':
1030 if(octave < 8) octave++;
1031 break;
1032 /* change instrument */
1033 case CTRL('J'):
1034 if(currtab == 2){
1035 act_viewinstrdec();
1036 }else if(currtab == 1){
1037 act_viewtrackdec();
1039 break;
1040 case CTRL('K'):
1041 if(currtab == 2){
1042 act_viewinstrinc();
1043 }else if(currtab == 1){
1044 act_viewtrackinc();
1046 break;
1047 case '[':
1048 act_viewinstrdec();
1049 break;
1050 case ']':
1051 act_viewinstrinc();
1052 break;
1053 case CTRL('H'):
1054 currtab--;
1055 if(currtab < 0)
1056 currtab = 2;
1057 break;
1058 case CTRL('L'):
1059 currtab++;
1060 currtab %= 3;
1061 break;
1062 case 'Z':
1063 c = nextchar();
1064 switch(c){
1065 case 'Z':
1066 savefile(filename);
1067 erase();
1068 refresh();
1069 endwin();
1070 exit(0);
1071 break;
1072 case 'Q':
1073 erase();
1074 refresh();
1075 endwin();
1076 exit(0);
1077 break;
1079 break;
1080 case ' ':
1081 silence();
1082 currmode = PM_NORMAL;
1083 guiloop();
1084 break;
1085 case ENTER:
1086 if(currtab != 2){
1087 if(currtab == 1){
1088 silence();
1089 startplaytrack(currtrack);
1090 }else if(currtab == 0){
1091 silence();
1092 startplaysong(songy);
1095 break;
1096 case '`':
1097 if(currtab == 0){
1098 int t = song[songy].track[songx / 4];
1099 if(t) currtrack = t;
1100 currtab = 1;
1101 }else if(currtab == 1){
1102 currtab = 0;
1104 break;
1105 default:
1106 _insertc(c);
1107 if(currtab == 1){
1108 tracky+=step;
1109 tracky %= tracklen;
1110 }else if(currtab == 2){
1111 //if(instry < instrument[currinstr].length-1) instry++;
1112 if(instrx < 2) instrx++;
1113 else instrx--;
1114 instry %= instrument[currinstr].length;
1116 saved = 0;
1118 drawgui();
1119 usleep(10000);
1123 /* jammer mode */
1124 void jammermode(void){
1125 int c, x;
1126 currmode = PM_JAMMER;
1127 while(currmode == PM_JAMMER){
1128 if((c = getch()) != ERR) switch(c){
1129 case KEY_ESCAPE:
1130 currmode = PM_NORMAL;
1131 break;
1132 case '[':
1133 act_viewinstrdec();
1134 break;
1135 case ']':
1136 act_viewinstrinc();
1137 break;
1138 case '<':
1139 if(octave) octave--;
1140 break;
1141 case '>':
1142 if(octave < 8) octave++;
1143 break;
1144 default:
1145 x = freqkey(c);
1147 if(x > 0){
1148 iedplonk(x, currinstr);
1151 break;
1153 drawgui();
1154 usleep(10000);
1158 /* visual mode */
1159 void visualmode(void){
1160 int c;
1162 currmode = PM_VISUAL;
1163 //attrset(A_REVERSE);
1164 if(currtab == 0){
1165 }else if(currtab == 1){
1166 highlight_firstx = trackx;
1167 highlight_lastx = trackx;
1168 highlight_firsty = tracky;
1169 highlight_lasty = tracky;
1170 }else if(currtab == 2){
1171 }else{
1172 highlight_firstx = -1;
1173 highlight_lastx = -1;
1174 highlight_firsty = -1;
1175 highlight_lasty = -1;
1178 while(currmode == PM_VISUAL){
1179 if((c = getch()) != ERR) switch(c){
1180 case 'v':
1181 case KEY_ESCAPE:
1182 currmode = PM_NORMAL;
1183 break;
1184 case 'V':
1185 visuallinemode();
1186 break;
1187 case 'h':
1188 act_mvleft();
1189 if(currtab==0){
1190 }else if(currtab==1){
1191 highlight_lastx = trackx;
1192 }else if(currtab==2){
1194 break;
1195 case 'j':
1196 act_mvdown();
1197 if(currtab==0){
1198 }else if(currtab==1){
1199 highlight_lasty = tracky;
1200 }else if(currtab==2){
1202 break;
1203 case 'k':
1204 act_mvup();
1205 if(currtab==0){
1206 }else if(currtab==1){
1207 highlight_lasty = tracky;
1208 }else if(currtab==2){
1210 break;
1211 case 'l':
1212 act_mvright();
1213 if(currtab==0){
1214 }else if(currtab==1){
1215 highlight_lastx = trackx;
1216 }else if(currtab==2){
1218 break;
1220 drawgui();
1222 attrset(A_BOLD);
1223 return;
1226 /* visual line mode */
1227 void visuallinemode(void){
1228 int c;
1229 int min, max;
1230 char buf[1024];
1232 currmode = PM_VISUALLINE;
1234 /* Store the current line as the first and last node of a linked list */
1235 if(currtab==0){
1236 highlight_firstline = songy;
1237 highlight_lastline = songy;
1238 }else if(currtab==1){
1239 highlight_firstline = tracky;
1240 highlight_lastline = tracky;
1241 }else if(currtab==2){
1242 highlight_firstline = instry;
1243 highlight_lastline = instry;
1244 }else{
1245 highlight_firstline = -1;
1246 highlight_lastline = -1;
1249 // initialize difference
1250 highlight_lineamount = 1;
1252 // make it visible to gui.c
1253 //highlightlines = firstnode;
1255 while(currmode == PM_VISUALLINE){
1256 if((c = getch()) != ERR) switch(c){
1257 case 'V':
1258 case KEY_ESCAPE:
1259 currmode = PM_NORMAL;
1260 break;
1261 case 'v':
1262 visualmode();
1263 case 'h':
1264 act_mvleft();
1265 break;
1266 case 'j':
1267 act_mvdown();
1268 // update lastnode
1269 if(currtab==0){
1270 highlight_lastline = songy;
1271 }else if(currtab==1){
1272 highlight_lastline = tracky;
1273 }else if(currtab==2){
1274 highlight_lastline = instry;
1276 // update the highlighted length
1277 highlight_lineamount = (highlight_firstline>highlight_lastline)?
1278 highlight_firstline - highlight_lastline +1
1279 : highlight_lastline - highlight_firstline +1;
1280 break;
1281 case 'k':
1282 act_mvup();
1283 // update lastnode
1284 if(currtab==0){
1285 highlight_lastline = songy;
1286 }else if(currtab==1){
1287 highlight_lastline = tracky;
1288 }else if(currtab==2){
1289 highlight_lastline = instry;
1291 // update the highlighted length
1292 highlight_lineamount = (highlight_firstline>highlight_lastline)?
1293 highlight_firstline - highlight_lastline +1
1294 : highlight_lastline - highlight_firstline +1;
1295 break;
1296 case 'l':
1297 act_mvright();
1298 break;
1299 case 'g':
1300 if(nextchar() == 'g'){
1301 act_mvtop();
1303 break;
1304 case 'G':
1305 act_mvbottom();
1306 break;
1307 // d: copy every line that is highlighted to the paste buffer and clear them, too
1308 case 'd':
1309 min = (highlight_firstline < highlight_lastline)?
1310 highlight_firstline
1311 : highlight_lastline;
1312 max = (highlight_firstline < highlight_lastline)?
1313 highlight_lastline
1314 : highlight_firstline;
1315 if(currtab == 0){
1316 for(int i=min; i<=max; i++)
1317 act_clrinsongtab(i);
1318 }else if(currtab == 1){
1319 for(int i=min; i<=max; i++)
1320 act_clrintracktab(currtrack, i);
1321 }else if(currtab == 2){
1322 for(int i=min; i<=max; i++)
1323 act_clrininstrtab(currinstr, i);
1325 //snprintf(buf, sizeof(buf), "%d fewer lines", highlight_lineamount);
1326 //infinitemsg = buf;
1327 currmode = PM_NORMAL;
1328 break;
1329 // y: copy every line that is highlighted to the paste buffer
1330 case 'y':
1331 if(currtab == 0){
1332 //tcliplen = 1;
1333 //memcpy(&tclip, &song[songy], sizeof(struct songline)*highlight_lineamount);
1334 tcliplen = highlight_lineamount;
1335 //moved up, then yanked
1336 if(highlight_firstline > highlight_lastline){
1337 for(int i = 0; i < highlight_lineamount; i++)
1338 memcpy(&tclip[i], &song[songy+i], sizeof(struct songline));
1339 //moved down, then yanked
1340 }else if(highlight_lastline > highlight_firstline){
1341 for(int i = highlight_lineamount-1, j = 0; i >= 0; i--, j++){
1342 memcpy(&tclip[i], &song[songy-j], sizeof(struct songline));
1345 }else if(currtab == 1){
1346 tcliplen = highlight_lineamount;
1347 //moved up, then yanked
1348 if(highlight_firstline > highlight_lastline){
1349 for(int i = 0; i < highlight_lineamount; i++)
1350 memcpy(&tclip[i], &track[currtrack].line[tracky+i], sizeof(struct trackline));
1351 //moved down, then yanked
1352 }else if(highlight_lastline > highlight_firstline){
1353 for(int i = highlight_lineamount-1, j = 0; i >= 0; i--, j++){
1354 memcpy(&tclip[i], &track[currtrack].line[tracky-j], sizeof(struct trackline));
1357 }else if(currtab == 2){
1358 //icliplen = 1;
1359 //memcpy(&iclip, &instrument[currinstr].line[instry], sizeof(struct instrline)*highlight_lineamount);
1360 icliplen = highlight_lineamount;
1361 //moved up, then yanked
1362 if(highlight_firstline > highlight_lastline){
1363 for(int i = 0; i < highlight_lineamount; i++)
1364 memcpy(&iclip[i], &instrument[currinstr].line[instry+i], sizeof(struct instrline));
1365 //moved down, then yanked
1366 }else if(highlight_lastline > highlight_firstline){
1367 for(int i = highlight_lineamount-1, j = 0; i >= 0; i--, j++){
1368 memcpy(&iclip[i], &instrument[currinstr].line[instry-j], sizeof(struct instrline));
1373 snprintf(buf, sizeof(buf), "%d lines yanked", highlight_lineamount);
1374 infinitemsg = buf;
1375 currmode = PM_NORMAL;
1376 break;
1378 drawgui();
1380 // update the highlighted length
1381 /*highlight_lineamount = (highlight_firstline>highlight_lastline)?
1382 highlight_firstline - highlight_lastline +1
1383 : highlight_lastline - highlight_firstline +1;
1386 highlight_firstline = -1;
1387 highlight_lastline = -1;
1389 return;