Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

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

notepat: UDP MIDI status badge — sibling to USB MIDI, pulses green on send

Rewrote the relay status indicator to read as the obvious sibling of the
existing "USB MIDI ON/OFF" badge in the top status bar. States:

disabled (no broadcast in /mnt/config.json) "UDP MIDI OFF" FG_DIM
broadcast enabled, socket not connected "UDP MIDI ..." amber
socket up, no notes sent yet "UDP MIDI ON" dim green
socket up, sending notes "UDP MIDI ON 60v100 ▸ 42"
pulsing green

The color pulses between dim green (100,220,140) and bright green
(160,255,190) on each note send, decaying back over ~1.5s via a new
udpMidiSendRecency() helper. Rapid play visibly lights the indicator
rather than sitting on a static "connected" state — makes it obvious
at a glance that notes are actually flowing through the UDP socket,
not just that the socket opened successfully.

Audit note: verified the end-to-end flow is correct:
rememberSound() → noteToMidiNumber(note, octave) = (oct+1)*12+idx
→ sendUdpMidiEvent() → udp.sendMidi() C binding
→ udp-client.c emits JSON {type:"notepat:midi", note, velocity, ...}
→ session-server fanouts via WebSocket `notepat:midi`
→ notepat-remote.mjs handleRelayEvent() receives ev.note/velocity
→ emitMaxNote() → send("daw:midi", {pitch, velocity, channel})
→ bios.mjs forwards to window.max.outlet("note", pitch, vel)
→ Max patcher [route note channel] → [noteout]

Middle C (note "c" octave 4) correctly maps to MIDI pitch 60 at every
hop, velocity is scaled 1..127, channel 0 passes through untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+45 -21
+45 -21
fedac/native/pieces/notepat.mjs
··· 1855 1855 udpMidiNextHeartbeatFrame = frame + 300; 1856 1856 } 1857 1857 1858 + // Build the UDP-MIDI status line — parallel in form to usbMidiStatusText so 1859 + // the two indicators read as siblings in the top bar. States: 1860 + // "UDP MIDI OFF" broadcast disabled in /mnt/config.json 1861 + // "UDP MIDI ..." broadcast enabled, socket not yet up 1862 + // "UDP MIDI ON" socket up, no notes sent yet 1863 + // "UDP MIDI ON 60v100 ▸ 42" socket up, last note + total-sent count 1864 + // The caller colors based on whether a note was sent in the last ~1.5s 1865 + // (bright green) vs idle-but-connected (dim green) vs disconnected (amber). 1858 1866 function udpMidiRelayStatusText(system) { 1859 - if (!udpMidiBroadcast) return ""; 1860 - const handle = system?.udp?.handle || system?.config?.handle || ""; 1867 + if (!udpMidiBroadcast) return "UDP MIDI OFF"; 1861 1868 const connected = !!system?.udp?.connected; 1862 - const prefix = connected 1863 - ? (handle ? "relay @" + handle : "relay on") 1864 - : (handle ? "relay ...@" + handle : "relay ..."); 1865 - // Append counters + last note when actively sending so the overlay shows 1866 - // the ThinkPad actually broadcasts notes (and not just that the socket is up). 1867 - if (!connected) return prefix; 1868 - if (udpMidiSentCount === 0) return prefix + " 0"; 1869 - const recent = frame - udpMidiLastSentFrame < 90; // ~1.5s fresh window 1870 - const tail = recent && udpMidiLastPitch >= 0 1871 - ? ` ${udpMidiSentCount} ${udpMidiLastPitch}v${udpMidiLastVelocity}` 1872 - : ` ${udpMidiSentCount}`; 1873 - return prefix + tail; 1869 + if (!connected) return "UDP MIDI ..."; 1870 + if (udpMidiSentCount === 0) return "UDP MIDI ON"; 1871 + const recent = frame - udpMidiLastSentFrame < 90; 1872 + if (recent && udpMidiLastPitch >= 0) { 1873 + return `UDP MIDI ON ${udpMidiLastPitch}v${udpMidiLastVelocity} \u25B8 ${udpMidiSentCount}`; 1874 + } 1875 + return `UDP MIDI ON \u25B8 ${udpMidiSentCount}`; 1876 + } 1877 + 1878 + // Returns 0 when no note has ever been sent; otherwise 0..1 recency with 1879 + // 1.0 at the moment of the send and fading to 0 over ~90 frames (1.5s). 1880 + // Used to pulse the badge color from bright-green → dim-green as notes fire. 1881 + function udpMidiSendRecency() { 1882 + if (udpMidiSentCount === 0) return 0; 1883 + const age = frame - udpMidiLastSentFrame; 1884 + if (age < 0 || age > 90) return 0; 1885 + return 1 - (age / 90); 1874 1886 } 1875 1887 1876 1888 function rememberSound(key, entry, system, velocity = 1) { ··· 3463 3475 statusWrite("key:" + lastKeyPressed, 180, 220, 255, fadeA); 3464 3476 } 3465 3477 3478 + // UDP MIDI — sibling indicator to USB MIDI. Color encodes state: 3479 + // disabled → FG_DIM (flat "OFF") 3480 + // enabled + down → amber (255,190,80) "..." 3481 + // enabled + up → dim green (100,220,140) "ON" 3482 + // actively sending→ bright green, pulsing with recency 3483 + // The pulse decays over ~1.5s after each note so rapid play visibly 3484 + // lights the indicator vs just sitting on "connected". 3466 3485 const relayText = udpMidiRelayStatusText(system); 3467 3486 if (relayText) { 3468 - statusWrite( 3469 - relayText, 3470 - system?.udp?.connected ? 80 : 255, 3471 - system?.udp?.connected ? 180 : 180, 3472 - system?.udp?.connected ? 255 : 90, 3473 - 210 3474 - ); 3487 + if (!udpMidiBroadcast) { 3488 + statusWrite(relayText, FG_DIM, FG_DIM, FG_DIM, 200); 3489 + } else if (!system?.udp?.connected) { 3490 + statusWrite(relayText, 255, 190, 80, 220); 3491 + } else { 3492 + const recency = udpMidiSendRecency(); 3493 + // dim green (100,220,140) → bright green (160,255,190) as recency rises 3494 + const r = Math.round(100 + recency * 60); 3495 + const g = Math.round(220 + recency * 35); 3496 + const b = Math.round(140 + recency * 50); 3497 + statusWrite(relayText, r, g, b, 220); 3498 + } 3475 3499 } 3476 3500 3477 3501 // Metronome indicator (pendulum) in status bar — shown when enabled