Spaces:
Running
Running
| from __future__ import annotations | |
| import numpy as np | |
| from scipy.io import wavfile | |
| from pathlib import Path | |
| OUTPUT_DIR = Path(__file__).parent / "sample_data" | |
| SR = 22050 | |
| def make_speech_like(duration_s: float, sr: int = SR) -> np.ndarray: | |
| """Generate a speech-like signal with drifting pitch and irregular envelope.""" | |
| n_samples = int(sr * duration_s) | |
| f0_base = 150.0 | |
| f0_drift = np.cumsum(np.random.randn(n_samples) * 0.05) | |
| f0_drift = f0_drift - np.mean(f0_drift) | |
| f0_curve = f0_base + np.clip(f0_drift, -40, 40) | |
| phase = np.cumsum(2 * np.pi * f0_curve / sr) | |
| signal = 0.30 * np.sin(phase) | |
| signal += 0.15 * np.sin(2 * phase + np.random.uniform(0, np.pi)) | |
| signal += 0.08 * np.sin(3 * phase + np.random.uniform(0, np.pi)) | |
| signal += 0.04 * np.sin(5 * phase + np.random.uniform(0, np.pi)) | |
| syllable_rate = np.random.uniform(3.0, 5.0) | |
| n_syllables = int(duration_s * syllable_rate) + 1 | |
| envelope = np.zeros(n_samples) | |
| samples_per_syl = n_samples // n_syllables | |
| for i in range(n_syllables): | |
| start = i * samples_per_syl | |
| length = int(samples_per_syl * np.random.uniform(0.4, 0.9)) | |
| end = min(start + length, n_samples) | |
| win = np.hanning(end - start) | |
| amplitude = np.random.uniform(0.5, 1.0) | |
| envelope[start:end] += win * amplitude | |
| envelope = np.clip(envelope, 0, 1) | |
| signal *= envelope | |
| noise_level = 0.03 * np.random.uniform(0.8, 1.2) | |
| signal += noise_level * np.random.randn(n_samples) | |
| peak = np.max(np.abs(signal)) | |
| if peak > 0: | |
| signal = signal / peak * 0.5 | |
| return signal | |
| def save_wav(filename: str, audio: np.ndarray, sr: int = SR): | |
| audio_16 = np.clip(audio * 32767, -32768, 32767).astype(np.int16) | |
| filepath = OUTPUT_DIR / filename | |
| wavfile.write(str(filepath), sr, audio_16) | |
| print(" Created: %s (%.1fs, %dHz)" % (filename, len(audio) / sr, sr)) | |
| def main(): | |
| OUTPUT_DIR.mkdir(parents=True, exist_ok=True) | |
| print("Generating sample audio data...\n") | |
| for i in range(1, 4): | |
| audio = make_speech_like(3.0 + i * 0.5) | |
| save_wav("good_%02d_clean_speech.wav" % i, audio) | |
| audio = make_speech_like(3.0) | |
| noisy_low = audio + 0.1 * np.random.randn(len(audio)) | |
| save_wav("noisy_01_low_snr.wav", noisy_low / np.max(np.abs(noisy_low)) * 0.8) | |
| noisy_high = audio + 0.3 * np.random.randn(len(audio)) | |
| save_wav("noisy_02_very_low_snr.wav", noisy_high / np.max(np.abs(noisy_high)) * 0.8) | |
| audio = make_speech_like(3.0) | |
| clipped = np.clip(audio * 2.0, -0.99, 0.99) | |
| save_wav("clipped_01_hard_clip.wav", clipped) | |
| audio2 = make_speech_like(2.5) | |
| clipped2 = np.clip(audio2 * 1.5, -0.99, 0.99) | |
| save_wav("clipped_02_soft_clip.wav", clipped2) | |
| audio = make_speech_like(2.0) | |
| padded_lead = np.concatenate([np.zeros(SR * 2), audio]) | |
| save_wav("silence_01_long_leading.wav", padded_lead) | |
| padded_trail = np.concatenate([audio, np.zeros(SR * 3)]) | |
| save_wav("silence_02_long_trailing.wav", padded_trail) | |
| audio1 = make_speech_like(1.5) | |
| audio2 = make_speech_like(1.5) | |
| gapped = np.concatenate([audio1, np.zeros(SR * 3), audio2]) | |
| save_wav("silence_03_internal_gap.wav", gapped) | |
| tiny = make_speech_like(0.2) | |
| save_wav("duration_01_too_short.wav", tiny) | |
| long_audio = np.tile(make_speech_like(5.0), 8) | |
| save_wav("duration_02_too_long.wav", long_audio) | |
| audio = make_speech_like(3.0, sr=11025) | |
| save_wav("samplerate_01_wrong.wav", audio, sr=11025) | |
| audio = make_speech_like(3.0) | |
| quiet = audio * 0.02 | |
| save_wav("loudness_01_too_quiet.wav", quiet) | |
| loud = audio * 0.99 | |
| save_wav("loudness_02_too_loud.wav", loud) | |
| audio = make_speech_like(3.0) | |
| save_wav("duplicate_01_original.wav", audio) | |
| dup = audio + 0.001 * np.random.randn(len(audio)) | |
| save_wav("duplicate_02_near_copy.wav", dup) | |
| t = np.linspace(0, 3.0, int(SR * 3.0), endpoint=False) | |
| metallic = 0.5 * np.random.randn(len(t)) | |
| metallic *= 0.5 + 0.5 * np.sin(2 * np.pi * 4 * t) | |
| save_wav("artifact_01_metallic.wav", metallic / np.max(np.abs(metallic)) * 0.7) | |
| # Upsampled file: generate at 8kHz then save at 22050Hz | |
| audio_8k = make_speech_like(3.0, sr=8000) | |
| from scipy.signal import resample | |
| upsampled = resample(audio_8k, int(len(audio_8k) * SR / 8000)) | |
| save_wav("upsampled_01_fake_22k.wav", upsampled / np.max(np.abs(upsampled)) * 0.5) | |
| # Stereo file (most TTS expects mono) | |
| mono = make_speech_like(3.0) | |
| stereo = np.stack([mono, mono], axis=-1) | |
| stereo_16 = np.clip(stereo * 32767, -32768, 32767).astype(np.int16) | |
| wavfile.write(str(OUTPUT_DIR / "channel_01_stereo.wav"), SR, stereo_16) | |
| print(" Created: channel_01_stereo.wav (3.0s, %dHz, stereo)" % SR) | |
| print("\nDone. Generated %d sample files in %s" % ( | |
| len(list(OUTPUT_DIR.glob("*.wav"))), OUTPUT_DIR)) | |
| if __name__ == "__main__": | |
| main() | |