Hydra (Yutong)

Tidalcycles (Elora & Yihan)

We initially approached our composition by coding separate sections of music and trying to piece them together, but found that the results from this were incohesive and clunky. We were heavily inspired by this composition by students from a previous live coding class. Its minimalist style generated high energy while still allowing for the sound to be stripped to its hollow, liquid bones. By keeping a melodic core intact, they achieved evolution by adding and subtracting beats, creating a seamless musical experience. Wanting to emulate this dynamism, we started the final draft by composing its melodic skeleton, and building upon it. Whereas before we had struggled to juggle multiple genres, we decided to establish a single tone and develop it further. Several references helped me decide what emotions we would evoke for this piece. I recently read about the difficult production behind Katy Perry’s “Teenage Dream.” Songwriter Bonnie Mckee said:

I thought about my own adolescent years, my own first love. I thought about watching Baz Luhrmann’s Romeo and Juliet and putting on a little mini discoball light and just dreaming of Leo. I thought about me and my friends sitting around at slumber parties in the ’90s, giddy even just THINKING about boys….. I thought about what Benny said and I listened to the song again, and I was like the Teenagers….. that’s such a great word, Teenager. It is a very descriptive word; it packs a lot of emotion and imagery into three syllables….. I couldn’t believe after all of our agonizing over ‘youth’ themes, that we had overlooked such an obvious one – the teenage condition.

I thought about the song I shared with the class at the beginning of the semester, Teenagers by French 79. How often have I listened to this song and repeated the word, forgetting myself as crests of synth broke over me like waves? This made me think about Kids by MGMT and childhood by daniel.mp3. About Just Kids by Pattie Smith on Robert Mapplethorpe. Like ‘teenagers,’ the word ‘kids’ raises indescribable feelings in all of us. We reminisce on the reckless, blind joys of the past, about what has been lost, and what is impossible to return to. For this composition, we wanted to deliver senses of playfulness and melancholy.

Like the aforementioned student group we were inspired by, we structured our code into do-blocks for legibility and easy execution. Yihan created a series of chords that served as the basis for the melody, which we made by using the ‘supervibe’ sample, a vibraphone sound often associated with childhood. After setting the tone, we gradually progressed the composition by bolstering the high melody with a bassline, and adding various beats. We discovered we could create a song simply by reducing elements and reintroducing them again. It wasn’t necessary to continually introduce new patterns and sounds into the composition––in fact, it became quite congested and messy when we tried that. We added a “supersaw” arpeggiated sequence chock-full of reverb to create a dreamlike atmosphere, and then suddenly dropped the other elements to create a sense of ‘floating’ in space. By layering a low bassline and the original melody on top of the synths, we created a sound that the audience could ‘sit’ in. It is my favorite part of the composition.

We interrupted the bridge by adding beats, and integrated a sample I found on freesound of kids laughing. Both MGMT and daniel.mp3 applied delay and echo effects to their samples of kids’ voices to create a sense of melancholic nostalgia. I did the same. We introduced a second “supersaw” arpeggiated sequence and immediately subtracted it, reducing the composition to the beats to generate tension. During our live performance in class, I let this sequence escalate for longer than I do in the video, and wish I had recorded it. We then added a third “supersaw” sequence, a second sample of kids yelling, and quickened the beat. Making the drop was the most difficult part of this assignment. We felt like we were stuck in a loop of building tension and struggled to think of a way to resolve it. Rather than try to code a dramatic transition, we created a slower, more muted sequence of notes that felt like they could stand on their own, with hints of the original melody to create a feeling of having circled back. We discovered that shifting from the high-tension beats to this block worked well, and achieved the resolution we had been looking for. My second favorite part of the composition is when the flying moon dissolves with the ending laugh sample, but Yutong can tell you about that.

Hydra Code

//visual script

//!!!visual array

visuals = [
//first visual-> purple sphere
()=>{setFunction({
name: 'sphereShaderglow',
type: 'src',
inputs: [
{ type: 'float', name: 'locX', default: 0.5 },
{ type: 'float', name: 'locY', default: 0.5 },
{ type: 'float', name: 'diameter', default: 0.3 },
{ type: 'float', name: 'r', default: 0.5 },
{ type: 'float', name: 'g', default: 0.4 },
{ type: 'float', name: 'b', default: 0.7 },
{ type: 'float', name: 'm1', default: 0.2 },
{ type: 'float', name: 'm2', default: 0.5 },
{ type: 'float', name: 'm3', default: 0.8 },
],
glsl: `
vec2 uv = _st * resolution;
vec2 center = vec2(locX * resolution.x, locY * resolution.y);
float dist = distance(uv, center);
float radius = (diameter * resolution.x) / 2.0;
vec3 moonColor = vec3(r, g, b);
// --- Glow halo (additive, outside AND inside the sphere) ---
float glowRadius = radius * 1.8; // how far the glow reaches
float glowStrength = 0.9; // peak brightness of halo
float glowFalloff = 3.5; // higher = tighter glow
float glowDist = max(dist - radius, 0.0); // distance beyond sphere edge
float glow = glowStrength * exp(-glowFalloff * glowDist / radius);
vec3 glowColor = moonColor * glow; // glow tinted to moon color
// Outside the sphere: just the glow halo
if (dist > radius) {
return vec4(glowColor, 1.0);
}
// --- Sphere surface shading ---
float normX = (uv.x - center.x) / radius;
float normY = (uv.y - center.y) / radius;
float z = sqrt(max(0.0, 1.0 - normX*normX - normY*normY));
vec3 normal = normalize(vec3(normX, normY, z));
vec3 lightDir = normalize(vec3(m1, m2, m3));
float light = max(dot(normal, lightDir), 0.0);
// Additive rim glow on the lit edge of the sphere
float rimGlow = pow(1.0 - z, 3.0) * light * 0.6;
vec3 color = moonColor * light;
color += moonColor * rimGlow; // add rim highlight
color += glowColor * 0.3; // bleed inner glow into surface
return vec4(color, 1.0);
`
})
// Orbiting moon version
let rotSpeed = 0.5
sphereShaderglow(
0.5,
() => (Math.sin(time * rotSpeed) / 10+0.5),
0.3,
0.5, 0.4, 0.9, // r, g, b — cool blue-white moon color
() => Math.sin(time * rotSpeed),
-0.3,
() => Math.cos(time * rotSpeed),
).out(o3)
//visual 1-> one singular ball
osc(24,0.1,0.5).modulateRotate(noise(2),()=>cc[0]).mask(o3).color(5,4,1).hue(0.5).blend(src(o0),0.9).out(o0)},
//------------------------------------
//visual 2-> spheres with bigger ossilation
()=> {osc(24,0.1,0.5).modulateRotate(noise(2),()=>(cc[0]*5)).mask(o3).color(5,4,1).hue(0.5).blend(src(o0),0.9).out(o0)},
//-----------------------------------------
//visials 3 bigger ossilation sphere with color change
()=> {osc(24,0.1,0.5).modulateRotate(noise(2),()=>(cc[0]*5)).mask(o3).color(2,4,1).hue(()=>cc[1]*2).blend(src(o0),0.9).out(o0)},
//-------------------------------------------
//visuals 4 change ball size
()=>{let rotSpeed = 0.5
sphereShaderglow(
0.5,
() => (Math.sin(time * rotSpeed) / 10+0.5),
()=> cc[3],
0.5, 0.4, 0.9, // r, g, b — cool blue-white moon color
() => Math.sin(time * rotSpeed),
-0.3,
() => Math.cos(time * rotSpeed),
).out(o3)
osc(24,0.1,0.5).modulateRotate(noise(2),()=>(cc[0])).mask(o3).color(2,4,1).hue(()=>cc[1]*2).blend(src(o0),0.9).out(o0)},
//--------------------------------------------------
//visuals 5 add another layer of effects scrollX
()=>{osc(24,0.1,0.5).modulateRotate(noise(2),()=>(cc[0])).mask(o3).color(2,4,1).hue(0.35).blend(src(o0).modulateScrollX(o0),0.9).out(o0)},
//-----------------------------------------------------
//visuals6-> multiple spheres in blender
()=> {osc(24,0.1,0.5).modulateRotate(noise(3),()=>(cc[0])).mask(o3).color(4,2.5,1.5).hue(()=>cc[2]).blend(src(o0),0.5).repeat(2,2).layer(src(o1)).out(o0)},
//------------------------------------------------
//visuals7->falling Stars wihtout planets
()=> { osc(24, 5, .7)
.mask(shape(100, 0.02, 0.01).scale(1, () => window.innerHeight / window.innerWidth))
.repeat(100, 100)
.modulate(noise(1, 0.5), 0.5).colorama(0.25)
.rotate(() => cc[0] * Math.PI, 0.03)
.out(o1)
// osc(24,0.1,.7).mask(shape(10,0.01,0.02).scale(1,()=>window.innerHeight/window.innerWidth)).
// repeat(100,100).modulate(noise(1,0.5,3),0.5).out(o1)
src(o0)
.modulate(voronoi(100,0.1,1.5).modulate(noise(5),1).brightness(0.03)
,0.003).layer(src(o1)).luma(0.2).colorama(0.5).out(o0)},
//---------------------------------------------------
//visuals 8->falling stars with a spheres
()=> {
setFunction({
name: 'sphereShader',
type: 'src',
inputs: [
{
type: 'float',
name: 'locX',
default: 0.5,
},
{
type: 'float',
name: 'locY',
default: 0.5,
},
{
type: 'float',
name: 'diameter',
default: 0.3, // in normalized space, 0.3 = 30% of screen
},
{
type: 'float',
name: 'r',
default: 0.5,
},
{
type: 'float',
name: 'g',
default: 0.4,
},
{
type: 'float',
name: 'b',
default: 0.7,
},
{
type: 'float',
name: 'm1',
default: 0.2, //1st parameter of the 3D vector the direction that the sphere faces
},
{
type: 'float',
name: 'm2',
default: 0.5, //2nd parameter of the 3D vector the direction that the sphere faces
},
{
type: 'float',
name: 'm3',
default: 0.8, //3rd parameter of the 3D vector the direction that the sphere faces
}
],
glsl: `
// current pixel in screen space
vec2 uv = _st * resolution;
// mouse in screen space
vec2 center = vec2(locX * resolution.x, locY * resolution.y);
// distance from center
float dist = distance(uv, center);
// convert diameter to screen space radius
float radius = (diameter * resolution.x) / 2.0;
// outside the circle = black
if (dist > radius) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
// sphere surface math
float normX = (uv.x - center.x) / radius; // -1 to 1
float normY = (uv.y - center.y) / radius; // -1 to 1
float z = sqrt(1.0 - normX*normX - normY*normY); // depth
// surface normal
vec3 normal = normalize(vec3(normX, normY, z));
// light direction
vec3 lightDir = normalize(vec3(m1, m2, m3));
// how much does surface face the light
float light = max(dot(normal, lightDir), 0.0);
// color
vec3 color = vec3(r, g, b);
return vec4(color * light, 1.0);
`
})
let rotSpeed = 0.5 // how fast it rotates
// m1 and m3 trace a circle over time = light orbits the sphere!
sphereShader(
0.5,
//() => (Math.sin(time * rotSpeed)/15+0.5),
0.5,
0.4,
0.5,
0.4,
0.9,
//0.2,
() => Math.sin(time * rotSpeed)*2, // m1 — light X orbits
//() => Math.sin(time * rotSpeed)*0.5,// m2 — light Y stays fixed
0.8,
() => Math.cos(time * rotSpeed)*2, // m3 — light Z orbits
).out(o3)
osc(24, 5, .7)
.mask(shape(100, 0.02, 0.01).scale(1, () => window.innerHeight / window.innerWidth))
.repeat(100, 100)
.modulate(noise(1, 0.5), 0.5).colorama(0.25)
.rotate(() => cc[0] * Math.PI, 0.03)
.out(o1)
// osc(24,0.1,.7).mask(shape(10,0.01,0.02).scale(1,()=>window.innerHeight/window.innerWidth)).
// repeat(100,100).modulate(noise(1,0.5,3),0.5).out(o0)
src(o0)
.modulate(voronoi(100,0.1,1.5).modulate(noise(5),1).brightness(0.03)
,0.003).layer(src(o1)).luma(0.2).colorama(0.5).out(o2)
src(o3).layer(o2).luma(0.02).brightness(0.02).hue(0.8).out(o0)},
//-----------------------------------------------
//visual 9 falling start in moon
()=> {
let rotSpeed = 0.5 // how fast it rotates
// m1 and m3 trace a circle over time = light orbits the sphere!
sphereShader(
() => (Math.sin(time * rotSpeed)/15+0.5),
() => (Math.sin(time * rotSpeed)/15+0.5),
0.35, //diameter
0.4, //r
0.5, //g
0.4,//b
0.9,
//0.2,
() => Math.sin(time * rotSpeed)*2, // m1 — light X orbits
() => Math.sin(time * rotSpeed)*0.5,// m2 — light Y stays fixed
//0.8,
() => Math.cos(time * rotSpeed)*2, // m3 — light Z orbits
).out(o3)
osc(24, 5, .7)
.mask(shape(100, 0.02, 0.01).scale(1, () => window.innerHeight / window.innerWidth))
.repeat(100, 100)
.modulate(noise(1, 0.5), 0.5).colorama(0.25)
.rotate(() => cc[0] * Math.PI, 0.03)
.out(o1)
// osc(24,0.1,.7).mask(shape(10,0.01,0.02).scale(1,()=>window.innerHeight/window.innerWidth)).
// repeat(100,100).modulate(noise(1,0.5,3),0.5).out(o0)
src(o0)
.modulate(voronoi(100,0.1,1.5).modulate(noise(5),1).brightness(0.03)
,0.003).layer(src(o1)).luma(0.2).colorama(0.5).out(o2)
src(o3).layer(o2).luma(0.02).brightness(0.02).hue(0.8).out(o0)},
//-------------------------------------
//visual 10 pulsing purple sphere with fixed color
()=>{
// Orbiting moon version
let rotSpeed = 0.5
sphereShaderglow(
0.5,
() => (Math.sin(time * rotSpeed) / 10+0.5),
0.5,
0.5, 0.4, 0.9, // r, g, b — cool blue-white moon color
() => Math.sin(time * rotSpeed),
-0.3,
() => Math.cos(time * rotSpeed),
).out(o3)
// //1 one singular ball
osc(24,0.1,0.5).modulateRotate(noise(2),()=>cc[0]).mask(o3).color(5,4,1).hue(0.5).blend(src(o0),0.9).out(o0)},
//-----------------------------------------------------
//visual 11 multiple sphers in blender with a filter
()=> {osc(24,0.1,0.5).modulateRotate(noise(3),()=>(cc[0])).mask(o3).color(4,2.5,1.5).hue(()=>cc[2]).blend(src(o0),0.9).repeat(6,6).layer(src(o1)).out(o0)},
//visua//visuals6-> multi
]


whichVisual = 0
visuals[8]()

visuals[whichVisual]()

// can use update and switch case with midi:
update = () =>{
if (ccActual[5]==24){
visuals[8]()
}
// very important! only change source once, when necessary
if (whichVisual != ccActual[1]){
whichVisual = ccActual[1];
visuals[whichVisual]()
},
}

hush()

Tidalcycles Code

-  -- Final -- 


--melody1--floating ball--
do
d1 $ qtrigger $ slow 4
$ note "[e5 ~ g5 b4] [c5 ~ e5 g4] [a4 c5 ~ e5] [b4 ~ g4 e4]"
# s "supervibe"
# lpf (range 160 480 (slow 4 sine))
# detune 0.16
# room 0.6 --small oscillations--
# sz 0.95
# gain 1.1
# sustain 0.32
d12 $ qtrigger $ slow 4 $ struct "[t ~ t t] [t ~ t t] [t t ~ t] [t ~ t t]" $ ccv ((segment 128 (range 127 0 saw))) # ccn "0" # s "midi"
d13 $ ccv "0" # ccn 1 # s "midi"


-- add bass-- add bigger oscillations here--
do
d2 $ qtrigger $ slow 4
$ note "[c2 ~ c2 g1] [a1 ~ a1 e1] [f1 ~ g1 a1] [e1 ~ g1 b1]"
# s "supervibe"
# lpf 180
# detune 0.08
# room 0.25
# sz 0.7
# gain 1.2
# sustain 0.85
d12 $ qtrigger $ slow 4 $ struct "[t ~ t t] [t ~ t t] [t t ~ t] [t ~ t t]" $ ccv ((segment 128 (range 127 0 saw))) # ccn "0" # s "midi"
d13 $ ccv "1" # ccn 1 # s "midi"


--add percussion--change color--
do
d3 $ slow 2 $ stack [
s "808:1 ~ 808:1 ~" # gain 0.9 # speed 0.65,
s "808:1(3,8)" # gain 0.7 # speed 0.9 # nudge 0.02,
s "808:1(5,16)" # gain 0.7 # speed 0.8 # pan (slow 4 sine),
s "~ 808:1 ~ 808:1" # gain 1.1 # speed 0.45 # room 0.3 ]
d14 $ qtrigger $ slow 4 $ struct "t(3,8)" $ ccv ((segment 128 (range 127 0 saw))) # ccn "1" # s "midi" --for color ccn 1
d13 $ ccv "2" # ccn 1 # s "midi" --for # of visuals



--add beat 1--change ball size-- tone down oscillator--
do
d4 $ s "909 909 909 <909, 808:1>" # gain 1 # size 0.4
d13 $ ccv "3" # ccn 1 # s "midi" --for # of visuals
d15 $ struct "t t t <t, t>" $ ccv ((segment 128 (range 30 20 rand))) # ccn "3" # s "midi" --pulsing


--only beat 2--- combine with another texture, remove color -- let's stay with this color thenn
do
d3 silence
d2 silence
d5 $ s "808:3*4" # gain 0.7 # krush 2
d13 $ ccv "4" # ccn 1 # s "midi" --for # of visuals


--add the percussion back in--
d3 $ stack [
s "808:1 ~ 808:1 ~" # gain 1.8 # speed 0.65,
s "808:1(3,8)" # gain 1 # speed 0.9 # nudge 0.02,
s "808:1(5,16)" # gain 1.6 # speed 1.3
# pan (slow 4 sine),
s "~ 808:1 ~ 808:1" # gain 0.8 # speed 0.45 # room 0.3 ]


--add bass back --
do
d2 $ qtrigger $ slow 4
$ note "[c2 ~ c2 g1] [a1 ~ a1 e1] [f1 ~ g1 a1] [e1 ~ g1 b1]"
# s "supervibe"
# lpf 180
# detune 0.08
# room 0.25
# sz 0.7
# gain 1.3
# sustain 0.85


--add stars-- pixelated moon--

do
d5 $ qtrigger $ slow 2
$ note "[~ g6 ~ b6] [c7 ~ b6 g6] [~ a6 c7 ~] [c6 ~ e7 ~]"
# s "supersaw"
# lpf (range 900 2000 (slow 8 sine))
# hpf 900
# detune 0.32
# room 0.75
# sz 0.98
# gain 0.6
# sustain 0.25
--d14 $ ccv "24" # ccn 5 # s "midi" --the if value to trigger one time effect
d13 $ ccv "7" # ccn 1 # s "midi" --star rotationnn


-- everything drops except for stars-- watch pixelated moon-- heree?
do
d1 silence
d2 silence
d3 silence
d4 silence


-- bass2 comes in--keep rotating planet--
d6 $ qtrigger $ slow 4
$ note "c3 ~ ~ ~ a2 ~ ~ ~ f2 ~ ~ ~ g2 ~ ~ ~"
# s "supersaw"
# lpf (range 90 260 (slow 8 sine))
# detune 0.06
# room 0.4
# sz 0.8
# gain (range 1 1.6 saw )
# sustain 2.1


--melody comes back in--keep rotating planet--

d1 $ qtrigger $ slow 4
$ note "[e5 ~ g5 b4] [c5 ~ e5 g4] [a4 c5 ~ e5] [b4 ~ g4 e4]"
# s "supervibe"
# lpf (range 160 480 (slow 4 sine))
# detune 0.16
# room 0.6
# sz 0.95
# gain 1.4
# sustain 0.32


--beat drops in -- return to normal pulsing ball--
do
d4 $ s "909 909 909 909" # gain 1.1 # size 0.4
d13 $ ccv "3" # ccn 1 # s "midi" --for # of visuals
d15 $ struct "t t t t" $ ccv ((segment 128 (range 30 20 rand))) # ccn "3" # s "midi"


--highhats-- normal pulsing ball
do
d7 $ s "hh*8" # gain 1.4
d13 $ ccv "5" # ccn 1 # s "midi" --for # of visuals


--add kids sample--keep same--
do
d8 $ jux rev $ slow 16
$ striateBy 128 (1/6)
$ s "kids"
# room 0.95
# size 0.98
# lpf 1800
# hpf 500
# gain 0.8


--stars2--shudder ball! --
do
d9 $ qtrigger $ slow 2
$ note "[e6 ~ g6 ~] [~ b6 d7 ~] [c7 ~ a6 e6] [~ g6 b6 ~]"
# s "supersaw"
# lpf (range 2000 5200 (slow 8 sine))
# hpf 1200
# detune 0.42
# room 0.9
# sz 0.98
# gain (range 0.4 1 (slow 16 sine))
# sustain 0.22
d13 $ ccv "4" # ccn 1 # s "midi"


--drop away to create tension-- pulsing purple spheres!!!
do
d9 silence
d8 silence
d6 silence
d1 silence
d13 $ ccv "9" # ccn 1 # s "midi"
d15 $ struct "t*8" $ ccv ((segment 128 (range 45 20 rand))) # ccn "3" # s "midi" --pulsing
--for # of visuals


-- buildup2-- pulsing purple spheres--
do
d7 $ slow 2
$ note "[~ e6 g6 b6] [c7 e7 d7 b6] [a6 c7 e7 g7] [e7 d7 c7 b6]"
# s "supersaw"
# lpf (range 1400 6200 (slow 8 sine))
# hpf 700
# detune 0.34
# room 0.78
# sz 0.95
# gain 0.8
# sustain 0.28
d8 $ slow 2
$ note "[c5 e5 g5 c6] [e5 g5 b5 e6] [a5 c6 e6 a6] [g5 b5 d6 g6]"
# s "supersaw"
# lpf (range 900 4800 (slow 8 sine))
# hpf 300
# detune 0.22
# room 0.7
# sz 0.9
# gain 0.65
# sustain 0.55
d9 $ slow 4
$ note "[c6 ~ e6 g6] [b6 c7 e7 ~] [a6 c7 e7 g7] [~ e7 d7 c7]"
# s "supervibe"
# lpf (range 1800 7600 (slow 6 sine))
# hpf 1200
# detune 0.18
# room 0.9
# sz 0.98
# pan (slow 4 sine)
# gain (range 0.35 0.85 (slow 8 sine))
# sustain 0.22
d13 $ ccv "5" # ccn 1 # s "midi" --for # of visuals


-- add kid sample2--
d10 $ slow 4 $ s "kids:1 ~ ~ ~ ~" # gain 1.4
# room 1 # size 0.98 # lpf 1800 # sustain 0.5
# legato 2

--add drum beat--faster pulsing purple spheres--
do
d4 $ s "909*8" # gain 1.1 # size 0.4 # krush 2 # room 0.2
d13 $ ccv "10" # ccn 1 # s "midi" --for # of visuals


--resolution--stars falling like snow
do
d10 silence
d4 silence
d7 $ slow 4
$ note "[c6 ~ e6 ~] [g5 ~ e6 c6] [a5 ~ c6 ~] [g5 ~ e5 c5]"
# s "supervibe"
# lpf (range 260 900 (slow 12 sine))
# hpf 120
# detune 0.12
# room 0.9
# sz 0.98
# gain (range 0.95 0.18 (slow 16 sine))
# sustain 0.9
d8 $ slow 4
$ note "[c4 ~ g4 ~] [e4 ~ c4 ~] [a3 ~ e4 ~] [f3 ~ c4 ~]"
# s "supervibe"
# lpf (range 180 620 (slow 16 sine))
# detune 0.08
# room 0.85
# sz 0.96
# gain (range 0.8 0.12 (slow 16 sine))
# sustain 1.6
d9 $ slow 8
$ note "[~ c6 ~ e6] [g5 ~ c6 ~] [~ a5 c6 ~] [g5 ~ e5 ~]"
# s "supervibe"
# lpf (range 320 1200 (slow 12 sine))
# hpf 400
# detune 0.18
# room 0.95
# sz 0.98
# pan (slow 6 sine)
# gain (range 0.55 0.05 (slow 16 sine))
# sustain 1.1
d13 $ ccv "8" # ccn 1 # s "midi"


--end on laugh--
do
d11 $ jux rev $ slow 16
$ striateBy 128 (1/6)
$ s "kids"
# room 0.95
# size 0.98
# lpf 1800
# hpf 500
# gain 0.8
d13 $ ccv "6" # ccn 1 # s "midi"

hush

Tidal Side

-- -- house intro

setcps(135/60/4)

-- percussion and bass

d1 $ s "808bd:5" * slow "<0.03 0.0625 0.125 0.25>" 1
  # note ("<fs d a e>" - 1)

xfadeIn 1 2 $ slow 2 $ s "[808bd:5]*8" # note ("<fs d a e>" - 1)  
   
d1 silence



xfadeIn 2  8 $ stack [
  s "bd:6(4,4)" # shape 0.4,
  s "~ db:13 ~ jazz:4",
  s "[~ db]*4" # gain 0.8 # pan 0.6
]
  # gain 0.8 # gain 0.8 # pan 0.6

hush

p "housemidi" $ stack [
  ccv "127 90 110 90" # ccn 0 # s "midi",
  ccv "0 100 0 120" # ccn 1 # s "midi",
  ccv "[0 80 0 100]*4" # ccn 2 # s "midi"
]

p "housemidi" $ stack [
  ccv "80 30 50 30" # ccn 0 # s "midi"
]

-- tempo change to 145

hush

d6 silence

xfadeIn 6 8 $ note "<fs fs d d a a e e>"
  # s "supersaw*4"
  # legato 0.5
  # lpf 3000
  # resonance 0.2
  # gain 0.8
  # octave 2

d6 silence

do
  p "drop" $ qtrigger $ seqP [
      (0, 8, s (cat [
          "808bd:12(4,4) ~ ~ ~",
          "808bd:12(4,4) ~ ~ ~",
          "808bd:12(4,4) ~ [~ jazz:6] ~",
          "808bd:12(4,4) ~ [~ jazz:6] ~",
          "808bd:12(4,4) ~ [~ jazz:6] ~",
          "808bd:12*4", 
          "808bd:12*8",
          "808bd:12*16"
        ]) # gain (range 0.9 1.2 $ slow 8 saw)
      )
    ]
  ct_ (145/60/4) 8
  


p "drop" silence

d7 silence

--melody and chords
-- keep throughout
xfadeIn 7 8 $ jux rev $ slow 2
  $ struct " t ~ t ~ ~ t ~ t"
  $ n "<fs'min7 d'maj7 a'maj7 e'maj7>"
  # s "superpiano"
  # sustain 4
  # velocity (range 0.4 0.75 $ slow 8 sine)
  # lpf (range 1500 8000 $ slow 4 saw) 
  # lpq 0.1
  # delay 0.7 # delayt (3/10) # delayfeedback 0.6
  # room 0.9 # size 0.95
  # gain 0.7
  # legato 2
  # orbit 6

xfadeIn 8 2 $ jux rev $ n "[~ fs'min7] [~ d'dom7] [a'maj7 ~] [~ e'maj7]"
    # s "superfork"
    # shape 0.2
    # room 0.5
    # lpf 2000
    # gain 0.7

d8 silence

d10 silence

hush

xfade 1    $ s "808bd:12*4 "
    # gain 1


xfadeIn 10 2 $ n (cat [
    "[~ fs'min9] [~ d'maj9] [a'maj9 ~] [~ e'dom9]",
    "[~ fs'min9] [~ d'maj9] [a'maj9 ~] [d'maj9 e'dom9]",
    "[~ fs'min9] d'maj9 [~ a'maj9] [~ e'dom9]",
    "[~ fs'min9] [d'maj9 d'maj9] [~ a'maj9] ~",
    "[~ fs'min9] [~ d'maj9] [a'maj9 ~] [~ e'dom9]",
    "[~ fs'min9] [~ d'maj9] [a'maj9 ~] [fs'min9 e'dom9]",
    "[~ fs'min9] [~ d'maj9] [~ a'maj9] [~ e'dom9]",
    "[fs'min9*2] [d'maj9 ~] [~ a'maj9] ~"
  ])
  # s "supervibe"
  # octave 4
  # sustain 0.25
  # amp (range 0.1 1.2 $ fast 4 saw)
  # djf 0.65
  # room 0.5 # sz 0.4
  # delay 0.5 # delayt 0.25 # delayfeedback 0.4
  # gain 0.5

hush

-- change tempo 

ct_ (175/60/4) 8

-- break beats -- 

d2 $ every 4 (slice 8 "0 1 [2 3] 4 5 [6 7 6 7] 3 1")
   $ sometimesBy 0.3 (# speed 2)
   $ slice 8 "0 3 1 [6 7] 4 2 5 3"
   $ s "breaks125:1 808bd"
   # cut 1 # krush 4 # lpf 6000 # speed " 1.36 1.07" # gain 0.9


xfade 2 $ every 4 (slice 8 "0 1 [2 3] 4 5 [6 7 6 7] 3 1")
   $ sometimesBy 0.3 (# speed 2)
   $ slice 8 "0 3 1 [6 7] 4 2 5 3"
   $ s "<[breaks165 breaks125:1] [breaks125:1] [breaks125:1 breaks165] [breaks165]>"
   # cut 1 # krush 4 # speed "<[1.07 1.36] [1.36] [1.36 1.07] [1.07]>" # gain 1
    #djf 0.5 # orbit 1 # lpf (range 1000 3000 $ slow 8 rand)

p "breakmidi" $ stack [
  ccv (segment 16 $ "127 80 100 [90 110] 127 80 100 90") # ccn 1 # s "midi",
  ccv (segment 16 $ sometimesBy 0.3 (const 127) $ "60 60 60 60 60 60 60 60") # ccn 2 # s "midi",  
  ccv (segment 16 $ range 30 127 $ slow 8 rand) # ccn 3 # s "midi",
  ccv (every 4 (const "127 127 [127 127] 127 127 [127 127 127 127] 127 127") $ "40 40 40 40 40 40 40 40") # ccn 6 # s "midi"
]



--breakbeats melody
xfadeIn 10 8 $ n ( cat ["[~ fs'min9] [~ d'maj9] [a'maj9 ~] [~ e'dom9]",
    "[~ fs'min9] [~ d'maj9] [a'maj9 ~] [d'maj9 e'dom9]",
    "[~ fs'min9] d'maj9 [~ a'maj9] [~ e'dom9]",
    "[~ fs'min9] [d'maj9 d'maj9] [~ a'maj9] ~",
    "[~ fs'min9] [~ d'maj9] [a'maj9 ~] [~ e'dom9]",
    "[~ fs'min9] [~ d'maj9] [a'maj9 ~] [fs'min9 e'dom9]",
    "[~ fs'min9] [~ d'maj9] [~ a'maj9] [~ e'dom9]",
    "[fs'min9*2] [d'maj9 ~] [~ a'maj9] ~"])
    # s "superfm"
    # octave 4
    # sustain 0.25
    # crush 3
    # shape "0 0.2 0.4 0.6"
    # amp (range 0.1 1.2 $ fast 4 saw)
    # djf 0.65
    # room 0.9 # sz 0.6
    # cut 1
    # gain 0.5

p "birds" $ jux (rev . (# crush 3)) $ every 4 (fast 2) $ striate 16 $ s "birds"
    # n (irand 10)
    # speed (range 0.5 4 $ fast 4 sine)
    # gain 0.6
    -- # squiz "2 4 1 5"
    # cut 2
    # legato 0.3
    # pan rand
    # room 0.2 # size 0.85
    

do 
  xfadeIn 10 12 silence
  xfadeIn 2 12 silence 
  


hush

-- you wanna try a quick run through with what we have now and we can note down what we shoul dfix


do 
  xfadeIn 1 16 silence
  xfadeIn 6 16 silence
  xfadeIn 8 16 silence
  xfadeIn 10 16 silence
  xfadeIn 2 16 silence 
-- for the end part DONT FORGET
  xfadeIn 7 16 $ jux rev $ slow 2
    $ struct " t ~ t ~ ~ t ~ t"
    $ n "<fs'min7 d'maj7 a'maj7 e'maj7>"
    # s "superfm"
    # crush 3
    # sustain 8
    # lpf (range 1000 8000 $ slow 4 saw) 
    # lpq 0.1
    # delay 0.7 # delayt (3/10) # delayfeedback 0.6
    # room 0.9 # size 0.95
    # gain (range 0.5 0.7 $ slow 16 sine)
    # legato 2
    # cut 1

p "root" $ slow 2 $ n "<fs'min d'maj a'maj e'maj>"
    # s "superfm"
    # octave 4
    # sustain 4
    # gain 0.6
    # room 0.5 # sz 0.9
    # lpf 300
    # legato 2

do
  d7 silence
  p "root" silence


hush


ct_ finishTempo numCycles = do
      start <- getcps
      p "change_tempo" $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0, numCycles,
            slow (pure numCycles) $
              cps $
                segment 128 $
                  range (pure $ realToFrac start) finishTempo saw
          )
        ]
-- i like this as our "transition" thing and i can just keep slowly increasing bpm here
Hydra Side

//  trigger next() to advance scenes


s0.initCam()


window.scenes = [

  //[0]ENTRY
  () => {
    osc(8, 0.5, 0.3)
      .color(1.5, 0.5, 0.15)
      .scale(0.35, 1.6)
      .scrollX(0.3)
      .modulate(noise(3, 0.4), 0.2)
      .thresh(() => 0.4 + Math.sin(time * 2.08) * 0.25, 0.05)
      .out(o3)

    noise(3, 0.1)
      .modulate(osc(2, 0.3), () => 0.3 + Math.sin(time * 1.04) * 0.2)
      .colorama(0.06)
      .luma(0.4, 0.4)
      .color(0.08, 0.1, 0.18)
      .hue(() => time * 0.05)
      .out(o2)

    src(s0)
      .scale(1.2)
      .saturate(0.3)
      .thresh(() => 0.52 + Math.sin(time * 2.5) * 0.12, 0.03)
      .invert()
      .color(0.08, 0.1, 0.2)
      .add(src(s0)
        .scale(1.22)
        .thresh(0.5, 0.04)
        .invert()
        .color(0.3, 0.15, 0.25)
        .scrollX(() => Math.sin(time * 0.7) * 0.01), 0.3)
      .out(o1)

    src(o2)
      .add(src(o3), 0.9)
      .layer(src(o1).luma(0.18, 0.3))
      .modulate(noise(1.5, 0.2), 0.04)
      .out(o0)

    render(o0)
  },

//[1]THRESHOLD
() => {
  osc(6, 0.3, 0.8)
    .diff(osc(6.4, 0.3, 0.8))
    .color(0.6, 0.3, 0.9)
    .scrollX(() => Math.sin(time * 0.5) * 0.08 + ccActual[0] * 0.15)
    .out(o3)
  noise(2, 0.15)
    .mult(osc(4, 0.2))
    .colorama(() => 0.05 + Math.sin(time * 0.6) * 0.04 + cc[0] * 0.08)
    .color(0.05, 0.08, 0.15)
    .out(o2)
  src(s0)
    .scale(() => 1.1 + cc[0] * 0.3)
    .saturate(0.5)
    .thresh(() => 0.5 + Math.sin(time * 1.5) * 0.1 - cc[0] * 0.2, 0.04)
    .color(0.2, 0.25, 0.4)
    .diff(src(o3).scale(0.98))
    .out(o1)
  src(o2)
    .add(src(o3), 0.4)
    .layer(src(o1).luma(0.2, 0.3))
    .blend(o0, () => 0.07 + cc[0] * 0.1)
    .modulate(noise(1, 0.1), () => 0.02 + cc[0] * 0.05)
    .out(o0)
  render(o0)
}

  //[2]BUILD
  () => {
    osc(15, 0.4, 1.2)
      .colorama(() => 0.4 + Math.sin(time * 0.5) * 0.3)
      .colorama(0.3)
      .scrollX(() => time * 0.04)
      .scrollY(() => Math.sin(time * 0.3) * 0.05)
      .rotate(() => time * 0.2)
      .modulate(noise(2, 0.4), 0.3)
      .out(o2)

    osc(50, 0.5, 1.5)
      .color(0.4, 1.2, 1.6)
      .thresh(() => 0.7 - Math.abs(Math.sin(time * 4.16)) * 0.3, 0.04)
      .rotate(() => time * 0.4)
      .out(o3)

    src(s0)
      .scale(() => 1.15 + Math.sin(time * 2.08) * 0.1)
      .colorama(() => 0.3 + Math.sin(time * 0.6) * 0.2)
      .colorama(0.2)
      .kaleid(() => 2 + Math.floor(Math.abs(Math.sin(time * 0.25)) * 3))
      .modulate(osc(3, 0.6), 0.06)
      .out(o1)

    src(o2)
      .add(src(o3), 0.5)
      .modulate(noise(1.5, 0.3), 0.15)
      .layer(src(o1).luma(0.3, 0.35))
      .blend(o0, 0.05)
      .out(o0)

    render(o0)
  },

  //[3]PEAK
  () => {
    osc(30, 0.5, 1.4)
      .colorama(0.5)
      .colorama(0.3)
      .rotate(() => time * 0.4)
      .modulate(noise(4, 0.5), 0.15)
      .out(o3)

    solid(1.8, 0.15, 0.2)
      .mult(osc(50, 0, 0)
        .thresh(() => {
          const burst = Math.floor(time * 4.66) % 7 === 0 ? 0.1 : 0.95
          return burst - Math.abs(Math.sin(time * 4.66)) * 0.85
        }, 0.02))
      .out(o2)

    src(s0)
      .scale(() => 1.2 + Math.sin(time * 2.33) * 0.15)
      .kaleid(() => 4 + Math.floor(Math.abs(Math.sin(time * 0.6)) * 4))
      .modulate(noise(3, 0.4), 0.08)
      .luma(0.3, 0.3)
      .mult(src(o3))
      .out(o1)

    src(o0)
      .scale(() => 0.988 + Math.sin(time * 0.8) * 0.006)
      .rotate(() => Math.sin(time * 0.6) * 0.008)
      .modulate(noise(4, 0.5), 0.05)
      .layer(src(o1))
      .add(src(o2), () => 0.6 + Math.abs(Math.sin(time * 4.66)) * 0.3)
      .modulatePixelate(noise(5, 0.1).pixelate(20, 20), 240)
      .out(o0)

    render(o0)
  },

  //[4]PLATEAU
  () => {
    voronoi(5, 0.4, 0.95)
      .modulate(osc(2, 0.2), () => 0.3 + Math.sin(time * 0.4) * 0.2)
      .kaleid(() => 8 + Math.floor(Math.abs(Math.sin(time * 0.2)) * 4))
      .rotate(() => time * 0.12)
      .colorama(0.3)
      .colorama(0.15)
      .hue(() => time * 0.1)
      .color(0.8, 0.4, 1.2)
      .out(o3)

    shape(6, 0.5, 0.6)
      .scale(() => 1 + Math.sin(time * 0.7) * 0.4)
      .rotate(() => time * 0.1)
      .out(o2)

    src(s0)
      .scale(() => 1.2 + Math.sin(time * 0.9) * 0.08)
      .kaleid(() => 5 + Math.floor(Math.sin(time * 0.3) * 2))
      .rotate(() => time * 0.1)
      .hue(() => time * 0.15)
      .colorama(0.15)
      .diff(src(o0).scale(0.98))
      .out(o1)

    src(o0)
      .modulateRotate(src(o2), 0.4)
      .modulateScale(src(o2), -0.02, -0.02)
      .scale(0.994)
      .blend(src(o3), 0.1)
      .layer(src(o1).luma(0.25, 0.35))
      .modulate(noise(2, 0.1), 0.02)
      .out(o0)

    render(o0)
  },

  //[5]SECOND SURGE tried it againn
  () => {
    osc(80, 0.6, 2.0)
      .colorama(() => 0.3 + Math.sin(time * 2) * 0.2)
      .thresh(() => 0.5 + Math.sin(time * 8) * 0.4, 0.01)
      .pixelate(
        () => 3 + Math.floor(Math.abs(Math.sin(time * 3)) * 12),
        () => 3 + Math.floor(Math.abs(Math.sin(time * 3)) * 12)
      )
      .color(0.6, 0.3, 1.0)
      .out(o3)

    src(s0)
      .scale(() => 1.3 + Math.sin(time * 4) * 0.15)
      .kaleid(() => 6 + Math.floor(Math.abs(Math.sin(time * 1.5)) * 6))
      .modulate(noise(6, 0.8), 0.12)
      .color(0.9, 0.5, 1.2)
      .out(o1)

    src(o0)
      .scale(0.985)
      .modulate(noise(5, 0.6), 0.06)
      .add(src(o3), () => 0.4 + Math.abs(Math.sin(time * 3)) * 0.5)
      .layer(src(o1).luma(0.2, 0.3))
      .out(o0)

    render(o0)
  },
  
  //[6] COMEDOWN — you at the bar. your face in the dark. alone but electric.
  () => {
    // you, thresholded into a ghost — features emerge and dissolve
    src(s0)
      .scale(1.08)
      .thresh(() => 0.45 + Math.sin(time * 0.3) * 0.12, 0.04)
      .color(0.15, 0.1, 0.28)
      .diff(src(s0)
        .scale(1.1)
        .thresh(() => 0.52 + Math.sin(time * 0.45) * 0.08, 0.03)
        .color(0.4, 0.22, 0.5))
      .out(o1)
  
    // slow interference — the haunting tune made visible
    osc(4, 0.08, 1.2)
      .diff(osc(4.3, 0.08, 1.2))
      .rotate(() => time * 0.02)
      .color(0.3, 0.18, 0.5)
      .modulate(noise(1, 0.06), 0.08)
      .out(o2)
  
    // feedback that breathes — the room holding its breath
    src(o0)
      .scale(0.994)
      .modulate(noise(1.2, 0.08), 0.018)
      .mult(src(o2), 0.85)
      .layer(src(o1).luma(0.12, 0.42))
      .out(o0)
  
    render(o0)
  },



  //[7] RESTING
  () => {

src(s0)
  .hue(0.05)
  .saturate(0.6)
  .out(o1)

gradient(0.3)
  .color(1.2, 0.4, 0.6)
  .hue(() => time * 0.02)
  .out(o2)

shape(200, () => 0.2 + Math.sin(time * 0.6) * 0.04, 0.9)
  .color(1.8, 1.4, 0.2)
  .brightness(0.5)
  .out(o3)

src(o2)
  .add(src(o3), 0.8)
  .add(src(o1), 0.6)
  .out(o0)

render(o0)

    
  },

  


  
]

window.scene = 0
window.next = () => { scenes[scene](); scene = (scene + 1) % scenes.length }

window.transition = (toScene, frames = 60) => {
  let f = 0
  const tick = setInterval(() => {     
    if (f++ >= frames) { clearInterval(tick); return }
    scenes[toScene]()
  }, 16)
}


//tried to make it look like birds
scenes[7]()


next()




hush()

Last Call A live audiovisual performance — TidalCycles + Hydra

Concept

The piece is built around a single, mundane Friday night, the kind that becomes something else entirely once you’re inside it. You’re outside a club at 11 pm. The line moves. You get in. What follows is less a narrative than a physiological arc: the disorientation of the crowd, the moment the music takes over your body before your brain consents, the peak where individual people stop being people and become just movement and light, and then the long slow return to yourself at the bar.

The theme is about losing and finding your own interiority in a public space. Clubs are interesting because they’re designed to dissolve the self and most people go willingly. The piece tries to make that process felt rather than described. The visuals fragment the webcam feed in parallel with that arc: the face starts legible and gradually becomes unrecognizable, kaleidoscoped and consumed by feedback, before reassembling into something quieter at the end. The music does the same thing rhythmically by stacking complexity until the breakbeats hit and the tempo feels almost hostile, then unwinding back to the same four chords it started on.

The ending is deliberately small. After everything, someone just asks for water. That felt true.


Structure

The audio is built around a four-chord progression in F♯ minor (F♯min7 → Dmaj7 → Amaj7 → Emaj7) that runs through the whole piece. Tempo climbs across three breakpoints — 135, 145, then 175 bpm — using a custom interpolation function (ct_) that ramps the clock gradually rather than cutting hard. Percussion layers stack progressively via xfadeIn, so the density of the mix builds in parallel with the narrative.

The visuals use the live webcam feed (s0) as their spine throughout. It gets thresholded, kaleidoscoped, color-shifted, and eventually fed back into itself depending on the scene. The core Hydra technique is a self-referencing feedback buffer: src(o0) reads the previous frame back into the pipeline, scaled fractionally below 1 and modulated by noise, so the image accumulates history rather than refreshing clean. At the peak scenes, this creates a sensation of the visuals consuming themselves.

MIDI CC signals bridge the two environments. TidalCycles sends continuous controller values via p “housemidi” and p “breakmidi”, which Hydra reads as cc[] arrays — so in several scenes, musical parameters are directly steering visual ones (camera zoom, threshold cutoff, blend amounts).

Biggest hurdle: Recording

The hardest part of the process had nothing to do with the code. We were recording across four machines and spent a significant amount of time trying to sync the video outputs with the webcam feeds in post. We tried manual timecode alignment, clap-sync markers, and various export-timing approaches — nothing held reliably. Frame rates drifted, audio latency was inconsistent across machines, and the camera feeds introduced their own additional delay. We eventually abandoned the sync attempt and submitted without it. The live performance is the real artifact; the recording is a best-effort document of it.


Roles:

Ahmed and Linus – Tidal-side, recording and concept

Uditi and Alwin – Write-up and Hydra-side

Description:

Our live-coding performance explores the tension between collective harmony and individual expression through the integration of TidalCycles for audio and Hydra for GLSL visuals. Bound together by a shared MIDI “nervous system,” the performance is anchored by a collective foundation featuring a unified 171 BPM clock and Euclidean rhythmic structures. Against this synchronized framework, distinct individual “personalities” emerge, ranging sonically from organic world percussion to digital Moog bass, and visually through specialized shaders (ritualBalls and gloopFace) that interpret the same data through entirely different aesthetic lenses. As the piece unfolds, the performance dynamically evolves from minimalist geometry into a complex, reactive 3D climax, symbolizing how diverse, autonomous components can seamlessly merge into a singular, high-energy experience.

Video:

Code:

Tidalcycles:

setcps (171/60/4)

let shakers = s "{hc*3, casio:1*2}" # gain (range 0.7 0.9 rand) # pan (slow 8 sine)

let talking_drums = degradeBy 0.15 $ s "lt*4" # n (irand 8) # speed (range 0.9 1.4 rand) # gain 0.8

let bass_line = s "supermandolin" >| note (scale "minor" ("<0 [~ 2] 3 [~ -2]>")) # sustain 0.2 # lpf 1000 # gain 0.8

let piano_chord = slow 0.5 $ s "superpiano(3,8)" # n (choose [0, 4, 7, 11]) # gain 0.8 # room 0.5 # size 0.8

let intro_d1 = stack [s "<bd*2 bd> ~ <bd*2 bd> ~ sd bd" # room 0.6 # gain 1.2, s "~ hh*2" # room 0.5 # gain 1.2]

let build = stack [s "bd(3,8)" # gain 1.1, s "~ cp" # room 0.4, shakers, bass_line, n "0 ~ 3 ~ 5 ~ 7 ~" # s "casio" # gain 0.8 # room 0.3]

let main_groove = stack [s "<bd*2 [bd [~ bd]]> ~ bd [bd*2]" # gain 1.1,s "~ sd ~ sd" # n "2", jux rev $ s "tabla2:113(5,8)" # gain 0.8 # room 0.2,talking_drums # pan (slow 2 saw),shakers,bass_line # lpf (range 200 1200 $ slow 8 sine) # resonance 0.2,struct "t(3,8,1)" $ note (scale "minor" "<0 2 4 -1>" + "'m9") # s "superpiano" # sustain 2 # gain 0.7 # room 0.5]

let sbreak = stack [s "jungbass:9" # gain 0.9 # cut 1, s "auto:3" # gain 0.8 # lpf (slow 4 $ range 500 4000 saw), shakers # gain 0.6]

let filler= n "0 7*8" # s "supermandolin" # speed (range 1 2 saw) # sustain 0.1 # room 0.4 # gain 0.7

let outro_d5 = s "casio:1*4" # gain 0.8

let vizClearMidi = stack [
        s "midi" # ccn "1" # ccv "0",
        s "midi" # ccn "2" # ccv "0",
        s "midi" # ccn "3" # ccv "0",
        s "midi" # ccn "4" # ccv "0",
        s "midi" # ccn "5" # ccv "0"
      ]

let vizShakersMidi = stack [
        s "midi*12" # ccn "3" # ccv "90 0 95 0 88 0 100 0 92 0 98 0",
        s "midi*8" # ccn "5" # ccv "0 0 127 0 0 0 127 0"
      ]

let vizTalkingDrumsMidi = s "midi*8" # ccn "4" # ccv "85 110 75 105 90 115 80 120"

let vizBassLineMidi = s "midi*8" # ccn "4" # ccv "115 0 105 118 0 112 0 108"

let vizPianoChordMidi = fast 2 $ s "midi*4" # ccn "5" # ccv "127 95 118 102"

let vizIntroD1Midi = stack [
        s "midi*16" # ccn "1" # ccv "127 127 127 0 127 127 127 0 0 127 0 0 0 0 0 0",
        s "midi*16" # ccn "2" # ccv "0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0",
        s "midi*16" # ccn "3" # ccv "0 70 0 70 0 70 0 70 0 75 0 75 0 75 0 75"
      ]

let vizBuildLetMidi = stack [
        s "midi*8" # ccn "1" # ccv "127 0 0 127 0 0 127 0",
        s "midi*8" # ccn "2" # ccv "0 0 0 0 127 0 0 0",
        s "midi*8" # ccn "3" # ccv "55 80 60 95 65 100 70 115",
        s "midi*8" # ccn "4" # ccv "115 0 105 118 0 112 0 108",
        s "midi*8" # ccn "5" # ccv "127 0 110 0 118 0 105 0"
      ]

let vizMainGrooveLetMidi = stack [
        s "midi*16" # ccn "1" # ccv "127 80 0 0 127 0 0 80 127 0 0 0 127 80 0 0",
        s "midi*16" # ccn "2" # ccv "0 0 0 0 127 0 0 0 0 0 0 0 127 0 0 0",
        s "midi*16" # ccn "3" # ccv "45 70 55 90 50 80 60 100 45 70 55 90 50 80 60 110",
        s "midi*8" # ccn "4" # ccv "85 110 75 105 90 115 80 120",
        slow 2 (s "midi*8" # ccn "4" # ccv "115 0 105 118 0 112 0 108"),
        struct "t(3,8,1)" $ s "midi*8" # ccn "5" # ccv "127 0 95 0 118 0 110 0"
      ]

let vizSbreakMidi = stack [
        s "midi*8" # ccn "1" # ccv "127 60 127 55 127 50 127 45",
        s "midi*8" # ccn "4" # ccv "90 100 110 120 100 90 85 95",
        s "midi*12" # ccn "3" # ccv "90 0 95 0 88 0 100 0 92 0 98 0"
      ]

let vizFillerLetMidi = s "midi*16" # ccn "5" # ccv "127 110 105 115 100 118 95 120 90 0 0 0 0 0 0 0"

let rise = d1 $ qtrigger $ filterWhen (>=0) $ seqP [
        (0, 1, n "0 7 0 7" # s "supermandolin"),
        (1, 2, n "0 7 0 7 0 7 0 7" # s "supermandolin"),
        (2, 3, n "0 7*8" # s "supermandolin"),
        (3, 4, n "0 7*16" # s "supermandolin")
      ]
      # room 0.3
      # hpf (slow 4 (range 100 2000 saw))
      # speed (slow 4 (range 1 3 saw))
      # detune 2

let transition = do
      d6 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0,2, slow 2 $
            s "supersquare*32"
            # note (range (-24) 12 saw)
            # sustain 0.08
            # hpf (range 180 4200 saw)
            # lpf 9000
            # room 0.45
            # gain (range 0.8 1.15 saw)
          )
        , (2,64, silence)
        ]
      d7 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0,2, silence)
        , (2,2.25, stack
            [ s "808bd*16" # gain 3.6 # speed 0.6 # crush 3 # distort 0.35 # room 0.3 # size 0.8
            , s "tabla2:113*8" # gain 1.8 # speed 0.8 # room 0.35
            , s "noise2:2*8" # gain 1.5 # hpf 1200 # room 0.25 # size 0.6
            , s "casio:2" # note "-24" # sustain 0.35 # lpf 220 # gain 1.9
            ])
        , (2.25,64, silence)
        ]
      d11 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0, 2.25, ccv "127" # ccn "4" # s "midi")
        , (2.25, 64, ccv "0" # ccn "4" # s "midi")
        ]
      d2 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0,2.25, s "cp(3,8,2)" # room 0.85 # gain 0.7)
        , (2.25,64, silence)
        ]

d1 $ s "bd(3,8)" # room 0.7 # gain 1.0

p "vizKickEuclid" $ s "midi*16"
  # ccn "1"
  # ccv "127 0 0 0 0 127 0 0 0 0 127 0 0 0 0 0"

d2 $ s "cp(3,8,2)" # room 0.85 # gain 0.7

p "vizClapEuclid" $ s "midi*16"
  # ccn "2"
  # ccv "0 0 127 0 0 0 0 127 0 0 0 0 127 0 0 0"

d3 $ slow 4 $ s "moog:2" >| note (scale "spanish" "0 ~ 2 ~ 4 ~ 5 ~" + "d4") # room 0.9 # gain 0.75 # legato 2.0 # lpf 800

d3 $ slow 4 $ s "moog:2" >| note (scale "spanish" "<[0 ~ 2 ~ 4 ~ 5 ~] [7 ~ 5 ~ 4 ~ 2 ~]>" + "d4") # room 0.9 # gain 0.75 # legato 2.0 # lpf 800

p "vizSpanishMoog" $ slow 4 $ s "midi*8"
  # ccn "3"
  # ccv "<[95 0 110 0 122 0 105 0] [127 0 105 0 95 0 80 0]>"

d1 $ every 4 (fast 2) $ s "bd ~ ~ bd ~ ~ bd ~" # room 0.7 # gain 1.1

p "vizFastKick" $ every 4 (fast 2) $ s "midi*8"
  # ccn "1"
  # ccv "127 0 0 127 0 0 127 0"

d2 $ s "cp ~ cp ~ cp ~ cp ~" # room 0.85 # gain 0.75

p "vizFourClaps" $ s "midi*8"
  # ccn "2"
  # ccv "127 0 127 0 127 0 127 0"

d1 silence
p "perfAfterSilenceD1" $ vizClearMidi

d3 silence
p "perfAfterSilenceD3" $ vizClearMidi

transition
p "perfDuringTransition" $ vizTransitionMidi

d1 intro_d1
p "perfDuringIntroD1" $ vizIntroD1Midi

d2 build
p "perfDuringBuild" $ vizBuildLetMidi

d6 filler
p "perfDuringFiller" $ vizFillerLetMidi

d2 silence

rise

d3 main_groove
p "perfDuringMainGroove" $ vizMainGrooveLetMidi

d6 silence

d1 $ s "bd*4"
  # gain 1.15
  # room 0.12

d10 $ s "midi*16"
  # ccn "1"
  # ccv "127 0 0 0 127 0 0 0 127 0 0 0 127 0 0 0"

d2 $ s "~ cp ~ cp"
  # gain 0.9
  # room 0.25
  # size 0.35

d11 $ s "midi*16"
  # ccn "2"
  # ccv "0 0 0 0 127 0 0 0 0 0 0 0 127 0 0 0"

d3 $ s "hh*16"
  # gain (range 0.65 0.95 $ slow 2 sine)
  # pan (range 0.35 0.65 $ slow 4 sine)

d12 $ s "midi*16"
  # ccn "3"
  # ccv "35 70 45 90 35 75 45 95 35 70 45 90 35 75 45 105"

d7 $ s "~ tabla2:113 ~ tabla2:113"
  # gain 0.8
  # room 0.2

d4 $ slow 2 $ s "bass*8"
  # note "<f2 c2 ef2 bf2>"
# legato 0.25
  # cutoff 900
  # resonance 0.25
  # gain 0.95

d8 $ slow 2 $ s "bass"
  # note "<f1 c1 ef1 bf1>"
  # sustain 1.8
  # cutoff 250
  # gain 0.85

d5 $ slow 2 $ s "supersquare"
  # note "<f'min c'min ef'maj bf'maj>"
  # sustain 1.8
  # lpf 2400
  # room 0.4
  # gain 0.75

d13 $ slow 2 $ s "midi*8"
  # ccn "4"
  # ccv "<100 75 90 80>"

rise

p "perfDuringRiseHydra" $ vizRiseSectionMidi

d6 $ slow 2 $ s "supersquare*8"
  # note "<[f4 af4 c5 f5 c5 af4 c5 f4] [c4 ef4 g4 c5 g4 ef4 g4 c4] [ef4 g4 bf4 ef5 bf4 g4 bf4 ef4] [bf3 d4 f4 bf4 f4 d4 f4 bf3]>"
  # sustain 0.18
  # lpf 4500
  # gain 0.7
  # room 0.3
  # delay 0.3
  # delaytime 0.125
  # delayfb 0.35

d9 $ slow 2 $ s "supersaw"
  # note "<[f5 ~ ab5 c6 ~ ab5 ~ ~] [g5 ~ c6 ef6 ~ c6 ~ ~] [bf5 ~ ef6 g6 ~ ef6 ~ ~] [f5 ~ bf5 d6 ~ bf5 ~ ~]>"
  # sustain 0.35
  # legato 1
  # lpf 5500
  # room 0.45
  # delay 0.3
  # delaytime 0.1875
  # delayfb 0.4
  # gain 0.85

d14 $ slow 2 $ s "midi*8"
  # ccn "5"
  # ccv "<[127 0 95 120 0 90 0 0] [105 0 127 115 0 95 0 0] [120 0 127 110 0 95 0 0] [105 0 120 110 0 95 0 0]>"

d9 silence

d6 silence

d8 silence

d4 silence

d5 silence

d3 silence

d2 silence

d7 silence

hush

Hydra:

setFunction({
  name: 'ritualBalls',
  type: 'src',
  inputs: [
    { type: 'float', name: 'kick',  default: 0.0 },
    { type: 'float', name: 'clap',  default: 0.0 },
    { type: 'float', name: 'hat',   default: 0.0 },
    { type: 'float', name: 'bass',  default: 0.0 },
    { type: 'float', name: 'rise',  default: 0.0 },
    { type: 'float', name: 'phase', default: 0.0 }
  ],
  glsl: `
    vec2 uv = _st - 0.5;
    uv.x *= resolution.x / resolution.y;
    float t = time * 0.4;
    uv.x += sin(uv.y * 90.0 + t * 18.0) * kick * 0.025;
    uv.y += sin(uv.x * 60.0 - t * 12.0) * kick * 0.015;
    float r = length(uv);
    float a = atan(uv.y, uv.x);
    vec3 col = vec3(0.005, 0.0, 0.015);
    float center = 0.020 / (r + 0.04);
    col += vec3(0.45, 0.04, 0.9) * center * (0.3 + bass * 0.9);
    int balls = 3 + int(phase * 7.0);
    for (int i = 0; i < 12; i++) {
      if (i >= balls) break;
      float fi = float(i);
      float orbit = 0.18 + 0.08 * sin(t * 0.25 + fi);
      orbit += kick * 0.08;
      orbit += rise * 0.05;
      orbit += phase * 0.05;
      vec2 p = vec2(
        cos(t * (0.4 + fi * 0.025) + fi * 6.283 / float(balls)),
        sin(t * (0.4 + fi * 0.025) + fi * 6.283 / float(balls))
      ) * orbit;
      float d = length(uv - p);
      float ball = 0.008 / (d + 0.005);
      float ring = sin(d * 95.0 - t * 5.0 + kick * 8.0);
      ring = smoothstep(0.7, 1.0, ring) * 0.014 / (d + 0.01);
      col += vec3(0.05, 0.8, 1.0) * ball;
      col += vec3(1.0, 0.1, 0.65) * ring * (0.5 + rise * 1.0) * (0.4 + phase * 0.6);
    }
    float spokes = sin(a * 18.0 + sin(r * 25.0 - t * 3.0) * 2.0);
    spokes = smoothstep(0.92 - kick * 0.15, 1.0, spokes);
    spokes *= 0.025 / (r + 0.05);
    col += vec3(0.2, 0.95, 1.0) * spokes * (0.3 + kick * 1.2) * (0.3 + phase * 0.7);
    float scan = sin(_st.y * 850.0 + t * 15.0);
    float scanMask = step(0.97 - hat * 0.2, scan);
    col += vec3(0.0, 1.0, 0.35) * scanMask * 0.10 * (0.4 + phase * 0.6);
    col += vec3(1.0, 0.9, 0.75) * clap * 0.20;
    col += vec3(1.0, 0.08, 0.02) * rise * 0.15;
    col *= smoothstep(1.05, 0.15, r);
    return vec4(col, 1.0);
  `
})


setFunction({
  name: 'gloopFace',
  type: 'src',
  inputs: [
    { type: 'float', name: 'kick',  default: 0.0 },
    { type: 'float', name: 'clap',  default: 0.0 },
    { type: 'float', name: 'hat',   default: 0.0 },
    { type: 'float', name: 'bass',  default: 0.0 },
    { type: 'float', name: 'rise',  default: 0.0 },
    { type: 'float', name: 'phase', default: 0.0 }
  ],
  glsl: `
    vec2 uv = _st - 0.5;
    uv.x *= resolution.x / resolution.y;
    uv *= 2.2;
    // background swirl
    float br = length(uv);
    float ba = atan(uv.y, uv.x);
    vec3 bg = vec3(0.025, 0.01, 0.07);
    float swirl = sin(ba * 5.0 + br * 3.0 - time * 1.5 + hat * 5.0);
    bg += 0.05 * vec3(0.6, 0.3, 1.0) * swirl;
    bg += 0.06 * vec3(0.2, 0.4, 0.9) * (0.4 + bass * 0.8);
    bg *= smoothstep(2.0, 0.2, br);
    vec3 col = bg;
    // ray
    vec3 ro = vec3(0.0, 0.0, -3.2);
    vec3 rd = normalize(vec3(uv, 2.0));
    // orbit cam — yaw with bass+phase, pitch with clap
    float camY = time * 0.4 + bass * 0.7 + phase * 1.4;
    float cy = cos(camY), sy = sin(camY);
    ro.xz = mat2(cy, -sy, sy, cy) * ro.xz;
    rd.xz = mat2(cy, -sy, sy, cy) * rd.xz;
    float camP = sin(time * 0.6 + clap * 2.5) * 0.22;
    float cp1 = cos(camP), sp1 = sin(camP);
    ro.yz = mat2(cp1, -sp1, sp1, cp1) * ro.yz;
    rd.yz = mat2(cp1, -sp1, sp1, cp1) * rd.yz;
    // gaze direction (eyes follow a wandering target)
    vec2 gaze = vec2(
      sin(time * 0.7 + phase * 6.0),
      cos(time * 0.5 + phase * 4.0)
    ) * 0.06;
    gaze.x += (clap - 0.5) * 0.04;
    gaze.y -= kick * 0.05;
    float t = 0.0;
    float dHit = 0.0;
    bool hit = false;
    vec3 hp = vec3(0.0);
    for (int i = 0; i < 56; i++) {
      vec3 p = ro + rd * t;
      // squash on kick, stretch on clap
      vec3 q = p;
      q.y *= 1.0 - kick * 0.22;
      q.x *= 1.0 + kick * 0.12 + clap * 0.05;
      // head ripple
      float wob = sin(q.x * 4.0 + time * 2.5)
                * sin(q.y * 3.5 + time * 2.0)
                * sin(q.z * 4.0 + time * 2.7);
      float headR = 0.85 + bass * 0.15;
      float dHead = length(q) - headR + wob * (0.05 + rise * 0.14);
      // eyes
      vec3 eOff = vec3(0.30, 0.18, -0.55);
      vec3 eL = q - vec3(-eOff.x, eOff.y, eOff.z);
      vec3 eR = q - vec3( eOff.x, eOff.y, eOff.z);
      eL.xy -= gaze * 0.5;
      eR.xy -= gaze * 0.5;
      float eyeR = 0.20 + clap * 0.07;
      float dEyeL = length(eL) - eyeR;
      float dEyeR = length(eR) - eyeR;
      float dEyes = min(dEyeL, dEyeR);
      // pupils (dark spheres slightly forward)
      vec3 pL = eL - vec3(0.0, 0.0, -0.13);
      pL.xy -= gaze * 0.6;
      vec3 pR = eR - vec3(0.0, 0.0, -0.13);
      pR.xy -= gaze * 0.6;
      float pupR = 0.085;
      float dPup = min(length(pL), length(pR)) - pupR;
      // mouth (subtracted from face — opens with clap)
      vec3 mp = q - vec3(0.0, -0.30 - clap * 0.05, -0.62);
      float mouthR = 0.16 + clap * 0.12;
      float dMouth = length(mp) - mouthR;
      // smooth-union (head, eyes)
      float k = 0.10;
      float h = clamp(0.5 + 0.5*(dEyes - dHead)/k, 0.0, 1.0);
      float dFace = mix(dEyes, dHead, h) - k*h*(1.0-h);
      // smooth-subtract mouth from face
      float ks = 0.07;
      float hs = clamp(0.5 - 0.5*(dFace + dMouth)/ks, 0.0, 1.0);
      dFace = mix(dFace, -dMouth, hs) + ks*hs*(1.0-hs);
      float d = min(dFace, dPup);
      if (d < 0.002) {
        hit = true;
        hp = q;
        dHit = t;
        break;
      }
      if (t > 10.0) break;
      t += d * 0.6;
    }
    if (hit) {
      // figure out which feature we hit (face / eye-white / pupil)
      vec3 eOff2 = vec3(0.30, 0.18, -0.55);
      vec3 eL2 = hp - vec3(-eOff2.x, eOff2.y, eOff2.z);
      vec3 eR2 = hp - vec3( eOff2.x, eOff2.y, eOff2.z);
      eL2.xy -= gaze * 0.5;
      eR2.xy -= gaze * 0.5;
      float dToEye = min(length(eL2), length(eR2)) - (0.20 + clap * 0.07);
      vec3 pL2 = eL2 - vec3(0.0, 0.0, -0.13);
      pL2.xy -= gaze * 0.6;
      vec3 pR2 = eR2 - vec3(0.0, 0.0, -0.13);
      pR2.xy -= gaze * 0.6;
      float dToPup = min(length(pL2), length(pR2)) - 0.085;
      int matId = 0;
      if (dToPup < 0.01) matId = 2;
      else if (dToEye < 0.02) matId = 1;
      // sphere-ish normal — cheap and good enough for goofy
      vec3 n = normalize(hp);
      vec3 baseCol;
      if (matId == 2) {
        baseCol = vec3(0.02, 0.0, 0.05);
      } else if (matId == 1) {
        baseCol = mix(vec3(0.95, 0.95, 1.0), vec3(1.0, 0.5, 0.2), clap);
      } else {
        baseCol = 0.5 + 0.5 * sin(vec3(0.0, 1.5, 3.0) + time * 0.8 + hp.x * 1.5 + bass * 4.0);
        baseCol = mix(baseCol, vec3(1.0, 0.4, 0.6), 0.25 + hat * 0.35);
      }
      vec3 lightDir = normalize(vec3(0.5, 0.8, -0.6));
      float diff = max(0.0, dot(n, lightDir));
      float fres = pow(1.0 - max(0.0, dot(n, -rd)), 2.5);
      vec3 lit = baseCol * (0.30 + diff * 0.75);
      lit += vec3(1.0, 0.9, 0.7) * fres * (0.3 + rise * 1.2);
      float fog = exp(-dHit * 0.08);
      col = mix(bg, lit, fog);
    }
    // overlays
    col += vec3(1.0, 0.7, 0.4) * clap * 0.12;
    col += vec3(0.8, 0.2, 1.0) * rise * 0.10;
    col *= 0.92 + 0.08 * sin(_st.y * 600.0 + time * 8.0) * (0.3 + hat * 0.5);
    return vec4(col, 1.0);
  `
})


// d1 $ s "bd(3,8)" ===
ritualBalls(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.0
).out(o0)
render(o0)

// d2 $ s "cp(3,8,2)" ===
ritualBalls(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.10
).out(o1)
src(o1)
  .blend(
    src(o0).scale(() => 1.002 + (cc[1]||0) * 0.006),
    0.22
  )
  .colorama(0.0008)
  .out(o0)
render(o0)


// d3 $ slow 4 $ moog===
ritualBalls(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.25
).out(o1)
src(o1)
  .blend(
    src(o0)
      .scale(() => 1.003 + Math.sin(time * 0.3) * 0.001)
      .rotate(() => Math.sin(time * 0.2) * 0.001 + (cc[2]||0) * 0.004),
    0.26
  )
  .modulate(noise(2, 0.02), () => 0.006 + (cc[2]||0) * 0.022)
  .colorama(() => 0.001 + (cc[2]||0) * 0.006)
  .out(o0)
render(o0)


//d3 melody variation 2
ritualBalls(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.4
).out(o1)
src(o1)
  .blend(
    src(o0)
      .scale(() => 1.0035 + Math.sin(time * 0.4) * 0.0015)
      .rotate(() => Math.sin(time * 0.25) * 0.0014 + (cc[2]||0) * 0.006),
    0.28
  )
  .modulate(noise(2, 0.025), () => 0.008 + (cc[2]||0) * 0.028)
  .colorama(() => 0.002 + (cc[2]||0) * 0.008)
  .saturate(() => 1.10 + (cc[2]||0) * 0.40)
  .out(o0)
render(o0)


//d1 $ every 4 (fast 2) $ s "bd ~ ~ bd ~ ~ bd ~" ===
ritualBalls(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.5
).out(o1)
src(o1)
  .pixelate(
    () => 280 - (cc[0]||0) * 60,
    () => 180 - (cc[0]||0) * 40
  )
  .blend(
    src(o0).scale(() => 1.003 + (cc[0]||0) * 0.005),
    0.30
  )
  .colorama(0.003)
  .contrast(() => 1.05 + (cc[0]||0) * 0.4)
  .out(o0)
render(o0)


//d2 $ s "cp ~ cp ~ cp ~ cp ~" ===
ritualBalls(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.6
).out(o1)
src(o1)
  .kaleid(() => 4 + Math.floor((cc[1]||0) * 4))
  .blend(
    src(o0)
      .scale(() => 1.0035 + Math.sin(time * 0.5) * 0.002)
      .rotate(() => Math.sin(time * 0.3) * 0.002),
    0.34
  )
  .modulate(noise(2, 0.03), () => 0.01 + (cc[1]||0) * 0.03)
  .colorama(() => 0.003 + (cc[1]||0) * 0.008)
  .saturate(1.2)
  .out(o0)
render(o0)

//d1/d3 silence + transition
gloopFace(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.0
).out(o0)
render(o0)


//d1 intro_d1
gloopFace(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.15
).out(o1)
src(o1)
  .blend(
    src(o0).scale(() => 1.0025 + (cc[0]||0) * 0.005),
    0.22
  )
  .colorama(0.0008)
  .out(o0)
render(o0)


//d2 build
gloopFace(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.3
).out(o1)
src(o1)
  .blend(
    src(o0)
      .scale(() => 1.003 + Math.sin(time * 0.4) * 0.0012)
      .rotate(() => Math.sin(time * 0.25) * 0.001 + (cc[2]||0) * 0.003),
    0.26
  )
  .modulate(noise(2, 0.02), () => 0.006 + (cc[2]||0) * 0.020)
  .colorama(() => 0.002 + (cc[3]||0) * 0.005)
  .out(o0)
render(o0)


//d6 filler / first rise
gloopFace(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.45
).out(o1)
src(o1)
  .kaleid(() => 3 + Math.floor((cc[4]||0) * 5))
  .blend(
    src(o0)
      .scale(() => 1.0035 + Math.sin(time * 0.5) * 0.002)
      .rotate(() => Math.sin(time * 0.3) * 0.002 + (cc[3]||0) * 0.001),
    0.30
  )
  .modulate(noise(3, 0.025), () => 0.008 + (cc[4]||0) * 0.030)
  .colorama(() => 0.003 + (cc[4]||0) * 0.008)
  .saturate(() => 1.15 + (cc[4]||0) * 0.40)
  .out(o0)
render(o0)


//d3 main_groove
gloopFace(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.6
).out(o1)
src(o1)
  .rotate(() => Math.sin(time * 0.2) * -0.002)
  .blend(
    src(o0)
      .scale(() => 1.0038 + Math.sin(time * 0.5) * 0.0022)
      .rotate(() => Math.sin(time * 0.3) * 0.0018 + (cc[3]||0) * 0.0008),
    0.32
  )
  .modulate(noise(() => 2 + (cc[2]||0) * 4), () => 0.010 + (cc[0]||0) * 0.025)
  .colorama(() => 0.003 + (cc[4]||0) * 0.007)
  .contrast(() => 1.07 + (cc[0]||0) * 0.30)
  .saturate(() => 1.10 + (cc[4]||0) * 0.30)
  .out(o0)
render(o0)


// (d1 bd*4, d2 ~cp~cp, d3 hh*16, d4 bass*8, d5 supersquare)
gloopFace(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.78
).out(o1)
src(o1)
  .pixelate(
    () => 220 - (cc[4]||0) * 40,
    () => 140 - (cc[0]||0) * 25
  )
  .modulateScale(noise(3, 0.03), () => 0.012 + (cc[4]||0) * 0.040)
  .blend(
    src(o0)
      .scale(() => 1.0040 + Math.sin(time * 0.5) * 0.0025)
      .rotate(() => Math.sin(time * 0.3) * 0.002 + (cc[3]||0) * 0.001),
    0.34
  )
  .colorama(() => 0.005 + (cc[4]||0) * 0.009)
  .contrast(() => 1.08 + (cc[0]||0) * 0.35)
  .saturate(() => 1.10 + (cc[4]||0) * 0.35)
  .out(o0)
render(o0)


//rise + d6 supersquare*8 + d9 supersaw climax
gloopFace(
  () => cc[0]||0, () => cc[1]||0, () => cc[2]||0,
  () => cc[3]||0, () => cc[4]||0, 0.95
).out(o1)
src(o1)
  .kaleid(() => 4 + Math.floor((cc[4]||0) * 6))
  .pixelate(
    () => 180 - (cc[4]||0) * 40,
    () => 110 - (cc[0]||0) * 25
  )
  .modulateScale(noise(3, 0.05), () => 0.015 + (cc[4]||0) * 0.060)
  .blend(
    src(o0)
      .scale(() => 1.005 + Math.sin(time * 0.6) * 0.003)
      .rotate(() => Math.sin(time * 0.35) * 0.0025 + (cc[3]||0) * 0.0012),
    0.36
  )
  .colorama(() => 0.006 + (cc[4]||0) * 0.012)
  .contrast(() => 1.10 + (cc[0]||0) * 0.40)
  .saturate(() => 1.15 + (cc[4]||0) * 0.40)
  .invert(() => (cc[0]||0) > 0.95 ? 1 : 0)
  .out(o0)
render(o0)


hush()

Contributions:

Salem — Made the main visual shader (ritualBalls) and connected the music to the visuals so they react together.
Tewoflos — Came up with the visual idea and style that Salem built on.
Lincoln — Helped write the music in TidalCycles and helped build the second shader (gloopFace, the 3D face).
Reginald — Helped write the music in TidalCycles and helped build the second shader (gloopFace, the 3D face).

by the live coding cats- >_<

Elora Trotter, Yihan Zhang, Yutong Tang

Hydra Code

We tried to keep the process minimalistic int he whole process of making

//visual script

//!!!visual array

visuals = [
//first visual-> purple sphere
  ()=>{setFunction({
  name: 'sphereShaderglow',
  type: 'src',
  inputs: [
    { type: 'float', name: 'locX', default: 0.5 },
    { type: 'float', name: 'locY', default: 0.5 },
    { type: 'float', name: 'diameter', default: 0.3 },
    { type: 'float', name: 'r', default: 0.5 },
    { type: 'float', name: 'g', default: 0.4 },
    { type: 'float', name: 'b', default: 0.7 },
    { type: 'float', name: 'm1', default: 0.2 },
    { type: 'float', name: 'm2', default: 0.5 },
    { type: 'float', name: 'm3', default: 0.8 },
  ],
  glsl: `
    vec2 uv = _st * resolution;
    vec2 center = vec2(locX * resolution.x, locY * resolution.y);
    float dist = distance(uv, center);
    float radius = (diameter * resolution.x) / 2.0;
    vec3 moonColor = vec3(r, g, b);
    // --- Glow halo (additive, outside AND inside the sphere) ---
    float glowRadius = radius * 1.8;          // how far the glow reaches
    float glowStrength = 0.9;                 // peak brightness of halo
    float glowFalloff = 3.5;                  // higher = tighter glow
    float glowDist = max(dist - radius, 0.0); // distance beyond sphere edge
    float glow = glowStrength * exp(-glowFalloff * glowDist / radius);
    vec3 glowColor = moonColor * glow;        // glow tinted to moon color
    // Outside the sphere: just the glow halo
    if (dist > radius) {
      return vec4(glowColor, 1.0);
    }
    // --- Sphere surface shading ---
    float normX = (uv.x - center.x) / radius;
    float normY = (uv.y - center.y) / radius;
    float z = sqrt(max(0.0, 1.0 - normX*normX - normY*normY));
    vec3 normal = normalize(vec3(normX, normY, z));
    vec3 lightDir = normalize(vec3(m1, m2, m3));
    float light = max(dot(normal, lightDir), 0.0);
    // Additive rim glow on the lit edge of the sphere
    float rimGlow = pow(1.0 - z, 3.0) * light * 0.6;
    vec3 color = moonColor * light;
    color += moonColor * rimGlow;   // add rim highlight
    color += glowColor * 0.3;       // bleed inner glow into surface
    return vec4(color, 1.0);
  `
})
// Orbiting moon version
let rotSpeed = 0.5
sphereShaderglow(
  0.5,
  () => (Math.sin(time * rotSpeed) / 10+0.5),
  0.3,
  0.5, 0.4, 0.9,         // r, g, b — cool blue-white moon color
  () => Math.sin(time * rotSpeed),
  -0.3,
  () => Math.cos(time * rotSpeed),
).out(o3)
//visual 1-> one singular ball
osc(24,0.1,0.5).modulateRotate(noise(2),()=>cc[0]).mask(o3).color(5,4,1).hue(0.5).blend(src(o0),0.9).out(o0)},
//------------------------------------
//visual 2-> spheres with bigger ossilation
()=> {osc(24,0.1,0.5).modulateRotate(noise(2),()=>(cc[0]*5)).mask(o3).color(5,4,1).hue(0.5).blend(src(o0),0.9).out(o0)},
//-----------------------------------------
//visials 3 bigger ossilation sphere with color change
()=> {osc(24,0.1,0.5).modulateRotate(noise(2),()=>(cc[0]*5)).mask(o3).color(2,4,1).hue(()=>cc[1]*2).blend(src(o0),0.9).out(o0)},
//-------------------------------------------
//visuals 4 change ball size
()=>{let rotSpeed = 0.5
sphereShaderglow(
  0.5,
  () => (Math.sin(time * rotSpeed) / 10+0.5),
  ()=> cc[3],
  0.5, 0.4, 0.9,         // r, g, b — cool blue-white moon color
  () => Math.sin(time * rotSpeed),
  -0.3,
  () => Math.cos(time * rotSpeed),
).out(o3)
osc(24,0.1,0.5).modulateRotate(noise(2),()=>(cc[0])).mask(o3).color(2,4,1).hue(()=>cc[1]*2).blend(src(o0),0.9).out(o0)},
//--------------------------------------------------
//visuals 5 add another layer of effects scrollX
()=>{osc(24,0.1,0.5).modulateRotate(noise(2),()=>(cc[0])).mask(o3).color(2,4,1).hue(0.35).blend(src(o0).modulateScrollX(o0),0.9).out(o0)},
//-----------------------------------------------------
//visuals6-> multiple spheres in blender
()=> {osc(24,0.1,0.5).modulateRotate(noise(3),()=>(cc[0])).mask(o3).color(4,2.5,1.5).hue(()=>cc[2]).blend(src(o0),0.5).repeat(2,2).layer(src(o1)).out(o0)},
//------------------------------------------------ 
//visuals7->falling Stars wihtout planets
()=> { osc(24, 5, .7)
      .mask(shape(100, 0.02, 0.01).scale(1, () => window.innerHeight / window.innerWidth))
      .repeat(100, 100)
      .modulate(noise(1, 0.5), 0.5).colorama(0.25)
      .rotate(() => cc[0] * Math.PI, 0.03)
      .out(o1)
//             osc(24,0.1,.7).mask(shape(10,0.01,0.02).scale(1,()=>window.innerHeight/window.innerWidth)).
//               repeat(100,100).modulate(noise(1,0.5,3),0.5).out(o1)
          src(o0)
              .modulate(voronoi(100,0.1,1.5).modulate(noise(5),1).brightness(0.03)
              ,0.003).layer(src(o1)).luma(0.2).colorama(0.5).out(o0)},
//---------------------------------------------------
//visuals 8->falling stars with a spheres
()=> {
  setFunction({
  name: 'sphereShader',
  type: 'src',           
  inputs: [
    {
      type: 'float',
      name: 'locX',
      default: 0.5,
    },
    {
      type: 'float',
      name: 'locY',
      default: 0.5,
    },
    {
      type: 'float',
      name: 'diameter',
      default: 0.3,   // in normalized space, 0.3 = 30% of screen
    },
    {
      type: 'float',
      name: 'r',
      default: 0.5,
    },
    {
      type: 'float',
      name: 'g',
      default: 0.4,
    },
    {
      type: 'float',
      name: 'b',
      default: 0.7,
    },
    {
      type: 'float',
      name: 'm1',
      default: 0.2,   //1st parameter of the 3D vector the direction that the sphere faces
    },
    {
      type: 'float',
      name: 'm2',
      default: 0.5,   //2nd parameter of the 3D vector the direction that the sphere faces
    },
    {
      type: 'float',
      name: 'm3',
      default: 0.8,  //3rd parameter of the 3D vector the direction that the sphere faces
    }
  ],
  glsl: `
    // current pixel in screen space
    vec2 uv = _st * resolution;
    // mouse in screen space
    vec2 center = vec2(locX * resolution.x, locY * resolution.y);
    // distance from center
    float dist = distance(uv, center);
    // convert diameter to screen space radius
    float radius = (diameter * resolution.x) / 2.0;
    // outside the circle = black
    if (dist > radius) {
      return vec4(0.0, 0.0, 0.0, 1.0);
    }
    // sphere surface math
    float normX = (uv.x - center.x) / radius;   // -1 to 1
    float normY = (uv.y - center.y) / radius;   // -1 to 1
    float z = sqrt(1.0 - normX*normX - normY*normY);  // depth
    // surface normal
    vec3 normal = normalize(vec3(normX, normY, z));
    // light direction
    vec3 lightDir = normalize(vec3(m1, m2, m3));
    // how much does surface face the light
    float light = max(dot(normal, lightDir), 0.0);
    // color
    vec3 color = vec3(r, g, b);
    return vec4(color * light, 1.0);
  `
})
let rotSpeed = 0.5 // how fast it rotates
  // m1 and m3 trace a circle over time = light orbits the sphere!
  sphereShader(
    0.5,
    //() => (Math.sin(time * rotSpeed)/15+0.5),
    0.5,
    0.4,
    0.5,
    0.4,
    0.9,
    //0.2,
    () => Math.sin(time * rotSpeed)*2,   // m1 — light X orbits
    //() => Math.sin(time * rotSpeed)*0.5,// m2 — light Y stays fixed
    0.8,
    () => Math.cos(time * rotSpeed)*2,   // m3 — light Z orbits
  ).out(o3)
        osc(24, 5, .7)
          .mask(shape(100, 0.02, 0.01).scale(1, () => window.innerHeight / window.innerWidth))
          .repeat(100, 100)
          .modulate(noise(1, 0.5), 0.5).colorama(0.25)
          .rotate(() => cc[0] * Math.PI, 0.03)
          .out(o1)
          //  osc(24,0.1,.7).mask(shape(10,0.01,0.02).scale(1,()=>window.innerHeight/window.innerWidth)).
      //    repeat(100,100).modulate(noise(1,0.5,3),0.5).out(o0)
                src(o0)
                  .modulate(voronoi(100,0.1,1.5).modulate(noise(5),1).brightness(0.03)
                  ,0.003).layer(src(o1)).luma(0.2).colorama(0.5).out(o2)            
src(o3).layer(o2).luma(0.02).brightness(0.02).hue(0.8).out(o0)},
//-----------------------------------------------
//visual 9 falling start in moon
()=> {
let rotSpeed = 0.5 // how fast it rotates
  // m1 and m3 trace a circle over time = light orbits the sphere!
  sphereShader(
    () => (Math.sin(time * rotSpeed)/15+0.5),
    () => (Math.sin(time * rotSpeed)/15+0.5),
    0.35, //diameter
    0.4, //r
    0.5, //g
    0.4,//b
    0.9,
    //0.2,
    () => Math.sin(time * rotSpeed)*2,   // m1 — light X orbits
    () => Math.sin(time * rotSpeed)*0.5,// m2 — light Y stays fixed
    //0.8,
    () => Math.cos(time * rotSpeed)*2,   // m3 — light Z orbits
  ).out(o3)
osc(24, 5, .7)
          .mask(shape(100, 0.02, 0.01).scale(1, () => window.innerHeight / window.innerWidth))
          .repeat(100, 100)
          .modulate(noise(1, 0.5), 0.5).colorama(0.25)
          .rotate(() => cc[0] * Math.PI, 0.03)
          .out(o1)
          //  osc(24,0.1,.7).mask(shape(10,0.01,0.02).scale(1,()=>window.innerHeight/window.innerWidth)).
      //    repeat(100,100).modulate(noise(1,0.5,3),0.5).out(o0)
                src(o0)
                  .modulate(voronoi(100,0.1,1.5).modulate(noise(5),1).brightness(0.03)
                  ,0.003).layer(src(o1)).luma(0.2).colorama(0.5).out(o2)            
src(o3).layer(o2).luma(0.02).brightness(0.02).hue(0.8).out(o0)},
//-------------------------------------
//visual 10 pulsing purple sphere with fixed color 
  ()=>{
// Orbiting moon version
let rotSpeed = 0.5
sphereShaderglow(
  0.5,
  () => (Math.sin(time * rotSpeed) / 10+0.5),
  0.5,
  0.5, 0.4, 0.9,         // r, g, b — cool blue-white moon color
  () => Math.sin(time * rotSpeed),
  -0.3,
  () => Math.cos(time * rotSpeed),
).out(o3)
// //1 one singular ball
osc(24,0.1,0.5).modulateRotate(noise(2),()=>cc[0]).mask(o3).color(5,4,1).hue(0.5).blend(src(o0),0.9).out(o0)},
//-----------------------------------------------------
//visual 11 multiple sphers in blender with a filter
()=> {osc(24,0.1,0.5).modulateRotate(noise(3),()=>(cc[0])).mask(o3).color(4,2.5,1.5).hue(()=>cc[2]).blend(src(o0),0.9).repeat(6,6).layer(src(o1)).out(o0)},
//visua//visuals6-> multi
]


whichVisual = 0
visuals[8]()

visuals[whichVisual]()

// can use update and switch case with midi:
update = () =>{
  if (ccActual[5]==24){
    visuals[8]()
  }
  // very important! only change source once, when necessary
  if (whichVisual != ccActual[1]){
    whichVisual = ccActual[1];
    visuals[whichVisual]()
  },
}

hush()

Tidal Code

-  -- Final -- 


  --melody1--floating ball-- 
    do
      d1 $ qtrigger $ slow 4
          $ note "[e5 ~ g5 b4] [c5 ~ e5 g4] [a4 c5 ~ e5] [b4 ~ g4 e4]"
          # s "supervibe"
          # lpf (range 160 480 (slow 4 sine))
          # detune 0.16
          # room 0.6           --small oscillations--
          # sz 0.95
          # gain 1.1
          # sustain 0.32
      d12 $ qtrigger $ slow 4 $ struct "[t ~ t t] [t ~ t t] [t t ~ t] [t ~ t t]" $ ccv ((segment 128 (range 127 0 saw))) # ccn "0" # s "midi"
      d13 $ ccv "0" # ccn 1 # s "midi"


-- add bass-- add bigger oscillations here--
do 
  d2 $ qtrigger $ slow 4
        $ note "[c2 ~ c2 g1] [a1 ~ a1 e1] [f1 ~ g1 a1] [e1 ~ g1 b1]"
        # s "supervibe"
        # lpf 180
        # detune 0.08
        # room 0.25
        # sz 0.7
        # gain 1.2
        # sustain 0.85
  d12 $ qtrigger $ slow 4 $ struct "[t ~ t t] [t ~ t t] [t t ~ t] [t ~ t t]" $ ccv ((segment 128 (range 127 0 saw))) # ccn "0" # s "midi"
  d13 $ ccv "1" # ccn 1 # s "midi"


--add percussion--change color--
do  
  d3 $ slow 2 $ stack [
       s "808:1 ~ 808:1 ~" # gain 0.9 # speed 0.65,
       s "808:1(3,8)" # gain 0.7 # speed 0.9 # nudge 0.02,
       s "808:1(5,16)" # gain 0.7 # speed 0.8 # pan (slow 4 sine),
       s "~ 808:1 ~ 808:1" # gain 1.1 # speed 0.45 # room 0.3 ]
  d14 $ qtrigger $ slow 4 $ struct "t(3,8)" $ ccv ((segment 128 (range 127 0 saw))) # ccn "1" # s "midi" --for color ccn 1
  d13 $ ccv "2" # ccn 1 # s "midi" --for # of visuals



--add beat 1--change ball size--  tone down oscillator-- 
do
  d4 $ s "909 909 909 <909, 808:1>" # gain 1 # size 0.4
  d13 $ ccv "3" # ccn 1 # s "midi"   --for # of visuals
  d15 $ struct "t t t <t, t>" $ ccv ((segment 128 (range 30 20 rand))) # ccn "3" # s "midi" --pulsing


--only beat 2--- combine with another texture, remove color -- let's stay with this color thenn
    do
       d3 silence
       d2 silence
       d5 $ s "808:3*4" # gain 0.7 # krush 2
       d13 $ ccv "4" # ccn 1 # s "midi"   --for # of visuals 

 
--add the percussion back in--
    d3 $ stack [
       s "808:1 ~ 808:1 ~" # gain 1.8 # speed 0.65,
       s "808:1(3,8)" # gain 1 # speed 0.9 # nudge 0.02,
       s "808:1(5,16)" # gain 1.6 # speed 1.3
       # pan (slow 4 sine),
       s "~ 808:1 ~ 808:1" # gain 0.8 # speed 0.45 # room 0.3 ]


  --add bass back -- 
      do
        d2 $ qtrigger $ slow 4
          $ note "[c2 ~ c2 g1] [a1 ~ a1 e1] [f1 ~ g1 a1] [e1 ~ g1 b1]"
          # s "supervibe"
          # lpf 180
          # detune 0.08
          # room 0.25
          # sz 0.7
          # gain 1.3
          # sustain 0.85


--add stars-- pixelated moon-- 

do
  d5 $ qtrigger $ slow 2
        $ note "[~ g6 ~ b6] [c7 ~ b6 g6] [~ a6 c7 ~] [c6 ~ e7 ~]"
        # s "supersaw"
        # lpf (range 900 2000 (slow 8 sine))
        # hpf 900
        # detune 0.32
        # room 0.75
        # sz 0.98
        # gain 0.6
        # sustain 0.25
  --d14 $ ccv "24" # ccn 5 # s "midi"  --the if value to trigger one time effect
  d13 $ ccv "7" # ccn 1 # s "midi"  --star rotationnn


-- everything drops except for stars-- watch pixelated moon-- heree?
      do
        d1 silence
        d2 silence
        d3 silence
        d4 silence


-- bass2 comes in--keep rotating planet--  
      d6 $ qtrigger $ slow 4
        $ note "c3 ~ ~ ~ a2 ~ ~ ~ f2 ~ ~ ~ g2 ~ ~ ~"
        # s "supersaw"
        # lpf (range 90 260 (slow 8 sine))
        # detune 0.06
        # room 0.4 
        # sz 0.8
        # gain (range 1 1.6 saw )
        # sustain 2.1


--melody comes back in--keep rotating planet--

d1 $ qtrigger $ slow 4
        $ note "[e5 ~ g5 b4] [c5 ~ e5 g4] [a4 c5 ~ e5] [b4 ~ g4 e4]"
        # s "supervibe"
        # lpf (range 160 480 (slow 4 sine))
        # detune 0.16
        # room 0.6
        # sz 0.95
        # gain 1.4
        # sustain 0.32 


--beat drops in -- return to normal pulsing ball--
do
  d4 $ s "909 909 909 909" # gain 1.1 # size 0.4
  d13 $ ccv "3" # ccn 1 # s "midi"   --for # of visuals
  d15 $ struct "t t t t" $ ccv ((segment 128 (range 30 20 rand))) # ccn "3" # s "midi"


--highhats-- normal pulsing ball
do
  d7 $ s "hh*8" # gain 1.4
  d13 $ ccv "5" # ccn 1 # s "midi"   --for # of visuals


--add kids sample--keep same-- 
do
  d8 $ jux rev $ slow 16
      $ striateBy 128 (1/6)
      $ s "kids"
      # room 0.95
      # size 0.98
      # lpf 1800
      # hpf 500
      # gain 0.8


--stars2--shudder ball! --
do
  d9 $ qtrigger $ slow 2
        $ note "[e6 ~ g6 ~] [~ b6 d7 ~] [c7 ~ a6 e6] [~ g6 b6 ~]"
        # s "supersaw"
        # lpf (range 2000 5200 (slow 8 sine))
        # hpf 1200
        # detune 0.42
        # room 0.9
        # sz 0.98
        # gain (range 0.4 1 (slow 16 sine))
        # sustain 0.22
  d13 $ ccv "4" # ccn 1 # s "midi" 


--drop away to create tension-- pulsing purple spheres!!! 
do
  d9 silence   
  d8 silence
  d6 silence 
  d1 silence
  d13 $ ccv "9" # ccn 1 # s "midi"
  d15 $ struct "t*8" $ ccv ((segment 128 (range 45 20 rand))) # ccn "3" # s "midi" --pulsing
    --for # of visuals


-- buildup2-- pulsing purple spheres--
do 
  d7 $ slow 2 
    $ note "[~ e6 g6 b6] [c7 e7 d7 b6] [a6 c7 e7 g7] [e7 d7 c7 b6]"
    # s "supersaw"
    # lpf (range 1400 6200 (slow 8 sine))
    # hpf 700
    # detune 0.34
    # room 0.78
    # sz 0.95
    # gain 0.8
    # sustain 0.28
  d8 $ slow 2
    $ note "[c5 e5 g5 c6] [e5 g5 b5 e6] [a5 c6 e6 a6] [g5 b5 d6 g6]"
    # s "supersaw"
    # lpf (range 900 4800 (slow 8 sine))
    # hpf 300
    # detune 0.22
    # room 0.7
    # sz 0.9
    # gain 0.65
    # sustain 0.55
  d9 $ slow 4
   $ note "[c6 ~ e6 g6] [b6 c7 e7 ~] [a6 c7 e7 g7] [~ e7 d7 c7]"
   # s "supervibe"
   # lpf (range 1800 7600 (slow 6 sine))
   # hpf 1200
   # detune 0.18
   # room 0.9
   # sz 0.98
   # pan (slow 4 sine)
   # gain (range 0.35 0.85 (slow 8 sine))
   # sustain 0.22
  d13 $ ccv "5" # ccn 1 # s "midi"   --for # of visuals


-- add kid sample2--
d10 $ slow 4 $ s "kids:1 ~ ~ ~ ~" # gain 1.4
   # room 1 # size 0.98 # lpf 1800 # sustain 0.5
   # legato 2

--add drum beat--faster pulsing purple spheres--  
do 
  d4 $ s "909*8" # gain 1.1 # size 0.4 # krush 2 # room 0.2
  d13 $ ccv "10" # ccn 1 # s "midi"   --for # of visuals


--resolution--stars falling like snow 
do
   d10 silence
   d4 silence
   d7 $ slow 4
      $ note "[c6 ~ e6 ~] [g5 ~ e6 c6] [a5 ~ c6 ~] [g5 ~ e5 c5]"
      # s "supervibe"
      # lpf (range 260 900 (slow 12 sine))
      # hpf 120
      # detune 0.12
      # room 0.9
      # sz 0.98
      # gain (range 0.95 0.18 (slow 16 sine))
      # sustain 0.9
   d8 $ slow 4
       $ note "[c4 ~ g4 ~] [e4 ~ c4 ~] [a3 ~ e4 ~] [f3 ~ c4 ~]"
       # s "supervibe"
       # lpf (range 180 620 (slow 16 sine))
       # detune 0.08
       # room 0.85
       # sz 0.96
       # gain (range 0.8 0.12 (slow 16 sine))
       # sustain 1.6
   d9 $ slow 8
       $ note "[~ c6 ~ e6] [g5 ~ c6 ~] [~ a5 c6 ~] [g5 ~ e5 ~]"
       # s "supervibe"
       # lpf (range 320 1200 (slow 12 sine))
       # hpf 400
       # detune 0.18
       # room 0.95
       # sz 0.98
       # pan (slow 6 sine)
       # gain (range 0.55 0.05 (slow 16 sine))
      # sustain 1.1
   d13 $ ccv "8" # ccn 1 # s "midi" 


--end on laugh-- 
do 
  d11 $ jux rev $ slow 16
      $ striateBy 128 (1/6)
      $ s "kids"
      # room 0.95
      # size 0.98
      # lpf 1800
      # hpf 500
      # gain 0.8
  d13 $ ccv "6" # ccn 1 # s "midi" 

hush

Title: Big Brother is Watching You

Demo:

Description:

Our project channels a creepy and unsettling feeling, with the visuals as well as sound. We wanted to capture a moment that is fleeting and uncertain through our work, with the use of darker visuals and eerie sounds. Inspired by Orwell’s 1984, we wanted to mimic the idea of being surveilled and trapped within a world where there is no sense of autonomy.

Process and Contributions:

The visuals begin at a calm tone with a light blue screen subtly oscillating waiting for the performance to begin. When the music begins to get a more steady beat so do the visuals as they shift steadily from one direction to the other. The integration of layers of noise and oscillation were with an intention to capture the visual randomness of noise within the visual order of the oscillator. The result was an almost flowing maze look, which tied in well with the theme as it evoked a feeling of entrapment. With this we wanted to create a visual that is fleeting in a way, changing its flow every time it looks like it’s about to drift away. At this point the visuals are a bright red colour, with an aim to evoke the creepy and unsettling feeling the music is pushing through. When the bass comes the visuals begin to momentarily shift to a greyscale version, creating a break in the visuals. Following that when the chaos in the audio increases so does the chaos in the  visuals with the use of modulateRotate for some feedback. 

For sound, we started by bringing the two piano sounds that we really liked during our group practice session. After working on it for a while, we had different sounds playing at the same time which was a bit noisy and messy to hear. Therefore, to make the sounds more cohesive, we used mask and whenmod pattern control functions throughout the composition to create a consistent rhythmic structure. For example, we used a mask on d2 and d10 so they alternate and play one after another. This created a more defined rhythmic pattern in our performance. Later, we removed one of the piano sounds then introduced a mi-UGens and bass sound to create a more creepy and unsettling vibe. Throughout the sound creation process, we continuously searched for and experimented with different samples and sounds. That is when we found the f sharp and c notes for the bass, they were a perfect fit for the unsettling atmosphere we wanted to create.

Regarding the contributions Lujain worked on the visuals while Buka and Zeina worked on sound. 

Hydra Code:

osc(50,1)
  .modulate(noise(100,2),cc[3])
  .mult(noise(10))
  .diff(noise(10))
  .brightness(0.6)
  .mult(shape(6,0.65,0.4))
  .modulate(osc(15,0.5).
            modulate(osc(15,0.5).rotate(2),0.2))
  .invert(()=>cc[0])
  .modulate(o0)
  .rotate(()=>cc[1]*2)
  .mult(osc(10,1),0.3)
  .colorama(()=>cc[2])
  .modulateRotate(src(o0).scale(2))
  .blend(o0)
  .blend(o0)
  .out(o0)

hush()

Tidal Code:

start = do
  d2 $ jux rev $ arp "pinkyup" $ n "a'min" # sound "superpiano" # legato 8 # krush 0.5 # sustain 4 # attack 0.5
  d12 $ slow 4 $ ccv "63 63 90 127 127" # ccn "0" # s "midi"
  d14 $ ccv "127" # ccn "2" # s "midi"
  d3 $ jux rev $ gap 2 $ s "feelfx:0 feelfx:1" # squiz 1 # legato 2 # lpf 1200 # room 0.4 # size 0.5

start

reverse = do
  d2 $ mask "[1 0]/4" $ jux rev $ arp "pinkyup" $ n "a'min" # sound "superpiano" # legato 8 # krush 0.5 # sustain 4 # attack 0.2 # gain (fast 2 $ range 0.8 0.9 sine)
  d10 $ mask "[0 1]/4" $ s "omi" <| note "a [~ g] [c b] [g gs]" # octave "<3 4 5 6>" # sustain "{1 2 1}%8"
  d15 $ ccv "0 127 0 127" # ccn "1" # s "midi"

reverse

d5 $ mask "[0 1]/4" $ jux rev $ striate 4 $ s "msg:1 msg:2 msg:3 msg:4" # gain 1 # room 0.4 # squiz 3

d6 $ mask "[1 0]/4" $ chop 2 $ fast 2 $ s " ~ < house:3 house:3*2 >" # squiz 3

d8 $ whenmod 6 4 (fast 2) $ slow 2 $ s "bd*8" # gain (fast 2 $ range 0.7 0.8 sine)
   
play_bass = do 
  d11 $ slow 2 $ n "c fs c fs" # s "bass3" # room 0.4 # size 0.8 # lpf 1200 
  d14 $ ccv "0 127 0 127" # ccn "2" # s "midi"

play_bass

 d3 $ jux rev $ gap 2 $ s "feelfx:0 feelfx:1" # squiz 1 # legato 2 # lpf 1200 # room 0.4 # size 0.5

d5 $ mask "[0 1]/4" $ jux rev $ striate 4 $ s "msg:1 msg:2 msg:3 msg:4" # gain 1 # room 0.4 # squiz 3


d10  $ s "omi" <| note "a [~ g] [c b] [g gs]" 
    # octave "<3 4 5 6 7 8>"
    # sustain "{1 2 1}%8"


d4 silence

d4 $ mask "[0 1]/4" $ arp "thumbup" $ n "e'maj" # sound "superpiano" # krush 0.5 # legato 8 # release 1.2 # attack 0.1 # room 0.5 # gain (fast 2 $ range 0.75 0.8 sine)

d11 $ ccv (segment 128 $ range 0 127 tri) # ccn "0" # s "midi"

d12 $ fast 2 $ ccv "0" # ccn "1" # s "midi"

d13 $ fast 2 $ ccv "0" # ccn "2" # s "midi"

d14 $ stack [
  ccv "63" # ccn "0" # s "midi",
  ccv "0" # ccn "1" # s "midi",
  ccv "60" # ccn "2" # s "midi"
]

Thank you for watching. The performance has ended, but the surveillance remains.