绑定到外部库

模块(Modules)

The Summator example in 自定义C++模块 is great for small, custom modules, but what if you want to use a larger, external library? Let’s look at an example using Festival, a speech synthesis (text-to-speech) library written in C++.

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

  1. godot/modules/tts/

接下来,您将使用简单的TTS类创建头文件:

  1. /* tts.h */
  2. #ifndef GODOT_TTS_H
  3. #define GODOT_TTS_H
  4. #include "core/reference.h"
  5. class TTS : public Reference {
  6. GDCLASS(TTS, Reference);
  7. protected:
  8. static void _bind_methods();
  9. public:
  10. bool say_text(String p_txt);
  11. TTS();
  12. };
  13. #endif // GODOT_TTS_H

然后您将添加cpp文件。

  1. /* tts.cpp */
  2. #include "tts.h"
  3. #include <festival.h>
  4. bool TTS::say_text(String p_txt) {
  5. //convert Godot String to Godot CharString to C string
  6. return festival_say_text(p_txt.ascii().get_data());
  7. }
  8. void TTS::_bind_methods() {
  9. ClassDB::bind_method(D_METHOD("say_text", "txt"), &TTS::say_text);
  10. }
  11. TTS::TTS() {
  12. festival_initialize(true, 210000); //not the best way to do it as this should only ever be called once.
  13. }

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

  1. register_types.h
  2. register_types.cpp

重要

These files must be in the top-level folder of your module (next to your SCsub and config.py files) for the module to be registered properly.

These files should contain the following:

  1. /* register_types.h */
  2. void register_tts_types();
  3. void unregister_tts_types();
  4. /* yes, the word in the middle must be the same as the module folder name */
  1. /* register_types.cpp */
  2. #include "register_types.h"
  3. #include "core/class_db.h"
  4. #include "tts.h"
  5. void register_tts_types() {
  6. ClassDB::register_class<TTS>();
  7. }
  8. void unregister_tts_types() {
  9. // Nothing to do here in this example.
  10. }

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

  1. # SCsub
  2. Import('env')
  3. env_tts = env.Clone()
  4. env_tts.add_source_files(env.modules_sources, "*.cpp") # Add all cpp files to the build

您需要在计算机上安装外部库才能获取.a库文件。有关如何为您的操作系统执行此操作的特定说明,请参见库的官方文档。我们在下面包含了Linux的安装命令,以供参考。

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

重要

The voices that Festival uses (and any other potential external/3rd-party resource) all have varying licenses and terms of use; some (if not most) of them may be be problematic with Godot, even if the Festival Library itself is MIT License compatible. Please be sure to check the licenses and terms of use.

外部库也需要安装在模块内部,以使编译器可以访问源文件,同时保持模块代码独立。可以通过 git 使用以下命令从 modules/tts/ 目录中安装 FestivalSpeech_tools 库:

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

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

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

重要

Please note that Git submodules are not used in the Godot repository. If you are developing a module to be merged into the main Godot repository, you should not use submodules. If your module doesn’t get merged in, you can always try to implement the external library as a GDNative C++ plugin.

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

  1. # These paths are relative to /modules/tts/
  2. env_tts.Append(CPPPATH=["speech_tools/include", "festival/src/include"])
  3. # LIBPATH and LIBS need to be set on the real "env" (not the clone)
  4. # to link the specified libraries to the Godot executable.
  5. # This is a path relative to /modules/tts/ where your .a libraries reside.
  6. # If you are compiling the module externally (not in the godot source tree),
  7. # these will need to be full paths.
  8. env.Append(LIBPATH=['libpath'])
  9. # Check with the documentation of the external library to see which library
  10. # files should be included/linked.
  11. env.Append(LIBS=['Festival', 'estools', 'estbase', 'eststring'])

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

  1. # SCsub
  2. Import('env')
  3. env_tts = env.Clone()
  4. env_tts.add_source_files(env.modules_sources, "*.cpp")
  5. env_tts.Append(CCFLAGS=['-O2']) # Flags for C and C++ code
  6. env_tts.Append(CXXFLAGS=['-std=c++11']) # Flags for C++ code only

最终模块应如下所示:

  1. godot/modules/tts/festival/
  2. godot/modules/tts/libpath/libestbase.a
  3. godot/modules/tts/libpath/libestools.a
  4. godot/modules/tts/libpath/libeststring.a
  5. godot/modules/tts/libpath/libFestival.a
  6. godot/modules/tts/speech_tools/
  7. godot/modules/tts/config.py
  8. godot/modules/tts/tts.h
  9. godot/modules/tts/tts.cpp
  10. godot/modules/tts/register_types.h
  11. godot/modules/tts/register_types.cpp
  12. godot/modules/tts/SCsub

使用模块

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

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

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