binding_to_external_libraries.rst 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. .. _doc_binding_to_external_libraries:
  2. Binding to external libraries
  3. =============================
  4. Modules
  5. -------
  6. The Summator example in :ref:`doc_custom_modules_in_cpp` is great for small,
  7. custom modules, but what if you want to use a larger, external library?
  8. Let's look at an example using `Festival <https://www.cstr.ed.ac.uk/projects/festival/>`_,
  9. a speech synthesis (text-to-speech) library written in C++.
  10. To bind to an external library, set up a module directory similar to the Summator example:
  11. .. code-block:: none
  12. godot/modules/tts/
  13. Next, you will create a header file with a TTS class:
  14. .. code-block:: cpp
  15. :caption: godot/modules/tts/tts.h
  16. #pragma once
  17. #include "core/object/ref_counted.h"
  18. class TTS : public RefCounted {
  19. GDCLASS(TTS, RefCounted);
  20. protected:
  21. static void _bind_methods();
  22. public:
  23. bool say_text(String p_txt);
  24. TTS();
  25. };
  26. And then you'll add the cpp file.
  27. .. code-block:: cpp
  28. :caption: godot/modules/tts/tts.cpp
  29. #include "tts.h"
  30. #include <festival.h>
  31. bool TTS::say_text(String p_txt) {
  32. //convert Godot String to Godot CharString to C string
  33. return festival_say_text(p_txt.ascii().get_data());
  34. }
  35. void TTS::_bind_methods() {
  36. ClassDB::bind_method(D_METHOD("say_text", "txt"), &TTS::say_text);
  37. }
  38. TTS::TTS() {
  39. festival_initialize(true, 210000); //not the best way to do it as this should only ever be called once.
  40. }
  41. Just as before, the new class needs to be registered somehow, so two more files
  42. need to be created:
  43. .. code-block:: none
  44. register_types.h
  45. register_types.cpp
  46. .. important::
  47. These files must be in the top-level folder of your module (next to your
  48. ``SCsub`` and ``config.py`` files) for the module to be registered properly.
  49. These files should contain the following:
  50. .. code-block:: cpp
  51. :caption: godot/modules/tts/register_types.h
  52. void initialize_tts_module(ModuleInitializationLevel p_level);
  53. void uninitialize_tts_module(ModuleInitializationLevel p_level);
  54. /* yes, the word in the middle must be the same as the module folder name */
  55. .. code-block:: cpp
  56. :caption: godot/modules/tts/register_types.cpp
  57. #include "register_types.h"
  58. #include "core/object/class_db.h"
  59. #include "tts.h"
  60. void initialize_tts_module(ModuleInitializationLevel p_level) {
  61. if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
  62. return;
  63. }
  64. ClassDB::register_class<TTS>();
  65. }
  66. void uninitialize_tts_module(ModuleInitializationLevel p_level) {
  67. // Nothing to do here in this example.
  68. }
  69. Next, you need to create an ``SCsub`` file so the build system compiles
  70. this module:
  71. .. code-block:: python
  72. :caption: godot/modules/tts/SCsub
  73. Import('env')
  74. env_tts = env.Clone()
  75. env_tts.add_source_files(env.modules_sources, "*.cpp") # Add all cpp files to the build
  76. You'll need to install the external library on your machine to get the .a library files. See the library's official
  77. documentation for specific instructions on how to do this for your operation system. We've included the
  78. installation commands for Linux below, for reference.
  79. .. code-block:: shell
  80. sudo apt-get install festival festival-dev # Installs festival and speech_tools libraries
  81. apt-cache search festvox-* # Displays list of voice packages
  82. sudo apt-get install festvox-don festvox-rablpc16k festvox-kallpc16k festvox-kdlpc16k # Installs voices
  83. .. important::
  84. The voices that Festival uses (and any other potential external/3rd-party
  85. resource) all have varying licenses and terms of use; some (if not most) of them may be
  86. be problematic with Godot, even if the Festival Library itself is MIT License compatible.
  87. Please be sure to check the licenses and terms of use.
  88. The external library will also need to be installed inside your module to make the source
  89. files accessible to the compiler, while also keeping the module code self-contained. The
  90. festival and speech_tools libraries can be installed from the modules/tts/ directory via
  91. git using the following commands:
  92. .. code-block:: shell
  93. git clone https://github.com/festvox/festival
  94. git clone https://github.com/festvox/speech_tools
  95. If you don't want the external repository source files committed to your repository, you
  96. can link to them instead by adding them as submodules (from within the modules/tts/ directory), as seen below:
  97. .. code-block:: shell
  98. git submodule add https://github.com/festvox/festival
  99. git submodule add https://github.com/festvox/speech_tools
  100. .. important::
  101. Please note that Git submodules are not used in the Godot repository. If
  102. you are developing a module to be merged into the main Godot repository, you should not
  103. use submodules. If your module doesn't get merged in, you can always try to implement
  104. the external library as a GDExtension.
  105. To add include directories for the compiler to look at you can append it to the
  106. environment's paths:
  107. .. code-block:: python
  108. :caption: godot/modules/tts/SCsub
  109. # These paths are relative to /modules/tts/
  110. env_tts.Append(CPPPATH=["speech_tools/include", "festival/src/include"])
  111. # LIBPATH and LIBS need to be set on the real "env" (not the clone)
  112. # to link the specified libraries to the Godot executable.
  113. # This is an absolute path where your .a libraries reside.
  114. # If using a relative path, you must convert it to a
  115. # full path using a utility function, such as `Dir('...').abspath`.
  116. env.Append(LIBPATH=[Dir('libpath').abspath])
  117. # Check with the documentation of the external library to see which library
  118. # files should be included/linked.
  119. env.Append(LIBS=['Festival', 'estools', 'estbase', 'eststring'])
  120. If you want to add custom compiler flags when building your module, you need to clone
  121. `env` first, so it won't add those flags to whole Godot build (which can cause errors).
  122. Example `SCsub` with custom flags:
  123. .. code-block:: python
  124. :caption: godot/modules/tts/SCsub
  125. Import('env')
  126. env_tts = env.Clone()
  127. env_tts.add_source_files(env.modules_sources, "*.cpp")
  128. # Append CCFLAGS flags for both C and C++ code.
  129. env_tts.Append(CCFLAGS=['-O2'])
  130. # If you need to, you can:
  131. # - Append CFLAGS for C code only.
  132. # - Append CXXFLAGS for C++ code only.
  133. The final module should look like this:
  134. .. code-block:: none
  135. godot/modules/tts/festival/
  136. godot/modules/tts/libpath/libestbase.a
  137. godot/modules/tts/libpath/libestools.a
  138. godot/modules/tts/libpath/libeststring.a
  139. godot/modules/tts/libpath/libFestival.a
  140. godot/modules/tts/speech_tools/
  141. godot/modules/tts/config.py
  142. godot/modules/tts/tts.h
  143. godot/modules/tts/tts.cpp
  144. godot/modules/tts/register_types.h
  145. godot/modules/tts/register_types.cpp
  146. godot/modules/tts/SCsub
  147. Using the module
  148. ----------------
  149. You can now use your newly created module from any script:
  150. ::
  151. var t = TTS.new()
  152. var script = "Hello world. This is a test!"
  153. var is_spoken = t.say_text(script)
  154. print('is_spoken: ', is_spoken)
  155. And the output will be ``is_spoken: True`` if the text is spoken.