Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

notepat-remote: native Max [key]/[keyup] for sub-ms local input; drop piece key handling

+125 -31
+117 -11
ac-m4l/AC-NotepatRemote.amxd.json
··· 3 3 "fileversion": 1, 4 4 "appversion": { "major": 9, "minor": 0, "revision": 7, "architecture": "x64", "modernui": 1 }, 5 5 "classnamespace": "box", 6 - "rect": [100, 100, 700, 500], 6 + "rect": [100, 100, 900, 620], 7 7 "openrect": [0, 0, 360, 220], 8 8 "openinpresentation": 1, 9 9 "gridsize": [15, 15], 10 10 "enablehscroll": 0, 11 11 "enablevscroll": 0, 12 12 "devicewidth": 360, 13 - "description": "Receive ac-native notepat MIDI via session-server relay and emit to this track", 13 + "description": "ac-native notepat relay + local hotkey input. Native [key]/[keyup] for sub-ms local note entry. jweb~ handles WS relay + UI only.", 14 14 "boxes": [ 15 15 { 16 16 "box": { ··· 25 25 "presentation": 1, 26 26 "presentation_rect": [0, 0, 360, 220], 27 27 "rendermode": 1, 28 - "url": "https://aesthetic.computer/notepat-remote?daw=1&density=1&nogap&v=4" 28 + "url": "https://aesthetic.computer/notepat-remote?daw=1&density=1&nogap&v=5" 29 29 } 30 30 }, 31 31 { ··· 47 47 "maxclass": "newobj", 48 48 "numinlets": 2, 49 49 "numoutlets": 0, 50 - "patching_rect": [10, 300, 60, 22], 50 + "patching_rect": [10, 580, 60, 22], 51 51 "text": "noteout" 52 52 } 53 53 }, 54 54 { 55 55 "box": { 56 - "comment": "Debug: unmatched messages", 56 + "comment": "Debug: unmatched jweb messages", 57 57 "id": "obj-print", 58 58 "maxclass": "newobj", 59 59 "numinlets": 1, 60 60 "numoutlets": 0, 61 - "patching_rect": [500, 300, 200, 22], 61 + "patching_rect": [700, 300, 180, 22], 62 62 "text": "print NOTEPAT-REMOTE" 63 63 } 64 64 }, ··· 91 91 "numinlets": 1, 92 92 "numoutlets": 3, 93 93 "outlettype": ["bang", "int", "int"], 94 - "patching_rect": [420, 250, 90, 22], 94 + "patching_rect": [700, 250, 90, 22], 95 95 "text": "live.thisdevice" 96 96 } 97 97 }, ··· 102 102 "numinlets": 1, 103 103 "numoutlets": 2, 104 104 "outlettype": ["", ""], 105 - "patching_rect": [420, 280, 60, 22], 105 + "patching_rect": [700, 280, 60, 22], 106 106 "text": "route ready" 107 107 } 108 108 }, 109 109 { 110 110 "box": { 111 - "comment": "Tell jweb~ page we are live (page can use this to trigger subscribe)", 111 + "comment": "Activate jweb once Live finishes init", 112 112 "id": "obj-activate", 113 113 "maxclass": "message", 114 114 "numinlets": 2, 115 115 "numoutlets": 1, 116 116 "outlettype": [""], 117 - "patching_rect": [420, 310, 90, 22], 117 + "patching_rect": [700, 330, 120, 22], 118 118 "text": "script daw-activate" 119 119 } 120 + }, 121 + 122 + { 123 + "box": { 124 + "comment": "Native keydown capture — sub-ms path to noteout, bypasses iframe", 125 + "id": "obj-key", 126 + "maxclass": "newobj", 127 + "numinlets": 1, 128 + "numoutlets": 3, 129 + "outlettype": ["int", "int", "int"], 130 + "patching_rect": [10, 420, 40, 22], 131 + "text": "key" 132 + } 133 + }, 134 + { 135 + "box": { 136 + "comment": "Native keyup capture for note-off", 137 + "id": "obj-keyup", 138 + "maxclass": "newobj", 139 + "numinlets": 1, 140 + "numoutlets": 3, 141 + "outlettype": ["int", "int", "int"], 142 + "patching_rect": [260, 420, 50, 22], 143 + "text": "keyup" 144 + } 145 + }, 146 + { 147 + "box": { 148 + "comment": "ASCII → MIDI pitch (notepat layout). 0 = unmapped.", 149 + "id": "obj-expr-on", 150 + "maxclass": "newobj", 151 + "numinlets": 1, 152 + "numoutlets": 1, 153 + "outlettype": ["int"], 154 + "patching_rect": [10, 450, 780, 22], 155 + "text": "expr ($i1==97)?69:($i1==98)?71:($i1==99)?60:($i1==100)?62:($i1==101)?64:($i1==102)?65:($i1==103)?67:($i1==104)?72:($i1==105)?74:($i1==106)?76:($i1==107)?77:($i1==108)?79:($i1==109)?81:($i1==110)?83:($i1==111)?80:($i1==112)?82:($i1==113)?70:($i1==114)?68:($i1==115)?63:($i1==116)?73:($i1==117)?78:($i1==118)?61:($i1==119)?66:($i1==120)?59:($i1==121)?75:($i1==122)?58:0" 156 + } 157 + }, 158 + { 159 + "box": { 160 + "comment": "Same mapping for keyup side", 161 + "id": "obj-expr-off", 162 + "maxclass": "newobj", 163 + "numinlets": 1, 164 + "numoutlets": 1, 165 + "outlettype": ["int"], 166 + "patching_rect": [10, 480, 780, 22], 167 + "text": "expr ($i1==97)?69:($i1==98)?71:($i1==99)?60:($i1==100)?62:($i1==101)?64:($i1==102)?65:($i1==103)?67:($i1==104)?72:($i1==105)?74:($i1==106)?76:($i1==107)?77:($i1==108)?79:($i1==109)?81:($i1==110)?83:($i1==111)?80:($i1==112)?82:($i1==113)?70:($i1==114)?68:($i1==115)?63:($i1==116)?73:($i1==117)?78:($i1==118)?61:($i1==119)?66:($i1==120)?59:($i1==121)?75:($i1==122)?58:0" 168 + } 169 + }, 170 + { 171 + "box": { 172 + "comment": "Drop 0 (unmapped key), pass pitch out of right outlet", 173 + "id": "obj-sel-on", 174 + "maxclass": "newobj", 175 + "numinlets": 1, 176 + "numoutlets": 2, 177 + "outlettype": ["bang", "int"], 178 + "patching_rect": [10, 510, 60, 22], 179 + "text": "select 0" 180 + } 181 + }, 182 + { 183 + "box": { 184 + "id": "obj-sel-off", 185 + "maxclass": "newobj", 186 + "numinlets": 1, 187 + "numoutlets": 2, 188 + "outlettype": ["bang", "int"], 189 + "patching_rect": [260, 510, 60, 22], 190 + "text": "select 0" 191 + } 192 + }, 193 + { 194 + "box": { 195 + "comment": "pitch → (pitch, 100) list for noteout (note-on)", 196 + "id": "obj-pack-on", 197 + "maxclass": "newobj", 198 + "numinlets": 2, 199 + "numoutlets": 1, 200 + "outlettype": ["list"], 201 + "patching_rect": [10, 540, 80, 22], 202 + "text": "pack 0 100" 203 + } 204 + }, 205 + { 206 + "box": { 207 + "comment": "pitch → (pitch, 0) list for noteout (note-off)", 208 + "id": "obj-pack-off", 209 + "maxclass": "newobj", 210 + "numinlets": 2, 211 + "numoutlets": 1, 212 + "outlettype": ["list"], 213 + "patching_rect": [260, 540, 80, 22], 214 + "text": "pack 0 0" 215 + } 120 216 } 121 217 ], 122 218 "lines": [ ··· 128 224 { "patchline": { "source": ["obj-route", 2], "destination": ["obj-print", 0] } }, 129 225 { "patchline": { "source": ["obj-thisdevice", 0], "destination": ["obj-routeready", 0] } }, 130 226 { "patchline": { "source": ["obj-routeready", 0], "destination": ["obj-activate", 0] } }, 131 - { "patchline": { "source": ["obj-activate", 0], "destination": ["obj-jweb", 0] } } 227 + { "patchline": { "source": ["obj-activate", 0], "destination": ["obj-jweb", 0] } }, 228 + 229 + { "patchline": { "source": ["obj-key", 0], "destination": ["obj-expr-on", 0] } }, 230 + { "patchline": { "source": ["obj-expr-on", 0], "destination": ["obj-sel-on", 0] } }, 231 + { "patchline": { "source": ["obj-sel-on", 1], "destination": ["obj-pack-on", 0] } }, 232 + { "patchline": { "source": ["obj-pack-on", 0], "destination": ["obj-noteout", 0] } }, 233 + 234 + { "patchline": { "source": ["obj-keyup", 0], "destination": ["obj-expr-off", 0] } }, 235 + { "patchline": { "source": ["obj-expr-off", 0], "destination": ["obj-sel-off", 0] } }, 236 + { "patchline": { "source": ["obj-sel-off", 1], "destination": ["obj-pack-off", 0] } }, 237 + { "patchline": { "source": ["obj-pack-off", 0], "destination": ["obj-noteout", 0] } } 132 238 ], 133 239 "dependency_cache": [], 134 240 "latency": 0,
+8 -20
system/public/aesthetic.computer/disks/notepat-remote.mjs
··· 204 204 205 205 function act({ event: e }) { 206 206 if (!e?.is) return; 207 - // Dump first ~15 events of any kind so we can see what actually propagates 208 - // into the piece from jweb~. `name` is the AC event type string. 209 - if (eventsSeen < 15) { 210 - eventsSeen += 1; 211 - const name = e.name || "?"; 212 - console.log(`🎹 evt#${eventsSeen} ${name} key=${e.key || ""}`); 213 - } 214 - // Click-to-test-note: tap anywhere on the device UI fires C4 so we can 215 - // verify the Max bridge path without depending on keyboard focus. 207 + // Keyboard input is handled natively in the Max patcher ([key] / [keyup] 208 + // objects direct to [noteout]) for sub-ms latency — no worker round-trip. 209 + // The piece intentionally does NOT listen for keyboard events here to 210 + // avoid double-firing. 211 + // 212 + // Click-to-test-note: tapping the device UI fires C4 so we can smoke-test 213 + // the iframe→BIOS→Max bridge path without depending on keyboard focus. 216 214 if (e.is("touch")) { 217 215 pressLocalKey("c"); 218 216 return; ··· 220 218 if (e.is("lift")) { 221 219 releaseLocalKey("c"); 222 220 return; 223 - } 224 - for (const key of Object.keys(KEY_TO_PITCH)) { 225 - if (e.is(`keyboard:down:${key}`)) { 226 - pressLocalKey(key); 227 - return; 228 - } 229 - if (e.is(`keyboard:up:${key}`)) { 230 - releaseLocalKey(key); 231 - return; 232 - } 233 221 } 234 222 } 235 223 ··· 321 309 322 310 // Footer hint 323 311 if (H - y > 12) { 324 - ink(...fgDim).write("click=C4 | keys c-b=C4..B4", { x: 4, y: H - 8 }); 312 + ink(...fgDim).write("keys=native | click=C4 | ws=relay", { x: 4, y: H - 8 }); 325 313 } 326 314 } 327 315
system/public/m4l/notepat-remote.amxd

This is a binary file and will not be displayed.