mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-15 06:52:23 +00:00
The SoundFont 2 reader of LoopCraft's loopcraft-audiofile crate (sf2.rs at storytold/loopcraft@0d150c1), over a neutral model of its own: the sample pool, presets and resolved key/velocity regions with tuning, loop points, pan, gain and volume envelope. The fixture writer its tests use is the test-support feature, so readers in other crates can test with real files. Co-authored-by: bflatastic <bombayapirat@gmail.com>
55 lines
2.6 KiB
Markdown
55 lines
2.6 KiB
Markdown
# craft-sf2
|
|
|
|
SoundFont 2 (`.sf2`) files, read. Bytes in, a neutral model out; no file access, no
|
|
dependencies beyond `thiserror`, builds for wasm32.
|
|
|
|
```rust
|
|
let bytes = craft_sf2::fixture::build(&[], &[], 1); // any .sf2 file's bytes
|
|
match craft_sf2::read(&bytes) {
|
|
Ok(font) => println!("{}: {} presets, {} frames", font.name, font.presets.len(), font.pool.len()),
|
|
Err(e) => println!("{e}"),
|
|
}
|
|
```
|
|
|
|
(The example needs the `test-support` feature for `fixture`.)
|
|
|
|
## The model
|
|
|
|
- `SoundFont`: the file's name, the sample pool (every sample end to end, mono `f32` at full
|
|
scale ±1) and the presets, ordered by bank and program.
|
|
- `Preset`: name, bank, program and its `Region`s.
|
|
- `Region`: what one preset zone and one instrument zone sound together: key and velocity range,
|
|
the pool frames it plays and loops over, the recorded sample rate, the fractional root key
|
|
(with every tuning applied), pan, linear gain and a volume `Envelope`.
|
|
|
|
Resolving zones is done here, as the specification describes: a first zone without an
|
|
instrument (or sample) is global, instrument generators are absolute, preset generators are
|
|
added to them, and key and velocity ranges intersect.
|
|
|
|
Honoured: keyRange, velRange, instrument, sampleID, overridingRootKey, coarseTune, fineTune (with
|
|
the sample's pitch correction), sampleModes (loop or not), the start, end and loop address
|
|
offsets (fine and coarse), pan, initialAttenuation and the volume envelope's attack, decay,
|
|
sustain and release. Ignored: modulators, the filter, the modulation envelope, both LFOs, the
|
|
chorus and reverb sends, the volume envelope's delay, hold and key scaling, scaleTuning,
|
|
exclusiveClass, the fixed key and velocity, the 24-bit extension (`sm24`) and ROM samples.
|
|
|
|
## Limits
|
|
|
|
Input is hostile. Every offset is checked against the file; a file whose chunks run past its
|
|
end is an error, not played in part. The pool is read up to `MAX_POOL_FRAMES` (2^28) frames and
|
|
regions are clamped to it. Reading stops after 2^24 generators and a file may make at most 65,536
|
|
regions (`Error::TooManyZones`), so a file that points every preset zone at the same long lists
|
|
cannot multiply itself out. A font with nothing that can sound is `Error::Empty`.
|
|
|
|
## Features
|
|
|
|
- `test-support`: `fixture::build`, a writer of small valid SoundFont 2 files, for the tests of
|
|
crates that read SoundFonts. Not a general SoundFont writer.
|
|
|
|
## Sources and clean room
|
|
|
|
Written from the SoundFont 2.04 Technical Specification (E-mu Systems / Creative Technology,
|
|
2006). No other product's code or data was used. The code comes from LoopCraft's
|
|
`loopcraft-audiofile` crate; the tests build every file they read in code, so the crate ships no
|
|
binary test data.
|