simulator: SVG snapshots, reconnecting
s-ol
28 days ago
23 | 23 | if rtmidi.API_UNIX_JACK in rtmidi.get_compiled_api(): |
24 | 24 | rtmidi_api = rtmidi.API_UNIX_JACK |
25 | 25 | |
26 | display_rotation = 0 | |
27 | ||
28 | 26 | |
29 | 27 | class MIDI: |
30 | 28 | def __init__(self, inp, out): |
54 | 52 | |
55 | 53 | |
56 | 54 | def create_midi_usb(board): |
57 | inp = rtmidi.MidiIn(rtmidi_api, "0x33.boad sim") | |
58 | out = rtmidi.MidiOut(rtmidi_api, "0x33.boad sim") | |
55 | inp = rtmidi.MidiIn(rtmidi_api, "0x33.board sim") | |
56 | out = rtmidi.MidiOut(rtmidi_api, "0x33.board sim") | |
59 | 57 | inp.open_virtual_port("USB in") |
60 | 58 | out.open_virtual_port("USB out") |
61 | 59 | inp.ignore_types(sysex=False) |
63 | 61 | |
64 | 62 | |
65 | 63 | def create_midi_trs(board): |
66 | out = rtmidi.MidiOut(rtmidi_api, "0x33.boad sim") | |
64 | out = rtmidi.MidiOut(rtmidi_api, "0x33.board sim") | |
67 | 65 | out.open_virtual_port("TRS out") |
68 | 66 | return MIDI(None, out) |
69 | 67 | |
206 | 204 | <html> |
207 | 205 | <head> |
208 | 206 | <style> |
209 | svg { width: 100%; height: 100%; } | |
207 | svg { | |
208 | width: 100%; | |
209 | height: calc(100vh - 4rem); | |
210 | touch-action: none; | |
211 | } | |
210 | 212 | </style> |
211 | 213 | </head> |
212 | 214 | <body> |
213 | 215 | """ |
214 | 216 | self.index += template |
215 | 217 | self.index += b""" |
218 | <div class="menu"> | |
219 | <button onclick="reconnect()" id="reconnect">reconnect</button> | |
220 | <button onclick="snapshot()">save SVG snapshot</button> | |
221 | </div> | |
216 | 222 | <script type="text/javascript"> |
217 | 223 | const svg = document.body.firstElementChild; |
218 | 224 | const oled = document.evaluate(".//*[@id='oled']", svg).iterateNext(); |
219 | 225 | let websocket; |
226 | ||
227 | const blockTouch = (e) => { | |
228 | e.preventDefault(); | |
229 | }; | |
230 | svg.ontouchstart = blockTouch; | |
231 | svg.ontouchcancel = blockTouch; | |
220 | 232 | |
221 | 233 | let res = document.evaluate(".//*[contains(@class,'led')]", svg); |
222 | 234 | let node = res.iterateNext(); |
234 | 246 | node = res.iterateNext(); |
235 | 247 | } |
236 | 248 | |
237 | ||
238 | Object.values(keys).forEach((node, key) => { | |
249 | Object.entries(keys).forEach(([key, node]) => { | |
239 | 250 | node.style.cursor = 'pointer'; |
240 | 251 | node.onpointerdown = (e) => { |
252 | e.preventDefault(); | |
253 | node.setPointerCapture(e.pointerId); | |
241 | 254 | if (!websocket) return; |
242 | websocket.send(JSON.stringify({ type: 'key', key, down: true })); | |
255 | websocket.send(JSON.stringify({ type: 'key', key: +key, down: true })); | |
243 | 256 | }; |
244 | 257 | node.onpointerup = (e) => { |
258 | e.preventDefault(); | |
245 | 259 | if (!websocket) return; |
246 | websocket.send(JSON.stringify({ type: 'key', key, down: false })); | |
260 | websocket.send(JSON.stringify({ type: 'key', key: +key, down: false })); | |
247 | 261 | }; |
248 | 262 | }); |
249 | ||
263 | ||
250 | 264 | let lastBlob = null; |
251 | 265 | setInterval(() => { |
266 | if (!websocket) return; | |
252 | 267 | fetch('/oled.png#' + Math.random()) |
253 | 268 | .then((response) => response.blob()) |
254 | 269 | .then((blob) => { |
258 | 273 | }); |
259 | 274 | }, 100); |
260 | 275 | |
261 | websocket = new WebSocket(`ws://${location.hostname}:8001/`); | |
262 | websocket.onmessage = ({ data }) => { | |
263 | const msg = JSON.parse(data); | |
264 | switch (msg.type) { | |
265 | case 'pixels': { | |
266 | msg.colors.forEach((color, i) => { | |
267 | pixels[i].style.fill = color; | |
268 | }); | |
269 | break; | |
276 | const reconnectButton = document.getElementById("reconnect"); | |
277 | ||
278 | const reconnect = () => { | |
279 | websocket = new WebSocket(`ws://${location.hostname}:8001/`); | |
280 | websocket.onmessage = ({ data }) => { | |
281 | const msg = JSON.parse(data); | |
282 | switch (msg.type) { | |
283 | case 'pixels': { | |
284 | msg.colors.forEach((color, i) => { | |
285 | pixels[i].style.fill = color; | |
286 | }); | |
287 | break; | |
288 | } | |
270 | 289 | } |
271 | } | |
290 | }; | |
291 | websocket.onopen = (event) => { | |
292 | reconnectButton.disabled = true; | |
293 | svg.style.opacity = 1; | |
294 | }; | |
295 | websocket.onclose = (event) => { | |
296 | websocket = null; | |
297 | reconnectButton.disabled = false; | |
298 | svg.style.opacity = 0.5; | |
299 | }; | |
300 | websocket.onerror = (event) => console.error("socket error", event); | |
272 | 301 | }; |
273 | websocket.onclose = (event) => console.log("socket closed"); | |
274 | websocket.onerror = (event) => console.error("socket error", event); | |
302 | ||
303 | const snapshot = () => { | |
304 | fetch('/oled.png#' + Math.random()) | |
305 | .then((response) => response.blob()) | |
306 | .then((blob) => { | |
307 | const reader = new FileReader(); | |
308 | reader.onloadend = () => { | |
309 | oled.href.baseVal = reader.result; | |
310 | const svgBlob = new Blob([svg.outerHTML], { type: 'image/svg+xml' }); | |
311 | ||
312 | var link = document.createElement('a'); | |
313 | link.href = URL.createObjectURL(svgBlob); | |
314 | link.download = 'snapshot.svg'; | |
315 | link.click(); | |
316 | URL.revokeObjectURL(link.href); | |
317 | }; | |
318 | reader.readAsDataURL(blob); | |
319 | }); | |
320 | }; | |
321 | ||
322 | reconnect(); | |
275 | 323 | </script> |
276 | 324 | </body> |
277 | 325 | </html> |
66 | 66 | width="54.768047" |
67 | 67 | height="13.692011" |
68 | 68 | preserveAspectRatio="none" |
69 | style="image-rendering:optimizeSpeed" | |
69 | style="image-rendering:crisp-edges" | |
70 | 70 | xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAAAgCAYAAADaInAlAAAABHNCSVQICAgIfAhkiAAAAVFJREFU eJztm9sSgyAMRJMO///L9okpRUIJyqXunpfOKJhA1gTUqogc8kCO4zMsVR1qZ+T1e2n1K8TGkbST 57hlMG2bX8eLJ6i5v6OCtGPwPYRa4H4dz4NrYU1S7N8yiaPvtJpQa36W/LLaz8pKFqUxBlV1BeKK 4dmD9tqNc5H+pv1bRJjfIHn7VRnDEmpInRp1l1nX7LXV6udd42rNdP9I6Ol014SsygweekrejqSZ Pj0WrLqUd8jPiZwnxLuYvDqAGr02SynbY3dGSe2l5I/KQ7eBM9h1Cyji3AaSPnYNvkWxBCzyhUzG 2gW8FvlDNoECAIcCAKG4A1ClANChAIDhIpBwG4iC9TSTAgDBepXNEgAOBQAMHwUDkq8FKAAQrFfU LAHgMAOAYH3EQwGAwRJAvmAGAMF6EsgMAISqnv7rQAGAQwEAki4EKQAQ+EUQKfIGuRS8jgipetwA AAAASUVORK5CYII= " |
71 | 71 | id="oled" |
72 | 72 | x="78.599312" |
91 | 91 | class="key led" |
92 | 92 | inkscape:label="minus" |
93 | 93 | data-led-i="2" |
94 | data-key-i="49" | |
94 | data-key-i="52" | |
95 | 95 | id="path147" /><path |
96 | 96 | style="fill:#87deaa;stroke:#000000;stroke-width:0.999999" |
97 | 97 | d="m 427.32415,36.362939 -0.25783,-0.172281 -0.25007,-0.18336 -0.24185,-0.194093 -0.23313,-0.204456 -0.22399,-0.214431 -0.21443,-0.223999 -0.20446,-0.233137 -0.1941,-0.241835 -0.18335,-0.25007 -0.17235,-0.25783 -0.1608,-0.265101 -0.14908,-0.271863 -0.13717,-0.278113 -0.12491,-0.283828 -0.11247,-0.289006 -0.0997,-0.293633 -0.0867,-0.297702 -0.0737,-0.301204 -0.0604,-0.304132 -0.0471,-0.306481 -0.0338,-0.308247 -0.0203,-0.309426 -0.007,-0.310017 -7e-5,-12.072154 0.007,-0.310012 0.0203,-0.309425 0.0338,-0.308247 0.0471,-0.306481 0.0604,-0.304132 0.0737,-0.301203 0.0867,-0.297701 0.0997,-0.293635 0.11247,-0.289006 0.12492,-0.283829 0.13717,-0.278112 0.14907,-0.271863 0.1608,-0.265101 0.17236,-0.25783 0.18335,-0.25007 0.1941,-0.241835 0.20446,-0.233137 0.21442,-0.223998 0.22399,-0.214432 0.23314,-0.204456 0.24184,-0.194093 0.25007,-0.183358 0.25784,-0.172281 0.2651,-0.160874 10.45479,-6.0360775 0.27187,-0.149076 0.27811,-0.137171 0.28383,-0.12491 0.289,-0.112296 0.29364,-0.09968 0.29769,-0.08671 0.30121,-0.07374 0.30414,-0.06059 0.30648,-0.04726 0.30824,-0.03376 0.30942,-0.02026 0.31002,-0.0071 0.31002,0.0071 0.30942,0.02026 0.30824,0.03376 0.30649,0.04726 0.30414,0.06059 0.3012,0.07374 0.29769,0.08671 0.29364,0.09968 0.289,0.112296 0.28383,0.12491 0.27811,0.137171 0.27187,0.149076 10.45471,6.0360725 0.26503,0.160868 0.25784,0.172281 0.25007,0.183358 0.24184,0.194093 0.23314,0.204456 0.22398,0.214433 0.21443,0.223997 0.20446,0.233137 0.1941,0.241835 0.18335,0.250071 0.17235,0.25783 0.16081,0.2651 0.14907,0.271863 0.13717,0.278113 0.12491,0.283828 0.11248,0.289006 0.0997,0.293635 0.0867,0.297702 0.0737,0.301202 0.0604,0.304132 0.0471,0.306481 0.0338,0.308247 0.0203,0.309426 0.007,0.310017 8e-5,12.072153 -0.007,0.310011 -0.0203,0.309425 -0.0338,0.308248 -0.0471,0.306481 -0.0604,0.304132 -0.0737,0.301204 -0.0867,0.297702 -0.0997,0.293633 -0.11247,0.289006 -0.12491,0.283828 -0.13717,0.278112 -0.14908,0.271864 -0.1608,0.2651 -0.17235,0.25783 -0.18335,0.250071 -0.1941,0.241834 -0.20446,0.233138 -0.21443,0.223999 -0.22399,0.214431 -0.23314,0.204456 -0.24184,0.194093 -0.25007,0.183359 -0.25783,0.172281 -0.26511,0.160874 -10.45479,6.03608 -0.27187,0.149147 -0.27811,0.137153 -0.28383,0.124893 -0.289,0.112384 -0.29364,0.09968 -0.29769,0.08678 -0.3012,0.0737 -0.30414,0.0605 -0.30649,0.04718 -0.30824,0.03376 -0.30942,0.02027 -0.31002,0.0068 -0.31002,-0.0068 -0.30942,-0.02027 -0.30824,-0.03376 -0.30648,-0.04718 -0.30414,-0.0605 -0.30121,-0.0737 -0.29769,-0.08678 -0.29364,-0.09968 -0.289,-0.112384 -0.28383,-0.124893 -0.27811,-0.137153 -0.27187,-0.149147 -10.45471,-6.036074 z" |
98 | 98 | class="key led" |
99 | 99 | inkscape:label="plus" |
100 | 100 | data-led-i="3" |
101 | data-key-i="50" | |
101 | data-key-i="53" | |
102 | 102 | id="path149" /></g><g |
103 | 103 | id="g8698" |
104 | 104 | inkscape:label="main keys"><path |