A lightweight Go library (~595K) that implements a simple SFZ sampler with WAV and FLAC sample loading.
Note: You must manually connect the JACK ports for audio and MIDI:
- Connect JACK output port
MyInstrument:out_1
andMyInstrument:out_2
to your system audio outputs - Connect your MIDI controller to JACK input port
MyInstrument:midi_in
🎵 Piano Arpeggio Sample - Generated by TestRenderPianoArpeggio
🎧 Listen to piano_arpeggio.wav
Audio file automatically updated on every successful CI run to main branch
The sample demonstrates:
- FLAC sample loading (FreePats Upright Piano KW)
- Multi-velocity layers (soft/loud playing dynamics)
- Pitch-shifting (full 88-key range from sparse sample set)
- ADSR envelope processing (attack/decay/sustain/release)
- Loop support (continuous loops for sustained notes)
- Decent-quality reverb (Freeverb algorithm with hall-like acoustics)
Primary Interface:
func NewSfzPlayer(sfzPath string, jackClientName string) (*SfzPlayer, error)
sample
- Path to the audio sample file (required)key
- Root key for the samplepitch_keycenter
- Reference pitch for the sample
lokey
- Lowest key that triggers this regionhikey
- Highest key that triggers this regionlovel
- Lowest velocity that triggers this regionhivel
- Highest velocity that triggers this region
volume
- Volume adjustment in dBpan
- Stereo panning (-100 to 100)tune
- Fine tuning in centstranspose
- Transposition in semitonespitch
- Pitch adjustment
ampeg_attack
- Attack time in secondsampeg_decay
- Decay time in secondsampeg_sustain
- Sustain level (0-100%)ampeg_release
- Release time in seconds
loop_mode
- Loop mode (no_loop, one_shot, loop_continuous, loop_sustain)loop_start
- Loop start point in samplesloop_end
- Loop end point in samples
reverb_send
- Reverb send level (0-100)reverb_room_size
- Room size parameter (0-100)reverb_damping
- Damping amount (0-100)reverb_wet
- Wet signal level (0-100)reverb_dry
- Dry signal level (0-100)reverb_width
- Stereo width (0-100)
- SFZ File Parsing: Complete parser for SFZ files with structured data representation
- Multi-Format Sample Loading: Automatic loading and caching of WAV and FLAC audio samples
- Decent-Quality Reverb: Built-in Freeverb algorithm with real-time control
- MIDI Control: Full MIDI CC support for reverb parameters (CC91-95)
- SFZ Reverb Opcodes: Support for reverb opcodes in SFZ files
- Sample Caching: Efficient caching system to avoid duplicate sample loads
- Normalized Audio Data: Audio samples normalized to float64 range (-1.0 to 1.0)
- Error Handling: Graceful handling of missing files and invalid syntax
- Debug Logging: Comprehensive logging with configurable namespaces
- Type Conversion: Helper functions for string to numeric type conversion
package main
import (
"fmt"
"gosfzplayer"
)
func main() {
// Create SFZ player - parses file, loads samples, starts JACK client
player, err := gosfzplayer.NewSfzPlayer("path/to/instrument.sfz", "MyInstrument")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Println("SFZ Player created successfully!")
// Player is now ready for MIDI input and audio output
// Use JACK connection tools like QJackCtl to connect MIDI and audio
}
Enable debug output with the DEBUG
environment variable:
# Enable all debug output
DEBUG=sfzplayer:* go run gosfzplayer.go
# Enable only parser debug output
DEBUG=sfzplayer:parser go run gosfzplayer.go
The SFZ player includes a decent-quality Freeverb implementation with low CPU usage (~5-10% overhead) and good sound quality.
// Create SFZ player
player, err := gosfzplayer.NewSfzPlayer("instrument.sfz", "MyInstrument")
// Configure reverb
player.SetReverbSend(0.3) // 30% reverb send
player.SetReverbRoomSize(0.7) // Large room size
player.SetReverbDamping(0.4) // Moderate damping
player.SetReverbWet(0.8) // High reverb level
player.SetReverbDry(0.6) // Moderate dry signal
player.SetReverbWidth(1.0) // Full stereo width
MIDI CC | Parameter | Range | Description |
---|---|---|---|
CC91 | Reverb Send | 0-127 | Standard MIDI reverb depth |
CC92 | Room Size | 0-127 | Reverb decay time |
CC93 | Damping | 0-127 | High-frequency absorption |
CC94 | Wet Level | 0-127 | Reverb signal level |
CC95 | Dry Level | 0-127 | Direct signal level |
Add reverb settings directly to your SFZ files:
<global>
reverb_send=30 // 30% reverb send
reverb_room_size=70 // Large room
reverb_damping=40 // Moderate damping
reverb_wet=80 // High wet level
reverb_dry=60 // Moderate dry level
<region>
sample=piano_c4.flac
// Inherits global reverb settings
Run tests:
go test -v
Run tests with debug output:
DEBUG=sfzplayer:* go test -v
- Go 1.22+ (toolchain 1.24.0)
- github.com/GeoffreyPlitt/debuggo v0.1.0 - for debug logging
- github.com/go-audio/wav v1.1.0 - for WAV file loading
- github.com/mewkiz/flac v1.0.12 - for FLAC file loading
- github.com/xthexder/go-jack v0.0.0-20220805234212-bc8604043aba - for JACK audio integration
Indirect dependencies:
- github.com/go-audio/audio v1.0.0
- github.com/go-audio/riff v1.0.0
- github.com/icza/bitio v1.1.0
- github.com/mewkiz/pkg v0.0.0-20230226050401-4010bf0fec14