Skip to content

Instantly share code, notes, and snippets.

@piotrmacha
Created September 29, 2023 11:50
Show Gist options
  • Save piotrmacha/15569a50b34b2f1aa6589749bd9b7db3 to your computer and use it in GitHub Desktop.
Save piotrmacha/15569a50b34b2f1aa6589749bd9b7db3 to your computer and use it in GitHub Desktop.
import argparse
import re
import os
import sys
import subprocess
parser = argparse.ArgumentParser(prog='tts-generator', description='Script to generate TTS for Gothic mod.')
parser.add_argument('-f', '--filter', default='', help='Regex to filter line names (empty to disable)')
parser.add_argument('-e', '--engine', default='gtts', help='Engine for TTS (default: gtts, available: [gtts])')
parser.add_argument('-o', '--output', default='./out', help='Output directory (default: ./out)')
parser.add_argument('--vdfs', default='NH_Speech_PL.mod', help='Output VDFS name (default: NH_Speech_PL.mod)')
parser.add_argument('--encoding', default='windows-1250', help='Encoding of OU.CSL file (default: windows-1250)')
parser.add_argument('filename', help='Filename of OU.CSL file (_work\Data\Scripts\Content\Cutscene\OU.CSL)')
args = parser.parse_args()
dialogues = {}
# Read dialogues from OU.CSL
with open(args.filename, mode='r', encoding=args.encoding) as file:
lines = file.readlines()
text = ''
for line in lines:
if line.strip().startswith('text=string:'):
text = line.replace('text=string:', '').strip()
if line.strip().startswith('name=string:'):
id = line.replace('name=string:', '').strip()
if args.filter == '' or re.match(args.filter, id):
dialogues[id] = text
# Setup/Cleanup output directory
vdfs_filename = os.path.join(args.output, args.vdfs)
vs_filename = os.path.join(args.output, 'script.vs')
wav_directory = os.path.join(args.output, '_work/Data/Sound/Speech')
if not os.path.exists(wav_directory):
print('Creating directory: {}'.format(wav_directory))
os.makedirs(wav_directory)
print('Cleaning up output directory...')
if os.path.isfile(vdfs_filename):
os.remove(vdfs_filename)
if os.path.isfile(vs_filename):
os.remove(vs_filename)
for file in os.listdir(wav_directory):
filename = os.path.join(wav_directory, file)
if file != '.gitkeep' and os.path.isfile(filename):
os.remove(filename)
# Generate wave files
if args.engine == 'gtts':
from gtts import gTTS
from pydub import AudioSegment
progress = 0
maxProgress = len(dialogues)
for id in dialogues:
text = dialogues[id]
mp3_filename = os.path.join(wav_directory, "{}.mp3".format(id))
speech = gTTS(text=text, lang='pl', slow=False)
speech.save(mp3_filename)
mp3 = AudioSegment.from_mp3(mp3_filename)
mp3.export(os.path.join(wav_directory, id), format='wav')
os.remove(mp3_filename)
progress = progress + 1
percent = float(progress) / float(maxProgress) * 100
print('{}/{} ({:.2f}%) - {}: {}'.format(progress, maxProgress, percent, id, text))
else:
print('Unknown engine: {}'.format(args.engine), file=sys.stderr)
exit(1)
# Building vdfs
print('Preparing VDFS script...')
vs_script = ''
with open('vdfs/script.vs.in', 'r') as file:
vs_script = file.read()
vs_script = vs_script.replace('%VDFS_DIR%', '')
vs_script = vs_script.replace('%VDFS_NAME%', args.vdfs)
with open(vs_filename, 'w') as file:
file.write(vs_script)
print('Building VDFS...')
os.chdir(args.output)
result = subprocess.run('..\\vdfs\\GothicVDFS.exe /B ./script.vs', shell=True)
if result.returncode == 0:
print('VDFS built: {}'.format(vdfs_filename))
else:
print(result.stderr, file=sys.stderr)
exit(result.returncode)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment