Initial Commit

This commit is contained in:
2025-07-04 20:33:06 +03:00
commit 8f09347ae0
9219 changed files with 2447903 additions and 0 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bbef58853aa598f48a7c33ac1f6aee0f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8eb9498a67cb0d640aafac2c509b1272
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

@@ -0,0 +1,128 @@
fileFormatVersion: 2
guid: f9d0f3319db97e04181db42930d90a4f
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 4096
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 4096
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 4096
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 4096
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aabf1e81ff2442d499f8b3d7b9b8e340
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8848dd0aaf9c1cd49bd992656eebb954
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 64b5e4399ce1894409af2cf7dcab6365
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7913ff34317620543add7ccf91153f48
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f8a301fcccd2a404a9820dc1e9c0d5c3
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ce420a201d5144a44b4c15f1b9c4cff5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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>
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4b8f297a827717846a390137480216b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7000a4548ba72474f9222567d06a50fc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 110ee5aeb672b914bbc92f92061bcbd4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8f0c2fb9674b409c869f53df88912235
timeCreated: 1657568993
@@ -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();
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9809a25e34ab45d6a522b8f43e4c3703
timeCreated: 1657569002
@@ -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();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d481126888a4412939f6940b2fa3950
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b23994c7bbf9462ca7b6939d3d364e7c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 866a0a2cd26dd0c469bb96bf7be7ec27
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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>
{
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c8d63aebd47343999a855f5eff93e7a2
timeCreated: 1657570491
@@ -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
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 910a956078d2ff4429c717211dcfaecb
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,109 @@
using System;
using System.Text;
using Meta.WitAi.Events;
using UnityEngine;
namespace Meta.WitAi.Dictation
{
public class MultiRequestTranscription : MonoBehaviour
{
[SerializeField] private DictationService 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<DictationService>();
_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.DictationEvents.OnFullTranscription.AddListener(OnFullTranscription);
witDictation.DictationEvents.OnPartialTranscription.AddListener(OnPartialTranscription);
witDictation.DictationEvents.OnAborting.AddListener(OnCancelled);
}
private void OnDisable()
{
_activeText = string.Empty;
witDictation.DictationEvents.OnFullTranscription.RemoveListener(OnFullTranscription);
witDictation.DictationEvents.OnPartialTranscription.RemoveListener(OnPartialTranscription);
witDictation.DictationEvents.OnAborting.RemoveListener(OnCancelled);
}
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());
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a960272debaf35b4f8df9292e4191044
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3e507c9f16a2497a940845bf47606a99
timeCreated: 1656528581
@@ -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;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e2029a881fa07405c941899ca44707e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a487e94faee3e430989a08cd6d770e3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4398589986ec92e46a7e1585e63ff2a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cce4aa4005d374a4b94f0b4d6edc298d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e18f1785366987e4886fb11f30d70040
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cde9306012742314db5ada2fe0d9bff2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

@@ -0,0 +1,128 @@
fileFormatVersion: 2
guid: 701ca4114422ead418e08b1c0bc26348
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

@@ -0,0 +1,128 @@
fileFormatVersion: 2
guid: a3ec408155652024f94168a419eabdcc
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@@ -0,0 +1,128 @@
fileFormatVersion: 2
guid: 3387a752287aa7845892fd1c1ca0eb8f
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

@@ -0,0 +1,128 @@
fileFormatVersion: 2
guid: 45b126b5c88878b42840b8dd157251b6
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,40 @@
# Text-to-Speech Overview
## Overview
Voice SDKs Text-to-Speech (TTS) feature uses a Wit.ai based service to provide audio files for text strings. Its handled by a single TTSService prefab for all TTS settings and you can use a simple TTSSpeaker script for each scene location in which a TTS clip can be played.
To keep TTS working smoothly, Voice SDK handles the caching of TTS files during runtime (or when otherwise needed). If streaming TTS audio files is not an option for your application, however, you can set it to use preloaded static TTS files prior to building your app.
<b>Note:</b> With this initial release of TTS, only a few Wit.ai TTS voice settings are adjustable, but the package will be updated as more voices become available.
## Setup
Use the following steps to set up TTS for your app once the plugin has been imported:
1. Open the scene you want to use TTS within.
2. Generate a new Wit Configuration using the Wit Configurations menu within the Oculus > Voice SDK > Voice HUB. Ensure it refreshes successfully and displays all voices available for your configuration.
2. Navigate to Assets > Create > Voice SDK > TTS > Add Default TTS Setup
3. In your scene heirarchy navigate inside the newly generated TTS GameObject to select the TTSWitService gameobject and adjust the inspector to fit your needs:
3a. Use TTSWit > Request Settings > Configuration to select the Wit Configuration asset generated in step 2.
3b. Once your configuration is setup, go to 'Preset Voice Settings' and setup any voices that might be shared by multiple TTSSpeakers.
For more information, see TTS Voice Customization: https://developer.oculus.com/documentation/unity/voice-sdk-tts-voice-customization
![image](Images/tts_service_settings.png)
3c. Under TTS Runtime Cache (Script), adjust the settings to indicate how often clips will be automatically uploaded from memory.
For more information, see TTS Cache Options: https://developer.oculus.com/documentation/unity/voice-sdk-tts-cache-options
3d. If needed, adjust your disk cache directory location and name in the tree under TTS Disk Cache (Script).
For more information, see TTS Cache Options: https://developer.oculus.com/documentation/unity/voice-sdk-tts-cache-options/
![image](Images/tts_service_cachesettings.png)
4. Move & duplicate the TTSSpeaker to all the locations in your app where you would like TTS to be played.
5. Modify each TTSSpeaker via the Inspector to fit your needs:
5a. Under Voice Settings, select the Voice Preset for the specific speaker or select Custom to apply speaker specific settings.
5b. Adjust the AudioSource in order to add the TTSSpeaker to a custom audio group or set audio from 2D to 3D.
6. Via a script use the following TTSSpeaker methods to load and play text.
6a. Use the TTSSpeaker scripts Speak(textToSpeak : string) method to request and say specified text on load.
6b. Use the TTSSpeaker scripts SpeakQueued(textToSpeak : string) method to request and say specified text.
6c. Send a custom TTSSpeakerClipEvents into any Speak/SpeakQueued method for request specific text load & playback event callbacks.
6d. Use the TTSSpeaker scripts Stop() method to immediately stop all loading & playing TTS clips.
6e. Use TTSSpeaker's Stop(textToSpeak : string) to immediately stop loading & playing of a specific text string.
<b>Note:</b> Check out TTS/Samples/Scenes/TTSSample.unity for an example of TTS implementation. Ensure that you set your WitConfiguration to the sample prior to running.
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0a78e70d61637eb498ee552bab9479ab
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,19 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 98bfdca232b84c3db2527e4b5c9d3b9d, type: 3}
m_Name: TTS Overview Readme
m_EditorClassIdentifier:
_displayName: Overview
_prefix: Documentation/TTS/
_context: {fileID: 11400000, guid: f2e797de12b196c40ad409b92d6394fc, type: 2}
_markdownFile: {fileID: 4900000, guid: 0a78e70d61637eb498ee552bab9479ab, type: 3}
_priority: 200
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c745949bbb55f7b4dba6eeac61f4a7bd
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d5d4d513ffe662a4db92f38c8468357e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 68d2ecf49ba62e0408b8f86acb9b103c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 748ff8d1d0d4814429b86058a56a3ee4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5e581f7e133ba2048995048327a1ef85
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 466ea4f9ad1762f41a5effc0e1985b21
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b1da9fac71952343b124f3771afe034
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e31cc0253d8f956459091c800a16d68d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 716af1288c1a89d44950d38c999fe096
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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.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();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 80be64a601ff65e41b0a8036ba872084
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,481 @@
/*
* 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.TTS.Data;
using Meta.WitAi.Utilities;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.TTS.Preload
{
[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;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: af9c44712a1f27646a9538dbb053e961
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,632 @@
/*
* 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.TTS.Data;
using Meta.WitAi.Data.Configuration;
using Meta.WitAi.Json;
using Meta.WitAi.TTS.Utilities;
using UnityEngine.SceneManagement;
namespace Meta.WitAi.TTS.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
List<string> voiceIds = phraseProvider.GetVoiceIds();
if (voiceIds == null || voiceIds.Count == 0)
{
continue;
}
// Iterate voice ids
foreach (var voiceId in voiceIds)
{
// Ignore empty voice id
if (string.IsNullOrEmpty(voiceId))
{
continue;
}
// Ignore if phrases are null
List<string> phrases = phraseProvider.GetVoicePhrases(voiceId);
if (phrases == null || phrases.Count == 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
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6428a97eb23d27b48bff4ecaa464004e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,292 @@
/*
* 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 System.Linq;
using Meta.WitAi.Data.Configuration;
using Meta.WitAi.TTS.Integrations;
using Meta.WitAi.TTS.Utilities;
using Meta.WitAi.Data.Info;
using Meta.WitAi.Lib;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.TTS
{
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
internal static void RefreshAvailableVoices(TTSWit ttsWit, Action<WitAppInfo> onUpdateComplete = null)
{
// 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;
}
// Update app info
WitAppInfoUtility.Update(ttsWit.RequestSettings.configuration, (newInfo, r) =>
{
configuration.SetApplicationInfo(newInfo);
UpdatePresets(ttsWit, newInfo);
onUpdateComplete?.Invoke(newInfo);
});
}
// Add all presets
private static void UpdatePresets(TTSWit ttsWit, WitAppInfo appInfo)
{
// Cannot update presets without voices
if (appInfo.voices == null || appInfo.voices.Length == 0)
{
VLog.W("TTS Refresh failed to find voices");
return;
}
// Add all voices to preset voice list
if (ttsWit.PresetWitVoiceSettings == null || ttsWit.PresetWitVoiceSettings.Length == 0)
{
AddPresetsForInfo(ttsWit, appInfo.voices);
}
// Refresh speakers
RefreshEmptySpeakers(ttsWit);
}
// Adds a list of voice infos
internal static void AddPresetsForInfo(TTSWit ttsWit, WitVoiceInfo[] voiceInfos)
{
// Ignore without infos
if (voiceInfos == null || voiceInfos.Length == 0)
{
return;
}
// Add all voices to preset voice list
List<TTSWitVoiceSettings> voices = new List<TTSWitVoiceSettings>();
if (ttsWit.PresetWitVoiceSettings != null)
{
voices.AddRange(ttsWit.PresetWitVoiceSettings);
}
foreach (var voiceData in voiceInfos)
{
voices.Add(GetDefaultVoiceSetting(voiceData));
}
ttsWit.SetVoiceSettings(voices.ToArray());
}
// Adds a preset for a specific voice
internal static void AddPresetForInfo(TTSWit ttsWit, WitVoiceInfo voiceData)
{
List<TTSWitVoiceSettings> voices = new List<TTSWitVoiceSettings>();
if (ttsWit.PresetWitVoiceSettings != null)
{
voices.AddRange(ttsWit.PresetWitVoiceSettings);
}
voices.Add(GetDefaultVoiceSetting(voiceData));
ttsWit.SetVoiceSettings(voices.ToArray());
}
// 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;
}
// 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))
{
speaker.presetVoiceID = defaultVoiceID;
}
}
}
// 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
// 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;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c590c0f8426e4194db6efc14c68db75c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,127 @@
/*
* 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
{
[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 sealed override void OnInspectorGUI()
{
// Display default ui
OnEditTimeGUI();
OnPlaytimeGUI();
}
protected virtual void OnEditTimeGUI()
{
base.OnInspectorGUI();
}
protected virtual void OnPlaytimeGUI()
{
// Ignore if in editor
if (!Application.isPlaying)
{
return;
}
// Get service
if (!_service)
{
_service = target as TTSService;
}
// 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);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a7b031cd5a557e14fa08e59b869a2e78
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,189 @@
/*
* 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.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Meta.WitAi.TTS.Utilities;
using Meta.WitAi.TTS.Data;
namespace Meta.WitAi.TTS
{
[CustomEditor(typeof(TTSSpeaker), true)]
public class TTSSpeakerInspector : Editor
{
// Speaker
private TTSSpeaker _speaker;
private SerializedProperty _presetVoiceProperty;
private SerializedProperty _customVoiceProperty;
// Voices
private int _voiceIndex = -1;
private string[] _voicePresetIds = null;
// Voice text
private const string UI_PRESET_VOICE_KEY = "Voice Preset";
private const string UI_CUSTOM_VOICE_KEY = "Custom Voice";
private const string UI_CUSTOM_KEY = "CUSTOM";
//
void OnEnable()
{
_speaker = target as TTSSpeaker;
_presetVoiceProperty = serializedObject.FindProperty("presetVoiceID");
_customVoiceProperty = serializedObject.FindProperty("customWitVoiceSettings");
}
// GUI
public override void OnInspectorGUI()
{
// Display default ui
base.OnInspectorGUI();
// Check voices
TTSService tts = _speaker.TTSService;
TTSVoiceSettings[] settings = tts?.GetAllPresetVoiceSettings();
if (_voicePresetIds == null
|| (settings != null && _voicePresetIds.Length != settings.Length + 1)
|| (_voiceIndex >= 0 && _voiceIndex < _voicePresetIds.Length - 1 && !string.Equals(_speaker.presetVoiceID, _voicePresetIds[_voiceIndex])))
{
RefreshVoices(settings);
}
// No preset voices found, assume custom
if (_voicePresetIds == null || _voicePresetIds.Length == 0)
{
GUI.enabled = false;
EditorGUILayout.TextField(UI_PRESET_VOICE_KEY, UI_CUSTOM_KEY);
GUI.enabled = true;
}
// Voice dropdown
else
{
bool updated = false;
WitEditorUI.LayoutPopup(UI_PRESET_VOICE_KEY, _voicePresetIds, ref _voiceIndex, ref updated);
if (updated)
{
if (_voiceIndex >= 0 && _voiceIndex < _voicePresetIds.Length - 1)
{
_presetVoiceProperty.stringValue = _voicePresetIds[_voiceIndex];
}
else
{
_presetVoiceProperty.stringValue = null;
}
}
}
// Add custom layout
if (_voicePresetIds == null || _voiceIndex < 0 || _voiceIndex >= _voicePresetIds.Length - 1)
{
EditorGUILayout.PropertyField(_customVoiceProperty, new GUIContent(UI_CUSTOM_VOICE_KEY));
}
// Apply all modified properties
serializedObject.ApplyModifiedProperties();
// Layout TTS clip queue
LayoutClipQueue();
}
// Refresh voices
private void RefreshVoices(TTSVoiceSettings[] settings)
{
// Reset voice data
_voiceIndex = -1;
_voicePresetIds = null;
if (settings == null)
{
return;
}
// Get all ids
List<string> presetIds = settings.Select(s => s.SettingsId).ToList();
// Get voice index
_voiceIndex = presetIds.IndexOf(_speaker.presetVoiceID);
if (_voiceIndex == -1)
{
_voiceIndex = presetIds.Count;
}
// Add custom key
presetIds.Add(UI_CUSTOM_KEY);
// Apply preset ids
_voicePresetIds = presetIds.ToArray();
}
// 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
List<TTSClipData> queuedClips = _speaker.QueuedClips;
_queueFoldout = EditorGUILayout.Foldout(_queueFoldout, $"{UI_CLIP_QUEUE_TEXT} {(queuedClips == null ? 0 : queuedClips.Count)}");
if (_queueFoldout)
{
EditorGUI.indentLevel++;
if (queuedClips == null || queuedClips.Count == 0)
{
EditorGUILayout.LabelField("None");
}
else
{
for (int i = 0; i < queuedClips.Count; 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--;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3835212f72d4d5149bed0f07915f204e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,77 @@
/*
* 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.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Meta.WitAi.TTS.Integrations;
namespace Meta.WitAi.TTS
{
[CustomEditor(typeof(TTSWit), true)]
public class TTSWitInspector : TTSServiceInspector
{
private int selectedBaseVoice;
protected override void OnEditTimeGUI()
{
base.OnEditTimeGUI();
var ttsWit = (TTSWit)target;
var config = ttsWit.RequestSettings.configuration;
if (!config) return;
// Get app info for voices
var appInfo = config.GetApplicationInfo();
if (null != appInfo.voices && appInfo.voices.Length > 0)
{
// Get all voice names from wit
string[] voiceNames = appInfo.voices.Select(v => v.name).ToArray();
// Add a selected preset
GUILayout.BeginHorizontal();
selectedBaseVoice = EditorGUILayout.Popup(selectedBaseVoice, voiceNames);
GUI.enabled = selectedBaseVoice >= 0 && selectedBaseVoice < appInfo.voices.Length;
if (WitEditorUI.LayoutTextButton("Add Preset"))
{
TTSEditorUtilities.AddPresetForInfo(ttsWit, appInfo.voices[selectedBaseVoice]);
}
GUILayout.EndHorizontal();
// Add all unused presets
GUI.enabled = true;
if (GUILayout.Button("Add Unused Voices as Presets"))
{
// Get used voices
List<string> usedVoiceNames = ttsWit.PresetWitVoiceSettings.Select(v => v.voice).ToList();
// Get unused voices
var unusedVoices = appInfo.voices.Where(v => !usedVoiceNames.Contains(v.name)).ToArray();
// Add all unused presets
TTSEditorUtilities.AddPresetsForInfo(ttsWit, unusedVoices);
}
}
// Log warning
else
{
GUILayout.Label("There are currently no base presets available. Click refresh to check for updates.", EditorStyles.helpBox);
}
// Refresh button
if (GUILayout.Button("Refresh Presets"))
{
TTSEditorUtilities.RefreshAvailableVoices(ttsWit, info =>
{
Repaint();
});
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2f6696f09b6647cda45870d07c064cab
timeCreated: 1681499481
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 69fad6077e2eeef4a812dc81d313fc2a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,322 @@
/*
* 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 Meta.WitAi.TTS.Data;
using Meta.WitAi.TTS.Utilities;
using UnityEngine;
namespace Meta.WitAi.TTS.Voices
{
[CustomPropertyDrawer(typeof( TTSWitVoiceSettings))]
public class TTSWitVoiceSettingsDrawer : PropertyDrawer
{
// Constants for var layout
private const float VAR_HEIGHT = 20f;
private const float VAR_MARGIN = 4f;
private const float FIELD_HEIGHT = 60f;
// 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 TTSService _ttsService;
private bool _onSpeaker;
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)
{
// Get service
if (!_ttsService)
{
GetService(property, out _ttsService, out _onSpeaker);
}
// Property
if (!property.isExpanded)
{
return VAR_HEIGHT;
}
// Add each field + 1 for dropdown
int total = _fields.Length + 1;
// Remove 3 on speaker
if (_onSpeaker)
{
total -= 3;
}
// Add 2 for voice properties
int voiceIndex = GetVoiceIndex(property);
if (voiceIndex != -1)
{
total += 2;
}
// Get height
float height = total * VAR_HEIGHT + Mathf.Max(0, total - 1) * VAR_MARGIN;
// Add fields
if (!_onSpeaker)
{
height += 2 * (FIELD_HEIGHT - VAR_HEIGHT);
}
return height;
}
// Handles gui layout
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Get service if needed
if (!_ttsService)
{
GetService(property, out _ttsService, out _onSpeaker);
}
// On gui
float y = position.y;
string voiceName = property.FindPropertyRelative(VAR_SETTINGS).stringValue;
if (string.IsNullOrEmpty(voiceName))
{
voiceName = property.displayName;
}
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(_ttsService, property);
// Get voice index
int voiceIndex = GetVoiceIndex(property);
// Iterate subfields
for (int s = 0; s < _fields.Length; s++)
{
// Get subfield
FieldInfo subfield = _fields[s];
// Ignore base fields on speaker
if (_onSpeaker && subfield.DeclaringType == typeof(TTSVoiceSettings))
{
continue;
}
// Get subfield property
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--;
}
//
TextAreaAttribute area = subfield.GetCustomAttribute<TextAreaAttribute>();
if (area != null)
{
subfieldRect.height = FIELD_HEIGHT;
y += FIELD_HEIGHT - VAR_HEIGHT;
}
// 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--;
}
// Get service & if on a speaker
private void GetService(SerializedProperty property, out TTSService ttsService, out bool onSpeaker)
{
// Get tts wit if possible
object targetObject = property.serializedObject.targetObject;
if (targetObject != null)
{
// Currently on TTSService
if (targetObject is TTSService service)
{
ttsService = service;
onSpeaker = false;
return;
}
// Currently on TTSSpeaker
if (targetObject is TTSSpeaker speaker)
{
ttsService = speaker.TTSService;
onSpeaker = true;
return;
}
}
// Speaker not found
ttsService = null;
onSpeaker = false;
}
// Refresh voices
private void RefreshVoices(TTSService ttsService, SerializedProperty property)
{
// Ensure service exists
if (!(ttsService is TTSWit))
{
return;
}
// Get configuration
IWitRequestConfiguration configuration = (ttsService as TTSWit).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;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0bf9132926065a54da619451f5258d3e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8c945bb3fb3322b4eb73aba670cad74a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f4d30ee47fb6e7d4a888e9ee4b707391
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,135 @@
/*
* 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.Voice.Audio;
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;
/// <summary>
/// Unique request id used for tracking & logging
/// </summary>
public string queryRequestId => _queryRequestId;
private string _queryRequestId = Guid.NewGuid().ToString();
// Whether service should stream audio or just provide all at once
public bool queryStream;
// Request data
public Dictionary<string, string> queryParameters;
// Clip stream
public IAudioClipStream clipStream
{
get => _clipStream;
set
{
// Unload previous clip stream
IAudioClipStream v = value;
if (_clipStream != null && _clipStream != v)
{
clipStream.OnStreamReady = null;
clipStream.OnStreamUpdated = null;
clipStream.OnStreamComplete = null;
_clipStream.Unload();
}
// Apply new clip stream
_clipStream = v;
}
}
private IAudioClipStream _clipStream;
public AudioClip clip
{
get
{
if (clipStream is IAudioClipProvider uacs)
{
return uacs.Clip;
}
return null;
}
}
// 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;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef626b8cea4f59646a5076430a0e14aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a4d1170a24dd77d49bf3cd610dd1c9a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,28 @@
/*
* 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.Serialization;
namespace Meta.WitAi.TTS.Data
{
public abstract class TTSVoiceSettings
{
[Tooltip("A unique id used for linking these voice settings to a TTS Speaker")]
[FormerlySerializedAs("settingsID")]
public string SettingsId;
[Tooltip("Text that is added to the front of any TTS request using this voice setting")]
[TextArea]
public string PrependedText;
[TextArea]
[Tooltip("Text that is added to the end of any TTS request using this voice setting")]
public string AppendedText;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5dbbd0a6d06807d4f8a3190785a267f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5a7b8f23689f0b94dbe6a9aae4811de6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a8c6f2c6a5fdba344b75e8f613c5dc09
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,38 @@
/*
* 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();
/// <summary>
/// All events related to web requests
/// </summary>
public TTSWebRequestEvents WebRequest = new TTSWebRequestEvents();
/// <summary>
/// All events related to streaming from web or disk
/// </summary>
public TTSStreamEvents Stream = new TTSStreamEvents();
/// <summary>
/// All events related to downloading from the web
/// </summary>
public TTSDownloadEvents Download = new TTSDownloadEvents();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a41b87319719e004da4ad59b6a70358d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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.Speech;
using UnityEngine;
using UnityEngine.Events;
using Meta.WitAi.TTS.Data;
namespace Meta.WitAi.TTS.Utilities
{
/// <summary>
/// A unity event that returns a TTSSpeaker & TTSClipData
/// for a specific speaker playback request.
/// </summary>
[Serializable]
public class TTSSpeakerClipEvent : UnityEvent<TTSSpeaker, TTSClipData> { }
/// <summary>
/// A unity event that returns a TTSSpeaker, TTSClipData & text
/// for a specific speaker playback request
/// </summary>
[Serializable]
public class TTSSpeakerClipMessageEvent : UnityEvent<TTSSpeaker, TTSClipData, string> { }
/// <summary>
/// A collection of events used for speaker tts playback.
/// </summary>
[Serializable]
public class TTSSpeakerClipEvents : VoiceSpeechEvents
{
[Header("Speaker Lifecycle Events")]
[SerializeField] [Tooltip("Initial callback as soon as the audio clip speak request is generated")]
private TTSSpeakerClipEvent _onInit = new TTSSpeakerClipEvent();
/// <summary>
/// Initial callback as soon as the audio clip speak request is generated
/// </summary>
public TTSSpeakerClipEvent OnInit => _onInit;
[SerializeField] [Tooltip("Final call for a 'Speak' request that is called following a load failure, load abort, playback cancellation or playback completion")]
private TTSSpeakerClipEvent _onComplete = new TTSSpeakerClipEvent();
/// <summary>
/// Final call for a 'Speak' request that is called following a load failure,
/// load abort, playback cancellation or playback completion
/// </summary>
public TTSSpeakerClipEvent OnComplete => _onComplete;
[Header("Speaker Loading Events")]
[SerializeField] [Tooltip("Called when TTS audio clip load begins")]
private TTSSpeakerClipEvent _onLoadBegin = new TTSSpeakerClipEvent();
/// <summary>
/// Called when TTS audio clip load begins
/// </summary>
public TTSSpeakerClipEvent OnLoadBegin => _onLoadBegin;
[SerializeField] [Tooltip("Called when TTS audio clip load is cancelled")]
private TTSSpeakerClipEvent _onLoadAbort = new TTSSpeakerClipEvent();
/// <summary>
/// Called when TTS audio clip load is cancelled
/// </summary>
public TTSSpeakerClipEvent OnLoadAbort => _onLoadAbort;
[SerializeField] [Tooltip("Called when TTS audio clip load fails due to a network or load error")]
private TTSSpeakerClipMessageEvent _onLoadFailed = new TTSSpeakerClipMessageEvent();
/// <summary>
/// Called when TTS audio clip load fails due to a network or load error
/// </summary>
public TTSSpeakerClipMessageEvent OnLoadFailed => _onLoadFailed;
[SerializeField] [Tooltip("Called when TTS audio clip load successfully")]
private TTSSpeakerClipEvent _onLoadSuccess = new TTSSpeakerClipEvent();
/// <summary>
/// Called when TTS audio clip load successfully
/// </summary>
public TTSSpeakerClipEvent OnLoadSuccess => _onLoadSuccess;
[Header("Speaker Playback Events")]
[SerializeField] [Tooltip("Called when TTS audio clip playback is ready")]
private TTSSpeakerClipEvent _onPlaybackReady = new TTSSpeakerClipEvent();
/// <summary>
/// Called when TTS audio clip playback is ready
/// </summary>
public TTSSpeakerClipEvent OnPlaybackReady => _onPlaybackReady;
[SerializeField] [Tooltip("Called when TTS audio clip playback has begun")]
private TTSSpeakerClipEvent _onPlaybackStart = new TTSSpeakerClipEvent();
/// <summary>
/// Called when TTS audio clip playback has begun
/// </summary>
public TTSSpeakerClipEvent OnPlaybackStart => _onPlaybackStart;
[SerializeField] [Tooltip("Called when TTS audio clip playback been cancelled")]
private TTSSpeakerClipMessageEvent _onPlaybackCancelled = new TTSSpeakerClipMessageEvent();
/// <summary>
/// Called when TTS audio clip playback been cancelled
/// </summary>
public TTSSpeakerClipMessageEvent OnPlaybackCancelled => _onPlaybackCancelled;
[SerializeField] [Tooltip("Called when TTS audio clip is updated during streamed playback")]
private TTSSpeakerClipEvent _onPlaybackClipUpdated = new TTSSpeakerClipEvent();
/// <summary>
/// Called when TTS audio clip is updated during streamed playback
/// </summary>
public TTSSpeakerClipEvent OnPlaybackClipUpdated => _onPlaybackClipUpdated;
[SerializeField] [Tooltip("Called when TTS audio clip playback completed successfully")]
private TTSSpeakerClipEvent _onPlaybackComplete = new TTSSpeakerClipEvent();
/// <summary>
/// Called when TTS audio clip playback completed successfully
/// </summary>
public TTSSpeakerClipEvent OnPlaybackComplete => _onPlaybackComplete;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2c303e406a42b8b4d9853bfd74e434ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,70 @@
/*
* 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;
using UnityEngine.Serialization;
namespace Meta.WitAi.TTS.Utilities
{
[Serializable]
public class TTSSpeakerEvent : UnityEvent<TTSSpeaker, string> { }
[Serializable]
public class TTSSpeakerClipDataEvent : UnityEvent<TTSClipData> { }
[Serializable]
public class TTSSpeakerEvents : TTSSpeakerClipEvents
{
[Header("Queue Events")]
[Tooltip("Called when a tts request is added to an empty queue")]
[SerializeField] [FormerlySerializedAs("OnPlaybackQueueBegin")]
private UnityEvent _onPlaybackQueueBegin = new UnityEvent();
public UnityEvent OnPlaybackQueueBegin => _onPlaybackQueueBegin;
[Tooltip("Called the final request is removed from a queue")]
[SerializeField] [FormerlySerializedAs("OnPlaybackQueueComplete")]
private UnityEvent _onPlaybackQueueComplete = new UnityEvent();
public UnityEvent OnPlaybackQueueComplete => _onPlaybackQueueComplete;
[Header("Deprecated Events")]
[Obsolete("Use 'OnLoadBegin' event")]
public TTSSpeakerClipDataEvent OnClipDataQueued;
[Obsolete("Use 'OnLoadBegin' event")]
public TTSSpeakerEvent OnClipLoadBegin;
[Obsolete("Use 'OnLoadBegin' event")]
public TTSSpeakerClipDataEvent OnClipDataLoadBegin;
[Obsolete("Use 'OnLoadAbort' event")]
public TTSSpeakerEvent OnClipLoadAbort;
[Obsolete("Use 'OnLoadAbort' event")]
public TTSSpeakerClipDataEvent OnClipDataLoadAbort;
[Obsolete("Use 'OnLoadFailed' event")]
public TTSSpeakerEvent OnClipLoadFailed;
[Obsolete("Use 'OnLoadFailed' event")]
public TTSSpeakerClipDataEvent OnClipDataLoadFailed;
[Obsolete("Use 'OnLoadSuccess' event")]
public TTSSpeakerEvent OnClipLoadSuccess;
[Obsolete("Use 'OnLoadSuccess' event")]
public TTSSpeakerClipDataEvent OnClipDataLoadSuccess;
[Obsolete("Use 'OnPlaybackReady' event")]
public TTSSpeakerClipDataEvent OnClipDataPlaybackReady;
[Obsolete("Use 'OnPlaybackStart' event")]
public TTSSpeakerEvent OnStartSpeaking;
[Obsolete("Use 'OnPlaybackStart' event")]
public TTSSpeakerClipDataEvent OnClipDataPlaybackStart;
[Obsolete("Use 'OnPlaybackCancelled' event")]
public TTSSpeakerEvent OnCancelledSpeaking;
[Obsolete("Use 'OnPlaybackCancelled' event")]
public TTSSpeakerClipDataEvent OnClipDataPlaybackCancelled;
[Obsolete("Use 'OnPlaybackComplete' event")]
public TTSSpeakerEvent OnFinishedSpeaking;
[Obsolete("Use 'OnPlaybackComplete' event")]
public TTSSpeakerClipDataEvent OnClipDataPlaybackFinished;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f8f392c4b8438cd4e8a5318177de7a23
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,46 @@
/*
* 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 TTSClipEvent : UnityEvent<TTSClipData>
{
}
[Serializable]
public class TTSClipErrorEvent : UnityEvent<TTSClipData, string>
{
}
[Serializable]
public class TTSStreamEvents
{
[Tooltip("Called when a audio clip stream begins")]
public TTSClipEvent OnStreamBegin = new TTSClipEvent();
[Tooltip("Called when a audio clip is ready for playback")]
public TTSClipEvent OnStreamReady = new TTSClipEvent();
[Tooltip("Called if/when an audio clip is adjusted")]
public TTSClipEvent OnStreamClipUpdate = new TTSClipEvent();
[Tooltip("Called when a audio clip is completely loaded")]
public TTSClipEvent OnStreamComplete = new TTSClipEvent();
[Tooltip("Called when a audio clip stream has been cancelled")]
public TTSClipEvent OnStreamCancel = new TTSClipEvent();
[Tooltip("Called when a audio clip stream has failed")]
public TTSClipErrorEvent OnStreamError = new TTSClipErrorEvent();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc1209a088b657247b1f0c645ae7ee93
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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
{
/// <summary>
/// Events related to web requests
/// </summary>
[Serializable]
public class TTSWebRequestEvents
{
[Tooltip("Called when a web request begins transmission")]
public TTSClipEvent OnRequestBegin = new TTSClipEvent();
[Tooltip("Called when a web request is cancelled")]
public TTSClipEvent OnRequestCancel = new TTSClipEvent();
[Tooltip("Called when a web request fails")]
public TTSClipErrorEvent OnRequestError = new TTSClipErrorEvent();
[Tooltip("Called when a web request receives first data")]
public TTSClipEvent OnRequestFirstResponse = new TTSClipEvent();
[Tooltip("Called when a web request is ready for playback")]
public TTSClipEvent OnRequestReady = new TTSClipEvent();
[Tooltip("Called when a web request is completed via success, cancellation or failure")]
public TTSClipEvent OnRequestComplete = new TTSClipEvent();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 59d937d620dd3ea45abde93fe056c240
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,17 @@
{
"name": "Meta.WitAi.TTS",
"rootNamespace": "",
"references": [
"GUID:1c28d8b71ced07540b7c271537363cc6",
"GUID:4504b1a6e0fdcc3498c30b266e4a63bf"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

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