fix: localize annoying imports
todo: replace librosa with numpy and torch native functions
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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,4 +1,3 @@
|
||||
import mido
|
||||
import os
|
||||
import folder_paths
|
||||
from .features_midi import MIDIFeature
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user