1 /* vi:set syntax= ts=8 sts=8 sw=8 noexpandtab: */
2 /* WARNING: this file is ROSS STYLE */
15 int tcliplen
, icliplen
= 0;
19 if(c
>= '0' && c
<= '9') return c
- '0';
20 if(c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
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?
41 // this track is free, so return the index
42 if(j
== tracklen
-1) return i
;
46 setdisplay("nextfreetrack() failed somehow..");
51 for(int i
= 1; i
<= 0xff; i
++){
52 if(instrument
[i
].line
[0].cmd
== '0')
56 setdisplay("nextfreeinstr() failed somehow..");
67 && instrument
[currinstr
].line
[instry
].cmd
!= '+'
68 && instrument
[currinstr
].line
[instry
].cmd
!= '='){
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){
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;
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;
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
;
107 track
[currtrack
].line
[tracky
].instr
= currinstr
;
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
;
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)){
137 }else if( str
[i
]=='\0' ){
145 // Converts a hexadecimal string to integer
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
);
158 // Converting more than 32bit hexadecimal value?
159 if (szlen
>8) return 2; // exit
161 // Begin conversion here
165 // Run until no more character to convert
166 for(i
=szlen
-1; i
>=0 ;i
--){
167 if(isxdigit(*(xs
+i
))){
169 xv
= ( *(xs
+i
) - 97) + 10;
170 }else if( *(xs
+i
) >= 65){
171 xv
= (*(xs
+i
) - 65) + 10;
175 *result
+= (xv
* fact
);
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)
186 // Nothing to convert
190 void _parsecmd(char cmd
[]){
193 if(strcmp(cmd
, ":w") == 0){
194 lft_savefile(filename
);
196 }else if(strcmp(cmd
, ":q") == 0){
198 setdisplay("no write since last change! use :q! to override");
205 }else if(strcmp(cmd
, ":q!") == 0){
210 }else if(strcmp(cmd
, ":write") == 0){
211 lft_savefile(filename
);
213 }else if(strcmp(cmd
, ":wq") == 0 || strcmp(cmd
, ":x") == 0){
214 lft_savefile(filename
);
220 }else if(strcmp(cmd
, ":quit") == 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
)){
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;
246 songy
= (goton
>tune
.songlen
)? tune
.songlen
-1 : goton
;
249 currtrack
= (goton
>0xff)? 0xff : goton
;
252 currinstr
= (goton
>0xff)? 0xff : goton
;
255 }else if(cmd
[1] == 'c' && cmd
[2] == ' '){
256 strncpy(comment
, cmd
+3, sizeof(comment
));
258 setdisplay("not a tracker command!");
263 void normalmode(int c
){
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
283 lastrepeatnum
= cmdrepeatnum
;
286 for(i
=0; i
<cmdrepeatnum
; i
++){
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
);
298 normalmode(lastaction
);
299 cmdrepeatnum
= lastrepeatnum
;
309 if(songy
==getmaxy(stdscr
)-3+songoffs
)
316 if(tracky
==getmaxy(stdscr
)-3+trackoffs
)
323 if(instry
==getmaxy(stdscr
)-3+instroffs
)
333 if(songy
<=tune
.songlen
-2){
340 if(tracky
<=tracklen
-2){
341 if(tracky
==trackoffs
)
347 if(instry
<=instrument
[currinstr
].length
-2){
348 if(instry
==instroffs
)
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.
375 songy
= (tune
.songlen
<= getmaxy(stdscr
)-2)?
377 : ((getmaxy(stdscr
)-6)/2) + songoffs
;
380 tracky
= (tracklen
<= getmaxy(stdscr
)-2)?
382 : ((getmaxy(stdscr
)-6)/2) + trackoffs
;
385 instry
= (instrument
[currinstr
].length
<= getmaxy(stdscr
)-2)?
386 instrument
[currinstr
].length
/2
387 : ((getmaxy(stdscr
)-6)/2) + instroffs
;
394 songy
= (tune
.songlen
<= getmaxy(stdscr
)-2)?
396 : getmaxy(stdscr
)-3+songoffs
;
399 tracky
= (tracklen
<= getmaxy(stdscr
)-2)?
401 : getmaxy(stdscr
)-3+trackoffs
;
404 instry
= (instrument
[currinstr
].length
<= getmaxy(stdscr
)-2)?
405 instrument
[currinstr
].length
-1
406 : getmaxy(stdscr
)-3+instroffs
;
411 if(nextchar() == 'g'){
427 memcpy(&tclip
, &song
[songy
], sizeof(struct songline
));
428 }else if(currtab
== 1){
430 memcpy(&tclip
, &track
[currtrack
].line
[tracky
], sizeof(struct trackline
));
431 }else if(currtab
== 2){
433 memcpy(&iclip
, &instrument
[currinstr
].line
[instry
], sizeof(struct instrline
));
440 memcpy(&tclip
[0], &song
[songy
], sizeof(struct songline
));
442 memcpy(&tclip
[1], &song
[songy
], sizeof(struct songline
));
443 }else if(currtab
== 1){
445 memcpy(&tclip
[0], &track
[currtrack
].line
[tracky
], sizeof(struct trackline
));
447 memcpy(&tclip
[1], &track
[currtrack
].line
[tracky
], sizeof(struct trackline
));
448 }else if(currtab
== 2){
450 memcpy(&iclip
[0], &instrument
[currinstr
].line
[instry
], sizeof(struct instrline
));
452 memcpy(&iclip
[1], &instrument
[currinstr
].line
[instry
], sizeof(struct instrline
));
459 memcpy(&tclip
[1], &song
[songy
], sizeof(struct songline
));
461 memcpy(&tclip
[0], &song
[songy
], sizeof(struct songline
));
462 }else if(currtab
== 1){
464 memcpy(&tclip
[1], &track
[currtrack
].line
[tracky
], sizeof(struct trackline
));
466 memcpy(&tclip
[0], &track
[currtrack
].line
[tracky
], sizeof(struct trackline
));
467 }else if(currtab
== 2){
469 memcpy(&iclip
[1], &instrument
[currinstr
].line
[instry
], sizeof(struct instrline
));
471 memcpy(&iclip
[0], &instrument
[currinstr
].line
[instry
], sizeof(struct instrline
));
480 if(tune
.songlen
< 256){
481 for(int i
= 0; i
< tcliplen
; i
++){
483 memmove(&song
[songy
+ 2], &song
[songy
+ 1], sizeof(struct songline
) * (tune
.songlen
- songy
- 1));
486 memset(&song
[songy
], 0, sizeof(struct songline
));
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){
501 for(int i
= 0; i
< icliplen
; i
++){
502 struct instrument
*in
= &instrument
[currinstr
];
505 memmove(&in
->line
[instry
+ 1], &in
->line
[instry
+ 0], sizeof(struct instrline
) * (in
->length
- instry
));
507 in
->line
[instry
].cmd
= '0';
508 in
->line
[instry
].param
= 0;
511 memcpy(&instrument
[currinstr
].line
[instry
], &iclip
[i
], sizeof(struct instrline
));
514 //if(instry < instrument[currinstr].length-1) instry++;
518 // copy everything in the current phrase or instrument into the next free one
522 memcpy(&track
[f
], &track
[currtrack
], sizeof(struct track
));
524 }else if(currtab
== 2){
526 memcpy(&instrument
[f
], &instrument
[currinstr
], sizeof(struct instrument
));
531 // TODO: Y and P can be removed after we make visual mode
532 // copy whole phrase or instrument
535 memcpy(&tclip
, &track
[currtrack
], sizeof(struct track
));
536 }else if(currtab
== 2){
537 memcpy(&iclip
, &instrument
[currinstr
], sizeof(struct instrument
));
540 // paste whole phrase or instrument
543 memcpy(&track
[currtrack
], &tclip
, sizeof(struct track
));
544 }else if(currtab
== 2){
545 memcpy(&instrument
[currinstr
], &iclip
, sizeof(struct instrument
));
550 // TODO: clean this SHIT up
551 // TODO: add an ACT_ function for delete
560 struct instrument
*in
= &instrument
[currinstr
];
565 memmove(&in
->line
[instry
+ 0], &in
->line
[instry
+ 1], sizeof(struct instrline
) * (in
->length
- instry
- 1));
567 if(instry
>= in
->length
) instry
= in
->length
- 1;
570 }else if(currtab
== 0){
574 if(tune
.songlen
> 1){
575 memmove(&song
[songy
+ 0], &song
[songy
+ 1], sizeof(struct songline
) * (tune
.songlen
- songy
- 1));
577 if(songy
>= tune
.songlen
) songy
= tune
.songlen
- 1;
584 struct instrument
*in
= &instrument
[currinstr
];
589 memmove(&in
->line
[instry
+ 0], &in
->line
[instry
+ 1], sizeof(struct instrline
) * (in
->length
- instry
- 1));
591 if(instry
>= in
->length
) instry
= in
->length
- 1;
594 }else if(currtab
== 0){
597 if(tune
.songlen
> 1){
598 memmove(&song
[songy
+ 0], &song
[songy
+ 1], sizeof(struct songline
) * (tune
.songlen
- songy
- 1));
600 if(songy
>= tune
.songlen
) songy
= tune
.songlen
- 1;
621 startplaytrack(currtrack
);
622 }else if(currtab
== 0){
624 startplaysong(songy
);
632 lft_savefile(filename
);
646 /* Enter command mode */
653 // TODO: make an act_ function for '`'
656 int t
= song
[songy
].track
[songx
/ 4];
660 startplaytrack(currtrack
);
662 }else if((currtab
== 1) && ((trackx
== 2) || (trackx
== 3))){
663 int i
= track
[currtrack
].line
[tracky
].instr
;
666 } else if(currtab
== 1){
668 }else if(currtab
== 2){
672 /* Enter insert mode */
676 /* Enter visual mode */
680 /* Enter visual line mode */
684 /* enter jammer mode */
688 /* Add new line and enter insert mode */
713 if(octave
< 8) octave
++;
716 if(currtrack
> 1) currtrack
--;
719 if(currtrack
< 255) currtrack
++;
728 }else if(currtab
== 1){
760 }else if(currtab
== 2){
766 if(instrument
[currinstr
].line
[instry
].cmd
== '+' || instrument
[currinstr
].line
[instry
].cmd
== '='){
773 if(instrument
[currinstr
].line
[instry
].cmd
== '+' || instrument
[currinstr
].line
[instry
].cmd
== '='){
789 }else if(currtab
== 1){
821 }else if(currtab
== 2){
827 if(instrument
[currinstr
].line
[instry
].cmd
== '+' || instrument
[currinstr
].line
[instry
].cmd
== '='){
834 if(instrument
[currinstr
].line
[instry
].cmd
== '+' || instrument
[currinstr
].line
[instry
].cmd
== '='){
846 }else if(currtab
== 1){
853 }else if(currtab
== 1){
902 _insertc(nextchar());
913 /* vi cmdline mode */
914 void cmdlinemode(void){
916 keypad(stdscr
, TRUE
);
918 currmode
= PM_CMDLINE
;
919 strncat(cmdstr
, ":", 100);
927 currmode
= PM_NORMAL
;
935 cmdstr
[strlen(cmdstr
)-1] = '\0';
941 strncat(cmdstr
, &c
, 50);
947 keypad(stdscr
, FALSE
);
952 void insertmode(void){
954 currmode
= PM_INSERT
;
957 if((c
= getch()) != ERR
) switch(c
){
959 currmode
= PM_NORMAL
;
982 if(octave
< 8) octave
++;
984 /* change instrument */
988 }else if(currtab
== 1){
995 }else if(currtab
== 1){
1018 lft_savefile(filename
);
1034 currmode
= PM_NORMAL
;
1040 startplaytrack(currtrack
);
1041 }else if(currtab
== 0){
1043 startplaysong(songy
);
1049 int t
= song
[songy
].track
[songx
/ 4];
1050 if(t
) currtrack
= t
;
1052 }else if(currtab
== 1){
1061 }else if(currtab
== 2){
1062 //if(instry < instrument[currinstr].length-1) instry++;
1063 if(instrx
< 2) instrx
++;
1065 instry
%= instrument
[currinstr
].length
;
1075 void jammermode(void){
1077 currmode
= PM_JAMMER
;
1078 while(currmode
== PM_JAMMER
){
1079 if((c
= getch()) != ERR
) switch(c
){
1081 currmode
= PM_NORMAL
;
1090 if(octave
) octave
--;
1093 if(octave
< 8) octave
++;
1099 iedplonk(x
, currinstr
);
1110 void visualmode(void){
1113 currmode
= PM_VISUAL
;
1114 //attrset(A_REVERSE);
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){
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
){
1133 currmode
= PM_NORMAL
;
1141 }else if(currtab
==1){
1142 highlight_lastx
= trackx
;
1143 }else if(currtab
==2){
1149 }else if(currtab
==1){
1150 highlight_lasty
= tracky
;
1151 }else if(currtab
==2){
1157 }else if(currtab
==1){
1158 highlight_lasty
= tracky
;
1159 }else if(currtab
==2){
1165 }else if(currtab
==1){
1166 highlight_lastx
= trackx
;
1167 }else if(currtab
==2){
1177 /* visual line mode */
1178 void visuallinemode(void){
1183 currmode
= PM_VISUALLINE
;
1185 /* Store the current line as the first and last node of a linked list */
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
;
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
){
1210 currmode
= PM_NORMAL
;
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;
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;
1251 if(nextchar() == 'g'){
1258 // d: copy every line that is highlighted to the paste buffer and clear them, too
1260 min
= (highlight_firstline
< highlight_lastline
)?
1262 : highlight_lastline
;
1263 max
= (highlight_firstline
< highlight_lastline
)?
1265 : highlight_firstline
;
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
;
1280 // y: copy every line that is highlighted to the paste buffer
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){
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
);
1326 currmode
= PM_NORMAL
;
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;