kobimusic

a general midi bank in 20mb

tldr: i made a series of compressed general midi sound libraries that is like 200mb quality, packed into 20mb.

18 pieces, 66 minutesdrop a MIDI file to add it
0:00 / 0:00

The player above plays the same eighteen pieces through either bank. On the right, it shows how many bytes each track has downloaded. Try starting a track, then switch the bank and start it again to hear the difference.

one of the things i see most overlooked in websites with midi playback is the playback (if it runs in-browser), is like, honestly crappy 99% of the time. The 1% of the time it isn't terrible, the con is that you'll be waiting for a minute to download the samples, not a great user experience.

the reason why i believe you should have good playback (even if it's not the focus of your site at all), is because, you want your site to reflect the music. with what I plan to add to this site is audio-to-midi, and OMR. with both, it might be a geniunely emotionally moment for someone (listening to long-lost music, rendition of favorite obscure music). then the silence is broken by the flat airfont piano or 24kbps phone-call sounding version of fluidgm. it's like bringing a clown to a funeral (maybe not that far, but you get the point).

most decent piano sf2s/sfz run at like, atleast 25mb. why so big? 2 reasons. one: for sf2s, sound samples have to be a .wav. two - the problem that most sf2s and sfzs share - is that they often don't loop their samples. not for piano atleast.

one reason why is because piano / other percussive instruments decay in volume, so you need to compress the audio to be equal, then find a good looping point, then figure out how to re-implement the decay. sounds easy, until you realise you have to do this, probably a hundred times depending on how many samples you have.

another reason, is that the loops generated (if you don't manually do yourself - actually like finding a needle in a haystack if you do), are often bad. typically people use crossfading, typically works for longer loops (several seconds), but collapses when you go below that.

anyway, what i achieved, is a new algorithm for generating loops that work at any sample size, and is significantly more seamless that crossfading. i use crossfading for transitioning from the initial impulse, to the loop's start. i've taken a mix of sfz libraries and built a general-midi complete version from them:

original
loopdctloopcrossfade
0.098s
0.297s
1.005s
The same sustain, cut to the same number of samples, closed two ways — the crossfade at whichever fade length gave it its quietest seam. Each clip is its loop repeated for three and a half seconds, so a seam has to survive being heard over and over.

The comparison above uses the same samples for both methods. At a tenth of a second, the crossfade has 2 to 3 times the seam error and 5 to 16 times the tone error of my loops. This is what I meant by crossfading collapsing on shorter loops. By one second, the two methods end up about the same. The string section is the exception. A hundred players already smear the seam, so a crossfade has less to ruin. There, crossfading wins on the seam, but it still loses on tone.

the actual transitioning part to the loop still could be improved i think, and I may iterate on this in the future if i get picky again. but feel free to use for your own projects! creative commons liscence. additionally, the code is fully open sourced here, and it should be fairly easy (ask your favorite agentic harness if having trouble) to set up for your own sound libraries.

future work

  • different looping points for different samples (ex. piano, string orchestra, should get higher quality vs easy cases like oceriana)
  • keyswitches??

technical

The bank has 128 programs and a drum kit. The programs come from FreePats, the Versilian Community Sample Library, Karoryfer, VSCO 2 Community Edition, the University of Iowa samples and the Sonatina Symphonic Orchestra. They are mapped to General MIDI in priority order. The octave corrections were checked with a pitch audit instead of by ear. The 92 MB of source samples come out as 2.8 MB at the smallest setting.

For each note, the compressor does one of two things. A note that sustains keeps a short attack, and it gets a harmonic bridge into a loop that is left untouched. A note that decays is flattened to a constant loudness and then looped. Its decay is given back to it as stacked SFZ envelopes. This is the trick that lets a piano loop at all. That part is dctjoin.

To make a bank smaller, every note of a program is brought to the loudness of the program, and every program is brought to −23 LUFS. Then the bank is fitted to a size target. It drops round robins first, then velocity layers, then keys. Only after that does it lower the codec quality, the channels and the sample rate. The slim bank is 26 MB at 44.1 kHz stereo. The microscopic bank is 4.3 MB at 22 kHz mono, with one velocity layer, every fourth key, and stray samples without loops dropped.

how the player streams it

The demo above never downloads a whole bank. Each program is packed as one Ogg Vorbis file, and the SFZ points to each note by its byte offset. Next to it, a slices.json file records the byte range of the Ogg pages that hold every note. The player turns the MIDI file into a timeline. Then it fetches each note with an HTTP range request, in the order the song needs it. It adds the header pages to the front, renumbers the page sequence and recomputes the CRCs. The result goes to decodeAudioData. Vorbis decoding is deterministic, so a note fetched this way is the same, bit for bit, as that part of the whole file.

Notes are ranked by how soon they are needed. One sample per instrument is fetched first, so that later notes have something to transpose from. If a sample has not arrived yet, the note plays the closest one that has (another velocity layer, or a nearby key shifted). This way the music starts right away and gets sharper as it plays. The counters in the playlist show what this costs. Economics is a minute and thirteen seconds long. It downloads about 905 KB of the 26 MB slim bank, and 217 KB of the 4.3 MB microscopic bank. If you play it a second time, it fetches nothing, because the notes it needs are already downloaded. A different piece still has to download its own notes though. The cache holds the notes that have been heard, not whole instruments, so four pieces came to 3.3 MB.

take it

Both archives come with an ATTRIBUTION.md that lists which library every program came from. Everything in the banks is CC0, except the University of Iowa samples, which can be used for any project without restrictions. The drum kit is Big Rusty Drums from Karoryfer with some VCSL percussion. The celesta is from stamperadam's samples on freesound, which are also CC0. So none of it needs attribution, and you can use the banks in your own projects.

← all research