| name | music-skill |
| description | A complete toolkit for working with MIDI music files. Covers: analyzing MIDI instruments (乐器分析, what instruments, which channels, GM program), listing all songs in the library (列出曲子, show songs, 曲库), organizing loose MIDI files into bundles (整理 midi, organize data folder), replacing/swapping instruments in a MIDI (换乐器, replace instrument, change sound, 替换乐器), converting audio to MIDI via AI transcription (音频转midi, audio to midi, wav to mid, mp3 to mid), and rendering MIDI to WAV audio (渲染, midi to wav, export audio,
fluidsynth). Use this skill for any music-file manipulation task involving .mid, .midi,
.wav, or audio transcription in the assets/data/ directory.
|
| compatibility | Requires uv (https://docs.astral.sh/uv/getting-started/installation/). Requires fluidsynth for WAV rendering:
macOS: brew install fluidsynth
Ubuntu/Debian: sudo apt install fluidsynth
Fedora/RHEL: sudo dnf install fluidsynth
Windows: choco install fluidsynth (or download binary from fluidsynth.org)
|
music-skill
统一的 MIDI 音乐处理工具包。
Capabilities
| # | Capability | Trigger keywords |
|---|
| 1 | Analyze instruments — scan a MIDI for channels & GM programs, write JSON | 乐器分析, what instruments, program_change, 通道乐器 |
| 2 | List songs — enumerate all bundles in assets/data/, show instruments per song | 列出曲子, show songs, 曲库, list songs |
| 3 | Organize bundles — move loose .mid files into per-song bundle directories | 整理 midi, organize data, loose midi, bundle |
| 4 | Replace instrument — swap GM program on one or more channels, save as next numbered version | 换乐器, replace instrument, change sound, 替换乐器 |
| 5 | Audio → MIDI — transcribe audio (WAV/MP3/FLAC) to MIDI using basic-pitch | 音频转midi, audio to midi, transcribe, wav to mid |
| 6 | MIDI → WAV — render a MIDI to playable WAV using FluidSynth | 渲染, midi to wav, export audio, fluidsynth |
Prerequisites & File Ingestion
Before running any workflow, confirm the environment is ready and the user has a way to get files into it. See references/prerequisites-and-file-ingestion.md for the full checklist (dependency verification, SoundFont setup, and supported file-transfer methods).
Telegram users: .mid files are not accepted as documents; they must be sent inside .zip archives. See references/telegram-file-exchange.md for extraction/re-packing recipes and WAV-size guidance.
Data Layout Convention
assets/
data/
<song-name>/
<song-name>.mid ← original MIDI
<song-name>.json ← instrument analysis (channel/program map)
<song-name>.wav ← rendered audio
<song-name>01.mid ← first modified version
<song-name>01.json
<song-name>01.wav
<song-name>02.mid ← second modified version
...
soundfront/
Arachno SoundFont - Version 1.0.sf2
FluidR3 GM.sf2
Numbered versions count up from 01. Never overwrite an existing version; always compute the next available number with:
ls assets/data/<song>/<song>[0-9][0-9].mid 2>/dev/null | wc -l
Scripts
Scripts run in an isolated uv project under music-skill/scripts/.
Always use uv run --project music-skill/scripts ... so dependency resolution remains local to this skill.
scripts/analyze_instruments.py — scan program_change events, print channel/program table, optionally write JSON
scripts/change_midi_instrument.py — replace program_change on a specific channel, write new MIDI
Workflow 1 — Analyze Instruments
Invoke when: user asks what instruments are in a MIDI, which channels, GM program numbers, or wants to refresh the JSON.
- Identify target MIDI inside its bundle directory.
- Check if a same-name
.json already exists. If it exists and the user did not ask to refresh, read the JSON directly and explain it — do not re-run the script.
- To refresh or create the JSON:
uv run --project scripts scripts/analyze_instruments.py \
--input "assets/data/<song>/<file>.mid" \
--json-output "assets/data/<song>/<file>.json"
- Interpret output:
Channel X -> Program Y: Instrument Name. Channel 9 = Drum Kit (always). Programs 0–127, see references/general-midi-instrument-codes.md.
- Confirm JSON written at same path as MIDI with
.json extension.
Workflow 2 — List Songs
Invoke when: user asks what songs exist, what instruments are used, or wants a library overview.
list_dir on assets/data/ to enumerate bundle subdirectories.
- For each bundle, verify
.json, .wav, numbered variants exist. If a bundle is incomplete, call Workflow 3 (organize) first.
- Read each
.json, extract instruments[].instrument_name per channel.
- Present a summary table: song name | version | instruments.
- Note differences between original and numbered variants.
Workflow 3 — Organize Bundles
Invoke when: loose .mid files appear directly under assets/data/, or a bundle is missing its JSON/WAV.
- Find loose files:
find assets/data -maxdepth 1 -type f \( -name '*.mid' -o -name '*.MID' \) | sort
- For each loose file
assets/data/<name>.mid:
mkdir -p "assets/data/<name>"
mv "assets/data/<name>.mid" "assets/data/<name>/<name>.mid"
- Run Workflow 1 to generate the
.json.
- Run Workflow 6 to generate the
.wav.
Workflow 4 — Replace Instrument
Invoke when: user wants to swap an instrument, change a channel's sound, or create a modified version.
- Identify source MIDI (default: original
<song>.mid; user may specify a numbered version).
- If instrument analysis is missing, run Workflow 1 first.
- Look up target GM program number in
references/general-midi-instrument-codes.md.
- Determine next version number:
NEXT=$(printf "%02d" $(( $(ls "assets/data/<song>/<song>"[0-9][0-9].mid 2>/dev/null | wc -l) + 1 )) )
OUT="assets/data/<song>/<song>${NEXT}.mid"
- Single channel replacement:
uv run --project scripts scripts/change_midi_instrument.py \
--input "assets/data/<song>/<song>.mid" \
--output "$OUT" \
--channel <ch> --from-program <old> --to-program <new>
- Batch replacement (replace all melodic channels with the same instrument):
cp "assets/data/<song>/<song>.mid" "$OUT"
for CH in <ch1> <ch2> ...; do
uv run --project scripts scripts/change_midi_instrument.py \
--input "$OUT" --output "$OUT" \
--channel $CH --from-program -1 --to-program <new>
done
Skip channel 9 (percussion) unless the user explicitly wants it changed.
- Run Workflow 1 on
$OUT to generate its .json.
- Run Workflow 6 on
$OUT to generate its .wav.
- Report: version created, channels changed, new instrument name.
Workflow 5 — Audio → MIDI
Invoke when: user wants to transcribe an audio file (WAV, MP3, FLAC, OGG) to MIDI.
⚠️ Critical limitation: Audio-to-MIDI tools detect pitch and timing only — they do NOT know what instrument produced the original sound. The resulting .mid will show a single default program (usually "Acoustic Grand Piano" or "Electric Piano 1") and will NOT reflect the actual instruments used in the recording. For accurate instrument analysis, always use the original .mid if available. See references/audio-to-midi-limitations.md for details.
- Identify the audio file path.
- Determine output directory (default:
assets/data/<audio-basename>/):
mkdir -p "assets/data/<basename>"
- Transcribe with basic-pitch. First run downloads ~500 MB of TensorFlow dependencies and may take 2–4 minutes; set timeout ≥ 300s:
uv run --project scripts basic-pitch "assets/data/<basename>/" "<audio-file>"
basic-pitch writes <basename>_basic_pitch.mid (and optionally a CSV) into the output directory.
- Rename the output to match the bundle convention:
mv "assets/data/<basename>/<basename>_basic_pitch.mid" "assets/data/<basename>/<basename>.mid"
- Run Workflow 1 to generate
.json, then Workflow 6 to generate .wav.
- Report the bundle path and explain the transcription limitation. Do NOT present default instruments as if they were the real original instruments.
Workflow 6 — MIDI → WAV
Invoke when: user wants to render a MIDI as playable audio, or a bundle is missing its .wav.
- Identify target MIDI.
- Locate SoundFont — check in order:
assets/soundfront/Arachno SoundFont - Version 1.0.sf2
assets/soundfront/FluidR3 GM.sf2
- Any other
.sf2 under assets/soundfront/
- Render:
WAV_PATH="${MIDI_PATH%.mid}.wav"
fluidsynth -ni -F "$WAV_PATH" -r 44100 "$SF2_PATH" "$MIDI_PATH"
- Verify WAV exists and size > 0.
Common errors:
fluidsynth: command not found → install per the compatibility field above.
Failed to open SoundFont → verify .sf2 path; try the other SoundFont.
- Silent WAV → switch between Arachno and FluidR3 GM and retry.
Notes & Gotchas
- Channel 9 is always percussion.
program_change on channel 9 has no effect on most synthesizers; the drum kit is fixed.
- Program numbers are 0-indexed (0–127). Some DAWs display them as 1–128. The scripts use 0-indexed values.
--from-program -1 in change_midi_instrument.py means "replace all programs on the channel regardless of current value."
- De-duplication:
analyze_instruments.py de-duplicates (channel, program) pairs; a channel that switches programs mid-song will show multiple entries.
- Numbered versions never overwrite originals. Always compute
NEXT before writing.
References
references/general-midi-instrument-codes.md — full GM program number → instrument name table, including percussion note map
references/analyze-midi-instruments.md — detailed procedure for instrument analysis
references/replace-midi-instrument.md — detailed procedure for instrument replacement
references/list-songs.md — detailed procedure for song listing
references/organize-midi-data-bundles.md — detailed procedure for bundle organization
references/midi-to-wav-fluidsynth.md — detailed procedure for WAV rendering
references/audio-to-midi-basic-pitch.md — detailed procedure for audio transcription