|
import os |
|
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) |
|
|
|
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 |
|
|
|
|
|
|