diff --git a/README.md b/README.md index f887502..d476776 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,15 @@ MIDI and open source software to convert an old Pioneer CDJ200 to a standalone p - /print-assets/ -> STL file to 3D print + adhesive custom skin to print - /docs/ -> Documentation of this project -## Raspberry Pi 3B+ Image file: #in progress 01.2026 + +## Raspberry Pi 3B+ Image file Note it only works with the Raspberry Pi 3B+ -[Image File](https://drive.google.com/). +[Image File](https://drive.google.com/file/d/1fU8ckY35uxCYHJtw1JgclCYaJdQCbCJT/view?usp=sharing). + + +[![Discord](https://img.shields.io/badge/Discord-Join_the_community-5865F2?logo=discord&logoColor=white)](https://discord.gg/4D3xxvuDTy) ### πŸ“œ License - All code in this repository is released under the [GNU GPL v3 License](https://www.gnu.org/licenses/gpl-3.0.html). @@ -37,3 +41,5 @@ Note it only works with the Raspberry Pi 3B+ 2025 Marc Monka 2026 Markus Golec + +2026 Jeancarlo Cardoso de Faria Filho (jaianlab) β€” Raspberry Pi Pico port, MCP developer tool diff --git a/docs/XDJ100SX.pdf b/docs/XDJ100SX.pdf index f03e67f..478114d 100644 Binary files a/docs/XDJ100SX.pdf and b/docs/XDJ100SX.pdf differ diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000..876fdbd --- /dev/null +++ b/tools/README.md @@ -0,0 +1,165 @@ +# XDJ-100SX Developer Tool + +Claude Code MCP server + CLI + TUI for the XDJ-100SX Pi system. +Push skin files, take screenshots, flash firmware, and manage the Pi β€” all from your editor. + +--- + +## Requirements + +```bash +pip install paramiko watchdog textual +``` + +--- + +## Quick start + +```bash +python3 tools/xdj-pi-dev.py --check # verify connection + environment +python3 tools/xdj-pi-dev.py --status # live Pi + Mixxx status +python3 tools/xdj-pi-dev.py --ui # interactive TUI +python3 tools/xdj-pi-dev.py --about # authors & credits +python3 tools/xdj-pi-dev.py --help # full command reference +``` + +--- + +## Connection + +The tool tries these in order: + +1. `--host` flag +2. `XDJ_HOST` environment variable +3. `XDJ100SX.local` β€” mDNS, works on any network (WiFi or LAN) +4. `192.168.10.2` β€” static IP fallback for direct cable + +### Direct cable (no router) + +One-time setup on your machine: + +```bash +# macOS +sudo ifconfig en0 alias 192.168.10.1 255.255.255.0 + +# Linux +sudo ip addr add 192.168.10.1/24 dev eth0 + +# Windows (run as Administrator) +netsh interface ip set address "Ethernet" static 192.168.10.1 255.255.255.0 +``` + +Then on the Pi (once): + +```bash +python3 tools/xdj-pi-dev.py --setup-pi-dhcp +``` + +After that the Pi hands out IPs automatically β€” no manual config needed on any machine. + +### Multi-unit + +Each Pi should have a unique hostname: + +```bash +python3 tools/xdj-pi-dev.py --set-hostname xdj-unit2 +``` + +Then from Claude Code: +- `discover_units` β€” lists all reachable XDJ units on the network +- `select_unit` β€” switches the active connection to a specific unit + +--- + +## Claude Code MCP setup + +Add to `.mcp.json` in your project root: + +```json +{ + "mcpServers": { + "xdj-pi-dev": { + "command": "python3", + "args": ["tools/xdj-pi-dev.py"] + } + } +} +``` + +Add to `.claude/settings.local.json`: + +```json +{ + "enabledMcpjsonServers": ["xdj-pi-dev"] +} +``` + +Restart Claude Code. Once connected, you can say things like: + +- *"push the skin and take a screenshot"* +- *"change the play button color in style.qss, push and screenshot"* +- *"restart Mixxx and navigate to the beat loop panel"* +- *"flash the firmware"* +- *"find all XDJ units on the network"* + +--- + +## CLI reference + +### Setup + +```bash +--check # preflight: deps, SSH, Mixxx, audio, Pico +--discover # scan network for all Pi units +--setup-pi-dhcp # configure Pi as DHCP server on eth0 +--setup-ssh-keys # passwordless SSH (recommended) +--set-hostname NAME # rename Pi (e.g. xdj-unit2) +--backup-image # backup SD card to .tar archive +--restore-ssh # recovery guide if SSH is locked out +``` + +### Skin development + +```bash +--push # push all skin files to Pi +--push "*.qss" # push only matching files +--pull # pull skin files from Pi to repo +--screenshot # capture Pi display +--screenshot --panel ks # navigate to panel first (hc/bl/bj/ks/st) +--restart # restart Mixxx +--watch # watch, auto-push + screenshot on save +--watch --panel hc # watch with panel navigation +``` + +### MIDI + +```bash +--push-midi # push MIDI mapping to Pi +--pull-midi # pull MIDI mapping from Pi +--midi-mon # stream live MIDI messages (Ctrl-C to stop) +``` + +### Pico firmware + +```bash +--setup-pico-cli # install arduino-cli on Pi (one-time) +--pico-compile # compile firmware on Pi +--pico-bootloader # reset Pico to UF2 bootloader +--pico-flash FILE.uf2 # flash a local .uf2 to Pi +--analyze # live GPIO signal analyzer +``` + +### Other + +```bash +--cmd 'CMD' # run arbitrary SSH command on Pi +--host 192.168.1.42 # target a specific IP or hostname +--ui # open interactive TUI (requires textual) +--about # show authors and credits +``` + +--- + +## Skin development guide + +See [`SKIN_DEV.md`](SKIN_DEV.md) for Mixxx widget types, layout rules, ConfigKeys, QSS constraints, and color palette β€” everything Claude needs to build and modify skin files correctly. diff --git a/tools/SKIN_DEV.md b/tools/SKIN_DEV.md new file mode 100644 index 0000000..963a102 --- /dev/null +++ b/tools/SKIN_DEV.md @@ -0,0 +1,358 @@ +# XDJ-100SX Skin Development Guide + +Context for Claude Code (via MCP) and human contributors working on the Mixxx skin. + +--- + +## Overview + +The skin runs on a **Raspberry Pi** connected to a **480Γ—272 touchscreen** (landscape). +Mixxx renders the skin as a single-deck player β€” no second deck, no samplers, no vinyl control. + +The skin files live in `mixxx/SKIN/XDJ100SX/`. Push changes with: + +```bash +python3 tools/xdj-pi-dev.py --push # push all files +python3 tools/xdj-pi-dev.py --push "*.qss" # push only QSS +python3 tools/xdj-pi-dev.py --screenshot # see the result +``` + +Or use `--watch` to auto-push and screenshot on every save. + +--- + +## File Structure + +| File | Purpose | +|------|---------| +| `skin.xml` | Root β€” loads style.qss, sets minimum size, defines launch image | +| `config.xml` | Top-level layout: Day/Night toggle + deck area | +| `deck.xml` | Main deck template β€” info row, waveform, transport, performance panels | +| `deckminimal.xml` | Minimal deck view (collapsed state) | +| `tab.xml` | Reusable tab button template | +| `topbar.xml` | Top bar β€” BPM, pitch, track info | +| `waveform.xml` / `waveforms.xml` | Waveform display widgets | +| `overview.xml` | Track overview / position bar | +| `hotcues.xml` | Hot cue performance panel | +| `beatloop.xml` | Beat loop performance panel | +| `beatjump.xml` | Beat jump performance panel | +| `keyshift.xml` | Key shift performance panel | +| `stems.xml` | Stems performance panel | +| `beffect.xml` / `ceffectl.xml` / `ceffectr.xml` | Effect panels | +| `effects.xml` | Effects rack | +| `library.xml` | Library browser panel | +| `style.qss` | All QSS styling | + +--- + +## Layout System + +### Size syntax + +```xml +WIDTH,HEIGHT +``` + +Suffixes: +- `f` β€” fixed (exact pixels, no stretch) +- `me` β€” minimum, expands +- `max` β€” maximum (won't grow beyond this) +- `min` β€” minimum (won't shrink below this) +- No suffix β€” exact fixed size + +Examples: +```xml +65f,40f +0me,65max +me,me +``` + +### SizePolicy + +```xml +me,me +f,f +``` + +### Layout + +```xml +vertical +horizontal +``` + +### WidgetStack + +Shows one child at a time based on a ConfigKey value. Used for the performance panel tabs (hotcues, beatloop, etc.): + +```xml + + + ... + ... + + +``` + +### Templates + +Reusable XML fragments with variables: + +```xml + + + + + +``` + +--- + +## Widget Types + +### PushButton + +```xml + + MyButton + 65f,40f + 2 + + 0 + OFF + + + + 1 + ON + + + [Channel1],play + + +``` + +### Label + +```xml + +``` + +### NumberLabel / NumberDisplay + +For numeric values (BPM, pitch, time): + +```xml + + BPM + 60f,25f + + [Channel1],bpm + + +``` + +### WaveformDisplay + +```xml + + Waveform + me,80f + 1 + #000 + + #ff4444 + +``` + +### Overview (track position bar) + +```xml + + TrackOverview + me,30f + 1 + #111 + #ff0000 + +``` + +### WidgetGroup (container) + +```xml + + MyGroup + horizontal + me,40f + + + + +``` + +--- + +## ConfigKeys + +Format: `[Group],control` + +### Deck controls (single deck β€” always Channel1) + +| ConfigKey | Description | +|-----------|-------------| +| `[Channel1],play` | Play/pause toggle | +| `[Channel1],cue_default` | Cue button | +| `[Channel1],bpm` | Current BPM | +| `[Channel1],rate` | Pitch/rate slider | +| `[Channel1],volume` | Channel volume | +| `[Channel1],quantize` | Quantize on/off | +| `[Channel1],keylock` | Key lock on/off | +| `[Channel1],sync_enabled` | Sync on/off | +| `[Channel1],loop_enabled` | Loop active | +| `[Channel1],beatloop_size` | Current loop size | +| `[Channel1],hotcue_X_activate` | Trigger hot cue X | +| `[Channel1],hotcue_X_clear` | Clear hot cue X | +| `[Channel1],title` | Track title (text) | +| `[Channel1],artist` | Track artist (text) | +| `[Channel1],track_loaded` | 1 if track is loaded | + +### Tab/panel switching (skin-internal) + +The performance panels are driven by `[Channel2]` filter kill controls repurposed as tab flags β€” this is a hack to use existing bool ConfigKeys for panel visibility without needing Mixxx scripting: + +```xml + + + [Channel2],filterLowKill + visible + +``` + +**Do not change this pattern** β€” it would require updating both skin XML and the MIDI mapping script. + +### Skin-internal toggles + +```xml +[Skin],daynight_toggle +``` + +--- + +## QSS Styling + +Standard Qt stylesheet β€” subset of CSS. Applied via `style.qss`. + +### What works + +- `background-color`, `color`, `border`, `border-radius` +- `font-family`, `font-size`, `font-weight` +- `padding`, `margin` +- `min-width`, `max-width`, `min-height`, `max-height` +- `image: url(skin:/images/file.png)` β€” skin-relative paths +- State selectors: `WPushButton[value="1"]` β€” styling when button is active + +### What does NOT work + +- CSS Grid, Flexbox β€” not Qt +- CSS variables (`--my-var`) β€” not supported +- Animations / transitions +- `::before` / `::after` pseudo-elements +- `url()` with absolute paths β€” always use `skin:/` prefix for images +- `rgba()` with 4 args sometimes fails β€” test on device + +### Object name targeting + +```css +#MyButton { background: #333; } /* by ObjectName */ +WPushButton { border: 1px solid white; } /* by widget type */ +WPushButton[value="1"] { color: red; } /* active state */ +``` + +### Color palette (Pioneer style) + +``` +Play green: #6ee128 +Cue orange: #eb870f +Slip red: #d73535 +Tab yellow: #c3d541 +Header dark: #32323c +Title blue bg: #112f5c +Blue accent: #2d85cd +Text white: #e5e6ea +Background: #000000 +``` + +--- + +## Constraints & Rules + +### Screen + +- **Physical display**: 480Γ—272px +- **Skin minimum**: 480Γ—420 (Mixxx scales to fit, Pi display is rotated/scaled) +- Keep UI elements large enough to be finger-tappable (minimum ~40px touch targets) +- No horizontal scrolling β€” everything must fit in 480px width + +### Single deck only + +- Always use `[Channel1]` β€” never `[Channel2]`, `[Channel3]`, `[Channel4]` for actual controls +- `[Channel2]` filter kills are repurposed as panel tab visibility flags β€” don't use them for audio + +### Performance panels + +The skin has 5 performance panels (tabs): Hot Cue, Beat Loop, Beat Jump, Key Shift, Stems. +They are mutually exclusive (WidgetStack). Do not add a 6th tab without updating: +- The tab button row in `deck.xml` +- The WidgetStack in `deck.xml` +- The MIDI mapping in `XDJ100SX.midi.xml` and `XDJ100SX.js` + +### Images + +- Place in `mixxx/SKIN/XDJ100SX/images/` +- Reference as `skin:/images/filename.png` +- Keep image sizes minimal β€” Pi SD card and RAM are limited +- PNG preferred; avoid large JPEGs + +### Templates + +- Template files must start with `