Microsoft / Roland
gm.dls · 1996 · © Microsoft / Roland
Every Windows PC since 98 has made General MIDI sound like this: a GS sound set Roland licensed to Microsoft, in 3.4 MB. It is the target of gen-gm, read from a local copy and never shipped.
robson / Exceed · a unisynth project
The General MIDI bank every Windows PC ships, 235 instruments and 495 waves, rebuilt from synthesis parameters instead of samples. Each wave is fitted by measuring it, then listening to it, until the copy sounds like the original.
gm.dlsGeneral MIDI is the cheapest way to write music: 128 instruments and a drum kit, known to every sequencer. Windows has the bank built in, but macOS, Linux and the browser do not, and the file is © Microsoft / Roland, so it cannot be shipped. The answer here: describe every wave with a small, fixed set of synthesis models, and let a no_std generator rebuild the bank at load time.
A GM wave is an attack and a short loop. The long decay is not in the wave: the note's volume envelope lives in the DLS articulation. Piano 1, waves 289–298, are 4.8 k–13.7 k samples: 0.2–0.6 s of attack, then a loop of 155–2272 samples. So a model only has to reproduce the first half second plus one steady loop, not a ten-second piano decay.
A loop of L samples is periodic in L, so its spectrum sits on the grid rate/L. The 1339-sample loop of wave 293 has a 16.5 Hz grid. Stretched piano partials and beating unisons are already quantised to that grid in the original. Every periodic family therefore renders its loop with integer phasors on exactly that grid. The loop is periodic by construction, with no click and nothing lost.
The structure is copied; only the waves are synthesised. Instruments, regions, key ranges, articulation, rates, lengths and loop points come from the original as a skeleton without audio. The output is a normal RIFF 'DLS ' buffer: any DLS player, the unisynth sampler, WaveSabre's Adultery and the browser DAW all play it unchanged.
A wave is up to four layers, each one of ten fixed model families, placed in a region: the exactly periodic sustain, a free-running attack that fades into the loop, or the whole one-shot. Parameters have ranges and defaults, and the build rejects anything over budget, so a parameter file can never smuggle in a waveform.
tf→fine envelope env→soft knee 0.9→int16
Harmonic correction: dB gains at harmonics of f0, exact on the loop (DFT, gain per bin, inverse DFT) and a linear-phase FIR of at least four periods on the attack. tf: 20 log-spaced bands × up to 9 rows from 0 to 640 ms, applied by STFT to the attack only. env: up to 24 points from 0 to 400 ms, finer than the STFT can see.
Deterministic by construction. The generator uses only basic IEEE operations: its own sin, exp2, log2, an xorshift RNG seeded with the wave index, and a radix-2 + Bluestein FFT whose twiddles come from the same math. clippy bans f32 transcendentals and mul_add in the crate. The bank is byte-identical natively and in WebAssembly, built whole or in part.
gmfit never searches blind. It reads the instrument's published physics as priors, analyses the original into a model it can already defend, lets each family propose candidates, and only then hands a narrowed box to CMA-ES. Every step must beat the committed result or nothing is written.
Every GM program and drum key maps to a prior: model kind, families to try, and physical starting points. Piano inharmonicity B, mallet mode ratios, Hammond footages, TR-808 hi-hat square frequencies, cowbell 540/800 Hz, the vowel formants of a choir. Search ranges are narrowed around them.
Pitch on the loop grid, harmonic tables by cluster energy, unison and detune from split partials, inharmonicity, envelopes on windows of at least two periods. Loop vibrato and AM become per-harmonic tables, and the noise floor between partials becomes a periodic noise layer.
Not every sound is a tone. Onset detection and Morlet-wavelet band tracking find strikes, trills and glides (modal). Collision statistics and per-band ring times find shakers. Analytic-signal chirp tracking finds FM. LPC and syllables find voices, and the T60 band decay finds plucked strings.
Each family proposes models; all are scored and the best by rank survives. Then a seeded, full-covariance CMA-ES (Hansen's formulation, rank-one + rank-μ, cumulative step size) tunes the explicit scalars inside the unit box. It is deterministic for a seed and runs in parallel.
What the models cannot express is corrected in closed form within budget: a harmonic gain curve (exact on the loop), a time × band gain grid on the attack, and a fine envelope that catches onset detail finer than the STFT. refine alternates fit and correction.
A result is written only if its rank, the score minus penalties for audible defects, beats the committed one, and report --check fails if any wave drops. Bulk fits run per GM category, and each round ends with listening.
The optimiser needs one number. But one number averages away exactly what a listener hears: a buzz once per period, a missing noise floor, a 2 dB hole before the loop. So the score carries defect flags, and above it sits a hearing model built after PEAQ. Each listening round turned what the ear caught into a new measurement.
# similarity of the played signals
# (loop unrolled to 0.5 s, A-weighted)
score = exp(−( d_spec/W₁ + d_onset/W₂
+ d_env/W₃ + d_loop/W₄
+ d_per + d_mod ))
rank = score − 0.1 · character flags
− hearing excess
$ gmfit render 376 # standard kick
score 0.721 tier B flags: lines
Tiers: A ≥ 0.85, B ≥ 0.70; any defect flag drops a wave to C.
pitch_off (5 cents), env_off, loop_click, buzz (per-period peakiness), clipped, tone_off, mod_off, lines, transient_off.Every wave of both sets is fitted, with no placeholders left. Reeds, pipes, organs and brass score highest: steady harmonic tones are what the families express best. Drums, chromatic percussion, ensembles and sound effects score lowest, because their attacks and noisy textures carry detail the models can only approximate. The scores are strict: a wave can sound right in a song and still score 0.6. In whole songs the per-wave score undersells it: the median song is closer to gm.dls through the procedural bank (≈ 1.9 dB) than through gmplus, another real Roland-derived bank (≈ 4.1 dB).
Not done: generation takes 1.14 s natively (1.4 s in the browser) against a 300 ms budget, and the gmplus set is about 8× more audio (12 s in the browser). Fitting continues in the repository; these pages are re-rendered from each committed state.
Windows gm.dls is copyrighted, so it plays as a recording. The other three play live in your browser from the MIDI file: the gmplus Sound Canvas soundfont, and the procedural banks gen-gm and gen-plus, which this page builds on your machine from the committed parameters with gmgen compiled to WebAssembly (about 1.4 s and 12 s). All four use the same engine, so only the banks differ. Keys 1–4 switch banks without losing your place.
46 DOS game tracks from John Novak's General MIDI showdown (Doom, TIE Fighter, Warcraft II, Descent, Sam & Max…) and 24 from The Very Best of GUS MIDI, picked for instrument coverage. Play the full mix or any channel solo.
Open the song selector → sound browserEvery wave played as a note of an instrument that uses it, in four versions, with its fit score, the gmplus sample it was fitted to, and its open defects.
Browse the sounds →Each family, prior and measurement traces back to a paper, a standard or an open-source reference. The per-instrument notes, with every prior, are in research/gm-procedural-instruments.md; the full design in docs/synth/gm-procedural.md.
tilt)phisem, fof, the vowel formant tables.shakers, choir formantsNeither sample bank is in the repository or on this site. They are read from the developer's own copies. The repository holds structure and fitted parameters only; the audio here is our own render, published for comparison.
gm.dls · 1996 · © Microsoft / Roland
Every Windows PC since 98 has made General MIDI sound like this: a GS sound set Roland licensed to Microsoft, in 3.4 MB. It is the target of gen-gm, read from a local copy and never shipped.
gmplus · Release 1 · fan soundfont
A soundfont built from Roland Sound Canvas samples, longer and cleaner than the Windows bank. gen-plus is fitted to it at 32 kHz, including its layered and stereo zones.
Grand MS-DOS gaming General MIDI showdown
46 game soundtracks collected for comparing GM devices. That is exactly the job here, so they became the main test set.
archive.org BESTMID1–7 · 1994
About 720 files hand-picked in 1994 as ones that sound good on any GM card. 24 were taken greedily, each adding the most instruments not yet played.
Song credits go to their composers and arrangers, named in the song selector. The renders are for comparison only and are removed on request. Tools: Rust, Bun, SpessaSynth (Apache-2.0; the engine for both the recordings and live playback), LAME, Google Cloud Storage. Part of unisynth, the 64k-intro synth this bank was made for.