{
   "name" : "A Simple Synthesizer Keyboard 2",
   "author" : "prko",
   "ancestor_list" : [],
   "description" : "[MIDI output enabled version](https://scsynth.org/t/a-small-utility-computer-midi-keyboard-supporting-midi-output/8868)",
   "labels" : [
      "keyboard"
   ],
   "id" : "1-5hI",
   "is_private" : null,
   "code" : "(\r\n\ts.waitForBoot{\r\n\t\tvar midiPitchOffset, k, n, kLabel, intervals, bIndecise, x;\r\n\t\tvar w, kView, bView, k1, k2, k3, k4, b, bs1, bs2, bs3, bs4, bs;\r\n\t\tvar bLay, kLay, ctl, kAct, lastPressedButton, pressedOrReleased;\r\n\t\r\n\tmidiPitchOffset = 48;\r\n\r\n\t\tk = ();\r\n\t\t[\r\n\t\t\t\\z, \\s, \\x, \\d, \\c, \\v, \\g, \\b, \\h, \\n, \\j, \\m, ',',\r\n\t\t\t\\l, '.', ';', '/', \\q, \\2, \\w, \\3, \\e, \\4, \\r,\r\n\t\t\t\\t, \\6, \\y, \\7, \\u, \\i, \\9, \\o, \\0, \\p, '-', '[', ']'\r\n\t\t].do { |item, index|\r\n\t\t\tk.add(item -> index)\r\n\t\t};\r\n\t\tn = k.size;\r\n\r\n\t\tkLabel = {|parent, label, width|\r\n\t\t\tlabel = if (\"nil\".matchRegexp(label.asString)) { \"\" } { label };\r\n\t\t\tStaticText(parent, width@30)\r\n\t\t\t.string_(\" \" ++ label)\r\n\t\t\t.align_(\\topLeft)\r\n\t\t\t.font_(Font(\"Arial\", 9))\r\n\t\t\t.stringColor_(Color.grey(0.2))\r\n\t\t};\r\n\r\n\t\tintervals = [\r\n\t\t\t[18, 20, 22, \\, 25, 27, \\, 30, 32, 34, \\],\r\n\t\t\t[17, 19, 21, 23, 24, 26, 28, 29, 31, 33, 35, 36, \\],\r\n\t\t\t[\\, 1, 3, \\, 6, 8, 10, \\, 13, 15, \\],\r\n\t\t\t[0, 2, 4, 5, 7, 9, 11, 12, 14, 16]\r\n\t\t];\r\n\r\n\t\tbIndecise = intervals.flat;\r\n\r\n\t\tx = { |i|\r\n\t\t\t{ |g = 0|\r\n\t\t\t\tLFTri.ar((i + 48 + [0, 0.15]).midicps)\r\n\t\t\t\t* 0.1\r\n\t\t\t\t* Env.adsr.kr(gate:g);\r\n\t\t\t}.play\r\n\t\t}!n;\r\n\r\n\t\tctl = { |i=0, gate=0|\r\n\t\t\tif(i.class.asSymbol == \\Integer) { x[i].set(\\g, gate) }\r\n\t\t};\r\n\r\n\t\tw = Window(\"Computer MIDI Keyboard\", Rect(0, 0, 500, 220));\r\n\t\tw.front\r\n\t\t.onClose_{ { |i| x[i].free }!n };\r\n\r\n\t\tkView = w.view;\r\n\t\tbView = w.view;\r\n\r\n\t\tb = { |parent, label, width|\r\n\t\t\tvar lableIndex;\r\n\t\t\tButton(parent, width@30)\r\n\t\t\t.states_([\r\n\t\t\t\t[label + midiPitchOffset, Color.white, Color.grey(0.5, 0.5)],\r\n\t\t\t\t[label + midiPitchOffset, Color.white, Color.grey(0.2, 0.5)]\r\n\t\t\t])\r\n\t\t\t.mouseDownAction_{\r\n\t\t\t\tlastPressedButton = label;\r\n\t\t\t\tlableIndex = bIndecise.find([label]);\r\n\t\t\t\tctl.(label, 1);\r\n\t\t\t\tbs[lableIndex].value = 1\r\n\t\t\t}\r\n\t\t\t.action_{\t\t\t\t\r\n\t\t\t\tlastPressedButton = nil;\r\n\t\t\t\tctl.(label, 0);\r\n\t\t\t\tbs[lableIndex].value = 0\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tkLay = kView.addFlowLayout;\r\n\r\n\t\tkLabel.(kView, \"\", 30);\r\n\t\tkLabel.(kView, \"\", 30);\r\n\t\tintervals[0].collect { |i| kLabel.(kView, k.findKeyForValue(i), 30) };\r\n\t\tkLabel.(kView, \"⌫\", 30);\r\n\r\n\t\tkLay.nextLine;\r\n\r\n\t\tkLabel.(kView, \"⇥\", 50);\r\n\t\tintervals[1].collect { |i| kLabel.(kView, k.findKeyForValue(i), 30) };\r\n\r\n\t\tkLay.nextLine;\r\n\r\n\t\tkLabel.(kView, \"⇪\", 60);\r\n\t\tintervals[2].collect { |i| kLabel.(kView, k.findKeyForValue(i), 30) };\r\n\t\tkLabel.(kView, \"⏎\", 50);\r\n\r\n\t\tkLay.nextLine;\r\n\r\n\t\tkLabel.(kView, \"⇧\", 74);\r\n\t\tintervals[3].collect { |i| kLabel.(kView, k.findKeyForValue(i), 30) };\r\n\t\tkLabel.(kView, \"⇧\", 74);\r\n\r\n\t\tbLay = bView.addFlowLayout;\r\n\r\n\t\tb.(bView, \\, 30);\r\n\t\tb.(bView, \\, 30);\r\n\t\tbs1 = intervals[0].collect { |i| b.(bView, i, 30) };\r\n\t\tb.(bView, \\, 50);\r\n\r\n\t\tbLay.nextLine;\r\n\r\n\t\tb.(bView, \\, 50);\r\n\t\tbs2 = intervals[1].collect { |i| b.(bView, i, 30) };\r\n\r\n\t\tbLay.nextLine;\r\n\r\n\r\n\t\tb.(bView, \\, 60);\r\n\t\tbs3 = intervals[2].collect { |i| b.(bView, i, 30) };\r\n\t\tb.(bView, \\, 54);\r\n\r\n\t\tbLay.nextLine;\r\n\r\n\t\tb.(bView, \\, 74);\r\n\t\tbs4 = intervals[3].collect { |i| b.(bView, i, 30) };\r\n\t\tb.(bView, \\, 74);\r\n\r\n\t\tbLay.nextLine;\r\n\r\n\t\tbs = bs1 ++ bs2 ++ bs3 ++ bs4;\r\n\t\tkAct = { |character, v|\r\n\t\t\tcharacter = character.asSymbol;\r\n\t\t\tif(k.includesKey(character) != false) {\r\n\t\t\t\tvar kToChromaticInterval, bIndex;\r\n\t\t\t\tkToChromaticInterval = k[character];\r\n\t\t\t\tbIndex = bIndecise.find([kToChromaticInterval]);\r\n\t\t\t\tctl.(kToChromaticInterval, v);\r\n\t\t\t\tbs[bIndex].value = v\r\n\t\t\t}\r\n\t\t};\r\n\t\tStaticText(w, 500@70).string_(\r\n\t\t\t\"Press, hold and then release the keys for the numbered buttons using your\\n\"\t++\r\n\t\t\t\"computer keyboard. Alternatively, you might press, hold, and then release each\\n\" ++\r\n\t\t\t\"button using the left button of the computermouse. The multi-touch on\\n\" ++\r\n\t\t\t\"touchscreen may function, but it hasn't been tested.\");\r\n\t\t\r\n\t\tpressedOrReleased = ();\r\n\t\tw.view\r\n\t\t.keyDownAction_{ |view, char|\r\n\t\t\tif (pressedOrReleased[char] != 1) { kAct.(char, 1) };\r\n\t\t\tpressedOrReleased.add(char -> 1)\r\n\t\t}\r\n\t\t.keyUpAction_{ |view, char, mod, unicode, keycode, key|\r\n\t\t\tkAct.(char, 0);\r\n\t\t\tpressedOrReleased.add(char -> 0)\r\n\t\t}\r\n\t\t.mouseUpAction_{ //|view, x, y, modifiers, buttonNumber|\r\n\t\t\tvar lastPressedButtonK = k.findKeyForValue(lastPressedButton);\r\n\t\t\tif(lastPressedButton != nil) { kAct.(lastPressedButtonK, 0) }\r\n\t\t}\r\n\t}\r\n)"
}
