Вопрос или проблема
Я пытаюсь получить сгенерированную речь от SpeechSynthesizer и воспроизвести аудио через Audio Source в Unity. Мне нужно воспроизвести аудио через Audio Source в Unity, потому что я использую аудиодвижок для пакета липсинха.
Я могу воспроизводить нейронный голос и даже создавать аудиоклипы локально. Но мне не удалось извлечь сгенерированный аудиоклип из локального хранилища во время работы программы и воспроизвести его в AudioSource.
Это возможно как для настольных ПК, так и для Oculus? Я использую Cognitive Services Speech SDK для Unity.
//
// Copyright (c) Microsoft. Все права защищены.
// Лицензировано по лицензии MIT. См. файл LICENSE.md в корне проекта для получения полной информации о лицензии.
//
// <code>
using System;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
using Microsoft.CognitiveServices.Speech;
public class HelloWorld : MonoBehaviour
{
// Привяжите три свойства ниже к элементам Text, InputField и Button в вашем интерфейсе.
public Text outputText;
public InputField inputField;
public Button speakButton;
public AudioSource audioSource;
// Замените на свой собственный ключ подписки и регион службы (например, "westus").
private const string SubscriptionKey = "YourSubscriptionKey";
private const string Region = "YourServiceRegion";
private const int SampleRate = 24000;
private object threadLocker = new object();
private bool waitingForSpeak;
private bool audioSourceNeedStop;
private string message;
private SpeechConfig speechConfig;
private SpeechSynthesizer synthesizer;
public void ButtonClick()
{
lock (threadLocker)
{
waitingForSpeak = true;
}
string newMessage = null;
var startTime = DateTime.Now;
// Начинает синтез речи и возвращает результат, когда синтез начат.
using (var result = synthesizer.StartSpeakingTextAsync(inputField.text).Result)
{
// Натуральное воспроизведение пока еще не поддерживается в Unity (в данный момент поддерживается только на настольных Windows/Linux).
// Используйте API Unity для воспроизведения аудио здесь как краткосрочное решение.
// Поддержка натурального воспроизведения будет добавлена в будущем релизе.
var audioDataStream = AudioDataStream.FromResult(result);
var isFirstAudioChunk = true;
var audioClip = AudioClip.Create(
"Speech",
SampleRate * 600, // Максимальная громкость звука на 10 минут
1,
SampleRate,
true,
(float[] audioChunk) =>
{
var chunkSize = audioChunk.Length;
var audioChunkBytes = new byte[chunkSize * 2];
var readBytes = audioDataStream.ReadData(audioChunkBytes);
if (isFirstAudioChunk && readBytes > 0)
{
var endTime = DateTime.Now;
var latency = endTime.Subtract(startTime).TotalMilliseconds;
newMessage = $"Синтез речи выполнен успешно!\nЗадержка: {latency} мс.";
isFirstAudioChunk = false;
}
for (int i = 0; i < chunkSize; ++i)
{
if (i < readBytes / 2)
{
audioChunk[i] = (short)(audioChunkBytes[i * 2 + 1] << 8 | audioChunkBytes[i * 2]) / 32768.0F;
}
else
{
audioChunk[i] = 0.0f;
}
}
if (readBytes == 0)
{
Thread.Sleep(200); // Оставьте немного времени для завершения воспроизведения audioSource
audioSourceNeedStop = true;
}
});
audioSource.clip = audioClip;
audioSource.Play();
}
lock (threadLocker)
{
if (newMessage != null)
{
message = newMessage;
}
waitingForSpeak = false;
}
}
void Start()
{
if (outputText == null)
{
UnityEngine.Debug.LogError("Свойство outputText null! Назначьте элемент UI Text для него.");
}
else if (inputField == null)
{
message = "Свойство inputField null! Назначьте элемент UI InputField для него.";
UnityEngine.Debug.LogError(message);
}
else if (speakButton == null)
{
message = "Свойство speakButton null! Назначьте элемент UI Button для него.";
UnityEngine.Debug.LogError(message);
}
else
{
// Продолжите инициализацию, элементы Text, InputField и Button присутствуют.
inputField.text = "Введите текст, который вы хотите произнести здесь.";
message = "Нажмите кнопку для синтеза речи";
speakButton.onClick.AddListener(ButtonClick);
// Создает экземпляр конфигурации речи с указанным ключом подписки и регионом службы.
speechConfig = SpeechConfig.FromSubscription(SubscriptionKey, Region);
// Формат по умолчанию - RIFF, который имеет заголовок riff.
// Мы воспроизводим звук в памяти как аудиоклип, который не требует заголовка riff.
// Поэтому нам нужно установить формат в raw (24KHz для лучшего качества).
speechConfig.SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm);
// Создает синтезатор речи.
// Не забудьте освободить ресурс синтезатора после его использования!
synthesizer = new SpeechSynthesizer(speechConfig, null);
synthesizer.SynthesisCanceled += (s, e) =>
{
var cancellation = SpeechSynthesisCancellationDetails.FromResult(e.Result);
message = $"ОТМЕНЕНО:\nПричина=[{cancellation.Reason}]\nПодробности об ошибке=[{cancellation.ErrorDetails}]\nВы обновили информацию о подписке?";
};
}
}
void Update()
{
lock (threadLocker)
{
if (speakButton != null)
{
speakButton.interactable = !waitingForSpeak;
}
if (outputText != null)
{
outputText.text = message;
}
if (audioSourceNeedStop)
{
audioSource.Stop();
audioSourceNeedStop = false;
}
}
}
void OnDestroy()
{
if (synthesizer != null)
{
synthesizer.Dispose();
}
}
}
// </code>
Ответ или решение
Чтобы интегрировать синтезированный голос из Microsoft Cognitive Services в Unity и воспроизвести его с использованием Audio Source, следуйте детальной инструкции ниже. Это решение будет работать как для настольных ПК, так и для Oculus, используя предоставленный вами код.
Общая структура решения
- Настройки проекта: Убедитесь, что ваш проект настроен для использования Cognitive Services Speech SDK.
- Изменения в скрипте: Реализуйте корректное воспроизведение аудиоданных через аудиоклип Unity.
- Обработка ошибок: Обрабатывайте возможные ошибки, возникающие во время синтеза речи.
Шаг 1: Настройка проекта
- Убедитесь, что вы установили Cognitive Services Speech SDK для Unity. Подключите необходимые библиотеки в вашем проекте.
- Получите ключ подписки и регион, чтобы подключаться к API. Замените
YourSubscriptionKey
иYourServiceRegion
в коде на свои данные.
Шаг 2: Изменения в коде
Ниже приведен адаптированный код, чтобы правильно воспроизводить аудио с использованием AudioSource
в Unity:
using System;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
using Microsoft.CognitiveServices.Speech;
public class TextToSpeech : MonoBehaviour
{
public Text outputText;
public InputField inputField;
public Button speakButton;
public AudioSource audioSource;
private const string SubscriptionKey = "ВашКлючПодписки";
private const string Region = "ВашРегионСервиса";
private SpeechConfig speechConfig;
private SpeechSynthesizer synthesizer;
void Start()
{
if (outputText == null || inputField == null || speakButton == null || audioSource == null)
{
Debug.LogError("Пожалуйста, проверьте все поля на наличие ошибок.");
return;
}
speakButton.onClick.AddListener(ButtonClick);
InitializeSpeechSynthesizer();
}
private void InitializeSpeechSynthesizer()
{
speechConfig = SpeechConfig.FromSubscription(SubscriptionKey, Region);
speechConfig.SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm);
synthesizer = new SpeechSynthesizer(speechConfig, null);
}
public async void ButtonClick()
{
outputText.text = "Синтез речи...";
var result = await synthesizer.SpeakTextAsync(inputField.text);
if (result.Reason == ResultReason.SynthesizingAudioCompleted)
{
Debug.Log("Синтез завершен.");
var audioDataStream = AudioDataStream.FromResult(result);
PlayAudio(audioDataStream);
}
else
{
Debug.LogError($"Ошибка синтеза: {result.Reason}");
}
}
private void PlayAudio(AudioDataStream audioDataStream)
{
int audioSampleRate = 24000; // 24kHz
var audioClip = AudioClip.Create("SynthesizedSpeech", audioSampleRate * 60, 1, audioSampleRate, true, false);
audioClip.SetData(ReadAudioData(audioDataStream, audioClip.samples), 0);
audioSource.clip = audioClip;
audioSource.Play();
}
private float[] ReadAudioData(AudioDataStream audioDataStream, int samples)
{
var audioChunkBytes = new byte[samples * 2]; // 16 бит на сэмпл
var audioChunk = new float[samples];
int readBytes = audioDataStream.ReadData(audioChunkBytes);
for (int i = 0; i < samples && i * 2 < readBytes; ++i)
{
audioChunk[i] = (short)(audioChunkBytes[i * 2 + 1] << 8 | audioChunkBytes[i * 2]) / 32768.0f;
}
return audioChunk;
}
void OnDestroy()
{
synthesizer?.Dispose();
}
}
Шаг 3: Обработка ошибок и оптимизация
- Проверка конфигурации: Убедитесь, что все компоненты Unity, такие как
Text
,InputField
,Button
, иAudioSource
, правильно настроены и прикреплены к скрипту. - Проверка доступности аудио: Перед воспроизведением AudioSource проверьте, что аудиоданные успешно считаны из потока.
Итог
Следуя этому руководству, вы сможете интегрировать Neural Voice от Microsoft Cognitive Services в Unity и воспроизводить результат через AudioSource. Эта реализация подходит как для настольных ПК, так и для VR-устройств, таких как Oculus. Надеюсь, что эта инструкция будет вам полезна!