first strudel via AI
This commit is contained in:
231
agentic_workflow/prod_tips.md
Normal file
231
agentic_workflow/prod_tips.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# Production Tips for Strudel
|
||||
|
||||
Professional-level techniques for polished output.
|
||||
|
||||
## 1. Mixing in Strudel
|
||||
|
||||
### Gain Staging
|
||||
Always set explicit gain values. Elements should not fight for space:
|
||||
|
||||
```js
|
||||
$: s("bd*4").gain(1.1) // kick = loudest
|
||||
$: s("[~ sd]*2").gain(0.7) // snare = clear
|
||||
$: s("[~ hh]*4").gain(0.25) // hats = subtle
|
||||
$: note("c2*4").s("sine").gain(0.5) // bass = strong
|
||||
$: note("[c4,e4,g4]").s("triangle").gain(0.15) // pad = background
|
||||
$: note("c5 e5 g5").s("sine").gain(0.1) // melody = present but soft
|
||||
```
|
||||
|
||||
### Frequency Separation
|
||||
Each layer should own a frequency range. Use `.lpf()` and `.hpf()` to carve space:
|
||||
|
||||
```js
|
||||
// Sub bass: ONLY low frequencies
|
||||
note("c1").sound("sine").lpf(80).gain(0.6)
|
||||
|
||||
// Mid bass: remove sub, keep warmth
|
||||
note("c2").sound("sawtooth").lpf(600).hpf(80).gain(0.3)
|
||||
|
||||
// Pad: remove low-end mud
|
||||
note("[c3,e3,g3]").sound("triangle").hpf(300).lpf(3000).gain(0.15)
|
||||
|
||||
// Hi-hats: only highs
|
||||
s("hh*8").hpf(3000).gain(0.25)
|
||||
```
|
||||
|
||||
### Stereo Width with Pan
|
||||
Center: kick, bass, snare. Sides: hats, pads, FX.
|
||||
|
||||
```js
|
||||
$: s("bd*4").gain(1) // center (default)
|
||||
$: s("hh*8").gain(0.2).pan(sine.range(0.3, 0.7)) // gentle side movement
|
||||
$: note("[c4,e4,g4]").s("saw").gain(0.1).jux(rev) // wide stereo
|
||||
```
|
||||
|
||||
## 2. Movement & Variation
|
||||
|
||||
### Filter Automation (Essential for Non-Static Sound)
|
||||
```js
|
||||
// Slow sweep over 8 cycles
|
||||
.lpf(sine.range(300, 3000).slow(8))
|
||||
|
||||
// Fast wobble
|
||||
.lpf(sine.range(200, 1500).fast(2))
|
||||
|
||||
// Random variation
|
||||
.lpf(perlin.range(500, 2000))
|
||||
|
||||
// Stepped changes
|
||||
.lpf("<400 800 1200 2000>")
|
||||
```
|
||||
|
||||
### Rhythmic Variation with `every`
|
||||
```js
|
||||
// Reverse every 4th cycle
|
||||
s("bd sd [~ bd] sd").every(4, x => x.rev())
|
||||
|
||||
// Double speed every 3rd cycle (fill)
|
||||
s("bd sd [~ bd] sd").every(3, x => x.ply(2))
|
||||
|
||||
// Add filter sweep every 8th cycle
|
||||
s("hh*16").every(8, x => x.lpf(sine.range(500, 5000)))
|
||||
```
|
||||
|
||||
### The `off` Technique (Ghost Notes / Echoes)
|
||||
```js
|
||||
// Ghost notes: offset copy played softer and pitch-shifted
|
||||
n("0 2 4 6").scale("C:minor")
|
||||
.off(1/8, x => x.add(7).gain(0.3))
|
||||
.sound("piano")
|
||||
```
|
||||
|
||||
### Humanize with Randomness
|
||||
```js
|
||||
// Random gain variation (human feel)
|
||||
s("hh*16").gain(perlin.range(0.1, 0.35))
|
||||
|
||||
// Random panning
|
||||
s("rim*4").pan(rand)
|
||||
|
||||
// Sometimes skip notes
|
||||
s("hh*16").sometimesBy(0.2, x => x.gain(0))
|
||||
```
|
||||
|
||||
## 3. Sound Design Techniques
|
||||
|
||||
### Layering Synths
|
||||
```js
|
||||
// Fat bass: two detuned saws
|
||||
note("c2").sound("sawtooth,sawtooth").detune("0 0.3")
|
||||
|
||||
// Rich pad: multiple waveforms
|
||||
note("[c3,e3,g3]").sound("sawtooth,triangle,square")
|
||||
.gain("0.15 0.1 0.05")
|
||||
```
|
||||
|
||||
### Acid Bass (Resonant Filter)
|
||||
```js
|
||||
note("c2 c2 [c2 eb2] c2")
|
||||
.sound("sawtooth")
|
||||
.lpf(sine.range(200, 4000).fast(2))
|
||||
.lpq(10) // high resonance = acid sound
|
||||
.decay(0.1).sustain(0)
|
||||
```
|
||||
|
||||
### Pluck Sound
|
||||
```js
|
||||
note("c4 e4 g4 c5")
|
||||
.sound("triangle")
|
||||
.lpf(3000)
|
||||
.decay(0.15).sustain(0).release(0.3)
|
||||
```
|
||||
|
||||
### Pad Sound
|
||||
```js
|
||||
note("[c3,e3,g3,b3]")
|
||||
.sound("sawtooth")
|
||||
.lpf(800).lpq(1)
|
||||
.attack(0.5).release(1.5)
|
||||
.room(0.7).size(0.9)
|
||||
```
|
||||
|
||||
### Sub Bass (808 Style)
|
||||
```js
|
||||
note("c1").sound("sine")
|
||||
.lpf(100).gain(0.6)
|
||||
.decay(0.8).sustain(0)
|
||||
```
|
||||
|
||||
## 4. Arrangement in a Single Loop
|
||||
|
||||
Since Strudel works in cycles, use `<>` and `/N` for section variation:
|
||||
|
||||
### A/B Pattern Alternation
|
||||
```js
|
||||
// Drums: minimal A, full B
|
||||
$: s("<[bd ~ ~ ~]*4 [bd*4]>/8") // kick: sparse then full every 8 cycles
|
||||
$: s("<[~ ~ ~ ~]*4 [[~ sd]*2]*4>/8") // snare: silent then enters
|
||||
```
|
||||
|
||||
### Build-up Effect
|
||||
```js
|
||||
// Filter opens gradually over 16 cycles
|
||||
$: note("c2*4").sound("sawtooth")
|
||||
.lpf(sine.range(200, 4000).slow(16))
|
||||
|
||||
// Hats get denser
|
||||
$: s("hh*<4 8 12 16>")
|
||||
.gain(0.2)
|
||||
```
|
||||
|
||||
### Drop
|
||||
```js
|
||||
// Build: filtered, no kick, rising
|
||||
// Drop: everything at once, filter open
|
||||
$: s("<[~ ~ ~ ~]*4 [bd*4]*4>/8") // kick enters at drop
|
||||
$: note("c2*4").sound("sawtooth")
|
||||
.lpf(saw.range(200, 3000).slow(8)) // filter opens
|
||||
```
|
||||
|
||||
## 5. Advanced Pattern Techniques
|
||||
|
||||
### Polyrhythm
|
||||
```js
|
||||
// 3 against 4
|
||||
note("c3 e3 g3, c4 e4 g4 b4").sound("piano")
|
||||
```
|
||||
|
||||
### Euclidean Rhythms
|
||||
```js
|
||||
// Euclidean distribution of 3 hits in 8 steps
|
||||
sound("{bd bd bd}%8")
|
||||
```
|
||||
|
||||
### Probability
|
||||
```js
|
||||
// Random elements
|
||||
s("bd sd? hh bd").bank("RolandTR909") // sd has 50% chance
|
||||
```
|
||||
|
||||
### Progressive Transformation
|
||||
```js
|
||||
// Pattern morphs over time using every + sometimes
|
||||
n("0 2 4 6").scale("C:minor").sound("piano")
|
||||
.every(4, x => x.add(2))
|
||||
.every(3, x => x.rev())
|
||||
.sometimes(x => x.delay(0.5))
|
||||
```
|
||||
|
||||
## 6. Common Professional Patterns
|
||||
|
||||
### Side-chain Simulation
|
||||
Strudel can't do real sidechain, but you can simulate pump:
|
||||
```js
|
||||
// Pad volume ducks on kick hits
|
||||
note("[c3,e3,g3]").sound("sawtooth")
|
||||
.gain("0.05 0.15 0.2 0.15") // quiet on beat 1 (where kick is)
|
||||
.lpf(1200).room(0.5)
|
||||
```
|
||||
|
||||
### Call and Response
|
||||
```js
|
||||
note("<[c4 e4 g4 ~] [~ ~ ~ [b3 c4]]>")
|
||||
.sound("piano")
|
||||
```
|
||||
|
||||
### Rhythmic Chord Stabs
|
||||
```js
|
||||
note("<[c3,eb3,g3] ~ ~ ~ [ab2,c3,eb3] ~ ~ ~>")
|
||||
.sound("square")
|
||||
.decay(0.05).sustain(0).gain(0.15)
|
||||
```
|
||||
|
||||
## 7. Debugging Checklist
|
||||
|
||||
If it sounds wrong:
|
||||
1. **No sound?** — Check `.sound()` is set. Check gain > 0. Check `lpf` isn't too low.
|
||||
2. **Too muddy?** — Add `.hpf()` to pads/mids. Reduce room on bass.
|
||||
3. **Too static?** — Add signal modulation to filters. Use `every()` for variation.
|
||||
4. **Timing weird?** — Check `setcps()` formula. Verify mini-notation subdivisions.
|
||||
5. **Clashing notes?** — Use `.scale()` to stay in key. Check octave numbers.
|
||||
6. **Too loud/quiet?** — Review gain staging. Kick ~1.0, everything else lower.
|
||||
Reference in New Issue
Block a user