1 /* vi:set ts=8 sts=8 sw=8 noexpandtab: */
3 /* welcome to gui.c, enjoy your stay 8-) */
22 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
24 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
27 static char *notenames
[] = {"C-", "C#", "D-", "D#", "E-", "F-", "F#",
28 "G-", "G#", "A-", "A#", "H-"};
30 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
31 \\\ local functions
.\
32 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
33 int _char2int(char ch
);
36 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
37 \\\ end local declarations
.\
38 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
40 char cmdstr
[500] = "";
43 int currmode
= PM_NORMAL
;
46 int tracklen
= TRACKLEN
;
58 // 0 is like a blank command
59 char *validcmds
= "0dfi@smtvw~+=*";
71 /* hexinc and hexdec wrap around */
73 return (x
>= 0 && x
<= 14)? x
+1 : 0;
76 return (x
>= 1 && x
<= 15)? x
-1 : 15;
79 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
80 \\\
< int _char2int(char) > .|
82 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
83 int _char2int(char ch
){
90 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
91 \\\
< int freqkey(int) > .|
92 /// Calculates the frequency of key c. .\
93 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
98 if(c
== '-' || c
== KEY_DC
) return 0;
100 s
= strchr(keymap
[0], c
);
102 f
= (s
- (keymap
[0])) + octave
* 12 + 1;
104 s
= strchr(keymap
[1], c
);
106 f
= (s
- (keymap
[1])) + octave
* 12 + 12 + 1;
110 if(f
> 12 * 9 + 1) return -1;
114 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
115 \\\
< void initsonglines() > .|
117 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
118 void initsonglines(void){
119 for(int i
=0; i
< songlen
; i
++){
120 memmove(&tune
->sng
[i
+ 0], &tune
->sng
[i
+ 1], sizeof(struct songline
) * (songlen
- i
- 1));
122 tune
->sng
[0].track
[i
] = 0x00;
123 tune
->sng
[0].transp
[i
] = 0x00;
129 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
130 \\\
< void inittracks() > .\
131 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
132 void inittracks(void){
133 for(int i
=0; i
< 256; i
++){
134 for(int j
=0; j
< TRACKLEN
; j
++){
135 tune
->trk
[i
].line
[j
].note
= 0x00;
136 tune
->trk
[i
].line
[j
].instr
= 0x00;
137 for(int k
=0; k
< 2; k
++){
138 tune
->trk
[i
].line
[j
].cmd
[k
] = 0x0000;
139 tune
->trk
[i
].line
[j
].param
[k
] = 0x0000;
145 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
146 \\\
< void initinstrs() > .\
147 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
148 void initinstrs(void){
149 for(int i
=1; i
< 256; i
++){
150 instrument
[i
].length
= 1;
151 instrument
[i
].line
[0].cmd
= '0';
152 instrument
[i
].line
[0].param
= 0;
156 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
157 \\\
< void readsong(int,int,u8
) > .\
158 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
159 void readsong(int pos
, int ch
, u8
*dest
){
160 dest
[0] = tune
->sng
[pos
].track
[ch
];
161 dest
[1] = tune
->sng
[pos
].transp
[ch
];
165 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
166 \\\
< void readinstr(int,int,u8
) > .\
167 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
168 void readinstr(int num
, int pos
, u8
*il
){
169 if(pos
>= instrument
[num
].length
){
173 il
[0] = instrument
[num
].line
[pos
].cmd
;
174 il
[1] = instrument
[num
].line
[pos
].param
;
178 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
179 \\\
< void exitgui() > .|
180 /// Exits the gui. .\
181 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
186 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
187 \\\
< void initgui() > .|
188 /// Initializes the gui. .\
189 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
193 //if(setlocale(LC_CTYPE,"en_US.utf8") != NULL){
194 // setdisplay("UTF-8 enabled!");
197 // don't send newline on Enter key, and don't echo chars to the screen.
201 // make sure behaviour for special keys like ^H isn't overridden
202 keypad(stdscr
, FALSE
);
204 nodelay(stdscr
, TRUE
);
211 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
212 \\\
< void handleinput() > .|
213 /// Main input loop. .\
214 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
215 void handleinput(void){
218 //if(currmode == PM_NORMAL){
219 if((c
= getch()) != ERR
){
225 cmdrepeatnum
= _char2int(c
);
227 cmdrepeatnum
= (cmdrepeatnum
*10) + _char2int(c
);
235 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
236 \\\
< char nextchar() > .|
237 /// Wait for the next keyboard char and return it. .\
238 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
250 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
251 \\\
< void setdisplay(char*) > .|
252 /// Sets a message to be popped up for a while. .\
253 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
254 void setdisplay(char *str
){
259 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
260 \\\
< void drawgui() > .|
261 /// Draw all text and graphix to the screen. .\
262 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
266 int songcols
[] = {0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21, 22};
267 int trackcols
[] = {0, 2, 4, 5, 7, 8, 9, 11, 12, 13};
268 int instrcols
[] = {0, 2, 3};
272 attrset(A_UNDERLINE
);
273 mvaddstr(0, 0, "PINEAPPLEtRACKER");
277 mvaddch(0, 31, ACS_ULCORNER
);
278 snprintf(buf
, sizeof(buf
), "%02x{}", currtrack
);
279 mvaddstr(0, 32, buf
);
280 drawtracked(29, 1, lines
- 2);
282 // display instrument num
283 mvaddch(0, 51, ACS_ULCORNER
);
284 snprintf(buf
, sizeof(buf
), "%02x[]", currinstr
);
285 mvaddstr(0, 52, buf
);
286 drawinstred(49, 1, lines
- 2);
288 mvaddstr(1, 0, "Song");
289 drawsonged(0, 1, lines
- 2);
291 // just a wild guess here..
292 tempo
= callbacktime
* (-1) + 300;
294 mvaddch(0, 17, ACS_DEGREE
);
295 snprintf(buf
, sizeof(buf
), "%d()", tempo
);
296 mvaddstr(0, 18, buf
);
299 mvaddch(0, 24, ACS_PI
);
300 snprintf(buf
, sizeof(buf
), "%d<>", octave
);
301 mvaddstr(0, 25, buf
);
303 // display step amount
304 mvaddstr(0, 60, "step -=");
305 snprintf(buf
, sizeof(buf
), "%0x", step
);
306 mvaddstr(0, 68, buf
);
309 mvaddstr(2, 60, "comment:");
310 snprintf(buf
, sizeof(buf
), "%s", comment
);
311 mvaddstr(3, 60, buf
);
313 if(currmode
== PM_NORMAL
){
314 mvaddstr(getmaxy(stdscr
)-1, 0, filename
);
315 if(!saved
&& currmode
!= PM_INSERT
){
326 if(currmode
== PM_INSERT
){
329 move(getmaxy(stdscr
)-1,0);
331 mvaddstr(getmaxy(stdscr
)-1, 0, "-- INSERT --");
332 }else if(currmode
== PM_VISUAL
){
335 move(getmaxy(stdscr
)-1,0);
337 mvaddstr(getmaxy(stdscr
)-1, 0, "-- VISUAL --");
338 }else if(currmode
== PM_VISUALLINE
){
341 move(getmaxy(stdscr
)-1,0);
343 mvaddstr(getmaxy(stdscr
)-1, 0, "-- VISUAL LINE --");
344 }else if(currmode
== PM_JAMMER
){
347 move(getmaxy(stdscr
)-1,0);
349 mvaddstr(getmaxy(stdscr
)-1, 0, "-- JAMMER --");
350 }else if(currmode
== PM_CMDLINE
){
353 move(getmaxy(stdscr
)-1,0);
355 mvaddstr(getmaxy(stdscr
) - 1, 0, cmdstr
);
356 }else if(infinitemsg
!= NULL
){
357 move(getmaxy(stdscr
)-1,0);
359 mvaddstr(getmaxy(stdscr
) - 1, 0, infinitemsg
);
364 move(1 + songy
- songoffs
, 0 + 4 + songcols
[songx
]);
367 move(1 + tracky
- trackoffs
, 29 + 4 + trackcols
[trackx
]);
370 move(1 + instry
- instroffs
, 49 + 4 + instrcols
[instrx
]);
381 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
382 \\\
< void *spin_input(void *) > .|
383 /// Pass this function to a thread to get the next key without blocking the .\
385 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
386 /*void *spin_input(void *tid){
393 void *spin_gui(void *tid){
400 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
401 \\\
< void eventloop() > .|
402 /// Main event loop .\
403 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
404 void eventloop(void){
414 //--------------------------------------------------------------------------\\
415 // this is when i tried to make separate threads for the screen and the
417 //--------------------------------------------------------------------------//
418 //TODO: figure out a method where we don't have to use usleep()... the
419 // screen also jitters sometimes
420 /*void eventloop(void){
422 pthread_t inputthread;
426 // make it detached ... we won't need to join it
427 pthread_attr_init(&attr);
428 pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
430 rc = pthread_create(&inputthread,&attr,spin_input,(void *)0);
432 setdisplay("Uh oh!!! thread please");
434 rc = pthread_create(&guithread,&attr,spin_gui,(void *)0);
437 // don't treat the escape key like a meta key
446 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
447 \\\ Internal functions
.\
448 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
450 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
451 \\\
< void _display() > .|
452 /// Display dispmesg in the center of the screen. .\
453 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
455 int cx
= (getmaxx(stdscr
)/2)-(strlen(dispmesg
)/2)-1;
456 int cy
= getmaxy(stdscr
)/2;
458 mvaddch(cy
-1, cx
, ACS_ULCORNER
);
459 for(int i
=cx
+1; i
<cx
+strlen(dispmesg
)+1; i
++)
460 mvaddch(cy
-1, i
, ACS_HLINE
);
461 mvaddch(cy
-1, cx
+strlen(dispmesg
)+1, ACS_URCORNER
);
463 mvaddch(cy
, cx
, ACS_VLINE
);
464 mvaddstr(cy
, cx
+1, dispmesg
);
465 mvaddch(cy
, cx
+strlen(dispmesg
)+1, ACS_VLINE
);
467 mvaddch(cy
+1, cx
, ACS_LLCORNER
);
468 for(int i
=cx
+1; i
<cx
+strlen(dispmesg
)+1; i
++)
469 mvaddch(cy
+1, i
, ACS_HLINE
);
470 mvaddch(cy
+1, cx
+strlen(dispmesg
)+1, ACS_LRCORNER
);
473 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
474 \\\
< void drawsonged(int,int,int) > .|
475 /// Draws the song editor. .\
476 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
477 void drawsonged(int x
, int y
, int height
){
482 if(songy
< songoffs
) songoffs
= songy
;
483 if(songy
>= songoffs
+ height
) songoffs
= songy
- height
+ 1;
485 for(i
= 0; i
< tune
->songlen
; i
++){
486 if(i
>= songoffs
&& i
- songoffs
< height
){
487 move(y
+ i
- songoffs
, x
+ 0);
488 if(i
== songy
) attrset(A_BOLD
);
490 snprintf(buf
, sizeof(buf
), "%02x", i
);
492 if(i
== 0){ addch(ACS_ULCORNER
); }
493 else if(i
== tune
->songlen
-1){ addch(ACS_LLCORNER
); }
494 else if(i
%4 == 0){ addch(ACS_LTEE
); }
495 else if(i
< tune
->songlen
-1){ addch(ACS_VLINE
); }
498 // should this line be highlighted?
499 //if( (match = list_contains(highlightlines, findu8, &i)) ){
500 if( currtab
== 0 && currmode
== PM_VISUALLINE
&&
501 ((i
<= highlight_firstline
&& i
>= highlight_lastline
)
502 || (i
>= highlight_firstline
&& i
<= highlight_lastline
)) ){
507 for(j
= 0; j
< 4; j
++){
508 snprintf(buf
, sizeof(buf
), "%02x:%02x", tune
->sng
[i
].track
[j
], tune
->sng
[i
].transp
[j
]);
510 if(j
!= 3) addch(' ');
512 if(playsong
&& tune
->songpos
== (i
+ 1)){
521 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
522 \\\
< void drawtracked(int,int,int) > .|
523 /// Draws the track editor. .\
524 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
525 void drawtracked(int x
, int y
, int height
){
529 if(tracky
< trackoffs
) trackoffs
= tracky
;
530 if(tracky
>= trackoffs
+ height
) trackoffs
= tracky
- height
+ 1;
532 for(i
= 0; i
< tune
->tracklen
; i
++){
533 if(i
>= trackoffs
&& i
- trackoffs
< height
){
534 move(y
+ i
- trackoffs
, x
+ 0);
535 if(i
== tracky
) attrset(A_BOLD
);
537 snprintf(buf
, sizeof(buf
), "%02x", i
);
540 if(i
== 0){ addch(ACS_LLCORNER
); }
541 else if(i
== 1){ addch(ACS_ULCORNER
); }
542 else if(i
== tune
->tracklen
-1){ addch(ACS_LLCORNER
); }
543 else if(i
%4 == 0){ addch(ACS_LTEE
); }
544 else if(i
< tune
->tracklen
-1){ addch(ACS_VLINE
); }
547 // should this line be highlighted?
548 //if( (match = list_contains(highlightlines, findu8, &i)) ){
549 if(currtab
== 1 && currmode
== PM_VISUALLINE
550 && ((i
<= highlight_firstline
&& i
>= highlight_lastline
)
551 || (i
>= highlight_firstline
&& i
<= highlight_lastline
)) ){
555 if (currtab
== 1 && currmode
== PM_VISUAL
)
558 if(tune
->trk
[currtrack
].line
[i
].note
){
559 snprintf(buf
, sizeof(buf
), "%s%d",
560 notenames
[(tune
->trk
[currtrack
].line
[i
].note
- 1) % 12],
561 (tune
->trk
[currtrack
].line
[i
].note
- 1) / 12);
563 snprintf(buf
, sizeof(buf
), "---");
566 snprintf(buf
, sizeof(buf
), " %02x", tune
->trk
[currtrack
].line
[i
].instr
);
568 for(j
= 0; j
< 2; j
++){
569 if(tune
->trk
[currtrack
].line
[i
].cmd
[j
]){
570 //this is pretty dumb just checking the type, we can probably
571 //do something better like make cmd more generic somehow...
572 if(tune
->type
== LFT
) {
573 snprintf(buf
, sizeof(buf
), " %c%02x",
574 tune
->trk
[currtrack
].line
[i
].cmd
[j
],
575 tune
->trk
[currtrack
].line
[i
].param
[j
]);
576 }else if(tune
->type
== AHX
) {
577 snprintf(buf
, sizeof(buf
), " %02x%02x",
578 tune
->trk
[currtrack
].line
[i
].cmd
[j
],
579 tune
->trk
[currtrack
].line
[i
].param
[j
]);
582 snprintf(buf
, sizeof(buf
), " ...");
586 if(playtrack
&& ((i
+ 1) % tune
->tracklen
) == trackpos
){
595 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
596 \\\
< void drawinstred(int,int,int) > .|
597 /// Draws the instrument editor. .\
598 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
599 void drawinstred(int x
, int y
, int height
){
603 if(instry
>= instrument
[currinstr
].length
) instry
= instrument
[currinstr
].length
- 1;
605 if(instry
< instroffs
) instroffs
= instry
;
606 if(instry
>= instroffs
+ height
) instroffs
= instry
- height
+ 1;
608 for(i
= 0; i
< instrument
[currinstr
].length
; i
++){
609 if(i
>= instroffs
&& i
- instroffs
< height
){
610 move(y
+ i
- instroffs
, x
+ 0);
611 if(i
== instry
) attrset(A_BOLD
);
613 snprintf(buf
, sizeof(buf
), "%02x", i
);
616 if(i
== 0){ addch(ACS_LLCORNER
); }
617 else if(i
== 1){ addch(ACS_ULCORNER
); }
618 else if(i
== instrument
[currinstr
].length
-1){ addch(ACS_LLCORNER
); }
619 else if(i
< instrument
[currinstr
].length
-1){ addch(ACS_VLINE
); }
622 // should this line be highlighted?
623 //if( (match = list_contains(highlightlines, findu8, &i)) ){
624 if( currtab
== 2 && currmode
== PM_VISUALLINE
&&
625 ((i
<= highlight_firstline
&& i
>= highlight_lastline
)
626 || (i
>= highlight_firstline
&& i
<= highlight_lastline
)) ){
630 snprintf(buf
, sizeof(buf
), "%c ", instrument
[currinstr
].line
[i
].cmd
);
632 if(instrument
[currinstr
].line
[i
].cmd
== '+' || instrument
[currinstr
].line
[i
].cmd
== '='){
633 if(instrument
[currinstr
].line
[i
].param
){
634 snprintf(buf
, sizeof(buf
), "%s%d",
635 notenames
[(instrument
[currinstr
].line
[i
].param
- 1) % 12],
636 (instrument
[currinstr
].line
[i
].param
- 1) / 12);
638 snprintf(buf
, sizeof(buf
), "---");
641 snprintf(buf
, sizeof(buf
), "%02x", instrument
[currinstr
].line
[i
].param
);