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.
Doc (engine/src/doc.h:54)
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.
InputOutputMap (engine/src/inputoutputmap.h:27)
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).
Scene
Chaser
EFX
RGBMatrix
Collection
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 );
};
Sequences multiple functions in order: class Chaser : public Function
{
// Step management
bool addStep ( const ChaserStep & step );
bool removeStep ( int index );
QList < ChaserStep > steps () const ;
// Playback
enum RunOrder { Loop , PingPong , SingleShot };
void setRunOrder ( RunOrder order );
void setDirection ( Direction dir );
};
Creates geometric movement patterns: class EFX : public Function
{
// Algorithms
enum Algorithm { Circle , Square , Diamond , Lissajous , ... };
void setAlgorithm ( Algorithm algo );
// Fixture heads
bool addFixture ( EFXFixture * fixture );
QList < EFXFixture * > fixtures ();
};
Controls LED matrix effects: class RGBMatrix : public Function
{
// Script
void setScript ( const QString & name );
RGBScript * script () const ;
// Fixture group
void setFixtureGroup ( quint32 id );
// Animation
enum AnimationStyle { Forward , Backward , PingPong , ... };
};
Runs multiple functions simultaneously: class Collection : public Function
{
// Function management
bool addFunction ( quint32 functionId );
bool removeFunction ( quint32 functionId );
QList < quint32 > functions () const ;
};
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:
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
Function Execution
MasterTimer calls write() on each running function
Value Generation
Functions generate channel values based on their logic
Fader Application
GenericFader applies fade curves and HTP/LTP rules
Universe Assembly
MasterTimer combines all values into universe buffers
Plugin Output
InputOutputMap sends universe data to plugins via writeUniverse()
Hardware Transmission
Plugins transmit data to physical hardware/network
Hardware Input
Plugin receives input from hardware
Signal Emission
Plugin emits valueChanged() signal
Input Map
InputOutputMap receives and routes input
Profile Application
Input profiles map physical controls to channels
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.
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