A command-line tool to generate SFZ files from audio samples, using intelligent filename parsing.
Based on the soundmap project by KMIJPH, this Go implementation provides the same filename parsing logic in a standalone CLI tool.
- Intelligent filename parsing: Automatically detects MIDI note numbers, note names, dynamics, and round-robin information from filenames
- Configurable envelope: Customize ADSR envelope parameters and loop modes
- Key range stretching: Optionally stretches sample key ranges to fill gaps
- Velocity mapping: Automatically maps dynamics to velocity ranges
- Round-robin support: Detects and properly sequences round-robin samples
- Multiple audio formats: Supports WAV, MP3, FLAC, OGG, AIF, AIFF, M4A
- Go 1.21 or later
make build # Build the executable in the current directory
make test # Run tests
make lint # Run golangci-lint
make install # Install to $GOPATH/binNote: The lint target requires golangci-lint to be installed.
Basic usage:
./sfzgen --input /path/to/samples --output output.sfzNAME:
sfzgen - Generate SFZ files from audio samples
USAGE:
sfzgen [global options]
VERSION:
1.0.0
DESCRIPTION:
sfzgen automatically generates SFZ sampler files from a directory of audio samples.
It intelligently parses filenames to extract musical information like note names,
MIDI numbers, dynamics, and round-robin variations.
FILENAME PARSING RULES:
- Parts separated by underscore (_) or dot (.)
- First part: key name (e.g., c4, c#4, bb3) or MIDI note number (0-127)
- Optional: dynamic marking (pp, p, mp, mf, f, ff)
- Optional: round-robin number (integer)
EXAMPLES:
bongo_c4_p_3.wav -> C4, piano dynamic, round-robin 3
piano_60_mf.wav -> MIDI note 60, mezzo-forte
kick_36.wav -> MIDI note 36, no dynamic
AUTHOR:
Based on soundmap by KMIJPH (codeberg.org/KMIJPH/soundmap)
GLOBAL OPTIONS:
--help, -h show help
--quiet, -q suppress informational output
--version, -v print the version
Envelope settings
--attack float envelope attack time in seconds (default: 0)
--decay float envelope decay time in seconds (default: 0)
--delay float envelope delay time in seconds (default: 0)
--loop-mode string loop mode: no_loop, one_shot, loop_continuous, loop_sustain (default: "no_loop")
--release float envelope release time in seconds (default: 0.001)
--sustain float envelope sustain level (0-100) (default: 100)
Input/Output
--input string, -i string input directory containing audio files (default: ".")
--output string, -o string output SFZ file path (default: "output.sfz")
Key mapping
--c4 int, -c int MIDI note number for C4 reference (default: 60)
--stretch, -s stretch key ranges to fill gaps
Generate SFZ from samples in a directory:
./sfzgen -i ./samples -o piano.sfzUse a different C4 reference (e.g., for non-standard tuning):
./sfzgen -i ./samples -o piano.sfz -c 72Disable key stretching:
./sfzgen -i ./samples -o piano.sfz --stretch=falseQuiet mode (no output except errors):
./sfzgen -i ./samples -o piano.sfz -qCustom envelope settings for a pad sound:
./sfzgen -i ./samples -o pad.sfz --attack 0.5 --release 2.0 --sustain 80Looping samples:
./sfzgen -i ./samples -o loops.sfz --loop-mode loop_continuousComplete example with all envelope settings:
./sfzgen -i ./samples -o custom.sfz \
--attack 0.01 \
--decay 0.3 \
--sustain 70 \
--release 1.5 \
--delay 0.0 \
--loop-mode loop_sustainShow help:
./sfzgen --helpThe tool allows customization of ADSR (Attack, Decay, Sustain, Release) envelope parameters and loop mode:
- Attack: Time in seconds for the sound to reach full volume (default: 0.0)
- Decay: Time in seconds for the sound to decay from peak to sustain level (default: 0.0)
- Sustain: Level (0-100) at which the sound is held while a note is pressed (default: 100.0)
- Release: Time in seconds for the sound to fade out after note release (default: 0.001)
- Delay: Time in seconds before the envelope starts (default: 0.0)
no_loop: Play sample once, no looping (default)one_shot: Play sample once, ignore note-offloop_continuous: Loop continuously while note is heldloop_sustain: Loop during sustain phase, then continue to end
The tool parses filenames by splitting on underscores (_) and dots (.). It looks for these components in order:
-
Key number or note name (required):
- MIDI note number:
0to127 - Note name:
c4,c#4,bb3,f#5, etc.
- MIDI note number:
-
Dynamic marking (optional):
pp(pianissimo)p(piano)mp(mezzo-piano)mf(mezzo-forte)f(forte)ff(fortissimo)
-
Round-robin number (optional):
- Any integer value
bongo_c4_p_3.wav→ C4, piano dynamic, round-robin 3piano_60_mf.wav→ MIDI note 60 (C4), mezzo-fortekick_36.wav→ MIDI note 36, no dynamicsnare_d3_ff_1.mp3→ D3, fortissimo, round-robin 1hihat_42.flac→ MIDI note 42, no dynamicbass_bb3.wav→ B♭3 (MIDI 58), no dynamicguitar_b4_f.wav→ B4 (MIDI 71), forte
Files that don't contain a valid key number or note name will be skipped with a warning.
- Scanning: Recursively scans the input directory for audio files
- Parsing: Parses each filename to extract musical information
- Processing:
- Groups samples by key number and dynamic
- Stretches key ranges if enabled
- Fixes round-robin numbering
- Calculates velocity ranges based on dynamics
- Writing: Generates an SFZ file with proper region mappings
The generated SFZ file includes:
- Default envelope settings (attack, decay, sustain, release)
- Loop mode configuration
- Per-sample regions with:
- Sample path
- Pitch key center
- Key range (lokey/hikey)
- Velocity range (lovel/hivel)
- Round-robin sequencing (seq_length/seq_position)
This Go implementation is based on the core filename parsing logic from the PureScript soundmap project, with improvements:
- ✅ Same filename parsing rules
- ✅ Same dynamic marking detection
- ✅ Same round-robin handling
- ✅ Same key range stretching algorithm
- ✅ Same velocity mapping
- ✅ Fixed: Correct note name to MIDI conversion (the original had a bug where 'B' notes were parsed as 'A')
Improvements:
- Standalone CLI tool with proper command-line interface
- Correct parsing of B notes (e.g.,
bb3→ B♭3/MIDI 58, not A♭3/MIDI 56) - Configurable envelope settings (attack, decay, sustain, release, delay, loop mode)
- Short flag aliases for convenience (
-i,-o,-q, etc.) - Quiet mode for scripting
- Better error handling and messages with validation
Scope Changes:
- Only generates SFZ format (not DecentSampler)
- Command-line only (no web interface)
- Simpler configuration (flags instead of UI)
The generated SFZ files conform to the official SFZ specification and are compatible with:
-
SFZ Players:
- sforzando (Plogue)
- LinuxSampler
- Sfizz
- Carla (SFZ plugin)
- ARIA Engine (Plogue)
-
DAWs with SFZ support:
- Reaper (via ReaSamplomatic5000 or SFZ plugins)
- Ardour (via LinuxSampler)
- LMMS
Tested Opcodes: All opcodes used in the generated files are part of the SFZ 1.0 specification and widely supported:
- Basic sample mapping:
sample,pitch_keycenter,lokey,hikey - Velocity layers:
lovel,hivel - Round-robin:
seq_length,seq_position - Envelope:
ampeg_attack,ampeg_decay,ampeg_sustain,ampeg_release,ampeg_delay - Looping:
loop_mode
GPL-3.0 (same as the original soundmap project)
Based on soundmap by KMIJPH.