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.

Binding de bibliotecas externas

Módulos

O exemplo do Summator em Módulos personalizados em C++ é ótimo para módulos pequenos e personalizados, mas e se você quiser usar uma biblioteca externa maior? Vamos examinar um exemplo usando o Festival, uma biblioteca de síntese de fala (texto para fala) escrita em C++.

Para vincular-se a uma biblioteca externa, configure um diretório de módulo semelhante ao exemplo do Summator:

godot/modules/tts/

Em seguida, você criará um arquivo de cabeçalho com uma classe 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();
};

E então você adicionará o arquivo 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.
}

Assim como antes, a nova classe precisa ser registrada de alguma forma, então mais dois arquivos precisam ser criados:

register_types.h
register_types.cpp

Importante

Esses arquivos devem estar na pasta de nível superior do seu módulo (ao lado dos arquivos SCsub e config.py) para que o módulo seja registrado corretamente.

Esses arquivos devem conter o seguinte:

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

Em seguida, você precisa criar um arquivo SCsub para que o sistema de build compile este módulo:

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

Você precisará instalar a biblioteca externa em sua máquina para obter os arquivos de biblioteca .a. Consulte a documentação oficial da biblioteca para obter instruções específicas sobre como fazer isso para o seu sistema operacional. Incluímos os comandos de instalação para Linux abaixo, para referência.

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

Importante

As vozes que o Festival usa (e qualquer outro recurso externo/de terceiros em potencial) têm licenças e termos de uso variados; algumas (se não a maioria) delas podem ser problemáticas com o Godot, mesmo que a própria Biblioteca Festival seja compatível com a Licença MIT. Por favor, certifique-se de verificar as licenças e os termos de uso.

A biblioteca externa também precisará ser instalada dentro do seu módulo para tornar os arquivos de origem acessíveis ao compilador, mantendo também o código do módulo autocontido. As bibliotecas festival e speech_tools podem ser instaladas a partir do diretório modules/tts/ via git usando os seguintes comandos:

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

Se você não quiser que os arquivos de origem do repositório externo sejam enviados para o seu repositório, você pode criar um link para eles, adicionando-os como submódulos (de dentro do diretório modules/tts/), conforme visto abaixo:

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

Importante

Por favor, note que submódulos do Git não são usados no repositório do Godot. Se você está desenvolvendo um módulo para ser mesclado no repositório principal do Godot, você não deve usar submódulos. Se o seu módulo não for mesclado, você sempre pode tentar implementar a biblioteca externa como uma GDExtension.

Para adicionar diretórios de inclusão (include directories) para o compilador procurar, você pode anexá-los aos caminhos do ambiente (environment's paths):

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'])

Se você quiser adicionar flags de compilação personalizadas ao compilar seu módulo, você precisa clonar o env primeiro, para que ele não adicione essas flags a toda a compilação do Godot (o que pode causar erros). Exemplo de SCsub com flags personalizadas:

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.

O módulo final deve se parecer com isto:

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

Usando o módulo

Agora você pode usar seu módulo recém-criado a partir de qualquer 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)

E a saída será is_spoken: True se o texto for falado.