Files

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()