* Mod parser parses patterns, just got to figure out what the period values mean...
[pineappletracker.git] / modes.c
blob386ef61f33ec84b5f88361e789c9814aebfb0034
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 int f;
9 int tcliplen, icliplen = 0;
10 int lastinsert = 0;
12 int _hexdigit(char c);
13 int _nextfreetrack(void);
14 int _nextfreeinstr(void);
16 /* Let's make a linked list! */
17 /* Here's a great generic implementation:
18 * http://en.literateprograms.org/Singly_linked_list_(C)
20 /*NODE *list_create(void *e){
21 NODE *n;
22 if(!(n=malloc(sizeof(NODE)))) return NULL;
23 n->element = e;
24 n->next = NULL;
25 return n;
28 NODE *list_insertafter(NODE *oldnode, void *newelement){
29 NODE *newnode;
30 newnode = list_create(newelement);
31 newnode->next = oldnode->next;
32 oldnode->next = newnode;
33 return newnode;
36 // have a look at this wizardry! wow. what does int(*func) do?
37 NODE *list_contains(NODE *n, int (*func) (void *, void *), void *match){
38 while(n){
39 if(func(n->element, match) > 0) return n;
40 n = n->next;
42 return NULL;
45 int findu8(void *a, void *b){
46 return a==b;
47 }*/
49 int _hexdigit(char c){
50 if(c >= '0' && c <= '9') return c - '0';
51 if(c >= 'a' && c <= 'f') return c - 'a' + 10;
52 return -1;
55 int _nextfreetrack(){
56 int skiptherest = 0;
58 for(int i = 1; i <= 0xff; i++){
59 for(int j = 0; j < tracklen; j++){
60 if(track[i].line[j].note) skiptherest = 1;
61 for(int k = 0; k < 2; k++){
62 if(track[i].line[j].cmd[k]) skiptherest = 1;
63 if(track[i].line[j].param[k]) skiptherest = 1;
66 // skip the rest of this track?
67 if(skiptherest){
68 skiptherest = 0;
69 break;
72 // this track is free, so return the index
73 if(j == tracklen-1) return i;
77 setdisplay("_nextfreetrack() failed somehow..");
78 return -1;
81 int _nextfreeinstr(){
82 for(int i = 1; i <= 0xff; i++){
83 if(instrument[i].line[0].cmd == '0')
84 return i;
87 setdisplay("_nextfreeinstr() failed somehow..");
88 return -1;
91 void _insertc(int c){
92 int x;
94 x = _hexdigit(c);
95 if(x >= 0){
96 if(currtab == 2
97 && instrx > 0
98 && instrument[currinstr].line[instry].cmd != '+'
99 && instrument[currinstr].line[instry].cmd != '='){
100 switch(instrx){
101 case 1: SETHI(instrument[currinstr].line[instry].param, x); break;
102 case 2: SETLO(instrument[currinstr].line[instry].param, x); break;
105 if(currtab == 1 && trackx > 1){
106 switch(trackx){
107 case 2: SETHI(track[currtrack].line[tracky].instr, x); break;
108 case 3: SETLO(track[currtrack].line[tracky].instr, x); break;
109 case 5: if(track[currtrack].line[tracky].cmd[0])
110 SETHI(track[currtrack].line[tracky].param[0], x); break;
111 case 6: if(track[currtrack].line[tracky].cmd[0])
112 SETLO(track[currtrack].line[tracky].param[0], x); break;
113 case 8: if(track[currtrack].line[tracky].cmd[1])
114 SETHI(track[currtrack].line[tracky].param[1], x); break;
115 case 9: if(track[currtrack].line[tracky].cmd[1])
116 SETLO(track[currtrack].line[tracky].param[1], x); break;
119 if(currtab == 0){
120 switch(songx & 3){
121 case 0: SETHI(song[songy].track[songx / 4], x); break;
122 case 1: SETLO(song[songy].track[songx / 4], x); break;
123 case 2: SETHI(song[songy].transp[songx / 4], x); break;
124 case 3: SETLO(song[songy].transp[songx / 4], x); break;
128 x = freqkey(c);
129 if(x >= 0){
130 if(currtab == 2
131 && instrx
132 && (instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '=')){
133 instrument[currinstr].line[instry].param = x;
135 if(currtab == 1 && !trackx){
136 track[currtrack].line[tracky].note = x;
137 if(x){
138 track[currtrack].line[tracky].instr = currinstr;
139 }else{
140 track[currtrack].line[tracky].instr = 0;
142 if(x) iedplonk(x, currinstr);
145 if(currtab == 2 && instrx == 0){
146 if(strchr(validcmds, c))
147 instrument[currinstr].line[instry].cmd = c;
149 if(currtab == 1 && (trackx == 4 || trackx == 7)){
150 if(strchr(validcmds, c)){
151 if(c == '.' || c == '0') c = 0;
152 track[currtrack].line[tracky].cmd[(trackx - 3) / 3] = c;
155 // for repeat
156 lastinsert = c;
159 // isnumber() determines if a string is a number
160 // returns 1 if the given arg is a number, 0 otherwise.
161 // for use with isdigit(), isxdigit(), etc...
162 int isnumber(const int* str, int (*func) (int)){
163 int i = 0;
165 for(;;){
166 if( func(str[i]) ){
167 i++;
168 }else if( str[i]=='\0' ){
169 return 1;
170 }else{
171 return 0;
176 // Converts a hexadecimal string to integer
177 // return values:
178 // 0: conversion successful
179 // 1: string is empty
180 // 2: string has more than 8 bytes
181 // 4: Conversion is in process but abnormally terminated by
182 // illegal hexadecimal character
183 // from http://devpinoy.org/blogs/cvega/archive/2006/06/19/xtoi-hex-to-integer-c-function.aspx
184 int xtoi(const char* xs, unsigned int* result){
185 size_t szlen = strlen(xs);
186 int i, xv, fact;
188 if(szlen > 0){
189 // Converting more than 32bit hexadecimal value?
190 if (szlen>8) return 2; // exit
192 // Begin conversion here
193 *result = 0;
194 fact = 1;
196 // Run until no more character to convert
197 for(i=szlen-1; i>=0 ;i--){
198 if(isxdigit(*(xs+i))){
199 if (*(xs+i)>=97){
200 xv = ( *(xs+i) - 97) + 10;
201 }else if( *(xs+i) >= 65){
202 xv = (*(xs+i) - 65) + 10;
203 }else{
204 xv = *(xs+i) - 48;
206 *result += (xv * fact);
207 fact *= 16;
208 }else{
209 // Conversion was abnormally terminated
210 // by non hexadecimal digit, hence
211 // returning only the converted with
212 // an error value 4 (illegal hex character)
213 return 4;
217 // Nothing to convert
218 return 1;
221 void _parsecmd(char cmd[]){
222 //if(cmd[1] == 'w'){
223 //switch(strcmp(cmd,
224 if(strcmp(cmd, ":w") == 0){
225 savefile(filename);
226 saved = 1;
227 }else if(strcmp(cmd, ":q") == 0){
228 if(!saved){
229 setdisplay("no write since last change! use :q! to override");
230 }else{
231 erase();
232 refresh();
233 endwin();
234 exit(0);
236 }else if(strcmp(cmd, ":q!") == 0){
237 erase();
238 refresh();
239 endwin();
240 exit(0);
241 }else if(strcmp(cmd, ":write") == 0){
242 savefile(filename);
243 saved = 1;
244 }else if(strcmp(cmd, ":wq") == 0){
245 savefile(filename);
246 saved = 1;
247 erase();
248 refresh();
249 endwin();
250 exit(0);
251 }else if(strcmp(cmd, ":quit") == 0){
252 erase();
253 refresh();
254 endwin();
255 exit(0);
256 }else if(cmd[1]=='e' && cmd[2]==' '){
257 // if the file doesn't exist, clear the song
258 if(loadfile(cmd+3)){
259 initsonglines();
260 inittracks();
261 initinstrs();
263 //yucky if statement below.....probably better way to do it
264 }else if(cmd[1]=='s' &&
265 cmd[2]=='a' &&
266 cmd[3]=='v' &&
267 cmd[4]=='e' &&
268 cmd[5]==' '){
269 saveinstrument(cmd+6);
270 setdisplay("d-_-b saved ins! d-_-b");
271 }else if(cmd[1]=='l' &&
272 cmd[2]=='o' &&
273 cmd[3]=='a' &&
274 cmd[4]=='d' &&
275 cmd[5]==' '){
276 loadinstrument(cmd+6);
277 setdisplay("d-_-b loaded ins! d-_-b");
278 }else if( isnumber((int *)cmd+1,isxdigit) ){
279 unsigned int goton = 1;
280 xtoi(cmd+1,&goton);
282 switch(currtab){
283 case 0:
284 songy = (goton>songlen)? songlen-1 : goton;
285 break;
286 case 1:
287 currtrack = (goton>0xff)? 0xff : goton;
288 break;
289 case 2:
290 currinstr = (goton>0xff)? 0xff : goton;
291 break;
293 }else if(cmd[1] == 'c' && cmd[2] == ' '){
294 strncpy(comment, cmd+3, sizeof(comment));
295 }else
296 setdisplay("not a tracker command!");
297 return;
300 /* normal mode */
301 void normalmode(int c){
302 int i;
304 // don't save the action for repeat if it's a movement or a repeat, or
305 // something else that doesnt make sense to repeat
306 if(c != 'h' &&
307 c != 'j' &&
308 c != 'k' &&
309 c != 'l' &&
310 c != CTRL('D') &&
311 c != CTRL('U') &&
312 c != CTRL('H') &&
313 c != CTRL('L') &&
314 c != 'H' &&
315 c != 'M' &&
316 c != 'L' &&
317 c != 'g' &&
318 c != 'G' &&
319 c != '.'){
320 lastaction = c;
321 lastrepeatnum = cmdrepeatnum;
324 for(i=0; i<cmdrepeatnum; i++){
325 switch(c){
326 /* add line */
327 case 'a':
328 if(currtab == 2){
329 struct instrument *in = &instrument[currinstr];
331 if(in->length < 256){
332 memmove(&in->line[instry + 2], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
333 instry++;
334 in->length++;
335 in->line[instry].cmd = '0';
336 in->line[instry].param = 0;
338 }else if(currtab == 0){
339 if(songlen < 256){
340 memmove(&song[songy + 2], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
341 songy++;
342 songlen++;
343 memset(&song[songy], 0, sizeof(struct songline));
346 break;
347 case '.':
348 // if the last command was a replace, just insert the last thing
349 // inserted instead of calling insertmode()
350 if(lastaction == 'r')
351 _insertc(lastinsert);
352 else
353 normalmode(lastaction);
354 cmdrepeatnum = lastrepeatnum;
355 break;
356 case KEY_ESCAPE:
357 disptick = 0;
358 jammermode();
359 break;
360 case CTRL('Y'):
361 switch(currtab){
362 case 0:
363 if(songoffs>0){
364 if(songy==getmaxy(stdscr)-3+songoffs)
365 songy--;
366 songoffs--;
368 break;
369 case 1:
370 if(trackoffs>0){
371 if(tracky==getmaxy(stdscr)-3+trackoffs)
372 tracky--;
373 trackoffs--;
375 break;
376 case 2:
377 if(instroffs>0){
378 if(instry==getmaxy(stdscr)-3+instroffs)
379 instry--;
380 instroffs--;
382 break;
384 break;
385 case CTRL('E'):
386 switch(currtab){
387 case 0:
388 if(songy<=songlen-2){
389 if(songy==songoffs)
390 songy++;
391 songoffs++;
393 break;
394 case 1:
395 if(tracky<=tracklen-2){
396 if(tracky==trackoffs)
397 tracky++;
398 trackoffs++;
400 break;
401 case 2:
402 if(instry<=instrument[currinstr].length-2){
403 if(instry==instroffs)
404 instry++;
405 instroffs++;
407 break;
409 break;
410 case 'H':
411 switch(currtab){
412 case 0:
413 songy = songoffs;
414 break;
415 case 1:
416 tracky = trackoffs;
417 break;
418 case 2:
419 instry = instroffs;
420 break;
422 break;
424 // the second cases (to the right of the colon) for M and L
425 // took some serious guesswork, so I'm not sure if they're
426 // correct but they seem to work.
427 case 'M':
428 switch(currtab){
429 case 0:
430 songy = (songlen <= getmaxy(stdscr)-2)?
431 songlen/2
432 : ((getmaxy(stdscr)-6)/2) + songoffs;
433 break;
434 case 1:
435 tracky = (tracklen <= getmaxy(stdscr)-2)?
436 tracklen/2
437 : ((getmaxy(stdscr)-6)/2) + trackoffs;
438 break;
439 case 2:
440 instry = (instrument[currinstr].length <= getmaxy(stdscr)-2)?
441 instrument[currinstr].length/2
442 : ((getmaxy(stdscr)-6)/2) + instroffs;
443 break;
445 break;
446 case 'L':
447 switch(currtab){
448 case 0:
449 songy = (songlen <= getmaxy(stdscr)-2)?
450 songlen-1
451 : getmaxy(stdscr)-3+songoffs;
452 break;
453 case 1:
454 tracky = (tracklen <= getmaxy(stdscr)-2)?
455 tracklen-1
456 : getmaxy(stdscr)-3+trackoffs;
457 break;
458 case 2:
459 instry = (instrument[currinstr].length <= getmaxy(stdscr)-2)?
460 instrument[currinstr].length-1
461 : getmaxy(stdscr)-3+instroffs;
462 break;
464 break;
465 case 'g':
466 if(nextchar() == 'g'){
467 act_mvtop();
469 break;
470 case 'G':
471 act_mvbottom();
472 break;
474 // yank
475 case 'y':
476 c = nextchar();
477 switch(c){
478 case 'y':
479 //tclip = malloc(1);
480 if(currtab == 0){
481 tcliplen = 1;
482 memcpy(&tclip, &song[songy], sizeof(struct songline));
483 }else if(currtab == 1){
484 tcliplen = 1;
485 memcpy(&tclip, &track[currtrack].line[tracky], sizeof(struct trackline));
486 }else if(currtab == 2){
487 icliplen = 1;
488 memcpy(&iclip, &instrument[currinstr].line[instry], sizeof(struct instrline));
490 break;
491 case 'j':
492 //tclip = malloc(2);
493 if(currtab == 0){
494 tcliplen = 2;
495 memcpy(&tclip[0], &song[songy], sizeof(struct songline));
496 act_mvdown();
497 memcpy(&tclip[1], &song[songy], sizeof(struct songline));
498 }else if(currtab == 1){
499 tcliplen = 2;
500 memcpy(&tclip[0], &track[currtrack].line[tracky], sizeof(struct trackline));
501 act_mvdown();
502 memcpy(&tclip[1], &track[currtrack].line[tracky], sizeof(struct trackline));
503 }else if(currtab == 2){
504 icliplen = 2;
505 memcpy(&iclip[0], &instrument[currinstr].line[instry], sizeof(struct instrline));
506 act_mvdown();
507 memcpy(&iclip[1], &instrument[currinstr].line[instry], sizeof(struct instrline));
509 break;
510 case 'k':
511 //tclip = malloc(2);
512 if(currtab == 0){
513 tcliplen = 2;
514 memcpy(&tclip[1], &song[songy], sizeof(struct songline));
515 act_mvup();
516 memcpy(&tclip[0], &song[songy], sizeof(struct songline));
517 }else if(currtab == 1){
518 tcliplen = 2;
519 memcpy(&tclip[1], &track[currtrack].line[tracky], sizeof(struct trackline));
520 act_mvup();
521 memcpy(&tclip[0], &track[currtrack].line[tracky], sizeof(struct trackline));
522 }else if(currtab == 2){
523 icliplen = 2;
524 memcpy(&iclip[1], &instrument[currinstr].line[instry], sizeof(struct instrline));
525 act_mvup();
526 memcpy(&iclip[0], &instrument[currinstr].line[instry], sizeof(struct instrline));
528 break;
530 break;
532 //paste
533 case 'p':
534 if(currtab == 0){
535 if(songlen < 256){
536 for(int i = 0; i < tcliplen; i++){
537 // insert new line
538 memmove(&song[songy + 2], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
539 songy++;
540 songlen++;
541 memset(&song[songy], 0, sizeof(struct songline));
543 // paste to new line
544 memcpy(&song[songy], &tclip[i], sizeof(struct songline));
547 }else if(currtab == 1){
548 for(int i = 0; i < tcliplen; i++){
549 memcpy(&track[currtrack].line[tracky], &tclip[i], sizeof(struct trackline));
550 if(tracky < tracklen-step) tracky += step;
551 else tracky = tracklen-1;
553 }else if(currtab == 2){
554 if(instrument[currinstr].length < 256){
555 // insert new line
556 for(int i = 0; i < icliplen; i++){
557 struct instrument *in = &instrument[currinstr];
559 instry++;
560 memmove(&in->line[instry + 1], &in->line[instry + 0], sizeof(struct instrline) * (in->length - instry));
561 in->length++;
562 in->line[instry].cmd = '0';
563 in->line[instry].param = 0;
565 // paste to new line
566 memcpy(&instrument[currinstr].line[instry], &iclip[i], sizeof(struct instrline));
569 //if(instry < instrument[currinstr].length-1) instry++;
571 break;
573 // copy everything in the current phrase or instrument into the next free one
574 case '^':
575 if(currtab == 1){
576 f = _nextfreetrack();
577 memcpy(&track[f], &track[currtrack], sizeof(struct track));
578 currtrack = f;
579 }else if(currtab == 2){
580 f = _nextfreeinstr();
581 memcpy(&instrument[f], &instrument[currinstr], sizeof(struct instrument));
582 currinstr = f;
584 break;
586 // TODO: Y and P can be removed after we make visual mode
587 // copy whole phrase or instrument
588 case 'Y':
589 if(currtab == 1){
590 memcpy(&tclip, &track[currtrack], sizeof(struct track));
591 }else if(currtab == 2){
592 memcpy(&iclip, &instrument[currinstr], sizeof(struct instrument));
594 break;
595 // paste whole phrase or instrument
596 case 'P':
597 if(currtab == 1){
598 memcpy(&track[currtrack], &tclip, sizeof(struct track));
599 }else if(currtab == 2){
600 memcpy(&instrument[currinstr], &iclip, sizeof(struct instrument));
602 break;
604 /* delete line */
605 // TODO: clean this SHIT up
606 // TODO: add an ACT_ function for delete
607 case 'd':
608 c = nextchar();
609 switch(c){
610 case 'd':
611 if(currtab == 2){
612 struct instrument *in = &instrument[currinstr];
614 if(in->length > 1){
615 memmove(&in->line[instry + 0], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
616 in->length--;
617 if(instry >= in->length) instry = in->length - 1;
619 }else if(currtab == 0){
620 if(songlen > 1){
621 memmove(&song[songy + 0], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
622 songlen--;
623 if(songy >= songlen) songy = songlen - 1;
626 break;
627 case 'k':
628 if(currtab == 2){
629 struct instrument *in = &instrument[currinstr];
630 instry--;
631 int i;
632 for(i=0; i<2; i++){
633 if(in->length > 1){
634 memmove(&in->line[instry + 0], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
635 in->length--;
636 if(instry >= in->length) instry = in->length - 1;
639 }else if(currtab == 0){
640 songy--;
641 int i;
642 for(i=0; i<2; i++){
643 if(songlen > 1){
644 memmove(&song[songy + 0], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
645 songlen--;
646 if(songy >= songlen) songy = songlen - 1;
650 break;
651 case 'j':
652 if(currtab == 2){
653 struct instrument *in = &instrument[currinstr];
655 int i;
656 for(i=0; i<2; i++){
657 if(in->length > 1){
658 memmove(&in->line[instry + 0], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
659 in->length--;
660 if(instry >= in->length) instry = in->length - 1;
663 }else if(currtab == 0){
664 int i;
665 for(i=0; i<2; i++){
666 if(songlen > 1){
667 memmove(&song[songy + 0], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
668 songlen--;
669 if(songy >= songlen) songy = songlen - 1;
673 break;
675 break;
676 /* undo */
677 case 'u':
678 act_undo();
679 /* Clear */
680 case 'x':
681 act_clronething();
682 break;
683 case 'X':
684 act_clritall();
685 break;
686 case ENTER:
687 if(currtab != 2){
688 if(currtab == 1){
689 silence();
690 startplaytrack(currtrack);
691 }else if(currtab == 0){
692 silence();
693 startplaysong(songy);
696 break;
697 case 'Z':
698 c = nextchar();
699 switch(c){
700 case 'Z':
701 savefile(filename);
702 erase();
703 refresh();
704 endwin();
705 exit(0);
706 break;
707 case 'Q':
708 erase();
709 refresh();
710 endwin();
711 exit(0);
712 break;
714 break;
715 /* Enter command mode */
716 case ':':
717 cmdlinemode();
718 break;
719 case ' ':
720 silence();
721 break;
722 // TODO: make an act_ function for '`'
723 case '`':
724 if(currtab == 0){
725 int t = song[songy].track[songx / 4];
726 if(t) currtrack = t;
727 currtab = 1;
728 if(playtrack){
729 startplaytrack(currtrack);
731 }else if((currtab == 1) && ((trackx == 2) || (trackx == 3))){
732 int i = track[currtrack].line[tracky].instr;
733 if(i) currinstr = i;
734 currtab = 2;
735 } else if(currtab == 1){
736 currtab = 0;
737 }else if(currtab == 2){
738 currtab = 1;
740 break;
741 /* Enter insert mode */
742 case 'i':
743 insertmode();
744 break;
745 /* Enter visual mode */
746 case 'v':
747 visualmode();
748 break;
749 /* Enter visual line mode */
750 case 'V':
751 visuallinemode();
752 break;
753 /* enter jammer mode */
754 case CTRL('A'):
755 jammermode();
756 break;
757 /* Add new line and enter insert mode */
758 case 'o':
759 if(currtab == 2){
760 struct instrument *in = &instrument[currinstr];
762 if(in->length < 256){
763 memmove(&in->line[instry + 2], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
764 instry++;
765 in->length++;
766 in->line[instry].cmd = '0';
767 in->line[instry].param = 0;
769 }else if(currtab == 0){
770 if(songlen < 256){
771 memmove(&song[songy + 2], &song[songy + 1], sizeof(struct songline) * (songlen - songy - 1));
772 songy++;
773 songlen++;
774 memset(&song[songy], 0, sizeof(struct songline));
777 insertmode();
778 break;
779 case 'h':
780 case KEY_LEFT:
781 act_mvleft();
782 break;
783 case 'j':
784 case KEY_DOWN:
785 act_mvdown();
786 break;
787 case 'k':
788 case KEY_UP:
789 act_mvup();
790 break;
791 case 'l':
792 case KEY_RIGHT:
793 act_mvright();
794 break;
795 case '<':
796 if(octave) octave--;
797 break;
798 case '>':
799 if(octave < 8) octave++;
800 break;
801 case '{':
802 if(currtrack > 1) currtrack--;
803 break;
804 case '}':
805 if(currtrack < 255) currtrack++;
806 break;
807 case 'J':
808 if(currtab == 0){
809 if( (songx%4) < 2){
810 act_trackdec();
811 }else{
812 act_transpdec();
814 }else if(currtab == 1){
815 switch(trackx){
816 case 0:
817 act_notedec();
818 break;
819 case 1:
820 act_octavedec();
821 break;
822 case 2:
823 act_instrdec();
824 break;
825 case 3:
826 act_instrdec();
827 break;
828 case 4:
829 act_fxdec();
830 break;
831 case 5:
832 case 6:
833 act_paramdec();
834 break;
835 case 7:
836 act_fxdec();
837 break;
838 case 8:
839 case 9:
840 act_paramdec();
841 break;
842 default:
843 setdisplay("in J");
844 break;
846 }else if(currtab == 2){
847 switch(instrx){
848 case 0:
849 act_fxdec();
850 break;
851 case 1:
852 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
853 act_notedec();
854 }else{
855 act_paramdec();
857 break;
858 case 2:
859 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
860 act_notedec();
861 }else{
862 act_paramdec();
864 break;
867 break;
868 case 'K':
869 if(currtab == 0){
870 if( (songx%4) < 2){
871 act_trackinc();
872 }else{
873 act_transpinc();
875 }else if(currtab == 1){
876 switch(trackx){
877 case 0:
878 act_noteinc();
879 break;
880 case 1:
881 act_octaveinc();
882 break;
883 case 2:
884 act_instrinc();
885 break;
886 case 3:
887 act_instrinc();
888 break;
889 case 4:
890 act_fxinc();
891 break;
892 case 5:
893 case 6:
894 act_paraminc();
895 break;
896 case 7:
897 act_fxinc();
898 break;
899 case 8:
900 case 9:
901 act_paraminc();
902 break;
903 default:
904 setdisplay("in K");
905 break;
907 }else if(currtab == 2){
908 switch(instrx){
909 case 0:
910 act_fxinc();
911 break;
912 case 1:
913 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
914 act_noteinc();
915 }else{
916 act_paraminc();
918 break;
919 case 2:
920 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
921 act_noteinc();
922 }else{
923 act_paraminc();
925 break;
928 break;
929 case CTRL('J'):
930 if(currtab == 2){
931 act_viewinstrdec();
932 }else if(currtab == 1){
933 act_viewtrackdec();
935 break;
936 case CTRL('K'):
937 if(currtab == 2){
938 act_viewinstrinc();
939 }else if(currtab == 1){
940 act_viewtrackinc();
942 break;
943 case '[':
944 act_viewinstrdec();
945 break;
946 case ']':
947 act_viewinstrinc();
948 break;
949 case '(':
950 callbacktime++;
951 break;
952 case ')':
953 callbacktime--;
954 break;
955 case '-':
956 if(step > 0)
957 step--;
958 break;
959 case '=':
960 if(step < 0x0f)
961 step++;
962 break;
963 case CTRL('H'):
964 currtab--;
965 if(currtab < 0)
966 currtab = 2;
967 break;
968 case CTRL('L'):
969 currtab++;
970 currtab %= 3;
971 break;
972 case KEY_TAB:
973 currtab++;
974 currtab %= 3;
975 break;
976 case CTRL('U'):
977 act_bigmvup();
978 break;
979 case CTRL('D'):
980 act_bigmvdown();
981 break;
982 /*case CTRL('P'):
983 vimode = false;
984 break;*/
986 // replace
987 case 'r':
988 _insertc(nextchar());
989 break;
991 default:
992 break;
993 } // end switch
994 } // end for
995 cmdrepeatnum = 1;
996 cmdrepeat = 0;
999 /* vi cmdline mode */
1000 void cmdlinemode(void){
1001 u16 c;
1002 keypad(stdscr, TRUE);
1004 currmode = PM_CMDLINE;
1005 strncat(cmdstr, ":", 50);
1006 for(;;){
1007 drawgui();
1009 c = nextchar();
1010 switch(c){
1011 case KEY_ESCAPE:
1012 //cmdstr = "";
1013 currmode = PM_NORMAL;
1014 goto end;
1015 case ENTER:
1016 _parsecmd(cmdstr);
1017 goto end;
1018 #ifndef WINDOWS
1019 case BACKSPACE:
1020 setdisplay("\\o/");
1021 cmdstr[strlen(cmdstr)-1] = '\0';
1022 break;
1023 #endif
1024 case '\t':
1025 break;
1026 default:
1027 strncat(cmdstr, &c, 50);
1028 break;
1031 end:
1032 strcpy(cmdstr, "");
1033 keypad(stdscr, FALSE);
1034 return;
1037 /* vi insert mode */
1038 void insertmode(void){
1039 int c;
1040 currmode = PM_INSERT;
1041 drawgui();
1042 for(;;){
1043 if((c = getch()) != ERR) switch(c){
1044 case KEY_ESCAPE:
1045 currmode = PM_NORMAL;
1046 guiloop();
1047 case 'h':
1048 case KEY_LEFT:
1049 act_mvleft();
1050 break;
1051 case 'j':
1052 case KEY_DOWN:
1053 act_mvdown();
1054 break;
1055 case 'k':
1056 case KEY_UP:
1057 act_mvup();
1058 break;
1059 case 'l':
1060 case KEY_RIGHT:
1061 act_mvright();
1062 break;
1063 /* change octave */
1064 case '<':
1065 if(octave) octave--;
1066 break;
1067 case '>':
1068 if(octave < 8) octave++;
1069 break;
1070 /* change instrument */
1071 case CTRL('J'):
1072 if(currtab == 2){
1073 act_viewinstrdec();
1074 }else if(currtab == 1){
1075 act_viewtrackdec();
1077 break;
1078 case CTRL('K'):
1079 if(currtab == 2){
1080 act_viewinstrinc();
1081 }else if(currtab == 1){
1082 act_viewtrackinc();
1084 break;
1085 case '[':
1086 act_viewinstrdec();
1087 break;
1088 case ']':
1089 act_viewinstrinc();
1090 break;
1091 case CTRL('H'):
1092 currtab--;
1093 if(currtab < 0)
1094 currtab = 2;
1095 break;
1096 case CTRL('L'):
1097 currtab++;
1098 currtab %= 3;
1099 break;
1100 case 'Z':
1101 c = nextchar();
1102 switch(c){
1103 case 'Z':
1104 savefile(filename);
1105 erase();
1106 refresh();
1107 endwin();
1108 exit(0);
1109 break;
1110 case 'Q':
1111 erase();
1112 refresh();
1113 endwin();
1114 exit(0);
1115 break;
1117 break;
1118 case ' ':
1119 silence();
1120 currmode = PM_NORMAL;
1121 guiloop();
1122 break;
1123 case ENTER:
1124 if(currtab != 2){
1125 if(currtab == 1){
1126 silence();
1127 startplaytrack(currtrack);
1128 }else if(currtab == 0){
1129 silence();
1130 startplaysong(songy);
1133 break;
1134 case '`':
1135 if(currtab == 0){
1136 int t = song[songy].track[songx / 4];
1137 if(t) currtrack = t;
1138 currtab = 1;
1139 }else if(currtab == 1){
1140 currtab = 0;
1142 break;
1143 default:
1144 _insertc(c);
1145 if(currtab == 1){
1146 tracky+=step;
1147 tracky %= tracklen;
1148 }else if(currtab == 2){
1149 //if(instry < instrument[currinstr].length-1) instry++;
1150 if(instrx < 2) instrx++;
1151 else instrx--;
1152 instry %= instrument[currinstr].length;
1154 saved = 0;
1156 drawgui();
1157 usleep(10000);
1161 /* jammer mode */
1162 void jammermode(void){
1163 int c, x;
1164 currmode = PM_JAMMER;
1165 while(currmode == PM_JAMMER){
1166 if((c = getch()) != ERR) switch(c){
1167 case KEY_ESCAPE:
1168 currmode = PM_NORMAL;
1169 break;
1170 case '[':
1171 act_viewinstrdec();
1172 break;
1173 case ']':
1174 act_viewinstrinc();
1175 break;
1176 case '<':
1177 if(octave) octave--;
1178 break;
1179 case '>':
1180 if(octave < 8) octave++;
1181 break;
1182 default:
1183 x = freqkey(c);
1185 if(x > 0){
1186 iedplonk(x, currinstr);
1189 break;
1191 drawgui();
1192 usleep(10000);
1196 /* visual mode */
1197 void visualmode(void){
1198 int c;
1200 currmode = PM_VISUAL;
1201 //attrset(A_REVERSE);
1202 if(currtab == 0){
1203 }else if(currtab == 1){
1204 highlight_firstx = trackx;
1205 highlight_lastx = trackx;
1206 highlight_firsty = tracky;
1207 highlight_lasty = tracky;
1208 }else if(currtab == 2){
1209 }else{
1210 highlight_firstx = -1;
1211 highlight_lastx = -1;
1212 highlight_firsty = -1;
1213 highlight_lasty = -1;
1216 while(currmode == PM_VISUAL){
1217 if((c = getch()) != ERR) switch(c){
1218 case 'v':
1219 case KEY_ESCAPE:
1220 currmode = PM_NORMAL;
1221 break;
1222 case 'V':
1223 visuallinemode();
1224 break;
1225 case 'h':
1226 act_mvleft();
1227 if(currtab==0){
1228 }else if(currtab==1){
1229 highlight_lastx = trackx;
1230 }else if(currtab==2){
1232 break;
1233 case 'j':
1234 act_mvdown();
1235 if(currtab==0){
1236 }else if(currtab==1){
1237 highlight_lasty = tracky;
1238 }else if(currtab==2){
1240 break;
1241 case 'k':
1242 act_mvup();
1243 if(currtab==0){
1244 }else if(currtab==1){
1245 highlight_lasty = tracky;
1246 }else if(currtab==2){
1248 break;
1249 case 'l':
1250 act_mvright();
1251 if(currtab==0){
1252 }else if(currtab==1){
1253 highlight_lastx = trackx;
1254 }else if(currtab==2){
1256 break;
1258 drawgui();
1260 attrset(A_BOLD);
1261 return;
1264 /* visual line mode */
1265 void visuallinemode(void){
1266 int c;
1267 int min, max;
1268 char buf[1024];
1270 currmode = PM_VISUALLINE;
1272 /* Store the current line as the first and last node of a linked list */
1273 if(currtab==0){
1274 highlight_firstline = songy;
1275 highlight_lastline = songy;
1276 }else if(currtab==1){
1277 highlight_firstline = tracky;
1278 highlight_lastline = tracky;
1279 }else if(currtab==2){
1280 highlight_firstline = instry;
1281 highlight_lastline = instry;
1282 }else{
1283 highlight_firstline = -1;
1284 highlight_lastline = -1;
1287 // initialize difference
1288 highlight_lineamount = 1;
1290 // make it visible to gui.c
1291 //highlightlines = firstnode;
1293 while(currmode == PM_VISUALLINE){
1294 if((c = getch()) != ERR) switch(c){
1295 case 'V':
1296 case KEY_ESCAPE:
1297 currmode = PM_NORMAL;
1298 break;
1299 case 'v':
1300 visualmode();
1301 case 'h':
1302 act_mvleft();
1303 break;
1304 case 'j':
1305 act_mvdown();
1306 // update lastnode
1307 if(currtab==0){
1308 highlight_lastline = songy;
1309 }else if(currtab==1){
1310 highlight_lastline = tracky;
1311 }else if(currtab==2){
1312 highlight_lastline = instry;
1314 // update the highlighted length
1315 highlight_lineamount = (highlight_firstline>highlight_lastline)?
1316 highlight_firstline - highlight_lastline +1
1317 : highlight_lastline - highlight_firstline +1;
1318 break;
1319 case 'k':
1320 act_mvup();
1321 // update lastnode
1322 if(currtab==0){
1323 highlight_lastline = songy;
1324 }else if(currtab==1){
1325 highlight_lastline = tracky;
1326 }else if(currtab==2){
1327 highlight_lastline = instry;
1329 // update the highlighted length
1330 highlight_lineamount = (highlight_firstline>highlight_lastline)?
1331 highlight_firstline - highlight_lastline +1
1332 : highlight_lastline - highlight_firstline +1;
1333 break;
1334 case 'l':
1335 act_mvright();
1336 break;
1337 case 'g':
1338 if(nextchar() == 'g'){
1339 act_mvtop();
1341 break;
1342 case 'G':
1343 act_mvbottom();
1344 break;
1345 // d: copy every line that is highlighted to the paste buffer and clear them, too
1346 case 'd':
1347 min = (highlight_firstline < highlight_lastline)?
1348 highlight_firstline
1349 : highlight_lastline;
1350 max = (highlight_firstline < highlight_lastline)?
1351 highlight_lastline
1352 : highlight_firstline;
1353 if(currtab == 0){
1354 for(int i=min; i<=max; i++)
1355 act_clrinsongtab(i);
1356 }else if(currtab == 1){
1357 for(int i=min; i<=max; i++)
1358 act_clrintracktab(currtrack, i);
1359 }else if(currtab == 2){
1360 for(int i=min; i<=max; i++)
1361 act_clrininstrtab(currinstr, i);
1363 //snprintf(buf, sizeof(buf), "%d fewer lines", highlight_lineamount);
1364 //infinitemsg = buf;
1365 currmode = PM_NORMAL;
1366 break;
1367 // y: copy every line that is highlighted to the paste buffer
1368 case 'y':
1369 if(currtab == 0){
1370 //tcliplen = 1;
1371 //memcpy(&tclip, &song[songy], sizeof(struct songline)*highlight_lineamount);
1372 tcliplen = highlight_lineamount;
1373 //moved up, then yanked
1374 if(highlight_firstline > highlight_lastline){
1375 for(int i = 0; i < highlight_lineamount; i++)
1376 memcpy(&tclip[i], &song[songy+i], sizeof(struct songline));
1377 //moved down, then yanked
1378 }else if(highlight_lastline > highlight_firstline){
1379 for(int i = highlight_lineamount-1, j = 0; i >= 0; i--, j++){
1380 memcpy(&tclip[i], &song[songy-j], sizeof(struct songline));
1383 }else if(currtab == 1){
1384 tcliplen = highlight_lineamount;
1385 //moved up, then yanked
1386 if(highlight_firstline > highlight_lastline){
1387 for(int i = 0; i < highlight_lineamount; i++)
1388 memcpy(&tclip[i], &track[currtrack].line[tracky+i], sizeof(struct trackline));
1389 //moved down, then yanked
1390 }else if(highlight_lastline > highlight_firstline){
1391 for(int i = highlight_lineamount-1, j = 0; i >= 0; i--, j++){
1392 memcpy(&tclip[i], &track[currtrack].line[tracky-j], sizeof(struct trackline));
1395 }else if(currtab == 2){
1396 //icliplen = 1;
1397 //memcpy(&iclip, &instrument[currinstr].line[instry], sizeof(struct instrline)*highlight_lineamount);
1398 icliplen = highlight_lineamount;
1399 //moved up, then yanked
1400 if(highlight_firstline > highlight_lastline){
1401 for(int i = 0; i < highlight_lineamount; i++)
1402 memcpy(&iclip[i], &instrument[currinstr].line[instry+i], sizeof(struct instrline));
1403 //moved down, then yanked
1404 }else if(highlight_lastline > highlight_firstline){
1405 for(int i = highlight_lineamount-1, j = 0; i >= 0; i--, j++){
1406 memcpy(&iclip[i], &instrument[currinstr].line[instry-j], sizeof(struct instrline));
1411 snprintf(buf, sizeof(buf), "%d lines yanked", highlight_lineamount);
1412 infinitemsg = buf;
1413 currmode = PM_NORMAL;
1414 break;
1416 drawgui();
1418 // update the highlighted length
1419 /*highlight_lineamount = (highlight_firstline>highlight_lastline)?
1420 highlight_firstline - highlight_lastline +1
1421 : highlight_lastline - highlight_firstline +1;
1424 highlight_firstline = -1;
1425 highlight_lastline = -1;
1427 return;