# 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)
- **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
- **Modular design** with separate packages for WAV I/O and convolution
- **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

### 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
```

### 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).

### 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) | - | Yes |
| `--recorded` | Path to recorded WAV file (any format) | - | Yes |
| `--output` | Path to output IR WAV file | - | Yes |
| `--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 |

## 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

### 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
```

## 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 