create_dialogue_wav.php
create_dialogue_wav.php (php)
<?php
$context_opts = [];
$http_opts = [];
function exceptions_error_handler($severity, $message, $filename, $lineno) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
set_error_handler('exceptions_error_handler');
try {
if ($argc < 2) {
usage();
exit;
}
$options = getopt('cfm:nv');
$clean_up_mode = array_key_exists('c', $options);
$force_create = array_key_exists('f', $options);
$model_name = array_key_exists('m', $options) ? $options['m'] : null;
$test_mode = array_key_exists('n', $options);
$verbose_mode = array_key_exists('v', $options);
$csv_filename = $argv[$argc - 1];
if ( !$model_name || !$csv_filename ) {
usage();
exit;
}
if ( !is_readable($csv_filename) ) {
throw new Exception($csv_filename . ' is not readable.');
}
if ( !is_file($csv_filename) ) {
throw new Exception($csv_filename . ' is not file.');
}
$path_parts = pathinfo($csv_filename);
$export_dir = $path_parts['filename'] . '_' . $model_name;
if ( !$test_mode && !is_dir($export_dir) ) {
mkdir($export_dir);
}
$csv_data = parse_csv($csv_filename);
$context_opts = [
'http' => [
'method' => 'GET',
]
];
$http_opts = [
'model_name' => $model_name,
'model_id' => 0,
'speaker_id' => 0,
'sdp_ratio' => 0.2,
'noise' => 0.6,
'noisew' => 0.8,
'length' => 1,
'language' => 'JP', // JP or EN
'auto_split' => 'true',
'split_interval' => 0.5,
'assist_text_weight' => 1,
'style' => 'Neutral',
'style_weight' => 1,
];
$count_total = count($csv_data);
printf('csv total: %d', $count_total);
echo PHP_EOL;
$count_current = 0;
if ( $clean_up_mode ) {
$dh = opendir($export_dir);
if ( !$dh ) {
throw new Exception('could not open dir - ' . $export_dir);
}
$pattern = '/^(.+)\.(wav|lip|fuz)$/';
$count_deleted = 0;
while ( $file = readdir($dh) ) {
if ( $file == '.' ) {
continue;
}
if ( $file == '..' ) {
continue;
}
if ( preg_match($pattern, $file, $matches) ) {
$count_current++;
$basename = $matches[1];
$test_key = $basename . '.wav';
//echo 'test_key=[' . $test_key . ']' . PHP_EOL;
if ( !array_key_exists($test_key, $csv_data) ) {
if ( $verbose_mode ) {
echo $file . PHP_EOL;
}
if ( !$test_mode ) {
$fullpath = $export_dir . '/' . $file;
unlink($fullpath);
}
$count_deleted++;
}
}
}
closedir($dh);
printf('deleted: %d / %d', $count_deleted, $count_current);
echo PHP_EOL;
//print_r($csv_data);
} else {
foreach ($csv_data as $filename => $dialogue) {
$count_current++;
$dialogue = proofread($dialogue);
if ( strlen($dialogue) == 0 ) {
continue;
}
$filename = $export_dir . '/' . $filename;
$exists = file_exists($filename);
if ( $test_mode || !$exists ) {
printf('%d / %d : %s', $count_current, $count_total, $filename);
echo PHP_EOL;
printf('%s %s %s', str_repeat(' ', strlen($count_current)), str_repeat(' ', strlen($count_total)), $dialogue);
echo PHP_EOL;
}
if ( !$test_mode && !$exists ) {
create_wav($dialogue, $filename);
}
}
}
} catch (Exception $e) {
echo $e->GetMessage() . PHP_EOL;
echo 'line: ' . $e->GetLine() . PHP_EOL;
}
function usage()
{
echo 'Usage: create_dialogue_wav.php [-cfnv] -m <model name> <LazyVoiceFinder_export.csv>';
echo PHP_EOL;
}
function proofread($text)
{
// 括弧とその中身は読まない
$text = preg_replace('/\(.+?\)/', '', $text);
// グローバル変数を展開するマクロは読まない
$text = preg_replace('/__[0-9a-zA-Z=\.]+?__/', '', $text);
// 中黒は無駄に間がおかれるので読まない
$text = preg_replace('/・/', '', $text);
// 文末の無駄な_を削除
$text = preg_replace('/?_/', '?', $text);
$text = preg_replace('/!_/', '!', $text);
// 空白は読点に変換して間をおかせる
$text = str_replace('_', '、', $text);
// ここまでの処理で発生したゴミを除去
$text = trim($text);
// 文末の句点は不要
$text = preg_replace('/。$/', '', $text);
// ここまでの処理で発生したゴミを除去
$text = trim($text);
return $text;
}
function create_wav($text, $filename)
{
global $context_opts, $http_opts;
$http_opts['text'] = $text;
$url = 'http://127.0.0.1:5000/voice?' . http_build_query($http_opts);
$context = stream_context_create($context_opts);
$data = file_get_contents($url, false, $context);
file_put_contents($filename, $data);
}
function parse_csv($csv_filename)
{
$csv_data = [];
$fp = fopen($csv_filename, 'r');
if ( !$fp ) {
throw new Exception('could not open csv file - ' . $csv_filename);
}
// ヘッダ行を検証する
$buf = fgets($fp);
$buf = trim($buf);
// ファイルの先頭の制御コードを取り除く (BOM?)
$buf = substr($buf, 3, strlen($buf) - 1);
// "State","Plugin","Quest Edid","FormId","Topic Edid","File Name","Voice Type","Dialogue 1 - English","Dialogue 2 - English"
$header_list = explode(',', $buf);
$header_count = count($header_list);
$quest_edid_index = array_search('"Quest Edid"', $header_list);
$form_id_index = array_search('"FormId"', $header_list);
$topic_edid_index = array_search('"Topic Edid"', $header_list);
$filename_index = array_search('"File Name"', $header_list);
$dialogue_index = array_search('"Dialogue 1 - English"', $header_list);
if ( $dialogue_index === FALSE ) {
throw new Exception('column not found - "Dialogue 1 - English"');
}
if ( $filename_index === FALSE ) {
throw new Exception('column not found - "File Name"');
}
if ( $topic_edid_index === FALSE ) {
throw new Exception('column not found - "Topic Edid"');
}
if ( $form_id_index === FALSE ) {
throw new Exception('column not found - "FormId"');
}
if ( $quest_edid_index === FALSE ) {
throw new Exception('column not found - "Quest Edid"');
}
$no_dialogue = 0;
$no_filename = 0;
$no_quest_edid = 0;
$no_topic_edid = 0;
$no_form_id = 0;
$last_form_id = '';
while ( !feof($fp) ) {
$ary = fgetcsv($fp, 10000, ',', '"', '');
// CSVですらない不正な行(ファイルの末尾など)
if ( !is_array($ary) ) {
continue;
}
// カラムの数が合わない不正な行
if ( count($ary) != $header_count ) {
continue;
}
// セリフが存在しない行
$dialogue = trim($ary[$dialogue_index]);
if ( strlen($dialogue) == 0 ) {
$no_dialogue++;
continue;
}
// filename
$filename = $ary[$filename_index];
if ( strlen($filename) == 0 ) {
$quest_edid = trim($ary[$quest_edid_index]);
if ( strlen($quest_edid) == 0 ) {
$no_quest_edid++;
continue;
}
$topic_edid = trim($ary[$topic_edid_index]);
if ( strlen($topic_edid) == 0 ) {
$no_topic_edid++;
continue;
}
$form_id = trim($ary[$form_id_index]);
if ( strlen($form_id) == 0 ) {
$no_form_id++;
continue;
}
if ( $form_id == $last_form_id ) {
$info_count++;
} else {
$info_count = 1;
$last_form_id = $form_id;
}
// BaboDialog_BaboDialogueGen_00D80D5F_1
// BaboDialog_GuardEroGreetin_008D049A_1
$form_id = '00' . substr($form_id, 2, 6);
if ( strpos($topic_edid, '[') !== FALSE ) {
$topic_edid = '';
} else {
$topic_edid = substr($topic_edid, 0, 15);
}
if ( $topic_edid != '' ) {
$quest_edid = substr($quest_edid, 0, 10);
}
$filename = sprintf('%s_%s_%s_%d.fuz', $quest_edid, $topic_edid, $form_id, $info_count);
}
$filename = str_replace('.fuz', '.wav', $filename);
$csv_data[$filename] = $dialogue;
}
fclose($fp);
if ($no_dialogue >= 1) {
printf('no_dialogue: %d', $no_dialogue);
echo PHP_EOL;
}
if ($no_filename >= 1) {
printf('no_filename: %d', $no_filename);
echo PHP_EOL;
}
if ($no_quest_edid >= 1) {
printf('no_quest_edid: %d', $no_quest_edid);
echo PHP_EOL;
}
if ($no_topic_edid >= 1) {
printf('no_topic_edid: %d', $no_topic_edid);
echo PHP_EOL;
}
if ($no_form_id >= 1) {
printf('no_form_id: %d', $no_form_id);
echo PHP_EOL;
}
return $csv_data;
}
xTranslator_dic_to_DBVO.php
xTranslator_dic_to_DBVO.php (php)
<?php
try {
if ( $argc != 2 ) {
throw new Exception('Usage: xTranslator_dic_to_DBVO.php <input filename>');
}
$in_filename = $argv[1];
parse_xml($in_filename);
} catch (Exception $e) {
echo $e->GetMessage() . PHP_EOL;
}
function parse_xml($in_filename)
{
$fp = fopen($in_filename, 'r');
if ( !$fp ) {
throw new Exception('could not open input file - ' . $in_filename);
}
$buf = '';
while ( !feof($fp) ) {
$buf .= fgets($fp);
}
fclose($fp);
if ( !preg_match_all('!<String.+?</String>!ms', $buf, $matches, PREG_SET_ORDER) ) {
throw new Exception('no match');
}
$fp1 = null;
$fp2 = null;
$fp3 = null;
try {
$out_filename = 'voicevox.csv';
$fp1 = fopen($out_filename, 'w');
if ( !$fp1 ) {
throw new Exception('could not open output file - ' . $out_filename);
}
$out_filename = 'LazyVoiceFinder_export.csv';
$fp2 = fopen($out_filename, 'w');
if ( !$fp2 ) {
throw new Exception('could not open output file - ' . $out_filename);
}
fputs($fp2, '"State","Plugin","FormId","Topic Edid","File Name","Voice Type","Dialogue 1 - en","Dialogue 2 - en"' . PHP_EOL);
$out_filename = 'DBVO.json';
$fp3 = fopen($out_filename, 'w');
if ( !$fp3 ) {
throw new Exception('could not open output file - ' . $out_filename);
}
fputs($fp3, '{' . PHP_EOL);
} catch (Exception $e) {
if ($fp1) {
fclose($fp1);
}
if ($fp2) {
fclose($fp2);
}
if ($fp3) {
fclose($fp3);
}
throw $e;
}
$history = [];
$dbvo_dic_buf = '';
foreach ($matches as $regs) {
if ( strpos($regs[0], '<REC>DIAL:FULL</REC>') === false ) {
continue;
}
if ( !preg_match('!<Source>(.+?)</Source>!ms', $regs[0], $regs2) ) {
continue;
}
$source = $regs2[1];
if ( in_array($source, $history) ) {
continue;
}
$history[] = $source;
if ( !preg_match('!<Dest>(.+?)</Dest>!ms', $regs[0], $regs2) ) {
continue;
}
$dest = $regs2[1];
// OK_Followerの翻訳辞書は日英なので入れ替える
//list($source, $dest) = [$dest, $source];
$dest = str_replace("\r", '', $dest);
$dest = str_replace("\n", '', $dest);
$source = str_replace("\r", '', $source);
$source = str_replace("\n", '', $source);
$dest = str_replace(''', "'", $dest);
$dest = str_replace('"', '', $dest);
$dest = str_replace('<', '<', $dest);
$dest = str_replace('>', '>', $dest);
$dest = preg_replace('/<Alias=Player> */', 'ドバコ', $dest);
$dest = preg_replace('/<[^>]+>/', '', $dest);
$dest = str_replace('(', '(', $dest);
$dest = str_replace(')', ')', $dest);
$dest = preg_replace('/\.\.\.+/', '…', $dest);
$dest = trim($dest);
$dest = preg_replace('/[\.……]+$/u', '', $dest);
$dest = trim($dest);
if ( strlen($dest) == 0 ) {
continue;
}
$dest = preg_replace('/^\((.+)\) *\((.+)\)$/', '$1', $dest);
$dest = preg_replace('/^\((.+)\)$/', '$1', $dest);
$dest = preg_replace('/^\[(.+)\]$/', '$1', $dest);
$dest = preg_replace('/^\*(.+)\*$/', '$1', $dest);
$dest = preg_replace('/^(.+)\(.+?\)/', '$1', $dest);
$dest = preg_replace('/^(.+)\[.+?\]/', '$1', $dest);
$dest = preg_replace('/^(.+)\*.+?\*/', '$1', $dest);
$dest = preg_replace('/^\(.+?\)(.+)$/', '$1', $dest);
$dest = preg_replace('/^\[.+?\](.+)$/', '$1', $dest);
$dest = preg_replace('/^\*.+?\*(.+)$/', '$1', $dest);
$dest = trim($dest);
if ( strlen($dest) == 0 ) {
continue;
}
$dest = preg_replace('/?/u', '?', $dest);
$dest = preg_replace('/!/u', '!', $dest);
$dest_old = $dest;
// ほぼ確実
$dest = str_replace('マスタードバコ', 'ご主人様', $dest);
$dest = str_replace('ウェンチ', '娼婦', $dest);
$dest = str_replace('主が', 'あるじが', $dest);
$dest = str_replace('主に', 'あるじに', $dest);
$dest = preg_replace('/Deadly Wenches */u', '娼婦', $dest);
$dest = str_replace('見えますが、', '見えるが、', $dest);
$dest = str_replace('しれませんが、', 'しれないが、', $dest);
$dest = str_replace('ありませんが、', 'ないが、', $dest);
$dest = str_replace('はい、', 'そうだ、', $dest);
$dest = str_replace('なのですから、', 'なのだから、', $dest);
$dest = str_replace('続けていますが、', '続けているが、', $dest);
$dest = str_replace('そうですね…', 'そうだな…', $dest);
$dest = str_replace('わかりました…', 'わかった…', $dest);
$dest = str_replace('やめています…', 'やめている…', $dest);
$dest = str_replace('ありませんでした…', 'なかった…', $dest);
$dest = str_replace('はどのようにして', 'はどうやって', $dest);
$dest = str_replace('どのようにして', 'どうして', $dest);
$dest = str_replace('いたのですが', 'いたのだが', $dest);
$dest = str_replace('ごめんなさい', 'すまない', $dest);
$dest = str_replace('わかりません', 'わからない', $dest);
$dest = str_replace('気がします', '気がする', $dest);
$dest = str_replace('していただければ', 'してもらえれば', $dest);
$dest = fixString('何ですか', '何だ', $dest);
$dest = fixString('何をしましたか', '何をしたんだ', $dest);
$dest = fixString('信じています', '信じている', $dest);
$dest = fixString('元気ですか', '元気か', $dest);
$dest = fixString('助けます', '助けよう', $dest);
$dest = fixString('奴隷です', '奴隷だ', $dest);
$dest = fixString('好きです', '好きだ', $dest);
$dest = fixString('好きですか', '好きか', $dest);
$dest = fixString('必要ですか', '必要だ', $dest);
$dest = fixString('思いました', '思った', $dest);
$dest = fixString('思います', '思う', $dest);
$dest = fixString('思いますか', '思う', $dest);
$dest = fixString('思えません', '思えない', $dest);
$dest = fixString('思っています', '思っている', $dest);
$dest = fixString('持っています', '持っている', $dest);
$dest = fixString('楽しんでいますか', '楽しんでいるのか', $dest);
$dest = fixString('構いません', '構わない', $dest);
$dest = fixString('決めます', '決める', $dest);
$dest = fixString('着ています', '着ている', $dest);
$dest = fixString('知っていますか', '知っている', $dest);
$dest = fixString('知りたいのです', '知りたいんだ', $dest);
$dest = fixString('知れませんが', '知れないが', $dest);
$dest = fixString('言いません', '言わない', $dest);
$dest = fixString('言うんですか', '言うのか', $dest);
$dest = fixString('誰ですか', '誰なんだ', $dest);
$dest = fixString('従ったのです', '従ったんだ', $dest);
// まず大丈夫
$dest = fixString('いくらですか', 'いくらだ', $dest);
$dest = fixString('いるの', 'いる', $dest);
$dest = fixString('いるのです', 'いるんだ', $dest);
$dest = fixString('おかしいですか', 'おかしいか', $dest);
$dest = fixString('おきます', 'おこう', $dest);
$dest = fixString('ことですか', 'ことか', $dest);
$dest = fixString('したんですか', 'したのか', $dest);
$dest = fixString('していません', 'していない', $dest);
$dest = fixString('しましたか', 'したのか', $dest);
$dest = fixString('するつもりですか', 'するつもりなんだ', $dest);
$dest = fixString('たいですか', 'たいか', $dest);
$dest = fixString('たかったのです', 'たかったんだ', $dest);
$dest = fixString('できます', 'できる', $dest);
$dest = fixString('どうですか', 'どうだ', $dest);
$dest = fixString('なのでしょうか', 'なのか', $dest);
$dest = fixString('なんですか', 'なのか', $dest);
$dest = fixString('るのでしょうか', 'るんだ', $dest);
$dest = fixString('わかるよ', 'わかる', $dest);
// 誤変換の可能性がある
$dest = fixString('つもりですか', 'つもりか', $dest);
$dest = fixString('いますか', 'いるんだ', $dest);
$dest = fixString('ください', 'ほしい', $dest);
$dest = fixString('ありません', 'ない', $dest);
$dest = fixString('あります', 'ある', $dest);
$dest = fixString('でした', 'だった', $dest);
$dest = fixString('でしょう', 'だろう', $dest);
$dest = fixString('のでしょうか', 'んだ', $dest);
$dest = fixString('しました', 'した', $dest);
$dest = fixString('しれません', 'しれない', $dest);
$dest = fixString('いいよ', 'いいだろう', $dest);
$dest = fixString('だけです', 'だけだ', $dest);
// 誤変換の可能性が非常に高い
$dest = fixString('します', 'しよう', $dest);
$dest = fixString('のですか', 'んだ', $dest);
$dest = fixString('ですか', 'なのか', $dest);
$dest = fixString('です', 'だ', $dest);
if ($dest != $dest_old) {
echo $dest_old . PHP_EOL;
echo $dest . PHP_EOL;
}
fputs($fp1, 'ずんだもん,' . $dest . PHP_EOL);
$s = sprintf('"オーバーライド","fallout4.esm","00043A15","[000E0BFF]","%s.fuz","synthgen1male01","%s",""', $source, $dest);
fputs($fp2, $s . PHP_EOL);
if ( $dbvo_dic_buf ) {
fputs($fp3, $dbvo_dic_buf . ',' . PHP_EOL);
}
$dbvo_dic_buf = "\t" . '"' . $dest . '": "' . $source . '"';
}
if ( $dbvo_dic_buf ) {
fputs($fp3, $dbvo_dic_buf . PHP_EOL);
}
fputs($fp3, '}' . PHP_EOL);
fclose($fp1);
fclose($fp2);
fclose($fp3);
}
function fixString($replace_from, $replace_to, $haystack)
{
$haystack = preg_replace('/' . $replace_from . '$/u', $replace_to, $haystack);
$haystack = preg_replace('/' . $replace_from . '([、。…!\?])/u', $replace_to . '$1', $haystack);
return $haystack;
}
create_DBVO_wav.php
create_DBVO_wav.php (php)
<?php
define('WAV_DIR', 'wav');
$context_opts = [];
$http_opts = [];
try {
if ($argc < 2) {
throw new Exception('Usage: create_DBVO_wav.php [-cfnv] <DBVO local pack json>');
}
$options = getopt('cfnv');
$clean_up_mode = array_key_exists('c', $options);
$force_create = array_key_exists('f', $options);
$test_mode = array_key_exists('n', $options);
$verbose_mode = array_key_exists('v', $options);
$json_filename = $argv[$argc - 1];
if ( !is_readable($json_filename) ) {
throw new Exception($json_filename . ' is not readable.');
}
//$json_data = json_decode( file_get_contents($json_filename) );
$json_data = json_decode_flip( file_get_contents($json_filename) );
if ( !$json_data ) {
throw new Exception('json decode failed.');
}
//print_r($json_data);
//exit;
if ( !is_dir(WAV_DIR) ) {
mkdir(WAV_DIR);
}
$context_opts = [
'http' => [
'method' => 'GET',
]
];
$http_opts = [
'model_name' => '2B',
'model_id' => 0,
'speaker_id' => 0,
'sdp_ratio' => 0.2,
'noise' => 0.6,
'noisew' => 0.8,
'length' => 1,
'language' => 'JP',
'auto_split' => 'true',
'split_interval' => 0.5,
'assist_text_weight' => 1,
'style' => 'Neutral',
'style_weight' => 1,
];
$basename_list = [];
$counter = 0;
//foreach ($json_data as $japanese => $english) {
foreach ($json_data as $english => $japanese) {
$counter++;
$japanese = preg_replace('/\(.+?\)/', '', $japanese);
$japanese = preg_replace('/__[0-9a-zA-Z=\.]+?__/', '', $japanese);
$japanese = preg_replace('/?_/', '?', $japanese);
$japanese = preg_replace('/!_/', '!', $japanese);
$japanese = str_replace('_', '、', $japanese);
$japanese = trim($japanese);
$japanese = preg_replace('/。$/', '', $japanese);
$japanese = trim($japanese);
if ( strlen($japanese) == 0 ) {
continue;
}
if ( $verbose_mode ) {
echo $counter . ' ' . $english . PHP_EOL;
}
$english = str_replace(''', "'", $english);
$english = str_replace('"', '_', $english);
$english = str_replace('<', '<', $english);
$english = str_replace('>', '>', $english);
$english = preg_replace('/<Alias=Player> */', 'Dovaco', $english);
$english = preg_replace('/<[^>]+>/', '', $english);
$english = preg_replace('/(^.+) +\(.+?\)$/', '$1', $english);
$english = str_replace(' ', '_', $english);
$english = str_replace('?', '_', $english);
$english = str_replace('*', '_', $english);
$english = str_replace('[', '_', $english);
$english = str_replace(']', '_', $english);
$english = str_replace('%', '_', $english);
$english = str_replace(':', '_', $english);
$filename = WAV_DIR . '/' . $english . '.wav';
if ( $clean_up_mode ) {
$basename_list[] = $english;
} else {
if ( $verbose_mode ) {
echo $counter . ' ' . $filename . PHP_EOL;
echo $counter . ' ' . $japanese . PHP_EOL;
}
if ( $force_create || !file_exists($filename) ) {
if ( !$verbose_mode ) {
echo $filename . PHP_EOL;
echo $japanese . PHP_EOL;
}
if ( !$test_mode ) {
create_wav($japanese, $filename);
}
}
}
}
if ( $clean_up_mode ) {
$dh = opendir(WAV_DIR);
if ( !$dh ) {
throw new Exception('could not open dir - ' . WAV_DIR);
}
$pattern = '/^(.+)\.(wav|lip|fuz)$/';
while ( $file = readdir($dh) ) {
if ( $file == '.' ) {
continue;
}
if ( $file == '..' ) {
continue;
}
if ( preg_match($pattern, $file, $matches) ) {
$basename = $matches[1];
if ( !in_array($basename, $basename_list) ) {
echo $file . PHP_EOL;
$fullpath = WAV_DIR . '/' . $file;
unlink($fullpath);
}
}
}
closedir($dh);
}
} catch (Exception $e) {
echo $e->GetMessage() . PHP_EOL;
}
function create_wav($text, $filename)
{
global $context_opts, $http_opts;
$http_opts['text'] = $text;
$url = 'http://127.0.0.1:5000/voice?' . http_build_query($http_opts);
$context = stream_context_create($context_opts);
$data = file_get_contents($url, false, $context);
file_put_contents($filename, $data);
}
function json_decode_flip($json)
{
$array = explode("\n", $json);
$result = [];
$counter = 0;
foreach ($array as $line) {
$line = trim($line);
if ( $line == '' || $line == '{' || $line == '}' ) {
continue;
}
$ary = explode('": "', $line);
$value = ltrim($ary[0], '"');
$key = rtrim($ary[1], '",');
//echo $counter . ' ' . $key . PHP_EOL;
//echo $counter . ' ' . $value . PHP_EOL;
$result[$key] = $value;
$counter++;
}
return $result;
}
create_lip.php
create_lip.php (php)
<?php
define('FACEFXWRAPPER', 'E:\SteamLibrary\steamapps\common\Skyrim Special Edition\Tools\Audio\FaceFXWrapper.exe');
define('ARG_TYPE', 'Skyrim');
define('ARG_LANG', 'USEnglish');
define('FONIXDATAPATH', 'E:\SteamLibrary\steamapps\common\Skyrim Special Edition\Data\Sound\Voice\Processing\FonixData.cdf');
try {
$wav_dir = '.';
if ($argc >= 2) {
$wav_dir = $argv[$argc - 1];
}
parse_dir($wav_dir);
} catch (Exception $e) {
echo $e->GetMessage() . PHP_EOL;
}
function parse_dir($dir)
{
$dh = opendir($dir);
if ( !$dh ) {
throw new Exception('could not open dir - ' . $dir);
}
$pattern = '/\.wav$/';
while ( $file = readdir($dh) ) {
if ( $file == '.' ) {
continue;
}
if ( $file == '..' ) {
continue;
}
if ( preg_match($pattern, $file) ) {
$fullpath = $dir . '/' . $file;
create_lip($fullpath);
}
}
closedir($dh);
}
function create_lip($wav_filename)
{
$lip_filename = str_replace('.wav', '.lip', $wav_filename);
if ( file_exists($lip_filename) ) {
return;
}
$wav_filename_new = $wav_filename;
$lip_filename_new = $lip_filename;
if ( strpos($wav_filename, '!') ) {
$wav_filename_new = str_replace('!', '_', $wav_filename_new);
$lip_filename_new = str_replace('.wav', '.lip', $wav_filename_new);
copy($wav_filename, $wav_filename_new);
}
echo $wav_filename_new . PHP_EOL;
echo $lip_filename_new . PHP_EOL;
// FaceFXWrapper [Type] [Lang] [FonixDataPath] [ResampledWavPath] [LipPath] [Text]
$cmd = sprintf(
'"%s" %s %s %s %s %s ""',
FACEFXWRAPPER,
escapeshellarg(ARG_TYPE),
escapeshellarg(ARG_LANG),
escapeshellarg(FONIXDATAPATH),
escapeshellarg($wav_filename_new),
escapeshellarg($lip_filename_new)
);
exec($cmd);
if ( !file_exists($lip_filename_new) ) {
return;
}
if ( $lip_filename_new != $lip_filename ) {
rename($lip_filename_new, $lip_filename);
unlink($wav_filename_new);
}
}