.

./plugged-in

tidal hydra tekno

Audio

Music is made using TidalCycles, here’s the code:

setcps(178/60/4)
let drums =
[
("hh", stack [s "[808:1 <808:1!7 808oh:2>]*4" # attack 0 # release 0.05 # decay 0 # sustain 0.1 # gain "0.7 0.8 0.7 0.8" # room 0.1
]
),
("bd", stack [s "<hardkick!3 <hardkick [hardkick hardkick] hardkick <[hardkick hardkick - hardkick] [hardkick hardkick - -]>>>*4" # release 1 # gain 0.8 # distort 0.1 # crush 12
]
),
("clap", stack [s "[- <808:3!3 <808:3*4 <808:3*2 [808:3 808:3 - 808:3]>>>]*2" # gain "0.6 0.7 0.6 0.7" # room 0.3
]
)
]
in
d1 $ ur 2 "<hh!1 [hh -] <hh, bd>!6 hh!2 <hh, clap>!2 <hh, bd, clap>!10 <bd, clap>!2>" drums []
-- 48
let stab =
[
("f", stack [note "12 - 0 2 1 0" # sound "rave2" # crush 4 # room 0.6 # attack 0.1 # delay 0.3 # gain 0.9 # release 1
]
),
("s", stack [note "12 - 0 - - -" # sound "rave2" # crush 4 # room 0.6 # attack 0.1 # delay 0.3 # gain 0.9 # release 1
]
)
]
in
d2 $ ur 2 "<-!1 [- s] -!2 s!2 [s f]!6 f [s f] <f s f s>!2 - s f>" stab []
-- d2 $ ur 2 "<-!8 s!6 f s <f s f s>!16>" stab []
-- d2 $ ur 2 "<[- s] _ -!6 <s s [f f f f]>!6 f s <f s f s>!2 - s f f f f>" stab []
-- $ jux rev $ ur 2 "<[- s] _ -!6 <s s [f f f f]>!6 f s <f s f s>!2 - s f f f f>" stab []
-- # slower 2 # delay 1
let tick =
[
("f", stack [note "<6 3 _ 6 3 _ 13 12>*8" # sound "wind:3" # room 0.3 # release 0.15 # gain 1
]
),
("s", stack [note "<6 3 _ _ _ _ _ _>*8" # sound "wind:3" # room 0.3 # release 0.15 # gain 1
]
)
-- ("s", stack [note "<6 3 _ 9 17 _ [16 3] _>*8" # sound "wind:3" # room 0.6 # release 0.15 # gain 1
-- ]
-- )
-- ("s", stack [note "<6 3 _ [9 17] _ [18 3] _>*8" # sound "wind:3" # room 0.6 # release 0.15 # gain 1
-- ]
-- )
]
in
-- d3 $ ur 3 "<s s f s>!8" tick []
d3 $ ur 3 "<s s f s>*8" tick []
-- d3 $ ur 3 "<s _ f [s s]>*8" tick []
-- d3 $ ur 3 "<_ _ [f s] s>*8" tick []
-- d3 $ ur 3 "<s s [f f] [s s]>*8" tick []
let bass =
[
("f", stack [note "<19 <12 2> - <2 10>>*8" # "bass3" # room 0.2 # attack 0.1 # release 0.1 # distort 0.4 # gain 0.8
]
),
("s", stack [note "<- 2 - 2>*8" # "bass3" # room 0.2 # attack 0.1 # release 0.1 # distort 0.4 # gain 0.8
]
)
]
in
d4 $ ur 2 "<-!14 <s s f s>!10>*2" bass []
unmute 4
d5 $ note "<-!20 -4 _ _ _ _>" # s "quotes-terminator:0" # gain 1.4
--
d6 $ note "<-!48 -4 _ _ _ _>" # s "quotes-terminator:1" # gain 1.4 # delay 0.4

There’s 3 drum voices: kick, clap and closed hats.

Then there’s a wind sample doing that ticking sound, some rave stabs and a simple bass.

Visuals

And here’s the Hydra code.

It uses OSC to receive events from SuperDirt.

Images are GIFs found online.

// OSC plugin
await loadScript("https://cdn.jsdelivr.net/gh/ojack/hydra-osc/lib/osc.min.js")
// "if then else"
// licensed with GNU AFFERO GENERAL PUBLIC LICENSE Version 3
// author: Thomas Jourdan
setFunction({
name: 'ifpos',
type: 'combine',
inputs: [
{name: 'value', type: 'float', default: 1.0},
],
glsl: 'return value < 0.0 ? _c0 : _c1;'
})
setFunction({
name: 'ifeven',
type: 'combine',
inputs: [
{name: 'value', type: 'float', default: 0.0},
{name: 'eps', type: 'float', default: 0.01},
],
glsl: 'return abs(mod(floor(value), 2.0)) < eps ? _c0 : _c1;'
})
setFunction({
name: 'ifzero',
type: 'combine',
inputs: [
{name: 'value', type: 'float', default: 0.0},
{name: 'eps', type: 'float', default: 0.1},
],
glsl: 'return abs(value) < eps ? _c0 : _c1;'
})
setFunction({
name: 'splitview',
type: 'combine',
inputs: [
{name: 'where', type: 'float', default: 0.5},
],
glsl: 'return gl_FragCoord.x/resolution.x > where ? _c0 : _c1;'
})
setFunction({
name: 'splitviewh',
type: 'combine',
inputs: [
{name: 'where', type: 'float', default: 0.5},
],
glsl: 'return gl_FragCoord.y/resolution.y > where ? _c0 : _c1;'
})
// msg.setPort(3333)
var S = {
cycle: 0
}
var P = {
shape: 3,
stabs: 0,
winds: 0,
kicks: 0
}
_osc = new OSC()
_osc.open()
function parse(msg) {
const obj = {}
for (var i = 0; i < msg.length; i+=2) {
obj[msg[i]] = msg[i + 1]
}
return obj
}
_osc.on("/dirt/play", (msg) => {
S = parse(msg.args)
P.isKick = S.s === 'hardkick'
P.isWind = S.s === 'wind'
P.isStab = S.s === 'rave2'
if (P.isWind) {
P.winds++
P.shape = P.winds % 5 + 3
}
if (P.isStab) {
P.stabs++
}
if (P.isKick) {
P.kicks++
}
})
s0.initVideo( "https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExcDVlYmVwNmMwbWw4OXFob2s5b2d1aHRzc216ZjB4bTV0d3dkOWExayZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/xnDVd93DMnOLK/giphy.mp4"
)
s1.initVideo( "https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExOTAyd2hjcjd0ZGNndGs2ZmpycDF0eGtjdHU0MW5pZGEyamtuazFwZCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/8f0y3p7TpvWFO/giphy.mp4"
)
s2.initVideo( "https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExanNyZW9ocHQwZmRsY3BheWllcHAwd2MwNnhnazVobmF3NXlpZG1tbSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/h8j1vnUMElormqm8E8/giphy.mp4"
)
function getChain() {
return src(s0)
.blend(s1, () => P.kicks % 3 === 1 ? 1 : 0)
.blend(s2, () => P.kicks % 3 === 2 ? 1 : 0)
.mult(solid(0.2, 0.8, 1), 1)
.scale(() => ((P.kicks + 1) % 20 / 20) * 0.6 + 0.1, 1, 1)
}
const chain1 = getChain()
const chain2 = getChain()
chain1.ifeven(
chain2
// .modulate(noise(() => 10 + P.kicks % 100 / 100 * 4))
.modulateKaleid(
osc(
() => P.stabs % 100 + 1,
0,
0
),
() => S.cycle % 4
)
.modulate(noise(() => 10 + P.kicks % 100 / 100 * 4))
,() => S.cycle >= 52
? S.cycle % 2
: 2
// ,1
// ,0
)
.modulate(noise(
() =>
S.cycle > 24 && S.cycle < 48
? (S.cycle - 24) / 24 * 30
: 0
))
.mult(
shape(
() => P.shape,
() => 0.4 - (3 / P.shape) * 0.1,
)
.modulate(noise(() => (P.stabs + 23) % 3))
.mult(solid(1, 1, 0), 1)
.rotate(
() =>P.stabs * Math.PI * Math.PI,
0, 0
),
() =>
S.cycle >= 52
? (S.cycle % 4 / 4) * 3
: 0.5 + S.cycle % 4 / 4 * 0.1
// : 0.6 + S.cycle % 4 / 4 * 10000
).out()

Each element in the visual reacts to an audio element.

The shape in the middle grows an extra side at every tick sound and rotates at every stab.

Images on the background instead get swapped and zoomed based on the kicks count.

...
Content Warning

This site contains loud noises and flashing images.