Files
c0ffymachyne-ComfyUI_Signal…/core/io.py
T
2024-12-07 20:16:47 -08:00

264 lines
10 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Author: C0ffymachyne
License: GPLv3
Version: 1.0.0
Description:
io for audio files and comfy
"""
import torch, torchaudio
from pathlib import Path
from typing import Dict, Tuple, Any
import numpy as np
# this mess needs some cleanup !!
# when we return audio to comfy, turn it to cpu
def audio_to_comfy_3d(waveform : torch.Tensor ,sample_rate: int, cpu = True, clip : bool = False) -> Tuple[Dict]:
# try to fix wrong shape
if (waveform.ndim == 2):
waveform = waveform.unsqueeze(0)
if (waveform.ndim != 3):
raise RuntimeError(f"returning to_comfy failed {waveform.shape}@{waveform.device}[{waveform.ndim}] has incorrect dimentions, it should be of dimension [batch,channels,audio]")
if cpu:
if waveform.device != 'cpu':
waveform = waveform.cpu()
if waveform.dtype != torch.float64:
waveform = waveform.to(dtype=torch.float64)
if clip:
waveform = np.clip(waveform, -1.0, 1.0)
return_value = ({'waveform':waveform, 'sample_rate': sample_rate},)
print(f"audio_to_comfy_3d '{return_value}' with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
return return_value
# when we return audio to comfy, turn it to cpu
def audio_to_comfy_3dp1(waveform : torch.Tensor ,sample_rate: int, value0 : Any, cpu = True, clip : bool = False) -> Tuple[Dict]:
# try to fix wrong shape
if (waveform.ndim == 2):
waveform = waveform.unsqueeze(0)
if (waveform.ndim != 3):
raise RuntimeError(f"returning to_comfy failed {waveform.shape}@{waveform.device}dim[{waveform.ndim}] has incorrect dimentions, it should be of dimension [batch,channels,audio]")
if cpu:
if waveform.device != 'cpu':
waveform = waveform.cpu()
if waveform.dtype != torch.float64:
waveform = waveform.to(dtype=torch.float64)
if clip:
waveform = np.clip(waveform, -1.0, 1.0)
return_value = ({'waveform':waveform, 'sample_rate': sample_rate},value0,)
print(f"audio_to_comfy_3d '{return_value}' with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
return return_value
# when we return audio to comfy, turn it to cpu
def audio_to_comfy_3dp2(waveform : torch.Tensor, sample_rate: int,value0 : Any, value1 : Any, cpu = True, clip: bool = False) -> Tuple[Dict]:
# try to fix wrong shape
if (waveform.ndim == 2):
waveform = waveform.unsqueeze(0)
if (waveform.ndim != 3):
raise RuntimeError(f"returning to_comfy failed {waveform.shape}@{waveform.device}dim[{waveform.ndim}] has incorrect dimentions, it should be of dimension [batch,channels,audio]")
if cpu:
if waveform.device != 'cpu':
waveform = waveform.cpu()
if waveform.dtype != torch.float64:
waveform = waveform.to(dtype=torch.float64)
if clip:
waveform = np.clip(waveform, -1.0, 1.0)
return_value = ({'waveform':waveform, 'sample_rate': sample_rate}, value0, value1,)
print(f"audio_to_comfy_3d '{return_value}' with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
return return_value
# when we get audio from comfy, load it to gpu
def audio_from_comfy_2d(audio : Tuple[Dict], repeat=True, try_gpu = True) -> Tuple[torch.Tensor,int]:
if audio is None:
raise ValueError("Input audio must be provided.")
waveform = audio.get('waveform') # [batch, channels, samples]
sample_rate = audio.get('sample_rate')
if waveform.dtype != torch.float64:
waveform = waveform.to(dtype=torch.float64)
if waveform is None or sample_rate is None:
raise ValueError("Input audio must contain 'waveform' and 'sample_rate'.")
if not isinstance(waveform, torch.Tensor):
raise TypeError("Waveform must be a torch.Tensor.")
print(f"audio_from_comfy_2d with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
if waveform.ndim != 3:
raise ValueError(f"Waveform must be a 3D tensor with shape (batch, channels, samples) not {waveform.shape}@{waveform.device}")
if repeat:
if waveform.ndim == 1: # add extra channel in case of mono
print(f"audio_from_comfy_2d repeat")
waveform = waveform.unsqueeze(0) # Add channel dimension
waveform = waveform.repeat(2, 1) # copy mono to the new channel
waveform = waveform.squeeze(0).contiguous()
if try_gpu:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
waveform = waveform.to(device)
print(f"audio_from_comfy_2d with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
return waveform, sample_rate
def audio_from_comfy_3d(audio : Tuple[Dict], repeat=True, try_gpu = True) -> Tuple[torch.Tensor,int]:
if audio is None:
raise ValueError("Input audio must be provided.")
waveform = audio.get('waveform') # [batch, channels, samples]
sample_rate = audio.get('sample_rate')
if waveform.dtype != torch.float64:
waveform = waveform.to(dtype=torch.float64)
if waveform is None or sample_rate is None:
raise ValueError("Input audio must contain 'waveform' and 'sample_rate'.")
if not isinstance(waveform, torch.Tensor):
raise TypeError("Waveform must be a torch.Tensor.")
print(f"audio_from_comfy_2d with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
if waveform.ndim != 3:
raise ValueError(f"Waveform must be a 3D tensor with shape (batch, channels, samples) not {waveform.shape}@{waveform.device}")
if repeat:
if waveform.ndim == 1: # add extra channel in case of mono
print(f"audio_from_comfy_2d repeat")
waveform = waveform.unsqueeze(0) # Add channel dimension
waveform = waveform.repeat(2, 1) # copy mono to the new channel
#waveform = waveform.squeeze(0).contiguous()
if try_gpu:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
waveform = waveform.to(device)
print(f"audio_from_comfy_3d with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
return waveform, sample_rate
def from_disk_as_dict_3d(audio_file : str, gain: float = 1.0, repeat = True, start_time : float = 0.0, end_time : float = 0.0) -> Dict:
# all loaded audio comes in 3 dimensions
#[batch,channels,audio] 3 dimensions
if not Path(audio_file).exists():
raise ValueError(f"File {audio_file} Does Not Exist")
info= torchaudio.info(audio_file)
sample_rate = info.sample_rate
# cut sudio segment
if (start_time > 0.0) and (end_time > start_time):
frame_offset = int(start_time * sample_rate) # Start frame
num_frames = int((end_time - start_time) * sample_rate) # Total frames to read
waveform, sample_rate = torchaudio.load(
audio_file, frame_offset=frame_offset, num_frames=num_frames
)
else:
waveform, sample_rate = torchaudio.load(audio_file)
if waveform.dtype != torch.float64:
waveform = waveform.to(dtype=torch.float64)
waveform = waveform * gain
if repeat:
if waveform.ndim == 1: # add extra channel in case of mono
waveform = waveform.repeat(2, 1) # copy mono to the new channel
# add batch dimension at the front
waveform = waveform.unsqueeze(0).contiguous()
#waveform = waveform * gain
print(f"from_disk_as_dict_3d loaded audio file: '{audio_file}' with shape: {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate: {sample_rate} Hz.")
return audio_to_comfy_3d(waveform,sample_rate)
def from_disk_as_raw_3d(audio_file : str, repeat : bool = True, try_gpu : bool = False) -> Tuple[torch.Tensor, int]:
# all loaded audio comes in 3 dimensions
#[batch,channels,audio] 3 dimensions
waveform, sample_rate = torchaudio.load(audio_file)
info= torchaudio.info(audio_file)
print(f"from_disk_as_raw_3d loaded audio file: '{audio_file}' with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
if waveform.dtype != torch.float64:
waveform = waveform.to(dtype=torch.float64)
if repeat:
if info.num_channels == 1: # add extra channel in case of mono
waveform = waveform.repeat(2, 1) # copy mono to the new channel
# add batch dimension at the front
waveform = waveform.unsqueeze(0).contiguous()
if try_gpu:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
waveform = waveform.to(device)
print(f"from_disk_as_raw_3d loaded audio file: '{audio_file}' with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
return waveform, sample_rate
def from_disk_as_raw_2d(audio_file : str, repeat : bool = True, try_gpu : bool = False) -> Tuple[torch.Tensor, int]:
# all loaded audio comes in 3 dimensions
#[batch,channels,audio] 3 dimensions
waveform, sample_rate = torchaudio.load(audio_file)
info= torchaudio.info(audio_file)
print(f"from_disk_as_raw_2d loaded audio file: '{audio_file}' with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
if waveform.dtype != torch.float64:
waveform = waveform.to(dtype=torch.float64)
if repeat:
if info.num_channels == 1: # add extra channel in case of mono
waveform = waveform.repeat(2, 1) # copy mono to the new channel
#waveform = waveform.unsqueeze(0) # Add channel dimension
if try_gpu:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
waveform = waveform.to(device)
print(f"from_disk_as_raw_2d loaded audio file: '{audio_file}' with shape {waveform.shape}@{waveform.device}dim[{waveform.ndim}] and sample rate {sample_rate} Hz.")
return waveform, sample_rate