This commit is contained in:
Nikolaj Olsson 2024-04-21 11:56:05 +02:00
parent fb52adb22f
commit 181e50d723
12 changed files with 1082 additions and 84 deletions

View File

@ -2,8 +2,8 @@
4.0.6 (xth May 2024) BETA
* NEW:
* Add "Text To Speech" - thx darnn
* Add burn-in batch mode - thx Leon
* Add "Text To Speech" - thx darnn/cvrle77/msjsc001
* Add burn-in batch mode - thx Leon/David
* IMPROVED:
* Update Portuguese translation - thx hugok79
* Update Bulgarian translation - thx Калин

View File

@ -191,6 +191,7 @@ namespace Nikse.SubtitleEdit.Core.Common
public int AutoTranslateDelaySeconds { get; set; }
public string GeminiProApiKey { get; set; }
public string TextToSpeechEngine { get; set; }
public string TextToSpeechLastVoice { get; set; }
public string TextToSpeechElevenLabsApiKey { get; set; }
public bool DisableVidoInfoViaLabel { get; set; }
public bool ListViewSyntaxColorDurationSmall { get; set; }
@ -5464,6 +5465,12 @@ $HorzAlign = Center
settings.Tools.TextToSpeechEngine = subNode.InnerText;
}
subNode = node.SelectSingleNode("TextToSpeechLastVoice");
if (subNode != null)
{
settings.Tools.TextToSpeechLastVoice = subNode.InnerText;
}
subNode = node.SelectSingleNode("TextToSpeechElevenLabsApiKey");
if (subNode != null)
{
@ -11992,6 +11999,7 @@ $HorzAlign = Center
textWriter.WriteElementString("AutoTranslateDelaySeconds", settings.Tools.AutoTranslateDelaySeconds.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("GeminiProApiKey", settings.Tools.GeminiProApiKey);
textWriter.WriteElementString("TextToSpeechEngine", settings.Tools.TextToSpeechEngine);
textWriter.WriteElementString("TextToSpeechLastVoice", settings.Tools.TextToSpeechLastVoice);
textWriter.WriteElementString("TextToSpeechElevenLabsApiKey", settings.Tools.TextToSpeechElevenLabsApiKey);
textWriter.WriteElementString("DisableVidoInfoViaLabel", settings.Tools.DisableVidoInfoViaLabel.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ListViewSyntaxColorDurationSmall", settings.Tools.ListViewSyntaxColorDurationSmall.ToString(CultureInfo.InvariantCulture));

View File

@ -0,0 +1,150 @@
namespace Nikse.SubtitleEdit.Forms.Tts
{
partial class RegenerateAudioClip
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.buttonCancel = new System.Windows.Forms.Button();
this.TextBoxReGenerate = new Nikse.SubtitleEdit.Controls.NikseTextBox();
this.buttonReGenerate = new System.Windows.Forms.Button();
this.labelVoice = new System.Windows.Forms.Label();
this.nikseComboBoxVoice = new Nikse.SubtitleEdit.Controls.NikseComboBox();
this.labelText = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// buttonCancel
//
this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.buttonCancel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.buttonCancel.Location = new System.Drawing.Point(730, 208);
this.buttonCancel.Name = "buttonCancel";
this.buttonCancel.Size = new System.Drawing.Size(84, 23);
this.buttonCancel.TabIndex = 7;
this.buttonCancel.Text = "C&ancel";
this.buttonCancel.UseVisualStyleBackColor = true;
this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click);
//
// TextBoxReGenerate
//
this.TextBoxReGenerate.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.TextBoxReGenerate.FocusedColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215)))));
this.TextBoxReGenerate.Location = new System.Drawing.Point(12, 40);
this.TextBoxReGenerate.Multiline = true;
this.TextBoxReGenerate.Name = "TextBoxReGenerate";
this.TextBoxReGenerate.Size = new System.Drawing.Size(802, 162);
this.TextBoxReGenerate.TabIndex = 22;
//
// buttonReGenerate
//
this.buttonReGenerate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonReGenerate.Location = new System.Drawing.Point(550, 208);
this.buttonReGenerate.Name = "buttonReGenerate";
this.buttonReGenerate.Size = new System.Drawing.Size(174, 23);
this.buttonReGenerate.TabIndex = 21;
this.buttonReGenerate.Text = "Regenerate ";
this.buttonReGenerate.UseVisualStyleBackColor = true;
this.buttonReGenerate.Click += new System.EventHandler(this.buttonReGenerate_Click);
//
// labelVoice
//
this.labelVoice.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.labelVoice.AutoSize = true;
this.labelVoice.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.labelVoice.Location = new System.Drawing.Point(153, 213);
this.labelVoice.Name = "labelVoice";
this.labelVoice.Size = new System.Drawing.Size(34, 13);
this.labelVoice.TabIndex = 24;
this.labelVoice.Text = "Voice";
//
// nikseComboBoxVoice
//
this.nikseComboBoxVoice.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | 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(193, 208);
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 = 23;
this.nikseComboBoxVoice.UsePopupWindow = false;
//
// labelText
//
this.labelText.AutoSize = true;
this.labelText.Location = new System.Drawing.Point(13, 21);
this.labelText.Name = "labelText";
this.labelText.Size = new System.Drawing.Size(28, 13);
this.labelText.TabIndex = 25;
this.labelText.Text = "Text";
//
// RegenerateAudioClip
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(826, 243);
this.Controls.Add(this.labelText);
this.Controls.Add(this.labelVoice);
this.Controls.Add(this.nikseComboBoxVoice);
this.Controls.Add(this.TextBoxReGenerate);
this.Controls.Add(this.buttonReGenerate);
this.Controls.Add(this.buttonCancel);
this.KeyPreview = true;
this.MinimumSize = new System.Drawing.Size(600, 250);
this.Name = "RegenerateAudioClip";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Regenerate audio clip";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button buttonCancel;
private Controls.NikseTextBox TextBoxReGenerate;
private System.Windows.Forms.Button buttonReGenerate;
private System.Windows.Forms.Label labelVoice;
private Controls.NikseComboBox nikseComboBoxVoice;
private System.Windows.Forms.Label labelText;
}
}

View File

@ -0,0 +1,62 @@
using Nikse.SubtitleEdit.Core.Common;
using Nikse.SubtitleEdit.Logic;
using System;
using System.Windows.Forms;
namespace Nikse.SubtitleEdit.Forms.Tts
{
public partial class RegenerateAudioClip : Form
{
public string NewAudioFileName { get; set; }
private readonly TextToSpeech _textToSpeech;
private readonly Subtitle _subtitle;
private readonly int _index;
public RegenerateAudioClip(TextToSpeech textToSpeech, Subtitle subtitle, int idx)
{
UiUtil.PreInitialize(this);
InitializeComponent();
UiUtil.FixFonts(this);
_subtitle = subtitle;
_textToSpeech = textToSpeech;
_index = idx;
buttonCancel.Text = LanguageSettings.Current.General.Cancel;
UiUtil.FixLargeFonts(this, buttonCancel);
TextBoxReGenerate.Text = subtitle.Paragraphs[idx].Text;
textToSpeech.SetCurrentVoices(nikseComboBoxVoice);
}
private async void buttonReGenerate_Click(object sender, EventArgs e)
{
var paragraph = _subtitle.Paragraphs[_index];
paragraph.Text = TextBoxReGenerate.Text.Trim();
try
{
Cursor = Cursors.WaitCursor;
buttonReGenerate.Enabled = false;
var fileName = await _textToSpeech.GenerateAudio(paragraph, nikseComboBoxVoice.Text);
if (!string.IsNullOrEmpty(fileName))
{
NewAudioFileName = fileName;
Cursor = Cursors.Default;
DialogResult = DialogResult.OK;
}
}
finally
{
Cursor = Cursors.Default;
buttonReGenerate.Enabled = true;
}
}
private void buttonCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,216 @@
namespace Nikse.SubtitleEdit.Forms.Tts
{
sealed partial class ReviewAudioClips
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.listView1 = new System.Windows.Forms.ListView();
this.columnHeaderInclude = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeaderNo = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeaderVoice = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeaderCps = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeaderText = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.buttonOK = new System.Windows.Forms.Button();
this.labelInfo = new System.Windows.Forms.Label();
this.buttonPlay = new System.Windows.Forms.Button();
this.labelParagraphInfo = new System.Windows.Forms.Label();
this.checkBoxContinuePlay = new System.Windows.Forms.CheckBox();
this.buttonStop = new System.Windows.Forms.Button();
this.buttonReGenerate = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// listView1
//
this.listView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listView1.CheckBoxes = true;
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeaderInclude,
this.columnHeaderNo,
this.columnHeaderVoice,
this.columnHeaderCps,
this.columnHeaderText});
this.listView1.FullRowSelect = true;
this.listView1.HideSelection = false;
this.listView1.Location = new System.Drawing.Point(12, 52);
this.listView1.MultiSelect = false;
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(684, 319);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.Details;
this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged);
this.listView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listView1_KeyDown);
//
// columnHeaderInclude
//
this.columnHeaderInclude.Text = "Include";
//
// columnHeaderNo
//
this.columnHeaderNo.Text = "#";
this.columnHeaderNo.Width = 50;
//
// columnHeaderVoice
//
this.columnHeaderVoice.Text = "Voice";
this.columnHeaderVoice.Width = 120;
//
// columnHeaderCps
//
this.columnHeaderCps.Text = "CPS";
//
// columnHeaderText
//
this.columnHeaderText.Text = "Text";
this.columnHeaderText.Width = 460;
//
// buttonOK
//
this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonOK.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.buttonOK.Location = new System.Drawing.Point(795, 413);
this.buttonOK.Name = "buttonOK";
this.buttonOK.Size = new System.Drawing.Size(87, 23);
this.buttonOK.TabIndex = 5;
this.buttonOK.Text = "&OK";
this.buttonOK.UseVisualStyleBackColor = true;
this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click);
//
// labelInfo
//
this.labelInfo.AutoSize = true;
this.labelInfo.Location = new System.Drawing.Point(12, 33);
this.labelInfo.Name = "labelInfo";
this.labelInfo.Size = new System.Drawing.Size(219, 13);
this.labelInfo.TabIndex = 8;
this.labelInfo.Text = "Review and un-include unwanted audio clips";
//
// buttonPlay
//
this.buttonPlay.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonPlay.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.buttonPlay.Location = new System.Drawing.Point(702, 295);
this.buttonPlay.Name = "buttonPlay";
this.buttonPlay.Size = new System.Drawing.Size(180, 23);
this.buttonPlay.TabIndex = 9;
this.buttonPlay.Text = "Play";
this.buttonPlay.UseVisualStyleBackColor = true;
this.buttonPlay.Click += new System.EventHandler(this.buttonPlay_Click);
//
// labelParagraphInfo
//
this.labelParagraphInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelParagraphInfo.AutoSize = true;
this.labelParagraphInfo.Location = new System.Drawing.Point(12, 383);
this.labelParagraphInfo.Name = "labelParagraphInfo";
this.labelParagraphInfo.Size = new System.Drawing.Size(76, 13);
this.labelParagraphInfo.TabIndex = 10;
this.labelParagraphInfo.Text = "Paragraph info";
//
// checkBoxContinuePlay
//
this.checkBoxContinuePlay.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.checkBoxContinuePlay.AutoSize = true;
this.checkBoxContinuePlay.Location = new System.Drawing.Point(703, 353);
this.checkBoxContinuePlay.Name = "checkBoxContinuePlay";
this.checkBoxContinuePlay.Size = new System.Drawing.Size(92, 17);
this.checkBoxContinuePlay.TabIndex = 11;
this.checkBoxContinuePlay.Text = "Auto continue";
this.checkBoxContinuePlay.UseVisualStyleBackColor = true;
//
// buttonStop
//
this.buttonStop.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonStop.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.buttonStop.Location = new System.Drawing.Point(703, 324);
this.buttonStop.Name = "buttonStop";
this.buttonStop.Size = new System.Drawing.Size(179, 23);
this.buttonStop.TabIndex = 12;
this.buttonStop.Text = "Stop ";
this.buttonStop.UseVisualStyleBackColor = true;
this.buttonStop.Click += new System.EventHandler(this.buttonStop_Click);
//
// buttonReGenerate
//
this.buttonReGenerate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonReGenerate.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.buttonReGenerate.Location = new System.Drawing.Point(703, 249);
this.buttonReGenerate.Name = "buttonReGenerate";
this.buttonReGenerate.Size = new System.Drawing.Size(180, 23);
this.buttonReGenerate.TabIndex = 13;
this.buttonReGenerate.Text = "Regenerate";
this.buttonReGenerate.UseVisualStyleBackColor = true;
this.buttonReGenerate.Click += new System.EventHandler(this.buttonReGenerate_Click);
//
// ReviewAudioClips
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(894, 448);
this.Controls.Add(this.buttonReGenerate);
this.Controls.Add(this.buttonStop);
this.Controls.Add(this.checkBoxContinuePlay);
this.Controls.Add(this.labelParagraphInfo);
this.Controls.Add(this.buttonPlay);
this.Controls.Add(this.labelInfo);
this.Controls.Add(this.buttonOK);
this.Controls.Add(this.listView1);
this.KeyPreview = true;
this.MinimumSize = new System.Drawing.Size(800, 450);
this.Name = "ReviewAudioClips";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Review audio clips";
this.Load += new System.EventHandler(this.VoicePreviewList_Load);
this.Shown += new System.EventHandler(this.VoicePreviewList_Shown);
this.ResizeEnd += new System.EventHandler(this.VoicePreviewList_ResizeEnd);
this.Resize += new System.EventHandler(this.VoicePreviewList_Resize);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ListView listView1;
private System.Windows.Forms.Button buttonOK;
private System.Windows.Forms.Label labelInfo;
private System.Windows.Forms.ColumnHeader columnHeaderInclude;
private System.Windows.Forms.ColumnHeader columnHeaderNo;
private System.Windows.Forms.ColumnHeader columnHeaderVoice;
private System.Windows.Forms.ColumnHeader columnHeaderCps;
private System.Windows.Forms.ColumnHeader columnHeaderText;
private System.Windows.Forms.Button buttonPlay;
private System.Windows.Forms.Label labelParagraphInfo;
private System.Windows.Forms.CheckBox checkBoxContinuePlay;
private System.Windows.Forms.Button buttonStop;
private System.Windows.Forms.Button buttonReGenerate;
}
}

View File

@ -0,0 +1,215 @@
using Nikse.SubtitleEdit.Core.Common;
using Nikse.SubtitleEdit.Logic;
using Nikse.SubtitleEdit.Logic.VideoPlayers;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Forms;
namespace Nikse.SubtitleEdit.Forms.Tts
{
public sealed partial class ReviewAudioClips : Form
{
public List<int> SkipIndices { get; set; }
private readonly Subtitle _subtitle;
private readonly TextToSpeech _textToSpeech;
private readonly List<string> _fileNames;
private bool _abortPlay;
private LibMpvDynamic _libMpv;
private Timer _mpvDoneTimer;
public ReviewAudioClips(TextToSpeech textToSpeech, Subtitle subtitle, List<string> fileNames)
{
UiUtil.PreInitialize(this);
InitializeComponent();
UiUtil.FixFonts(this);
buttonOK.Text = LanguageSettings.Current.General.Ok;
UiUtil.FixLargeFonts(this, buttonOK);
_textToSpeech = textToSpeech;
_subtitle = subtitle;
_fileNames = fileNames;
SkipIndices = new List<int>();
listView1.BeginUpdate();
foreach (var p in subtitle.Paragraphs)
{
var item = new ListViewItem { Tag = p, Checked = true };
item.SubItems.Add(p.Number.ToString(CultureInfo.InvariantCulture));
item.SubItems.Add(_textToSpeech.GetParagraphAudio(p));
item.SubItems.Add(Utilities.GetCharactersPerSecond(p).ToString("0.#", CultureInfo.InvariantCulture));
item.SubItems.Add(p.Text);
listView1.Items.Add(item);
}
listView1.EndUpdate();
if (listView1.Items.Count > 0)
{
listView1.Items[0].Selected = true;
}
labelParagraphInfo.Text = string.Empty;
}
private void buttonOK_Click(object sender, EventArgs e)
{
_libMpv?.Stop();
for (var index = 0; index < listView1.Items.Count; index++)
{
if (!listView1.Items[index].Checked)
{
SkipIndices.Add(index);
}
}
DialogResult = DialogResult.OK;
}
private void VoicePreviewList_Load(object sender, EventArgs e)
{
listView1.AutoSizeLastColumn();
}
private void VoicePreviewList_ResizeEnd(object sender, EventArgs e)
{
listView1.AutoSizeLastColumn();
}
private void VoicePreviewList_Resize(object sender, EventArgs e)
{
listView1.AutoSizeLastColumn();
}
private void Play(bool noAutoContinue = false)
{
if (listView1.SelectedItems.Count == 0)
{
return;
}
var idx = listView1.SelectedItems[0].Index;
var waveFileName = _fileNames[idx];
if (_libMpv != null)
{
_libMpv.Initialize(
null,
waveFileName,
(sender, args) =>
{
_libMpv.Play();
},
null);
if (checkBoxContinuePlay.Checked && !noAutoContinue)
{
_mpvDoneTimer.Start();
}
}
else
{
using (var soundPlayer = new System.Media.SoundPlayer(waveFileName))
{
soundPlayer.PlaySync();
}
if (!noAutoContinue)
{
PlayNext(idx);
}
}
}
private void PlayNext(int idx)
{
if (checkBoxContinuePlay.Checked && !_abortPlay && idx < listView1.Items.Count - 1)
{
listView1.Items[idx].Selected = false;
listView1.Items[idx + 1].Selected = true;
listView1.Items[idx + 1].Focused = true;
listView1.Items[idx + 1].EnsureVisible();
TaskDelayHelper.RunDelayed(TimeSpan.FromMilliseconds(10), () => Play());
Application.DoEvents();
}
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count == 0)
{
labelParagraphInfo.Text = string.Empty;
return;
}
var idx = listView1.SelectedItems[0].Index;
var p = _subtitle.Paragraphs[idx];
labelParagraphInfo.Text = p.StartTime.ToDisplayString() + " --> " + p.EndTime.ToDisplayString() + " : " + p.Duration.ToShortDisplayString();
}
private void buttonPlay_Click(object sender, EventArgs e)
{
_abortPlay = false;
Play();
}
private void buttonStop_Click(object sender, EventArgs e)
{
_libMpv?.Stop();
_abortPlay = true;
}
private void VoicePreviewList_Shown(object sender, EventArgs e)
{
if (LibMpvDynamic.IsInstalled)
{
_libMpv = new LibMpvDynamic();
_mpvDoneTimer = new Timer();
_mpvDoneTimer.Interval = 100;
_mpvDoneTimer.Tick += (o, args) =>
{
if (listView1.SelectedItems.Count == 0)
{
return;
}
var idx = listView1.SelectedItems[0].Index;
if (_libMpv.IsPaused && _libMpv.CurrentPosition > _libMpv.Duration - 1)
{
_mpvDoneTimer.Stop();
PlayNext(idx);
}
};
}
}
private void listView1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Space || e.KeyCode == Keys.P || e.KeyCode == Keys.Play)
{
e.SuppressKeyPress = true;
TaskDelayHelper.RunDelayed(TimeSpan.FromMilliseconds(1), () => Play());
}
}
private void buttonReGenerate_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count == 0)
{
return;
}
var idx = listView1.SelectedItems[0].Index;
using (var form = new RegenerateAudioClip(_textToSpeech, _subtitle, idx))
{
var dr = form.ShowDialog(this);
if (dr == DialogResult.OK)
{
_fileNames[idx] = form.NewAudioFileName;
listView1.Items[idx].SubItems[4].Text = _subtitle.Paragraphs[idx].Text;
Play(true);
}
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -35,19 +35,20 @@
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.labelEngine = new System.Windows.Forms.Label();
this.groupBoxMsSettings = new System.Windows.Forms.GroupBox();
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.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.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.SuspendLayout();
//
@ -109,6 +110,7 @@
//
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.checkBoxShowPreview);
this.groupBoxMsSettings.Controls.Add(this.labelApiKey);
this.groupBoxMsSettings.Controls.Add(this.nikseTextBoxApiKey);
this.groupBoxMsSettings.Controls.Add(this.TextBoxTest);
@ -125,6 +127,19 @@
this.groupBoxMsSettings.TabStop = false;
this.groupBoxMsSettings.Text = "Settings";
//
// checkBoxShowPreview
//
this.checkBoxShowPreview.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.checkBoxShowPreview.AutoSize = true;
this.checkBoxShowPreview.Checked = true;
this.checkBoxShowPreview.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBoxShowPreview.Location = new System.Drawing.Point(17, 350);
this.checkBoxShowPreview.Name = "checkBoxShowPreview";
this.checkBoxShowPreview.Size = new System.Drawing.Size(115, 17);
this.checkBoxShowPreview.TabIndex = 25;
this.checkBoxShowPreview.Text = "Review audio clips";
this.checkBoxShowPreview.UseVisualStyleBackColor = true;
//
// labelApiKey
//
this.labelApiKey.AutoSize = true;
@ -135,28 +150,6 @@
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, 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);
//
// buttonTestVoice
//
this.buttonTestVoice.Location = new System.Drawing.Point(17, 158);
@ -190,6 +183,72 @@
this.labelVoice.TabIndex = 16;
this.labelVoice.Text = "Voice";
//
// listViewActors
//
this.listViewActors.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listViewActors.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeaderActor,
this.columnHeaderVoice});
this.listViewActors.ContextMenuStrip = this.contextMenuStripActors;
this.listViewActors.FullRowSelect = true;
this.listViewActors.GridLines = true;
this.listViewActors.HideSelection = false;
this.listViewActors.Location = new System.Drawing.Point(412, 42);
this.listViewActors.Name = "listViewActors";
this.listViewActors.Size = new System.Drawing.Size(430, 375);
this.listViewActors.TabIndex = 40;
this.listViewActors.UseCompatibleStateImageBehavior = false;
this.listViewActors.View = System.Windows.Forms.View.Details;
//
// columnHeaderActor
//
this.columnHeaderActor.Text = "Actor";
this.columnHeaderActor.Width = 200;
//
// columnHeaderVoice
//
this.columnHeaderVoice.Text = "Voice";
this.columnHeaderVoice.Width = 200;
//
// contextMenuStripActors
//
this.contextMenuStripActors.Name = "contextMenuStripActors";
this.contextMenuStripActors.Size = new System.Drawing.Size(61, 4);
//
// labelActors
//
this.labelActors.AutoSize = true;
this.labelActors.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.labelActors.Location = new System.Drawing.Point(412, 20);
this.labelActors.Name = "labelActors";
this.labelActors.Size = new System.Drawing.Size(170, 13);
this.labelActors.TabIndex = 19;
this.labelActors.Text = "Right-click to assign actor to voice";
//
// 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)
@ -243,50 +302,6 @@
this.nikseComboBoxEngine.UsePopupWindow = false;
this.nikseComboBoxEngine.SelectedIndexChanged += new System.EventHandler(this.nikseComboBoxEngine_SelectedIndexChanged);
//
// listViewActors
//
this.listViewActors.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listViewActors.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeaderActor,
this.columnHeaderVoice});
this.listViewActors.ContextMenuStrip = this.contextMenuStripActors;
this.listViewActors.FullRowSelect = true;
this.listViewActors.GridLines = true;
this.listViewActors.HideSelection = false;
this.listViewActors.Location = new System.Drawing.Point(412, 42);
this.listViewActors.Name = "listViewActors";
this.listViewActors.Size = new System.Drawing.Size(430, 375);
this.listViewActors.TabIndex = 40;
this.listViewActors.UseCompatibleStateImageBehavior = false;
this.listViewActors.View = System.Windows.Forms.View.Details;
//
// columnHeaderActor
//
this.columnHeaderActor.Text = "Actor";
this.columnHeaderActor.Width = 200;
//
// columnHeaderVoice
//
this.columnHeaderVoice.Text = "Voice";
this.columnHeaderVoice.Width = 200;
//
// contextMenuStripActors
//
this.contextMenuStripActors.Name = "contextMenuStripActors";
this.contextMenuStripActors.Size = new System.Drawing.Size(61, 4);
//
// labelActors
//
this.labelActors.AutoSize = true;
this.labelActors.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.labelActors.Location = new System.Drawing.Point(412, 20);
this.labelActors.Name = "labelActors";
this.labelActors.Size = new System.Drawing.Size(170, 13);
this.labelActors.TabIndex = 19;
this.labelActors.Text = "Right-click to assign actor to voice";
//
// TextToSpeech
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -338,5 +353,6 @@
private System.Windows.Forms.Label labelActors;
private System.Windows.Forms.Label labelApiKey;
private Controls.NikseTextBox nikseTextBoxApiKey;
private System.Windows.Forms.CheckBox checkBoxShowPreview;
}
}

View File

@ -14,6 +14,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Nikse.SubtitleEdit.Controls;
using MessageBox = Nikse.SubtitleEdit.Forms.SeMsgBox.MessageBox;
namespace Nikse.SubtitleEdit.Forms.Tts
@ -29,7 +30,8 @@ namespace Nikse.SubtitleEdit.Forms.Tts
private bool _abort;
private readonly List<string> _actors;
private readonly List<TextToSpeechEngine> _engines;
private readonly List<ElevenLabModel> _elevelLabVoices;
private readonly List<ElevenLabModel> _elevenLabVoices;
private bool _actorsOn;
public class ActorAndVoice
{
@ -68,11 +70,11 @@ namespace Nikse.SubtitleEdit.Forms.Tts
InitializeComponent();
UiUtil.FixFonts(this);
_subtitle = subtitle;
_subtitle = new Subtitle(subtitle, false);
_subtitleFormat = subtitleFormat;
_videoFileName = videoFileName;
_videoInfo = videoInfo;
_elevelLabVoices = new List<ElevenLabModel>();
_elevenLabVoices = new List<ElevenLabModel>();
_actors = _subtitle.Paragraphs
.Where(p => !string.IsNullOrEmpty(p.Actor))
.Select(p => p.Actor)
@ -135,6 +137,8 @@ namespace Nikse.SubtitleEdit.Forms.Tts
MinimumSize = new Size(w, MinimumSize.Height);
Width = w;
}
nikseComboBoxVoice.Text = Configuration.Settings.Tools.TextToSpeechLastVoice;
}
private void SetActor(ActorAndVoice actor)
@ -196,6 +200,25 @@ namespace Nikse.SubtitleEdit.Forms.Tts
return;
}
if (checkBoxShowPreview.Checked)
{
using (var form = new ReviewAudioClips(this, _subtitle, fileNames))
{
var dr = form.ShowDialog(this);
if (dr != DialogResult.OK)
{
_abort = true;
HandleAbort();
return;
}
foreach (var idx in form.SkipIndices)
{
fileNames[idx] = null; // skip these files
}
}
}
var tempAudioFile = MergeAudioParagraphs(fileNames);
if (_abort)
{
@ -778,8 +801,6 @@ namespace Nikse.SubtitleEdit.Forms.Tts
}
var httpClient = new HttpClient();
//httpClient.BaseAddress = new Uri("https://api.elevenlabs.io/v1/text-to-speech/");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("accept", "audio/mpeg");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("xi-api-key", nikseTextBoxApiKey.Text.Trim());
@ -788,7 +809,7 @@ namespace Nikse.SubtitleEdit.Forms.Tts
progressBar1.Maximum = subtitle.Paragraphs.Count;
progressBar1.Visible = showProgressBar;
var voices = _elevelLabVoices;
var voices = _elevenLabVoices;
var v = nikseComboBoxVoice.Text;
for (var index = 0; index < subtitle.Paragraphs.Count; index++)
@ -920,12 +941,12 @@ namespace Nikse.SubtitleEdit.Forms.Tts
labelApiKey.Visible = true;
nikseTextBoxApiKey.Visible = true;
if (_elevelLabVoices.Count == 0)
if (_elevenLabVoices.Count == 0)
{
_elevelLabVoices.AddRange(GetElevelLabVoices());
_elevenLabVoices.AddRange(GetElevelLabVoices());
}
foreach (var voice in _elevelLabVoices)
foreach (var voice in _elevenLabVoices)
{
nikseComboBoxVoice.Items.Add(voice.ToString());
}
@ -1002,7 +1023,7 @@ namespace Nikse.SubtitleEdit.Forms.Tts
}
else if (engine.Id == TextToSpeechEngineId.ElevenLabs)
{
var voices = _elevelLabVoices;
var voices = _elevenLabVoices;
foreach (var voiceLanguage in voices
.GroupBy(p => p.Language)
.OrderBy(p => p.Key))
@ -1063,6 +1084,7 @@ namespace Nikse.SubtitleEdit.Forms.Tts
labelActors.Visible = true;
listViewActors.Visible = true;
_actorsOn = true;
}
}
}
@ -1152,6 +1174,21 @@ namespace Nikse.SubtitleEdit.Forms.Tts
listViewActors.AutoSizeLastColumn();
}
public async Task<string> GenerateAudio(Paragraph p, string voice)
{
nikseComboBoxVoice.Text = voice;
var sub = new Subtitle();
sub.Paragraphs.Add(p);
var waveFileNameOnly = Guid.NewGuid() + ".wav";
var ok = await GenerateParagraphAudio(sub, false, waveFileNameOnly);
if (!ok)
{
return null;
}
return Path.Combine(_waveFolder, waveFileNameOnly);
}
private async void buttonTestVoice_Click(object sender, EventArgs e)
{
try
@ -1235,6 +1272,7 @@ namespace Nikse.SubtitleEdit.Forms.Tts
}
Configuration.Settings.Tools.TextToSpeechEngine = engine.Id.ToString();
Configuration.Settings.Tools.TextToSpeechLastVoice = nikseComboBoxVoice.Text;
}
private void TextToSpeech_KeyDown(object sender, KeyEventArgs e)
@ -1253,5 +1291,40 @@ namespace Nikse.SubtitleEdit.Forms.Tts
buttonTestVoice_Click(null, null);
}
}
public string GetParagraphAudio(Paragraph paragraph)
{
if (_actorsOn)
{
var engine = _engines.First(p => p.Index == nikseComboBoxEngine.SelectedIndex);
if (engine.Id == TextToSpeechEngineId.Piper)
{
var voices = PiperModels.GetVoices();
var voice = voices.First(x => x.ToString() == nikseComboBoxVoice.Text);
if (_actorAndVoices.Count > 0 && !string.IsNullOrEmpty(paragraph.Actor))
{
var f = _actorAndVoices.FirstOrDefault(x => x.Actor == paragraph.Actor);
if (f != null && !string.IsNullOrEmpty(f.Voice))
{
return voices[f.VoiceIndex].Voice;
}
}
}
}
return nikseComboBoxVoice.Text;
}
public void SetCurrentVoices(NikseComboBox nikseComboBox)
{
nikseComboBox.Items.Clear();
foreach (var voice in nikseComboBoxVoice.Items)
{
nikseComboBox.Items.Add(voice.ToString());
}
nikseComboBox.SelectedIndex = nikseComboBoxVoice.SelectedIndex;
}
}
}

View File

@ -851,9 +851,9 @@ namespace Nikse.SubtitleEdit.Logic.VideoPlayers
}
}
Application.DoEvents();
OnVideoLoaded?.Invoke(this, null);
Application.DoEvents();
Pause();
Application.DoEvents();
OnVideoLoaded?.Invoke(this, null);
}
public override void DisposeVideoPlayer()

View File

@ -686,6 +686,12 @@
<Compile Include="Forms\Tts\PiperDownload.Designer.cs">
<DependentUpon>PiperDownload.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Tts\RegenerateAudioClip.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Tts\RegenerateAudioClip.Designer.cs">
<DependentUpon>RegenerateAudioClip.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Tts\TextToSpeech.cs">
<SubType>Form</SubType>
</Compile>
@ -1416,6 +1422,12 @@
<Compile Include="Forms\TransportStreamSubtitleChooser.Designer.cs">
<DependentUpon>TransportStreamSubtitleChooser.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Tts\ReviewAudioClips.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Tts\ReviewAudioClips.Designer.cs">
<DependentUpon>ReviewAudioClips.cs</DependentUpon>
</Compile>
<Compile Include="Forms\UnknownSubtitle.cs">
<SubType>Form</SubType>
</Compile>
@ -1960,6 +1972,9 @@
<EmbeddedResource Include="Forms\Tts\PiperDownload.resx">
<DependentUpon>PiperDownload.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Tts\RegenerateAudioClip.resx">
<DependentUpon>RegenerateAudioClip.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Tts\TextToSpeech.resx">
<DependentUpon>TextToSpeech.cs</DependentUpon>
</EmbeddedResource>
@ -2312,6 +2327,9 @@
<EmbeddedResource Include="Forms\TransportStreamSubtitleChooser.resx">
<DependentUpon>TransportStreamSubtitleChooser.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Tts\ReviewAudioClips.resx">
<DependentUpon>ReviewAudioClips.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\UnknownSubtitle.resx">
<DependentUpon>UnknownSubtitle.cs</DependentUpon>
<SubType>Designer</SubType>