Make sure to copy your client_secrets.json file string as a resource to be loaded by the code below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Imports System.Windows.Forms Public Class FileSelectorDialog Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click Me.DialogResult = System.Windows.Forms.DialogResult.OK Me.Close() End Sub Private Sub Cancel_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel_Button.Click Me.DialogResult = System.Windows.Forms.DialogResult.Cancel Me.Close() End Sub End Class |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
Imports System.IO Imports System.Runtime.InteropServices Imports System.Text Imports Google.Cloud.TextToSpeech.V1 Imports NAudio.Wave 'Install-Package Google.Cloud.TextToSpeech.V1 -Version 2.1.0 Module Program 'Const JsonPath As String = "C:\Users\MyUser\Desktop\GoogleSpeechToText\GoogleSpeechToText\client_secrets.json" 'Embedded as a resource Dim MyTextToSpeechClient As TextToSpeechClient Dim StringArrayList As New ArrayList Dim FilesPaths As New List(Of String) <DllImport("winmm.dll")> Private Function mciSendString(ByVal command As String, ByVal returnValue As StringBuilder, ByVal returnLength As Integer, ByVal winHandle As IntPtr) As UInteger End Function Function GetSoundLength(ByVal fileName As String) As Integer Dim lengthBuf As StringBuilder = New StringBuilder(32) mciSendString(String.Format("open ""{0}"" type waveaudio alias wave", fileName), Nothing, 0, IntPtr.Zero) mciSendString("status wave length", lengthBuf, lengthBuf.Capacity, IntPtr.Zero) mciSendString("close wave", Nothing, 0, IntPtr.Zero) Dim length As Integer = 0 Integer.TryParse(lengthBuf.ToString(), length) Return length End Function Private Function GetMediaDuration(ByVal Path As String) As Double Dim duration As Double = 0.0 Using fs As FileStream = File.OpenRead(Path) Dim frame As Mp3Frame = Mp3Frame.LoadFromStream(fs) Dim _sampleFrequency As Integer If frame IsNot Nothing Then _sampleFrequency = CUInt(frame.SampleRate) End If While frame IsNot Nothing If frame.ChannelMode = ChannelMode.Mono Then duration += CDbl(frame.SampleCount) / CDbl(frame.SampleRate) 'duration += CDbl(frame.SampleCount) * 2.0 / CDbl(frame.SampleRate) Else duration += CDbl(frame.SampleCount) * 4.0 / CDbl(frame.SampleRate) End If frame = Mp3Frame.LoadFromStream(fs) End While End Using Return duration End Function Sub Main(args As String()) Dim Selector As New FileSelectorDialog Selector.Show() Selector.Text = "CNET Text To Speech" Selector.OpenFileDialog1.Multiselect = True Selector.OpenFileDialog1.Filter = "Text files (*.txt) | *.txt" Selector.OpenFileDialog1.ShowDialog() 'Debug.WriteLine(Selector.OpenFileDialog1.FileName) If Not IO.File.Exists(Selector.OpenFileDialog1.FileName) Or Not Selector.OpenFileDialog1.FileName Like "*.txt" Then System.Windows.Forms.MessageBox.Show(Selector.OpenFileDialog1.FileName & " does not appear to be a valid file") End End If For Each Filename As String In Selector.OpenFileDialog1.FileNames Debug.WriteLine(Filename) Selector.Label1.Text = Selector.OpenFileDialog1.FileName System.Windows.Forms.Application.DoEvents() ConvertTextFile(Filename) Next End Sub Private Function SplitWithoutSplittingSentenaces(text As String, Optional maxLength As Integer = 4000) As String() Dim substrings As New List(Of String) Do Until text.Length = 0 If text.Length <= maxLength Then 'There is only one substring left. substrings.Add(text) text = String.Empty Else Dim length = maxLength 'Find the index at or before the maxLength that there is not a letter on both sides of the split. Do While text(length - 1) <> "." ' Char.IsLetter(text(length)) AndAlso Char.IsLetter(text(length - 1)) length -= 1 Loop substrings.Add(text.Substring(0, length)) text = text.Substring(length) End If Loop Return substrings.ToArray() End Function Private Sub ConvertTextFile(ByVal FilePath As String, Optional RegexPagePattern As String = vbNullString) Dim I As Integer = 0 Dim FileText As String = IO.File.ReadAllText(FilePath).Trim Dim FinalLineToAdd As String = vbNullString For Each MyLine In FileText.Split(vbCrLf) If MyLine.Length >= 5000 Then For Each MyString In SplitWithoutSplittingSentenaces(MyLine, 4500) FinalLineToAdd &= MyString & vbCrLf Next Else FinalLineToAdd &= MyLine & vbCrLf End If Next For Each MyLine In FinalLineToAdd.Split(vbCrLf) MyLine = MyLine.Trim().Replace(vbNullChar, "") & ".<break time=""1s""/>" If StringArrayList.Count = 0 Then StringArrayList.Add(MyLine) Else If StringArrayList(I).ToString.Count + MyLine.Length + "<speak></speak>".Length >= 5000 Then If MyLine.Contains("***") Then Continue For System.Diagnostics.Debugger.Break() End If StringArrayList.Add(MyLine) I += 1 Debug.WriteLine("{" & MyLine & "}") Else StringArrayList(I) &= MyLine Debug.WriteLine(MyLine) End If End If Next Dim CueStream As IO.TextWriter = New StreamWriter(FilePath.Replace(".txt", ".cue"), False) CueStream.WriteLine("PERFORMER ""Name""") CueStream.WriteLine("TITLE ""Title""") CueStream.WriteLine("FILE """ & IO.Path.GetFileName(FilePath.Replace(".txt", ".mp3")) & """ WAVE") For I = 0 To StringArrayList.Count - 1 Debug.WriteLine(I & " - " & StringArrayList(I).ToString.Length) Next Dim Mp3Filenames As String = FilePath.Replace(".txt", "") Dim CurrentMP3Filename As String = Mp3Filenames Dim CurrentDurationIndex As Double = 0 For I = 0 To StringArrayList.Count - 1 CurrentMP3Filename = Mp3Filenames & "-" & I & ".mp3" ' Run(CurrentMP3Filename, "<speak>" & StringArrayList(I) & "</speak>", 1.4).Wait() Run(CurrentMP3Filename, "<speak>" & StringArrayList(I) & "</speak>", 1.4).Wait() FilesPaths.Add(CurrentMP3Filename) 'Dim wmp As New WindowsMediaPlayer ''Works but not with .NET CORE 'Dim mediainfo As IWMPMedia = wmp.newMedia(CurrentMP3Filename) 'Dim Double1 As Double = Math.Round(mediainfo.duration, 2) 'Debug.WriteLine(Double1) 'Dim ts As TimeSpan = TimeSpan.FromSeconds(Double1) 'Debug.WriteLine(String.Format("{0}:{1}:{2}.{3}", ts.Hours.ToString.PadLeft(2, "0"), ts.Minutes.ToString.PadLeft(2, "0"), ts.Seconds.ToString.PadLeft(2, "0"), ts.Milliseconds.ToString.PadLeft(2, "0"))) 'Dim myWaveFile As New WaveFileReader(CurrentMP3Filename) 'myWaveFile.Close() Dim ts As TimeSpan = TimeSpan.FromSeconds(CurrentDurationIndex) 'Dim FormatedDuration As String = String.Format("{0}:{1}:{2}.00", ts.Hours.ToString.PadLeft(2, "0"), ts.Minutes.ToString.PadLeft(2, "0"), ts.Seconds.ToString.PadLeft(2, "0"), ts.Milliseconds.ToString.PadLeft(2, "0")) Dim FormatedDuration As String = String.Format("{0}:{1}:00", ts.Minutes.ToString.PadLeft(2, "0"), ts.Seconds.ToString.PadLeft(2, "0")) Dim CurrentTile As String = IO.Path.GetFileName(CurrentMP3Filename.Replace("mp3.", "")) If RegexPagePattern IsNot vbNullString Then 'CurrentTile 'Regex the pages and add to Cue file End If CueStream.WriteLine("TRACK 0" & (I + 1) & " AUDIO") CueStream.WriteLine("TITLE """ & CurrentTile & """") 'CueStream.WriteLine("INDEX 0" & (I + 1) & " " & FormatedDuration) CueStream.WriteLine("INDEX 01 " & FormatedDuration) CurrentDurationIndex += GetMediaDuration(CurrentMP3Filename) Next CueStream.Close() Dim MyNewStream As New IO.FileStream(FilePath.Replace(".txt", ".mp3"), FileMode.Create) Combine(FilesPaths, MyNewStream) MyNewStream.Close() MyNewStream.Dispose() For Each MyFile As String In FilesPaths Debug.WriteLine(MyFile) If MyFile.EndsWith(".mp3") Then IO.File.Delete(MyFile) End If Next 'System.Diagnostics.Process.Start("cmd.exe ", "/c " & Selector.OpenFileDialog1.FileName.Replace(".txt", ".mp3")) End Sub Public Sub Combine(inputFiles As List(Of String), output As Stream) For Each file As String In inputFiles Dim reader As New Mp3FileReader(file) If (output.Position = 0) AndAlso (reader.Id3v2Tag IsNot Nothing) Then output.Write(reader.Id3v2Tag.RawData, 0, reader.Id3v2Tag.RawData.Length) End If Dim frame As Mp3Frame frame = reader.ReadNextFrame While frame IsNot Nothing output.Write(frame.RawData, 0, frame.RawData.Length) frame = reader.ReadNextFrame End While reader.Close() reader.Dispose() Next End Sub Public Async Function Run(ByVal Filename As String, ByVal SAML As String, Optional ByVal SpeakingRate As Double = 1.0) As Task(Of SynthesizeSpeechResponse) 'Upload to Youtube Try Dim MyTextToSpeechClientBuilder As New TextToSpeechClientBuilder() MyTextToSpeechClientBuilder.JsonCredentials = Global.GoogleSpeechToText.My.Resources.GoogleAuth 'MyTextToSpeechClientBuilder.CredentialsPath = JsonPath MyTextToSpeechClient = MyTextToSpeechClientBuilder.Build() 'Dim response = MyTextToSpeechClient.ListVoices("en") 'For Each Myvoice In response.Voices 'Console.WriteLine($"{Myvoice.Name} ({Myvoice.SsmlGender}); Language codes: {String.Join(", ", Myvoice.LanguageCodes)}") 'Next Catch ex As Exception Debug.WriteLine(ex.Message) End Try '.Text = Text Dim input As SynthesisInput = New SynthesisInput With { .Ssml = SAML } Debug.WriteLine(input.Ssml) Dim voice As VoiceSelectionParams = New VoiceSelectionParams With { .LanguageCode = "en-US", .SsmlGender = SsmlVoiceGender.Neutral } Dim config As AudioConfig = New AudioConfig With { .AudioEncoding = AudioEncoding.Mp3, .SpeakingRate = SpeakingRate } Dim response2 = MyTextToSpeechClient.SynthesizeSpeech(New SynthesizeSpeechRequest With { .Input = input, .Voice = voice, .AudioConfig = config }) Using output As Stream = File.Create(Filename) 'Dim Mp3Dur As New Mp3FileReader(output) 'Debug.WriteLine(Mp3Dur.TotalTime) response2.AudioContent.WriteTo(output) Debug.WriteLine($"Audio content written to file: " & Filename & " - Length: " & response2.AudioContent.Length) End Using End Function End Module |