近年来,人们对人工智能 (AI) 研发的投入力度越来越大。AI 已不再仅仅存在于科幻小说和电影当中。全球互联网访问能力的提升、计算硬件的改进、机器学习和神经网络的进步无不改变着我们今天的生活。可以说,这一领域取得的成果是相当惊人的。显然,AI 时代已经到来并将持续下去。
目前 AI 领域取得的成果已经对游戏开发(包括游戏音频)产生了积极的影响。在此,我想以公司最近开发的项目为例说说 AI 如何帮助我们团队节省了游戏语音的 (VO) 制作时间和精力。
《Pagan Online》是一款由 Mad Head Games 和 Wargaming 联合开发的快节奏动作类 RPG 砍杀游戏,其背景设定在基于斯拉夫神话构建的奇幻世界。除了多人合作任务、追捕和刺杀,它还设有丰富多样的战役模式,其中包含了超过五十个小时的内容。在撰写本文时,这款游戏刚推出抢先体验版。各位不妨通过 Steam 和 Wargaming 下载到个人电脑上试玩一下。我敢保证,它绝对是 Mad Head 目前为止投入规模最大的项目。
《PAGAN ONLINE》:战役关卡的游戏截屏(以 Kingewitch 为玩家角色)
Mad Head Games 的发展历程
在展开本文所要讲述的故事之前,有必要简单说下我们工作室的发展历程。Mad Head Games (MHG) 于 2011 年由一帮志同道合的游戏达人联合创立,总部位于塞尔维亚的首都贝尔格莱德。在今年之前,我们工作室开发的大多都是像《Rite of Passage》和《Nevertales》这样的隐藏物品解谜冒险 (HOPA) 游戏。随着业务的不断增长,越来越多的人加入工作室(其中有很多本身就是硬核玩家),大家慢慢地就想试着开发不同类型的项目。
三年多前,我们启动了如今被大家所熟知的《Pagan Online》项目。这款游戏的开发主要源于我们对游戏和斯拉夫传说共同的热爱。在此之前,没人拥有 Unreal Engine (UE) 和多人游戏开发方面的实际经验。大家都是边做边学,音频团队也不例外。在《Pagan Online》之前,我们只给 HOPA 游戏和手游做过音效,而且用的都是自研游戏引擎和它自己的脚本语言。
我们所有的声音设计师都是全职的 MHG 员工,而且大家都有一个共同的处事信条。那就是:
“谁制作声音就由谁负责将其整合到游戏中。”
这意味着我们所有的声音设计师都得熟悉基本的编程和版本控制原则。正因如此,我们才能很快地适应新的引擎,并学习使用 Wwise 作为中间件。
当然,我们这种在实践中学习的方式有好有坏,在具体运用时有可能并非完全依循正统。我之所以在此事先声明是想告诉大家,我们选择做事情的方式从理论上来说不一定是最好的。但是,我们就是这么一路脚踏实地摸索过来的。虽然之前不曾拥有 AAA 级游戏的制作经验,但我们还是意识到了至少管线的有些部分是有必要自动完成的。正是这一点推动了我们对 AI 的探索。
当时面临的处境
HOPA 游戏在很大程度上由剧情驱动,这意味着里面会包含大量的对白。由于很难找到以英语为母语的本土演员,我们工作室经过考虑最终决定把 VO 录制外包出去。这样的话我们团队只要负责剪辑和语音整合就可以了。在《Pagan Online》的开发之初,我们直接沿用了之前的工作流程。下面来了解下我们最初采用的制作管线。
Mad Head Games 原本采用的 VO 制作管线
从上图可以看到,刚开始由叙事设计师负责撰写台词。随后由程序员将对白文本整合到游戏中。他们会将所有台词全部放在一个本地化文件中,并分别为其指派唯一标识符字符串。
ch1_archives:dlg_horrible_11 "Something horrible took Riley!"
示例 – HOPA 本地化文件内的对白台词
之后,我们再将 VO 文档发给演员。各个演员会按照书面说明录制自己那部分的台词,并发回原始的、未经剪辑的、包含多遍take的长音频文件。然后,我们再对这些文件进行剪辑,选取效果最好的录音,并给文件命名。不过,所有文件都要依据指派给本地化文件的唯一标识符来命名(比如 vo_ch1_archives_dlg_horrible_11.ogg)。也就是说,语音剪辑师必须手动命名每一个音频文件。这个过程非常单调而且十分耗时。在一门心思制作 HOPA 游戏时,还没什么大碍。但是,当我们开始制作《Pagan Online》时,就开始有问题了。
这款游戏中对白台词的数量跟之前相比多太多了。由于要使用 Wwise 和 UE,所以我们需要命名并导入音频文件,为 Sound Voice(语音)创建 Container(容器),创建 Event(事件)并将其放在相应的SoundBank(音频包)中,最后还要在 UE 中重复创建所有这些 Event。另外,此工程中并没有统一的用户可读的本地化文件。所以,我们不得不使用大量的 UE DataTable(数据表),然而其可读性却不怎么好。于是,我们顿时感到非常地挫败。
为此,我们考察了 Nuendo 的 Rename events from list 功能。我们觉得这样的工具应该可以帮到我们,但它要求必须按照游戏列表中出现的顺序来编排音频条目。由于我们把 VO 录制外包了出去,所以既不能奢求让所有演员集中到一个房间里一块录音,也没法实时指导他们如何进行表演。因此,我们都是在不同的时间收到来自不同演员的文件,只有在所有演员全部完成台词录制之后才能听到不同角色之间的对话。然而,就算等到那个时候,要是按照游戏中出现的顺序来剪辑对白台词,一样得花费大量的时间。所以,我们真正需要的是一款方便在各个演员发来文件时快速进行剪辑和命名的工具。
UE 内典型的对白 DataTable
在仔细分析我们的处境之后,为了能够更加快速、高效地完成 VO 的制作和整合,我专门创建了一个有待解决的事项列表。
- DataTable 命名规范
- AkEvent 命名规范
- 自动触发 Event
- 自动命名音频文件
- 自动导入 Wwise 音频
- 自动创建 Wwise Event
其中大部分解决起来都非常简单。程序员创建了 Blueprint(蓝图)来按照基于 DataTable 中的对白 ID 的字符串搜索 AkEvent。我们只需在一些基本的命名规则上达成一致并严格遵守即可。我本来觉得自动创建 Wwise Container 和 Event 会特别棘手,但后来发现可以通过在 Wwise 中使用 TSV 来轻松解决这一问题。
自动命名音频文件 – 解决方案
那么,我们在手动命名音频文件时到底都做了些什么呢?首先试听音频,然后在特定文件中查找自己听到的文本,最后按照团队商定的规则来正确命名。所以,大致包含三个过程:试听、搜索和命名。第一个过程非常关键。光听是不够的,还要能够理解音频中编入的文本消息。为此,大脑会将声音转换为有意义的文字。因此,要想自动完成此过程,我们需要一个能将录制的语音转换成文本的系统。这时,便可适当借助于 AI。还好,这种系统已经存在,它叫做 Speech to Text(语音识别)。语音识别并不是一个新的理念,只不过随着科技的发展,尤其是智能手机的普及,最近才变得真正能用、好用。
从另一方面来说,语音在本质上是非常灵活多变的。即便在两个人相互交谈时,都存在语音可懂度问题。机器处理起来就更加困难了,因为它们还不能像人一样理解语境和语调。当然,这种状况迟早会改变。但是,在此之前我们仍需将算法识别的文本与实际的对白台词进行比对,然后评估两者之间的匹配率。总的来说,我们的想法是整合以下两个系统:
-
语音识别
-
近似字符串比对
这种想法最重要的一点在于可用性。也就是说,光有技术是不够的。我还得设法利用其来实现我们的目的,而且要能在 DAW 内剪辑文件的同时做到这一点。
我们 MHG 目前在使用 REAPER。这个平台拥有很大的灵活性和可扩展性,对上述诉求来说再合适不过了。REAPER 支持使用 Lua、Eel 和 Python 语言编写脚本。其中,前两种相对而言较为便捷,Python 则可提供大量的模块数据库。
我开始探索各种各样的解决方案,经过几周的尝试和失败,最终构建了一个实验性的解决方案:ReaCognition。它是一套针对 REAPER 编写的 Python 脚本,可通过 SpeechRecognition 和 fuzzywuzzy 字符串匹配来自动命名对白文件。
ReaCognition
该脚本会扫描选定的音频文件部分,并针对其应用语音识别。我们可以由此获取相应的文本,并与包含游戏中所有对白台词的专用数据库进行比对。当然,需要在运行脚本之前事先构建好这个数据库。在找到匹配项时,脚本会检索对白台词的 ID,并利用其为音频文件生成唯一名称。
改进后的制作管线
在下图中,我们可以看到改进后的对白制作管线。流程跟之前基本相同,只是添加了关键的 ReaCognition。接下来,我将详细阐述所有相关步骤,以便各位更好地理解新增的环节。
1. VO 文档
叙事设计师为游戏撰写所有台词,并将其全部放在一个规整的文档中。
2. UE DataTables
程序员使用 DataTable 将 VO 文档中的台词整合到游戏中。
DataTable 内其中一句对白台词的详情
从上图可以看到 DataTable 内其中一句针对 Crypt 区域构建的对白台词的内容。数据分为多行,每行包含两列。DataTable 的作用就像词典一样。其中,左边为键值,右边为数值。每条对白都具有唯一名称 (ID) 且包含多句台词。每句台词都对应有 Index 和 Character ID。在运行时,专用的 Blueprint (BP_DialogueManager) 会从 DataTable 提取数值,并使用公式创建一个长字符串。我们可以在下面看到用来创建 AkEvent 字符串的公式。
公式: DLG_(Area)_(DialogueID)_(Index)_(CharacterID)
示例:
DataTable: Crypt
ID: MQ001DukatAppears
Index: 01
Character: Dukat
Line: Hello there! How can I help you?
AkEvent name: DLG_MQ001DukatAppears_01_Dukat
其中,AkEvent name 字符串用于触发 AkEvent。为了不用在 UE 工程内创建上百个 AkEvent 素材,我们最终决定采用这种方式。这样的话只需确保 Event 存在于 Wwise 工程内并加载相应的对白 SoundBank 即可。
BP_DialogueManager 创建文本框并触发 AkEvent
3. VO 录制和剪辑
各个演员录制自己那部分的台词并发回音频文件。VO 剪辑师剪辑文件,选取效果最好的录音片段,并进行更正和创意加工。
4. ReaCognition
4.1 创建对白数据库
在使用 ReaCognition 之前,首先要创建/更新 ReaCognition 对白数据库。它是一个专用的 Python 词典文件,包含来自所有对白 DataTable 的最新对白台词。在这个文件中,键值为 AkEvent 的名称,数值为台词本身。我们需要分两步来创建这个数据库。首先,在 UE 内选中所有对白 DataTable,并将其导出为 JSON 文件。
UE 内的 DataTable 上下文菜单
然后,在 REAPER 内运行专用脚本,来从所有 JSON 文件收集数据,并将其存储到一个大的词典中。这个词典会被用来与 AI 识别的文本进行比对。
成功创建对白数据库后 Console 输出的消息
4.2 命名音频条目
接下来,我们便可开始在 REAPER 内命名音频条目。语音剪辑师会按照时间来选择条目或条目的一部分,并运行 ReaCognition 脚本。在数秒之后,便会显示类似下图的消息框。
典型的 ReaCognition 输出消息框
- QUERY 是 AI 从所选音频条目中识别的文本。
- DLG NAME 是所找到的对白台词的名称。
- DLG TEXT 是台词文本本身。
- DLG MATCH 是 QUERY 和 DLG TEXT 之间的匹配度。
示例 – AI 识别错了部分单词
在上面的例子中,我们可以清楚地看到有些单词完全被识别错了。这个没有太大关系,只要有识别正确的其他单词就行。脚本会不断查找与 QUERY 最接近的匹配项。在大部分情况下,第一条结果就是我们想要的。倘若不是,可单击 No 来显示下一最佳匹配项。
假如对结果满意,可直接单击 Yes。这时音频条目会获得一个新的名称。
使用 ReaCognition 后获得的音频条目名称
注意:从图中可以看到名称格式部分的数据值之间插入的是空格而非下划线。在后文中,我们会对此作出解释。
ReaCognition 的使用模式有两种:安全和快速。
在安全模式下,会始终扫描整句 VO 台词。这样可以确保获得最佳结果,但是音频越长,返回结果的时间也会越久。在快速模式下,只会选择最有特点也最好识别的 VO 台词部分。这种模式的问题在于匹配度取决于所选音频部分在整个对白数据库中的的独特性。因此,请务必慎重选用。下图为该模式的示例。
仅使用 ReaCognition 扫描特定的 VO 部分
只扫描一段 VO 后的 ReaCognition 输出
手动 ReaCognition
在有些情况下,AI 就是无法识别音频的内容。为此,我专门创建了手动模式。这样的话用户可以自由选择音频条目,然后通过在文本框中键入内容来手动创建 QUERY。没必要键入标点符号,也不用区分大小写,甚至单词的顺序都可打乱。唯独一点很重要,就是要从 VO 中选择足够多的关键词来加以识别。
手动输入 QUERY
5. Wwise – 创建 Container 和 Event
在正确重命名所有条目后,必须对所有文件进行渲染并导入到 Wwise 工程中。“渲染”可通过 REAPER 灵活的渲染引擎来完成。在本例中,我们针对文件名使用 $item 通配符将所有选中条目渲染到了一个绝对位置。
“导入”解决起来有点复杂。为此,我使用 TSV 文件自动完成了这一流程步骤。可能有些读者对 Wwise 中的这一功能并不熟悉,所以有必要在此简单介绍一下。TSV 是一个使用文本列表创建 Container 和 Event 的系统。其中,文本列表内包含了音频文件的路径以及 Container 和 Event 的预定义结构。它的功能非常强大,唯一比它还强大的恐怕只有 WAAPI 了。只是在构建 ReaCognition 的时候,我还不知道有 WAPPI。
在整个流程中,首先要选中所有音频条目,然后加以渲染,接着运行脚本,以此创建 TSV 文件并使用命令行将其自动导入到 Wwise 中。在前面有关 ReaCognition 输出的示例中,各位估计也注意到了,针对音频条目生成的名称并非完全不含空格(如 DLG MQ001DukatAppears 01 Dukat)。AkEvent 必须使用下划线来命名,而音频文件和 Container 并没有这方面的限制。正是利用这一点,我根据所选音频条目的名称中编入的信息生成了 TSV 文件。其中,空格用来解析信息。名称的每个部分对应一个特定的 Container。
<WorkUnit> Dialogue
<Actor-Mixer>Dialogue
<Actor-Mixer> Map
<Actor-Mixer> DialogueID
<Sound Voice>Filename
<Sound Voice>Filename
<Sound Voice>Filename
黑色代码行是绝对路径,蓝色代码行是相对路径(对每个音频条目来说都不相同)。Event 创建采用的是同样的逻辑,只不过要将空格替换为下划线而已。
Audio 类别的 Dialogue WorkUnit 的结构 – 自动创建
6.Unreal Engine
最后,使用刚才创建的 Event 来构建对白 SoundBank。在游戏中出现对白框时,Blueprint 会自动触发音频。
结语
但愿我讲明了 VO 制作管线中存在的问题,并说清了我们是如何加以解决的。假如各位喜欢我们的解决方案,并想对自己的项目做类似的改进,随时都可以与我取得联系。目前,ReaCognition 只是一款我们针对某个特定项目构建的工具。不过,如果大家都有这种需求,将来我肯定会把它公开以便各位使用。
再次声明,我并不是说这套工作流程或者 ReaCognition 是前述问题的最佳解决方案,只是我们是这么处理的而已。我之所以跟游戏音频社区的诸位分享这些是希望大家能够相互学习。MHG 音频团队愿意接受任何与流程相关的建议和批评。没准您可以帮助我们加以改进,也可能根本没必要使用 ReaCognition。我们团队在 AAA 级游戏音频制作方面并没有太多经验,有些地方可能做得不对。倘若如此,请务必告知我们。
语音识别只不过是一个表明 AI 在游戏开发当中具备应用潜力的小例子。通过本文的探讨,我觉得大家至少应该能够想象得到游戏开发行业更加美好的未来,希望到时我们可以自动完成所有繁琐的任务,让设计师有更多的时间专心发挥自己的创意。到那个时候,我们只要保证创作水准就可以了。
评论