Solved

TTS

Posted on 2012-04-12
12
959 Views
Last Modified: 2012-04-17
In my Andoid app, I am trying to save Text-To-Speech to a file for playback at a later time. I am saving to a file using synthesizeToFile function of the TTS Engine. When I am using that function, I am providing a string variable called destFileName as one of the parameters, which holds the full path of the file.

My question is, once I synthesizeToFile, is there any way to use that file later to retrieve the  destFileName string?


Code below:

// Saves Text-To-Speech in a .wav file for future playback
//******************************************
string destFileName = "/sdcard/"  + ".wav";

HashMap<String, String> myHashRender = new HashMap();
              myHashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, previewName);
             
              try{
              if(myTTS.synthesizeToFile(saveText, myHashRender, destFileName) == TextToSpeech.SUCCESS)
              {
                    audioFileArrayList = GetFileInfo(previewName, destFileName);
                    Toast.makeText(getBaseContext(), "Saved Successfully!", Toast.LENGTH_SHORT).show();
              }
              else
                    Toast.makeText(getBaseContext(), "Oops! Something happened. Your text was not saved.", Toast.LENGTH_SHORT).show();
              } catch(Exception e) {
                    Toast.makeText(getBaseContext(), "synthesizeToFile Failed", Toast.LENGTH_SHORT).show();
                    e.printStackTrace();
              }
0
Comment
Question by:InfoTechEE
  • 7
  • 5
12 Comments
 
LVL 7

Expert Comment

by:tampnic
ID: 37845319
I'm not sure I understand your question - if you are using the file later then surely you must have known the path to it when you retrieved it.

A few other notes on the code ....
You should use getExternalFilesDir() to get a suitable path to write files to, after you have verified the SD card is available with Environment.getExternalStorageState().

You are not naming the file properly in your current code, just specifying a path and extension, so every time the function is called it overwrites the same file "/sdcard/.wav"

Cheers,
   Chris
0
 

Author Comment

by:InfoTechEE
ID: 37846737
I am able to write a for loop to cycle through all the files ending in .wav on the sd card and that's how I'm able to list them in my ListView. The problem is that it's not very user friendly and looks ugly to have a list of file names. I'd rather display the first 3 or 4 words of the saved text to speech (.wav) file. I store those first couple words in the string --  previewName.

Then -- myHashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, previewName);

I would like to display the previewName in a ListView and if the user clicks on that ListView Item it will play that .wav file.

Changed code below (added substring to .wav file name).


// Saves Text-To-Speech in a .wav file for future playback
//******************************************
string substr = saveText.substring(0,15);
string destFileName = "/sdcard/"  +  substr + ".wav";

HashMap<String, String> myHashRender = new HashMap();
              myHashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, previewName);
             
              try{
              if(myTTS.synthesizeToFile(saveText, myHashRender, destFileName) == TextToSpeech.SUCCESS)
              {
                    audioFileArrayList = GetFileInfo(previewName, destFileName);
                    Toast.makeText(getBaseContext(), "Saved Successfully!", Toast.LENGTH_SHORT).show();
              }
              else
                    Toast.makeText(getBaseContext(), "Oops! Something happened. Your text was not saved.", Toast.LENGTH_SHORT).show();
              } catch(Exception e) {
                    Toast.makeText(getBaseContext(), "synthesizeToFile Failed", Toast.LENGTH_SHORT).show();
                    e.printStackTrace();
              }
0
 

Author Comment

by:InfoTechEE
ID: 37846759
Here's an example of what I'm looking for.

User types: "This is a test TTS message being saved to a file."

saveText = "This is a test TTS message being saved to a file."
previewName = "This is a test TTS..."
destFileName = "/sdcard/this.wav"

I know I will have to calculate the index of the first "space" character in order to save the first word of the sentence + .wav.

Anyways, then on the ListView I would like to display to the user, the many previewNames associated with the .wav files.

ListView:

This is a test TTS...
Just another test...
Here is one more...

If the user clicks on "This is a test TTS" it needs to play this.wav file.
0
 
LVL 7

Expert Comment

by:tampnic
ID: 37848328
You could store the WAV files in a database with metadata fields to describe the data. An Android cursor is limited to about 1Mb per row if I remember correctly so that's no good if your data is bigger then 1Mb. In that case store the filepath along with the descripition in the database instead.

Cheers,
   Chris
0
 

Author Comment

by:InfoTechEE
ID: 37848790
I'm a beginner and this is for a class project. Databases sound really complex and complicated. Is that true?

I just need to save short sentences for playback. Never exceeding 1mb.

I was thinking some kind of text file on the sd card that holds a list of description and file paths to whatever files on that card. That is if extracting the PreviewName from the wav file -- like in the original question -- is not possible.
0
 
LVL 7

Accepted Solution

by:
tampnic earned 500 total points
ID: 37848841
WAV is a format that holds binary sound data and does not have the capability for holding metadata (e.g. a description) built in. MP3 format can store metadata e.g. Album, Artist, Track Name etc.

Have a look at the database examples around the internet or the Notepad example in the SDK. Using a SimpleCursorAdapter with a ListActivity is really not too difficult if you have any SQL experience. Also a great learning exercise if you are starting out.

I understand your position that for something as simple as this a text file would be just as good and would not be a lot of effort to code.

Another option could be to create a custom class for your data which implements "serializable". You can then store the metadata and the WAV data together in one file.

Cheers,
   Chris
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:InfoTechEE
ID: 37849203
OK so extracting anything from the WAV file is not an option is what I'm understanding.

Will look into the database option as I do have MS SQL experience, but I only have 2 weeks left to finalize this project and I don't know how likely it is that I'll finish it in time. I only have about one and a half months experience programming the Android and about a year experience with JAVA all together. Having said that, I have doubts in my abilitites to implement this.

So are you saying a text file IS an option???

As far as "serializable" goes, I have read something about it when I was trying to pass an objects array from one activity to another. Instead I ended up implementing parselabel. What I'm doing now is inserting the PreviewName and DestinationFileName into a class object and storing that object into an Array. Then passing that array from my Main Activity which saves the WAV files to antoher Activity which displays the available files. The problem is once the App closes is that the Array is gone. Thats why I'm exploring these other options.
0
 
LVL 7

Assisted Solution

by:tampnic
tampnic earned 500 total points
ID: 37849394
Parcelable is best for IPC (inter-process-communication) where you are passing data between processes. Remember its implementation dependent, so the internal format can change at any time. That's not good for files you are saving as you have no guaranteed compatibility between java versions i.e. different versions of the jre might not be able to read the file. You did the right thing avoiding serializable for passing data between activities, but its a good choice for saving objects to disk. If you implement serializable for your array objects, you can write the whole array to disk quite easily.

Using a text file is definitely an option for a small amount of items, but its not scalable to a large amount of items unless you implement an ISAM format or similar. If the array gets very large this can cause an IO bottleneck as you read it in and write it out, but with a database you can add/remove/update the items on disk incrementally instead of all at once. Android has an API to SQLite which fits into the List-Adapter model so I recommend using that.

Cheers,
   Chris
0
 

Author Comment

by:InfoTechEE
ID: 37849884
If I had more time I would definitely use a database. Can u please point me in the right direction to use serializable to save array of objects to disk? And then retrieve that array later?
0
 
LVL 7

Assisted Solution

by:tampnic
tampnic earned 500 total points
ID: 37851308
Here is a little example of using serializable to serialize an array of objects...

MyData.java
import java.io.Serializable;

public class MyData implements Serializable {

	private static final long serialVersionUID = 1L;

	private String mName;
	private String mDescription;
	private String mPath;
	
	public MyData(String name, String desc, String path)
	{
		mName = name;
		mDescription = desc;
		mPath = path;
	}
	
}

Open in new window


And code snippet to read and write an array of MyData objects
// first check external storage is available 
String state = Environment.getExternalStorageState();   
if (Environment.MEDIA_MOUNTED.equals(state)) {
	MyData[] arrayDataOut = new MyData[5];
 	// make a suitable path to a file on the external storage
	String dataFilePath = this.getBaseContext().getExternalFilesDir(null).getAbsolutePath() + File.separatorChar + "MyDataFile.dat";
	// create some data and fill up array
	arrayDataOut[0] = new MyData("name1", "desc1", "path1");
	arrayDataOut[1] = new MyData("name2", "desc2", "path2");
	arrayDataOut[2] = new MyData("name3", "desc3", "path3");
	arrayDataOut[3] = new MyData("name4", "desc4", "path4");
	arrayDataOut[4] = new MyData("name5", "desc5", "path5");
	
	
	try {
		// write array to disk
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(dataFilePath));
		out.writeObject(arrayDataOut);
		out.flush();
		out.close();
		
		// read array from disk
		ObjectInputStream in = new ObjectInputStream(new FileInputStream(dataFilePath));
		MyData[] arrayDataIn = (MyData[]) in.readObject();
		// now the data is in an array again 
		// and we can do something with it
		in.close();
		
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	}
}

Open in new window


Cheers,
  Chris
0
 

Author Comment

by:InfoTechEE
ID: 37851917
Wow, thanks so much for that example. I will try that code ASAP when I come home today.

When I was making my decision to use serializable vs. parselabel, I had to implement many weird methods to MyData class, but with Serializable, I'm noticing it's pretty simple. Looks easy. Will let you know how it goes.

Thanks again.
0
 

Author Comment

by:InfoTechEE
ID: 37859135
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
android cookies 9 27
Hybrid app to listen a radio 12 115
computer science syllabus 3 52
Voice command sync to outlook calendar 11 68
Recently Amazon announced their entry in the tablet device called the Amazon Kindle Fire. Some of you might have used an Ipad or have considered buying one. While they're similar in form and function in that they both have color displays with multit…
Introduction This article is a continuation of Part-1 as evident from the title. Please visit this page (http://www.experts-exchange.com/articles/18706/Backing-up-personal-data-on-your-Android-device-Part-1.html) to read the earlier Part -1. If y…
This video is in connection to the article "The case of a missing mobile phone (https://www.experts-exchange.com/articles/28474/The-Case-of-a-Missing-Mobile-Phone.html)". It will help one to understand clearly the steps to track a lost android phone.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now