refactor: 3-module pd architecture + viz non-blocking fix
- midi-in.pd: netreceive -> route -> unpack -> pitch/velocity outlets - audio-out.pd: inlet~ -> dac~ abstraction - synth.pd: consumer patch wiring midi-in -> voice -> audio-out - led-matrix-viz.py: router socket non-blocking, registered with poller - pd.rego: skip outlet/abstraction false positives in validation
This commit is contained in:
@@ -100,7 +100,7 @@ violation contains msg if {
|
|||||||
msg := sprintf("connect[%d]/[%d]: duplicate (%d,%d)->(%d,%d)", [a.x_index, b.x_index, a.src, a.outlet, a.dst, a.inlet])
|
msg := sprintf("connect[%d]/[%d]: duplicate (%d,%d)->(%d,%d)", [a.x_index, b.x_index, a.src, a.outlet, a.dst, a.inlet])
|
||||||
}
|
}
|
||||||
|
|
||||||
# Signal-to-control connection
|
# Signal-to-control connection (skip unknown objects — might be abstractions with inlet~)
|
||||||
violation contains msg if {
|
violation contains msg if {
|
||||||
some rec in input.records
|
some rec in input.records
|
||||||
rec.type == "connect"
|
rec.type == "connect"
|
||||||
@@ -110,6 +110,7 @@ violation contains msg if {
|
|||||||
dst_rec.type == "obj"
|
dst_rec.type == "obj"
|
||||||
is_signal(src_rec.name)
|
is_signal(src_rec.name)
|
||||||
not is_signal(dst_rec.name)
|
not is_signal(dst_rec.name)
|
||||||
|
known_inlets[dst_rec.name]
|
||||||
msg := sprintf("connect[%d]: signal (~) outlet %d (%s) to control inlet %d (%s)", [rec.x_index, rec.src, src_rec.name, rec.dst, dst_rec.name])
|
msg := sprintf("connect[%d]: signal (~) outlet %d (%s) to control inlet %d (%s)", [rec.x_index, rec.src, src_rec.name, rec.dst, dst_rec.name])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,11 +138,14 @@ violation contains msg if {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Inlet exceeds known count (skip -1 = variable)
|
# Inlet exceeds known count (skip -1 = variable)
|
||||||
|
# Skip outlet objects (valid in abstractions) and unknown abstractions
|
||||||
violation contains msg if {
|
violation contains msg if {
|
||||||
some rec in input.records
|
some rec in input.records
|
||||||
rec.type == "connect"
|
rec.type == "connect"
|
||||||
dst_rec := record_by_idx(rec.dst)
|
dst_rec := record_by_idx(rec.dst)
|
||||||
dst_rec.type == "obj"
|
dst_rec.type == "obj"
|
||||||
|
dst_rec.name != "outlet"
|
||||||
|
dst_rec.name != "outlet~"
|
||||||
known_inlets[dst_rec.name]
|
known_inlets[dst_rec.name]
|
||||||
known_inlets[dst_rec.name] != -1
|
known_inlets[dst_rec.name] != -1
|
||||||
rec.inlet >= known_inlets[dst_rec.name]
|
rec.inlet >= known_inlets[dst_rec.name]
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#N canvas 0 0 200 100 10;
|
||||||
|
#X obj 40 20 inlet~;
|
||||||
|
#X obj 40 60 dac~;
|
||||||
|
#X connect 0 0 1 0;
|
||||||
|
#X connect 0 0 1 1;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#N canvas 0 0 300 200 10;
|
||||||
|
#X obj 40 20 netreceive -u 8081;
|
||||||
|
#X obj 40 50 route midi;
|
||||||
|
#X obj 40 80 route 144 128;
|
||||||
|
#X obj 40 110 unpack 0 0;
|
||||||
|
#X obj 40 150 outlet;
|
||||||
|
#X obj 120 150 outlet;
|
||||||
|
#X text 155 150 pitch;
|
||||||
|
#X text 155 170 velocity;
|
||||||
|
#X connect 0 0 1 0;
|
||||||
|
#X connect 1 0 2 0;
|
||||||
|
#X connect 2 0 3 0;
|
||||||
|
#X connect 3 0 4 0;
|
||||||
|
#X connect 3 1 5 0;
|
||||||
+29
-36
@@ -1,40 +1,33 @@
|
|||||||
#N canvas 0 0 350 500 10;
|
#N canvas 0 0 500 600 10;
|
||||||
#X obj 40 20 netreceive -u 8081;
|
#X obj 40 20 midi-in;
|
||||||
#X obj 40 50 route midi;
|
#X obj 40 80 stripnote;
|
||||||
#X obj 40 80 route 144 128;
|
#X obj 40 140 mtof;
|
||||||
#X obj 40 110 unpack 0 0;
|
#X obj 40 180 osc~;
|
||||||
#X obj 40 150 s midi-pitch;
|
#X obj 160 180 osc~;
|
||||||
#X obj 120 150 s midi-vel;
|
#X obj 40 220 *~ 1;
|
||||||
#X obj 40 200 r midi-vel;
|
#X obj 160 220 *~ 1;
|
||||||
#X obj 120 200 r midi-pitch;
|
#X obj 100 260 +~;
|
||||||
#X obj 40 250 stripnote;
|
#X obj 100 300 lop~ 10000;
|
||||||
#X obj 40 310 mtof;
|
#X obj 40 340 env~ 2 10 1 40;
|
||||||
#X obj 40 350 env~ 2 10 1 40;
|
#X obj 100 380 *~;
|
||||||
#X obj 40 430 osc~;
|
#X obj 100 440 audio-out;
|
||||||
#X obj 160 430 osc~;
|
#X text 200 180 osc~ 1 (main);
|
||||||
#X obj 40 470 *~ 1;
|
#X text 320 180 osc~ 2 (+7ct);
|
||||||
#X obj 160 470 *~ 1;
|
#X text 155 220 mix;
|
||||||
#X obj 100 510 +~;
|
#X text 155 300 lop~;
|
||||||
#X obj 100 550 lop~ 10000;
|
#X text 155 340 envelope;
|
||||||
#X obj 100 610 *~;
|
#X text 155 380 amp;
|
||||||
#X obj 100 670 dac~;
|
|
||||||
#X connect 0 0 1 0;
|
#X connect 0 0 1 0;
|
||||||
|
#X connect 0 1 1 1;
|
||||||
#X connect 1 0 2 0;
|
#X connect 1 0 2 0;
|
||||||
|
#X connect 1 1 9 1;
|
||||||
#X connect 2 0 3 0;
|
#X connect 2 0 3 0;
|
||||||
#X connect 3 0 4 0;
|
#X connect 2 0 4 0;
|
||||||
#X connect 3 1 5 0;
|
#X connect 3 0 5 0;
|
||||||
#X connect 6 0 8 1;
|
#X connect 4 0 6 0;
|
||||||
|
#X connect 5 0 7 0;
|
||||||
|
#X connect 6 0 7 1;
|
||||||
#X connect 7 0 8 0;
|
#X connect 7 0 8 0;
|
||||||
#X connect 8 1 10 0;
|
#X connect 8 0 10 0;
|
||||||
#X connect 8 0 9 0;
|
#X connect 9 0 10 1;
|
||||||
#X connect 9 0 11 0;
|
#X connect 10 0 11 0;
|
||||||
#X connect 9 0 12 0;
|
|
||||||
#X connect 10 0 17 1;
|
|
||||||
#X connect 11 0 13 0;
|
|
||||||
#X connect 12 0 14 0;
|
|
||||||
#X connect 13 0 15 0;
|
|
||||||
#X connect 14 0 15 1;
|
|
||||||
#X connect 15 0 16 0;
|
|
||||||
#X connect 16 0 17 0;
|
|
||||||
#X connect 17 0 18 0;
|
|
||||||
#X connect 17 0 18 1;
|
|
||||||
|
|||||||
+11
-10
@@ -26,9 +26,10 @@ def main():
|
|||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
sock.bind(("0.0.0.0", VIZ_PORT))
|
sock.bind(("0.0.0.0", VIZ_PORT))
|
||||||
|
sock.setblocking(False)
|
||||||
|
|
||||||
router = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
router = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
router.settimeout(2)
|
router.setblocking(False)
|
||||||
router.connect(ROUTER_SOCK)
|
router.connect(ROUTER_SOCK)
|
||||||
packer = msgpack.Packer()
|
packer = msgpack.Packer()
|
||||||
|
|
||||||
@@ -38,9 +39,11 @@ def main():
|
|||||||
msg_id = 0
|
msg_id = 0
|
||||||
frame_interval = 1.0 / FPS
|
frame_interval = 1.0 / FPS
|
||||||
next_frame = time.monotonic()
|
next_frame = time.monotonic()
|
||||||
|
router_buf = b""
|
||||||
|
|
||||||
poller = select.poll()
|
poller = select.poll()
|
||||||
poller.register(sock, select.POLLIN)
|
poller.register(sock, select.POLLIN)
|
||||||
|
poller.register(router, select.POLLIN)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
timeout = max(0, int((next_frame - time.monotonic()) * 1000))
|
timeout = max(0, int((next_frame - time.monotonic()) * 1000))
|
||||||
@@ -70,6 +73,12 @@ def main():
|
|||||||
except BlockingIOError:
|
except BlockingIOError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if fd == router.fileno() and flags & select.POLLIN:
|
||||||
|
try:
|
||||||
|
router_buf += router.recv(4096)
|
||||||
|
except BlockingIOError:
|
||||||
|
pass
|
||||||
|
|
||||||
if time.monotonic() >= next_frame:
|
if time.monotonic() >= next_frame:
|
||||||
next_frame = time.monotonic() + frame_interval
|
next_frame = time.monotonic() + frame_interval
|
||||||
|
|
||||||
@@ -92,16 +101,8 @@ def main():
|
|||||||
req = packer.pack([0, msg_id, "draw_frame", params])
|
req = packer.pack([0, msg_id, "draw_frame", params])
|
||||||
try:
|
try:
|
||||||
router.sendall(req)
|
router.sendall(req)
|
||||||
router.settimeout(0.3)
|
except BlockingIOError:
|
||||||
router.recv(128)
|
|
||||||
router.settimeout(2)
|
|
||||||
except socket.timeout:
|
|
||||||
pass
|
pass
|
||||||
except OSError:
|
|
||||||
router.close()
|
|
||||||
router = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
||||||
router.settimeout(2)
|
|
||||||
router.connect(ROUTER_SOCK)
|
|
||||||
last_frame = frame
|
last_frame = frame
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user