// title: A Simple Synthesizer Keyboard 2 // author: prko // description: // [MIDI output enabled version](https://scsynth.org/t/a-small-utility-computer-midi-keyboard-supporting-midi-output/8868) // code: ( s.waitForBoot{ var midiPitchOffset, 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; midiPitchOffset = 48; 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(0, 0, 500, 220)); 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 } .action_{ lastPressedButton = nil; ctl.(label, 0); bs[lableIndex].value = 0 } }; 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 } }; StaticText(w, 500@70).string_( "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) } } } )