Add "refresh voices" context menu for Piper/ElevenLabs

This commit is contained in:
Nikolaj Olsson 2024-04-27 19:07:14 +02:00
parent ecdcb7fe7e
commit 0c6e8fb10f
12 changed files with 1219 additions and 224 deletions

View File

@ -192,5 +192,50 @@ namespace Test.Core
}".Replace('\'', '"'), "items");
Assert.AreEqual(4, result.Count);
}
[TestMethod]
public void GetRootElements_Simple_Value()
{
var parser = new SeJsonParser();
var result = parser.GetRootElements("{ \"tag\": \"hi there!\" }");
Assert.AreEqual(1, result.Count);
Assert.AreEqual("tag", result[0].Name);
Assert.AreEqual("hi there!", result[0].Json);
}
[TestMethod]
public void GetRootElements_Simple_Object()
{
var parser = new SeJsonParser();
var result = parser.GetRootElements("{ \"tag\": { \"name\" : \"Joe\" } }");
Assert.AreEqual(1, result.Count);
Assert.AreEqual("tag", result[0].Name);
Assert.AreEqual("{ \"name\" : \"Joe\" }", result[0].Json);
}
[TestMethod]
public void GetRootElements_Simple_Value_And_Object()
{
var parser = new SeJsonParser();
var result = parser.GetRootElements("{ \"tag1\": \"hi there!\", \"tag2\": { \"name\" : \"Joe\" } }");
Assert.AreEqual(2, result.Count);
Assert.AreEqual("tag1", result[0].Name);
Assert.AreEqual("hi there!", result[0].Json);
Assert.AreEqual("tag2", result[1].Name);
Assert.AreEqual("{ \"name\" : \"Joe\" }", result[1].Json);
}
[TestMethod]
public void GetRootElements_Two_Simple_Value()
{
var parser = new SeJsonParser();
var result = parser.GetRootElements("{ \"tag\": \"hi there!\",\"tag2\": \"hi!\", }");
Assert.AreEqual(2, result.Count);
Assert.AreEqual("tag", result[0].Name);
Assert.AreEqual("hi there!", result[0].Json);
Assert.AreEqual("tag2", result[1].Name);
Assert.AreEqual("hi!", result[1].Json);
}
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using Nikse.SubtitleEdit.Core.ContainerFormats.Ebml;
using System.Collections.Generic;
using System.Text;
namespace Nikse.SubtitleEdit.Core.Common
@ -1300,5 +1301,389 @@ namespace Nikse.SubtitleEdit.Core.Common
}
return string.Empty;
}
public class RootElement
{
public string Name { get; set; }
public string Json { get; set; }
}
public List<RootElement> GetRootElements(string content)
{
Errors = new List<string>();
var list = new List<RootElement>();
var i = 0;
var max = content.Length;
var state = new Stack<StateElement>();
var objectName = string.Empty;
var start = -1;
while (i < max)
{
var ch = content[i];
if (_whiteSpace.Contains(ch)) // ignore white space
{
i++;
}
else if (state.Count == 0) // root
{
if (ch == '{')
{
state.Push(new StateElement
{
Name = "Root",
State = SeJsonState.Object
});
i++;
}
else if (ch == '[')
{
state.Push(new StateElement
{
Name = "Root",
State = SeJsonState.Array
});
i++;
}
else
{
Errors.Add($"Unexpected char {ch} at position {i}");
return list;
}
}
else if (state.Peek().State == SeJsonState.Object) // after '{'
{
if (ch == '"')
{
i++;
int end = content.IndexOf('"', i);
objectName = content.Substring(i, end - i).Trim();
int colon = content.IndexOf(':', end);
if (colon < 0)
{
Errors.Add($"Fatal - expected char : after position {end}");
return list;
}
i += colon - i + 1;
state.Push(new StateElement
{
Name = objectName,
State = SeJsonState.Value
});
if (state.Count == 2)
{
start = i; // element in root
}
}
else if (ch == '}')
{
i++;
state.Pop();
if (state.Count == 2 && start >= 0)
{
var str = content.Substring(start, i - start).Trim();
list.Add(new RootElement()
{
Name = state.Peek().Name,
Json = str,
});
start = -1;
}
}
else if (ch == ',') // next object
{
if (state.Count == 1 && start >= 0)
{
var str = content.Substring(start, i - start).Trim();
list.Add(new RootElement()
{
Name = state.Peek().Name,
Json = str,
});
start = i + 1;
}
i++;
if (state.Peek().Count > 0)
{
state.Peek().Count++;
}
else
{
Errors.Add($"Unexpected char {ch} at position {i}");
return list;
}
}
else if (ch == ']') // next object
{
i++;
if (state.Peek().Count > 0)
{
state.Pop();
}
else
{
Errors.Add($"Unexpected char {ch} at position {i}");
return list;
}
}
else
{
Errors.Add($"Unexpected char {ch} at position {i}");
return list;
}
}
else if (state.Peek().State == SeJsonState.Value) // value - string/ number / object / array / true / false / null + "," + "}"
{
if (ch == '"') // string
{
i++;
var skip = true;
int end = 0;
var endSeek = i;
while (skip)
{
end = content.IndexOf('"', endSeek);
if (end < 0)
{
Errors.Add($"Fatal - expected char \" after position {endSeek}");
return list;
}
skip = content[end - 1] == '\\';
if (skip)
{
endSeek = end + 1;
}
if (endSeek >= max)
{
Errors.Add($"Fatal - expected end tag after position {endSeek}");
return list;
}
}
if (state.Count == 2)
{
var objectValue = content.Substring(i, end - i).Trim();
var x = state.Peek();
list.Add(new RootElement(){ Name = x.Name, Json = objectValue });
start = -1;
}
i += end - i + 1;
state.Pop();
if (state.Count > 0)
{
state.Peek().Count++;
}
}
else if (ch == '}') // empty value
{
i++;
var value = state.Pop();
if (state.Count > 0)
{
if (value.State == SeJsonState.Value)
{
var st = state.Pop();
if (state.Count == 2)
{
var str = content.Substring(start, i - start).Trim();
list.Add(new RootElement()
{
Name = state.Peek().Name,
Json = str,
});
start = -1;
}
}
else
{
state.Peek().Count++;
}
}
}
else if (ch == ',') // next object
{
i++;
state.Pop();
if (state.Count > 0 && state.Peek().Count > 0)
{
state.Peek().Count++;
}
else
{
Errors.Add($"Unexpected char {ch} at position {i}");
return list;
}
}
else if (ch == 'n' && max > i + 3 && content[i + 1] == 'u' && content[i + 2] == 'l' && content[i + 3] == 'l')
{
i += 4;
state.Pop();
if (state.Count > 0)
{
state.Peek().Count++;
}
//if (objectName == name)
//{
// list.Add(null);
//}
}
else if (ch == 't' && max > i + 3 && content[i + 1] == 'r' && content[i + 2] == 'u' && content[i + 3] == 'e')
{
i += 4;
state.Pop();
if (state.Count > 0)
{
state.Peek().Count++;
}
//if (objectName == name)
//{
// list.Add("true");
//}
}
else if (ch == 'f' && max > i + 4 && content[i + 1] == 'a' && content[i + 2] == 'l' && content[i + 3] == 's' && content[i + 4] == 'e')
{
i += 5;
state.Pop();
if (state.Count > 0)
{
state.Peek().Count++;
}
//if (objectName == name)
//{
// list.Add("false");
//}
}
else if ("+-0123456789".IndexOf(ch) >= 0)
{
var sb = new StringBuilder();
while (i < max && "+-0123456789.Ee".IndexOf(content[i]) >= 0)
{
sb.Append(content[i]);
i++;
}
state.Pop();
if (state.Count > 0)
{
state.Peek().Count++;
}
//if (objectName == name)
//{
// list.Add(sb.ToString());
//}
}
else if (ch == '{')
{
if (state.Count > 1)
{
var value = state.Pop();
state.Peek().Count++;
state.Push(value);
}
state.Push(new StateElement
{
State = SeJsonState.Object,
Name = objectName
});
i++;
}
else if (ch == '[')
{
if (state.Count > 1)
{
var value = state.Pop();
state.Peek().Count++;
state.Push(value);
}
state.Push(new StateElement
{
State = SeJsonState.Array,
Name = objectName
});
i++;
//if (start < 0 && objectName == name)
//{
// start = i;
//}
}
else
{
Errors.Add($"Unexpected char {ch} at position {i}");
return list;
}
}
else if (state.Peek().State == SeJsonState.Array) // array, after '['
{
if (ch == ']')
{
state.Pop();
i++;
//if (state.Count > 0 && state.Peek().Name == name && start > -1)
//{
// list.Add(content.Substring(start, i - start - 1).Trim());
// start = -1;
//}
}
else if (ch == ',' && state.Peek().Count > 0)
{
//if (start >= 0 && state.Peek().State == SeJsonState.Array && state.Peek().Name == name)
//{
// list.Add(content.Substring(start, i - start).Trim());
// start = i + 1;
//}
if (state.Count > 0 && state.Peek().Count > 0)
{
state.Peek().Count++;
}
else
{
Errors.Add($"Unexpected char {ch} at position {i}");
return list;
}
i++;
}
else if (ch == '{')
{
if (state.Count > 0)
{
state.Peek().Count++;
}
state.Push(new StateElement
{
Name = objectName,
State = SeJsonState.Object
});
i++;
}
else
{
if (state.Count > 0)
{
state.Peek().Count++;
}
state.Push(new StateElement
{
Name = objectName + "_array_value",
State = SeJsonState.Value
});
}
}
}
return list;
}
}
}

View File

@ -193,6 +193,8 @@ namespace Nikse.SubtitleEdit.Core.Common
public string TextToSpeechEngine { get; set; }
public string TextToSpeechLastVoice { get; set; }
public string TextToSpeechElevenLabsApiKey { get; set; }
public string TextToSpeechAzureApiKey { get; set; }
public string TextToSpeechAzureRegion { get; set; }
public bool DisableVidoInfoViaLabel { get; set; }
public bool ListViewSyntaxColorDurationSmall { get; set; }
public bool ListViewSyntaxColorDurationBig { get; set; }
@ -557,6 +559,7 @@ namespace Nikse.SubtitleEdit.Core.Common
AnthropicApiUrl = "https://api.anthropic.com/v1/messages";
AnthropicPrompt = "Translate from {0} to {1}, keep sentences in {1} as they are, do not censor the translation, give only the output without commenting on what you read:";
AnthropicApiModel = "claude-3-opus-20240229";
TextToSpeechAzureRegion = "westeurope";
TranslateAllowSplit = true;
TranslateViaCopyPasteAutoCopyToClipboard = true;
TranslateViaCopyPasteMaxSize = 5000;
@ -5481,6 +5484,18 @@ $HorzAlign = Center
settings.Tools.TextToSpeechElevenLabsApiKey = subNode.InnerText;
}
subNode = node.SelectSingleNode("TextToSpeechAzureApiKey");
if (subNode != null)
{
settings.Tools.TextToSpeechAzureApiKey = subNode.InnerText;
}
subNode = node.SelectSingleNode("TextToSpeechAzureRegion");
if (subNode != null)
{
settings.Tools.TextToSpeechAzureRegion = subNode.InnerText;
}
subNode = node.SelectSingleNode("TranslateViaCopyPasteAutoCopyToClipboard");
if (subNode != null)
{
@ -12023,6 +12038,8 @@ $HorzAlign = Center
textWriter.WriteElementString("TextToSpeechEngine", settings.Tools.TextToSpeechEngine);
textWriter.WriteElementString("TextToSpeechLastVoice", settings.Tools.TextToSpeechLastVoice);
textWriter.WriteElementString("TextToSpeechElevenLabsApiKey", settings.Tools.TextToSpeechElevenLabsApiKey);
textWriter.WriteElementString("TextToSpeechAzureApiKey", settings.Tools.TextToSpeechAzureApiKey);
textWriter.WriteElementString("TextToSpeechAzureRegion", settings.Tools.TextToSpeechAzureRegion);
textWriter.WriteElementString("DisableVidoInfoViaLabel", settings.Tools.DisableVidoInfoViaLabel.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ListViewSyntaxColorDurationSmall", settings.Tools.ListViewSyntaxColorDurationSmall.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ListViewSyntaxColorDurationBig", settings.Tools.ListViewSyntaxColorDurationBig.ToString(CultureInfo.InvariantCulture));

View File

@ -0,0 +1,30 @@
using System.Linq;
namespace Nikse.SubtitleEdit.Core.TextToSpeech
{
public class PiperModel
{
public string Voice { get; set; }
public string Language { get; set; }
public string Quality { get; set; }
public string Model { get; set; }
public string ModelShort => Model.Split('/').Last();
public string Config { get; set; }
public string ConfigShort => Config.Split('/').Last();
public override string ToString()
{
return $"{Language} - {Voice} ({Quality})";
}
public PiperModel(string voice, string language, string quality, string model, string config)
{
Voice = voice;
Language = language;
Quality = quality;
Model = model;
Config = config;
}
}
}

View File

@ -1,105 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace Nikse.SubtitleEdit.Core.TextToSpeech
{
public class PiperModels
{
public string Voice { get; set; }
public string Language { get; set; }
public string Quality { get; set; }
public string Model { get; set; }
public string ModelShort => Model.Split('/').Last();
public string Config { get; set; }
public string ConfigShort => Config.Split('/').Last();
public override string ToString()
{
return $"{Language} - {Voice} ({Quality})";
}
public PiperModels(string voice, string language, string quality, string model, string config)
{
Voice = voice;
Language = language;
Quality = quality;
Model = model;
Config = config;
}
public static List<PiperModels> GetVoices()
{
var models = new List<PiperModels>
{
new PiperModels("kareem", "Arabic", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ar/ar_JO/kareem/medium/ar_JO-kareem-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ar/ar_JO/kareem/medium/ar_JO-kareem-medium.onnx.json"),
new PiperModels("upc_ona", "Catalan", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ca/ca_ES/upc_ona/medium/ca_ES-upc_ona-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ca/ca_ES/upc_ona/medium/ca_ES-upc_ona-medium.onnx.json"),
new PiperModels("jirka", "Czech", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/cs/cs_CZ/jirka/medium/cs_CZ-jirka-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/cs/cs_CZ/jirka/medium/cs_CZ-jirka-medium.onnx.json"),
new PiperModels("talesyntese", "Danish", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/da/da_DK/talesyntese/medium/da_DK-talesyntese-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/da/da_DK/talesyntese/medium/da_DK-talesyntese-medium.onnx.json"),
new PiperModels("eva_k", "German", "low", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/de/de_DE/eva_k/x_low/de_DE-eva_k-x_low.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/de/de_DE/eva_k/x_low/de_DE-eva_k-x_low.onnx.json"),
new PiperModels("rapunzelina", "Greek", "low", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/el/el_GR/rapunzelina/low/el_GR-rapunzelina-low.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/el/el_GR/rapunzelina/low/el_GR-rapunzelina-low.onnx.json"),
new PiperModels("alan", "English GB", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/alan/medium/en_GB-alan-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/alan/medium/en_GB-alan-medium.onnx.json"),
new PiperModels("alba", "English GB", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/alba/medium/en_GB-alba-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/alba/medium/en_GB-alba-medium.onnx.json"),
new PiperModels("cori", "English GB", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/cori/high/en_GB-cori-high.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/cori/medium/en_GB-cori-medium.onnx.json"),
new PiperModels("jenny_dioco", "English GB", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/jenny_dioco/medium/en_GB-jenny_dioco-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/jenny_dioco/medium/en_GB-jenny_dioco-medium.onnx.json"),
new PiperModels("northern_english_male", "English GB", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/northern_english_male/medium/en_GB-northern_english_male-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/northern_english_male/medium/en_GB-northern_english_male-medium.onnx.json"),
new PiperModels("semaine", "English GB", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/semaine/medium/en_GB-semaine-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/semaine/medium/en_GB-semaine-medium.onnx.json"),
new PiperModels("amy", "English US", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/amy/medium/en_US-amy-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/amy/medium/en_US-amy-medium.onnx.json"),
new PiperModels("arctic", "English US", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/arctic/medium/en_US-arctic-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/arctic/medium/en_US-arctic-medium.onnx.json"),
new PiperModels("hfc_female", "English US", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/hfc_female/medium/en_US-hfc_female-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/hfc_female/medium/en_US-hfc_female-medium.onnx.json"),
new PiperModels("hfc_male", "English US", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/hfc_male/medium/en_US-hfc_male-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/hfc_male/medium/en_US-hfc_male-medium.onnx.json"),
new PiperModels("joe", "English US", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/joe/medium/en_US-joe-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/joe/medium/en_US-joe-medium.onnx.json"),
new PiperModels("kristin", "English US", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/kristin/medium/en_US-kristin-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/kristin/medium/en_US-kristin-medium.onnx.json"),
new PiperModels("kusal", "English US", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/kusal/medium/en_US-kusal-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/kusal/medium/en_US-kusal-medium.onnx.json"),
new PiperModels("l2arctic", "English US", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/l2arctic/medium/en_US-l2arctic-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/l2arctic/medium/en_US-l2arctic-medium.onnx.json"),
new PiperModels("lessac", "English US", "high", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/lessac/high/en_US-lessac-high.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/lessac/high/en_US-lessac-high.onnx.json"),
new PiperModels("libritts", "English US", "high", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/libritts/high/en_US-libritts-high.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/libritts/high/en_US-libritts-high.onnx.json"),
new PiperModels("ljspeech", "English US", "high", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ljspeech/high/en_US-ljspeech-high.onnx.json"),
new PiperModels("ryan", "English US", "high", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ryan/high/en_US-ryan-high.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ryan/high/en_US-ryan-high.onnx.json"),
new PiperModels("davefx", "Spanish ES", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/es/es_ES/davefx/medium/es_ES-davefx-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/es/es_ES/davefx/medium/es_ES-davefx-medium.onnx.json"),
new PiperModels("claude", "Spanish MX", "high", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/es/es_MX/claude/high/es_MX-claude-high.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/es/es_MX/claude/high/es_MX-claude-high.onnx.json"),
new PiperModels("amir", "Farsi", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fa/fa_IR/amir/medium/fa_IR-amir-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fa/fa_IR/amir/medium/fa_IR-amir-medium.onnx.json"),
new PiperModels("gyro", "Farsi", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fa/fa_IR/gyro/medium/fa_IR-gyro-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fa/fa_IR/gyro/medium/fa_IR-gyro-medium.onnx.json"),
new PiperModels("harri", "Finnish", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fi/fi_FI/harri/medium/fi_FI-harri-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fi/fi_FI/harri/medium/fi_FI-harri-medium.onnx.json"),
new PiperModels("mls", "French", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fr/fr_FR/mls/medium/fr_FR-mls-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fr/fr_FR/mls/medium/fr_FR-mls-medium.onnx.json"),
new PiperModels("siwis", "French", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fr/fr_FR/siwis/medium/fr_FR-siwis-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fr/fr_FR/siwis/medium/fr_FR-siwis-medium.onnx.json"),
new PiperModels("tom", "French", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fr/fr_FR/tom/medium/fr_FR-tom-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fr/fr_FR/tom/medium/fr_FR-tom-medium.onnx.json"),
new PiperModels("upmc", "French", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fr/fr_FR/upmc/medium/fr_FR-upmc-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/fr/fr_FR/upmc/medium/fr_FR-upmc-medium.onnx.json?"),
new PiperModels("berta", "Hungarian", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/hu/hu_HU/berta/medium/hu_HU-berta-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/hu/hu_HU/berta/medium/hu_HU-berta-medium.onnx.json"),
new PiperModels("imre", "Hungarian", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/hu/hu_HU/imre/medium/hu_HU-imre-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/hu/hu_HU/imre/medium/hu_HU-imre-medium.onnx.json"),
new PiperModels("bui", "Icelandic", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/is/is_IS/bui/medium/is_IS-bui-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/is/is_IS/bui/medium/is_IS-bui-medium.onnx.json"),
new PiperModels("salka", "Icelandic", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/is/is_IS/salka/medium/is_IS-salka-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/is/is_IS/salka/medium/is_IS-salka-medium.onnx.json"),
new PiperModels("steinn", "Icelandic", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/is/is_IS/steinn/medium/is_IS-steinn-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/is/is_IS/steinn/medium/is_IS-steinn-medium.onnx.json"),
new PiperModels("ugla", "Icelandic", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/is/is_IS/ugla/medium/is_IS-ugla-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/is/is_IS/ugla/medium/is_IS-ugla-medium.onnx.json"),
new PiperModels("riccardo", "Italian", "low", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/it/it_IT/riccardo/x_low/it_IT-riccardo-x_low.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/it/it_IT/riccardo/x_low/it_IT-riccardo-x_low.onnx.json"),
new PiperModels("natia", "Georgian", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ka/ka_GE/natia/medium/ka_GE-natia-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ka/ka_GE/natia/medium/ka_GE-natia-medium.onnx.json"),
new PiperModels("issai", "Kazakh", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/kk/kk_KZ/issai/high/kk_KZ-issai-high.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/kk/kk_KZ/issai/high/kk_KZ-issai-high.onnx.json"),
new PiperModels("marylux", "Luxembourgish", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/lb/lb_LU/marylux/medium/lb_LU-marylux-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/lb/lb_LU/marylux/medium/lb_LU-marylux-medium.onnx.json"),
new PiperModels("google", "Nepali", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ne/ne_NP/google/medium/ne_NP-google-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ne/ne_NP/google/medium/ne_NP-google-medium.onnx.json"),
new PiperModels("nathalie", "Dutch BE", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/nl/nl_BE/nathalie/medium/nl_BE-nathalie-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/nl/nl_BE/nathalie/medium/nl_BE-nathalie-medium.onnx.json"),
new PiperModels("rdh", "Dutch BE", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/nl/nl_BE/rdh/medium/nl_BE-rdh-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/nl/nl_BE/rdh/medium/nl_BE-rdh-medium.onnx.json"),
new PiperModels("mls", "Dutch NL", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/nl/nl_NL/mls/medium/nl_NL-mls-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/nl/nl_NL/mls/medium/nl_NL-mls-medium.onnx.json"),
new PiperModels("talesyntese", "Norwegian", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/no/no_NO/talesyntese/medium/no_NO-talesyntese-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/no/no_NO/talesyntese/medium/no_NO-talesyntese-medium.onnx.json"),
new PiperModels("darkman", "Polish", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pl/pl_PL/darkman/medium/pl_PL-darkman-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pl/pl_PL/darkman/medium/pl_PL-darkman-medium.onnx.json"),
new PiperModels("gosia", "Polish", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pl/pl_PL/gosia/medium/pl_PL-gosia-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pl/pl_PL/gosia/medium/pl_PL-gosia-medium.onnx.json"),
new PiperModels("mc_speech", "Polish", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pl/pl_PL/mc_speech/medium/pl_PL-mc_speech-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pl/pl_PL/mc_speech/medium/pl_PL-mc_speech-medium.onnx.json"),
new PiperModels("faber", "Portuguese BR", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pt/pt_BR/faber/medium/pt_BR-faber-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pt/pt_BR/faber/medium/pt_BR-faber-medium.onnx.json"),
new PiperModels("tugão", "Portuguese PT", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pt/pt_PT/tug%C3%A3o/medium/pt_PT-tug%C3%A3o-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/pt/pt_PT/tug%C3%A3o/medium/pt_PT-tug%C3%A3o-medium.onnx.json"),
new PiperModels("mihai", "Romanian", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ro/ro_RO/mihai/medium/ro_RO-mihai-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ro/ro_RO/mihai/medium/ro_RO-mihai-medium.onnx.json"),
new PiperModels("dmitri", "Russian", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ru/ru_RU/dmitri/medium/ru_RU-dmitri-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ru/ru_RU/dmitri/medium/ru_RU-dmitri-medium.onnx.json"),
new PiperModels("irina", "Serbian", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ru/ru_RU/irina/medium/ru_RU-irina-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/ru/ru_RU/irina/medium/ru_RU-irina-medium.onnx.json"),
new PiperModels("lili", "Slovak ", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sr/sr_RS/serbski_institut/medium/sr_RS-serbski_institut-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sk/sk_SK/lili/medium/sk_SK-lili-medium.onnx.json"),
new PiperModels("artur", "Slovenian ", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sl/sl_SI/artur/medium/sl_SI-artur-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sl/sl_SI/artur/medium/sl_SI-artur-medium.onnx.json"),
new PiperModels("serbski_institut", "Serbian ", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sr/sr_RS/serbski_institut/medium/sr_RS-serbski_institut-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sr/sr_RS/serbski_institut/medium/sr_RS-serbski_institut-medium.onnx.json"),
new PiperModels("nst", "Swedish", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sv/sv_SE/nst/medium/sv_SE-nst-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sv/sv_SE/nst/medium/sv_SE-nst-medium.onnx.json"),
new PiperModels("lanfrica", "Swahili", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sw/sw_CD/lanfrica/medium/sw_CD-lanfrica-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/sw/sw_CD/lanfrica/medium/sw_CD-lanfrica-medium.onnx.json"),
new PiperModels("fettah", "Turkish", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/tr/tr_TR/fettah/medium/tr_TR-fettah-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/tr/tr_TR/fettah/medium/tr_TR-fettah-medium.onnx.json"),
new PiperModels("ukrainian_tts", "Ukrainian", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/uk/uk_UA/ukrainian_tts/medium/uk_UA-ukrainian_tts-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/uk/uk_UA/ukrainian_tts/medium/uk_UA-ukrainian_tts-medium.onnx.json"),
new PiperModels("vais1000", "Vietnamese", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/vi/vi_VN/vais1000/medium/vi_VN-vais1000-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/vi/vi_VN/vais1000/medium/vi_VN-vais1000-medium.onnx.json"),
new PiperModels("huayan", "Chinese", "medium", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/zh/zh_CN/huayan/medium/zh_CN-huayan-medium.onnx", "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/zh/zh_CN/huayan/medium/zh_CN-huayan-medium.onnx.json"),
};
return models.OrderBy(p=>p.ToString()).ToList();
}
}
}

View File

@ -23,6 +23,11 @@ namespace Nikse.SubtitleEdit.Controls
_items.AddRange(items);
}
public void AddRange(string[] items)
{
_items.AddRange(items);
}
public IEnumerator GetEnumerator()
{
return _items.GetEnumerator();

View File

@ -35,23 +35,28 @@
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.labelEngine = new System.Windows.Forms.Label();
this.groupBoxMsSettings = new System.Windows.Forms.GroupBox();
this.labelRegion = new System.Windows.Forms.Label();
this.nikseComboBoxRegion = new Nikse.SubtitleEdit.Controls.NikseComboBox();
this.labelVoiceCount = new System.Windows.Forms.Label();
this.checkBoxShowPreview = new System.Windows.Forms.CheckBox();
this.labelApiKey = new System.Windows.Forms.Label();
this.nikseTextBoxApiKey = new Nikse.SubtitleEdit.Controls.NikseTextBox();
this.TextBoxTest = new Nikse.SubtitleEdit.Controls.NikseTextBox();
this.buttonTestVoice = new System.Windows.Forms.Button();
this.checkBoxAddToVideoFile = new System.Windows.Forms.CheckBox();
this.labelVoice = new System.Windows.Forms.Label();
this.nikseComboBoxVoice = new Nikse.SubtitleEdit.Controls.NikseComboBox();
this.contextMenuStripVoices = new System.Windows.Forms.ContextMenuStrip(this.components);
this.refreshVoicesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.nikseComboBoxEngine = new Nikse.SubtitleEdit.Controls.NikseComboBox();
this.listViewActors = new System.Windows.Forms.ListView();
this.columnHeaderActor = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeaderVoice = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.contextMenuStripActors = new System.Windows.Forms.ContextMenuStrip(this.components);
this.labelActors = new System.Windows.Forms.Label();
this.buttonCancel = new System.Windows.Forms.Button();
this.labelVoiceCount = new System.Windows.Forms.Label();
this.nikseTextBoxApiKey = new Nikse.SubtitleEdit.Controls.NikseTextBox();
this.TextBoxTest = new Nikse.SubtitleEdit.Controls.NikseTextBox();
this.nikseComboBoxVoice = new Nikse.SubtitleEdit.Controls.NikseComboBox();
this.nikseComboBoxEngine = new Nikse.SubtitleEdit.Controls.NikseComboBox();
this.groupBoxMsSettings.SuspendLayout();
this.contextMenuStripVoices.SuspendLayout();
this.SuspendLayout();
//
// buttonOK
@ -112,6 +117,8 @@
//
this.groupBoxMsSettings.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.groupBoxMsSettings.Controls.Add(this.labelRegion);
this.groupBoxMsSettings.Controls.Add(this.nikseComboBoxRegion);
this.groupBoxMsSettings.Controls.Add(this.labelVoiceCount);
this.groupBoxMsSettings.Controls.Add(this.checkBoxShowPreview);
this.groupBoxMsSettings.Controls.Add(this.labelApiKey);
@ -130,6 +137,83 @@
this.groupBoxMsSettings.TabStop = false;
this.groupBoxMsSettings.Text = "Settings";
//
// labelRegion
//
this.labelRegion.AutoSize = true;
this.labelRegion.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.labelRegion.Location = new System.Drawing.Point(14, 267);
this.labelRegion.Name = "labelRegion";
this.labelRegion.Size = new System.Drawing.Size(41, 13);
this.labelRegion.TabIndex = 32;
this.labelRegion.Text = "Region";
//
// nikseComboBoxRegion
//
this.nikseComboBoxRegion.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.nikseComboBoxRegion.BackColor = System.Drawing.SystemColors.Window;
this.nikseComboBoxRegion.BackColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
this.nikseComboBoxRegion.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(171)))), ((int)(((byte)(173)))), ((int)(((byte)(179)))));
this.nikseComboBoxRegion.BorderColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120)))));
this.nikseComboBoxRegion.ButtonForeColor = System.Drawing.SystemColors.ControlText;
this.nikseComboBoxRegion.ButtonForeColorDown = System.Drawing.Color.Orange;
this.nikseComboBoxRegion.ButtonForeColorOver = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.nikseComboBoxRegion.DropDownHeight = 400;
this.nikseComboBoxRegion.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.nikseComboBoxRegion.DropDownWidth = 0;
this.nikseComboBoxRegion.FormattingEnabled = false;
this.nikseComboBoxRegion.Items.AddRange(new string[] {
"australiaeast",
"brazilsouth",
"canadacentral",
"centralus",
"eastasia",
"eastus",
"eastus2",
"francecentral",
"germanywestcentral",
"centralindia",
"japaneast",
"japanwest",
"jioindiawest",
"koreacentral",
"northcentralus",
"northeurope",
"norwayeast",
"southcentralus",
"southeastasia",
"swedencentral",
"switzerlandnorth",
"switzerlandwest",
"uaenorth",
"usgovarizona",
"usgovvirginia",
"uksouth",
"westcentralus",
"westeurope",
"westus",
"westus2",
"westus3"});
this.nikseComboBoxRegion.Location = new System.Drawing.Point(17, 283);
this.nikseComboBoxRegion.MaxLength = 32767;
this.nikseComboBoxRegion.Name = "nikseComboBoxRegion";
this.nikseComboBoxRegion.SelectedIndex = -1;
this.nikseComboBoxRegion.SelectedItem = null;
this.nikseComboBoxRegion.SelectedText = "";
this.nikseComboBoxRegion.Size = new System.Drawing.Size(351, 23);
this.nikseComboBoxRegion.TabIndex = 31;
this.nikseComboBoxRegion.UsePopupWindow = false;
//
// labelVoiceCount
//
this.labelVoiceCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.labelVoiceCount.Location = new System.Drawing.Point(268, 84);
this.labelVoiceCount.Name = "labelVoiceCount";
this.labelVoiceCount.Size = new System.Drawing.Size(100, 23);
this.labelVoiceCount.TabIndex = 29;
this.labelVoiceCount.Text = "255";
this.labelVoiceCount.TextAlign = System.Drawing.ContentAlignment.BottomRight;
//
// checkBoxShowPreview
//
this.checkBoxShowPreview.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
@ -147,15 +231,37 @@
//
this.labelApiKey.AutoSize = true;
this.labelApiKey.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.labelApiKey.Location = new System.Drawing.Point(20, 242);
this.labelApiKey.Location = new System.Drawing.Point(20, 224);
this.labelApiKey.Name = "labelApiKey";
this.labelApiKey.Size = new System.Drawing.Size(44, 13);
this.labelApiKey.TabIndex = 28;
this.labelApiKey.Text = "API key";
//
// nikseTextBoxApiKey
//
this.nikseTextBoxApiKey.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.nikseTextBoxApiKey.FocusedColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.nikseTextBoxApiKey.Location = new System.Drawing.Point(17, 240);
this.nikseTextBoxApiKey.Name = "nikseTextBoxApiKey";
this.nikseTextBoxApiKey.Size = new System.Drawing.Size(351, 20);
this.nikseTextBoxApiKey.TabIndex = 27;
//
// TextBoxTest
//
this.TextBoxTest.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.TextBoxTest.FocusedColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.TextBoxTest.Location = new System.Drawing.Point(17, 168);
this.TextBoxTest.Name = "TextBoxTest";
this.TextBoxTest.Size = new System.Drawing.Size(351, 20);
this.TextBoxTest.TabIndex = 20;
this.TextBoxTest.Text = "Hello, how are you?";
this.TextBoxTest.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxTest_KeyDown);
//
// buttonTestVoice
//
this.buttonTestVoice.Location = new System.Drawing.Point(17, 158);
this.buttonTestVoice.Location = new System.Drawing.Point(17, 139);
this.buttonTestVoice.Name = "buttonTestVoice";
this.buttonTestVoice.Size = new System.Drawing.Size(150, 23);
this.buttonTestVoice.TabIndex = 15;
@ -180,12 +286,80 @@
//
this.labelVoice.AutoSize = true;
this.labelVoice.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.labelVoice.Location = new System.Drawing.Point(14, 108);
this.labelVoice.Location = new System.Drawing.Point(14, 94);
this.labelVoice.Name = "labelVoice";
this.labelVoice.Size = new System.Drawing.Size(34, 13);
this.labelVoice.TabIndex = 16;
this.labelVoice.Text = "Voice";
//
// nikseComboBoxVoice
//
this.nikseComboBoxVoice.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.nikseComboBoxVoice.BackColor = System.Drawing.SystemColors.Window;
this.nikseComboBoxVoice.BackColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
this.nikseComboBoxVoice.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(171)))), ((int)(((byte)(173)))), ((int)(((byte)(179)))));
this.nikseComboBoxVoice.BorderColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120)))));
this.nikseComboBoxVoice.ButtonForeColor = System.Drawing.SystemColors.ControlText;
this.nikseComboBoxVoice.ButtonForeColorDown = System.Drawing.Color.Orange;
this.nikseComboBoxVoice.ButtonForeColorOver = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.nikseComboBoxVoice.ContextMenuStrip = this.contextMenuStripVoices;
this.nikseComboBoxVoice.DropDownHeight = 400;
this.nikseComboBoxVoice.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.nikseComboBoxVoice.DropDownWidth = 0;
this.nikseComboBoxVoice.FormattingEnabled = false;
this.nikseComboBoxVoice.Location = new System.Drawing.Point(17, 110);
this.nikseComboBoxVoice.MaxLength = 32767;
this.nikseComboBoxVoice.Name = "nikseComboBoxVoice";
this.nikseComboBoxVoice.SelectedIndex = -1;
this.nikseComboBoxVoice.SelectedItem = null;
this.nikseComboBoxVoice.SelectedText = "";
this.nikseComboBoxVoice.Size = new System.Drawing.Size(351, 23);
this.nikseComboBoxVoice.TabIndex = 10;
this.nikseComboBoxVoice.UsePopupWindow = false;
//
// contextMenuStripVoices
//
this.contextMenuStripVoices.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.refreshVoicesToolStripMenuItem});
this.contextMenuStripVoices.Name = "contextMenuStripVoices";
this.contextMenuStripVoices.Size = new System.Drawing.Size(150, 26);
this.contextMenuStripVoices.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStripVoices_Opening);
//
// refreshVoicesToolStripMenuItem
//
this.refreshVoicesToolStripMenuItem.Name = "refreshVoicesToolStripMenuItem";
this.refreshVoicesToolStripMenuItem.Size = new System.Drawing.Size(149, 22);
this.refreshVoicesToolStripMenuItem.Text = "Refresh voices";
this.refreshVoicesToolStripMenuItem.Click += new System.EventHandler(this.refreshVoicesToolStripMenuItem_Click);
//
// nikseComboBoxEngine
//
this.nikseComboBoxEngine.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.nikseComboBoxEngine.BackColor = System.Drawing.SystemColors.Window;
this.nikseComboBoxEngine.BackColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
this.nikseComboBoxEngine.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(171)))), ((int)(((byte)(173)))), ((int)(((byte)(179)))));
this.nikseComboBoxEngine.BorderColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120)))));
this.nikseComboBoxEngine.ButtonForeColor = System.Drawing.SystemColors.ControlText;
this.nikseComboBoxEngine.ButtonForeColorDown = System.Drawing.Color.Orange;
this.nikseComboBoxEngine.ButtonForeColorOver = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.nikseComboBoxEngine.DropDownHeight = 400;
this.nikseComboBoxEngine.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDown;
this.nikseComboBoxEngine.DropDownWidth = 391;
this.nikseComboBoxEngine.FormattingEnabled = false;
this.nikseComboBoxEngine.Location = new System.Drawing.Point(17, 40);
this.nikseComboBoxEngine.MaxLength = 32767;
this.nikseComboBoxEngine.Name = "nikseComboBoxEngine";
this.nikseComboBoxEngine.SelectedIndex = -1;
this.nikseComboBoxEngine.SelectedItem = null;
this.nikseComboBoxEngine.SelectedText = "";
this.nikseComboBoxEngine.Size = new System.Drawing.Size(351, 23);
this.nikseComboBoxEngine.TabIndex = 5;
this.nikseComboBoxEngine.TabStop = false;
this.nikseComboBoxEngine.Text = "nikseComboBox1";
this.nikseComboBoxEngine.UsePopupWindow = false;
//
// listViewActors
//
this.listViewActors.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
@ -243,91 +417,6 @@
this.buttonCancel.UseVisualStyleBackColor = true;
this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click);
//
// labelVoiceCount
//
this.labelVoiceCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.labelVoiceCount.Location = new System.Drawing.Point(268, 98);
this.labelVoiceCount.Name = "labelVoiceCount";
this.labelVoiceCount.Size = new System.Drawing.Size(100, 23);
this.labelVoiceCount.TabIndex = 29;
this.labelVoiceCount.Text = "255";
this.labelVoiceCount.TextAlign = System.Drawing.ContentAlignment.BottomRight;
//
// nikseTextBoxApiKey
//
this.nikseTextBoxApiKey.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.nikseTextBoxApiKey.FocusedColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.nikseTextBoxApiKey.Location = new System.Drawing.Point(17, 258);
this.nikseTextBoxApiKey.Name = "nikseTextBoxApiKey";
this.nikseTextBoxApiKey.Size = new System.Drawing.Size(351, 20);
this.nikseTextBoxApiKey.TabIndex = 27;
//
// TextBoxTest
//
this.TextBoxTest.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.TextBoxTest.FocusedColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.TextBoxTest.Location = new System.Drawing.Point(17, 187);
this.TextBoxTest.Name = "TextBoxTest";
this.TextBoxTest.Size = new System.Drawing.Size(351, 20);
this.TextBoxTest.TabIndex = 20;
this.TextBoxTest.Text = "Hello, how are you?";
this.TextBoxTest.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxTest_KeyDown);
//
// nikseComboBoxVoice
//
this.nikseComboBoxVoice.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.nikseComboBoxVoice.BackColor = System.Drawing.SystemColors.Window;
this.nikseComboBoxVoice.BackColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
this.nikseComboBoxVoice.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(171)))), ((int)(((byte)(173)))), ((int)(((byte)(179)))));
this.nikseComboBoxVoice.BorderColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120)))));
this.nikseComboBoxVoice.ButtonForeColor = System.Drawing.SystemColors.ControlText;
this.nikseComboBoxVoice.ButtonForeColorDown = System.Drawing.Color.Orange;
this.nikseComboBoxVoice.ButtonForeColorOver = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.nikseComboBoxVoice.DropDownHeight = 400;
this.nikseComboBoxVoice.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.nikseComboBoxVoice.DropDownWidth = 0;
this.nikseComboBoxVoice.FormattingEnabled = false;
this.nikseComboBoxVoice.Location = new System.Drawing.Point(17, 124);
this.nikseComboBoxVoice.MaxLength = 32767;
this.nikseComboBoxVoice.Name = "nikseComboBoxVoice";
this.nikseComboBoxVoice.SelectedIndex = -1;
this.nikseComboBoxVoice.SelectedItem = null;
this.nikseComboBoxVoice.SelectedText = "";
this.nikseComboBoxVoice.Size = new System.Drawing.Size(351, 23);
this.nikseComboBoxVoice.TabIndex = 10;
this.nikseComboBoxVoice.UsePopupWindow = false;
//
// nikseComboBoxEngine
//
this.nikseComboBoxEngine.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.nikseComboBoxEngine.BackColor = System.Drawing.SystemColors.Window;
this.nikseComboBoxEngine.BackColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
this.nikseComboBoxEngine.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(171)))), ((int)(((byte)(173)))), ((int)(((byte)(179)))));
this.nikseComboBoxEngine.BorderColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120)))));
this.nikseComboBoxEngine.ButtonForeColor = System.Drawing.SystemColors.ControlText;
this.nikseComboBoxEngine.ButtonForeColorDown = System.Drawing.Color.Orange;
this.nikseComboBoxEngine.ButtonForeColorOver = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.nikseComboBoxEngine.DropDownHeight = 400;
this.nikseComboBoxEngine.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDown;
this.nikseComboBoxEngine.DropDownWidth = 391;
this.nikseComboBoxEngine.FormattingEnabled = false;
this.nikseComboBoxEngine.Location = new System.Drawing.Point(17, 40);
this.nikseComboBoxEngine.MaxLength = 32767;
this.nikseComboBoxEngine.Name = "nikseComboBoxEngine";
this.nikseComboBoxEngine.SelectedIndex = -1;
this.nikseComboBoxEngine.SelectedItem = null;
this.nikseComboBoxEngine.SelectedText = "";
this.nikseComboBoxEngine.Size = new System.Drawing.Size(351, 23);
this.nikseComboBoxEngine.TabIndex = 5;
this.nikseComboBoxEngine.TabStop = false;
this.nikseComboBoxEngine.Text = "nikseComboBox1";
this.nikseComboBoxEngine.UsePopupWindow = false;
this.nikseComboBoxEngine.SelectedIndexChanged += new System.EventHandler(this.nikseComboBoxEngine_SelectedIndexChanged);
//
// TextToSpeech
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -342,7 +431,7 @@
this.Controls.Add(this.labelProgress);
this.Controls.Add(this.buttonOK);
this.KeyPreview = true;
this.MinimumSize = new System.Drawing.Size(827, 481);
this.MinimumSize = new System.Drawing.Size(860, 520);
this.Name = "TextToSpeech";
this.ShowIcon = false;
this.ShowInTaskbar = false;
@ -356,6 +445,7 @@
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextToSpeech_KeyDown);
this.groupBoxMsSettings.ResumeLayout(false);
this.groupBoxMsSettings.PerformLayout();
this.contextMenuStripVoices.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
@ -384,5 +474,9 @@
private System.Windows.Forms.CheckBox checkBoxShowPreview;
private System.Windows.Forms.Button buttonCancel;
private System.Windows.Forms.Label labelVoiceCount;
private System.Windows.Forms.Label labelRegion;
private Controls.NikseComboBox nikseComboBoxRegion;
private System.Windows.Forms.ContextMenuStrip contextMenuStripVoices;
private System.Windows.Forms.ToolStripMenuItem refreshVoicesToolStripMenuItem;
}
}

View File

@ -33,7 +33,9 @@ namespace Nikse.SubtitleEdit.Forms.Tts
private bool _abort;
private readonly List<string> _actors;
private readonly List<TextToSpeechEngine> _engines;
private readonly List<PiperModel> _piperVoices;
private readonly List<ElevenLabModel> _elevenLabVoices;
private readonly List<AzureVoiceModel> _azureVoices;
private bool _actorsOn;
private bool _converting;
@ -65,6 +67,20 @@ namespace Nikse.SubtitleEdit.Forms.Tts
}
}
public class AzureVoiceModel
{
public string DisplayName { get; set; }
public string LocalName { get; set; }
public string ShortName { get; set; }
public string Gender { get; set; }
public string Locale { get; set; }
public override string ToString()
{
return $"{Locale} - {DisplayName} ({Gender})";
}
}
public enum TextToSpeechEngineId
{
Piper,
@ -72,6 +88,7 @@ namespace Nikse.SubtitleEdit.Forms.Tts
Coqui,
MsSpeechSynthesizer,
ElevenLabs,
AzureTextToSpeech,
}
public TextToSpeech(Subtitle subtitle, SubtitleFormat subtitleFormat, string videoFileName, VideoInfo videoInfo)
@ -84,7 +101,9 @@ namespace Nikse.SubtitleEdit.Forms.Tts
_subtitleFormat = subtitleFormat;
_videoFileName = videoFileName;
_videoInfo = videoInfo;
_piperVoices = new List<PiperModel>();
_elevenLabVoices = new List<ElevenLabModel>();
_azureVoices = new List<AzureVoiceModel>();
_actors = _subtitle.Paragraphs
.Where(p => !string.IsNullOrEmpty(p.Actor))
.Select(p => p.Actor)
@ -108,13 +127,14 @@ namespace Nikse.SubtitleEdit.Forms.Tts
_engines = new List<TextToSpeechEngine>();
_engines.Add(new TextToSpeechEngine(TextToSpeechEngineId.Piper, "Piper (fast/good)", _engines.Count));
_engines.Add(new TextToSpeechEngine(TextToSpeechEngineId.Tortoise, "Tortoise TTS (very slow/good)", _engines.Count));
_engines.Add(new TextToSpeechEngine(TextToSpeechEngineId.Tortoise, "Tortoise TTS (slow/good)", _engines.Count));
_engines.Add(new TextToSpeechEngine(TextToSpeechEngineId.Coqui, "Coqui AI TTS (only one voice)", _engines.Count));
if (Configuration.IsRunningOnWindows)
{
_engines.Add(new TextToSpeechEngine(TextToSpeechEngineId.MsSpeechSynthesizer, "Microsoft SpeechSynthesizer (very fast/robotic)", _engines.Count));
}
_engines.Add(new TextToSpeechEngine(TextToSpeechEngineId.ElevenLabs, "ElevenLabs TTS (online/pay/good)", _engines.Count));
_engines.Add(new TextToSpeechEngine(TextToSpeechEngineId.AzureTextToSpeech, "Microsoft Azure TTS (online/pay/good)", _engines.Count));
_actorAndVoices = new List<ActorAndVoice>();
nikseComboBoxEngine.DropDownStyle = ComboBoxStyle.DropDownList;
@ -135,7 +155,6 @@ namespace Nikse.SubtitleEdit.Forms.Tts
labelActors.Visible = false;
listViewActors.Visible = false;
nikseComboBoxEngine_SelectedIndexChanged(null, null);
if (!SubtitleFormatHasActors() || !_actors.Any())
{
@ -150,6 +169,8 @@ namespace Nikse.SubtitleEdit.Forms.Tts
Width = w;
}
nikseComboBoxEngine_SelectedIndexChanged(null, null);
nikseComboBoxEngine.SelectedIndexChanged += nikseComboBoxEngine_SelectedIndexChanged;
nikseComboBoxVoice.Text = Configuration.Settings.Tools.TextToSpeechLastVoice;
}
@ -307,6 +328,12 @@ namespace Nikse.SubtitleEdit.Forms.Tts
return result;
}
if (engine.Id == TextToSpeechEngineId.AzureTextToSpeech)
{
var result = await GenerateParagraphAudioAzure(subtitle, showProgressBar, overrideFileName);
return result;
}
return false;
}
@ -594,7 +621,6 @@ namespace Nikse.SubtitleEdit.Forms.Tts
progressBar1.Value = 0;
progressBar1.Maximum = subtitle.Paragraphs.Count;
progressBar1.Visible = showProgressBar;
var voices = PiperModels.GetVoices();
for (var index = 0; index < subtitle.Paragraphs.Count; index++)
{
@ -618,13 +644,13 @@ namespace Nikse.SubtitleEdit.Forms.Tts
}
}
var voice = voices.First(x => x.ToString() == nikseComboBoxVoice.Text);
var voice = _piperVoices.First(x => x.ToString() == nikseComboBoxVoice.Text);
if (_actorAndVoices.Count > 0 && !string.IsNullOrEmpty(p.Actor))
{
var f = _actorAndVoices.FirstOrDefault(x => x.Actor == p.Actor);
if (f != null && !string.IsNullOrEmpty(f.Voice))
{
voice = voices[f.VoiceIndex];
voice = _piperVoices[f.VoiceIndex];
}
}
@ -900,6 +926,171 @@ namespace Nikse.SubtitleEdit.Forms.Tts
return true;
}
private async Task<List<AzureVoiceModel>> GetAzureVoices(bool useCache)
{
var ttsPath = Path.Combine(Configuration.DataDirectory, "TextToSpeech");
if (!Directory.Exists(ttsPath))
{
Directory.CreateDirectory(ttsPath);
}
var azurePath = Path.Combine(ttsPath, "Azure");
if (!Directory.Exists(azurePath))
{
Directory.CreateDirectory(azurePath);
}
var list = new List<AzureVoiceModel>();
var jsonFileName = Path.Combine(azurePath, "AzureVoices.json");
if (!File.Exists(jsonFileName))
{
var asm = System.Reflection.Assembly.GetExecutingAssembly();
var stream = asm.GetManifestResourceStream("Nikse.SubtitleEdit.Resources.AzureVoices.zip");
if (stream != null)
{
using (var zip = ZipExtractor.Open(stream))
{
var dir = zip.ReadCentralDir();
foreach (var entry in dir)
{
var fileName = Path.GetFileName(entry.FilenameInZip);
if (!string.IsNullOrEmpty(fileName))
{
var name = entry.FilenameInZip;
var path = Path.Combine(azurePath, name.Replace('/', Path.DirectorySeparatorChar));
zip.ExtractFile(entry, path);
}
}
}
}
}
if (!useCache)
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("accept", "application/json");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Ocp-Apim-Subscription-Key", nikseTextBoxApiKey.Text.Trim());
var url = $"https://{nikseComboBoxRegion.Text.Trim()}.tts.speech.microsoft.com/cognitiveservices/voices/list";
var result = await httpClient.GetAsync(new Uri(url), CancellationToken.None);
var bytes = await result.Content.ReadAsByteArrayAsync();
if (!result.IsSuccessStatusCode)
{
Cursor = Cursors.Default;
var error = Encoding.UTF8.GetString(bytes).Trim();
SeLogger.Error($"Failed getting voices form Azure via url \"{url}\" : Status code={result.StatusCode} {error}");
MessageBox.Show(this, "Calling url: " + url + Environment.NewLine + "Got error: " + error);
return new List<AzureVoiceModel>();
}
File.WriteAllBytes(jsonFileName, bytes);
}
var json = File.ReadAllText(jsonFileName);
var parser = new SeJsonParser();
var arr = parser.GetArrayElements(json);
foreach (var item in arr)
{
var displayName = parser.GetFirstObject(item, "DisplayName");
var localName = parser.GetFirstObject(item, "LocalName");
var shortName = parser.GetFirstObject(item, "ShortName");
var gender = parser.GetFirstObject(item, "Gender");
var locale = parser.GetFirstObject(item, "Locale");
list.Add(new AzureVoiceModel
{
DisplayName = displayName,
LocalName = localName,
ShortName = shortName,
Gender = gender,
Locale = locale,
});
}
return list;
}
private async Task<bool> GenerateParagraphAudioAzure(Subtitle subtitle, bool showProgressBar, string overrideFileName)
{
if (string.IsNullOrWhiteSpace(nikseTextBoxApiKey.Text))
{
MessageBox.Show("Please add API key");
nikseTextBoxApiKey.Focus();
return false;
}
if (string.IsNullOrWhiteSpace(nikseComboBoxRegion.Text))
{
MessageBox.Show("Please add region");
nikseComboBoxRegion.Focus();
return false;
}
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "ssml+xml");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("accept", "audio/mpeg");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("X-Microsoft-OutputFormat", "audio-16khz-32kbitrate-mono-mp3");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "SubtitleEdit");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Ocp-Apim-Subscription-Key", nikseTextBoxApiKey.Text.Trim());
progressBar1.Value = 0;
progressBar1.Maximum = subtitle.Paragraphs.Count;
progressBar1.Visible = showProgressBar;
var voices = _azureVoices;
var v = nikseComboBoxVoice.Text;
for (var index = 0; index < subtitle.Paragraphs.Count; index++)
{
if (showProgressBar)
{
progressBar1.Value = index + 1;
labelProgress.Text = string.Format(LanguageSettings.Current.TextToSpeech.GeneratingSpeechFromTextXOfY, index + 1, subtitle.Paragraphs.Count);
}
var p = subtitle.Paragraphs[index];
var outputFileName = Path.Combine(_waveFolder, string.IsNullOrEmpty(overrideFileName) ? index + ".mp3" : overrideFileName.Replace(".wav", ".mp3"));
if (_actorAndVoices.Count > 0 && !string.IsNullOrEmpty(p.Actor))
{
var f = _actorAndVoices.FirstOrDefault(x => x.Actor == p.Actor);
if (f != null && !string.IsNullOrEmpty(f.Voice))
{
v = f.Voice;
}
}
var voice = voices.First(x => x.ToString() == v);
var url = $"https://{nikseComboBoxRegion.Text.Trim()}.tts.speech.microsoft.com/cognitiveservices/v1";
var data = $"<speak version='1.0' xml:lang='en-US'><voice xml:lang='en-US' xml:gender='{voice.Gender}' name='{voice.ShortName}'>{System.Net.WebUtility.HtmlEncode(p.Text)}</voice></speak>";
var content = new StringContent(data, Encoding.UTF8);
var result = await httpClient.PostAsync(url, content, CancellationToken.None);
var bytes = await result.Content.ReadAsByteArrayAsync();
if (!result.IsSuccessStatusCode)
{
var error = Encoding.UTF8.GetString(bytes).Trim();
SeLogger.Error($"Azure TTS failed calling API on address {url} : Status code={result.StatusCode} {error}" + Environment.NewLine + "Data=" + data);
MessageBox.Show(this, "Calling url: " + url + Environment.NewLine + "With: " + data + Environment.NewLine + Environment.NewLine + "Error: " + error + result);
return false;
}
File.WriteAllBytes(outputFileName, bytes);
progressBar1.Refresh();
labelProgress.Refresh();
Application.DoEvents();
}
progressBar1.Visible = false;
labelProgress.Text = string.Empty;
return true;
}
private void buttonOK_Click(object sender, EventArgs e)
{
EditedSubtitle = _subtitle;
@ -913,6 +1104,8 @@ namespace Nikse.SubtitleEdit.Forms.Tts
labelApiKey.Visible = false;
nikseTextBoxApiKey.Visible = false;
labelRegion.Visible = false;
nikseComboBoxRegion.Visible = false;
labelVoice.Text = LanguageSettings.Current.TextToSpeech.Voice;
if (SubtitleFormatHasActors() && _actors.Any())
@ -937,7 +1130,12 @@ namespace Nikse.SubtitleEdit.Forms.Tts
if (engine.Id == TextToSpeechEngineId.Piper)
{
foreach (var voice in PiperModels.GetVoices())
if (_piperVoices.Count == 0)
{
_piperVoices.AddRange(GetPiperVoices(true));
}
foreach (var voice in _piperVoices)
{
nikseComboBoxVoice.Items.Add(voice.ToString());
}
@ -983,7 +1181,7 @@ namespace Nikse.SubtitleEdit.Forms.Tts
if (_elevenLabVoices.Count == 0)
{
_elevenLabVoices.AddRange(GetElevenLabVoices());
_elevenLabVoices.AddRange(GetElevenLabVoices(true));
}
foreach (var voice in _elevenLabVoices)
@ -992,6 +1190,22 @@ namespace Nikse.SubtitleEdit.Forms.Tts
}
}
if (engine.Id == TextToSpeechEngineId.AzureTextToSpeech)
{
nikseTextBoxApiKey.Text = Configuration.Settings.Tools.TextToSpeechAzureApiKey;
nikseComboBoxRegion.Text = Configuration.Settings.Tools.TextToSpeechAzureRegion;
labelApiKey.Visible = true;
nikseTextBoxApiKey.Visible = true;
var azureVoices = GetAzureVoices(true).Result;
_azureVoices.AddRange(azureVoices);
nikseComboBoxVoice.Items.AddRange(_azureVoices.Select(p => p.ToString()).ToArray());
labelRegion.Visible = true;
nikseComboBoxRegion.Visible = true;
}
if (nikseComboBoxVoice.Items.Count > 0)
{
nikseComboBoxVoice.SelectedIndex = 0;
@ -1025,7 +1239,7 @@ namespace Nikse.SubtitleEdit.Forms.Tts
if (engine.Id == TextToSpeechEngineId.Piper)
{
var voices = PiperModels.GetVoices();
var voices = _piperVoices;
foreach (var voiceLanguage in voices
.GroupBy(p => p.Language)
.OrderBy(p => p.Key))
@ -1062,7 +1276,98 @@ namespace Nikse.SubtitleEdit.Forms.Tts
parent.DropDownItems.Add(tsi);
}
DarkTheme.SetDarkTheme(parent);
if (Configuration.Settings.General.UseDarkTheme)
{
DarkTheme.SetDarkTheme(parent);
}
}
}
}
if (engine.Id == TextToSpeechEngineId.AzureTextToSpeech)
{
var voices = _azureVoices;
foreach (var voiceLanguage in voices
.GroupBy(p => p.Locale.Substring(0, 2))
.OrderBy(p => p.Key))
{
if (voiceLanguage.Count() == 1)
{
var voice = voiceLanguage.First();
var tsi = new ToolStripMenuItem();
tsi.Tag = new ActorAndVoice { Voice = voice.ToString(), VoiceIndex = voices.IndexOf(voice) };
tsi.Text = voice.ToString();
tsi.Click += (x, args) =>
{
var a = (ActorAndVoice)(x as ToolStripItem).Tag;
SetActor(a);
};
contextMenuStripActors.Items.Add(tsi);
}
else
{
if (voiceLanguage.Count() < 30)
{
var parent = new ToolStripMenuItem();
parent.Text = voiceLanguage.Key;
contextMenuStripActors.Items.Add(parent);
var tsiList = new List<ToolStripItem>(nikseComboBoxVoice.Items.Count);
foreach (var voice in voiceLanguage.OrderBy(p => p.ToString()).ToList())
{
var tsi = new ToolStripMenuItem();
tsi.Tag = new ActorAndVoice { Voice = voice.ToString(), VoiceIndex = voices.IndexOf(voice) };
tsi.Text = voice.ToString();
tsi.Click += (x, args) =>
{
var a = (ActorAndVoice)(x as ToolStripItem).Tag;
SetActor(a);
};
tsiList.Add(tsi);
}
parent.DropDownItems.AddRange(tsiList.ToArray());
if (Configuration.Settings.General.UseDarkTheme)
{
DarkTheme.SetDarkTheme(parent);
}
}
else
{
var parent = new ToolStripMenuItem();
parent.Text = voiceLanguage.Key;
contextMenuStripActors.Items.Add(parent);
var subGroup = voiceLanguage.GroupBy(p => p.Locale);
foreach (var subGroupElement in subGroup)
{
var groupParent = new ToolStripMenuItem();
groupParent.Text = subGroupElement.Key;
parent.DropDownItems.Add(groupParent);
var tsiList = new List<ToolStripItem>(subGroupElement.Count());
foreach (var voice in subGroupElement.OrderBy(p => p.DisplayName).ToList())
{
var tsi = new ToolStripMenuItem();
tsi.Tag = new ActorAndVoice { Voice = voice.ToString(), VoiceIndex = voices.IndexOf(voice) };
tsi.Text = voice.ToString();
tsi.Click += (x, args) =>
{
var a = (ActorAndVoice)(x as ToolStripItem).Tag;
SetActor(a);
};
tsiList.Add(tsi);
}
groupParent.DropDownItems.AddRange(tsiList.ToArray());
if (Configuration.Settings.General.UseDarkTheme)
{
DarkTheme.SetDarkTheme(groupParent);
}
}
if (Configuration.Settings.General.UseDarkTheme)
{
DarkTheme.SetDarkTheme(parent);
}
}
}
}
}
@ -1105,12 +1410,16 @@ namespace Nikse.SubtitleEdit.Forms.Tts
parent.DropDownItems.Add(tsi);
}
DarkTheme.SetDarkTheme(parent);
if (Configuration.Settings.General.UseDarkTheme)
{
DarkTheme.SetDarkTheme(parent);
}
}
}
}
else
{
var tsiList = new List<ToolStripItem>(nikseComboBoxVoice.Items.Count);
for (var index = 0; index < nikseComboBoxVoice.Items.Count; index++)
{
var item = nikseComboBoxVoice.Items[index];
@ -1123,8 +1432,10 @@ namespace Nikse.SubtitleEdit.Forms.Tts
var a = (ActorAndVoice)(x as ToolStripItem).Tag;
SetActor(a);
};
contextMenuStripActors.Items.Add(tsi);
tsiList.Add(tsi);
}
contextMenuStripActors.Items.AddRange(tsiList.ToArray());
}
labelActors.Visible = true;
@ -1134,7 +1445,104 @@ namespace Nikse.SubtitleEdit.Forms.Tts
}
}
private List<ElevenLabModel> GetElevenLabVoices()
private List<PiperModel> GetPiperVoices(bool useCache)
{
var ttsPath = Path.Combine(Configuration.DataDirectory, "TextToSpeech");
if (!Directory.Exists(ttsPath))
{
Directory.CreateDirectory(ttsPath);
}
var elevenLabsPath = Path.Combine(ttsPath, "Piper");
if (!Directory.Exists(elevenLabsPath))
{
Directory.CreateDirectory(elevenLabsPath);
}
var result = new List<PiperModel>();
var jsonFileName = Path.Combine(elevenLabsPath, "voices.json");
if (!File.Exists(jsonFileName))
{
var asm = System.Reflection.Assembly.GetExecutingAssembly();
var stream = asm.GetManifestResourceStream("Nikse.SubtitleEdit.Resources.PiperVoices.zip");
if (stream != null)
{
using (var zip = ZipExtractor.Open(stream))
{
var dir = zip.ReadCentralDir();
foreach (var entry in dir)
{
var fileName = Path.GetFileName(entry.FilenameInZip);
if (!string.IsNullOrEmpty(fileName))
{
var name = entry.FilenameInZip;
var path = Path.Combine(elevenLabsPath, name.Replace('/', Path.DirectorySeparatorChar));
zip.ExtractFile(entry, path);
}
}
}
}
}
if (!useCache)
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("accept", "application/json");
var url = "https://huggingface.co/rhasspy/piper-voices/resolve/main/voices.json?download=true";
var res = httpClient.GetAsync(new Uri(url), CancellationToken.None).Result;
var bytes = res.Content.ReadAsByteArrayAsync().Result;
if (!res.IsSuccessStatusCode)
{
var error = Encoding.UTF8.GetString(bytes).Trim();
SeLogger.Error($"Failed getting voices form Piper via url \"{url}\" : Status code={res.StatusCode} {error}");
MessageBox.Show(this, "Calling url: " + url + Environment.NewLine + "Got error: " + error + " " + result);
return result;
}
File.WriteAllBytes(jsonFileName, bytes);
}
if (File.Exists(jsonFileName))
{
var json = File.ReadAllText(jsonFileName);
var parser = new SeJsonParser();
var arr = parser.GetRootElements(json);
foreach (var element in arr)
{
var elements = parser.GetRootElements(element.Json);
var name = elements.FirstOrDefault(p => p.Name == "name");
var quality = elements.FirstOrDefault(p => p.Name == "quality");
var language = elements.FirstOrDefault(p => p.Name == "language");
var files = elements.FirstOrDefault(p => p.Name == "files");
if (name != null && quality != null && language != null && files != null)
{
var languageDisplay = parser.GetFirstObject(language.Json, "name_english");
var languageFamily = parser.GetFirstObject(language.Json, "family");
var languageCode = parser.GetFirstObject(language.Json, "code");
var filesElements = parser.GetRootElements(files.Json);
var model = filesElements.FirstOrDefault(p => p.Name.EndsWith(".onnx"));
var config = filesElements.FirstOrDefault(p => p.Name.EndsWith("onnx.json"));
if (model != null && config != null)
{
var modelUrl = "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/" + model.Name;
var configUrl = "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/" + config.Name;
result.Add(new PiperModel(name.Json, languageDisplay, quality.Json, modelUrl, configUrl));
}
}
}
}
return result;
}
private List<ElevenLabModel> GetElevenLabVoices(bool useCache)
{
var ttsPath = Path.Combine(Configuration.DataDirectory, "TextToSpeech");
if (!Directory.Exists(ttsPath))
@ -1175,6 +1583,33 @@ namespace Nikse.SubtitleEdit.Forms.Tts
}
}
if (!useCache)
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("accept", "application/json");
if (!string.IsNullOrWhiteSpace(nikseTextBoxApiKey.Text))
{
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("xi-api-key", nikseTextBoxApiKey.Text.Trim());
}
var url = "https://api.elevenlabs.io/v1/voices";
var res = httpClient.GetAsync(new Uri(url), CancellationToken.None).Result;
var bytes = res.Content.ReadAsByteArrayAsync().Result;
if (!res.IsSuccessStatusCode)
{
Cursor = Cursors.Default;
var error = Encoding.UTF8.GetString(bytes).Trim();
SeLogger.Error($"Failed getting voices form ElevenLabs via url \"{url}\" : Status code={res.StatusCode} {error}");
MessageBox.Show(this, "Calling url: " + url + Environment.NewLine + "Got error: " + error);
return new List<ElevenLabModel>();
}
File.WriteAllBytes(jsonFileName, bytes);
}
if (File.Exists(jsonFileName))
{
var json = File.ReadAllText(jsonFileName);
@ -1332,6 +1767,11 @@ namespace Nikse.SubtitleEdit.Forms.Tts
{
Configuration.Settings.Tools.TextToSpeechElevenLabsApiKey = nikseTextBoxApiKey.Text;
}
else if (engine.Id == TextToSpeechEngineId.AzureTextToSpeech)
{
Configuration.Settings.Tools.TextToSpeechAzureApiKey = nikseTextBoxApiKey.Text;
Configuration.Settings.Tools.TextToSpeechAzureRegion = nikseComboBoxRegion.Text;
}
Configuration.Settings.Tools.TextToSpeechEngine = engine.Id.ToString();
Configuration.Settings.Tools.TextToSpeechLastVoice = nikseComboBoxVoice.Text;
@ -1356,21 +1796,26 @@ namespace Nikse.SubtitleEdit.Forms.Tts
public string GetParagraphAudio(Paragraph paragraph)
{
if (_actorsOn)
if (_actorsOn && _actorAndVoices.Count > 0 && !string.IsNullOrEmpty(paragraph.Actor))
{
var engine = _engines.First(p => p.Index == nikseComboBoxEngine.SelectedIndex);
if (engine.Id == TextToSpeechEngineId.Piper)
var f = _actorAndVoices.FirstOrDefault(x => x.Actor == paragraph.Actor);
if (f != null && !string.IsNullOrEmpty(f.Voice))
{
var voices = PiperModels.GetVoices();
var voice = voices.First(x => x.ToString() == nikseComboBoxVoice.Text);
if (_actorAndVoices.Count > 0 && !string.IsNullOrEmpty(paragraph.Actor))
var engine = _engines.First(p => p.Index == nikseComboBoxEngine.SelectedIndex);
if (engine.Id == TextToSpeechEngineId.Piper)
{
var f = _actorAndVoices.FirstOrDefault(x => x.Actor == paragraph.Actor);
if (f != null && !string.IsNullOrEmpty(f.Voice))
{
return voices[f.VoiceIndex].Voice;
}
return _piperVoices[f.VoiceIndex].ToString();
}
if (engine.Id == TextToSpeechEngineId.AzureTextToSpeech)
{
return _azureVoices[f.VoiceIndex].ToString();
}
if (engine.Id == TextToSpeechEngineId.ElevenLabs)
{
return _elevenLabVoices[f.VoiceIndex].ToString();
}
}
}
@ -1405,5 +1850,79 @@ namespace Nikse.SubtitleEdit.Forms.Tts
nikseComboBoxEngine.DropDownWidth = nikseComboBoxEngine.Width;
nikseComboBoxVoice.DropDownWidth = nikseComboBoxVoice.Width;
}
private void RefreshVoices()
{
if (nikseTextBoxApiKey.Visible && string.IsNullOrWhiteSpace(nikseTextBoxApiKey.Text))
{
Cursor = Cursors.Default;
MessageBox.Show("Please add API key");
nikseTextBoxApiKey.Focus();
return;
}
var engine = _engines.First(p => p.Index == nikseComboBoxEngine.SelectedIndex);
if (engine.Id == TextToSpeechEngineId.AzureTextToSpeech)
{
if (string.IsNullOrWhiteSpace(nikseComboBoxRegion.Text))
{
Cursor = Cursors.Default;
MessageBox.Show("Please add region");
nikseComboBoxRegion.Focus();
return;
}
var _ = GetAzureVoices(false).Result;
nikseComboBoxEngine_SelectedIndexChanged(null, null);
}
else if (engine.Id == TextToSpeechEngineId.ElevenLabs)
{
GetElevenLabVoices(false);
nikseComboBoxEngine_SelectedIndexChanged(null, null);
}
}
private void contextMenuStripVoices_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
var engine = _engines.First(p => p.Index == nikseComboBoxEngine.SelectedIndex);
if (
//engine.Id == TextToSpeechEngineId.AzureTextToSpeech ||
engine.Id == TextToSpeechEngineId.ElevenLabs ||
engine.Id == TextToSpeechEngineId.Piper
)
{
return;
}
e.Cancel = true;
}
private void refreshVoicesToolStripMenuItem_Click(object sender, EventArgs e)
{
var dr = MessageBox.Show(this, "Download updated voice list from the internet?", "Update voices", MessageBoxButtons.YesNoCancel);
if (dr != DialogResult.Yes)
{
return;
}
try
{
Cursor = Cursors.WaitCursor;
RefreshVoices();
Cursor = Cursors.Default;
MessageBox.Show(this, "Voice list downloaded");
}
catch (Exception ex)
{
Cursor = Cursors.Default;
MessageBox.Show(this, "Voice list download failed!" + Environment.NewLine +
Environment.NewLine +
ex.Message);
}
finally
{
Cursor = Cursors.Default;
}
}
}
}

View File

@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="contextMenuStripVoices.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>200, 17</value>
</metadata>
<metadata name="contextMenuStripActors.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>

Binary file not shown.

Binary file not shown.

View File

@ -2454,7 +2454,9 @@
<EmbeddedResource Include="Resources\HunspellBackupDictionaries.xml.gz" />
<EmbeddedResource Include="Resources\TesseractDictionaries.xml.gz" />
<EmbeddedResource Include="Resources\eleven-labs-voices.zip" />
<EmbeddedResource Include="Resources\AzureVoices.zip" />
<None Include="Resources\nOCR_TesseractHelper.xml.gz" />
<EmbeddedResource Include="Resources\PiperVoices.zip" />
<None Include="Resources\SMPTE-428-7-2007-DCST.xsd">
<SubType>Designer</SubType>
</None>