C#: Google Text-to-speech Loop - c#

I'm creating a simple program that takes a string, sends it to Google's text to speech server, and downloads the text to speech in a mp3/wav file on the computer. I have the code below, but it only works with up to 100 characters (Google's limit). How can I make a loop to cut the string into 100 character parts and then save it in one mp3/wav file on the computer? I know this is possible with javascript and actionscript (as I have seen them) but how can I do this in C#?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
namespace TestCSharp
{
class Program
{
static void Main(string[] args)
{
WebClient web = new WebClient();
web.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/4.0 (compatible; MSIE 9.0; Windows;)");
string encstr = string.Empty;
string filename = "tts.mp3"; //could also be tts.wav
string s = "This string cannot be more than 100 characters.";
encstr = Uri.EscapeDataString(s);
Console.WriteLine(encstr);
web.DownloadFile("http://translate.google.com/translate_tts?tl=en&q=" + encstr, ".\\" + filename);
}
}
}

This is not a direct answer, but I think the splitting is not good because TTS has word intonation as well as sentence intonation. Instead, I recommend you use SpeechSynthesizer Class with free TTS engine. However, I don't know which TTS engine is good as free and where it is. If finding goodness, I'll post it.
UPDATED
MP3 files are just concatenated without a problem, from this question.
well, before I get to concatenating the mp3 files, how would the while
loop look like to first get those mp3 files on the computer? if i go
through my loop, the tts.mp3 file would be overwritten and i would be
left with only the last 100 character string that was received..
You can merge the two files like the code below.
Finally, the fs1 will get all content.
string tts1 = "tts1.mp3";
string tts2 = "tts2.mp3";
FileStream fs1 = null;
FileStream fs2 = null;
try
{
fs1 = File.Open(tts1, FileMode.Append);
fs2 = File.Open(tts2, FileMode.Open);
byte[] fs2Content = new byte[fs2.Length];
fs2.Read(fs2Content, 0, (int)fs2.Length);
fs1.Write(fs2Content, 0, (int)fs2.Length);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + " : " + ex.StackTrace);
}
finally
{
fs1.Close();
fs2.Close();
}

Related

Unity saving the player's username and score to a text file

I made an input field in which the user types their username and a "Send data" button that sends the username and the score to a text file, However, the score isn't saving for some reason. The output says 0 but the score is increasing in-game. I can't seem to figure out what is causing this.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using UnityEngine.Networking;
public class ScoreScript : MonoBehaviour
{
public Text MyscoreText, userTxt;
private int ScoreNum;
// Start is called before the first frame update
void Start()
{
ScoreNum = 0;
}
private void OnTriggerEnter2D(Collider2D Diamond)
{
if (Diamond.tag == "Diamond")
{
// Player's score increases when they collide with a diamond
ScoreNum++;
Destroy(Diamond.gameObject);
MyscoreText.text = "Score: " + ScoreNum;
}
}
public void SaveScore()
{
// Saves the username and score to a text file
string tmp = userTxt.text + "," + ScoreNum.ToString();
System.Text.UnicodeEncoding encode = new System.Text.UnicodeEncoding();
byte[] byteData = encode.GetBytes(tmp);
Debug.Log(tmp);
if (!File.Exists(Application.absoluteURL + #"\hiscore.txt"))
{
FileStream oFileStream = null;
oFileStream = new FileStream(Application.dataPath + #"\hiscore.txt", FileMode.Create);
oFileStream.Write(byteData, 0, byteData.Length);
oFileStream.Close();
}
else
{
using (StreamWriter stream = File.AppendText(Application.dataPath + #"\hiscore.txt"))
{
stream.WriteLine(tmp);
}
}
}
}
I tested your code and every time I call the method SaveScore() the program creates a new hiscore.txt file as if one wasn't created before. I replaced the "Aplication.absoluteURL" with "Application.dataPath" and the program functioned as intended, so now the method SaveScore() looks like this:
public void SaveScore()
{
string tmp = userTxt.text + "," + ScoreNum.ToString();
System.Text.UnicodeEncoding encode = new System.Text.UnicodeEncoding();
byte[] byteData = encode.GetBytes(tmp);
Debug.Log(tmp);
if (!File.Exists(Application.dataPath + #"\hiscore.txt"))
{
FileStream oFileStream = null;
oFileStream = new FileStream(Application.dataPath + #"\hiscore.txt", FileMode.Create);
oFileStream.Write(byteData, 0, byteData.Length);
oFileStream.Close();
}
else
{
using (StreamWriter stream = File.AppendText(Application.dataPath + #"\hiscore.txt"))
{
stream.WriteLine(tmp);
}
}
}
Two issues here, I think. The first seems like it could be because you're using File.AppendText in the else section of your code, which should be UTF-8 encoded text, per the documentation:
Creates a StreamWriter that appends UTF-8 encoded text to an existing file, or to a new file if the specified file does not exist.
But you're not encoding the text there like you are for the section above. What I would suggest instead is to just use File.AppendAllText, which has the following benefits:
Creates the file if it doesn't exist, otherwise appends to the file. This means that you don't need to check if the file exists and write it one way, else write it another, you can just call the one command and it creates-or-appends.
Lets you pass strings instead of byte arrays, so you can just write your strings without needing to bother with encoding.
Second big issue I think is when you check if the file exists, you're checking a URL and not a path:
if (!File.Exists(Application.absoluteURL + #"\hiscore.txt"))
But then you're writing/appending to a file at a path:
oFileStream = new FileStream(Application.dataPath + #"\hiscore.txt", FileMode.Create);
[...]
using (StreamWriter stream = File.AppendText(Application.dataPath + #"\hiscore.txt"))
The if statement is checking Application.absoluteURL and the if/else is using Application.dataPath.
Another issue you might be having is if you're having permissions troubles and you're not able to get write access to the file, like if you had created it when you had sudo privileges but now you don't (sudo expires! did you try restarting?) or if your application is in a protected Windows directory or something.
Are you sure you haven't disabled errors in the Unity Console? I would also try deleting the hiscore.txt file (spelling here? Are you checking hiscore or highscore?) and see if you get updates.
Finally also, and deleting the file might make this clear, it's not obvious here how the save function is getting called, so it's also very possible you've inadvertently broken that callback somehow, like changing the name or something.

C# - While writing into a text file, the ouput file is not created [duplicate]

This question already has answers here:
Easiest way to read from and write to files
(14 answers)
Closed 2 years ago.
Below is the code I have. My issue is that the file.txt is not created at all!
I cannot find the reason. Program should create it. Could you please help me ?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WriteToFile
{
class Program
{
static void Main(string[] args)
{
string line = "Please help me to write something!!";
System.IO.StreamWriter file = new System.IO.StreamWriter
(#"C:\Users\jgonc\source\repos\WriteToFile\WriteToFile\bin\Debug\file.txt");
file.Flush();
file.WriteLine(line);
file.Close();
Console.WriteLine("press a key");
Console.ReadKey();
}
}
}
//line you want to write to the document
string line = "Please help me to write something!!";
//path to my documents
string docPath =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
using (StreamWriter sw = new StreamWriter(Path.Combine(docPath, "test.txt")))
{
sw.WriteLine(line);
}
Console.WriteLine("press a key");
Console.ReadKey();
Here I make use of the using keyword. This is extremely useful as any object created in the parameters will automatically be destroyed when the using segment ends which is great because it means you don't need to clutter your code with unnecessary flushes and closes.
Its also important you understand the difference between a flush & a close. Here when the using segment ends dispose is called on streamwriter which in turn calls close, which closes the stream. A flush is simply clearing the buffer.
Check that you the application has permission to write to my documents directory - here
I have changed the path to my documents as the bin folder often changes or is deleted.
Thank you for your support and hints.
I've investigate the permissions topic and it seems it was related to it.
After uninstalling my antivirus it started to work.
below is the final code, to write a couple of strings using StreamWriter.
static void Main(string[] args)
{
string[] lines = {
"Please help me to write something!",
"It's working now, it was related with my antivirus, it was somehow blocking my permissions to the folder",
"Thanks for your support and your hints!!",
};
//string path = #"C:\Users\jgonc\source\repos\WriteToFile\WriteToFile\bin\Debug\file.txt";
string path = #"file.txt";
System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite);
System.IO.StreamWriter file = new System.IO.StreamWriter(fs, System.Text.Encoding.ASCII);
if (!File.Exists(path))
{
Console.WriteLine("file was not created");
}
else
{
using (file)
{
foreach (string line in lines) {
file.WriteLine(line);
}
}
}
fs.Close();
Console.WriteLine("Press a Key to End...");
Console.ReadKey();
}
Try :
System.IO.StreamWriter file = new System.IO.StreamWriter
(#"C:\Users\jgonc\source\repos\WriteToFile\WriteToFile\bin\Debug\file.txt", true);
true for append attribute set it false if you want to create file every time.

Wait for page load before downloading with WebClient

I have several URLs stored in a text file, each of them is a link leading to a Facebook emoji, like https://www.facebook.com/images/emoji.php/v5/u75/1/16/1f618.png
I'm trying to download these images and store them on my disk. I'm using WebClient with DownloadFileAsync, something like
using (var client = new WebClient())
{
client.DownloadFileAsync(imgURL, imgName);
}
My problem is even if the amount of URLs is small, say 10, some of the images are downloaded ok, some give me a file corrupt error. So I thought I needed to wait for files to be downloaded till the end and added DownloadFileCompleted event, like this
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Net;
class Program
{
static Queue<string> q;
static void Main(string[] args)
{
q = new Queue<string>(new[] {
"https://www.facebook.com/images/emoji.php/v5/u51/1/16/1f603.png",
"https://www.facebook.com/images/emoji.php/v5/ud2/1/16/1f604.png",
"https://www.facebook.com/images/emoji.php/v5/ud4/1/16/1f606.png",
"https://www.facebook.com/images/emoji.php/v5/u57/1/16/1f609.png",
"https://www.facebook.com/images/emoji.php/v5/u7f/1/16/1f60a.png",
"https://www.facebook.com/images/emoji.php/v5/ufb/1/16/263a.png",
"https://www.facebook.com/images/emoji.php/v5/u81/1/16/1f60c.png",
"https://www.facebook.com/images/emoji.php/v5/u2/1/16/1f60d.png",
"https://www.facebook.com/images/emoji.php/v5/u75/1/16/1f618.png",
"https://www.facebook.com/images/emoji.php/v5/u1e/1/16/1f61a.png"
});
DownloadItem();
Console.WriteLine("Hit return after 'finished' has appeared...");
Console.ReadLine();
}
private static void DownloadItem()
{
if (q.Any())
{
var uri = new Uri(q.Dequeue());
var file = uri.Segments.Last();
var webClient = new WebClient();
webClient.DownloadFileCompleted += DownloadFileCompleted;
webClient.DownloadFileAsync(uri, file);
}
else
{
Console.WriteLine("finished");
}
}
private static void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
DownloadItem();
}
}
It didn't help and I decided to look closer into the files that are corrupted.
It appeared that the files that were corrupted were not actually image files, but HTML pages, which either had some redirection JavaScript code to an image or were full HTML pages saying that my browser was not supported.
So my question is, how do I actually wait that an image file has been fully loaded and is ready to be downloaded?
EDIT I have also tried to remove the using statement, but that did not help either.
Nothing's being corrupted by your download - it's simply Facebook deciding (sometimes, which is odd) that it doesn't want to serve the image to your client.
It looks like it's the lack of a user agent that causes the problem. All you need to do is specify the user agent, and that looks like it fixes it:
webClient.Headers.Add(HttpRequestHeader.UserAgent,
"Mozilla/5.0 (compatible; http://example.org/)");

C# File directory issue

I have created a high score file for my game and I am having problems reading it.
When I change computers my USB drive changes letter .eg from drive E to drive G.
This is causing problems with reading the file. (as I use string path = #"g:\Scores.txt";)
So my question is.... can I set a default path to the program location??
My current code:-
string path = #"g:\Scores.txt";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(path))
{
while (sr.Peek() >= 0)
{
sb.Append(sr.ReadLine());
}
}
any help is appreciated.
Is the game on your USB drive as well? Do you want to save the file in the same directory as the game, or in a directory somewhere around it? Do something like this:
using System;
using System.IO;
using System.Reflection;
...
string thisAsmFile = Assembly.GetExecutingAssembly().Location;
string thisAsmDir = Path.GetDirectoryName(thisAsmPath);
string highScoreFile = Path.Combine(thisAsmDir, "scores.txt");
If your program is in the same folder as the file ( Eg. in G:\ ), then you can simply access the file with his name : `path = "Scores.txt".
In that case there is no need to know where is the file
You should use your application path, not an absolute path.
You may do something like this:
using System.IO;
using System.Windows.Forms;
string appPath = Path.GetDirectoryName(Application.ExecutablePath);

MediaComposition.RenderToFileAsync crashes with many static images

I have a Windows Phone 8.1 Silverlight app that renders .gif files to .mp4, using the Windows.Media.Editing.MediaComposition class.
Certain files will randomly crash the RenderToFileAsync method. There are at least two different error messages you can receive, one stating insufficient memory.
Does anyone have any ideas for a workaround, or some insider knowledge on how this is supposed to work?
Repro:
Create new c# WP8.1 Silverlight app blank project in VS2013
Add Usings and OnNavigatedTo to MainPage.xaml.cs as below.
Run in 512MB emulator. Observe crash (most of the time). Fiddle with value of i to see it work properly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.Windows.Media.Imaging;
using System.IO;
using Windows.Media.Editing;
using System.Diagnostics;
-
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
SystemTray.ProgressIndicator = new ProgressIndicator();
SystemTray.ProgressIndicator.IsVisible = true;
SystemTray.ProgressIndicator.IsIndeterminate= true;
var comp = new MediaComposition();
var r = new Random();
for (int i = 0; i < 190; i++)
{
var wb = new WriteableBitmap(576, 300);
for (int iPix = 0; iPix < wb.Pixels.Length; iPix++)
{
wb.Pixels[iPix] = r.Next();
}
string filename = "file" + i.ToString() + ".jpg";
var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(filename, Windows.Storage.CreationCollisionOption.ReplaceExisting);
using (var curr = await file.OpenStreamForWriteAsync())
{
wb.SaveJpeg(curr, wb.PixelWidth, wb.PixelHeight, 0, 95);
}
var clip = await MediaClip.CreateFromImageFileAsync(file, TimeSpan.FromMilliseconds(60));
comp.Clips.Add(clip);
}
// Ensure add capability to write to video library AND ID_CAP_MEDIALIB_PHOTO and change below to
// Windows.Storage.KnownFolders.VideosLibrary to see output in Videos app
var destFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var destFile = await destFolder.CreateFileAsync("test.mp4", Windows.Storage.CreationCollisionOption.ReplaceExisting);
Debug.WriteLine("Mem use before render to disk: " + Windows.System.MemoryManager.AppMemoryUsage.ToString("N0"));
await comp.RenderToFileAsync(destFile);
Debug.WriteLine("Mem use after render to disk: " + Windows.System.MemoryManager.AppMemoryUsage.ToString("N0"));
SystemTray.ProgressIndicator.IsVisible = false;
MessageBox.Show("Done OK");
}
I ran your code through the Windows Phone application analysis memory profiler. I can confirm that your app is running into the system memory limit of about 150 MB. The MediaComposition engine can require large amounts of memory depending on the size of the input and output formats. In your case you are adding a large number of clips. The number of clips that can be added is limited by the memory available for the decode.
Quite honestly the MediaComposition was not designed to handle such a large number of clips. The expected average number of clips hovers around five.
Unfortunately I was not able to get the only possible workaround I could think of to work. I think that this solution might be feasible but unfortunately I can't spend any more time on it: You might be to create multiple output files using lower numbers of clips. For instance you could create an output file with images one through twenty. You could then create a second file with images twenty one through forty. You could then join these two files together.
I hope this helps,
James
I had basically the same problem and after much trial and error I finally got rid of my "Value does not fall within the expected range" error which caused many or all missing frames.
I added GC.Collect(); right before every MediaClip.CreateFromImageFileAsync. It doesn't seem to effect performance or cause any problems and was the only way I could fix it. Hope this can help others.
Here is some of my code so you can see what I'm talking about:
foreach (var thisFrame in frames)
{
GC.Collect();
try
{
MediaClip clip = await MediaClip.CreateFromImageFileAsync(thisFrame, TimeSpan.FromMilliseconds(36 * speed));
app.mediaComposition.Clips.Add(clip);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + ex.StackTrace);
}
}

Categories