Skip to content

Commit

Permalink
ENH: Optimizations and larger scope of GIL release.
Browse files Browse the repository at this point in the history
  • Loading branch information
sabonerune committed Nov 3, 2024
1 parent 9c7a9e1 commit 3f20a06
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 112 deletions.
23 changes: 14 additions & 9 deletions pyopenjtalk/htsengine.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ cdef class HTSEngine(object):
HTS_Engine_initialize(self.engine)

if self.load(voice) != 1:
self.clear()
raise RuntimeError("Failed to initalize HTS_Engine")
self.clear()
raise RuntimeError("Failed to initalize HTS_Engine")

def load(self, bytes voice):
cdef char* voices = voice
cdef char ret
ret = HTS_Engine_load(self.engine, &voices, 1)
with nogil:
ret = HTS_Engine_load(self.engine, &voices, 1)
return ret

def get_sampling_frequency(self):
Expand Down Expand Up @@ -85,21 +86,25 @@ cdef class HTSEngine(object):
"""Synthesize from strings"""
cdef size_t num_lines = len(labels)
cdef char **lines = <char**> malloc((num_lines + 1) * sizeof(char*))
for n in range(len(labels)):
for n in range(num_lines):
lines[n] = <char*>labels[n]

cdef char ret = HTS_Engine_synthesize_from_strings(self.engine, lines, num_lines)
free(lines)
cdef char ret
with nogil:
ret = HTS_Engine_synthesize_from_strings(self.engine, lines, num_lines)
free(lines)
if ret != 1:
raise RuntimeError("Failed to run synthesize_from_strings")

def get_generated_speech(self):
"""Get generated speech"""
cdef size_t nsamples = HTS_Engine_get_nsamples(self.engine)
cdef np.ndarray speech = np.zeros([nsamples], dtype=np.float64)
cdef np.ndarray speech = np.empty([nsamples], dtype=np.float64)
cdef double[:] speech_view = speech
cdef size_t index
for index in range(nsamples):
speech[index] = HTS_Engine_get_generated_speech(self.engine, index)
with (nogil, cython.boundscheck(False)):
for index in range(nsamples):
speech_view[index] = HTS_Engine_get_generated_speech(self.engine, index)
return speech

def get_fullcontext_label_format(self):
Expand Down
8 changes: 4 additions & 4 deletions pyopenjtalk/htsengine/__init__.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ cdef extern from "HTS_engine.h":
ctypedef _HTS_Engine HTS_Engine

void HTS_Engine_initialize(HTS_Engine * engine)
char HTS_Engine_load(HTS_Engine * engine, char **voices, size_t num_voices)
char HTS_Engine_load(HTS_Engine * engine, char **voices, size_t num_voices) nogil
size_t HTS_Engine_get_sampling_frequency(HTS_Engine * engine)
size_t HTS_Engine_get_fperiod(HTS_Engine * engine)
void HTS_Engine_refresh(HTS_Engine * engine)
void HTS_Engine_clear(HTS_Engine * engine)
const char *HTS_Engine_get_fullcontext_label_format(HTS_Engine * engine)
char HTS_Engine_synthesize_from_strings(HTS_Engine * engine, char **lines, size_t num_lines)
char HTS_Engine_synthesize_from_strings(HTS_Engine * engine, char **lines, size_t num_lines) nogil
char HTS_Engine_synthesize_from_fn(HTS_Engine * engine, const char *fn)
double HTS_Engine_get_generated_speech(HTS_Engine * engine, size_t index)
double HTS_Engine_get_generated_speech(HTS_Engine * engine, size_t index) nogil
size_t HTS_Engine_get_nsamples(HTS_Engine * engine)

void HTS_Engine_set_speed(HTS_Engine * engine, double f)
void HTS_Engine_add_half_tone(HTS_Engine * engine, double f)
void HTS_Engine_add_half_tone(HTS_Engine * engine, double f)
120 changes: 59 additions & 61 deletions pyopenjtalk/openjtalk.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
# cython: boundscheck=True, wraparound=True
# cython: c_string_type=unicode, c_string_encoding=ascii

import numpy as np

cimport numpy as np
np.import_array()

cimport cython
from libc.stdlib cimport calloc
from libc.string cimport strlen

Expand Down Expand Up @@ -54,48 +48,48 @@ cdef njd_node_get_read(_njd.NJDNode* node):
cdef njd_node_get_pron(_njd.NJDNode* node):
return (<bytes>(_njd.NJDNode_get_pron(node))).decode("utf-8")

cdef njd_node_get_acc(_njd.NJDNode* node):
cdef int njd_node_get_acc(_njd.NJDNode* node) noexcept:
return _njd.NJDNode_get_acc(node)

cdef njd_node_get_mora_size(_njd.NJDNode* node):
cdef int njd_node_get_mora_size(_njd.NJDNode* node) noexcept:
return _njd.NJDNode_get_mora_size(node)

cdef njd_node_get_chain_rule(_njd.NJDNode* node):
return (<bytes>(_njd.NJDNode_get_chain_rule(node))).decode("utf-8")

cdef njd_node_get_chain_flag(_njd.NJDNode* node):
return _njd.NJDNode_get_chain_flag(node)
cdef int njd_node_get_chain_flag(_njd.NJDNode* node) noexcept:
return _njd.NJDNode_get_chain_flag(node)


cdef node2feature(_njd.NJDNode* node):
return {
"string": njd_node_get_string(node),
"pos": njd_node_get_pos(node),
"pos_group1": njd_node_get_pos_group1(node),
"pos_group2": njd_node_get_pos_group2(node),
"pos_group3": njd_node_get_pos_group3(node),
"ctype": njd_node_get_ctype(node),
"cform": njd_node_get_cform(node),
"orig": njd_node_get_orig(node),
"read": njd_node_get_read(node),
"pron": njd_node_get_pron(node),
"acc": njd_node_get_acc(node),
"mora_size": njd_node_get_mora_size(node),
"chain_rule": njd_node_get_chain_rule(node),
"chain_flag": njd_node_get_chain_flag(node),
}
return {
"string": njd_node_get_string(node),
"pos": njd_node_get_pos(node),
"pos_group1": njd_node_get_pos_group1(node),
"pos_group2": njd_node_get_pos_group2(node),
"pos_group3": njd_node_get_pos_group3(node),
"ctype": njd_node_get_ctype(node),
"cform": njd_node_get_cform(node),
"orig": njd_node_get_orig(node),
"read": njd_node_get_read(node),
"pron": njd_node_get_pron(node),
"acc": njd_node_get_acc(node),
"mora_size": njd_node_get_mora_size(node),
"chain_rule": njd_node_get_chain_rule(node),
"chain_flag": njd_node_get_chain_flag(node),
}


cdef njd2feature(_njd.NJD* njd):
cdef _njd.NJDNode* node = njd.head
features = []
while node is not NULL:
features.append(node2feature(node))
node = node.next
features.append(node2feature(node))
node = node.next
return features


cdef feature2njd(_njd.NJD* njd, features):
cdef void feature2njd(_njd.NJD* njd, features):
cdef _njd.NJDNode* node

for feature_node in features:
Expand All @@ -119,7 +113,7 @@ cdef feature2njd(_njd.NJD* njd, features):
_njd.NJD_push_node(njd, node)

# based on Mecab_load in impl. from mecab.cpp
cdef inline int Mecab_load_with_userdic(Mecab *m, char* dicdir, char* userdic):
cdef inline int Mecab_load_with_userdic(Mecab *m, char* dicdir, char* userdic) noexcept nogil:
if userdic == NULL or strlen(userdic) == 0:
return Mecab_load(m, dicdir)

Expand Down Expand Up @@ -164,45 +158,49 @@ cdef class OpenJTalk(object):
cdef JPCommon* jpcommon

def __cinit__(self, bytes dn_mecab=b"/usr/local/dic", bytes userdic=b""):
cdef char* _dn_mecab = dn_mecab
cdef char* _userdic = userdic

self.mecab = new Mecab()
self.njd = new NJD()
self.jpcommon = new JPCommon()

Mecab_initialize(self.mecab)
NJD_initialize(self.njd)
JPCommon_initialize(self.jpcommon)
with nogil:
Mecab_initialize(self.mecab)
NJD_initialize(self.njd)
JPCommon_initialize(self.jpcommon)

r = self._load(dn_mecab, userdic)
if r != 1:
self._clear()
raise RuntimeError("Failed to initalize Mecab")
r = self._load(_dn_mecab, _userdic)
if r != 1:
self._clear()
raise RuntimeError("Failed to initalize Mecab")

cdef void _clear(self) noexcept nogil:
Mecab_clear(self.mecab)
NJD_clear(self.njd)
JPCommon_clear(self.jpcommon)

def _clear(self):
Mecab_clear(self.mecab)
NJD_clear(self.njd)
JPCommon_clear(self.jpcommon)

def _load(self, bytes dn_mecab, bytes userdic):
cdef int _load(self, char* dn_mecab, char* userdic) noexcept nogil:
return Mecab_load_with_userdic(self.mecab, dn_mecab, userdic)


def run_frontend(self, text):
"""Run OpenJTalk's text processing frontend
"""
cdef char buff[8192]

if isinstance(text, str):
text = text.encode("utf-8")
text2mecab(buff, text)
Mecab_analysis(self.mecab, buff)
mecab2njd(self.njd, Mecab_get_feature(self.mecab), Mecab_get_size(self.mecab))
_njd.njd_set_pronunciation(self.njd)
_njd.njd_set_digit(self.njd)
_njd.njd_set_accent_phrase(self.njd)
_njd.njd_set_accent_type(self.njd)
_njd.njd_set_unvoiced_vowel(self.njd)
_njd.njd_set_long_vowel(self.njd)
cdef const char* _text = text
with nogil:
text2mecab(buff, _text)
Mecab_analysis(self.mecab, buff)
mecab2njd(self.njd, Mecab_get_feature(self.mecab), Mecab_get_size(self.mecab))
_njd.njd_set_pronunciation(self.njd)
_njd.njd_set_digit(self.njd)
_njd.njd_set_accent_phrase(self.njd)
_njd.njd_set_accent_type(self.njd)
_njd.njd_set_unvoiced_vowel(self.njd)
_njd.njd_set_long_vowel(self.njd)
features = njd2feature(self.njd)

# Note that this will release memory for njd feature
Expand All @@ -215,19 +213,19 @@ cdef class OpenJTalk(object):
"""Make full-context label
"""
feature2njd(self.njd, features)
njd2jpcommon(self.jpcommon, self.njd)
with nogil:
njd2jpcommon(self.jpcommon, self.njd)

JPCommon_make_label(self.jpcommon)
JPCommon_make_label(self.jpcommon)

cdef int label_size = JPCommon_get_label_size(self.jpcommon)
cdef char** label_feature
label_feature = JPCommon_get_label_feature(self.jpcommon)
label_size = JPCommon_get_label_size(self.jpcommon)
label_feature = JPCommon_get_label_feature(self.jpcommon)

labels = []
for i in range(label_size):
# This will create a copy of c string
# http://cython.readthedocs.io/en/latest/src/tutorial/strings.html
labels.append(<unicode>label_feature[i])
# This will create a copy of c string
# http://cython.readthedocs.io/en/latest/src/tutorial/strings.html
labels.append(<unicode>label_feature[i])

# Note that this will release memory for label feature
JPCommon_refresh(self.jpcommon)
Expand Down
32 changes: 16 additions & 16 deletions pyopenjtalk/openjtalk/jpcommon.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ from libc.stdio cimport FILE

cdef extern from "jpcommon.h":
cdef cppclass JPCommonNode:
char *pron
char *pos
char *ctype
char *cform
int acc
int chain_flag
void *prev
void *next
char *pron
char *pos
char *ctype
char *cform
int acc
int chain_flag
void *prev
void *next

cdef cppclass JPCommon:
JPCommonNode *head
JPCommonNode *tail
void *label
JPCommonNode *head
JPCommonNode *tail
void *label

void JPCommon_initialize(JPCommon * jpcommon)
void JPCommon_initialize(JPCommon * jpcommon) nogil
void JPCommon_push(JPCommon * jpcommon, JPCommonNode * node)
void JPCommon_make_label(JPCommon * jpcommon)
int JPCommon_get_label_size(JPCommon * jpcommon)
char **JPCommon_get_label_feature(JPCommon * jpcommon)
void JPCommon_make_label(JPCommon * jpcommon) nogil
int JPCommon_get_label_size(JPCommon * jpcommon) nogil
char **JPCommon_get_label_feature(JPCommon * jpcommon) nogil
void JPCommon_print(JPCommon * jpcommon)
void JPCommon_fprint(JPCommon * jpcommon, FILE * fp)
void JPCommon_refresh(JPCommon * jpcommon)
void JPCommon_clear(JPCommon * jpcommon)
void JPCommon_clear(JPCommon * jpcommon) nogil
20 changes: 10 additions & 10 deletions pyopenjtalk/openjtalk/mecab.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ cdef extern from "mecab.h":
void *tagger
void *lattice

cdef int Mecab_initialize(Mecab *m)
cdef int Mecab_load(Mecab *m, const char *dicdir)
cdef int Mecab_analysis(Mecab *m, const char *str)
cdef int Mecab_initialize(Mecab *m) nogil
cdef int Mecab_load(Mecab *m, const char *dicdir) nogil
cdef int Mecab_analysis(Mecab *m, const char *str) nogil
cdef int Mecab_print(Mecab *m)
int Mecab_get_size(Mecab *m)
char **Mecab_get_feature(Mecab *m)
cdef int Mecab_refresh(Mecab *m)
cdef int Mecab_clear(Mecab *m)
int Mecab_get_size(Mecab *m) nogil
char **Mecab_get_feature(Mecab *m) nogil
cdef int Mecab_refresh(Mecab *m) nogil
cdef int Mecab_clear(Mecab *m) nogil
cdef int mecab_dict_index(int argc, char **argv) nogil

cdef extern from "mecab.h" namespace "MeCab":
Expand All @@ -24,6 +24,6 @@ cdef extern from "mecab.h" namespace "MeCab":
cdef cppclass Lattice:
pass
cdef cppclass Model:
Tagger *createTagger()
Lattice *createLattice()
cdef Model *createModel(int argc, char **argv)
Tagger *createTagger() nogil
Lattice *createLattice() nogil
cdef Model *createModel(int argc, char **argv) nogil
2 changes: 1 addition & 1 deletion pyopenjtalk/openjtalk/mecab2njd.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
from .njd cimport NJD

cdef extern from "mecab2njd.h":
void mecab2njd(NJD * njd, char **feature, int size);
void mecab2njd(NJD * njd, char **feature, int size) nogil
16 changes: 8 additions & 8 deletions pyopenjtalk/openjtalk/njd.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ cdef extern from "njd.h":
NJDNode *head
NJDNode *tail

void NJD_initialize(NJD * njd)
void NJD_initialize(NJD * njd) nogil
void NJD_load(NJD * njd, const char *str)
void NJD_load_from_fp(NJD * njd, FILE * fp)
int NJD_get_size(NJD * njd)
Expand All @@ -76,22 +76,22 @@ cdef extern from "njd.h":
void NJD_fprint(NJD * njd, FILE * fp)
void NJD_sprint(NJD * njd, char *buff, const char *split_code)
void NJD_refresh(NJD * njd)
void NJD_clear(NJD * wl)
void NJD_clear(NJD * wl) nogil

cdef extern from "njd_set_accent_phrase.h":
void njd_set_accent_phrase(NJD * njd)
void njd_set_accent_phrase(NJD * njd) nogil

cdef extern from "njd_set_accent_type.h":
void njd_set_accent_type(NJD * njd)
void njd_set_accent_type(NJD * njd) nogil

cdef extern from "njd_set_digit.h":
void njd_set_digit(NJD * njd)
void njd_set_digit(NJD * njd) nogil

cdef extern from "njd_set_long_vowel.h":
void njd_set_long_vowel(NJD * njd)
void njd_set_long_vowel(NJD * njd) nogil

cdef extern from "njd_set_pronunciation.h":
void njd_set_pronunciation(NJD * njd)
void njd_set_pronunciation(NJD * njd) nogil

cdef extern from "njd_set_unvoiced_vowel.h":
void njd_set_unvoiced_vowel(NJD * njd)
void njd_set_unvoiced_vowel(NJD * njd) nogil
2 changes: 1 addition & 1 deletion pyopenjtalk/openjtalk/njd2jpcommon.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ from .jpcommon cimport JPCommon
from .njd cimport NJD

cdef extern from "njd2jpcommon.h":
void njd2jpcommon(JPCommon * jpcommon, NJD * njd)
void njd2jpcommon(JPCommon * jpcommon, NJD * njd) nogil
2 changes: 1 addition & 1 deletion pyopenjtalk/openjtalk/text2mecab.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# distutils: language = c++

cdef extern from "text2mecab.h":
void text2mecab(char *output, const char *input)
void text2mecab(char *output, const char *input) nogil
Loading

0 comments on commit 3f20a06

Please sign in to comment.