import os from typing import final import numpy as np import librosa import soundfile as sf from modules.slicer2 import Slicer class AutoSlicer: def __init__(self): self.slicer_params = { "threshold": -40, "min_length": 5000, "min_interval": 300, "hop_size": 10, "max_sil_kept": 500, } self.original_min_interval = self.slicer_params["min_interval"] def auto_slice(self, filename, input_dir, output_dir, max_sec): audio, sr = librosa.load(os.path.join(input_dir, filename), sr=None, mono=False) slicer = Slicer(sr=sr, **self.slicer_params) chunks = slicer.slice(audio) files_to_delete = [] for i, chunk in enumerate(chunks): if len(chunk.shape) > 1: chunk = chunk.T output_filename = f"{os.path.splitext(filename)[0]}_{i}" output_filename = "".join(c for c in output_filename if c.isascii() or c == "_") + ".wav" output_filepath = os.path.join(output_dir, output_filename) sf.write(output_filepath, chunk, sr) #Check and re-slice audio that more than max_sec. while True: new_audio, sr = librosa.load(output_filepath, sr=None, mono=False) if librosa.get_duration(y=new_audio, sr=sr) <= max_sec: break self.slicer_params["min_interval"] = self.slicer_params["min_interval"] // 2 if self.slicer_params["min_interval"] >= self.slicer_params["hop_size"]: new_chunks = Slicer(sr=sr, **self.slicer_params).slice(new_audio) for j, new_chunk in enumerate(new_chunks): if len(new_chunk.shape) > 1: new_chunk = new_chunk.T new_output_filename = f"{os.path.splitext(output_filename)[0]}_{j}.wav" sf.write(os.path.join(output_dir, new_output_filename), new_chunk, sr) files_to_delete.append(output_filepath) else: break self.slicer_params["min_interval"] = self.original_min_interval for file_path in files_to_delete: if os.path.exists(file_path): os.remove(file_path) def merge_short(self, output_dir, max_sec, min_sec): short_files = [] for filename in os.listdir(output_dir): filepath = os.path.join(output_dir, filename) if filename.endswith(".wav"): audio, sr = librosa.load(filepath, sr=None, mono=False) duration = librosa.get_duration(y=audio, sr=sr) if duration < min_sec: short_files.append((filepath, audio, duration)) short_files.sort(key=lambda x: x[2], reverse=True) merged_audio = [] current_duration = 0 for filepath, audio, duration in short_files: if current_duration + duration <= max_sec: merged_audio.append(audio) current_duration += duration os.remove(filepath) else: if merged_audio: output_audio = np.concatenate(merged_audio, axis=-1) if len(output_audio.shape) > 1: output_audio = output_audio.T output_filename = f"merged_{len(os.listdir(output_dir))}.wav" sf.write(os.path.join(output_dir, output_filename), output_audio, sr) merged_audio = [audio] current_duration = duration os.remove(filepath) if merged_audio and current_duration >= min_sec: output_audio = np.concatenate(merged_audio, axis=-1) if len(output_audio.shape) > 1: output_audio = output_audio.T output_filename = f"merged_{len(os.listdir(output_dir))}.wav" sf.write(os.path.join(output_dir, output_filename), output_audio, sr) def slice_count(self, input_dir, output_dir): orig_duration = final_duration = 0 for file in os.listdir(input_dir): if file.endswith(".wav"): _audio, _sr = librosa.load(os.path.join(input_dir, file), sr=None, mono=False) orig_duration += librosa.get_duration(y=_audio, sr=_sr) wav_files = [file for file in os.listdir(output_dir) if file.endswith(".wav")] num_files = len(wav_files) max_duration = -1 min_duration = float("inf") for file in wav_files: file_path = os.path.join(output_dir, file) audio, sr = librosa.load(file_path, sr=None, mono=False) duration = librosa.get_duration(y=audio, sr=sr) final_duration += float(duration) if duration > max_duration: max_duration = float(duration) if duration < min_duration: min_duration = float(duration) return num_files, max_duration, min_duration, orig_duration, final_duration