using UnityEngine; using UnityEngine.UI; namespace Crosstales.RTVoice.Demo { /// Simple GUI for runtime TTS with all available OS voices. [HelpURL("https://www.crosstales.com/media/data/assets/rtvoice/api/class_crosstales_1_1_r_t_voice_1_1_demo_1_1_g_u_i_speech.html")] public class GUISpeech : MonoBehaviour { #region Variables [Header("Settings")] public bool StartAsNative; public GUIMultiAudioFilter AudioFilter; [Header("Table")] public GameObject ItemPrefab; public GameObject Target; public Scrollbar Scroll; public int ColumnCount = 1; public Vector2 SpaceWidth = new Vector2(8, 8); public Vector2 SpaceHeight = new Vector2(8, 8); [Header("UI Objects")] public InputField Input; public InputField Culture; public Text Cultures; public Text Voices; public static float Rate = 1f; public static float Pitch = 1f; public static float Volume = 1f; public static bool isNative; private string lastCulture = "unknown"; //private System.Collections.Generic.List wrappers = new System.Collections.Generic.List(); private System.Collections.Generic.List items = new System.Collections.Generic.List(); private Crosstales.RTVoice.Model.Enum.Gender gender = Crosstales.RTVoice.Model.Enum.Gender.UNKNOWN; //private bool isCustomProvider; private const string forceUpdate = "RT-Voice rulez!"; #endregion #region MonoBehaviour methods private void Start() { Rate = 1f; Pitch = 1f; Volume = 1f; isNative = false; Speaker.Instance.OnProviderChange += onProviderChange; Speaker.Instance.OnVoicesReady += onVoicesReady; //isCustomProvider = Speaker.Instance.CustomMode; if (Cultures != null) Cultures.text = string.Join(", ", Speaker.Instance.Cultures.ToArray()); if (Speaker.Instance.isSSMLSupported) { if (Input != null) Input.text = "Hi there, my name is RT-Voice, your runtime speaker!" + System.Environment.NewLine + "I can speak with the complete SSML specification at half speed or 50% lower pitched.. " + System.Environment.NewLine + "I can talk with rising intonation or with falling intonation." + System.Environment.NewLine + "This is awesome!"; //Debug.Log(Input.text.Length); } else { if (Input != null) Input.text = "Hi there, my name is RT-Voice, your runtime speaker!"; } if (Culture != null) Culture.text = string.Empty; isNative = StartAsNative; if (Voices != null) Voices.text = "Voices (" + items.Count + ")"; } private void Update() { if (Culture != null && !lastCulture.Equals(Culture.text) && Speaker.Instance.areVoicesReady) { buildVoicesList(); lastCulture = Culture.text; Cultures.text = string.Join(", ", Speaker.Instance.Cultures.ToArray()); } } private void OnDestroy() { if (Speaker.Instance != null) { Speaker.Instance.OnProviderChange -= onProviderChange; Speaker.Instance.OnVoicesReady -= onVoicesReady; } } #endregion #region Public methods public void Silence() { Speaker.Instance.Silence(); } public void ChangeRate(float rate) { Rate = rate; } public void ChangeVolume(float volume) { Volume = volume; } public void ChangePitch(float pitch) { Pitch = pitch; } public void ChangeNative(bool native) { isNative = native; } public void GenderChanged(int index) { gender = (Crosstales.RTVoice.Model.Enum.Gender)index; Invoke(nameof(buildVoicesList), 0.2f); } #endregion #region Private methods private void onProviderChange(string provider) { lastCulture = forceUpdate; //force update } private void onVoicesReady() { //Debug.Log("+++ Voices ready... +++"); lastCulture = forceUpdate; //force update } private void clearVoicesList() { if (AudioFilter != null) AudioFilter.ClearFilters(); if (Target != null) { for (int ii = Target.transform.childCount - 1; ii >= 0; ii--) { Transform child = Target.transform.GetChild(ii); child.SetParent(null); Destroy(child.gameObject); } } } private void buildVoicesList() { clearVoicesList(); //make sure everything is deleted if (Target != null) { RectTransform containerRectTransform = Target.GetComponent(); items = Speaker.Instance.VoicesForGender(gender, Culture.text); if (items.Count > 0) { //calculate the width and height of each child item. float width = containerRectTransform.rect.width / ColumnCount - SpaceWidth.x; float height = SpaceHeight.x + SpaceHeight.y; int rowCount = items.Count / ColumnCount; if (rowCount > 0 && items.Count % rowCount > 0) rowCount++; //adjust the height of the container so that it will just barely fit all its children float scrollHeight = height * rowCount; containerRectTransform.offsetMin = new Vector2(containerRectTransform.offsetMin.x, -scrollHeight / 2); containerRectTransform.offsetMax = new Vector2(containerRectTransform.offsetMax.x, scrollHeight / 2); int jj = 0; for (int ii = 0; ii < items.Count; ii++) { //this is used instead of a double for loop because itemCount may not fit perfectly into the rows/columns if (ii % ColumnCount == 0) jj++; //create a new item, name it, and set the parent GameObject newItem = Instantiate(ItemPrefab, Target.transform, true); newItem.name = Target.name + " item at (" + ii + "," + jj + ")"; newItem.transform.localScale = Vector3.one; if (AudioFilter != null) { AudioFilter.Sources.Add(newItem.GetComponent()); AudioFilter.ReverbFilters.Add(newItem.GetComponent()); AudioFilter.ChorusFilters.Add(newItem.GetComponent()); AudioFilter.EchoFilters.Add(newItem.GetComponent()); AudioFilter.DistortionFilters.Add(newItem.GetComponent()); AudioFilter.LowPassFilters.Add(newItem.GetComponent()); AudioFilter.HighPassFilters.Add(newItem.GetComponent()); } SpeakWrapper wrapper = newItem.GetComponent(); wrapper.SpeakerVoice = items[ii]; wrapper.Input = Input; wrapper.Label.text = items[ii].Name; //wrappers.Add(wrapper); //move and size the new item RectTransform rectTransform = newItem.GetComponent(); float x = (width + SpaceWidth.x) * (ii % ColumnCount) + SpaceWidth.x; float y = -height * jj; Vector2 offsetMin = new Vector2(x, y); rectTransform.offsetMin = offsetMin; x = offsetMin.x + width; y = offsetMin.y + SpaceHeight.x; rectTransform.offsetMax = new Vector2(x, y); } if (AudioFilter != null) AudioFilter.ResetFilters(); } if (Scroll != null) Scroll.value = 1f; } if (Voices != null) Voices.text = "Voices (" + items.Count + ")"; } #endregion } } // © 2015-2023 crosstales LLC (https://www.crosstales.com)