Rewrote overwrite and layer operations to be undoable.
[epichord.git] / src / seq.cpp
blobcf98eaa701dcd12995e19abe6a2cf475cdedfb07
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 <math.h>
25 #include <list>
26 #include <vector>
28 #include "seq.h"
30 #include <fltk/TextDisplay.h>
31 #include "util.h"
33 #include "backend.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;
41 int solo_flag = 0;
43 int rec_track = 0;
45 static float default_hsv_value = 0.8;
51 int play_seq(int cur_tick, void (*dispatch_event)(mevent*, int port, int tick)){
53 seqpat* s;
54 pattern* p;
55 mevent* e;
56 int base;
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);
68 s = tracks[0]->skip;
69 for(int i=0; i<tracks.size(); i++){
70 //if(tracks[i]->alive == 0){continue;}
71 s = tracks[i]->skip;
72 if(!s){continue;}
73 p = s->p;
74 e = s->skip;
76 if(!e){ goto switchpatseq; }//no more events in this seqpat
78 again:
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);
87 e = e->next;
88 s->skip = e;
89 if(!e){//no more events in this seqpat
90 goto switchpatseq;
93 else if(e->tick > s->dur){//went past the end
94 goto switchpatseq;
96 else{//no more events on this track right now
97 continue;
99 goto again;//try to play next event
100 switchpatseq:
101 s = s->next;
103 tracks[i]->skip = s;
104 if(!s){continue;}//no more seqpats
105 p = s->p;
106 if(!p){continue;}//this shouldnt happen anymore
107 e = s->skip;
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){
115 //reset all skip
116 //reset cur_seqpat
117 seqpat* s;
118 pattern* p;
119 mevent* e;
121 for(int i=0; i<tracks.size(); i++){
123 s = tracks[i]->head;
124 tracks[i]->skip = s;
126 while(s){
127 s->skip = s->p->events;
128 s = s->next;
131 s = tracks[i]->head;
132 while(s){
133 if(s->tick+s->dur <= new_tick){
134 tracks[i]->skip = s;
136 else{
137 tracks[i]->skip = s;
138 break;
140 s = s->next;
143 if(!s){
144 tracks[i]->skip = NULL;
145 continue;
148 if(!s->p){continue;}
149 e = s->p->events;
151 while(1){
152 if(e == NULL){
153 s->skip = e;
154 break;
156 else if(e->tick >= new_tick - s->tick){
157 s->skip = e;
158 break;
160 e = e->next;
165 void set_rec_track(int t){
166 rec_track = t;
169 int get_rec_track(){
170 return rec_track;
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();
185 c->redo();
188 void undo_push(int n){
189 undo_number.push_back(n);
192 void do_undo(){
194 undo_ptr--;
195 (*undo_ptr)->undo();
198 void do_redo(){
200 (*undo_ptr)->redo();
201 undo_ptr++;
208 CreateSeqpat::CreateSeqpat(int track, int tick, seqpat* zs, int copy){
209 s = new seqpat(zs);
210 if(copy){
211 s->p = new pattern(zs->p);
212 s->skip = s->p->events;
214 s->track = track;
215 s->tick = tick;
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(){
226 tremove<seqpat>(s);
229 CreateSeqpatBlank::CreateSeqpatBlank(int track, int tick, int len){
230 s = new seqpat(track, tick, len, new pattern());
231 unsigned char r,g,b;
233 pattern* p = s->p;
234 p->ref_c = 1;
235 p->h = ((track%16) / 16.0) * 360;
236 p->v = default_hsv_value;
237 p->regen_colors();
239 s->scrolly = 300;
240 s->scrollx = 0;
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(){
249 //check for restate
250 int pos = get_play_position();
251 if(pos >= s->tick && pos <= s->tick+s->dur){
252 tracks[s->track]->skip = s->next;
255 tremove<seqpat>(s);
258 void DeleteSeqpat::undo(){
259 tinsert<seqpat>(s->prev, s);
260 //check for restate
263 void ResizeSeqpat::redo(){
264 tremove<seqpat>(s1);
265 tinsert<seqpat>(s1->prev,s2);
267 //check for restate
270 void ResizeSeqpat::undo(){
271 tremove<seqpat>(s2);
272 tinsert<seqpat>(s1->prev,s1);
275 MoveSeqpat::MoveSeqpat(seqpat* zs, int track, int tick){
276 s = zs;
277 track1 = s->track;
278 track2 = track;
279 tick1 = s->tick;
280 tick2 = tick;
281 targ1 = s->prev;
282 targ2 = tfind<seqpat>(tracks[track2]->head,tick);
283 if(targ2 == zs){//dont put it after itself
284 targ2 = zs->prev;
288 void MoveSeqpat::redo(){
290 tremove<seqpat>(s);
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
303 s->track = track2;
305 s->tick = tick2;
307 s->skip = tfind<mevent>(s->p->events, play_pos - s->tick)->next;
308 tinsert<seqpat>(targ2,s);
311 void MoveSeqpat::undo(){
313 tremove<seqpat>(s);
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;
319 s->track = track1;
320 s->tick = tick1;
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(){
345 s->p = p2;
348 void ClearSeqpat::undo(){
349 s->p = p1;
352 void LayerSeqpat::redo(){
353 if(s->layers == NULL){
354 s->layers = new layerstack(s->p);
356 s->layers->push(p);
357 s->p = p;
360 void LayerSeqpat::undo(){
361 s->p = s->layers->pop();
362 if(s->layers->total == 1){
363 delete s->layers;
364 s->layers = NULL;
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(){
377 tremove<mevent>(e1);
378 tremove<mevent>(e2);
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(){
389 tremove<mevent>(e1);
390 //tremove<mevent>(e2);
394 CreateNoteOff::CreateNoteOff(pattern* zp, int note, int vel, int tick){
395 p = zp;
396 e1 = NULL;
397 mevent* ptr = tfind<mevent>(zp->events,tick);
398 while(ptr){
399 if(ptr->type == MIDI_NOTE_ON && ptr->value1 == note){
400 dur1 = ptr->dur;
401 dur2 = tick - ptr->tick;
402 e1 = ptr;
403 break;
405 if(ptr->type == MIDI_NOTE_OFF && ptr->value1 == note){
406 break;
408 ptr = ptr->prev;
410 e2 = new mevent(MIDI_NOTE_OFF, tick, note);
411 e2->value2 = vel;
414 void CreateNoteOff::redo(){
415 //mevent* targ = tfind<mevent>(p->events, e1->tick);
416 //tinsert<mevent>(targ, e1);
417 mevent* targ;
418 targ = tfind<mevent>(p->events, e2->tick);
419 tinsert<mevent>(targ, e2);
420 if(e1){
421 e1->dur = dur2;
425 void CreateNoteOff::undo(){
426 //tremove<mevent>(e1);
427 if(e1){
428 e1->dur = dur1;
430 tremove<mevent>(e2);
433 void DeleteNote::redo(){
434 tremove<mevent>(e1);
435 if(e2){
436 tremove<mevent>(e2);
440 void DeleteNote::undo(){
441 tinsert<mevent>(e1->prev,e1);
442 if(e2){
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);
452 if(e2){
453 targ = tfind<mevent>(p->events, t+e1->dur);
454 tinsert<mevent>(targ, e2);
458 void MoveNote::redo(){
459 tremove<mevent>(e1);
460 e1->tick = t2;
461 e1->value1 = note2;
462 if(e2){
463 tremove<mevent>(e2);
464 e2->tick = t2+e1->dur;
465 e2->value1 = note2;
467 arrive(t2);
470 void MoveNote::undo(){
471 tremove<mevent>(e1);
472 e1->tick = t1;
473 e1->value1 = note1;
474 if(e2){
475 tremove<mevent>(e2);
476 e2->tick = t1+e1->dur;
477 e2->value1 = note1;
479 arrive(t1);
485 ResizeNote::ResizeNote(pattern* zp, mevent* ze, int dur){
486 p = zp;
487 l1 = ze;
488 l2 = new mevent(ze);
489 l2->dur = dur;
491 r2 = NULL;
492 r1 = find_off(ze);
493 if(r1){
494 r2 = new mevent(r1);
495 r2->prev = tfind<mevent>(p->events, ze->tick + dur);
496 if(r2->prev == r1 || r2->prev == l1){
497 r2->prev = l2;
499 r2->tick = ze->tick + dur;
503 void ResizeNote::redo(){
504 tremove<mevent>(l1);
505 if(r1){
506 tremove<mevent>(r1);
509 tinsert<mevent>(l2->prev, l2);
510 if(r2){
511 tinsert<mevent>(r2->prev, r2);
515 void ResizeNote::undo(){
516 if(r2){
517 tremove<mevent>(r2);
519 tremove<mevent>(l2);
521 tinsert<mevent>(l1->prev, l1);
522 if(r1){
523 tinsert<mevent>(r1->prev, r1);
530 void CreateEvent::redo(){
531 tinsert<mevent>(e->prev, e);
534 void CreateEvent::undo(){
535 tremove<mevent>(e);
538 void DeleteEvent::redo(){
539 tremove<mevent>(e);
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){
559 mevent* ptr = e;
560 while(ptr){
561 if(ptr->type == MIDI_NOTE_OFF && ptr->value1 == e->value1){
562 return ptr;
564 ptr = ptr->next;
566 return NULL;
576 pattern::pattern(){
577 events = new mevent();//dummy
578 events->tick = 0;
579 next = NULL;
580 ref_c = 0;
581 h=0;
582 s=1;
583 v=0.8;
584 regen_colors();
588 pattern::~pattern(){
589 mevent* e = events;
590 mevent* next;
591 while(e){
592 next = e->next;
593 delete e;
594 e = next;
599 pattern::pattern(pattern* p){
600 mevent* ptr = p->events;
601 mevent* ptr2;
602 events = new mevent(ptr);
603 ptr2 = events;
604 ptr=ptr->next;
605 while(ptr){
606 ptr2->next = new mevent(ptr);
607 ptr2->next->prev = ptr2;
608 ptr=ptr->next;
609 ptr2=ptr2->next;
611 ptr2->next = NULL;
613 next = NULL;
614 ref_c = 0;
615 h = p->h;
616 s = p->s;
617 v = p->v;
618 regen_colors();
622 void pattern::regen_colors(){
624 while(h>360){h-=360;}
625 while(h<0){h+=360;}
626 if(s < 0){s = 0;}
627 if(s > 1){s = 1;}
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);
634 if(v > 0.5){
635 hsv_to_rgb(h,s,v-0.3,&rx,&gx,&bx);
637 else{
638 hsv_to_rgb(h,s,0.7,&rx,&gx,&bx);
643 void pattern::append(mevent* ze){
644 mevent* e = events;
645 while(e->next){
646 e = e->next;
648 e->next = ze;
649 ze->prev = e;
652 void pattern::insert(mevent* ze, int tick){
653 mevent* ptr = events;
654 while(ptr->next){
655 if(ptr->next->tick > tick){
656 ze->next = ptr->next;
657 ze->next->prev = ze;
658 ptr->next = ze;
659 ze->prev = ptr;
660 return;
662 ptr=ptr->next;
664 ptr->next = ze;
665 ze->prev = ptr;
669 void pattern::fixdur(){
670 mevent* e = events;
671 mevent* f;
672 while(e->next){
673 if(e->type == MIDI_NOTE_ON){
674 f = find_off(e);
675 if(f){e->dur = f->tick - e->tick;}
677 e = e->next;
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;
688 int snullflag = 1;
689 int pnullflag = 1;
690 int pointfound = 0;
691 while(s){
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");
700 s->skip = NULL;
703 else if(s->tick+s->dur > pos && s->tick <= pos){//we are inside this block, point found
704 //printf("inside block\n");
705 pointfound = 1;
706 snullflag = 0;
707 skip = s;
708 mevent* e = s->p->events->next;
709 while(e){
710 if(e->tick+s->tick >= pos){
711 s->skip = e;
712 pointfound = 1;
713 pnullflag = 0;
714 break;
716 e = e->next;
718 if(pnullflag){
719 s->skip = NULL;
723 else{//we are not in a block, point found
724 //printf("pointfound outside block\n");
725 skip = s;
726 snullflag = 0;
727 pointfound = 1;
730 s = s->next;
733 if(snullflag){skip = NULL;}
737 void seqpat::restate(){
738 mevent* e = p->events->next;
739 int pos = get_play_position();
740 while(e){
741 if(e->tick+tick >= pos){
742 skip = e;
743 return;
745 e = e->next;
747 skip = NULL;
751 //clear the pattern
752 void seqpat::apply_erase(){
754 Command* c;
756 c = new ClearSeqpat(this);
757 set_undo(c);
758 undo_push(1);
761 //create new pattern and make it current
762 void seqpat::apply_layer(){
763 Command* c = new LayerSeqpat(this);
764 set_undo(c);
765 undo_push(1);
768 void seqpat::next_layer(){
769 if(layers){
770 p = layers->next();
774 void seqpat::prev_layer(){
775 if(layers){
776 p = layers->prev();
780 int seqpat::layer_index(){
781 if(layers){
782 return layers->index;
784 else{
785 return 0;
789 int seqpat::layer_total(){
790 if(layers){
791 return layers->total;
793 else{
794 return 1;
798 void seqpat::record_check(int mode){
799 if(record_flag==0){
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();
806 record_flag = 1;
810 //sends note off if it determines that
811 //we are in between two notes
812 void seqpat::autocomplete(){
813 mevent* ptr;
814 mevent* e = p->events->next;
815 mevent* eoff;
817 int pos = get_play_position()-tick;
819 int chan = tracks[track]->chan;
820 int port = tracks[track]->port;
822 while(e){
823 if(e->type == MIDI_NOTE_ON && e->tick < pos){
824 eoff = find_off(e);
825 if(eoff){
826 if(eoff->tick > pos){
827 midi_note_off(e->value1,chan,port);
831 e = e->next;
841 pattern* layerstack::push_new(){
842 if(total==memsize){
843 reallocate();
845 total++;
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();
851 index=total-1;
852 return array[index];
855 void layerstack::push(pattern* p){
856 if(total==memsize){
857 reallocate();
860 total++;
861 array[total-1] = p;
862 index = total-1;
863 p->ref_c++;
866 void layerstack::reallocate(){
867 pattern** ptmp = new pattern*[memsize*2];
868 for(int i=0; i<memsize; i++){
869 ptmp[i] = array[i];
871 memsize *= 2;
872 delete [] array;
873 array = ptmp;
876 pattern* layerstack::pop(){
877 if(index == 1){
878 return NULL;
880 if(index == total-1){
881 index--;
883 array[total-1]=NULL;
884 total--;
885 return array[index];
888 void layerstack::remove(int n){
892 void layerstack::insert(pattern* p, int n){
897 pattern* layerstack::next(){
898 if(index==total-1){
899 index=0;
901 else{
902 index++;
904 return array[index];
907 pattern* layerstack::prev(){
908 if(index==0){
909 index=total-1;
911 else{
912 index--;
914 return array[index];
917 layerstack::layerstack(pattern* p){
918 index = 0;
919 total = 1;
920 array = new pattern*[16];
921 memsize = 16;
922 array[0] = p;
923 // ptr = array[0];
924 ref_c = 0;
927 layerstack::~layerstack(){
928 for(int i=0; i<total; i++){
929 array[i]->ref_c--;
930 if(array[i]->ref_c == 0){
931 delete array[i];
938 void reset_record_flags(){
939 for(int i=0; i<tracks.size(); i++){
940 seqpat* s = tracks[i]->head->next;
941 while(s){
942 if(s->record_flag == 1){
943 s->record_flag = 0;
945 s = s->next;