Skip to content

abossard/qlcplus

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10,044 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QLC+ Logo

Q Light Controller+

⚠️ EXPERIMENTAL FORK — USE AT YOUR OWN RISK ⚠️

This fork was largely vibe-coded with AI pair-programming. It has NOT been through upstream code review or formal QA. Do NOT submit PRs to upstream from this fork.

For the official QLC+ project, go to: mcallegari/qlcplus

This fork adds an MCP (Model Context Protocol) server that lets AI agents (Copilot, Claude, Cursor, etc.) design and control lighting shows via natural language.

What this fork adds

  • mcp/ directory: Self-contained MCP server — 47 tools, 3 prompts, 230 unit tests
  • Streamable HTTP transport on http://localhost:9696/mcp (auto-starts with app)
  • autolight/ directory: Iterative LED effect research loop (Python)
  • Function Wizard for QML UI
  • Launchpad controller integration support
  • Audio capture / BPM detection for scripts
  • 22 audio-reactive RGB scripts (LedFX-ported atmospheric effects, strobes, motion, EQ visualizers)
  • RGB Matrix rotation & mirroring (engine-level, all algorithm types)
  • Blend mode ordering fix for Mask/Subtractive blend modes
  • Enhanced OS2L plugin — Bonjour/mDNS auto-discovery, song metadata, connection status LED
  • Auto-reload last workspace on startup (no --openlast flag needed)
  • Theme preset infrastructure — switchable UI themes (includes "VS Code Dark")

Recent engine changes

RGB Matrix Rotation & Mirroring

Rotation and mirroring are now engine-level properties on RGBMatrix, available for all algorithm types (Plain, Script, Text, Image, Audio).

Property Values Description
Rotation 0°, 90°, 180°, 270° Rotates the rendered pattern. 90°/270° swap the algorithm's input dimensions so the pattern renders in rotated coordinate space.
Mirror Off, Horizontal, Vertical, Both Places a mirror at the midpoint of the axis. Rotation is applied first, then mirroring.
Mirror Blend Flip, Max, Average, Additive How mirrored halves are combined. Flip = pure reflection (default). Max = brighter pixel wins. Average = (a+b)/2. Additive = min(255, a+b).

Previously, rotation/mirroring was only available for audio-reactive scripts via auto-injected script properties. The 90° rotation had a bug (sw vs sh coordinate index) that caused most pixels to be black on non-square grids. That bug is now fixed.

Blend Mode Ordering Fix (Mask / Subtractive)

Mask and Subtractive blend modes are order-dependent — they read the current universe value and transform it, so the base layer must write before the overlay. Previously, the write order depended on fader insertion order (essentially random from the user's perspective), which meant Mask/Subtractive often had no visible effect.

Fix: A new BlendOverlay fader priority ensures Mask/Subtractive faders always write after Normal/Additive faders. This makes blend modes work correctly regardless of function start order or collection function list order.

How blend modes work:

Mode Formula Use case
Normal HTP: max(current, new) Default — highest value wins
Additive min(current + new, 255) Layer effects on top of each other
Mask current × (new / 255) Function output = brightness multiplier. White=pass, Black=block.
Subtractive max(current − new, 0) Subtract function's values from existing output

Example — RGB Matrix as a mask: Set the RGB Matrix's blend mode to Mask. Run it alongside a chaser in a collection. The matrix's pixel pattern acts as a stencil — white areas show the chaser's colors, dark areas are blocked.

Enhanced OS2L Plugin — Bonjour Auto-Discovery

The OS2L (Open Sound 2 Light) plugin now supports Bonjour/mDNS service discovery on macOS. VirtualDJ's OS2L "Auto" mode finds QLC+ automatically — no manual IP configuration needed.

Feature Description
Bonjour discovery Registers _os2l._tcp service via native macOS dns_sd.h API. VirtualDJ discovers QLC+ automatically.
Song metadata Parses song events — title, artist, BPM, key, duration available for scripting.
Connection status LED Input patch shows orange (advertising) / green (connected) status indicator.
Bonjour checkbox Enable/disable Bonjour from the OS2L config dialog (default: ON).
Single-client enforcement Tracks TCP connection state; only one DJ app connects at a time.

Quick setup: Enable OS2L on a universe → set VirtualDJ OS2L to Auto → done. See plugins/os2l/README.md for details.

Audio-Reactive RGB Scripts (22 effects)

A complete library of audio-reactive RGB Matrix algorithms, including ports from the LedFX project. All scripts accept audio frequency data via Engine.getAudioFrequency() and support customizable parameters (palette, speed, sensitivity, trigger mode).

Category Scripts
Atmospheric aurora, lava, plasma, fire, water, soap, melt
Motion crawler, chaser, scroll, tunnel, vortex
Visualizers spectrum, equalizer, wavelength, scan
Beat-reactive strobe, shot, energy, power, glitch, blocks

All effects support engine-level rotation (0°/90°/180°/270°), mirroring, and customizable color palettes.

Auto-Reload Last Workspace

QLC+ now automatically loads the most recent workspace file on startup when no file is specified on the command line. Skips gracefully if the file no longer exists on disk.

Theme Presets

New theme preset infrastructure in UiManager allows switching between UI color schemes. Ships with a "VS Code Dark" preset. Presets control toolbar, frame header, and panel colors.

AutoLight — Iterative LED Effect Research

The autolight/ directory is a Python CLI tool that uses the MCP server to run structured A/B-style experiments on LED effects. It automates the create → preview → rate → iterate loop for finding the best-looking effects for your fixture setup.

How it works:

  1. Setup — builds a rating UI in QLC+ Virtual Console (star buttons, dimension ratings)
  2. Briefing — interactive CLI questionnaire (genre, energy, palette, BPM)
  3. Rounds — each round generates 3–4 experiments (different algorithms, colors, timing)
  4. Rate — preview each experiment live, rate it 1–5 stars + per-dimension feedback
  5. Iterate — analysis picks winners, next round refines based on feedback

Each round creates a git branch for safe rollback. State is persisted in autolight-state.json.

Prerequisites: QLC+ running with MCP enabled, fixtures patched, Python 3.10+.

Quick start:

# Install dependencies (one-time)
python3 -m venv .venv && source .venv/bin/activate
pip install -r autolight/requirements.txt

# Create rating UI in QLC+ Virtual Console
python3 -m autolight setup

# Start the research loop (briefing → experiments → rating → iterate)
python3 -m autolight

# Smoke test (verify setup end-to-end, no manual interaction)
python3 autolight/test_loop.py

See autolight/README.md for full documentation (custom dimensions, architecture, color palettes, state file format).

Install from DMG (macOS)

Download the latest DMG from Actions artifacts. After mounting the DMG and dragging QLC+ to /Applications:

sudo xattr -cr /Applications/QLC+.app   # clear quarantine (ad-hoc signed)
open /Applications/QLC+.app

Build from source (macOS)

# Configure (one-time, from repo root)
mkdir -p build && cd build
cmake .. -Dqmlui=ON -Dmcp_server=ON

# Build
cmake --build . -j$(sysctl -n hw.ncpu)

# Run (MCP auto-starts on port 9696)
./qmlui/qlcplus-qml

Runtime flags:

Flag Description
--no-mcp Disable MCP server
--mcp-http <port> Change MCP port (default: 9696)
-d Enable debug output to stderr
-g Log debug output to ~/QLC+.log

Dev cycle — after code changes:

# Rebuild only what changed
cd build && cmake --build . --target qlcplus-qml -j$(sysctl -n hw.ncpu)

# If only MCP server code changed:
cmake --build . --target qlcplusmcp -j$(sysctl -n hw.ncpu)

# Run tests
cmake --build . --target mcp_vc_query_filter_test -j8 && ./mcp/test/mcp_vc_query_filter_test

Connect your AI agent

Copilot CLI / VS Code — add to ~/.copilot/mcp.json:

{
  "servers": {
    "qlcplus": { "url": "http://localhost:9696/mcp" }
  }
}

Claude Code — run:

claude mcp add qlcplus --transport http http://localhost:9696/mcp

Claude Desktop — add to claude_desktop_config.json:

{
  "mcpServers": {
    "qlcplus": { "url": "http://localhost:9696/mcp" }
  }
}

Cursor — add to .cursor/mcp.json:

{
  "mcpServers": {
    "qlcplus": { "url": "http://localhost:9696/mcp" }
  }
}

Available tools (47)

Category Tools
Query query_fixtures, query_available_fixtures, query_functions, query_fixture_channels, query_palettes, query_universes, query_input_profiles, query_midi_devices, query_osc_status, query_channel_modifiers, query_feedback_profile
Patch patch_fixtures
Functions create_scenes, create_chasers, create_sequences, create_efxs, create_collections, create_rgb_matrices, create_scripts, create_fixture_groups, update_scene_from_dmx, delete_functions
Palettes create_palettes, delete_palettes
Channels configure_channels, read_dmx_values, set_channel_modifiers, convert_degrees_to_dmx, set_grand_master
I/O configure_universes, configure_plugin_params, configure_osc, configure_beat_source, configure_launchpad, set_input_profile, vc_configure_feedback
Virtual Console vc_create_pages, vc_create_widgets, vc_query_pages, vc_query_widgets, vc_update_widgets, vc_delete_widgets, vc_reparent_widgets
VC Input vc_map_inputs, vc_set_key_sequences, vc_detect_overlaps
VC Layout vc_reflow_frame

Prompts: design_dj_show, debug_channel_conflict, setup_launchpad

All tools are batch-based (arrays in, arrays out) and idempotent (upsert by name). See mcp/MCP-ARCHITECTURE.md for full documentation.

Script Engine (JavaScript)

create_scripts accepts raw JavaScript executed by QJSEngine in a dedicated thread. Scripts are validated before saving — syntax errors are rejected with line numbers.

Full Engine API (25 methods)

Function Control:

Method Returns Description
Engine.startFunction(id) bool Start any QLC+ function
Engine.stopFunction(id) bool Stop a running function
Engine.isFunctionRunning(id) bool Check if function is active
Engine.waitFunctionStart(id) bool Block until function starts
Engine.waitFunctionStop(id) bool Block until function stops
Engine.stopOnExit(bool) bool Auto-stop started functions on script exit

Fixture Control:

Method Returns Description
Engine.setFixture(fxID, ch, val) bool Set fixture channel (0-255)
Engine.setFixture(fxID, ch, val, fadeMs) bool Set with fade time
Engine.getChannelValue(universe, ch) int Read live pre-GM DMX value

Timing:

Method Returns Description
Engine.waitTime(ms) bool Pause execution (ms)
Engine.waitTime("2s.500") bool Pause using time string
Engine.random(min, max) int Random integer in [min,max]
Engine.random("1s.0", "5s.0") int Random ms from time strings

BPM & Beat:

Method Returns Description
Engine.setBPM(bpm) bool Set beat generator BPM
Engine.getBPM() int Current BPM (internal/MIDI/audio)
Engine.getBeatDuration() int Beat period in ms
Engine.isBeat() bool True if current tick is on a beat

Audio Input:

Method Returns Description
Engine.getAudioLevel() int Overall volume 0-255
Engine.getAudioFrequency(band, numBands) int Frequency band 0-255 (3=bass/mid/high, 16=detailed)

Envelope (from parent Chaser/Collection):

Method Returns Description
Engine.getOwnID() int This script's function ID
Engine.getElapsed() int Ms since script started
Engine.getEnvelopeDuration() int Allocated duration from parent (ms, 0 if standalone)
Engine.getEnvelopeFadeIn() int Fade-in from parent (ms, 0 if not set)
Engine.getEnvelopeFadeOut() int Fade-out from parent (ms, 0 if not set)

Function Attributes:

Method Returns Description
Engine.getFunctionAttribute(id, idx) float Read function attribute
Engine.setFunctionAttribute(id, idx, val) bool Modify running function attribute
Engine.setFunctionAttribute(id, "Name", val) bool By name (e.g. "Width", "Intensity")

System:

Method Returns Description
Engine.setBlackout(bool) bool Toggle global blackout
Engine.systemCommand("prog args") bool Run external process (detached)
Example patterns
// Candle flicker — Gaussian random, warm colors
function gaussRand(mean, std) {
    var u1 = Math.random(), u2 = Math.random();
    return mean + std * Math.sqrt(-2*Math.log(u1)) * Math.cos(2*Math.PI*u2);
}
for (var tick = 0; tick < 200; tick++) {
    for (var c = 0; c < 6; c++) {
        Engine.setFixture(c, 0, Math.max(100, Math.min(255, Math.round(gaussRand(210, 25)))));
    }
    Engine.waitTime(Engine.random(30, 120));
}

// Envelope-adaptive buildup — reusable across different chaser step durations
var totalMs = Engine.getEnvelopeDuration();
if (totalMs <= 0) totalMs = 5000;
var steps = Math.round(totalMs / 25);
for (var i = 0; i <= steps; i++) {
    Engine.setFixture(0, 0, Math.round(255 * i / steps));
    Engine.waitTime(25);
}

// Audio-reactive — bass drives brightness, mid drives color
for (var tick = 0; tick < 500; tick++) {
    var bass = Engine.getAudioFrequency(0, 3);
    var mid = Engine.getAudioFrequency(1, 3);
    Engine.setFixture(0, 0, bass);
    Engine.setFixture(0, 1, mid);
    Engine.waitTime(25);
}

(Often abbreviated as "QLC+")

Open-source lighting control for DMX, Art-Net, sACN and more.
Designed for live shows, theatre, architectural installations, and venues.

Latest release version badge Release date badge Commits since latest release badge Weekly commit activity badge Build status badge Test coverage badge


Download QLC+ badge Raspberry Pi badge Official store badge

Introduction

QLC+ is powerful and user-friendly software to control lighting. QLC+ supports a huge amount of hardware, runs on Linux, Windows (10+), macOS (10.12+), and Raspberry Pi. Whether you're an experienced lighting professional or just getting started, QLC+ empowers you to take control of your lighting fixtures with ease. The primary goal of this project is to bring QLC+ to the level of available commercial software.

Supported protocols

MIDI OSC HID DMX ArtNet E1.31/S.ACN OS2L

QLC+ on social media

Instagram YouTube Facebook

Support & bug reports

We have a dedicated page to help you find support, please check out SUPPORT.md. To learn about a specific feature of QLC+, take a look at the official documentation. To give feedback, submit new fixtures and get new ideas, go to the forum

Help wanted

Click the badge below to see the currently confirmed issues with QLC+. Perhaps you can find a solution?

Help Wanted

Building QLC+

Compilation guides and platform-specific instructions are available in our GitHub Wiki.

Developers at work

If you're regularly updating QLC+ sources with git pull, you may encounter compiler warnings, errors, or unresolved symbols. We strive to keep the master branch free of critical errors; however, dependencies between objects can sometimes cause issues, requiring a full package recompilation rather than just updating recent changes.

Contributing

Software development

We welcome contributions from the community to help make QLC+ even better. If you're working on something major, start a thread in the Development Forum first. Make sure you read the CONTRIBUTING.md document for more.

Financially

If you're reading this we already appreciate you. If you're just getting started with lighting you have absolutely no obligation to give us money. When QLC+ opens up revenue opportunities for you, we'd be very thankful for your support. GitHub sponsors is the preferred option.

GitHub Sponsors

If you're interested, QLC+ also has an official store where you can purchase clothing, themes, the Raspberry Pi image or one-on-one consultation with an expert.

Thank you!

QLC+ owes its success to the dedication and expertise of numerous individuals who have generously contributed their time and skills. The following list recognizes those whose remarkable contributions have played a pivotal role in building QLC+.

GitHub contributors

QLC+ 5
  • Eric Arnebäck (3D preview features)
  • Santiago Benejam Torres (Catalan translation)
  • Luis García Tornel (Spanish translation)
  • Nils Van Zuijlen, Jérôme Lebleu (French translation)
  • Felix Edelmann, Florian Edelmann (fixture definitions, German translation)
  • Jannis Achstetter (German translation)
  • Dai Suetake (Japanese translation)
  • Hannes Bossuyt (Dutch translation)
  • Aleksandr Gusarov (Russian translation)
  • Vadim Syniuhin (Ukrainian translation)
  • Mateusz Kędzierski + smaks6 (Polish translation)
QLC+ 4
  • Jano Svitok (bugfix, new features and improvements)
  • David Garyga (bugfix, new features and improvements)
  • Lukas Jähn (bugfix, new features)
  • Robert Box (fixtures review)
  • Thomas Achtner (ENTTEC wing improvements)
  • Joep Admiraal (MIDI SysEx init messages, Dutch translation)
  • Florian Euchner (FX5 USB DMX support)
  • Stefan Riemens (new features)
  • Bartosz Grabias (new features)
  • Simon Newton, Peter Newman (OLA plugin)
  • Janosch Frank (webaccess improvements)
  • Karri Kaksonen (DMX USB Eurolite USB DMX512 Pro support)
  • Stefan Krupop (HID DMXControl Projects e.V. Nodle U1 support)
  • Nathan Durnan (RGB scripts, new features)
  • Giorgio Rebecchi (new features)
  • Florian Edelmann (code cleanup, German translation)
  • Heiko Fanieng, Jannis Achstetter (German translation)
  • NiKoyes, Jérôme Lebleu, Olivier Humbert, Nils Van Zuijlen (French translation)
  • Raymond Van Laake (Dutch translation)
  • Luis García Tornel (Spanish translation)
  • Jan Lachman (Czech translation)
  • Nuno Almeida, Carlos Eduardo Porto de Oliveira (Portuguese translation)
  • Santiago Benejam Torres (Catalan translation)
  • Koichiro Saito, Dai Suetake (Japanese translation)
Q Light Controller
  • Stefan Krumm (Bugfixes, new features)
  • Christian Suehs (Bugfixes, new features)
  • Christopher Staite (Bugfixes)
  • Klaus Weidenbach (Bugfixes, German translation)
  • Lutz Hillebrand (uDMX plugin)
  • Matthew Jaggard (Velleman plugin)
  • Ptit Vachon (French translation)


License

GitHub License badge

Licensed under the Apache 2.0 License. See COPYING for details.


Copyright © Heikki Junnila, Massimo Callegari

C++ badge Qt badge CMake badge JavaScript badge

About

Q Light Controller Plus (QLC+) is a free and cross-platform software to control DMX or analog lighting systems like moving heads, dimmers, scanners etc. This project is a fork of the great QLC project written by Heikki Junnila that aims to continue the QLC development and to introduce new features.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • C++ 69.1%
  • QML 13.9%
  • HTML 7.0%
  • JavaScript 4.4%
  • CMake 2.5%
  • Python 1.0%
  • Other 2.1%