Cómo usar el plugin
El plugin Runtime Text To Speech sintetiza texto en voz utilizando modelos de voz descargables. Estos modelos se gestionan en la configuración del plugin dentro del editor, se descargan y se empaquetan para su uso en tiempo de ejecución. Sigue los pasos a continuación para comenzar.
Lado del editor
Descarga los modelos de voz apropiados para tu proyecto como se describe aquí. Puedes descargar múltiples modelos de voz al mismo tiempo.
Lado del runtime
Crea el sintetizador usando la función CreateRuntimeTextToSpeech
. Asegúrate de mantener una referencia a él (por ejemplo, como una variable separada en Blueprints o UPROPERTY en C++) para evitar que sea recolectado como basura.
- Blueprint
- C++
// Create the Runtime Text To Speech synthesizer in C++
URuntimeTextToSpeech* Synthesizer = URuntimeTextToSpeech::CreateRuntimeTextToSpeech();
// Ensure the synthesizer is referenced correctly to prevent garbage collection (e.g. as a UPROPERTY)
Sintetizando Voz
El plugin ofrece dos modos de síntesis de texto a voz:
- Texto a Voz Regular: Sintetiza el texto completo y devuelve el audio terminado
- Texto a Voz en Streaming: Proporciona fragmentos de audio a medida que se generan, permitiendo procesamiento en tiempo real
Cada modo soporta dos métodos para seleccionar modelos de voz:
- Por Nombre: Selecciona un modelo de voz por su nombre (recomendado para UE 5.4+)
- Por Objeto: Selecciona un modelo de voz por referencia directa (recomendado para UE 5.3 y versiones anteriores)
Texto a Voz Regular
Por Nombre
- Blueprint
- C++
La función Text To Speech (By Name)
es más conveniente en Blueprints a partir de UE 5.4. Permite seleccionar modelos de voz desde una lista desplegable de los modelos descargados. En versiones de UE anteriores a 5.3, este desplegable no aparece, por lo que si usas una versión más antigua, necesitarás iterar manualmente sobre el array de modelos de voz devuelto por GetDownloadedVoiceModels
para seleccionar el requerido.
En C++, la selección de modelos de voz puede ser ligeramente más compleja debido a la falta de una lista desplegable. Puedes usar la función GetDownloadedVoiceModelNames
para obtener los nombres de los modelos de voz descargados y seleccionar el necesario. Posteriormente, puedes llamar a la función TextToSpeechByName
para sintetizar texto usando el nombre del modelo de voz seleccionado.
// Assuming "Synthesizer" is a valid and referenced URuntimeTextToSpeech object (ensure it is not eligible for garbage collection during the callback)
TArray<FName> DownloadedVoiceNames = URuntimeTTSLibrary::GetDownloadedVoiceModelNames();
// If there are downloaded voice models, use the first one to synthesize text, just as an example
if (DownloadedVoiceNames.Num() > 0)
{
const FName& VoiceName = DownloadedVoiceNames[0]; // Select the first available voice model
Synthesizer->TextToSpeechByName(VoiceName, 0, TEXT("Text example 123"), FOnTTSResultDelegateFast::CreateLambda([](URuntimeTextToSpeech* TextToSpeechInstance, bool bSuccess, const TArray<uint8>& AudioData, int32 SampleRate, int32 NumChannels)
{
UE_LOG(LogTemp, Log, TEXT("TextToSpeech result: %s, AudioData size: %d, SampleRate: %d, NumChannels: %d"), bSuccess ? TEXT("Success") : TEXT("Failed"), AudioData.Num(), SampleRate, NumChannels);
}));
return;
}
Por Objeto
- Blueprint
- C++
La función Text To Speech (By Object)
funciona en todas las versiones de Unreal Engine, pero muestra los modelos de voz como una lista desplegable de referencias de assets, lo cual es menos intuitivo. Este método es adecuado para UE 5.3 y versiones anteriores, o si tu proyecto requiere una referencia directa a un asset de modelo de voz por alguna razón.
Si has descargado los modelos pero no puedes verlos, abre el desplegable Voice Model, haz clic en la configuración (icono de engranaje) y activa tanto Show Plugin Content como Show Engine Content para hacer visibles los modelos.
En C++, la selección de modelos de voz puede ser ligeramente más compleja debido a la falta de una lista desplegable. Puedes usar la función GetDownloadedVoiceModelNames
para obtener los nombres de los modelos de voz descargados y seleccionar el que necesites. Luego, puedes llamar a la función GetVoiceModelFromName
para obtener el objeto del modelo de voz y pasarlo a la función TextToSpeechByObject
para sintetizar texto.
// Assuming "Synthesizer" is a valid and referenced URuntimeTextToSpeech object (ensure it is not eligible for garbage collection during the callback)
TArray<FName> DownloadedVoiceNames = URuntimeTTSLibrary::GetDownloadedVoiceModelNames();
// If there are downloaded voice models, use the first one to synthesize text, for example
if (DownloadedVoiceNames.Num() > 0)
{
const FName& VoiceName = DownloadedVoiceNames[0]; // Select the first available voice model
TSoftObjectPtr<URuntimeTTSModel> VoiceModel;
if (!URuntimeTTSLibrary::GetVoiceModelFromName(VoiceName, VoiceModel))
{
UE_LOG(LogTemp, Error, TEXT("Failed to get voice model from name: %s"), *VoiceName.ToString());
return;
}
Synthesizer->TextToSpeechByObject(VoiceModel, 0, TEXT("Text example 123"), FOnTTSResultDelegateFast::CreateLambda([](URuntimeTextToSpeech* TextToSpeechInstance, bool bSuccess, const TArray<uint8>& AudioData, int32 SampleRate, int32 NumChannels)
{
UE_LOG(LogTemp, Log, TEXT("TextToSpeech result: %s, AudioData size: %d, SampleRate: %d, NumChannels: %d"), bSuccess ? TEXT("Success") : TEXT("Failed"), AudioData.Num(), SampleRate, NumChannels);
}));
return;
}
Texto a Voz en Streaming
Para textos largos o cuando deseas procesar datos de audio en tiempo real a medida que se generan, puedes usar las versiones en streaming de las funciones de Texto a Voz:
Streaming Text To Speech (By Name)
(StreamingTextToSpeechByName
en C++)Streaming Text To Speech (By Object)
(StreamingTextToSpeechByObject
en C++)
Estas funciones proporcionan datos de audio en fragmentos a medida que se generan, permitiendo un procesamiento inmediato sin tener que esperar a que se complete toda la síntesis. Esto es útil para diversas aplicaciones como reproducción de audio en tiempo real, visualización en vivo o cualquier escenario donde necesites procesar datos de voz de manera incremental.
Streaming Por Nombre
- Blueprint
- C++
La función Streaming Text To Speech (By Name)
funciona de manera similar a la versión regular pero proporciona audio en fragmentos a través del delegado On Speech Chunk
.
// Assuming "Synthesizer" is a valid and referenced URuntimeTextToSpeech object
TArray<FName> DownloadedVoiceNames = URuntimeTTSLibrary::GetDownloadedVoiceModelNames();
if (DownloadedVoiceNames.Num() > 0)
{
const FName& VoiceName = DownloadedVoiceNames[0]; // Select the first available voice model
Synthesizer->StreamingTextToSpeechByName(
VoiceName,
0,
TEXT("This is a long text that will be synthesized in chunks."),
FOnTTSStreamingChunkDelegateFast::CreateLambda([](URuntimeTextToSpeech* TextToSpeechInstance, const TArray<uint8>& ChunkAudioData, int32 SampleRate, int32 NumOfChannels, bool bIsFinalChunk)
{
// Process each chunk of audio data as it becomes available
UE_LOG(LogTemp, Log, TEXT("Received chunk %d with %d bytes of audio data. Sample rate: %d, Channels: %d, Is Final: %s"),
ChunkIndex, ChunkAudioData.Num(), SampleRate, NumOfChannels, bIsFinalChunk ? TEXT("Yes") : TEXT("No"));
// You can start processing/playing this chunk immediately
}),
FOnTTSStreamingCompleteDelegateFast::CreateLambda([](URuntimeTextToSpeech* TextToSpeechInstance, bool bSuccess, const FString& ErrorMessage)
{
// Called when the entire synthesis is complete or if it fails
if (bSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Streaming synthesis completed successfully"));
}
else
{
UE_LOG(LogTemp, Error, TEXT("Streaming synthesis failed: %s"), *ErrorMessage);
}
})
);
}
Streaming Por Objeto
- Blueprint
- C++
La función Streaming Text To Speech (By Object)
proporciona la misma funcionalidad de streaming pero toma una referencia de objeto del modelo de voz.
// Assuming "Synthesizer" is a valid and referenced URuntimeTextToSpeech object
TArray<FName> DownloadedVoiceNames = URuntimeTTSLibrary::GetDownloadedVoiceModelNames();
if (DownloadedVoiceNames.Num() > 0)
{
const FName& VoiceName = DownloadedVoiceNames[0]; // Select the first available voice model
TSoftObjectPtr<URuntimeTTSModel> VoiceModel;
if (!URuntimeTTSLibrary::GetVoiceModelFromName(VoiceName, VoiceModel))
{
UE_LOG(LogTemp, Error, TEXT("Failed to get voice model from name: %s"), *VoiceName.ToString());
return;
}
Synthesizer->StreamingTextToSpeechByObject(
VoiceModel,
0,
TEXT("This is a long text that will be synthesized in chunks."),
FOnTTSStreamingChunkDelegateFast::CreateLambda([](URuntimeTextToSpeech* TextToSpeechInstance, const TArray<uint8>& ChunkAudioData, int32 SampleRate, int32 NumOfChannels, bool bIsFinalChunk)
{
// Process each chunk of audio data as it becomes available
UE_LOG(LogTemp, Log, TEXT("Received chunk %d with %d bytes of audio data. Sample rate: %d, Channels: %d, Is Final: %s"),
ChunkIndex, ChunkAudioData.Num(), SampleRate, NumOfChannels, bIsFinalChunk ? TEXT("Yes") : TEXT("No"));
// You can start processing/playing this chunk immediately
}),
FOnTTSStreamingCompleteDelegateFast::CreateLambda([](URuntimeTextToSpeech* TextToSpeechInstance, bool bSuccess, const FString& ErrorMessage)
{
// Called when the entire synthesis is complete or if it fails
if (bSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Streaming synthesis completed successfully"));
}
else
{
UE_LOG(LogTemp, Error, TEXT("Streaming synthesis failed: %s"), *ErrorMessage);
}
})
);
}
Reproducción de Audio
- Reproducción Regular
- Streaming Playback
Para la síntesis de voz regular (no en streaming), el delegado On Speech Result
proporciona el audio sintetizado como datos PCM en formato float (como un array de bytes en Blueprints o TArray<uint8>
en C++), junto con la Sample Rate
y Num Of Channels
.
Para la reproducción, se recomienda utilizar el plugin Runtime Audio Importer para convertir los datos de audio crudos en una onda de sonido reproducible.
- Blueprint
- C++
Aquí hay un ejemplo de cómo podrían verse los nodos de Blueprint para sintetizar texto y reproducir el audio (Nodos copiables):
Aquí hay un ejemplo de cómo sintetizar texto y reproducir el audio en C++:
// Assuming "Synthesizer" is a valid and referenced URuntimeTextToSpeech object (ensure it is not eligible for garbage collection during the callback)
// Ensure "this" is a valid and referenced UObject (must not be eligible for garbage collection during the callback)
TArray<FName> DownloadedVoiceNames = URuntimeTTSLibrary::GetDownloadedVoiceModelNames();
// If there are downloaded voice models, use the first one to synthesize text, for example
if (DownloadedVoiceNames.Num() > 0)
{
const FName& VoiceName = DownloadedVoiceNames[0]; // Select the first available voice model
Synthesizer->TextToSpeechByName(VoiceName, 0, TEXT("Text example 123"), FOnTTSResultDelegateFast::CreateLambda([this](URuntimeTextToSpeech* TextToSpeechInstance, bool bSuccess, const TArray<uint8>& AudioData, int32 SampleRate, int32 NumOfChannels)
{
if (!bSuccess)
{
UE_LOG(LogTemp, Error, TEXT("TextToSpeech failed"));
return;
}
// Create the Runtime Audio Importer to process the audio data
URuntimeAudioImporterLibrary* RuntimeAudioImporter = URuntimeAudioImporterLibrary::CreateRuntimeAudioImporter();
// Prevent the RuntimeAudioImporter from being garbage collected by adding it to the root (you can also use a UPROPERTY, TStrongObjectPtr, etc.)
RuntimeAudioImporter->AddToRoot();
RuntimeAudioImporter->OnResultNative.AddWeakLambda(RuntimeAudioImporter, [this](URuntimeAudioImporterLibrary* Importer, UImportedSoundWave* ImportedSoundWave, ERuntimeImportStatus Status)
{
// Once done, remove it from the root to allow garbage collection
Importer->RemoveFromRoot();
if (Status != ERuntimeImportStatus::SuccessfulImport)
{
UE_LOG(LogTemp, Error, TEXT("Failed to import audio, status: %s"), *UEnum::GetValueAsString(Status));
return;
}
// Play the imported sound wave (ensure a reference is kept to prevent garbage collection)
UGameplayStatics::PlaySound2D(GetWorld(), ImportedSoundWave);
});
RuntimeAudioImporter->ImportAudioFromRAWBuffer(AudioData, ERuntimeRAWAudioFormat::Float32, SampleRate, NumOfChannels);
}));
return;
}
Para la conversión de texto a voz en streaming, recibirás datos de audio en fragmentos como datos PCM en formato float (como un arreglo de bytes en Blueprints o TArray<uint8>
en C++), junto con la Sample Rate
y Num Of Channels
. Cada fragmento puede procesarse inmediatamente a medida que esté disponible.
Para reproducción en tiempo real, se recomienda usar el plugin Runtime Audio Importer con su Streaming Sound Wave, que está específicamente diseñado para reproducción de audio en streaming o procesamiento en tiempo real.
- Blueprint
- C++
Aquí hay un ejemplo de cómo podrían verse los nodos de Blueprint para streaming de texto a voz y reproducción del audio (Nodos copiables):
Aquí hay un ejemplo de cómo implementar streaming de texto a voz con reproducción en tiempo real en C++:
UPROPERTY()
URuntimeTextToSpeech* Synthesizer;
UPROPERTY()
UStreamingSoundWave* StreamingSoundWave;
UPROPERTY()
bool bIsPlaying = false;
void StartStreamingTTS()
{
// Create synthesizer if not already created
if (!Synthesizer)
{
Synthesizer = URuntimeTextToSpeech::CreateRuntimeTextToSpeech();
}
// Create a sound wave for streaming if not already created
if (!StreamingSoundWave)
{
StreamingSoundWave = UStreamingSoundWave::CreateStreamingSoundWave();
StreamingSoundWave->OnPopulateAudioStateNative.AddWeakLambda(this, [this]()
{
if (!bIsPlaying)
{
bIsPlaying = true;
UGameplayStatics::PlaySound2D(GetWorld(), StreamingSoundWave);
}
});
}
TArray<FName> DownloadedVoiceNames = URuntimeTTSLibrary::GetDownloadedVoiceModelNames();
// If there are downloaded voice models, use the first one to synthesize text, for example
if (DownloadedVoiceNames.Num() > 0)
{
const FName& VoiceName = DownloadedVoiceNames[0]; // Select the first available voice model
Synthesizer->StreamingTextToSpeechByName(
VoiceName,
0,
TEXT("Streaming synthesis output begins with a steady flow of data. This data is processed in real-time to ensure consistency. As the process continues, information is streamed without interruption. The output adapts seamlessly to changing inputs. Each piece of data is instantly integrated into the stream. Real-time processing allows for immediate adjustments. This constant flow ensures that the synthesis output is dynamic. As new data comes in, the output evolves accordingly. The system is designed to maintain a continuous output stream. This uninterrupted flow is what drives the efficiency of streaming synthesis."),
FOnTTSStreamingChunkDelegateFast::CreateWeakLambda(this, [this](URuntimeTextToSpeech* TextToSpeechInstance, const TArray<uint8>& ChunkAudioData, int32 SampleRate, int32 NumOfChannels, bool bIsFinalChunk)
{
StreamingSoundWave->AppendAudioDataFromRAW(ChunkAudioData, ERuntimeRAWAudioFormat::Float32, SampleRate, NumOfChannels);
}),
FOnTTSStreamingCompleteDelegateFast::CreateWeakLambda(this, [this](URuntimeTextToSpeech* TextToSpeechInstance, bool bSuccess, const FString& ErrorMessage)
{
if (bSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Streaming text-to-speech synthesis is complete"));
}
else
{
UE_LOG(LogTemp, Error, TEXT("Streaming synthesis failed: %s"), *ErrorMessage);
}
})
);
}
}
Cancelando Text-to-Speech
Puedes cancelar una operación de síntesis de texto a voz en curso en cualquier momento llamando a la función CancelSpeechSynthesis
en tu instancia del sintetizador:
- Blueprint
- C++
// Assuming "Synthesizer" is a valid URuntimeTextToSpeech instance
// Start a long synthesis operation
Synthesizer->TextToSpeechByName(VoiceName, 0, TEXT("Very long text..."), ...);
// Later, if you need to cancel it:
bool bWasCancelled = Synthesizer->CancelSpeechSynthesis();
if (bWasCancelled)
{
UE_LOG(LogTemp, Log, TEXT("Successfully cancelled ongoing synthesis"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("No synthesis was in progress to cancel"));
}
Cuando se cancela una síntesis:
- El proceso de síntesis se detendrá lo antes posible
- Cualquier callback en curso será terminado
- El delegado de finalización será llamado con
bSuccess = false
y un mensaje de error indicando que la síntesis fue cancelada - Cualquier recurso asignado para la síntesis será liberado correctamente
Esto es particularmente útil para textos largos o cuando necesitas interrumpir la reproducción para iniciar una nueva síntesis.
Selección de Speaker
Ambas funciones de Text To Speech aceptan un parámetro opcional de ID de speaker, lo cual es útil cuando trabajas con modelos de voz que soportan múltiples speakers. Puedes usar las funciones GetSpeakerCountFromVoiceModel o GetSpeakerCountFromModelName para verificar si tu modelo de voz seleccionado soporta múltiples speakers. Si hay múltiples speakers disponibles, simplemente especifica el ID del speaker deseado al llamar a las funciones de Text To Speech. Algunos modelos de voz ofrecen una amplia variedad - por ejemplo, English LibriTTS incluye más de 900 speakers diferentes para elegir.
El plugin Runtime Audio Importer también proporciona características adicionales como exportar datos de audio a un archivo, pasarlos a SoundCue, MetaSound, y más. Para más detalles, consulta la documentación de Runtime Audio Importer.