Rebuild as a code-first MIDI composition toolkit
Replaces the April wreckage (fifteen 70-byte 'working' MIDIs, archived) with a proper pipeline: - lib/midikit.py: stdlib-only SMF format-1 writer + reader/verifier - lib/songkit.py: composition helpers (bar-grid score DSL with a 4/4 bar linter, OPL arps, driving bass, vibrato, drum patterns) - tunes/: three original tunes - DOS adventure theme (Dm/132), N64 ambient (G/72), chiptune racing (Em/152) - all with LOOP_START/ LOOP_END markers for game engines - tools/build_all.sh + tools/check_wav.py: generate, verify, render via timidity+FluidR3, fail on clipping/dead air - tests/smoke_test.py: round-trip verified against mido All three tunes render clean: no clipping, no dead air, durations match, chromaticism audited against the chord chart.
This commit is contained in:
1 parent
7ddabaff2a
commit
95480abdab
31 files changed
+1222
-31
No files matched your search
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
"Service Station at 2 AM" — DOS adventure main theme
|
||||
Style: early-90s point-and-click / LucasArts-meets-OPL. D minor, 132 BPM.
|
||||
Structure: 4-bar intro, A (8), B (8), A' with counter-melody (8), outro (4).
|
||||
|
||||
The DOS fingerprints:
|
||||
- OPL-style 16th-note arpeggios on electric piano
|
||||
- driving 8th-note synth bass with chromatic approach notes
|
||||
- square lead with pitch-bend vibrato on held notes
|
||||
- the G# in bar 4 (harmonic-minor leading tone — instant 1993)
|
||||
"""
|
||||
import os, sys
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
|
||||
from midikit import MidiFile, Track, MPQN, verify
|
||||
from songkit import (bar, melody, arp, bass_drive, drums, vibrato, crash,
|
||||
parse_score, TPQ)
|
||||
|
||||
BPM = 132
|
||||
OUT = os.path.join(os.path.dirname(__file__), "..", "midi",
|
||||
"01_service_station_2am.mid")
|
||||
|
||||
# Chord chart, one (root, quality) per bar, 32 bars
|
||||
CHORDS = (
|
||||
[("D", "m"), ("Bb", ""), ("G", "m"), ("A", "")] + # intro
|
||||
[("D", "m"), ("Bb", ""), ("G", "m"), ("A", ""),
|
||||
("D", "m"), ("Bb", ""), ("G", "m"), ("D", "m")] + # A
|
||||
[("Bb", ""), ("C", ""), ("D", "m"), ("Bb", ""),
|
||||
("G", "m"), ("D", "m"), ("Bb", ""), ("A", "")] + # B
|
||||
[("D", "m"), ("Bb", ""), ("G", "m"), ("A", ""),
|
||||
("D", "m"), ("Bb", ""), ("G", "m"), ("D", "m")] + # A'
|
||||
[("D", "m"), ("Bb", ""), ("A", ""), ("D", "m")] # outro
|
||||
)
|
||||
|
||||
# --- melodies (bar grids) -------------------------------------------------
|
||||
MELODY_A = """
|
||||
D4-8 F4-8 A4-4 A4-8 Bb4-8 A4-4 | F4-8 A4-8 Bb4-4 A4-8 F4-8 D4-4 |
|
||||
G4-8 Bb4-8 D5-8 C5-8 Bb4-4 A4-4 | B4-8 A4-8 G#4-8 A4-8 E4-2 |
|
||||
D5-8 C5-8 D5-8 F5-8 E5-4 D5-4 | C5-8 Bb4-8 C5-8 D5-8 Bb4-2 |
|
||||
A4-8 Bb4-8 C5-4 E5-4 D5-4 | D5-2 r2
|
||||
"""
|
||||
MELODY_B = """
|
||||
F5-4 F5-8 Eb5-8 F5-4 D5-4 | E5-4 G5-8 F5-8 E5-4 C5-4 |
|
||||
D5-8 F5-8 A5-4 G5-8 F5-8 E5-4 | F5-2 D5-4 Bb4-8 C5-8 |
|
||||
Bb5-4 A5-8 G5-8 F5-4 D5-4 | E5-4 F5-8 E5-8 D5-4 A4-4 |
|
||||
Bb4-8 C5-8 D5-4 E5-8 F5-8 G#5-4 | A5-2 G#5-4 E5-4
|
||||
"""
|
||||
MELODY_OUTRO = """
|
||||
A4-8 D5-8 F5-8 A5-8 D6-2 | C6-4 Bb5-4 F5-4 D5-4 |
|
||||
E5-4 D5-4 C#5-4 A4-4 | D5-1
|
||||
"""
|
||||
PICKUP = "r2 A4-8 Bb4-8 A4-8 G4-8" # intro bar 4 pickup
|
||||
# A' bars: octave-ish answer underneath the main melody
|
||||
COUNTER_A = """
|
||||
r2 D5-8 F5-8 E5-4 | r2 F5-8 D5-8 Bb4-4 |
|
||||
r2 G5-8 F5-8 D5-4 | r2 E5-8 G5-8 F5-8 E5-8 |
|
||||
r4 A5-8 G5-8 F5-4 A5-4 | r4 F5-8 A5-8 D5-4 F5-4 |
|
||||
r2 C6-4 Bb5-4 | r2 F5-4 D5-4 r4
|
||||
"""
|
||||
|
||||
|
||||
def build():
|
||||
mf = MidiFile(tpq=TPQ)
|
||||
mf.time_sig = (4, 2)
|
||||
mf.key_sig = (-1, True) # D minor
|
||||
mf.tempos = [MPQN.from_bpm(0, BPM)]
|
||||
|
||||
lead = Track("Lead (square)", channel=0)
|
||||
lead.program(0, "square lead")
|
||||
lead.cc(0, 7, 104); lead.cc(0, 10, 54) # vol, pan centre
|
||||
counter = Track("Counter (EP2)", channel=1)
|
||||
counter.program(0, "electric piano 2")
|
||||
counter.cc(0, 7, 80); counter.cc(0, 10, 90)
|
||||
bass = Track("Bass", channel=2)
|
||||
bass.program(0, "synth bass 1")
|
||||
bass.cc(0, 7, 92); bass.cc(0, 10, 30)
|
||||
acomp = Track("Arp (OPL)", channel=3)
|
||||
acomp.program(0, "electric piano 1")
|
||||
acomp.cc(0, 7, 66); acomp.cc(0, 10, 20)
|
||||
d = Track("Drums", channel=9)
|
||||
d.cc(0, 7, 100)
|
||||
|
||||
# intro: arp + bass only, pickup lead in bar 4
|
||||
arp(acomp, 0, CHORDS[0:4], pattern="012321", velocity=64)
|
||||
bass_drive(bass, 0, CHORDS[0:4], velocity=80)
|
||||
melody(lead, 3, PICKUP)
|
||||
drums(d, 3, 1, "shufflesnare", velocity_scale=0.8)
|
||||
|
||||
# A (bars 4-11)
|
||||
arp(acomp, 4, CHORDS[4:12], pattern="012321", velocity=70)
|
||||
bass_drive(bass, 4, CHORDS[4:12])
|
||||
melody(lead, 4, MELODY_A)
|
||||
vibrato(lead, bar(4), bar(12), tempo_bpm=BPM, depth=0.55)
|
||||
drums(d, 4, 8, "rock")
|
||||
drums(d, 6, 1, "dos_roll", velocity_scale=0.7)
|
||||
drums(d, 11, 1, "dos_roll", velocity_scale=0.9)
|
||||
crash(d, bar(12))
|
||||
|
||||
# B (bars 12-19)
|
||||
arp(acomp, 12, CHORDS[12:20], pattern="021321", velocity=72)
|
||||
bass_drive(bass, 12, CHORDS[12:20])
|
||||
melody(lead, 12, MELODY_B)
|
||||
vibrato(lead, bar(12), bar(20), tempo_bpm=BPM, depth=0.6)
|
||||
drums(d, 12, 8, "rock")
|
||||
drums(d, 15, 1, "dos_roll", velocity_scale=0.7)
|
||||
drums(d, 19, 1, "break", velocity_scale=0.9)
|
||||
crash(d, bar(20))
|
||||
|
||||
# A' (bars 20-27): same melody + counter-melody, busier hats
|
||||
arp(acomp, 20, CHORDS[20:28], pattern="012321", velocity=74)
|
||||
bass_drive(bass, 20, CHORDS[20:28])
|
||||
melody(lead, 20, MELODY_A)
|
||||
vibrato(lead, bar(20), bar(28), tempo_bpm=BPM, depth=0.65)
|
||||
melody(counter, 20, COUNTER_A)
|
||||
drums(d, 20, 8, "rock")
|
||||
drums(d, 23, 1, "dos_roll", velocity_scale=0.7)
|
||||
drums(d, 27, 1, "dos_roll")
|
||||
crash(d, bar(28))
|
||||
|
||||
# outro
|
||||
arp(acomp, 28, CHORDS[28:32], pattern="0121", velocity=66)
|
||||
bass_drive(bass, 28, CHORDS[28:32], subdivision=1, velocity=75)
|
||||
melody(lead, 28, MELODY_OUTRO)
|
||||
vibrato(lead, bar(28), bar(32), tempo_bpm=BPM, depth=0.5)
|
||||
crash(d, bar(28))
|
||||
drums(d, 28, 1, "break", velocity_scale=0.8)
|
||||
# final sustained chord (Dm) on counter
|
||||
from midikit import note as N
|
||||
for p in ("D3", "A3", "D4", "F4", "A4", "D5"):
|
||||
counter.note(bar(31), N(p), TPQ * 4, 70)
|
||||
|
||||
mf.add_track(lead); mf.add_track(counter); mf.add_track(bass)
|
||||
mf.add_track(acomp); mf.add_track(d)
|
||||
# loop points for game engines: intro plays once, A-B-A' loops
|
||||
lead.marker(bar(4), "LOOP_START")
|
||||
lead.marker(bar(28), "LOOP_END")
|
||||
return mf
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mf = build()
|
||||
mf.write(OUT)
|
||||
d = verify(OUT, min_sec=40, max_sec=120)
|
||||
print("OK:", OUT)
|
||||
print(" duration:", d["duration_sec"], "s | notes:",
|
||||
sum(len(t["notes"]) for t in d["tracks"]),
|
||||
"| tracks:", len(d["tracks"]))
|
||||
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
"Kestrel Over The Fens" — N64-era ambient exploration theme
|
||||
Style: Ocarina-of-Time-adjacent. G major with Lydian sparkle, 72 BPM.
|
||||
Structure: 4-bar intro, phrase 1 (8), phrase 2 higher (8), coda (4).
|
||||
|
||||
The N64 fingerprints:
|
||||
- pan flute lead, long breathy phrases, gentle vibrato
|
||||
- warm pad chords breathing underneath (whole notes, low velocity)
|
||||
- harp arpeggios instead of the DOS 16ths — everything floats
|
||||
- one C#6 in bar 13 (Lydian #11) that does the emotional heavy lifting
|
||||
"""
|
||||
import os, sys
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
|
||||
from midikit import MidiFile, Track, MPQN, verify, note as N
|
||||
from songkit import bar, melody, arp, vibrato, TPQ
|
||||
|
||||
BPM = 72
|
||||
OUT = os.path.join(os.path.dirname(__file__), "..", "midi",
|
||||
"02_kestrel_over_the_fens.mid")
|
||||
|
||||
CHORDS = (
|
||||
[("G", "add9"), ("D", "7"), ("E", "m7"), ("C", "maj7")] + # intro
|
||||
[("G", "add9"), ("D", "7"), ("E", "m7"), ("C", "maj7"),
|
||||
("A", "m7"), ("D", "sus"), ("G", "add9"), ("C", "add9")] + # P1
|
||||
[("C", "add9"), ("G", "add9"), ("E", "m7"), ("D", "sus"),
|
||||
("C", "add9"), ("G", "add9"), ("A", "m7"), ("D", "sus")] + # P2
|
||||
[("G", "add9"), ("C", "add9"), ("G", "add9"), ("G", "")] # coda
|
||||
)
|
||||
# D7/F# feel via bass line; Dsus resolves the phrase.
|
||||
|
||||
PHRASE_1 = """
|
||||
D5-4 G5-4 A5-2 | F#5-4 E5-4 D5-2 | E5-4 G5-4 F#5-2 | E5-4 D5-4 C5-2 |
|
||||
A4-8 C5-8 E5-4 A5-2 | D5-4 E5-4 D5-2 | G5-1 | r4 B5-4 A5-4 G5-4
|
||||
"""
|
||||
PHRASE_2 = """
|
||||
E5-4 G5-4 D5-4 E5-4 | B5-4 C#6-4 B5-2 | D6-4 B5-4 G5-4 E5-4 |
|
||||
F#5-4 A5-4 G5-2 | E5-8 G5-8 A5-4 G5-4 E5-4 | D5-4 G5-4 B5-2 |
|
||||
C6-4 B5-4 A5-4 E5-4 | D6-2 A5-4 F#5-4
|
||||
"""
|
||||
CODA = """
|
||||
G5-1 | E5-2 D5-2 | D5-2 B4-2 | G5-1
|
||||
"""
|
||||
|
||||
|
||||
def build():
|
||||
mf = MidiFile(tpq=TPQ)
|
||||
mf.time_sig = (4, 2)
|
||||
mf.key_sig = (1, False) # G major
|
||||
mf.tempos = [MPQN.from_bpm(0, BPM)]
|
||||
|
||||
lead = Track("Pan flute", channel=0)
|
||||
lead.program(0, "pan flute")
|
||||
lead.cc(0, 7, 92); lead.cc(0, 10, 58)
|
||||
pad = Track("Warm pad", channel=1)
|
||||
pad.program(0, "warm pad")
|
||||
pad.cc(0, 7, 58); pad.cc(0, 10, 40)
|
||||
harp = Track("Harp", channel=2)
|
||||
harp.program(0, "orchestral harp")
|
||||
harp.cc(0, 7, 72); harp.cc(0, 10, 84)
|
||||
bass = Track("Cello", channel=3)
|
||||
bass.program(0, "cello")
|
||||
bass.cc(0, 7, 80); bass.cc(0, 10, 34)
|
||||
|
||||
def pad_chords(start, count):
|
||||
for i in range(count):
|
||||
root, qual = CHORDS[start + i]
|
||||
for iv in (0, 4 if qual not in ("m", "m7", "m7b5") else 3, 7):
|
||||
pad.note(bar(start + i), N(root + "3") + iv, TPQ * 4, 55)
|
||||
|
||||
def bass_roots(start, count):
|
||||
for i in range(count):
|
||||
bass.note(bar(start + i), N(CHORDS[start + i][0] + "2"),
|
||||
TPQ * 4, 70)
|
||||
|
||||
# intro: harp + pad only
|
||||
arp(harp, 0, CHORDS[0:4], pattern="0121", subdivision=2,
|
||||
velocity=52, octave=4, duration=TPQ)
|
||||
pad_chords(0, 4); bass_roots(0, 4)
|
||||
|
||||
# phrase 1
|
||||
melody(lead, 4, PHRASE_1)
|
||||
vibrato(lead, bar(4), bar(12), tempo_bpm=BPM, depth=0.4, rate=4.5)
|
||||
arp(harp, 4, CHORDS[4:12], pattern="0121", subdivision=2,
|
||||
velocity=56, octave=4, duration=TPQ)
|
||||
pad_chords(4, 8); bass_roots(4, 8)
|
||||
|
||||
# phrase 2: harp moves up, pad swells
|
||||
melody(lead, 12, PHRASE_2)
|
||||
vibrato(lead, bar(12), bar(20), tempo_bpm=BPM, depth=0.45, rate=5.0)
|
||||
arp(harp, 12, CHORDS[12:20], pattern="012321", subdivision=2,
|
||||
velocity=62, octave=4, duration=TPQ)
|
||||
pad_chords(12, 8); bass_roots(12, 8)
|
||||
|
||||
# coda: everything lets go
|
||||
melody(lead, 20, CODA)
|
||||
vibrato(lead, bar(20), bar(24), tempo_bpm=BPM, depth=0.35, rate=4.0)
|
||||
arp(harp, 20, CHORDS[20:24], pattern="0121", subdivision=2,
|
||||
velocity=48, octave=4, duration=TPQ)
|
||||
pad_chords(20, 4); bass_roots(20, 4)
|
||||
# final G(add9), long, soft
|
||||
for p in ("G2", "D3", "G3", "B3", "D4", "A4"):
|
||||
pad.note(bar(23), N(p), TPQ * 6, 45)
|
||||
harp.note(bar(23), N(p), TPQ * 6, 40)
|
||||
|
||||
mf.add_track(lead); mf.add_track(pad); mf.add_track(harp); mf.add_track(bass)
|
||||
lead.marker(bar(4), "LOOP_START")
|
||||
lead.marker(bar(20), "LOOP_END")
|
||||
return mf
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mf = build()
|
||||
mf.write(OUT)
|
||||
d = verify(OUT, min_sec=50, max_sec=150)
|
||||
print("OK:", OUT)
|
||||
print(" duration:", d["duration_sec"], "s | notes:",
|
||||
sum(len(t["notes"]) for t in d["tracks"]),
|
||||
"| tracks:", len(d["tracks"]))
|
||||
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
"The U's Late Equaliser" — fast chiptune sports/fighting theme
|
||||
Style: Game Boy racing / fighting-game stage select. E minor, 152 BPM.
|
||||
Structure: 2-bar intro, A (8), B (8), A' with harmony (8), tag (2).
|
||||
|
||||
The chiptune fingerprints:
|
||||
- square lead hook in 8th-note runs, nothing sustains
|
||||
- 16th-note synth bass, octave pops
|
||||
- off-beat chord stabs (the "skank" that makes 152 BPM feel faster)
|
||||
- drum fills every 4 bars, crash on the downbeat of every section
|
||||
"""
|
||||
import os, sys
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
|
||||
from midikit import MidiFile, Track, MPQN, verify, note as N
|
||||
from songkit import (bar, melody, arp, bass_drive, drums, vibrato, crash,
|
||||
chord, parse_score, QUALITIES as QUAL, TPQ)
|
||||
|
||||
BPM = 152
|
||||
OUT = os.path.join(os.path.dirname(__file__), "..", "midi",
|
||||
"03_late_equaliser.mid")
|
||||
|
||||
CHORDS = (
|
||||
[("E", "m"), ("E", "m")] + # intro
|
||||
[("E", "m"), ("E", "m"), ("C", ""), ("C", ""),
|
||||
("G", ""), ("G", ""), ("D", ""), ("D", "")] + # A
|
||||
[("C", ""), ("D", ""), ("E", "m"), ("E", "m"),
|
||||
("C", ""), ("D", ""), ("E", "m"), ("E", "m")] + # B
|
||||
[("E", "m"), ("E", "m"), ("C", ""), ("C", ""),
|
||||
("G", ""), ("G", ""), ("D", ""), ("D", "")] + # A'
|
||||
[("E", "m"), ("E", "m")] # tag
|
||||
)
|
||||
|
||||
HOOK_A = """
|
||||
E5-8 G5-8 B5-8 A5-8 G5-8 E5-8 G5-4 | B5-8 A5-8 G5-8 E5-8 F#5-4 G5-4 |
|
||||
G5-8 A5-8 G5-8 E5-8 C5-2 | E5-8 G5-8 C6-8 B5-8 A5-4 G5-4 |
|
||||
B5-8 A5-8 B5-8 D6-8 B5-4 G5-4 | D6-8 B5-8 A5-8 G5-8 A5-4 B5-4 |
|
||||
A5-8 B5-8 A5-8 F#5-8 D5-4 F#5-4 | G5-8 A5-8 B5-8 C6-8 B5-2
|
||||
"""
|
||||
HOOK_B = """
|
||||
C6-8 B5-8 A5-8 G5-8 A5-4 E5-4 | B5-8 A5-8 G5-8 F#5-8 A5-4 D5-4 |
|
||||
E5-8 G5-8 B5-8 E6-8 D6-4 B5-4 | E6-2 B5-4 G5-4 |
|
||||
C6-8 D6-8 C6-8 A5-8 G5-4 E5-4 | F#5-8 A5-8 D6-8 C6-8 B5-4 A5-4 |
|
||||
G5-8 B5-8 E6-8 G6-8 F#6-4 E6-4 | E6-1
|
||||
"""
|
||||
INTRO_LICK = "B4-8 E5-8 G5-8 B5-8 A5-8 G5-8 F#5-8 G5-8"
|
||||
|
||||
|
||||
def build():
|
||||
mf = MidiFile(tpq=TPQ)
|
||||
mf.time_sig = (4, 2)
|
||||
mf.key_sig = (-1, True) # E minor
|
||||
mf.tempos = [MPQN.from_bpm(0, BPM)]
|
||||
|
||||
lead = Track("Square lead", channel=0)
|
||||
lead.program(0, "square lead")
|
||||
lead.cc(0, 7, 90); lead.cc(0, 10, 52)
|
||||
harm = Track("Harmony 3rd", channel=1)
|
||||
harm.program(0, "square lead")
|
||||
harm.cc(0, 7, 62); harm.cc(0, 10, 78)
|
||||
stabs = Track("Stabs", channel=2)
|
||||
stabs.program(0, "electric piano 1")
|
||||
stabs.cc(0, 7, 62); stabs.cc(0, 10, 24)
|
||||
bass = Track("Bass", channel=3)
|
||||
bass.program(0, "synth bass 2")
|
||||
bass.cc(0, 7, 84); bass.cc(0, 10, 36)
|
||||
d = Track("Drums", channel=9)
|
||||
d.cc(0, 7, 88)
|
||||
|
||||
def stab_chart(start, count):
|
||||
"""Off-beat chord stabs: hit on the 'and' of every beat."""
|
||||
for i in range(count):
|
||||
root, qual = CHORDS[start + i]
|
||||
for b in (0.5, 1.5, 2.5, 3.5):
|
||||
for iv in QUAL[qual]:
|
||||
stabs.note(bar(start + i, b), N(root + "4") + iv,
|
||||
TPQ // 2 - 40, 78)
|
||||
|
||||
for start, count in ((0, 2), (2, 8), (10, 8), (18, 8), (26, 2)):
|
||||
stab_chart(start, count)
|
||||
|
||||
# intro
|
||||
bass_drive(bass, 0, CHORDS[0:2], subdivision=2, velocity=90)
|
||||
melody(lead, 0, INTRO_LICK)
|
||||
melody(lead, 1, INTRO_LICK)
|
||||
drums(d, 1, 1, "dos_roll", velocity_scale=0.8)
|
||||
|
||||
# A
|
||||
bass_drive(bass, 2, CHORDS[2:10], subdivision=2)
|
||||
melody(lead, 2, HOOK_A)
|
||||
vibrato(lead, bar(2), bar(10), tempo_bpm=BPM, depth=0.4, rate=6.5)
|
||||
drums(d, 2, 8, "drive")
|
||||
drums(d, 5, 1, "dos_roll", velocity_scale=0.7)
|
||||
drums(d, 9, 1, "break")
|
||||
crash(d, bar(10))
|
||||
|
||||
# B
|
||||
bass_drive(bass, 10, CHORDS[10:18], subdivision=2)
|
||||
melody(lead, 10, HOOK_B)
|
||||
vibrato(lead, bar(10), bar(18), tempo_bpm=BPM, depth=0.45, rate=6.5)
|
||||
drums(d, 10, 8, "drive")
|
||||
drums(d, 13, 1, "dos_roll", velocity_scale=0.7)
|
||||
drums(d, 17, 1, "dos_roll")
|
||||
crash(d, bar(18))
|
||||
|
||||
# A' with third-harmony
|
||||
bass_drive(bass, 18, CHORDS[18:26], subdivision=2)
|
||||
melody(lead, 18, HOOK_A)
|
||||
vibrato(lead, bar(18), bar(26), tempo_bpm=BPM, depth=0.5, rate=6.5)
|
||||
# harmony a diatonic third below, velocity down
|
||||
for t, p, dur, v in parse_score(HOOK_A):
|
||||
harm.note(bar(18) + t, p - 4 if p % 12 in (0, 1) else p - 3,
|
||||
dur, max(40, v - 25))
|
||||
drums(d, 18, 8, "drive")
|
||||
drums(d, 21, 1, "dos_roll", velocity_scale=0.7)
|
||||
drums(d, 25, 1, "dos_roll")
|
||||
crash(d, bar(26))
|
||||
|
||||
# tag: cadence hit
|
||||
bass_drive(bass, 26, CHORDS[26:28], subdivision=2, velocity=100)
|
||||
for p in ("E2", "E3", "B3"):
|
||||
bass.note(bar(27), N(p), TPQ * 4, 100)
|
||||
for p in ("E4", "G4", "B4", "E5"):
|
||||
stabs.note(bar(27), N(p), TPQ * 4, 85)
|
||||
lead.note(bar(27), N("E6"), TPQ * 4, 95)
|
||||
crash(d, bar(26))
|
||||
drums(d, 26, 1, "break")
|
||||
|
||||
mf.add_track(lead); mf.add_track(harm); mf.add_track(stabs)
|
||||
mf.add_track(bass); mf.add_track(d)
|
||||
lead.marker(bar(2), "LOOP_START")
|
||||
lead.marker(bar(26), "LOOP_END")
|
||||
return mf
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mf = build()
|
||||
mf.write(OUT)
|
||||
dd = verify(OUT, min_sec=30, max_sec=120)
|
||||
print("OK:", OUT)
|
||||
print(" duration:", dd["duration_sec"], "s | notes:",
|
||||
sum(len(t["notes"]) for t in dd["tracks"]),
|
||||
"| tracks:", len(dd["tracks"]))
|
||||
Reference in new issue
Block a user