Documentation Index
Fetch the complete documentation index at: https://mintlify.com/plugdata-team/plugdata/llms.txt
Use this file to discover all available pages before exploring further.
Object Architecture
plugindata’s object system is built on Pure Data’s foundation but enhanced with modern UI features and improved visual feedback.
Object Lifecycle
From Object.cpp:35-69, objects are created in two ways:
New Object Creation:
Object::Object(Canvas* parent, String const& name, Point<int> const position)
: cnv(parent)
, editor(parent->editor)
{
setTopLeftPosition(position - Point<int>(margin, margin));
initialise();
if (name.isEmpty()) {
setSize(58, height); // Initial editor size
} else {
setType(name); // Create with specific type
}
}
Existing Object Reference:
Object::Object(pd::WeakReference object, Canvas* parent)
: cnv(parent)
, editor(parent->editor)
{
initialise();
setType("", object); // Link to existing Pd object
}
Object Types
1. GUI Objects
Interactive visual elements that extend Pure Data’s standard objects:
Number Boxes
- Display and edit numeric values
- Support mouse drag to adjust
- Can have custom ranges and display formats
Sliders (Horizontal/Vertical)
- Visual parameter control
- Linear or logarithmic scaling
- Customizable colors and ranges
Toggle/Bang
- Binary on/off states
- Momentary triggers
- Visual feedback on activation
Canvas/VU Meters
- Visual displays
- Real-time level monitoring
- Customizable appearance
From Object.cpp:498-503, GUI objects have special rendering:
void Object::resized()
{
setVisible(!((cnv->isGraph || cnv->presentationMode == var(true))
&& gui && gui->hideInGraph()));
if (gui) {
gui->setBounds(getLocalBounds().reduced(margin));
}
}
2. Audio Objects
Signal processing objects (with ~ suffix):
Oscillators
[osc~] - Sine wave oscillator
[phasor~] - Sawtooth/ramp oscillator
[noise~] - White noise generator
Filters
[lop~] - Low-pass filter
[hip~] - High-pass filter
[bp~] - Band-pass filter
[vcf~] - Voltage-controlled filter
Audio I/O
[adc~] - Audio input (analog-to-digital converter)
[dac~] - Audio output (digital-to-analog converter)
[readsf~] - Read sound file
[writesf~] - Write sound file
Math Operations
[+~], [-~], [*~], [/~] - Arithmetic
[clip~] - Limit signal range
[wrap~] - Wrap signal values
3. Control Objects
Message-based objects for logic and flow control:
Flow Control
[select] / [sel] - Route based on value
[route] - Message routing by symbol
[spigot] - Gate messages on/off
[moses] - Split numbers by threshold
Timing
[metro] - Metronome/clock
[delay] / [del] - Delayed bang
[timer] - Measure time between events
[pipe] - Delay messages with values
Math and Logic
[+], [-], [*], [/] - Arithmetic
[>], [<], [==] - Comparisons
[&&], [||] - Logical operators
[expr] - Mathematical expressions
Data Structures
[list] - List operations
[array] - Data arrays
[table] - Lookup tables
[text] - Text manipulation
Object Properties
Every object has configurable properties accessible through the inspector:
Position and Size
// From Object.cpp:76-94
Rectangle<int> Object::getObjectBounds() const
{
return getBounds().reduced(margin) - cnv->canvasOrigin;
}
void Object::setObjectBounds(Rectangle<int> const bounds)
{
setBounds(bounds.expanded(margin) + cnv->canvasOrigin);
}
Visual Properties
- Background color
- Label text and position
- Font and size
- Send/receive symbols
Functional Properties
- Value ranges (min/max)
- Initial values
- Send/receive names
- Arguments
Iolets: Object Interfaces
From Iolet.h:12-65, iolets are the connection points on objects:
class Iolet final : public Component
{
public:
Object* object;
Canvas* cnv;
uint16 ioletIdx; // Index on parent object
bool isInlet : 1; // Input vs output
bool isSignal : 1; // Signal (~) vs message
bool isGemState : 1; // GEM rendering chain
bool isTargeted : 1; // Being connected
};
Iolet Types
Signal Iolets (Audio Rate)
- Process continuous audio streams
- Identified by
~ in object name
- Visually distinct (colored when enabled)
- Sample-accurate timing
Message Iolets (Control Rate)
- Process discrete events
- Handle numbers, symbols, lists
- Event-driven execution
GEM Iolets
- Graphics rendering chain
- Pass GEM state between objects
- Special visual indicator
Iolet Layout
From Object.cpp:512-586, iolet positioning is calculated:
void Object::updateIoletGeometry()
{
int maxIoletWidth = std::min(
(getWidth() - doubleMargin) / std::max<int>(numInputs, 1) - 4,
(getWidth() - doubleMargin) / std::max<int>(numOutputs, 1) - 4
);
int ioletSize = PlugDataLook::getIoletSize();
ioletSize = std::max(std::min({ioletSize, maxIoletWidth, maxIoletHeight}), 10);
// Two layout modes: vanilla (edges) or centered
if (PlugDataLook::getUseIoletSpacingEdge()) {
// Distribute iolets from edge to edge
} else {
// Center iolets with spacing
}
}
Layout Modes:
-
Edge Spacing (Vanilla style)
- Iolets placed at object corners
- Matches Pure Data vanilla appearance
-
Centered Spacing (Default)
- Iolets distributed evenly
- Better visual balance
- Easier to connect
From Object.cpp:589-693, tooltips are automatically populated:
void Object::updateTooltips()
{
auto const objectInfo = cnv->pd->objectLibrary->getObjectInfo(
gui->getTypeWithOriginPrefix());
if (objectInfo.isValid()) {
// Set object tooltip from documentation
gui->setTooltip(objectInfo.getProperty("description").toString());
// Parse iolet tooltips from pddp files
ioletTooltips = cnv->pd->objectLibrary->parseIoletTooltips(
objectInfo.getChildWithName("iolets"),
gui->getText(), numInputs, numOutputs);
}
}
Tooltips show:
- Iolet purpose and accepted values
- GEM state indicators
- Signal vs message type
Connection System
The connection system manages the visual and functional links between objects.
Connection Creation
From Connection.cpp:26-95:
Connection::Connection(Canvas* parent, Iolet* s, Iolet* e, t_outconnect* oc)
: inlet(s->isInlet ? s : e)
, outlet(s->isInlet ? e : s)
, inobj(inlet->object)
, outobj(outlet->object)
, cnv(parent)
{
// Validate connection
if (!outlet || !inlet || outlet->isInlet == inlet->isInlet) {
jassertfalse;
return;
}
// Determine cable type
if (outlet->isSignal) {
cableType = SignalCable;
} else if (outlet->isGemState) {
cableType = GemCable;
} else {
cableType = DataCable;
}
// Create in Pd if needed
if (!oc) {
oc = parent->patch.createAndReturnConnection(
checkedOut, outIdx, checkedIn, inIdx);
}
}
Connection Types
Data Connections (Message)
- Control-rate messages
- Discrete events and values
- Black/base color (default)
Signal Connections (Audio)
- Audio-rate continuous signals
- Sample-accurate processing
- Colored differently (configurable)
- Multiple signal channels supported
GEM Connections
- Graphics rendering chain
- Special visual treatment
- Pass rendering state
Connection Paths
plugindata supports multiple connection path styles:
1. Curved Paths (Default)
From Connection.cpp:879-932, bezier curves for smooth appearance:
Path Connection::getNonSegmentedPath(Point<float> const start, Point<float> const end)
{
Path connectionPath;
connectionPath.startNewSubPath(start);
if (!PlugDataLook::getUseStraightConnections()) {
float const width = std::max(start.x, end.x) - std::min(start.x, end.x);
float const height = std::max(start.y, end.y) - std::min(start.y, end.y);
constexpr float maxShiftY = 20.f;
constexpr float maxShiftX = 20.f;
float shiftY = std::min<float>(maxShiftY, max * 0.5);
Point<float> const ctrlPoint1 { start.x - shiftX, start.y + shiftY };
Point<float> const ctrlPoint2 { end.x + shiftX, end.y - shiftY };
connectionPath.cubicTo(ctrlPoint1, ctrlPoint2, end);
}
return connectionPath;
}
2. Segmented Paths
- Orthogonal (right-angle) routing
- User-adjustable waypoints
- Automatic path-finding algorithm
- Saved with patch
From Connection.cpp:317-339, segmented paths are serialized:
void Connection::pushPathState(bool const force)
{
t_symbol* newPathState;
if (segmented) {
MemoryOutputStream stream;
for (auto const& point : currentPlan) {
stream.writeInt(point.x - outlet->getCanvasBounds().getCentre().x);
stream.writeInt(point.y - outlet->getCanvasBounds().getCentre().y);
}
auto const base64 = stream.getMemoryBlock().toBase64Encoding();
newPathState = cnv->pd->generateSymbol(base64);
} else {
newPathState = cnv->pd->generateSymbol("empty");
}
cnv->pathUpdater->pushPathState(this, newPathState);
}
3. Straight Lines
- Direct point-to-point
- Minimal visual overhead
- Matches Pd vanilla
Connection Interaction
Selection
- Click to select
- Multiple selection with Shift
- Selected connections highlighted
Reconnection
From Connection.cpp:749-787, reconnect handles allow redirecting:
void Connection::reconnect(Iolet const* target)
{
auto const& otherIolet = target == inlet ? outlet : inlet;
// Support multiple connection reconnection with Shift
SmallArray<Connection*> connections = { this };
if (Desktop::getInstance().getMainMouseSource()
.getCurrentModifiers().isShiftDown()) {
for (auto* c : otherIolet->object->getConnections()) {
if (c == this || !c->isSelected()) continue;
connections.add(c);
}
}
// Remove old connections and start new ones
for (auto* c : connections) {
cnv->patch.removeConnection(checkedOut, c->outIdx,
checkedIn, c->inIdx, c->getPathState());
cnv->connectionsBeingCreated.add(
target->isInlet ? c->inlet : c->outlet, cnv);
}
}
Path Editing
- Drag segments to adjust waypoints (segmented mode)
- Double-click to toggle segmented/curved
- Right-click for path options
Connection Ordering
From Canvas.cpp:824-868, connection rendering respects layering:
void Canvas::renderAllConnections(NVGcontext* nvg, Rectangle<int> const area)
{
SmallArray<Connection*> connectionsToDrawSelected;
Connection* hovered = nullptr;
// Draw non-selected connections first
for (auto* connection : connections) {
if (connection->isMouseHovering())
hovered = connection;
else if (!connection->isSelected())
connection->render(nvg);
else
connectionsToDrawSelected.add(connection);
}
// Draw selected connections on top
for (auto* connection : connectionsToDrawSelected) {
connection->render(nvg);
}
// Draw hovered connection last (highest)
if (hovered) {
hovered->render(nvg);
}
}
Ordering Display
When multiple connections share an outlet, numbers show execution order.
Object Management
Canvas Object Management
From Canvas.cpp:1093-1231, synchronization with Pure Data:
void Canvas::performSynchronise()
{
// Remove deleted objects
for (int n = objects.size() - 1; n >= 0; n--) {
if (auto* object = objects[n];
!object->getPointer() && !object->isInitialEditorShown()) {
setSelected(object, false, false);
objects.remove_at(n);
}
}
// Add new objects from Pd
auto pdObjects = patch.getObjects();
for (auto object : pdObjects) {
auto const* it = std::ranges::find_if(objects,
[&object](Object const* b) {
return b->getPointer() == object.getRawUnchecked<void>();
});
if (it == objects.end()) {
auto* newObject = objects.add(object, this);
newObject->toFront(false);
}
}
// Sort to match Pd order
std::ranges::sort(objects,
[&pdObjects](Object const* first, Object const* second) {
return pdObjects.index_of(first->getPointer()) <
pdObjects.index_of(second->getPointer());
});
}
Object Selection
Multiple selection modes:
Click Selection
- Single click: Select one
- Shift + click: Add to selection
- Cmd/Ctrl + click: Toggle selection
Lasso Selection
- Drag on canvas to select region
- All contained objects selected
- Works in edit mode only
Select All
- Cmd/Ctrl + A: Select all objects
- Cmd/Ctrl + Shift + A: Deselect all
Object Alignment and Distribution
From Object.cpp:36-226, the ObjectsResizer handles multi-object operations:
class ObjectsResizer final : public Component
{
enum class ResizerMode { Horizontal, Vertical };
ObjectsResizer(Canvas* parentCanvas,
std::function<float(Rectangle<int>)> onResize,
std::function<void(Point<int>)> onMove,
ResizerMode const mode = ResizerMode::Horizontal)
{
// Handle simultaneous resizing of multiple objects
// Distribute spacing evenly
// Align to grid
}
};
Alignment Options:
- Align left/right/top/bottom
- Distribute horizontally/vertically
- Align to grid
- Even spacing
Advanced Features
HVCC Compatibility
From Object.cpp:139-148, objects check compatibility:
void Object::settingsChanged(String const& name, var const& value)
{
if (name == "hvcc_mode") {
if (value)
isHvccCompatible = gui->checkHvccCompatibility();
else
isHvccCompatible = true;
repaint();
}
}
Incompatible objects are highlighted when HVCC mode is enabled.
Object Activity Visualization
From Object.cpp:479-489:
void Object::triggerOverlayActiveState()
{
if (!cnv->shouldShowObjectActivity())
return;
activeStateAlpha = 1.0f;
activityStateFade.start(); // Animate fade-out
}
Visual feedback shows which objects are processing data in real-time.
Graph on Parent (GOP)
Subpatches can display their contents on the parent canvas:
- Define visible area (x/y ranges)
- Show/hide name and arguments
- Create custom GUI objects
- Encapsulate complex interfaces
Best Practices
- Object Naming: Use descriptive names for subpatches and abstractions
- Connection Clarity: Use segmented paths for complex patches
- Visual Organization: Group related objects together
- Performance: Minimize unnecessary signal connections
- Modularity: Use subpatches to organize functionality
- Documentation: Add tooltips and comments to objects
Next Steps
Patching Basics
Learn fundamental patching concepts
Plugin vs Standalone
Understand the different operating modes