bc8df7f33b
- midnight_drive.mid: 90s House/Dance at 128 BPM (75s, 5-track) Arpeggiated synth lead, driving bass, pads, brass stabs, dance beat - starlit_conversation.mid: 90s Slow Jam/Love Song at 88 BPM (99s, 4-track) Rhodes electric piano, strings, choir pads, soft drum groove - tronica.mid: 90s Trance/EBM at 138 BPM (69s, 4-track) Multi-section arpeggiated lead, wide pads, trance beat, accent lead Each .mid has a corresponding .py source showing how to compose it with MIDIUtil.
116 lines
3.6 KiB
Python
116 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Tronica - 90s Trance / EBM
|
|
Driving hypnotic 90s trance with arpeggiated leads, wide choir pads,
|
|
and propulsive rhythm. 138 BPM.
|
|
|
|
Structure: 40 bars
|
|
Intro (4 bars) - sparse 16th-notes
|
|
Build (8 bars) - speed to 32nd-notes
|
|
Drop (8 bars) - full 32nd-notes
|
|
Break (8 bars) - back to 16th-notes
|
|
Drop2 (8 bars) - full 32nd-notes
|
|
Outro (4 bars) - fade out
|
|
|
|
Instruments:
|
|
T0: Lead 1 Synth GM 80 - driving arpeggio
|
|
T1: Pad 4 Choir GM 88 - sustained pads
|
|
T2: Drum set Ch 10 - trance dance beat
|
|
T3: Lead 3 Synth GM 84 - accent in drops
|
|
"""
|
|
from midiutil import MIDIFile
|
|
|
|
BPM = 138
|
|
PPQ = 960
|
|
|
|
CHORDS = [
|
|
{"root": 48, "arp": (0, 3, 7, 12)},
|
|
{"root": 45, "arp": (0, 4, 7, 12)},
|
|
{"root": 50, "arp": (0, 4, 7, 12)},
|
|
{"root": 46, "arp": (0, 2, 7, 12)},
|
|
]
|
|
|
|
total_bars = 40
|
|
fill_bars = {3, 11, 19, 27}
|
|
|
|
def sp(v):
|
|
"""Safe pitch: return only if 0-127."""
|
|
return v if 0 <= v < 128 else None
|
|
|
|
# ========= Create MIDI File =========
|
|
midi = MIDIFile(4, file_format=1, ticks_per_quarternote=PPQ)
|
|
midi.addTempo(0, 0, BPM)
|
|
midi.addProgramChange(0, 0, 0, 80)
|
|
midi.addProgramChange(1, 0, 0, 88)
|
|
midi.addProgramChange(3, 9, 0, 84)
|
|
|
|
# ========= Track 0: Arpeggio =========
|
|
for start, num, spd in [(0,4,4), (4,8,8), (12,8,8), (20,8,4), (28,8,8)]:
|
|
dt = 1.0 / spd
|
|
for bar in range(start, start + num):
|
|
chord = CHORDS[bar % 4]
|
|
r = chord["root"]
|
|
ints = chord["arp"]
|
|
for i in range(4 * spd):
|
|
p = sp(r + ints[i % 4] + (i // 4) * 12)
|
|
if p is not None:
|
|
v = 88 if i % 4 else 93
|
|
midi.addNote(0, 0, p, bar * 4 + i * dt, dt * 0.85, v)
|
|
|
|
# Outro fade (4 bars, decrescendo)
|
|
for bar in range(36, 40):
|
|
chord = CHORDS[bar % 4]
|
|
for i in range(4):
|
|
p = sp(chord["root"] + chord["arp"][i % 4])
|
|
if p is not None:
|
|
midi.addNote(0, 0, p, bar * 4 + i * 0.25, 0.2, max(35, 75 - (bar-36)*15))
|
|
|
|
# ========= Track 1: Pads =========
|
|
midi.addControllerEvent(1, 0, 0, 91, 75) # Reverb
|
|
midi.addControllerEvent(1, 0, 0, 93, 85) # Chorus
|
|
midi.addControllerEvent(1, 0, 0, 11, 127) # Expression
|
|
for bar in range(total_bars):
|
|
r = CHORDS[bar % 4]["root"]
|
|
for n in [r+7, r+12, r+19]:
|
|
midi.addNote(1, 0, n, bar*4, 3.9 if bar%2==0 else 3.7, 50)
|
|
|
|
# ========= Track 2: Drums =========
|
|
for bar in range(total_bars):
|
|
base = bar * 4
|
|
for beat in range(4):
|
|
bt = base + beat
|
|
midi.addNote(2, 9, 36, bt, 0.2, 115 if beat==0 else 105)
|
|
if beat in (1, 3):
|
|
midi.addNote(2, 9, 38, bt, 0.2, 110 if bar in fill_bars else 90)
|
|
midi.addNote(2, 9, 42, bt + 0.5, 0.1, 70)
|
|
if bar in fill_bars:
|
|
midi.addNote(2, 9, 46, base + 3.5, 0.3, 80)
|
|
midi.addNote(2, 9, 46, base + 3.75, 0.2, 75)
|
|
|
|
# ========= Track 3: Lead Cues =========
|
|
for bar in range(8):
|
|
bt = (12 + bar) * 4
|
|
r = CHORDS[(12 + bar) % 4]["root"]
|
|
for bp, off in [(0,12),(0.5,16),(1.0,19),(2.0,16),(2.5,19),(3.0,24)]:
|
|
midi.addNote(3, 9, r+off, bt+bp, 0.5, 90)
|
|
for bar in range(8):
|
|
bt = (28 + bar) * 4
|
|
r = CHORDS[(28 + bar) % 4]["root"]
|
|
for bp, off in [(0,12),(0.5,16),(1.0,19),(2.0,16),(2.5,19),(3.0,24)]:
|
|
midi.addNote(3, 9, r+off, bt+bp, 0.5, 90)
|
|
|
|
# Pitch bend
|
|
for bar in range(8):
|
|
bt = (4 + bar) * 4
|
|
midi.addPitchWheelEvent(0, 0, bt, 3000 + bar*500)
|
|
midi.addPitchWheelEvent(0, 0, bt + 2, -(3000 + bar*500))
|
|
|
|
# ========= Write =========
|
|
output_file = "/home/paperclip/projects/gitea/pi-midi-zone/midi_output/tronica.mid"
|
|
with open(output_file, "wb") as f:
|
|
midi.writeFile(f)
|
|
|
|
print(f"Written: {output_file}")
|
|
print(f" 4-track, {total_bars} bars at {BPM} BPM")
|
|
print(f" Style: 90s Trance / EBM")
|