Merge pull request 'Add linear fade-out to IRs with --fade-ms option (default 5ms); update README and CLI' (#1) from feature/fade-out into main
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
16
README.md
16
README.md
@@ -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
2
go.mod
@@ -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
19
main.go
@@ -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" {
|
||||
|
||||
@@ -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
BIN
testdata/ir.wav
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user