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)
This commit is contained in:
2026-04-17 17:42:16 +00:00
parent fa7ed62df7
commit bac1bd5686
5 changed files with 547 additions and 1 deletions
+168
View File
@@ -0,0 +1,168 @@
---
name: 90s-midi-composer
description: 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.
license: MIT
compatibility: 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):
```bash
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:
```python
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
```python
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
```bash
# 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
@@ -0,0 +1,51 @@
# GM Drum Kit Reference (Channel 10 = channel=9)
## Standard GM Drum Mapping
| Note | Voice | Note | Voice | Note | Voice | Note | Voice |
|------|---------------|------|--------------|------|----------------|------|------------|
| 35 | Low conga | 36 | **Kick 1** | 37 | High conga | 38 | **Snare 1** |
| 39 | Low tom | 40 | Crash cymbal | 41 | High tom | 42 | **Hi-hat Cl** |
| 43 | Ride cymbal 1 | 44 | Closed hi-hat | 45 | Open hi-hat | 46 | **Open Hi-hat** |
| 47 | Pedal hi-hat | 48 | Low tom | 49 | Crash cymbal | 50 | Low bongo |
| 51 | Ride cymbal 2| 52 | High bongo | 53 | Low-mid conga | 54 | Mid conga |
| 55 | High conga | 56 | Low-mid timbale | 57 | **Tambourine** | 58 | High timbale |
| 59 | Low agogo | 60 | High agogo | 61 | Cabasa | 62 | Maracas |
| 63 | Short whistle| 64 | Long whistle | 65 | Short guiro | 66 | Long guiro |
| 67 | Claves | 68 | Hi wood block | 69 | Low wood block | 70 | Mud claps / Cabasa |
| 71 | Hi snap | 72 | Maraca | 73 | Short shaker | 74 | Long shaker |
| 75 | Guiro | 76 | Cabasa | 77 | Whisper | 78 | Stroke hit / scrape |
| 79 | Stroke scrape | 80 | Slap | 81 | Scratch push | 82 | Slap |
| 83 | Scratch pull | 84 | Sticks | 85 | Square click | 86 | Metronome |
| 87 | Drum roll | 88 | Kick pedal | 89 | Kick pedal | 90 | Snare |
| 91 | Snare str. | 92 | Low tom | 93 | Snare str. | 94 | Rim shot |
| 95 | Open hh | 96 | Open hh | 97 | Low tom | 98 | Closed hh |
| 99 | Low-mid tom| 100 | Hi tom | 101 | Crash cym. | 102 | Mid tom |
| 103 | Closed hh| 104 | Ride cym| 105 | Kick 2 | 106 | Snare 2 |
| 107 | Timbale | 108 | Agogo | 109 | Steel drum | 110 | Bongos |
| 111 | congas | 112 | Bell | | | | |
## Classic Drum Patterns
### 128 BPM Dance (4/4)
```
Bar 1, 2, 3: Standard dance beat
Bar 4: Add fills
Kick: X . . . X . . . (on 1, 5)
Snare: . . . . X . . . (on 5)
HH closed:. . . . . . . . . (constant 8ths)
```
### 120 BPM Half-time
```
Kick: X . . . . . . . (on 1 only)
Snare: . . . . X . . . (on 5)
HH closed:. X . . . X . . (subdued, syncopated)
```
### 140 BPM Breakbeat-tinged
```
Kick: X . . X . . . . (16th feel)
Snare: . . . . X . . X (with accent on 9)
HH closed: (16th notes, accented)
```