Sound Bank
This module handles parsing and writing SoundFont2 (.sf2
, .sf3
and .sfogg
) files.
It also contains support for .dls
files.
Tip
If you encounter any errors in this documentation, please open an issue!
Specifications
Initialization
buffer
- AnArrayBuffer
representing the binary file data either DLS level 1/2 or SoundFont2.
The returned value is the parsed BasicSoundBank
, described below.
Methods
getPreset
Returns the matching Preset
class instance.
bankNr
- MIDI bank number, typically set with theBank Select
controller.presetNr
- MIDI program number, usually set with theProgram Change
message.
If the matching preset is not found, the first preset will be returned. If the requested bank is 128, the first preset with bank 128 will be returned (drums).
getPresetByName
Returns the matching Preset
class instance.
presetName
- The name of the preset as a string. If not found, the first preset will be returned.
write
Write out an SF2 or SF3 file. The return value is an Uint8Array
- the binary of the file.
options
- An optional object:writeDefaultModulators
- aboolean
indicating if the DMOD chunk should be written. Defaults to true.writeExtendedLimits
- if the xdta chunk should be written to allow virtually infinite parameters. Defaults to true.compress
- Aboolean
indicating if any uncompressed samples should be compressed using the lossy Ogg Vorbis codec. This significantly reduces file size. Defaults to false.decompress
- Aboolean
indicating if any compressed samples should be decompressed. If false, the compressed samples are preserved which results in faster write time and no quality loss. Defaults to false and not recommended.progressFunction
- See this for a detailed explanationcompressionFunction
- See this for a detailed explanation
Important
This function is asynchronous.
Note
If the sound bank was already compressed, it will not be decompressed to avoid losing quality.
Warning
This method is memory and CPU intensive with large sound banks, especially if compression is enabled.
writeDLS
Writes out a DLS Level 2 sound bank. The returned value is an Uint8Array
- the binary of the file.
options
- An optional object:progressFunction
- See this for a detailed explanation
Caution
This method is experimental and may produce corrupted files. See this for more info.
Important
This method is asynchronous.
Warning
This method is memory and CPU intensive with large sound banks.
mergeSoundfonts
Merges multiple SoundFonts, adding (not replacing) presets on top of the previous ones, and returns a new soundBank.
soundfonts
-BasicSoundBank
instances, with any number of inputs. The first is used as a base, and the rest are added on top.
The return value is a new BasicSoundBank
.
The INFO data is taken from the first sound bank
Note
This method is static.
trimSoundBank
Trims the SoundFont in place to only include samples used in the MIDI sequence, down to the exact key-velocity combinations.
midi
-MIDI
- The MIDI file for which to trim the soundBank.
getDummySoundfontFile
Creates a fake soundfont with a single saw wave preset. Useful when a synthesizer initialization is needed but the proper soundfont is not ready yet.
- the returned value is an
ArrayBuffer
- the binary represenation of a soundfont file.
Note
This method is static and asynchronous
Properties
isSF3DecoderReady
A Promise object indicating if the SF3/SF2Pack decoder is ready. Make sure to await it if you are loading SF3/SF2Pack files. It only needs to be awaited once, globally. Then all banks can be loaded synchronously.
Note
this property is static.
presets
An array of all presets in the bank, ordered by bank and preset number.
instruments
An array of all instruments in the bank, not ordered.
samples
An array of all samples in the bank, not ordered.
An array of all instruments in the bank, not ordered.
soundFontInfo
Represents the SoundFont2’s INFO
chunk data. Stored as an object like this:
const infoData = {
chunk: /* the read's 4-letter code, e.g. */ "INAM",
infoText: /* the read's data as text, e.g. */ "My cool SoundFont"
}
Check out this website for more information.
Important
ifil
and iver
are stored as strings like this: major.minor
.
For example, major 2 minor 1 will be 2.1
defaultModulators
All the default modulators for this bank. A list of Modulator Objects
customDefaultModulators
A boolean, indicating if the bank uses the DMOD chunk.
Sound bank Internal Structure
The following describes the internal structure of the sound bank and includes some methods not mentioned above. Useful for editing the sound bank.
BasicSoundBank structure
soundFontInfo
(described above)instruments
(BasicInstrument[]) -> All instruments.instrumentName
(string) -> The name of the instrument.globalZone
(BasicGlobalZone) -> The global zone of this instrument.keyRange
({min: number, max: number}) -> Key range of the zone.velRange
({min: number, max: number}) -> Velocity range of the zone.generators
(Generator[]) -> Generators of the zone.modulators
(Modulator[]) -> Modulators of the zone.linkedPresets
(BasicPreset[]) -> All the presets that are using this instrument. Note that there may be duplicates of the same preset if it uses the sample multiple times.instrumentZones
(InstrumentZone[]) -> All zones of the instrument.keyRange
({min: number, max: number}) -> Key range of the zone.velRange
({min: number, max: number}) -> Velocity range of the zone.generators
(Generator[]) -> Generators of the zone.modulators
(Modulator) -> Modulators of the zone.globalZone
(BasicZone) -> The global zone of this instrument.sample
(BasicSample) -> The sample of the zone. Undefined if global.- See Sample class
samples
(BasicSample[]) -> All samples.presets
(BasicPreset[]) -> All presets.presetName
(string) -> The name of the preset.program
(number) -> The preset’s MIDI program.bank
(number) -> The preset’s MIDI bank.library
(number) -> Generally unused but preserved.genre
(number) -> Generally unused but preserved.morphology
(number) -> Generally unused but preserved.globalZone
(BasicGlobalZone) -> The global zone of this preset.presetZones
(PresetZone[]) -> All zones of the preset.keyRange
({min: number, max: number}) -> Key range of the zone.velRange
({min: number, max: number}) -> Velocity range of the zone.generators
(Generator[]) -> Generators of the zone.modulators
(Modulator[]) -> Modulators of the zone.instrument
(BasicInstrument) -> The zone’s instrument. Undefined if global.
progressFunction
This optional function gets called after every sample has been written. It can be useful for displaying progress for long writing operations.
It takes the following arguments:
- sampleName -
string
- sample’s name. - writtenCount -
number
- the count of written samples so far. - totalSampleCount -
number
- the total number of samples.
Please note that it’s usually only effective when writing with compression, as raw writing is inlined for speed.
compressionFunction
This function must be provided if compress
is enabled.
The function takes the following arguments:
- audioData: a
Float32Array
with the sample data. - sampleRate: in Hertz.
The function is recommended to be asynchronous.
It must return an Uint8Array
instance containing the compressed bitstream.
Note
Note that using a custom function allows for using any type of compression for the SF3 soundBank. This is allowed by the RFC describing SF3 spec, but SpessaSynth can only read Ogg Vorbis compression.
Import your function:
Then pass it to the write method:
Why is it not bundled?
Importing it into the package would increase the size with the entire 1.1MB encoder, which would be unnecessary if the functionality is not used. This approach ensures that only software that uses this functionality can rely on this large file.