Auditory Space
Put on headphones. Press play. Close your eyes.
sound("cp").pan(sine.slow(2)).room(0.3)The sound is moving. Where is it going?
Try changing .slow(2) to .slow(8). What happens to the movement?
Now try .pan(rand) instead of .pan(sine.slow(2)). How does it feel different?
What you just experienced is auditory space - the three-dimensional perceptual stage where sounds exist in your mind. Every sound you hear occupies a position in this invisible architecture: left or right, near or far, bright or dark.
Professional audio engineers and electronic music producers think in these spatial terms constantly. When they talk about a mix sounding โwideโ or โdeepโ or โmuddy,โ theyโre describing how sounds occupy complementary spaces - or fail to.
This page will train your ears to perceive these dimensions and give you the tools to sculpt your own sonic landscapes.
Dimension One: Width (The Stereo Field)
The stereo field is the horizontal plane between your left and right ears. Itโs the first dimension of auditory space, and the most immediately perceptible.
The Pan Experience
Listen to this pattern:
$: sound("bd sd bd sd")
$: sound("hh*8")
$: note("c4 eb4 g4").s("sawtooth").lpf(1200)Everything is stacked in the center. Now listen to this:
$: sound("bd sd bd sd").pan(0.5)
$: sound("hh*8").pan(0.7)
$: note("c4 eb4 g4").s("sawtooth").lpf(1200).pan(0.3)The sounds now occupy different positions in the stereo field. This is panning - placing sounds on the left-right axis.
Try it yourself - use sliders to position each element:
const kickPan = slider(0.5, 0, 1)
const hatPan = slider(0.7, 0, 1)
const synthPan = slider(0.3, 0, 1)
$: sound("bd sd bd sd").pan(kickPan)
$: sound("hh*8").pan(hatPan).gain(0.5)
$: note("c4 eb4 g4").s("sawtooth").lpf(1200).pan(synthPan)Pan values:
0= hard left0.5= center1= hard right
The kick stays centered (.pan(0.5)) because low frequencies carry the most energy and typically anchor the mix in the middle.
Dynamic Panning
Static panning places sounds. Dynamic panning moves them through space.
sound("hh*16").pan(sine.range(0.2, 0.8).slow(2))The hi-hats glide smoothly from left to right and back. This creates movement and interest - the ear follows the sound across the stereo field. Watch the scope - you can see the amplitude shift between channels.
Control the movement range and speed:
const leftLimit = slider(0.2, 0, 0.5)
const rightLimit = slider(0.8, 0.5, 1)
const speed = slider(2, 0.5, 8)
sound("hh*16")
.pan(sine.range(leftLimit, rightLimit).slow(speed))
.gain(0.5)Experiment with different signals:
saw- linear sweep, abrupt resettri- smooth back-and-forth (likesinebut linear)rand- random jumps each hitperlin- organic, unpredictable drift
Try: sound("hh*16").pan(perlin.range(0.2, 0.8))
Instant Width with jux
Use the slider to control stereo width from mono to full spread:
const width = slider(0, 0, 1)
n("0 2 4 7").scale("C:minor").s("sawtooth").lpf(800)
.juxBy(width, rev)At 0, the pattern is mono. At 1, it explodes into full stereo.
jux (short for โjuxtaposeโ) splits your pattern into two copies: one panned left, one panned right. It applies a function to the right channel only. Here, the right channel plays the pattern reversed while the left plays it forward.
When your left and right ears hear slightly different versions of the same material, your brain perceives width - a sound that fills the space between your ears.
Width in Practice
stack(
// Kick: centered (low frequencies anchor the mix)
sound("bd*4").pan(0.5),
// Snare: slightly left
sound("~ sd ~ sd").pan(0.4),
// Hi-hats: moving right side
sound("hh*8").pan(sine.range(0.55, 0.75).fast(2)).gain(0.5),
// Synth: wide stereo spread
n("0 3 7 10").scale("C:minor").s("sawtooth").lpf(1500)
.juxBy(0.7, x => x.add(note(0.1))).gain(0.4)
).cpm(32)Notice how each element has its own horizontal territory. The kick and snare stay relatively centered while the hi-hats float to the right and the synth spreads wide. This is stereo separation - giving each sound its own space in the width dimension.
Dimension Two: Depth (Front-to-Back)
Depth is the perception of distance - how close or far a sound feels. In the physical world, distant sounds are quieter, have more reverb (room reflections), and lose high frequencies. We can simulate all of these.
The Proximity Experience
Move the slider from 0 (dry, upfront) to 1 (wet, distant):
const distance = slider(0, 0, 1)
sound("bd sd bd sd")
.room(distance.mul(0.8))
.roomsize(distance.mul(6))
.gain(distance.range(1, 0.5))At 0, the drums feel right in front of you. At 1, they sound like theyโre across a large hall. This is reverb - the collection of echoes that occur when sound bounces off surfaces in a space.
Depth cues:
- More reverb = further away
- Quieter = further away
- Less high frequencies = further away (sound loses โairโ over distance)
Combine these for convincing depth staging.
Room Parameters
Explore the room - from tight bathroom to vast cathedral:
const amount = slider(0.4, 0, 1)
const size = slider(0.5, 0.5, 20)
const brightness = slider(6000, 500, 8000)
note("c4 eb4 g4").s("gm_vibraphone")
.room(amount)
.roomsize(size)
.roomlp(brightness)Try these presets:
- Small room (bathroom): amount=0.4, size=0.5, brightness=6000
- Large hall (cathedral): amount=0.6, size=8, brightness=3000
Room parameters:
room- how much signal goes to the reverb (0-1+)roomsize- the size/decay of the virtual space (0.1 to 20+)roomlp- low-pass filter on the reverb (Hz) - darker rooms have lower valuesroomfade- fade time of the reverb tail
Try roomsize values from 0.5 to 20 and notice how the space expands.
Delay as Spatial Depth
Delay creates echoes - distinct repetitions of the sound. Where reverb is diffuse (many blurred reflections), delay is discrete (clear, rhythmic repeats).
sound("rim").delay(0.5).delaytime(0.25).delayfeedback(0.4)Shape your echoes:
const amount = slider(0.5, 0, 1)
const time = slider(0.25, 0.05, 0.5)
const feedback = slider(0.4, 0, 0.85)
sound("rim")
.delay(amount)
.delaytime(time)
.delayfeedback(feedback)Delay parameters:
delay- how much signal goes to the delay (0-1)delaytime- time between echoes in secondsdelayfeedback- how many times the echo repeats (0-1) - careful above 0.9!
Dub Delay Throws
Jamaican dub producers like King Tubby and Lee โScratchโ Perry discovered that delay could transform a simple recording into something vast and psychedelic. They would manually โthrowโ sounds into delay during mixing, creating dramatic spatial moments.
$: sound("bd rim").bank("RolandTR707")
$: note("[~ [d3,a3,f4]]*2").s("gm_electric_guitar_muted")
.delay(0.7).delaytime(sine.range(0.1, 0.3).slow(8)).delayfeedback(0.5)
.room(0.4)The guitar stabs echo through space with a slowly modulating delay time - a classic dub technique. The delay time drift creates a sense of instability and movement in the depth dimension.
Try this: Change .delay(0.7) to .delay("<0 0 0 0.8>") to throw only every fourth hit into the delay.
Combining Depth Techniques
Control the depth of each layer independently:
const drumDepth = slider(0.05, 0, 0.5)
const bassDepth = slider(0.15, 0, 0.5)
const padDepth = slider(0.6, 0, 1)
stack(
// Front: drums
sound("bd [~ bd] sd [bd sd]").room(drumDepth),
// Middle: bass
note("c2 ~ eb2 ~").s("sawtooth").lpf(500)
.room(bassDepth).roomsize(bassDepth.mul(10)),
// Back: pad
note("<c3,eb3,g3>").s("triangle").slow(2)
.room(padDepth).roomsize(padDepth.mul(10)).lpf(2000)
.delay(padDepth.mul(0.3)).delaytime(0.333).gain(0.4)
).cpm(30)Try pushing all sliders to the same value - the depth staging collapses. Pull them apart - each layer finds its own space.
Dimension Three: Height (The Frequency Spectrum)
The frequency spectrum runs from low (bass, ~20Hz) to high (treble, ~20kHz). Think of it as vertical space - bass frequencies at the bottom, high frequencies at the top. When two sounds occupy the same frequency range, they compete - this is called masking.
Frequency Masking
Use the slider to separate bass and chords in the frequency spectrum:
const separation = slider(0, 0, 1)
// Bass: lpf goes from 800 (masked) to 400 (separated)
$: note("c2").s("sawtooth").lpf(separation.range(800, 400))
// Chords: hpf goes from 0 (masked) to 300 (separated)
$: note("c3 eb3 g3").s("sawtooth")
.hpf(separation.range(50, 300))
.lpf(separation.range(800, 2000))At 0, bass and chords fight for the same frequencies. At 1, each has its own space - bass gets the lows (under 400Hz), chords get the mids (300Hz-2000Hz). This is subtractive EQ - removing frequencies to create space.
Filters in Strudel:
lpf(freq)- low-pass filter: frequencies belowfreqpass, highs are cuthpf(freq)- high-pass filter: frequencies abovefreqpass, lows are cutbpf(freq)- band-pass filter: only frequencies aroundfreqpass
Filter Resonance
Filters can emphasize the cutoff frequency with resonance (Q-factor). Higher resonance creates a more aggressive, โringingโ sound.
note("c2*8").s("sawtooth")
.lpf(sine.range(200, 2000).slow(2))
.lpq(12)This is the classic acid house sound - a resonant low-pass filter sweep. The high .lpq(12) value makes the filter โsingโ at its cutoff point. Watch the scope to see how resonance affects the waveform.
Sculpt your acid line:
const lowFreq = slider(200, 100, 800)
const highFreq = slider(2000, 800, 4000)
const speed = slider(2, 0.5, 8)
const resonance = slider(12, 1, 20)
note("c2*8").s("sawtooth")
.lpf(sine.range(lowFreq, highFreq).slow(speed))
.lpq(resonance)Try different Q values:
lpq(1)- gentle, smooth filteringlpq(8)- noticeable resonancelpq(15)- aggressive, self-oscillating at extreme values
Frequency Separation in Practice
stack(
// Sub bass: only the lowest frequencies
note("c1*4").s("sine").gain(0.6),
// Mid bass: punchy, filtered
note("c2 c2 eb2 c2").s("sawtooth").lpf(400).hpf(60),
// Chords: mid frequencies only
note("<c3,eb3,g3>").s("sawtooth").hpf(300).lpf(2000).gain(0.4),
// Lead: high mids and presence
note("c5 eb5 g5 bb5").s("triangle").hpf(800).gain(0.5),
// Hi-hats: highest frequencies
sound("hh*8").hpf(6000).gain(0.4)
).cpm(30)Each element has its own frequency band:
- Sub bass: 20-60Hz
- Mid bass: 60-400Hz
- Chords: 300Hz-2kHz
- Lead: 800Hz+
- Hi-hats: 6kHz+
This is complementary frequency allocation - the foundation of a clean mix.
Complementary Audio Spaces: The Three-Dimensional Mix
Now letโs combine all three dimensions into a complete spatial arrangement.
stack(
// DRUMS: centered, dry, punchy
stack(
sound("bd [~ bd:2] ~ bd").pan(0.5),
sound("~ cp ~ cp").pan(0.5).room(0.1),
sound("hh*8").pan(sine.range(0.4, 0.65).fast(2)).hpf(6000).gain(0.5)
),
// BASS: centered, dry, low frequencies
note("c2 c2 [eb2 c2] c2").s("sawtooth")
.lpf(400).pan(0.5).room(0),
// CHORDS: wide, mid-depth, mid frequencies
note("<c3,eb3,g3> <bb2,d3,f3>").s("sawtooth").slow(2)
.hpf(300).lpf(2000)
.juxBy(0.6, rev).room(0.25).gain(0.35),
// LEAD: off-center, deep, high-mid frequencies
note("g4 ~ bb4 c5 ~ bb4 g4 ~").s("triangle")
.hpf(600).pan(0.35)
.room(0.4).delay(0.2).delayfeedback(0.3)
.gain(0.5)
).cpm(30)The spatial allocation:
| Element | Width (pan) | Depth (room/delay) | Height (filter) |
|---|---|---|---|
| Kick | Center | Dry | Full range |
| Clap | Center | Slight room | Full range |
| Hi-hats | Moving right | Dry | High-pass 6kHz |
| Bass | Center | Dry | Low-pass 400Hz |
| Chords | Wide (jux) | Medium room | 300Hz-2kHz |
| Lead | Left of center | Room + delay | High-pass 600Hz |
Interactive Spatial Mixer
Take control of all three dimensions with this mixer. Each slider controls a different spatial parameter:
// Width controls
const kickPan = slider(0.5, 0, 1)
const snarePan = slider(0.5, 0, 1)
const hatPan = slider(0.6, 0, 1)
const chordPan = slider(0.5, 0, 1)
// Depth controls
const snareRoom = slider(0.1, 0, 0.6)
const chordRoom = slider(0.25, 0, 0.8)
// Height controls
const hatHpf = slider(6000, 2000, 10000)
const bassLpf = slider(400, 100, 1000)
const chordHpf = slider(300, 100, 800)
const chordLpf = slider(2000, 800, 4000)
stack(
sound("bd*4").pan(kickPan),
sound("~ sd ~ sd").pan(snarePan).room(snareRoom),
sound("hh*8").pan(hatPan).hpf(hatHpf).gain(0.5),
note("c2 c2 eb2 c2").s("sawtooth").lpf(bassLpf).pan(0.5),
note("<c3,eb3,g3>").s("sawtooth").slow(2)
.pan(chordPan).room(chordRoom).hpf(chordHpf).lpf(chordLpf).gain(0.4)
).cpm(30)Genre Spatial Signatures
Different genres have distinct spatial aesthetics. Learning these conventions helps you understand how professionals sculpt space.
House / Techno (Tight and Punchy)
stack(
sound("bd*4").room(0.05),
sound("~ cp ~ cp").room(0.12),
sound("hh*8").pan(0.6).gain(0.45),
sound("oh").euclid(3, 8).pan(0.35).room(0.15).gain(0.35),
note("c2*8").s("sawtooth").lpf(sine.range(200, 600).slow(4))
).cpm(31)Characteristics: Centered kick and bass, moderate width on percussion, short tight reverbs. Everything is upfront and punchy.
Dub (Cavernous and Spatial)
stack(
sound("bd ~ ~ bd ~ ~ bd ~").room(0.25),
sound("~ ~ rim ~").room(0.7).roomsize(6)
.delay(0.6).delaytime(0.375).delayfeedback(0.55)
.pan(sine.range(0.3, 0.7).slow(4)),
note("[~ c4] ~ [~ eb4] ~").s("gm_electric_guitar_muted")
.delay(0.5).delaytime(0.25).delayfeedback(0.4)
.room(0.3).pan(0.6),
note("c2 ~ ~ c2 ~ eb2 ~ ~").s("sawtooth").lpf(400)
).cpm(22)Characteristics: Heavy reverb, dramatic delay throws with modulated times, sparse arrangement letting the space breathe. Sounds travel across the stereo field.
Ambient (Deep and Diffuse)
note("<c3,g3,c4,e4> <a2,e3,a3,c4> <f3,a3,c4,f4> <g2,d3,g3,b3>")
.s("triangle").slow(8)
.attack(2).release(4)
.lpf(sine.range(800, 2500).slow(16))
.room(0.85).roomsize(12).roomlp(2500)
.delay(0.35).delaytime(0.5).delayfeedback(0.45)
.juxBy(0.4, x => x.add(note(0.05)))
.pan(perlin.range(0.3, 0.7).slow(4))Characteristics: Maximum depth (long reverbs), slow evolution, blurred transients, wide stereo field with gentle movement. The boundaries between sounds dissolve.
Using Orbits
Each orbit in Strudel has its own reverb and delay. When patterns share an orbit, they share effects - which can cause conflicts. Use separate orbits to give elements independent spatial treatment.
// Drums: dry, orbit 1
$: sound("bd sd bd [sd cp]").orbit(1).room(0)
// Synth: wet, orbit 2
$: note("c4 [eb4 g4] bb4 ~").s("triangle")
.orbit(2).room(0.6).roomsize(6)When to use separate orbits:
- Drums should typically be drier than synths/pads
- Different songs in a live set might need different reverb settings
- When reverb parameters are fighting between patterns
See the Audio Effects page for more on orbits.
Live Performance Techniques
Spatial parameters are powerful performance tools - they can transform a static pattern into something dynamic and evolving.
Spatial Automation
// Breathing reverb - space ebbs and flows
note("c3 eb3 g3 bb3").s("sawtooth").lpf(1500)
.room(sine.range(0.1, 0.5).slow(4))
.roomsize(sine.range(2, 8).slow(8))// Organic pan drift
sound("hh*16").pan(perlin.range(0.2, 0.8)).gain(0.5)// Classic filter build
note("c2*8").s("sawtooth")
.lpf(sine.range(200, 6000).slow(8))
.lpq(sine.range(1, 15).slow(8))Spatial Counterpoint with off
off creates delayed copies of a pattern. Combine it with spatial changes to create rich, layered textures:
n("0 3 5 7").scale("C:minor").s("triangle").lpf(2000)
.off(1/8, x => x.pan(0.75).lpf(1200).gain(0.6))
.off(1/4, x => x.pan(0.25).lpf(800).gain(0.4).room(0.4))The original plays center, a copy follows an 1/8th note later panned right and darker, another copy follows a 1/4 note later panned left, even darker, with reverb. This creates a cascading spatial texture.
Experiments
1. The Spatial Remix
Take this flat pattern and apply spatial separation. Give each element its own territory in width, depth, and frequency.
// Flat - everything fighting for the same space
stack(
sound("bd sd bd sd"),
sound("hh*8"),
note("c2 c2 eb2 c2").s("sawtooth"),
note("c4 eb4 g4").s("triangle")
).cpm(30)stack(
sound("bd sd bd sd").pan(0.5).room(0.05),
sound("hh*8").pan(0.65).hpf(6000).gain(0.5),
note("c2 c2 eb2 c2").s("sawtooth").lpf(400).pan(0.5),
note("c4 eb4 g4").s("triangle").pan(0.35)
.hpf(400).room(0.3).juxBy(0.4, rev).gain(0.5)
).cpm(30)2. Genre Transformation
Same notes, different spatial treatment. Start with this pattern and transform it into three different genres by changing only the spatial parameters (pan, room, delay, filters).
// Base pattern
stack(
sound("bd ~ bd ~, ~ sd ~ sd"),
note("c2 ~ eb2 ~").s("sawtooth"),
note("<c3,eb3,g3>").s("triangle").slow(2)
).cpm(28)Try making it sound like:
- Tight techno (dry, punchy)
- Spacious dub (reverb, delay throws)
- Floating ambient (maximum depth, blurred)
3. Width Challenge
Make a single note sound as wide as possible using only built-in Strudel tools. No samples, just one synthesizer note filling the entire stereo field.
// Start here - make it WIDE
note("c3").s("sawtooth").sustain(2)note("c3").s("sawtooth").sustain(2)
.jux(x => x.add(note(0.1)).fast(1.01))
.room(0.3).delay(0.2).delaytime(0.02)
.lpf(2000)Detune and slight speed difference between L/R creates width. Short delay and reverb add dimension.
4. Depth Staging
Create a three-layer arrangement where each layer is at a distinctly different depth: one upfront, one middle distance, one far back. Make it obvious which is which.
// Create near / mid / far layers
stack(
// Near:
sound("bd*4"),
// Mid:
note("c3 eb3").s("sawtooth").slow(2),
// Far:
note("g5").s("triangle").slow(4)
).cpm(28)Quick Reference
| Dimension | Function | Parameters | Range | Purpose |
|---|---|---|---|---|
| Width | pan | position | 0-1 | Left (0) to Right (1) |
jux | function | - | Apply function to right channel | |
juxBy | amount, fn | 0-1, fn | Controlled stereo split | |
| Depth | room | amount | 0-1+ | Reverb send level |
roomsize | size | 0.1-20+ | Reverb decay time | |
roomlp | frequency | Hz | Reverb high-frequency damping | |
roomfade | time | seconds | Reverb fade time | |
delay | amount | 0-1 | Delay send level | |
delaytime | time | 0-2 seconds | Time between echoes | |
delayfeedback | amount | 0-1 | Number of echo repeats | |
| Height | lpf | frequency | Hz | Low-pass filter cutoff |
hpf | frequency | Hz | High-pass filter cutoff | |
bpf | frequency | Hz | Band-pass filter center | |
lpq / hpq | resonance | 0-50+ | Filter resonance (Q) |
Where to Go Next
- Audio Effects - Deep dive into all effects including the signal chain and orbit system
- Signals - Learn more about using
sine,perlin,sawand other signals for modulation - Synths - Explore synthesis techniques to create richer source sounds
- Recipes - Ready-to-use patterns demonstrating spatial techniques