Patches from Jeff Snyder.

git-svn-id: svn://svn.code.sf.net/p/jack-keyboard/code/trunk@23 1fa2bf75-7d80-4145-9e94-f9b4e25a1cb2
This commit is contained in:
hselasky 2011-12-27 10:15:19 +00:00
parent b8c0445d75
commit 2367dcbebf
7 changed files with 206 additions and 28 deletions

View File

@ -1,2 +1,4 @@
Edward Tomasz Napierała <trasz@FreeBSD.org> Edward Tomasz Napierała <trasz@FreeBSD.org>
Hans Petter Selasky <hselasky@FreeBSD.org>
Jeff Snyder <jeff@caffeinated.me.uk>
Dan Muresan <danmbox@gmail.com>

View File

@ -28,7 +28,7 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/") set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/")
set(VERSION "2.6") set(VERSION "2.7.1")
set(JackEnable ON CACHE BOOL "Enable support for Jack") set(JackEnable ON CACHE BOOL "Enable support for Jack")
set(LashEnable ON CACHE BOOL "Enable support for Lash") set(LashEnable ON CACHE BOOL "Enable support for Lash")

View File

@ -1,4 +1,4 @@
VERSION?=2.6 VERSION?=2.7.1
help: help:
@echo "Targets: configure all clean install package" @echo "Targets: configure all clean install package"

23
NEWS
View File

@ -1,3 +1,26 @@
User-visible changes between 2.6 and 2.7.1 include:
- fix a warning regarding the redefinition of NNOTES
- raise NNOTES from 127 to 128 (only notes 0..125 were being shown
because 127 was < NNOTES and 126 is black)
- only show the keys that exist on a real piano by default, and add a
"-f" ('full midi keyboard') command line option to show all midi
notes.
- make the dimensions slightly closer to a real piano by:
> making the black key hight two third of the white key height
> making the black key positions vary based on their position in
the octave
- adding a QWERTY_REV layout that has the lower keys on the upper row
of the keyboard
- adding QWERTY_UK and QWERTY_UK_REV layouts that extend the QWERTY
and QWERTY_REV layouts with the punctuation keys available on those
rows
User-visible changes between 2.5 and 2.6 include: User-visible changes between 2.5 and 2.6 include:
- Bugfix: A key volume of zero means key off. - Bugfix: A key volume of zero means key off.

View File

@ -61,8 +61,6 @@
#include <gdk/gdkx.h> #include <gdk/gdkx.h>
#endif #endif
#define NNOTES 127
#define VELOCITY_MAX 127 #define VELOCITY_MAX 127
#define VELOCITY_HIGH 100 #define VELOCITY_HIGH 100
#define VELOCITY_NORMAL 64 #define VELOCITY_NORMAL 64
@ -1699,11 +1697,11 @@ show_version(void)
void void
usage(void) usage(void)
{ {
fprintf(stderr, "usage: jack-keyboard [-CGKTVktur] [ -a <input port>] [-c <channel>] [-b <bank> ] [-p <program>] [-l <layout>]\n"); fprintf(stderr, "usage: jack-keyboard [-CGKTVkturf] [ -a <input port>] [-c <channel>] [-b <bank> ] [-p <program>] [-l <layout>]\n");
fprintf(stderr, " where <channel> is MIDI channel to use for output, from 1 to 16,\n"); fprintf(stderr, " where <channel> is MIDI channel to use for output, from 1 to 16,\n");
fprintf(stderr, " <bank> is MIDI bank to use, from 0 to 16383,\n"); fprintf(stderr, " <bank> is MIDI bank to use, from 0 to 16383,\n");
fprintf(stderr, " <program> is MIDI program to use, from 0 to 127,\n"); fprintf(stderr, " <program> is MIDI program to use, from 0 to 127,\n");
fprintf(stderr, " and <layout> is QWERTY, QWERTZ, AZERTY or DVORAK.\n"); fprintf(stderr, " and <layout> is QWERTY, QWERTY_REV, QWERTY_UK, QWERTY_UK_REV, QWERTZ, AZERTY or DVORAK.\n");
fprintf(stderr, "See manual page for details.\n"); fprintf(stderr, "See manual page for details.\n");
exit(EX_USAGE); exit(EX_USAGE);
@ -1712,7 +1710,7 @@ usage(void)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int ch, enable_keyboard_cue = 0, initial_channel = 1, initial_bank = 0, initial_program = 0; int ch, enable_keyboard_cue = 0, initial_channel = 1, initial_bank = 0, initial_program = 0, full_midi_keyboard = 0;
char *keyboard_layout = NULL, *autoconnect_port_name = NULL; char *keyboard_layout = NULL, *autoconnect_port_name = NULL;
#ifdef HAVE_LASH #ifdef HAVE_LASH
@ -1729,7 +1727,7 @@ main(int argc, char *argv[])
g_log_set_default_handler(log_handler, NULL); g_log_set_default_handler(log_handler, NULL);
while ((ch = getopt(argc, argv, "CGKTVa:nktur:c:b:p:l:")) != -1) { while ((ch = getopt(argc, argv, "CGKTVa:nktur:c:b:p:l:f")) != -1) {
switch (ch) { switch (ch) {
case 'C': case 'C':
enable_keyboard_cue = 1; enable_keyboard_cue = 1;
@ -1826,6 +1824,10 @@ main(int argc, char *argv[])
break; break;
case 'f':
full_midi_keyboard = 1;
break;
case '?': case '?':
default: default:
usage(); usage();
@ -1837,11 +1839,14 @@ main(int argc, char *argv[])
init_gtk_2(); init_gtk_2();
if (full_midi_keyboard)
piano_keyboard_enable_all_midi_notes(keyboard);
if (keyboard_layout != NULL) { if (keyboard_layout != NULL) {
int ret = piano_keyboard_set_keyboard_layout(keyboard, keyboard_layout); int ret = piano_keyboard_set_keyboard_layout(keyboard, keyboard_layout);
if (ret) { if (ret) {
g_critical("Invalid layout, proper choices are QWERTY, QWERTZ, AZERTY and DVORAK."); g_critical("Invalid layout, proper choices are QWERTY, QWERTY_REV, QWERTY_UK, QWERTY_UK_REV, QWERTZ, AZERTY and DVORAK.");
exit(EX_USAGE); exit(EX_USAGE);
} }
} }

View File

@ -77,6 +77,10 @@ draw_keyboard_cue(PianoKeyboard *pk)
static void static void
draw_note(PianoKeyboard *pk, int note) draw_note(PianoKeyboard *pk, int note)
{ {
if (note < pk->min_note)
return;
if (note > pk->max_note)
return;
int is_white, x, w, h; int is_white, x, w, h;
GdkColor black = {0, 0, 0, 0}; GdkColor black = {0, 0, 0, 0};
@ -256,7 +260,7 @@ bind_keys_qwerty(PianoKeyboard *pk)
bind_key(pk, "m", 23); bind_key(pk, "m", 23);
/* Upper keyboard row, first octave - "qwertyu". */ /* Upper keyboard row, first octave - "qwertyu". */
bind_key(pk, "q", 24); bind_key(pk, "q", 24); /* C1 */
bind_key(pk, "2", 25); bind_key(pk, "2", 25);
bind_key(pk, "w", 26); bind_key(pk, "w", 26);
bind_key(pk, "3", 27); bind_key(pk, "3", 27);
@ -270,13 +274,93 @@ bind_keys_qwerty(PianoKeyboard *pk)
bind_key(pk, "u", 35); bind_key(pk, "u", 35);
/* Upper keyboard row, the rest - "iop". */ /* Upper keyboard row, the rest - "iop". */
bind_key(pk, "i", 36); bind_key(pk, "i", 36); /* C2 */
bind_key(pk, "9", 37); bind_key(pk, "9", 37);
bind_key(pk, "o", 38); bind_key(pk, "o", 38);
bind_key(pk, "0", 39); bind_key(pk, "0", 39);
bind_key(pk, "p", 40); bind_key(pk, "p", 40);
} }
static void
bind_keys_qwerty_uk(PianoKeyboard *pk)
{
bind_keys_qwerty(pk);
/* Lower keyboard row - "zxcvbnm". */
bind_key(pk, "backslash", 11); /* B0 */
/* ... */
bind_key(pk, "comma", 24); /* C1 */
bind_key(pk, "l", 25);
bind_key(pk, "period", 26);
bind_key(pk, "semicolon", 27);
bind_key(pk, "slash", 28);
/* Upper keyboard row, the rest - "iop". */
bind_key(pk, "bracketleft", 41); /* F6 */
bind_key(pk, "equal", 42);
bind_key(pk, "bracketright", 43);
}
static void
bind_keys_qwerty_rev(PianoKeyboard *pk)
{
clear_notes(pk);
/* Lower keyboard row - "zxcvbnm". */
bind_key(pk, "z", 24); /* C1 */
bind_key(pk, "s", 25);
bind_key(pk, "x", 26);
bind_key(pk, "d", 27);
bind_key(pk, "c", 28);
bind_key(pk, "v", 29);
bind_key(pk, "g", 30);
bind_key(pk, "b", 31);
bind_key(pk, "h", 32);
bind_key(pk, "n", 33);
bind_key(pk, "j", 34);
bind_key(pk, "m", 35);
/* Upper keyboard row, first octave - "qwertyu". */
bind_key(pk, "q", 12); /* C0 */
bind_key(pk, "2", 13);
bind_key(pk, "w", 14);
bind_key(pk, "3", 15);
bind_key(pk, "e", 16);
bind_key(pk, "r", 17);
bind_key(pk, "5", 18);
bind_key(pk, "t", 19);
bind_key(pk, "6", 20);
bind_key(pk, "y", 21);
bind_key(pk, "7", 22);
bind_key(pk, "u", 23);
/* Upper keyboard row, the rest - "iop". */
bind_key(pk, "i", 24); /* C1 */
bind_key(pk, "9", 25);
bind_key(pk, "o", 26);
bind_key(pk, "0", 27);
bind_key(pk, "p", 28);
}
static void
bind_keys_qwerty_uk_rev(PianoKeyboard *pk)
{
bind_keys_qwerty_rev(pk);
/* Lower keyboard row - "zxcvbnm". */
bind_key(pk, "backslash", 23); /* B-1 */
/* ... */
bind_key(pk, "comma", 36); /* C2 */
bind_key(pk, "l", 37);
bind_key(pk, "period", 38);
bind_key(pk, "semicolon", 39);
bind_key(pk, "slash", 40);
/* Upper keyboard row, the rest - "iop". */
bind_key(pk, "bracketleft", 29);
bind_key(pk, "equal", 30);
bind_key(pk, "bracketright", 31);
}
static void static void
bind_keys_qwertz(PianoKeyboard *pk) bind_keys_qwertz(PianoKeyboard *pk)
{ {
@ -431,8 +515,8 @@ get_note_for_xy(PianoKeyboard *pk, int x, int y)
height = GTK_WIDGET(pk)->allocation.height; height = GTK_WIDGET(pk)->allocation.height;
if (y <= height / 2) { if (y <= ((height * 2) / 3)) { /* might be a black key */
for (note = 0; note < NNOTES - 1; note++) { for (note = 0; note <= pk->max_note; ++note) {
if (pk->notes[note].white) if (pk->notes[note].white)
continue; continue;
@ -441,7 +525,7 @@ get_note_for_xy(PianoKeyboard *pk, int x, int y)
} }
} }
for (note = 0; note < NNOTES - 1; note++) { for (note = 0; note <= pk->max_note; ++note) {
if (!pk->notes[note].white) if (!pk->notes[note].white)
continue; continue;
@ -534,13 +618,48 @@ piano_keyboard_size_request(GtkWidget *widget, GtkRequisition *requisition)
requisition->height = PIANO_KEYBOARD_DEFAULT_HEIGHT; requisition->height = PIANO_KEYBOARD_DEFAULT_HEIGHT;
} }
static int is_black(int key)
{
int note_in_octave = key % 12;
if( note_in_octave == 1 || note_in_octave == 3 ||
note_in_octave == 6 || note_in_octave == 8 || note_in_octave == 10)
return 1;
return 0;
}
static double black_key_left_shift(int key)
{
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;
}
static void static void
recompute_dimensions(PianoKeyboard *pk) recompute_dimensions(PianoKeyboard *pk)
{ {
int number_of_white_keys, key_width, black_key_width, useful_width, note, int number_of_white_keys = 0, skipped_white_keys = 0, key_width, black_key_width, useful_width, note,
white_key = 0, note_in_octave, width, height; white_key, width, height;
number_of_white_keys = (NNOTES - 1) * (7.0 / 12.0); for (note = pk->min_note; note <= pk->max_note; ++note)
if (!is_black(note))
++number_of_white_keys;
for (note = 0; note < pk->min_note; ++note)
if (!is_black(note))
++skipped_white_keys;
width = GTK_WIDGET(pk)->allocation.width; width = GTK_WIDGET(pk)->allocation.width;
height = GTK_WIDGET(pk)->allocation.height; height = GTK_WIDGET(pk)->allocation.height;
@ -550,18 +669,15 @@ recompute_dimensions(PianoKeyboard *pk)
useful_width = number_of_white_keys * key_width; useful_width = number_of_white_keys * key_width;
pk->widget_margin = (width - useful_width) / 2; pk->widget_margin = (width - useful_width) / 2;
for (note = 0, white_key = 0; note < NNOTES - 2; note++) { for (note = 0, white_key = -skipped_white_keys; note < NNOTES; note++) {
note_in_octave = note % 12; if (is_black(note)) {
if (note_in_octave == 1 || note_in_octave == 3 || note_in_octave == 6 ||
note_in_octave == 8 || note_in_octave == 10) {
/* This note is black key. */ /* This note is black key. */
pk->notes[note].x = pk->widget_margin + white_key * key_width - black_key_width / 2; pk->notes[note].x = pk->widget_margin +
(white_key * key_width) -
(black_key_width * black_key_left_shift(note));
pk->notes[note].w = black_key_width; pk->notes[note].w = black_key_width;
pk->notes[note].h = height / 2; pk->notes[note].h = (height * 2) / 3;
pk->notes[note].white = 0; pk->notes[note].white = 0;
continue; continue;
} }
@ -663,6 +779,8 @@ piano_keyboard_new(void)
pk->note_being_pressed_using_mouse = -1; pk->note_being_pressed_using_mouse = -1;
memset((void *)pk->notes, 0, sizeof(struct Note) * NNOTES); memset((void *)pk->notes, 0, sizeof(struct Note) * NNOTES);
pk->key_bindings = g_hash_table_new(g_str_hash, g_str_equal); pk->key_bindings = g_hash_table_new(g_str_hash, g_str_equal);
pk->min_note = PIANO_MIN_NOTE;
pk->max_note = PIANO_MAX_NOTE;
bind_keys_qwerty(pk); bind_keys_qwerty(pk);
return (widget); return (widget);
@ -727,6 +845,15 @@ piano_keyboard_set_keyboard_layout(PianoKeyboard *pk, const char *layout)
if (!strcasecmp(layout, "QWERTY")) { if (!strcasecmp(layout, "QWERTY")) {
bind_keys_qwerty(pk); bind_keys_qwerty(pk);
} else if (!strcasecmp(layout, "QWERTY_REV")) {
bind_keys_qwerty_rev(pk);
} else if (!strcasecmp(layout, "QWERTY_UK")) {
bind_keys_qwerty_uk(pk);
} else if (!strcasecmp(layout, "QWERTY_UK_REV")) {
bind_keys_qwerty_uk_rev(pk);
} else if (!strcasecmp(layout, "QWERTZ")) { } else if (!strcasecmp(layout, "QWERTZ")) {
bind_keys_qwertz(pk); bind_keys_qwertz(pk);
@ -744,3 +871,11 @@ piano_keyboard_set_keyboard_layout(PianoKeyboard *pk, const char *layout)
return (FALSE); return (FALSE);
} }
void
piano_keyboard_enable_all_midi_notes(PianoKeyboard* pk)
{
pk->min_note = 0;
pk->max_note = NNOTES-1;
recompute_dimensions(pk);
}

View File

@ -42,7 +42,17 @@ G_BEGIN_DECLS
typedef struct _PianoKeyboard PianoKeyboard; typedef struct _PianoKeyboard PianoKeyboard;
typedef struct _PianoKeyboardClass PianoKeyboardClass; typedef struct _PianoKeyboardClass PianoKeyboardClass;
#define NNOTES 127 /* A note about note numbers:
0 = C-1 (midi minmum)
21 = A0 (piano minimum)
60 = C4 (middle C)
108 = C7 (piano maximum)
127 = G9 (midi maximum)
*/
#define NNOTES 128
#define PIANO_MIN_NOTE 21
#define PIANO_MAX_NOTE 108
#define OCTAVE_MIN -1 #define OCTAVE_MIN -1
#define OCTAVE_MAX 7 #define OCTAVE_MAX 7
@ -66,6 +76,8 @@ struct _PianoKeyboard
int octave; int octave;
int widget_margin; int widget_margin;
int note_being_pressed_using_mouse; int note_being_pressed_using_mouse;
int min_note;
int max_note;
volatile struct Note notes[NNOTES]; volatile struct Note notes[NNOTES];
/* Table used to translate from PC keyboard character to MIDI note number. */ /* Table used to translate from PC keyboard character to MIDI note number. */
GHashTable *key_bindings; GHashTable *key_bindings;
@ -85,6 +97,7 @@ void piano_keyboard_set_note_off (PianoKeyboard *pk, int note);
void piano_keyboard_set_keyboard_cue (PianoKeyboard *pk, int enabled); void piano_keyboard_set_keyboard_cue (PianoKeyboard *pk, int enabled);
void piano_keyboard_set_octave (PianoKeyboard *pk, int octave); void piano_keyboard_set_octave (PianoKeyboard *pk, int octave);
gboolean piano_keyboard_set_keyboard_layout (PianoKeyboard *pk, const char *layout); gboolean piano_keyboard_set_keyboard_layout (PianoKeyboard *pk, const char *layout);
void piano_keyboard_enable_all_midi_notes(PianoKeyboard* pk);
G_END_DECLS G_END_DECLS