Unhardcoded ticks per beat. Fixed triplet bugs.
[epichord.git] / src / timeline.cpp
blob365eaf8fa8cbafb202577bd7b6beec6c47e6bd9d
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 <stdio.h>
24 #include <unistd.h>
26 #include <fltk/Group.h>
27 #include <fltk/Widget.h>
28 #include <fltk/events.h>
32 #include "ui.h"
33 extern UI* ui;
35 #include "backend.h"
37 #include "config.h"
39 #include "uihelper.h"
41 extern struct conf config;
43 using namespace fltk;
45 Timeline::Timeline(int x, int y, int w, int h, const char* label = 0) : fltk::Widget(x, y, w, h, label) {
46 hand = fltk::SharedImage::get(ROOT_DATA_DIR"gfx/hand.gif");
47 if(!hand){
48 printf("Timeline: gfx files not found, installed correctly?\n");
50 scale = 1;
51 label_scale = 1;
52 zoom = 30;
53 ticks_offset = 0;
54 edit_flag = 0;
56 px_last = 0;
58 scroll=0;
61 int Timeline::handle(int event){
63 int tick;
65 switch(event){
66 case fltk::FOCUS:
67 return 1;
68 case fltk::PUSH:
69 take_focus();
70 if(event_button() == 1){//set left limit
71 //pixel -> tick -> quantize -> global tick
72 tick = quantize(xpix2tick(event_x())*scale/4);
73 //printf("%d %d %d\n",tick,loop_start,loop_end);
74 if(tick < get_loop_end()){
75 set_loop_start(tick);
78 else if(event_button() == 2){//set song position
79 tick = quantize(xpix2tick(event_x())*scale/4);
80 //printf("%d %d %d\n",tick,loop_start,loop_end);
81 //pointer_x = tick2xpix(tick);
82 ui->song_timeline->update(tick);
83 ui->pattern_timeline->update(tick);
84 all_notes_off();
85 reset_backend(tick);
86 ui->song_timeline->redraw();
87 ui->pattern_timeline->redraw();
89 else if(event_button() == 3){//set right limit
90 tick = quantize(xpix2tick(event_x())*scale/4);
91 //printf("%d %d %d\n",tick,loop_start,loop_end);
92 if(tick > get_loop_start()){
93 set_loop_end(tick);
96 redraw();
97 return 1;
99 return 0;
102 void Timeline::draw(){
104 fltk::setfont(fltk::HELVETICA,12);
105 fltk::setcolor(fltk::WHITE);
106 fltk::fillrect(0,0,w(),h());
108 fltk::push_clip(0,0,w(),h());
109 fltk::setcolor(fltk::BLACK);
110 fltk::drawline(0,h()-1,w()-1,h()-1);
112 if(edit_flag){//draw pattern timeline
114 int M = config.beats_per_measure;
116 int I=0;
117 for(int i=0; I<w(); i++){
118 I = i*zoom - scroll;
119 if(I>=0){
120 fltk::fillrect(I,h()/2,1,h()/2);
124 fltk::setcolor(fltk::BLACK);
126 char buf[64];
127 int j = 0;
129 I=0;
130 for(int i=0; I<w(); i++){
131 I = i*zoom*4 - scroll;
132 if(I>=0){
133 fltk::fillrect(I,0,1,h()/2);
134 sprintf(buf,"%u",j*label_scale);
135 fltk::drawtext(buf,I+3,h()-3);
137 j++;
141 else{//draw song timeline
143 int M = config.beats_per_measure;
144 int P = config.measures_per_phrase;
145 int I=0;
146 for(int i=0; I<w(); i++){
147 I = i*zoom*M/4 - scroll;
148 if(I>=0){
149 fltk::fillrect(I,h()/2,1,h()/2);
153 fltk::setcolor(fltk::BLACK);
155 char buf[64];
156 int j = 0;
158 int p = P>0 ? P : 4;
159 I=0;
160 for(int i=0; I<w(); i++){
161 I = i*zoom*4*p*M/4/4 - scroll;
162 if(I>=0){
163 fltk::fillrect(I,0,1,h()/2);
164 sprintf(buf,"%u",j*label_scale*p/4);
165 fltk::drawtext(buf,I+3,h()-3);
167 j++;
172 int X = tick2xpix(get_loop_start()*4/scale);
173 if(X >= -10){
174 fltk::setcolor(fltk::color(0,0,255));
175 fillrect(X+0,0,1,h()-1);
176 fltk::setcolor(fltk::color(85,85,255));
177 fillrect(X+1,0,1,h()-1);
178 fltk::setcolor(fltk::color(170,170,255));
179 fillrect(X+2,0,1,h()-1);
182 X = tick2xpix(get_loop_end()*4/scale);
183 if(X >= -10){
184 fltk::setcolor(fltk::color(128,0,0));
185 fillrect(X+0,0,1,h()-1);
186 fltk::setcolor(fltk::color(170,42,42));
187 fillrect(X-1,0,1,h()-1);
188 fltk::setcolor(fltk::color(255,170,170));
189 fillrect(X-2,0,1,h()-1);
192 if(hand && pointer_x*4/scale-scroll-10 >= -20){
193 hand->draw(pointer_x*4/scale-scroll-10,h()-19);
196 fltk::pop_clip();
201 void Timeline::update(int ticks){
202 //printf("%d\n",ticks);
203 pointer_x = (ticks/16 - ticks_offset/16) * zoom / 8;
204 if(pointer_x != px_last && ticks != get_loop_end()){
205 px_last = pointer_x;
206 redraw();
210 int Timeline::tick2xpix(int tick){
211 //return (tick - ticks_offset) * zoom / 128 - scroll;
212 return tick * zoom / TICKS_PER_BEAT - scroll - ticks_offset*zoom/(32);
215 int Timeline::xpix2tick(int xpix){
216 //return (xpix+scroll+ticks_offset*32/zoom)*128 / zoom;
217 return (xpix+scroll) * TICKS_PER_BEAT / zoom + ticks_offset*120/30;
220 int Timeline::quantize(int tick){
221 return tick/TICKS_PER_BEAT * TICKS_PER_BEAT;