21 KiB
Valhallir Deconvolver
A CLI tool for processing WAV files to generate impulse responses (IR) from sweep and recorded WAV files, designed for guitar speaker IR creation.
Features
- Fast FFT-based deconvolution for accurate IR extraction
- Automatic input conversion: Accepts any WAV sample rate, bit depth, or channel count
- Optional output IR length: Specify output IR length in milliseconds with --length-ms
- Optional low-cut and high-cut filtering: Apply Butterworth filters to the recorded sweep before IR extraction (--lowcut, --highcut, --cut-slope)
- Automatic fade-out: Linear fade-out at the end of the IR to avoid clicks (default 5 ms, configurable with --fade-ms)
- IR Visualization: Generate frequency response and waveform plots with
--plot-ir - Automatic Phase Correction: Detects and corrects phase-inverted recorded sweeps for consistent IR polarity
- Manual Phase Inversion: Use
--force-invert-phaseto explicitly invert the recorded sweep for testing or manual override - 96kHz 24-bit WAV file support for high-quality audio processing
- Multiple output formats with configurable sample rates and bit depths
- Minimum Phase Transform (MPT) option for reduced latency IRs
- Automatic silence trimming and normalization
- Batch processing: Process entire directories of recorded files automatically
- Cabpack generation: Create complete cabpack structures with IRs in multiple formats organized in a directory tree
- Modular design with separate packages for WAV I/O, convolution, and visualization
- Robust error handling and validation
Installation
# Clone the repository
git clone <repository-url>
cd valhallir-convoluter
# Build the application
go build -o valhallir-deconvolver
Usage
Default Mode (No Options)
If you run the tool without any command-line options, it automatically creates a cabpack:
./valhallir-deconvolver
This will:
- Use the current directory as the recorded directory
- Look for
sweep.wavin the current directory as the sweep file - Create output in a
cabpackfolder one directory level up from the current directory - Automatically enable cabpack mode
- Process all WAV files in the current directory (excluding the sweep file)
- Use
selection.txtandambient.txtfrom the current directory if present
Perfect for: Simply placing the tool in a folder with recorded WAV files and running it to create a complete cabpack in the parent directory's cabpack folder.
Basic IR Generation
Generate a standard impulse response from sweep and recorded files (any WAV format):
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav
Batch Processing (Directory Mode)
Process all WAV files in a directory of recorded files. The tool will automatically detect if --recorded is a directory and process all WAV files found in it (including subdirectories):
./valhallir-deconvolver --sweep sweep.wav --recorded ./recordings/ --output ./ir_output/
This will:
- Find all
.wavfiles in the./recordings/directory (recursively) - Process each recorded file with the same sweep file
- Generate IR files in the
./ir_output/directory - Use the original recorded filename for each output IR (e.g.,
recorded1.wav→recorded1.wav)
Note: If --output is a directory, it will be created automatically if it doesn't exist. If --output is a file path, single-file mode is used.
Example with options:
./valhallir-deconvolver \
--sweep sweep.wav \
--recorded ./recordings/ \
--output ./ir_output/ \
--mpt \
--length-ms 50 \
--sample-rate 48000 \
--bit-depth 24
This processes all WAV files in ./recordings/ and generates both regular and MPT IRs in ./ir_output/.
Cabpack Generation
Generate a complete cabpack with IRs in multiple formats organized in a structured directory tree:
Simple mode (default - no options needed):
./valhallir-deconvolver
This uses:
- Current directory as recorded directory
sweep.wavin current directory as sweep filecabpackfolder one directory level up from current directory as output- Automatically enables cabpack mode
- Excludes the sweep file from processing
Explicit mode:
./valhallir-deconvolver \
--sweep sweep.wav \
--recorded ./recordings/ \
--output ./cabpack_output/ \
--cabpack
Both modes create a cabpack structure with:
- Format folders named like
V2-1960STV 96000Hz-24bit 500ms(extracted from WAV filenames) - 9 different formats covering various sample rates, bit depths, and lengths:
- 44100Hz, 16bit, 170ms
- 44100Hz, 24bit, 170ms
- 44100Hz, 24bit, 500ms
- 48000Hz, 16bit, 170ms
- 48000Hz, 24bit, 170ms
- 48000Hz, 24bit, 500ms
- 48000Hz, 24bit, 1370ms
- 96000Hz, 24bit, 500ms
- 96000Hz, 24bit, 1370ms
- Subfolders in each format:
close mics(always), plusambient mics,selection, andmixes(only if corresponding files/folders exist) - RAW and MPT IRs in
close mics/RAWandclose mics/MPTrespectively - IR visualizations in the
plotsfolder (96000Hz format) - Automatic file organization using
selection.txtandambient.txtfiles - Mixes folder support: Convert ready-to-use IRs from
mixesfolder to all formats
The cabpack base name is automatically extracted from WAV filenames. For example, V2-1960STV-d-SM7B-A1.wav will create a cabpack named V2-1960STV.
Automatic File Organization
You can automatically populate the selection and ambient mics folders by placing text files in the recorded directory:
selection.txt: Lists filenames (one per line) to copy fromclose micstoselectionfolders. Both RAW and MPT versions are copied.ambient.txt: Lists filenames (one per line) to move fromclose micstoambient micsfolders. Both RAW and MPT versions are moved.
Example selection.txt:
V2-1960STV-d-SM7B-A1.wav
V2-1960STV-d-SM7B-A2.wav
V2-1960STV-d-SM7B-A3.wav
Example ambient.txt:
V2-1960STV-d-SM7B-B1.wav
V2-1960STV-d-SM7B-B2.wav
Notes:
- If
selection.txtis missing, theselectionfolder is not created in any format folder. - If
ambient.txtis missing, theambient micsfolder is not created in any format folder. - If the
mixesfolder is missing, themixessubfolder is not created in any format folder. - Files are processed for all format folders automatically.
- The
.wavextension is automatically added if missing in the list files.
Mixes Folder Support
If a mixes folder exists in the recorded directory, it will be processed automatically:
- Ready-to-use IRs: Place pre-processed IR files (already deconvolved) in the
mixesfolder - Automatic conversion: Each IR file is converted to all 9 cabpack formats
- Format storage: Converted IRs are stored in the
mixessubfolder of each format folder (only created ifmixesfolder exists) - Plot generation: IR visualizations are generated in the
plots/mixesfolder (only created ifmixesfolder exists)
Note: If the mixes folder is missing in the recorded directory, the mixes subfolder is not created in any format folder, and no mix processing occurs.
Example structure:
recorded/
├── sweep.wav
├── recorded1.wav
├── recorded2.wav
└── mixes/
├── mix1.wav
└── mix2.wav
This will create converted versions of mix1.wav and mix2.wav in all format folders under the mixes subfolder, plus plots in plots/mixes/.
With Minimum Phase Transform
Generate both regular and minimum phase IRs:
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --mpt
This creates:
ir.wav- Standard impulse responseir_mpt.wav- Minimum phase transform version
Limit Output IR Length
Trim or zero-pad the output IR to a specific length (in milliseconds):
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --length-ms 100
This will ensure the output IR is exactly 100 ms long (trimming or zero-padding as needed).
Fade-Out to Avoid Clicks
By default, a 5 ms linear fade-out is applied to the end of the IR to avoid clicks. You can change the fade duration:
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --fade-ms 10
This applies a 10 ms fade-out at the end of the IR.
Filtering the Recorded Sweep
You can apply a low-cut (high-pass) and/or high-cut (low-pass) filter to the recorded sweep before IR extraction. This is useful for removing rumble, DC, or high-frequency noise:
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --lowcut 40 --highcut 18000
This applies a 40 Hz low-cut (high-pass) and 18 kHz high-cut (low-pass) filter to the recorded sweep.
You can control the filter steepness (slope) with --cut-slope (in dB/octave, default 12). For example:
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --lowcut 40 --highcut 18000 --cut-slope 24
This applies a 40 Hz low-cut and 18 kHz high-cut, both with a 24 dB/octave slope (steeper than the default 12).
Filter Implementation: The tool uses Linkwitz-Riley design principles with Direct Form II Transposed filter structures for optimal numerical stability and minimal artifacts, even at very steep slopes (48+ dB/octave). The filters are designed to provide clean cutoffs without introducing unwanted artifacts in the frequency response.
Automatic Phase Correction
Valhallir Deconvolver automatically detects and corrects phase-inverted recorded sweeps to ensure consistent IR polarity. This is especially important when mixing multiple IRs later.
By default, the tool:
- Detects phase inversion by analyzing the correlation between sweep and recorded signals
- Automatically corrects phase-inverted recorded sweeps
- Ensures consistent polarity across all generated IRs
If you know your recorded sweep has the correct phase, you can disable automatic correction:
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --no-phase-correction
Forcing Phase Inversion (Testing/Manual Override)
You can force the recorded sweep to be inverted (regardless of automatic detection) using:
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --force-invert-phase
This is useful for testing or if you know your recorded sweep is out of phase and want to override the automatic detection.
IR Visualization
Generate frequency response and waveform plots of your IRs:
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --plot-ir
This creates:
ir.wav- The impulse response fileir.png- A professional plot showing frequency response and waveform
The plot includes:
- Frequency Response: dB vs Hz with log frequency scale (20Hz-20kHz)
- Waveform: Time-domain view of the first 10ms of the IR
- Valhallir Branding: Logo displayed in upper-left corner and filename information
- Professional Layout: Clean, publication-ready visualization
Note: The logo is embedded directly in the binary, so no external assets folder is required. The logo will always be available regardless of where the binary is located or how it's executed.
Different Output Formats
Generate IRs in different sample rates and bit depths:
# 44kHz 16-bit (CD quality)
./valhallir-deconvolver \
--sweep sweep.wav \
--recorded recorded.wav \
--output ir_cd.wav \
--sample-rate 44100 \
--bit-depth 16
# 48kHz 32-bit (studio quality)
./valhallir-deconvolver \
--sweep sweep.wav \
--recorded recorded.wav \
--output ir_studio.wav \
--sample-rate 48000 \
--bit-depth 32 \
--mpt
# 96kHz 24-bit (high resolution)
./valhallir-deconvolver \
--sweep sweep.wav \
--recorded recorded.wav \
--output ir_hires.wav \
--sample-rate 96000 \
--bit-depth 24
Advanced Options
./valhallir-deconvolver \
--sweep sweep.wav \
--recorded recorded.wav \
--output ir.wav \
--mpt \
--sample-rate 48000 \
--bit-depth 24 \
--normalize 0.95 \
--trim-threshold 0.001 \
--length-ms 50
Command Line Options
| Flag | Description | Default | Required |
|---|---|---|---|
--sweep |
Path to sweep WAV file (any format) | sweep.wav in current directory |
No |
--recorded |
Path to recorded WAV file or directory containing WAV files | Current directory | No |
--output |
Path to output IR WAV file or directory for batch processing | cabpack folder one directory level up from recorded directory |
No |
--mpt |
Generate minimum phase transform IR | false | No |
--sample-rate |
Output sample rate (44, 48, 88, 96 kHz) | 96000 | No |
--bit-depth |
Output bit depth (16, 24, 32 bit) | 24 | No |
--normalize |
Normalize output to peak value (0.0-1.0) | 0.95 | No |
--trim-threshold |
Silence threshold for trimming (0.0-1.0) | 0.001 | No |
--length-ms |
Output IR length in milliseconds (trim or zero-pad) | - | No |
--fade-ms |
Fade-out duration in milliseconds at end of IR (default 5) | 5 | No |
--lowcut |
Low-cut filter (high-pass) cutoff frequency in Hz (recorded sweep) | - | No |
--highcut |
High-cut filter (low-pass) cutoff frequency in Hz (recorded sweep) | - | No |
--cut-slope |
Filter slope in dB/octave (12, 24, 36, ...; default 12) | 12 | No |
--plot-ir |
Generate frequency response and waveform plot | false | No |
--no-phase-correction |
Disable automatic phase correction | false | No |
--force-invert-phase |
Force inversion of the recorded sweep (manual override) | false | No |
--cabpack |
Generate a cabpack with IRs in multiple formats organized in a directory tree | false | No |
File Requirements
Input Files
- Format: Any uncompressed WAV file
- Sample Rate: Any (will be automatically resampled to 96kHz for processing)
- Bit Depth: Any (16, 24, 32-bit supported; will be converted to float64 internally)
- Channels: Any (mono, stereo, or multi-channel; will be converted to mono by averaging channels)
Output Files
- Format: WAV files
- Sample Rate: 44kHz, 48kHz, 88kHz, or 96kHz (set by
--sample-rate) - Bit Depth: 16-bit, 24-bit, or 32-bit (set by
--bit-depth) - Channels: Mono (1 channel)
Technical Details
Input Conversion
- All input files are automatically converted to mono, 96kHz, float64 for processing
- Stereo or multi-channel files are averaged to mono
- Sample rates are resampled to 96kHz using linear interpolation
- Bit depths are normalized to float64
Output IR Length
- If
--length-msis set, the output IR (and MPT IR) will be trimmed or zero-padded to the specified length in milliseconds - If not set, the full IR is used
Fade-Out
- By default, a 5 ms linear fade-out is applied to the end of the IR (and MPT IR) to avoid clicks
- You can change the fade duration with
--fade-ms
Filtering
- You can apply a low-cut (high-pass) and/or high-cut (low-pass) filter to the recorded sweep before IR extraction
- Uses Linkwitz-Riley design principles with Direct Form II Transposed structures for optimal stability
- Use
--lowcutand/or--highcutto specify cutoff frequencies in Hz - Use
--cut-slopeto control the filter steepness (12 dB/octave = gentle, 24+ = steeper) - The filter implementation is designed to provide clean cutoffs without artifacts, even at very steep slopes (48+ dB/octave)
Deconvolution Process
- FFT-based deconvolution of recorded signal by sweep signal
- Regularization to prevent division by zero
- Silence trimming to remove leading/trailing silence
- Normalization to prevent clipping
Minimum Phase Transform
- Uses real cepstrum method for accurate minimum phase conversion
- Reduces latency by minimizing pre-ringing
- Maintains frequency response while optimizing phase characteristics
- Suitable for real-time applications like guitar amp modeling
IR Visualization
- Frequency Response Plot: Shows magnitude response in dB vs Hz with log frequency scale
- Waveform Plot: Displays the first 10ms of the IR in the time domain
- Professional Layout: Clean, publication-ready plots with Valhallir branding
- Automatic File Naming: Plots are saved with the same base name as the IR file
- High-Quality Output: PNG format suitable for documentation and sharing
Phase Correction
- Automatic Detection: Analyzes correlation between sweep and recorded signals to detect phase inversion
- Smart Correction: Uses the first 100ms of signals for reliable phase analysis
- Consistent Polarity: Ensures all IRs have the same phase polarity for easy mixing
- Optional Disable: Use
--no-phase-correctionif you know the phase is correct
Output Format Options
- Sample Rates: 44.1kHz (CD), 48kHz (studio), 88.2kHz, 96kHz (high-res)
- Bit Depths: 16-bit (CD), 24-bit (studio), 32-bit (high-res)
- File Sizes: 16-bit ≈ 50% smaller, 32-bit ≈ 33% larger than 24-bit
Dependencies
- urfave/cli - CLI framework
- go-audio/wav - WAV file I/O
- go-dsp/fft - FFT implementation
- gonum - Numerical computing
Examples
Guitar Cabinet IR (CD Quality)
# Generate IR from guitar cab sweep and recording (any WAV format), 50ms length
./valhallir-deconvolver \
--sweep guitar_cab_sweep.wav \
--recorded guitar_cab_recorded.wav \
--output cab_ir_cd.wav \
--sample-rate 44100 \
--bit-depth 16 \
--length-ms 50 \
--mpt
Room Acoustics IR (Studio Quality)
# Generate room impulse response
./valhallir-deconvolver \
--sweep room_sweep.wav \
--recorded room_recorded.wav \
--output room_ir_studio.wav \
--sample-rate 48000 \
--bit-depth 24
High-Resolution IR (Mastering)
# Generate high-resolution IR for mastering
./valhallir-deconvolver \
--sweep mastering_sweep.wav \
--recorded mastering_recorded.wav \
--output mastering_ir.wav \
--sample-rate 96000 \
--bit-depth 32 \
--length-ms 100 \
--mpt
Cabpack Generation
# Generate a complete cabpack with all formats
./valhallir-deconvolver \
--sweep sweep.wav \
--recorded ./recordings/ \
--output ./cabpack_output/ \
--cabpack
This will process all WAV files in ./recordings/ and create a complete cabpack structure with IRs in 9 different formats, organized in folders with RAW and MPT versions, plus visualization plots.
CI/CD & Multi-Platform Builds
This project includes a Dagger pipeline for building binaries for multiple platforms:
- macOS ARM64 (darwin/arm64)
- macOS AMD64 (darwin/amd64)
- Windows AMD64 (windows/amd64)
- Linux AMD64 (linux/amd64)
The pipeline is defined in ci/dagger.go. It outputs binaries named valhallir-deconvolver-<os>-<arch> in the dist/ directory.
Usage
- Install the Dagger Go SDK and dependencies:
go install dagger.io/dagger@latest go get github.com/joho/godotenv go mod tidy - Build for all platforms:
go run ci/dagger.go - (Optional) Upload binaries to a Gitea release:
- Create a
.envfile in the project root with:GITEA_TOKEN=your_token GITEA_URL=https://your.gitea.server GITEA_OWNER=youruser GITEA_REPO=yourrepo - Run:
go run ci/dagger.go --release v1.0.0 - This will create (if needed) and upload all binaries to the specified release tag on your Gitea instance.
- The pipeline will also create and push a local git tag for the release if it does not already exist.
- Create a
Troubleshooting Dagger
- If you see
could not import dagger.io/dagger, make sure you have installed the Dagger Go SDK and rungo mod tidy. - The pipeline requires Docker or a compatible container runtime.
- For Gitea upload, ensure your
.envfile is present and correct.
Troubleshooting
Common Issues
Input file errors
- Input files must be uncompressed WAV format. MP3, FLAC, or other compressed formats are not supported.
- Input sample rate, bit depth, and channel count are automatically converted (no need to preprocess).
"Invalid sample rate" error (output)
- Use only supported output sample rates: 44100, 48000, 88200, 96000
- Check the
--sample-rateflag value
"Invalid bit depth" error (output)
- Use only supported output bit depths: 16, 24, 32
- Check the
--bit-depthflag value
Dagger pipeline errors
- If you see
could not import dagger.io/dagger, install the Dagger Go SDK and rungo mod tidy. - Make sure Docker or a compatible container runtime is running.
Performance
- Processing time depends on file length
- FFT-based deconvolution is much faster than time-domain methods
- Large files (>1GB) may take several minutes
- Higher bit depths require more memory but don't significantly affect processing time
License
[Add your license information here]
Contributing
[Add contribution guidelines here]
Changelog
See CHANGELOG.md for version history and details. Current version: v1.2.0