Zalgorithm

Basic template for sending OSC data from Python (and receiving OSC data in Python)

Related to notes / Sending OSC messages from the command line

Install pyliblo3 :

pip install pyliblo3

start_listening() starts a server that listens for messages sent to the port (port 9000 by default). The verbose argument is useful for debugging methods.

# basic_server.py

from pyliblo3 import ServerThread, send, make_method, Address

_server = None
# the address the client is listening on
processing = Address("localhost", 12000)


# starts the server; intended to be run from the REPL with start_listening()
def start_listening(port=9000, verbose=True):
    global _server

    class InteractiveServer(ServerThread):
        # a method that responds to a path; in ths case "/complex/status"
        @make_method("/complex/status", "ff")
        def status_callback(self, path, args):
            re, im = args
            print(f"\u2190 Received status update, re: {re}, im: {im}")

        # a fallback method that will respond to paths that haven't been caught
        # by previous methods
        @make_method(None, None)
        def fallback(self, path, args):
            print(f"\u2190 {path} {args}")

    _server = InteractiveServer(port)
    _server.start()
    print(f"Listening on port {port}")


# send an OSC message to the client. e.g.:
# osc("/complex/number", -1.5, 0.001)
def osc(address, *values):
    print(f"\u2192 {address} {values}")
    send(processing, address, *values)

Running the server from the REPL #

Start the Python REPL in the same directory as the server code is in. E.g.:

❯ ipython

Import start_listening and osc:

Python 3.11.13 (main, Oct  7 2025, 15:34:32) [Clang 20.1.4 ]
Type 'copyright', 'credits' or 'license' for more information
IPython 9.9.0 -- An enhanced Interactive Python. Type '?' for help.
Tip: Use `%timeit` or `%%timeit`, and the  `-r`, `-n`, and `-o` options to easily profile your code.

In [1]: from basic_server import start_listening, osc

In [2]: start_listening()
Listening on port 9000

In [3]: osc("/complex/number", -1.25, 0.001)
 /complex/number (-1.25, 0.001)

Sending data to the server #

An example Processing app that uses oscP5 to send and receive OSC messages:

import oscP5.*;
import netP5.*;

Complex z;
Complex c;
float rePrev = 0.0;
float imPrev = 0.0;

OscP5 oscP5;
NetAddress myLocation;

float scaleAdjustment;
float zoom = 1.0;
boolean clearBg = false;

void setup() {
  size(600, 600);
  background(235);
  oscP5 = new OscP5(this, 12000);
  myLocation = new NetAddress("127.0.0.1", 9000);
  scaleAdjustment = (width/2 - 10) / 4.0;
}

/*
 * interesting points:
 * -0.391+-0.587i (chaotic)
 * -1.25+0.004i (takes a while to escape)
 */
void draw() {
  translate(width/2, height/2);
  scale(1, -1);
  strokeWeight(4);
  stroke(252, 3, 111);

  if (clearBg) {
    background(235);
    clearBg = false;
  }

  if (z != null && z.magnitude() <= 8.0 && clearBg != true) {
    float re = z.re * scaleAdjustment * zoom;
    float im = z.im * scaleAdjustment * zoom;
    strokeWeight(4);
    point(re, im);
    strokeWeight(1);
    line(rePrev, imPrev, re, im);
    rePrev = re;
    imPrev = im;
    z = z.mult(z).add(c);
  }
}

void oscEvent(OscMessage message) {
  println("### OSC message received:");

  if (message.checkAddrPattern("/complex/number")) {
    if (message.checkTypetag("ff")) {
      clearBg = true;
      float re = message.get(0).floatValue();
      float im = message.get(1).floatValue();
      c = new Complex(re, im);
      z = new Complex(0.0, 0.0);
      rePrev = 0;
      imPrev = 0;
      println("Updated z to (0.0, 0.0); Updated z to (" + re + ", " + im + ")" );

      // Send a response back to Python, just to confirm that a response can be sent and received:
      OscMessage statusMessage = new OscMessage("/complex/status");
      statusMessage.add(re);
      statusMessage.add(im);
      oscP5.send(statusMessage, myLocation);
    }
  }

  if (message.checkAddrPattern("/complex/zoom")) {
    if (message.checkTypetag("f")) {
      zoom = message.get(0).floatValue();
    }
  }
}
class Complex {
  float re, im;

  Complex(float re, float im) {
    this.re = re;
    this.im = im;
  }

  Complex add(Complex other) {
    return new Complex(re + other.re, im + other.im);
  }

  Complex mult(Complex other) {
    return new Complex(
      re * other.re - im * other.im,
      re * other.im + im * other.re
      );
  }

  float magnitude() {
    return sqrt(re*re + im*im);
  }
}