Liaison à des bibliothèques externes

Modules

L'exemple Summator dans Modules personnalisées en C++ est géniale pour les modules personnalisés de petite taille, mais si vous souhaitez utiliser une bibliothèque externe plus grande ? Regardons un exemple en utilisant Festival, une bibliothèque de synthétisation de parole (text-to-speech) écrite en C++.

Pour lier une bibliothèque externe, configurez un module similaire à l'exemple Summator :

godot/modules/tts/

Ensuite, vous allez créer un fichier d'en-tête avec une simple classe TTS :

/* tts.h */

#ifndef GODOT_TTS_H
#define GODOT_TTS_H

#include "core/reference.h"

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

protected:
    static void _bind_methods();

public:
    bool say_text(String p_txt);

    TTS();
};

#endif // GODOT_TTS_H

Et puis vous ajouterez le fichier cpp.

/* 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.
}

Tout comme avant, la nouvelle classe doit être enregistrée d'une manière ou d'une autre, deux fichiers supplémentaires doivent être créés :

register_types.h
register_types.cpp

Important

Ces fichiers doivent se trouver dans le dossier de haut niveau de votre module (à côté de vos fichiers SCsub et config.py) pour que le module soit correctement enregistré.

Ces fichiers doivent contenir les éléments suivants :

/* register_types.h */

void register_tts_types();
void unregister_tts_types();
/* yes, the word in the middle must be the same as the module folder name */
/* register_types.cpp */

#include "register_types.h"

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

void register_tts_types() {
    ClassDB::register_class<TTS>();
}

void unregister_tts_types() {
    // Nothing to do here in this example.
}

Ensuite, vous devez créer un fichier SCsub pour que le système de compilation compile ce module :

# 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 operation 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

Important

Les voix utilisées par Festival (et toute autre ressource potentielle externe ou tierce partie) ont toutes des licences et des conditions d'utilisation variées ; certaines (si ce n'est la plupart) d'entre elles peuvent être problématiques avec Godot, même si la bibliothèque Festival elle-même est sous Licence compatible MIT. Veuillez lire les licences et les conditions d'utilisation.

The external library will also need to be installed inside your module to make the source files accessible to the compiler, while also keeping the module code self-contained. The festival and speech_tools libraries can be installed from the modules/tts/ directory via git using the following commands:

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

Si vous ne voulez pas les fichiers source des répertoires externes committés dans votre répertoire, vous pouvez, à la place, les lier en les ajoutant comme sous-modules (depuis les répertoires modules/tts/), comme montré ci-dessous :

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

Important

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.

Pour ajouter des répertoires d'include à consulter par le compilateur, vous pouvez l'ajouter aux chemins de l'environnement :

# 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 a path relative to /modules/tts/ where your .a libraries reside.
# If you are compiling the module externally (not in the godot source tree),
# these will need to be full paths.
env.Append(LIBPATH=['libpath'])

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

Si vous voulez ajouter des drapeaux de compilation personnalisés lors de la construction de votre module, vous devez d'abord cloner env, afin qu'il n'ajoute pas ces drapeaux à la construction de Godot (ce qui peut causer des erreurs). Exemple SCsub avec des drapeaux personnalisés :

# 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.

Le module final devrait ressembler à cela :

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

Utilisation du module

Vous pouvez maintenant utiliser votre module nouvellement créé à partir de n'importe quel script :

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

Et la sortie sera is_spoken: True si le texte est prononcé.