Dup Ver Goto 📝

OSC Control Panel

PT2/lang/python/net python osc http does not exist
To
229 lines, 558 words, 5444 chars Page 'OscControlPanel_02' does not exist.

This is something very quick and dirty so that I can use my Thinkpad T470s with its touchscreen as an array of shortcut buttons for triggering Reaper actions via OSC messages. (The look of the buttons is deliberately done to make it touch friendly.)

You define the buttons in a JSON file, as below.

pages.json

{
  "order": [ "page1", "page2" ],
  "pages": {
    "page1": [
      [ "/insert/hz", "/boing/snarf" ],
      [ "/insert/z2", "/insert/ana2" ]
    ],
    "page2": [
      [ "/insert/serum", "/boing/snarf" ],
      [ "/insert/serum2", "/insert/spire" ],
      [ "/append/realimit", "/append/reaeq" ]
    ]
  }
}

Server

#!/usr/bin/env python3

# Python 3 server example
from http.server import BaseHTTPRequestHandler, HTTPServer
from subprocess import run, PIPE
import time
import sys
import re
from jda1 import *
from datetime import datetime
from threading import Thread

hostName = ""
serverPort = 4041

from myosc import Osc
osc = Osc("localhost",2708)

class MyServer(BaseHTTPRequestHandler):
  def page_to_html(self,name,page):
    lines = []
    lines.append(f'<section class="page" page="{name}" pagename="{name}">')
    lines.append('<table>')
    for row in page:
      tr = ["<tr>"]
      for col in row:
        osc = col
        text = col.replace("/"," ").strip()
        tr.append(f'<td><span class="button" osc="{osc}">{text}</span></td>')
      tr.append("</tr>")
      lines.append("".join(tr))
    lines.append('</table>')
    lines.append("</section>")
    content = "\n".join(lines)
    return content
  def homepage(self):
    frame = open("frame.html").read()
    pages_json = rjf("pages.json") 
    pages = []
    try:
      order = pages_json["order"]
      for name in order:
        page = pages_json["pages"][name]
        pages.append((name,page))
      pages_html = [ self.page_to_html(*x) for x in pages ]
      content = "\n".join(pages_html)
    except KeyError as e:
      content = f"KEY ERROR {e}"
    homepage_html = frame.replace("CONTENT",content)
    self.send_response(200)
    self.send_header("Content-type", "text/html")
    self.end_headers()
    self.wfile.write(bytes(homepage_html, "utf-8"))

  def do_GET(self):
    if self.path == "/favicon.ico":
      self.send_response(404)
      self.end_headers()
      self.wfile.write(b"No favicon")
      return
    if self.path.strip("/") == "":
      return self.homepage()
    if self.path.lstrip("/").startswith("send/"):
      x = self.path.lstrip("/")
      x = x[len("send/"):]
      osc.send(x)
      self.send_response(200)
      self.end_headers()
      self.wfile.write(b"OK")
    self.send_response(404)
    self.end_headers()
    self.wfile.write(b"Not Found")
    return

if __name__ == "__main__":    
  webServer = HTTPServer((hostName, serverPort), MyServer)
  print("Server started http://%s:%s" % (hostName, serverPort))

  try:
    webServer.serve_forever()
  except KeyboardInterrupt:
    pass

  webServer.server_close()
  print("Server stopped.")

frame.html


<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf8'/>
    <title>OSC Buttons</title>
<style>
span.button.clicked {
  background-color: #ff0;
  color: black;
}

span.button {
  display: inline-block;
  padding: 1rem;
  font-size: 1.5rem;
  border: 1px solid black;
  margin: 1rem;
  box-shadow: 0.5rem 0.5rem 0.5rem black;
  background-color: #007;
  color: white;
  font-family: sans-serif;
}

div.pager section.page {
  display: none;
}

div.pager section.page.active {
  display: block;
}

div.pager div.controls span.button.active {
  background-color: #070;
}

</style>
  </head>
  <body>
    <div class="pager">
      <div class="controls"></div>
      CONTENT
    </div>
  </body>
  <script>

window.q = (x,y=document) => y.querySelector(x)
const qq = window.qq = (x,y=document) => Array.from(y.querySelectorAll(x))


function acms(e) {
    let key = e.key
    const code = e.code.toLowerCase()
    if( code === "backquote" ) { key = "`" }
    if( code.startsWith("digit") ) { key = code.substr(5) }
    if( code === "space" ) { key = "space" }
    let t = key.toLowerCase()
    if( e.shiftKey ) t = "S-"+t
    if( e.metaKey ) t = "M-"+t
    if( e.ctrlKey ) t = "C-"+t
    if( e.altKey ) t = "A-"+t
    return t
}

const pager = q(".pager")
const controls = q("div.controls",pager)
const pages = qq("section.page",pager)
const tabs = []
pages.forEach( page => {
  const page_id = page.getAttribute("page")
  const page_text = page.getAttribute("pagename")
  const span = document.createElement("span")
  span.classList.add("button")
  span.textContent = page_text
  span.addEventListener("click", e => {
    e.preventDefault()
    pages.forEach( p => p.classList.remove("active") )
    tabs.forEach( t => t.classList.remove("active") )
    span.classList.add("active")
    page.classList.add("active")
  })
  tabs.push(span)
  controls.append(span)
})
pages[0].classList.add("active")
tabs[0].classList.add("active")

const clicked_duration = 300
function sig(button) {
  button.classList.add("clicked")
  setTimeout(_ => {
    button.classList.remove("clicked")
  },clicked_duration)
}
function send(msg) {
  fetch(`/send/${msg}`)
}

qq("span.button[osc]").forEach(button => {
  button.addEventListener("click",e => {
    e.preventDefault()
    let x = button.getAttribute("osc")
    if( x ) {
      send(x)
      sig(button)
    }
  })
})
  </script>
</html>