mirror of
https://github.com/rhasspy/piper-sample-generator.git
synced 2026-08-27 18:15:58 -04:00
Move to package
This commit is contained in:
parent
c9d824c0e2
commit
1a8c49bd29
20 changed files with 47 additions and 63 deletions
|
|
@ -1,5 +1,9 @@
|
|||
# Changelog
|
||||
|
||||
## 3.2.0
|
||||
|
||||
- Refactor as `piper_sample_generator` package
|
||||
|
||||
## 3.1.0
|
||||
|
||||
- Support MPS acceleration on Apple Silicon
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -33,7 +33,7 @@ wget -O voices/en_US-lessac-medium.onnx.json 'https://huggingface.co/rhasspy/pip
|
|||
Generate a small set of samples with the CLI:
|
||||
|
||||
``` sh
|
||||
python3 generate_samples.py 'okay piper.' --model voices/en_US-lessac-medium.onnx --max-samples 10 --output-dir okay_piper/
|
||||
python3 -m piper_sample_generator 'okay piper.' --model voices/en_US-lessac-medium.onnx --max-samples 10 --output-dir okay_piper/
|
||||
```
|
||||
|
||||
Check the `okay_piper/` directory for 10 WAV files (named `0.wav` to `9.wav`).
|
||||
|
|
@ -53,7 +53,7 @@ wget -O models/en-us-libritts-high.pt 'https://github.com/rhasspy/piper-sample-g
|
|||
Generate a small set of samples with the CLI:
|
||||
|
||||
``` sh
|
||||
python3 generate_samples.py 'okay piper.' --model models/en-us-libritts-high.pt --max-samples 10 --output-dir okay_piper/
|
||||
python3 -m piper_sample_generator 'okay piper.' --model models/en-us-libritts-high.pt --max-samples 10 --output-dir okay_piper/
|
||||
```
|
||||
|
||||
Check the `okay_piper/` directory for 10 WAV files (named `0.wav` to `9.wav`).
|
||||
|
|
@ -61,7 +61,7 @@ Check the `okay_piper/` directory for 10 WAV files (named `0.wav` to `9.wav`).
|
|||
Generation can be much faster and more efficient if you have a GPU available and PyTorch is configured to use it. In this case, increase the batch size:
|
||||
|
||||
``` sh
|
||||
python3 generate_samples.py 'okay piper.' --model models/en-us-libritts-high.pt --max-samples 100 --batch-size 10 --output-dir okay_piper/
|
||||
python3 -m piper_sample_generator 'okay piper.' --model models/en-us-libritts-high.pt --max-samples 100 --batch-size 10 --output-dir okay_piper/
|
||||
```
|
||||
|
||||
On an NVidia 2080 Ti with 11GB, a batch size of 100 was possible (generating approximately 100 samples per second).
|
||||
|
|
@ -75,14 +75,14 @@ See `--help` for more options, including the `--length-scales` (speaking speeds)
|
|||
Once you have samples generated, you can augment them using [audiomentation](https://iver56.github.io/audiomentations/):
|
||||
|
||||
``` sh
|
||||
python3 augment.py --sample-rate 22050 okay_piper/ okay_piper_augmented/
|
||||
python3 -m piper_sample_generator.augment --sample-rate 22050 okay_piper/ okay_piper_augmented/
|
||||
```
|
||||
|
||||
This will do several things to each sample:
|
||||
|
||||
1. Randomly decrease the volume
|
||||
* The original samples are normalized, so different volume levels are needed
|
||||
2. Randomly apply an [impulse response][] using the files in `impulses/`
|
||||
2. Randomly apply an [impulse response][] using the files in `piper_sample_generator/impulses/`
|
||||
* Change the acoustics of the sample to sound like the speaker was in a room with echo or using a poor quality microphone
|
||||
3. Resample to 16Khz for training (e.g., [openWakeWord][])
|
||||
|
||||
|
|
|
|||
1
piper_sample_generator/__init__.py
Normal file
1
piper_sample_generator/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
"""Piper sample generator."""
|
||||
|
|
@ -16,7 +16,10 @@ import torch
|
|||
from piper import PiperVoice, SynthesisConfig
|
||||
from piper.phonemize_espeak import EspeakPhonemizer
|
||||
|
||||
from piper_train.vits import commons
|
||||
try:
|
||||
from piper_train.vits import commons
|
||||
except ImportError:
|
||||
from piper_train.vits import commons
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
|
@ -176,7 +179,8 @@ def generate_samples(
|
|||
audio_numpy = audio.cpu().numpy()
|
||||
|
||||
if torch.backends.mps.is_available():
|
||||
# There seems to be a memory leak if we don't empty the cache after each batch with mps
|
||||
# There seems to be a memory leak if we don't empty the cache
|
||||
# after each batch with mps
|
||||
torch.mps.empty_cache()
|
||||
gc.collect()
|
||||
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import audioop
|
||||
import sys
|
||||
import wave
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from audiomentations import Compose, ApplyImpulseResponse, Gain
|
||||
from audiomentations import ApplyImpulseResponse, Compose, Gain
|
||||
|
||||
_DIR = Path(__file__).parent
|
||||
|
||||
|
|
@ -35,9 +34,10 @@ def main() -> None:
|
|||
output_wav = output_dir / (input_wav.relative_to(input_dir))
|
||||
output_wav.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with wave.open(str(input_wav), "rb") as input_wav_file, wave.open(
|
||||
str(output_wav), "wb"
|
||||
) as output_wav_file:
|
||||
with (
|
||||
wave.open(str(input_wav), "rb") as input_wav_file,
|
||||
wave.open(str(output_wav), "wb") as output_wav_file,
|
||||
):
|
||||
assert input_wav_file.getsampwidth() == 2
|
||||
assert input_wav_file.getnchannels() == 1
|
||||
|
||||
12
pylintrc
12
pylintrc
|
|
@ -1,3 +1,6 @@
|
|||
[MASTER]
|
||||
ignored-modules=torch
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
disable=
|
||||
format,
|
||||
|
|
@ -31,14 +34,7 @@ disable=
|
|||
missing-class-docstring,
|
||||
missing-function-docstring,
|
||||
import-error,
|
||||
consider-using-with
|
||||
relative-beyond-top-level
|
||||
|
||||
[FORMAT]
|
||||
expected-line-ending-format=LF
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=numpy.*,torch.*
|
||||
|
|
|
|||
|
|
@ -4,41 +4,31 @@ build-backend = "setuptools.build_meta"
|
|||
|
||||
[project]
|
||||
name = "piper-sample-generator"
|
||||
version = "3.1.0"
|
||||
license = {text = "Apache-2.0"}
|
||||
version = "3.2.0"
|
||||
license = {text = "MIT"}
|
||||
description = "Generate TTS audio samples for training wake word systems"
|
||||
readme = "README.md"
|
||||
authors = [
|
||||
{name = "The Home Assistant Authors", email = "hello@home-assistant.io"}
|
||||
]
|
||||
keywords = ["piper", "sample", "tts", "wakeword"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Text Processing :: Linguistic",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
requires-python = ">=3.9.0"
|
||||
dependencies = [
|
||||
"piper-tts>=1.3.0,<2",
|
||||
"audiomentations==0.33.0",
|
||||
"piper-tts==1.3.0",
|
||||
"numpy>=2,<3",
|
||||
"torch>=2,<3",
|
||||
"torchaudio",
|
||||
"audiomentations",
|
||||
"numpy",
|
||||
"webrtcvad",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"black==24.8.0",
|
||||
"flake8==7.2.0",
|
||||
"mypy==1.14.0",
|
||||
"pylint==3.2.7",
|
||||
"pytest==8.3.5",
|
||||
"black==22.12.0",
|
||||
"flake8==6.0.0",
|
||||
"isort==5.11.3",
|
||||
"mypy==0.991",
|
||||
"pylint==2.15.9",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
|
|
@ -49,4 +39,4 @@ platforms = ["any"]
|
|||
zip-safe = true
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = []
|
||||
include = ["piper_sample_generator*"]
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
audiomentations==0.33.0
|
||||
piper-phonemize==1.1.0
|
||||
numpy<2
|
||||
torch<2
|
||||
torchaudio
|
||||
webrtcvad
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
black==22.12.0
|
||||
flake8==6.0.0
|
||||
isort==5.11.3
|
||||
mypy==0.991
|
||||
pylint==2.15.9
|
||||
|
|
@ -6,7 +6,7 @@ from pathlib import Path
|
|||
_DIR = Path(__file__).parent
|
||||
_PROGRAM_DIR = _DIR.parent
|
||||
_VENV_DIR = _PROGRAM_DIR / ".venv"
|
||||
_SCRIPT = _PROGRAM_DIR / "generate_samples.py"
|
||||
_MODULE_DIR = _PROGRAM_DIR / "piper_sample_generator"
|
||||
|
||||
if _VENV_DIR.exists():
|
||||
context = venv.EnvBuilder().ensure_directories(_VENV_DIR)
|
||||
|
|
@ -14,5 +14,5 @@ if _VENV_DIR.exists():
|
|||
else:
|
||||
python_exe = "python3"
|
||||
|
||||
subprocess.check_call([python_exe, "-m", "black", str(_SCRIPT)])
|
||||
subprocess.check_call([python_exe, "-m", "isort", str(_SCRIPT)])
|
||||
subprocess.check_call([python_exe, "-m", "black", str(_MODULE_DIR)])
|
||||
subprocess.check_call([python_exe, "-m", "isort", str(_MODULE_DIR)])
|
||||
|
|
|
|||
12
script/lint
12
script/lint
|
|
@ -6,7 +6,7 @@ from pathlib import Path
|
|||
_DIR = Path(__file__).parent
|
||||
_PROGRAM_DIR = _DIR.parent
|
||||
_VENV_DIR = _PROGRAM_DIR / ".venv"
|
||||
_SCRIPT = _PROGRAM_DIR / "generate_samples.py"
|
||||
_MODULE_DIR = _PROGRAM_DIR / "piper_sample_generator"
|
||||
|
||||
if _VENV_DIR.exists():
|
||||
context = venv.EnvBuilder().ensure_directories(_VENV_DIR)
|
||||
|
|
@ -14,8 +14,8 @@ if _VENV_DIR.exists():
|
|||
else:
|
||||
python_exe = "python3"
|
||||
|
||||
subprocess.check_call([python_exe, "-m", "black", str(_SCRIPT), "--check"])
|
||||
subprocess.check_call([python_exe, "-m", "isort", str(_SCRIPT), "--check"])
|
||||
subprocess.check_call([python_exe, "-m", "flake8", str(_SCRIPT)])
|
||||
subprocess.check_call([python_exe, "-m", "pylint", str(_SCRIPT)])
|
||||
subprocess.check_call([python_exe, "-m", "mypy", str(_SCRIPT)])
|
||||
subprocess.check_call([python_exe, "-m", "black", str(_MODULE_DIR), "--check"])
|
||||
subprocess.check_call([python_exe, "-m", "isort", str(_MODULE_DIR), "--check"])
|
||||
subprocess.check_call([python_exe, "-m", "flake8", str(_MODULE_DIR)])
|
||||
subprocess.check_call([python_exe, "-m", "pylint", str(_MODULE_DIR)])
|
||||
subprocess.check_call([python_exe, "-m", "mypy", str(_MODULE_DIR)])
|
||||
|
|
|
|||
|
|
@ -14,4 +14,4 @@ if _VENV_DIR.exists():
|
|||
else:
|
||||
python_exe = "python3"
|
||||
|
||||
subprocess.check_call([python_exe, "generate_samples.py"] + sys.argv[1:])
|
||||
subprocess.check_call([python_exe, "-m", "piper_sample_generator"] + sys.argv[1:])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue