from __future__ import annotations from logging import getLogger from pathlib import Path import keyboard import librosa import sounddevice as sd import soundfile as sf from rich.console import Console from tqdm.rich import tqdm LOG = getLogger(__name__) def preprocess_classify( input_dir: Path | str, output_dir: Path | str, create_new: bool = True ) -> None: # paths input_dir_ = Path(input_dir) output_dir_ = Path(output_dir) speed = 1 if not input_dir_.is_dir(): raise ValueError(f"{input_dir} is not a directory.") output_dir_.mkdir(exist_ok=True) console = Console() # get audio paths and folders audio_paths = list(input_dir_.glob("*.*")) last_folders = [x for x in output_dir_.glob("*") if x.is_dir()] console.print("Press ↑ or ↓ to change speed. Press any other key to classify.") console.print(f"Folders: {[x.name for x in last_folders]}") pbar_description = "" pbar = tqdm(audio_paths) for audio_path in pbar: # read file audio, sr = sf.read(audio_path) # update description duration = librosa.get_duration(y=audio, sr=sr) pbar_description = f"{duration:.1f} {pbar_description}" pbar.set_description(pbar_description) while True: # start playing sd.play(librosa.effects.time_stretch(audio, rate=speed), sr, loop=True) # wait for key press key = str(keyboard.read_key()) if key == "down": speed /= 1.1 console.print(f"Speed: {speed:.2f}") elif key == "up": speed *= 1.1 console.print(f"Speed: {speed:.2f}") else: break # stop playing sd.stop() # print if folder changed folders = [x for x in output_dir_.glob("*") if x.is_dir()] if folders != last_folders: console.print(f"Folders updated: {[x.name for x in folders]}") last_folders = folders # get folder folder_candidates = [x for x in folders if x.name.startswith(key)] if len(folder_candidates) == 0: if create_new: folder = output_dir_ / key else: console.print(f"No folder starts with {key}.") continue else: if len(folder_candidates) > 1: LOG.warning( f"Multiple folders ({[x.name for x in folder_candidates]}) start with {key}. " f"Using first one ({folder_candidates[0].name})." ) folder = folder_candidates[0] folder.mkdir(exist_ok=True) # move file new_path = folder / audio_path.name audio_path.rename(new_path) # update description pbar_description = f"Last: {audio_path.name} -> {folder.name}" # yield result # yield audio_path, key, folder, new_path