Skip to content

Hello World

Creating a py4pd Object

To define a new py4pd object, create a subclass of puredata.NewObject, name the object, and finally name the script with the name + .pd_py. For example, pymetro.pd_py for the object pymetro. Place the file in a place where Pd can find it.

Don't forget to load py4pd first

Example

import puredata as pd

class pymetro(pd.NewObject):
    name: str = "pymetro"  # Name of the Pure Data object

    def __init__(self, args):
        self.inlets = 2    # Number of inlets
        self.outlets = 1   # Number of outlets

Key Points

The Python class name (e.g., pymetro) can be any valid class name. The name attribute determines the name of the object inside Pure Data. self.inlets and self.outlets define the number of inlets and outlets for the object. When loading this object in Pure Data, use the name attribute value (pymetro in this example) as the object name.

Input and Output

Input

The input design is inspired by the mature pd-lua project. For methods, use the format in_<inlet_number>_<method>. For example, to execute code when a float is received on inlet 1, define a method called in_1_float. Pd provides predefined methods that do not require a custom selector: bang, float, symbol, list, and anything. You can also create custom selectors (prefixes); for instance, in_1_mymethod will be executed when the message mymethod is sent to inlet 1 of the object.

Output

To produce output, use the method self.out. For example, self.out(0, pd.SYMBOL, "test238") sends the symbol "test238" to outlet 0. The second argument specifies the data type, which can be pd.SYMBOL or pd.FLOAT. To output a list, use pd.LIST instead.

PyObject

py4pd also implements the PyObject message, which allows you to share Python data types between py4pd objects. This enables the transfer of class instances, NumPy arrays, and other Python objects that are not supported by Pure Data’s traditional data types.

Metronome Example

import puredata as pd


class pymetro(pd.NewObject):
    name: str = "pymetro"

    def __init__(self, args):
        self.inlets = 2
        self.outlets = 1
        self.toggle = False
        if len(args) > 0:
            self.time = float(args[0])
        else:
            self.time = 1000
        self.metro = self.new_clock(self.tick)
        self.args = args

    def in_2_float(self, f: float):
        self.time = f

    def in_1_float(self, f: float):
        if f:
            self.toggle = True
            self.tick()
        else:
            self.metro.unset()
            self.toggle = False

    def in_1_reload(self, args: list):
        self.reload()

    def tick(self):
        if self.toggle:
            self.metro.delay(self.time)
        self.out(0, pd.SYMBOL, "test238")