SOTCD DJ Bot Setup Documentation

Overview

The DJ Bot is a headless Puppeteer-based automation that runs Strudel (live coding music environment) to generate Acid House audio for the Suns of the Cosmic Dust Twitch stream.

Infrastructure

Host Machine

  • IP: 192.168.1.16 (Proxmox LXC container)
  • Hostname: SOTCD streaming container
  • SSH Access: ssh -i ~/.ssh/github_ed25519 root@192.168.1.16

Directory Structure

/root/sunsofthecosmicdust/
β”œβ”€β”€ .env                    # Twitch credentials (TWITCH_STREAM_KEY, TWITCH_INGEST_URL)
β”œβ”€β”€ go-live.sh              # Main stream launcher script
β”œβ”€β”€ dj-bot/
β”‚   β”œβ”€β”€ index.js            # Puppeteer script that runs Strudel
β”‚   β”œβ”€β”€ package.json        # Node.js dependencies
β”‚   └── node_modules/       # Installed dependencies (puppeteer)
└── website/                # GitHub Pages site (red40mademedoit/sunsofthecosmicdust)

Config Backup Location

  • Local workspace: /home/shdwdev/clawd/sunsofthecosmicdust/
  • Remote: /root/sunsofthecosmicdust/ on 192.168.1.16

Dependencies Installed on 192.168.1.16

System Packages

apt-get install -y xvfb fluxbox xterm cmatrix pulseaudio \
  libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 \
  libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 \
  libxrandr2 libgbm1 libasound2

Node.js (via NVM)

# NVM installed at ~/.nvm
source ~/.nvm/nvm.sh
nvm install --lts  # v24.13.0

Puppeteer Chrome

cd ~/sunsofthecosmicdust/dj-bot
npm install
npx puppeteer browsers install chrome
# Chrome installed at: ~/.cache/puppeteer/chrome/linux-*/chrome-linux64/chrome

Stream Components

1. Xvfb (Virtual Display)

  • Display: :99
  • Resolution: 1920x1080x24

2. Fluxbox (Window Manager)

  • Runs on display :99
  • Provides window management for xterm

3. Visual Layer (Pink & Green Matrix)

  • Two xterm instances running cmatrix
  • Left side: Green (-C green)
  • Right side: Magenta (-C magenta)

4. DJ Bot (Strudel Audio)

  • Headless Chrome via Puppeteer (headless: true)
  • Navigates to https://strudel.cc/?panel=repl
  • Injects Acid House code into the REPL
  • Key Chrome args for audio:
    • --autoplay-policy=no-user-gesture-required
    • --no-sandbox
    • --disable-setuid-sandbox

5. PulseAudio

  • Virtual sink: virtual_speaker
  • Monitor source: virtual_speaker.monitor
  • Start with: pulseaudio --start --exit-idle-time=-1
  • Create sink: pactl load-module module-null-sink sink_name=virtual_speaker

6. FFmpeg (Stream Encoder)

  • Video: x11grab from :99
  • Audio: PulseAudio monitor OR lavfi sine wave (drone fallback)
  • Output: RTMP to Twitch

go-live.sh Script Flow

  1. Load environment variables from .env
  2. Start Xvfb on :99
  3. Start Fluxbox window manager
  4. Launch dual xterm windows with cmatrix (Pink & Green)
  5. Start DJ Bot (node index.js)
  6. Start FFmpeg to capture and stream

Troubleshooting

DJ Bot Crashes

  • Check /tmp/dj-bot.log for errors
  • Common issue: Missing X server β†’ ensure headless: true in index.js
  • Missing Chrome libs β†’ reinstall dependencies

No Audio

  • Verify PulseAudio is running: pulseaudio --check
  • Check virtual sink exists: pactl list sinks short
  • Verify Chrome is outputting to sink: pactl list sink-inputs

Stream Not Starting

  • Check for stale lock file: rm -f /tmp/.X99-lock
  • Kill all processes: pkill -9 ffmpeg xterm fluxbox Xvfb node

Quick Commands

Start Stream (Matrix + Drone Audio)

ssh -i ~/.ssh/github_ed25519 root@192.168.1.16 \
  "cd ~/sunsofthecosmicdust && nohup bash go-live.sh > /tmp/sotcd.log 2>&1 &"

Stop Stream

ssh -i ~/.ssh/github_ed25519 root@192.168.1.16 \
  "pkill -9 ffmpeg xterm fluxbox Xvfb node; rm -f /tmp/.X99-lock"

Check Stream Status

ssh -i ~/.ssh/github_ed25519 root@192.168.1.16 "pgrep -a ffmpeg && tail -20 /tmp/sotcd.log"

Current Status (2026-02-02)

  • βœ… Matrix visuals working (Pink & Green)
  • βœ… Drone audio working (55Hz sine wave)
  • ❌ DJ Bot Strudel audio: ABANDONED (WebAudio issues - see below)
  • βœ… SuperCollider acid house engine: WORKING
  • βœ… Multi-genre audio switching: FIXED (v3 with crossfades)
  • βœ… Stream bitrates: 6500k for both Twitch & YouTube

Milestone: 15+ Hour Livestream POC (2026-02-02)

Completed 15+ hour continuous Twitch stream documenting full proof-of-concept build. Video cached for archival. Demonstrated working SuperCollider audio pipeline with VB-Cable routing to FFmpeg.

SuperCollider Setup (ShadowMaster - Windows)

Host Machine

  • IP: 192.168.1.214
  • Hostname: ShadowMaster
  • User: shdwadmin
  • SSH Access: ssh shdwadmin@192.168.1.214 -i ~/.ssh/id_ed25519

Directory Structure

C:\Users\shdwadmin\sotcd\
β”œβ”€β”€ START_CONDUIT.bat       # Main launcher (starts SC + Bridge + Hydra)
β”œβ”€β”€ cosmic_genres.scd       # Multi-genre engine with crossfades (v3)
β”œβ”€β”€ headless_boot.scd       # Single-genre adaptive acid
β”œβ”€β”€ signal_bridge_visual.js # Cosmic data β†’ OSC + WebSocket bridge
β”œβ”€β”€ hydra_cosmic.js         # Hydra visual code
β”œβ”€β”€ stream_twitch.bat       # FFmpeg β†’ Twitch (6500k bitrate)
β”œβ”€β”€ stream_youtube.bat      # FFmpeg β†’ YouTube (6500k bitrate)
β”œβ”€β”€ kill_stream.bat         # Stop all streams
└── node_modules/           # Node dependencies (osc, ws)

Audio Routing

SuperCollider β†’ VB-Audio Virtual Cable β†’ FFmpeg capture β†’ RTMP
  • Server port: 58110 (avoiding Windows Hyper-V reserved 57xxx range)
  • Audio device: β€œCABLE Input (VB-Audio Virtual Cable)β€œ

The Conduit System

START_CONDUIT.bat orchestrates the full stream:

  1. Launches SuperCollider IDE with cosmic_genres.scd
  2. Starts Signal Bridge (signal_bridge_visual.js)
  3. Opens Hydra code + Hydra website for visuals
  4. User manually runs stream_twitch.bat / stream_youtube.bat

Signal Bridge pulls real-time cosmic data:

  • 🌍 USGS Earthquake feed
  • β˜€οΈ NOAA Solar X-ray flux
  • 🌬️ Solar wind plasma (density, speed, temp)
  • πŸŒ™ Planetary positions & moon phase

Data maps to audio parameters via OSC on port 57120.

Working SynthDefs

  • \acidBass - 303-style acid bass with filter envelope
  • \acid303 - Classic squelchy acid line
  • \kick - 4/4 kick drum with pitch sweep
  • \hihat - Hi-hat (white noise + HPF)
  • \dronePad - Ambient pad with reverb
  • \darkDrone - Low rumbling drone
  • \chaosPad - Chaos-modulated pad

Multi-Genre Switching (FIXED 2026-02-02)

v3 now working with smooth transitions:

  • 4-second crossfades between genres (patterns overlap)
  • Gradual BPM interpolation (5% per tick, no jarring tempo jumps)
  • Transition lock prevents rapid genre thrashing
  • Signal-based auto-switching:
    • < 0.33 β†’ Ambient (75 BPM)
    • 0.33-0.66 β†’ Acid House (125 BPM)
    • > 0.66 β†’ Dark (85 BPM)
  • Manual override: send /genre ambient|acid|dark via OSC

Fixes applied 2026-02-02:

  • START_CONDUIT.bat now loads cosmic_genres.scd (was incorrectly loading headless_boot.scd)
  • Genre switcher rewritten with crossfade overlap instead of hard stops
  • BPM smoother routine for gradual tempo changes
  • Both stream batch files set to 6500k bitrate

OSC Endpoints (port 57120)

AddressRangeDescription
/signal0-1Master signal (triggers genre switch)
/bpm60-200Target tempo
/filter100-8000Filter cutoff frequency
/chaos0-1Chaos/modulation amount
/genresymbolManual genre override (ambient/acid/dark)

Stream Encoding (FFmpeg)

Both Twitch and YouTube use identical settings:

ffmpeg -f gdigrab -framerate 30 -i desktop \
  -f dshow -i audio="CABLE Output (VB-Audio Virtual Cable)" \
  -c:v libx264 -preset veryfast -b:v 6500k \
  -pix_fmt yuv420p -g 60 \
  -c:a aac -b:a 128k -ar 44100 -ac 2 \
  -f flv "rtmp://..."

WebAudio Suspension Problem

The Issue

Browser WebAudio (used by Strudel) is designed to prevent autoplay abuse. Even with all the β€œright” flags, the AudioContext suspends without real user interaction:

  • --autoplay-policy=no-user-gesture-required doesn’t fully work
  • AudioContext gets suspended randomly
  • Audio plays for a few seconds/bars, then stops
  • Not viable for 24/7 unattended streaming

What We Tried

  • Puppeteer with headless Chrome
  • xdotool to simulate clicks
  • Various Chrome flags for autoplay
  • PulseAudio virtual sink routing

Result

Occasional 2-bar bursts of audio, then silence.

Alternative Approaches (If Revisiting)

ApproachProsCons
SuperColliderHeadless-native, pro audioLearning curve
SonicPiRuby-based, no browserRequires display for GUI
Node + tone.jsJavaScript, server-sidenode-web-audio-api limitations
Pre-rendered tracksSimple, reliableNo live generation
Icecast + liquidsoapProper radio stackComplex setup

Lessons Learned

  • Browser WebAudio is hostile to automation by design (anti-autoplay)
  • For reliable 24/7 headless audio: use native audio tools, not browsers

See Also