Arranger scrolling works again.
[epichord.git] / src / seq.cpp
blob10d1a6ffb3fd9ea66db3c7892ca9dbf01b815da6
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(){
329 s->p = p2;
332 void SplitSeqpat::undo(){
333 s->p = p1;
339 void CreateNote::redo(){
340 mevent* targ = tfind<mevent>(p->events, e1->tick);
341 tinsert<mevent>(targ, e1);
342 targ = tfind<mevent>(p->events, e2->tick);
343 tinsert<mevent>(targ, e2);
346 void CreateNote::undo(){
347 tremove<mevent>(e1);
348 tremove<mevent>(e2);
351 void CreateNoteOn::redo(){
352 mevent* targ = tfind<mevent>(p->events, e1->tick);
353 tinsert<mevent>(targ, e1);
354 //targ = tfind<mevent>(p->events, e2->tick);
355 //tinsert<mevent>(targ, e2);
358 void CreateNoteOn::undo(){
359 tremove<mevent>(e1);
360 //tremove<mevent>(e2);
364 CreateNoteOff::CreateNoteOff(pattern* zp, int note, int vel, int tick){
365 p = zp;
366 e1 = NULL;
367 mevent* ptr = tfind<mevent>(zp->events,tick);
368 while(ptr){
369 if(ptr->type == MIDI_NOTE_ON && ptr->value1 == note){
370 dur1 = ptr->dur;
371 dur2 = tick - ptr->tick;
372 e1 = ptr;
373 break;
375 if(ptr->type == MIDI_NOTE_OFF && ptr->value1 == note){
376 break;
378 ptr = ptr->prev;
380 e2 = new mevent(MIDI_NOTE_OFF, tick, note);
381 e2->value2 = vel;
384 void CreateNoteOff::redo(){
385 //mevent* targ = tfind<mevent>(p->events, e1->tick);
386 //tinsert<mevent>(targ, e1);
387 mevent* targ;
388 targ = tfind<mevent>(p->events, e2->tick);
389 tinsert<mevent>(targ, e2);
390 if(e1){
391 e1->dur = dur2;
395 void CreateNoteOff::undo(){
396 //tremove<mevent>(e1);
397 if(e1){
398 e1->dur = dur1;
400 tremove<mevent>(e2);
403 void DeleteNote::redo(){
404 tremove<mevent>(e1);
405 if(e2){
406 tremove<mevent>(e2);
410 void DeleteNote::undo(){
411 tinsert<mevent>(e1->prev,e1);
412 if(e2){
413 tinsert<mevent>(e2->prev,e2);
419 void MoveNote::arrive(int t){
420 mevent* targ = tfind<mevent>(p->events, t);
421 tinsert<mevent>(targ, e1);
422 if(e2){
423 targ = tfind<mevent>(p->events, t+e1->dur);
424 tinsert<mevent>(targ, e2);
428 void MoveNote::redo(){
429 tremove<mevent>(e1);
430 e1->tick = t2;
431 e1->value1 = note2;
432 if(e2){
433 tremove<mevent>(e2);
434 e2->tick = t2+e1->dur;
435 e2->value1 = note2;
437 arrive(t2);
440 void MoveNote::undo(){
441 tremove<mevent>(e1);
442 e1->tick = t1;
443 e1->value1 = note1;
444 if(e2){
445 tremove<mevent>(e2);
446 e2->tick = t1+e1->dur;
447 e2->value1 = note1;
449 arrive(t1);
455 ResizeNote::ResizeNote(pattern* zp, mevent* ze, int dur){
456 p = zp;
457 l1 = ze;
458 l2 = new mevent(ze);
459 l2->dur = dur;
461 r2 = NULL;
462 r1 = find_off(ze);
463 if(r1){
464 r2 = new mevent(r1);
465 r2->prev = tfind<mevent>(p->events, ze->tick + dur);
466 if(r2->prev == r1 || r2->prev == l1){
467 r2->prev = l2;
469 r2->tick = ze->tick + dur;
473 void ResizeNote::redo(){
474 tremove<mevent>(l1);
475 if(r1){
476 tremove<mevent>(r1);
479 tinsert<mevent>(l2->prev, l2);
480 if(r2){
481 tinsert<mevent>(r2->prev, r2);
485 void ResizeNote::undo(){
486 if(r2){
487 tremove<mevent>(r2);
489 tremove<mevent>(l2);
491 tinsert<mevent>(l1->prev, l1);
492 if(r1){
493 tinsert<mevent>(r1->prev, r1);
500 void CreateEvent::redo(){
501 tinsert<mevent>(e->prev, e);
504 void CreateEvent::undo(){
505 tremove<mevent>(e);
508 void DeleteEvent::redo(){
509 tremove<mevent>(e);
512 void DeleteEvent::undo(){
513 tinsert<mevent>(e->prev, e);
516 void ChangeEvent::redo(){
517 tswap<mevent>(e1,e2);
520 void ChangeEvent::undo(){
521 tswap<mevent>(e2,e1);
528 mevent* find_off(mevent* e){
529 mevent* ptr = e;
530 while(ptr){
531 if(ptr->type == MIDI_NOTE_OFF && ptr->value1 == e->value1){
532 return ptr;
534 ptr = ptr->next;
536 return NULL;
546 pattern::pattern(){
547 events = new mevent();//dummy
548 events->tick = 0;
549 next = NULL;
550 ref_c = 0;
551 h=0;
552 s=1;
553 v=0.8;
554 regen_colors();
558 pattern::~pattern(){
559 mevent* e = events;
560 mevent* next;
561 while(e){
562 next = e->next;
563 delete e;
564 e = next;
569 pattern::pattern(pattern* p){
570 mevent* ptr = p->events;
571 mevent* ptr2;
572 events = new mevent(ptr);
573 ptr2 = events;
574 ptr=ptr->next;
575 while(ptr){
576 ptr2->next = new mevent(ptr);
577 ptr2->next->prev = ptr2;
578 ptr=ptr->next;
579 ptr2=ptr2->next;
581 ptr2->next = NULL;
583 next = NULL;
584 ref_c = 0;
585 h = p->h;
586 s = p->s;
587 v = p->v;
588 regen_colors();
592 void pattern::regen_colors(){
594 while(h>360){h-=360;}
595 while(h<0){h+=360;}
596 if(s < 0){s = 0;}
597 if(s > 1){s = 1;}
598 if(v < 0.2){v = 0.2;}
599 if(v > 0.8){v = 0.8;}
601 hsv_to_rgb(h,s,v,&r1,&g1,&b1);
602 hsv_to_rgb(h,s,v/2,&r2,&g2,&b2);
603 hsv_to_rgb(h,s,v+0.2 > 1 ? 1 : v+0.2,&r3,&g3,&b3);
604 if(v > 0.5){
605 hsv_to_rgb(h,s,v-0.3,&rx,&gx,&bx);
607 else{
608 hsv_to_rgb(h,s,0.7,&rx,&gx,&bx);
613 void pattern::append(mevent* ze){
614 mevent* e = events;
615 while(e->next){
616 e = e->next;
618 e->next = ze;
619 ze->prev = e;
622 void pattern::insert(mevent* ze, int tick){
623 mevent* ptr = events;
624 while(ptr->next){
625 if(ptr->next->tick > tick){
626 ze->next = ptr->next;
627 ze->next->prev = ze;
628 ptr->next = ze;
629 ze->prev = ptr;
630 return;
632 ptr=ptr->next;
634 ptr->next = ze;
635 ze->prev = ptr;
639 void pattern::fixdur(){
640 mevent* e = events;
641 mevent* f;
642 while(e->next){
643 if(e->type == MIDI_NOTE_ON){
644 f = find_off(e);
645 if(f){e->dur = f->tick - e->tick;}
647 e = e->next;
653 //used when the sequence is changed in such a way
654 //that the sequencer state needs to be updated
655 void track::restate(){
656 int pos = get_play_position();
657 seqpat* s = head->next;
658 int snullflag = 1;
659 int pnullflag = 1;
660 int pointfound = 0;
661 while(s){
662 //printf("trying block: pos %d, tick %d, t2 %d\n",pos,s->tick,s->tick+s->dur);
663 if(pointfound){//we are past the point, reset up coming blocks
664 //printf("future block\n");
665 s->skip = s->p->events->next;
668 else if(s->tick+s->dur < pos){//we are past this block
669 //printf("past block\n");
670 s->skip = NULL;
673 else if(s->tick+s->dur > pos && s->tick <= pos){//we are inside this block, point found
674 //printf("inside block\n");
675 pointfound = 1;
676 snullflag = 0;
677 skip = s;
678 mevent* e = s->p->events->next;
679 while(e){
680 if(e->tick+s->tick >= pos){
681 s->skip = e;
682 pointfound = 1;
683 pnullflag = 0;
684 break;
686 e = e->next;
688 if(pnullflag){
689 s->skip = NULL;
693 else{//we are not in a block, point found
694 //printf("pointfound outside block\n");
695 skip = s;
696 snullflag = 0;
697 pointfound = 1;
700 s = s->next;
703 if(snullflag){skip = NULL;}
707 void seqpat::restate(){
708 mevent* e = p->events->next;
709 int pos = get_play_position();
710 while(e){
711 if(e->tick+tick >= pos){
712 skip = e;
713 return;
715 e = e->next;
717 skip = NULL;
721 //clear the pattern
722 void seqpat::apply_erase(){
723 if(layers){
724 layers->ref_c--;
725 if(layers->ref_c == 0){
726 delete layers;
727 layers = NULL;
731 pattern* ptmp = new pattern();
732 ptmp->ref_c = 1;
733 ptmp->h = p->h;
734 ptmp->s = p->s;
735 ptmp->v = p->v;
736 ptmp->regen_colors();
738 if(p){
739 if(--(p->ref_c) == 0){
740 delete p;
744 p = ptmp;
747 //create new pattern and make it current
748 void seqpat::apply_layer(){
749 if(layers){
750 p = layers->push_new();
752 else{
753 layers = new layerstack(p);
754 layers->ref_c = 1;
755 p = layers->push_new();
759 void seqpat::next_layer(){
760 if(layers){
761 p = layers->next();
765 void seqpat::prev_layer(){
766 if(layers){
767 p = layers->prev();
771 int seqpat::layer_index(){
772 if(layers){
773 return layers->index;
775 else{
776 return 0;
780 int seqpat::layer_total(){
781 if(layers){
782 return layers->total;
784 else{
785 return 1;
789 void seqpat::record_check(int mode){
790 if(record_flag==0){
791 if(mode==1 || mode==2){
792 autocomplete();//end stuck notes
793 if(mode == 1){apply_erase();}
794 else if(mode == 2){apply_layer();}
795 tracks[track]->restate();
797 record_flag = 1;
801 //sends note off if it determines that
802 //we are in between two notes
803 void seqpat::autocomplete(){
804 mevent* ptr;
805 mevent* e = p->events->next;
806 mevent* eoff;
808 int pos = get_play_position()-tick;
810 int chan = tracks[track]->chan;
811 int port = tracks[track]->port;
813 while(e){
814 if(e->type == MIDI_NOTE_ON && e->tick < pos){
815 eoff = find_off(e);
816 if(eoff){
817 if(eoff->tick > pos){
818 midi_note_off(e->value1,chan,port);
822 e = e->next;
832 pattern* layerstack::push_new(){
833 if(total==memsize){
834 reallocate();
836 total++;
837 array[total-1] = new pattern();
838 array[total-1]->h = array[0]->h;
839 array[total-1]->s = array[0]->s;
840 array[total-1]->v = array[0]->v;
841 array[total-1]->regen_colors();
842 index=total-1;
843 return array[index];
846 void layerstack::push_new(pattern* p){
847 if(total==memsize){
848 reallocate();
851 total++;
852 array[total-1] = p;
853 index = total-1;
854 p->ref_c++;
857 void layerstack::reallocate(){
858 pattern** ptmp = new pattern*[memsize*2];
859 for(int i=0; i<memsize; i++){
860 ptmp[i] = array[i];
862 memsize *= 2;
863 delete [] array;
864 array = ptmp;
868 pattern* layerstack::next(){
869 if(index==total-1){
870 index=0;
872 else{
873 index++;
875 return array[index];
878 pattern* layerstack::prev(){
879 if(index==0){
880 index=total-1;
882 else{
883 index--;
885 return array[index];
888 layerstack::layerstack(pattern* p){
889 index = 0;
890 total = 1;
891 array = new pattern*[16];
892 memsize = 16;
893 array[0] = p;
894 // ptr = array[0];
895 ref_c = 0;
898 layerstack::~layerstack(){
899 for(int i=0; i<total; i++){
900 array[i]->ref_c--;
901 if(array[i]->ref_c == 0){
902 delete array[i];
909 void reset_record_flags(){
910 for(int i=0; i<tracks.size(); i++){
911 seqpat* s = tracks[i]->head->next;
912 while(s){
913 if(s->record_flag == 1){
914 s->record_flag = 0;
916 s = s->next;