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 <fltk/TextDisplay.h>
35 std::vector
<track
*> tracks
;
37 std::list
<Command
*> undo_stack
;
38 std::list
<int> undo_number
;
39 std::list
<Command
*>::iterator undo_ptr
;
45 static float default_hsv_value
= 0.8;
51 int play_seq(int cur_tick
, void (*dispatch_event
)(mevent
*, int port
, int tick
)){
58 /* start at skip s, and skip e
59 if e is in the past, dispatch event and set new skip
60 if next e is past pattern dur, switch patseq
61 if next e is null, switch patseq
62 switch patseq sets skip s
63 do the above until e is in the future and not past end
64 then go to next track and start over
67 //printf("playing. cur_tick = %d\n",cur_tick);
69 for(int i
=0; i
<tracks
.size(); i
++){
70 //if(tracks[i]->alive == 0){continue;}
76 if(!e
){ goto switchpatseq
; }//no more events in this seqpat
80 if(e
->tick
+s
->tick
<= cur_tick
&& e
->tick
<= s
->dur
){//should have happened
82 if(e
->tick
!= s
->dur
|| e
->type
== MIDI_NOTE_OFF
)
83 if(tracks
[i
]->mute
== 0)
84 if((get_solo() && tracks
[i
]->solo
!= 0) || !get_solo())
85 dispatch_event(e
, i
, s
->tick
);
89 if(!e
){//no more events in this seqpat
93 else if(e
->tick
> s
->dur
){//went past the end
96 else{//no more events on this track right now
99 goto again
;//try to play next event
104 if(!s
){continue;}//no more seqpats
106 if(!p
){continue;}//this shouldnt happen anymore
108 if(!e
){continue;}//...means this pattern has played already...
110 goto again
;//play some or all of the next seqpat
114 int set_seq_pos(int new_tick
){
121 for(int i
=0; i
<tracks
.size(); i
++){
127 s
->skip
= s
->p
->events
;
133 if(s
->tick
+s
->dur
<= new_tick
){
144 tracks
[i
]->skip
= NULL
;
156 else if(e
->tick
>= new_tick
- s
->tick
){
165 void set_rec_track(int t
){
173 int set_default_hsv_value(float v
){
174 default_hsv_value
= v
;
177 void set_undo(Command
* c
){
178 if(undo_ptr
!= undo_stack
.end()){
179 //then we need to clean house
180 //delete everything at and after undo_ptr (for real);
183 undo_stack
.push_back(c
);
184 undo_ptr
= undo_stack
.end();
188 void undo_push(int n
){
189 undo_number
.push_back(n
);
208 CreateSeqpat::CreateSeqpat(int track
, int tick
, seqpat
* zs
, int copy
){
211 s
->p
= new pattern(zs
->p
);
212 s
->skip
= s
->p
->events
;
217 s
->prev
= tfind
<seqpat
>(tracks
[track
]->head
,tick
);
218 s
->next
= s
->prev
->next
;
221 void CreateSeqpat::redo(){
222 tinsert
<seqpat
>(s
->prev
, s
);
225 void CreateSeqpat::undo(){
229 CreateSeqpatBlank::CreateSeqpatBlank(int track
, int tick
, int len
){
230 s
= new seqpat(track
, tick
, len
, new pattern());
235 p
->h
= ((track
%16) / 16.0) * 360;
236 p
->v
= default_hsv_value
;
242 s
->prev
= tfind
<seqpat
>(tracks
[track
]->head
,tick
);
243 s
->next
= s
->prev
->next
;
244 s
->skip
= s
->p
->events
;
248 void DeleteSeqpat::redo(){
250 int pos
= get_play_position();
251 if(pos
>= s
->tick
&& pos
<= s
->tick
+s
->dur
){
252 tracks
[s
->track
]->skip
= s
->next
;
258 void DeleteSeqpat::undo(){
259 tinsert
<seqpat
>(s
->prev
, s
);
263 void ResizeSeqpat::redo(){
265 tinsert
<seqpat
>(s1
->prev
,s2
);
270 void ResizeSeqpat::undo(){
272 tinsert
<seqpat
>(s1
->prev
,s1
);
275 MoveSeqpat::MoveSeqpat(seqpat
* zs
, int track
, int tick
){
282 targ2
= tfind
<seqpat
>(tracks
[track2
]->head
,tick
);
283 if(targ2
== zs
){//dont put it after itself
288 void MoveSeqpat::redo(){
293 int play_pos
= get_play_position();
294 if(play_pos
>= s
->tick
&& play_pos
<= s
->tick
+s
->dur
){//no entry into s by cb
295 tracks
[track1
]->skip
= s
->next
;
298 track
* t
= tracks
[track2
];
300 //here possibly wait a few ms for the audio to leave s if it was in
302 //perform nitty gritty
307 s
->skip
= tfind
<mevent
>(s
->p
->events
, play_pos
- s
->tick
)->next
;
308 tinsert
<seqpat
>(targ2
,s
);
311 void MoveSeqpat::undo(){
315 int play_pos
= get_play_position();
316 if(play_pos
>= s
->tick
&& play_pos
<= s
->tick
+s
->dur
){
317 tracks
[track2
]->skip
= s
->next
;
323 s
->skip
= tfind
<mevent
>(s
->p
->events
, play_pos
- s
->tick
)->next
;
325 tinsert
<seqpat
>(targ1
,s
);
328 void SplitSeqpat::redo(){
332 void SplitSeqpat::undo(){
336 void JoinSeqpat::redo(){
340 void JoinSeqpat::undo(){
344 void ClearSeqpat::redo(){
348 void ClearSeqpat::undo(){
352 void LayerSeqpat::redo(){
353 if(s
->layers
== NULL
){
354 s
->layers
= new layerstack(s
->p
);
360 void LayerSeqpat::undo(){
361 s
->p
= s
->layers
->pop();
362 if(s
->layers
->total
== 1){
369 void CreateNote::redo(){
370 mevent
* targ
= tfind
<mevent
>(p
->events
, e1
->tick
);
371 tinsert
<mevent
>(targ
, e1
);
372 targ
= tfind
<mevent
>(p
->events
, e2
->tick
);
373 tinsert
<mevent
>(targ
, e2
);
376 void CreateNote::undo(){
381 void CreateNoteOn::redo(){
382 mevent
* targ
= tfind
<mevent
>(p
->events
, e1
->tick
);
383 tinsert
<mevent
>(targ
, e1
);
384 //targ = tfind<mevent>(p->events, e2->tick);
385 //tinsert<mevent>(targ, e2);
388 void CreateNoteOn::undo(){
390 //tremove<mevent>(e2);
394 CreateNoteOff::CreateNoteOff(pattern
* zp
, int note
, int vel
, int tick
){
397 mevent
* ptr
= tfind
<mevent
>(zp
->events
,tick
);
399 if(ptr
->type
== MIDI_NOTE_ON
&& ptr
->value1
== note
){
401 dur2
= tick
- ptr
->tick
;
405 if(ptr
->type
== MIDI_NOTE_OFF
&& ptr
->value1
== note
){
410 e2
= new mevent(MIDI_NOTE_OFF
, tick
, note
);
414 void CreateNoteOff::redo(){
415 //mevent* targ = tfind<mevent>(p->events, e1->tick);
416 //tinsert<mevent>(targ, e1);
418 targ
= tfind
<mevent
>(p
->events
, e2
->tick
);
419 tinsert
<mevent
>(targ
, e2
);
425 void CreateNoteOff::undo(){
426 //tremove<mevent>(e1);
433 void DeleteNote::redo(){
440 void DeleteNote::undo(){
441 tinsert
<mevent
>(e1
->prev
,e1
);
443 tinsert
<mevent
>(e2
->prev
,e2
);
449 void MoveNote::arrive(int t
){
450 mevent
* targ
= tfind
<mevent
>(p
->events
, t
);
451 tinsert
<mevent
>(targ
, e1
);
453 targ
= tfind
<mevent
>(p
->events
, t
+e1
->dur
);
454 tinsert
<mevent
>(targ
, e2
);
458 void MoveNote::redo(){
464 e2
->tick
= t2
+e1
->dur
;
470 void MoveNote::undo(){
476 e2
->tick
= t1
+e1
->dur
;
485 ResizeNote::ResizeNote(pattern
* zp
, mevent
* ze
, int dur
){
495 r2
->prev
= tfind
<mevent
>(p
->events
, ze
->tick
+ dur
);
496 if(r2
->prev
== r1
|| r2
->prev
== l1
){
499 r2
->tick
= ze
->tick
+ dur
;
503 void ResizeNote::redo(){
509 tinsert
<mevent
>(l2
->prev
, l2
);
511 tinsert
<mevent
>(r2
->prev
, r2
);
515 void ResizeNote::undo(){
521 tinsert
<mevent
>(l1
->prev
, l1
);
523 tinsert
<mevent
>(r1
->prev
, r1
);
530 void CreateEvent::redo(){
531 tinsert
<mevent
>(e
->prev
, e
);
534 void CreateEvent::undo(){
538 void DeleteEvent::redo(){
542 void DeleteEvent::undo(){
543 tinsert
<mevent
>(e
->prev
, e
);
546 void ChangeEvent::redo(){
547 tswap
<mevent
>(e1
,e2
);
550 void ChangeEvent::undo(){
551 tswap
<mevent
>(e2
,e1
);
558 mevent
* find_off(mevent
* e
){
561 if(ptr
->type
== MIDI_NOTE_OFF
&& ptr
->value1
== e
->value1
){
577 events
= new mevent();//dummy
599 pattern::pattern(pattern
* p
){
600 mevent
* ptr
= p
->events
;
602 events
= new mevent(ptr
);
606 ptr2
->next
= new mevent(ptr
);
607 ptr2
->next
->prev
= ptr2
;
622 void pattern::regen_colors(){
624 while(h
>360){h
-=360;}
628 if(v
< 0.2){v
= 0.2;}
629 if(v
> 0.8){v
= 0.8;}
631 hsv_to_rgb(h
,s
,v
,&r1
,&g1
,&b1
);
632 hsv_to_rgb(h
,s
,v
/2,&r2
,&g2
,&b2
);
633 hsv_to_rgb(h
,s
,v
+0.2 > 1 ? 1 : v
+0.2,&r3
,&g3
,&b3
);
635 hsv_to_rgb(h
,s
,v
-0.3,&rx
,&gx
,&bx
);
638 hsv_to_rgb(h
,s
,0.7,&rx
,&gx
,&bx
);
643 void pattern::append(mevent
* ze
){
652 void pattern::insert(mevent
* ze
, int tick
){
653 mevent
* ptr
= events
;
655 if(ptr
->next
->tick
> tick
){
656 ze
->next
= ptr
->next
;
669 void pattern::fixdur(){
673 if(e
->type
== MIDI_NOTE_ON
){
675 if(f
){e
->dur
= f
->tick
- e
->tick
;}
683 //used when the sequence is changed in such a way
684 //that the sequencer state needs to be updated
685 void track::restate(){
686 int pos
= get_play_position();
687 seqpat
* s
= head
->next
;
692 //printf("trying block: pos %d, tick %d, t2 %d\n",pos,s->tick,s->tick+s->dur);
693 if(pointfound
){//we are past the point, reset up coming blocks
694 //printf("future block\n");
695 s
->skip
= s
->p
->events
->next
;
698 else if(s
->tick
+s
->dur
< pos
){//we are past this block
699 //printf("past block\n");
703 else if(s
->tick
+s
->dur
> pos
&& s
->tick
<= pos
){//we are inside this block, point found
704 //printf("inside block\n");
708 mevent
* e
= s
->p
->events
->next
;
710 if(e
->tick
+s
->tick
>= pos
){
723 else{//we are not in a block, point found
724 //printf("pointfound outside block\n");
733 if(snullflag
){skip
= NULL
;}
737 void seqpat::restate(){
738 mevent
* e
= p
->events
->next
;
739 int pos
= get_play_position();
741 if(e
->tick
+tick
>= pos
){
752 void seqpat::apply_erase(){
756 c
= new ClearSeqpat(this);
761 //create new pattern and make it current
762 void seqpat::apply_layer(){
763 Command
* c
= new LayerSeqpat(this);
768 void seqpat::next_layer(){
774 void seqpat::prev_layer(){
780 int seqpat::layer_index(){
782 return layers
->index
;
789 int seqpat::layer_total(){
791 return layers
->total
;
798 void seqpat::record_check(int mode
){
800 if(mode
==1 || mode
==2){
801 autocomplete();//end stuck notes
802 if(mode
== 1){apply_erase();}
803 else if(mode
== 2){apply_layer();}
804 tracks
[track
]->restate();
810 //sends note off if it determines that
811 //we are in between two notes
812 void seqpat::autocomplete(){
814 mevent
* e
= p
->events
->next
;
817 int pos
= get_play_position()-tick
;
819 int chan
= tracks
[track
]->chan
;
820 int port
= tracks
[track
]->port
;
823 if(e
->type
== MIDI_NOTE_ON
&& e
->tick
< pos
){
826 if(eoff
->tick
> pos
){
827 midi_note_off(e
->value1
,chan
,port
);
841 pattern
* layerstack::push_new(){
846 array
[total
-1] = new pattern();
847 array
[total
-1]->h
= array
[0]->h
;
848 array
[total
-1]->s
= array
[0]->s
;
849 array
[total
-1]->v
= array
[0]->v
;
850 array
[total
-1]->regen_colors();
855 void layerstack::push(pattern
* p
){
866 void layerstack::reallocate(){
867 pattern
** ptmp
= new pattern
*[memsize
*2];
868 for(int i
=0; i
<memsize
; i
++){
876 pattern
* layerstack::pop(){
880 if(index
== total
-1){
888 void layerstack::remove(int n
){
892 void layerstack::insert(pattern
* p
, int n
){
897 pattern
* layerstack::next(){
907 pattern
* layerstack::prev(){
917 layerstack::layerstack(pattern
* p
){
920 array
= new pattern
*[16];
927 layerstack::~layerstack(){
928 for(int i
=0; i
<total
; i
++){
930 if(array
[i
]->ref_c
== 0){
938 void reset_record_flags(){
939 for(int i
=0; i
<tracks
.size(); i
++){
940 seqpat
* s
= tracks
[i
]->head
->next
;
942 if(s
->record_flag
== 1){