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
26 #include <fltk/Group.h>
27 #include <fltk/Widget.h>
28 #include <fltk/events.h>
40 extern std::vector
<track
*> tracks
;
42 extern struct conf config
;
46 #define SWAP(X,Y) tmp=X; X=Y; Y=tmp;
48 Arranger::Arranger(int x
, int y
, int w
, int h
, const char* label
= 0) : fltk::Widget(x
, y
, w
, h
, label
) {
49 new_default_w
= TICKS_PER_BEAT
*4;
58 q_tick
= TICKS_PER_BEAT
*4;
71 if(fakeh
< h
){fakeh
= h
;}
79 resize_handle_width
= 4;
91 int Arranger::handle(int event
){
109 case fltk::MOUSEWHEEL
:
116 else if(event_dy()<0){
124 if(event_key()==fltk::DeleteKey
){
130 if(zoom_out_key(event_key(),event_state())){
131 //if(event_key()==fltk::LeftKey){
133 prevt
= xpix2tick(scrollx
);
135 zoom
= 30*(1<<zoom_n
)/16;
136 ui
->song_timeline
->zoom
= 30*(1<<zoom_n
)/16;
137 scrollTo(tick2xpix(prevt
),scrolly
);
138 //ui->song_timeline->update(get_play_position());
139 //ui->song_timeline->redraw();
145 if(zoom_in_key(event_key(),event_state())){
146 //if(event_key()==fltk::RightKey){
148 prevt
= xpix2tick(scrollx
);
150 zoom
= 30*(1<<zoom_n
)/16;
151 ui
->song_timeline
->zoom
= 30*(1<<zoom_n
)/16;
152 scrollTo(tick2xpix(prevt
),scrolly
);
153 //ui->song_timeline->update(get_play_position());
154 //ui->song_timeline->redraw();
164 if(event_button()==1){//left mouse
165 seqpat
* s
= over_seqpat();
167 if(color_flag
||unclone_flag
||split_flag
||join_flag
){//do nothing
169 else if(event_state()&fltk::SHIFT
){//begin box
175 box_t1
=xpix2tick(X
+scrollx
);
177 box_k1
=(Y
+scrolly
)/30;
182 insert_torig
= xpix2tick(X
+scrollx
)/q_tick
*q_tick
;
183 insert_toffset
= q_tick
;
184 insert_track
= (Y
+scrolly
) / 30;
193 color_orig_h
= color_sel
->h
;
194 color_orig_v
= color_sel
->v
;
195 color_h
= color_orig_h
;
196 color_v
= color_orig_v
;
216 if(!s
->selected
&& !(event_state()&SHIFT
)){
220 if(fltk::event_clicks() > 0){//'double click'
221 ui
->piano_roll
->load(s
);
222 ui
->event_edit
->load(s
);
223 ui
->pattern_timeline
->update(get_play_position());
224 ui
->keyboard
->cur_port
= tracks
[s
->track
]->port
;
225 ui
->keyboard
->cur_chan
= tracks
[s
->track
]->chan
;
226 ui
->track_info
->set_rec(s
->track
);
227 set_rec_track(s
->track
);
232 if(over_lhandle(s
)){//begin resize
234 lresize_torig
= s
->tick
;
237 else if(over_rhandle(s
)){//begin resizemove
239 rresize_torig
= s
->tick
+s
->dur
;
245 move_torig
= s
->tick
;
247 move_korig
= s
->track
;
251 move_offset
= xpix2tick(X
+scrollx
)/q_tick
*q_tick
- s
->tick
;
255 else if(event_button()==2){//middle mouse
256 seqpat
* s
= over_seqpat();
260 s
->p
->regen_colors();
266 paste_tcenter1
= quantize(xpix2tick(X
+scrollx
));
267 paste_kcenter1
= (Y
+scrolly
) / 30;
270 else if(event_button()==3){//right mouse
271 seqpat
* s
= over_seqpat();
273 seqpat
* ptr
= tracks
[s
->track
]->head
->next
;
277 ptr
->p
->regen_colors();
291 delete_sel
= s
;//this line needs to be removed
296 resize_arrow_color
= fltk::color(128,0,0);
302 if(split_flag
||unclone_flag
||join_flag
){return 0;}
306 box_t2
= xpix2tick(X
+scrollx
);
307 box_k2
= (Y
+scrolly
)/30;
309 if(color_flag
&& color_sel
){
310 color_sel
->h
= color_orig_h
+ (color_orig_x
- X
)/1.0;
311 color_sel
->v
= color_orig_v
+ (color_orig_y
- Y
)/100.0;
312 color_sel
->regen_colors();
313 color_h
= color_sel
->h
;
314 color_v
= color_sel
->v
;
315 set_default_hsv_value(color_v
);
318 insert_toffset
= xpix2tick(X
+scrollx
)/q_tick
*q_tick
+q_tick
-insert_torig
;
319 if(insert_toffset
<=0){
320 insert_toffset
-= q_tick
;
322 insert_track
= (Y
+scrolly
) / 30;
324 else if(rresize_flag
){
325 rresize_toffset
= xpix2tick(X
+scrollx
)/TICKS_PER_BEAT
*TICKS_PER_BEAT
-
328 else if(lresize_flag
){
329 lresize_toffset
= xpix2tick(X
+scrollx
)/TICKS_PER_BEAT
*TICKS_PER_BEAT
-
333 move_toffset
= quantize(xpix2tick(X
+scrollx
)) - move_torig
- move_offset
;
334 move_koffset
= (Y
+scrolly
) / 30 - move_korig
;
337 paste_tcenter1
= quantize(xpix2tick(X
+scrollx
));
338 paste_kcenter1
= (Y
+scrolly
) / 30;
343 if(split_flag
||unclone_flag
||join_flag
){return 0;}
344 if(event_button()==1){
357 else if(rresize_flag
){
362 else if(lresize_flag
){
371 else if(event_button()==2){
377 else if(event_button()==3){
378 seqpat
* over_s
= over_seqpat();
379 if(delete_flag
&& over_s
){
380 if(over_s
->selected
){
393 if(color_flag
||unclone_flag
){break;}
394 seqpat
* s
= over_seqpat();
397 int temp_t
= xpix2tick(X
+scrollx
)/TICKS_PER_BEAT
*TICKS_PER_BEAT
;
398 if(split_s
!= s
|| temp_t
!= split_t
){
407 if(check_join_safety()){
416 else if(over_rhandle(s
)){
417 if(resize_s
!= s
|| resize_arrow
!= 1){
418 if(s
->selected
){resize_arrow_color
= fltk::color(128,128,0);}
419 else{resize_arrow_color
= fltk::color(s
->p
->r2
,s
->p
->g2
,s
->p
->b2
);}
422 resize_x
= tick2xpix(s
->tick
+ s
->dur
)-scrollx
-resize_handle_width
-1;
423 resize_y
= s
->track
*30-scrolly
;
427 else if(over_lhandle(s
)){
428 if(resize_s
!= s
|| resize_arrow
!= 1){
429 if(s
->selected
){resize_arrow_color
= fltk::color(128,128,0);}
430 else{resize_arrow_color
= fltk::color(s
->p
->r2
,s
->p
->g2
,s
->p
->b2
);}
433 resize_x
= tick2xpix(s
->tick
)+1 - scrollx
;
434 resize_y
= s
->track
*30 - scrolly
;
439 if(resize_arrow
!= 0){
446 int redraw_question
= 0;
455 if(resize_arrow
!= 0){
459 if(redraw_question
){redraw();}
467 void Arranger::draw(){
469 fltk::push_clip(0,0,w(),h());
471 fltk::setfont(fltk::HELVETICA
,8);
473 fltk::setcolor(fltk::GRAY05
);
474 fltk::fillrect(0,0,w(),h());
476 fltk::setcolor(fltk::GRAY20
);
477 int M
= config
.beats_per_measure
;
479 for(int i
=1; I
<w(); i
++){
480 I
= i
*zoom
*M
/4 - scrollx
;
482 fltk::fillrect(I
,0,1,h());
486 fltk::setcolor(fltk::GRAY50
);
487 int P
= config
.measures_per_phrase
;
490 for(int i
=1; I
<w(); i
++){
491 I
= i
*zoom
*4*P
*M
/4/4 - scrollx
;
493 fltk::fillrect(I
,0,1,h());
499 fltk::setcolor(fltk::BLUE
);
500 int T1
= insert_torig
;
501 int T2
= T1
+ insert_toffset
;
503 if(T1
>T2
){SWAP(T1
,T2
);}
504 int X
= tick2xpix(T1
)+1 - scrollx
;
505 int Y
= insert_track
*30 - scrolly
;
506 int W
= tick2xpix(T2
)-tick2xpix(T1
) - 1;
507 fltk::fillrect(X
,Y
,W
,28);
511 if(check_move_safety()){
512 fltk::setcolor(fltk::MAGENTA
);
515 fltk::setcolor(fltk::RED
);
518 for(int i
=0; i
<tracks
.size(); i
++){
519 seqpat
* s
= tracks
[i
]->head
->next
;
522 int X
= tick2xpix(s
->tick
+ move_toffset
) - scrollx
;
523 int Y
= (s
->track
+ move_koffset
)*30 - scrolly
;
524 int W
= tick2xpix(s
->dur
);
525 fltk::fillrect(X
+1,Y
+1,W
-1,1);
526 fltk::fillrect(X
+1,Y
+1,1,29-1);
527 fltk::fillrect(X
+1,Y
+29-1,W
-1,1);
528 fltk::fillrect(X
+W
-1,Y
+1,1,29-1);
537 //recalc_paste_center();
538 if(check_paste_safety()){
539 fltk::setcolor(fltk::GREEN
);
542 fltk::setcolor(fltk::RED
);
545 for(int i
=0; i
<tracks
.size(); i
++){
546 seqpat
* s
= tracks
[i
]->head
->next
;
549 //int X = tick2xpix(s->tick-paste_tcenter0+paste_tcenter1) - scrollx;
550 //int Y = (s->track-paste_tcenter0+paste_kcenter1)*30 - scrolly;
551 int X
= tick2xpix(paste_tcenter1
) - scrollx
;
552 int Y
= paste_kcenter1
*30 - scrolly
;
553 int W
= tick2xpix(s
->dur
);
554 fltk::fillrect(X
+1,Y
+1,W
-1,1);
555 fltk::fillrect(X
+1,Y
+1,1,29-1);
556 fltk::fillrect(X
+1,Y
+29-1,W
-1,1);
557 fltk::fillrect(X
+W
-1,Y
+1,1,29-1);
566 fltk::setcolor(fltk::GREEN
);
572 if(X1
>X2
){SWAP(X1
,X2
);}
573 if(Y1
>Y2
){SWAP(Y1
,Y2
);}
574 fltk::fillrect(X1
,Y1
,X2
-X1
,1);
575 fltk::fillrect(X1
,Y1
,1,Y2
-Y1
);
576 fltk::fillrect(X2
,Y1
,1,Y2
-Y1
);
577 fltk::fillrect(X1
,Y2
,X2
-X1
,1);
584 fltk::Color c1
,c2
,c3
,cx
;
587 for(int i
=0; i
<tracks
.size(); i
++){
589 s
= tracks
[i
]->head
->next
;
594 get_outline_color(s
,&c1
,&c2
,&c3
,&cx
);
598 int R1
= lresize_flag
&&s
->selected
? lresize_toffset
: 0;
599 int R2
= rresize_flag
&&s
->selected
? rresize_toffset
: 0;
602 int T2
= s
->tick
+s
->dur
+R2
;
604 if(T1
> T2
){SWAP(T1
,T2
)};
606 int X
= tick2xpix(T1
)+1 - scrollx
;
607 int Y
= s
->track
* 30 - scrolly
;
608 int W
= tick2xpix(T2
)-tick2xpix(T1
)-1;
610 if(rresize_flag
&& s
->selected
&& T1
==T2
){
611 W
= tick2xpix(TICKS_PER_BEAT
)-1;
613 if(lresize_flag
&& s
->selected
&& T1
==T2
){
614 W
= tick2xpix(TICKS_PER_BEAT
)-1;
617 fillrect(X
+1,Y
+1,W
-2,27);
622 fillrect(X
+W
-1,Y
,1,29);
623 fillrect(X
,Y
+28,W
-1,1);
630 fltk::setcolor(fltk::YELLOW
);
631 fillrect(X
-2,Y
,3,28);
632 fltk::setcolor(fltk::color(128,128,0));
633 fillrect(X
-2,Y
+28,3,1);
636 fltk::push_clip(X
,Y
,W
,30);
640 mevent
* e
= s
->p
->events
;
642 if(e
->tick
>= s
->dur
){
645 if(e
->type
== MIDI_NOTE_ON
){
646 int X2
= tick2xpix(e
->tick
) + tick2xpix(s
->tick
)+2 - scrollx
;
647 Y
= s
->track
*30 + 27 - e
->value1
*27/127 - scrolly
;
648 int W2
= tick2xpix(e
->dur
);
650 if(!(X2
+W2
<0 || X2
>X
+W
)){
658 int total
= s
->layer_total();
660 fltk::setcolor(fltk::BLACK
);
661 int X
= tick2xpix(s
->tick
) - scrollx
;
662 int Y
= s
->track
* 30 - scrolly
;
663 int count
= s
->layer_index()+1;
665 snprintf(buf
,16,"%d / %d",count
,total
);
666 fltk::drawtext(buf
,X
+2,Y
+27);
676 if(!rresize_flag
&& !lresize_flag
){
677 if(resize_arrow
> 0){
678 setcolor(resize_arrow_color
);
680 int W
= resize_handle_width
;
687 addvertex(X
+W
,Y
+H
/2);
690 else if(resize_arrow
< 0){
691 setcolor(resize_arrow_color
);
693 int W
= resize_handle_width
;
706 fltk::setcolor(fltk::RED
);
707 int X
= tick2xpix(split_t
) - scrollx
;
708 int Y
= split_s
->track
*30;
709 fltk::fillrect(X
,Y
+1,1,28);
716 void Arranger::scrollTo(int X
, int Y
){
718 if(is_backend_playing() && config
.follow
){
719 int pos
= tick2xpix(get_play_position());
720 if(pos
< X
|| pos
> X
+ w() - scrollbuffer
- 30){
721 ui
->song_hscroll
->value(scrollx
);
727 ui
->song_hscroll
->value(scrollx
);
730 ui
->song_timeline
->scroll
= X
;
731 ui
->song_timeline
->redraw();
732 ui
->track_info
->scroll
= Y
;
733 ui
->track_info
->redraw();
738 seqpat
* Arranger::over_seqpat(){
739 int track
= (event_y()+scrolly
) / 30;
740 if(track
>= tracks
.size()){
743 int tick
= xpix2tick(event_x()+scrollx
);
744 seqpat
* s
= tfind
<seqpat
>(tracks
[track
]->head
,tick
);
746 if(tick
< s
->tick
+s
->dur
){
754 //true if over right handle of s
755 int Arranger::over_rhandle(seqpat
* s
){
758 int X1
= tick2xpix(s
->tick
) - scrollx
;
759 int X2
= X1
+ tick2xpix(s
->dur
);
760 int Y1
= s
->track
* 30 + 1 - scrolly
;
763 if(tick2xpix(s
->dur
) < 10){
767 return (Y
> Y1
&& Y
< Y2
&& X
< X2
&& X
> X2
- 5);
770 //true if over left handle of s
771 int Arranger::over_lhandle(seqpat
* s
){
774 int X1
= tick2xpix(s
->tick
) - scrollx
;
775 int X2
= X1
+ tick2xpix(s
->dur
);
776 int Y1
= s
->track
* 30 + 1 - scrolly
;
779 if(tick2xpix(s
->dur
) < 10){
783 if(Y
> Y1
&& Y
< Y2
&& X
< X1
+ 5 + 1 && X
> X1
+1){
784 //printf("success\n");
786 return (Y
> Y1
&& Y
< Y2
&& X
< X1
+ 5 + 1 && X
> X1
+1);
789 // 4=beats per measure, TICKS_PER_BEAT=ticks per beat, 30=width of measure in pixels
790 int Arranger::tick2xpix(int tick
){
791 return tick
*zoom
/(TICKS_PER_BEAT
*4);
794 int Arranger::xpix2tick(int xpix
){
795 return xpix
* (TICKS_PER_BEAT
*4) /zoom
;
798 int Arranger::quantize(int tick
){
799 return tick
/q_tick
* q_tick
;
803 void Arranger::update(int pos
){
804 if(!is_backend_playing()){
807 int X1
= tick2xpix(pos
);
808 int X2
= X1
- scrollx
;
810 int target
= X1
-50<0?0:X1
-50;
811 scrollTo(target
,scrolly
);
812 // ui->song_hscroll->value(target);
814 if(X2
> w()-scrollbuffer
){
816 scrollTo(target
,scrolly
);
817 //ui->song_hscroll->value(target);
822 void Arranger::layout(){
827 fakeh
= tracks
.size()*30;
831 ui
->song_vscroll
->maximum(0);
832 ui
->song_vscroll
->minimum(fakeh
-h());
834 int newsize
= M
-(fakeh
-h());
838 //ui->song_vscroll->slider_size(379);
842 void Arranger::unselect_all(){
844 for(int i
=0; i
<tracks
.size(); i
++){
845 s
= tracks
[i
]->head
->next
;
855 void Arranger::get_outline_color(seqpat
* s
, fltk::Color
* c1
, fltk::Color
* c2
, fltk::Color
* c3
, fltk::Color
* cx
){
858 *c1
= fltk::color(p
->r1
, p
->g1
, p
->b1
);
859 *cx
= fltk::color(p
->rx
, p
->gx
, p
->bx
);
863 seqpat
* over_s
= over_seqpat();
864 if(delete_flag
&& s
->selected
){
865 *c1
= fltk::color(255,0,0);
866 *c2
= fltk::color(255,0,0);
867 *c3
= fltk::color(255,0,0);
877 if(T1
>T2
){SWAP(T1
,T2
);}
878 if(K1
<K2
){SWAP(K1
,K2
);}
879 if(s
->tick
+s
->dur
> T1
&& s
->tick
< T2
&& K
>= K2
&& K
<= K1
){
880 *c1
= fltk::color(0,255,0);
881 *c2
= fltk::color(71,120,59);
882 *c3
= fltk::color(108,229,75);
888 *c1
= fltk::color(255,255,0);
889 *c2
= fltk::color(140,137,46);
890 *c3
= fltk::color(232,255,37);
891 *cx
= fltk::color(128,128,0);
896 *c2
= fltk::color(p
->r2
,p
->g2
,p
->b2
);
897 *c3
= fltk::color(p
->r3
,p
->g3
,p
->b3
);
902 void Arranger::apply_insert(){
904 if(!check_insert_safety()){
909 int T1
= insert_torig
;
910 int T2
= T1
+ insert_toffset
;
911 if(T1
>T2
){SWAP(T1
,T2
);}
913 Command
* c
=new CreateSeqpatBlank(insert_track
,T1
,T2
-T1
);
917 if(T2
>maxt
){relayout();}
920 void Arranger::apply_box(){
927 if(T1
>T2
){SWAP(T1
,T2
);}
928 if(K1
>K2
){SWAP(K1
,K2
);}
930 if(K2
> tracks
.size()-1){K2
= tracks
.size()-1;}
931 for(int i
=K1
; i
<=K2
; i
++){
932 s
= tracks
[i
]->head
->next
;
934 if(s
->tick
+s
->dur
> T1
&& s
->tick
< T2
){
943 void Arranger::apply_delete(){
948 for(int i
=0; i
<tracks
.size(); i
++){
949 s
= tracks
[i
]->head
->next
;
953 tracks
[s
->track
]->modified
= 1;
954 c
=new DeleteSeqpat(s
);
963 unmodify_and_unstick_tracks();
967 void Arranger::apply_move(){
968 if(move_toffset
==0 && move_koffset
==0){
972 if(!check_move_safety()){
980 for(int i
=0; i
<tracks
.size(); i
++){
981 s
= tracks
[i
]->head
->next
;
984 if(s
->selected
&& s
->modified
== 0){
985 int K
= s
->track
+ move_koffset
;
986 int T
= s
->tick
+ move_toffset
;
987 tracks
[s
->track
]->modified
= 1;
988 tracks
[K
]->modified
= 1;
990 c
=new MoveSeqpat(s
,K
,T
);
994 if(T
+s
->dur
> maxt
){relayout();}
1002 unmodify_and_unstick_tracks();
1005 void Arranger::apply_paste(){
1007 //recalc_paste_center();
1010 //if(!check_paste_safety()){
1015 c
= new CreateSeqpat(paste_kcenter1
,paste_tcenter1
,main_sel
,config
.alwayscopy
);
1019 tracks
[paste_kcenter1
]->restate();
1022 void Arranger::recalc_paste_center(){
1031 for(int i
=0; i
<tracks
.size(); i
++){
1032 s
= tracks
[i
]->head
->next
;
1035 accum_t
= (s
->tick
+s
->dur
) / 2;
1046 printf("T %d K %d %d %d \n",T
,K
,accum_t
/T
,accum_k
/K
);
1048 paste_tcenter0
= accum_t
/ T
;
1049 paste_kcenter0
= accum_k
/ K
;
1053 void Arranger::apply_rresize(){
1054 if(rresize_toffset
==0){
1058 if(!check_resize_safety()){
1067 for(int i
=0; i
<tracks
.size(); i
++){
1068 s
= tracks
[i
]->head
->next
;
1071 if(s
->selected
&& s
->modified
== 0){
1072 tracks
[i
]->modified
= 1;
1075 int T2
= s
->tick
+ s
->dur
+ rresize_toffset
;
1078 seqpat
* stmp
= s
->prev
;
1079 //c=new ReverseSeqpat(s);
1082 c
=new ResizeSeqpat(s
,T2
-T1
);
1085 c
=new MoveSeqpat(s
,s
->track
,T1
);
1090 if(s
->tick
+s
->dur
> maxt
){relayout();}
1094 T2
= T1
+TICKS_PER_BEAT
;
1096 c
=new ResizeSeqpat(s
,T2
-T1
);
1100 if(T2
> maxt
){relayout();}
1110 unmodify_and_unstick_tracks();
1113 void Arranger::apply_lresize(){
1114 if(lresize_toffset
==0){
1118 if(!check_resize_safety()){
1127 for(int i
=0; i
<tracks
.size(); i
++){
1128 s
= tracks
[i
]->head
->next
;
1131 if(s
->selected
&& s
->modified
== 0){
1132 tracks
[i
]->modified
= 1;
1134 int T1
= s
->tick
+ lresize_toffset
;
1135 int T2
= s
->tick
+ s
->dur
;
1138 seqpat
* stmp
= s
->prev
;
1139 //c=new ReverseSeqpat(s);
1142 c
=new ResizeSeqpat(s
,T2
-T1
);
1145 c
=new MoveSeqpat(s
,s
->track
,T1
);
1150 if(s
->tick
+s
->dur
> maxt
){relayout();}
1154 T2
= T1
+TICKS_PER_BEAT
;
1156 seqpat
* stmp
= s
->prev
;
1157 c
=new MoveSeqpat(s
,s
->track
,T1
);
1160 c
=new ResizeSeqpat(s
,T2
-T1
);
1165 if(s
->tick
+s
->dur
>maxt
){relayout();}
1175 unmodify_and_unstick_tracks();
1180 int collision_test(int t11
, int t12
, int t21
, int t22
){
1181 return !((t11
< t21
&& t12
<= t21
) ||
1182 (t11
>= t22
&& t12
> t22
)) ? 1 : 0;
1185 int Arranger::check_move_safety(){
1189 for(int i
=0; i
<tracks
.size(); i
++){
1190 s
= tracks
[i
]->head
->next
;
1193 if(i
+move_koffset
< 0 || i
+move_koffset
> tracks
.size()-1 ||
1194 s
->tick
+ move_toffset
< 0){
1197 ptr
= tracks
[i
+move_koffset
]->head
->next
;
1200 ptr
=ptr
->next
; continue;
1202 if(collision_test(s
->tick
+move_toffset
,s
->tick
+s
->dur
+move_toffset
,ptr
->tick
,ptr
->tick
+ptr
->dur
) ){
1217 int Arranger::check_insert_safety(){
1220 int T1
= insert_torig
;
1221 int T2
= T1
+ insert_toffset
;
1224 if(T1
>T2
){SWAP(T1
,T2
);}
1229 if(insert_track
> tracks
.size()-1){
1232 if(tracks
[insert_track
]==NULL
){
1236 s
= tracks
[insert_track
]->head
->next
;
1239 if(collision_test(T1
,T2
,s
->tick
,s
->tick
+s
->dur
)){
1248 int Arranger::check_resize_safety(){
1256 for(int i
=0; i
<tracks
.size(); i
++){
1257 s
= tracks
[i
]->head
->next
;
1260 s
= s
->next
; continue;
1265 T2
= s
->tick
+ s
->dur
+ rresize_toffset
;
1267 else if(lresize_flag
){
1268 T1
= s
->tick
+ lresize_toffset
;
1269 T2
= s
->tick
+ s
->dur
;
1271 if(T1
>T2
){SWAP(T1
,T2
);}
1276 ptr
= tracks
[s
->track
]->head
->next
;
1279 ptr
=ptr
->next
; continue;
1283 S2
= ptr
->tick
+ ptr
->dur
;
1286 S2
+= rresize_toffset
;
1288 else if(lresize_flag
){
1289 S1
+= lresize_toffset
;
1293 if(collision_test(T1
,T2
,S1
,S2
)){
1307 int Arranger::check_paste_safety(){
1312 int Arranger::check_join_safety(){
1314 if(s
->prev
->tick
+s
->prev
->dur
==s
->tick
&& s
->prev
->prev
){
1321 void Arranger::apply_unclone(){
1324 pattern
* p2
= new pattern(main_sel
->p
);
1325 //does p2 need to have its ref_c set
1326 float a
= randf(0.2,0.8);
1327 while(fabs(p2
->v
- a
)<0.1){
1333 //this creates a copy of the block, but uses a copy of the pattern
1334 seqpat
* s2
= new seqpat(main_sel
,p2
);
1337 c
= new DeleteSeqpat(main_sel
);
1341 c
= new CreateSeqpat(s2
->track
,s2
->tick
,s2
,0);
1348 void Arranger::apply_split(){
1349 seqpat
* s
= split_s
;
1350 if(split_t
== s
->tick
|| split_t
== s
->tick
+s
->dur
){
1353 Command
* c
= new SplitSeqpat(split_s
,split_t
);
1359 void Arranger::apply_join(){
1361 if(!check_join_safety()){
1364 Command
* c
= new JoinSeqpat(join_s
->prev
,join_s
);