fix: localize annoying imports

todo: replace librosa with numpy and torch native functions
This commit is contained in:
RyanOnTheInside
2026-02-09 09:15:34 -05:00
parent fd074ef4f9
commit 665f9f90ab
7 changed files with 43 additions and 29 deletions
+3 -2
View File
@@ -1,7 +1,7 @@
import torch
import numpy as np
from scipy.ndimage import zoom
from .audio_processor_legacy import AudioVisualizer, PygameAudioVisualizer
from scipy import signal
import comfy.model_management as mm
import folder_paths
@@ -421,7 +421,8 @@ class AudioFeatureVisualizer(AudioNodeBase):
def visualize_audio_feature(self, audio, video_frames, visualization_type, frame_rate, x_axis, y_axis, cmap, visualizer):
num_frames, height, width, _ = video_frames.shape
if visualizer == "pygame":
from .audio_processor_legacy import AudioVisualizer, PygameAudioVisualizer
if visualizer == "pygame":
visualizer = PygameAudioVisualizer(audio, num_frames, height, width, frame_rate)
elif visualizer == "matplotlib":
visualizer = AudioVisualizer(audio, num_frames, height, width, frame_rate, x_axis, y_axis, cmap)
+3 -1
View File
@@ -11,7 +11,6 @@ from .audio_utils import (
)
import torch
from ...tooltips import apply_tooltips
import librosa
import numpy as np
class AudioUtility(AudioNodeBase):
@@ -232,6 +231,7 @@ class AudioInfo(AudioUtility):
def _detect_key(self, audio_mono, sample_rate):
"""Detect musical key using chromagram and Krumhansl-Kessler key profiles."""
import librosa
# Extract chromagram using Constant-Q Transform (better for pitch detection)
chromagram = librosa.feature.chroma_cqt(y=audio_mono, sr=sample_rate)
@@ -269,6 +269,7 @@ class AudioInfo(AudioUtility):
return best_key
def get_audio_info(self, audio, frame_rate):
import librosa
# Get basic audio info
waveform = audio['waveform']
sample_rate = audio['sample_rate']
@@ -399,6 +400,7 @@ class Knob(AudioUtility):
FUNCTION = "enhance_audio"
def enhance_audio(self, audio, knob, other_knob):
import librosa
waveform, sample_rate = audio['waveform'], audio['sample_rate']
# Make a copy of the input waveform
+21 -19
View File
@@ -1,14 +1,8 @@
import numpy as np
import torch
import librosa
import cv2
import matplotlib.pyplot as plt
from comfy.utils import ProgressBar
import numpy as np
import librosa
import torch
import cv2
import matplotlib.pyplot as plt
from ... import ProgressMixin
@@ -42,13 +36,7 @@ class BaseAudioProcessor(ProgressMixin):
end_sample = int(end_time * self.sample_rate)
return self.audio[start_sample:end_sample]
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
import torch
class AudioVisualizer(BaseAudioProcessor):
class AudioVisualizer(BaseAudioProcessor):
def __init__(self, audio, num_frames, height, width, frame_rate, x_axis, y_axis, cmap):
super().__init__(audio, num_frames, height, width, frame_rate)
@@ -58,6 +46,8 @@ class AudioVisualizer(BaseAudioProcessor):
self.cmap = cmap
def _generate_frame(self, data):
import librosa
import librosa.display
fig, ax = plt.subplots(figsize=(self.width / 100, self.height / 100), dpi=100)
librosa.display.specshow(data, sr=self.sample_rate, x_axis=self.x_axis, y_axis=self.y_axis, cmap=self.cmap, ax=ax)
if self.x_axis == 'off':
@@ -81,6 +71,7 @@ class AudioVisualizer(BaseAudioProcessor):
return frame
def create_spectrogram(self):
import librosa
frames = []
self.start_progress(self.num_frames, "Creating Spectrogram")
for i in range(self.num_frames):
@@ -97,6 +88,8 @@ class AudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames).float() / 255.0
def create_waveform(self):
import librosa
import librosa.display
frames = []
self.start_progress(self.num_frames, "Creating Waveform")
for i in range(self.num_frames):
@@ -130,6 +123,7 @@ class AudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames).float() / 255.0
def create_mfcc(self):
import librosa
frames = []
self.start_progress(self.num_frames, "Creating MFCC")
for i in range(self.num_frames):
@@ -144,6 +138,7 @@ class AudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames).float() / 255.0
def create_chroma(self):
import librosa
frames = []
self.start_progress(self.num_frames, "Creating Chroma")
for i in range(self.num_frames):
@@ -158,6 +153,7 @@ class AudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames).float() / 255.0
def create_tonnetz(self):
import librosa
frames = []
self.start_progress(self.num_frames, "Creating Tonnetz")
for i in range(self.num_frames):
@@ -172,6 +168,7 @@ class AudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames).float() / 255.0
def create_spectral_centroid(self):
import librosa
frames = []
self.start_progress(self.num_frames, "Creating Spectral Centroid")
for i in range(self.num_frames):
@@ -214,22 +211,20 @@ class AudioFeatureExtractor(BaseAudioProcessor):
return np.array([np.sqrt(np.mean(self._get_audio_frame(i)**2)) for i in range(self.num_frames)])
def _spectral_centroid(self):
import librosa
return np.array([np.mean(librosa.feature.spectral_centroid(y=self._get_audio_frame(i), sr=self.sample_rate)[0]) for i in range(self.num_frames)])
def _onset_detection(self):
import librosa
return np.array([np.mean(librosa.onset.onset_strength(y=self._get_audio_frame(i), sr=self.sample_rate)) for i in range(self.num_frames)])
def _chroma_features(self):
import librosa
return np.array([np.mean(librosa.feature.chroma_stft(y=self._get_audio_frame(i), sr=self.sample_rate), axis=1) for i in range(self.num_frames)])
import numpy as np
import torch
import pygame
import librosa
from comfy.utils import ProgressBar
class PygameAudioVisualizer(BaseAudioProcessor):
def __init__(self, audio, num_frames, height, width, frame_rate, scroll_direction='left'):
import pygame
super().__init__(audio, num_frames, height, width, frame_rate)
self.height = height
self.width = width
@@ -244,6 +239,7 @@ class PygameAudioVisualizer(BaseAudioProcessor):
self.total_samples = len(self.full_waveform)
def _surface_to_array(self, surface):
import pygame
# Convert Pygame surface to NumPy array
frame_array = pygame.surfarray.array3d(surface)
# Transpose to (H, W, C)
@@ -310,6 +306,7 @@ class PygameAudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames)
def _generate_spectrogram_frame(self, audio_frame):
import librosa
self.screen.fill((0, 0, 0)) # Clear the screen
# Compute spectrogram
n_fft = min(2048, len(audio_frame))
@@ -345,6 +342,7 @@ class PygameAudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames)
def _generate_mfcc_frame(self, audio_frame):
import librosa
self.screen.fill((0, 0, 0)) # Clear the screen
# Compute MFCCs
mfccs = librosa.feature.mfcc(y=audio_frame, sr=self.sample_rate, n_mfcc=20)
@@ -377,6 +375,7 @@ class PygameAudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames)
def _generate_chroma_frame(self, audio_frame):
import librosa
self.screen.fill((0, 0, 0)) # Clear the screen
# Compute Chroma features
chromagram = librosa.feature.chroma_stft(y=audio_frame, sr=self.sample_rate)
@@ -409,6 +408,7 @@ class PygameAudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames)
def _generate_tonnetz_frame(self, audio_frame):
import librosa
self.screen.fill((0, 0, 0)) # Clear the screen
# Compute Tonnetz
tonnetz = librosa.feature.tonnetz(y=audio_frame, sr=self.sample_rate)
@@ -441,6 +441,7 @@ class PygameAudioVisualizer(BaseAudioProcessor):
return torch.from_numpy(frames)
def _generate_spectral_centroid_frame(self, audio_frame):
import librosa
self.screen.fill((0, 0, 0)) # Clear the screen
# Compute Spectral Centroid
centroid = librosa.feature.spectral_centroid(y=audio_frame, sr=self.sample_rate)
@@ -459,4 +460,5 @@ class PygameAudioVisualizer(BaseAudioProcessor):
return self.screen.copy()
def __del__(self):
import pygame
pygame.quit()
+1 -1
View File
@@ -2,7 +2,6 @@ import torch
import torchaudio
import torchaudio.transforms as T
import torchaudio.functional as F
import librosa
import numpy as np
import torch.nn.functional as nnf
@@ -85,6 +84,7 @@ def time_stretch(waveform, rate):
device = waveform.device
waveform = waveform.cpu()
import librosa
# Convert to numpy for librosa processing
waveform_np = waveform.numpy()
+4 -1
View File
@@ -1,6 +1,5 @@
import torch
import numpy as np
import mido
import os
import folder_paths
import math
@@ -350,6 +349,7 @@ class MIDILoader:
CATEGORY = "RyanOnTheInside/Audio/MIDI"
def load_midi(self, midi_file, track_selection, start_measure=1, start_beat=1, end_measure=0, end_beat=1):
import mido
try:
midi_path = folder_paths.get_full_path("midi_files", midi_file)
if not midi_path or not os.path.exists(midi_path):
@@ -491,6 +491,7 @@ class MIDILoader:
@classmethod
def analyze_midi(cls, midi_path, start_measure=1, start_beat=1, end_measure=0, end_beat=1):
import mido
midi_data = mido.MidiFile(midi_path)
# Get the total measures
@@ -546,6 +547,7 @@ class MIDILoader:
@classmethod
def VALIDATE_INPUTS(cls, midi_file, track_selection, start_measure=1, start_beat=1, end_measure=0, end_beat=1):
import mido
midi_path = folder_paths.get_full_path("midi_files", midi_file)
if not midi_path or not os.path.isfile(midi_path):
return f"MIDI file not found: {midi_file}"
@@ -642,6 +644,7 @@ async def upload_midi(request):
@routes.post('/refresh_midi_data')
async def refresh_midi_data(request):
import mido
data = await request.json()
midi_file = data.get('midi_file')
track_selection = data.get('track_selection')
-1
View File
@@ -1,4 +1,3 @@
import mido
import os
import folder_paths
from .features_midi import MIDIFeature
+11 -4
View File
@@ -1,12 +1,10 @@
from .features import BaseFeature
import librosa
import numpy as np
from scipy.signal import hilbert
from scipy import signal
import functools
from abc import ABC, abstractmethod
import numpy as np
import librosa
from scipy.signal import medfilt, hilbert
from scipy import signal
import functools
@@ -96,6 +94,7 @@ class AudioFeature(BaseAudioFeature):
return self
def _calculate_feature(self, frame):
import librosa
if frame.size == 0:
return 0.0
if self.feature_name == 'amplitude_envelope':
@@ -125,7 +124,6 @@ class AudioFeature(BaseAudioFeature):
self.features[self.feature_name] = normalized.tolist()
import numpy as np
import librosa
class RhythmFeature(BaseAudioFeature):
def __init__(self, feature_name, audio, frame_count, frame_rate, width, height, feature_type='beat_locations', time_signature=4):
@@ -150,8 +148,9 @@ class RhythmFeature(BaseAudioFeature):
]
def extract(self):
import librosa
self.features = {}
# Extract basic rhythm features
tempo, beat_frames = librosa.beat.beat_track(y=self.audio_array, sr=self.sample_rate)
onset_env = librosa.onset.onset_strength(y=self.audio_array, sr=self.sample_rate)
@@ -178,6 +177,7 @@ class RhythmFeature(BaseAudioFeature):
return self
def _extract_beat_locations(self, beat_frames):
import librosa
beat_times = librosa.frames_to_time(beat_frames, sr=self.sample_rate)
beat_sequence = np.zeros(self.frame_count)
for beat_time in beat_times:
@@ -200,6 +200,7 @@ class RhythmFeature(BaseAudioFeature):
self.features[self.feature_name] = resampled_onset.tolist()
def _extract_beat_emphasis(self, beat_frames, onset_env):
import librosa
beat_emphasis = np.zeros(self.frame_count)
for beat in beat_frames:
if beat < len(onset_env):
@@ -224,12 +225,14 @@ class RhythmFeature(BaseAudioFeature):
self.features[self.feature_name] = resampled_syncopation.tolist()
def _extract_rhythm_regularity(self, beat_frames):
import librosa
# Measure regularity by calculating the standard deviation of inter-beat intervals
ibi = np.diff(librosa.frames_to_time(beat_frames, sr=self.sample_rate))
regularity = 1 / (1 + np.std(ibi)) # Invert so that higher values mean more regular
self.features[self.feature_name] = [regularity] * self.frame_count
def _extract_beat_types(self, beat_frames):
import librosa
beat_times = librosa.frames_to_time(beat_frames, sr=self.sample_rate)
down_beats = np.zeros(self.frame_count)
up_beats = np.zeros(self.frame_count)
@@ -327,11 +330,13 @@ class PitchFeature(BaseAudioFeature):
@classmethod
def pitch_to_note(cls, pitch):
import librosa
if pitch == 0:
return "N/A"
return librosa.hz_to_note(pitch)
def _calculate_pitch_sequence(self):
import librosa
# Try to use CREPE model if available
if self.crepe_model != "none":
try:
@@ -385,6 +390,7 @@ class PitchFeature(BaseAudioFeature):
self.features[self.feature_name + '_confidence'] = confidences.tolist()
def _fallback_pitch_estimation(self):
import librosa
pitches, magnitudes = librosa.piptrack(
y=self.audio_array,
sr=self.sample_rate,
@@ -429,6 +435,7 @@ class PitchFeature(BaseAudioFeature):
self.features[self.feature_name] = feature_values.tolist()
def _extract_semitone(self):
import librosa
pitches = np.array(self.features[self.feature_name + '_pitch'])
midi_notes = librosa.hz_to_midi(pitches)
midi_notes = np.round(midi_notes)