The approach I took to creating a composition was a reverse engineering build-up where I found sounds and combinations that I enjoy and after finding those who sounded cohesive joined them into a composition. I wanted to create a more whimsical or alien-like energy to the work when choosing the sounds that I liked as I noticed several of the dirt samples had a high-pitched noise that went well really together. There was a main part that I thought brought together the composition which ended up being my A that is repeated. With that I integrated the other parts, creating the pattern A-B-A-C pattern. I tried to experiment with several of the techniques we learnt in class to find which ones fit into my work which helped out a lot in getting a hang of them, I think the part I focused the most on was creating a visual and audio fade out which was initially a transition, but then ended up looking like a great way end the work on a high instead. Which you see at the end when the screen goes fades into fight with a rising sound matching the rise in brightness in part C.

Hydra code

render()

shape(100, ()=> 0.65-cc[3])
  .scale(1,1,() => window.innerWidth / window.innerHeight)
  .scroll(0.5,()=> -0.5+cc[1])
  .invert(()=>cc[0])
  .modulateKaleid(voronoi(55))
  .colorama(1.2).posterize(4).saturate(0.7).contrast(6)
  .blend(
    shape(4, 100),()=>cc[5]
  )
  .blend(osc(30,0.0001,0.75)
      .colorama(0.5)
      .mult(osc(20,0.0001,0.2).modulate(noise(3,1)).rotate(0.4))
      .modulateScrollY(osc(2)).modulate(osc().rotate(),.011), ()=>cc[8]
  )
  .rotate(11,()=>cc[6]/127)
  .blend(shape(10,0.5).modulatePixelate(osc(25,0.5),100).colorama(0.5),()=>cc[7])
  .out(o0)

shape(100, ()=> 0.65-cc[3])
  .scale(1,1,() => window.innerWidth / window.innerHeight)
  .scroll(0.5,()=> -0.5+cc[1])
  .invert(()=>cc[0])
  .modulateKaleid(osc(55))
  .colorama(1.2).posterize(4).saturate(0.7).contrast(6)
  .blend(
    shape(4, 100),()=>cc[5]
  )
  .out(o0)

shape(100, ()=> 0.65-cc[3])
  .scale(1,1,() => window.innerWidth / window.innerHeight)
  .scroll(0.5,()=> -0.5+cc[1])
  .invert(() => 1 - cc[0])
  .color(() => 0.2 + cc[2], 0, 1)
  .modulateKaleid(osc(55),0.1,1)
  .blend(
    shape(4, 100),()=>cc[5]
  )
  .out(o1)


shape(100, ()=> 0.65-cc[3])
  .scale(1,1,() => window.innerWidth / window.innerHeight)
  .scroll(0.5,()=> -0.5+cc[1])
  .invert(() => 1 - cc[0])
  .color(() => 0.2 + cc[2], 0, 1)
  .modulateKaleid(osc(55),0.1,1)
  .blend(
    shape(4, 100),()=>cc[5]
  )
  .out(o2)

shape(100, ()=> 0.65-cc[3])
  .scale(1,1,() => window.innerWidth / window.innerHeight)
  .scroll(0.5,()=> -0.5+cc[1])
  .invert(()=>cc[0])
  .modulateKaleid(osc(55),0.1,1)
  .colorama(1.2).posterize(4).saturate(0.7).contrast(6)
  .blend(
    shape(4, 100),()=>cc[5]
  )
  .out(o3)

hush()

Tidal Code

--A
d1 $ stack[
  s "bass1 ~ <bass1 dr_few:2> ~" # room 0.4,
  s "bd bd*4 bd ~" # room 2,
  s "hh*8" # gain 0.75,
  ccv "0 127" # ccn "0" # s "midi",
  ccv (segment 128 $ range 0 127 saw) # ccn "1" # s "midi",
  s "feelfx*8" # note (scale "major" "1 1 3 5"-24) # room 1,
  s "tink:1 tink:2 tink:4 tink:5" # room 2,
  ccv "0 30 60 127" # ccn "2" # s "midi",
  ccv "0 60" # ccn "8" # s "midi"
]

xfade 1 silence

--B
d1 $ stack [
  ccv "60" # ccn "8" # s "midi",
  s "pluck:2 pluck:3",
  ccv "0 127" # ccn "6" # s "midi"
]

d1 $ qtrigger $ seqP [
  (0, 10, ccv "0 127" # ccn "6" # s "midi"),
  (0, 10, ccv "0 0 0 60 60 0 0 0" # ccn "7" # s "midi"),
  (0, 10, ccv 0 # ccn "8" # s "midi"),
  (0, 4, s "feelfx*8" # note (scale "sine" "0 0 0 2 2 0 0 0"-24) # room 0.8),
  (0, 4, s "pluck:2 pluck:3" # distort 0.2 # room 0.8),
  (4, 6, s "feelfx*8" # note (scale "sine" "0 0 0 2 2 0 0 0"-24) # room 0.6),
  (4, 6, s "pluck:2 pluck:3" # distort 0.2 # room 0.6),
  (6, 8, s "feelfx*8" # note (scale "sine" "0 0 0 2 2 0 0 0"-24) # room 0.4),
  (6, 8, s "pluck:2 pluck:3" # distort 0.2 # room 0.4),
  (8, 10, s "feelfx*8" # note (scale "sine" "0 0 0 2 2 0 0 0"-24) # room 0.2),
  (8, 10, s "pluck:2 pluck:3" # distort 0.2 # room 0.2)
]

--A

d2 $ stack[
  s "bass1 ~ <bass1 dr_few:2> ~" # room 0.4,
  s "bd bd*4 bd ~" # room 2,
  s "hh*8" # gain 0.75,
  ccv "0 127" # ccn "0" # s "midi"
]

d1 $ stack[
  ccv (segment 128 $ range 0 127 saw) # ccn "1" # s "midi",
  s "feelfx*8" # note (scale "major" "1 1 3 5"-24) # room 1,
  s "tink:1 tink:2 tink:4 tink:5" # room 2,
  ccv "0 30 60 127" # ccn "2" # s "midi"
]

--C

d2 $ stack [
  "reverbkick!4" # room 1.2,
  "realclaps*8" # room 1,
  fast 8 $ ccv (segment 128 $ range 0 127 tri) # ccn "3" # s "midi"
]


d1 $ qtrigger $ filterWhen (>0) $ seqP [
  (0, 2, s "juno:9" # room 0.2),
  (2, 4, s "juno:9" # room 0.65),
  (4, 6, s "juno:9" # room 0.85),
  (6, 8, s "juno:10" # room 1),
  (6, 10, slow 4 $ ccv (segment 128 $ range 0 127 saw) # ccn "5" # s "midi"),
  (8, 10, fast 2 $ s "juno:9*16" # room 1.2)
]

xfade 2 silence

hush

d1 $ stack [
  ccv 0 # ccn "0" # s "midi",
  ccv 0 # ccn "1" # s "midi",
  ccv 0 # ccn "2" # s "midi",
  ccv 0 # ccn "3" # s "midi",
  ccv 0 # ccn "4" # s "midi",
  ccv 0 # ccn "5" # s "midi",
  ccv 0 # ccn "6" # s "midi",
  ccv 0 # ccn "7" # s "midi",
  ccv 0 # ccn "8" # s "midi"
]

Demo

I originally had a very different idea in mind for my composition project, but after everything happening around us, I found myself lacking inspiration and creativity. To combat that, I decided to go through the dirt samples again. I went back to our class basics and ran lines on the class examples of week 2. This led me to combine sounds I liked and then figure out how to put them together into a nice beat. I was aiming for something groovy. A lot of my process involved trying to sound out a tune I like, then trying to translate that into Tidal.

I think a lot of the time in class we tend to shift towards more EDM or Tech music, but I found myself enjoying myself more with groovier beats as they sound more like songs I often listen to. After I had almost finalized my sounds, I needed to tackle visuals. For my visuals, I was thinking of contrasts, and one of the artists that I listen to, Kaytranada, tends to have album covers with a lot of contrast, so that was something I wanted to incorporate.

As for song structure, I would say I followed A-B-C-A, but I wouldn’t say I have a classic build or drop within my composition. I was kind of testing the different sounds until I found something I liked listening to, essentially playing it by ear, mostly. Every time I attempted the classic build, then drop structure, I felt like it was too generic, and I thought that might’ve been due to me not listening to a lot of EDM, so I decided to do a composition with a music style I am more familiar with, and would enjoy playing around with more.

Tidal Code:

--a 
d1 $ slow 3 $ sound "[bd sn sn][bd bd sn]" # gain 0.7 # room 0.5
d7 $ ccv "[0 20 64 127]" # ccn "0" # s "midi"

d3 $ struct "t(3,8)" $ sound "hc*4" # gain 0.7 # room 0.4
d9 $ struct "t(3,8)" $ ccv "[0 64 127 64]" # ccn "1" # s "midi"

d2 $ slow 2 $ s "padlong" # gain 0.5


d4 $ s "pluck" <| n (run 8) # gain 0.8 # room 0.4
d8 $ ccv "[0 20 20 64 64 127]" # ccn "2" # s "midi"

--b
d1 $ fast 2 $ sound "bd*4" # gain 0.7  # room 0.4
d7 $ fast 2 $ ccv "[127 0 127 0]" # ccn "0" # s "midi"

d2 $ sound "sn*4" # gain 0.7 # room 0.7
d9 $ struct "t(3,8)" $ ccv "[127 127 0 127]" # ccn "1" # s "midi"

d3 $ struct "t(3,8)" $ sound "hc*8" # gain 0.7 # room 0.4
d9 $ struct "t(3,8)" $ ccv "[64 127 64 127]" # ccn "1" # s "midi"

d6 $ struct "t(3,8)" $ sound "bass3" <| n "[c2 c2 c2 c2]" # gain 0.7 # room 0.9
d11 $ struct "t(3,8)" $ ccv "[0 127 0 127]" # ccn "3" # s "midi"

d4 $ s "pluck" <| n (run 11) # gain 0.9 
d8 $ struct "t(3,8)" $ ccv (segment 8 (range 0 127 saw)) # ccn "2" # s "midi"

d5 $ s "msg" <| n (run 4) # gain 0.9 # room 0.4


-- c
d1 $ slow 3 $ sound "[bd sn sn][bd bd sn]" # gain 0.6 # room 0.5
d7 $ ccv "[0 20 0 20]" # ccn "0" # s "midi"

d2 $ struct "t(3,8)" $ sound "hc*4" # gain 0.6 # room 0.4
d9 $ struct "t(3,8)" $ ccv "[0 127 0 127]" # ccn "1" # s "midi"

-- a
d3 $ slow 2 $ s "padlong" # gain 0.5
d10 $ ccv "[64 127 64 0]" # ccn "3" # s "midi"

d4 $ s "pluck" <| n (run 8) # gain 0.8 
d8 $ ccv (segment 8 (range 0 127 saw)) # ccn "2" # s "midi"

d6 silence 
d5 silence


hush

Hydra Code:

osc(() => 150 + cc[0]*50, 0.05 + cc[3]*0.05, 1)
  .rotate(() => time*0.5 + cc[3]*0.2)      
  .scale(() => 1 + cc[1]*0.5)             
  .color(() => cc[0], () => cc[1], () => cc[2])
  .modulate(
    noise(() => cc[0]*10 + cc[2]*5 + cc[3]*5, 0.3)
  )  .layer(
    osc(() => 80 + cc[2]*40, 0.1, 1)
      .luma(() => cc[1]*0.8 + cc[3]*0.3, 0.05)
      .pixelate(() => 2 + cc[0]*15, () => 2 + cc[1]*15)
      .color(() => cc[0], 0.5, () => cc[1])
      .modulate(noise(() => (cc[0]+cc[1])*8 + cc[3]*3, 0.25))
  )
  .layer(
    noise(() => cc[1]*8 + cc[3]*5, 0.15)
      .pixelate(() => 3 + cc[2]*15, () => 3 + cc[0]*15)
      .color(() => cc[2], () => cc[0], () => cc[1])
      .modulate(
        osc(20, 0.1, 1).luma(() => cc[3]*0.8 + cc[2]*0.2, 0.05)
      )
  )
  .modulate(
    osc(10 + cc[3]*20, 0.02 + cc[3]*0.05, 1)
      .rotate(time*0.2 + cc[3]*0.2)
      .modulate(noise(time*0.2, 0.2 + cc[3]*0.1))
  )
  .contrast(1.8 + cc[3]*0.5)
  .saturate(1.6 + cc[3]*0.5)
  .blend(o0, 0.6 + cc[3]*0.3)
  .out(o0)


hush()

Demo:

My composition is based on a more rave and kind of eerie style. The basic structure I have it follow is an intro where we bring in different elements, a breakdown, where everything goes silent and only a synth remains, that is followed by a little buildup and dropping everything back in. After letting that play for a while , each element is removed until all sounds are gone. The visuals based on different variations of the voronoi effect with different parameters being changed by the midi notes throughout the composition. I utilized darker and more muted colors as i thought it fit with the eerie vibe of the composition more. When the beat drops, a oscillator is applied over the original voronoi with some additional parameters that results in a sort of glitchy effect where there are pauses between the showing of the visual.

For this composition I created an audiovisual piece using TidalCycles for sound and Hydra for visuals.

The piece is structured into five sections:

intro

buildup

breakdown

beatdrop

outro

Each of them are triggered manually in Tidal by evaluating a named do block. The sound is built around tabla samples layered with glitch percussion, with each section adding or removing layers to create a sense of tension and release. The visual side was built in Hydra with four scenes that match each compositional section. I chose tabla specifically because I wanted to bring in a sound that felt personal and culturally grounded and pairing it with glitch electronics felt like an interesting contrast between something organic and something digital.

Composition Video:

Code Snippet:

setcps (130/60/4)

intro = do
 d1 $ slow 2 $ degradeBy 0.6 $ s "tabla" # n (irand 4) # gain 0.8 # room 0.95 # size 0.9 # speed 0.5
 d2 $ degradeBy 0.8 $ s "glitch" # crush 12 # gain 0.6 # pan rand
 d3 $ s "space" # gain 0.5 # room 0.5 # size 0.5 # speed 0.5
 d8 $ ccv 0 # ccn 0 # s "midi"

buildup = do
 d1 $ s "tabla*2" # n (irand 8) # gain 1.0 # room 0.6 # speed (choose [1, 1.5, 0.75])
 d2 $ whenmod 4 3 (stutter 2 0.25) $ s "glitch*4" # crush 8 # gain 0.75 # pan rand
 d3 $ every 4 (fast 2) $ s "tabla" # n (irand 8) # gain 0.9 # room 0.8 # speed 0.75
 d4 $ degradeBy 0.8 $ s "glitch" # crush 6 # gain 0.7 # speed (choose [1, 2])
 d8 $ ccv 42 # ccn 0 # s "midi"

breakdown = do
 d1 $ slow 2 $ degradeBy 0.4 $ s "tabla" # n (irand 4) # gain 1.1 # room 0.95 # size 0.9 # speed (choose [0.5, 0.75])
 d2 $ whenmod 8 7 (density 4) $ s "glitch*2" # crush 4 # gain 0.85 # pan rand
 d3 $ silence
 d4 $ every 2 (# speed 0.5) $ s "glitch" # crush 3 # gain 0.9 # room 0.7
 d8 $ ccv 84 # ccn 0 # s "midi"

beatdrop = do
 d1 $ s "tabla*4" # n (irand 16) # gain 1.3 # room 0.2 # size 0.3 # speed (choose [1, 1.5, 2, -1])
 d2 $ whenmod 4 3 (stutter 4 0.125) $ s "glitch*8" # gain 0.9 # crush 6 # speed (choose [1, 2, -1]) # pan rand
 d3 $ every 3 (fast 2) $ s "tabla" # n (irand 16) # gain 1.1 # room 0.9 # size 0.8 # speed (choose [0.5, 1, 2])
 d4 $ whenmod 8 7 (density 4) $ s "glitch" # crush 8 # gain 0.8 # pan rand
 d5 $ fast 2 $ s "tabla*2" # n (irand 8) # gain 1.2 # crush 5 # speed (choose [1, -1, 2])
 d8 $ ccv 127 # ccn 0 # s "midi"

outro = do
 d1 $ degradeBy 0.7 $ slow 2 $ s "tabla" # n (irand 4) # gain 0.7 # room 0.95 # size 0.9 # speed 0.5
 d2 $ degradeBy 0.8 $ s "glitch" # crush 12 # gain 0.5
 d3 $ s "space" # gain 0.4 # room 0.5 # size 0.5 # speed 0.5
 d4 $ silence
 d5 $ silence
 d8 $ ccv 0 # ccn 0 # s "midi"

stop_it = do
 d1 $ silence
 d2 $ silence
 d3 $ silence
 d4 $ silence
 d5 $ silence
 d8 $ silence

intro
buildup
breakdown
beatdrop
outro
stop_it
ccActual = [0,0,0,0,0,0,0,0]
whichVisual = 0
visuals = [
  ()=>{noise(2,0.1).color(0.2,0.1,0.5).modulate(osc(4,0.01,0.5),0.2).scale(1,innerHeight/innerWidth).add(src(o0).scale(1.005).brightness(-0.02),0.92).out(o0)},
  ()=>{shape(()=>Math.floor(Math.sin(time)*4+5),0.3,0.02).scale(1,innerHeight/innerWidth).color(0.8,0.2,1).modulate(osc(20,0.05,2),0.4).rotate(()=>Math.sin(time*0.5)*3).add(src(o1).scale(0.99),0.85).out(o1);src(o1).blend(o0,0.3).out(o0)},
  ()=>{osc(60,0.1,3).color(1.5,0.2,0.8).pixelate(()=>Math.floor(Math.random()*32+4),()=>Math.floor(Math.random()*32+4)).modulate(noise(8,1.2),0.5).diff(src(o0).scale(1.005)).add(src(o0).brightness(-0.3),0.7).out(o0)},
  ()=>{noise(()=>Math.sin(time)*8+10,0.4).color(2,0.5,1.5).modulate(osc(30,0.2,1).rotate(()=>time*0.3),0.6).scale(1,innerHeight/innerWidth).add(src(o0).scale(1.008).rotate(0.02).color(1.5,0.8,2),0.92).out(o0)}
]
visuals[0]()
update = ()=>{
  if(whichVisual != ccActual[0]){
    whichVisual = ccActual[0]
    visuals[whichVisual]()
  }
}
navigator.requestMIDIAccess().then(midiAccess=>{
  midiAccess.inputs.forEach(input=>{
    input.onmidimessage=msg=>{
      const [status,cc,value]=msg.data
      if((status&0xf0)===0xb0){
        ccActual[cc]=Math.round(value/127*3)
      }
    }
  })
  console.log('MIDI connected!')
}).catch(err=>console.log('MIDI error:',err))

In my Tidal code (composition.tidal), I grouped the audio patterns into named blocks like intro, melody, and transition. This made it easy to perform the piece by triggering different parts, moving from a calm beginning to a rhythmic middle section, and finishing with a bright ending. To connect the audio and visuals, Tidal sends MIDI signals to my Hydra code (composition.js). Hydra uses these signals to control a sequence of four background videos and apply visual effects that react directly to the beat. For example, the kick drum changes the video’s contrast, while other musical elements control effects like rotation, pixelation, and scaling. This setup ensures that all the visual changes are perfectly synchronized with the music. Though I synced the visuals with the tidal sound via ccns, for the background chords I used timing in the .js file, similar to what I did in the .tidal for these chords, customizing the chord times with sustain.

Tidal Code:

setcps (0.5)


let intro = do
      resetCycles
      d9 $ ccv "127"
        # ccn "2"
        # s "midi"
      d1 $ slow 16 $ s "supersquare"
        <| n "c'min7 f'min7 bf'maj7 g'dom7 c'min7 f'min7 bf'maj7 g4'dom7"
        # lpf 400
        # gain 0.9
        # sustain 4

let bd = do
      d2 $ struct "t f f t@t f f t" $ s "808bd*4"
        # gain 2
        # room 0.8
      d8 $ struct "t f f t@t f f t" $ ccv "127 0 127 0"
        # ccn "1"
        # s "midi"

let bd2 = do
      d2 $ struct "t f f t@t f f t" $ s "808bd*4"
        # gain 2
        # room 0.5
      d8 $ struct "t f f t@t f f t" $ ccv "127 0 127 0"
        # ccn "1"
        # s "midi"

let melody = do
      d3 $ s "simplesine"
        >| note ((scale "major" "<[[0 5 10 7] [0 5 10 -5]] [[0 0 5 ~ 10 ~ 7 ~] [0 5 ~ -5]]>"))
        # room 0.6
        #gain 0.9
      d10 $ struct "t ~ t ~ t ~ t ~" $ ccv "127 0 127 0"
        # ccn "3"
        # s "midi"

let shimmer = do
      d4 $ s "simplesine"
        >| note ((scale "major" "<[12 14 15 17] [12 ~ 15 ~]>"))
        # gain 0.8
        # room 0.8
        # lpf 2000

let melody2 = do
      d5 $ s "simplesine"
        >| note ((scale "major" "<[[3 7 5 10] [3 ~ 7 ~]] [[5 3 7 ~ 5 ~] [7 5 ~ 3]]>"))
        # room 0.5
        # gain 0.9
        # delay 0.2
        # delaytime 0.25

let rise = do
      d6 $ qtrigger $ filterWhen (>=0) $ 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)

let stop = do
      d1 silence
      d2 silence
      d3 silence
      d4 silence
      d5 silence
      d6 silence
      d7 silence
      d8 silence
      d9 $ ccv "0"
        # ccn "2"
        # s "midi"
      d10 $ ccv "0"
        # ccn "3"
        # s "midi"
      d11 $ ccv "0"
        # ccn "4"
        # s "midi"
      d12 $ ccv "0"
        # ccn "5"
        # s "midi"

let pauseStart = do
      d1 silence
      d2 silence
      d3 silence
      d8 silence
      d9 $ ccv "0"
        # ccn "2"
        # s "midi"
      d10 $ ccv "0"
        # ccn "3"
        # s "midi"

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 "crash*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 "supersquare" # 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")
        ]

let mid = do
      d1 $ stack
        [ fast 2 $ s "glitch*4"
            # gain 0.7
            # room 0.2
        , fast 2 $ s "bass 808bd 808bd <bass realclaps:3>"
            # gain 0.8
            # room 0.2
        , fast 2 $ s "hh*8"
            # gain 0.75
        ]
      d2 $ slow 2 $ s "arpy"
        <| up "c'min7(5,8) ~ f'maj5(5,8,3) bf4'min7(3,8)"
        # room 0.45
        # gain 0.9
      d3 $ slow 2 $ s "feelfx"
        <| up "c'min7(5,8) ~ f'maj5(5,8,3) bf4'min7(3,8)"
        # hpf 800
        # room 0.6
        # gain 0.45
      d4 silence
      d5 silence
      d6 silence
      d7 silence
      d8 silence
      d9 $ ccv "0"
        # ccn "2"
        # s "midi"
      d10 $ ccv "0"
        # ccn "3"
        # s "midi"
      d11 $ ccv "0"
        # ccn "4"
        # s "midi"
      d12 $ ccv "127"
        # ccn "5"
        # s "midi"

let transitionAndPause = do
      transition
      d1 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0, 2, slow 16 $ s "supersquare"
            <| n "c'min7 f'min7 bf'maj7 g'dom7 c'min7 f'min7 bf'maj7 g4'dom7"
            # lpf 400 # gain 0.9 # sustain 4)
        , (2, 64, silence)
        ]
      d2 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0, 2, struct "t f f t@t f f t" $ s "808bd*4" # gain 2 # room 0.8)
        , (2, 64, silence)
        ]
      d3 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0, 2, s "simplesine"
            >| note ((scale "major" "<[[0 5 10 7] [0 5 10 -5]] [[0 0 5 ~ 10 ~ 7 ~] [0 5 ~ -5]]>"))
            # room 0.6 # gain 0.9)
        , (2, 64, silence)
        ]
      d8 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0, 2, struct "t f f t@t f f t" $ ccv "127 0 127 0" # ccn "1" # s "midi")
        , (2, 64, ccv "0" # ccn "1" # s "midi")
        ]
      d9 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0, 2, ccv "127" # ccn "2" # s "midi")
        , (2, 64, ccv "0" # ccn "2" # s "midi")
        ]
      d10 $ qtrigger $ filterWhen (>=0) $ seqP
        [ (0, 2, struct "t ~ t ~ t ~ t ~" $ ccv "127 0 127 0" # ccn "3" # s "midi")
        , (2, 64, ccv "0" # ccn "3" # s "midi")
        ]

--start
intro
bd
melody

--transition
transitionAndPause
mid

stop

 --final
shimmer
melody2
bd2
intro


d4 silence
d5 silence
d6 silence
d7 silence
d8 silence
d3 silence
d2 silence
d9 $ ccv "0" # ccn "2" # s "midi"
d1 silence

hush

JS Code:

hush()
solid(0,0,0,1).out(o0)


if (typeof ccActual === "undefined") {
  loadScript("/Users/rekas/Documents/NYUAD/SeniorSpring/Livecoding/liveCoding/midi.js")
}


let basePath = "/Users/rekas/Documents/NYUAD/SeniorSpring/Livecoding/vids/"
let videoNames = []
let vids = []
let allLoaded = false
let loadedCount = 0
let whichVid = 0
let switchEverySeconds = 4
let introStartTime = 0
let introRunning = false
let beatEnv = 0
let prevIntroGate = false
let introArmed = false
let initVideos = () => {
  videoNames = [
    basePath + "vid1.mp4",
    basePath + "vid2.mp4",
    basePath + "vid3.mp4",
    basePath + "vid4.mp4"
  ]
  vids = []
  allLoaded = false
  loadedCount = 0
  whichVid = 0
  introStartTime = 0
  introRunning = false
  prevIntroGate = false
  introArmed = false
  beatEnv = 0
  for (let i = 0; i < videoNames.length; i++) {
    vids[i] = document.createElement("video")
    vids[i].autoplay = true
    vids[i].loop = true
    vids[i].muted = true
    vids[i].playsInline = true
    vids[i].crossOrigin = "anonymous"
    vids[i].src = videoNames[i]
    vids[i].addEventListener("loadeddata", function () {
      loadedCount += 1
      vids[i].play().catch(() => {})
      if (loadedCount === videoNames.length) {
        allLoaded = true
      }
    }, false)
  }
  if (vids[0]) {
    s0.init({src: vids[0]})
    vids[0].currentTime = 0
    vids[0].playbackRate = 1
    vids[0].play().catch(() => {})
  }
}
let getCcNorm = (index) => {
  if (typeof ccActual !== "undefined" && Array.isArray(ccActual)) {
    return Math.max(0, Math.min(1, ccActual[index] / 127))
  }
  if (typeof cc !== "undefined" && Array.isArray(cc)) {
    return Math.max(0, Math.min(1, cc[index]))
  }
  return 0
}
let switchToVid = (index, force = false) => {
  let safeIndex = Math.max(0, Math.min(vids.length - 1, index))
  if (!force && safeIndex === whichVid) return
  whichVid = safeIndex
  let nextVid = vids[whichVid]
  if (!nextVid) return
  nextVid.currentTime = 0
  nextVid.playbackRate = 1
  s0.init({src: nextVid})
  nextVid.play().catch(() => {})
}
update = () => {
  if (!vids || vids.length === 0) return
  let introGate = getCcNorm(2) > 0.5
  if (!introGate) {
    introArmed = true
  }
  if (introArmed && introGate && !prevIntroGate) {
    introStartTime = time
    switchToVid(0, true)
  }
  introRunning = introGate
  prevIntroGate = introGate
  //4s per video when intro is on
  if (introRunning) {
    let elapsed = Math.max(0, time - introStartTime)
    let nextIndex = Math.floor(elapsed / switchEverySeconds) % vids.length
    switchToVid(nextIndex)
  }
  beatEnv = Math.max(beatEnv * 0.82, getCcNorm(1))
}
src(s0)
  .blend(src(s0).invert(), () => getCcNorm(1) > 0.55 ? 0.95 : 0)
  .rotate(() => getCcNorm(3) > 0.55 ? 0.12 : 0)
  .scale(() => getCcNorm(4) > 0.55 ? 1.4 : 1)
  .modulate(noise(3), () => getCcNorm(4) > 0.55 ? 0.08 : 0)
  .pixelate(
    () => getCcNorm(5) > 0.55 ? 30 : 2000,
    () => getCcNorm(5) > 0.55 ? 30 : 2000
  )
  .colorama(() => getCcNorm(5) > 0.55 ? 0.04 : 0)
  .contrast(() => 1 + beatEnv * 0.08)
  .out(o0)
initVideos()

I began the composition with a simple drum and snare pattern, initially aiming to come up with an Afrobeat composition. But ended up with something completely different which sort of sounded good to me, so I chose to follow that direction. The structure follows an Intro → A → Rise → B → A → B. The composition is organized using timed sequences and multiple channels to allow me control individual layers. MIDI patterns are used to drive Hydra visuals, but this was quite challenging as my entire visual setup is made of videos. Getting them to sync with the pattern from the midi was, and is still very challenging.

Code snippets:


Hydra visuals

Tidal snippets:

Demo Video:

Composition structure: A + B + A + B(with slight modification)

I first started my composition in Tidal by gathering all the class examples and sample patterns that I liked. I experimented by changing the beats and playing around with different speeds. After settling on two parts, A and B, that I liked, I organized them into a composition with an A + B + A + B structure. Because I wanted a clear sense of beginning and ending, I kept both the opening and closing sections simple, with minimal beats and visuals, so the composition could build up and then gradually fade out.

For the visuals, I initially used a blob slowly flowing on the screen. When I synced it with my sound by adding a glitch effect to match the glitch sound, it felt too boring, and there were no significant differences between parts A and B. Therefore, I added a new section where more chaotic and unexpected visuals appear in part B.

Code Snippets:

shape(200, 0.4, 0.02)
  .repeat(() => cc[3] + 1, () => cc[3] + 1)
  .modulate(osc(6, 0.1, 1.5), 0.2)
  .modulateScale(osc(3,0.5),-0.6)
  .modulate(noise(() => cc[1], 0.2), 0.3)
  .color(
    () => Math.sin(time) * 0.5 + 0.5,
    0.4,
    1
  )
  .modulate(
    noise(50, 0.5),
    () => cc[0] + cc[0] * Math.sin(time*8)
  )
  .add(o0, () => cc[3])
  .scale(0.9)
  .out()
start = do
  d1 $ slow 2 $ s "house(4,8)" # gain 0.9
  d2 $ ccv "0 127" # ccn 1 # s "midi"
  d3 $ s "chin"   <| n (run 4) # gain 2
  d4 $ s "click"  <| n (run 4)
  d5 $ s "bubble" <| n (run 8)
  d12 $ ccv "0" # ccn 3 # s "midi"

start

back_drop_with_glitch = do
  d6 $
    s "supersnare(9,16)?"
      # cps (range 0.45 0.5 $ fast 2 tri)
      # sustain (range 0.05 0.25 $ slow 0.2 sine)
      # djf (range 0.4 0.9 $ slow 32 tri)
      # pan (range 0.2 0.8 $ slow 0.3 sine)
      # gain (range 0.3 0.7 $ fast 9.2 sine)
      # amp 0.9
  d7 $
    every 8 rev $
      s "bd*8 sn*8"
        # n "[1 ~ ~ ~ 1 ~ ~ ~] [[2 0?] ~ ~ [~ 0?]]"
        # amp "0.02 0.02"
        # shape "0.4 0.5"
  d8 $
    every 4 rev $
      s "[sostoms? ~ ~ sostoms?]*2"
        # sustain (range 0.02 0.1 $ slow 0.2 sine)
        # freq 420
        # shape (range 0.25 0.7 $ slow 0.43 sine)
        # voice (range 0.25 0.5 $ slow 0.3 sine)
        # delay 0.1
        # delayt 0.4
        # delayfb 0.5
        # amp 0.2
  d9 $
    s "[~ superhat]*4"
      # accelerate 1.5
      # nudge 0.02
      # amp 0.1
  d10 $ s "glitch" <| n (run 8)
  d11 $ ccv "0 0 0 0 0 0 0 10" # ccn 0 # s "midi"

back_drop_with_glitch

another_beat = do
  -- d1 $ s "ul" # n (run 16)
  d5 $ s "supersnare(9,16)?" # cps (range 0.5 0.45 $ fast 2 tri ) # sustain (range 0.05 0.25 $ slow 0.2 sine )  # djf (range 0.4 0.9 $ slow 32 tri )  # pan (range 0.2 0.8 $ slow 0.3 sine )
  d7 $ fast 2 $ every 8 rev $ s "bd*8 sn*8" # n "[1 ~ ~ ~ 1 ~ ~ ~] [[2 0?] ~ ~ [~ 0?]]" # amp "0.02 0.02" # shape "0.4 0.5"
  d7 $ fast 2 $ every 4 rev $ s "[sostoms? ~ ~ sostoms?]*2" # sustain (range 0.1 0.02 $ slow 0.2 sine ) # freq 420 # shape (range 00.7 0.25 $ slow 0.43 sine ) # voice (range 00.5 0.25 $ slow 0.3 sine ) # delay 0.1 # delayt 0.4 # delayfb 0.5
  d8 $ s "[~ superhat]*4" # accelerate 1.5 # nudge 0.02
  d9 $ sound "bd:13 [~ bd] sd:2 bd:13" # krush "4"
  d12 $ slow 2 $ s "arpy" <| up "c'maj(3,8) f'maj(3,8) ef'maj(3,8,1) bf4'maj(3,8)"
  d1 $ ccv "0 0 0 0 0 127" # ccn 3 # s "midi"
  d4 $ fast 2 $ s "kurt" <| n (run 1)
  
another_beat

do
  start
  back_drop_with_glitch

beat_silence = do
  start
  d6 silence
  d7 silence
  d8 silence
  d9 silence
  d10 silence

beat_silence

hush