This commit is contained in:
2023-11-28 11:38:59 +05:30
commit ce059d4bf6
2742 changed files with 618089 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
/*
* 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.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("witai.tests")]
[assembly: InternalsVisibleTo("Meta.WitAi.Tests.Editor")]

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c2286babc47d49e68e8ebb7c9ef3bae8
timeCreated: 1652815735

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aabf1e81ff2442d499f8b3d7b9b8e340
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8848dd0aaf9c1cd49bd992656eebb954
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 64b5e4399ce1894409af2cf7dcab6365
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7913ff34317620543add7ccf91153f48
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
{
"name": "Facebook.Wit.Dictation.Editor",
"rootNamespace": "",
"references": [
"GUID:910a956078d2ff4429c717211dcfaecb",
"GUID:fa958eb9f0171754fb207d563a15ddfa"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f8a301fcccd2a404a9820dc1e9c0d5c3
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ce420a201d5144a44b4c15f1b9c4cff5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,18 @@
/*
* 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 Meta.WitAi.Events.Editor;
using UnityEditor;
namespace Meta.WitAi.Dictation.Events.Editor
{
[CustomPropertyDrawer(typeof(DictationEvents))]
public class DictationEventPropertyDrawer : EventPropertyDrawer<DictationEvents>
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4b8f297a827717846a390137480216b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7000a4548ba72474f9222567d06a50fc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 110ee5aeb672b914bbc92f92061bcbd4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8f0c2fb9674b409c869f53df88912235
timeCreated: 1657568993

View File

@@ -0,0 +1,30 @@
/*
* 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 Meta.WitAi.Data;
namespace Meta.WitAi.Dictation.Data
{
[Serializable]
public class DictationSession : VoiceSession
{
/// <summary>
/// Dictation service being used
/// </summary>
public IDictationService dictationService;
/// <summary>
/// Collection of Request IDs generated from client for Wit requests
/// </summary>
public string[] clientRequestId;
/// <summary>
/// An identifier for the current dictation session
/// </summary>
public string sessionId = Guid.NewGuid().ToString();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9809a25e34ab45d6a522b8f43e4c3703
timeCreated: 1657569002

View File

@@ -0,0 +1,173 @@
/*
* 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 Meta.WitAi.Configuration;
using Meta.WitAi.Dictation.Events;
using Meta.WitAi.Events;
using Meta.WitAi.Events.UnityEventListeners;
using Meta.WitAi.Interfaces;
using Meta.WitAi.Requests;
using UnityEngine;
namespace Meta.WitAi.Dictation
{
public abstract class DictationService : MonoBehaviour, IDictationService, IAudioEventProvider, ITranscriptionEventProvider
{
[Tooltip("Events that will fire before, during and after an activation")]
[SerializeField] protected DictationEvents dictationEvents = new DictationEvents();
///<summary>
/// Internal events used to report telemetry. These events are reserved for internal
/// use only and should not be used for any other purpose.
/// </summary>
protected TelemetryEvents telemetryEvents = new TelemetryEvents();
/// <summary>
/// Returns true if this voice service is currently active and listening with the mic
/// </summary>
public abstract bool Active { get; }
/// <summary>
/// Returns true if the service is actively communicating with Wit.ai during an Activation. The mic may or may not still be active while this is true.
/// </summary>
public abstract bool IsRequestActive { get; }
/// <summary>
/// Gets/Sets a custom transcription provider. This can be used to replace any built in asr
/// with an on device model or other provided source
/// </summary>
public abstract ITranscriptionProvider TranscriptionProvider { get; set; }
/// <summary>
/// Returns true if this voice service is currently reading data from the microphone
/// </summary>
public abstract bool MicActive { get; }
public virtual DictationEvents DictationEvents
{
get => dictationEvents;
set => dictationEvents = value;
}
public TelemetryEvents TelemetryEvents { get => telemetryEvents; set => telemetryEvents = value; }
/// <summary>
/// A subset of events around collection of audio data
/// </summary>
public IAudioInputEvents AudioEvents => DictationEvents;
/// <summary>
/// A subset of events around receiving transcriptions
/// </summary>
public ITranscriptionEvent TranscriptionEvents => DictationEvents;
/// <summary>
/// Returns true if the audio input should be read in an activation
/// </summary>
protected abstract bool ShouldSendMicData { get; }
/// <summary>
/// Activate the microphone and send data for NLU processing. Includes optional additional request parameters like dynamic entities and maximum results.
/// </summary>
public void Activate() => Activate(new WitRequestOptions(), new VoiceServiceRequestEvents());
/// <summary>
/// Activate the microphone and send data for NLU processing. Includes optional additional request parameters like dynamic entities and maximum results.
/// </summary>
/// <param name="requestOptions">Additional options such as custom request id</param>
public void Activate(WitRequestOptions requestOptions) => Activate(requestOptions, new VoiceServiceRequestEvents());
/// <summary>
/// Activate the microphone and send data for NLU processing. Includes optional additional request parameters like dynamic entities and maximum results.
/// </summary>
/// <param name="requestOptions">Additional options such as custom request id</param>
public VoiceServiceRequest Activate(VoiceServiceRequestEvents requestEvents) => Activate(new WitRequestOptions(), requestEvents);
/// <summary>
/// Activate the microphone and send data for NLU processing. Includes optional additional request parameters like dynamic entities and maximum results.
/// </summary>
/// <param name="requestOptions">Additional options such as custom request id</param>
/// <param name="requestEvents">Events specific to the request's lifecycle</param>
public abstract VoiceServiceRequest Activate(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents);
/// <summary>
/// Activate the microphone and send data for NLU processing immediately without waiting for sound/speech from the user to begin. Includes optional additional request parameters like dynamic entities and maximum results.
/// </summary>
public void ActivateImmediately() => ActivateImmediately(new WitRequestOptions(), new VoiceServiceRequestEvents());
/// <summary>
/// Activate the microphone and send data for NLU processing immediately without waiting for sound/speech from the user to begin. Includes optional additional request parameters like dynamic entities and maximum results.
/// </summary>
/// <param name="requestOptions">Additional options such as custom request id</param>
public void ActivateImmediately(WitRequestOptions requestOptions) => ActivateImmediately(requestOptions, new VoiceServiceRequestEvents());
/// <summary>
/// Activate the microphone and send data for NLU processing immediately without waiting for sound/speech from the user to begin. Includes optional additional request parameters like dynamic entities and maximum results.
/// </summary>
/// <param name="requestOptions">Additional options such as custom request id</param>
public VoiceServiceRequest ActivateImmediately(VoiceServiceRequestEvents requestEvents) => ActivateImmediately(new WitRequestOptions(), requestEvents);
/// <summary>
/// Activate the microphone and send data for NLU processing immediately without waiting for sound/speech from the user to begin. Includes optional additional request parameters like dynamic entities and maximum results.
/// </summary>
/// <param name="requestOptions">Additional options such as custom request id</param>
/// <param name="requestEvents">Events specific to the request's lifecycle</param>
public abstract VoiceServiceRequest ActivateImmediately(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents);
/// <summary>
/// Stop listening and submit any remaining buffered microphone data for processing.
/// </summary>
public abstract void Deactivate();
/// <summary>
/// Cancels the current transcription. No FullTranscription event will fire.
/// </summary>
public abstract void Cancel();
protected virtual void Awake()
{
var audioEventListener = GetComponent<AudioEventListener>();
if (!audioEventListener)
{
gameObject.AddComponent<AudioEventListener>();
}
var transcriptionEventListener = GetComponent<TranscriptionEventListener>();
if (!transcriptionEventListener)
{
gameObject.AddComponent<TranscriptionEventListener>();
}
}
protected virtual void OnEnable()
{
}
protected virtual void OnDisable()
{
}
}
public interface IDictationService: ITelemetryEventsProvider
{
bool Active { get; }
bool IsRequestActive { get; }
bool MicActive { get; }
ITranscriptionProvider TranscriptionProvider { get; set; }
DictationEvents DictationEvents { get; set; }
new TelemetryEvents TelemetryEvents { get; set; }
VoiceServiceRequest Activate(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents);
VoiceServiceRequest ActivateImmediately(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents);
void Deactivate();
void Cancel();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d481126888a4412939f6940b2fa3950
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b23994c7bbf9462ca7b6939d3d364e7c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,57 @@
/*
* 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 Meta.WitAi.Events;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;
namespace Meta.WitAi.Dictation.Events
{
[Serializable]
public class DictationEvents : SpeechEvents
{
private const string EVENT_CATEGORY_DICTATION_EVENTS = "Dictation Events";
/// <summary>
/// Called when an individual dictation session has started. This can include multiple server activations if
/// dictation is set up to automatically reactivate when the server endpoints an utterance.
/// </summary>
[Tooltip("Called when an individual dictation session has started. This can include multiple server activations if dictation is set up to automatically reactivate when the server endpoints an utterance.")]
[EventCategory(EVENT_CATEGORY_DICTATION_EVENTS)]
[FormerlySerializedAs("onDictationSessionStarted")] [SerializeField] [HideInInspector]
private DictationSessionEvent _onDictationSessionStarted = new DictationSessionEvent();
public DictationSessionEvent OnDictationSessionStarted => _onDictationSessionStarted;
/// <summary>
/// Called when a dictation is completed after Deactivate has been called or auto-reactivate is disabled.
/// </summary>
[Tooltip("Called when a dictation is completed after Deactivate has been called or auto-reactivate is disabled.")]
[EventCategory(EVENT_CATEGORY_DICTATION_EVENTS)]
[FormerlySerializedAs("onDictationSessionStopped")] [SerializeField] [HideInInspector]
private DictationSessionEvent _onDictationSessionStopped = new DictationSessionEvent();
public DictationSessionEvent OnDictationSessionStopped => _onDictationSessionStopped;
// Deprecated events
[Obsolete("Deprecated for 'OnDictationSessionStarted' event")]
public DictationSessionEvent onDictationSessionStarted => OnDictationSessionStarted;
[Obsolete("Deprecated for 'OnDictationSessionStopped' event")]
public DictationSessionEvent onDictationSessionStopped => OnDictationSessionStopped;
[Obsolete("Deprecated for 'OnStartListening' event")]
public UnityEvent onStart => OnStartListening;
[Obsolete("Deprecated for 'OnStoppedListening' event")]
public UnityEvent onStopped => OnStoppedListening;
[Obsolete("Deprecated for 'OnMicLevelChanged' event")]
public WitMicLevelChangedEvent onMicAudioLevel => OnMicLevelChanged;
[Obsolete("Deprecated for 'OnError' event")]
public WitErrorEvent onError => OnError;
[Obsolete("Deprecated for 'OnResponse' event")]
public WitResponseEvent onResponse => OnResponse;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 866a0a2cd26dd0c469bb96bf7be7ec27
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
/*
* 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 Meta.WitAi.Dictation.Data;
using UnityEngine.Events;
namespace Meta.WitAi.Dictation.Events
{
[Serializable]
public class DictationSessionEvent : UnityEvent<DictationSession>
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c8d63aebd47343999a855f5eff93e7a2
timeCreated: 1657570491

View File

@@ -0,0 +1,17 @@
{
"name": "Facebook.Wit.Dictation",
"rootNamespace": "",
"references": [
"GUID:1c28d8b71ced07540b7c271537363cc6",
"GUID:4504b1a6e0fdcc3498c30b266e4a63bf"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 910a956078d2ff4429c717211dcfaecb
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,108 @@
using System;
using System.Text;
using Meta.WitAi.Events;
using UnityEngine;
namespace Meta.WitAi.Dictation
{
public class MultiRequestTranscription : MonoBehaviour
{
[SerializeField] private WitDictation witDictation;
[SerializeField] private int linesBetweenActivations = 2;
[Multiline]
[SerializeField] private string activationSeparator = String.Empty;
[Header("Events")]
[SerializeField] private WitTranscriptionEvent onTranscriptionUpdated = new
WitTranscriptionEvent();
private StringBuilder _text;
private string _activeText;
private bool _newSection;
private StringBuilder _separator;
private void Awake()
{
if (!witDictation) witDictation = FindObjectOfType<WitDictation>();
_text = new StringBuilder();
_separator = new StringBuilder();
for (int i = 0; i < linesBetweenActivations; i++)
{
_separator.AppendLine();
}
if (!string.IsNullOrEmpty(activationSeparator))
{
_separator.Append(activationSeparator);
}
}
private void OnEnable()
{
witDictation.VoiceEvents.OnFullTranscription.AddListener(OnFullTranscription);
witDictation.VoiceEvents.OnPartialTranscription.AddListener(OnPartialTranscription);
witDictation.VoiceEvents.OnAborting.AddListener(OnCancelled);
}
private void OnDisable()
{
_activeText = string.Empty;
witDictation.VoiceEvents.OnFullTranscription.RemoveListener(OnFullTranscription);
witDictation.VoiceEvents.OnPartialTranscription.RemoveListener(OnPartialTranscription);
}
private void OnCancelled()
{
_activeText = string.Empty;
OnTranscriptionUpdated();
}
private void OnFullTranscription(string text)
{
_activeText = string.Empty;
if (_text.Length > 0)
{
_text.Append(_separator);
}
_text.Append(text);
OnTranscriptionUpdated();
}
private void OnPartialTranscription(string text)
{
_activeText = text;
OnTranscriptionUpdated();
}
public void Clear()
{
_text.Clear();
onTranscriptionUpdated.Invoke(string.Empty);
}
private void OnTranscriptionUpdated()
{
var transcription = new StringBuilder();
transcription.Append(_text);
if (!string.IsNullOrEmpty(_activeText))
{
if (transcription.Length > 0)
{
transcription.Append(_separator);
}
if (!string.IsNullOrEmpty(_activeText))
{
transcription.Append(_activeText);
}
}
onTranscriptionUpdated.Invoke(transcription.ToString());
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a960272debaf35b4f8df9292e4191044
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3e507c9f16a2497a940845bf47606a99
timeCreated: 1656528581

View File

@@ -0,0 +1,22 @@
/*
* 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 Meta.WitAi.Interfaces;
using Meta.WitAi.Utilities;
using UnityEngine;
namespace Meta.WitAi.ServiceReferences
{
public class DictationServiceAudioEventReference : AudioInputServiceReference
{
[SerializeField] private DictationServiceReference _dictationServiceReference;
public override IAudioInputEvents AudioEvents =>
_dictationServiceReference.DictationService.AudioEvents;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e2029a881fa07405c941899ca44707e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
/*
* 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 Meta.WitAi.Dictation;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Meta.WitAi.Utilities
{
[Serializable]
public struct DictationServiceReference
{
[SerializeField] internal DictationService dictationService;
public DictationService DictationService
{
get
{
if (!dictationService)
{
DictationService[] services = Resources.FindObjectsOfTypeAll<DictationService>();
if (services != null)
{
// Set as first instance that isn't a prefab
dictationService = Array.Find(services, (o) => o.gameObject.scene.rootCount != 0);
}
}
return dictationService;
}
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(DictationServiceReference))]
public class DictationServiceReferenceDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.singleLineHeight;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var refProp = property.FindPropertyRelative("DictationService");
var reference = refProp.objectReferenceValue as DictationService;
var dictationServices = GameObject.FindObjectsOfType<DictationService>();
var dictationServiceNames = new string[dictationServices.Length + 1];
int index = 0;
dictationServiceNames[0] = "Autodetect";
if (dictationServices.Length == 1)
{
dictationServiceNames[0] = $"{dictationServiceNames[0]} - {dictationServices[0].name}";
}
for (int i = 0; i < dictationServices.Length; i++)
{
dictationServiceNames[i + 1] = dictationServices[i].name;
if (dictationServices[i] == reference)
{
index = i + 1;
}
}
EditorGUI.BeginProperty(position, label, property);
var updatedIndex = EditorGUI.Popup(position, index, dictationServiceNames);
if (index != updatedIndex)
{
if (updatedIndex > 0)
{
refProp.objectReferenceValue = dictationServices[updatedIndex - 1];
}
else
{
refProp.objectReferenceValue = null;
}
property.serializedObject.ApplyModifiedProperties();
}
EditorGUI.EndProperty();
}
}
#endif
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a487e94faee3e430989a08cd6d770e3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,153 @@
/*
* 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.IO;
using Meta.WitAi.Configuration;
using Meta.WitAi.Data.Configuration;
using Meta.WitAi.Dictation.Events;
using Meta.WitAi.Events;
using Meta.WitAi.Interfaces;
using Meta.WitAi.Requests;
using UnityEngine;
namespace Meta.WitAi.Dictation
{
public class WitDictation : DictationService, IWitRuntimeConfigProvider, IVoiceEventProvider, IWitRequestProvider, IWitConfigurationProvider
{
[SerializeField] private WitRuntimeConfiguration witRuntimeConfiguration;
private WitService witService;
public WitRuntimeConfiguration RuntimeConfiguration
{
get => witRuntimeConfiguration;
set => witRuntimeConfiguration = value;
}
public WitConfiguration Configuration => RuntimeConfiguration?.witConfiguration;
#region Voice Service Properties
public override bool Active => null != witService && witService.Active;
public override bool IsRequestActive => null != witService && witService.IsRequestActive;
public override ITranscriptionProvider TranscriptionProvider
{
get => witService.TranscriptionProvider;
set => witService.TranscriptionProvider = value;
}
public override bool MicActive => null != witService && witService.MicActive;
protected override bool ShouldSendMicData => witRuntimeConfiguration.sendAudioToWit ||
null == TranscriptionProvider;
/// <summary>
/// Events specific to wit voice activation.
/// </summary>
public VoiceEvents VoiceEvents => _voiceEvents;
private readonly VoiceEvents _voiceEvents = new VoiceEvents();
public override DictationEvents DictationEvents
{
get => dictationEvents;
set
{
DictationEvents oldEvents = dictationEvents;
dictationEvents = value;
if (gameObject.activeSelf)
{
VoiceEvents.RemoveListener(oldEvents);
VoiceEvents.AddListener(dictationEvents);
}
}
}
#endregion
#region IWitRequestProvider
public WitRequest CreateWitRequest(WitConfiguration config, WitRequestOptions requestOptions,
VoiceServiceRequestEvents requestEvents,
IDynamicEntitiesProvider[] additionalEntityProviders = null)
{
return config.CreateDictationRequest(requestOptions, requestEvents);
}
#endregion
#region Voice Service Methods
/// <summary>
/// Activates and waits for the user to exceed the min wake threshold before data is sent to the server.
/// </summary>
/// <param name="requestOptions">Additional options such as custom request id</param>
/// <param name="requestEvents">Events specific to the request's lifecycle</param>
public override VoiceServiceRequest Activate(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents)
{
return witService.Activate(requestOptions, requestEvents);
}
/// <summary>
/// Activates immediately and starts sending data to the server. This will not wait for min wake threshold
/// </summary>
/// <param name="requestOptions">Additional options such as custom request id</param>
/// <param name="requestEvents">Events specific to the request's lifecycle</param>
public override VoiceServiceRequest ActivateImmediately(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents)
{
return witService.ActivateImmediately(requestOptions, requestEvents);
}
/// <summary>
/// Deactivates. If a transcription is in progress the network request will complete and any additional
/// transcription values will be returned.
/// </summary>
public override void Deactivate()
{
witService.Deactivate();
}
/// <summary>
/// Deactivates and ignores any pending transcription content.
/// </summary>
public override void Cancel()
{
witService.DeactivateAndAbortRequest();
}
#endregion
protected override void Awake()
{
base.Awake();
witService = gameObject.AddComponent<WitService>();
witService.VoiceEventProvider = this;
witService.ConfigurationProvider = this;
witService.WitRequestProvider = this;
witService.TelemetryEventsProvider = this;
}
protected override void OnEnable()
{
base.OnEnable();
VoiceEvents.AddListener(DictationEvents);
}
protected override void OnDisable()
{
base.OnDisable();
VoiceEvents.RemoveListener(DictationEvents);
}
public void TranscribeFile(string fileName)
{
var request = CreateWitRequest(witRuntimeConfiguration.witConfiguration, new WitRequestOptions(), new VoiceServiceRequestEvents());
var data = File.ReadAllBytes(fileName);
request.postData = data;
witService.ExecuteRequest(request);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4398589986ec92e46a7e1585e63ff2a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cce4aa4005d374a4b94f0b4d6edc298d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d5d4d513ffe662a4db92f38c8468357e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
{
"name": "Meta.WitAi.TTS.Samples",
"rootNamespace": "",
"references": [
"GUID:8bbcefc153e1f1b4a98680670797dd16",
"GUID:1c28d8b71ced07540b7c271537363cc6"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e67ffd8913b227943835c952869d26fb
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 68d2ecf49ba62e0408b8f86acb9b103c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,269 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &3550832292187419422
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3550832292187419420}
- component: {fileID: 3550832292187419423}
- component: {fileID: 1295848615748463565}
m_Layer: 0
m_Name: TTSSpeaker
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3550832292187419420
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3550832292187419422}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 3550832292895390900}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &3550832292187419423
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3550832292187419422}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b15403450229c3a4b8455a61d6143a6d, type: 3}
m_Name:
m_EditorClassIdentifier:
presetVoiceID: CHARLIE
AudioSource: {fileID: 3550832292895390901}
_cloneAudioSource: 0
prependedText:
appendedText:
_events:
OnTextPlaybackStart:
m_PersistentCalls:
m_Calls: []
OnTextPlaybackCancelled:
m_PersistentCalls:
m_Calls: []
OnTextPlaybackFinished:
m_PersistentCalls:
m_Calls: []
OnAudioClipPlaybackReady:
m_PersistentCalls:
m_Calls: []
OnAudioClipPlaybackStart:
m_PersistentCalls:
m_Calls: []
OnAudioClipPlaybackCancelled:
m_PersistentCalls:
m_Calls: []
OnAudioClipPlaybackFinished:
m_PersistentCalls:
m_Calls: []
OnStartSpeaking:
m_PersistentCalls:
m_Calls: []
OnFinishedSpeaking:
m_PersistentCalls:
m_Calls: []
OnCancelledSpeaking:
m_PersistentCalls:
m_Calls: []
OnClipLoadBegin:
m_PersistentCalls:
m_Calls: []
OnClipLoadFailed:
m_PersistentCalls:
m_Calls: []
OnClipLoadSuccess:
m_PersistentCalls:
m_Calls: []
OnClipLoadAbort:
m_PersistentCalls:
m_Calls: []
OnClipDataQueued:
m_PersistentCalls:
m_Calls: []
OnClipDataLoadBegin:
m_PersistentCalls:
m_Calls: []
OnClipDataLoadFailed:
m_PersistentCalls:
m_Calls: []
OnClipDataLoadSuccess:
m_PersistentCalls:
m_Calls: []
OnClipDataLoadAbort:
m_PersistentCalls:
m_Calls: []
OnClipDataPlaybackReady:
m_PersistentCalls:
m_Calls: []
OnClipDataPlaybackStart:
m_PersistentCalls:
m_Calls: []
OnClipDataPlaybackFinished:
m_PersistentCalls:
m_Calls: []
OnClipDataPlaybackCancelled:
m_PersistentCalls:
m_Calls: []
OnPlaybackQueueBegin:
m_PersistentCalls:
m_Calls: []
OnPlaybackQueueComplete:
m_PersistentCalls:
m_Calls: []
_ttsService: {fileID: 0}
--- !u!114 &1295848615748463565
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3550832292187419422}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 81f17bb00ee9f68428d962165826f2fd, type: 3}
m_Name:
m_EditorClassIdentifier:
_maxTextLength: 250
--- !u!1 &3550832292895390903
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3550832292895390900}
- component: {fileID: 3550832292895390901}
m_Layer: 0
m_Name: Voice
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3550832292895390900
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3550832292895390903}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 2, y: 1.665, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 3550832292187419420}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!82 &3550832292895390901
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3550832292895390903}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 0}
m_PlayOnAwake: 0
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 45fe3f4c7b67f4d4c83f7c1d3c8f1a50
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e264fcb4f1c2dc248bacd7a1f80da833
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,175 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &4852061571279439017
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4852061571279439020}
- component: {fileID: 4852061571279439023}
- component: {fileID: 3627599131962939471}
- component: {fileID: 4852061571279439022}
m_Layer: 0
m_Name: TTSWit
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4852061571279439020
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4852061571279439017}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &4852061571279439023
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4852061571279439017}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a6b3124b830442d45b9f357ff99b152f, type: 3}
m_Name:
m_EditorClassIdentifier:
_events:
OnClipCreated:
m_PersistentCalls:
m_Calls: []
OnClipUnloaded:
m_PersistentCalls:
m_Calls: []
Stream:
OnStreamBegin:
m_PersistentCalls:
m_Calls: []
OnStreamReady:
m_PersistentCalls:
m_Calls: []
OnStreamClipUpdate:
m_PersistentCalls:
m_Calls: []
OnStreamComplete:
m_PersistentCalls:
m_Calls: []
OnStreamCancel:
m_PersistentCalls:
m_Calls: []
OnStreamError:
m_PersistentCalls:
m_Calls: []
Download:
OnDownloadBegin:
m_PersistentCalls:
m_Calls: []
OnDownloadSuccess:
m_PersistentCalls:
m_Calls: []
OnDownloadCancel:
m_PersistentCalls:
m_Calls: []
OnDownloadError:
m_PersistentCalls:
m_Calls: []
RequestSettings:
configuration: {fileID: 11400000, guid: 8ca721df475c92e4ca9167b74de4b2f6, type: 2}
audioType: 0
audioStream: 1
audioStreamReadyDuration: 0.1
audioStreamChunkLength: 5
audioStreamPreloadCount: 3
_presetVoiceSettings:
- settingsID: CHARLIE
voice: Charlie
style: default
speed: 100
pitch: 100
gain: 50
- settingsID: REBECCA
voice: Rebecca
style: default
speed: 100
pitch: 100
gain: 50
- settingsID: COOPER
voice: Cooper
style: default
speed: 100
pitch: 100
gain: 50
- settingsID: VAMPIRE
voice: Vampire
style: default
speed: 100
pitch: 100
gain: 50
- settingsID: PROSPECTOR
voice: Prospector
style: default
speed: 100
pitch: 100
gain: 50
--- !u!114 &3627599131962939471
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4852061571279439017}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1d60dcb6d02034b4b96284db469db5e3, type: 3}
m_Name:
m_EditorClassIdentifier:
ClipLimit: 1
ClipCapacity: 100
RamLimit: 0
RamCapacity: 20000
--- !u!114 &4852061571279439022
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4852061571279439017}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b0ffdd015bcb8ea41bb96f19a723bf7d, type: 3}
m_Name:
m_EditorClassIdentifier:
_diskPath: TTS/
_defaultSettings:
DiskCacheLocation: 0
_events:
OnStreamBegin:
m_PersistentCalls:
m_Calls: []
OnStreamReady:
m_PersistentCalls:
m_Calls: []
OnStreamClipUpdate:
m_PersistentCalls:
m_Calls: []
OnStreamComplete:
m_PersistentCalls:
m_Calls: []
OnStreamCancel:
m_PersistentCalls:
m_Calls: []
OnStreamError:
m_PersistentCalls:
m_Calls: []

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a89561c2ba096ad4dbf37bbb423d6f3c
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 748ff8d1d0d4814429b86058a56a3ee4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 79647fe399cbd69458a2728d01b2f739
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5e581f7e133ba2048995048327a1ef85
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
/*
* 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 Meta.WitAi.TTS.Data;
using Meta.WitAi.TTS.Integrations;
using UnityEngine;
using UnityEngine.UI;
namespace Meta.WitAi.TTS.Samples
{
public class TTSCacheToggle : MonoBehaviour
{
// UI references
[SerializeField] private TTSDiskCache _diskCache;
[SerializeField] private Text _cacheLabel;
[SerializeField] private Button _button;
// Current disk cache location
private TTSDiskCacheLocation _cacheLocation = (TTSDiskCacheLocation) (-1);
// Add listeners
private void OnEnable()
{
// Obtain disk cache if possible
if (_diskCache == null)
{
_diskCache = GameObject.FindObjectOfType<TTSDiskCache>();
}
// Reset location text
RefreshLocation();
_button.onClick.AddListener(ToggleCache);
}
// Current disk cache location
private TTSDiskCacheLocation GetCurrentCacheLocation() => _diskCache == null ? TTSDiskCacheLocation.Stream : _diskCache.DiskCacheDefaultSettings.DiskCacheLocation;
// Check for changes
private void Update()
{
if (_cacheLocation != GetCurrentCacheLocation())
{
RefreshLocation();
}
}
// Refresh location & button text
private void RefreshLocation()
{
_cacheLocation = GetCurrentCacheLocation();
_cacheLabel.text = $"Disk Cache: {_cacheLocation}";
}
// Remove listeners
private void OnDisable()
{
_button.onClick.RemoveListener(ToggleCache);
}
// Toggle cache
public void ToggleCache()
{
// Toggle to next option
TTSDiskCacheLocation cacheLocation = GetCurrentCacheLocation();
switch (cacheLocation)
{
case TTSDiskCacheLocation.Stream:
cacheLocation = TTSDiskCacheLocation.Temporary;
break;
case TTSDiskCacheLocation.Temporary:
cacheLocation = TTSDiskCacheLocation.Persistent;
break;
case TTSDiskCacheLocation.Persistent:
cacheLocation = TTSDiskCacheLocation.Preload;
break;
default:
cacheLocation = TTSDiskCacheLocation.Stream;
break;
}
// Set next option
_diskCache.DiskCacheDefaultSettings.DiskCacheLocation = cacheLocation;
// Clear runtime cache
TTSService.Instance.UnloadAll();
// Refresh location
RefreshLocation();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e7aad95c862d94f4f912114f5fd46959
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
/*
* 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 UnityEngine;
using UnityEngine.UI;
namespace Meta.WitAi.TTS.Samples
{
public class TTSErrorText : MonoBehaviour
{
// Label
[SerializeField] private Text _errorLabel;
// Current error response
private string _error = string.Empty;
// Add listeners
private void Update()
{
if (TTSService.Instance != null)
{
string invalidError = TTSService.Instance.GetInvalidError();
if (!string.Equals(invalidError, _error))
{
_error = invalidError;
if (string.IsNullOrEmpty(_error))
{
_errorLabel.text = string.Empty;
}
else
{
_errorLabel.text = $"TTS Service Error: {_error}";
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f9580bff99ab114d85ccce9a75b067b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,100 @@
/*
* 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 UnityEngine;
using UnityEngine.UI;
using Meta.WitAi.TTS.Utilities;
namespace Meta.WitAi.TTS.Samples
{
public class TTSSpeakerInput : MonoBehaviour
{
[SerializeField] private Text _title;
[SerializeField] private InputField _input;
[SerializeField] private TTSSpeaker _speaker;
[SerializeField] private Button _stopButton;
[SerializeField] private Button _speakButton;
[SerializeField] private Button _speakQueuedButton;
[SerializeField] private string _dateId = "[DATE]";
[SerializeField] private string[] _queuedText;
// States
private bool _loading;
private bool _speaking;
// Add delegates
private void OnEnable()
{
RefreshButtons();
_stopButton.onClick.AddListener(StopClick);
_speakButton.onClick.AddListener(SpeakClick);
_speakQueuedButton.onClick.AddListener(SpeakQueuedClick);
}
// Stop click
private void StopClick() => _speaker.Stop();
// Speak phrase click
private void SpeakClick() => _speaker.Speak(FormatText(_input.text));
// Speak queued phrase click
private void SpeakQueuedClick()
{
foreach (var text in _queuedText)
{
_speaker.SpeakQueued(FormatText(text));
}
_speaker.SpeakQueued(FormatText(_input.text));
}
// 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.ToShortTimeString()}";
result = text.Replace(_dateId, dateString);
}
return result;
}
// Remove delegates
private void OnDisable()
{
_stopButton.onClick.RemoveListener(StopClick);
_speakButton.onClick.RemoveListener(SpeakClick);
_speakQueuedButton.onClick.RemoveListener(SpeakQueuedClick);
}
// Preset text fields
private void Update()
{
// On preset voice id update
if (!string.Equals(_title.text, _speaker.presetVoiceID))
{
_title.text = _speaker.presetVoiceID;
_input.placeholder.GetComponent<Text>().text = $"Write something to say in {_speaker.presetVoiceID}'s voice";
}
// On state changes
if (_loading != _speaker.IsLoading)
{
_loading = _speaker.IsLoading;
RefreshButtons();
}
if (_speaking != _speaker.IsSpeaking)
{
_speaking = _speaker.IsSpeaking;
RefreshButtons();
}
}
// Refresh interactable based on states
private void RefreshButtons()
{
_stopButton.interactable = _loading || _speaking;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a57b9d9fb2760434e859220f24690a1e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
/*
* 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.Text;
using Meta.WitAi.TTS.Data;
using UnityEngine;
using UnityEngine.UI;
using Meta.WitAi.TTS.Utilities;
namespace Meta.WitAi.TTS.Samples
{
public class TTSStatusLabel : MonoBehaviour
{
[SerializeField] private TTSSpeaker _speaker;
[SerializeField] private Text _label;
private void OnEnable()
{
RefreshLabel();
_speaker.Events.OnClipDataLoadBegin.AddListener(OnClipRefresh);
_speaker.Events.OnClipDataLoadAbort.AddListener(OnClipRefresh);
_speaker.Events.OnClipDataLoadFailed.AddListener(OnClipRefresh);
_speaker.Events.OnClipDataLoadSuccess.AddListener(OnClipRefresh);
_speaker.Events.OnClipDataQueued.AddListener(OnClipRefresh);
_speaker.Events.OnClipDataPlaybackReady.AddListener(OnClipRefresh);
_speaker.Events.OnClipDataPlaybackStart.AddListener(OnClipRefresh);
_speaker.Events.OnClipDataPlaybackFinished.AddListener(OnClipRefresh);
_speaker.Events.OnClipDataPlaybackCancelled.AddListener(OnClipRefresh);
}
private void OnClipRefresh(TTSClipData clipData)
{
RefreshLabel();
}
private void OnDisable()
{
_speaker.Events.OnClipDataQueued.RemoveListener(OnClipRefresh);
_speaker.Events.OnClipDataLoadBegin.RemoveListener(OnClipRefresh);
_speaker.Events.OnClipDataLoadAbort.RemoveListener(OnClipRefresh);
_speaker.Events.OnClipDataLoadFailed.RemoveListener(OnClipRefresh);
_speaker.Events.OnClipDataLoadSuccess.RemoveListener(OnClipRefresh);
_speaker.Events.OnClipDataPlaybackReady.RemoveListener(OnClipRefresh);
_speaker.Events.OnClipDataPlaybackStart.RemoveListener(OnClipRefresh);
_speaker.Events.OnClipDataPlaybackFinished.RemoveListener(OnClipRefresh);
_speaker.Events.OnClipDataPlaybackCancelled.RemoveListener(OnClipRefresh);
}
private void RefreshLabel()
{
StringBuilder status = new StringBuilder();
if (_speaker.SpeakingClip != null)
{
status.AppendLine($"Speaking: {_speaker.IsSpeaking}");
}
int index = 0;
foreach (var clip in _speaker.QueuedClips)
{
status.Insert(0, $"Queue[{index}]: {clip.loadState.ToString()}\n");
index++;
}
if (status.Length > 0)
{
status.Remove(status.Length - 1, 1);
}
_label.text = status.ToString();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 443d56f5ec5b41c4aa647a2350247db1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
/*
* 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 UnityEngine;
using UnityEngine.UI;
using Meta.WitAi.TTS.Integrations;
namespace Meta.WitAi.TTS.Samples
{
public class TTSStreamToggle : MonoBehaviour
{
// UI references
[SerializeField] private TTSWit _service;
[SerializeField] private Text _label;
[SerializeField] private Button _button;
// Current stream
private bool _streamEnabled = true;
// Add listeners
private void OnEnable()
{
// Obtain disk cache if possible
if (_service == null)
{
_service = GameObject.FindObjectOfType<TTSWit>();
}
// Log for missing service
if (_service == null)
{
VLog.E("TTS Stream Toggle - Cannot work without a TTSWit reference");
}
// Reset
RefreshStreaming();
_button.onClick.AddListener(ToggleStreaming);
}
// Remove listeners
private void OnDisable()
{
_button.onClick.RemoveListener(ToggleStreaming);
}
// Refresh location & button text
private void RefreshStreaming()
{
_streamEnabled = GetStreaming();
_label.text = $"Streaming: {(_streamEnabled ? "ON" : "OFF")}";
}
// Toggle streaming
public void ToggleStreaming()
{
SetStreaming(!_streamEnabled);
RefreshStreaming();
}
// Get streaming option from service
private bool GetStreaming()
{
return _service && _service.RequestSettings.audioStream;
}
// Set streaming option to
private void SetStreaming(bool toStreaming)
{
if (_service != null)
{
_service.RequestSettings.audioStream = toStreaming;
}
}
// Update if changed externally
private void Update()
{
if (_streamEnabled != GetStreaming())
{
RefreshStreaming();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 62fa707a35782fb4dafd0da34ea548a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
Welcome to Voice SDK Text-To-Speech!
The following are phrases to be auto-loaded.
Hi, how are you?
I am great! Thank you for asking!
Would you mind repeating that?
I actually cannot hear you right now.
Hmmm
Well that is interesting!
My favorite color is green.
My favorite color is purple.
Sentence one begins with a few words and then ends with an ellipsis... Does sentence two start with two spaces and end with a question mark? Sentence three also starts with two spaces, has a comma; has a semicolon and ends with two exclamation points!! A sentence with a semicolon; may be used as well.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c94bdcb6d297dfe41a49608ed6309ab9
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 466ea4f9ad1762f41a5effc0e1985b21
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b1da9fac71952343b124f3771afe034
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
{
"name": "Meta.WitAi.TTS.Editor",
"rootNamespace": "",
"references": [
"GUID:4504b1a6e0fdcc3498c30b266e4a63bf",
"GUID:fa958eb9f0171754fb207d563a15ddfa",
"GUID:8bbcefc153e1f1b4a98680670797dd16",
"GUID:1c28d8b71ced07540b7c271537363cc6",
"GUID:5c61c7ae4b0c6f94299e51352f802670"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e31cc0253d8f956459091c800a16d68d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 716af1288c1a89d44950d38c999fe096
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
/*
* 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 UnityEngine;
namespace Meta.WitAi.TTS.Editor.Preload
{
[Serializable]
public class TTSPreloadPhraseData
{
/// <summary>
/// ID used to identify this phrase
/// </summary>
public string clipID;
/// <summary>
/// Actual phrase to be spoken
/// </summary>
public string textToSpeak;
/// <summary>
/// Meta data for whether clip is downloaded or not
/// </summary>
public bool downloaded;
/// <summary>
/// Meta data for clip download progress
/// </summary>
public float downloadProgress;
}
[Serializable]
public class TTSPreloadVoiceData
{
/// <summary>
/// Specific preset voice settings id to be used with TTSService
/// </summary>
public string presetVoiceID;
/// <summary>
/// All data corresponding to text to speak
/// </summary>
public TTSPreloadPhraseData[] phrases;
}
[Serializable]
public class TTSPreloadData
{
public TTSPreloadVoiceData[] voices;
}
public class TTSPreloadSettings : ScriptableObject
{
[SerializeField] public TTSPreloadData data = new TTSPreloadData();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 80be64a601ff65e41b0a8036ba872084
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,483 @@
/*
* 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.Generic;
using Meta.WitAi.Data.Configuration;
using Meta.WitAi.TTS.Data;
using Meta.WitAi.TTS.Editor.Preload;
using Meta.WitAi.Utilities;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.TTS.Editor
{
[CustomEditor(typeof(TTSPreloadSettings), true)]
public class TTSPreloadSettingsInspector : UnityEditor.Editor
{
// TTS Settings
public TTSPreloadSettings Settings { get; private set; }
// TTS Service
public TTSService TtsService { get; private set; }
private List<string> _ttsVoiceIDs;
// Layout items
public const float ACTION_BTN_INDENT = 15f;
public virtual Texture2D HeaderIcon => WitTexts.HeaderIcon;
public virtual string HeaderUrl => WitTexts.GetAppURL(string.Empty, WitTexts.WitAppEndpointType.Settings);
public virtual string DocsUrl => WitTexts.Texts.WitDocsUrl;
// Layout
public override void OnInspectorGUI()
{
// Get settings
if (Settings != target)
{
Settings = target as TTSPreloadSettings;
}
// Draw header
WitEditorUI.LayoutHeaderButton(HeaderIcon, HeaderUrl, DocsUrl);
GUILayout.Space(WitStyles.HeaderPaddingBottom);
// Layout actions
LayoutPreloadActions();
// Layout data
LayoutPreloadData();
}
// Layout Preload Data
protected virtual void LayoutPreloadActions()
{
// Layout preload actions
EditorGUILayout.Space();
WitEditorUI.LayoutSubheaderLabel("TTS Preload Actions");
// Indent
EditorGUI.indentLevel++;
EditorGUILayout.Space();
// Hide when playing
if (Application.isPlaying)
{
EditorUtility.ClearProgressBar();
WitEditorUI.LayoutErrorLabel("TTS preload actions cannot be performed at runtime.");
EditorGUI.indentLevel--;
return;
}
// Get TTS Service if needed
TtsService = EditorGUILayout.ObjectField("TTS Service", TtsService, typeof(TTSService), true) as TTSService;
if (TtsService == null)
{
TtsService = GameObjectSearchUtility.FindSceneObject<TTSService>(true);
if (TtsService == null)
{
EditorUtility.ClearProgressBar();
WitEditorUI.LayoutErrorLabel("You must add a TTS Service to the loaded scene in order perform TTS actions.");
EditorGUI.indentLevel--;
return;
}
}
if (_ttsVoiceIDs == null)
{
_ttsVoiceIDs = GetVoiceIDs(TtsService);
}
// Begin buttons
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
// Import JSON
GUILayout.Space(ACTION_BTN_INDENT * EditorGUI.indentLevel);
if (WitEditorUI.LayoutTextButton("Refresh Data"))
{
RefreshData();
}
GUILayout.Space(ACTION_BTN_INDENT);
if (WitEditorUI.LayoutTextButton("Import JSON"))
{
EditorUtility.ClearProgressBar();
if (TTSPreloadUtility.ImportData(Settings))
{
RefreshData();
}
}
GUILayout.Space(ACTION_BTN_INDENT);
if (WitEditorUI.LayoutTextButton("Import AutoLoader Data"))
{
EditorUtility.ClearProgressBar();
if (TTSPreloadUtility.ImportPhrases(Settings))
{
RefreshData();
}
}
// Clear disk cache
GUI.enabled = TtsService != null;
EditorGUILayout.Space();
Color col = GUI.color;
GUI.color = Color.red;
if (WitEditorUI.LayoutTextButton("Delete Cache"))
{
EditorUtility.ClearProgressBar();
TTSPreloadUtility.DeleteData(TtsService);
RefreshData();
}
// Preload disk cache
GUILayout.Space(ACTION_BTN_INDENT);
GUI.color = Color.green;
if (WitEditorUI.LayoutTextButton("Preload Cache"))
{
DownloadClips();
}
GUI.color = col;
GUI.enabled = true;
// End buttons
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
// Indent
EditorGUI.indentLevel--;
}
// Refresh
private void RefreshData()
{
TTSPreloadUtility.RefreshPreloadData(TtsService, Settings.data, (p) =>
{
EditorUtility.DisplayProgressBar("TTS Preload Utility", "Refreshing Data", p);
}, (d, l) =>
{
EditorUtility.ClearProgressBar();
EditorUtility.SetDirty(Settings);
Debug.Log($"TTS Preload Utility - Refresh Complete{l}");
});
}
// Download
private void DownloadClips()
{
TTSPreloadUtility.PreloadData(TtsService, Settings.data, (p) =>
{
EditorUtility.DisplayProgressBar("TTS Preload Utility", "Downloading Clips", p);
}, (d, l) =>
{
EditorUtility.ClearProgressBar();
EditorUtility.SetDirty(Settings);
AssetDatabase.Refresh();
Debug.Log($"TTS Preload Utility - Preload Complete{l}");
});
}
// Layout Preload Data
protected virtual void LayoutPreloadData()
{
// For updates
bool updated = false;
// Layout preload items
GUILayout.Space(WitStyles.WindowPaddingBottom);
GUILayout.BeginHorizontal();
WitEditorUI.LayoutSubheaderLabel("TTS Preload Data");
if (WitEditorUI.LayoutTextButton("Add Voice"))
{
AddVoice();
updated = true;
}
GUILayout.EndHorizontal();
EditorGUILayout.Space();
// Indent
EditorGUI.indentLevel++;
// Generate
if (Settings.data == null)
{
Settings.data = new TTSPreloadData();
}
if (Settings.data.voices == null)
{
Settings.data.voices = new TTSPreloadVoiceData[] {new TTSPreloadVoiceData()};
}
// Begin scroll
for (int v = 0; v < Settings.data.voices.Length; v++)
{
if (!LayoutVoiceData(Settings.data, v, ref updated))
{
break;
}
}
// Set dirty
if (updated)
{
EditorUtility.SetDirty(Settings);
}
// Indent
EditorGUI.indentLevel--;
}
// Layout
private bool LayoutVoiceData(TTSPreloadData preloadData, int voiceIndex, ref bool updated)
{
// Indent
EditorGUI.indentLevel++;
// Get data
TTSPreloadVoiceData voiceData = preloadData.voices[voiceIndex];
string voiceID = voiceData.presetVoiceID;
if (string.IsNullOrEmpty(voiceID))
{
voiceID = "No Voice Selected";
}
voiceID = $"{(voiceIndex+1)} - {voiceID}";
// Foldout
GUILayout.BeginHorizontal();
bool show = WitEditorUI.LayoutFoldout(new GUIContent(voiceID), voiceData);
if (!show)
{
GUILayout.EndHorizontal();
EditorGUI.indentLevel--;
return true;
}
// Delete
if (WitEditorUI.LayoutTextButton("Delete Voice"))
{
DeleteVoice(voiceIndex);
GUILayout.EndHorizontal();
EditorGUI.indentLevel--;
updated = true;
return false;
}
// Begin Voice Data
GUILayout.EndHorizontal();
EditorGUI.indentLevel++;
// Voice Text Field
if (TtsService == null || _ttsVoiceIDs == null || _ttsVoiceIDs.Count == 0)
{
WitEditorUI.LayoutTextField(new GUIContent("Voice ID"), ref voiceData.presetVoiceID, ref updated);
}
// Voice Preset Select
else
{
int presetIndex = _ttsVoiceIDs.IndexOf(voiceData.presetVoiceID);
bool presetUpdated = false;
WitEditorUI.LayoutPopup("Voice ID", _ttsVoiceIDs.ToArray(), ref presetIndex, ref presetUpdated);
if (presetUpdated)
{
voiceData.presetVoiceID = _ttsVoiceIDs[presetIndex];
string l = string.Empty;
TTSPreloadUtility.RefreshVoiceData(TtsService, voiceData, null, ref l);
updated = true;
}
}
// Ensure phrases exist
if (voiceData.phrases == null)
{
voiceData.phrases = new TTSPreloadPhraseData[] { };
}
// Phrase Foldout
EditorGUILayout.BeginHorizontal();
bool isLayout = WitEditorUI.LayoutFoldout(new GUIContent($"Phrases ({voiceData.phrases.Length})"),
voiceData.phrases);
if (WitEditorUI.LayoutTextButton("Add Phrase"))
{
TTSPreloadPhraseData lastPhrase = voiceData.phrases.Length == 0 ? null : voiceData.phrases[voiceData.phrases.Length - 1];
voiceData.phrases = AddArrayItem<TTSPreloadPhraseData>(voiceData.phrases, new TTSPreloadPhraseData()
{
textToSpeak = lastPhrase?.textToSpeak,
clipID = lastPhrase?.clipID
});
GUILayout.EndHorizontal();
EditorGUI.indentLevel--;
updated = true;
return false;
}
EditorGUILayout.EndHorizontal();
if (isLayout)
{
for (int p = 0; p < voiceData.phrases.Length; p++)
{
if (!LayoutPhraseData(voiceData, p, ref updated))
{
break;
}
}
}
// End Voice Data
EditorGUILayout.Space();
EditorGUI.indentLevel--;
EditorGUI.indentLevel--;
return true;
}
// Layout phrase data
private bool LayoutPhraseData(TTSPreloadVoiceData voiceData, int phraseIndex, ref bool updated)
{
// Begin Phrase
EditorGUI.indentLevel++;
// Get data
TTSPreloadPhraseData phraseData = voiceData.phrases[phraseIndex];
string title = $"{(phraseIndex+1)} - {phraseData.textToSpeak}";
// Foldout
GUILayout.BeginHorizontal();
bool show = WitEditorUI.LayoutFoldout(new GUIContent(title), phraseData);
if (!show)
{
GUILayout.EndHorizontal();
EditorGUI.indentLevel--;
return true;
}
// Delete
if (WitEditorUI.LayoutTextButton("Delete Phrase"))
{
voiceData.phrases = DeleteArrayItem<TTSPreloadPhraseData>(voiceData.phrases, phraseIndex);
GUILayout.EndHorizontal();
EditorGUI.indentLevel--;
updated = true;
return false;
}
// Begin phrase Data
GUILayout.EndHorizontal();
EditorGUI.indentLevel++;
// Phrase
bool phraseChange = false;
WitEditorUI.LayoutTextField(new GUIContent("Phrase"), ref phraseData.textToSpeak, ref phraseChange);
if (phraseChange)
{
TTSPreloadUtility.RefreshPhraseData(TtsService, new TTSDiskCacheSettings()
{
DiskCacheLocation = TTSDiskCacheLocation.Preload
}, TtsService?.GetPresetVoiceSettings(voiceData.presetVoiceID), phraseData);
updated = true;
}
// Clip
string clipID = phraseData.clipID;
WitEditorUI.LayoutTextField(new GUIContent("Clip ID"), ref clipID, ref phraseChange);
// State
Color col = GUI.color;
Color stateColor = Color.green;
string stateValue = "Downloaded";
if (!phraseData.downloaded)
{
if (phraseData.downloadProgress <= 0f)
{
stateColor = Color.red;
stateValue = "Missing";
}
else
{
stateColor = Color.yellow;
stateValue = $"Downloading {(phraseData.downloadProgress * 100f):00.0}%";
}
}
GUI.color = stateColor;
WitEditorUI.LayoutKeyLabel("State", stateValue);
GUI.color = col;
// End Phrase
EditorGUILayout.Space();
EditorGUI.indentLevel--;
EditorGUI.indentLevel--;
return true;
}
// Add
private T[] AddArrayItem<T>(T[] array, T item) => EditArray<T>(array, (l) => l.Add(item));
// Delete
private T[] DeleteArrayItem<T>(T[] array, int index) => EditArray<T>(array, (l) => l.RemoveAt(index));
// Edit array
private T[] EditArray<T>(T[] array, Action<List<T>> edit)
{
// Generate list
List<T> list = new List<T>();
// Add array to list
if (array != null)
{
list.AddRange(array);
}
// Call edit action
edit(list);
// Set to array
T[] result = list.ToArray();
// Refresh foldout value
WitEditorUI.SetFoldoutValue(result, WitEditorUI.GetFoldoutValue(array));
// Return array
return result;
}
//
private void AddVoice()
{
List<TTSPreloadVoiceData> voices = new List<TTSPreloadVoiceData>();
if (Settings?.data?.voices != null)
{
voices.AddRange(Settings.data.voices);
}
voices.Add(new TTSPreloadVoiceData()
{
presetVoiceID = _ttsVoiceIDs == null || _ttsVoiceIDs.Count == 0 ? "" : _ttsVoiceIDs[0],
phrases = new TTSPreloadPhraseData[] { new TTSPreloadPhraseData() }
});
Settings.data.voices = voices.ToArray();
}
// Delete voice
private void DeleteVoice(int index)
{
// Invalid
if (Settings?.data?.voices == null || index < 0 || index >= Settings.data.voices.Length)
{
return;
}
// Cancelled
if (!EditorUtility.DisplayDialog("Delete Voice?",
$"Are you sure you would like to remove voice data:\n#{(index + 1)} - {Settings.data.voices[index].presetVoiceID}?",
"Okay", "Cancel"))
{
return;
}
// Remove
List<TTSPreloadVoiceData> voices = new List<TTSPreloadVoiceData>(Settings.data.voices);
voices.RemoveAt(index);
Settings.data.voices = voices.ToArray();
}
// Get voice ids
private List<string> GetVoiceIDs(TTSService service)
{
List<string> results = new List<string>();
if (service != null)
{
foreach (var voiceSetting in service.GetAllPresetVoiceSettings())
{
if (voiceSetting != null && !string.IsNullOrEmpty(voiceSetting.settingsID) &&
!results.Contains(voiceSetting.settingsID))
{
results.Add(voiceSetting.settingsID);
}
}
}
return results;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: af9c44712a1f27646a9538dbb053e961
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,633 @@
/*
* 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 System.IO;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Meta.WitAi;
using Meta.WitAi.TTS.Data;
using Meta.WitAi.Data.Configuration;
using Meta.WitAi.Json;
using Meta.WitAi.TTS.Utilities;
using UnityEngine.SceneManagement;
namespace Meta.WitAi.TTS.Editor.Preload
{
public static class TTSPreloadUtility
{
#region MANAGEMENT
/// <summary>
/// Create a new preload settings asset by prompting a save location
/// </summary>
public static TTSPreloadSettings CreatePreloadSettings()
{
string savePath = WitConfigurationUtility.GetFileSaveDirectory("Save TTS Preload Settings", "TTSPreloadSettings", "asset");
return CreatePreloadSettings(savePath);
}
/// <summary>
/// Create a new preload settings asset at specified location
/// </summary>
public static TTSPreloadSettings CreatePreloadSettings(string savePath)
{
// Ignore if empty
if (string.IsNullOrEmpty(savePath))
{
return null;
}
// Get asset path
string assetPath = savePath.Replace("\\", "/");
if (!assetPath.StartsWith(Application.dataPath))
{
VLog.E(
$"TTS Preload Utility - Cannot Create Setting Outside of Assets Directory\nPath: {assetPath}");
return null;
}
assetPath = assetPath.Replace(Application.dataPath, "Assets");
// Generate & save
TTSPreloadSettings settings = ScriptableObject.CreateInstance<TTSPreloadSettings>();
AssetDatabase.CreateAsset(settings, assetPath);
AssetDatabase.SaveAssets();
// Reload & return
return AssetDatabase.LoadAssetAtPath<TTSPreloadSettings>(assetPath);
}
/// <summary>
/// Find all preload settings currently in the Assets directory
/// </summary>
public static TTSPreloadSettings[] GetPreloadSettings()
{
List<TTSPreloadSettings> results = new List<TTSPreloadSettings>();
string[] guids = AssetDatabase.FindAssets("t:TTSPreloadSettings");
foreach (var guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
TTSPreloadSettings settings = AssetDatabase.LoadAssetAtPath<TTSPreloadSettings>(path);
results.Add(settings);
}
return results.ToArray();
}
#endregion
#region ITERATE
// Performer
public static CoroutineUtility.CoroutinePerformer _performer;
//
public delegate IEnumerator TTSPreloadIterateDelegate(TTSService service, TTSDiskCacheSettings cacheSettings, TTSVoiceSettings voiceSettings, TTSPreloadPhraseData phraseData, Action<float> onProgress, Action<string> onComplete);
// Iterating
public static bool IsIterating()
{
return _performer != null;
}
// Perform a check of all data
private static bool CheckIterateData(TTSService service, TTSPreloadData preloadData, TTSPreloadIterateDelegate onIterate, Action<float> onProgress, Action<string> onComplete)
{
// No service
if (service == null)
{
onProgress?.Invoke(1f);
onComplete?.Invoke("\nNo TTSService found in current scene");
return false;
}
// No preload data
if (preloadData == null)
{
onProgress?.Invoke(1f);
onComplete?.Invoke("\nTTS Preload Data Not Found");
return false;
}
// No preload data
if (preloadData.voices == null)
{
onProgress?.Invoke(1f);
onComplete?.Invoke("\nTTS Preload Data Voices Not Found");
return false;
}
// Ignore if running
if (Application.isPlaying)
{
onProgress?.Invoke(1f);
onComplete?.Invoke("Cannot preload while running");
return false;
}
// Ignore if running
if (onIterate == null)
{
onProgress?.Invoke(1f);
onComplete?.Invoke("Code recompiled mid update");
return false;
}
return true;
}
// Iterate phrases
private static void IteratePhrases(TTSService service, TTSPreloadData preloadData, TTSPreloadIterateDelegate onIterate, Action<float> onProgress, Action<string> onComplete)
{
// Skip if check fails
if (!CheckIterateData(service, preloadData, onIterate, onProgress, onComplete))
{
return;
}
// Unload previous coroutine performer
if (_performer != null)
{
_performer.gameObject.DestroySafely();
_performer = null;
}
// Run new coroutine
_performer = CoroutineUtility.StartCoroutine(PerformIteratePhrases(service, preloadData, onIterate, onProgress, onComplete));
}
// Perform iterate
private static IEnumerator PerformIteratePhrases(TTSService service, TTSPreloadData preloadData, TTSPreloadIterateDelegate onIterate, Action<float> onProgress, Action<string> onComplete)
{
// Get cache settings
TTSDiskCacheSettings cacheSettings = new TTSDiskCacheSettings()
{
DiskCacheLocation = TTSDiskCacheLocation.Preload
};
// Get total phrases
int phraseTotal = 0;
foreach (var voice in preloadData.voices)
{
if (voice.phrases == null)
{
continue;
}
foreach (var phrase in voice.phrases)
{
phraseTotal++;
}
}
// Begin
onProgress?.Invoke(0f);
// Iterate
int phraseCount = 0;
float phraseInc = 1f / (float)phraseTotal;
string log = string.Empty;
for (int v = 0; v < preloadData.voices.Length; v++)
{
// Get voice data
TTSPreloadVoiceData voiceData = preloadData.voices[v];
if (voiceData.phrases == null)
{
continue;
}
// Get voice
TTSVoiceSettings voiceSettings = service.GetPresetVoiceSettings(voiceData.presetVoiceID);
if (voiceSettings == null)
{
log += "\n-Missing Voice Setting: " + voiceData.presetVoiceID;
phraseCount += voiceData.phrases.Length;
continue;
}
// Iterate phrases
for (int p = 0; p < voiceData.phrases.Length; p++)
{
// Iterate progress
float progress = (float) phraseCount / (float) phraseTotal;
onProgress?.Invoke(progress);
phraseCount++;
// Iterate Load
yield return onIterate(service, cacheSettings, voiceSettings, voiceData.phrases[p],
(p2) => onProgress?.Invoke(progress + p2 * phraseInc), (l) => log += l);
// Skip if check fails
if (!CheckIterateData(service, preloadData, onIterate, onProgress, onComplete))
{
yield break;
}
}
}
// Complete
onProgress?.Invoke(1f);
onComplete?.Invoke(log);
}
#endregion
#region PRELOAD
// Can preload data
public static bool CanPreloadData()
{
return TTSService.Instance != null;
}
// Preload from data
public static void PreloadData(TTSService service, TTSPreloadData preloadData, Action<float> onProgress, Action<TTSPreloadData, string> onComplete)
{
IteratePhrases(service, preloadData, PreloadPhraseData, onProgress, (l) => onComplete?.Invoke(preloadData, l));
}
// Preload voice text
private static IEnumerator PreloadPhraseData(TTSService service, TTSDiskCacheSettings cacheSettings, TTSVoiceSettings voiceSettings, TTSPreloadPhraseData phraseData, Action<float> onProgress, Action<string> onComplete)
{
// Begin running
bool running = true;
// Download
string log = string.Empty;
service.DownloadToDiskCache(phraseData.textToSpeak, string.Empty, voiceSettings, cacheSettings, delegate(TTSClipData data, string path, string error)
{
// Set phrase data
phraseData.clipID = data.clipID;
phraseData.downloaded = string.IsNullOrEmpty(error);
// Failed
if (!phraseData.downloaded)
{
log += $"\n-{voiceSettings.settingsID} Preload Failed: {phraseData.textToSpeak}";
}
// Next
running = false;
});
// Wait for running to complete
while (running)
{
//Debug.Log($"Preload Wait: {voiceSettings.settingsID} - {phraseData.textToSpeak}");
yield return null;
}
// Invoke
onComplete?.Invoke(log);
}
#endregion
#region REFRESH
// Refresh
public static void RefreshPreloadData(TTSService service, TTSPreloadData preloadData, Action<float> onProgress, Action<TTSPreloadData, string> onComplete)
{
IteratePhrases(service, preloadData, RefreshPhraseData, onProgress, (l) => onComplete?.Invoke(preloadData, l));
}
// Refresh
private static IEnumerator RefreshPhraseData(TTSService service, TTSDiskCacheSettings cacheSettings, TTSVoiceSettings voiceSettings, TTSPreloadPhraseData phraseData, Action<float> onProgress, Action<string> onComplete)
{
RefreshPhraseData(service, cacheSettings, voiceSettings, phraseData);
yield return null;
onComplete?.Invoke(string.Empty);
}
// Refresh phrase data
public static void RefreshVoiceData(TTSService service, TTSPreloadVoiceData voiceData, TTSDiskCacheSettings cacheSettings, ref string log)
{
// Get voice settings
if (service == null)
{
log += "\n-No TTS service found";
return;
}
// No voice data
if (voiceData == null)
{
log += "\n-No voice data provided";
return;
}
// Get voice
TTSVoiceSettings voiceSettings = service.GetPresetVoiceSettings(voiceData.presetVoiceID);
if (voiceSettings == null)
{
log += "\n-Missing Voice Setting: " + voiceData.presetVoiceID;
return;
}
// Generate
if (cacheSettings == null)
{
cacheSettings = new TTSDiskCacheSettings()
{
DiskCacheLocation = TTSDiskCacheLocation.Preload
};
}
// Iterate phrases
for (int p = 0; p < voiceData.phrases.Length; p++)
{
RefreshPhraseData(service, cacheSettings, voiceSettings, voiceData.phrases[p]);
}
}
// Refresh phrase data
public static void RefreshPhraseData(TTSService service, TTSDiskCacheSettings cacheSettings, TTSVoiceSettings voiceSettings, TTSPreloadPhraseData phraseData)
{
// Get voice settings
if (service == null || voiceSettings == null || string.IsNullOrEmpty(phraseData.textToSpeak))
{
phraseData.clipID = string.Empty;
phraseData.downloaded = false;
phraseData.downloadProgress = 0f;
return;
}
if (cacheSettings == null)
{
cacheSettings = new TTSDiskCacheSettings()
{
DiskCacheLocation = TTSDiskCacheLocation.Preload
};
}
// Get phrase data
phraseData.clipID = service.GetClipID(phraseData.textToSpeak, voiceSettings);
// Check if file exists
string path = service.GetDiskCachePath(phraseData.textToSpeak, phraseData.clipID, voiceSettings, cacheSettings);
phraseData.downloaded = File.Exists(path);
phraseData.downloadProgress = phraseData.downloaded ? 1f : 0f;
}
#endregion
#region DELETE
// Clear all clips in a tts preload file
public static void DeleteData(TTSService service)
{
// Get test file path
string path = service.GetDiskCachePath(string.Empty, "TEST", null, new TTSDiskCacheSettings()
{
DiskCacheLocation = TTSDiskCacheLocation.Preload
});
// Get directory
string directory = new FileInfo(path).DirectoryName;
if (!Directory.Exists(directory))
{
return;
}
// Ask
if (!EditorUtility.DisplayDialog("Delete Preload Cache",
$"Are you sure you would like to delete the TTS Preload directory at:\n{directory}?", "Okay", "Cancel"))
{
return;
}
// Delete recursively
Directory.Delete(directory, true);
// Delete meta
string meta = directory + ".meta";
if (File.Exists(meta))
{
File.Delete(meta);
}
// Refresh assets
AssetDatabase.Refresh();
}
#endregion
#region IMPORT
/// <summary>
/// Prompt user for a json file to be imported into an existing TTSPreloadSettings asset
/// </summary>
public static bool ImportData(TTSPreloadSettings preloadSettings)
{
// Select a file
string textFilePath = EditorUtility.OpenFilePanel("Select TTS Preload Json", Application.dataPath, "json");
if (string.IsNullOrEmpty(textFilePath))
{
return false;
}
// Import with selected file path
return ImportData(preloadSettings, textFilePath);
}
/// <summary>
/// Imported json data into an existing TTSPreloadSettings asset
/// </summary>
public static bool ImportData(TTSPreloadSettings preloadSettings, string textFilePath)
{
// Check for file
if (!File.Exists(textFilePath))
{
VLog.E($"TTS Preload Utility - Preload file does not exist\nPath: {textFilePath}");
return false;
}
// Load file
string textFileContents = File.ReadAllText(textFilePath);
if (string.IsNullOrEmpty(textFileContents))
{
VLog.E($"TTS Preload Utility - Preload file load failed\nPath: {textFilePath}");
return false;
}
// Parse file
WitResponseNode node = WitResponseNode.Parse(textFileContents);
if (node == null)
{
VLog.E($"TTS Preload Utility - Preload file parse failed\nPath: {textFilePath}");
return false;
}
// Iterate children for texts
WitResponseClass data = node.AsObject;
Dictionary<string, List<string>> textsByVoice = new Dictionary<string, List<string>>();
foreach (var voiceName in data.ChildNodeNames)
{
// Get texts list
List<string> texts;
if (textsByVoice.ContainsKey(voiceName))
{
texts = textsByVoice[voiceName];
}
else
{
texts = new List<string>();
}
// Add text phrases
string[] voicePhrases = data[voiceName].AsStringArray;
if (voicePhrases != null)
{
foreach (var phrase in voicePhrases)
{
if (!string.IsNullOrEmpty(phrase) && !texts.Contains(phrase))
{
texts.Add(phrase);
}
}
}
// Apply
textsByVoice[voiceName] = texts;
}
// Import
return ImportData(preloadSettings, textsByVoice);
}
/// <summary>
/// Find all ITTSPhraseProviders loaded in scenes & generate
/// data file to import all phrases associated with the files.
/// </summary>
public static bool ImportPhrases(TTSPreloadSettings preloadSettings)
{
// Find phrase providers in all scenes
List<ITTSPhraseProvider> phraseProviders = new List<ITTSPhraseProvider>();
for (int s = 0; s < SceneManager.sceneCount; s++)
{
Scene scene = SceneManager.GetSceneAt(s);
foreach (var root in scene.GetRootGameObjects())
{
ITTSPhraseProvider[] found = root.GetComponentsInChildren<ITTSPhraseProvider>(true);
if (found != null)
{
phraseProviders.AddRange(found);
}
}
}
// Get all phrases by voice id
Dictionary<string, List<string>> textsByVoice = new Dictionary<string, List<string>>();
foreach (var phraseProvider in phraseProviders)
{
// Ignore if no voices are found
string[] voiceIds = phraseProvider.GetVoiceIds();
if (voiceIds == null || voiceIds.Length == 0)
{
continue;
}
// Iterate voice ids
foreach (var voiceId in voiceIds)
{
// Ignore empty voice id
if (string.IsNullOrEmpty(voiceId))
{
continue;
}
// Ignore if phrases are null
string[] phrases = phraseProvider.GetVoicePhrases(voiceId);
if (phrases == null || phrases.Length == 0)
{
continue;
}
// Get phrase list
List<string> voicePhrases;
if (textsByVoice.ContainsKey(voiceId))
{
voicePhrases = textsByVoice[voiceId];
}
else
{
voicePhrases = new List<string>();
}
// Append unique phrases
foreach (var phrase in phrases)
{
if (!string.IsNullOrEmpty(phrase) && !voicePhrases.Contains(phrase))
{
voicePhrases.Add(phrase);
}
}
// Apply phrase list
textsByVoice[voiceId] = voicePhrases;
}
}
// Import with data
return ImportData(preloadSettings, textsByVoice);
}
/// <summary>
/// Imported dictionary data into an existing TTSPreloadSettings asset
/// </summary>
public static bool ImportData(TTSPreloadSettings preloadSettings, Dictionary<string, List<string>> textsByVoice)
{
// Import
if (preloadSettings == null)
{
VLog.E("TTS Preload Utility - Import Failed - Null Preload Settings");
return false;
}
// Whether or not changed
bool changed = false;
// Generate if needed
if (preloadSettings.data == null)
{
preloadSettings.data = new TTSPreloadData();
changed = true;
}
// Begin voice list
List<TTSPreloadVoiceData> voices = new List<TTSPreloadVoiceData>();
if (preloadSettings.data.voices != null)
{
voices.AddRange(preloadSettings.data.voices);
}
// Iterate voice names
foreach (var voiceName in textsByVoice.Keys)
{
// Get voice index if possible
int voiceIndex = voices.FindIndex((v) => string.Equals(v.presetVoiceID, voiceName));
// Generate voice
TTSPreloadVoiceData voice;
if (voiceIndex == -1)
{
voice = new TTSPreloadVoiceData();
voice.presetVoiceID = voiceName;
voiceIndex = voices.Count;
voices.Add(voice);
}
// Use existing
else
{
voice = voices[voiceIndex];
}
// Get texts & phrases for current voice
List<string> texts = new List<string>();
List<TTSPreloadPhraseData> phrases = new List<TTSPreloadPhraseData>();
if (voice.phrases != null)
{
foreach (var phrase in voice.phrases)
{
if (!string.IsNullOrEmpty(phrase.textToSpeak) && !texts.Contains(phrase.textToSpeak))
{
texts.Add(phrase.textToSpeak);
phrases.Add(phrase);
}
}
}
// Get data
List<string> newTexts = textsByVoice[voiceName];
if (newTexts != null)
{
foreach (var newText in newTexts)
{
if (!string.IsNullOrEmpty(newText) && !texts.Contains(newText))
{
changed = true;
texts.Add(newText);
phrases.Add(new TTSPreloadPhraseData()
{
textToSpeak = newText
});
}
}
}
// Apply voice
voice.phrases = phrases.ToArray();
voices[voiceIndex] = voice;
}
// Apply data
if (changed)
{
preloadSettings.data.voices = voices.ToArray();
EditorUtility.SetDirty(preloadSettings);
}
// Return changed
return changed;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6428a97eb23d27b48bff4ecaa464004e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,262 @@
/*
* 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 Meta.WitAi.Data.Configuration;
using Meta.WitAi.TTS.Data;
using Meta.WitAi.TTS.Editor.Voices;
using Meta.WitAi.TTS.Integrations;
using Meta.WitAi.TTS.Utilities;
using Meta.WitAi;
using Meta.WitAi.Data.Info;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.TTS.Editor
{
public static class TTSEditorUtilities
{
// Default TTS Setup
public static Transform CreateDefaultSetup()
{
// Generate parent
Transform parent = GenerateGameObject("TTS").transform;
// Add TTS Service
TTSService service = CreateService(parent);
// Add TTS Speaker
CreateSpeaker(parent, service);
// Select parent
Selection.activeObject = parent.gameObject;
return parent;
}
// Default TTS Service
public static TTSService CreateService(Transform parent = null, bool ignoreErrors = false)
{
// Get parent
if (parent == null)
{
Transform selected = Selection.activeTransform;
if (selected != null && selected.gameObject.scene.rootCount > 0)
{
parent = Selection.activeTransform;
}
}
// Ignore if found
TTSService instance = GameObject.FindObjectOfType<TTSService>();
if (instance != null)
{
// Log
if (!ignoreErrors)
{
VLog.W($"TTS Service - A TTSService is already in scene\nGameObject: {instance.gameObject.name}");
}
// Move into parent
if (parent != null)
{
instance.transform.SetParent(parent, true);
}
}
// Generate TTSWit
else
{
instance = CreateWitService(parent);
}
// Select & return instance
Selection.activeObject = instance.gameObject;
return instance;
}
// Default TTS Service
private static TTSWit CreateWitService(Transform parent = null)
{
// Generate new TTSWit & add caches
TTSWit ttsWit = GenerateGameObject("TTSWitService", parent).AddComponent<TTSWit>();
ttsWit.gameObject.AddComponent<TTSRuntimeCache>();
ttsWit.gameObject.AddComponent<TTSDiskCache>();
VLog.D($"TTS Service - Instantiated Service {ttsWit.gameObject.name}");
// Refresh configuration
WitConfiguration configuration = SetupConfiguration(ttsWit);
if (configuration != null)
{
RefreshAvailableVoices(ttsWit);
}
// Log
return ttsWit;
}
// Wit configuration
private static WitConfiguration SetupConfiguration(TTSService instance)
{
// Ignore non-tts wit
if (instance.GetType() != typeof(TTSWit))
{
return null;
}
// Already setup
TTSWit ttsWit = instance as TTSWit;
if (ttsWit.RequestSettings.configuration != null)
{
return ttsWit.RequestSettings.configuration;
}
// Refresh configuration list
if (WitConfigurationUtility.WitConfigs == null)
{
WitConfigurationUtility.ReloadConfigurationData();
}
// Assign first wit configuration found
if (WitConfigurationUtility.WitConfigs != null && WitConfigurationUtility.WitConfigs.Length > 0)
{
ttsWit.RequestSettings.configuration = WitConfigurationUtility.WitConfigs[0];
VLog.D($"TTS Service - Assigned Wit Configuration {ttsWit.RequestSettings.configuration.name}");
}
// Warning
if (ttsWit.RequestSettings.configuration == null)
{
VLog.W($"TTS Service - Please create and assign a WitConfiguration to TTSWit");
}
// Return configuration
return ttsWit.RequestSettings.configuration;
}
// Refresh available voices
private static void RefreshAvailableVoices(TTSWit ttsWit)
{
// Fail without configuration
if (ttsWit == null)
{
VLog.W($"TTS Service - Cannot refresh voices without TTS Wit Service");
return;
}
IWitRequestConfiguration configuration = ttsWit.RequestSettings.configuration;
if (configuration == null)
{
VLog.W($"TTS Service - Cannot refresh voices without TTS Wit Configuration");
return;
}
// Get application info
WitAppInfo appInfo = configuration.GetApplicationInfo();
if (appInfo.voices == null || appInfo.voices.Length == 0)
{
VLog.W($"TTS Service - No voices found");
if (ttsWit.PresetVoiceSettings == null || ttsWit.PresetVoiceSettings.Length == 0)
{
WitVoiceInfo voiceInfo = new WitVoiceInfo()
{
name = TTSWitVoiceSettings.DEFAULT_VOICE,
};
TTSWitVoiceSettings placeholder = GetDefaultVoiceSetting(voiceInfo);
ttsWit.SetVoiceSettings(new TTSWitVoiceSettings[] { placeholder });
}
}
// Reset list of voices
else
{
WitVoiceInfo[] voices = appInfo.voices;
TTSWitVoiceSettings[] newSettings = new TTSWitVoiceSettings[voices.Length];
for (int i = 0; i < voices.Length; i++)
{
newSettings[i] = GetDefaultVoiceSetting(voices[i]);
}
ttsWit.SetVoiceSettings(newSettings);
VLog.D($"TTS Service - Successfully applied {voices.Length} voices to {ttsWit.gameObject.name}");
}
// Refresh
RefreshEmptySpeakers(ttsWit);
}
// Set all blank IDs to default voice id
private static void RefreshEmptySpeakers(TTSService service)
{
string defaultVoiceID = service.VoiceProvider.VoiceDefaultSettings.settingsID;
foreach (var speaker in GameObject.FindObjectsOfType<TTSSpeaker>())
{
if (string.IsNullOrEmpty(speaker.presetVoiceID) || string.Equals(speaker.presetVoiceID, TTSVoiceSettings.DEFAULT_ID))
{
speaker.presetVoiceID = defaultVoiceID;
}
}
}
// Get default voice settings
private static TTSWitVoiceSettings GetDefaultVoiceSetting(WitVoiceInfo voiceData)
{
TTSWitVoiceSettings result = new TTSWitVoiceSettings()
{
settingsID = voiceData.name.ToUpper(),
voice = voiceData.name
};
// Use first style provided
if (voiceData.styles != null && voiceData.styles.Length > 0)
{
result.style = voiceData.styles[0];
}
return result;
}
// Default TTS Speaker
public static TTSSpeaker CreateSpeaker(Transform parent = null, TTSService service = null)
{
// Get parent
if (parent == null)
{
Transform selected = Selection.activeTransform;
if (selected != null && selected.gameObject.scene.rootCount > 0)
{
parent = Selection.activeTransform;
}
}
// Generate service if possible
if (service == null)
{
service = CreateService(parent);
}
// TTS Speaker
string goName = typeof(TTSSpeaker).Name;
TTSSpeaker speaker = GenerateGameObject(goName, parent).AddComponent<TTSSpeaker>();
speaker.presetVoiceID = string.Empty;
// Audio Source
AudioSource audio = GenerateGameObject($"{goName}Audio", speaker.transform).AddComponent<AudioSource>();
audio.playOnAwake = false;
audio.loop = false;
audio.spatialBlend = 0f; // Default to 2D
speaker.AudioSource = audio;
// Return speaker
VLog.D($"TTS Service - Instantiated Speaker {speaker.gameObject.name}");
Selection.activeObject = speaker.gameObject;
return speaker;
}
// Generate with specified name
private static GameObject GenerateGameObject(string name, Transform parent = null)
{
Transform result = new GameObject(name).transform;
result.SetParent(parent);
result.localPosition = Vector3.zero;
result.localRotation = Quaternion.identity;
result.localScale = Vector3.one;
return result.gameObject;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c590c0f8426e4194db6efc14c68db75c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,117 @@
/*
* 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 Meta.WitAi.TTS.Data;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.TTS.Editor
{
[CustomEditor(typeof(TTSService), true)]
public class TTSServiceInspector : UnityEditor.Editor
{
// Service
private TTSService _service;
// Dropdown
private bool _clipFoldout = false;
// Maximum text for abbreviated
private const int MAX_DISPLAY_TEXT = 20;
// GUI
public override void OnInspectorGUI()
{
// Display default ui
base.OnInspectorGUI();
// Get service
if (_service == null)
{
_service = target as TTSService;
}
// Ignore if in editor
if (!Application.isPlaying)
{
return;
}
// Add spaces
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Runtime Clip Cache", EditorStyles.boldLabel);
// No clips
TTSClipData[] clips = _service.GetAllRuntimeCachedClips();
if (clips == null || clips.Length == 0)
{
WitEditorUI.LayoutErrorLabel("No clips found");
return;
}
// Has clips
_clipFoldout = WitEditorUI.LayoutFoldout(new GUIContent($"Clips: {clips.Length}"), _clipFoldout);
if (_clipFoldout)
{
EditorGUI.indentLevel++;
// Iterate clips
foreach (TTSClipData clip in clips)
{
// Get display name
string displayName = clip.textToSpeak;
// Crop if too long
if (displayName.Length > MAX_DISPLAY_TEXT)
{
displayName = displayName.Substring(0, MAX_DISPLAY_TEXT);
}
// Add voice setting id
if (clip.voiceSettings != null)
{
displayName = $"{clip.voiceSettings.settingsID} - {displayName}";
}
// Foldout if desired
bool foldout = WitEditorUI.LayoutFoldout(new GUIContent(displayName), clip);
if (foldout)
{
EditorGUI.indentLevel++;
DrawClipGUI(clip);
EditorGUI.indentLevel--;
}
}
EditorGUI.indentLevel--;
}
}
// Clip data
public static void DrawClipGUI(TTSClipData clip)
{
// Generation Settings
WitEditorUI.LayoutKeyLabel("Text", clip.textToSpeak);
EditorGUILayout.TextField("Clip ID", clip.clipID);
EditorGUILayout.ObjectField("Clip", clip.clip, typeof(AudioClip), true);
// Loaded
TTSClipLoadState loadState = clip.loadState;
if (loadState != TTSClipLoadState.Preparing)
{
WitEditorUI.LayoutKeyLabel("Load State", loadState.ToString());
}
// Loading with progress
else
{
EditorGUILayout.BeginHorizontal();
int loadProgress = Mathf.FloorToInt(clip.loadProgress * 100f);
WitEditorUI.LayoutKeyLabel("Load State", $"{loadState} ({loadProgress}%)");
GUILayout.HorizontalSlider(loadProgress, 0, 100);
EditorGUILayout.EndHorizontal();
}
// Additional Settings
WitEditorUI.LayoutKeyObjectLabels("Voice Settings", clip.voiceSettings);
WitEditorUI.LayoutKeyObjectLabels("Cache Settings", clip.diskCacheSettings);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a7b031cd5a557e14fa08e59b869a2e78
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,171 @@
/*
* 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 UnityEditor;
using UnityEngine;
using Meta.WitAi.TTS.Utilities;
using Meta.WitAi.TTS.Data;
namespace Meta.WitAi.TTS.Editor
{
[CustomEditor(typeof(TTSSpeaker), true)]
public class TTSSpeakerInspector : UnityEditor.Editor
{
// Speaker
private TTSSpeaker _speaker;
// Voices
private int _voiceIndex = -1;
private string[] _voices = null;
// Voice text
private const string UI_VOICE_HEADER = "Voice Settings";
private const string UI_VOICE_KEY = "Voice Preset";
// GUI
public override void OnInspectorGUI()
{
// Get speaker
if (_speaker == null)
{
_speaker = target as TTSSpeaker;
}
// Get voices
if (_voices == null || (_voiceIndex >= 0 && _voiceIndex < _voices.Length && !string.Equals(_speaker.presetVoiceID, _voices[_voiceIndex])))
{
RefreshVoices();
}
// Voice select
EditorGUILayout.LabelField(UI_VOICE_HEADER, EditorStyles.boldLabel);
// No voices found
if (_voices == null || _voices.Length == 0)
{
EditorGUILayout.TextField(UI_VOICE_KEY, _speaker.presetVoiceID);
}
// Voice dropdown
else
{
bool updated = false;
WitEditorUI.LayoutPopup(UI_VOICE_KEY, _voices, ref _voiceIndex, ref updated);
if (updated)
{
string newVoiceID = _voiceIndex >= 0 && _voiceIndex < _voices.Length
? _voices[_voiceIndex]
: string.Empty;
_speaker.presetVoiceID = newVoiceID;
EditorUtility.SetDirty(_speaker);
}
}
// Display default ui
EditorGUILayout.Space();
EditorGUILayout.Space();
base.OnInspectorGUI();
// Layout TTS clip queue
LayoutClipQueue();
}
// Layout clip queue
private const string UI_CLIP_HEADER_TEXT = "Clip Queue";
private const string UI_CLIP_SPEAKER_TEXT = "Speaker Clip:";
private const string UI_CLIP_QUEUE_TEXT = "Loading Clips:";
private bool _speakerFoldout = false;
private bool _queueFoldout = false;
private void LayoutClipQueue()
{
// Ignore unless playing
if (!Application.isPlaying)
{
return;
}
// Add header
EditorGUILayout.Space();
EditorGUILayout.LabelField(UI_CLIP_HEADER_TEXT, EditorStyles.boldLabel);
// Speaker Foldout
_speakerFoldout = EditorGUILayout.Foldout(_speakerFoldout, UI_CLIP_SPEAKER_TEXT);
if (_speakerFoldout)
{
EditorGUI.indentLevel++;
if (!_speaker.IsSpeaking)
{
EditorGUILayout.LabelField("None");
}
else
{
TTSServiceInspector.DrawClipGUI(_speaker.SpeakingClip);
}
EditorGUI.indentLevel--;
}
// Queue Foldout
TTSClipData[] QueuedClips = _speaker.QueuedClips;
_queueFoldout = EditorGUILayout.Foldout(_queueFoldout, $"{UI_CLIP_QUEUE_TEXT} {(QueuedClips == null ? 0 : QueuedClips.Length)}");
if (_queueFoldout)
{
EditorGUI.indentLevel++;
if (QueuedClips == null || QueuedClips.Length == 0)
{
EditorGUILayout.LabelField("None");
}
else
{
for (int i = 0; i < QueuedClips.Length; i++)
{
TTSClipData clipData = QueuedClips[i];
bool oldFoldout = WitEditorUI.GetFoldoutValue(clipData);
bool newFoldout = EditorGUILayout.Foldout(oldFoldout, $"Clip[{i}]");
if (oldFoldout != newFoldout)
{
WitEditorUI.SetFoldoutValue(clipData, newFoldout);
}
if (newFoldout)
{
EditorGUI.indentLevel++;
TTSServiceInspector.DrawClipGUI(clipData);
EditorGUI.indentLevel--;
}
}
}
EditorGUI.indentLevel--;
}
}
// Refresh voices
private void RefreshVoices()
{
// Reset voice data
_voiceIndex = -1;
_voices = null;
// Get settings
TTSService tts = TTSService.Instance;
TTSVoiceSettings[] settings = tts?.GetAllPresetVoiceSettings();
if (settings == null)
{
VLog.E("No Preset Voice Settings Found!");
return;
}
// Apply all settings
_voices = new string[settings.Length];
for (int i = 0; i < settings.Length; i++)
{
_voices[i] = settings[i].settingsID;
if (string.Equals(_speaker.presetVoiceID, _voices[i], StringComparison.CurrentCultureIgnoreCase))
{
_voiceIndex = i;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3835212f72d4d5149bed0f07915f204e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 69fad6077e2eeef4a812dc81d313fc2a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
/*
* 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;
namespace Oculus.Interaction.Deprecated
{
[Obsolete("Replaced by Meta.WitAi.Data.Lib.WitVoiceInfo")]
public class TTSWitVoiceData { }
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0b485971ba702574fa0f255d17bbc46f
MonoImporter:
labels: ["oculus_interaction_deprecated"]
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,248 @@
/*
* 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.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using Meta.WitAi.TTS.Integrations;
using Meta.WitAi.Windows;
using Meta.WitAi.Data.Info;
using Meta.WitAi.Lib;
using Meta.WitAi.Data.Configuration;
using UnityEngine;
namespace Meta.WitAi.TTS.Editor.Voices
{
[CustomPropertyDrawer(typeof( TTSWitVoiceSettings))]
public class TTSWitVoiceSettingsDrawer : PropertyDrawer
{
// Constants for var layout
private const float VAR_HEIGHT = 20f;
private const float VAR_MARGIN = 4f;
// Constants for var lookup
private const string VAR_SETTINGS = "settingsID";
private const string VAR_VOICE = "voice";
private const string VAR_STYLE = "style";
// Voice data
private IWitRequestConfiguration _configuration;
private bool _configUpdating;
private WitVoiceInfo[] _voices;
private string[] _voiceNames;
// Subfields
private static readonly FieldInfo[] _fields = FieldGUI.GetFields(typeof( TTSWitVoiceSettings));
// Determine height
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
// Property
if (!property.isExpanded)
{
return VAR_HEIGHT;
}
// Add each
int total = _fields.Length + 1;
int voiceIndex = GetVoiceIndex(property);
if (voiceIndex != -1)
{
total += 2;
}
return total * VAR_HEIGHT + Mathf.Max(0, total - 1) * VAR_MARGIN;
}
// Handles gui layout
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// On gui
float y = position.y;
string voiceName = property.FindPropertyRelative(VAR_SETTINGS).stringValue;
property.isExpanded =
EditorGUI.Foldout(new Rect(position.x, y, position.width, VAR_HEIGHT), property.isExpanded, voiceName);
if (!property.isExpanded)
{
return;
}
y += VAR_HEIGHT + VAR_MARGIN;
// Increment
EditorGUI.indentLevel++;
// Refresh voices if needed
RefreshVoices(property);
// Get voice index
int voiceIndex = GetVoiceIndex(property);
// Iterate subfields
for (int s = 0; s < _fields.Length; s++)
{
FieldInfo subfield = _fields[s];
SerializedProperty subfieldProperty = property.FindPropertyRelative(subfield.Name);
Rect subfieldRect = new Rect(position.x, y, position.width, VAR_HEIGHT);
if (string.Equals(subfield.Name, VAR_VOICE) && voiceIndex != -1)
{
int newVoiceIndex = EditorGUI.Popup(subfieldRect, subfieldProperty.displayName, voiceIndex,
_voiceNames);
newVoiceIndex = Mathf.Clamp(newVoiceIndex, 0, _voiceNames.Length);
if (voiceIndex != newVoiceIndex)
{
voiceIndex = newVoiceIndex;
subfieldProperty.stringValue = _voiceNames[voiceIndex];
GUI.FocusControl(null);
}
y += VAR_HEIGHT + VAR_MARGIN;
continue;
}
if (string.Equals(subfield.Name, VAR_STYLE) && voiceIndex >= 0 && voiceIndex < _voices.Length)
{
// Get voice data
WitVoiceInfo voiceInfo = _voices[voiceIndex];
EditorGUI.indentLevel++;
// Locale layout
EditorGUI.LabelField(subfieldRect, "Locale", voiceInfo.locale);
y += VAR_HEIGHT + VAR_MARGIN;
// Gender layout
subfieldRect = new Rect(position.x, y, position.width, VAR_HEIGHT);
EditorGUI.LabelField(subfieldRect, "Gender", voiceInfo.gender);
y += VAR_HEIGHT + VAR_MARGIN;
// Style layout/select
subfieldRect = new Rect(position.x, y, position.width, VAR_HEIGHT);
if (voiceInfo.styles != null && voiceInfo.styles.Length > 0)
{
// Get style index
string style = subfieldProperty.stringValue;
int styleIndex = new List<string>(voiceInfo.styles).IndexOf(style);
// Show style select
int newStyleIndex = EditorGUI.Popup(subfieldRect, subfieldProperty.displayName, styleIndex,
voiceInfo.styles);
newStyleIndex = Mathf.Clamp(newStyleIndex, 0, voiceInfo.styles.Length);
if (styleIndex != newStyleIndex)
{
// Apply style
styleIndex = newStyleIndex;
subfieldProperty.stringValue = voiceInfo.styles[styleIndex];
GUI.FocusControl(null);
}
// Move down
y += VAR_HEIGHT + VAR_MARGIN;
EditorGUI.indentLevel--;
continue;
}
// Undent
EditorGUI.indentLevel--;
}
// Default layout
EditorGUI.PropertyField(subfieldRect, subfieldProperty, new GUIContent(subfieldProperty.displayName));
// Clamp in between range
RangeAttribute range = subfield.GetCustomAttribute<RangeAttribute>();
if (range != null)
{
int newValue = Mathf.Clamp(subfieldProperty.intValue, (int)range.min, (int)range.max);
if (subfieldProperty.intValue != newValue)
{
subfieldProperty.intValue = newValue;
}
}
// Increment
y += VAR_HEIGHT + VAR_MARGIN;
}
// Undent
EditorGUI.indentLevel--;
}
// Refresh voices
private void RefreshVoices(SerializedProperty property)
{
// Get tts wit if possible
object targetObject = property.serializedObject.targetObject;
if (targetObject == null || targetObject.GetType() != typeof(TTSWit))
{
return;
}
// Get configuration
TTSWit wit = property.serializedObject.targetObject as TTSWit;
IWitRequestConfiguration configuration = wit.RequestSettings.configuration;
// Set configuration
if (_configuration != configuration)
{
_configuration = configuration;
_voices = null;
_voiceNames = null;
_configUpdating = false;
}
// Ignore if null
if (configuration == null)
{
return;
}
// Ignore if already set up
if (_voices != null && _voiceNames != null && !_configUpdating)
{
return;
}
// Get voices
_voices = configuration.GetApplicationInfo().voices;
_voiceNames = _voices?.Select(voice => voice.name).ToArray();
// Voices found!
if (_voices != null && _voices.Length > 0)
{
_configUpdating = false;
}
// Configuration needs voices, perform update
else if (!_configUpdating)
{
// Perform update if possible
if (_configuration is WitConfiguration witConfig && !witConfig.IsUpdatingData())
{
witConfig.RefreshAppInfo();
}
// Now updating
_configUpdating = true;
}
}
// Get voice index
private int GetVoiceIndex(SerializedProperty property)
{
SerializedProperty voiceProperty = property.FindPropertyRelative(VAR_VOICE);
string voiceID = voiceProperty.stringValue;
int voiceIndex = -1;
List<string> voiceNames = new List<string>();
if (_voiceNames != null)
{
voiceNames.AddRange(_voiceNames);
}
if (voiceNames.Count > 0)
{
if (string.IsNullOrEmpty(voiceID))
{
voiceIndex = 0;
voiceID = voiceNames[0];
voiceProperty.stringValue = voiceID;
GUI.FocusControl(null);
}
else
{
voiceIndex = voiceNames.IndexOf(voiceID);
}
}
return voiceIndex;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0bf9132926065a54da619451f5258d3e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
/*
* 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;
namespace Oculus.Interaction.Deprecated
{
[Obsolete("Handled by Meta.WitAi.WitAppInfoUtility")]
public class TTSWitVoiceUtility { }
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ca11f6ef3c756c64dbbf6d74fdd4c954
MonoImporter:
labels: ["oculus_interaction_deprecated"]
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8c945bb3fb3322b4eb73aba670cad74a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f4d30ee47fb6e7d4a888e9ee4b707391
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,98 @@
/*
* 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.Generic;
using UnityEngine;
namespace Meta.WitAi.TTS.Data
{
// Various request load states
public enum TTSClipLoadState
{
Unloaded,
Preparing,
Loaded,
Error
}
[Serializable]
public class TTSClipData
{
// Text to be spoken
public string textToSpeak;
// Unique identifier
public string clipID;
// Audio type
public AudioType audioType;
// Voice settings for request
public TTSVoiceSettings voiceSettings;
// Cache settings for request
public TTSDiskCacheSettings diskCacheSettings;
// Request data
public Dictionary<string, string> queryParameters;
// Clip
[NonSerialized] public AudioClip clip;
// Clip load state
[NonSerialized] public TTSClipLoadState loadState;
// Clip load progress
[NonSerialized] public float loadProgress;
// On clip state change
public Action<TTSClipData, TTSClipLoadState> onStateChange;
/// <summary>
/// A callback when clip stream is ready
/// Returns an error if there was an issue
/// </summary>
public Action<string> onPlaybackReady;
/// <summary>
/// A callback when clip has downloaded successfully
/// Returns an error if there was an issue
/// </summary>
public Action<string> onDownloadComplete;
/// <summary>
/// Compare clips if possible
/// </summary>
public override bool Equals(object obj)
{
if (obj is TTSClipData other)
{
return Equals(other);
}
return false;
}
/// <summary>
/// Compare clip ids
/// </summary>
public bool Equals(TTSClipData other)
{
return HasClipId(other?.clipID);
}
/// <summary>
/// Compare clip ids
/// </summary>
public bool HasClipId(string clipId)
{
return string.Equals(clipID, clipId, StringComparison.CurrentCultureIgnoreCase);
}
/// <summary>
/// Get hash code
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
var hash = 17;
hash = hash * 31 + clipID.GetHashCode();
return hash;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef626b8cea4f59646a5076430a0e14aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,51 @@
/*
* 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;
namespace Meta.WitAi.TTS.Data
{
// TTS Cache disk location
public enum TTSDiskCacheLocation
{
/// <summary>
/// Does not cache
/// </summary>
Stream,
/// <summary>
/// Stores files in editor only & loads files from internal project location (Application.streamingAssetsPath)
/// </summary>
Preload,
/// <summary>
/// Stores files at persistent location (Application.persistentDataPath)
/// </summary>
Persistent,
/// <summary>
/// Stores files at temporary cache location (Application.temporaryCachePath)
/// </summary>
Temporary
}
[Serializable]
public class TTSDiskCacheSettings
{
/// <summary>
/// Where the TTS clip should be cached
/// </summary>
public TTSDiskCacheLocation DiskCacheLocation = TTSDiskCacheLocation.Stream;
/// <summary>
/// Where the TTS clip should streamed from cache
/// </summary>
public bool StreamFromDisk = false;
/// <summary>
/// Length of a streamed clip buffer in seconds
/// </summary>
public float StreamBufferLength = 5f;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a4d1170a24dd77d49bf3cd610dd1c9a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
/*
* 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.
*/
namespace Meta.WitAi.TTS.Data
{
public abstract class TTSVoiceSettings
{
// Used for initial value
public const string DEFAULT_ID = "Default Voice";
/// <summary>
/// The unique voice settings id
/// </summary>
public string settingsID = DEFAULT_ID;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5dbbd0a6d06807d4f8a3190785a267f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5a7b8f23689f0b94dbe6a9aae4811de6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
/*
* 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 Meta.WitAi.TTS.Data;
using UnityEngine;
using UnityEngine.Events;
namespace Meta.WitAi.TTS.Events
{
[Serializable]
public class TTSClipDownloadEvent : UnityEvent<TTSClipData, string>
{
}
[Serializable]
public class TTSClipDownloadErrorEvent : UnityEvent<TTSClipData, string, string>
{
}
[Serializable]
public class TTSDownloadEvents
{
[Tooltip("Called when a audio clip download begins")]
public TTSClipDownloadEvent OnDownloadBegin = new TTSClipDownloadEvent();
[Tooltip("Called when a audio clip is downloaded successfully")]
public TTSClipDownloadEvent OnDownloadSuccess = new TTSClipDownloadEvent();
[Tooltip("Called when a audio clip downloaded has been cancelled")]
public TTSClipDownloadEvent OnDownloadCancel = new TTSClipDownloadEvent();
[Tooltip("Called when a audio clip downloaded has failed")]
public TTSClipDownloadErrorEvent OnDownloadError = new TTSClipDownloadErrorEvent();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a8c6f2c6a5fdba344b75e8f613c5dc09
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
/*
* 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 UnityEngine;
namespace Meta.WitAi.TTS.Events
{
[Serializable]
public class TTSServiceEvents
{
[Tooltip("Called when a audio clip has been added to the runtime cache")]
public TTSClipEvent OnClipCreated = new TTSClipEvent();
[Tooltip("Called when a audio clip has been removed from the runtime cache")]
public TTSClipEvent OnClipUnloaded = new TTSClipEvent();
// Streaming events
public TTSStreamEvents Stream = new TTSStreamEvents();
// Download events
public TTSDownloadEvents Download = new TTSDownloadEvents();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a41b87319719e004da4ad59b6a70358d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,66 @@
/*
* 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 Meta.WitAi.Speech;
using UnityEngine;
using UnityEngine.Events;
using Meta.WitAi.TTS.Data;
namespace Meta.WitAi.TTS.Utilities
{
[Serializable]
public class TTSSpeakerEvent : UnityEvent<TTSSpeaker, string> { }
[Serializable]
public class TTSSpeakerClipDataEvent : UnityEvent<TTSClipData> { }
[Serializable]
public class TTSSpeakerEvents : VoiceSpeechEvents
{
[Header("Speaker Events")]
[Tooltip("Called when a speaking begins")]
public TTSSpeakerEvent OnStartSpeaking;
[Tooltip("Called when a speaking finishes")]
public TTSSpeakerEvent OnFinishedSpeaking;
[Tooltip("Called when a speaking is cancelled")]
public TTSSpeakerEvent OnCancelledSpeaking;
[Tooltip("Called when TTS audio clip load begins")]
public TTSSpeakerEvent OnClipLoadBegin;
[Tooltip("Called when TTS audio clip load fails")]
public TTSSpeakerEvent OnClipLoadFailed;
[Tooltip("Called when TTS audio clip load successfully")]
public TTSSpeakerEvent OnClipLoadSuccess;
[Tooltip("Called when TTS audio clip load is cancelled")]
public TTSSpeakerEvent OnClipLoadAbort;
[Header("TTSClip Data Events")]
[Tooltip("Called when a new clip is added to the playback queue")]
public TTSSpeakerClipDataEvent OnClipDataQueued;
[Tooltip("Called when TTS audio clip load begins")]
public TTSSpeakerClipDataEvent OnClipDataLoadBegin;
[Tooltip("Called when TTS audio clip load fails")]
public TTSSpeakerClipDataEvent OnClipDataLoadFailed;
[Tooltip("Called when TTS audio clip load successfully")]
public TTSSpeakerClipDataEvent OnClipDataLoadSuccess;
[Tooltip("Called when TTS audio clip load is cancelled")]
public TTSSpeakerClipDataEvent OnClipDataLoadAbort;
[Tooltip("Called when a clip is ready for playback")]
public TTSSpeakerClipDataEvent OnClipDataPlaybackReady;
[Tooltip("Called when a clip playback has begun")]
public TTSSpeakerClipDataEvent OnClipDataPlaybackStart;
[Tooltip("Called when a clip playback has completed successfully")]
public TTSSpeakerClipDataEvent OnClipDataPlaybackFinished;
[Tooltip("Called when a clip playback has been cancelled")]
public TTSSpeakerClipDataEvent OnClipDataPlaybackCancelled;
[Header("Queue Events")]
[Tooltip("Called when a tts request is added to an empty queue")]
public UnityEvent OnPlaybackQueueBegin;
[Tooltip("Called the final request is removed from a queue")]
public UnityEvent OnPlaybackQueueComplete;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f8f392c4b8438cd4e8a5318177de7a23
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More