Added basic metronome. Fixed a bug. Scope works.
The metronome widget ticks when playing or recording. The beats per measure affects the display of the metronome. Better graphics would be nice here. There was a bug in the song editor which failed to place new blocks correctly when not using 4 beats per measure. Fixed. The monitor callback which updates the midi scope now runs continuously. When not in playback mode, the callback runs generally ten times a second. In order to update widgets faster during playback it automatically speeds up to 100 times per second and returns to 10 after stopping.
This commit is contained in:
parent
a2b6c9662a
commit
ef99964d0f
|
@ -10,4 +10,5 @@ trackmodule.cpp util.cpp midi.cpp uihelper.cpp \
|
|||
saveload.cpp seq.h backend.h ui.h pianoroll.h \
|
||||
trackselect.h eventedit.h timeline.h sampleview.h \
|
||||
trackinfo.h arranger.h keyboard.h trackmodule.h \
|
||||
util.h midi.h uihelper.h saveload.h
|
||||
util.h midi.h uihelper.h saveload.h metronome.cpp \
|
||||
metronome.h
|
||||
|
|
|
@ -217,7 +217,8 @@ int Arranger::handle(int event){
|
|||
move_flag = 1;
|
||||
}
|
||||
if(new_drag){
|
||||
new_right_t = quantize(xpix2tick(event_x())+q_tick);
|
||||
//new_right_t = quantize(xpix2tick(event_x())) + quantize(q_tick);
|
||||
new_right_t = quantize(xpix2tick(event_x()+tick2xpix(q_tick)));
|
||||
if(new_right_t <= new_orig_t){
|
||||
new_left_t = new_right_t - quantize(q_tick);
|
||||
new_right_t = new_orig_t;
|
||||
|
@ -492,8 +493,7 @@ int Arranger::xpix2tick(int xpix){
|
|||
}
|
||||
|
||||
int Arranger::quantize(int tick){
|
||||
int M = config.beats_per_measure;
|
||||
return tick/(q_tick*M/4) * (q_tick*M/4);
|
||||
return tick/q_tick * q_tick;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define TICKS_PER_BEAT 128
|
||||
|
||||
int init_backend();
|
||||
int shutdown_backend();
|
||||
int start_backend();
|
||||
|
|
|
@ -70,7 +70,7 @@ static int cur_tick;
|
|||
static int last_tick;
|
||||
static int bpm = 120;
|
||||
static int new_bpm = 120;
|
||||
static int tpb = 128;
|
||||
static int tpb = TICKS_PER_BEAT;
|
||||
static int sample_rate = 0;
|
||||
static int frame_count = 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <fltk/Widget.h>
|
||||
#include <fltk/events.h>
|
||||
#include <fltk/draw.h>
|
||||
|
||||
#include "metronome.h"
|
||||
|
||||
using namespace fltk;
|
||||
|
||||
Metronome::Metronome(int x, int y, int w, int h, const char* label = 0) : fltk::Widget(x, y, w, h, label) {
|
||||
N = 4;
|
||||
n = 2;
|
||||
|
||||
last_beat = 0;
|
||||
plus = 0;
|
||||
|
||||
r=255; g=0; b=0;
|
||||
|
||||
update(0);
|
||||
}
|
||||
|
||||
int Metronome::handle(int event){
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Metronome::draw(){
|
||||
draw_box();
|
||||
|
||||
//setcolor(fltk::color(r,g,b));
|
||||
//fillrect(2,2,w()-4,h()-4);
|
||||
|
||||
setcolor(fltk::WHITE);
|
||||
int X = last_beat%N*(w()-4)/N+2;
|
||||
int W = (w()-4)/N;
|
||||
int H = h()-4;
|
||||
fillrect(X,2,W,h()-4);
|
||||
|
||||
//int W2 = W/2;
|
||||
//int H2 = H/2;
|
||||
//setcolor(fltk::color(r,g,b));
|
||||
//fillrect(X+W/2-W2/2,h()/2-H2/2,W2,H2);
|
||||
|
||||
//setcolor(fltk::BLACK);
|
||||
//int C = (getascent()-getdescent())/2;
|
||||
//drawtext(label(),X+W/2-getwidth(label())/2,h()/2+C);
|
||||
|
||||
}
|
||||
|
||||
//div N is the greatest divisor of N less than or equal to sqrt(N)
|
||||
int div(int N){
|
||||
int d = 0;
|
||||
for(int i=1; i<=sqrt(N); i++){
|
||||
if(N%i==0){
|
||||
d=i;
|
||||
}
|
||||
}
|
||||
if(d==1){
|
||||
//prime
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
void Metronome::update(int tick){
|
||||
int now_beat = tick/128;
|
||||
|
||||
if(now_beat != last_beat){
|
||||
int step = last_beat - now_beat;
|
||||
last_beat = now_beat;
|
||||
|
||||
char buf[16];
|
||||
snprintf(buf,16,"%d",now_beat%N + plus);
|
||||
copy_label(buf);
|
||||
|
||||
if(now_beat%N == 0){
|
||||
r=255; g=0; b=0;
|
||||
}
|
||||
else if(now_beat%n == 0){
|
||||
r=128; g=0; b=0;
|
||||
}
|
||||
else{
|
||||
r=0; g=0; b=0;
|
||||
}
|
||||
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void Metronome::set_N(int zN){
|
||||
N = zN;
|
||||
n = div(zN);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
class Metronome : public fltk::Widget {
|
||||
|
||||
int N, n;
|
||||
int last_beat;
|
||||
int plus;
|
||||
|
||||
unsigned char r,g,b;
|
||||
|
||||
public:
|
||||
|
||||
Metronome(int x, int y, int w, int h, const char* label);
|
||||
|
||||
int handle(int event);
|
||||
void draw();
|
||||
|
||||
void update(int tick);
|
||||
void set_N(int zN);
|
||||
|
||||
};
|
|
@ -478,7 +478,10 @@ UI::UI() {
|
|||
o->callback((fltk::Callback*)cb_record_button);
|
||||
o->type(fltk::Button::TOGGLE);
|
||||
}
|
||||
metronome = new fltk::Widget(125, 5, 25, 25, "metr");
|
||||
{Metronome* o = metronome = new Metronome(95, 5, 100, 25, "0");
|
||||
o->color((fltk::Color)56);
|
||||
o->labelcolor((fltk::Color)0xffffff00);
|
||||
}
|
||||
{fltk::Group* o = new fltk::Group(180, 0, 20, 35);
|
||||
o->set_vertical();
|
||||
fltk::Group::current()->resizable(o);
|
||||
|
@ -920,5 +923,6 @@ track.");
|
|||
qbutton0->image(fltk::SharedImage::get(ROOT_DATA_DIR"gfx/q0.gif"));
|
||||
track_info->set_rec(0);
|
||||
config_init();
|
||||
start_monitor();
|
||||
main_window->show();
|
||||
}
|
||||
|
|
10
src/ui.fl
10
src/ui.fl
|
@ -231,8 +231,10 @@ ui->song_buttons->show();}
|
|||
extra_code {o->type(fltk::Button::TOGGLE);}
|
||||
}
|
||||
{fltk::Widget} metronome {
|
||||
label metr
|
||||
xywh {125 5 25 25}
|
||||
label 0
|
||||
xywh {95 5 100 25} color 56 labelcolor 0xffffff00
|
||||
extra_code {\#include <metronome.h>}
|
||||
class Metronome
|
||||
}
|
||||
{fltk::Group} {} {
|
||||
xywh {180 0 20 35} resizable
|
||||
|
@ -757,7 +759,7 @@ savesmf(fltk::file_chooser("export file",NULL,get_last_dir()));}
|
|||
}
|
||||
}
|
||||
{fltk::Window} scope_window {
|
||||
label scope selected
|
||||
label scope
|
||||
xywh {647 310 425 280} hide resizable
|
||||
} {
|
||||
{fltk::TextDisplay} scope {
|
||||
|
@ -785,6 +787,8 @@ qbutton128->image(fltk::SharedImage::get(ROOT_DATA_DIR"gfx/q128.gif"));
|
|||
qbutton0->image(fltk::SharedImage::get(ROOT_DATA_DIR"gfx/q0.gif"));} {}
|
||||
code {track_info->set_rec(0);} {}
|
||||
code {config_init();} {}
|
||||
code {start_monitor();} {selected
|
||||
}
|
||||
code {main_window->show();} {}
|
||||
}
|
||||
}
|
||||
|
|
4
src/ui.h
4
src/ui.h
|
@ -18,7 +18,7 @@
|
|||
#include "trackselect.h"
|
||||
#include "sampleview.h"
|
||||
#include "keyboard.h"
|
||||
#include <fltk/Widget.h>
|
||||
#include <metronome.h>
|
||||
#include "saveload.h"
|
||||
#include <fltk/TabGroup.h>
|
||||
#include <fltk/ValueInput.h>
|
||||
|
@ -75,7 +75,7 @@ private:
|
|||
inline void cb_record_button_i(fltk::Button*, void*);
|
||||
static void cb_record_button(fltk::Button*, void*);
|
||||
public:
|
||||
fltk::Widget *metronome;
|
||||
Metronome *metronome;
|
||||
fltk::Group *pattern_buttons;
|
||||
fltk::Button *qbutton4;
|
||||
private:
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <fltk/run.h>
|
||||
|
||||
#include "seq.h"
|
||||
|
@ -54,13 +56,18 @@ void config_init(){
|
|||
config.robmode = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void playing_timeout_cb(void* v){
|
||||
if(!is_backend_playing()){
|
||||
return;
|
||||
}
|
||||
//if(!is_backend_playing()){
|
||||
// return;
|
||||
//}
|
||||
|
||||
int pos = get_play_position();
|
||||
ui->song_timeline->update(pos);
|
||||
ui->pattern_timeline->update(pos);
|
||||
ui->metronome->update(pos);
|
||||
if(config.follow){
|
||||
ui->arranger->update(pos);
|
||||
ui->piano_roll->update(pos);
|
||||
|
@ -72,7 +79,7 @@ void playing_timeout_cb(void* v){
|
|||
int type;
|
||||
int val1;
|
||||
int val2;
|
||||
|
||||
|
||||
track* t = tracks[get_rec_track()];
|
||||
Command* c;
|
||||
seqpat* s;
|
||||
|
@ -239,14 +246,25 @@ void playing_timeout_cb(void* v){
|
|||
}
|
||||
|
||||
}
|
||||
fltk::repeat_timeout(0.01, playing_timeout_cb, NULL);
|
||||
|
||||
if(is_backend_playing()){
|
||||
fltk::repeat_timeout(0.01, playing_timeout_cb, NULL);
|
||||
}
|
||||
else{
|
||||
fltk::repeat_timeout(0.1, playing_timeout_cb, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void start_monitor(){
|
||||
printf("started\n");
|
||||
fltk::add_timeout(0.1, playing_timeout_cb, NULL);
|
||||
}
|
||||
|
||||
void press_play(){
|
||||
if(!is_backend_playing()){
|
||||
start_backend();
|
||||
ui->play_button->label("@||");
|
||||
fltk::add_timeout(0.01, playing_timeout_cb, NULL);
|
||||
//fltk::add_timeout(0.01, playing_timeout_cb, NULL);
|
||||
}
|
||||
else{
|
||||
pause_backend();
|
||||
|
@ -277,6 +295,8 @@ void press_stop(){
|
|||
ui->play_button->label("@>");
|
||||
ui->play_button->redraw();
|
||||
|
||||
ui->metronome->update(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -358,8 +378,10 @@ void set_quant(int q){
|
|||
|
||||
void set_beats_per_measure(int n){
|
||||
config.beats_per_measure = n;
|
||||
ui->metronome->set_N(n);
|
||||
ui->piano_roll->redraw();
|
||||
ui->arranger->redraw();
|
||||
ui->arranger->q_tick = n*TICKS_PER_BEAT;
|
||||
ui->song_timeline->redraw();
|
||||
ui->pattern_timeline->redraw();
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ struct conf{
|
|||
};
|
||||
|
||||
void config_init();
|
||||
|
||||
void start_monitor();
|
||||
|
||||
void press_stop();
|
||||
void press_panic();
|
||||
|
|
Loading…
Reference in New Issue