schellingb / TinySoundFont

SoundFont2 synthesizer library in a single C/C++ file
MIT License
608 stars 71 forks source link

How many channels does this support? #57

Closed chriscoomber closed 3 years ago

chriscoomber commented 3 years ago

In the MIDI spec, a channel MIDI message (e.g. note on, note off, program changed, etc.) has a channel represented by 4 bits (i.e. 0-15). However, that's only a limitation of the MIDI messages. Since TSF uses functions as its interface, not MIDI messages, does it still have this restriction of only 16 channels? (Having searched the code for the number 16, I think the answer is "no", which is good, but it's safer to check with you!)

The reason I ask is because we're looking at trying to support >16 channels in our MIDI player. As far as I can tell, normally these are encoded by choosing which MIDI device to send the event to, with the assumption that each MIDI device handles just 16 channels. So channels 0-15 go to MIDI device 0, 16-31 go to MIDI device 1, 32-47 go to MIDI device 2, etc. You would configure this on your MIDI software. To record this concept in a Standard MIDI files, this is usually done by telling each track which MIDI device to use with a 0x21 (port name) or 0x9 (device name) meta-event.

Taken literally, this would mean spinning up multiple TSF instances, since TSF takes the role of an output MIDI device. However, if TSF can handle more than 16 channels, it would be far easier just to have a shim layer in front of TSF that simply receives a MIDI event for MIDI device D for channel C, and maps that to channel 16*D+C on TSF. This way we need just one instance of TSF, one audio stream connecting TSF to an audio device, etc.

schellingb commented 3 years ago

A soundfont synthesizer is usually limited by voices not channels. Because a single SF2 instrument can be built out of multiple voices that play simultaneously that is what actually matters for the mixing, not the meta layer that is MIDI. TSF by default allocates more voices when needed when new notes are requested to start. If desired, a limit can be set with tsf_set_max_voices (which can also help with multithreading concurrency, see #49).

Now TSF has 2 interfaces, one is to just play raw SF2 presets with tsf_note_on. The other is playing MIDI messages with the tsf_channel_* functions. The tsf_note_on is lower level and directly starts up voices. The tsf_channel_* functions take a channel number and it will (re-)allocate an array up to whatever number is requested. So if you were to call tsf_channel_set_presetindex(f, 5000, preset_index); it would just allocate an array for managing 5000 MIDI channels and that's it. So that also has no limit.

In short, you should be fine with just one instance :-)

chriscoomber commented 3 years ago

Great news, thanks.