Files
2025-07-21 09:11:14 +02:00

176 lines
5.2 KiB
C#

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using Meta.WitAi.TTS.Utilities;
namespace Meta.Voice.Samples.TTSVoices
{
public class TTSSpeakerInput : MonoBehaviour
{
// Speaker
[SerializeField] private TTSSpeaker _speaker;
// Default input
[SerializeField] private InputField _input;
[SerializeField] private Button _stopButton;
[SerializeField] private Button _pauseButton;
[SerializeField] private Button _speakButton;
// Queue button that will not stop previous clip
[SerializeField] private Toggle _queueButton;
// Async toggle that will play a clip on completion
[SerializeField] private Toggle _asyncToggle;
[SerializeField] private AudioClip _asyncClip;
[SerializeField] private string _dateId = "[DATE]";
[SerializeField] private string[] _queuedText;
// States
private string _voice;
private bool _loading;
private bool _speaking;
private bool _paused;
// Add delegates
private void OnEnable()
{
RefreshStopButton();
RefreshPauseButton();
_stopButton.onClick.AddListener(StopClick);
_pauseButton.onClick.AddListener(PauseClick);
_speakButton.onClick.AddListener(SpeakClick);
}
// Stop click
private void StopClick() => _speaker.Stop();
// Pause click
private void PauseClick()
{
if (_speaker.IsPaused)
{
_speaker.Resume();
}
else
{
_speaker.Pause();
}
}
// Speak phrase click
private void SpeakClick()
{
// Speak phrase
string phrase = FormatText(_input.text);
bool queued = _queueButton != null && _queueButton.isOn;
bool async = _asyncToggle != null && _asyncToggle.isOn;
// Speak async
if (async)
{
StartCoroutine(SpeakAsync(phrase, queued));
}
// Speak queued
else if (queued)
{
_speaker.SpeakQueued(phrase);
}
// Speak
else
{
_speaker.Speak(phrase);
}
// Queue additional phrases
if (_queuedText != null && _queuedText.Length > 0 && queued)
{
foreach (var text in _queuedText)
{
_speaker.SpeakQueued(FormatText(text));
}
}
}
// Speak async
private IEnumerator SpeakAsync(string phrase, bool queued)
{
// Queue
if (queued)
{
yield return _speaker.SpeakQueuedAsync(new string[] { phrase });
}
// Default
else
{
yield return _speaker.SpeakAsync(phrase);
}
// Play complete clip
if (_asyncClip != null)
{
_speaker.AudioSource.PlayOneShot(_asyncClip);
}
}
// Format text with current datetime
private string FormatText(string text)
{
string result = text;
if (result.Contains(_dateId))
{
DateTime now = DateTime.Now;
string dateString = $"{now.ToLongDateString()} at {now.ToLongTimeString()}";
result = text.Replace(_dateId, dateString);
}
return result;
}
// Remove delegates
private void OnDisable()
{
_stopButton.onClick.RemoveListener(StopClick);
_speakButton.onClick.RemoveListener(SpeakClick);
}
// Preset text fields
private void Update()
{
// On preset voice id update
if (!string.Equals(_voice, _speaker.presetVoiceID))
{
_voice = _speaker.presetVoiceID;
_input.placeholder.GetComponent<Text>().text = $"Write something to say in {_voice}'s voice";
}
// On state changes
if (_loading != _speaker.IsLoading)
{
RefreshStopButton();
}
if (_speaking != _speaker.IsSpeaking)
{
RefreshStopButton();
}
if (_paused != _speaker.IsPaused)
{
RefreshPauseButton();
}
}
// Refresh interactable based on states
private void RefreshStopButton()
{
_loading = _speaker.IsLoading;
_speaking = _speaker.IsSpeaking;
_stopButton.interactable = _loading || _speaking;
}
// Refresh text based on pause state
private void RefreshPauseButton()
{
_paused = _speaker.IsPaused;
_pauseButton.GetComponentInChildren<Text>().text = _paused ? "Resume" : "Pause";
}
}
}