169 lines
5.1 KiB
Markdown
169 lines
5.1 KiB
Markdown
|
|
---
|
|||
|
|
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
|