66 lines
2.4 KiB
Python
66 lines
2.4 KiB
Python
"""Step 3: the text for the voice, cut into segments (work/segs.json).
|
|
|
|
Every note: lexicon.pre -> lines (a blank line = paragraph 'p', a single newline = 'l') -> lines over
|
|
MAXC characters cut at sentence ends into near-equal pieces ('s') -> RUAccent '+' -> lexicon.post ->
|
|
U+0301 text for the ru-stress model.
|
|
A segment's takes are named <id>_<hash>_s<seed>.wav, the hash of the reference and the spoken text:
|
|
change the lexicon or the reference and only the segments it touches are rendered again.
|
|
"""
|
|
import hashlib
|
|
import json
|
|
import math
|
|
import re
|
|
|
|
from .accent import acute_marks, plus_marks
|
|
from .config import load
|
|
from .lexicon import post, pre
|
|
|
|
MAXC = 380
|
|
|
|
|
|
def split_long(s):
|
|
if len(s) <= MAXC:
|
|
return [s]
|
|
sents = [x.strip() for x in re.findall(r".+?(?:[.!?…]+[»\"')]*(?=\s)|$)\s*", s) if x.strip()]
|
|
k = math.ceil(len(s) / 330)
|
|
target, out, cur = len(s) / k, [], ""
|
|
for x in sents:
|
|
if cur and len(cur) + len(x) + 1 > target * 1.15 and len(out) < k - 1:
|
|
out.append(cur); cur = x
|
|
else:
|
|
cur = (cur + " " + x).strip()
|
|
out.append(cur)
|
|
return out
|
|
|
|
|
|
def main():
|
|
cfg = load()
|
|
ref = cfg["voice"]["reference"]
|
|
notes = json.load(open(cfg.w("notes.json"), encoding="utf-8"))
|
|
if cfg.only: # ENSVOICE_NOTES=n016,n238: a quick experiment on a few notes
|
|
notes = [n for n in notes if n["k"] in cfg.only]
|
|
segs = []
|
|
for n in notes:
|
|
units, join = [], "p"
|
|
for line in pre(n["text"]).split("\n"):
|
|
line = line.strip()
|
|
if not line:
|
|
join = "p"; continue
|
|
for j, piece in enumerate(split_long(line)):
|
|
units.append(("s" if j else join, piece))
|
|
join = "l"
|
|
for i, (jn, u) in enumerate(units):
|
|
plus = post(plus_marks(u))
|
|
acute = acute_marks(plus)
|
|
sid = f"{n['k']}_{i:02d}"
|
|
h = hashlib.sha1(f"{ref}|{acute}".encode()).hexdigest()[:10]
|
|
segs.append(dict(id=sid, take=f"{sid}_{h}", k=n["k"], i=i, join=jn if i else "-",
|
|
text=u, plus=plus, acute=acute))
|
|
json.dump(segs, open(cfg.w("segs.json"), "w", encoding="utf-8"), ensure_ascii=False, indent=0)
|
|
L = [len(s["text"]) for s in segs]
|
|
print("segments", len(segs), "notes", len(notes), "longest", max(L), "chars", sum(L))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|