You can see that in the Load handler I create an instance of the Converter class and call it's getInstalledVoices method to return a string array of the installed SAPI voices on the machine, which is Databound to the combobox.
When the ComboBox's selected index is changed (the user selects a voice from the dropdown), we call the Text2WavPlay static method, which accepts a string of text to speak, and the voice id string (e.g. "Microsoft Sam") from the control. You can also pass null for the second parameter and it will use the default voice profile.
Finally, when the user clicks the "Get Rss" button on the form, we retreive an RSS feed from Url spcified in the textbox, and populate our datagrid with it. The GetSelectedRow method is used to find a row on the grid that the user has clicked, and then to play the column of information that represents the Title item from that RSS item.
Switching over to the actual Converter Class, which is now embedded with the rest of the CSWavPlay / Record library:
using System;
using System.IO;
using System.Threading;
using System.Web;
using SpeechLib;
namespace WaveLib
{
public class Converter
{
public Converter()
{
}
public string[] getInstalledVoices()
{
SpVoice speech = new SpVoice();
ISpeechObjectTokens sot = speech.GetVoices("", "");
string[] voiceIds = new string[sot.Count];
for (int i = 0; i < sot.Count; i++)
voiceIds[i] = sot.Item(i).GetDescription(1033);
return voiceIds;
}
public void TextToWav(string inputText, string filePath, string voiceIdString)
{
try
{
HttpContext ctx = HttpContext.Current;
if (ctx != null)
{
DirectoryInfo di = new DirectoryInfo(ctx.Server.MapPath("."));
FileInfo[] fi = di.GetFiles("*.wav");
foreach (FileInfo f in fi)
File.Delete(ctx.Server.MapPath(f.Name));
}
SpeechVoiceSpeakFlags SpFlags = SpeechVoiceSpeakFlags.SVSFlagsAsync;
SpVoice speech = new SpVoice();
if (voiceIdString != String.Empty)
{
ISpeechObjectTokens sot = speech.GetVoices("", "");
string[] voiceIds = new string[sot.Count];
for (int i = 0; i < sot.Count; i++)
{
voiceIds[i] = sot.Item(i).GetDescription(1033);
if (voiceIds[i] == voiceIdString)
speech.Voice = sot.Item(i);
}
}
SpeechStreamFileMode SpFileMode = SpeechStreamFileMode.SSFMCreateForWrite;
SpFileStream SpFileStream = new SpFileStream();
SpFileStream.Format.Type = SpeechAudioFormatType.SAFT11kHz8BitMono;
if (! filePath.ToLower().EndsWith(".wav")) filePath += ".wav";
SpFileStream.Open(filePath, SpFileMode, false);
speech.AudioOutputStream = SpFileStream;
speech.Speak(inputText, SpFlags);
speech.WaitUntilDone(Timeout.Infinite);
SpFileStream.Close();
}
catch
{
throw;
}
}
public static void TextToWavPlay(string inputText, string voiceIdString)
{
byte[] b = TextToWav(inputText, voiceIdString);
// play bytes here
Player m_Player = Player.Instance;
WaveFormat fmt;
fmt = new WaveFormat(11000, 8, 1);
m_Player.SetInput(new MemoryStream(b), fmt);
m_Player.Start(b.Length);
}
public static byte[] TextToWav(string inputText, string voiceIdString)
{
byte[] b = null;
try
{
SpeechVoiceSpeakFlags SpFlags = SpeechVoiceSpeakFlags.SVSFlagsAsync;
SpVoice speech = new SpVoice();
if (voiceIdString != String.Empty)
{
ISpeechObjectTokens sot = speech.GetVoices("", "");
string[] voiceIds = new string[sot.Count];
for (int i = 0; i < sot.Count; i++)
{
voiceIds[i] = sot.Item(i).GetDescription(1033);
if (voiceIds[i] == voiceIdString)
speech.Voice = sot.Item(i);
}
}
SpMemoryStream spMemStream = new SpMemoryStream();
spMemStream.Format.Type = SpeechAudioFormatType.SAFT11kHz8BitMono;
object buf = new object();
speech.AudioOutputStream = spMemStream;
int r = speech.Speak(inputText, SpFlags);
speech.WaitUntilDone(Timeout.Infinite);
spMemStream.Seek(0, SpeechStreamSeekPositionType.SSSPTRelativeToStart);
buf = spMemStream.GetData();
b = (byte[]) buf;
}
catch
{
throw;
}
return b;
}
}
} |
Above you can see how the various methods are implemented to get the installed voices, play a string of text in memory, or return a byte array representing the raw PCM audio portion of a TextToWav string (without WAV header). I hope this concept is useful to you.
Download the Visual Studio.NET 2003 Solution accompanying this article |