File size: 3,718 Bytes
c40e77f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | """Phase 7 — préparation des mel-spectrogrammes audio (jouets).
Calcule les log-mel (maison) pour le générateur de voyelles synthétiques et les
met en cache en `.npy` avec les légendes.
Usage :
python -m src.data.prepare_audio --out-dir data/processed/toy_audio \\
--n-train 2000 --n-val 200 --n-mels 64 --n-frames 96
"""
from __future__ import annotations
import argparse
import json
from pathlib import Path
import numpy as np
import torch
from src.data.audio_features import LogMelSpectrogram
from src.data.toy_audio import SR, generate_dataset, to_arrays
def compute_mels(waveforms: np.ndarray, sr: int, n_fft: int, hop: int, n_mels: int,
n_frames: int) -> np.ndarray:
"""Waveforms ``(N, T)`` -> log-mel ``(N, n_mels, n_frames)`` (recadré/paddé)."""
transform = LogMelSpectrogram(sr=sr, n_fft=n_fft, hop_length=hop, n_mels=n_mels)
with torch.no_grad():
mel = transform(torch.from_numpy(waveforms)) # (N, 1, n_mels, T)
mel = mel.squeeze(1)
t = mel.size(-1)
if t >= n_frames:
mel = mel[:, :, :n_frames]
else:
mel = torch.nn.functional.pad(mel, (0, n_frames - t))
return mel.numpy().astype(np.float32)
def prepare(out_dir: Path, n_train: int, n_val: int, sr: int = SR, n_fft: int = 256,
hop: int = 64, n_mels: int = 64, n_frames: int = 96, seed: int = 0) -> dict:
out_dir = Path(out_dir)
out_dir.mkdir(parents=True, exist_ok=True)
tr = generate_dataset(n_train, seed=seed)
va = generate_dataset(n_val, seed=seed + 999)
tr_mel = compute_mels(to_arrays(tr), sr, n_fft, hop, n_mels, n_frames)
va_mel = compute_mels(to_arrays(va), sr, n_fft, hop, n_mels, n_frames)
np.save(out_dir / "train_mel.npy", tr_mel)
np.save(out_dir / "val_mel.npy", va_mel)
(out_dir / "train_captions.json").write_text(
json.dumps([it.caption for it in tr], ensure_ascii=False), encoding="utf-8")
(out_dir / "val_captions.json").write_text(
json.dumps([it.caption for it in va], ensure_ascii=False), encoding="utf-8")
classes = sorted({it.caption for it in tr})
meta = {"source": "toy_vowels", "sr": sr, "n_fft": n_fft, "hop": hop,
"n_mels": n_mels, "n_frames": n_frames, "n_train": n_train, "n_val": n_val,
"n_classes": len(classes), "classes": classes}
(out_dir / "meta.json").write_text(json.dumps(meta, ensure_ascii=False, indent=2),
encoding="utf-8")
return meta
def load_mels(out_dir: Path, split: str = "train"):
out_dir = Path(out_dir)
mel = np.load(out_dir / f"{split}_mel.npy")
caps = json.loads((out_dir / f"{split}_captions.json").read_text(encoding="utf-8"))
return mel, caps
def main() -> None:
parser = argparse.ArgumentParser(description="Préparer les mel-spectrogrammes (Phase 7).")
parser.add_argument("--out-dir", type=Path, required=True)
parser.add_argument("--n-train", type=int, default=2000)
parser.add_argument("--n-val", type=int, default=200)
parser.add_argument("--sr", type=int, default=SR)
parser.add_argument("--n-fft", type=int, default=256)
parser.add_argument("--hop", type=int, default=64)
parser.add_argument("--n-mels", type=int, default=64)
parser.add_argument("--n-frames", type=int, default=96)
parser.add_argument("--seed", type=int, default=0)
args = parser.parse_args()
meta = prepare(args.out_dir, args.n_train, args.n_val, args.sr, args.n_fft,
args.hop, args.n_mels, args.n_frames, args.seed)
print(json.dumps({k: v for k, v in meta.items() if k != "classes"},
ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()
|