Virtual keyboard experience upgraded.
Keyboard keys light up when you press them. Hold space bar to enable sustain. Inserting notes or moving notes plays the keyboard. Sensor regions were adjusted by 1 pixel. Now it is better. Horizontal rule at C. Bright horizontal rule indicates middle C.
This commit is contained in:
parent
ca0c42881d
commit
b952ecad61
|
@ -40,7 +40,7 @@ using namespace fltk;
|
|||
|
||||
Keyboard::Keyboard(int x, int y, int w, int h, const char* label = 0) : fltk::Widget(x, y, w, h, label) {
|
||||
sustain = 0;
|
||||
cur_note = 60;
|
||||
cur_note = -1;
|
||||
fltk::add_event_handler(keyboard_handler);
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,9 @@ int keyboard_handler(int e, fltk::Window* w){
|
|||
return 0;
|
||||
}
|
||||
switch(event_key()){
|
||||
case fltk::SpaceKey:
|
||||
ui->keyboard->set_sustain(1);
|
||||
break;
|
||||
case '[':
|
||||
//printf("octave down\n");
|
||||
break;
|
||||
|
@ -76,6 +79,9 @@ int keyboard_handler(int e, fltk::Window* w){
|
|||
return 1;
|
||||
case fltk::KEYUP:
|
||||
switch(event_key()){
|
||||
case fltk::SpaceKey:
|
||||
ui->keyboard->set_sustain(0);
|
||||
break;
|
||||
case 'q':
|
||||
//printf("C off\n");
|
||||
break;
|
||||
|
@ -102,17 +108,36 @@ void note_on(int note, int vel, int channel){
|
|||
|
||||
}
|
||||
|
||||
void Keyboard::set_sustain(int state){
|
||||
sustain=state;
|
||||
if(state==0){
|
||||
for(int i=0; i<128; i++){
|
||||
if(ons[i]==1 && cur_note!=i){
|
||||
ons[i]=0;
|
||||
midi_note_off(i,cur_chan,cur_port);
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
int Keyboard::handle(int event){
|
||||
char buf[16];
|
||||
int note;
|
||||
switch(event){
|
||||
case fltk::FOCUS:
|
||||
return 1;
|
||||
case fltk::PUSH:
|
||||
take_focus();
|
||||
note = ypix2note(event_y()+scroll, event_x() < w()/2 ? 1 : 0);
|
||||
play_note(note);
|
||||
redraw();
|
||||
return 1;
|
||||
case fltk::RELEASE:
|
||||
cur_note=-1;
|
||||
if(sustain == 0){
|
||||
cut_notes();
|
||||
redraw();
|
||||
}
|
||||
return 1;
|
||||
case fltk::DRAG:
|
||||
|
@ -122,6 +147,7 @@ int Keyboard::handle(int event){
|
|||
cut_notes();
|
||||
}
|
||||
play_note(note);
|
||||
redraw();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -129,21 +155,26 @@ int Keyboard::handle(int event){
|
|||
}
|
||||
|
||||
void Keyboard::play_note(int note){
|
||||
if(ons[note]==1){
|
||||
return;
|
||||
}
|
||||
cur_note = note;
|
||||
char buf[3];
|
||||
buf[0] = 0x90 | cur_chan;
|
||||
buf[1] = note;
|
||||
buf[2] = 0x7f;
|
||||
send_midi(buf,3,cur_port);
|
||||
|
||||
ons[note] = 1;
|
||||
}
|
||||
|
||||
void Keyboard::cut_notes(){
|
||||
//if sustain needs to cut all playing notes
|
||||
char buf[3];
|
||||
buf[0] = 0x80 | cur_chan;
|
||||
buf[1] = cur_note;
|
||||
buf[2] = 0x00;
|
||||
send_midi(buf,3,cur_port);
|
||||
for(int i=0; i<128; i++){
|
||||
if(ons[i]){
|
||||
ons[i] = 0;
|
||||
midi_note_off(i,cur_chan,cur_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -153,6 +184,18 @@ void Keyboard::draw(){
|
|||
|
||||
fltk::push_clip(0,0,w(),h());
|
||||
|
||||
//draw held white notes
|
||||
int black;
|
||||
for(int i=0; i<128; i++){
|
||||
if(ons[i]){
|
||||
int Y = note2ypix(i,&black)-scroll;
|
||||
if(!black){
|
||||
fltk::setcolor(fltk::GRAY50);
|
||||
fltk::fillrect(0,Y,w(),12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fltk::setcolor(fltk::BLACK);
|
||||
for(int i=-scroll; i<h(); i+=12){
|
||||
fltk::drawline(0,i,w(),i);
|
||||
|
@ -171,6 +214,17 @@ void Keyboard::draw(){
|
|||
}
|
||||
}
|
||||
|
||||
//draw held black notes
|
||||
for(int i=0; i<128; i++){
|
||||
if(ons[i]){
|
||||
int Y = note2ypix(i,&black)-scroll;
|
||||
if(black){
|
||||
fltk::setcolor(fltk::GRAY70);
|
||||
fltk::fillrect(1,Y+1,w()/2 - 2,5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fltk::pop_clip();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ class Keyboard : public fltk::Widget {
|
|||
int cur_note;
|
||||
int sustain;
|
||||
|
||||
char ons[128];
|
||||
|
||||
public:
|
||||
int cur_port;
|
||||
int cur_chan;
|
||||
|
@ -38,7 +40,7 @@ class Keyboard : public fltk::Widget {
|
|||
|
||||
void play_note(int note);
|
||||
void cut_notes();
|
||||
void set_sustain(int state){sustain = state;}
|
||||
void set_sustain(int state);
|
||||
|
||||
int handle(int event);
|
||||
void draw();
|
||||
|
|
|
@ -87,13 +87,20 @@ int PianoRoll::handle(int event){
|
|||
}
|
||||
return 0;
|
||||
case fltk::PUSH:
|
||||
take_focus();
|
||||
if(event_button()==1){//left mouse
|
||||
if(over_note()==NULL){//begin pattern creation
|
||||
if(over_note()==NULL){//new note init
|
||||
new_drag = 1;
|
||||
new_left_t = quantize(xpix2tick(event_x()));
|
||||
new_orig_t = new_left_t;
|
||||
new_note = ypix2note(event_y(),1);
|
||||
new_right_t = new_left_t + q_tick;
|
||||
|
||||
last_note = new_note;
|
||||
if(1){//play on insert
|
||||
ui->keyboard->play_note(last_note);
|
||||
ui->keyboard->redraw();
|
||||
}
|
||||
}
|
||||
else{
|
||||
//if shift, add to selection
|
||||
|
@ -106,6 +113,12 @@ int PianoRoll::handle(int event){
|
|||
move_offset = quantize(xpix2tick(event_x())) - move_t;
|
||||
//move_track = event_y() / 30;
|
||||
move_note = ypix2note(event_y(),1);
|
||||
|
||||
last_note = move_note;
|
||||
if(1){//play on move
|
||||
ui->keyboard->play_note(last_note);
|
||||
ui->keyboard->redraw();
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
}
|
||||
|
@ -135,12 +148,28 @@ int PianoRoll::handle(int event){
|
|||
new_left_t = new_orig_t;
|
||||
}
|
||||
new_note = ypix2note(event_y(),1);
|
||||
if(new_note != last_note){
|
||||
last_note = new_note;
|
||||
if(1){//play on insert
|
||||
ui->keyboard->cut_notes();
|
||||
ui->keyboard->play_note(last_note);
|
||||
ui->keyboard->redraw();
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
return 1;
|
||||
}
|
||||
else if(move_flag){
|
||||
move_t = quantize(xpix2tick(event_x())) - move_offset;
|
||||
move_note = ypix2note(event_y(),1);
|
||||
if(move_note != last_note){
|
||||
last_note = move_note;
|
||||
if(1){//play on move
|
||||
ui->keyboard->cut_notes();
|
||||
ui->keyboard->play_note(last_note);
|
||||
ui->keyboard->redraw();
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
return 1;
|
||||
}
|
||||
|
@ -151,6 +180,8 @@ int PianoRoll::handle(int event){
|
|||
c=new CreateNote(p,new_note,new_left_t,new_right_t-new_left_t);
|
||||
set_undo(c);
|
||||
undo_push(1);
|
||||
ui->keyboard->cut_notes();
|
||||
ui->keyboard->redraw();
|
||||
}
|
||||
else if(move_flag && move_note < 128 && move_note >= 0){
|
||||
int play_pos = get_play_position();
|
||||
|
@ -167,6 +198,9 @@ int PianoRoll::handle(int event){
|
|||
int cur_chan = tracks[cur_seqpat->track]->chan;
|
||||
int cur_port = tracks[cur_seqpat->track]->port;
|
||||
midi_note_off(old_note,cur_chan,cur_port);
|
||||
|
||||
ui->keyboard->cut_notes();
|
||||
ui->keyboard->redraw();
|
||||
}
|
||||
new_drag=0;
|
||||
move_flag=0;
|
||||
|
@ -198,12 +232,18 @@ void PianoRoll::draw(){
|
|||
fltk::drawline(i,0,i,h());
|
||||
}
|
||||
|
||||
fltk::setcolor(fltk::GRAY30);
|
||||
for(int i=12*5; i<h(); i+=12*7){
|
||||
fltk::drawline(0,i,w(),i);
|
||||
}
|
||||
|
||||
fltk::setcolor(fltk::GRAY50);
|
||||
for(int i=zoom*4; i<w(); i+=zoom*4){
|
||||
fltk::drawline(i,0,i,h());
|
||||
}
|
||||
|
||||
|
||||
fltk::setcolor(fltk::color(128,128,0));
|
||||
fltk::drawline(0,12*40,w(),12*40);
|
||||
|
||||
if(new_drag){
|
||||
fltk::setcolor(fltk::BLUE);
|
||||
|
|
|
@ -32,6 +32,8 @@ class PianoRoll : public fltk::Widget {
|
|||
int wkeyh;
|
||||
int bkeyh;
|
||||
|
||||
int last_note;
|
||||
|
||||
int new_left_t;
|
||||
int new_right_t;
|
||||
int new_orig_t;
|
||||
|
|
25
src/util.cpp
25
src/util.cpp
|
@ -93,20 +93,29 @@ void hsv_to_rgb(float h, float s, float v, unsigned char* r, unsigned char* g, u
|
|||
|
||||
|
||||
int ypix2note(int ypix, int black){
|
||||
int udy = 900 - ypix + 2;
|
||||
int udy = 900 - ypix + 1;
|
||||
int white = udy/12;
|
||||
int note = 2*white - white/7 - (white+4)/7;
|
||||
|
||||
//printf("white %d\n",white);
|
||||
//printf("wmidi %d\n",note);
|
||||
//printf("udy%12 = %d\n",udy%12);
|
||||
|
||||
if(black){
|
||||
if(udy%12<3 && white%7!=0 && (white+4)%7!=0){note--;}
|
||||
else if(udy%12>9 && (white+1)%7!=0 && (white+5)%7!=0){note++;}
|
||||
if(udy%12<4 && white%7!=0 && (white+4)%7!=0){note--;}
|
||||
else if(udy%12>8 && (white+1)%7!=0 && (white+5)%7!=0){note++;}
|
||||
}
|
||||
|
||||
//printf("total midi %d\n",note);
|
||||
return note;
|
||||
}
|
||||
|
||||
int note2ypix(int note, int* black){
|
||||
int key = (note + (note+7)/12 + note/12)/2;
|
||||
|
||||
if((note + (note+7)/12 + note/12)%2 == 0){//white key
|
||||
*black=0;
|
||||
return 900 - key*12 - 12;
|
||||
}
|
||||
else{//black key
|
||||
*black=1;
|
||||
return 900 - key*12 - 12 - 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -29,5 +29,6 @@ void load_text(fltk::TextDisplay* o, const char* filename);
|
|||
void hsv_to_rgb(float h, float s, float v, unsigned char* r, unsigned char* g, unsigned char* b);
|
||||
|
||||
int ypix2note(int ypix, int black);
|
||||
int note2ypix(int note, int* black);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue