Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

绑定到外部库

模块

自定义 C++ 模块 中提到的 Summator(求和器)示例非常适合用来制作小型的自定义模块,但如果你想使用一个更大、更复杂的外部库该怎么办呢?接下来,让我们通过一个例子来看看吧——使用的是 Festival,这是一个用 C++ 编写的语音合成(文字转语音)库。

要绑定到外部库, 请设置类似于Summator示例的模块目录:

godot/modules/tts/

接下来,创建 TTS 类的头文件:

godot/modules/tts/tts.h
#pragma once

#include "core/object/ref_counted.h"

class TTS : public RefCounted {
    GDCLASS(TTS, RefCounted);

protected:
    static void _bind_methods();

public:
    bool say_text(String p_txt);

    TTS();
};

然后添加 cpp 文件。

godot/modules/tts/tts.cpp
#include "tts.h"

#include <festival.h>

bool TTS::say_text(String p_txt) {

    //convert Godot String to Godot CharString to C string
    return festival_say_text(p_txt.ascii().get_data());
}

void TTS::_bind_methods() {

    ClassDB::bind_method(D_METHOD("say_text", "txt"), &TTS::say_text);
}

TTS::TTS() {
    festival_initialize(true, 210000); //not the best way to do it as this should only ever be called once.
}

和以前一样, 需要以某种方式注册新类, 因此还需要创建两个文件:

register_types.h
register_types.cpp

重要

这些文件必须在模块的顶层文件夹中(SCsubconfig.py 文件旁边),这样才能正确注册模块。

这些文件应包含以下内容:

godot/modules/tts/register_types.h
void initialize_tts_module(ModuleInitializationLevel p_level);
void uninitialize_tts_module(ModuleInitializationLevel p_level);
/* yes, the word in the middle must be the same as the module folder name */
godot/modules/tts/register_types.cpp
#include "register_types.h"

#include "core/object/class_db.h"
#include "tts.h"

void initialize_tts_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
        return;
    }
    ClassDB::register_class<TTS>();
}

void uninitialize_tts_module(ModuleInitializationLevel p_level) {
    // Nothing to do here in this example.
}

接下来需要创建一个 SCsub 文件,让构建系统编译该模块:

godot/modules/tts/SCsub
Import('env')

env_tts = env.Clone()
env_tts.add_source_files(env.modules_sources, "*.cpp") # Add all cpp files to the build

你需要在你的机器上安装这个外部库,以获取 .a 库文件。关于如何针对你的操作系统进行安装,请查阅该库的官方文档以获取具体的操作说明。为了方便参考,我们在下方提供了 Linux 系统的安装命令。

sudo apt-get install festival festival-dev  # Installs festival and speech_tools libraries
apt-cache search festvox-*  # Displays list of voice packages
sudo apt-get install festvox-don festvox-rablpc16k festvox-kallpc16k festvox-kdlpc16k  # Installs voices

重要

Festival使用的声音(以及任何其他潜在的外部/第三方资源)都有不同的许可证和使用条款;其中一些(如果不是大多数)可能会对Godot产生问题, 即使Festival库本身是与MIT许可证兼容. 请务必检查许可证和使用条款.

外部库也需要被安装到你的模块之中,这样编译器就可以访问到源代码,保持模块独立于外界环境。可以使用如下的 git 命令从 modules/tts/ 目录安装 festival 和 speech_tools:

git clone https://github.com/festvox/festival
git clone https://github.com/festvox/speech_tools

如果不希望将外部仓库的源文件提交到你的仓库中,你可以通过将它们添加为子模块(从 modules/tts/ 目录中)来链接它们,如下所示:

git submodule add https://github.com/festvox/festival
git submodule add https://github.com/festvox/speech_tools

重要

请注意,Godot 的官方仓库中并不使用 Git 子模块(submodules)。如果你正在开发一个打算合并进 Godot 主仓库的模块,那么你不应该使用子模块。如果你的模块最终没能被合并进去,你随时可以尝试将这个外部库封装成一个 GDExtension 来使用。

要添加供编译器查看的包含目录,可以将其追加到环境的路径中:

godot/modules/tts/SCsub
# These paths are relative to /modules/tts/
env_tts.Append(CPPPATH=["speech_tools/include", "festival/src/include"])

# LIBPATH and LIBS need to be set on the real "env" (not the clone)
# to link the specified libraries to the Godot executable.

# This is an absolute path where your .a libraries reside.
# If using a relative path, you must convert it to a
# full path using a utility function, such as `Dir('...').abspath`.
env.Append(LIBPATH=[Dir('libpath').abspath])

# Check with the documentation of the external library to see which library
# files should be included/linked.
env.Append(LIBS=['Festival', 'estools', 'estbase', 'eststring'])

如果要在构建模块时添加自定义编译器标志, 则需要首先克隆 env, 这样它就不会将这些标志添加到整个Godot构建中(这可能会导致错误). 带有自定义标志的示例 SCsub:

godot/modules/tts/SCsub
Import('env')

env_tts = env.Clone()
env_tts.add_source_files(env.modules_sources, "*.cpp")
# Append CCFLAGS flags for both C and C++ code.
env_tts.Append(CCFLAGS=['-O2'])
# If you need to, you can:
# - Append CFLAGS for C code only.
# - Append CXXFLAGS for C++ code only.

最终模块应如下所示:

godot/modules/tts/festival/
godot/modules/tts/libpath/libestbase.a
godot/modules/tts/libpath/libestools.a
godot/modules/tts/libpath/libeststring.a
godot/modules/tts/libpath/libFestival.a
godot/modules/tts/speech_tools/
godot/modules/tts/config.py
godot/modules/tts/tts.h
godot/modules/tts/tts.cpp
godot/modules/tts/register_types.h
godot/modules/tts/register_types.cpp
godot/modules/tts/SCsub

使用模块

现在, 你可以通过任何脚本使用新创建的模块:

var t = TTS.new()
var script = "Hello world. This is a test!"
var is_spoken = t.say_text(script)
print('is_spoken: ', is_spoken)

如果说出文本, 输出将是 is_spoken:True .