MIDIKeyboard a simple GUI keyboard

This GUI widget is pretty similar to the Keyboard (kslider) object in Max - basically

a tool to play MIDI notes and perhaps map scales, visualise real keyboard, etc.

The MIDIKeyboard does not handle any system-midi (SC has other ways of doing that),

the only "midi" about it is that the keys are numbered according to the MIDI standard.

*new(window, bounds, octaves, startnote);

window - A SCWindow in which the MIDIKeyboard will appear

bounds - The Rect of the MIDIKeyboard

octaves - The number of octaves on the keyboard

startnote - The MIDI note number of the first key (48 is the default - that's C3)

keyDownAction_ - The function that key down will trigger.

keyTrackAction_ - The function that moving the cursor will trigger.

keyUpAction_ - The function that key up will trigger.

showScale([scale], startnote, color) - Takes an array with the scale. Startnote is the fundamental.

playScale([scale], startnote, wait) - Takes an array with the scale. Startnote is the fundamental.

inScale(note) - returns true or false if a note is part of a set scale.

setColor(note, Color) - Set a color of a note (still keeps black/white tint).

removeColor(note) - Remove the color of a specific note.

clear - clears the scale or all colors from the keyboard.

keyDown(note) - colors the selected key grey.

keyUp(note) - resets the selected key.

// choose a gui (see GUI helpfile)

GUI.swing;

GUI.cocoa;

// examples

MIDIKeyboard.new

MIDIKeyboard.new(bounds: Rect(20, 10, 273, 60), octaves: 3)

MIDIKeyboard.new(bounds: Rect(20, 10, 364, 60), octaves: 4)

(

w = GUI.window.new("using the keyboard in a SCWindow", Rect(10, 500, 500, 212)).front;

k = MIDIKeyboard.new(w, Rect(20, 20, 364, 60), 4, 48);

l = MIDIKeyboard.new(w, Rect(20, 110, 455, 60), 5, 48);

)

// posting the MIDI note number and the frequency of the note

(

w = GUI.window.new(" using the midi keyboard", Rect(10, 260, 820, 212)).front;

k = MIDIKeyboard.new(w, Rect(20, 20, 776, 160), 4, 48);

k.keyDownAction_({arg note; [\midinote, note, \freq, note.midicps].postln;});

k.keyTrackAction_({arg note; [\midinote, note, \freq, note.midicps].postln;});

)

// displaying a scale on the keyboard

(

k = MIDIKeyboard.new;

k.keyDownAction_({arg note; "Key down : ".post; note.postln;});

k.keyUpAction_({arg note; "Key up : ".post; note.postln;});

k.keyTrackAction_({arg note; "Key tracking : ".post; note.postln;});

k.showScale([0, 2, 4, 6, 8, 10], 48, Color.new(0.4, 0.6,0.8));

)

k.clear; // clear the scale

k.showScale([0, 1, 3, 6, 7, 8, 10]); // in C

k.showScale([0, 1, 3, 6, 7, 8, 10], 50); // in D

k.inScale(69) // returns true or false depending on the note being in the scale

// play a scale

k.playScale([0, 1, 3, 6, 7, 8, 10], 60);

k.playScale([0, 1, 3, 6, 7, 8, 10], 60, 0.3);

k.keyDown(60) // midinote

k.keyUp(60)

k.keyDown(65)

k.keyUp(65)

// a chord

(

k.clear;

k.keyDown(60);

k.keyDown(64);

k.keyDown(67);

)

k.clear;

// or

k.keyDown([60, 64, 68])

k.keyUp([60, 64, 68])

// a sounding example

(

SynthDef(\midikeyboardsine, {arg freq, amp = 0.25;

Out.ar(0, (SinOsc.ar(freq,0,amp)*EnvGen.ar(Env.perc, doneAction:2)).dup)

}).add;

k = MIDIKeyboard.new;

k.keyDownAction_({arg note; Synth(\midikeyboardsine, [\freq, note.midicps])});

k.keyTrackAction_({arg note; Synth(\midikeyboardsine, [\freq, note.midicps])});

k.showScale([0, 3, 6, 9, 10]);

)

// Displaying incoming MIDI notes

// an example where the MIDIKeyboard shows which notes are played on a MIDI controller

// NOTE: there are many ways of working with MIDI in SC, so this is just one quick example...

(

k = MIDIKeyboard.new;

MIDIIn.connect;

MIDIIn.noteOn_({ arg src, chan, num, vel; {k.keyDown(num)}.defer; });

MIDIIn.noteOff_({ arg src, chan, num, vel; {k.keyUp(num)}.defer; });

)

// Playing (outputting) MIDI notes on midi channel 1

(

k = MIDIKeyboard.new;

MIDIClient.init;

m = MIDIOut(0, MIDIClient.destinations.at(0).uid);

k.keyDownAction_({arg note; m.noteOn(0, note, 60);}); // (midi channel 1, midinote, velocity 60)

k.keyUpAction_({arg note; m.noteOff(0, note, 60);});

)

k.setColor(60, Color.red)

// setting color ranges:

(

var oct;

oct = 4;

k = MIDIKeyboard.new(bounds: Rect(20, 10, 364, 60), octaves: oct);

c = [Color.red, Color.yellow, Color.blue, Color.green];

oct.do({arg j;

12.do({arg i;

k.setColor(48+i+(j*12), c[j]);

});

});

)

k.clear // and clear the keyboard of colors

// chords

(

var chord, chords, chordnames;

var menu, play;

var fString, fundamental=60;

w = GUI.window.new("Common Chords", Rect(10, 260, 820, 252)).front;

k = MIDIKeyboard.new(w, Rect(20, 60, 776, 160), 4, 48);

k.keyDownAction_({arg note; fundamental = note;

fString.string_(note.asString);

k.showScale(chord, fundamental, Color.new255(103, 148, 103));

});

k.keyTrackAction_({arg note; fundamental = note;

fString.string_(note.asString);

k.showScale(chord, fundamental, Color.new255(103, 148, 103));

});

k.keyUpAction_({arg note; fundamental = note;

fString.string_(note.asString);

k.showScale(chord, fundamental, Color.new255(103, 148, 103));

});

GUI.staticText.new(w, Rect(350, 20, 100, 20)).string_("Fundamental :");

fString = GUI.staticText.new(w, Rect(436, 20, 50, 20)).string_(fundamental.asString);

chords = [["Major", [0, 4, 7]], ["Minor", [0, 3, 7]],["5", [0, 7]], ["Dominant 7th", [0, 4, 7, 10]], ["Major 7th", [0, 4, 7, 11]], ["Minor 7th", [0, 3, 7, 10]], ["Minor Major 7th", [0, 3, 7, 11]], ["Sus 4", [0, 5, 7]], ["Sus 2", [0, 2, 7]], ["6", [0, 4, 7, 9]], ["Minor 6", [0, 3, 7, 9]], ["9", [0, 2, 4, 7, 10]], ["Minor 9", [0, 2, 3, 7, 10]], ["Major 9", [0, 2, 4, 7, 11]], ["Minor Major 9", [0, 2, 3, 7, 11]], ["11", [0, 2, 4, 5, 7, 11]], ["Minor 11", [0, 2, 3, 5, 7, 10]], ["Major 11", [0, 2, 4, 5, 7, 11]], ["Minor Major 11", [0, 2, 3, 5, 7, 11]], ["13", [0, 2, 4, 7, 9, 10]], ["Minor 13", [0, 2, 3, 7, 9, 10]], ["Major 13", [0, 2, 4, 7, 9, 11]], ["Minor Major 13", [0, 2, 3, 7, 9, 11]], ["add 9", [0, 2, 4, 7]], ["Minor add 9", [0, 2, 3, 7]], ["6 add 9", [0, 2, 4, 7, 9]], ["Minor 6 add 9", [0, 2, 3, 7, 9]], ["Dominant 7th add 11", [0, 4, 5, 7, 10]], ["Major 7th add 11", [0, 4, 5, 7, 11]], ["Minor 7th add 11", [0, 3, 5, 7, 10]], ["Minor Major 7th add 11", [0, 3, 5, 7, 11]], ["Dominant 7th add 13", [0, 4, 7, 9, 10]], ["Major 7th add 13", [0, 4, 7, 9, 11]], ["Minor 7th add 13", [0, 3, 7, 9, 10]], ["Minor Major 7th add 13", [0, 3, 7, 9, 11]], ["7b5", [0, 4, 6, 10]], ["7#5", [0, 4, 8, 10]], ["7b9", [0, 1, 4, 7, 10]], ["7#9", [0, 3, 4, 7, 10]], ["7#5b9", [0, 1, 4, 8, 10]], ["m7b5", [0, 3, 6, 10]], ["m7#5", [0, 3, 8, 10]], ["m7b9", [0, 1, 3, 7, 10]], ["9#11", [0, 2, 4, 6, 7, 10]], ["9b13", [0, 2, 4, 7, 8, 10]], ["6sus4", [0, 5, 7, 9]], ["7sus4", [0, 5, 7, 10]], ["Major 7th Sus4", [0, 5, 7, 11]], ["9sus4", [0, 2, 5, 7, 10]], ["Major 9 Sus4", [0, 2, 5, 7, 11]]];

chordnames = [];

chords.do({arg item; item[0].postln; chordnames = chordnames.add(item[0])});

chord = chords[0][1];

menu = GUI.popUpMenu.new(w,Rect(500,20,150,20))

.items_(chordnames)

.background_(Color.white)

.action_({arg item;

chord = chords[item.value][1];

k.showScale(chord, fundamental, Color.new255(103, 148, 103));

play.focus;

});

play = GUI.button.new(w,Rect(660,20,60,20))

.states_([["play", Color.black, Color.clear]])

.action_({

Task({

chord.do({arg note;

note = note + fundamental;

Synth(\midikeyboardsine, [\freq, note.midicps]);

0.4.wait;

});

0.6.wait;

chord.do({arg note;

note = note + fundamental;

Synth(\midikeyboardsine, [\freq, note.midicps, \amp, 0.1]);

});

}).start;

});

)