Wavetable SoundFonts (SF2) - wrightflyer/Synth GitHub Wiki

Wavetable

Going right back to the start of these pages you'll see that the initial inspiration to design and build a synth was "something a bit like a Casio VL-Tone/VL-1". Well that had:

Instrument selector

So the "ADSR" one (at right) basically meant the synth where the calculator memory was used to define wave shape, attack, decay, sustain, release, etc but then it also had 5 "real" instruments: Piano, "Fantasy", Violin, Flute and Guitar and clearly these used some kind of wavetable to provide the shape of the note that would then be scaled to the right frequency of the note played.

Well Teensy Audio not only has waveform generators (VCO), Envelopes, Filters and so on but there is also:

Wavetable module

And this uses an instrument that can be extracted from an SF2 SoundFont file (this format originally created for the Creative Soundblaster AWE32 - a card I bought about 20+ years ago!!) using:

SF2 extractor

which is invoked with Python 3.6 using "python controller.py":

SF2 decoder

Now my first thought was simply to add just the same instruments as VL-1 (Piano, Flute, Violin etc) but I'm also a sucker for the sound of Church Organ so I thought I might add that too. Then I started to think about "General MIDI". Back in the mists of time the powers that be suggested a fixed collection of 128 instruments in a certain order so if you played the same MIDI file to different sound sources, as long as they implemented the GM list, it would sound similar. So I started to look around at collections of those 128 instruments as SF2 files which ultimately led to me collecting quite a few at:

SF2 archive

This ranges from the very small (and very poor quality) up to the very (VERY!) large and some really great samples. But we're talking about a Teensy 4 here with 2MB of flash and that also needs to hold other stuff. So I needed a collection that was about 1.5MB.

Off at a very wide tangent!

This is where I headed off at a tangent as I needed a way to "audition" SF2s to hear what sounded good and what sounded rough. So I looked for SF2 players. Almost everything I found came in the form of a VST (a plugin for Digital Audio Workstation software) so next I looked for SF2 playing VST and also some way to actually load and run VST themselves. For SF2 players I found things like:

  • Jeskola
  • DSK SF2
  • Kobe (actually a full synth but with SF2 support but just too complicated to operate!)
  • KXSF2-ST
  • SoundFonter

In the end I think I preferred the elegant simplicity of "Soundfonter" from that list though Jeskola deserves an honourable mention.

But then I needed a way to play them. At first I used each VST as standalone programs - to do this you need a "wrapper" that can run a single VST standalone. I tried several but in the end I think I like the elegant simplicity of "Nanohost" from Tone2: https://www.tone2.com/nanohost.html . That gives you two versions called NanoHost32bit.exe and NanoHost64bit.exe. Depending on whether the VST .dll file is built as 32 bit or 64 bit you just copy the relevant NanoHostXXbit.exe into the same directory and give the name before ".exe" as exactly the same name as the DLL. Then when you run the EXE it loads the DLL (VST) and lets you use whatever functionality it offers.

But then I wanted to try several VST at once (as well as the SF2 players there are free Oscilloscope and Spectrum Analyzers in the form of VST) so rather than wrapping each individually I looked for a "DAW" that would allow you to use VST. There is a good comparison in the YoutTube video at:

Video: https://www.youtube.com/watch?v=4cFwUXSZgEs Notes: https://transverseaudio.com/posts/best-free-daws-free-software-to-make-music

Now before I watched that I had already downloaded and started to use LMMS but I found some problems with things like resizing VST windows so I then looked for alternatives. As that video will tell you the free version of Cakewalk https://www.bandlab.com/products/cakewalk turns out to be the best (in the interim I had also come across Waveform Free but there were things I found wrong in trying to use that too).

So Cakewalk lets you run several VST at once. It happens that a MIDI controller I bought also gave access to a free copy of Ableton Live Lite so I've used that too but it's a bit "cumbersome" simply in terms of the size of the program and how long it takes to load.

Back on track

After all that and spending several days trying to work out how to find and "audition" SF2 files using VSTs and DAWs and stuff I then found the thing I should have found in the first place (which would have avoided many wasted hours!!). There is a totally incredible program for SF2 use called Polyphone that you get at: https://www.polyphone-soundfonts.com/ - How I wish I had found this sooner! It is the PERFECT tool for working with SF2 files. Not only does it let you look "inside" them in far greater detail than any simple "player", it allows access (right down to see how different samples are spread across different octaves of the keyboard) but you can also hop from sample to sample and just audition them by playing the on-screen keyboard with no DAWs or VSTs or anything like that. What's more you can look at it at the "Preset" level (so for example the 128 GM instruments listed in order) or at the "Instrument" level (an easier to navigate alpha order list of all the "instruments") or even at the sample level. I love this program - the UI looks like the highest class commercial software yet it's a free tool.

Polyphone SF2 editor

Now, do you know what's really ironic?!? After downloading a ton of SF2 files and listening to how good each one sounds (compared to the amount of flash space that might be available to hold them in Teensy) the one I think is best goes by the name "gm.sf2" and it's the one that everyone has got in every copy of Windows since Microsoft started to added Media/MIDI support to Windows around about Win95. If you ever toyed with any MIDI in Windows and just let it play to the "Microsoft GS Wavetable Synth" then you have already heard the sounds that I thought were best for this (wish I'd realised this at the start and I could have saved many more hours!!)

So I took GM.SF2 and the SF2 decoder for Teensy and I decoded every instrument into a pair of .h and .cpp files (but not before I had modified the Python to locate the data in "PROGMEM" which is pretty important for Teensy 4!). The decoded data is in one of my repos at:

https://github.com/wrightflyer/SF2_SoundFonts/tree/master/decode/gm

What's interesting is how they differ in size. The smallest .cpp is 3K (so compiles to about 1K of sample data) and the largest is 80MB. But not all of the samples are in the 128 instrument group for General MIDI and that include the 80MB one which is actually a Timpani drum. However the GM list does include things like 500K files for some of the pianos.

So I initially tried to fit all 128 instruments and was up at about 8MB which overflowed Teensy's 2MB by miles so I selectively started to take out the "real big ones" and try to replace with instruments of a similar type (maybe a grand piano with an electric piano say?) where the samples were much smaller. After ditching about 40 of the instruments and giving them smaller replacements (so there were still 128 selectable instruments) I got the code to compile so it would fit.

But sadly the USB interfaces stopped working. :-( So I cut out more and still there were problems. Clearly there's some limit in buidling code for Teensy 4 I am not yet aware of. For the time being I am going back to the original "VL-1 plan" and just trying to add the same instruments as VL-1 had (and a "Church Organ" as all keyboards need to be able to act like a Church Organ if they are going to play Toccata and Fugue in Dminor!)

If I get a small (non-GM) subset to work then I may begin to add back more and more until it breaks and end up with a better selection of instruments.

Thinks: Not sure what GM sample maps to the "Fantasy" instrument that VL-1 had though ?!?

UPDATE: basic programming error! I was creating an array of struct when it should be an array of pointer to struct so I finally got the long list of instruments to build without interfering with USB.

Then several companies had "Black Friday" sales and I picked up a Teensy 4.1 (8M flash rather than 2M flash, more pins, USB host etc etc) for a great price so now I abandoned my "hand picked" list of cut down instruments and, instead tried to fit all 128 samples. I almost succeeded, I can get 125 of 128 in just over 4MB so Teensy 4.1 has almost another 4MB for other goodies.