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 為例示範。Festival 是一個以 C++ 編寫的語音合成(TTS,文字轉語音)函式庫。

要繫結外部函式庫,請像 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

You'll need to install the external library on your machine to get the .a library files. See the library's official documentation for specific instructions on how to do this for your operating system. We've included the installation commands for Linux below, for reference.

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 所使用的語音(以及其他外部或第三方資源)都有不同的授權條款與使用條件;即使 Festival 函式庫本身符合 MIT 授權,有些資源在 Godot 中仍可能產生授權問題,請務必詳閱各自的授權與使用條款。

外部函式庫也需要安裝在你的模組內,讓編譯器能夠存取其原始檔,並保持模組的程式碼自足(self-contained)。Festival 與 speech_tools 函式庫可在 modules/tts/ 資料夾下用下列 git 指令安裝:

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

如果你不想將外部儲存庫的原始檔提交到你的儲存庫,可以在 modules/tts/ 資料夾中將它們加為 git 子模組來連結,如下所示:

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

重要

請注意,Godot 官方儲存庫不使用 Git 子模組。如果你開發的模組預計要合併進 Godot 主儲存庫,請不要用子模組。若模組未被合併,可以考慮改用 GDExtension 來實作外部函式庫。

若要新增編譯器搜尋的 include 目錄,可將其附加至建置環境的路徑中:

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