Name-Feld mit fortlaufender Nummer für alle Audio-Nodes
Alle Generierungs-Nodes (MusicGen, MusicGenLong, AudioGen) haben jetzt ein 'name' Feld. Dateien werden als name_001.wav, name_002.wav, etc. gespeichert statt mit Timestamp. z.B. heavy_strike_001.wav Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b5af85a890
commit
5b326e2de6
2 changed files with 35 additions and 7 deletions
|
|
@ -2,6 +2,8 @@ import torch
|
||||||
import torchaudio
|
import torchaudio
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
import glob as globmod
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
class MusicGenNode:
|
class MusicGenNode:
|
||||||
|
|
@ -10,6 +12,7 @@ class MusicGenNode:
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"prompt": ("STRING", {"multiline": True, "default": "dark dungeon ambience, slow, mysterious"}),
|
"prompt": ("STRING", {"multiline": True, "default": "dark dungeon ambience, slow, mysterious"}),
|
||||||
|
"name": ("STRING", {"default": "music"}),
|
||||||
"duration": ("FLOAT", {"default": 10.0, "min": 1.0, "max": 120.0, "step": 1.0}),
|
"duration": ("FLOAT", {"default": 10.0, "min": 1.0, "max": 120.0, "step": 1.0}),
|
||||||
"model": (["facebook/musicgen-stereo-medium", "facebook/musicgen-stereo-large", "facebook/musicgen-medium", "facebook/musicgen-large", "facebook/musicgen-small"],),
|
"model": (["facebook/musicgen-stereo-medium", "facebook/musicgen-stereo-large", "facebook/musicgen-medium", "facebook/musicgen-large", "facebook/musicgen-small"],),
|
||||||
"seed": ("INT", {"default": 0, "min": 0, "max": 2**32 - 1}),
|
"seed": ("INT", {"default": 0, "min": 0, "max": 2**32 - 1}),
|
||||||
|
|
@ -26,7 +29,7 @@ class MusicGenNode:
|
||||||
CATEGORY = "AudioCraft"
|
CATEGORY = "AudioCraft"
|
||||||
OUTPUT_NODE = True
|
OUTPUT_NODE = True
|
||||||
|
|
||||||
def generate(self, prompt, duration, model, seed, temperature, cfg_coef, top_k, extend_stride):
|
def generate(self, prompt, name, duration, model, seed, temperature, cfg_coef, top_k, extend_stride):
|
||||||
from audiocraft.models import MusicGen
|
from audiocraft.models import MusicGen
|
||||||
from audiocraft.data.audio import audio_write
|
from audiocraft.data.audio import audio_write
|
||||||
|
|
||||||
|
|
@ -49,9 +52,12 @@ class MusicGenNode:
|
||||||
|
|
||||||
output_dir = "/app/ComfyUI/output/audio"
|
output_dir = "/app/ComfyUI/output/audio"
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
filename = f"musicgen_{int(time.time())}"
|
base_name = re.sub(r'[^\w\-]', '_', name.strip().lower())
|
||||||
|
num = _next_number(output_dir, base_name)
|
||||||
|
filename = f"{base_name}_{num:03d}"
|
||||||
out_path = os.path.join(output_dir, filename)
|
out_path = os.path.join(output_dir, filename)
|
||||||
audio_write(out_path, wav[0].cpu(), mg.sample_rate, strategy="loudness")
|
audio_write(out_path, wav[0].cpu(), mg.sample_rate, strategy="loudness")
|
||||||
|
print(f"[MusicGen] Saved: {filename}.wav")
|
||||||
|
|
||||||
return (out_path + ".wav",)
|
return (out_path + ".wav",)
|
||||||
|
|
||||||
|
|
@ -63,6 +69,7 @@ class MusicGenLongNode:
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"prompt": ("STRING", {"multiline": True, "default": "dark fantasy orchestral music, deep cello, french horn, slow war drums, mysterious ambient"}),
|
"prompt": ("STRING", {"multiline": True, "default": "dark fantasy orchestral music, deep cello, french horn, slow war drums, mysterious ambient"}),
|
||||||
|
"name": ("STRING", {"default": "music_long"}),
|
||||||
"total_duration": ("FLOAT", {"default": 90.0, "min": 10.0, "max": 300.0, "step": 5.0}),
|
"total_duration": ("FLOAT", {"default": 90.0, "min": 10.0, "max": 300.0, "step": 5.0}),
|
||||||
"segment_duration": ("FLOAT", {"default": 30.0, "min": 10.0, "max": 30.0, "step": 5.0}),
|
"segment_duration": ("FLOAT", {"default": 30.0, "min": 10.0, "max": 30.0, "step": 5.0}),
|
||||||
"context_seconds": ("FLOAT", {"default": 5.0, "min": 1.0, "max": 10.0, "step": 0.5}),
|
"context_seconds": ("FLOAT", {"default": 5.0, "min": 1.0, "max": 10.0, "step": 0.5}),
|
||||||
|
|
@ -80,7 +87,7 @@ class MusicGenLongNode:
|
||||||
CATEGORY = "AudioCraft"
|
CATEGORY = "AudioCraft"
|
||||||
OUTPUT_NODE = True
|
OUTPUT_NODE = True
|
||||||
|
|
||||||
def generate_long(self, prompt, total_duration, segment_duration, context_seconds, model, seed, temperature, cfg_coef, top_k):
|
def generate_long(self, prompt, name, total_duration, segment_duration, context_seconds, model, seed, temperature, cfg_coef, top_k):
|
||||||
from audiocraft.models import MusicGen
|
from audiocraft.models import MusicGen
|
||||||
from audiocraft.data.audio import audio_write
|
from audiocraft.data.audio import audio_write
|
||||||
|
|
||||||
|
|
@ -128,19 +135,34 @@ class MusicGenLongNode:
|
||||||
|
|
||||||
output_dir = "/app/ComfyUI/output/audio"
|
output_dir = "/app/ComfyUI/output/audio"
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
filename = f"musicgen_long_{int(time.time())}"
|
base_name = re.sub(r'[^\w\-]', '_', name.strip().lower())
|
||||||
|
num = _next_number(output_dir, base_name)
|
||||||
|
filename = f"{base_name}_{num:03d}"
|
||||||
out_path = os.path.join(output_dir, filename)
|
out_path = os.path.join(output_dir, filename)
|
||||||
audio_write(out_path, result, sample_rate, strategy="loudness")
|
audio_write(out_path, result, sample_rate, strategy="loudness")
|
||||||
print(f"[MusicGenLong] Fertig: {out_path}.wav ({result.shape[1]/sample_rate:.1f}s)")
|
print(f"[MusicGenLong] Fertig: {filename}.wav ({result.shape[1]/sample_rate:.1f}s)")
|
||||||
return (out_path + ".wav",)
|
return (out_path + ".wav",)
|
||||||
|
|
||||||
|
|
||||||
|
def _next_number(output_dir, base_name):
|
||||||
|
"""Findet die nächste fortlaufende Nummer für einen Dateinamen"""
|
||||||
|
pattern = os.path.join(output_dir, f"{base_name}_*.wav")
|
||||||
|
existing = globmod.glob(pattern)
|
||||||
|
max_num = 0
|
||||||
|
for f in existing:
|
||||||
|
match = re.search(rf"{re.escape(base_name)}_(\d+)", os.path.basename(f))
|
||||||
|
if match:
|
||||||
|
max_num = max(max_num, int(match.group(1)))
|
||||||
|
return max_num + 1
|
||||||
|
|
||||||
|
|
||||||
class AudioGenNode:
|
class AudioGenNode:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(cls):
|
def INPUT_TYPES(cls):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"prompt": ("STRING", {"multiline": True, "default": "sword clash metal sound effect"}),
|
"prompt": ("STRING", {"multiline": True, "default": "sword clash metal sound effect"}),
|
||||||
|
"name": ("STRING", {"default": "sfx"}),
|
||||||
"duration": ("FLOAT", {"default": 3.0, "min": 0.5, "max": 30.0, "step": 0.5}),
|
"duration": ("FLOAT", {"default": 3.0, "min": 0.5, "max": 30.0, "step": 0.5}),
|
||||||
"seed": ("INT", {"default": 0, "min": 0, "max": 2**32 - 1}),
|
"seed": ("INT", {"default": 0, "min": 0, "max": 2**32 - 1}),
|
||||||
"temperature": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 2.0, "step": 0.05}),
|
"temperature": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 2.0, "step": 0.05}),
|
||||||
|
|
@ -155,7 +177,7 @@ class AudioGenNode:
|
||||||
CATEGORY = "AudioCraft"
|
CATEGORY = "AudioCraft"
|
||||||
OUTPUT_NODE = True
|
OUTPUT_NODE = True
|
||||||
|
|
||||||
def generate(self, prompt, duration, seed, temperature, cfg_coef, top_k):
|
def generate(self, prompt, name, duration, seed, temperature, cfg_coef, top_k):
|
||||||
from audiocraft.models import AudioGen
|
from audiocraft.models import AudioGen
|
||||||
from audiocraft.data.audio import audio_write
|
from audiocraft.data.audio import audio_write
|
||||||
|
|
||||||
|
|
@ -176,9 +198,12 @@ class AudioGenNode:
|
||||||
|
|
||||||
output_dir = "/app/ComfyUI/output/audio"
|
output_dir = "/app/ComfyUI/output/audio"
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
filename = f"audiogen_{int(time.time())}"
|
base_name = re.sub(r'[^\w\-]', '_', name.strip().lower())
|
||||||
|
num = _next_number(output_dir, base_name)
|
||||||
|
filename = f"{base_name}_{num:03d}"
|
||||||
out_path = os.path.join(output_dir, filename)
|
out_path = os.path.join(output_dir, filename)
|
||||||
audio_write(out_path, wav[0].cpu(), ag.sample_rate, strategy="loudness")
|
audio_write(out_path, wav[0].cpu(), ag.sample_rate, strategy="loudness")
|
||||||
|
print(f"[AudioGen] Saved: {filename}.wav")
|
||||||
|
|
||||||
return (out_path + ".wav",)
|
return (out_path + ".wav",)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"properties": {"Node name for S&R": "AudioGen"},
|
"properties": {"Node name for S&R": "AudioGen"},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
"fast metal sword swing whoosh close range",
|
"fast metal sword swing whoosh close range",
|
||||||
|
"heavy_strike",
|
||||||
1.5,
|
1.5,
|
||||||
0,
|
0,
|
||||||
"fixed",
|
"fixed",
|
||||||
|
|
@ -72,6 +73,7 @@
|
||||||
"properties": {"Node name for S&R": "AudioGen"},
|
"properties": {"Node name for S&R": "AudioGen"},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
"magical energy charging electric crackling buildup impact",
|
"magical energy charging electric crackling buildup impact",
|
||||||
|
"spell_effect",
|
||||||
2.5,
|
2.5,
|
||||||
0,
|
0,
|
||||||
"fixed",
|
"fixed",
|
||||||
|
|
@ -127,6 +129,7 @@
|
||||||
"properties": {"Node name for S&R": "AudioGen"},
|
"properties": {"Node name for S&R": "AudioGen"},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
"wind blowing through dark stone dungeon corridor echoing",
|
"wind blowing through dark stone dungeon corridor echoing",
|
||||||
|
"dungeon_ambient",
|
||||||
8.0,
|
8.0,
|
||||||
0,
|
0,
|
||||||
"fixed",
|
"fixed",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue