Skip to main content
QLC+ is built with a modular architecture separating the core engine from the user interface and I/O plugins. This design enables multiple UI implementations and extensive hardware support.

High-Level Architecture

Core Components

Engine

The engine (engine/src/) is the heart of QLC+, managing all lighting control logic independently of the UI.
The main document class that owns and manages all project data:
class Doc final : public QObject
{
    // Engine components
    QLCFixtureDefCache *fixtureDefCache();
    RGBScriptsCache *rgbScriptsCache();
    IOPluginCache *ioPluginCache();
    InputOutputMap *inputOutputMap();
    MasterTimer *masterTimer();
    
    // Fixture management
    bool addFixture(Fixture* fixture, quint32 id);
    Fixture* fixture(quint32 id) const;
    QList<Fixture*> const& fixtures() const;
    
    // Function management
    bool addFunction(Function* function, quint32 id);
    Function* function(quint32 id) const;
    QList<Function*> functions() const;
    
    // Operating modes
    enum Mode { Design = 0, Operate = 1 };
    void setMode(Mode mode);
};
Responsibilities:
  • Fixture and function lifecycle
  • Project loading/saving
  • Operating mode management (Design/Operate)
  • Engine component coordination
The real-time engine that runs all functions and generates DMX output:
  • Runs at configurable rate (typically 50Hz)
  • Executes running functions
  • Manages faders and crossfades
  • Generates final DMX values
  • Handles Grand Master
Thread-safe and runs independently of UI.
Manages the mapping between universes and I/O plugins:
class InputOutputMap : public QObject
{
    // Universe management
    quint32 universes() const;
    
    // Plugin management
    IOPluginCache* pluginCache();
    
    // Patching
    bool setInputPatch(quint32 universe, const QString& pluginName,
                      quint32 input);
    bool setOutputPatch(quint32 universe, const QString& pluginName,
                       quint32 output);
    
    // DMX I/O
    void setUniverseValue(quint32 universe, quint32 channel, uchar value);
    uchar getUniverseValue(quint32 universe, quint32 channel);
};
Features:
  • Multiple universe support (default: 4)
  • Plugin hot-swapping
  • Input feedback
  • Pass-through mode

Fixtures

Fixtures are instances of fixture definitions, representing physical lighting devices.
class Fixture final : public QObject  // engine/src/fixture.h:71
{
    // Identity
    void setID(quint32 id);
    quint32 id() const;
    void setName(const QString& name);
    QString name() const;
    
    // Addressing
    void setUniverse(quint32 universe);
    quint32 universe() const;
    void setAddress(quint32 address);
    quint32 address() const;
    
    // Definition
    QLCFixtureDef* fixtureDef() const;
    QLCFixtureMode* fixtureMode() const;
    quint32 channels() const;
    
    // Channel access
    const QLCChannel* channel(quint32 channel) const;
};
Fixture Definition Cache:
  • Loads .qxf files from resources/fixtures/
  • Shared across multiple fixture instances
  • Contains channel definitions, capabilities, and modes

Functions

Functions are reusable lighting programs. All inherit from the base Function class (engine/src/function.h:93).
Sets specific DMX values for fixtures:
class Scene : public Function
{
    // Set channel values
    void setValue(quint32 fixture, quint32 channel, uchar value);
    uchar value(quint32 fixture, quint32 channel);
    
    // Fade times
    void setFadeInSpeed(uint ms);
    void setFadeOutSpeed(uint ms);
};
Common Function Interface:
class Function : public QObject  // engine/src/function.h:93
{
public:
    enum Type {
        SceneType      = 1 << 0,
        ChaserType     = 1 << 1,
        EFXType        = 1 << 2,
        CollectionType = 1 << 3,
        ScriptType     = 1 << 4,
        RGBMatrixType  = 1 << 5,
        ShowType       = 1 << 6,
        SequenceType   = 1 << 7,
        AudioType      = 1 << 8,
        VideoType      = 1 << 9
    };
    
    // Lifecycle
    virtual void start(MasterTimer* timer, FunctionParent* parent);
    virtual void stop(FunctionParent* parent);
    virtual void write(MasterTimer* timer, QList<Universe*> universes);
    
    // Properties
    void setName(const QString& name);
    Type type() const;
    quint32 totalDuration() const;
};

User Interfaces

QLC+ supports two UI implementations:

QtWidgets UI (QLC+ 4)

Traditional desktop interface in ui/src/:
  • Virtual Console - Live control interface
  • Simple Desk - Direct channel control
  • Show Manager - Timeline editor
  • Fixture Manager - Fixture patching
  • Function Manager - Function creation/editing
  • Input/Output - Plugin configuration

QML UI (QLC+ 5)

Touch-optimized interface in qmlui/:
  • Modern, responsive design
  • Better touch support
  • 3D visualization
  • Same engine underneath
Built with Qt3D for 3D preview features.

Web Interface

The webaccess/ module provides browser-based control:
  • Remote control via HTTP
  • Virtual console access
  • Simple desk
  • Function triggering
  • No installation required on client

Plugin System

Plugins provide hardware I/O and protocol support through a common interface.

Plugin Interface

All plugins implement QLCIOPlugin (plugins/interfaces/qlcioplugin.h:90):
class QLCIOPlugin : public QObject
{
public:
    enum Capability {
        Output   = 1 << 0,  // DMX output
        Input    = 1 << 1,  // DMX input
        Feedback = 1 << 2,  // Input feedback
        Infinite = 1 << 3,  // Unlimited universes
        RDM      = 1 << 4,  // RDM support
        Beats    = 1 << 5   // Beat detection
    };
    
    // Initialization
    virtual void init() = 0;
    virtual QString name() const = 0;
    virtual int capabilities() const = 0;
    
    // I/O lines
    virtual QStringList outputs() const = 0;
    virtual QStringList inputs() const = 0;
    
    // Open/close
    virtual bool openOutput(quint32 output, quint32 universe) = 0;
    virtual void closeOutput(quint32 output, quint32 universe) = 0;
    virtual bool openInput(quint32 input, quint32 universe) = 0;
    virtual void closeInput(quint32 input, quint32 universe) = 0;
    
    // Data transfer
    virtual void writeUniverse(quint32 universe, quint32 output,
                               const QByteArray& data) = 0;
    
signals:
    void valueChanged(quint32 universe, quint32 input,
                     quint32 channel, uchar value);
};

Available Plugins

Plugins in plugins/:

DMX USB

  • ENTTEC DMX USB Pro
  • DMXKing
  • Eurolite
  • Many USB-DMX adapters

Art-Net

  • Art-Net III protocol
  • Multiple universes
  • Broadcast and unicast

E1.31 (sACN)

  • ANSI E1.31 protocol
  • Streaming ACN
  • Multicast support

MIDI

  • MIDI input/output
  • Show control
  • External controller support

OSC

  • Open Sound Control
  • Network-based control
  • TouchOSC compatible

HID

  • Generic HID devices
  • Keyboards
  • Game controllers

OLA

  • Open Lighting Architecture
  • Many protocols via OLA

Loopback

  • Internal universe routing
  • Testing

Plugin Architecture

Data Flow

DMX Output Pipeline

1

Function Execution

MasterTimer calls write() on each running function
2

Value Generation

Functions generate channel values based on their logic
3

Fader Application

GenericFader applies fade curves and HTP/LTP rules
4

Universe Assembly

MasterTimer combines all values into universe buffers
5

Plugin Output

InputOutputMap sends universe data to plugins via writeUniverse()
6

Hardware Transmission

Plugins transmit data to physical hardware/network

Input Processing

1

Hardware Input

Plugin receives input from hardware
2

Signal Emission

Plugin emits valueChanged() signal
3

Input Map

InputOutputMap receives and routes input
4

Profile Application

Input profiles map physical controls to channels
5

Widget Handling

Virtual Console widgets respond to input

Resource Management

Fixture Definitions

  • Location: resources/fixtures/
  • Format: XML (.qxf files)
  • Cache: QLCFixtureDefCache
  • Validation: XML schema in resources/schemas/

RGB Scripts

  • Location: resources/rgbscripts/
  • Format: JavaScript
  • API Version: 2
  • Cache: RGBScriptsCache
See RGB Scripts for API details.

Input Profiles

  • Location: resources/inputprofiles/
  • Format: XML
  • Purpose: Map input devices to QLC+ controls

Threading Model

The MasterTimer runs in its own thread. All function write() methods must be thread-safe.

Thread Organization

  • Main Thread: UI and user interaction
  • MasterTimer Thread: Function execution and DMX generation
  • Plugin Threads: Some plugins use separate threads for I/O

Thread Safety

  • Use QMutex for shared data structures
  • Emit signals across thread boundaries
  • Be careful with Doc access from MasterTimer

Build System Integration

The architecture is reflected in the CMake structure (CMakeLists.txt:73-89):
add_subdirectory(hotplugmonitor)
add_subdirectory(engine)
add_subdirectory(resources)
add_subdirectory(plugins)
add_subdirectory(webaccess)
if(qmlui)
    add_subdirectory(qmlui)
else()
    add_subdirectory(ui)
    add_subdirectory(main)
    add_subdirectory(fixtureeditor)
endif()

Next Steps

Build docs developers (and LLMs) love