Compare commits

...

2 Commits

5 changed files with 55 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ A CLI tool for processing WAV files to generate impulse responses (IR) from swee
- **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
- **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
@@ -57,6 +58,16 @@ Trim or zero-pad the output IR to a specific length (in milliseconds):
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.
### Different Output Formats
Generate IRs in different sample rates and bit depths:
@@ -116,6 +127,7 @@ Generate IRs in different sample rates and bit depths:
| `--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 |
## File Requirements
@@ -143,6 +155,10 @@ Generate IRs in different sample rates and bit depths:
- 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`
### Deconvolution Process
1. **FFT-based deconvolution** of recorded signal by sweep signal
2. **Regularization** to prevent division by zero

2
go.mod
View File

@@ -1,6 +1,6 @@
module valhallir-deconvolver
go 1.24.1
go 1.24.5
require (
dagger.io/dagger v0.18.12

19
main.go
View File

@@ -60,6 +60,11 @@ func main() {
Name: "length-ms",
Usage: "Optional: Output IR length in milliseconds (will trim or zero-pad as needed)",
},
&cli.Float64Flag{
Name: "fade-ms",
Usage: "Fade-out duration in milliseconds to apply at the end of the IR (default 5)",
Value: 5.0,
},
},
Action: func(c *cli.Context) error {
// Read sweep WAV file
@@ -135,6 +140,14 @@ func main() {
ir = convolve.TrimOrPad(ir, targetSamples)
}
// Apply fade-out
fadeMs := c.Float64("fade-ms")
fadeSamples := int(float64(targetSampleRate) * fadeMs / 1000.0)
if fadeSamples > 0 {
log.Printf("Applying linear fade-out: %d samples (%.2f ms)...", fadeSamples, fadeMs)
ir = convolve.FadeOutLinear(ir, fadeSamples)
}
// Write regular IR
log.Printf("Writing IR to: %s (%dHz, %d-bit WAV)", c.String("output"), sampleRate, bitDepth)
if err := wav.WriteWAVFileWithOptions(c.String("output"), ir, sampleRate, bitDepth); err != nil {
@@ -165,6 +178,12 @@ func main() {
mptIR = convolve.TrimOrPad(mptIR, targetSamples)
}
// Apply fade-out to MPT IR
if fadeSamples > 0 {
log.Printf("Applying linear fade-out to MPT IR: %d samples (%.2f ms)...", fadeSamples, fadeMs)
mptIR = convolve.FadeOutLinear(mptIR, fadeSamples)
}
// Generate MPT output filename
outputPath := c.String("output")
if len(outputPath) > 4 && outputPath[len(outputPath)-4:] == ".wav" {

View File

@@ -322,3 +322,22 @@ func Resample(data []float64, fromSampleRate, toSampleRate int) []float64 {
return result
}
// FadeOutLinear applies a linear fade-out to the last fadeSamples of the data.
// fadeSamples is the number of samples over which to fade to zero.
func FadeOutLinear(data []float64, fadeSamples int) []float64 {
if fadeSamples <= 0 || len(data) == 0 {
return data
}
if fadeSamples > len(data) {
fadeSamples = len(data)
}
out := make([]float64, len(data))
copy(out, data)
start := len(data) - fadeSamples
for i := start; i < len(data); i++ {
fade := float64(len(data)-i) / float64(fadeSamples)
out[i] *= fade
}
return out
}

BIN
testdata/ir.wav vendored Normal file

Binary file not shown.