Strudelify

A Good Heart

Feargal Sharkey

KeyB♭ majorTempo110 bpm
0:00/0:00
// A Good Heart — Feargal Sharkey
// 110 bpm, 4/4, key A# major. Source: midi.
// Generated by strudelify. One cycle = one bar.
// note: pitch bends are ignored
// note: Full arrangement: all 123 bars on a 16-step grid, each part at one level; ghost notes are separate "_soft" parts. Source detail keeps the original performance.
setcpm(110/4)

// Notation: c3@3 lasts 3 steps · ~ is a rest · [c3,e3] is a chord · "a, b" plays two voices at once · [...]/2 spreads a riff over 2 bars.
// A part's distinct bars are riffs (A, B, C...) played in order: edit a riff to change every repeat.

// bass · electric bass finger · "FINGERDBAS"
const bass = note(`<
  ~ A@2 B C A@2 B D E F G H I J K L M N O P Q N R S T U V W X U Y Z AA@2 E F G H I J K L M N O P Q N R AB T U V W X U Y
  Z AA@2 N O P Q N R AB T E F G H I J K L M N O P Q N R AB T U V W X U Y Z AA@2 U V W X U Y Z AA AC AD@2 AA@2 AD@2 AA@2
  AD@2 AA@2 AD@2 AA@2 AD AE ~
>`.pickRestart({
  A: "bb1@2 g1 f1 bb1@2 g1 f1 bb1@2 g1 f1 bb1@2 g1 f1", B: "g1@2 f1 d1 g1@2 f1 d1 g1@2 f1 d1 g1@2 f1 d1",
  C: "g1@2 f1 d1 g1@2 f1 d1 g1@2 f1 d1 f1@2 g1 c2", D: "g1@2 f1 d1 g1@2 f1 d1 g1@2 bb1@2 g1@2 f1@2",
  E: "bb1 ~@2 bb1 ~@2 g1 ~ g1 ~@3 g1@3 ~", F: "f1@2 ~ f1 ~@2 bb1 ~ bb1 ~@3 bb1@2 f1 ~",
  G: "bb1 ~@2 bb1 ~@2 eb2 ~ eb2 ~@3 eb2@2 c2 bb1", H: "bb1 ~@2 bb1 ~@2 f1 ~ f1 ~@2 f1 f1@2 g1 f1",
  I: "bb1 ~@2 bb1 ~@2 g1 ~ g1 ~@2 f1 g1@2 f1 g1", J: "f1 ~@2 f1 ~@2 f1 ~ bb1 ~ g1 f1 bb1@2 g1 f1",
  K: "bb1 ~@2 bb1 ~@2 f1 ~ f1 ~ f1!3 ~ f1!2", L: "eb1 ~@2 eb1 ~@2 eb1 ~@3 eb1 eb1@2 ~ eb1!2",
  M: "eb2 ~ eb2!3 ~@2 eb2!2 ~ eb2!3 ~ eb2!2", N: "eb1@2 eb2 bb1 eb1@2 eb2 bb1 eb1@2 c2 bb1 eb1 ~ c2 bb1",
  O: "eb1@2 eb2 bb1 eb1@2 ~ bb1 eb1@2 c2 bb1 eb1@2 c2 bb1, ~@3 eb2 ~@4", P: "bb1 ~ bb1!3 ~ bb1!2 g1@2 bb1!2 g1@2 bb1!2",
  Q: "f1@2 a1 c2 f1@2 a1 c2 bb1 ~ g1 f1 bb1 ~ g1 f1", R: "eb1@2 eb2 bb1 eb1@2 eb2 bb1 eb1@2 c2 bb1 eb1@2 c2 bb1",
  S: "f2 c2 f1!2 ~@2 f1 ~ f1@4 ~@4", T: "f1@2 ~ f1 ~@2 f1 ~ f2 ~ f2!6", U: "bb1 ~@2 bb1 ~@2 f1 ~ f1 ~ f1!3 ~ f1 gb1",
  V: "g1 ~@2 g1 ~@2 eb2 ~ eb2 ~ eb2!3 ~ c2 bb1", W: "bb1 ~@2 bb1 ~@2 eb2 ~ eb2 ~ eb2!4 c2 bb1",
  X: "bb1 ~@2 bb1 ~@2 f1 ~ f1 ~ f2 c2 f1 ~ f2 c2", Y: "g1 ~@2 g1 ~@2 eb2 ~ eb2 ~ eb2 c2 bb1 ~ eb2 c2",
  Z: "bb1 ~@2 bb1 ~@2 g2 f2 f1 ~ f1!3 ~ f1!2", AA: "eb2 ~@2 eb2 ~@2 eb2 ~ eb2 ~ eb2!3 ~ eb2!2",
  AB: "f2@2 [f1,c2] f1 ~@2 f1 ~ f1@4 ~@4", AC: "f2 ~@2 f2 ~@2 f2 ~ f2 ~ f2!3 ~ f2!2",
  AD: "bb1 ~@2 bb1 ~@2 bb1 ~ bb1 ~ bb1!3 ~ bb1!2", AE: "bb1 ~@2 bb1 ~@2 bb1 ~ bb1 ~ bb1!3 ~ bb1 ~",
})).s("gm_electric_bass_finger").gain(0.48)

// other · distortion guitar · "DISTORTION"
const distortion_guitar = note("<~@60 A@2 B C D E F@2 G ~@54>".pickRestart({
  A: "[~@16 g5@15 ~, ~@15 bb4@2 ~@15]/2", B: "g5@2 eb5@10 ~@2 bb4 ~", C: "d5@12 ~@2 f5 ~", D: "bb5@12 ~@2 eb5 ~",
  E: "g5@6 g5@4 eb5@2 ~@2 eb4 ~", F: "[g4@6 eb4@6 f4@17 ~@3]/2", G: "d5 ~@2 eb5 ~@2 f5@9 ~",
})).s("gm_distortion_guitar").gain(0.5).pan(0.3)

// chords · piano · "HONKY TONK"
const piano = note(`<
  ~ A@2 B@2 A@2 C@2 ~@9 D@2 E F G@2 H@2 ~@18 D@2 E F G@2 H@2 ~@9 D@2 E F G@2 H@2 ~@9 D@2 E F G@2 H@2 ~@20 I J K@2 L M
  N@2 I J K@2 L M N@2 ~
>`.pickRestart({
  A: "[f4@23 ~ c5@4 bb4@4]/2", B: "[c4@3 bb3@12 ~]/2", C: "[[c4,g4]@3 [bb3,f4]@12 ~]/2",
  D: "[[bb3,eb4,ab4]@6 [eb3,bb3,eb4,g4]@10 [eb3,bb3,eb4,ab4]@5 ~ [eb3,bb3,eb4,g4]@9 ~, eb2@29 ~@3, eb3 ~@7]/2", // Ebsus4 Eb Ebsus4 Eb
  E: "[bb2,bb3,d4,f4]@3 [g2,d4]@5, ~@3 [g3,bb3]@4 ~", F: "[f2,f3,a3,c4]@6 [bb2,d4]@9 ~, ~@6 [f3,bb3]@7 ~@3",
  G: "[[eb2,eb3,bb3,eb4,ab4]@6 [bb3,eb4,g4]@9 ~ [eb2,ab4]@6 [eb3,bb3,eb4,g4]@9 ~, ~@6 eb3@15 ~@11, ~@16 [bb3,eb4]@5 ~@11]/2", // Ebsus4 Eb Ab5 Eb Eb5
  H: "[[f2,a3,c4,f4]@31 ~]/2", I: "[eb3,bb3,eb4,ab4]@3 [eb3,bb3,eb4,g4]@12 ~",
  J: "[eb3,bb3,eb4,ab4]@3 ~ eb3@11 ~, ~@3 [bb3,g4]@12 ~, ~@3 eb4@10 ~@3", // Ebsus4 Eb
  K: "[d4@6 c4@10 bb2@15 ~, [bb3,f4]@15 ~, bb2@15 ~ d4@13 ~@3]/2", L: "ab4@3 ~ eb2@12, [eb3,bb3,eb4]@15 ~, ~@3 g4@12 ~",
  M: "ab4@2 [eb2,g4]@5 ~, [eb3,bb3]@15 ~, eb4@13 ~@3", // Eb Eb5
  N: "[~@4 bb3 ~@17 d4@7 ~@3, f4@29 ~@3, c4@6 bb3@25 ~, ~ bb2@29 ~@2, ~@3 d4@5 c4@6 ~@2]/2",
})).s("gm_piano").gain(0.48).pan(0.3)

// chords · lead 2 sawtooth · "SAW WAVE"
const lead_2_sawtooth = note(`<
  ~ A@2 B@2 A@2 B@2 C D E F C D G H@3 I C D H I J@2 G K L G@2 K G H@2 C D E F C D G H@3 I C D H I J@2 G K L G@2 K G H@3
  I C D H I J@2 C D E F C D G H@3 I C D H I J@2 ~@9 G K L G@2 K G H J A@2 M@2 A@2 M@2 A@2 M@2 A@2 M@2 A N ~
>`.pickRestart({
  A: "[f3,bb3,d4]!16", B: "[f3,g3,c4]!16", C: "[f3,bb3,d4]!8 [g3,bb3,d4]!8", D: "[f3,a3,c4]!6 [f3,bb3,d4]!10",
  E: "[f3,bb3,d4]!6 [g3,bb3,eb4]!10", F: "[f3,bb3,d4]!6 [f3,a3,c4]!10", G: "[f3,bb3,d4]!8 [f3,a3,c4]!8",
  H: "[g3,bb3,eb4]!16", I: "[ab3,c4,f4]!6 [g3,bb3,eb4]!10", J: "[a3,c4,f4]!16", K: "[g3,bb3,d4]!8 [g3,bb3,eb4]!8",
  L: "[f3,bb3,d4]!8 [g3,bb3,eb4]!8", M: "[c4,f4,ab4]!3 [bb3,eb4,g4]!13", N: "[f3,bb3,d4]!15 ~",
})).s("gm_lead_2_sawtooth").gain(0.15).pan(0.9)

// chords · pad halo · "HALO PAD"
const pad_halo = note(`<
  ~ A@2 B@2 A@2 C@2 D E F G H I J K@2 L M N O P Q R@2 J S T U V S W K@2 D E F G H I J K@2 L M N O P Q R@2 J S T U V S W
  K@2 L M N O P Q R@2 D E F G H I J K@2 L M N O P Q R@2 ~@9 J S T U V S W X Y A@2 Z AA AB@2 Z AA AB@2 Z AA AB@2 Z AA
  AC@2 ~
>`.pickRestart({
  A: "[[f3,bb3,d4]@31 ~]/2", B: "[f3,g3,c4]/2", C: "[[f3,g3,c4]@31 ~]/2", D: "~@8 g3@7 ~, [f3,bb3,d4]@15 ~",
  E: "[a3,c4]@6 [f3,d4]@9 ~, f3@5 ~ bb3@7 ~@3", F: "[f3,bb3,d4]@6 [g3,bb3,eb4]@9 ~",
  G: "[bb3,d4]@3 [a3,c4]@4 ~, f3@7 ~", H: "f3@5 ~ g3@9 ~, [bb3,d4]@15 ~", I: "[a3,c4]@6 [bb3,d4]@9 ~, f3@15 ~",
  J: "[bb3,d4]@8 [a3,c4]@7 ~, f3@15 ~", K: "[g3,bb3,eb4]/2", L: "ab4@6 g4@9 ~, [bb3,eb4]@15 ~",
  M: "ab4@3 g4@4 ~, [bb3,eb4]@7 ~", N: "[bb3,d4,f4]@6 [g3,bb3,d4]@9 ~", O: "[a3,c4]@6 [bb3,d4]@9 ~, f3@7 ~",
  P: "ab4@3 g4@4 ~, [bb3,eb4]@15 ~", Q: "ab4@6 g4@9 ~, bb3@15 ~, eb4@13 ~@3", R: "[[a3,c4,f4]@31 ~]/2",
  S: "d4@8 eb4@7 ~, [g3,bb3]@15 ~", T: "[f3,bb3,d4]@8 [g3,bb3,eb4]@7 ~", U: "[bb3,d4]@7 ~ [a3,c4]@7 ~, f3@15 ~",
  V: "[bb3,d4]@7 ~ [a3,c4]@7 ~, f3@7 ~", W: "[bb3,d4]@7 ~ [a3,c4]@8, f3@15 ~", X: "[g3,bb3,eb4]", Y: "[a3,c4,f4]",
  Z: "ab4@3 g4@12 ~, [bb3,eb4]@15 ~", AA: "ab4@3 g4@11 ~@2, [bb3,eb4]@15 ~", AB: "[bb3,d4,f4]/2",
  AC: "[[bb3,d4], f4@15 ~]/2", // Bb
})).s("gm_pad_halo").gain(0.17).pan(0.2)

// drums · kick
const kick = s("bd").struct("<A B@16 C B@8 D@6 B@2 C B@8 C B@8 D@6 B@2 C B@16 C B@8 D@6 B@2 C D@6 B@21 ~>".pickRestart({
  A: "~@5 x ~@2", B: "x!2", C: "x!2 ~ x!2 ~@3", D: "x ~@2 x!2 ~@3",
})).gain(0.45)

// drums · snare
const snare = s("sd").struct("<A B@16 C B@7 D B@17 C B@7 D B@16 D B@8 C B@7 D B@36 ~>".pickRestart({
  A: "~@3 x", B: "~ x ~ x", C: "~@4 x ~@7 x!2 ~@2", D: "~@4 x ~@6 x!2 ~@3",
})).gain(0.5)

// drums · hihat
const hihat = s("hh").struct(`<
  ~ A@11 B A@4 B A@3 B A@3 C A@12 B A@4 B A@3 B A@3 C A@12 B A@3 C A@3 B A@4 B A@3 B A@3 C A@36 ~
>`.pickRestart({
  A: "x ~ x!3 ~ x ~ x ~ x!3 ~ x ~", B: "x ~ x!3 ~ x ~ x ~ x!3 ~@3", C: "x ~ x!3 ~ x ~ x ~@3 x ~@3",
})).gain(0.35)

// drums · low tom
const low_tom = s("lt").struct("<[~@11 x ~@4] ~@122>").gain(0.45)

// drums · open hat
const open_hat = s("oh").struct(`<
  ~@12 A ~@4 A ~@3 A ~@3 B ~@12 A ~@4 A ~@3 A ~@3 B ~@12 A ~@3 B ~@3 A ~@4 A ~@3 A ~@3 B ~@37
>`.pickRestart({
  A: "~@7 x", B: "~@5 x ~ x",
})).gain(0.45)

// drums · crash
const crash = s("cr").struct(`<
  ~@9 A ~@3 A ~@4 A ~@3 A ~@3 A ~@3 A ~@4 A ~@3 A ~@4 A ~@3 A ~@3 A ~@3 A ~@4 A ~@3 A ~@3 A ~@3 A ~@4 A ~@3 A ~@3 A ~@3
  A ~@4 A ~@3 A ~@23
>`.pickRestart({
  A: "x",
})).gain(0.45)

// drums · tambourine
const tambourine = s("tb").struct(`<
  ~ A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B
  A B@2 A B A B A B A@2 B A B A B A B A B A B A B A B A B A B A B A B A B@2 A B A B A B A@3 B A@3 B A@3 B A@3 B A@3 C ~
>`.pickRestart({
  A: "x!3 ~ x!7 ~ x!4", B: "x!16", C: "x!15 ~",
})).gain(0.25)

// drums · tambourine · soft notes
const tambourine_soft = s("tb").struct(`<
  ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~
  A ~@2 A ~ A ~ A ~ A@2 ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~@2 A ~ A ~ A ~ A@3 ~ A@3 ~ A@3 ~ A@3 ~ A@3 ~@2
>`.pickRestart({
  A: "~@3 x ~@7 x ~@4",
})).gain(0.15)

// drums · cabasa
const cabasa = s("cabasa:4").struct(`<
  ~ A@3 B C A@6 B C A@7 B C A@6 B C A@7 B C A@7 B C A@6 B C A@7 B C A@6 B C A@7 B C A@6 B C A@7 B C A@22 ~
>`.pickRestart({
  A: "~@12 x!3 ~", B: "~@12 x!2 ~@2", C: "~@12 x!2 ~ x",
})).gain(1.51)

// drums · cabasa · soft notes
const cabasa_soft = s("cabasa:4").struct(`<
  ~ A@3 B ~@2 A ~ A@3 B ~@2 A ~@2 A@3 B ~@2 A ~ A@3 B ~@2 A ~@2 A@3 B ~@2 A ~@2 A@3 B ~@2 A ~ A@3 B ~@2 A ~@2 A@3 B ~@2
  A ~ A@3 B ~@2 A ~@2 A@3 B ~@2 A ~ A@3 B ~@2 A ~@2 A@3 B ~@2 A ~@2 A@2 ~@2 A@2 ~@2 A@2 ~@2 A@2 ~@2 A ~@2
>`.pickRestart({
  A: "~@15 x", B: "~@7 x",
})).gain(1.01)

stack(
  bass, distortion_guitar, piano, lead_2_sawtooth, pad_halo, kick, snare, hihat, low_tom, open_hat, crash, tambourine,
  tambourine_soft, cabasa, cabasa_soft
)