# Strudel Integration Analysis for KidLisp Jukebox ## Overview Strudel is a web-based live coding environment for algorithmic music patterns, a JavaScript port of TidalCycles. It's licensed under AGPL-3.0, which requires source code disclosure for network services. **Repository**: https://codeberg.org/uzu/strudel (cloned to `reference/strudel/`) ## Integration Options ### Option 1: `@strudel/embed` - Iframe Embed (Easiest) Load Strudel REPL in an iframe: ```html ``` **Pros**: Simplest, fully isolated, version pinning **Cons**: No access to audio output for analysis, no KidLisp integration ### Option 2: `@strudel/repl` - Direct Web Component ```html ``` **Pros**: Direct access to REPL API, can control playback **Cons**: Still no direct audio node access ### Option 3: `@strudel/web` - Headless Mode (Best for Integration) ```html ``` **Pros**: Full control, can inject custom audio routing **Cons**: Requires understanding Strudel pattern API ## Audio Analysis Integration ### Key Files in Strudel 1. **`packages/superdough/audioContext.mjs`**: - `getAudioContext()` - Returns shared AudioContext - `setAudioContext(ctx)` - Set custom AudioContext 2. **`packages/superdough/superdough.mjs`**: - `analysers` - Map of AnalyserNodes by ID - `getAnalyserById(id, fftSize, smoothingTimeConstant)` - Get/create analyser - `getAnalyzerData(type, id)` - Get 'time' or 'frequency' data 3. **`packages/superdough/superdoughoutput.mjs`**: - `SuperdoughOutput` - Main output controller - `SuperdoughAudioController` - Manages orbits (channels) and buses - `destinationGain` - Final output gain node before destination ### Hooking Into Audio Output To get audio analysis from Strudel, we need to: 1. **Access the destination gain node**: ```javascript import { getAudioContext } from '@strudel/superdough'; // After initStrudel(), the audio context is available const ctx = getAudioContext(); // Create our own analyser const analyser = ctx.createAnalyser(); analyser.fftSize = 512; // We need to intercept the output - Strudel connects to ctx.destination // Option: Create a custom destination wrapper ``` 2. **Use Strudel's built-in analysers**: ```javascript import { getAnalyserById, getAnalyzerData } from '@strudel/superdough'; // Get analyser (creates if needed) const analyser = getAnalyserById(1, 512, 0.5); // In animation loop: const freqData = getAnalyzerData('frequency', 1); const timeData = getAnalyzerData('time', 1); ``` **Issue**: Strudel's analysers are per-orbit, not global output. Need to investigate how to connect to global output. ### Recommended Integration Approach 1. **Use `@strudel/web` for headless control** 2. **Intercept audio at the destination**: ```javascript // After initStrudel() const ctx = getAudioContext(); // Create a gain node to intercept ALL audio const masterGain = ctx.createGain(); const analyser = ctx.createAnalyser(); analyser.fftSize = 512; // Monkey-patch or use custom AudioContext setup // to route all Strudel output through our analyser masterGain.connect(analyser); analyser.connect(ctx.destination); ``` 3. **Alternative: Modify superdoughoutput.mjs** In `SuperdoughOutput.initializeAudio()`: ```javascript this.destinationGain.connect(audioContext.destination); // Add: this.destinationGain.connect(window.strudelAnalyser); ``` ## Jukebox Implementation Plan ### Phase 1: Basic Strudel Playback 1. Add Strudel tab to Jukebox 2. Load `@strudel/web` dynamically 3. Provide code editor for Strudel patterns 4. Play/Stop buttons call `evaluate()` and `hush()` ### Phase 2: Audio Analysis 1. Create custom AudioContext wrapper that includes our analyser 2. Call `setAudioContext(customCtx)` before `initStrudel()` 3. Route Strudel output through our analyser 4. Send analysis data to KidLisp (`amp`, `bass`, `mid`, `treble`, `kick`) ### Phase 3: KidLisp Integration 1. Strudel patterns can be stored alongside KidLisp code 2. `(strudel "s('bd sd')")` function in KidLisp 3. Live audio variables react to Strudel playback ## Sample Code: Custom Audio Context with Analysis ```javascript // Create our AudioContext with analyser in the chain const audioContext = new AudioContext(); const masterGain = audioContext.createGain(); const analyser = audioContext.createAnalyser(); analyser.fftSize = 512; // Create a proxy destination const proxyDestination = masterGain; masterGain.connect(analyser); analyser.connect(audioContext.destination); // Set up Strudel with our context import { setAudioContext } from '@strudel/superdough'; setAudioContext(audioContext); // Now initStrudel will use our context initStrudel(); // Analysis loop function analyze() { const freqData = new Uint8Array(analyser.frequencyBinCount); const timeData = new Uint8Array(analyser.fftSize); analyser.getByteFrequencyData(freqData); analyser.getByteTimeDomainData(timeData); // Calculate amp, bass, mid, treble, kick... // Send to KidLisp requestAnimationFrame(analyze); } ``` ## License Considerations Strudel uses AGPL-3.0: - Source code must be made available for network services - Derivative works must use same license - Our use is embedding/integration, not modification - If we modify Strudel code, must share those changes - aesthetic.computer is already open source, so this is fine ## Dependencies @strudel/web (1.3.0) bundles: - @strudel/core - Pattern engine - @strudel/mini - Mini-notation parser - @strudel/tonal - Music theory - @strudel/webaudio - WebAudio integration - @strudel/transpiler - Code transformation - superdough - Synthesis engine Total unpacked size: ~1.55 MB ## Next Steps 1. Create proof-of-concept in kidlisp.com with @strudel/web 2. Test audio interception approach 3. Implement pattern editor in Jukebox tab 4. Connect analysis to KidLisp audio variables 5. Add preset patterns for quick testing