Skip to main content
Functions are the building blocks of lighting shows in QLC+. Each function type inherits from the base Function class and implements specific behaviors.

Base Function Class

All functions inherit from Function (engine/src/function.h:93).

Creating Functions

Function(Doc* doc, Type t);
doc
Doc*
Parent document that owns this function
t
Type
Function type (SceneType, ChaserType, etc.)

Common Properties

void setID(quint32 id);
quint32 id() const;
static quint32 invalidId();

void setName(const QString& name);
QString name() const;

Type type() const;
QString typeString() const;
static QString typeToString(Type type);
static Type stringToType(const QString& str);

Scene

Sets specific DMX values for fixtures.

Creating Scenes

Scene* scene = new Scene(doc);
scene->setName("My Scene");

// Set channel values
scene->setValue(fixtureId, channelIndex, value);
scene->setValue(SceneValue(fixtureId, channelIndex, value));

// Add to document
doc->addFunction(scene);

Channel Values

class SceneValue
{
public:
    SceneValue(quint32 fxi, quint32 ch, uchar val);
    
    quint32 fxi;      // Fixture ID
    quint32 channel;  // Channel index
    uchar value;      // DMX value (0-255)
};

Scene API

// Set values
void setValue(quint32 fxi, quint32 ch, uchar value);
void setValue(const SceneValue& scv);
void setValues(QList<SceneValue>& values);

// Get values
uchar value(quint32 fxi, quint32 ch) const;
QList<SceneValue> values() const;

// Remove values
void unsetValue(quint32 fxi, quint32 ch);
void clear();

Example: Creating a Red Wash

Scene* redWash = new Scene(doc);
redWash->setName("Red Wash");
redWash->setFadeInSpeed(2000);   // 2 second fade in
redWash->setFadeOutSpeed(1000);  // 1 second fade out

// Set all RGB fixtures to red
for (Fixture* fixture : doc->fixtures())
{
    if (fixture->type() == Fixture::GenericRGB)
    {
        redWash->setValue(fixture->id(), 0, 255);  // Red channel
        redWash->setValue(fixture->id(), 1, 0);    // Green channel
        redWash->setValue(fixture->id(), 2, 0);    // Blue channel
    }
}

doc->addFunction(redWash);

Chaser

Sequences multiple functions in order.

Chaser Steps

class ChaserStep
{
public:
    ChaserStep(quint32 fid = Function::invalidId());
    
    quint32 fid;           // Function ID to run
    uint fadeIn;           // Fade in time (ms)
    uint hold;             // Hold time (ms)
    uint fadeOut;          // Fade out time (ms)
    uint duration;         // Total duration (ms)
    QString note;          // Optional note
};

Chaser API

// Add/remove steps
bool addStep(const ChaserStep& step);
bool addStep(const ChaserStep& step, int index);
bool removeStep(int index);
bool replaceStep(const ChaserStep& step, int index);
bool moveStep(int from, int to);

// Access steps
QList<ChaserStep> steps() const;
ChaserStep stepAt(int index) const;
int stepsCount() const;

// Clear
void clear();

Example: RGB Color Chase

Chaser* colorChase = new Chaser(doc);
colorChase->setName("RGB Chase");
colorChase->setRunOrder(Function::Loop);
colorChase->setDuration(500);  // 500ms per step

// Create and add color scenes
Scene* red = createColorScene(doc, "Red", 255, 0, 0);
Scene* green = createColorScene(doc, "Green", 0, 255, 0);
Scene* blue = createColorScene(doc, "Blue", 0, 0, 255);

doc->addFunction(red);
doc->addFunction(green);
doc->addFunction(blue);

// Add as chaser steps
colorChase->addStep(ChaserStep(red->id()));
colorChase->addStep(ChaserStep(green->id()));
colorChase->addStep(ChaserStep(blue->id()));

doc->addFunction(colorChase);

EFX

Creates geometric movement patterns for pan/tilt fixtures.

EFX Algorithms

enum Algorithm {
    Circle,
    Eight,
    Line,
    Diamond,
    Square,
    SquareChoppy,
    Triangle,
    Lissajous,
    Custom
};

EFX API

// Set algorithm
void setAlgorithm(Algorithm algo);
Algorithm algorithm() const;
QString algorithmName() const;
static QStringList algorithmList();

// Algorithm parameters
void setWidth(int width);
int width() const;
void setHeight(int height);
int height() const;
void setXOffset(int offset);
int xOffset() const;
void setYOffset(int offset);
int yOffset() const;
void setRotation(int degrees);
int rotation() const;

// Lissajous-specific
void setXFrequency(int freq);
int xFrequency() const;
void setYFrequency(int freq);
int yFrequency() const;
void setXPhase(int phase);
int xPhase() const;
void setYPhase(int phase);
int yPhase() const;

Example: Circle Movement

EFX* circle = new EFX(doc);
circle->setName("Circle");
circle->setAlgorithm(EFX::Circle);
circle->setWidth(127);    // Half range
circle->setHeight(127);
circle->setXOffset(127);  // Center
circle->setYOffset(127);
circle->setDuration(5000); // 5 second cycle

// Add moving heads
for (Fixture* fixture : doc->fixtures())
{
    if (fixture->type() == Fixture::MovingHead)
    {
        EFXFixture* ef = new EFXFixture(circle);
        ef->setHead(FixtureHead(fixture->id(), 0));
        circle->addFixture(ef);
    }
}

doc->addFunction(circle);

RGB Matrix

Controls LED matrix effects using RGB scripts.

RGB Matrix API

// Set RGB script
void setScript(const QString& name);
QString script() const;
RGBScript* rgbScript() const;

// Script properties
void setProperty(const QString& name, const QString& value);
QString property(const QString& name) const;
QMap<QString, QString> properties() const;

Example: Rainbow Effect

RGBMatrix* rainbow = new RGBMatrix(doc);
rainbow->setName("Rainbow");
rainbow->setScript("Gradient");
rainbow->setProperty("presetIndex", "Rainbow");
rainbow->setProperty("orientation", "Horizontal");
rainbow->setFixtureGroup(matrixGroupId);
rainbow->setAnimationStyle(RGBMatrix::Forward);
rainbow->setDuration(100);  // Animation speed

doc->addFunction(rainbow);

Collection

Runs multiple functions simultaneously.

Collection API

class Collection : public Function
{
public:
    // Add/remove functions
    bool addFunction(quint32 fid);
    bool removeFunction(quint32 fid);
    
    // Access functions
    QList<quint32> functions() const;
    int functionsCount() const;
    
    // Clear
    void clear();
};

Example: Full Stage Scene

Collection* fullStage = new Collection(doc);
fullStage->setName("Full Stage");

// Add multiple scenes and effects
fullStage->addFunction(washScene->id());
fullStage->addFunction(beamEffects->id());
fullStage->addFunction(movementEFX->id());
fullStage->addFunction(matrixEffect->id());

doc->addFunction(fullStage);

Show

Timeline-based function with precise timing control.

Show Tracks

class Track
{
public:
    quint32 id() const;
    QString name() const;
    quint32 sceneID() const;
    bool isMute() const;
    
    // Get functions on this track
    QMultiHash<uint, ShowFunction*> showFunctions() const;
};

Show API

class Show : public Function
{
public:
    // Tracks
    Track* createTrack(quint32 sceneID);
    bool deleteTrack(quint32 trackId);
    QList<Track*> tracks() const;
    Track* track(quint32 id) const;
    
    // Show functions
    bool addShowFunction(quint32 trackId, quint32 startTime, quint32 functionId);
    bool removeShowFunction(quint32 trackId, quint32 startTime);
    
    // Time
    quint32 totalDuration() const;
    void setCurrentTime(quint32 time);
    quint32 currentTime() const;
};

Sequence

Specialized scene for recording channel changes over time.

Sequence API

class Sequence : public Scene
{
public:
    // Bound scene (controls which fixtures)
    void setBoundSceneID(quint32 id);
    quint32 boundSceneID() const;
    
    // Steps
    void addStep(QList<SceneValue> values);
    void removeStep(int index);
    QList<SceneValue> stepValues(int index) const;
    int stepsCount() const;
    
    // Tempo
    void setTempoType(TempoType type);
    TempoType tempoType() const;
};

Audio

Controls audio playback.

Audio API

class Audio : public Function
{
public:
    // Audio file
    void setSourceFileName(const QString& filename);
    QString sourceFileName() const;
    
    // Playback
    AudioDecoder* getAudioDecoder() const;
    qint64 getDuration();
    
    // Volume
    void adjustAttribute(qreal fraction, int attributeIndex) override;
};

Video

Controls video playback.

Video API

class Video : public Function
{
public:
    // Video file
    void setSourceFileName(const QString& filename);
    QString sourceFileName() const;
    
    // Playback
    void setFullscreen(bool fullscreen);
    bool fullscreen() const;
    
    // Geometry
    void setGeometry(const QRect& rect);
    QRect geometry() const;
};

Function Execution Flow

Lifecycle

1

Creation

Function* func = new Scene(doc);
func->setName("My Function");
// Configure function...
doc->addFunction(func);
2

Starting

// Start function
doc->masterTimer()->startFunction(func);

// Function's start() method is called
void Function::start(MasterTimer* timer, FunctionParent* parent)
{
    // Initialize for playback
    m_running = true;
    emit running(m_id);
}
3

Execution

// write() is called every tick (typically 50Hz)
void Function::write(MasterTimer* timer, QList<Universe*> universes)
{
    // Generate DMX output
    // Update internal state
    // Increment elapsed time
}
4

Stopping

// Stop function
doc->masterTimer()->stopFunction(func);

// Function's stop() method is called
void Function::stop(FunctionParent* parent)
{
    m_running = false;
    emit stopped(m_id);
}

Custom Functions

You can create custom function types by subclassing Function.

Example: Custom Function

class MyFunction : public Function
{
    Q_OBJECT

public:
    MyFunction(Doc* doc)
        : Function(doc, Function::ScriptType)
    {
        setName("My Function");
    }
    
    // Required overrides
    Function* createCopy(Doc* doc, bool addToDoc = true) override
    {
        MyFunction* copy = new MyFunction(doc);
        if (copy->copyFrom(this) == false || (addToDoc && doc->addFunction(copy) == false))
        {
            delete copy;
            return nullptr;
        }
        return copy;
    }
    
    void write(MasterTimer* timer, QList<Universe*> universes) override
    {
        // Your custom logic here
        if (elapsed() >= duration())
        {
            stop();
        }
    }
    
    bool loadXML(QXmlStreamReader& doc) override
    {
        // Load from XML
        return true;
    }
    
    bool saveXML(QXmlStreamWriter* doc) override
    {
        // Save to XML
        return true;
    }
};

Best Practices

  • Functions are owned by Doc
  • Don’t delete functions manually - use Doc::deleteFunction()
  • Use QPointer for function references that may become invalid
  • write() is called from MasterTimer thread
  • Use QMutex to protect shared data
  • Emit signals safely across threads
  • write() is called at high frequency (50Hz)
  • Minimize calculations in write path
  • Cache expensive operations
  • Avoid allocations in hot path
  • Always implement loadXML() and saveXML()
  • Call Function::loadXML() and Function::saveXML() for base class handling
  • Use XML constants defined in function.h

Resources

Build docs developers (and LLMs) love