Files
pi-agent bac1bd5686 feat: add 90s-midi-composer skill and Neon Dreams demo
- SKILL.md: complete reference for creating 90s-style MIDI with Python/mido
- drum_reference.md: full GM drum kit note mapping
- compose_neon_dreams.py: 1.5 min A minor dance track at 128 BPM
- neon_dreams.mid: compiled 6-track MIDI (drums, pads, bass, synth lead, piano)
2026-04-17 17:42:20 +00:00

5.1 KiB
Raw Permalink Blame History

name, description, license, compatibility
name description license compatibility
90s-midi-composer Create authentic 90s-style MIDI music files with General MIDI/SC-55 aesthetic. Use when creating MIDI music, composing dance/electronic tracks, or making 90s retro-sounding songs. MIT Linux with Python3, mido library

90s MIDI Composer

Create authentic early-to-mid 90s-style MIDI music using Linux tools and Python + mido.

Prerequisites

Install required tools (one-time setup, requires sudo):

sudo apt-get install -y fluidsynth fluid-soundfont-gm
pip3 install --break-system-packages mido

The Tool: Python + Mido

Mido is a Python library for working with MIDI files. Key classes:

  • MidiFile(ticks_per_beat=480) — MIDI file container
  • MidiTrack() — list of Message objects (one per instrument)
  • Message('note_on', note=N, velocity=V, channel=C, time=T) — start a note
  • Message('note_off', note=N, velocity=V, channel=C, time=T) — stop a note
  • Message('program_change', program=N, channel=C, time=T) — change instrument
  • Message('control_change', control=N, value=V, channel=C, time=T) — CC control
  • MetaMessage('set_tempo', tempo=μs_per_beat, time=0) — set tempo (μs/beat)

Timing in Mido

Mido uses relative timing. Each message has time = ticks since the previous one.

ticks_per_beat = 480  (PPQ)
1 sixteenth-note = 120 ticks
1 eighth-note    = 240 ticks
1 quarter-note   = 480 ticks (1 beat)
1 bar (4/4)      = 1920 ticks (4 beats × 480)

Absolute → Relative Conversion

Build events with absolute tick offsets, then convert:

def rel(items):  # items = [(abs_tick, Message), ...]
    items.sort(key=lambda x: x[0])
    out, prev = [], 0
    for at, msg in items:
        msg.time = at - prev
        out.append(msg)
        prev = at
    return out

Creating a Basic MIDI File

from mido import MidiFile, MidiTrack, Message as M, MetaMessage

PPQ = 480          # pulses per quarter note (ticks/beat)
BPM = 128
TEMPO = 60_000_000 // BPM

mid = MidiFile(ticks_per_beat=PPQ)

# Track 0: Tempo
trk = MidiTrack()
trk.append(MetaMessage('set_tempo', tempo=TEMPO, time=0))
mid.tracks.append(trk)

# Track 1: Drums (channel 10 = 9)
drums = MidiTrack()
# ... add drum messages ...
mid.tracks.append(drums)

mid.save('output.mid')

90s Aesthetic Guide

Essential GM Patches (General MIDI)

Patch Name 90s Role
1 Acoustic Grand Piano / melodic
37 Synth Bass 1 Driving synth bass
59 Brass Section Hits, accents
80 Lead 1 Synth Arpeggio lead
88 Pad 4 (Choir) Warm atmospheric pads
49 Strings Harmonic texture
16 Electric Piano 1 Rhodes-style

GM Drum Set (Channel 10 = channel 9)

Note Voice Note Voice
36 Kick 1 38 Snare 1
42 Hi-hat closed 46 Hi-hat open
49 Crash cymbal 57 Tambourine
51 Ride cymbal 50 Low bongo

Classic 90s Dance Beat (120-140 BPM)

Kick on every quarter note (1, 2, 3, 4)
Snare on beats 2 & 4
Hi-hat on every eighth note
Open hi-hat on off-beats for groove

90s Chord Progressions

  • Am | F | G | E7 — vi-IV-V-I in C (the quintessential 90s pop progression)
  • C | G | Am | F — I-V-vi-IV (the "axis of awesome")
  • Em | C | G | D — vi-IV-I-V (melancholy 90s feel)
  • Am | C | G | E7 — i-III-VII-V (minor-key drama)

Instrument Patterns

  • Arpeggio lead: 16th-note chords cycling root-3rd-5th-octave, ascending and descending
  • Walking bass: Quarter-note chord tone movement, alternating arpeggio directions
  • Pad chords: 3-voice voicings, hold ~90% of bar for smooth crossfading
  • Piano melody: Pentatonic or natural minor scale, sparse 4-note phrases per bar

Effects (Control Changes)

  • Reverb: CC91, value 40-80 (higher = more spacious hall)
  • Chorus: CC93, value 50-90
  • Filter: CC5 or CC74, value 40-127
  • Expression: CC11, value 100-127

Song Structure Template

Intro (4 bars)  — Pads only, dreamy and sparse
Verse (8 bars)  — Drums enter, bass + pads + arpeggio  (no piano)
Chorus (8 bars) — Full arrangement, piano melody joins
Bridge (4 bars) — Breakdown or key change
Final Chorus (8 bars) — Return, full energy
Outro (8 bars)  — Drums simplify, piano arpeggio fade

At 128 BPM: 40 bars ≈ 1.25 minutes. Example: 48 bars = 1.5 minutes.

BPM Recommendations

Genre Typical BPM
90s slow jam 80-100
House / dance 120-130
Trance / techno 130-150
Drum & bass 170-180

Playing MIDI Files

# With fluidsynth
fluidsynth -a alsa /usr/share/sounds/sf2/FluidR3_GM.sf2 output.mid

# On macOS
fluidsynth -a core /path/to/FluidR3_GM.sf2 output.mid

See Also

  • Drum reference: /drum_reference.md in this skill directory