Strudelify
A Groovy Kind of Love cover art

A Groovy Kind of Love

Phil Collins

KeyA majorTempo73 bpm
0:00/0:00
// A Groovy Kind of Love — Collins Phil
// 73 bpm, 4/4, key A major. Source: midi.
// Generated by strudelify. One cycle = one bar.
// note: Tempo changes preserved in elapsed time; displayed bars use the dominant tempo.
// note: pitch bends are ignored
// note: Full arrangement: all 63 bars on a 16-step grid, each part at one level; ghost notes are separate "_soft" parts. Source detail keeps the original performance.
setcpm(73/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 · acoustic bass · "Bass"
const bass = note("<~@30 A B A@4 C D E@2 A@4 C D F G A@5 H I J I J I J K@2 ~>".pickRestart({
  A: "a1", B: "a1@3 a1", C: "b1", D: "c#2", E: "d2/2", F: "d2@3 d2", G: "e2@2 e2!2", H: "a1@15 ~", I: "f#1@3 f#1",
  J: "e1", K: "[~ a1@31]/2",
})).s("gm_acoustic_bass").gain(0.45)

// bass · piano · "Piano bass"
const bass_2 = note(`<
  ~@2 A@2 B C B D@2 B E F G H B C@2 I B@3 C J F G H D C K B E L E@4 F M N@2 E@4 F O P Q E@5 R S T S U S V W@2 ~
>`.pickRestart({
  A: "[g2@7 g2@8 ~]/2", B: "g2@7 g2", C: "g2", D: "g2@14 ~ g2", E: "a2", F: "b2", G: "c3", H: "d3", I: "d2",
  J: "a2@7 a2", K: "g2@15 g2", L: "a2@3 a2", M: "c#3@7 c#3", N: "d3/2", O: "c#3", P: "d3@3 d3", Q: "e3@2 e3!2",
  R: "a2@15 ~", S: "[f#2,f#3]@3 [f#2,f#3]", T: "e3@6 ~ e3, e2", U: "[e2,e3]@3 [e2,e3]", V: "[e2,e3]",
  W: "[~ [a2,e3]@31]/2", // A5
})).s("gm_piano").gain(0.4).pan(0.3)

// chords · piano · "Piano treble"
const piano = note(`<
  ~@2 A B A C D E F G H I J K L B A C L M F N O P Q R S T S U V W X Y Z AA AB AC AD@2 V Y Z AE AF AG AH AI AJ Y AK Y AL
  AM AN AO AN AP AQ AR AS@2 ~
>`.pickRestart({
  A: "[d4,g4,b4]@3 [d4,a4]@2 [d4,g4,b4]@3", B: "[d4,f#4,a4]@2 [d4,g4] [d4,f#4,a4]", C: "[d4,f#4,a4]", D: "[d4,g4,b4]!2",
  E: "[d4,f#4,a4]@3 [d4,f#4,a4]@3 [d4,f#4,a4]@2", F: "[d4,g4,b4]@3 [d4,g4,b4]@3 [d4,g4,b4]@2",
  G: "[c4,e4,a4]@2 a4 e4@3 [c4,e4,a4]@4 [c4,e4,a4]@2 [c4,e4,a4]@3 ~", H: "e5@2 ~ e5, [g4,c5], ~@4 d5@3 ~",
  I: "f#5@2 ~ f#5, [a4,d5], ~ e5", J: "[e5,g5] e5 g5 e5, c5", K: "[d5,f#5,a5]@5 [d5,f#5,a5]@3",
  L: "[d4,g4,b4]@3 [d4,a4]@3 [d4,g4,b4]@2", M: "[d4,f#4,a4]@3 [d4,f#4,a4]@3 [d4,f#4,a4]!2",
  N: "[c4,e4,a4]@6 [c4,e4,a4]@6 [c4,e4,a4]@3 ~", O: "[g4,c5,e5]@3 [g4,c5,e5]@3 [g4,c5,e5]@2",
  P: "[a4,d5,f#5]@6 f#5@3 ~ e5@2 [a4,d5,f#5]@4, ~@3 [a4,d5]@3 ~@2", Q: "[c5,e5,g5]@3 [c5,e5,g5]@3 [c5,e5,g5]@2",
  R: "[a4,d5,f#5]@15 ~", S: "[d4,g4,b4]@6 [d4,a4]@3 ~ [d4,g4,b4]@6", T: "[d4,f#4,a4]@3 [d4,g4]@3 [d4,f#4,a4]@2",
  U: "[d4,f#4,a4]@15 ~", V: "[e4,a4,c#5]@3 [e4,b4]@3 [e4,a4,c#5]@2", W: "[e4,g#4,b4]@11 ~ [e4,g#4,b4]@4",
  X: "[e4,a4,c#5]@6 [e4,a4,c#5]@6 [e4,a4,c#5]@3 ~", Y: "[e4,g#4,b4]@3 [e4,g#4,b4]@3 [e4,g#4,b4]@2",
  Z: "[e4,a4,c#5]@3 [e4,a4,c#5]@3 [e4,a4,c#5]@2", AA: "[d4,f#4,b4]@6 [d4,f#4,b4]@6 [d4,f#4,b4]@3 ~",
  AB: "[f#4,a4,d5]@6 [f#4,a4,d5]@6 [f#4,a4,d5]@3 ~", AC: "[g#4,b4,e5]@6 [g#4,b4,e5]@6 [g#4,b4,e5]@3 ~",
  AD: "[f#5@7 ~ a5@4 f#5@6 a5@2 f#5@4 a5@7 ~, [a4,d5]@31 ~]/2", AE: "[d4,f#4,b4]",
  AF: "[f#4,a4,d5]@7 ~ [f#4,a4,d5]@4 [a4,d5,f#5]@3 ~", // D
  AG: "[b4,e5,g#5]@6 [b4,e5,g#5]@2 [g#4,b4,e5]@3 ~ [g#4,b4,e5]@3 ~", AH: "[f#4,a4,d5]@15 ~",
  AI: "[g#4,b4,e5]@3 ~ [b4,e5,g#5]@4 [g#4,b4,e5]@3 ~ [g#4,b4,e5]@4", // E
  AJ: "c#5@2 ~ d5 c#5@2 [e4,b4]@3 ~ [e4,a4,c#5]@3 ~ [e4,a4,c#5]@2, [e4,a4]@3 ~@5", // E5 A A5
  AK: "[e4,a4,c#5]@3 [e4,b4]@2 [e4,a4,c#5]@3", AL: "[e4,a4,c#5]@6 [e4,b4]@3 ~ [e4,a4,c#5]@6",
  AM: "[e4,g#4,b4]@6 [e4,g#4,b4]@5 ~ [e4,g#4,b4]@4", AN: "[d4,e4,a4]@11 ~ [d4,e4,a4]@4", AO: "[d4,e4,a4]@15 ~",
  AP: "[d4,e4,a4]@11 ~ [d4,e4,a4]@3 ~", AQ: "[d4,e4,a4]@3 [d4,e4,a4]", AR: "[d4,e4,a4]", AS: "[~ [a3,c#4,e4]@31]/2",
})).s("gm_piano").gain(0.4).pan(0.7)

// chords · string ensemble 1 · "Strings"
const string_ensemble_1 = note("<~@30 A B C D E F G H I@2 J K L M N O P O Q O R S T U V@4 W X Y@2 ~>".pickRestart({
  A: "c#4@3 b3@3 c#4@2", B: "~@4 a4 b4 c#5 d5", C: "e5@4 d5 c#5 b4 a4", D: "g#4@4 a4 g#4 f#4 g#4",
  E: "a4@4 b4 a4 g#4 a4", F: "b4@7 ~ b5@2 c#6@2 d6@2 e6@2", G: "f#6@4 e6 d6 c#6 b5", H: "e6@2 e6@2 d6 c#6 b5 c#6",
  I: "[a5@31 ~]/2", J: "e5 d5 e5 d5 e5@4, [e4,a4,c#5]", K: "b4 a4 b4 a4 b4@4, [e4,g#4]",
  L: "e5 d5 e5 d5 [a4,c#5,e5]@2 [c#5,e5,a5]@2, [e4,a4,c#5] ~", M: "[b4,d5,f#5]", N: "[a4,d5,f#5]", O: "[b4,e5,g#5]",
  P: "[d5,f#5,a5]", Q: "c#5@3 d5 c#5@2 b4@2 [a4,c#5,e5]@4 [c#5,e5,a5]@4, [e4,a4] ~", R: "[c#5,e5,a5]@3 [c#5,e5,a5]!5",
  S: "[g#4,b4,e5]", T: "~@3 [c#5,e5,a5]!5", U: "[g#4,b4,e5]@15 ~", V: "[[d5,e5,a5]@63 ~]/4",
  W: "~ a5 g#5 e5 a5 g#5 e5!2", X: "e5", Y: "[~ [a3,e4,a4,c#5,e5]@31]/2",
})).s("gm_string_ensemble_1").gain(0.45)

// chords · string ensemble 2 · "Strings"
const string_ensemble_2 = note("<~@18 A B A C D E F G A B A B ~ H ~@2 I J K L M@2 ~@3 N ~@14 O P ~@3>".pickRestart({
  A: "[g3,b3,d4]", B: "[f#3,a3,d4]", C: "[a3,c4,e4]", D: "[g3,c4,e4]", E: "[a3,d4,f#4]", F: "[c4,e4,g4]",
  G: "[d4,f#4,a4]@15 ~", H: "[g#3,b3]@15 ~", I: "[a3,c#4]@15 ~",
  J: "a3!2 b3 c#4 [b3,d4] c#4 [b3,d4] [a3,e4], d4@5 ~@11", K: "f#4@7 ~ g#4@2 f#4@2 e4@2 d4@2, b3@15 ~",
  L: "g#4@2 g#4@2 f#4 e4 d4 a4", M: "[[a4,d5]@15 ~]/2", N: "~ a3 b3 c#4 d4 c#4 b3 f#3", O: "~ a4 g#4 e4 a4 g#4 e4!2",
  P: "e4",
})).s("gm_string_ensemble_2").gain(0.3).pan(0.1)

// other · string ensemble 1 · "Strings"
const string_ensemble_1_2 = note("<~@30 A B ~@2 C D E F G@2 ~@3 H ~@8 I J ~@4 K L@2 ~@2>".pickRestart({
  A: "[e3,a3]", B: "[g#3,b3]", C: "[a3,c#4]", D: "[a3,d4]@3 ~@5", E: "f#5@4 g#5 f#5 e5 d5",
  F: "g#5@2 g#5@2 f#5 e5 d5 a5", G: "a4/2", H: "~ a3 b3 c#4 d4 c#4 b3 f#3", I: "~@3 a6!5", J: "e6@15 ~",
  K: "~ a4 g#4 e4 a4 g#4 e4!2", L: "[~ e4@17 ~@14]/2",
})).s("gm_string_ensemble_1").gain(0.4).pan(0.9)

// other · string ensemble 2 · "Strings"
const string_ensemble_2_2 = note("<~@35 A B C D@2 ~@12 E F ~@9>".pickRestart({
  A: "~@4 [b4,b5] [c#5,c#6] [d5,d6] [e5,e6]", B: "[f#5,f#6]@4 [e5,e6] [d5,d6] [c#5,c#6] [b4,b5]",
  C: "[e5,e6]@2 [e5,e6]@2 [d5,d6] [c#5,c#6] [b4,b5] [c#5,c#6]", D: "[a4,a5]/2", E: "~@3 a6!5", F: "e6@15 ~",
})).s("gm_string_ensemble_2").gain(0.4)

// drums · kick
const kick = s("bd").struct("<~@30 x!30 ~@3>").gain(0.45)

// drums · snare
const snare = s("sd").struct("<~@30 [~ x ~ x]!30 ~@3>").gain(0.45)

// drums · hihat
const hihat = s("hh").struct("<[x!2] [x!4] ~@16 [x ~@2 x ~@4]!12 [x ~@2 x ~@2 x ~]!30 ~@3>").gain(0.45)

// drums · crash
const crash = s("cr").struct("<~@60 [~ x!15] [x!13 ~@3] ~>").gain(0.2)

// drums · crash · soft notes
const crash_soft = s("cr").struct("<~@61 [~@13 x!3] [x!2 ~@14]>").gain(0.1)

// drums · tambourine
const tambourine = s("tb").struct(`<
  ~@18
  [~@4 x!5 ~@3 x!4]
  [x ~@3 x!5 ~@3 x!4]!8
  [x!2 ~@2 x!6 ~@2 x!4]!32
  [x!2 ~@2 x!6 ~@2 x ~ x!2]
  [x!3 ~@13]
  ~@2
>`).gain(0.2)

// drums · tambourine · soft notes
const tambourine_soft = s("tb").struct(`<
  ~@18
  [~@9 x!3 ~@4]
  [~ x!3 ~@5 x!3 ~@4]!8
  [~@2 x!2 ~@6 x!2 ~@4]!33
  [~@3 x!2 ~@11]
  ~@2
>`).gain(0.05)

// drums · congas
const congas = s("conga:13").struct(`<
  ~@30 A B A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A C ~@3
>`.pickRestart({
  A: "~@7 x", B: "~ x ~ x ~@4", C: "~ x ~@6",
})).gain(1.11)

// drums · congas
const congas_2 = s("conga:18").struct(`<
  ~@30 A B A C A C A C A C A C A C A C A C A C A C A C A C A C A D ~@3
>`.pickRestart({
  A: "~@5 x ~@2", B: "~@4 x ~@9 x!2", C: "~@14 x!2", D: "~@2 x!2 ~@4",
})).gain(1.11)

stack(
  bass, bass_2, piano, string_ensemble_1, string_ensemble_2, string_ensemble_1_2, string_ensemble_2_2, kick, snare,
  hihat, crash, crash_soft, tambourine, tambourine_soft, congas, congas_2
)

More by Phil Collins