Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

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

sync: merge knot/tangled main into GitHub main

+63 -18
+27 -3
ac-m4l/AC-NotepatRemote.amxd.json
··· 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&nogap" 28 + "url": "https://aesthetic.computer/notepat-remote?daw=1&density=1&nogap" 29 29 } 30 30 }, 31 31 { ··· 53 53 }, 54 54 { 55 55 "box": { 56 - "comment": "Debug: unmatched messages land here", 56 + "comment": "Debug: unmatched messages", 57 57 "id": "obj-print", 58 58 "maxclass": "newobj", 59 59 "numinlets": 1, 60 60 "numoutlets": 0, 61 - "patching_rect": [200, 300, 200, 22], 61 + "patching_rect": [500, 300, 200, 22], 62 62 "text": "print NOTEPAT-REMOTE" 63 63 } 64 64 }, 65 65 { 66 66 "box": { 67 + "comment": "Debug: note pitch/vel after route", 68 + "id": "obj-print-note", 69 + "maxclass": "newobj", 70 + "numinlets": 1, 71 + "numoutlets": 0, 72 + "patching_rect": [200, 340, 200, 22], 73 + "text": "print NOTEPAT-NOTE" 74 + } 75 + }, 76 + { 77 + "box": { 78 + "comment": "Debug: channel after route", 79 + "id": "obj-print-chan", 80 + "maxclass": "newobj", 81 + "numinlets": 1, 82 + "numoutlets": 0, 83 + "patching_rect": [200, 380, 200, 22], 84 + "text": "print NOTEPAT-CHAN" 85 + } 86 + }, 87 + { 88 + "box": { 67 89 "id": "obj-thisdevice", 68 90 "maxclass": "newobj", 69 91 "numinlets": 1, ··· 100 122 "lines": [ 101 123 { "patchline": { "source": ["obj-jweb", 2], "destination": ["obj-route", 0] } }, 102 124 { "patchline": { "source": ["obj-route", 0], "destination": ["obj-noteout", 0] } }, 125 + { "patchline": { "source": ["obj-route", 0], "destination": ["obj-print-note", 0] } }, 103 126 { "patchline": { "source": ["obj-route", 1], "destination": ["obj-noteout", 1] } }, 127 + { "patchline": { "source": ["obj-route", 1], "destination": ["obj-print-chan", 0] } }, 104 128 { "patchline": { "source": ["obj-route", 2], "destination": ["obj-print", 0] } }, 105 129 { "patchline": { "source": ["obj-thisdevice", 0], "destination": ["obj-routeready", 0] } }, 106 130 { "patchline": { "source": ["obj-routeready", 0], "destination": ["obj-activate", 0] } },
+36 -15
system/public/aesthetic.computer/disks/notepat-remote.mjs
··· 49 49 let frame = 0; 50 50 let lastEmittedChannel = -1; 51 51 52 - // Max for Live jweb~ bridge (exposes window.max.outlet) 53 - const maxBridge = 54 - typeof window !== "undefined" && 55 - window.max && 56 - typeof window.max.outlet === "function" 57 - ? window.max 58 - : null; 52 + // Max for Live jweb~ bridge — looked up lazily because jweb~ injects 53 + // window.max AFTER the page load, not before module evaluation. 54 + function maxBridge() { 55 + if (typeof window === "undefined") return null; 56 + const m = window.max; 57 + if (!m || typeof m.outlet !== "function") return null; 58 + return m; 59 + } 59 60 60 61 function emitMaxNote(pitch, velocity, channel) { 61 - if (!maxBridge) return; 62 + const m = maxBridge(); 63 + if (!m) return; 62 64 try { 63 65 if (channel !== lastEmittedChannel) { 64 - maxBridge.outlet(["channel", channel]); 66 + m.outlet("channel", channel); 65 67 lastEmittedChannel = channel; 66 68 } 67 - maxBridge.outlet(["note", pitch, velocity]); 68 - } catch (_err) {} 69 + m.outlet("note", pitch, velocity); 70 + // Mirror to Max console so it's obvious when a note fired. 71 + console.log(`🎹 out note=${pitch} vel=${velocity} ch=${channel}`); 72 + } catch (err) { 73 + console.log("🎹 outlet err:", err?.message || err); 74 + } 69 75 } 70 76 71 77 function connectWs() { ··· 198 204 199 205 function act({ event: e }) { 200 206 if (!e?.is) return; 207 + // Click-to-test-note: tap anywhere on the device UI fires C4 so we can 208 + // verify the Max bridge path without depending on keyboard focus. 209 + if (e.is("touch")) { 210 + pressLocalKey("c"); 211 + return; 212 + } 213 + if (e.is("lift")) { 214 + releaseLocalKey("c"); 215 + return; 216 + } 217 + // Best-effort debug: log raw keyboard events to Max console. 218 + if (e.is("keyboard:down") || e.is("keyboard:up")) { 219 + console.log(`🎹 kbd ${e.key || e.name || "?"}`); 220 + } 201 221 for (const key of Object.keys(KEY_TO_PITCH)) { 202 222 if (e.is(`keyboard:down:${key}`)) { 203 223 pressLocalKey(key); ··· 224 244 const H = screen.height; 225 245 let y = 4; 226 246 227 - // Header 247 + // Header — check bridge each frame in case jweb~ injected window.max late 248 + const bridgeActive = !!maxBridge(); 228 249 ink(...accent).write("NOTEPAT-REMOTE", { x: 4, y, size: 1 }); 229 - ink(...(maxBridge ? good : warn)).write( 230 - maxBridge ? "[M4L]" : "[solo]", 250 + ink(...(bridgeActive ? good : warn)).write( 251 + bridgeActive ? "[M4L]" : "[solo]", 231 252 { x: 112, y }, 232 253 ); 233 254 y += 10; ··· 297 318 298 319 // Footer hint 299 320 if (H - y > 12) { 300 - ink(...fgDim).write("c,d,e,f,g,a,b = C4..B4 scale", { x: 4, y: H - 8 }); 321 + ink(...fgDim).write("click=C4 | keys c-b=C4..B4", { x: 4, y: H - 8 }); 301 322 } 302 323 } 303 324
system/public/m4l/notepat-remote.amxd

This is a binary file and will not be displayed.