mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-31 14:33:54 -04:00
Get the piper module working on windows
This commit is contained in:
parent
848de725de
commit
9021419440
@ -18,9 +18,9 @@
|
|||||||
"name": "cmake",
|
"name": "cmake",
|
||||||
"os": "macos",
|
"os": "macos",
|
||||||
"unix": {
|
"unix": {
|
||||||
"filename": "cmake-3.27.6.tar.gz",
|
"filename": "cmake-3.31.8.tar.gz",
|
||||||
"hash": "sha256:ef3056df528569e0e8956f6cf38806879347ac6de6a4ff7e4105dc4578732cfb",
|
"hash": "sha256:e3cde3ca83dc2d3212105326b8f1b565116be808394384007e7ef1c253af6caa",
|
||||||
"urls": ["https://github.com/Kitware/CMake/releases/download/v3.27.6/{filename}"]
|
"urls": ["https://github.com/Kitware/CMake/releases/download/v3.31.8/{filename}"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ import zipfile
|
|||||||
from bypy.constants import CL, LINK, MT, PREFIX, RC, SIGNTOOL, SW, build_dir, python_major_minor_version, worker_env
|
from bypy.constants import CL, LINK, MT, PREFIX, RC, SIGNTOOL, SW, build_dir, python_major_minor_version, worker_env
|
||||||
from bypy.constants import SRC as CALIBRE_DIR
|
from bypy.constants import SRC as CALIBRE_DIR
|
||||||
from bypy.freeze import cleanup_site_packages, extract_extension_modules, freeze_python, path_to_freeze_dir
|
from bypy.freeze import cleanup_site_packages, extract_extension_modules, freeze_python, path_to_freeze_dir
|
||||||
from bypy.pkgs.piper import copy_piper_dir
|
|
||||||
from bypy.utils import mkdtemp, py_compile, run, walk
|
from bypy.utils import mkdtemp, py_compile, run, walk
|
||||||
|
|
||||||
iv = globals()['init_env']
|
iv = globals()['init_env']
|
||||||
@ -96,6 +95,7 @@ class Env:
|
|||||||
self.lib_dir = j(self.app_base, 'Lib')
|
self.lib_dir = j(self.app_base, 'Lib')
|
||||||
self.pylib = j(self.app_base, 'pylib.zip')
|
self.pylib = j(self.app_base, 'pylib.zip')
|
||||||
self.dll_dir = j(self.app_base, 'bin')
|
self.dll_dir = j(self.app_base, 'bin')
|
||||||
|
self.share_dir = j(self.app_base, 'share')
|
||||||
self.portable_base = j(d(self.base), 'Calibre Portable')
|
self.portable_base = j(d(self.base), 'Calibre Portable')
|
||||||
self.obj_dir = j(build_dir, 'launcher')
|
self.obj_dir = j(build_dir, 'launcher')
|
||||||
self.installer_dir = j(build_dir, 'wix')
|
self.installer_dir = j(build_dir, 'wix')
|
||||||
@ -105,6 +105,7 @@ class Env:
|
|||||||
def initbase(env):
|
def initbase(env):
|
||||||
os.makedirs(env.app_base)
|
os.makedirs(env.app_base)
|
||||||
os.mkdir(env.dll_dir)
|
os.mkdir(env.dll_dir)
|
||||||
|
os.mkdir(env.share_dir)
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(env.dist)
|
shutil.rmtree(env.dist)
|
||||||
except EnvironmentError as err:
|
except EnvironmentError as err:
|
||||||
@ -130,18 +131,24 @@ def freeze(env, ext_dir, incdir):
|
|||||||
shutil.copy2(x + '.manifest', dest)
|
shutil.copy2(x + '.manifest', dest)
|
||||||
|
|
||||||
bindir = os.path.join(PREFIX, 'bin')
|
bindir = os.path.join(PREFIX, 'bin')
|
||||||
|
libdir = os.path.join(PREFIX, 'lib')
|
||||||
for x in ('pdftohtml', 'pdfinfo', 'pdftoppm', 'pdftotext', 'jpegtran-calibre', 'cjpeg-calibre', 'optipng-calibre', 'cwebp-calibre', 'JXRDecApp-calibre'):
|
for x in ('pdftohtml', 'pdfinfo', 'pdftoppm', 'pdftotext', 'jpegtran-calibre', 'cjpeg-calibre', 'optipng-calibre', 'cwebp-calibre', 'JXRDecApp-calibre'):
|
||||||
copybin(os.path.join(bindir, x + '.exe'))
|
copybin(os.path.join(bindir, x + '.exe'))
|
||||||
|
# piper
|
||||||
|
for x in ('espeak-ng-data',):
|
||||||
|
shutil.copytree(os.path.join(PREFIX, 'share', x), os.path.join(env.share_dir, x))
|
||||||
|
copybin(os.path.join(libdir, "onnxruntime.dll"))
|
||||||
|
|
||||||
for f in glob.glob(os.path.join(bindir, '*.dll')):
|
for f in glob.glob(os.path.join(bindir, '*.dll')):
|
||||||
if re.search(r'(easylzma|icutest)', f.lower()) is None:
|
if re.search(r'(easylzma|icutest)', f.lower()) is None:
|
||||||
copybin(f)
|
copybin(f)
|
||||||
|
|
||||||
ossm = os.path.join(env.dll_dir, 'ossl-modules')
|
ossm = os.path.join(env.dll_dir, 'ossl-modules')
|
||||||
os.mkdir(ossm)
|
os.mkdir(ossm)
|
||||||
for f in glob.glob(os.path.join(PREFIX, 'lib', 'ossl-modules', '*.dll')):
|
for f in glob.glob(os.path.join(libdir, 'ossl-modules', '*.dll')):
|
||||||
copybin(f, ossm)
|
copybin(f, ossm)
|
||||||
for f in glob.glob(os.path.join(PREFIX, 'ffmpeg', 'bin', '*.dll')):
|
for f in glob.glob(os.path.join(PREFIX, 'ffmpeg', 'bin', '*.dll')):
|
||||||
copybin(f)
|
copybin(f)
|
||||||
copy_piper_dir(PREFIX, env.dll_dir)
|
|
||||||
|
|
||||||
copybin(os.path.join(env.python_base, 'python%s.dll' % env.py_ver.replace('.', '')))
|
copybin(os.path.join(env.python_base, 'python%s.dll' % env.py_ver.replace('.', '')))
|
||||||
copybin(os.path.join(env.python_base, 'python%s.dll' % env.py_ver[0]))
|
copybin(os.path.join(env.python_base, 'python%s.dll' % env.py_ver[0]))
|
||||||
|
@ -181,6 +181,9 @@ if iswindows:
|
|||||||
zlib_lib_dirs = [sw_lib_dir]
|
zlib_lib_dirs = [sw_lib_dir]
|
||||||
podofo_inc = os.path.join(sw_inc_dir, 'podofo')
|
podofo_inc = os.path.join(sw_inc_dir, 'podofo')
|
||||||
podofo_lib = sw_lib_dir
|
podofo_lib = sw_lib_dir
|
||||||
|
piper_inc_dirs = [sw_inc_dir, os.path.join(sw_inc_dir, 'onnxruntime')]
|
||||||
|
piper_lib_dirs = [sw_lib_dir]
|
||||||
|
piper_libs = ['espeak-ng', 'onnxruntime']
|
||||||
elif ismacos:
|
elif ismacos:
|
||||||
sw = os.environ.get('SW', os.path.expanduser('~/sw'))
|
sw = os.environ.get('SW', os.path.expanduser('~/sw'))
|
||||||
sw_inc_dir = os.path.join(sw, 'include')
|
sw_inc_dir = os.path.join(sw, 'include')
|
||||||
|
@ -11,11 +11,14 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <onnxruntime_cxx_api.h>
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define ORT_DLL_IMPORT
|
||||||
|
#endif
|
||||||
|
#include <onnxruntime_cxx_api.h>
|
||||||
|
|
||||||
#define CLAUSE_INTONATION_FULL_STOP 0x00000000
|
#define CLAUSE_INTONATION_FULL_STOP 0x00000000
|
||||||
#define CLAUSE_INTONATION_COMMA 0x00001000
|
#define CLAUSE_INTONATION_COMMA 0x00001000
|
||||||
@ -137,8 +140,8 @@ phonemize(PyObject *self, PyObject *pytext) {
|
|||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
set_voice(PyObject *self, PyObject *args) {
|
set_voice(PyObject *self, PyObject *args) {
|
||||||
PyObject *cfg; const char *model_path;
|
PyObject *cfg; PyObject *pymp;
|
||||||
if (!PyArg_ParseTuple(args, "Os", &cfg, &model_path)) return NULL;
|
if (!PyArg_ParseTuple(args, "OU", &cfg, &pymp)) return NULL;
|
||||||
|
|
||||||
PyObject *evn = PyObject_GetAttrString(cfg, "espeak_voice_name");
|
PyObject *evn = PyObject_GetAttrString(cfg, "espeak_voice_name");
|
||||||
if (!evn) return NULL;
|
if (!evn) return NULL;
|
||||||
@ -155,10 +158,10 @@ set_voice(PyObject *self, PyObject *args) {
|
|||||||
}
|
}
|
||||||
G(sample_rate, current_sample_rate, PyLong_AsLong);
|
G(sample_rate, current_sample_rate, PyLong_AsLong);
|
||||||
G(num_speakers, current_num_speakers, PyLong_AsLong);
|
G(num_speakers, current_num_speakers, PyLong_AsLong);
|
||||||
G(length_scale, current_length_scale, PyFloat_AsDouble);
|
G(length_scale, current_length_scale, (float)PyFloat_AsDouble);
|
||||||
G(noise_scale, current_noise_scale, PyFloat_AsDouble);
|
G(noise_scale, current_noise_scale, (float)PyFloat_AsDouble);
|
||||||
G(noise_w, current_noise_w, PyFloat_AsDouble);
|
G(noise_w, current_noise_w, (float)PyFloat_AsDouble);
|
||||||
G(sentence_delay, current_sentence_delay, PyFloat_AsDouble);
|
G(sentence_delay, current_sentence_delay, (float)PyFloat_AsDouble);
|
||||||
#undef G
|
#undef G
|
||||||
|
|
||||||
PyObject *map = PyObject_GetAttrString(cfg, "phoneme_id_map");
|
PyObject *map = PyObject_GetAttrString(cfg, "phoneme_id_map");
|
||||||
@ -187,7 +190,14 @@ set_voice(PyObject *self, PyObject *args) {
|
|||||||
opts.DisableProfiling();
|
opts.DisableProfiling();
|
||||||
Ort::Env ort_env{ORT_LOGGING_LEVEL_WARNING, "piper"};
|
Ort::Env ort_env{ORT_LOGGING_LEVEL_WARNING, "piper"};
|
||||||
session.reset();
|
session.reset();
|
||||||
|
#ifdef _WIN32
|
||||||
|
wchar_t *model_path = PyUnicode_AsWideCharString(pymp, NULL);
|
||||||
|
if (!model_path) return NULL;
|
||||||
session = std::make_unique<Ort::Session>(Ort::Session(ort_env, model_path, opts));
|
session = std::make_unique<Ort::Session>(Ort::Session(ort_env, model_path, opts));
|
||||||
|
PyMem_Free(model_path);
|
||||||
|
#else
|
||||||
|
session = std::make_unique<Ort::Session>(Ort::Session(ort_env, PyUnicode_AsUTF8(pymp), opts));
|
||||||
|
#endif
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
@ -341,20 +351,20 @@ next(PyObject *self, PyObject *args) {
|
|||||||
int num_samples; const float *audio_tensor_data;
|
int num_samples; const float *audio_tensor_data;
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
auto audio_shape = output_tensors.front().GetTensorTypeAndShapeInfo().GetShape();
|
auto audio_shape = output_tensors.front().GetTensorTypeAndShapeInfo().GetShape();
|
||||||
num_samples = audio_shape[audio_shape.size() - 1];
|
num_samples = (int)audio_shape[audio_shape.size() - 1];
|
||||||
audio_tensor_data = output_tensors.front().GetTensorData<float>();
|
audio_tensor_data = output_tensors.front().GetTensorData<float>();
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
PyObject *ans = NULL, *data = NULL;
|
PyObject *ans = NULL, *data = NULL;
|
||||||
int num_of_silence_samples = 0;
|
int num_of_silence_samples = 0;
|
||||||
if (current_sentence_delay > 0) num_of_silence_samples = current_sample_rate * current_sentence_delay;
|
if (current_sentence_delay > 0) num_of_silence_samples = (int)(current_sample_rate * current_sentence_delay);
|
||||||
if (as_16bit_samples) {
|
if (as_16bit_samples) {
|
||||||
data = PyBytes_FromStringAndSize(NULL, sizeof(int16_t) * (num_samples + num_of_silence_samples));
|
data = PyBytes_FromStringAndSize(NULL, sizeof(int16_t) * (num_samples + num_of_silence_samples));
|
||||||
if (data) {
|
if (data) {
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
int16_t *x = (int16_t*)PyBytes_AS_STRING(data);
|
int16_t *x = (int16_t*)PyBytes_AS_STRING(data);
|
||||||
for (int i = 0; i < num_samples; i++) {
|
for (int i = 0; i < num_samples; i++) {
|
||||||
x[i] = std::max(-1.f, std::min(audio_tensor_data[i], 1.f)) * std::numeric_limits<int16_t>::max();
|
x[i] = (int16_t)(std::max(-1.f, std::min(audio_tensor_data[i], 1.f)) * std::numeric_limits<int16_t>::max());
|
||||||
}
|
}
|
||||||
memset(x + num_samples, 0, num_of_silence_samples * sizeof(int16_t));
|
memset(x + num_samples, 0, num_of_silence_samples * sizeof(int16_t));
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
|
@ -12,6 +12,7 @@ from threading import Lock, Thread
|
|||||||
from typing import Any, NamedTuple
|
from typing import Any, NamedTuple
|
||||||
|
|
||||||
import calibre_extensions.piper as piper
|
import calibre_extensions.piper as piper
|
||||||
|
from calibre.constants import iswindows
|
||||||
|
|
||||||
DEFAULT_LENGTH_SCALE = 1.0
|
DEFAULT_LENGTH_SCALE = 1.0
|
||||||
DEFAULT_NOISE_SCALE = 0.667
|
DEFAULT_NOISE_SCALE = 0.667
|
||||||
@ -61,6 +62,8 @@ def load_voice_config(path: str) -> VoiceConfig:
|
|||||||
def espeak_data_dir() -> str:
|
def espeak_data_dir() -> str:
|
||||||
if not getattr(sys, 'frozen', False):
|
if not getattr(sys, 'frozen', False):
|
||||||
return ''
|
return ''
|
||||||
|
if iswindows:
|
||||||
|
return os.path.join(os.path.dirname(sys.executables_location), 'share', 'espeak-ng-data')
|
||||||
return os.path.join(sys.executables_location, 'share', 'espeak-ng-data')
|
return os.path.join(sys.executables_location, 'share', 'espeak-ng-data')
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user