The “Not-just-for-sci-fi electronic instrument” that is played without being touched + a graphic tablet on top & some very simple electronics in the case (power / convert the theremin via USB). Both antennas (control voltage for volume and pitch) are routed to PureData.
The patch is really just a bridge (open sound control) to MyPaint (open-source graphics application for digital painters). Right now the volume is linked to the diameter of the brush and the pitch is linked to the brightness color (this can be changed in the code see below).
BTW this is the beauty of the open source movement: had the idea in the morning, talk to some people on #mypaint in the afternoon, hack the source for my needs during the night and went to bed with a working prototype. Ready-made Solutions Require Ready-made Problems; For Everything Else There Is Open Source Software!
MyPaint: share/gui/document.py -> pyliblo server (receive from pd)
import liblo, sys class Document (CanvasController): def __init__(self, app, leader=None): global created if(created == False): self.server = liblo.Server(9997) self.server.add_method("/mp/radius", 'f', self.oscradius) self.server.add_method("/mp/zoom", 'f', self.osczoom) self.server.add_method("/mp/rotate", 'f', self.oscrotate) gobject.timeout_add(20, self.pollcheck) created = True def oscradius(self, path, args): adj = self.app.brush_adjustment['radius_logarithmic'] adj.set_value(args) def oscv(self, path, args): h, s, v = self.app.brush.get_color_hsv() v = args if v < 0.005: v = 0.005 if v > 1.0: v = 1.0 self.app.brush.set_color_hsv((h, s, v)) def osczoom(self, path, args): self.tdw.set_zoom(args) def oscrotate(self, path, args): self.tdw.set_rotation(args) def pollcheck(self): self.server.recv(10) self.finished = False Stroke.serial_number += 1 self.serial_number = Stroke.serial_number return True
MyPaint: share/mypaint/lib/stroke.py -> pyliblo client (send pressure, x, y to pd)
import liblo, sys def __init__(self): self.target = liblo.Address(1234) def record_event(self, dtime, x, y, pressure, xtilt,ytilt): self.tmp_event_list.append((dtime, x, y, pressure, xtilt,ytilt)) liblo.send(self.target, "/mypaint/pressure", pressure)