Files
valhallir-deconvolver/README.md

556 lines
21 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 a `cabpack` 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 `cabpack` 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
- `cabpack` 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: `close mics` (always), plus `ambient mics`, `selection`, and `mixes` (only if corresponding files/folders exist)
- **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
- **Mixes folder support**: Convert ready-to-use IRs from `mixes` folder 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** 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` is missing, the `selection` folder is not created in any format folder.
- If `ambient.txt` is missing, the `ambient mics` folder is not created in any format folder.
- If the `mixes` folder is missing, the `mixes` subfolder is not created in any format folder.
- Files are processed for all format folders automatically.
- The `.wav` extension 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 `mixes` folder
- **Automatic conversion**: Each IR file is converted to all 9 cabpack formats
- **Format storage**: Converted IRs are stored in the `mixes` subfolder of each format folder (only created if `mixes` folder exists)
- **Plot generation**: IR visualizations are generated in the `plots/mixes` folder (only created if `mixes` folder 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:
```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).
**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:
```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 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:
```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 | `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-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 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 `--lowcut` and/or `--highcut` to specify cutoff frequencies in Hz
- Use `--cut-slope` to 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
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.2.0