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
30 #include <arpa/inet.h>
34 #include <fltk/file_chooser.h>
35 #include <fltk/filename.h>
51 extern std::vector
<track
*> tracks
;
54 extern struct conf config
;
58 std::string last_filename
;
59 char last_dir
[1024] = "";
62 void nextline(ifstream
& f
){
69 std::list
<pattern
*> collectpatterns(){
70 std::list
<pattern
*> patlist
;
72 for(int i
=0; i
<tracks
.size(); i
++){
73 seqpat
* s
= tracks
[i
]->head
->next
;
76 for(int j
=0; j
<s
->layers
->total
; j
++){
77 pattern
* p
= s
->layers
->array
[j
];
82 patlist
.push_back(s
->p
);
94 int findpatternindex(pattern
* p
, std::list
<pattern
*>& patlist
){
95 std::list
<pattern
*>::iterator i
= patlist
.begin();
97 while(i
!= patlist
.end()){
107 pattern
* findpatternbyindex(int index
, std::list
<pattern
*>& patlist
){
108 std::list
<pattern
*>::iterator i
= patlist
.begin();
110 while(i
!= patlist
.end()){
129 set_beats_per_measure(4);
130 set_measures_per_phrase(4);
133 set_beats_per_minute(120);
137 int total
= tracks
.size();
139 for(int i
=0; i
<total
; i
++){
140 t
= tracks
[tracks
.size()-1];
145 ui
->title_text
->text("");
146 ui
->author_text
->text("");
148 fltk::TextBuffer
* tb
= ui
->info_text
->buffer();
151 ui
->track_info
->clear_tracks();
156 ui
->main_window
->redraw();
160 void set_last_dir(const char* name
){
161 const char* theend
= fltk::filename_name(name
);
162 int n
= (int)(theend
- name
) / sizeof(char);
163 memcpy(last_dir
,name
,n
);
167 const char* get_last_dir(){
172 if(last_filename
!= ""){
173 return save(last_filename
.c_str());
176 return save(fltk::file_chooser("save file",NULL
,last_dir
));
182 int save(const char* filename
){
184 if(filename
== NULL
){
190 file
.open(filename
, fstream::out
);
193 printf("save: can't open file for saving.\n");
197 last_filename
= filename
;
198 set_last_dir(filename
);
200 //header to protect against accidentally opening wrong file
201 file
<< "J2ULJwCgwHA" << endl
;
202 file
<< "epichord" << endl
;
203 file
<< "fileversion " << FILE_VERSION
<< endl
;
204 file
<< "ticksperbeat " << TICKS_PER_BEAT
<< endl
<< endl
;
207 file
<< "title " << ui
->title_text
->size() << " "
208 << ui
->title_text
->text() << endl
;
209 file
<< "author " << ui
->author_text
->size() << " "
210 << ui
->author_text
->text() << endl
;
211 file
<< "info " << ui
->info_text
->size() << " "
212 << ui
->info_text
->text() << endl
;
214 file
<< "bpm " << ui
->bpm_wheel
->value() << endl
;
215 file
<< "beatspermeasure " << config
.beats_per_measure
<< endl
;
216 file
<< "measuresperphrase " << config
.measures_per_phrase
<< endl
;
218 file
<< "loopstart " << get_loop_start() << endl
;
219 file
<< "loopend " << get_loop_end() << endl
;
224 //collect all visible patterns
225 std::list
<pattern
*> patlist
= collectpatterns();
228 std::list
<pattern
*>::iterator p
= patlist
.begin();
231 while(p
!= patlist
.end()){
232 file
<< "pattern " << endl
;
233 file
<< (*p
)->h
<< " " << (*p
)->s
<< " " << (*p
)->v
<< endl
;
234 e
= (*p
)->events
->next
;
241 delta
= e
->tick
- last_tick
;
243 file
<< delta
<< " ";
244 file
<< e
->type
<< " ";
245 file
<< e
->value1
<< " ";
246 file
<< e
->value2
<< endl
;
247 //file << e->dur << endl;
252 file
<< -1 << endl
<< endl
;
257 for(int i
=0; i
<tracks
.size(); i
++){
258 file
<< endl
<< endl
<< "track " << endl
;
259 file
<< "port " << tracks
[i
]->port
<< endl
;
260 file
<< "chan " << tracks
[i
]->chan
<< endl
;
261 file
<< "prog " << tracks
[i
]->prog
<< endl
;
262 file
<< "bank " << tracks
[i
]->bank
<< endl
;
263 file
<< "mute " << tracks
[i
]->mute
<< endl
;
264 file
<< "solo " << tracks
[i
]->solo
<< endl
;
265 file
<< "vol " << tracks
[i
]->vol
<< endl
;
266 file
<< "pan " << tracks
[i
]->pan
<< endl
;
267 file
<< "name " << strlen(tracks
[i
]->name
) << " "
268 << tracks
[i
]->name
<< endl
;
269 file
<< "alive " << tracks
[i
]->alive
<< endl
;
270 s
= tracks
[i
]->head
->next
;
273 file
<< endl
<< endl
<< "seqpat " << endl
;
274 file
<< s
->tick
<< " " << s
->dur
<< endl
;
275 file
<< s
->scrollx
<< " " << s
->scrolly
<< endl
;
278 file
<< s
->layers
->total
<< " ";
279 for(int j
=0; j
<s
->layers
->total
; j
++){
281 int index
= findpatternindex(s
->layers
->array
[j
],patlist
);
283 printf("save: pattern not found, cannot save\n");
287 file
<< index
<< " ";
290 file
<< s
->layers
->index
;
294 int index
= findpatternindex(s
->p
,patlist
);
296 printf("save: pattern not found, cannot save\n");
320 int load(const char* filename
){
323 if(filename
== NULL
){
329 file
.open(filename
, fstream::in
);
332 printf("load: can't open file for loading.\n");
339 last_filename
= filename
;
340 set_last_dir(filename
);
342 //pattern* pend = patterns;
343 std::list
<pattern
*> patlist
;
348 if(str
!= "J2ULJwCgwHA"){
349 printf("load: this is definitely not a valid file (missing magic)\n");
354 if(str
!= "epichord"){
355 printf("load: this is definitely not a valid file (missing magic)\n");
360 if(str
!= "fileversion"){
361 printf("load: this is definitely not a valid file\n");
368 printf("load: file has wrong version %d (need %d).\n",M
,FILE_VERSION
);
371 if(str
!= "ticksperbeat"){
372 printf("load: file is broken. (missing ticks per beat)\n");
379 printf("load: file is broken. (bad ticks per beat %d)\n",file_tpb
);
396 ui
->title_text
->text(buf
);
398 else if(str
== "author"){
404 ui
->author_text
->text(buf
);
406 else if(str
== "info"){
409 fltk::TextBuffer
* tb
= ui
->info_text
->buffer();
415 else if(str
== "bpm"){
419 ui
->bpm_wheel
->value(bpm
);
420 ui
->bpm_output
->value(bpm
);
422 else if(str
== "beatspermeasure"){
425 set_beats_per_measure(N
);
427 else if(str
== "measuresperphrase"){
430 set_measures_per_phrase(N
);
432 else if(str
== "loopstart"){
437 else if(str
== "loopend"){
442 else if(str
== "pattern"){
443 pattern
* p
= new pattern();
448 mevent
* eend
= p
->events
;
458 if(delta
== -1){delete e
; break;}
471 patlist
.push_back(p
);
473 else if(str
== "track"){
476 track
* t
= new track();
477 t
->head
->track
= tracks
.size();
478 seqpat
* send
= t
->head
;
481 while(key
!= "kcart"){
482 if(key
== "port"){ file
>> t
->port
; }
483 else if(key
== "chan"){ file
>> t
->chan
; }
484 else if(key
== "prog"){ file
>> t
->prog
; }
485 else if(key
== "bank"){ file
>> t
->bank
; }
486 else if(key
== "mute"){ file
>> t
->mute
; }
487 else if(key
== "solo"){ file
>> t
->solo
; }
488 else if(key
== "vol"){ file
>> t
->vol
; }
489 else if(key
== "pan"){ file
>> t
->pan
; }
490 else if(key
== "name"){
493 char* buf
= (char*)malloc(n
+1);
498 else if(key
== "alive"){ file
>> t
->alive
; }
499 else if(key
== "seqpat"){
501 seqpat
* s
= new seqpat();
502 s
->track
= tracks
.size();
509 file
>> s
->scrollx
>> s
->scrolly
;
510 file
>> total_layers
;
512 if(total_layers
== 1){
514 p
= findpatternbyindex(index
, patlist
);
518 else if(total_layers
> 1){
520 p
= findpatternbyindex(index
, patlist
);
521 layerstack
* layers
= new layerstack(p
);
523 for(int j
=1; j
<total_layers
; j
++){
525 p
= findpatternbyindex(index
,patlist
);
529 file
>> layers
->index
;
530 s
->p
= layers
->array
[layers
->index
];
535 printf("load: bad number of layers\n");
547 ui
->track_info
->add_track();
550 file
.ignore(std::numeric_limits
<streamsize
>::max(),'\n');
557 ui
->track_info
->set_rec(0);
558 ui
->track_info
->update();
560 ui
->arranger
->redraw();
572 int tick2delta(unsigned tick
, vector
<unsigned char>& vbuf
){
573 unsigned char buf
[4];
576 vbuf
.push_back(tick
);
579 else if(tick
< 16383){
582 vbuf
.push_back(0x80|((buf
[0]<<1)|(buf
[1]&0x80)>>7));
583 vbuf
.push_back(buf
[1]&0x7f);
586 else if(tick
< 2097151){
589 vbuf
.push_back(0x80|((buf
[0]<<2)|(buf
[1]&0xC0)>>6));
590 vbuf
.push_back(0x80|((buf
[1]<<1)|(buf
[2]&0x80)>>7));
591 vbuf
.push_back(buf
[2]&0x7f);
597 vbuf
.push_back(0x80|((buf
[0]<<3)|(buf
[1]&0xE0)>>5));
598 vbuf
.push_back(0x80|((buf
[1]<<2)|(buf
[2]&0xC0)>>6));
599 vbuf
.push_back(0x80|((buf
[2]<<1)|(buf
[3]&0x80)>>7));
600 vbuf
.push_back(buf
[3]&0x7f);
605 int savesmf(const char* filename
){
607 if(filename
== NULL
){
612 file
.open(filename
, fstream::out
);
615 printf("savesmf: can't open file for exporting.\n");
619 unsigned char buf
[64];
638 uint16_t L
= tracks
.size();
643 buf
[12] = TICKS_PER_BEAT
>> 8;
644 buf
[13] = TICKS_PER_BEAT
& 0x00ff;
646 file
.write((const char*)buf
,14);
648 vector
<unsigned char> vbuf
;
651 int MAX
= tracks
.size();
653 for(int i
=0; i
<MAX
; i
++){
664 //chunk size (yet unknown)
666 vbuf
.push_back(0x00);
667 vbuf
.push_back(0x00);
668 vbuf
.push_back(0x00);
669 vbuf
.push_back(0x00);
671 track
* t
= tracks
[i
];
676 //change program for this track
682 e
= s
->p
->events
->next
;
686 if(e
->tick
> s
->dur
){
691 N
+= tick2delta(e
->tick
+s
->tick
- last_tick
,vbuf
);
692 last_tick
= e
->tick
+s
->tick
;
693 vbuf
.push_back(0x80 | t
->chan
);
694 vbuf
.push_back(e
->value1
);
695 vbuf
.push_back(e
->value2
);
699 N
+= tick2delta(e
->tick
+s
->tick
- last_tick
,vbuf
);
700 last_tick
= e
->tick
+s
->tick
;
701 vbuf
.push_back(0x90 | t
->chan
);
702 vbuf
.push_back(e
->value1
);
703 vbuf
.push_back(e
->value2
);
706 case 0xA0://after touch
707 N
+= tick2delta(e
->tick
+s
->tick
- last_tick
,vbuf
);
708 last_tick
= e
->tick
+s
->tick
;
709 vbuf
.push_back(0xA0 | t
->chan
);
710 vbuf
.push_back(e
->value1
);
711 vbuf
.push_back(e
->value2
);
714 case 0xB0://control change
715 N
+= tick2delta(e
->tick
+s
->tick
- last_tick
,vbuf
);
716 last_tick
= e
->tick
+s
->tick
;
717 vbuf
.push_back(0xB0 | t
->chan
);
718 vbuf
.push_back(e
->value1
);
719 vbuf
.push_back(e
->value2
);
722 case 0xC0://program change
723 N
+= tick2delta(e
->tick
+s
->tick
- last_tick
,vbuf
);
724 last_tick
= e
->tick
+s
->tick
;
725 vbuf
.push_back(0xC0 | t
->chan
);
726 vbuf
.push_back(e
->value1
);
729 case 0xD0://channel pressure
730 N
+= tick2delta(e
->tick
+s
->tick
- last_tick
,vbuf
);
731 last_tick
= e
->tick
+s
->tick
;
732 vbuf
.push_back(0xD0 | t
->chan
);
733 vbuf
.push_back(e
->value1
);
736 case 0xE0://pitch wheel
737 N
+= tick2delta(e
->tick
+s
->tick
- last_tick
,vbuf
);
738 last_tick
= e
->tick
+s
->tick
;
739 vbuf
.push_back(0xE0 | t
->chan
);
740 vbuf
.push_back(e
->value1
);
741 vbuf
.push_back(e
->value2
);
751 //end of track meta event
752 vbuf
.push_back(0x00);
753 vbuf
.push_back(0xff);
754 vbuf
.push_back(0x2f);
755 vbuf
.push_back(0x00);
765 for(int i
=0; i
<vbuf
.size(); i
++){
767 file
.write((const char*)buf
,1);
777 int getdelta(std::fstream
& f
){
778 unsigned char a
,b
,c
,d
;
781 if(a
<0x80){return a
;}
784 if(b
<0x80){return ((a
&0x7f)<<7) | b
;}
787 if(c
<0x80){return ((a
&0x7f)<<14) | ((b
&0x7f)<<7) | c
;}
790 return ((a
&0x7f)<<21) | ((b
&0x7f)<<14) | ((c
&0x7f)<<7) | d
;
798 char fifths
[15][8] = {
817 int loadsmf(const char* filename
){
818 if(filename
== NULL
){
823 file
.open(filename
, fstream::in
);
826 printf("loadsmf: can't open file for importing.\n");
830 last_filename
= filename
;
831 set_last_dir(filename
);
835 unsigned char buf
[64];
844 std::list
<pattern
*> patlist
;
845 std::vector
<int> chanlist
;
846 std::vector
<int> proglist
;
847 std::vector
<int> banklist
;
849 std::vector
<track
*> extratracks
;
851 std::vector
<char*> tracknames
;
855 for(int i
=0; i
<16; i
++){
856 extratracks
.push_back(NULL
);
861 file
.read((char*)buf
,4);
862 if(memcmp(buf
,"MThd",4)){
863 printf("missing header, probably not a midi file\n");
868 scope_print("Standard Midi File\n");
870 file
.read((char*)buf
,4);
872 printf("header has wrong size, probably a broken midi file\n");
873 scope_print("error: bad header size");
877 //printf("header size\n");
879 file
.read((char*)buf
,2);
881 printf("bad smf type code, probably a broken midi file\n");
882 scope_print("error: bad smf type");
890 case 0: smftype
=0; break;
891 case 1: smftype
=1; break;
892 case 2: smftype
=2; break;
894 printf("bad smf type code, probably a broken midi file\n");
895 scope_print("error: bad smf type");
900 snprintf(sbuf
,256," type: %d\n",smftype
);
903 file
.read((char*)buf
,2);
904 size
= ntohs(*(unsigned short*)buf
);
906 printf("track count of zero, probably a broken midi file\n");
907 scope_print("error: zero tracks");
913 snprintf(sbuf
,256," tracks: %d\n",ntracks
);
917 int tpb
= TICKS_PER_BEAT
;
918 file
.read((char*)buf
,2);
919 size
= ntohs(*(unsigned short*)buf
);
922 snprintf(sbuf
,256," time division: %d ticks per beat\n",tpb
);
926 int fps
= size
&0x7fff;
927 snprintf(sbuf
,256," time division: %d frames per second (wrong)\n",fps
);
929 scope_print("error: smpte time division not support\n");
936 /*** read tracks ***/
937 file
.read((char*)buf
,4);
940 if(memcmp(buf
,"MTrk",4)){
941 printf("bad track header, probably a broken midi file\n");
946 pattern
* p
= new pattern();
950 snprintf(sbuf
,256," track %d\n",trackindex
);
953 file
.read((char*)buf
,4);
954 size
= ntohl(*(unsigned long*)buf
);
956 printf("empty track\n");
965 chanlist
.push_back(-1);
966 banklist
.push_back(-1);
967 proglist
.push_back(-1);
969 tracknames
.push_back(NULL
);
974 int delta
= getdelta(file
);
976 printf("bad delta time, broken midi file\n");
981 tick
= time
*TICKS_PER_BEAT
/tpb
;
983 if(tick
> maxblockdur
){
988 file
.read((char*)buf
,1);
992 if(byte0
< 0x80){//implicit byte0
998 if(byte0
< 0xf0){//channel event
1000 int type
= byte0
&0xf0;
1001 int chan
= byte0
&0x0f;
1003 if(chanlist
[N
]==-1){
1007 if(byte1
<0){//didnt read byte1 yet
1008 file
.read((char*)buf
,1);
1017 if(!(type
== 0xC0 || type
== 0xD0)){
1018 file
.read((char*)buf
,1);
1022 e
= new mevent(type
,tick
,val1
);
1027 if(val2
==0){//fake note off
1032 case 0x80://note off
1033 case 0xA0://aftertouch
1034 case 0xB0://controller change
1035 case 0xE0://pitchbend
1036 if(type
==0xB0 && val1
==0x00 && banklist
[N
]==-1){
1042 case 0xC0://program change
1043 if(proglist
[N
]==-1){
1047 case 0xD0://channel pressure
1050 printf("unrecognized channel event %d\n",type
);
1055 if(chan
!=chanlist
[N
]){//put event in the a misfit track
1056 //printf("mistfit N=%d chan=%d type=%d\n",chanlist[N],chan,type);
1057 if(extratracks
[chan
] == NULL
){
1058 track
* t
= new track();
1064 extratracks
[chan
] = t
;
1065 seqpat
* s
= new seqpat();
1068 s
->p
= new pattern();
1071 extratracks
[chan
]->head
->next
->p
->insert(e
,tick
);
1073 else{//put it in a normal track
1078 else{/*** not a channel event ***/
1082 if(byte0
== 255){//meta events
1084 file
.read((char*)buf
,1);
1088 size
= getdelta(file
);
1090 printf("bad delta time\n");
1096 abuf
= new char[size
+1];
1099 case 0://sequence number
1101 snprintf(sbuf
,256," %d sequence: ? ?\n",time
);
1104 printf("bad sequence number data length: %d\n",size
);
1108 file
.read((char*)buf
,2);
1111 file
.read(abuf
,size
);
1113 asprintf(&tbuf
," %d text: \"%s\"\n",time
,abuf
);
1117 ui
->info_text
->buffer()->append(abuf
);
1118 ui
->info_text
->buffer()->append("\n");
1121 case 2://copyright notice
1122 file
.read((char*)abuf
,size
);
1124 asprintf(&tbuf
," %d copyright: \"%s\"\n",time
,abuf
);
1129 file
.read((char*)abuf
,size
);
1131 asprintf(&tbuf
," %d track name: \"%s\"\n",time
,abuf
);
1135 tracknames
[N
] = (char*)malloc(sizeof(char)*(size
+1));
1136 strncpy(tracknames
[N
],abuf
,size
+1);
1139 case 4://instrument name
1140 file
.read((char*)abuf
,size
);
1142 asprintf(&tbuf
," %d instrument name: \"%s\"\n",time
,abuf
);
1147 file
.read((char*)abuf
,size
);
1149 asprintf(&tbuf
," %d lyrics: \"%s\"\n",time
,abuf
);
1154 file
.read((char*)abuf
,size
);
1156 asprintf(&tbuf
," %d marker: \"%s\"\n",time
,abuf
);
1161 file
.read((char*)abuf
,size
);
1163 asprintf(&tbuf
," %d cue point: \"%s\"\n",time
,abuf
);
1167 case 32://channel prefix
1169 printf("bad channel prefix data size: %d\n",size
);
1173 file
.read((char*)buf
,1);
1174 asprintf(&tbuf
," %d channel prefix: %d\n",time
,buf
[0]);
1178 case 47://end of track
1180 printf("end of track has non zero data size: %d\n",size
);
1188 printf("set tempo has non-3 data size: %d\n",size
);
1192 file
.read((char*)buf
,3);
1199 micros
= *(unsigned*)buf
;
1200 micros
= ntohl(micros
);
1202 asprintf(&tbuf
," %d set tempo: %d us/quarter\n",time
,micros
);
1208 set_beats_per_minute(60000000/micros
);
1212 case 84://smpte offset
1214 printf("smpte offset has non-5 data size: %d\n",size
);
1218 file
.read((char*)buf
,5);
1219 asprintf(&tbuf
," %d smpte offset: ?\n",time
);
1223 case 88://time signature
1225 printf("time signature has non-4 data size: %d\n",size
);
1229 file
.read((char*)buf
,4);
1230 asprintf(&tbuf
," %d time signature: %d/%d\n",time
,buf
[0],1<<buf
[1]);
1234 case 89://key signature
1236 printf("key signature has non-2 data size: %d\n",size
);
1240 file
.read((char*)buf
,2);
1241 asprintf(&tbuf
," %d key signature: %s %s\n",time
,fifths
[(signed char)buf
[0]+7],buf
[1]?"minor":"major");
1245 case 127://sequencer specific
1246 file
.read((char*)abuf
,size
);
1248 asprintf(&tbuf
," %d sequencer specific: \"%s\"\n",time
,abuf
);
1252 default://unknown meta event
1253 file
.read((char*)abuf
,size
);
1255 asprintf(&tbuf
," %d meta %d: \"%s\"\n",time
,meta
,abuf
);
1261 else if(byte0
== 240){//sysex event
1262 size
= getdelta(file
);
1264 printf("bad delta time\n");
1267 abuf
= new char[size
+1];
1268 file
.read((char*)abuf
,size
);
1271 asprintf(&tbuf
," %d sysex: \"%s\"\n",time
,abuf
);
1275 file
.read((char*)buf
,1);
1277 file
.putback(buf
[0]);
1280 scope_print(" end of sysex\n");
1287 else if(byte0
== 247){//divided sysex event
1288 size
= getdelta(file
);
1290 printf("bad delta time\n");
1293 abuf
= new char[size
+1];
1294 file
.read((char*)abuf
,size
);
1297 asprintf(&tbuf
," %d sysex fragment: \"%s\"\n",time
,abuf
);
1301 file
.read((char*)buf
,1);
1303 file
.putback(buf
[0]);
1306 scope_print(" end of sysex\n");
1311 printf("bad event type %d, broken midi file\n",byte0
);
1320 if(proglist
[N
]==-1){
1323 if(banklist
[N
]==-1){
1326 if(chanlist
[N
]==-1){
1334 patlist
.push_back(p
);
1336 file
.read((char*)buf
,4);//read first byte of next track or EOF
1341 scope_print("End Of File\n\n");
1344 //TODO set up track settings using data remembered from the reading
1345 std::list
<pattern
*>::iterator p
= patlist
.begin();
1347 while(p
!=patlist
.end()){
1348 track
* t
= new track();
1349 seqpat
* s
= new seqpat(i
,0,128*64,*p
);
1350 int Q
= TICKS_PER_BEAT
;
1351 s
->dur
= maxblockdur
/ Q
* Q
+ Q
;
1356 s
->p
->h
= 360*i
/ 16;
1358 while(s
->p
->h
> 360){s
->p
->h
-= 360;}
1359 s
->p
->regen_colors();
1361 t
->chan
= chanlist
[i
];
1362 t
->prog
= proglist
[i
];
1363 t
->bank
= banklist
[i
];
1367 t
->name
= tracknames
[i
];
1370 t
->name
= (char*)malloc(8);
1379 if(tempo_flag
== 0){
1380 set_beats_per_minute(120);
1384 ui
->track_info
->set_rec(0);
1385 ui
->track_info
->update();
1387 ui
->arranger
->redraw();
1389 update_config_gui();