mitvho09 commited on
Commit
a47facd
·
verified ·
1 Parent(s): cdd60e1

Upload audio_utils.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. audio_utils.py +57 -0
audio_utils.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Audio preparation helpers for DreamVoice reference clips."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import tempfile
7
+
8
+ import librosa
9
+ import numpy as np
10
+ import soundfile as sf
11
+
12
+ REFERENCE_SAMPLE_RATE = 16_000
13
+ MIN_REFERENCE_SECONDS = 5.0
14
+ MAX_REFERENCE_SECONDS = 60.0
15
+ MIN_RMS = 0.005
16
+
17
+
18
+ def prepare_reference(path: str) -> str:
19
+ """Clean and validate a voice reference clip for VoxCPM2.
20
+
21
+ The returned file is a temporary mono 16 kHz WAV. The caller owns cleanup of
22
+ that returned path after synthesis finishes.
23
+ """
24
+ if not path or not os.path.exists(path):
25
+ raise ValueError("Please record or upload a voice clip first.")
26
+
27
+ try:
28
+ audio, _ = librosa.load(path, sr=REFERENCE_SAMPLE_RATE, mono=True)
29
+ except Exception as exc: # noqa: BLE001 - present a friendly UI-safe error.
30
+ raise ValueError("I couldn't read that audio clip. Please try a WAV or MP3 recording.") from exc
31
+
32
+ if audio.size == 0 or not np.isfinite(audio).all():
33
+ raise ValueError("That voice clip looks empty. Please record 5-60 seconds of clear speech.")
34
+
35
+ audio = np.asarray(audio, dtype=np.float32)
36
+ audio, _ = librosa.effects.trim(audio, top_db=35)
37
+
38
+ if audio.size == 0:
39
+ raise ValueError("That voice clip is too quiet. Please record closer to the microphone.")
40
+
41
+ peak = float(np.max(np.abs(audio)))
42
+ rms = float(np.sqrt(np.mean(np.square(audio))))
43
+ if peak <= 0.0 or rms < MIN_RMS:
44
+ raise ValueError("That voice clip is too quiet. Please record in a quiet room, closer to the microphone.")
45
+
46
+ duration = audio.size / REFERENCE_SAMPLE_RATE
47
+ if duration < MIN_REFERENCE_SECONDS:
48
+ raise ValueError("Please record at least 5 seconds of clear speech.")
49
+ if duration > MAX_REFERENCE_SECONDS:
50
+ max_samples = int(MAX_REFERENCE_SECONDS * REFERENCE_SAMPLE_RATE)
51
+ audio = audio[:max_samples]
52
+
53
+ audio = np.clip(audio, -1.0, 1.0)
54
+ fd, cleaned_path = tempfile.mkstemp(prefix="dreamvoice_ref_", suffix=".wav")
55
+ os.close(fd)
56
+ sf.write(cleaned_path, audio, REFERENCE_SAMPLE_RATE, subtype="PCM_16")
57
+ return cleaned_path