Add --cut-slope option for filter steepness (default 12 dB/oct); cascade biquads for steeper slopes; update docs
This commit is contained in:
14
README.md
14
README.md
@@ -7,7 +7,7 @@ A CLI tool for processing WAV files to generate impulse responses (IR) from swee
|
|||||||
- **Fast FFT-based deconvolution** for accurate IR extraction
|
- **Fast FFT-based deconvolution** for accurate IR extraction
|
||||||
- **Automatic input conversion:** Accepts any WAV sample rate, bit depth, or channel count
|
- **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 output IR length:** Specify output IR length in milliseconds with --length-ms
|
||||||
- **Optional low-cut and high-cut filtering:** Apply 2nd-order Butterworth filters to the recorded sweep before IR extraction (--lowcut, --highcut)
|
- **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)
|
- **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
|
- **96kHz 24-bit WAV file support** for high-quality audio processing
|
||||||
- **Multiple output formats** with configurable sample rates and bit depths
|
- **Multiple output formats** with configurable sample rates and bit depths
|
||||||
@@ -79,6 +79,14 @@ You can apply a low-cut (high-pass) and/or high-cut (low-pass) filter to the rec
|
|||||||
|
|
||||||
This applies a 40 Hz low-cut (high-pass) and 18 kHz high-cut (low-pass) filter to the recorded sweep.
|
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
|
### Different Output Formats
|
||||||
|
|
||||||
Generate IRs in different sample rates and bit depths:
|
Generate IRs in different sample rates and bit depths:
|
||||||
@@ -141,6 +149,7 @@ Generate IRs in different sample rates and bit depths:
|
|||||||
| `--fade-ms` | Fade-out duration in milliseconds at end of IR (default 5) | 5 | 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 |
|
| `--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 |
|
| `--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
|
## File Requirements
|
||||||
|
|
||||||
@@ -173,8 +182,9 @@ Generate IRs in different sample rates and bit depths:
|
|||||||
- You can change the fade duration with `--fade-ms`
|
- You can change the fade duration with `--fade-ms`
|
||||||
|
|
||||||
### Filtering
|
### Filtering
|
||||||
- You can apply a 2nd-order Butterworth low-cut (high-pass) and/or high-cut (low-pass) filter to the recorded sweep before IR extraction
|
- 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 `--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
|
### Deconvolution Process
|
||||||
1. **FFT-based deconvolution** of recorded signal by sweep signal
|
1. **FFT-based deconvolution** of recorded signal by sweep signal
|
||||||
|
|||||||
17
main.go
17
main.go
@@ -73,6 +73,11 @@ func main() {
|
|||||||
Name: "lowcut",
|
Name: "lowcut",
|
||||||
Usage: "Low-cut filter (high-pass) cutoff frequency in Hz (applied to recorded sweep, optional)",
|
Usage: "Low-cut filter (high-pass) cutoff frequency in Hz (applied to recorded sweep, optional)",
|
||||||
},
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "cut-slope",
|
||||||
|
Usage: "Cut filter slope in dB/octave (12, 24, 36, 48, ...; default 12)",
|
||||||
|
Value: 12,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
// Read sweep WAV file
|
// Read sweep WAV file
|
||||||
@@ -95,13 +100,17 @@ func main() {
|
|||||||
recSampleRate := recordedData.SampleRate
|
recSampleRate := recordedData.SampleRate
|
||||||
highcutHz := c.Float64("highcut")
|
highcutHz := c.Float64("highcut")
|
||||||
lowcutHz := c.Float64("lowcut")
|
lowcutHz := c.Float64("lowcut")
|
||||||
|
cutSlope := c.Int("cut-slope")
|
||||||
|
if cutSlope < 12 || cutSlope%12 != 0 {
|
||||||
|
return fmt.Errorf("cut-slope must be a positive multiple of 12 (got %d)", cutSlope)
|
||||||
|
}
|
||||||
if lowcutHz > 0 {
|
if lowcutHz > 0 {
|
||||||
log.Printf("Applying low-cut (high-pass) filter to recorded sweep: %.2f Hz", lowcutHz)
|
log.Printf("Applying low-cut (high-pass) filter to recorded sweep: %.2f Hz, slope: %d dB/oct", lowcutHz, cutSlope)
|
||||||
recordedFiltered = convolve.ApplyHighpassButterworth(recordedFiltered, recSampleRate, lowcutHz)
|
recordedFiltered = convolve.CascadeLowcut(recordedFiltered, recSampleRate, lowcutHz, cutSlope)
|
||||||
}
|
}
|
||||||
if highcutHz > 0 {
|
if highcutHz > 0 {
|
||||||
log.Printf("Applying high-cut (low-pass) filter to recorded sweep: %.2f Hz", highcutHz)
|
log.Printf("Applying high-cut (low-pass) filter to recorded sweep: %.2f Hz, slope: %d dB/oct", highcutHz, cutSlope)
|
||||||
recordedFiltered = convolve.ApplyLowpassButterworth(recordedFiltered, recSampleRate, highcutHz)
|
recordedFiltered = convolve.CascadeHighcut(recordedFiltered, recSampleRate, highcutHz, cutSlope)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Performing deconvolution...")
|
log.Println("Performing deconvolution...")
|
||||||
|
|||||||
@@ -425,3 +425,31 @@ func ApplyHighpassButterworth(data []float64, sampleRate int, cutoffHz float64)
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CascadeLowcut applies the low-cut (high-pass) filter multiple times for steeper slopes.
|
||||||
|
// slopeDb: 12, 24, 36, ... (dB/octave)
|
||||||
|
func CascadeLowcut(data []float64, sampleRate int, cutoffHz float64, slopeDb int) []float64 {
|
||||||
|
if slopeDb < 12 {
|
||||||
|
slopeDb = 12
|
||||||
|
}
|
||||||
|
n := slopeDb / 12
|
||||||
|
out := data
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
out = ApplyHighpassButterworth(out, sampleRate, cutoffHz)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// CascadeHighcut applies the high-cut (low-pass) filter multiple times for steeper slopes.
|
||||||
|
// slopeDb: 12, 24, 36, ... (dB/octave)
|
||||||
|
func CascadeHighcut(data []float64, sampleRate int, cutoffHz float64, slopeDb int) []float64 {
|
||||||
|
if slopeDb < 12 {
|
||||||
|
slopeDb = 12
|
||||||
|
}
|
||||||
|
n := slopeDb / 12
|
||||||
|
out := data
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
out = ApplyLowpassButterworth(out, sampleRate, cutoffHz)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|||||||
BIN
testdata/ir.wav
vendored
BIN
testdata/ir.wav
vendored
Binary file not shown.
Reference in New Issue
Block a user