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>
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)
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(LashEnable ON CACHE BOOL "Enable support for Lash")

View File

@ -1,4 +1,4 @@
VERSION?=2.6
VERSION?=2.7.1
help:
@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:
- Bugfix: A key volume of zero means key off.

View File

@ -61,8 +61,6 @@
#include <gdk/gdkx.h>
#endif
#define NNOTES 127
#define VELOCITY_MAX 127
#define VELOCITY_HIGH 100
#define VELOCITY_NORMAL 64
@ -1699,11 +1697,11 @@ show_version(void)
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, " <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, " 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");
exit(EX_USAGE);
@ -1712,7 +1710,7 @@ usage(void)
int
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;
#ifdef HAVE_LASH
@ -1729,7 +1727,7 @@ main(int argc, char *argv[])
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) {
case 'C':
enable_keyboard_cue = 1;
@ -1826,6 +1824,10 @@ main(int argc, char *argv[])
break;
case 'f':
full_midi_keyboard = 1;
break;
case '?':
default:
usage();
@ -1837,11 +1839,14 @@ main(int argc, char *argv[])
init_gtk_2();
if (full_midi_keyboard)
piano_keyboard_enable_all_midi_notes(keyboard);
if (keyboard_layout != NULL) {
int ret = piano_keyboard_set_keyboard_layout(keyboard, keyboard_layout);
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);
}
}

View File

@ -77,6 +77,10 @@ draw_keyboard_cue(PianoKeyboard *pk)
static void
draw_note(PianoKeyboard *pk, int note)
{
if (note < pk->min_note)
return;
if (note > pk->max_note)
return;
int is_white, x, w, h;
GdkColor black = {0, 0, 0, 0};
@ -256,7 +260,7 @@ bind_keys_qwerty(PianoKeyboard *pk)
bind_key(pk, "m", 23);
/* 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, "w", 26);
bind_key(pk, "3", 27);
@ -270,13 +274,93 @@ bind_keys_qwerty(PianoKeyboard *pk)
bind_key(pk, "u", 35);
/* 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, "o", 38);
bind_key(pk, "0", 39);
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
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;
if (y <= height / 2) {
for (note = 0; note < NNOTES - 1; note++) {
if (y <= ((height * 2) / 3)) { /* might be a black key */
for (note = 0; note <= pk->max_note; ++note) {
if (pk->notes[note].white)
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)
continue;
@ -534,13 +618,48 @@ piano_keyboard_size_request(GtkWidget *widget, GtkRequisition *requisition)
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
recompute_dimensions(PianoKeyboard *pk)
{
int number_of_white_keys, key_width, black_key_width, useful_width, note,
white_key = 0, note_in_octave, width, height;
int number_of_white_keys = 0, skipped_white_keys = 0, key_width, black_key_width, useful_width, note,
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;
height = GTK_WIDGET(pk)->allocation.height;
@ -550,18 +669,15 @@ recompute_dimensions(PianoKeyboard *pk)
useful_width = number_of_white_keys * key_width;
pk->widget_margin = (width - useful_width) / 2;
for (note = 0, white_key = 0; note < NNOTES - 2; note++) {
note_in_octave = note % 12;
if (note_in_octave == 1 || note_in_octave == 3 || note_in_octave == 6 ||
note_in_octave == 8 || note_in_octave == 10) {
for (note = 0, white_key = -skipped_white_keys; note < NNOTES; note++) {
if (is_black(note)) {
/* 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].h = height / 2;
pk->notes[note].h = (height * 2) / 3;
pk->notes[note].white = 0;
continue;
}
@ -663,6 +779,8 @@ piano_keyboard_new(void)
pk->note_being_pressed_using_mouse = -1;
memset((void *)pk->notes, 0, sizeof(struct Note) * NNOTES);
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);
return (widget);
@ -727,6 +845,15 @@ piano_keyboard_set_keyboard_layout(PianoKeyboard *pk, const char *layout)
if (!strcasecmp(layout, "QWERTY")) {
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")) {
bind_keys_qwertz(pk);
@ -744,3 +871,11 @@ piano_keyboard_set_keyboard_layout(PianoKeyboard *pk, const char *layout)
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 _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_MAX 7
@ -66,6 +76,8 @@ struct _PianoKeyboard
int octave;
int widget_margin;
int note_being_pressed_using_mouse;
int min_note;
int max_note;
volatile struct Note notes[NNOTES];
/* Table used to translate from PC keyboard character to MIDI note number. */
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_octave (PianoKeyboard *pk, int octave);
gboolean piano_keyboard_set_keyboard_layout (PianoKeyboard *pk, const char *layout);
void piano_keyboard_enable_all_midi_notes(PianoKeyboard* pk);
G_END_DECLS