Every function that uses songlen now uses tune.songlen, except initsonglines, not...
[pineappletracker.git] / modes.c
blob7c5bb299ddc7a22e031824446d33e841dc0d57b8
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 "lft.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 lft_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 lft_savefile(filename);
212 saved = 1;
213 }else if(strcmp(cmd, ":wq") == 0 || strcmp(cmd, ":x") == 0){
214 lft_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(lft_loadfile(cmd+3,&tune)){
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 lft_saveinstrument(cmd+6);
236 setdisplay("d-_-b saved ins! d-_-b");
237 }else if(!strncmp(cmd+1,"load ",5)){
238 lft_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>tune.songlen)? tune.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 act_addline();
291 break;
292 case '.':
293 // if the last command was a replace, just insert the last thing
294 // inserted instead of calling insertmode()
295 if(lastaction == 'r')
296 _insertc(lastinsert);
297 else
298 normalmode(lastaction);
299 cmdrepeatnum = lastrepeatnum;
300 break;
301 case KEY_ESCAPE:
302 disptick = 0;
303 jammermode();
304 break;
305 case CTRL('Y'):
306 switch(currtab){
307 case 0:
308 if(songoffs>0){
309 if(songy==getmaxy(stdscr)-3+songoffs)
310 songy--;
311 songoffs--;
313 break;
314 case 1:
315 if(trackoffs>0){
316 if(tracky==getmaxy(stdscr)-3+trackoffs)
317 tracky--;
318 trackoffs--;
320 break;
321 case 2:
322 if(instroffs>0){
323 if(instry==getmaxy(stdscr)-3+instroffs)
324 instry--;
325 instroffs--;
327 break;
329 break;
330 case CTRL('E'):
331 switch(currtab){
332 case 0:
333 if(songy<=tune.songlen-2){
334 if(songy==songoffs)
335 songy++;
336 songoffs++;
338 break;
339 case 1:
340 if(tracky<=tracklen-2){
341 if(tracky==trackoffs)
342 tracky++;
343 trackoffs++;
345 break;
346 case 2:
347 if(instry<=instrument[currinstr].length-2){
348 if(instry==instroffs)
349 instry++;
350 instroffs++;
352 break;
354 break;
355 case 'H':
356 switch(currtab){
357 case 0:
358 songy = songoffs;
359 break;
360 case 1:
361 tracky = trackoffs;
362 break;
363 case 2:
364 instry = instroffs;
365 break;
367 break;
369 // the second cases (to the right of the colon) for M and L
370 // took some serious guesswork, so I'm not sure if they're
371 // correct but they seem to work.
372 case 'M':
373 switch(currtab){
374 case 0:
375 songy = (tune.songlen <= getmaxy(stdscr)-2)?
376 tune.songlen/2
377 : ((getmaxy(stdscr)-6)/2) + songoffs;
378 break;
379 case 1:
380 tracky = (tracklen <= getmaxy(stdscr)-2)?
381 tracklen/2
382 : ((getmaxy(stdscr)-6)/2) + trackoffs;
383 break;
384 case 2:
385 instry = (instrument[currinstr].length <= getmaxy(stdscr)-2)?
386 instrument[currinstr].length/2
387 : ((getmaxy(stdscr)-6)/2) + instroffs;
388 break;
390 break;
391 case 'L':
392 switch(currtab){
393 case 0:
394 songy = (tune.songlen <= getmaxy(stdscr)-2)?
395 tune.songlen-1
396 : getmaxy(stdscr)-3+songoffs;
397 break;
398 case 1:
399 tracky = (tracklen <= getmaxy(stdscr)-2)?
400 tracklen-1
401 : getmaxy(stdscr)-3+trackoffs;
402 break;
403 case 2:
404 instry = (instrument[currinstr].length <= getmaxy(stdscr)-2)?
405 instrument[currinstr].length-1
406 : getmaxy(stdscr)-3+instroffs;
407 break;
409 break;
410 case 'g':
411 if(nextchar() == 'g'){
412 act_mvtop();
414 break;
415 case 'G':
416 act_mvbottom();
417 break;
419 // yank
420 case 'y':
421 c = nextchar();
422 switch(c){
423 case 'y':
424 //tclip = malloc(1);
425 if(currtab == 0){
426 tcliplen = 1;
427 memcpy(&tclip, &song[songy], sizeof(struct songline));
428 }else if(currtab == 1){
429 tcliplen = 1;
430 memcpy(&tclip, &track[currtrack].line[tracky], sizeof(struct trackline));
431 }else if(currtab == 2){
432 icliplen = 1;
433 memcpy(&iclip, &instrument[currinstr].line[instry], sizeof(struct instrline));
435 break;
436 case 'j':
437 //tclip = malloc(2);
438 if(currtab == 0){
439 tcliplen = 2;
440 memcpy(&tclip[0], &song[songy], sizeof(struct songline));
441 act_mvdown();
442 memcpy(&tclip[1], &song[songy], sizeof(struct songline));
443 }else if(currtab == 1){
444 tcliplen = 2;
445 memcpy(&tclip[0], &track[currtrack].line[tracky], sizeof(struct trackline));
446 act_mvdown();
447 memcpy(&tclip[1], &track[currtrack].line[tracky], sizeof(struct trackline));
448 }else if(currtab == 2){
449 icliplen = 2;
450 memcpy(&iclip[0], &instrument[currinstr].line[instry], sizeof(struct instrline));
451 act_mvdown();
452 memcpy(&iclip[1], &instrument[currinstr].line[instry], sizeof(struct instrline));
454 break;
455 case 'k':
456 //tclip = malloc(2);
457 if(currtab == 0){
458 tcliplen = 2;
459 memcpy(&tclip[1], &song[songy], sizeof(struct songline));
460 act_mvup();
461 memcpy(&tclip[0], &song[songy], sizeof(struct songline));
462 }else if(currtab == 1){
463 tcliplen = 2;
464 memcpy(&tclip[1], &track[currtrack].line[tracky], sizeof(struct trackline));
465 act_mvup();
466 memcpy(&tclip[0], &track[currtrack].line[tracky], sizeof(struct trackline));
467 }else if(currtab == 2){
468 icliplen = 2;
469 memcpy(&iclip[1], &instrument[currinstr].line[instry], sizeof(struct instrline));
470 act_mvup();
471 memcpy(&iclip[0], &instrument[currinstr].line[instry], sizeof(struct instrline));
473 break;
475 break;
477 //paste
478 case 'p':
479 if(currtab == 0){
480 if(tune.songlen < 256){
481 for(int i = 0; i < tcliplen; i++){
482 // insert new line
483 memmove(&song[songy + 2], &song[songy + 1], sizeof(struct songline) * (tune.songlen - songy - 1));
484 songy++;
485 tune.songlen++;
486 memset(&song[songy], 0, sizeof(struct songline));
488 // paste to new line
489 memcpy(&song[songy], &tclip[i], sizeof(struct songline));
492 }else if(currtab == 1){
493 for(int i = 0; i < tcliplen; i++){
494 memcpy(&track[currtrack].line[tracky], &tclip[i], sizeof(struct trackline));
495 if(tracky < tracklen-step) tracky += step;
496 else tracky = tracklen-1;
498 }else if(currtab == 2){
499 if(instrument[currinstr].length < 256){
500 // insert new line
501 for(int i = 0; i < icliplen; i++){
502 struct instrument *in = &instrument[currinstr];
504 instry++;
505 memmove(&in->line[instry + 1], &in->line[instry + 0], sizeof(struct instrline) * (in->length - instry));
506 in->length++;
507 in->line[instry].cmd = '0';
508 in->line[instry].param = 0;
510 // paste to new line
511 memcpy(&instrument[currinstr].line[instry], &iclip[i], sizeof(struct instrline));
514 //if(instry < instrument[currinstr].length-1) instry++;
516 break;
518 // copy everything in the current phrase or instrument into the next free one
519 case '^':
520 if(currtab == 1){
521 f = nextfreetrack();
522 memcpy(&track[f], &track[currtrack], sizeof(struct track));
523 currtrack = f;
524 }else if(currtab == 2){
525 f = nextfreeinstr();
526 memcpy(&instrument[f], &instrument[currinstr], sizeof(struct instrument));
527 currinstr = f;
529 break;
531 // TODO: Y and P can be removed after we make visual mode
532 // copy whole phrase or instrument
533 case 'Y':
534 if(currtab == 1){
535 memcpy(&tclip, &track[currtrack], sizeof(struct track));
536 }else if(currtab == 2){
537 memcpy(&iclip, &instrument[currinstr], sizeof(struct instrument));
539 break;
540 // paste whole phrase or instrument
541 case 'P':
542 if(currtab == 1){
543 memcpy(&track[currtrack], &tclip, sizeof(struct track));
544 }else if(currtab == 2){
545 memcpy(&instrument[currinstr], &iclip, sizeof(struct instrument));
547 break;
549 /* delete line */
550 // TODO: clean this SHIT up
551 // TODO: add an ACT_ function for delete
552 case 'd':
553 c = nextchar();
554 switch(c){
555 case 'd':
556 act_delline();
557 break;
558 case 'k':
559 if(currtab == 2){
560 struct instrument *in = &instrument[currinstr];
561 instry--;
562 int i;
563 for(i=0; i<2; i++){
564 if(in->length > 1){
565 memmove(&in->line[instry + 0], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
566 in->length--;
567 if(instry >= in->length) instry = in->length - 1;
570 }else if(currtab == 0){
571 songy--;
572 int i;
573 for(i=0; i<2; i++){
574 if(tune.songlen > 1){
575 memmove(&song[songy + 0], &song[songy + 1], sizeof(struct songline) * (tune.songlen - songy - 1));
576 tune.songlen--;
577 if(songy >= tune.songlen) songy = tune.songlen - 1;
581 break;
582 case 'j':
583 if(currtab == 2){
584 struct instrument *in = &instrument[currinstr];
586 int i;
587 for(i=0; i<2; i++){
588 if(in->length > 1){
589 memmove(&in->line[instry + 0], &in->line[instry + 1], sizeof(struct instrline) * (in->length - instry - 1));
590 in->length--;
591 if(instry >= in->length) instry = in->length - 1;
594 }else if(currtab == 0){
595 int i;
596 for(i=0; i<2; i++){
597 if(tune.songlen > 1){
598 memmove(&song[songy + 0], &song[songy + 1], sizeof(struct songline) * (tune.songlen - songy - 1));
599 tune.songlen--;
600 if(songy >= tune.songlen) songy = tune.songlen - 1;
604 break;
606 break;
607 /* undo */
608 case 'u':
609 act_undo();
610 /* Clear */
611 case 'x':
612 act_clronething();
613 break;
614 case 'X':
615 act_clritall();
616 break;
617 case ENTER:
618 if(currtab != 2){
619 if(currtab == 1){
620 silence();
621 startplaytrack(currtrack);
622 }else if(currtab == 0){
623 silence();
624 startplaysong(songy);
627 break;
628 case 'Z':
629 c = nextchar();
630 switch(c){
631 case 'Z':
632 lft_savefile(filename);
633 erase();
634 refresh();
635 endwin();
636 exit(0);
637 break;
638 case 'Q':
639 erase();
640 refresh();
641 endwin();
642 exit(0);
643 break;
645 break;
646 /* Enter command mode */
647 case ':':
648 cmdlinemode();
649 break;
650 case ' ':
651 silence();
652 break;
653 // TODO: make an act_ function for '`'
654 case '`':
655 if(currtab == 0){
656 int t = song[songy].track[songx / 4];
657 if(t) currtrack = t;
658 currtab = 1;
659 if(playtrack){
660 startplaytrack(currtrack);
662 }else if((currtab == 1) && ((trackx == 2) || (trackx == 3))){
663 int i = track[currtrack].line[tracky].instr;
664 if(i) currinstr = i;
665 currtab = 2;
666 } else if(currtab == 1){
667 currtab = 0;
668 }else if(currtab == 2){
669 currtab = 1;
671 break;
672 /* Enter insert mode */
673 case 'i':
674 insertmode();
675 break;
676 /* Enter visual mode */
677 case 'v':
678 visualmode();
679 break;
680 /* Enter visual line mode */
681 case 'V':
682 visuallinemode();
683 break;
684 /* enter jammer mode */
685 case CTRL('A'):
686 jammermode();
687 break;
688 /* Add new line and enter insert mode */
689 case 'o':
690 act_addline();
691 insertmode();
692 break;
693 case 'h':
694 case KEY_LEFT:
695 act_mvleft();
696 break;
697 case 'j':
698 case KEY_DOWN:
699 act_mvdown();
700 break;
701 case 'k':
702 case KEY_UP:
703 act_mvup();
704 break;
705 case 'l':
706 case KEY_RIGHT:
707 act_mvright();
708 break;
709 case '<':
710 if(octave) octave--;
711 break;
712 case '>':
713 if(octave < 8) octave++;
714 break;
715 case '{':
716 if(currtrack > 1) currtrack--;
717 break;
718 case '}':
719 if(currtrack < 255) currtrack++;
720 break;
721 case 'J':
722 if(currtab == 0){
723 if( (songx%4) < 2){
724 act_trackdec();
725 }else{
726 act_transpdec();
728 }else if(currtab == 1){
729 switch(trackx){
730 case 0:
731 act_notedec();
732 break;
733 case 1:
734 act_octavedec();
735 break;
736 case 2:
737 act_instrdec();
738 break;
739 case 3:
740 act_instrdec();
741 break;
742 case 4:
743 act_fxdec();
744 break;
745 case 5:
746 case 6:
747 act_paramdec();
748 break;
749 case 7:
750 act_fxdec();
751 break;
752 case 8:
753 case 9:
754 act_paramdec();
755 break;
756 default:
757 setdisplay("in J");
758 break;
760 }else if(currtab == 2){
761 switch(instrx){
762 case 0:
763 act_fxdec();
764 break;
765 case 1:
766 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
767 act_notedec();
768 }else{
769 act_paramdec();
771 break;
772 case 2:
773 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
774 act_notedec();
775 }else{
776 act_paramdec();
778 break;
781 break;
782 case 'K':
783 if(currtab == 0){
784 if( (songx%4) < 2){
785 act_trackinc();
786 }else{
787 act_transpinc();
789 }else if(currtab == 1){
790 switch(trackx){
791 case 0:
792 act_noteinc();
793 break;
794 case 1:
795 act_octaveinc();
796 break;
797 case 2:
798 act_instrinc();
799 break;
800 case 3:
801 act_instrinc();
802 break;
803 case 4:
804 act_fxinc();
805 break;
806 case 5:
807 case 6:
808 act_paraminc();
809 break;
810 case 7:
811 act_fxinc();
812 break;
813 case 8:
814 case 9:
815 act_paraminc();
816 break;
817 default:
818 setdisplay("in K");
819 break;
821 }else if(currtab == 2){
822 switch(instrx){
823 case 0:
824 act_fxinc();
825 break;
826 case 1:
827 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
828 act_noteinc();
829 }else{
830 act_paraminc();
832 break;
833 case 2:
834 if(instrument[currinstr].line[instry].cmd == '+' || instrument[currinstr].line[instry].cmd == '='){
835 act_noteinc();
836 }else{
837 act_paraminc();
839 break;
842 break;
843 case CTRL('J'):
844 if(currtab == 2){
845 act_viewinstrdec();
846 }else if(currtab == 1){
847 act_viewtrackdec();
849 break;
850 case CTRL('K'):
851 if(currtab == 2){
852 act_viewinstrinc();
853 }else if(currtab == 1){
854 act_viewtrackinc();
856 break;
857 case '[':
858 act_viewinstrdec();
859 break;
860 case ']':
861 act_viewinstrinc();
862 break;
863 case '(':
864 callbacktime++;
865 break;
866 case ')':
867 callbacktime--;
868 break;
869 case '-':
870 if(step > 0)
871 step--;
872 break;
873 case '=':
874 if(step < 0x0f)
875 step++;
876 break;
877 case CTRL('H'):
878 currtab--;
879 if(currtab < 0)
880 currtab = 2;
881 break;
882 case CTRL('L'):
883 currtab++;
884 currtab %= 3;
885 break;
886 case KEY_TAB:
887 currtab++;
888 currtab %= 3;
889 break;
890 case CTRL('U'):
891 act_bigmvup();
892 break;
893 case CTRL('D'):
894 act_bigmvdown();
895 break;
896 /*case CTRL('P'):
897 vimode = false;
898 break;*/
900 // replace
901 case 'r':
902 _insertc(nextchar());
903 break;
905 default:
906 break;
907 } // end switch
908 } // end for
909 cmdrepeatnum = 1;
910 cmdrepeat = 0;
913 /* vi cmdline mode */
914 void cmdlinemode(void){
915 u16 c;
916 keypad(stdscr, TRUE);
918 currmode = PM_CMDLINE;
919 strncat(cmdstr, ":", 100);
920 for(;;){
921 drawgui();
923 c = nextchar();
924 switch(c){
925 case KEY_ESCAPE:
926 //cmdstr = "";
927 currmode = PM_NORMAL;
928 goto end;
929 case ENTER:
930 _parsecmd(cmdstr);
931 goto end;
932 #ifndef WINDOWS
933 case BACKSPACE:
934 setdisplay("\\o/");
935 cmdstr[strlen(cmdstr)-1] = '\0';
936 break;
937 #endif
938 case '\t':
939 break;
940 default:
941 strncat(cmdstr, &c, 50);
942 break;
945 end:
946 strcpy(cmdstr, "");
947 keypad(stdscr, FALSE);
948 return;
951 /* vi insert mode */
952 void insertmode(void){
953 int c;
954 currmode = PM_INSERT;
955 drawgui();
956 for(;;){
957 if((c = getch()) != ERR) switch(c){
958 case KEY_ESCAPE:
959 currmode = PM_NORMAL;
960 return;
961 case 'h':
962 case KEY_LEFT:
963 act_mvleft();
964 break;
965 case 'j':
966 case KEY_DOWN:
967 act_mvdown();
968 break;
969 case 'k':
970 case KEY_UP:
971 act_mvup();
972 break;
973 case 'l':
974 case KEY_RIGHT:
975 act_mvright();
976 break;
977 /* change octave */
978 case '<':
979 if(octave) octave--;
980 break;
981 case '>':
982 if(octave < 8) octave++;
983 break;
984 /* change instrument */
985 case CTRL('J'):
986 if(currtab == 2){
987 act_viewinstrdec();
988 }else if(currtab == 1){
989 act_viewtrackdec();
991 break;
992 case CTRL('K'):
993 if(currtab == 2){
994 act_viewinstrinc();
995 }else if(currtab == 1){
996 act_viewtrackinc();
998 break;
999 case '[':
1000 act_viewinstrdec();
1001 break;
1002 case ']':
1003 act_viewinstrinc();
1004 break;
1005 case CTRL('H'):
1006 currtab--;
1007 if(currtab < 0)
1008 currtab = 2;
1009 break;
1010 case CTRL('L'):
1011 currtab++;
1012 currtab %= 3;
1013 break;
1014 case 'Z':
1015 c = nextchar();
1016 switch(c){
1017 case 'Z':
1018 lft_savefile(filename);
1019 erase();
1020 refresh();
1021 endwin();
1022 exit(0);
1023 break;
1024 case 'Q':
1025 erase();
1026 refresh();
1027 endwin();
1028 exit(0);
1029 break;
1031 break;
1032 case ' ':
1033 silence();
1034 currmode = PM_NORMAL;
1035 return;
1036 case ENTER:
1037 if(currtab != 2){
1038 if(currtab == 1){
1039 silence();
1040 startplaytrack(currtrack);
1041 }else if(currtab == 0){
1042 silence();
1043 startplaysong(songy);
1046 break;
1047 case '`':
1048 if(currtab == 0){
1049 int t = song[songy].track[songx / 4];
1050 if(t) currtrack = t;
1051 currtab = 1;
1052 }else if(currtab == 1){
1053 currtab = 0;
1055 break;
1056 default:
1057 _insertc(c);
1058 if(currtab == 1){
1059 tracky+=step;
1060 tracky %= tracklen;
1061 }else if(currtab == 2){
1062 //if(instry < instrument[currinstr].length-1) instry++;
1063 if(instrx < 2) instrx++;
1064 else instrx--;
1065 instry %= instrument[currinstr].length;
1067 saved = 0;
1069 drawgui();
1070 usleep(10000);
1074 /* jammer mode */
1075 void jammermode(void){
1076 int c, x;
1077 currmode = PM_JAMMER;
1078 while(currmode == PM_JAMMER){
1079 if((c = getch()) != ERR) switch(c){
1080 case KEY_ESCAPE:
1081 currmode = PM_NORMAL;
1082 break;
1083 case '[':
1084 act_viewinstrdec();
1085 break;
1086 case ']':
1087 act_viewinstrinc();
1088 break;
1089 case '<':
1090 if(octave) octave--;
1091 break;
1092 case '>':
1093 if(octave < 8) octave++;
1094 break;
1095 default:
1096 x = freqkey(c);
1098 if(x > 0){
1099 iedplonk(x, currinstr);
1102 break;
1104 drawgui();
1105 usleep(10000);
1109 /* visual mode */
1110 void visualmode(void){
1111 int c;
1113 currmode = PM_VISUAL;
1114 //attrset(A_REVERSE);
1115 if(currtab == 0){
1116 }else if(currtab == 1){
1117 highlight_firstx = trackx;
1118 highlight_lastx = trackx;
1119 highlight_firsty = tracky;
1120 highlight_lasty = tracky;
1121 }else if(currtab == 2){
1122 }else{
1123 highlight_firstx = -1;
1124 highlight_lastx = -1;
1125 highlight_firsty = -1;
1126 highlight_lasty = -1;
1129 while(currmode == PM_VISUAL){
1130 if((c = getch()) != ERR) switch(c){
1131 case 'v':
1132 case KEY_ESCAPE:
1133 currmode = PM_NORMAL;
1134 break;
1135 case 'V':
1136 visuallinemode();
1137 break;
1138 case 'h':
1139 act_mvleft();
1140 if(currtab==0){
1141 }else if(currtab==1){
1142 highlight_lastx = trackx;
1143 }else if(currtab==2){
1145 break;
1146 case 'j':
1147 act_mvdown();
1148 if(currtab==0){
1149 }else if(currtab==1){
1150 highlight_lasty = tracky;
1151 }else if(currtab==2){
1153 break;
1154 case 'k':
1155 act_mvup();
1156 if(currtab==0){
1157 }else if(currtab==1){
1158 highlight_lasty = tracky;
1159 }else if(currtab==2){
1161 break;
1162 case 'l':
1163 act_mvright();
1164 if(currtab==0){
1165 }else if(currtab==1){
1166 highlight_lastx = trackx;
1167 }else if(currtab==2){
1169 break;
1171 drawgui();
1173 attrset(A_BOLD);
1174 return;
1177 /* visual line mode */
1178 void visuallinemode(void){
1179 int c;
1180 int min, max;
1181 char buf[1024];
1183 currmode = PM_VISUALLINE;
1185 /* Store the current line as the first and last node of a linked list */
1186 if(currtab==0){
1187 highlight_firstline = songy;
1188 highlight_lastline = songy;
1189 }else if(currtab==1){
1190 highlight_firstline = tracky;
1191 highlight_lastline = tracky;
1192 }else if(currtab==2){
1193 highlight_firstline = instry;
1194 highlight_lastline = instry;
1195 }else{
1196 highlight_firstline = -1;
1197 highlight_lastline = -1;
1200 // initialize difference
1201 highlight_lineamount = 1;
1203 // make it visible to gui.c
1204 //highlightlines = firstnode;
1206 while(currmode == PM_VISUALLINE){
1207 if((c = getch()) != ERR) switch(c){
1208 case 'V':
1209 case KEY_ESCAPE:
1210 currmode = PM_NORMAL;
1211 break;
1212 case 'v':
1213 visualmode();
1214 case 'h':
1215 act_mvleft();
1216 break;
1217 case 'j':
1218 act_mvdown();
1219 // update lastnode
1220 if(currtab==0){
1221 highlight_lastline = songy;
1222 }else if(currtab==1){
1223 highlight_lastline = tracky;
1224 }else if(currtab==2){
1225 highlight_lastline = instry;
1227 // update the highlighted length
1228 highlight_lineamount = (highlight_firstline>highlight_lastline)?
1229 highlight_firstline - highlight_lastline +1
1230 : highlight_lastline - highlight_firstline +1;
1231 break;
1232 case 'k':
1233 act_mvup();
1234 // update lastnode
1235 if(currtab==0){
1236 highlight_lastline = songy;
1237 }else if(currtab==1){
1238 highlight_lastline = tracky;
1239 }else if(currtab==2){
1240 highlight_lastline = instry;
1242 // update the highlighted length
1243 highlight_lineamount = (highlight_firstline>highlight_lastline)?
1244 highlight_firstline - highlight_lastline +1
1245 : highlight_lastline - highlight_firstline +1;
1246 break;
1247 case 'l':
1248 act_mvright();
1249 break;
1250 case 'g':
1251 if(nextchar() == 'g'){
1252 act_mvtop();
1254 break;
1255 case 'G':
1256 act_mvbottom();
1257 break;
1258 // d: copy every line that is highlighted to the paste buffer and clear them, too
1259 case 'd':
1260 min = (highlight_firstline < highlight_lastline)?
1261 highlight_firstline
1262 : highlight_lastline;
1263 max = (highlight_firstline < highlight_lastline)?
1264 highlight_lastline
1265 : highlight_firstline;
1266 if(currtab == 0){
1267 for(int i=min; i<=max; i++)
1268 act_clrinsongtab(i);
1269 }else if(currtab == 1){
1270 for(int i=min; i<=max; i++)
1271 act_clrintracktab(currtrack, i);
1272 }else if(currtab == 2){
1273 for(int i=min; i<=max; i++)
1274 act_clrininstrtab(currinstr, i);
1276 //snprintf(buf, sizeof(buf), "%d fewer lines", highlight_lineamount);
1277 //infinitemsg = buf;
1278 currmode = PM_NORMAL;
1279 break;
1280 // y: copy every line that is highlighted to the paste buffer
1281 case 'y':
1282 if(currtab == 0){
1283 //tcliplen = 1;
1284 //memcpy(&tclip, &song[songy], sizeof(struct songline)*highlight_lineamount);
1285 tcliplen = highlight_lineamount;
1286 //moved up, then yanked
1287 if(highlight_firstline > highlight_lastline){
1288 for(int i = 0; i < highlight_lineamount; i++)
1289 memcpy(&tclip[i], &song[songy+i], sizeof(struct songline));
1290 //moved down, then yanked
1291 }else if(highlight_lastline > highlight_firstline){
1292 for(int i = highlight_lineamount-1, j = 0; i >= 0; i--, j++){
1293 memcpy(&tclip[i], &song[songy-j], sizeof(struct songline));
1296 }else if(currtab == 1){
1297 tcliplen = highlight_lineamount;
1298 //moved up, then yanked
1299 if(highlight_firstline > highlight_lastline){
1300 for(int i = 0; i < highlight_lineamount; i++)
1301 memcpy(&tclip[i], &track[currtrack].line[tracky+i], sizeof(struct trackline));
1302 //moved down, then yanked
1303 }else if(highlight_lastline > highlight_firstline){
1304 for(int i = highlight_lineamount-1, j = 0; i >= 0; i--, j++){
1305 memcpy(&tclip[i], &track[currtrack].line[tracky-j], sizeof(struct trackline));
1308 }else if(currtab == 2){
1309 //icliplen = 1;
1310 //memcpy(&iclip, &instrument[currinstr].line[instry], sizeof(struct instrline)*highlight_lineamount);
1311 icliplen = highlight_lineamount;
1312 //moved up, then yanked
1313 if(highlight_firstline > highlight_lastline){
1314 for(int i = 0; i < highlight_lineamount; i++)
1315 memcpy(&iclip[i], &instrument[currinstr].line[instry+i], sizeof(struct instrline));
1316 //moved down, then yanked
1317 }else if(highlight_lastline > highlight_firstline){
1318 for(int i = highlight_lineamount-1, j = 0; i >= 0; i--, j++){
1319 memcpy(&iclip[i], &instrument[currinstr].line[instry-j], sizeof(struct instrline));
1324 snprintf(buf, sizeof(buf), "%d lines yanked", highlight_lineamount);
1325 infinitemsg = buf;
1326 currmode = PM_NORMAL;
1327 break;
1329 drawgui();
1331 // update the highlighted length
1332 /*highlight_lineamount = (highlight_firstline>highlight_lastline)?
1333 highlight_firstline - highlight_lastline +1
1334 : highlight_lastline - highlight_firstline +1;
1337 highlight_firstline = -1;
1338 highlight_lastline = -1;
1340 return;