“Matar” (مطر — Rain)
Audio/Visual Composition — TidalCycles + Hydra
Concept
Rain is very rare in the UAE desert, sometimes only 2 or 3 rainy days per year. When it comes, it is considered a blessing. This piece takes you through the full cycle of a rainstorm: from bright sun, to clouds forming, to a full storm with thunder and lightning, to wind clearing the sky, and finally the sun returning peacefully.
This is a 3-minute audio/visual composition about a UAE rainstorm, built with TidalCycles and Hydra.
The piece has 7 sections that follow the story of rain:
A (sun slow) → B (sun bright) → C (clouds form) → D (storm) → E (wind) → F (sun returns) → G (fade out).
Each section adds or removes sound layers and switches the Hydra visuals automatically through MIDI. The audio uses hijaz and bayati scales with tabla for an Arabian feel, and bubble samples for rain, wind samples, and a low 808 kick for thunder. The visuals show a sun that pulses with the drums, clouds that grow, rain streaks falling, trees swaying in the wind, and the sun returning at the end.
Video:
Tidal Code block :
setcps (85/60/4)
sunTone = struct "t(3,8)" $ s "simplesine" >| note (scale "hijaz" "<0 3 5 0>" + "c5") # gain 0.75 # room 0.7
sunBright = struct "t(5,8)" $ sometimesBy 0.2 (shuffle 4) $ s "simplesine" >| note (scale "hijaz" "<0 3 5 7 3>" + "c5") # gain 0.8 # room 0.6
sitar1 = slow 4 $ s "sitar" # n (irand 8) # gain 0.5 # room 0.85 # speed 0.75
drumSlow = every 4 (# n "30 20 10 6") $ s "tabla2(3,8)" # n "2 12 20" # gain 0.75 # room 0.6
drumFast = sometimesBy 0.3 (# speed "1.5 0.8 2") $ s "tabla2(5,8)" # n "3 7 12 20 5" # gain 0.8 # room 0.5
cloudStart = s "bubble(3,16)" # n (irand 8) # gain 0.7 # room 0.7 # speed 0.6
cloudGrow = s "bubble(5,8)" # n (irand 8) # gain 0.75 # room 0.6 # speed "<0.6 0.8 1 0.5>" # lpf (range 800 4000 $ slow 4 saw)
cloudDrum = s "tabla2(3,8)" # n "5 15 25" # gain 0.7 # room 0.5 # speed 0.9
waterDrop = degradeBy 0.2 $ s "bubble*8" # n (irand 8) # gain 0.6 # room 0.8 # speed (range 0.4 1.2 rand)
waterHeavy = s "bubble*16" # n (irand 8) # gain 0.65 # room 0.85 # speed (range 0.3 1 rand)
windCont = s "wind:3" # gain 0.75 # room 0.5 # cut 1 # legato 2
windGust = s "wind:5 wind:3" # gain 0.85 # room 0.4 # cut 2 # legato 2 # speed 1.2
thunder = s "808bd:4(3,8)" # gain 1.1 # room 0.9 # lpf 300 # speed 0.5 # krush 3
stormTab = s "[tabla2*7, tabla2*5]" # n (irand 30) # gain 0.7 # room 0.35
stormMel = fast 2 $ s "simplesine" >| note (arp "pinkyup" (scale "bayati" "[0,1,5,8]" + "<0 -3 2 4>") + "c5") # gain 0.55 # room 0.5 # lpf (range 400 3500 $ slow 2 sine) # pan (slow 3 sine)
earth = slow 4 $ s "simplesine" >| note "c3" # gain 0.35 # lpf 400 # room 0.95
birds = slow 8 $ s "birds" # n (irand 10) # gain 0.55 # room 0.8
endMel = slow 2 $ s "simplesine" >| note (arp "converge" (scale "hijaz" "[0,3,5]" + "<0 4>") + "c5") # gain 0.45 # room 0.9 # delay 0.4 # delaytime 0.3 # delayfeedback 0.4
sec1 = do {
d1 $ sunTone;
d2 $ drumSlow;
d3 $ sitar1;
d4 silence;
d5 $ ccv 0 # ccn 0 # s "midi";
d6 $ ccv (stitch "t(3,8)" 60 15) # ccn 1 # s "midi";
d7 $ ccv (stitch "t(3,8)" 90 0) # ccn 2 # s "midi"
}
sec2 = do {
d1 $ sunBright;
d2 $ drumFast;
d3 $ sitar1 # gain 0.35;
d4 silence;
d5 $ ccv 1 # ccn 0 # s "midi";
d6 $ ccv (stitch "t(5,8)" 90 25) # ccn 1 # s "midi";
d7 $ ccv (stitch "t(5,8)" 110 0) # ccn 2 # s "midi"
}
sec3 = do {
d1 $ sunTone # gain 0.25;
d2 $ stack [cloudStart, cloudDrum];
d3 $ cloudGrow;
d4 $ stack [windCont # gain 0.3, waterDrop # gain 0.3];
d5 $ ccv 2 # ccn 0 # s "midi";
d6 $ ccv (segment 32 (range 20 100 saw)) # ccn 1 # s "midi";
d7 $ ccv (stitch "t(3,8)" 70 0) # ccn 2 # s "midi"
}
sec4 = do {
d1 $ thunder;
d2 $ stormTab;
d3 $ stack [waterHeavy, stormMel];
d4 $ windCont;
d5 $ ccv 3 # ccn 0 # s "midi";
d6 $ ccv (stitch "t(7,8)" 110 40) # ccn 1 # s "midi";
d7 $ ccv (stitch "t(3,8)" 100 0) # ccn 2 # s "midi"
}
sec5 = do {
d1 $ earth;
d2 silence;
d3 $ waterDrop # gain 0.2;
d4 $ windGust;
d5 $ ccv 4 # ccn 0 # s "midi";
d6 $ ccv (segment 32 (range 80 20 saw)) # ccn 1 # s "midi";
d7 $ ccv 0 # ccn 2 # s "midi"
}
sec6 = do {
d1 $ slow 2 $ sunTone # gain 0.5 # room 0.9;
d2 $ drumSlow # gain 0.5;
d3 $ birds;
d4 silence;
d5 $ ccv 5 # ccn 0 # s "midi";
d6 $ ccv (segment 32 (range 40 10 saw)) # ccn 1 # s "midi";
d7 $ ccv (stitch "t(3,8)" 50 0) # ccn 2 # s "midi"
}
sec7 = do {
d1 $ endMel;
d2 silence;
d3 silence;
d4 silence;
d5 $ ccv 6 # ccn 0 # s "midi";
d6 $ ccv (segment 32 (range 10 0 saw)) # ccn 1 # s "midi";
d7 $ ccv 0 # ccn 2 # s "midi"
}
sec1
sec2
sec3
sec4
sec5
sec6
sec7
hush
Hydra code block :
hush()
navigator.requestMIDIAccess().then(function(m) { for (var i of m.inputs.values()) { i.onmidimessage = function(msg) { var arr = msg.data; cc[arr[1]] = arr[2] / 127.0; ccActual[arr[1]] = arr[2]; } } }); var cc = Array(128).fill(0.5); var ccActual = Array(128).fill(0);
loadScript('/Users/salemalshamsi/Desktop/liveCoding/COMPOSITION/matar_visuals_load.js')
visuals[0]()
var whichVisual = 0
update = () => { if (whichVisual != ccActual[0]) { whichVisual = ccActual[0]; if (whichVisual < visuals.length) { visuals[whichVisual]() } } }
Visual load code block :
visuals = [
() => {
solid(0.05, 0.03, 0.12).modulateRotate(noise(1, 0.005), 0.02).out(o2)
shape(99, () => 0.12 + cc[2] * 0.08, 0.4).color(1, 0.85, 0.3).brightness(() => cc[2] * 0.3).out(o1)
src(o2).layer(src(o1)).out(o0)
render(o0)
},
() => {
solid(0.08, 0.05, 0.15).modulateRotate(noise(1, 0.008), 0.03).out(o2)
shape(99, () => 0.18 + cc[2] * 0.1, 0.5).color(1, 0.9, 0.4).brightness(() => cc[2] * 0.4).out(o1)
gradient(0.3).color(0.9, 0.6, 0.2).mult(shape(99, 0.4, 0.6)).hue(() => Math.sin(time * 0.3) * 0.02).out(o3)
src(o2).layer(src(o3).mult(solid(1,1,1), 0.15)).layer(src(o1)).out(o0)
render(o0)
},
() => {
solid(0.1, 0.1, 0.16).out(o2)
shape(99, 0.05, 0.2).color(0.6, 0.5, 0.2).scrollY(-0.12).out(o1)
noise(2.5, 0.04).color(0.8, 0.8, 0.85).thresh(() => 0.75 - cc[1] * 0.4, 0.12).modulate(voronoi(8, 0.02, 0.05), 0.02).scrollY(-0.1).out(o3)
src(o2).layer(src(o1)).layer(src(o3).mult(solid(1,1,1), 0.75)).out(o0)
render(o0)
},
() => {
solid(0.05, 0.06, 0.15).out(o2)
osc(100, 0, 0).thresh(0.9, 0.004).scrollY(0, 0.25).color(0.75, 0.78, 0.88).out(o1)
noise(3, 0.06).color(0.4, 0.4, 0.48).thresh(0.4, 0.15).scrollY(-0.18).modulatePixelate(noise(5, 0.05).pixelate(20, 20), 512).out(o3)
src(o0).diff(src(o2), 0.3).blend(src(o3), 0.06).layer(src(o1).mult(solid(1,1,1), 0.45)).brightness(() => cc[2] * 0.1).contrast(1.2).out(o0)
render(o0)
},
() => {
solid(0.22, 0.28, 0.35).out(o2)
noise(2, 0.05).color(0.5, 0.52, 0.56).thresh(0.5, 0.12).scrollX(0, 0.1).scrollY(-0.2).out(o3)
shape(3, 0.15, 0.02).color(0.15, 0.4, 0.12).rotate(() => Math.sin(time * 2) * 0.25).scrollY(0.22).kaleid(6).scale(0.5).scrollY(0.2).out(o1)
src(o0).diff(src(o0).scale(0.998), 0.6).blend(src(o2), 0.04).layer(src(o3).mult(solid(1,1,1), 0.45)).layer(src(o1).luma(0.08, 0.02)).out(o0)
render(o0)
},
() => {
solid(0.12, 0.18, 0.32).out(o2)
shape(99, 0.13, 0.4).color(1, 0.9, 0.5).brightness(0.15).scrollY(-0.18).out(o1)
solid(0.25, 0.45, 0.18).mult(shape(4, 1, 0.01).scrollY(0.15)).out(o3)
shape(3, 0.08, 0.01).color(0.15, 0.38, 0.1).scrollY(0.24).kaleid(4).scale(0.4).scrollY(0.18).out()
src(o2).layer(src(o3).mult(solid(1,1,1), 0.55)).layer(src(o1)).layer(shape(3, 0.08, 0.01).color(0.15, 0.38, 0.1).scrollY(0.28).scrollX(-0.1).luma(0.08, 0.02)).layer(shape(3, 0.07, 0.01).color(0.15, 0.38, 0.1).scrollY(0.28).scrollX(0.12).luma(0.08, 0.02)).out(o0)
render(o0)
},
() => {
solid(0.03, 0.03, 0.06).out(o2)
shape(99, 0.06, 0.5).color(0.7, 0.6, 0.3).brightness(-0.15).scrollY(-0.1).out(o1)
src(o0).blend(src(o2), 0.1).layer(src(o1).mult(solid(1,1,1), () => 0.5 - time * 0.01)).saturate(0.6).out(o0)
render(o0)
}
]
whichVisual = 0