Unhardcoded ticks per beat. Fixed triplet bugs.
[epichord.git] / src / uihelper.cpp
blob7c11a47e9c3c7562c90c4495b2e6c8bb27a1869d
1 /*
2 Epichord - a midi sequencer
3 Copyright (C) 2008 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
23 #include <stdlib.h>
24 #include <vector>
25 #include <fstream>
26 #include <string.h>
27 #include <math.h>
29 #include <limits>
31 #include <fltk/run.h>
33 #include "seq.h"
34 #include "ui.h"
35 #include "backend.h"
37 #include "uihelper.h"
40 #define CONFIG_FILENAME ".epichordrc"
42 extern UI* ui;
43 extern std::vector<track*> tracks;
45 struct conf config;
47 using namespace std;
49 char* config_filename;
53 void load_config(){
55 config.beats_per_measure = 4;
56 config.measures_per_phrase = 4;
57 config.measures_until_record = 1;
58 config.alwayscopy = 0;
59 config.autotrackname = 0;
60 config.passthru = 1;
61 config.playinsert = 1;
62 config.recordonchan = 0;
63 config.playmove = 1;
64 config.follow = 1;
65 config.recordmode = 0;
66 config.robmode = 0;
67 config.defaultvelocity = 96;
68 config.trackinit = 1;
70 //linux dependent
71 char* homepath = getenv("HOME");
72 asprintf(&config_filename,"%s/"CONFIG_FILENAME,homepath);
74 fstream f;
75 f.open(config_filename,fstream::in);
76 if(!f.is_open()){
77 printf("load_config: Unable to open config file for reading.\n");
79 load_default_keymap();
80 update_config_gui();
81 return;
84 config.beats_per_measure = 4;
85 config.measures_per_phrase = 4;
87 std::string word;
89 while(!f.eof()){
90 word = "";
91 f >> word;
92 if(word == "leadin"){f>>config.measures_until_record;}
93 else if(word == "alwayscopy"){f>>config.alwayscopy;}
94 else if(word == "autotrackname"){f>>config.autotrackname;}
95 else if(word == "passthru"){f>>config.passthru;}
96 else if(word == "playinsert"){f>>config.playinsert;}
97 else if(word == "recordonchan"){f>>config.recordonchan;}
98 else if(word == "playmove"){f>>config.playmove;}
99 else if(word == "follow"){f>>config.follow;}
100 else if(word == "recordmode"){f>>config.recordmode;}
101 else if(word == "robmode"){f>>config.robmode;}
102 else if(word == "keymap"){load_keymap(f);}
103 else if(word == "defaultvelocity"){f>>config.defaultvelocity;}
104 else if(word == "trackinit"){f>>config.trackinit;}
105 else{
106 f.ignore(std::numeric_limits<streamsize>::max(),'\n');
110 backend_set_trackinit(config.trackinit);
112 update_config_gui();
113 f.close();
116 void save_config(){
117 fstream f;
118 f.open(config_filename,fstream::out);
119 if(!f.is_open()){
120 printf("save_config: Unable to open config file %s for saving.\n", config_filename);
121 return;
124 f << "leadin " << config.measures_until_record << endl;
125 f << "alwayscopy " << config.alwayscopy << endl;
126 f << "autotrackname " << config.autotrackname << endl;
127 f << "passthru " << config.passthru << endl;
128 f << "playinsert " << config.playinsert << endl;
129 f << "recordonchan " << config.recordonchan << endl;
130 f << "playmove " << config.playmove << endl;
131 f << "follow " << config.follow << endl;
132 //f << "quantizedur " << config.quantizedur << endl;
133 f << "recordmode " << config.recordmode << endl;
134 f << "robmode " << config.robmode << endl;
135 f << "defaultvelocity " << config.defaultvelocity << endl;
136 f << "trackinit " << config.trackinit << endl;
137 f << endl;
138 save_keymap(f);
139 f.close();
142 void update_config_gui(){
143 ui->beats_per_measure->value(config.beats_per_measure);
144 ui->measures_per_phrase->value(config.measures_per_phrase);
145 ui->measures_until_record->value(config.measures_until_record);
147 ui->bpm_wheel->value(config.beats_per_minute);
148 ui->bpm_output->value(config.beats_per_minute);
150 ui->check_alwayscopy->state(config.alwayscopy);
151 ui->check_autotrackname->state(config.autotrackname);
152 ui->check_passthru->state(config.passthru);
153 ui->check_playinsert->state(config.playinsert);
154 ui->check_recordonchan->state(config.recordonchan);
155 ui->check_playmove->state(config.playmove);
156 ui->check_follow->state(config.follow);
158 ui->menu_recordmode->value(config.recordmode);
159 ui->menu_rob->value(config.robmode);
161 ui->default_velocity->value(config.defaultvelocity);
163 ui->check_trackinit->value(config.trackinit);
165 ui->config_window->redraw();
170 seqpat* rob_check(seqpat* s){
171 seqpat* prev = s->prev;
172 Command* c;
173 if(config.robmode == 0){
174 return NULL;
176 else if(config.robmode == 1 || prev == NULL){
177 int pos = get_play_position();
178 int M = config.measures_per_phrase;
179 if(M!=0){
180 M = M*config.beats_per_measure*TICKS_PER_BEAT;
182 else{
183 M = 4*config.beats_per_measure*TICKS_PER_BEAT;
185 int P1 = pos/M*M;
186 int P2 = P1 + M;
187 int T = P1;
188 int R = s->tick+s->dur;
189 if(R > P1){
190 T = R;
192 int W = P2 - T;
193 if(s->next){
194 int L = s->next->tick;
195 if(L < P2){
196 W = L - T;
199 c = new CreateSeqpatBlank(s->track,T,W);
200 set_undo(c);
201 undo_push(1);
202 return s->next;
204 else if(config.robmode == 2){
205 int pos = get_play_position();
206 int M = config.measures_per_phrase;
207 if(M!=0){
208 M = M*config.beats_per_measure*TICKS_PER_BEAT;
210 else{
211 M = 4*config.beats_per_measure*TICKS_PER_BEAT;
213 int P = pos/M*M + M;//tick at next phrase boundary
214 int W = P - s->tick;
215 if(s->next){
216 int W2 = s->next->tick - s->tick;
217 if(W2 < W){
218 W=W2;
221 c = new ResizeSeqpat(s,W);
222 set_undo(c);
223 undo_push(1);
224 return prev->next;
230 int last_pos=0;
231 void playing_timeout_cb(void* v){
232 int pos = get_play_position();
234 if(pos < last_pos){
235 reset_record_flags();
237 last_pos = pos;
239 if(config.follow){
240 ui->arranger->update(pos);
241 ui->piano_roll->update(pos);
243 ui->song_timeline->update(pos);
244 ui->pattern_timeline->update(pos);
245 ui->metronome->update(pos);
247 //check for midi input
248 int tick;
249 int chan;
250 int type;
251 int val1;
252 int val2;
254 track* t = tracks[get_rec_track()];
255 Command* c;
256 seqpat* s;
257 pattern* p;
259 char report[256];
261 while(recv_midi(&chan,&tick,&type,&val1,&val2)){
263 if(config.recordonchan){
264 for(int i=0; i<tracks.size(); i++){
265 if(tracks[i]->chan == chan){
266 t = tracks[i];
271 switch(type){
272 case 0x80://note off
273 snprintf(report,256,"%02x %02x %02x : note off - ch %d note %d vel %d\n",type|chan,val1,val2,chan,val1,val2);
274 scope_print(report);
276 if(!is_backend_recording())
277 break;
279 s = tfind<seqpat>(t->head,tick);
280 if(s->tick+s->dur < tick){
281 s = rob_check(s);
282 if(!s){continue;}
285 //if(s->record_flag==1 && config.recordmode>0){show_song_edit();}
286 s->record_check(config.recordmode);
287 p = s->p;
288 c=new CreateNoteOff(p,val1,val2,tick-s->tick);
289 set_undo(c);
290 undo_push(1);
291 if(ui->piano_roll->visible()){
292 ui->piano_roll->redraw();
293 ui->event_edit->redraw();
294 if(ui->event_edit->cur_seqpat == s){ui->event_edit->has[1]=1;}
295 ui->event_menu->redraw();
297 if(ui->arranger->visible())
298 ui->arranger->redraw();
299 break;
300 case 0x90://note on
301 snprintf(report,256,"%02x %02x %02x : note on - ch %d note %d vel %d\n",type|chan,val1,val2,chan,val1,val2);
302 scope_print(report);
304 if(!is_backend_recording())
305 break;
307 s = tfind<seqpat>(t->head,tick);
308 if(s->tick+s->dur < tick){
309 s = rob_check(s);
310 if(!s){continue;}
313 // if(s->record_flag==1 && config.recordmode>0){show_song_edit();}
314 s->record_check(config.recordmode);
315 p = s->p;
316 c=new CreateNoteOn(p,val1,val2,tick-s->tick,16);
317 set_undo(c);
318 undo_push(1);
319 if(ui->piano_roll->visible()){
320 ui->piano_roll->redraw();
321 ui->event_edit->redraw();
322 if(ui->event_edit->cur_seqpat == s){ui->event_edit->has[0]=1;}
323 ui->event_menu->redraw();
325 if(ui->arranger->visible())
326 ui->arranger->redraw();
327 break;
328 case 0xa0://aftertouch
329 case 0xb0://controller
330 case 0xc0://program change
331 case 0xd0://channel pressure
332 case 0xe0://pitch wheel
334 s = tfind<seqpat>(t->head,tick);
335 if(s->tick+s->dur < tick){
336 s = rob_check(s);
337 if(!s){continue;}
340 switch(type){
341 case 0xa0:
342 snprintf(report,256,"%02x %02x %02x : aftertouch - ch %d note %d %d\n",type|chan,val1,val2,chan,val1,val2);
343 if(ui->event_edit->cur_seqpat == s){ui->event_edit->has[2]=1;}
344 break;
345 case 0xb0:
346 snprintf(report,256,"%02x %02x %02x : controller change - ch %d cntr %d val %d\n",type|chan,val1,val2,chan,val1,val2);
347 if(ui->event_edit->cur_seqpat == s){
348 ui->event_edit->has[val1+6]=1;
350 break;
351 case 0xc0:
352 snprintf(report,256,"%02x %02x : program change - ch %d pgrm %d \n",type|chan,val1,chan,val1);
353 if(ui->event_edit->cur_seqpat == s){ui->event_edit->has[3]=1;}
354 break;
355 case 0xd0:
356 snprintf(report,256,"%02x %02x : channel pressure - ch %d val %d \n",type|chan,val1,chan,val1);
357 if(ui->event_edit->cur_seqpat == s){ui->event_edit->has[4]=1;}
358 break;
359 case 0xe0:
360 snprintf(report,256,"%02x %02x %02x : pitch wheel - ch %d val %d \n",type|chan,val1,val2,chan,(val2<<7)|val1);
361 if(ui->event_edit->cur_seqpat == s){ui->event_edit->has[5]=1;}
362 break;
364 scope_print(report);
366 if(!is_backend_recording())
367 break;
369 // if(s->record_flag==1 && config.recordmode>0){show_song_edit();}
370 s->record_check(config.recordmode);
371 p = s->p;
372 c=new CreateEvent(p,type,tick,val1,val2);
373 set_undo(c);
374 undo_push(1);
375 if(ui->piano_roll->visible()){
376 ui->piano_roll->redraw();
377 ui->event_edit->redraw();
378 ui->event_menu->redraw();
380 if(ui->arranger->visible())
381 ui->arranger->redraw();
382 break;
383 case 0xf0:
384 switch(chan){
385 case 1://undefined (reserved) system common message
386 snprintf(report,256,"%02x : undefined (reserved) system common message\n",type|chan);
387 break;
388 case 2://song position pointer
389 snprintf(report,256,"%02x %02x %02x : song position - %d \n",type|chan,val1,val2,(val2<<7)|val1);
390 break;
391 case 3://song select
392 snprintf(report,256,"%02x %02x : song select - %d \n",type|chan,val1,val1);
393 break;
394 case 4://undefined (reserved) system common message
395 case 5://undefined (reserved) system common message
396 snprintf(report,256,"%02x : undefined (reserved) system common message\n",type|chan);
397 break;
398 case 6://tune request
399 snprintf(report,256,"%02x : tune request\n",type|chan);
400 break;
401 case 7://end of exclusive
402 snprintf(report,256,"%02x : end of exclusive\n",type|chan);
403 break;
404 case 8://timing clock
405 snprintf(report,256,"%02x : timing clock\n",type|chan);
406 break;
407 case 9://undefined (reserved) system common message
408 snprintf(report,256,"%02x : undefined (reserved) system common message\n",type|chan);
409 break;
410 case 10://start
411 snprintf(report,256,"%02x : start\n",type|chan);
412 break;
413 case 11://continue
414 snprintf(report,256,"%02x : continue\n",type|chan);
415 break;
416 case 12://stop
417 snprintf(report,256,"%02x : stop\n",type|chan);
418 break;
419 case 13://undefined
420 snprintf(report,256,"%02x : undefined (reserved) system common message\n",type|chan);
421 break;
422 case 14://active sensing
423 snprintf(report,256,"%02x : active sensing\n",type|chan);
424 break;
425 case 15://reset
426 snprintf(report,256,"%02x : reset\n",type|chan);
427 break;
429 if(chan==0){
430 snprintf(report,256,"%02x %02x : system exclusive - id %d ; data follows\n",type|chan,val1,val1);
431 scope_print(report);
432 scope_print(getsysexbuf());
433 scope_print("\nf7 : end of sysex\n");
435 else{
436 scope_print(report);
443 //handle session events (LASH)
444 int ret;
445 char* session_string;
446 char* filename_string;
447 ret=backend_session_process();
448 while(ret != SESSION_NOMORE){
449 session_string=get_session_string();
450 filename_string = (char*)malloc(strlen(session_string)+16);
451 strcpy(filename_string,session_string);
452 strcat(filename_string,"/song.epi");
453 switch(ret){
454 case SESSION_SAVE: save(filename_string); break;
455 case SESSION_LOAD: load(filename_string); break;
456 case SESSION_QUIT: shutdown_gui(); break;
457 case SESSION_UNHANDLED: break;
459 free(session_string);
460 ret=backend_session_process();
464 if(is_backend_playing()){
465 fltk::repeat_timeout(0.005, playing_timeout_cb, NULL);
467 else{
468 fltk::repeat_timeout(0.1, playing_timeout_cb, NULL);
472 void start_monitor(){
473 fltk::add_timeout(0.1, playing_timeout_cb, NULL);
476 void press_play(){
477 if(!is_backend_playing()){
478 start_backend();
479 ui->play_button->label("@||");
480 //fltk::add_timeout(0.01, playing_timeout_cb, NULL);
482 else{
483 pause_backend();
484 all_notes_off();
485 ui->play_button->label("@>");
489 void press_stop(){
491 int left = get_loop_start();
492 if(get_play_position()==left || get_play_position()==0){
493 left=0;
496 pause_backend();
497 reset_backend(left);
498 all_notes_off();
500 ui->song_timeline->update(left);
501 ui->pattern_timeline->update(left);
503 ui->song_timeline->redraw();
504 ui->pattern_timeline->redraw();
506 ui->play_button->label("@>");
507 ui->play_button->redraw();
509 ui->metronome->update(left);
514 void set_quant(int q){
515 switch(q){
516 case 0:
517 ui->qbutton4->state(0);
518 ui->qbutton8->state(0);
519 ui->qbutton16->state(0);
520 ui->qbutton32->state(0);
521 ui->qbutton64->state(0);
522 ui->qbutton128->state(0);
523 ui->qbutton0->state(1);
524 ui->piano_roll->set_qtick(1);
525 break;
526 case 4:
527 ui->qbutton4->state(1);
528 ui->qbutton8->state(0);
529 ui->qbutton16->state(0);
530 ui->qbutton32->state(0);
531 ui->qbutton64->state(0);
532 ui->qbutton128->state(0);
533 ui->qbutton0->state(0);
534 ui->piano_roll->set_qtick(TICKS_PER_BEAT);
535 break;
536 case 8:
537 ui->qbutton4->state(0);
538 ui->qbutton8->state(1);
539 ui->qbutton16->state(0);
540 ui->qbutton32->state(0);
541 ui->qbutton64->state(0);
542 ui->qbutton128->state(0);
543 ui->qbutton0->state(0);
544 ui->piano_roll->set_qtick(TICKS_PER_BEAT/2);
545 break;
546 case 16:
547 ui->qbutton4->state(0);
548 ui->qbutton8->state(0);
549 ui->qbutton16->state(1);
550 ui->qbutton32->state(0);
551 ui->qbutton64->state(0);
552 ui->qbutton128->state(0);
553 ui->qbutton0->state(0);
554 ui->piano_roll->set_qtick(TICKS_PER_BEAT/4);
555 break;
556 case 32:
557 ui->qbutton4->state(0);
558 ui->qbutton8->state(0);
559 ui->qbutton16->state(0);
560 ui->qbutton32->state(1);
561 ui->qbutton64->state(0);
562 ui->qbutton128->state(0);
563 ui->qbutton0->state(0);
564 ui->piano_roll->set_qtick(TICKS_PER_BEAT/8);
565 break;
566 case 64:
567 ui->qbutton4->state(0);
568 ui->qbutton8->state(0);
569 ui->qbutton16->state(0);
570 ui->qbutton32->state(0);
571 ui->qbutton64->state(1);
572 ui->qbutton128->state(0);
573 ui->qbutton0->state(0);
574 ui->piano_roll->set_qtick(TICKS_PER_BEAT/16);
575 break;
576 case 128:
577 ui->qbutton4->state(0);
578 ui->qbutton8->state(0);
579 ui->qbutton16->state(0);
580 ui->qbutton32->state(0);
581 ui->qbutton64->state(0);
582 ui->qbutton128->state(1);
583 ui->qbutton0->state(0);
584 ui->piano_roll->set_qtick(TICKS_PER_BEAT/32);
585 break;
589 void set_songtool(int i){
590 switch(i){
591 case 0:
592 ui->edit_button->state(1);
593 ui->color_button->state(0);
594 ui->unclone_button->state(0);
595 ui->split_button->state(0);
596 ui->join_button->state(0);
597 ui->arranger->color_flag = 0;
598 ui->arranger->unclone_flag = 0;
599 ui->arranger->split_flag = 0;
600 ui->arranger->join_flag = 0;
601 break;
602 case 1:
603 ui->edit_button->state(0);
604 ui->color_button->state(1);
605 ui->unclone_button->state(0);
606 ui->split_button->state(0);
607 ui->join_button->state(0);
608 ui->arranger->color_flag = 1;
609 ui->arranger->unclone_flag = 0;
610 ui->arranger->split_flag = 0;
611 ui->arranger->join_flag = 0;
612 break;
613 case 2:
614 ui->edit_button->state(0);
615 ui->color_button->state(0);
616 ui->unclone_button->state(1);
617 ui->split_button->state(0);
618 ui->join_button->state(0);
619 ui->arranger->color_flag = 0;
620 ui->arranger->unclone_flag = 1;
621 ui->arranger->split_flag = 0;
622 ui->arranger->join_flag = 0;
623 break;
624 case 3:
625 ui->edit_button->state(0);
626 ui->color_button->state(0);
627 ui->unclone_button->state(0);
628 ui->split_button->state(1);
629 ui->join_button->state(0);
630 ui->arranger->color_flag = 0;
631 ui->arranger->unclone_flag = 0;
632 ui->arranger->split_flag = 1;
633 ui->arranger->join_flag = 0;
634 break;
635 case 4:
636 ui->edit_button->state(0);
637 ui->color_button->state(0);
638 ui->unclone_button->state(0);
639 ui->split_button->state(0);
640 ui->join_button->state(1);
641 ui->arranger->color_flag = 0;
642 ui->arranger->unclone_flag = 0;
643 ui->arranger->split_flag = 0;
644 ui->arranger->join_flag = 1;
645 break;
650 void set_trip(int v){
651 ui->piano_roll->set_trip(v);
656 void set_beats_per_measure(int n){
657 config.beats_per_measure = n;
658 ui->metronome->set_N(n);
659 ui->piano_roll->redraw();
660 ui->arranger->redraw();
661 ui->arranger->q_tick = n*TICKS_PER_BEAT;
662 ui->song_timeline->redraw();
663 ui->pattern_timeline->redraw();
666 void set_measures_per_phrase(int n){
667 config.measures_per_phrase = n;
668 ui->piano_roll->redraw();
669 ui->arranger->redraw();
670 ui->song_timeline->redraw();
671 ui->pattern_timeline->redraw();
674 void set_beats_per_minute(int n){
675 config.beats_per_minute = n;
676 set_bpm(n);
679 void set_measures_until_record(int n){
680 config.measures_until_record = n;
683 void set_alwayscopy(int v){
684 config.alwayscopy = v;
687 void set_autotrackname(int v){
688 config.autotrackname = v;
691 void set_passthru(int v){
692 config.passthru = v;
693 backend_set_passthru(v);
696 void set_playinsert(int v){
697 config.playinsert = v;
700 void set_recordonchan(int v){
701 config.recordonchan = v;
704 void set_playmove(int v){
705 config.playmove = v;
708 void set_follow(int v){
709 config.follow = v;
712 void set_recordmode(int n){
713 config.recordmode = n;
716 void set_robmode(int n){
717 config.robmode = n;
720 void set_defaultvelocity(int n){
721 config.defaultvelocity = n;
724 void set_trackinit(int n){
725 config.trackinit = n;
726 backend_set_trackinit(n);
730 int scopeon=0;
731 void turnonscope(){
732 scopeon=1;
735 void turnoffscope(){
736 scopeon=0;
737 fltk::TextBuffer* ptr = ui->scope->buffer();
738 ptr->remove(0,ptr->length());
739 // ui->redraw();
742 void scope_print(const char* text){
743 if(scopeon){
744 ui->scope->append(text);
745 int N = ui->scope->buffer()->length();
746 ui->scope->scroll(N,0);
752 void show_song_edit(){
753 ui->pattern_edit->hide();
754 ui->pattern_buttons->hide();
755 ui->song_edit->activate();
756 ui->song_edit->show();
757 ui->song_edit->take_focus();
758 ui->song_buttons->show();
761 void show_pattern_edit(){
762 ui->song_edit->hide();
763 ui->song_edit->deactivate();
764 ui->song_buttons->hide();
765 ui->pattern_edit->take_focus();
766 ui->pattern_edit->show();
767 ui->pattern_buttons->show();
771 static int tool = 0;
772 //switch between normal, note off, portamento, and aftertouch
773 void toggle_tool(){
774 switch(tool){
775 case 0:
776 tool=1;
777 ui->tool_button->copy_label("80");
778 ui->tool_button->state(1);
779 break;
780 case 1:
781 tool=2;
782 ui->tool_button->copy_label("A0");
783 break;
784 case 2:
785 tool=3;
786 ui->tool_button->copy_label("po");
787 break;
788 case 3:
789 tool=0;
790 ui->tool_button->copy_label("tool");
791 ui->tool_button->state(0);
792 break;
798 void reset_song(){
799 clear();
801 track* t;
802 for(int i=0; i<16; i++){
803 t = new track();
804 t->head->track = i;
805 t->chan = i;
806 add_track(t);
809 set_rec_track(0);
810 ui->track_info->set_rec(0);
811 ui->track_info->update();
812 ui->action_window->hide();
817 void add_track(track* t){
818 tracks.push_back(t);
819 ui->track_info->add_track();
822 void remove_track(int n){
827 void dump_pattern(){
828 pattern* p = ui->piano_roll->cur_seqpat->p;
829 mevent* e = p->events;
831 printf("dump of pattern %p\n",p);
832 printf("time type value1 value2\n");
833 int this_t = 0;
834 while(e){
835 int last_t = this_t;
836 this_t = e->tick;
837 if(this_t < last_t){printf("WARNING\n");}
838 switch(e->type){
839 case -1:
840 printf("%d DUMMY %d %d\n",e->tick,e->value1,e->value2);
841 break;
842 case MIDI_NOTE_OFF:
843 printf("%d NOTEOFF %d %d\n",e->tick,e->value1,e->value2);
844 break;
845 case MIDI_NOTE_ON:
846 printf("%d NOTEON %d %d\n",e->tick,e->value1,e->value2);
847 break;
848 case MIDI_AFTERTOUCH:
849 printf("%d AFTERTOUCH %d %d\n",e->tick,e->value1,e->value2);
850 break;
851 case MIDI_CONTROLLER_CHANGE:
852 printf("%d CC %d %d\n",e->tick,e->value1,e->value2);
853 break;
854 case MIDI_PROGRAM_CHANGE:
855 printf("%d PROGRAM %d %d\n",e->tick,e->value1,e->value2);
856 break;
857 case MIDI_CHANNEL_PRESSURE:
858 printf("%d CHANNELPRESSURE %d %d\n",e->tick,e->value1,e->value2);
859 break;
860 case MIDI_PITCH_WHEEL:
861 printf("%d PITCHWHEEL %d %d\n",e->tick,e->value1,e->value2);
862 break;
864 e=e->next;
866 printf("\n");
870 void init_gui(){
872 ui->arranger->layout();
873 ui->song_vscroll->slider_size(60);
874 ui->song_vscroll->value(0);
876 ui->pattern_timeline->edit_flag = 1;
877 ui->pattern_timeline->zoom = 15;
878 ui->pattern_vscroll->minimum(12*75);
879 ui->pattern_vscroll->maximum(0);
880 ui->pattern_vscroll->value(300);
881 ui->pattern_vscroll->slider_size(50);
882 ui->pattern_hscroll->value(0);
884 ui->track_info->relayout();
887 void shutdown_gui(){
888 ui->main_window->hide();
889 ui->config_window->hide();
890 ui->help_window->hide();
891 ui->action_window->hide();
892 ui->scope_window->hide();