From e94f3ef4d52722ab154a028e32d8a3f1bb908969 Mon Sep 17 00:00:00 2001 From: pietru Date: Mon, 3 Mar 2025 19:01:11 +0100 Subject: [PATCH] tests --- MicRecord.gd | 32 + MicRecord.tscn | 15 + addons/ai_voices/Dock_aivoices.tscn | 92 ++ addons/ai_voices/GenerateDialog.cs | 1544 +++++++++++++++++++++ addons/ai_voices/GenerateDialog.cs.uid | 1 + addons/ai_voices/Voices.cs | 23 + addons/ai_voices/Voices.cs.uid | 1 + addons/ai_voices/icon-aivoices.png | Bin 0 -> 504 bytes addons/ai_voices/icon-aivoices.png.import | 34 + addons/ai_voices/plugin.cfg | 7 + project.godot | 1 + 11 files changed, 1750 insertions(+) create mode 100644 addons/ai_voices/Dock_aivoices.tscn create mode 100644 addons/ai_voices/GenerateDialog.cs create mode 100644 addons/ai_voices/GenerateDialog.cs.uid create mode 100644 addons/ai_voices/Voices.cs create mode 100644 addons/ai_voices/Voices.cs.uid create mode 100644 addons/ai_voices/icon-aivoices.png create mode 100644 addons/ai_voices/icon-aivoices.png.import create mode 100644 addons/ai_voices/plugin.cfg diff --git a/MicRecord.gd b/MicRecord.gd index e0e57c8..7fc390e 100644 --- a/MicRecord.gd +++ b/MicRecord.gd @@ -11,6 +11,13 @@ var format := AudioStreamWAV.FORMAT_16_BITS # This is the default format on rec var noise_max_lvl := 2000000#10000000 func _ready() -> void: + %TTS_Voices.clear() + var i = 0 + for vc in DisplayServer.tts_get_voices(): + %TTS_Voices.add_item(vc["language"]+" "+vc["name"]) + %TTS_Voices.set_item_metadata(i,vc) + i+=1 + var idx := AudioServer.get_bus_index("Record") effect = AudioServer.get_bus_effect(idx, 2) %Controls.visible=false @@ -32,6 +39,16 @@ func save_words(): fl.close() func _process(delta: float) -> void: + if tts_mode: + if %WordList.item_count=auto_timer_val: auto_timer_t=0 @@ -48,6 +65,8 @@ var auto_timer := false var auto_timer_val := 1.0 var auto_timer_t := 0.0 func _on_auto_switch_pressed() -> void: + if tts_mode: + return auto_timer_val = %Time.value auto_timer_t=0 auto_timer=!auto_timer @@ -56,6 +75,19 @@ func _on_auto_switch_pressed() -> void: else: %AutoSwitch.text="Start Timer" +var tts_mode := false +var tts_spoken := 0 +func _on_tts_mode_pressed() -> void: + if auto_timer: + _on_auto_switch_pressed() + tts_mode=!tts_mode + tts_spoken=0 + if tts_mode: + %TTSMode.text="Stop TTS" + _on_record_button_pressed() + else: + %TTSMode.text="Start TTS" + func run_swap_code(dir): if effect.is_recording_active(): diff --git a/MicRecord.tscn b/MicRecord.tscn index c88beba..cb9c61c 100644 --- a/MicRecord.tscn +++ b/MicRecord.tscn @@ -228,6 +228,20 @@ step = 0.25 value = 1.0 ticks_on_borders = true +[node name="HBoxContainer4" type="HBoxContainer" parent="TabContainer/Record/HBoxContainer3/Controls"] +layout_mode = 2 +alignment = 1 + +[node name="TTSMode" type="Button" parent="TabContainer/Record/HBoxContainer3/Controls/HBoxContainer4"] +unique_name_in_owner = true +layout_mode = 2 +text = "Start TTS" + +[node name="TTS_Voices" type="OptionButton" parent="TabContainer/Record/HBoxContainer3/Controls/HBoxContainer4"] +unique_name_in_owner = true +custom_minimum_size = Vector2(200, 0) +layout_mode = 2 + [node name="HSeparator2" type="HSeparator" parent="TabContainer/Record/HBoxContainer3/Controls"] self_modulate = Color(1, 1, 1, 0) custom_minimum_size = Vector2(0, 40) @@ -316,6 +330,7 @@ placeholder_text = "Text to read load worlds" [connection signal="pressed" from="TabContainer/Record/HBoxContainer3/Controls/HBoxContainer/SaveButton" to="." method="_on_save_button_pressed"] [connection signal="pressed" from="TabContainer/Record/HBoxContainer3/Controls/HBoxContainer/OpenUserFolderButton" to="." method="_on_open_user_folder_button_pressed"] [connection signal="pressed" from="TabContainer/Record/HBoxContainer3/Controls/HBoxContainer3/AutoSwitch" to="." method="_on_auto_switch_pressed"] +[connection signal="pressed" from="TabContainer/Record/HBoxContainer3/Controls/HBoxContainer4/TTSMode" to="." method="_on_tts_mode_pressed"] [connection signal="pressed" from="TabContainer/Record/HBoxContainer3/Controls/HBoxContainer2/DeleteButton" to="." method="_on_delete_button_pressed"] [connection signal="pressed" from="TabContainer/PlanText/HBoxContainer2/PlayTextBTN" to="." method="_on_play_text_btn_pressed"] [connection signal="pressed" from="TabContainer/PlanText/HBoxContainer2/AddWordsBTN" to="." method="_on_add_words_btn_pressed"] diff --git a/addons/ai_voices/Dock_aivoices.tscn b/addons/ai_voices/Dock_aivoices.tscn new file mode 100644 index 0000000..6325cb9 --- /dev/null +++ b/addons/ai_voices/Dock_aivoices.tscn @@ -0,0 +1,92 @@ +[gd_scene load_steps=4 format=3 uid="uid://dw3yneckugr7i"] + +[ext_resource type="Script" uid="uid://srkgrxnfaw0o" path="res://addons/ai_voices/GenerateDialog.cs" id="1_u4t6r"] + +[sub_resource type="SystemFont" id="SystemFont_u4t6r"] +font_weight = 800 + +[sub_resource type="LabelSettings" id="LabelSettings_0yynb"] +font = SubResource("SystemFont_u4t6r") +font_size = 20 + +[node name="AIVoicesMenu" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="MainContainer" type="VBoxContainer" parent="."] +layout_mode = 0 +offset_right = 424.0 +offset_bottom = 185.0 + +[node name="LabelSettings" type="Label" parent="MainContainer"] +layout_mode = 2 +text = "Settings:" +label_settings = SubResource("LabelSettings_0yynb") + +[node name="VoiceContainer" type="HBoxContainer" parent="MainContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="MainContainer/VoiceContainer"] +layout_mode = 2 +text = "Voice:" + +[node name="voice" type="OptionButton" parent="MainContainer/VoiceContainer"] +layout_mode = 2 +item_count = 1 +popup/item_0/text = "Default" +popup/item_0/id = 0 + +[node name="LangContainer" type="HBoxContainer" parent="MainContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="MainContainer/LangContainer"] +layout_mode = 2 +text = "Lang:" + +[node name="lang" type="OptionButton" parent="MainContainer/LangContainer"] +layout_mode = 2 +item_count = 5 +popup/item_0/text = "en" +popup/item_0/id = 0 +popup/item_1/text = "fr" +popup/item_1/id = 1 +popup/item_2/text = "es" +popup/item_2/id = 2 +popup/item_3/text = "it" +popup/item_3/id = 3 +popup/item_4/text = "de" +popup/item_4/id = 4 + +[node name="Label" type="Label" parent="MainContainer"] +layout_mode = 2 +text = "Text to generate:" + +[node name="DialogToGenerate" type="TextEdit" parent="MainContainer"] +custom_minimum_size = Vector2(0, 80) +layout_mode = 2 +placeholder_text = "Lorem ipsum" +scroll_smooth = true +scroll_fit_content_height = true +caret_type = 1 + +[node name="GenerateButton" type="Button" parent="MainContainer"] +layout_mode = 2 +text = "Generate wav file" +script = ExtResource("1_u4t6r") + +[node name="HSeparator" type="HSeparator" parent="MainContainer"] +layout_mode = 2 + +[node name="LinkButton" type="LinkButton" parent="MainContainer"] +layout_mode = 2 +text = "AllTalk_TTS repos" +uri = "https://github.com/erew123/alltalk_tts" + +[node name="LinkButton2" type="LinkButton" parent="MainContainer"] +layout_mode = 2 +text = "How to install AllTalk?" +uri = "https://www.anthony-cardinale.fr/_public/unity-tools/AITools/AllTalk_Installation.pdf" diff --git a/addons/ai_voices/GenerateDialog.cs b/addons/ai_voices/GenerateDialog.cs new file mode 100644 index 0000000..2390dde --- /dev/null +++ b/addons/ai_voices/GenerateDialog.cs @@ -0,0 +1,1544 @@ +using Godot; +using System; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; +using System.Net; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Diagnostics; + +namespace AiToolsSuite +{ + [Tool] + public partial class GenerateDialog : Godot.Button + { + + string apiUrl = "http://127.0.0.1:7851/api/"; + + private TextEdit _textEdit; + private OptionButton _voice; + private OptionButton _lang; + + public List voiceList = new List(); + + public override async void _EnterTree() + { + Pressed += GenerateClicked; + _textEdit = GetNode("../DialogToGenerate"); + _voice = GetNode("../VoiceContainer/voice"); + _lang = GetNode("../LangContainer/lang"); + + voiceList = await GetVoicesList(); + + // Add voices to the OptionButton + _voice.Clear(); + foreach (var voice in voiceList) + _voice.AddItem(voice); + + // Select first item by default if available + if (voiceList.Count > 0) + _voice.Selected = 0; + } + + public void GenerateClicked() + { + GD.Print("Generate dial"); + string voice = _voice.GetItemText(_voice.Selected); + string lang = _lang.GetItemText(_lang.Selected); // _lang.Text; + string text = _textEdit.Text; + + GenerateDialogue(text, voice, lang); + } + + public async Task> GetVoicesList() + { + var client = new System.Net.Http.HttpClient(); + HttpResponseMessage response = await client.GetAsync( + apiUrl + "voices"); + HttpContent responseContent = response.Content; + + using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync())) + { + string jsonResult = await reader.ReadToEndAsync(); + var N = JSON.Parse(jsonResult); + List voiceList = new List(); + + foreach (var voice in N["voices"]) + voiceList.Add(voice.ToString().Replace("[", "").Replace("]", "").Replace('"', ',').Replace(",", "").Replace(".wav", "").Replace(" ", "")); + + return voiceList; + } + } + + public async void GenerateDialogue(string line, string voice, string lang) + { + var client = new System.Net.Http.HttpClient(); + + var requestContent = new FormUrlEncodedContent(new[] { + new KeyValuePair("text_input", line), + new KeyValuePair("text_filtering", "standard"), + new KeyValuePair("character_voice_gen", voice + ".wav"), + new KeyValuePair("narrator_enabled", "true"), + new KeyValuePair("narrator_voice_gen", "male_03.wav"), + new KeyValuePair("text_not_inside", "character"), + new KeyValuePair("language", lang), + new KeyValuePair("output_file_name", "output"), + new KeyValuePair("output_file_timestamp", "true"), + new KeyValuePair("autoplay", "true"), + new KeyValuePair("autoplay_volume", "0.8") + }); + + HttpResponseMessage response = await client.PostAsync( + apiUrl + "tts-generate", + requestContent); + + HttpContent responseContent = response.Content; + + using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync())) + { + string jsonResult = await reader.ReadToEndAsync(); + var N = JSON.Parse(jsonResult); + string wavPath = N["output_file_path"]; + GD.Print(wavPath); + + string voicesDir = "Voices"; + if (!Directory.Exists(voicesDir)) + Directory.CreateDirectory(voicesDir); + + string voiceDir = Path.Combine(voicesDir, voice); + if (!Directory.Exists(voiceDir)) + Directory.CreateDirectory(voiceDir); + + string langDir = Path.Combine(voiceDir, lang); + if (!Directory.Exists(langDir)) + Directory.CreateDirectory(langDir); + + if (File.Exists(wavPath)) + { + string fileName = Path.GetFileName(wavPath); + string destinationPath = Path.Combine(langDir, fileName); + + File.Move(wavPath, destinationPath); + GD.Print("File moved to: " + destinationPath); + + if (Engine.IsEditorHint()) + { + EditorInterface editorInterface = EditorInterface.Singleton; + editorInterface.GetResourceFilesystem().Scan(); + + // Add a small delay to ensure the file is indexed + await Task.Delay(1000); + + // Select the file in the FileSystem dock + var projectPath = ProjectSettings.GlobalizePath(destinationPath); + editorInterface.SelectFile(projectPath); + + // Optionnellement, ouvrir l'inspecteur + editorInterface.EditResource(GD.Load(projectPath)); + } + } + else + GD.Print("Error: Generated audio file not found at " + wavPath); + } + } + } +} + +#region json +namespace AiToolsSuite +{ + public enum JSONNodeType + { + Array = 1, + Object = 2, + String = 3, + Number = 4, + NullValue = 5, + Boolean = 6, + None = 7, + Custom = 0xFF, + } + public enum JSONTextMode + { + Compact, + Indent + } + + public abstract partial class JSONNode + { + #region Enumerators + public struct Enumerator + { + private enum Type { None, Array, Object } + private Type type; + private Dictionary.Enumerator m_Object; + private List.Enumerator m_Array; + public bool IsValid { get { return type != Type.None; } } + public Enumerator(List.Enumerator aArrayEnum) + { + type = Type.Array; + m_Object = default(Dictionary.Enumerator); + m_Array = aArrayEnum; + } + public Enumerator(Dictionary.Enumerator aDictEnum) + { + type = Type.Object; + m_Object = aDictEnum; + m_Array = default(List.Enumerator); + } + public KeyValuePair Current + { + get + { + if (type == Type.Array) + return new KeyValuePair(string.Empty, m_Array.Current); + else if (type == Type.Object) + return m_Object.Current; + return new KeyValuePair(string.Empty, null); + } + } + public bool MoveNext() + { + if (type == Type.Array) + return m_Array.MoveNext(); + else if (type == Type.Object) + return m_Object.MoveNext(); + return false; + } + } + public struct ValueEnumerator + { + private Enumerator m_Enumerator; + public ValueEnumerator(List.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { } + public ValueEnumerator(Dictionary.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { } + public ValueEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } + public JSONNode Current { get { return m_Enumerator.Current.Value; } } + public bool MoveNext() { return m_Enumerator.MoveNext(); } + public ValueEnumerator GetEnumerator() { return this; } + } + public struct KeyEnumerator + { + private Enumerator m_Enumerator; + public KeyEnumerator(List.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { } + public KeyEnumerator(Dictionary.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { } + public KeyEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } + public string Current { get { return m_Enumerator.Current.Key; } } + public bool MoveNext() { return m_Enumerator.MoveNext(); } + public KeyEnumerator GetEnumerator() { return this; } + } + + public class LinqEnumerator : IEnumerator>, IEnumerable> + { + private JSONNode m_Node; + private Enumerator m_Enumerator; + internal LinqEnumerator(JSONNode aNode) + { + m_Node = aNode; + if (m_Node != null) + m_Enumerator = m_Node.GetEnumerator(); + } + public KeyValuePair Current { get { return m_Enumerator.Current; } } + object IEnumerator.Current { get { return m_Enumerator.Current; } } + public bool MoveNext() { return m_Enumerator.MoveNext(); } + + public void Dispose() + { + m_Node = null; + m_Enumerator = new Enumerator(); + } + + public IEnumerator> GetEnumerator() + { + return new LinqEnumerator(m_Node); + } + + public void Reset() + { + if (m_Node != null) + m_Enumerator = m_Node.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new LinqEnumerator(m_Node); + } + } + + #endregion Enumerators + + #region common interface + + public static bool forceASCII = false; // Use Unicode by default + public static bool longAsString = false; // lazy creator creates a JSONString instead of JSONNumber + public static bool allowLineComments = true; // allow "//"-style comments at the end of a line + + public abstract JSONNodeType Tag { get; } + + public virtual JSONNode this[int aIndex] { get { return null; } set { } } + + public virtual JSONNode this[string aKey] { get { return null; } set { } } + + public virtual string Value { get { return ""; } set { } } + + public virtual int Count { get { return 0; } } + + public virtual bool IsNumber { get { return false; } } + public virtual bool IsString { get { return false; } } + public virtual bool IsBoolean { get { return false; } } + public virtual bool IsNull { get { return false; } } + public virtual bool IsArray { get { return false; } } + public virtual bool IsObject { get { return false; } } + + public virtual bool Inline { get { return false; } set { } } + + public virtual void Add(string aKey, JSONNode aItem) + { + } + public virtual void Add(JSONNode aItem) + { + Add("", aItem); + } + + public virtual JSONNode Remove(string aKey) + { + return null; + } + + public virtual JSONNode Remove(int aIndex) + { + return null; + } + + public virtual JSONNode Remove(JSONNode aNode) + { + return aNode; + } + public virtual void Clear() { } + + public virtual JSONNode Clone() + { + return null; + } + + public virtual IEnumerable Children + { + get + { + yield break; + } + } + + public IEnumerable DeepChildren + { + get + { + foreach (var C in Children) + foreach (var D in C.DeepChildren) + yield return D; + } + } + + public virtual bool HasKey(string aKey) + { + return false; + } + + public virtual JSONNode GetValueOrDefault(string aKey, JSONNode aDefault) + { + return aDefault; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + WriteToStringBuilder(sb, 0, 0, JSONTextMode.Compact); + return sb.ToString(); + } + + public virtual string ToString(int aIndent) + { + StringBuilder sb = new StringBuilder(); + WriteToStringBuilder(sb, 0, aIndent, JSONTextMode.Indent); + return sb.ToString(); + } + internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode); + + public abstract Enumerator GetEnumerator(); + public IEnumerable> Linq { get { return new LinqEnumerator(this); } } + public KeyEnumerator Keys { get { return new KeyEnumerator(GetEnumerator()); } } + public ValueEnumerator Values { get { return new ValueEnumerator(GetEnumerator()); } } + + #endregion common interface + + #region typecasting properties + + + public virtual double AsDouble + { + get + { + double v = 0.0; + if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out v)) + return v; + return 0.0; + } + set + { + Value = value.ToString(CultureInfo.InvariantCulture); + } + } + + public virtual int AsInt + { + get { return (int)AsDouble; } + set { AsDouble = value; } + } + + public virtual float AsFloat + { + get { return (float)AsDouble; } + set { AsDouble = value; } + } + + public virtual bool AsBool + { + get + { + bool v = false; + if (bool.TryParse(Value, out v)) + return v; + return !string.IsNullOrEmpty(Value); + } + set + { + Value = (value) ? "true" : "false"; + } + } + + public virtual long AsLong + { + get + { + long val = 0; + if (long.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out val)) + return val; + return 0L; + } + set + { + Value = value.ToString(CultureInfo.InvariantCulture); + } + } + + public virtual ulong AsULong + { + get + { + ulong val = 0; + if (ulong.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out val)) + return val; + return 0; + } + set + { + Value = value.ToString(CultureInfo.InvariantCulture); + } + } + + public virtual JSONArray AsArray + { + get + { + return this as JSONArray; + } + } + + public virtual JSONObject AsObject + { + get + { + return this as JSONObject; + } + } + + + #endregion typecasting properties + + #region operators + + public static implicit operator JSONNode(string s) + { + return (s == null) ? (JSONNode)JSONNull.CreateOrGet() : new JSONString(s); + } + public static implicit operator string(JSONNode d) + { + return (d == null) ? null : d.Value; + } + + public static implicit operator JSONNode(double n) + { + return new JSONNumber(n); + } + public static implicit operator double(JSONNode d) + { + return (d == null) ? 0 : d.AsDouble; + } + + public static implicit operator JSONNode(float n) + { + return new JSONNumber(n); + } + public static implicit operator float(JSONNode d) + { + return (d == null) ? 0 : d.AsFloat; + } + + public static implicit operator JSONNode(int n) + { + return new JSONNumber(n); + } + public static implicit operator int(JSONNode d) + { + return (d == null) ? 0 : d.AsInt; + } + + public static implicit operator JSONNode(long n) + { + if (longAsString) + return new JSONString(n.ToString(CultureInfo.InvariantCulture)); + return new JSONNumber(n); + } + public static implicit operator long(JSONNode d) + { + return (d == null) ? 0L : d.AsLong; + } + + public static implicit operator JSONNode(ulong n) + { + if (longAsString) + return new JSONString(n.ToString(CultureInfo.InvariantCulture)); + return new JSONNumber(n); + } + public static implicit operator ulong(JSONNode d) + { + return (d == null) ? 0 : d.AsULong; + } + + public static implicit operator JSONNode(bool b) + { + return new JSONBool(b); + } + public static implicit operator bool(JSONNode d) + { + return (d == null) ? false : d.AsBool; + } + + public static implicit operator JSONNode(KeyValuePair aKeyValue) + { + return aKeyValue.Value; + } + + public static bool operator ==(JSONNode a, object b) + { + if (ReferenceEquals(a, b)) + return true; + bool aIsNull = a is JSONNull || ReferenceEquals(a, null) || a is JSONLazyCreator; + bool bIsNull = b is JSONNull || ReferenceEquals(b, null) || b is JSONLazyCreator; + if (aIsNull && bIsNull) + return true; + return !aIsNull && a.Equals(b); + } + + public static bool operator !=(JSONNode a, object b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + return ReferenceEquals(this, obj); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + #endregion operators + + [ThreadStatic] + private static StringBuilder m_EscapeBuilder; + internal static StringBuilder EscapeBuilder + { + get + { + if (m_EscapeBuilder == null) + m_EscapeBuilder = new StringBuilder(); + return m_EscapeBuilder; + } + } + internal static string Escape(string aText) + { + var sb = EscapeBuilder; + sb.Length = 0; + if (sb.Capacity < aText.Length + aText.Length / 10) + sb.Capacity = aText.Length + aText.Length / 10; + foreach (char c in aText) + { + switch (c) + { + case '\\': + sb.Append("\\\\"); + break; + case '\"': + sb.Append("\\\""); + break; + case '\n': + sb.Append("\\n"); + break; + case '\r': + sb.Append("\\r"); + break; + case '\t': + sb.Append("\\t"); + break; + case '\b': + sb.Append("\\b"); + break; + case '\f': + sb.Append("\\f"); + break; + default: + if (c < ' ' || (forceASCII && c > 127)) + { + ushort val = c; + sb.Append("\\u").Append(val.ToString("X4")); + } + else + sb.Append(c); + break; + } + } + string result = sb.ToString(); + sb.Length = 0; + return result; + } + + private static JSONNode ParseElement(string token, bool quoted) + { + if (quoted) + return token; + if (token.Length <= 5) + { + string tmp = token.ToLower(); + if (tmp == "false" || tmp == "true") + return tmp == "true"; + if (tmp == "null") + return JSONNull.CreateOrGet(); + } + double val; + if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out val)) + return val; + else + return token; + } + + public static JSONNode Parse(string aJSON) + { + Stack stack = new Stack(); + JSONNode ctx = null; + int i = 0; + StringBuilder Token = new StringBuilder(); + string TokenName = ""; + bool QuoteMode = false; + bool TokenIsQuoted = false; + bool HasNewlineChar = false; + while (i < aJSON.Length) + { + switch (aJSON[i]) + { + case '{': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + stack.Push(new JSONObject()); + if (ctx != null) + { + ctx.Add(TokenName, stack.Peek()); + } + TokenName = ""; + Token.Length = 0; + ctx = stack.Peek(); + HasNewlineChar = false; + break; + + case '[': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + + stack.Push(new JSONArray()); + if (ctx != null) + { + ctx.Add(TokenName, stack.Peek()); + } + TokenName = ""; + Token.Length = 0; + ctx = stack.Peek(); + HasNewlineChar = false; + break; + + case '}': + case ']': + if (QuoteMode) + { + + Token.Append(aJSON[i]); + break; + } + if (stack.Count == 0) + throw new Exception("JSON Parse: Too many closing brackets"); + + stack.Pop(); + if (Token.Length > 0 || TokenIsQuoted) + ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted)); + if (ctx != null) + ctx.Inline = !HasNewlineChar; + TokenIsQuoted = false; + TokenName = ""; + Token.Length = 0; + if (stack.Count > 0) + ctx = stack.Peek(); + break; + + case ':': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + TokenName = Token.ToString(); + Token.Length = 0; + TokenIsQuoted = false; + break; + + case '"': + QuoteMode ^= true; + TokenIsQuoted |= QuoteMode; + break; + + case ',': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + if (Token.Length > 0 || TokenIsQuoted) + ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted)); + TokenIsQuoted = false; + TokenName = ""; + Token.Length = 0; + TokenIsQuoted = false; + break; + + case '\r': + case '\n': + HasNewlineChar = true; + break; + + case ' ': + case '\t': + if (QuoteMode) + Token.Append(aJSON[i]); + break; + + case '\\': + ++i; + if (QuoteMode) + { + char C = aJSON[i]; + switch (C) + { + case 't': + Token.Append('\t'); + break; + case 'r': + Token.Append('\r'); + break; + case 'n': + Token.Append('\n'); + break; + case 'b': + Token.Append('\b'); + break; + case 'f': + Token.Append('\f'); + break; + case 'u': + { + string s = aJSON.Substring(i + 1, 4); + Token.Append((char)int.Parse( + s, + System.Globalization.NumberStyles.AllowHexSpecifier)); + i += 4; + break; + } + default: + Token.Append(C); + break; + } + } + break; + case '/': + if (allowLineComments && !QuoteMode && i + 1 < aJSON.Length && aJSON[i + 1] == '/') + { + while (++i < aJSON.Length && aJSON[i] != '\n' && aJSON[i] != '\r') ; + break; + } + Token.Append(aJSON[i]); + break; + case '\uFEFF': // remove / ignore BOM (Byte Order Mark) + break; + + default: + Token.Append(aJSON[i]); + break; + } + ++i; + } + if (QuoteMode) + { + throw new Exception("JSON Parse: Quotation marks seems to be messed up."); + } + if (ctx == null) + return ParseElement(Token.ToString(), TokenIsQuoted); + return ctx; + } + + } + // End of JSONNode + + public partial class JSONArray : JSONNode + { + private List m_List = new List(); + private bool inline = false; + public override bool Inline + { + get { return inline; } + set { inline = value; } + } + + public override JSONNodeType Tag { get { return JSONNodeType.Array; } } + public override bool IsArray { get { return true; } } + public override Enumerator GetEnumerator() { return new Enumerator(m_List.GetEnumerator()); } + + public override JSONNode this[int aIndex] + { + get + { + if (aIndex < 0 || aIndex >= m_List.Count) + return new JSONLazyCreator(this); + return m_List[aIndex]; + } + set + { + if (value == null) + value = JSONNull.CreateOrGet(); + if (aIndex < 0 || aIndex >= m_List.Count) + m_List.Add(value); + else + m_List[aIndex] = value; + } + } + + public override JSONNode this[string aKey] + { + get { return new JSONLazyCreator(this); } + set + { + if (value == null) + value = JSONNull.CreateOrGet(); + m_List.Add(value); + } + } + + public override int Count + { + get { return m_List.Count; } + } + + public override void Add(string aKey, JSONNode aItem) + { + if (aItem == null) + aItem = JSONNull.CreateOrGet(); + m_List.Add(aItem); + } + + public override JSONNode Remove(int aIndex) + { + if (aIndex < 0 || aIndex >= m_List.Count) + return null; + JSONNode tmp = m_List[aIndex]; + m_List.RemoveAt(aIndex); + return tmp; + } + + public override JSONNode Remove(JSONNode aNode) + { + m_List.Remove(aNode); + return aNode; + } + + public override void Clear() + { + m_List.Clear(); + } + + public override JSONNode Clone() + { + var node = new JSONArray(); + node.m_List.Capacity = m_List.Capacity; + foreach (var n in m_List) + { + if (n != null) + node.Add(n.Clone()); + else + node.Add(null); + } + return node; + } + + public override IEnumerable Children + { + get + { + foreach (JSONNode N in m_List) + yield return N; + } + } + + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append('['); + int count = m_List.Count; + if (inline) + aMode = JSONTextMode.Compact; + for (int i = 0; i < count; i++) + { + if (i > 0) + aSB.Append(','); + if (aMode == JSONTextMode.Indent) + aSB.AppendLine(); + + if (aMode == JSONTextMode.Indent) + aSB.Append(' ', aIndent + aIndentInc); + m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); + } + if (aMode == JSONTextMode.Indent) + aSB.AppendLine().Append(' ', aIndent); + aSB.Append(']'); + } + } + // End of JSONArray + + public partial class JSONObject : JSONNode + { + private Dictionary m_Dict = new Dictionary(); + + private bool inline = false; + public override bool Inline + { + get { return inline; } + set { inline = value; } + } + + public override JSONNodeType Tag { get { return JSONNodeType.Object; } } + public override bool IsObject { get { return true; } } + + public override Enumerator GetEnumerator() { return new Enumerator(m_Dict.GetEnumerator()); } + + + public override JSONNode this[string aKey] + { + get + { + if (m_Dict.ContainsKey(aKey)) + return m_Dict[aKey]; + else + return new JSONLazyCreator(this, aKey); + } + set + { + if (value == null) + value = JSONNull.CreateOrGet(); + if (m_Dict.ContainsKey(aKey)) + m_Dict[aKey] = value; + else + m_Dict.Add(aKey, value); + } + } + + public override JSONNode this[int aIndex] + { + get + { + if (aIndex < 0 || aIndex >= m_Dict.Count) + return null; + return m_Dict.ElementAt(aIndex).Value; + } + set + { + if (value == null) + value = JSONNull.CreateOrGet(); + if (aIndex < 0 || aIndex >= m_Dict.Count) + return; + string key = m_Dict.ElementAt(aIndex).Key; + m_Dict[key] = value; + } + } + + public override int Count + { + get { return m_Dict.Count; } + } + + public override void Add(string aKey, JSONNode aItem) + { + if (aItem == null) + aItem = JSONNull.CreateOrGet(); + + if (aKey != null) + { + if (m_Dict.ContainsKey(aKey)) + m_Dict[aKey] = aItem; + else + m_Dict.Add(aKey, aItem); + } + else + m_Dict.Add(Guid.NewGuid().ToString(), aItem); + } + + public override JSONNode Remove(string aKey) + { + if (!m_Dict.ContainsKey(aKey)) + return null; + JSONNode tmp = m_Dict[aKey]; + m_Dict.Remove(aKey); + return tmp; + } + + public override JSONNode Remove(int aIndex) + { + if (aIndex < 0 || aIndex >= m_Dict.Count) + return null; + var item = m_Dict.ElementAt(aIndex); + m_Dict.Remove(item.Key); + return item.Value; + } + + public override JSONNode Remove(JSONNode aNode) + { + try + { + var item = m_Dict.Where(k => k.Value == aNode).First(); + m_Dict.Remove(item.Key); + return aNode; + } + catch + { + return null; + } + } + + public override void Clear() + { + m_Dict.Clear(); + } + + public override JSONNode Clone() + { + var node = new JSONObject(); + foreach (var n in m_Dict) + { + node.Add(n.Key, n.Value.Clone()); + } + return node; + } + + public override bool HasKey(string aKey) + { + return m_Dict.ContainsKey(aKey); + } + + public override JSONNode GetValueOrDefault(string aKey, JSONNode aDefault) + { + JSONNode res; + if (m_Dict.TryGetValue(aKey, out res)) + return res; + return aDefault; + } + + public override IEnumerable Children + { + get + { + foreach (KeyValuePair N in m_Dict) + yield return N.Value; + } + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append('{'); + bool first = true; + if (inline) + aMode = JSONTextMode.Compact; + foreach (var k in m_Dict) + { + if (!first) + aSB.Append(','); + first = false; + if (aMode == JSONTextMode.Indent) + aSB.AppendLine(); + if (aMode == JSONTextMode.Indent) + aSB.Append(' ', aIndent + aIndentInc); + aSB.Append('\"').Append(Escape(k.Key)).Append('\"'); + if (aMode == JSONTextMode.Compact) + aSB.Append(':'); + else + aSB.Append(" : "); + k.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); + } + if (aMode == JSONTextMode.Indent) + aSB.AppendLine().Append(' ', aIndent); + aSB.Append('}'); + } + + } + // End of JSONObject + + public partial class JSONString : JSONNode + { + private string m_Data; + + public override JSONNodeType Tag { get { return JSONNodeType.String; } } + public override bool IsString { get { return true; } } + + public override Enumerator GetEnumerator() { return new Enumerator(); } + + + public override string Value + { + get { return m_Data; } + set + { + m_Data = value; + } + } + + public JSONString(string aData) + { + m_Data = aData; + } + public override JSONNode Clone() + { + return new JSONString(m_Data); + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append('\"').Append(Escape(m_Data)).Append('\"'); + } + public override bool Equals(object obj) + { + if (base.Equals(obj)) + return true; + string s = obj as string; + if (s != null) + return m_Data == s; + JSONString s2 = obj as JSONString; + if (s2 != null) + return m_Data == s2.m_Data; + return false; + } + public override int GetHashCode() + { + return m_Data.GetHashCode(); + } + public override void Clear() + { + m_Data = ""; + } + } + // End of JSONString + + public partial class JSONNumber : JSONNode + { + private double m_Data; + + public override JSONNodeType Tag { get { return JSONNodeType.Number; } } + public override bool IsNumber { get { return true; } } + public override Enumerator GetEnumerator() { return new Enumerator(); } + + public override string Value + { + get { return m_Data.ToString(CultureInfo.InvariantCulture); } + set + { + double v; + if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out v)) + m_Data = v; + } + } + + public override double AsDouble + { + get { return m_Data; } + set { m_Data = value; } + } + public override long AsLong + { + get { return (long)m_Data; } + set { m_Data = value; } + } + public override ulong AsULong + { + get { return (ulong)m_Data; } + set { m_Data = value; } + } + + public JSONNumber(double aData) + { + m_Data = aData; + } + + public JSONNumber(string aData) + { + Value = aData; + } + + public override JSONNode Clone() + { + return new JSONNumber(m_Data); + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append(Value.ToString(CultureInfo.InvariantCulture)); + } + private static bool IsNumeric(object value) + { + return value is int || value is uint + || value is float || value is double + || value is decimal + || value is long || value is ulong + || value is short || value is ushort + || value is sbyte || value is byte; + } + public override bool Equals(object obj) + { + if (obj == null) + return false; + if (base.Equals(obj)) + return true; + JSONNumber s2 = obj as JSONNumber; + if (s2 != null) + return m_Data == s2.m_Data; + if (IsNumeric(obj)) + return Convert.ToDouble(obj) == m_Data; + return false; + } + public override int GetHashCode() + { + return m_Data.GetHashCode(); + } + public override void Clear() + { + m_Data = 0; + } + } + // End of JSONNumber + + public partial class JSONBool : JSONNode + { + private bool m_Data; + + public override JSONNodeType Tag { get { return JSONNodeType.Boolean; } } + public override bool IsBoolean { get { return true; } } + public override Enumerator GetEnumerator() { return new Enumerator(); } + + public override string Value + { + get { return m_Data.ToString(); } + set + { + bool v; + if (bool.TryParse(value, out v)) + m_Data = v; + } + } + public override bool AsBool + { + get { return m_Data; } + set { m_Data = value; } + } + + public JSONBool(bool aData) + { + m_Data = aData; + } + + public JSONBool(string aData) + { + Value = aData; + } + + public override JSONNode Clone() + { + return new JSONBool(m_Data); + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append((m_Data) ? "true" : "false"); + } + public override bool Equals(object obj) + { + if (obj == null) + return false; + if (obj is bool) + return m_Data == (bool)obj; + return false; + } + public override int GetHashCode() + { + return m_Data.GetHashCode(); + } + public override void Clear() + { + m_Data = false; + } + } + // End of JSONBool + + public partial class JSONNull : JSONNode + { + static JSONNull m_StaticInstance = new JSONNull(); + public static bool reuseSameInstance = true; + public static JSONNull CreateOrGet() + { + if (reuseSameInstance) + return m_StaticInstance; + return new JSONNull(); + } + private JSONNull() { } + + public override JSONNodeType Tag { get { return JSONNodeType.NullValue; } } + public override bool IsNull { get { return true; } } + public override Enumerator GetEnumerator() { return new Enumerator(); } + + public override string Value + { + get { return "null"; } + set { } + } + public override bool AsBool + { + get { return false; } + set { } + } + + public override JSONNode Clone() + { + return CreateOrGet(); + } + + public override bool Equals(object obj) + { + if (object.ReferenceEquals(this, obj)) + return true; + return (obj is JSONNull); + } + public override int GetHashCode() + { + return 0; + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append("null"); + } + } + // End of JSONNull + + internal partial class JSONLazyCreator : JSONNode + { + private JSONNode m_Node = null; + private string m_Key = null; + public override JSONNodeType Tag { get { return JSONNodeType.None; } } + public override Enumerator GetEnumerator() { return new Enumerator(); } + + public JSONLazyCreator(JSONNode aNode) + { + m_Node = aNode; + m_Key = null; + } + + public JSONLazyCreator(JSONNode aNode, string aKey) + { + m_Node = aNode; + m_Key = aKey; + } + + private T Set(T aVal) where T : JSONNode + { + if (m_Key == null) + m_Node.Add(aVal); + else + m_Node.Add(m_Key, aVal); + m_Node = null; // Be GC friendly. + return aVal; + } + + public override JSONNode this[int aIndex] + { + get { return new JSONLazyCreator(this); } + set { Set(new JSONArray()).Add(value); } + } + + public override JSONNode this[string aKey] + { + get { return new JSONLazyCreator(this, aKey); } + set { Set(new JSONObject()).Add(aKey, value); } + } + + public override void Add(JSONNode aItem) + { + Set(new JSONArray()).Add(aItem); + } + + public override void Add(string aKey, JSONNode aItem) + { + Set(new JSONObject()).Add(aKey, aItem); + } + + public static bool operator ==(JSONLazyCreator a, object b) + { + if (b == null) + return true; + return System.Object.ReferenceEquals(a, b); + } + + public static bool operator !=(JSONLazyCreator a, object b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (obj == null) + return true; + return System.Object.ReferenceEquals(this, obj); + } + + public override int GetHashCode() + { + return 0; + } + + public override int AsInt + { + get { Set(new JSONNumber(0)); return 0; } + set { Set(new JSONNumber(value)); } + } + + public override float AsFloat + { + get { Set(new JSONNumber(0.0f)); return 0.0f; } + set { Set(new JSONNumber(value)); } + } + + public override double AsDouble + { + get { Set(new JSONNumber(0.0)); return 0.0; } + set { Set(new JSONNumber(value)); } + } + + public override long AsLong + { + get + { + if (longAsString) + Set(new JSONString("0")); + else + Set(new JSONNumber(0.0)); + return 0L; + } + set + { + if (longAsString) + Set(new JSONString(value.ToString(CultureInfo.InvariantCulture))); + else + Set(new JSONNumber(value)); + } + } + + public override ulong AsULong + { + get + { + if (longAsString) + Set(new JSONString("0")); + else + Set(new JSONNumber(0.0)); + return 0L; + } + set + { + if (longAsString) + Set(new JSONString(value.ToString(CultureInfo.InvariantCulture))); + else + Set(new JSONNumber(value)); + } + } + + public override bool AsBool + { + get { Set(new JSONBool(false)); return false; } + set { Set(new JSONBool(value)); } + } + + public override JSONArray AsArray + { + get { return Set(new JSONArray()); } + } + + public override JSONObject AsObject + { + get { return Set(new JSONObject()); } + } + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append("null"); + } + } + // End of JSONLazyCreator + + public static class JSON + { + public static JSONNode Parse(string aJSON) + { + return JSONNode.Parse(aJSON); + } + } +} +#endregion diff --git a/addons/ai_voices/GenerateDialog.cs.uid b/addons/ai_voices/GenerateDialog.cs.uid new file mode 100644 index 0000000..1d7a3af --- /dev/null +++ b/addons/ai_voices/GenerateDialog.cs.uid @@ -0,0 +1 @@ +uid://srkgrxnfaw0o diff --git a/addons/ai_voices/Voices.cs b/addons/ai_voices/Voices.cs new file mode 100644 index 0000000..8e42a65 --- /dev/null +++ b/addons/ai_voices/Voices.cs @@ -0,0 +1,23 @@ +#if TOOLS +using Godot; +using System; + +[Tool] +public partial class Voices : EditorPlugin +{ + Control dock; + + public override void _EnterTree() + { + dock = (Control)GD.Load("addons/ai_voices/Dock_aivoices.tscn").Instantiate(); + AddControlToDock(DockSlot.LeftUl, dock); + } + + public override void _ExitTree() + { + RemoveControlFromDocks(dock); + dock.Free(); + } + +} +#endif diff --git a/addons/ai_voices/Voices.cs.uid b/addons/ai_voices/Voices.cs.uid new file mode 100644 index 0000000..88e0e97 --- /dev/null +++ b/addons/ai_voices/Voices.cs.uid @@ -0,0 +1 @@ +uid://dbb78cttweipf diff --git a/addons/ai_voices/icon-aivoices.png b/addons/ai_voices/icon-aivoices.png new file mode 100644 index 0000000000000000000000000000000000000000..589d74ba49f9ea9a5b645d4db710323be3d2e8dc GIT binary patch literal 504 zcmV0&bB*M9UdN&iX}3WaEZE^rFm19MOd6iKm{=$rlU^^ uT`2-yd_S6=RKPQEWBPR4*o8ttHSrB+CcJQ>vDqpB0000