Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
oatsu-gh committed Jun 14, 2021
0 parents commit 77580e8
Show file tree
Hide file tree
Showing 45 changed files with 4,254 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
nnsvs
singing_database

*.ini
*.lab
*.mid
*.ust
*.wav
*.xml
*.musicxml
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# ENUNU Training Kit

USTとLABとWAVがあれば楽にモデル生成できます。

## 用途

UST ファイルが同梱されている歌唱データベースから、[ENUNU](https://github.com/oatsu-gh/ENUNU) 用の歌声モデルを生成します。

## 必要なもの

- Windows 10

- Python 3.8
- Git for Windows
- Visual C++ v142

## 使い方

1. install.bat をダブルクリックします。(初回のみ)
2. フォルダ "singing_database" に、学習させたい歌唱データベースを丸ごと入れます。音声は **16bit/44.1kHz** にしておくこと。
3. フォルダ "train" を開いて、右クリックメニューの "Git Bash Here" を選択。
4. 表示されている黒い画面に `bash run.sh --stage 0 --stage 6` と打ち込んでエンターを押します。
5. 待ちます。学習データが多いほど時間がかかります。
6. 処理が正常に終わったら、黒い画面に `python make_it_for_release_enunu.py` と打ち込んでエンターを押します。
7. release フォルダの中に unnamed_--- というフォルダができるので、フォルダ名を変更してください。
8. 名前を変更したフォルダに、readme.txt と character.txt と 空の oto.ini を入れてください。
9. 名前を変更したフォルダを、UTAU の voice フォルダに入れたら完成です。

## 更新履歴

- v0.0.1 (2021-06-13)
- 学習キット試作
- v0.0.2 (2021-06-14)
- hedファイルを差し替えて母音無声化に対応
- enuconfigなどの編集を不要にした
12 changes: 12 additions & 0 deletions install.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@REM ENUNU Portable Train Kit 用の環境構築バッチファイル
@REM CPU環境向け

pip install --upgrade pip
pip install wheel
pip install numpy cython
pip install hydra-core<1.1
pip install utaupy tqdm pydub pyyaml
pip install torch==1.8.1+cpu torchvision==0.9.1+cpu torchaudio===0.8.1 -f "https://download.pytorch.org/whl/torch_stable.html"

git clone "https://github.com/r9y9/nnsvs"
pip install ./nnsvs
12 changes: 12 additions & 0 deletions install_for_CUDA102.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@REM ENUNU Portable Train Kit 用の環境構築バッチファイル
@REM CUDA 10.2 環境向け

pip install --upgrade pip
pip install wheel
pip install numpy cython
pip install hydra-core<1.1
pip install utaupy tqdm pydub pyyaml
pip install torch==1.8.1+cu102 torchvision==0.9.1+cu102 torchaudio===0.8.1 -f "https://download.pytorch.org/whl/torch_stable.html"

git clone "https://github.com/r9y9/nnsvs"
pip install ./nnsvs
12 changes: 12 additions & 0 deletions install_for_CUDA111.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@REM ENUNU Portable Train Kit 用の環境構築バッチファイル
@REM CUDA 11.1 環境向け

pip install --upgrade pip
pip install wheel
pip install numpy cython
pip install hydra-core<1.1
pip install utaupy tqdm pydub pyyaml
pip install torch==1.8.1+cu111 torchvision==0.9.1+cu111 torchaudio===0.8.1 -f "https://download.pytorch.org/whl/torch_stable.html"

git clone "https://github.com/r9y9/nnsvs"
pip install ./nnsvs
7 changes: 7 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
numpy
cython
hydra-core<1.1
utaupy>=1.12.0
tqdm
pydub
pyyaml
4 changes: 4 additions & 0 deletions train/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
data
dump
exp
outputs
64 changes: 64 additions & 0 deletions train/0_01_copy_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
# Copyright (c) 2021 oatsu
"""
歌唱DBから必要そうなファイルを全てコピーする。
USTとMusicXMLとLABとWAVとINI
"""

import shutil
from glob import glob
from os import makedirs
from os.path import expanduser, join
from sys import argv

import yaml
from tqdm import tqdm


def copy_target_files(db_root, out_dir, ext):
"""
拡張子を指定して、ファイルを複製する。
"""
target_files = glob(f'{db_root}/**/*.{ext}', recursive=True)
if len(target_files) != 0:
makedirs(join(out_dir, ext), exist_ok=True)
print(f'Copying {ext} files')
for path in tqdm(target_files):
shutil.copy2(path, join(out_dir, ext))


def make_gitignore(out_dir):
"""
{out_dir}/.gitignoreファイルを作る。
"""
makedirs(f'{out_dir}', exist_ok=True)
with open(f'{out_dir}/.gitignore', 'w') as f:
f.write('*\n')


def main(path_config_yaml):
"""
設定ファイルを読み取って、使いそうなファイルを複製する。
"""
# 設定ファイルを読み取る
with open(path_config_yaml, 'r') as fy:
config = yaml.load(fy, Loader=yaml.FullLoader)
# 歌唱DBのパスを取得
db_root = expanduser(config['db_root']).strip('"')
# ファイルのコピー先を取得
out_dir = config['out_dir'].strip('"')

make_gitignore(out_dir)
# 移動元と移動先を標準出力
print(f'Copy files from "{db_root}" to "{out_dir}"')
# ファイルをコピー
target_extensions = ('wav', 'xml', 'musicxml', 'ust', 'ini', 'lab')
for ext in target_extensions:
copy_target_files(db_root, out_dir, ext)


if __name__ == '__main__':
if len(argv) == 1:
main('config.yaml')
else:
main(argv[1].strip('"'))
57 changes: 57 additions & 0 deletions train/0_02_check_lab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
# Copyright (c) 2021 oatsu
"""
歌唱DBに含まれるモノラベルに不具合がないか点検する。
- 極端に短い音素(5ms以下)がないか
- 時刻の順序が逆転しているラベルがないか
"""
import sys
from glob import glob
from os.path import dirname, expanduser, join
from pprint import pprint

import utaupy as up
import yaml
from tqdm import tqdm


def check_lab_files(lab_dir):
"""
時刻がちゃんとしてるか点検
"""
mono_lab_files = sorted(glob(f'{lab_dir}/*.lab'))
# 発声時間が短すぎないか点検
invalid_lab_files = []
for path_mono in tqdm(mono_lab_files):
label = up.label.load(path_mono)
if not label.is_valid(5):
invalid_lab_files.append(path_mono)
if len(invalid_lab_files) != 0:
print('LABファイルの発声時刻に不具合があります。以下のファイルを点検してください。')
pprint(invalid_lab_files)
sys.exit(1)


def main(path_config_yaml):
"""
config.yaml から歌唱DBのパスを取得して、
そのDB中のLABファイルを点検する。
"""
# 設定ファイルを読み取る
with open(path_config_yaml, 'r') as fy:
config = yaml.load(fy, Loader=yaml.FullLoader)
# 歌唱DBのパスを取得する
config_dir = dirname(path_config_yaml)
out_dir = expanduser(join(config_dir, config['out_dir'])).strip('"')
lab_dir = join(out_dir, 'lab')
# LABファイルを点検する
print(f'Checking LAB files in {lab_dir}')
check_lab_files(lab_dir)


if __name__ == '__main__':
if len(sys.argv) == 1:
main('config.yaml')
else:
main(sys.argv[1].strip('"'))
45 changes: 45 additions & 0 deletions train/0_03_force_ust_end_with_rest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
# Copyright (c) 2021 oatsu
"""
USTファイルの最終ノートを休符にする。
"""
from glob import glob
from os.path import join
from sys import argv

import utaupy as up
import yaml
from tqdm import tqdm


def force_ust_files_end_with_rest(ust_dir):
"""
フォルダを指定し、その中にあるUSTファイルが全て休符で終わるようにする。
"""
ust_files = glob(f'{ust_dir}/*.ust')
for path_ust in tqdm(ust_files):
ust = up.ust.load(path_ust)
ust.make_finalnote_R()
ust.write(path_ust)


def main(path_config_yaml):
"""
フォルダとかを指定
"""
# 設定ファイルを読み取る
with open(path_config_yaml, 'r') as fy:
config = yaml.load(fy, Loader=yaml.FullLoader)
# 処理対象のフォルダを指定
out_dir = config['out_dir'].strip('"')
ust_dir = join(out_dir, 'ust')
# oto2kabの仕様に合わせて、USTが休符で終わるようにする。
print('Overwriting UST file so that it end with rest note.')
force_ust_files_end_with_rest(ust_dir)


if __name__ == '__main__':
if len(argv) == 1:
main('config.yaml')
else:
main(argv[1].strip('"'))
108 changes: 108 additions & 0 deletions train/0_04_ust2lab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env python3
# Copyright (c) 2021 oatsu
"""
UST版
フルラベルを生成する。また、DB中のモノラベルを複製する。
- '{out_dir}/sinsy_full' にフルラベルを生成する。
- '{out_dir}/sinsy_mono' にモノラベルを生成する。(この工程は省略した)
- '{out_dir}/mono_label' にDBのモノラベルを複製する
"""
from glob import glob
from os import makedirs
from os.path import basename, expanduser, join, splitext
from sys import argv

import yaml
from tqdm import tqdm
from utaupy.utils import ust2hts


def ust2full(path_ust_dir_in, path_full_dir_out, path_table, exclude_songs):
"""
複数のUSTファイルから、フルラベルファイルを一括生成する。
"""
makedirs(path_full_dir_out, exist_ok=True)
ust_files = glob(f'{path_ust_dir_in}/**/*.ust', recursive=True)

for path_ust in tqdm(ust_files):
songname = splitext(basename(path_ust))[0]
if songname in exclude_songs:
print(f'Skip excluded song: {songname}')
else:
path_full = f'{path_full_dir_out}/{songname}.lab'
ust2hts(path_ust, path_full, path_table, strict_sinsy_style=False)


def compare_number_of_ustfiles_and_labfiles(ust_dir, mono_align_dir):
"""
入力ファイルの数が一致するか点検する。
"""
# UST一覧を取得
ust_files = sorted(glob(f'{ust_dir}/*.ust'))
# DB内のラベルファイル一覧を取得
mono_files = sorted(glob(f'{mono_align_dir}/*.lab'))
# 個数が合うか点検
assert len(ust_files) == len(mono_files), \
f'USTファイル数({len(ust_files)})とLABファイル数({len(mono_files)})が一致しません'


def compare_name_of_ustfiles_and_labfiles(ust_dir, mono_align_dir):
"""
入力ファイルの名前が一致するか点検する。
"""
# UST一覧を取得
ust_files = sorted(glob(f'{ust_dir}/*.ust'))
# DB内のラベルファイル一覧を取得
mono_files = sorted(glob(f'{mono_align_dir}/*.lab'))

# 名前が合うか点検
songnames_dont_match = []
for path_ust, path_lab in zip(ust_files, mono_files):
ust_songname = splitext(basename(path_ust))[0]
mono_songname = splitext(basename(path_lab))[0]
if ust_songname != mono_songname:
songnames_dont_match.append([path_ust, path_lab])
# すべての名前が一致したか確認
if len(songnames_dont_match) != 0:
for path_ust_and_path_lab in songnames_dont_match:
print('USTファイル名とLABファイル名が一致しません:')
print(' path_ust:', path_ust_and_path_lab[0])
print(' path_lab:', path_ust_and_path_lab[1])
raise ValueError('USTファイル名とLABファイル名が一致しませんでした。ファイル名を点検してください')


def main(path_config_yaml):
"""
1. yamlを読み取って、以下の項目を取得する。
- 歌唱DBのパス
- 変換辞書のパス
- 学習用データ出力フォルダ
2. USTファイルとLABファイルの数と名前が一致するか点検する。
3. USTファイルからフルラベルを生成する。
"""
# 設定ファイルを読み取る
with open(path_config_yaml, 'r') as fy:
config = yaml.load(fy, Loader=yaml.FullLoader)
exclude_songs = config['exclude_songs']
out_dir = config['out_dir'].strip('"')
path_table = config['table_path'].strip('"')

ust_dir = join(out_dir, 'ust')
mono_align_dir = join(out_dir, 'lab')
full_score_dir = join(out_dir, 'full_score')

# ファイル数と名前が一致するか点検
compare_number_of_ustfiles_and_labfiles(ust_dir, mono_align_dir)
compare_name_of_ustfiles_and_labfiles(ust_dir, mono_align_dir)

print('Converting UST files to full-LAB files')
# USTからフルラベルを生成
ust2full(ust_dir, full_score_dir, path_table, exclude_songs=exclude_songs)


if __name__ == '__main__':
if len(argv) == 1:
main('config.yaml')
else:
main(argv[1].strip('"'))
Loading

0 comments on commit 77580e8

Please sign in to comment.