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
38 #define CONFIG_FILENAME ".epichordrc"
41 extern std::vector
<track
*> tracks
;
47 char* config_filename
;
54 char* homepath
= getenv("HOME");
55 asprintf(&config_filename
,"%s/"CONFIG_FILENAME
,homepath
);
58 f
.open(config_filename
,fstream::in
);
60 printf("unable to open config file for reading\n");
61 config
.beats_per_measure
= 4;
62 config
.measures_per_phrase
= 4;
63 config
.measures_until_record
= 1;
64 config
.alwayscopy
= 0;
65 config
.autotrackname
= 0;
67 config
.playinsert
= 1;
68 config
.recordonchan
= 0;
71 config
.recordmode
= 0;
74 load_default_keymap();
79 config
.beats_per_measure
= 4;
80 config
.measures_per_phrase
= 4;
87 if(word
== "leadin"){f
>>config
.measures_until_record
;}
88 else if(word
== "alwayscopy"){f
>>config
.alwayscopy
;}
89 else if(word
== "autotrackname"){f
>>config
.autotrackname
;}
90 else if(word
== "passthru"){f
>>config
.passthru
;}
91 else if(word
== "playinsert"){f
>>config
.playinsert
;}
92 else if(word
== "recordonchan"){f
>>config
.recordonchan
;}
93 else if(word
== "playmove"){f
>>config
.playmove
;}
94 else if(word
== "follow"){f
>>config
.follow
;}
95 else if(word
== "recordmode"){f
>>config
.recordmode
;}
96 else if(word
== "robmode"){f
>>config
.robmode
;}
97 else if(word
== "keymap"){load_keymap(f
);}
108 f
.open(config_filename
,fstream::out
);
110 printf("unable to open config file %s for saving\n",config_filename
);
114 f
<< "leadin " << config
.measures_until_record
<< endl
;
115 f
<< "alwayscopy " << config
.alwayscopy
<< endl
;
116 f
<< "autotrackname " << config
.autotrackname
<< endl
;
117 f
<< "passthru " << config
.passthru
<< endl
;
118 f
<< "playinsert " << config
.playinsert
<< endl
;
119 f
<< "recordonchan " << config
.recordonchan
<< endl
;
120 f
<< "playmove " << config
.playmove
<< endl
;
121 f
<< "follow " << config
.follow
<< endl
;
122 //f << "quantizedur " << config.quantizedur << endl;
123 f
<< "recordmode " << config
.recordmode
<< endl
;
124 f
<< "robmode " << config
.robmode
<< endl
;
130 void update_config_gui(){
131 ui
->beats_per_measure
->value(config
.beats_per_measure
);
132 ui
->measures_per_phrase
->value(config
.measures_per_phrase
);
133 //ui->bpm_wheel.value(config.bpm);
134 //ui->bpm_output.value(config.bpm);
135 ui
->measures_until_record
->value(config
.measures_until_record
);
137 ui
->check_alwayscopy
->state(config
.alwayscopy
);
138 ui
->check_autotrackname
->state(config
.autotrackname
);
139 ui
->check_passthru
->state(config
.passthru
);
140 ui
->check_playinsert
->state(config
.playinsert
);
141 ui
->check_recordonchan
->state(config
.recordonchan
);
142 ui
->check_playmove
->state(config
.playmove
);
143 ui
->check_follow
->state(config
.follow
);
145 ui
->config_window
->redraw();
149 void playing_timeout_cb(void* v
){
150 //if(!is_backend_playing()){
154 int pos
= get_play_position();
156 ui
->arranger
->update(pos
);
157 ui
->piano_roll
->update(pos
);
159 ui
->song_timeline
->update(pos
);
160 ui
->pattern_timeline
->update(pos
);
161 ui
->metronome
->update(pos
);
163 //check for midi input
170 track
* t
= tracks
[get_rec_track()];
177 while(recv_midi(&chan
,&tick
,&type
,&val1
,&val2
)){
179 if(config
.recordonchan
){
180 for(int i
=0; i
<tracks
.size(); i
++){
181 if(tracks
[i
]->chan
== chan
){
189 snprintf(report
,256,"%02x %02x %02x : note off - ch %d note %d vel %d\n",type
|chan
,val1
,val2
,chan
,val1
,val2
);
192 if(!is_backend_recording())
195 s
= tfind
<seqpat
>(t
->head
,tick
);
196 if(s
->tick
+s
->dur
< tick
){
197 //printf("rec head outside block\n");
201 c
=new CreateNoteOff(p
,val1
,val2
,tick
-s
->tick
);
204 if(ui
->piano_roll
->visible()){
205 ui
->piano_roll
->redraw();
206 ui
->event_edit
->redraw();
207 if(ui
->event_edit
->cur_seqpat
== s
){ui
->event_edit
->has
[1]=1;}
208 ui
->event_menu
->redraw();
210 if(ui
->arranger
->visible())
211 ui
->arranger
->redraw();
214 snprintf(report
,256,"%02x %02x %02x : note on - ch %d note %d vel %d\n",type
|chan
,val1
,val2
,chan
,val1
,val2
);
217 if(!is_backend_recording())
220 s
= tfind
<seqpat
>(t
->head
,tick
);
221 if(s
->tick
+s
->dur
< tick
){
222 //printf("rec head outside block\n");
226 c
=new CreateNoteOn(p
,val1
,val2
,tick
-s
->tick
,16);
229 if(ui
->piano_roll
->visible()){
230 ui
->piano_roll
->redraw();
231 ui
->event_edit
->redraw();
232 if(ui
->event_edit
->cur_seqpat
== s
){ui
->event_edit
->has
[0]=1;}
233 ui
->event_menu
->redraw();
235 if(ui
->arranger
->visible())
236 ui
->arranger
->redraw();
238 case 0xa0://aftertouch
239 case 0xb0://controller
240 case 0xc0://program change
241 case 0xd0://channel pressure
242 case 0xe0://pitch wheel
244 s
= tfind
<seqpat
>(t
->head
,tick
);
245 if(s
->tick
+s
->dur
< tick
){
246 //scope_print("record head outside block\n");
252 snprintf(report
,256,"%02x %02x %02x : aftertouch - ch %d note %d %d\n",type
|chan
,val1
,val2
,chan
,val1
,val2
);
253 if(ui
->event_edit
->cur_seqpat
== s
){ui
->event_edit
->has
[2]=1;}
256 snprintf(report
,256,"%02x %02x %02x : controller change - ch %d cntr %d val %d\n",type
|chan
,val1
,val2
,chan
,val1
,val2
);
257 if(ui
->event_edit
->cur_seqpat
== s
){
258 ui
->event_edit
->has
[val1
+6]=1;
262 snprintf(report
,256,"%02x %02x : program change - ch %d pgrm %d \n",type
|chan
,val1
,chan
,val1
);
263 if(ui
->event_edit
->cur_seqpat
== s
){ui
->event_edit
->has
[3]=1;}
266 snprintf(report
,256,"%02x %02x : channel pressure - ch %d val %d \n",type
|chan
,val1
,chan
,val1
);
267 if(ui
->event_edit
->cur_seqpat
== s
){ui
->event_edit
->has
[4]=1;}
270 snprintf(report
,256,"%02x %02x %02x : pitch wheel - ch %d val %d \n",type
|chan
,val1
,val2
,chan
,(val2
<<7)|val1
);
271 if(ui
->event_edit
->cur_seqpat
== s
){ui
->event_edit
->has
[5]=1;}
276 if(!is_backend_recording())
281 c
=new CreateEvent(p
,type
,tick
,val1
,val2
);
284 if(ui
->piano_roll
->visible()){
285 ui
->piano_roll
->redraw();
286 ui
->event_edit
->redraw();
287 ui
->event_menu
->redraw();
289 if(ui
->arranger
->visible())
290 ui
->arranger
->redraw();
294 case 1://undefined (reserved) system common message
295 snprintf(report
,256,"%02x : undefined (reserved) system common message\n",type
|chan
);
297 case 2://song position pointer
298 snprintf(report
,256,"%02x %02x %02x : song position - %d \n",type
|chan
,val1
,val2
,(val2
<<7)|val1
);
301 snprintf(report
,256,"%02x %02x : song select - %d \n",type
|chan
,val1
,val1
);
303 case 4://undefined (reserved) system common message
304 case 5://undefined (reserved) system common message
305 snprintf(report
,256,"%02x : undefined (reserved) system common message\n",type
|chan
);
307 case 6://tune request
308 snprintf(report
,256,"%02x : tune request\n",type
|chan
);
310 case 7://end of exclusive
311 snprintf(report
,256,"%02x : end of exclusive\n",type
|chan
);
313 case 8://timing clock
314 snprintf(report
,256,"%02x : timing clock\n",type
|chan
);
316 case 9://undefined (reserved) system common message
317 snprintf(report
,256,"%02x : undefined (reserved) system common message\n",type
|chan
);
320 snprintf(report
,256,"%02x : start\n",type
|chan
);
323 snprintf(report
,256,"%02x : continue\n",type
|chan
);
326 snprintf(report
,256,"%02x : stop\n",type
|chan
);
329 snprintf(report
,256,"%02x : undefined (reserved) system common message\n",type
|chan
);
331 case 14://active sensing
332 snprintf(report
,256,"%02x : active sensing\n",type
|chan
);
335 snprintf(report
,256,"%02x : reset\n",type
|chan
);
339 snprintf(report
,256,"%02x %02x : system exclusive - id %d ; data follows\n",type
|chan
,val1
,val1
);
341 scope_print((char*)getsysexbuf());
342 scope_print("\nf7 : end of sysex\n");
352 //handle session events (LASH)
354 char* session_string
;
355 char* filename_string
;
356 ret
=backend_session_process();
357 while(ret
!= SESSION_NOMORE
){
358 session_string
=get_session_string();
359 filename_string
= (char*)malloc(strlen(session_string
)+16);
360 strcpy(filename_string
,session_string
);
361 strcat(filename_string
,"/song.epi");
363 case SESSION_SAVE
: save(filename_string
); break;
364 case SESSION_LOAD
: load(filename_string
); break;
365 case SESSION_QUIT
: ui
->main_window
->hide(); break;
366 case SESSION_UNHANDLED
: break;
368 free(session_string
);
369 ret
=backend_session_process();
373 if(is_backend_playing()){
374 fltk::repeat_timeout(0.005, playing_timeout_cb
, NULL
);
377 fltk::repeat_timeout(0.1, playing_timeout_cb
, NULL
);
381 void start_monitor(){
382 fltk::add_timeout(0.1, playing_timeout_cb
, NULL
);
386 if(!is_backend_playing()){
388 ui
->play_button
->label("@||");
389 //fltk::add_timeout(0.01, playing_timeout_cb, NULL);
394 ui
->play_button
->label("@>");
400 //stops playback and sets the play position to zero
405 ui
->song_timeline
->update(0);
406 ui
->pattern_timeline
->update(0);
408 ui
->song_timeline
->redraw();
409 ui
->pattern_timeline
->redraw();
411 //send program change on all channels
413 //for(int i = 0; i<tracks.size(); i++){
414 // program_change(i, tracks[i]->program);
417 ui
->play_button
->label("@>");
418 ui
->play_button
->redraw();
420 ui
->metronome
->update(0);
425 void set_quant(int q
){
428 ui
->qbutton4
->state(0);
429 ui
->qbutton8
->state(0);
430 ui
->qbutton16
->state(0);
431 ui
->qbutton32
->state(0);
432 ui
->qbutton64
->state(0);
433 ui
->qbutton128
->state(0);
434 ui
->qbutton0
->state(1);
435 ui
->piano_roll
->set_qtick(1);
438 ui
->qbutton4
->state(1);
439 ui
->qbutton8
->state(0);
440 ui
->qbutton16
->state(0);
441 ui
->qbutton32
->state(0);
442 ui
->qbutton64
->state(0);
443 ui
->qbutton128
->state(0);
444 ui
->qbutton0
->state(0);
445 ui
->piano_roll
->set_qtick(128);
448 ui
->qbutton4
->state(0);
449 ui
->qbutton8
->state(1);
450 ui
->qbutton16
->state(0);
451 ui
->qbutton32
->state(0);
452 ui
->qbutton64
->state(0);
453 ui
->qbutton128
->state(0);
454 ui
->qbutton0
->state(0);
455 ui
->piano_roll
->set_qtick(64);
458 ui
->qbutton4
->state(0);
459 ui
->qbutton8
->state(0);
460 ui
->qbutton16
->state(1);
461 ui
->qbutton32
->state(0);
462 ui
->qbutton64
->state(0);
463 ui
->qbutton128
->state(0);
464 ui
->qbutton0
->state(0);
465 ui
->piano_roll
->set_qtick(32);
468 ui
->qbutton4
->state(0);
469 ui
->qbutton8
->state(0);
470 ui
->qbutton16
->state(0);
471 ui
->qbutton32
->state(1);
472 ui
->qbutton64
->state(0);
473 ui
->qbutton128
->state(0);
474 ui
->qbutton0
->state(0);
475 ui
->piano_roll
->set_qtick(16);
478 ui
->qbutton4
->state(0);
479 ui
->qbutton8
->state(0);
480 ui
->qbutton16
->state(0);
481 ui
->qbutton32
->state(0);
482 ui
->qbutton64
->state(1);
483 ui
->qbutton128
->state(0);
484 ui
->qbutton0
->state(0);
485 ui
->piano_roll
->set_qtick(8);
488 ui
->qbutton4
->state(0);
489 ui
->qbutton8
->state(0);
490 ui
->qbutton16
->state(0);
491 ui
->qbutton32
->state(0);
492 ui
->qbutton64
->state(0);
493 ui
->qbutton128
->state(1);
494 ui
->qbutton0
->state(0);
495 ui
->piano_roll
->set_qtick(4);
501 void set_beats_per_measure(int n
){
502 config
.beats_per_measure
= n
;
503 ui
->metronome
->set_N(n
);
504 ui
->piano_roll
->redraw();
505 ui
->arranger
->redraw();
506 ui
->arranger
->q_tick
= n
*TICKS_PER_BEAT
;
507 ui
->song_timeline
->redraw();
508 ui
->pattern_timeline
->redraw();
511 void set_measures_per_phrase(int n
){
512 config
.measures_per_phrase
= n
;
513 ui
->piano_roll
->redraw();
514 ui
->arranger
->redraw();
515 ui
->song_timeline
->redraw();
516 ui
->pattern_timeline
->redraw();
519 void set_measures_until_record(int n
){
520 config
.measures_until_record
= n
;
523 void set_alwayscopy(int v
){
524 config
.alwayscopy
= v
;
527 void set_autotrackname(int v
){
528 config
.autotrackname
= v
;
531 void set_passthru(int v
){
533 backend_set_passthru(v
);
536 void set_playinsert(int v
){
537 config
.playinsert
= v
;
540 void set_recordonchan(int v
){
541 config
.recordonchan
= v
;
544 void set_playmove(int v
){
548 void set_follow(int v
){
552 void set_recordmode(int n
){
553 config
.recordmode
= n
;
556 void set_robmode(int n
){
561 void scope_print(char* text
){
562 ui
->scope
->append(text
);
563 int N
= ui
->scope
->buffer()->length();
564 ui
->scope
->scroll(N
,0);
569 void show_song_edit(){
570 ui
->pattern_edit
->hide();
571 ui
->pattern_buttons
->hide();
572 ui
->song_edit
->activate();
573 ui
->song_edit
->show();
574 ui
->song_edit
->take_focus();
575 ui
->song_buttons
->show();
578 void show_pattern_edit(){
579 ui
->song_edit
->hide();
580 ui
->song_edit
->deactivate();
581 ui
->song_buttons
->hide();
582 ui
->pattern_edit
->take_focus();
583 ui
->pattern_edit
->show();
584 ui
->pattern_buttons
->show();