Hi there,
I have made a small utility: computer MIDI keyboard supporting MIDI output. Would it be useful for many users if I released it as a Quark? Or is there already a Quark or library with this feature?
(
MIDIClient.init;
~midiOut = MIDIOut(0);
~musicalTyping = { |ch = 0, midiPitchOffset = 48, onVelocity = 63, offVelocity = 63, left = 0, bottom = 0|
s.waitForBoot{
var k, n, kLabel, intervals, bIndecise, x;
var w, kView, bView, k1, k2, k3, k4, b, bs1, bs2, bs3, bs4, bs;
var bLay, kLay, ctl, kAct, lastPressedButton, pressedOrReleased;
k = ();
[
\z, \s, \x, \d, \c, \v, \g, \b, \h, \n, \j, \m, ',',
\l, '.', ';', '/', \q, \2, \w, \3, \e, \4, \r,
\t, \6, \y, \7, \u, \i, \9, \o, \0, \p, '-', '[', ']'
].do { |item, index|
k.add(item -> index)
};
n = k.size;
kLabel = {|parent, label, width|
label = if ("nil".matchRegexp(label.asString)) { "" } { label };
StaticText(parent, width@30)
.string_(" " ++ label)
.align_(\topLeft)
.font_(Font("Arial", 9))
.stringColor_(Color.grey(0.2))
};
intervals = [
[18, 20, 22, \, 25, 27, \, 30, 32, 34, \],
[17, 19, 21, 23, 24, 26, 28, 29, 31, 33, 35, 36, \],
[\, 1, 3, \, 6, 8, 10, \, 13, 15, \],
[0, 2, 4, 5, 7, 9, 11, 12, 14, 16]
];
bIndecise = intervals.flat;
x = { |i|
{ |g = 0|
LFTri.ar((i + 48 + [0, 0.15]).midicps)
* 0.1
* Env.adsr.kr(gate:g);
}.play
}!n;
ctl = { |i=0, gate=0|
if(i.class.asSymbol == \Integer) { x[i].set(\g, gate) }
};
w = Window("Computer MIDI Keyboard", Rect(left, bottom, 500, 370));
w.front
.onClose_{ { |i| x[i].free }!n };
kView = w.view;
bView = w.view;
b = { |parent, label, width|
var lableIndex;
Button(parent, width@30)
.states_([
[label + midiPitchOffset, Color.white, Color.grey(0.5, 0.5)],
[label + midiPitchOffset, Color.white, Color.grey(0.2, 0.5)]
])
.mouseDownAction_{
lastPressedButton = label;
lableIndex = bIndecise.find([label]);
ctl.(label, 1);
bs[lableIndex].value = 1;
~midiOut.noteOn(ch, label + midiPitchOffset, onVelocity)
}
.action_{
lastPressedButton = nil;
ctl.(label, 0);
bs[lableIndex].value = 0;
~midiOut.noteOff(ch, label + midiPitchOffset, onVelocity)
}
};
kLay = kView.addFlowLayout;
kLabel.(kView, "", 30);
kLabel.(kView, "", 30);
intervals[0].collect { |i| kLabel.(kView, k.findKeyForValue(i), 30) };
kLabel.(kView, "⌫", 30);
kLay.nextLine;
kLabel.(kView, "⇥", 50);
intervals[1].collect { |i| kLabel.(kView, k.findKeyForValue(i), 30) };
kLay.nextLine;
kLabel.(kView, "⇪", 60);
intervals[2].collect { |i| kLabel.(kView, k.findKeyForValue(i), 30) };
kLabel.(kView, "⏎", 50);
kLay.nextLine;
kLabel.(kView, "⇧", 74);
intervals[3].collect { |i| kLabel.(kView, k.findKeyForValue(i), 30) };
kLabel.(kView, "⇧", 74);
bLay = bView.addFlowLayout;
b.(bView, \, 30);
b.(bView, \, 30);
bs1 = intervals[0].collect { |i| b.(bView, i, 30) };
b.(bView, \, 50);
bLay.nextLine;
b.(bView, \, 50);
bs2 = intervals[1].collect { |i| b.(bView, i, 30) };
bLay.nextLine;
b.(bView, \, 60);
bs3 = intervals[2].collect { |i| b.(bView, i, 30) };
b.(bView, \, 54);
bLay.nextLine;
b.(bView, \, 74);
bs4 = intervals[3].collect { |i| b.(bView, i, 30) };
b.(bView, \, 74);
bLay.nextLine;
bs = bs1 ++ bs2 ++ bs3 ++ bs4;
kAct = { |character, v|
character = character.asSymbol;
if(k.trueAt(character) != false) {
var kToChromaticInterval, bIndex;
kToChromaticInterval = k[character];
bIndex = bIndecise.find([kToChromaticInterval]);
ctl.(kToChromaticInterval, v);
bs[bIndex].value = v;
if (v == 0) {
~midiOut.noteOff(ch, kToChromaticInterval + midiPitchOffset, onVelocity)
} {
~midiOut.noteOn(ch, kToChromaticInterval + midiPitchOffset, offVelocity)
}
}
};
StaticText(w, 500@220).string_(
"Assgined MIDI output device:" + MIDIClient.destinations[~midiOut.port].device + "\n" ++
"Assgined MIDI output name:" + MIDIClient.destinations[~midiOut.port].name + "\n" ++
"Assgined MIDI output uid:" + MIDIClient.destinations[~midiOut.port].uid + "\n\n" ++
"output channel:" + (ch + 1) ++ "\n\n" ++
"note on velocity:" + onVelocity ++ "\n" ++
"note off velocity:" + offVelocity ++ "\n\n" ++
"Press, hold and then release the keys for the numbered buttons using your\n" ++
"computer keyboard. Alternatively, you might press, hold, and then release each\n" ++
"button using the left button of the computermouse. The multi-touch on\n" ++
"touchscreen may function, but it hasn't been tested.");
pressedOrReleased = ();
w.view
.keyDownAction_{ |view, char|
if (pressedOrReleased[char] != 1) { kAct.(char, 1) };
pressedOrReleased.add(char -> 1)
}
.keyUpAction_{ |view, char, mod, unicode, keycode, key|
kAct.(char, 0);
pressedOrReleased.add(char -> 0)
}
.mouseUpAction_{ //|view, x, y, modifiers, buttonNumber|
var lastPressedButtonK = k.findKeyForValue(lastPressedButton);
if(lastPressedButton != nil) { kAct.(lastPressedButtonK, 0) }
}
}
};
~musicalTyping.()
)