524 lines
19 KiB
Markdown
524 lines
19 KiB
Markdown
# 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-phase` to 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
|
|
|
|
```sh
|
|
# 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:
|
|
|
|
```sh
|
|
./valhallir-deconvolver
|
|
```
|
|
|
|
This will:
|
|
- Use the current directory as the recorded directory
|
|
- Look for `sweep.wav` in the current directory as the sweep file
|
|
- Create output in an `IRs` folder 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.txt` and `ambient.txt` from 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 `IRs` folder.
|
|
|
|
### Basic IR Generation
|
|
|
|
Generate a standard impulse response from sweep and recorded files (any WAV format):
|
|
|
|
```sh
|
|
./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):
|
|
|
|
```sh
|
|
./valhallir-deconvolver --sweep sweep.wav --recorded ./recordings/ --output ./ir_output/
|
|
```
|
|
|
|
This will:
|
|
- Find all `.wav` files 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:**
|
|
```sh
|
|
./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):**
|
|
```sh
|
|
./valhallir-deconvolver
|
|
```
|
|
This uses:
|
|
- Current directory as recorded directory
|
|
- `sweep.wav` in current directory as sweep file
|
|
- `IRs` folder one directory level up from current directory as output
|
|
- Automatically enables cabpack mode
|
|
- Excludes the sweep file from processing
|
|
|
|
**Explicit mode:**
|
|
```sh
|
|
./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: `ambient mics`, `close mics`, `mixees`, `selection`
|
|
- **RAW and MPT IRs** in `close mics/RAW` and `close mics/MPT` respectively
|
|
- **IR visualizations** in the `plots` folder (96000Hz format)
|
|
- **Automatic file organization** using `selection.txt` and `ambient.txt` files
|
|
|
|
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** from `close mics` to `selection` folders. Both RAW and MPT versions are copied.
|
|
- **`ambient.txt`**: Lists filenames (one per line) to **move** from `close mics` to `ambient mics` folders. 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.txt` or `ambient.txt` are missing, those operations are skipped (no error).
|
|
- Files are processed for all format folders automatically.
|
|
- The `.wav` extension is automatically added if missing in the list files.
|
|
- The `mixees` folder is left empty for manual filling.
|
|
|
|
### With Minimum Phase Transform
|
|
|
|
Generate both regular and minimum phase IRs:
|
|
|
|
```sh
|
|
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --mpt
|
|
```
|
|
|
|
This creates:
|
|
- `ir.wav` - Standard impulse response
|
|
- `ir_mpt.wav` - Minimum phase transform version
|
|
|
|
### Limit Output IR Length
|
|
|
|
Trim or zero-pad the output IR to a specific length (in milliseconds):
|
|
|
|
```sh
|
|
./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:
|
|
|
|
```sh
|
|
./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:
|
|
|
|
```sh
|
|
./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:
|
|
|
|
```sh
|
|
./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).
|
|
|
|
### 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:
|
|
|
|
```sh
|
|
./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:
|
|
|
|
```sh
|
|
./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:
|
|
|
|
```sh
|
|
./valhallir-deconvolver --sweep sweep.wav --recorded recorded.wav --output ir.wav --plot-ir
|
|
```
|
|
|
|
This creates:
|
|
- `ir.wav` - The impulse response file
|
|
- `ir.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 and filename information
|
|
- **Professional Layout:** Clean, publication-ready visualization
|
|
|
|
### Different Output Formats
|
|
|
|
Generate IRs in different sample rates and bit depths:
|
|
|
|
```sh
|
|
# 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
|
|
|
|
```sh
|
|
./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 | `IRs` 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-ms` is 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 Butterworth low-cut (high-pass) and/or high-cut (low-pass) filter to the recorded sweep before IR extraction
|
|
- Use `--lowcut` and/or `--highcut` to specify cutoff frequencies in Hz
|
|
- Use `--cut-slope` to control the filter steepness (12 dB/octave = gentle, 24+ = steeper)
|
|
|
|
### Deconvolution Process
|
|
1. **FFT-based deconvolution** of recorded signal by sweep signal
|
|
2. **Regularization** to prevent division by zero
|
|
3. **Silence trimming** to remove leading/trailing silence
|
|
4. **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-correction` if 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](https://github.com/urfave/cli) - CLI framework
|
|
- [go-audio/wav](https://github.com/go-audio/wav) - WAV file I/O
|
|
- [go-dsp/fft](https://github.com/mjibson/go-dsp) - FFT implementation
|
|
- [gonum](https://gonum.org/) - Numerical computing
|
|
|
|
## Examples
|
|
|
|
### Guitar Cabinet IR (CD Quality)
|
|
```sh
|
|
# 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)
|
|
```sh
|
|
# 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)
|
|
```sh
|
|
# 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
|
|
```sh
|
|
# 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`](./ci/dagger.go). It outputs binaries named `valhallir-deconvolver-<os>-<arch>` in the `dist/` directory.
|
|
|
|
### Usage
|
|
|
|
1. Install the Dagger Go SDK and dependencies:
|
|
```sh
|
|
go install dagger.io/dagger@latest
|
|
go get github.com/joho/godotenv
|
|
go mod tidy
|
|
```
|
|
2. Build for all platforms:
|
|
```sh
|
|
go run ci/dagger.go
|
|
```
|
|
3. (Optional) Upload binaries to a Gitea release:
|
|
- Create a `.env` file in the project root with:
|
|
```
|
|
GITEA_TOKEN=your_token
|
|
GITEA_URL=https://your.gitea.server
|
|
GITEA_OWNER=youruser
|
|
GITEA_REPO=yourrepo
|
|
```
|
|
- Run:
|
|
```sh
|
|
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.**
|
|
|
|
### Troubleshooting Dagger
|
|
- If you see `could not import dagger.io/dagger`, make sure you have installed the Dagger Go SDK and run `go mod tidy`.
|
|
- The pipeline requires Docker or a compatible container runtime.
|
|
- For Gitea upload, ensure your `.env` file 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-rate` flag value
|
|
|
|
**"Invalid bit depth" error (output)**
|
|
- Use only supported output bit depths: 16, 24, 32
|
|
- Check the `--bit-depth` flag value
|
|
|
|
**Dagger pipeline errors**
|
|
- If you see `could not import dagger.io/dagger`, install the Dagger Go SDK and run `go 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](./CHANGELOG.md) for version history and details. Current version: v1.0.0 |