Files
c0ffymachyne-ComfyUI_Signal…/SignalProcessingFilter.py
T
2024-11-20 22:27:33 -08:00

91 lines
3.8 KiB
Python

import torch, torchaudio
import torch
from typing import Dict
class SignalProcessingFilter:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"audio": ("AUDIO", {"forceInput": True}),
"cutoff": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
"filter_type": (["lowpass", "highpass", "bandpass", "bandstop"], {"default": "lowpass"}),
"q_factor": ("FLOAT", {"default": 0.707, "min": 0.1, "max": 5.0, "step": 0.01}), # For resonance/bandwidth
}
}
RETURN_TYPES = ("AUDIO","INT")
RETURN_NAMES = ("audio","sample_rate")
CATEGORY = "Signal Processing"
FUNCTION = "apply_filter"
def apply_filter(self, audio: Dict[str, torch.Tensor], cutoff: float, filter_type: str, q_factor: float):
"""
Apply a specified filter to the input audio.
Parameters:
audio (Dict[str, torch.Tensor]): Input audio with 'waveform' and 'sample_rate'.
cutoff (float): Normalized cutoff frequency (0.0 to 1.0).
filter_type (str): Type of filter ('lowpass', 'highpass', 'bandpass', 'bandstop').
q_factor (float): Quality factor determining the filter's bandwidth.
Returns:
Tuple[Dict[str, torch.Tensor]]: Filtered audio.
"""
waveform = audio['waveform'].squeeze(0)
sample_rate = audio['sample_rate']
nyquist = sample_rate / 2.0
# Define minimum and maximum frequencies for mapping
log_min = 20.0 # 20 Hz, typical lower bound of human hearing
log_max = nyquist - 100.0 # Slightly below Nyquist to prevent instability
# Avoid log(0) by ensuring cutoff is within (0,1)
cutoff = min(max(cutoff, 1e-6), 1.0 - 1e-6)
# Logarithmic mapping
log_min = torch.log(torch.tensor(log_min))
log_max = torch.log(torch.tensor(log_max))
log_cutoff = log_min + cutoff * (log_max - log_min)
cutoff_freq = torch.exp(log_cutoff).item()
# Debug: Print mapped cutoff frequency
print(f"Normalized cutoff: {cutoff} mapped to frequency: {cutoff_freq:.2f} Hz")
# Choose filter type
if filter_type == "lowpass":
filtered_waveform = torchaudio.functional.lowpass_biquad(
waveform, sample_rate, cutoff_freq, Q=q_factor
)
elif filter_type == "highpass":
filtered_waveform = torchaudio.functional.highpass_biquad(
waveform, sample_rate, cutoff_freq, Q=q_factor
)
elif filter_type in ["bandpass", "bandstop"]:
center_freq = cutoff_freq
# Ensure that the bandwidth does not exceed the Nyquist frequency
bandwidth = center_freq / q_factor
lower_freq = max(center_freq - bandwidth / 2.0, 20.0) # Prevent dropping below 20 Hz
upper_freq = min(center_freq + bandwidth / 2.0, nyquist - 100.0) # Prevent exceeding Nyquist
# Debug: Print bandwidth details
print(f"Band filter with center frequency: {center_freq:.2f} Hz, "
f"lower: {lower_freq:.2f} Hz, upper: {upper_freq:.2f} Hz")
if filter_type == "bandpass":
filtered_waveform = torchaudio.functional.bandpass_biquad(
waveform, sample_rate, center_freq, Q=q_factor
)
else: # bandstop
filtered_waveform = torchaudio.functional.band_biquad(
waveform, sample_rate, center_freq, Q=q_factor
)
else:
raise ValueError(f"Unsupported filter type: {filter_type}")
filtered_waveform = filtered_waveform.unsqueeze(0)
print('SignalProcessingFilter.filtered_waveform',filtered_waveform.shape)
return {'waveform': filtered_waveform, 'sample_rate': sample_rate}, sample_rate