Skip to content

tomasmark79/DreamScalerUsbLedStripController

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DreamScaler LedStrip USB Controller

USB/Serial controller for SK6812 RGBW LED strips with Piano Mode support for Arturia Keylab 49 MKII and visualisation of 60+ musical scales, integrated with Bitwig Studio via OSC.

🌱 Help Keep This Going Your support makes a real difference. If you value my work and want to help me continue creating, please consider making a donation. 💙 Donate here: https://paypal.me/TomasMark Every contribution is truly appreciated ✨


Video

Youtube video of usage

🚀 Quick Start

# 1. Upload firmware to Arduino
# Arduino IDE → Open → ds_usb_controller/ds_usb_controller.ino → Upload

# 2. Install Python dependencies
pip install -r requirements.txt

# 3. Run the launcher
python launcher.py              # interactive menu
python launcher.py --mode osc   # OSC bridge (Bitwig → LED)
python launcher.py --mode piano # Piano interactive tool

✨ Features

🎹 Piano Mode

  • Arturia Keylab 49 MKII (49 keys → 107 LEDs)
  • 60+ musical scales (Major, Minor, Pentatonic, Blues, Exotic…)
  • Scale degree colour-coding on the LED strip
  • GUI scale selector (Tkinter dark theme)
  • Chord progression explorer
  • Demo effects: rainbow, knight rider, fire, wave, gradient

🔵 LED Controller

  • Fast binary protocol (~16–21 FPS full strip updates)
  • SK6812 RGBW (4-channel)
  • Pixel / Range / Stream / Buffer / Bulk modes
  • Hardware gradient and global brightness
  • Up to 1000 LEDs

🎼 Scale Visualisation

  • Real-time LED visualisation of 60+ musical scales directly on the strip
  • Each scale degree mapped to a distinct colour (Root = Red, 5th = Blue, …)
  • Instant visual feedback when root note or scale type changes
  • Works both in live Piano Mode and via the Bitwig OSC Bridge

🎛️ Bitwig OSC Bridge

  • Receives /dreamscaler/scale OSC messages from Bitwig Studio
  • Thread-safe serial access (concurrent calls debounced via Lock)
  • Buffer mode writes (single atomic update per scale change)

🔧 Hardware

Arduino Pin 6  →  SK6812 Data In
Arduino GND    →  SK6812 GND  →  PSU GND    (common ground!)
PSU 5 V        →  SK6812 5 V

Requirements:

  • Arduino Uno / Nano / Mega
  • SK6812 RGBW LED strip (not WS2812 — 4 channels required)
  • External 5 V PSU (107 LEDs ≈ 8.6 A, 144 LEDs ≈ 11.5 A)

Tested PSU for 1 m / 144-LED strip: A 5 V 10 A 50 W mains adapter (switching power supply) is the ideal choice. It provides enough headroom for full-brightness RGBW operation while keeping heat and voltage drop under control.

Main components:

DreamScaler components

Firmware defaults: 107 LEDs, Pin 6, 115200 baud, Protocol v11


📦 Installation

Arduino

  1. Open ds_usb_controller/ds_usb_controller.ino in Arduino IDE
  2. Upload (Ctrl+U)

No external Arduino libraries are required. The SK6812 driver is bundled in ds_usb_controller/.

Python

pip install -r requirements.txt

Find your port:

  • Windows: Device Manager → Ports (COM & LPT)
  • Linux: ls /dev/ttyUSB* /dev/ttyACM*
  • macOS: ls /dev/tty.usbserial-*

📁 Project Layout

DreamScaler/
├── config.py                   # ⚙️  Central config — port, brightness, colours
├── DreamScaler.control.js      # Bitwig controller script (sends OSC and stores project settings)
├── launcher.py                 # Single CLI entry point (--mode osc|piano)
├── osc_bridge.py               # OSC listener → LED driver
├── piano.py                    # Unified piano tool (GUI, scales, chords, demos)
├── controller_api.py           # Low-level Arduino serial API
├── arturia_keylab49_map.py     # 49-key → 107-LED mapping
├── arturia_keylab61_map.py     # 61-key mapping variant
├── scales.json                 # Single source of truth for scale definitions
├── scales_data.js              # Auto-generated scale data used by Bitwig
├── generate_scales_js.py       # Regenerates scales_data.js and markdown references
├── scales_en.md                # Generated English scale reference
├── scales_cs.md                # Generated Czech scale reference
├── release_port.py             # Force-release a blocked serial port
├── install_task.bat            # Register Windows auto-start task (double-click)
├── install_task.ps1            # PowerShell script behind install_task.bat
├── remove_task.ps1             # Remove Windows auto-start task
├── requirements.txt
└── ds_usb_controller/
    └── ds_usb_controller.ino   # Arduino firmware (Protocol v11)

🧭 Architecture

Data Flow

Bitwig Studio
  └─ DreamScaler.control.js
      └─ OSC /dreamscaler/scale {rootIndex, scaleName}  →  UDP:9001
          └─ osc_bridge.py
              └─ controller_api.py  →  Serial 115200 baud
                  └─ Arduino ds_usb_controller.ino
                      └─ SK6812 RGBW LED strip (Pin 6)

piano.py can also drive the strip directly through controller_api.py, without Bitwig.

Key Files

File Role
launcher.py Starts either OSC Bridge or Piano Mode from one entry point
osc_bridge.py Receives OSC from Bitwig and translates it into LED updates
piano.py Interactive tool for scales, chords, layout checks and demo effects
controller_api.py Owns the serial protocol and Arduino communication
config.py Default port, LED intensity and scale-degree colours
scales.json Single source of truth for all scale definitions and metadata
scales_data.js Generated JavaScript data consumed by the Bitwig controller
generate_scales_js.py Rebuilds scales_data.js, scales_en.md and scales_cs.md
DreamScaler.control.js Bitwig controller script with per-project settings and OSC output

Arduino Protocol Summary

All LED operations are sent as compact binary commands at 115200 baud. The Arduino replies with 0xF0 for success or 0xFE plus an error code.

Command Code Parameters
PING 0x01
SET_PIXEL_RGBW 0x20 [idx] [R G B W]
SET_ALL_RGBW 0x31 [R G B W]
STREAM_START 0x50 [count]
SYNC 0x60 Push frame to strip

⚙️ Configuration (config.py)

All user-facing settings are in one place — edit this file, no need to touch anything else:

# =============================================================
# DreamScaler — central configuration
# Edit this file to change port, brightness and LED colours.
# =============================================================

import sys

# Serial port of the Arduino USB controller — selected automatically by OS.
if sys.platform == 'win32':
    COM_PORT = 'COM4'
else:
    COM_PORT = '/dev/ttyUSB0'

# LED brightness  (R, G, B, W values are multiplied by this)
# Evening / dark room : 1–3
# Daytime / bright room : 10–30
LED_INTENSITY = 1

# Maximum brightness for a note that is actively played (velocity 127).
# Scales linearly with velocity: brightness = NOTE_PLAYING_INTENSITY * velocity / 127
# The playing note keeps its scale-degree colour, just brighter.
# Notes outside the current scale flash white at this intensity.
NOTE_PLAYING_INTENSITY = 10

# Scale degree colours  (R, G, B, W)
# Each tuple maps a scale degree (1 = root … 7 = leading tone)
# to an RGBW colour.  Adjust to taste.
SCALE_DEGREE_COLORS = {
    1: (LED_INTENSITY, 0,             0,             0),             # Root     – Red
    2: (0,             0,             0,             LED_INTENSITY), # Second   – White
    3: (0,             LED_INTENSITY, 0,             0),             # Third    – Green
    4: (LED_INTENSITY, LED_INTENSITY, 0,             0),             # Fourth   – Yellow
    5: (0,             0,             LED_INTENSITY, 0),             # Fifth    – Blue
    6: (0,             LED_INTENSITY, LED_INTENSITY, 0),             # Sixth    – Cyan
    7: (LED_INTENSITY, 0,             LED_INTENSITY, 0),             # Seventh  – Purple
    'dim': (1,         0,             0,             0),             # Diminished – dim red
}

After changing COM_PORT, re-run install_task.bat to update the scheduled task.

SCALE_DEGREE_COLORS controls the default root-to-degree colour mapping, and NOTE_PLAYING_INTENSITY sets how bright actively played notes are relative to the static scale display.


🚦 Auto-start with Windows (install_task.bat)

The OSC bridge can start automatically every time you log into Windows:

  1. Double-click install_task.bat — registers a Windows Scheduled Task
  2. From that point on, osc_bridge.py starts silently on every login
  3. It will auto-reconnect to the Arduino if the USB is plugged in after login
Task name : DreamScaler OSC Bridge
Trigger   : At log on (current user)
Action    : pythonw osc_bridge.py --port COM4
Restart   : up to 3× if it crashes

To remove the task:

powershell -ExecutionPolicy Bypass -File remove_task.ps1

To update the task (e.g. after changing COM_PORT in config.py):

Double-click install_task.bat again

🛠️ Launcher (launcher.py)

Single entry point for the whole project.

python launcher.py                                        # interactive menu
python launcher.py --mode osc                             # OSC bridge
python launcher.py --mode piano                           # Piano tool
python launcher.py --mode osc   --port COM5 --osc-port 9001
python launcher.py --mode piano --port COM5 --jump 12     # jump to GUI selector
Argument Default Description
--mode (menu) osc or piano
--port config.py Arduino serial port
--osc-port 9001 UDP port for incoming OSC (osc mode)
--jump Skip to a specific piano menu option

🎹 Piano Tool (piano.py)

Interactive tool — run via launcher or directly:

python piano.py COM4
python piano.py COM4 12     # jump straight to the GUI scale selector

Menu options:

Option Description
1 All keys (white = warm white, black = green)
2 White keys only
3 Black keys only
4 Keys coloured by octave
5 Key test animation (sweeps through all 107 LEDs)
7 Print key map (C2–C6, 49 keys)
10 Show a scale on LEDs (category → scale → root note)
11 Chord progressions explorer
12 GUI scale selector (Tkinter window)
20 Demo effects (rainbow, knight rider, fire, wave, gradient)
0 Quit

Scale degree colour coding (LEDs):

Degree Colour
1 – Root Red
2 – Major 2nd White
3 – Major 3rd Green
4 – Perfect 4th Yellow
5 – Perfect 5th Blue
6 – Major 6th Cyan
7 – Major 7th Purple

🎸 OSC Bridge (osc_bridge.py)

Receives scale changes from Bitwig Studio and updates the LED strip.

python osc_bridge.py --port COM4 --osc-port 9001

OSC message from Bitwig:

/dreamscaler/scale  <rootIndex: int 0–11>  <scaleName: string>

rootIndex 0 = C, 1 = C#, …, 11 = B. scaleName is the English scale name generated from scales.json and consumed via scales_data.js.

Thread safety: Two rapid OSC messages (root + scale type from Bitwig) are handled by a Lock — the second concurrent call is silently dropped (debounce effect). The LED is updated on the next message when the lock is free.

Auto-reconnect: If the Arduino is not connected at startup (or disconnects), the bridge keeps running and automatically retries the connection on the next incoming OSC message (cooldown: 10 s).


🐍 Python API (controller_api.py)

from controller_api import LEDController

with LEDController('COM4') as led:
    # Single pixel
    led.set_pixel(0, r=255, g=0, b=0, w=0)

    # Range (same colour)
    led.set_range(0, 10, 255, 0, 0, 0)

    # All pixels
    led.set_all(0, 0, 0, 100)   # all white (W channel)
    led.clear_all()              # all off

    # Stream (fastest for animations — sends all 107 pixels at once)
    pixels = [(r, g, b, w)] * 107
    led.stream_update(pixels)

    # Buffer mode (atomic update — no partial flicker)
    led.buffer_begin()
    for i, (r, g, b, w) in enumerate(pixels):
        led.buffer_set_pixel(i, r, g, b, w)
    led.buffer_end()

    # Hardware gradient (computed on Arduino)
    led.fill_gradient(0, 106, 255, 0, 0, 0,  0, 0, 255, 0)

    # Global brightness
    led.set_brightness(128)   # 50%

    # Utility
    led.ping()
    print(led.get_info())     # {'protocol_version': 11, 'led_count': 107, ...}

    # Colour helpers
    r, g, b = led.hsv_to_rgb(180, 1.0, 0.5)

📊 Performance

Method FPS Best used for
stream_update() 16–21 Full-strip animations
buffer_begin/end() ~16 Atomic scale display
set_range() instant Solid-colour regions
fill_gradient() instant Hardware gradients
set_all() instant Whole strip one colour

Tips:

  • Use stream_update() for animations, not set_pixel() in a loop.
  • Use buffer_begin/end() when you need a flicker-free update (e.g. scale display).
  • Use set_brightness() globally instead of scaling each colour value manually.

🔍 Troubleshooting

Problem Solution
Arduino not connecting Check USB cable, port name, driver. Windows: check Device Manager.
LEDs not lighting External PSU required. Verify common GND. Use Pin 6. SK6812, not WS2812.
Brightness not working Call set_brightness() before set_all().
Port already in use python release_port.py COM5
Low FPS 16 FPS is normal at 115200 baud. Use stream_update() for best throughput.
Random LED 0 lights up Caused by reset_input_buffer() — already fixed in controller_api.py.
Write timeout Concurrent OSC messages — already handled by Lock in osc_bridge.py.

🎸 Bitwig Integration (DreamScaler.control.js)

  1. Copy DreamScaler.control.js and scales_data.js to your Bitwig controller scripts folder.
  2. In Bitwig: Settings → Controllers → Add controller → Generic → DreamScaler.
  3. Start osc_bridge.py (or launcher.py --mode osc).
  4. Change root note or scale type in Bitwig — the LED strip updates immediately.

The controller script sends:

OSC /dreamscaler/scale  rootIndex(0–11)  scaleName(string)

to 127.0.0.1:9001 by default.

Debounce: Bitwig sends two separate OSC messages (root note + scale type) in quick succession. The JS side debounces them with a 200 ms token pattern so only the final state is sent.

Per-project settings: Scale settings (Root Note, Scale Type, Scale Display, LED Intensity) are stored via Bitwig's documentState API and saved inside each .bwproject file. Every project remembers its own scale configuration independently. The Language preference is global (stored via host.getPreferences()) and shared across all projects.

If you edit scales.json, run python generate_scales_js.py before copying DreamScaler.control.js into Bitwig so the controller script and scale reference stay in sync.


Made with ❤️

About

USB/Serial controller for SK6812 RGBW LED strips with Piano Mode support for ANY MIDI Controller and visualization of 60+ musical scales, integrated with Bitwig Studio via OSC.

Topics

Resources

License

Stars

Watchers

Forks

Contributors