| from pathlib import Path |
| from concurrent.futures import ProcessPoolExecutor, as_completed |
| import os |
|
|
| import numpy as np |
| import pandas as pd |
| import soundfile as sf |
| from scipy.signal import resample_poly |
| from math import gcd |
| from tqdm import tqdm |
|
|
|
|
| |
| |
| |
|
|
| AUDIO_ROOT = Path("/home/debarpanb1/TREA_2.0/UrbanSound8K/audio") |
| CSV_PATH = Path("/home/debarpanb1/TREA_2.0/UrbanSound8K/metadata/UrbanSound8K.csv") |
|
|
| OUTPUT_ROOT = Path("/home/debarpanb1/TREA_2.0/UrbanSound8K_preprocessed_fast") |
| OUTPUT_AUDIO_ROOT = OUTPUT_ROOT / "audio" |
| OUTPUT_METADATA_PATH = OUTPUT_ROOT / "UrbanSound8K_with_audio_metadata.csv" |
|
|
| OUTPUT_AUDIO_ROOT.mkdir(parents=True, exist_ok=True) |
|
|
|
|
| |
| |
| |
|
|
| TARGET_SR = 44100 |
| TARGET_SUBTYPE = "PCM_16" |
| NORMALIZE_PEAK = True |
|
|
| |
| NUM_WORKERS = min(16, os.cpu_count() or 4) |
|
|
|
|
| |
| |
| |
|
|
| def safe_class_name(x): |
| return str(x).replace(" ", "_").replace("/", "_") |
|
|
|
|
| def make_output_filename(row): |
| fold = int(row["fold"]) |
| class_name = safe_class_name(row["class"]) |
| stem = Path(row["slice_file_name"]).stem |
| return f"fold{fold}_{class_name}_{stem}.wav" |
|
|
|
|
| def to_mono(audio): |
| if audio.ndim == 1: |
| return audio |
| return audio.mean(axis=1) |
|
|
|
|
| def resample_audio(audio, orig_sr, target_sr): |
| if orig_sr == target_sr: |
| return audio |
|
|
| factor = gcd(orig_sr, target_sr) |
| up = target_sr // factor |
| down = orig_sr // factor |
|
|
| return resample_poly(audio, up, down) |
|
|
|
|
| def peak_normalize(audio, eps=1e-8): |
| peak = np.max(np.abs(audio)) if len(audio) > 0 else 0.0 |
| if peak < eps: |
| return audio |
| return audio / peak * 0.98 |
|
|
|
|
| def process_one(row_dict): |
| fold = int(row_dict["fold"]) |
| filename = row_dict["slice_file_name"] |
|
|
| original_audio_path = AUDIO_ROOT / f"fold{fold}" / filename |
| output_filename = make_output_filename(row_dict) |
| clean_audio_path = OUTPUT_AUDIO_ROOT / f"fold{fold}" / output_filename |
| clean_audio_path.parent.mkdir(parents=True, exist_ok=True) |
|
|
| row_dict["original_audio_path"] = str(original_audio_path) |
| row_dict["clean_audio_path"] = str(clean_audio_path) |
|
|
| row_dict["preprocess_target_sample_rate"] = TARGET_SR |
| row_dict["preprocess_target_channels"] = 1 |
| row_dict["preprocess_target_subtype"] = TARGET_SUBTYPE |
| row_dict["preprocess_peak_normalize"] = NORMALIZE_PEAK |
| row_dict["preprocess_success"] = False |
| row_dict["preprocess_error"] = "" |
|
|
| if not original_audio_path.exists(): |
| row_dict["preprocess_error"] = "missing_audio_file" |
| return row_dict |
|
|
| try: |
| |
| info = sf.info(str(original_audio_path)) |
|
|
| row_dict["original_sample_rate"] = info.samplerate |
| row_dict["original_channels"] = info.channels |
| row_dict["original_frames"] = info.frames |
| row_dict["original_duration"] = info.frames / info.samplerate |
| row_dict["original_format"] = info.format |
| row_dict["original_subtype"] = info.subtype |
|
|
| row_dict["csv_slice_duration"] = float(row_dict["end"]) - float(row_dict["start"]) |
|
|
| |
| audio, sr = sf.read(str(original_audio_path), dtype="float32", always_2d=False) |
|
|
| |
| audio = to_mono(audio) |
|
|
| |
| audio = resample_audio(audio, sr, TARGET_SR) |
|
|
| |
| if NORMALIZE_PEAK: |
| audio = peak_normalize(audio) |
|
|
| |
| sf.write(str(clean_audio_path), audio, TARGET_SR, subtype=TARGET_SUBTYPE) |
|
|
| |
| clean_info = sf.info(str(clean_audio_path)) |
|
|
| row_dict["clean_sample_rate"] = clean_info.samplerate |
| row_dict["clean_channels"] = clean_info.channels |
| row_dict["clean_frames"] = clean_info.frames |
| row_dict["clean_duration"] = clean_info.frames / clean_info.samplerate |
| row_dict["clean_format"] = clean_info.format |
| row_dict["clean_subtype"] = clean_info.subtype |
|
|
| row_dict["preprocess_action"] = "soundfile_scipy_resample_to_44100_mono_pcm16_peaknorm" |
| row_dict["preprocess_success"] = True |
|
|
| except Exception as e: |
| row_dict["preprocess_error"] = repr(e) |
|
|
| return row_dict |
|
|
|
|
| def main(): |
| df = pd.read_csv(CSV_PATH) |
|
|
| records = df.to_dict("records") |
| results = [] |
|
|
| print(f"Processing {len(records)} files with {NUM_WORKERS} workers...") |
|
|
| with ProcessPoolExecutor(max_workers=NUM_WORKERS) as executor: |
| futures = [executor.submit(process_one, row) for row in records] |
|
|
| for future in tqdm(as_completed(futures), total=len(futures)): |
| results.append(future.result()) |
|
|
| out_df = pd.DataFrame(results) |
| out_df.to_csv(OUTPUT_METADATA_PATH, index=False) |
|
|
| print("\nDone.") |
| print(f"Preprocessed audio saved to: {OUTPUT_AUDIO_ROOT}") |
| print(f"Metadata saved to: {OUTPUT_METADATA_PATH}") |
|
|
| print("\nSuccess count:") |
| print(out_df["preprocess_success"].value_counts(dropna=False)) |
|
|
| print("\nOriginal sample rates:") |
| print(out_df["original_sample_rate"].value_counts(dropna=False).sort_index()) |
|
|
| print("\nOriginal channels:") |
| print(out_df["original_channels"].value_counts(dropna=False).sort_index()) |
|
|
| print("\nOriginal subtypes:") |
| print(out_df["original_subtype"].value_counts(dropna=False)) |
|
|
|
|
| if __name__ == "__main__": |
| main() |