theremin à crayon

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/ -> 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 =['radius_logarithmic']
    def oscv(self, path, args):
        h, s, v =
        v = args[0]
        if v < 0.005: v = 0.005
        if v > 1.0: v = 1.0, s, v))
    def osczoom(self, path, args):
    def oscrotate(self, path, 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/ -> pyliblo client (send pressure, x, y to pd)

import liblo, sys
    def __init__(self): = 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(, "/mypaint/pressure", pressure)

PureData patch:


03 2013

Your Comment