setcpm(120 / 4)

const FORM_CYCLES = 22.5

const P1 = (notes) =>
  note(notes)
    .s("pulse")
    .pw(.5)
    .attack(.002)
    .decay(.055)
    .sustain(.2)
    .release(.022)
    .gain(.29)
    .pan(.4)

const P2 = (notes) =>
  note(notes)
    .s("pulse")
    .pw(.125)
    .attack(.002)
    .decay(.038)
    .sustain(.1)
    .release(.018)
    .gain(.17)
    .pan(.6)

const WAVE = (notes) =>
  note(notes)
    .s("triangle")
    .attack(.003)
    .decay(.09)
    .sustain(.34)
    .release(.03)
    .lpf(1050)
    .gain(.32)
    .pan(.5)

const NOISE = (hits, hp, lp, decay, level) =>
  s(hits)
    .hpf(hp)
    .lpf(lp)
    .attack(.001)
    .decay(decay)
    .sustain(0)
    .release(.01)
    .gain(level)
    .pan(.5)

const leadIntro = cat(
  P1("a5 ~ e5 a5 c6 a5 g5 a5 a5 ~ f#5 a5 e5 a5 ~ ~"),
  P1("a5 c6 a5 e6 a5 d6 a5 c6 a5 ~ b5 a5 g5 a5 e5 ~"),
  P1("a5 d6 a5 f#5 a5 e6 a5 g5 a5 c6 a5 e5 a5 d6 ~ a5"),
  P1("a5 b5 a5 g5 a5 e6 a5 f#5 a5 ~ c6 a5 e5 a5 g5 ~")
)

const leadA = cat(
  P1("a5 e5 a5 c6 a5 g5 a5 e5 a5 b5 a5 f#5 a5 e5 a5 c6"),
  P1("a5 f#5 a5 d6 a5 c6 a5 f#5 a5 e6 a5 d6 a5 g5 a5 f#5"),
  P1("a5 g5 a5 d6 a5 b5 a5 f#5 a5 c6 a5 g5 a5 e5 a5 b5"),
  P1("a5 e5 a5 b5 a5 g5 a5 e6 a5 d6 a5 f#5 a5 c6 a5 e5")
)

const leadB = cat(
  P1("a5 a5 e6 a5 g5 a5 c6 a5 a5 f#5 a5 d6 a5 b5 a5 e5"),
  P1("a5 d6 a5 a5 f#5 a5 e6 a5 c6 a5 a5 g5 a5 b5 a5 f#5"),
  P1("a5 e5 a5 a5 b5 a5 f#5 a5 d6 a5 a5 c6 a5 g5 a5 e6"),
  P1("a5 g5 a5 e6 a5 a5 f#5 a5 c6 a5 d6 a5 a5 e5 a5 b5")
)

const leadOutro = cat(
  P1("a5 a5 e6 a5 a5 c6 a5 g5 a5 d6 a5 f#5 a5 e5 a5 c6"),
  P1("a5 e5 a5 b5 a5 g5 a5 e6 a5 d6 a5 f#5 a5 c6 a5 ~")
)

const leadTurn = P1("a5 e6 a5 d6 a5 e5 ~ ~").fast(2)

const gridIntro = cat(
  P2("a3 e4 c4 e4 a3 d4 c4 e4 a3 e4 b3 e4 g3 d4 b3 d4"),
  P2("a3 e4 c4 e4 a3 f#4 c4 e4 a3 e4 b3 e4 d4 a4 f#4 a4"),
  P2("d4 a4 f#4 a4 d4 e4 f#4 a4 d4 a4 c4 a4 e4 b4 g4 b4"),
  P2("e4 b4 g4 b4 e4 f#4 g4 b4 e4 b4 d4 b4 a3 e4 c4 e4")
)

const gridA = cat(
  P2("a3 e4 c4 e4 a3 d4 c4 e4 a3 e4 b3 e4 a3 f#4 c4 e4"),
  P2("d4 a4 f#4 a4 d4 e4 f#4 a4 d4 a4 c4 a4 d4 b4 f#4 a4"),
  P2("g3 d4 b3 d4 g3 e4 b3 d4 g3 d4 a3 d4 g3 f#4 b3 d4"),
  P2("e3 b3 g3 b3 e3 f#4 g3 b3 e3 b3 d4 b3 e3 a3 g3 b3")
)

const gridB = cat(
  P2("a3 c4 e4 c4 a3 e4 b3 e4 a3 d4 e4 d4 a3 f#4 c4 e4"),
  P2("d4 f#4 a4 f#4 d4 a4 e4 a4 d4 c4 a4 c4 d4 b4 f#4 a4"),
  P2("e4 g4 b4 g4 e4 b4 f#4 b4 e4 d4 b4 d4 e4 a4 g4 b4"),
  P2("e4 b4 g4 b4 e4 a4 g4 b4 e4 f#4 b4 f#4 e4 d4 g4 b4")
)

const gridOutro = cat(
  P2("a3 e4 c4 e4 a3 d4 c4 e4 a3 e4 b3 e4 a3 f#4 c4 e4"),
  P2("e3 b3 g3 b3 e3 f#4 g3 b3 e3 b3 d4 b3 e3 a3 g3 b3")
)

const gridTurn = P2("a3 e4 c4 e4 a3 b3 ~ ~").fast(2)

const bassIntro = cat(
  WAVE("a1 ~ a2 e2 a1 ~ g2 e2"),
  WAVE("a1 e2 a2 e2 a1 e2 g2 f#2"),
  WAVE("d2 a2 d3 a2 d2 a2 e2 f#2"),
  WAVE("e2 b2 e3 b2 e2 b2 d3 b2")
)

const bassA = cat(
  WAVE("a1 a2 e2 a2 a1 a2 g2 e2"),
  WAVE("d2 d3 a2 d3 d2 d3 c3 a2"),
  WAVE("g1 g2 d2 g2 g1 g2 f#2 d2"),
  WAVE("e2 e3 b2 e3 e2 b2 d3 e3")
)

const bassB = cat(
  WAVE("a1 e2 a2 c3 a1 e2 g2 a2"),
  WAVE("d2 a2 d3 f#3 d2 a2 c3 d3"),
  WAVE("e2 b2 e3 g3 e2 b2 d3 e3"),
  WAVE("e2 b2 e3 g3 e2 d3 c3 b2")
)

const bassOutro = cat(
  WAVE("a1 e2 a2 e2 a1 e2 g2 a2"),
  WAVE("e2 b2 e3 b2 e2 d3 c3 b2")
)

const bassTurn = WAVE("a1 ~ a2 ~ e2 a1 ~ ~").fast(2)

const noiseMeasure = NOISE(
  "white white white white white white white white",
  "110 6800 1100 7600 110 6800 1800 6200",
  "850 10500 5200 11200 850 10500 7200 9600",
  ".055 .013 .04 .012 .055 .013 .052 .02",
  ".16 .035 .13 .035 .16 .035 .17 .06"
)

const noiseHammer = NOISE(
  "white white white white white white white white",
  "110 7200 950 7200 110 7200 950 5400",
  "900 11000 4300 11000 900 11000 4300 9000",
  ".06 .012 .036 .012 .06 .012 .038 .024",
  ".19 .04 .16 .04 .19 .04 .17 .08"
)

const noiseFill = NOISE(
  "white white white white white white white white",
  "110 7000 1100 7000 110 1600 2500 4000",
  "900 10800 5200 10800 900 6500 8200 10200",
  ".06 .012 .044 .012 .06 .048 .034 .024",
  ".19 .04 .17 .04 .19 .11 .14 .18"
)

const drumsIntro = cat(silence, noiseMeasure, noiseMeasure, noiseFill)
const drumsA = cat(noiseHammer, noiseHammer, noiseMeasure, noiseFill)
const drumsB = cat(noiseHammer, noiseFill, noiseHammer, noiseFill)
const drumsOutro = cat(noiseHammer, noiseFill)

const drumsTurn = NOISE(
  "white ~ white white white white ~ ~",
  "110 7200 1100 7200 110 2800 7200 7200",
  "900 11000 5200 11000 900 8800 11000 11000",
  ".06 .012 .044 .012 .06 .032 .012 .012",
  ".19 .04 .17 .04 .19 .13 .04 .04"
).fast(2)

const pulse1 = arrange(
  [4, leadIntro],
  [8, leadA],
  [8, leadB],
  [2, leadOutro],
  [.5, leadTurn]
)

const pulse2 = arrange(
  [4, gridIntro],
  [8, gridA],
  [8, gridB],
  [2, gridOutro],
  [.5, gridTurn]
)

const wave = arrange(
  [4, bassIntro],
  [8, bassA],
  [8, bassB],
  [2, bassOutro],
  [.5, bassTurn]
)

const noise = arrange(
  [4, drumsIntro],
  [8, drumsA],
  [8, drumsB],
  [2, drumsOutro],
  [.5, drumsTurn]
)

stack(pulse1, pulse2, wave, noise)
  .gain(.96)
  .ribbon(0, FORM_CYCLES)
