Rough-in gtk-pianokeyboard C -> C++
This commit is contained in:
parent
7664f8fd29
commit
3f2f517291
|
@ -88,7 +88,6 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrol
|
||||||
, is_scrollable(scrollable)
|
, is_scrollable(scrollable)
|
||||||
, _plugin_pianokeyboard_expander (_("MIDI Keyboard"))
|
, _plugin_pianokeyboard_expander (_("MIDI Keyboard"))
|
||||||
, _piano (0)
|
, _piano (0)
|
||||||
, _pianomm (0)
|
|
||||||
, _piano_velocity (*manage (new Adjustment (100, 1, 127, 1, 16)))
|
, _piano_velocity (*manage (new Adjustment (100, 1, 127, 1, 16)))
|
||||||
, _piano_channel (*manage (new Adjustment (0, 1, 16, 1, 1)))
|
, _piano_channel (*manage (new Adjustment (0, 1, 16, 1, 1)))
|
||||||
{
|
{
|
||||||
|
@ -140,13 +139,11 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrol
|
||||||
VBox* v1_box = manage (new VBox);
|
VBox* v1_box = manage (new VBox);
|
||||||
VBox* v2_box = manage (new VBox);
|
VBox* v2_box = manage (new VBox);
|
||||||
if (pi->is_instrument ()) {
|
if (pi->is_instrument ()) {
|
||||||
_piano = (PianoKeyboard*)piano_keyboard_new();
|
_piano = new PianoKeyboard ();
|
||||||
_pianomm = Glib::wrap((GtkWidget*)_piano);
|
_piano->set_flags(Gtk::CAN_FOCUS);
|
||||||
_pianomm->set_flags(Gtk::CAN_FOCUS);
|
|
||||||
_pianomm->add_events(Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
|
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (_piano), "note-on", G_CALLBACK (GenericPluginUI::_note_on_event_handler), this);
|
_piano->NoteOn.connect (sigc::mem_fun (*this, &GenericPluginUI::note_on_event_handler));
|
||||||
g_signal_connect (G_OBJECT (_piano), "note-off", G_CALLBACK (GenericPluginUI::_note_off_event_handler), this);
|
_piano->NoteOff.connect (sigc::mem_fun (*this, &GenericPluginUI::note_off_event_handler));
|
||||||
|
|
||||||
HBox* box = manage (new HBox);
|
HBox* box = manage (new HBox);
|
||||||
box->pack_start (*manage (new Label (_("Channel:"))), false, false);
|
box->pack_start (*manage (new Label (_("Channel:"))), false, false);
|
||||||
|
@ -159,7 +156,7 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrol
|
||||||
|
|
||||||
_pianobox.set_spacing (4);
|
_pianobox.set_spacing (4);
|
||||||
_pianobox.pack_start (*box2, true, true);
|
_pianobox.pack_start (*box2, true, true);
|
||||||
_pianobox.pack_start (*_pianomm, true, true);
|
_pianobox.pack_start (*_piano, true, true);
|
||||||
|
|
||||||
_plugin_pianokeyboard_expander.set_expanded(false);
|
_plugin_pianokeyboard_expander.set_expanded(false);
|
||||||
_plugin_pianokeyboard_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &GenericPluginUI::toggle_pianokeyboard));
|
_plugin_pianokeyboard_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &GenericPluginUI::toggle_pianokeyboard));
|
||||||
|
@ -236,7 +233,7 @@ GenericPluginUI::~GenericPluginUI ()
|
||||||
screen_update_connection.disconnect();
|
screen_update_connection.disconnect();
|
||||||
}
|
}
|
||||||
delete automation_menu;
|
delete automation_menu;
|
||||||
delete _pianomm;
|
delete _piano;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1392,22 +1389,10 @@ GenericPluginUI::toggle_pianokeyboard ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GenericPluginUI::_note_on_event_handler(GtkWidget*, int note, int, gpointer arg)
|
GenericPluginUI::note_on_event_handler (int note, int)
|
||||||
{
|
|
||||||
((GenericPluginUI*)arg)->note_on_event_handler(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GenericPluginUI::_note_off_event_handler(GtkWidget*, int note, gpointer arg)
|
|
||||||
{
|
|
||||||
((GenericPluginUI*)arg)->note_off_event_handler(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GenericPluginUI::note_on_event_handler (int note)
|
|
||||||
{
|
{
|
||||||
MidiTrack* mt = dynamic_cast<MidiTrack*> (insert->owner());
|
MidiTrack* mt = dynamic_cast<MidiTrack*> (insert->owner());
|
||||||
_pianomm->grab_focus ();
|
_piano->grab_focus ();
|
||||||
uint8_t channel = _piano_channel.get_value_as_int () - 1;
|
uint8_t channel = _piano_channel.get_value_as_int () - 1;
|
||||||
uint8_t event[3];
|
uint8_t event[3];
|
||||||
event[0] = (MIDI_CMD_NOTE_ON | channel);
|
event[0] = (MIDI_CMD_NOTE_ON | channel);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
994
gtk2_ardour/gtk_pianokeyboard.cc
Normal file
994
gtk2_ardour/gtk_pianokeyboard.cc
Normal file
|
@ -0,0 +1,994 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2007, 2008 Edward Tomasz Napierała <trasz@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is piano_keyboard, piano keyboard-like GTK+ widget. It contains
|
||||||
|
* no MIDI-specific code.
|
||||||
|
*
|
||||||
|
* For questions and comments, contact Edward Tomasz Napierala <trasz@FreeBSD.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <cairo/cairo.h>
|
||||||
|
#include <pango/pango.h>
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
|
#include <gdk/gdkkeysyms.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#include "gtk_pianokeyboard.h"
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
# define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
# define MIN(A, B) ((A) < (B)) ? (A) : (B)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
# define MAX(A, B) ((A) > (B)) ? (A) : (B)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PIANO_KEYBOARD_DEFAULT_WIDTH 730
|
||||||
|
#define PIANO_KEYBOARD_DEFAULT_HEIGHT 70
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::draw_keyboard_cue (cairo_t* cr, int note)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
int w = _notes[0].w;
|
||||||
|
int h = _notes[0].h;
|
||||||
|
|
||||||
|
int first_note_in_lower_row = (_octave + 1) * 12;
|
||||||
|
int last_note_in_lower_row = (_octave + 2) * 12 - 1;
|
||||||
|
int first_note_in_higher_row = (_octave + 2) * 12;
|
||||||
|
int last_note_in_higher_row = (_octave + 3) * 12 + 4;
|
||||||
|
|
||||||
|
first_note_in_lower_row = MIN (127, MAX (0, first_note_in_lower_row));
|
||||||
|
last_note_in_lower_row = MIN (127, MAX (0, last_note_in_lower_row));
|
||||||
|
first_note_in_higher_row = MIN (127, MAX (0, first_note_in_higher_row));
|
||||||
|
last_note_in_higher_row = MIN (127, MAX (0, last_note_in_higher_row));
|
||||||
|
|
||||||
|
cairo_set_source_rgb (cr, 1.0f, 0.0f, 0.0f);
|
||||||
|
cairo_move_to (cr, _notes[first_note_in_lower_row].x + 3, h - 6);
|
||||||
|
cairo_line_to (cr, _notes[last_note_in_lower_row].x + w - 3, h - 6);
|
||||||
|
cairo_stroke (cr);
|
||||||
|
|
||||||
|
cairo_set_source_rgb (cr, 0.0f, 0.0f, 1.0f);
|
||||||
|
cairo_move_to (cr, _notes[first_note_in_higher_row].x + 3, h - 9);
|
||||||
|
cairo_line_to (cr, _notes[last_note_in_higher_row].x + w - 3, h - 9);
|
||||||
|
cairo_stroke (cr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int nkey = note - _octave * 12;
|
||||||
|
if (nkey < 0 || nkey >= NNOTES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_note_bindings.find (nkey) == _note_bindings.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Cache PangoFontDescription for each expose call.
|
||||||
|
// TODO display above note/octave label if both are visible
|
||||||
|
int is_white = _notes[note].white;
|
||||||
|
int x = _notes[note].x;
|
||||||
|
int w = _notes[note].w;
|
||||||
|
int h = _notes[note].h;
|
||||||
|
|
||||||
|
int tw, th;
|
||||||
|
char buf[32];
|
||||||
|
sprintf (buf, "ArdourMono %dpx", MAX (8, MIN (20, w / 2 + 3)));
|
||||||
|
PangoFontDescription* font = pango_font_description_from_string (buf);
|
||||||
|
snprintf(buf, 16, "%lc", gdk_keyval_to_unicode (gdk_keyval_to_upper (gdk_keyval_from_name (_note_bindings[nkey].c_str()))));
|
||||||
|
PangoLayout* pl = pango_cairo_create_layout (cr);
|
||||||
|
pango_layout_set_font_description (pl, font);
|
||||||
|
pango_layout_set_text (pl, buf, -1);
|
||||||
|
pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT);
|
||||||
|
pango_layout_get_pixel_size (pl, &tw, &th);
|
||||||
|
|
||||||
|
if (is_white) {
|
||||||
|
cairo_set_source_rgba (cr, 0.0, 0.0, 0.5, 1.0);
|
||||||
|
} else {
|
||||||
|
cairo_set_source_rgba (cr, 1.0, 1.0, 0.5, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tw < w) {
|
||||||
|
cairo_save (cr);
|
||||||
|
cairo_move_to (cr, x + (w - tw) / 2, h - th - 5);
|
||||||
|
pango_cairo_show_layout (cr, pl);
|
||||||
|
cairo_restore (cr);
|
||||||
|
}
|
||||||
|
g_object_unref (pl);
|
||||||
|
pango_font_description_free (font);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::queue_note_draw (int note)
|
||||||
|
{
|
||||||
|
Gdk::Rectangle rect;
|
||||||
|
Glib::RefPtr<Gdk::Window> win = get_window();
|
||||||
|
|
||||||
|
rect.set_x (_notes[note].x);
|
||||||
|
rect.set_y (0);
|
||||||
|
rect.set_width (_notes[note].w);
|
||||||
|
rect.set_height (_notes[note].h);
|
||||||
|
|
||||||
|
win->invalidate_rect(rect, true); // -> queue_draw_area ()
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::draw_note (cairo_t* cr, int note)
|
||||||
|
{
|
||||||
|
if (note < _min_note || note > _max_note) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_white = _notes[note].white;
|
||||||
|
int x = _notes[note].x;
|
||||||
|
int w = _notes[note].w;
|
||||||
|
int h = _notes[note].h;
|
||||||
|
|
||||||
|
if (_notes[note].pressed || _notes[note].sustained) {
|
||||||
|
if (is_white) {
|
||||||
|
cairo_set_source_rgb (cr, 0.7, 0.5, 0.5);
|
||||||
|
} else {
|
||||||
|
cairo_set_source_rgb (cr, 0.6, 0.4, 0.4);
|
||||||
|
}
|
||||||
|
} else if (_highlight_grand_piano_range && (note < PIANO_MIN_NOTE || note > PIANO_MAX_NOTE)) {
|
||||||
|
if (is_white) {
|
||||||
|
cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
|
||||||
|
} else {
|
||||||
|
cairo_set_source_rgb (cr, 0.3, 0.3, 0.3);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (is_white) {
|
||||||
|
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
||||||
|
} else {
|
||||||
|
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_set_line_width (cr, 1.0);
|
||||||
|
|
||||||
|
cairo_rectangle (cr, x, 0, w, h);
|
||||||
|
cairo_fill (cr);
|
||||||
|
|
||||||
|
cairo_set_source_rgb (cr, 0.0f, 0.0f, 0.0f); /* black outline */
|
||||||
|
cairo_rectangle (cr, x, 0, w, h);
|
||||||
|
cairo_stroke (cr);
|
||||||
|
|
||||||
|
if (_enable_keyboard_cue) {
|
||||||
|
draw_keyboard_cue (cr, note);
|
||||||
|
}
|
||||||
|
else if (_print_note_label && (note % 12) == 0) {
|
||||||
|
int tw, th;
|
||||||
|
char buf[32];
|
||||||
|
sprintf (buf, "ArdourMono %dpx", MAX (10, MIN (20, MIN (w / 2 + 3, h / 7))));
|
||||||
|
PangoFontDescription* font = pango_font_description_from_string (buf);
|
||||||
|
sprintf (buf, "C%2d", (note / 12) - 1);
|
||||||
|
PangoLayout* pl = pango_cairo_create_layout (cr);
|
||||||
|
pango_layout_set_font_description (pl, font);
|
||||||
|
pango_layout_set_text (pl, buf, -1);
|
||||||
|
pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT);
|
||||||
|
pango_layout_get_pixel_size (pl, &tw, &th);
|
||||||
|
|
||||||
|
if (th < w && tw < h * .3) {
|
||||||
|
cairo_save (cr);
|
||||||
|
cairo_move_to (cr, x + (w - th) / 2, h - 3);
|
||||||
|
cairo_rotate (cr, M_PI / -2.0);
|
||||||
|
cairo_set_source_rgba (cr, .0, .0, .0, 1.0);
|
||||||
|
pango_cairo_show_layout (cr, pl);
|
||||||
|
cairo_restore (cr);
|
||||||
|
}
|
||||||
|
g_object_unref (pl);
|
||||||
|
pango_font_description_free (font);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to redraw black keys that partially obscure the white one. */
|
||||||
|
if (note < NNOTES - 2 && !_notes[note + 1].white) {
|
||||||
|
draw_note (cr, note + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (note > 0 && !_notes[note - 1].white) {
|
||||||
|
draw_note (cr, note - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PianoKeyboard::press_key (int key, int vel)
|
||||||
|
{
|
||||||
|
assert (key >= 0);
|
||||||
|
assert (key < NNOTES);
|
||||||
|
|
||||||
|
_maybe_stop_sustained_notes = false;
|
||||||
|
|
||||||
|
/* This is for keyboard autorepeat protection. */
|
||||||
|
if (_notes[key].pressed)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (_sustain_new_notes) {
|
||||||
|
_notes[key].sustained = 1;
|
||||||
|
} else {
|
||||||
|
_notes[key].sustained = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_monophonic && _last_key != key) {
|
||||||
|
_notes[_last_key].pressed = 0;
|
||||||
|
_notes[_last_key].sustained = 0;
|
||||||
|
queue_note_draw (_last_key);
|
||||||
|
}
|
||||||
|
_last_key = key;
|
||||||
|
|
||||||
|
_notes[key].pressed = 1;
|
||||||
|
|
||||||
|
NoteOn (key, vel); /* EMIT SIGNAL */
|
||||||
|
queue_note_draw (key);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PianoKeyboard::release_key (int key)
|
||||||
|
{
|
||||||
|
assert (key >= 0);
|
||||||
|
assert (key < NNOTES);
|
||||||
|
|
||||||
|
_maybe_stop_sustained_notes = false;
|
||||||
|
|
||||||
|
if (!_notes[key].pressed)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (_sustain_new_notes) {
|
||||||
|
_notes[key].sustained = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_notes[key].pressed = 0;
|
||||||
|
|
||||||
|
if (_notes[key].sustained)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
NoteOff (key); /* EMIT SIGNAL */
|
||||||
|
queue_note_draw (key);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::stop_unsustained_notes ()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < NNOTES; ++i) {
|
||||||
|
if (_notes[i].pressed && !_notes[i].sustained) {
|
||||||
|
_notes[i].pressed = 0;
|
||||||
|
NoteOff (i); /* EMIT SIGNAL */
|
||||||
|
queue_note_draw (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::stop_sustained_notes ()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < NNOTES; ++i) {
|
||||||
|
if (_notes[i].sustained) {
|
||||||
|
_notes[i].pressed = 0;
|
||||||
|
_notes[i].sustained = 0;
|
||||||
|
NoteOff (i); /* EMIT SIGNAL */
|
||||||
|
queue_note_draw (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PianoKeyboard::key_binding (const char* key)
|
||||||
|
{
|
||||||
|
if (_key_bindings.find (key) != _key_bindings.end()) {
|
||||||
|
return _key_bindings.at (key);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::bind_key (const char* key, int note)
|
||||||
|
{
|
||||||
|
_key_bindings[key] = note;
|
||||||
|
_note_bindings[note] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::clear_notes ()
|
||||||
|
{
|
||||||
|
_key_bindings.clear ();
|
||||||
|
_note_bindings.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::bind_keys_qwerty ()
|
||||||
|
{
|
||||||
|
clear_notes ();
|
||||||
|
|
||||||
|
bind_key ("space", 128);
|
||||||
|
|
||||||
|
/* Lower keyboard row - "zxcvbnm". */
|
||||||
|
bind_key ("z", 12); /* C0 */
|
||||||
|
bind_key ("s", 13);
|
||||||
|
bind_key ("x", 14);
|
||||||
|
bind_key ("d", 15);
|
||||||
|
bind_key ("c", 16);
|
||||||
|
bind_key ("v", 17);
|
||||||
|
bind_key ("g", 18);
|
||||||
|
bind_key ("b", 19);
|
||||||
|
bind_key ("h", 20);
|
||||||
|
bind_key ("n", 21);
|
||||||
|
bind_key ("j", 22);
|
||||||
|
bind_key ("m", 23);
|
||||||
|
|
||||||
|
/* Upper keyboard row, first octave - "qwertyu". */
|
||||||
|
bind_key ("q", 24);
|
||||||
|
bind_key ("2", 25);
|
||||||
|
bind_key ("w", 26);
|
||||||
|
bind_key ("3", 27);
|
||||||
|
bind_key ("e", 28);
|
||||||
|
bind_key ("r", 29);
|
||||||
|
bind_key ("5", 30);
|
||||||
|
bind_key ("t", 31);
|
||||||
|
bind_key ("6", 32);
|
||||||
|
bind_key ("y", 33);
|
||||||
|
bind_key ("7", 34);
|
||||||
|
bind_key ("u", 35);
|
||||||
|
|
||||||
|
/* Upper keyboard row, the rest - "iop". */
|
||||||
|
bind_key ("i", 36);
|
||||||
|
bind_key ("9", 37);
|
||||||
|
bind_key ("o", 38);
|
||||||
|
bind_key ("0", 39);
|
||||||
|
bind_key ("p", 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::bind_keys_qwertz ()
|
||||||
|
{
|
||||||
|
bind_keys_qwerty ();
|
||||||
|
|
||||||
|
/* The only difference between QWERTY and QWERTZ is that the "y" and "z" are swapped together. */
|
||||||
|
bind_key ("y", 12);
|
||||||
|
bind_key ("z", 33);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::bind_keys_azerty ()
|
||||||
|
{
|
||||||
|
clear_notes ();
|
||||||
|
|
||||||
|
bind_key ("space", 128);
|
||||||
|
|
||||||
|
/* Lower keyboard row - "wxcvbn,". */
|
||||||
|
bind_key ("w", 12); /* C0 */
|
||||||
|
bind_key ("s", 13);
|
||||||
|
bind_key ("x", 14);
|
||||||
|
bind_key ("d", 15);
|
||||||
|
bind_key ("c", 16);
|
||||||
|
bind_key ("v", 17);
|
||||||
|
bind_key ("g", 18);
|
||||||
|
bind_key ("b", 19);
|
||||||
|
bind_key ("h", 20);
|
||||||
|
bind_key ("n", 21);
|
||||||
|
bind_key ("j", 22);
|
||||||
|
bind_key ("comma", 23);
|
||||||
|
|
||||||
|
/* Upper keyboard row, first octave - "azertyu". */
|
||||||
|
bind_key ("a", 24);
|
||||||
|
bind_key ("eacute", 25);
|
||||||
|
bind_key ("z", 26);
|
||||||
|
bind_key ("quotedbl", 27);
|
||||||
|
bind_key ("e", 28);
|
||||||
|
bind_key ("r", 29);
|
||||||
|
bind_key ("parenleft", 30);
|
||||||
|
bind_key ("t", 31);
|
||||||
|
bind_key ("minus", 32);
|
||||||
|
bind_key ("y", 33);
|
||||||
|
bind_key ("egrave", 34);
|
||||||
|
bind_key ("u", 35);
|
||||||
|
|
||||||
|
/* Upper keyboard row, the rest - "iop". */
|
||||||
|
bind_key ("i", 36);
|
||||||
|
bind_key ("ccedilla", 37);
|
||||||
|
bind_key ("o", 38);
|
||||||
|
bind_key ("agrave", 39);
|
||||||
|
bind_key ("p", 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::bind_keys_dvorak ()
|
||||||
|
{
|
||||||
|
clear_notes ();
|
||||||
|
|
||||||
|
bind_key ("space", 128);
|
||||||
|
|
||||||
|
/* Lower keyboard row - ";qjkxbm". */
|
||||||
|
bind_key ("semicolon", 12); /* C0 */
|
||||||
|
bind_key ("o", 13);
|
||||||
|
bind_key ("q", 14);
|
||||||
|
bind_key ("e", 15);
|
||||||
|
bind_key ("j", 16);
|
||||||
|
bind_key ("k", 17);
|
||||||
|
bind_key ("i", 18);
|
||||||
|
bind_key ("x", 19);
|
||||||
|
bind_key ("d", 20);
|
||||||
|
bind_key ("b", 21);
|
||||||
|
bind_key ("h", 22);
|
||||||
|
bind_key ("m", 23);
|
||||||
|
bind_key ("w", 24); /* overlaps with upper row */
|
||||||
|
bind_key ("n", 25);
|
||||||
|
bind_key ("v", 26);
|
||||||
|
bind_key ("s", 27);
|
||||||
|
bind_key ("z", 28);
|
||||||
|
|
||||||
|
/* Upper keyboard row, first octave - "',.pyfg". */
|
||||||
|
bind_key ("apostrophe", 24);
|
||||||
|
bind_key ("2", 25);
|
||||||
|
bind_key ("comma", 26);
|
||||||
|
bind_key ("3", 27);
|
||||||
|
bind_key ("period", 28);
|
||||||
|
bind_key ("p", 29);
|
||||||
|
bind_key ("5", 30);
|
||||||
|
bind_key ("y", 31);
|
||||||
|
bind_key ("6", 32);
|
||||||
|
bind_key ("f", 33);
|
||||||
|
bind_key ("7", 34);
|
||||||
|
bind_key ("g", 35);
|
||||||
|
|
||||||
|
/* Upper keyboard row, the rest - "crl". */
|
||||||
|
bind_key ("c", 36);
|
||||||
|
bind_key ("9", 37);
|
||||||
|
bind_key ("r", 38);
|
||||||
|
bind_key ("0", 39);
|
||||||
|
bind_key ("l", 40);
|
||||||
|
#if 0
|
||||||
|
bind_key("slash", 41); /* extra F */
|
||||||
|
bind_key("bracketright", 42);
|
||||||
|
bind_key("equal", 43);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PianoKeyboard::on_key_press_event (GdkEventKey* event)
|
||||||
|
{
|
||||||
|
int note;
|
||||||
|
char* key;
|
||||||
|
guint keyval;
|
||||||
|
|
||||||
|
GdkKeymapKey kk;
|
||||||
|
|
||||||
|
/* We're not using event->keyval, because we need keyval with level set to 0.
|
||||||
|
E.g. if user holds Shift and presses '7', we want to get a '7', not '&'. */
|
||||||
|
kk.keycode = event->hardware_keycode;
|
||||||
|
kk.level = 0;
|
||||||
|
kk.group = 0;
|
||||||
|
|
||||||
|
keyval = gdk_keymap_lookup_key (NULL, &kk);
|
||||||
|
|
||||||
|
key = gdk_keyval_name (gdk_keyval_to_lower (keyval));
|
||||||
|
|
||||||
|
if (key == NULL) {
|
||||||
|
g_message ("gtk_keyval_name() returned NULL; please report this.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
note = key_binding (key);
|
||||||
|
|
||||||
|
if (note < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (note == 128) {
|
||||||
|
if (event->type == GDK_KEY_RELEASE) {
|
||||||
|
Rest (); /* EMIT SIGNAL */
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
note += _octave * 12;
|
||||||
|
|
||||||
|
assert (note >= 0);
|
||||||
|
assert (note < NNOTES);
|
||||||
|
|
||||||
|
if (event->type == GDK_KEY_PRESS) {
|
||||||
|
press_key (note, _key_velocity);
|
||||||
|
} else if (event->type == GDK_KEY_RELEASE) {
|
||||||
|
release_key (note);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PianoKeyboard::on_key_release_event (GdkEventKey* event)
|
||||||
|
{
|
||||||
|
return on_key_press_event (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PianoKeyboard::get_note_for_xy (int x, int y) const
|
||||||
|
{
|
||||||
|
int height = get_height ();
|
||||||
|
int note;
|
||||||
|
|
||||||
|
if (y <= ((height * 2) / 3)) { /* might be a black key */
|
||||||
|
for (note = 0; note <= _max_note; ++note) {
|
||||||
|
if (_notes[note].white) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x >= _notes[note].x && x <= _notes[note].x + _notes[note].w) {
|
||||||
|
return note;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (note = 0; note <= _max_note; ++note) {
|
||||||
|
if (!_notes[note].white) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x >= _notes[note].x && x <= _notes[note].x + _notes[note].w) {
|
||||||
|
return note;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PianoKeyboard::get_velocity_for_note_at_y (int note, int y) const
|
||||||
|
{
|
||||||
|
if (note < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int vel = _min_velocity + (_max_velocity - _min_velocity) * y / _notes[note].h;
|
||||||
|
|
||||||
|
if (vel < 1) {
|
||||||
|
return 1;
|
||||||
|
} else if (vel > 127) {
|
||||||
|
return 127;
|
||||||
|
}
|
||||||
|
return vel;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PianoKeyboard::on_button_press_event (GdkEventButton* event)
|
||||||
|
{
|
||||||
|
int x = event->x;
|
||||||
|
int y = event->y;
|
||||||
|
|
||||||
|
int note = get_note_for_xy (x, y);
|
||||||
|
|
||||||
|
if (event->button != 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (event->type == GDK_BUTTON_PRESS) {
|
||||||
|
if (note < 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_note_being_pressed_using_mouse >= 0) {
|
||||||
|
release_key (_note_being_pressed_using_mouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
press_key (note, get_velocity_for_note_at_y ( note, y));
|
||||||
|
_note_being_pressed_using_mouse = note;
|
||||||
|
|
||||||
|
} else if (event->type == GDK_BUTTON_RELEASE) {
|
||||||
|
if (note >= 0) {
|
||||||
|
release_key (note);
|
||||||
|
} else {
|
||||||
|
if (_note_being_pressed_using_mouse >= 0) {
|
||||||
|
release_key (_note_being_pressed_using_mouse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_note_being_pressed_using_mouse = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PianoKeyboard::on_button_release_event (GdkEventButton* event)
|
||||||
|
{
|
||||||
|
return on_button_press_event (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PianoKeyboard::on_motion_notify_event (GdkEventMotion* event)
|
||||||
|
{
|
||||||
|
int note;
|
||||||
|
|
||||||
|
if ((event->state & GDK_BUTTON1_MASK) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int x = event->x;
|
||||||
|
int y = event->y;
|
||||||
|
|
||||||
|
note = get_note_for_xy (x, y);
|
||||||
|
|
||||||
|
if (note != _note_being_pressed_using_mouse && note >= 0) {
|
||||||
|
if (_note_being_pressed_using_mouse >= 0) {
|
||||||
|
release_key (_note_being_pressed_using_mouse);
|
||||||
|
}
|
||||||
|
press_key (note, get_velocity_for_note_at_y (note, y));
|
||||||
|
_note_being_pressed_using_mouse = note;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PianoKeyboard::on_expose_event (GdkEventExpose* event)
|
||||||
|
{
|
||||||
|
cairo_t* cr = gdk_cairo_create (GDK_DRAWABLE (get_window ()->gobj ()));
|
||||||
|
cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height);
|
||||||
|
cairo_clip (cr);
|
||||||
|
|
||||||
|
for (int i = 0; i < NNOTES; ++i) {
|
||||||
|
GdkRectangle r;
|
||||||
|
|
||||||
|
r.x = _notes[i].x;
|
||||||
|
r.y = 0;
|
||||||
|
r.width = _notes[i].w;
|
||||||
|
r.height = _notes[i].h;
|
||||||
|
|
||||||
|
switch (gdk_region_rect_in (event->region, &r)) {
|
||||||
|
case GDK_OVERLAP_RECTANGLE_PART:
|
||||||
|
case GDK_OVERLAP_RECTANGLE_IN:
|
||||||
|
draw_note (cr, i);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_destroy (cr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::on_size_request (Gtk::Requisition* requisition)
|
||||||
|
{
|
||||||
|
requisition->width = PIANO_KEYBOARD_DEFAULT_WIDTH;
|
||||||
|
requisition->height = PIANO_KEYBOARD_DEFAULT_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PianoKeyboard::is_black (int key) const
|
||||||
|
{
|
||||||
|
int note_in_octave = key % 12;
|
||||||
|
switch (note_in_octave) {
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
case 6:
|
||||||
|
case 8:
|
||||||
|
case 10:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
PianoKeyboard::black_key_left_shift (int key) const
|
||||||
|
{
|
||||||
|
int note_in_octave = key % 12;
|
||||||
|
switch (note_in_octave) {
|
||||||
|
case 1:
|
||||||
|
return 2.0 / 3.0;
|
||||||
|
case 3:
|
||||||
|
return 1.0 / 3.0;
|
||||||
|
case 6:
|
||||||
|
return 2.0 / 3.0;
|
||||||
|
case 8:
|
||||||
|
return 0.5;
|
||||||
|
case 10:
|
||||||
|
return 1.0 / 3.0;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::recompute_dimensions ()
|
||||||
|
{
|
||||||
|
int note;
|
||||||
|
int number_of_white_keys = 0;
|
||||||
|
int skipped_white_keys = 0;
|
||||||
|
|
||||||
|
for (note = _min_note; note <= _max_note; ++note) {
|
||||||
|
if (!is_black (note)) {
|
||||||
|
++number_of_white_keys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (note = 0; note < _min_note; ++note) {
|
||||||
|
if (!is_black (note)) {
|
||||||
|
++skipped_white_keys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = get_width ();
|
||||||
|
int height = get_height ();
|
||||||
|
|
||||||
|
int key_width = width / number_of_white_keys;
|
||||||
|
int black_key_width = key_width * 0.8;
|
||||||
|
int useful_width = number_of_white_keys * key_width;
|
||||||
|
|
||||||
|
int widget_margin = (width - useful_width) / 2;
|
||||||
|
|
||||||
|
int white_key;
|
||||||
|
for (note = 0, white_key = -skipped_white_keys; note < NNOTES; ++note) {
|
||||||
|
if (is_black (note)) {
|
||||||
|
/* This note is black key. */
|
||||||
|
_notes[note].x = widget_margin +
|
||||||
|
(white_key * key_width) -
|
||||||
|
(black_key_width * black_key_left_shift (note));
|
||||||
|
_notes[note].w = black_key_width;
|
||||||
|
_notes[note].h = (height * 2) / 3;
|
||||||
|
_notes[note].white = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This note is white key. */
|
||||||
|
_notes[note].x = widget_margin + white_key * key_width;
|
||||||
|
_notes[note].w = key_width;
|
||||||
|
_notes[note].h = height;
|
||||||
|
_notes[note].white = 1;
|
||||||
|
|
||||||
|
white_key++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::on_size_allocate (Gtk::Allocation& allocation)
|
||||||
|
{
|
||||||
|
DrawingArea::on_size_allocate (allocation);
|
||||||
|
recompute_dimensions ();
|
||||||
|
}
|
||||||
|
|
||||||
|
PianoKeyboard::PianoKeyboard ()
|
||||||
|
{
|
||||||
|
using namespace Gdk;
|
||||||
|
add_events (KEY_PRESS_MASK|KEY_RELEASE_MASK|BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK|POINTER_MOTION_MASK|POINTER_MOTION_HINT_MASK);
|
||||||
|
|
||||||
|
_maybe_stop_sustained_notes = false;
|
||||||
|
_sustain_new_notes = false;
|
||||||
|
_enable_keyboard_cue = false;
|
||||||
|
_highlight_grand_piano_range = false;
|
||||||
|
_print_note_label = false;
|
||||||
|
_octave = 4;
|
||||||
|
_octave_range = 7;
|
||||||
|
_note_being_pressed_using_mouse = -1;
|
||||||
|
_min_note = 0;
|
||||||
|
_max_note = 127;
|
||||||
|
_last_key = 0;
|
||||||
|
_monophonic = false;
|
||||||
|
|
||||||
|
_min_velocity = 1;
|
||||||
|
_max_velocity = 127;
|
||||||
|
_key_velocity = 100;
|
||||||
|
|
||||||
|
bind_keys_qwerty ();
|
||||||
|
}
|
||||||
|
|
||||||
|
PianoKeyboard::~PianoKeyboard ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::set_keyboard_cue (bool enabled)
|
||||||
|
{
|
||||||
|
_enable_keyboard_cue = enabled;
|
||||||
|
queue_draw ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::set_grand_piano_highlight (bool enabled)
|
||||||
|
{
|
||||||
|
_highlight_grand_piano_range = enabled;
|
||||||
|
queue_draw ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::show_note_label (bool enabled)
|
||||||
|
{
|
||||||
|
_print_note_label = enabled;
|
||||||
|
queue_draw ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::set_monophonic (bool monophonic)
|
||||||
|
{
|
||||||
|
_monophonic = monophonic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::set_velocities (int min_vel, int max_vel, int key_vel)
|
||||||
|
{
|
||||||
|
if (min_vel <= max_vel && min_vel > 0 && max_vel < 128) {
|
||||||
|
_min_velocity = min_vel;
|
||||||
|
_max_velocity = max_vel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_vel > 0 && key_vel < 128) {
|
||||||
|
_key_velocity = key_vel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::sustain_press ()
|
||||||
|
{
|
||||||
|
if (!_sustain_new_notes) {
|
||||||
|
_sustain_new_notes = true;
|
||||||
|
_maybe_stop_sustained_notes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::sustain_release ()
|
||||||
|
{
|
||||||
|
if (_maybe_stop_sustained_notes) {
|
||||||
|
stop_sustained_notes ();
|
||||||
|
}
|
||||||
|
_sustain_new_notes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::set_note_on (int note)
|
||||||
|
{
|
||||||
|
if (_notes[note].pressed == 0) {
|
||||||
|
_notes[note].pressed = 1;
|
||||||
|
queue_note_draw (note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::set_note_off (int note)
|
||||||
|
{
|
||||||
|
if (_notes[note].pressed || _notes[note].sustained) {
|
||||||
|
_notes[note].pressed = 0;
|
||||||
|
_notes[note].sustained = 0;
|
||||||
|
queue_note_draw (note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::set_octave (int octave)
|
||||||
|
{
|
||||||
|
stop_unsustained_notes ();
|
||||||
|
|
||||||
|
if (octave < -1) {
|
||||||
|
octave = -1;
|
||||||
|
} else if (octave > 7) {
|
||||||
|
octave = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
_octave = octave;
|
||||||
|
set_octave_range (_octave_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::set_octave_range (int octave_range)
|
||||||
|
{
|
||||||
|
stop_unsustained_notes ();
|
||||||
|
|
||||||
|
if (octave_range < 2) {
|
||||||
|
octave_range = 2;
|
||||||
|
}
|
||||||
|
if (octave_range > 11) {
|
||||||
|
octave_range = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
_octave_range = octave_range;
|
||||||
|
|
||||||
|
/* -1 <= _octave <= 7
|
||||||
|
* key-bindings are at offset 12 .. 40
|
||||||
|
* default piano range: _octave = 4, range = 7 -> note 21..108
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch (_octave_range) {
|
||||||
|
default:
|
||||||
|
assert (0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
_min_note = (_octave + 1) * 12;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
_min_note = (_octave + 0) * 12;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
_min_note = (_octave - 1) * 12;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
_min_note = (_octave - 2) * 12;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
case 10:
|
||||||
|
_min_note = (_octave - 3) * 12;
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
_min_note = (_octave - 4) * 12;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int upper_offset = 0;
|
||||||
|
|
||||||
|
if (_min_note < 3) {
|
||||||
|
upper_offset = 0;
|
||||||
|
_min_note = 0;
|
||||||
|
} else if (_octave_range > 5) {
|
||||||
|
/* extend down to A */
|
||||||
|
upper_offset = 3;
|
||||||
|
_min_note -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
_max_note = MIN (127, upper_offset + _min_note + _octave_range * 12);
|
||||||
|
|
||||||
|
if (_max_note == 127) {
|
||||||
|
_min_note = MAX (0, _max_note - _octave_range * 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
recompute_dimensions ();
|
||||||
|
queue_draw ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PianoKeyboard::set_keyboard_layout (Layout layout)
|
||||||
|
{
|
||||||
|
switch (layout) {
|
||||||
|
case QWERTY:
|
||||||
|
bind_keys_qwerty ();
|
||||||
|
break;
|
||||||
|
case QWERTZ:
|
||||||
|
bind_keys_qwertz ();
|
||||||
|
break;
|
||||||
|
case AZERTY:
|
||||||
|
bind_keys_azerty ();
|
||||||
|
break;
|
||||||
|
case DVORAK:
|
||||||
|
bind_keys_dvorak ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
queue_draw ();
|
||||||
|
}
|
|
@ -20,20 +20,10 @@
|
||||||
#ifndef __PIANO_KEYBOARD_H__
|
#ifndef __PIANO_KEYBOARD_H__
|
||||||
#define __PIANO_KEYBOARD_H__
|
#define __PIANO_KEYBOARD_H__
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gtk/gtkdrawingarea.h>
|
#include <gtkmm/drawingarea.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define TYPE_PIANO_KEYBOARD (piano_keyboard_get_type ())
|
|
||||||
#define PIANO_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PIANO_KEYBOARD, PianoKeyboard))
|
|
||||||
#define PIANO_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PIANO_KEYBOARD, PianoKeyboardClass))
|
|
||||||
#define IS_PIANO_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PIANO_KEYBOARD))
|
|
||||||
#define IS_PIANO_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PIANO_KEYBOARD))
|
|
||||||
#define PIANO_KEYBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PIANO_KEYBOARD, PianoKeyboardClass))
|
|
||||||
|
|
||||||
typedef struct _PianoKeyboard PianoKeyboard;
|
|
||||||
typedef struct _PianoKeyboardClass PianoKeyboardClass;
|
|
||||||
|
|
||||||
#define NNOTES (128)
|
#define NNOTES (128)
|
||||||
#define PIANO_MIN_NOTE 21
|
#define PIANO_MIN_NOTE 21
|
||||||
|
@ -42,59 +32,111 @@ typedef struct _PianoKeyboardClass PianoKeyboardClass;
|
||||||
#define OCTAVE_MIN (-1)
|
#define OCTAVE_MIN (-1)
|
||||||
#define OCTAVE_MAX (7)
|
#define OCTAVE_MAX (7)
|
||||||
|
|
||||||
struct PKNote {
|
class PianoKeyboard : public Gtk::DrawingArea
|
||||||
int pressed; /* 1 if key is in pressed down state. */
|
{
|
||||||
int sustained; /* 1 if note is sustained. */
|
public:
|
||||||
int x; /* Distance between the left edge of the key
|
PianoKeyboard ();
|
||||||
* and the left edge of the widget, in pixels. */
|
~PianoKeyboard ();
|
||||||
int w; /* Width of the key, in pixels. */
|
|
||||||
int h; /* Height of the key, in pixels. */
|
sigc::signal<void, int, int> NoteOn;
|
||||||
int white; /* 1 if key is white; 0 otherwise. */
|
sigc::signal<void, int> NoteOff;
|
||||||
|
sigc::signal<void > Rest;
|
||||||
|
|
||||||
|
enum Layout {
|
||||||
|
QWERTY,
|
||||||
|
QWERTZ,
|
||||||
|
AZERTY,
|
||||||
|
DVORAK
|
||||||
|
};
|
||||||
|
|
||||||
|
void sustain_press ();
|
||||||
|
void sustain_release ();
|
||||||
|
void set_note_on (int note);
|
||||||
|
void set_note_off (int note);
|
||||||
|
void set_keyboard_cue (bool enabled);
|
||||||
|
void set_grand_piano_highlight (bool enabled);
|
||||||
|
void show_note_label (bool enabled);
|
||||||
|
void set_monophonic (bool monophonic);
|
||||||
|
void set_octave (int octave);
|
||||||
|
void set_octave_range (int octave_range);
|
||||||
|
void set_keyboard_layout (Layout layout);
|
||||||
|
void set_velocities (int min_vel, int max_vel, int key_vel);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool on_key_press_event (GdkEventKey *);
|
||||||
|
bool on_key_release_event (GdkEventKey *);
|
||||||
|
bool on_button_press_event (GdkEventButton*);
|
||||||
|
bool on_button_release_event (GdkEventButton*);
|
||||||
|
bool on_motion_notify_event (GdkEventMotion*);
|
||||||
|
bool on_expose_event (GdkEventExpose*);
|
||||||
|
|
||||||
|
void on_size_request (Gtk::Requisition*);
|
||||||
|
void on_size_allocate (Gtk::Allocation&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void draw_keyboard_cue (cairo_t* cr, int note);
|
||||||
|
void queue_note_draw (int note);
|
||||||
|
void draw_note (cairo_t* cr, int note);
|
||||||
|
int press_key (int key, int vel);
|
||||||
|
int release_key (int key);
|
||||||
|
void release_key ();
|
||||||
|
void stop_unsustained_notes ();
|
||||||
|
void stop_sustained_notes ();
|
||||||
|
int key_binding (const char* key);
|
||||||
|
void bind_key (const char* key, int note);
|
||||||
|
void clear_notes ();
|
||||||
|
|
||||||
|
void bind_keys_qwerty ();
|
||||||
|
void bind_keys_qwertz ();
|
||||||
|
void bind_keys_azerty ();
|
||||||
|
void bind_keys_dvorak ();
|
||||||
|
|
||||||
|
int get_note_for_xy (int x, int y) const;
|
||||||
|
int get_velocity_for_note_at_y (int note, int y) const;
|
||||||
|
|
||||||
|
int is_black (int key) const;
|
||||||
|
double black_key_left_shift (int key) const;
|
||||||
|
|
||||||
|
void recompute_dimensions ();
|
||||||
|
|
||||||
|
struct PKNote {
|
||||||
|
PKNote ()
|
||||||
|
: pressed (false)
|
||||||
|
, sustained (false)
|
||||||
|
, white (false)
|
||||||
|
, x (0)
|
||||||
|
, w (0)
|
||||||
|
, h (0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool pressed; /* 1 if key is in pressed down state. */
|
||||||
|
bool sustained; /* 1 if note is sustained. */
|
||||||
|
bool white; /* 1 if key is white; 0 otherwise. */
|
||||||
|
int x; /* Distance between the left edge of the key * and the left edge of the widget, in pixels. */
|
||||||
|
int w; /* Width of the key, in pixels. */
|
||||||
|
int h; /* Height of the key, in pixels. */
|
||||||
|
};
|
||||||
|
|
||||||
|
bool _maybe_stop_sustained_notes;
|
||||||
|
bool _sustain_new_notes;
|
||||||
|
bool _enable_keyboard_cue;
|
||||||
|
bool _highlight_grand_piano_range;
|
||||||
|
bool _print_note_label;
|
||||||
|
int _octave;
|
||||||
|
int _octave_range;
|
||||||
|
int _note_being_pressed_using_mouse;
|
||||||
|
int _min_note;
|
||||||
|
int _max_note;
|
||||||
|
int _last_key;
|
||||||
|
bool _monophonic;
|
||||||
|
int _min_velocity;
|
||||||
|
int _max_velocity;
|
||||||
|
int _key_velocity;
|
||||||
|
|
||||||
|
PKNote _notes[NNOTES];
|
||||||
|
|
||||||
|
std::map<std::string, int> _key_bindings; /**< Table used to translate from PC keyboard character to MIDI note number. */
|
||||||
|
std::map<int, std::string> _note_bindings; /**< Table to translate from MIDI note number to PC keyboard character. */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _PianoKeyboard {
|
|
||||||
GtkDrawingArea da;
|
|
||||||
int maybe_stop_sustained_notes;
|
|
||||||
int sustain_new_notes;
|
|
||||||
gboolean enable_keyboard_cue;
|
|
||||||
gboolean highlight_grand_piano_range;
|
|
||||||
gboolean print_note_label;
|
|
||||||
int octave;
|
|
||||||
int octave_range;
|
|
||||||
int widget_margin;
|
|
||||||
int note_being_pressed_using_mouse;
|
|
||||||
int min_note;
|
|
||||||
int max_note;
|
|
||||||
int last_key;
|
|
||||||
gboolean monophonic;
|
|
||||||
struct PKNote notes[NNOTES];
|
|
||||||
GHashTable* key_bindings; /**< Table used to translate from PC keyboard character to MIDI note number. */
|
|
||||||
char* note_bindings[NNOTES]; /**< Table to translate from MIDI note number to PC keyboard character. */
|
|
||||||
int min_velocity;
|
|
||||||
int max_velocity;
|
|
||||||
int key_velocity;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _PianoKeyboardClass {
|
|
||||||
GtkDrawingAreaClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
GType piano_keyboard_get_type (void) G_GNUC_CONST;
|
|
||||||
GtkWidget* piano_keyboard_new (void);
|
|
||||||
|
|
||||||
void piano_keyboard_sustain_press (PianoKeyboard* pk);
|
|
||||||
void piano_keyboard_sustain_release (PianoKeyboard* pk);
|
|
||||||
void piano_keyboard_set_note_on (PianoKeyboard* pk, int note);
|
|
||||||
void piano_keyboard_set_note_off (PianoKeyboard* pk, int note);
|
|
||||||
void piano_keyboard_set_keyboard_cue (PianoKeyboard* pk, gboolean enabled);
|
|
||||||
void piano_keyboard_set_grand_piano_highlight (PianoKeyboard* pk, gboolean enabled);
|
|
||||||
void piano_keyboard_show_note_label (PianoKeyboard* pk, gboolean enabled);
|
|
||||||
void piano_keyboard_set_monophonic (PianoKeyboard* pk, gboolean monophonic);
|
|
||||||
void piano_keyboard_set_octave (PianoKeyboard* pk, int octave);
|
|
||||||
void piano_keyboard_set_octave_range (PianoKeyboard* pk, int octave_range);
|
|
||||||
void piano_keyboard_set_keyboard_layout (PianoKeyboard* pk, const char* layout);
|
|
||||||
void piano_keyboard_set_velocities (PianoKeyboard* pk, int min_vel, int max_vel, int key_vel);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __PIANO_KEYBOARD_H__ */
|
#endif /* __PIANO_KEYBOARD_H__ */
|
||||||
|
|
|
@ -23,33 +23,26 @@
|
||||||
|
|
||||||
#include "pbd/i18n.h"
|
#include "pbd/i18n.h"
|
||||||
|
|
||||||
static void
|
NoteSelectDialog::NoteSelectDialog ()
|
||||||
_note_on_event_handler(GtkWidget* /*widget*/, int note, int, gpointer arg)
|
|
||||||
{
|
|
||||||
((NoteSelectDialog*)arg)->note_on_event_handler(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
NoteSelectDialog::NoteSelectDialog()
|
|
||||||
: ArdourDialog (_("Select Note"))
|
: ArdourDialog (_("Select Note"))
|
||||||
, _piano((PianoKeyboard*)piano_keyboard_new())
|
|
||||||
, _pianomm(Glib::wrap((GtkWidget*)_piano))
|
|
||||||
, _note_number(60)
|
, _note_number(60)
|
||||||
{
|
{
|
||||||
_pianomm->set_flags(Gtk::CAN_FOCUS);
|
_piano.set_flags(Gtk::CAN_FOCUS);
|
||||||
_pianomm->show();
|
_piano.show();
|
||||||
g_signal_connect(G_OBJECT(_piano), "note-on", G_CALLBACK(_note_on_event_handler), this);
|
_piano.NoteOn.connect (sigc::mem_fun (*this, &NoteSelectDialog::note_on_event_handler));
|
||||||
piano_keyboard_set_monophonic(_piano, TRUE);
|
|
||||||
piano_keyboard_sustain_press(_piano);
|
_piano.set_monophonic (true);
|
||||||
|
_piano.sustain_press ();
|
||||||
|
|
||||||
|
get_vbox()->pack_start(_piano);
|
||||||
|
|
||||||
get_vbox()->pack_start(*_pianomm);
|
|
||||||
add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
|
add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
|
||||||
add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
|
add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
|
||||||
set_default_response(Gtk::RESPONSE_ACCEPT);
|
set_default_response(Gtk::RESPONSE_ACCEPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NoteSelectDialog::note_on_event_handler(int note)
|
NoteSelectDialog::note_on_event_handler(int note, int)
|
||||||
{
|
{
|
||||||
printf("NOTE: %d\n", note);
|
|
||||||
_note_number = note;
|
_note_number = note;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,11 @@ public:
|
||||||
|
|
||||||
uint8_t note_number() const { return _note_number; }
|
uint8_t note_number() const { return _note_number; }
|
||||||
|
|
||||||
void note_on_event_handler(int note);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PianoKeyboard* _piano;
|
PianoKeyboard _piano;
|
||||||
Gtk::Widget* _pianomm;
|
uint8_t _note_number;
|
||||||
uint8_t _note_number;
|
|
||||||
|
void note_on_event_handler(int, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __gtk2_ardour_note_select_dialog_h__ */
|
#endif /* __gtk2_ardour_note_select_dialog_h__ */
|
||||||
|
|
|
@ -57,8 +57,6 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
|
||||||
, _audition_end_spin (*manage (new Adjustment (60, 0, 127, 1, 16)))
|
, _audition_end_spin (*manage (new Adjustment (60, 0, 127, 1, 16)))
|
||||||
, _audition_velocity (*manage (new Adjustment (100, 1, 127, 1, 16)))
|
, _audition_velocity (*manage (new Adjustment (100, 1, 127, 1, 16)))
|
||||||
, _audition_note_on (false)
|
, _audition_note_on (false)
|
||||||
, _piano ((PianoKeyboard*)piano_keyboard_new())
|
|
||||||
, _pianomm (Glib::wrap((GtkWidget*)_piano))
|
|
||||||
{
|
{
|
||||||
Box* box;
|
Box* box;
|
||||||
box = manage (new HBox ());
|
box = manage (new HBox ());
|
||||||
|
@ -114,11 +112,12 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
|
||||||
_channel_select.AddMenuElem (MenuElemNoMnemonic (buf, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_channel), chn)));
|
_channel_select.AddMenuElem (MenuElemNoMnemonic (buf, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_channel), chn)));
|
||||||
}
|
}
|
||||||
|
|
||||||
piano_keyboard_set_monophonic (_piano, TRUE);
|
_piano.set_monophonic (true);
|
||||||
g_signal_connect (G_OBJECT (_piano), "note-on", G_CALLBACK (PatchChangeWidget::_note_on_event_handler), this);
|
_piano.NoteOn.connect (sigc::mem_fun (*this, &PatchChangeWidget::_note_on_event_handler));
|
||||||
g_signal_connect (G_OBJECT (_piano), "note-off", G_CALLBACK (PatchChangeWidget::_note_off_event_handler), this);
|
_piano.NoteOff.connect (sigc::mem_fun (*this, &PatchChangeWidget::note_off_event_handler));
|
||||||
_pianomm->set_flags(Gtk::CAN_FOCUS);
|
|
||||||
pack_start (*_pianomm, false, false);
|
_piano.set_flags(Gtk::CAN_FOCUS);
|
||||||
|
pack_start (_piano, false, false);
|
||||||
|
|
||||||
_audition_start_spin.set_sensitive (false);
|
_audition_start_spin.set_sensitive (false);
|
||||||
_audition_end_spin.set_sensitive (false);
|
_audition_end_spin.set_sensitive (false);
|
||||||
|
@ -145,7 +144,6 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
|
||||||
PatchChangeWidget::~PatchChangeWidget ()
|
PatchChangeWidget::~PatchChangeWidget ()
|
||||||
{
|
{
|
||||||
cancel_audition ();
|
cancel_audition ();
|
||||||
delete _pianomm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -434,7 +432,7 @@ PatchChangeWidget::cancel_audition ()
|
||||||
|
|
||||||
if (_audition_note_on) {
|
if (_audition_note_on) {
|
||||||
note_off_event_handler (_audition_note_num);
|
note_off_event_handler (_audition_note_num);
|
||||||
piano_keyboard_set_note_off (_piano, _audition_note_num);
|
_piano.set_note_off (_audition_note_num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,25 +465,19 @@ PatchChangeWidget::audition_next ()
|
||||||
{
|
{
|
||||||
if (_audition_note_on) {
|
if (_audition_note_on) {
|
||||||
note_off_event_handler (_audition_note_num);
|
note_off_event_handler (_audition_note_num);
|
||||||
piano_keyboard_set_note_off (_piano, _audition_note_num);
|
_piano.set_note_off (_audition_note_num);
|
||||||
return ++_audition_note_num <= _audition_end_spin.get_value_as_int() && _audition_enable.get_active ();
|
return ++_audition_note_num <= _audition_end_spin.get_value_as_int() && _audition_enable.get_active ();
|
||||||
} else {
|
} else {
|
||||||
note_on_event_handler (_audition_note_num, true);
|
note_on_event_handler (_audition_note_num, true);
|
||||||
piano_keyboard_set_note_on (_piano, _audition_note_num);
|
_piano.set_note_on (_audition_note_num);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PatchChangeWidget::_note_on_event_handler(GtkWidget*, int note, int, gpointer arg)
|
PatchChangeWidget::_note_on_event_handler (int note, int)
|
||||||
{
|
{
|
||||||
((PatchChangeWidget*)arg)->note_on_event_handler(note, false);
|
note_on_event_handler(note, false);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PatchChangeWidget::_note_off_event_handler(GtkWidget*, int note, gpointer arg)
|
|
||||||
{
|
|
||||||
((PatchChangeWidget*)arg)->note_off_event_handler(note);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -493,7 +485,7 @@ PatchChangeWidget::note_on_event_handler (int note, bool for_audition)
|
||||||
{
|
{
|
||||||
if (!for_audition) {
|
if (!for_audition) {
|
||||||
cancel_audition ();
|
cancel_audition ();
|
||||||
_pianomm->grab_focus ();
|
_piano.grab_focus ();
|
||||||
}
|
}
|
||||||
uint8_t event[3];
|
uint8_t event[3];
|
||||||
event[0] = (MIDI_CMD_NOTE_ON | _channel);
|
event[0] = (MIDI_CMD_NOTE_ON | _channel);
|
||||||
|
|
|
@ -99,11 +99,9 @@ private:
|
||||||
uint8_t _audition_note_num;
|
uint8_t _audition_note_num;
|
||||||
bool _audition_note_on;
|
bool _audition_note_on;
|
||||||
|
|
||||||
PianoKeyboard* _piano;
|
PianoKeyboard _piano;
|
||||||
Gtk::Widget* _pianomm;
|
|
||||||
|
|
||||||
static void _note_on_event_handler (GtkWidget*, int, int, gpointer);
|
void _note_on_event_handler (int, int);
|
||||||
static void _note_off_event_handler (GtkWidget*, int, gpointer);
|
|
||||||
void note_on_event_handler (int, bool for_audition);
|
void note_on_event_handler (int, bool for_audition);
|
||||||
void note_off_event_handler (int);
|
void note_off_event_handler (int);
|
||||||
};
|
};
|
||||||
|
|
|
@ -319,14 +319,11 @@ private:
|
||||||
|
|
||||||
Gtk::Expander _plugin_pianokeyboard_expander;
|
Gtk::Expander _plugin_pianokeyboard_expander;
|
||||||
PianoKeyboard* _piano;
|
PianoKeyboard* _piano;
|
||||||
Gtk::Widget* _pianomm;
|
|
||||||
Gtk::VBox _pianobox;
|
Gtk::VBox _pianobox;
|
||||||
Gtk::SpinButton _piano_velocity;
|
Gtk::SpinButton _piano_velocity;
|
||||||
Gtk::SpinButton _piano_channel;
|
Gtk::SpinButton _piano_channel;
|
||||||
|
|
||||||
static void _note_on_event_handler (GtkWidget*, int, int, gpointer);
|
void note_on_event_handler (int, int);
|
||||||
static void _note_off_event_handler (GtkWidget*, int, gpointer);
|
|
||||||
void note_on_event_handler (int);
|
|
||||||
void note_off_event_handler (int);
|
void note_off_event_handler (int);
|
||||||
|
|
||||||
void toggle_pianokeyboard ();
|
void toggle_pianokeyboard ();
|
||||||
|
|
|
@ -50,18 +50,6 @@ using namespace ArdourWidgets;
|
||||||
Gtkmm2ext::Bindings* StepEntry::bindings = 0;
|
Gtkmm2ext::Bindings* StepEntry::bindings = 0;
|
||||||
StepEntry* StepEntry::_instance = 0;
|
StepEntry* StepEntry::_instance = 0;
|
||||||
|
|
||||||
static void
|
|
||||||
_note_off_event_handler (GtkWidget* /*widget*/, int note, gpointer arg)
|
|
||||||
{
|
|
||||||
((StepEntry*)arg)->note_off_event_handler (note);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_rest_event_handler (GtkWidget* /*widget*/, gpointer arg)
|
|
||||||
{
|
|
||||||
((StepEntry*)arg)->rest_event_handler ();
|
|
||||||
}
|
|
||||||
|
|
||||||
StepEntry&
|
StepEntry&
|
||||||
StepEntry::instance()
|
StepEntry::instance()
|
||||||
{
|
{
|
||||||
|
@ -99,8 +87,6 @@ StepEntry::StepEntry ()
|
||||||
, program_adjustment (0, 0.0, 127.0, 1.0, 4.0)
|
, program_adjustment (0, 0.0, 127.0, 1.0, 4.0)
|
||||||
, program_spinner (program_adjustment)
|
, program_spinner (program_adjustment)
|
||||||
, program_button (_("+"))
|
, program_button (_("+"))
|
||||||
, _piano (0)
|
|
||||||
, piano (0)
|
|
||||||
, se (0)
|
, se (0)
|
||||||
{
|
{
|
||||||
set_data ("ardour-bindings", bindings);
|
set_data ("ardour-bindings", bindings);
|
||||||
|
@ -436,13 +422,10 @@ StepEntry::StepEntry ()
|
||||||
length_divisor_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &StepEntry::length_value_change));
|
length_divisor_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &StepEntry::length_value_change));
|
||||||
dot_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &StepEntry::dot_value_change));
|
dot_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &StepEntry::dot_value_change));
|
||||||
|
|
||||||
_piano = (PianoKeyboard*) piano_keyboard_new ();
|
_piano.set_flags (Gtk::CAN_FOCUS);
|
||||||
piano = wrap ((GtkWidget*) _piano);
|
|
||||||
|
|
||||||
piano->set_flags (Gtk::CAN_FOCUS);
|
_piano.NoteOff.connect (sigc::mem_fun (*this, &StepEntry::note_off_event_handler));
|
||||||
|
_piano.Rest.connect (sigc::mem_fun (*this, &StepEntry::rest_event_handler));
|
||||||
g_signal_connect(G_OBJECT(_piano), "note-off", G_CALLBACK(_note_off_event_handler), this);
|
|
||||||
g_signal_connect(G_OBJECT(_piano), "rest", G_CALLBACK(_rest_event_handler), this);
|
|
||||||
|
|
||||||
program_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::program_click));
|
program_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::program_click));
|
||||||
bank_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::bank_click));
|
bank_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::bank_click));
|
||||||
|
@ -453,7 +436,7 @@ StepEntry::StepEntry ()
|
||||||
|
|
||||||
packer.set_spacing (6);
|
packer.set_spacing (6);
|
||||||
packer.pack_start (upper_box, false, false);
|
packer.pack_start (upper_box, false, false);
|
||||||
packer.pack_start (*piano, false, false);
|
packer.pack_start (_piano, false, false);
|
||||||
packer.show_all ();
|
packer.show_all ();
|
||||||
|
|
||||||
add (packer);
|
add (packer);
|
||||||
|
@ -592,7 +575,7 @@ void
|
||||||
StepEntry::on_show ()
|
StepEntry::on_show ()
|
||||||
{
|
{
|
||||||
ArdourWindow::on_show ();
|
ArdourWindow::on_show ();
|
||||||
//piano->grab_focus ();
|
//_piano->grab_focus ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -51,9 +51,6 @@ class StepEntry : public ArdourWindow
|
||||||
|
|
||||||
void set_step_editor (StepEditor*);
|
void set_step_editor (StepEditor*);
|
||||||
|
|
||||||
void note_off_event_handler (int note);
|
|
||||||
void rest_event_handler ();
|
|
||||||
|
|
||||||
Temporal::Beats note_length();
|
Temporal::Beats note_length();
|
||||||
uint8_t note_velocity() const;
|
uint8_t note_velocity() const;
|
||||||
uint8_t note_channel() const;
|
uint8_t note_channel() const;
|
||||||
|
@ -66,6 +63,9 @@ class StepEntry : public ArdourWindow
|
||||||
static StepEntry* _instance;
|
static StepEntry* _instance;
|
||||||
StepEntry ();
|
StepEntry ();
|
||||||
|
|
||||||
|
void note_off_event_handler (int note);
|
||||||
|
void rest_event_handler ();
|
||||||
|
|
||||||
Temporal::Beats _current_note_length;
|
Temporal::Beats _current_note_length;
|
||||||
uint8_t _current_note_velocity;
|
uint8_t _current_note_velocity;
|
||||||
|
|
||||||
|
@ -140,8 +140,8 @@ class StepEntry : public ArdourWindow
|
||||||
void velocity_value_change ();
|
void velocity_value_change ();
|
||||||
void length_value_change ();
|
void length_value_change ();
|
||||||
|
|
||||||
PianoKeyboard* _piano;
|
PianoKeyboard _piano;
|
||||||
Gtk::Widget* piano;
|
|
||||||
StepEditor* se;
|
StepEditor* se;
|
||||||
|
|
||||||
void bank_click ();
|
void bank_click ();
|
||||||
|
|
|
@ -57,12 +57,10 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
|
||||||
, _piano_octave_range (*manage (new Adjustment (7, 2, 11, 1, 1)))
|
, _piano_octave_range (*manage (new Adjustment (7, 2, 11, 1, 1)))
|
||||||
, _pitch_adjustment (8192, 0, 16383, 1, 256)
|
, _pitch_adjustment (8192, 0, 16383, 1, 256)
|
||||||
{
|
{
|
||||||
_piano = (PianoKeyboard*)piano_keyboard_new ();
|
_piano.set_flags (Gtk::CAN_FOCUS);
|
||||||
_pianomm = Glib::wrap ((GtkWidget*)_piano);
|
|
||||||
_pianomm->set_flags (Gtk::CAN_FOCUS);
|
_piano.set_keyboard_layout(PianoKeyboard::QWERTY);
|
||||||
_pianomm->add_events (Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
|
_piano.show_note_label (true);
|
||||||
piano_keyboard_set_keyboard_layout (_piano, "QWERTY");
|
|
||||||
piano_keyboard_show_note_label (_piano, true);
|
|
||||||
|
|
||||||
using namespace Menu_Helpers;
|
using namespace Menu_Helpers;
|
||||||
_keyboard_layout.AddMenuElem (MenuElem ("QWERTY",
|
_keyboard_layout.AddMenuElem (MenuElem ("QWERTY",
|
||||||
|
@ -218,7 +216,7 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
|
||||||
vbox->pack_start (*box1, false, false, 4);
|
vbox->pack_start (*box1, false, false, 4);
|
||||||
vbox->pack_start (*_pgm_box, false, false, 4);
|
vbox->pack_start (*_pgm_box, false, false, 4);
|
||||||
vbox->pack_start (*_cfg_box, false, false, 4);
|
vbox->pack_start (*_cfg_box, false, false, 4);
|
||||||
vbox->pack_start (*_pianomm, true, true);
|
vbox->pack_start (_piano, true, true);
|
||||||
add (*vbox);
|
add (*vbox);
|
||||||
|
|
||||||
_bank_msb.signal_value_changed ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::bank_patch));
|
_bank_msb.signal_value_changed ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::bank_patch));
|
||||||
|
@ -240,8 +238,9 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
|
||||||
_show_note_label.signal_button_release_event ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::toggle_note_label), false);
|
_show_note_label.signal_button_release_event ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::toggle_note_label), false);
|
||||||
_send_panic.signal_button_release_event ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::send_panic_message), false);
|
_send_panic.signal_button_release_event ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::send_panic_message), false);
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (_piano), "note-on", G_CALLBACK (VirtualKeyboardWindow::_note_on_event_handler), this);
|
|
||||||
g_signal_connect (G_OBJECT (_piano), "note-off", G_CALLBACK (VirtualKeyboardWindow::_note_off_event_handler), this);
|
_piano.NoteOn.connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::note_on_event_handler));
|
||||||
|
_piano.NoteOff.connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::note_off_event_handler));
|
||||||
|
|
||||||
update_velocity_settings (0);
|
update_velocity_settings (0);
|
||||||
update_octave_range ();
|
update_octave_range ();
|
||||||
|
@ -252,7 +251,6 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
|
||||||
|
|
||||||
VirtualKeyboardWindow::~VirtualKeyboardWindow ()
|
VirtualKeyboardWindow::~VirtualKeyboardWindow ()
|
||||||
{
|
{
|
||||||
delete _pianomm;
|
|
||||||
delete _pitch_slider_tooltip;
|
delete _pitch_slider_tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,8 +304,7 @@ VirtualKeyboardWindow::set_state (const XMLNode& root)
|
||||||
|
|
||||||
std::string layout;
|
std::string layout;
|
||||||
if (node->get_property (X_("Layout"), layout)) {
|
if (node->get_property (X_("Layout"), layout)) {
|
||||||
piano_keyboard_set_keyboard_layout (_piano, layout.c_str ());
|
select_keyboard_layout (layout);
|
||||||
_keyboard_layout.set_active (layout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < VKBD_NCTRLS; ++i) {
|
for (int i = 0; i < VKBD_NCTRLS; ++i) {
|
||||||
|
@ -325,15 +322,15 @@ VirtualKeyboardWindow::set_state (const XMLNode& root)
|
||||||
}
|
}
|
||||||
if (node->get_property (X_("HighlightGrandPiano"), a)) {
|
if (node->get_property (X_("HighlightGrandPiano"), a)) {
|
||||||
_highlight_grand_piano.set_active (a);
|
_highlight_grand_piano.set_active (a);
|
||||||
piano_keyboard_set_grand_piano_highlight (_piano, a);
|
_piano.set_grand_piano_highlight (a);
|
||||||
}
|
}
|
||||||
if (node->get_property (X_("HighlightKeyRange"), a)) {
|
if (node->get_property (X_("HighlightKeyRange"), a)) {
|
||||||
_highlight_key_range.set_active (a);
|
_highlight_key_range.set_active (a);
|
||||||
piano_keyboard_set_keyboard_cue (_piano, a);
|
_piano.set_keyboard_cue (a);
|
||||||
}
|
}
|
||||||
if (node->get_property (X_("ShowNoteLabel"), a)) {
|
if (node->get_property (X_("ShowNoteLabel"), a)) {
|
||||||
_show_note_label.set_active (a);
|
_show_note_label.set_active (a);
|
||||||
piano_keyboard_show_note_label (_piano, a);
|
_piano.show_note_label (a);
|
||||||
}
|
}
|
||||||
|
|
||||||
int v;
|
int v;
|
||||||
|
@ -367,7 +364,7 @@ VirtualKeyboardWindow::set_state (const XMLNode& root)
|
||||||
bool
|
bool
|
||||||
VirtualKeyboardWindow::on_focus_in_event (GdkEventFocus *ev)
|
VirtualKeyboardWindow::on_focus_in_event (GdkEventFocus *ev)
|
||||||
{
|
{
|
||||||
_pianomm->grab_focus ();
|
_piano.grab_focus ();
|
||||||
return ArdourWindow::on_focus_in_event(ev);
|
return ArdourWindow::on_focus_in_event(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,15 +378,22 @@ VirtualKeyboardWindow::on_unmap ()
|
||||||
bool
|
bool
|
||||||
VirtualKeyboardWindow::on_key_press_event (GdkEventKey* ev)
|
VirtualKeyboardWindow::on_key_press_event (GdkEventKey* ev)
|
||||||
{
|
{
|
||||||
_pianomm->grab_focus ();
|
_piano.grab_focus ();
|
||||||
return ARDOUR_UI_UTILS::relay_key_press (ev, this);
|
return ARDOUR_UI_UTILS::relay_key_press (ev, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VirtualKeyboardWindow::select_keyboard_layout (std::string const& l)
|
VirtualKeyboardWindow::select_keyboard_layout (std::string const& l)
|
||||||
{
|
{
|
||||||
piano_keyboard_set_keyboard_layout (_piano, l.c_str ());
|
if (l == "QWERTY") {
|
||||||
_keyboard_layout.set_active (l);
|
_piano.set_keyboard_layout (PianoKeyboard::QWERTY);
|
||||||
|
} else if (l == "QWERTZ") {
|
||||||
|
_piano.set_keyboard_layout (PianoKeyboard::QWERTZ);
|
||||||
|
} else if (l == "AZERTY") {
|
||||||
|
_piano.set_keyboard_layout (PianoKeyboard::AZERTY);
|
||||||
|
} else if (l == "DVORAK") {
|
||||||
|
_piano.set_keyboard_layout (PianoKeyboard::DVORAK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -421,15 +425,15 @@ VirtualKeyboardWindow::toggle_bankpatch (GdkEventButton*)
|
||||||
void
|
void
|
||||||
VirtualKeyboardWindow::update_octave_key ()
|
VirtualKeyboardWindow::update_octave_key ()
|
||||||
{
|
{
|
||||||
piano_keyboard_set_octave (_piano, _piano_octave_key.get_value_as_int ());
|
_piano.set_octave (_piano_octave_key.get_value_as_int ());
|
||||||
_pianomm->grab_focus ();
|
_piano.grab_focus ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VirtualKeyboardWindow::update_octave_range ()
|
VirtualKeyboardWindow::update_octave_range ()
|
||||||
{
|
{
|
||||||
piano_keyboard_set_octave_range (_piano, _piano_octave_range.get_value_as_int ());
|
_piano.set_octave_range (_piano_octave_range.get_value_as_int ());
|
||||||
_pianomm->grab_focus ();
|
_piano.grab_focus ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -445,7 +449,7 @@ VirtualKeyboardWindow::toggle_highlight_piano (GdkEventButton*)
|
||||||
{
|
{
|
||||||
bool a = !_highlight_grand_piano.get_active ();
|
bool a = !_highlight_grand_piano.get_active ();
|
||||||
_highlight_grand_piano.set_active (a);
|
_highlight_grand_piano.set_active (a);
|
||||||
piano_keyboard_set_grand_piano_highlight (_piano, a);
|
_piano.set_grand_piano_highlight (a);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +458,7 @@ VirtualKeyboardWindow::toggle_highlight_key (GdkEventButton*)
|
||||||
{
|
{
|
||||||
bool a = !_highlight_key_range.get_active ();
|
bool a = !_highlight_key_range.get_active ();
|
||||||
_highlight_key_range.set_active (a);
|
_highlight_key_range.set_active (a);
|
||||||
piano_keyboard_set_keyboard_cue (_piano, a);
|
_piano.set_keyboard_cue (a);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,7 +467,7 @@ VirtualKeyboardWindow::toggle_note_label (GdkEventButton*)
|
||||||
{
|
{
|
||||||
bool a = !_show_note_label.get_active ();
|
bool a = !_show_note_label.get_active ();
|
||||||
_show_note_label.set_active (a);
|
_show_note_label.set_active (a);
|
||||||
piano_keyboard_show_note_label (_piano, a);
|
_piano.show_note_label (a);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,15 +522,13 @@ VirtualKeyboardWindow::update_velocity_settings (int ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_yaxis_velocity.get_active ()) {
|
if (_yaxis_velocity.get_active ()) {
|
||||||
piano_keyboard_set_velocities (_piano,
|
_piano.set_velocities (_piano_min_velocity.get_value_as_int (),
|
||||||
_piano_min_velocity.get_value_as_int (),
|
_piano_max_velocity.get_value_as_int (),
|
||||||
_piano_max_velocity.get_value_as_int (),
|
_piano_key_velocity.get_value_as_int ());
|
||||||
_piano_key_velocity.get_value_as_int ());
|
|
||||||
} else {
|
} else {
|
||||||
piano_keyboard_set_velocities (_piano,
|
_piano.set_velocities (_piano_key_velocity.get_value_as_int (),
|
||||||
_piano_key_velocity.get_value_as_int (),
|
_piano_key_velocity.get_value_as_int (),
|
||||||
_piano_key_velocity.get_value_as_int (),
|
_piano_key_velocity.get_value_as_int ());
|
||||||
_piano_key_velocity.get_value_as_int ());
|
|
||||||
}
|
}
|
||||||
update_sensitivity ();
|
update_sensitivity ();
|
||||||
}
|
}
|
||||||
|
@ -537,7 +539,7 @@ VirtualKeyboardWindow::update_sensitivity ()
|
||||||
bool c = _yaxis_velocity.get_active ();
|
bool c = _yaxis_velocity.get_active ();
|
||||||
_piano_min_velocity.set_sensitive (c);
|
_piano_min_velocity.set_sensitive (c);
|
||||||
_piano_max_velocity.set_sensitive (c);
|
_piano_max_velocity.set_sensitive (c);
|
||||||
_pianomm->grab_focus ();
|
_piano.grab_focus ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -552,7 +554,7 @@ VirtualKeyboardWindow::pitch_slider_adjusted ()
|
||||||
void
|
void
|
||||||
VirtualKeyboardWindow::note_on_event_handler (int note, int velocity)
|
VirtualKeyboardWindow::note_on_event_handler (int note, int velocity)
|
||||||
{
|
{
|
||||||
_pianomm->grab_focus ();
|
_piano.grab_focus ();
|
||||||
if (!_session) {
|
if (!_session) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,16 +96,6 @@ protected:
|
||||||
bool on_focus_in_event (GdkEventFocus*);
|
bool on_focus_in_event (GdkEventFocus*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void _note_on_event_handler (GtkWidget*, int note, int vel, gpointer arg)
|
|
||||||
{
|
|
||||||
static_cast<VirtualKeyboardWindow*> (arg)->note_on_event_handler (note, vel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _note_off_event_handler (GtkWidget*, int note, gpointer arg)
|
|
||||||
{
|
|
||||||
static_cast<VirtualKeyboardWindow*> (arg)->note_off_event_handler (note);
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_unmap ();
|
void on_unmap ();
|
||||||
bool on_key_press_event (GdkEventKey*);
|
bool on_key_press_event (GdkEventKey*);
|
||||||
|
|
||||||
|
@ -129,8 +119,7 @@ private:
|
||||||
bool toggle_note_label (GdkEventButton*);
|
bool toggle_note_label (GdkEventButton*);
|
||||||
bool send_panic_message (GdkEventButton*);
|
bool send_panic_message (GdkEventButton*);
|
||||||
|
|
||||||
PianoKeyboard* _piano;
|
PianoKeyboard _piano;
|
||||||
Gtk::Widget* _pianomm;
|
|
||||||
Gtk::SpinButton _piano_channel;
|
Gtk::SpinButton _piano_channel;
|
||||||
|
|
||||||
Gtk::SpinButton _transpose_output;
|
Gtk::SpinButton _transpose_output;
|
||||||
|
|
|
@ -125,7 +125,7 @@ gtk2_ardour_sources = [
|
||||||
'ghostregion.cc',
|
'ghostregion.cc',
|
||||||
'global_port_matrix.cc',
|
'global_port_matrix.cc',
|
||||||
'group_tabs.cc',
|
'group_tabs.cc',
|
||||||
'gtk_pianokeyboard.c',
|
'gtk_pianokeyboard.cc',
|
||||||
'gui_object.cc',
|
'gui_object.cc',
|
||||||
'idleometer.cc',
|
'idleometer.cc',
|
||||||
'insert_remove_time_dialog.cc',
|
'insert_remove_time_dialog.cc',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user