Drydo's Blog

Teenager of the Internet

vbCity Blogs moved to:
http://cs.vbcity.com/blogs
  Home :: Syndication  :: Login   Community Forums   :: vbCity.com   :: DevCity.NET  

Eh up,

OK - I admit it has been awhile.  But after all that stuff in the papers and the whole on-off thing with Angelina Jolie - well, you could understand my mind has been elsewhere.

Anyhoo, I'm back and after the brushing the cobwebs away I thought I'll use my blog for the power of good and dump up some stuff as I go along, like interesting pieces of code and that kind of thing.

Today's masterpiece is this little thing I posted up on the forum the other day.  In short, it piggybacks onto the ATT Text-To-Speech demonstration site that allows simply words / sentences to be converted to speech by returning a WAV file.  The data is POST'ed to the server and the WAV file returned.  You can find out more information at -> http://www.research.att.com/projects/tts/demo.html

Anyway, I thought it would be fun to mess around with the HTTPWebRequest and HTTPWebResponse objects to achieve this and you can find the source below.  Of course, I also thought it would be fun to make it process complicated swearing terms often accompanied by people I know, e.g. 'Felching' in the voice of Rosa brings tears to my eyes.

It makes the request sending over the appropriate POST data, it receives the response back with the location of the WAV file, it then makes a second request for the WAV file - obtains the byte data in a stream - copies that in a byte array and plays it using the sndPlaySound API Function.

There are a few of things of note...

  • I've set the 'request.AllowAutoRedirect' to false to check whether any session data was used and decided to keep it in.  Yes, I could set this to true and simply get the WAV directly from the initial request - but hey, it was fun to check out the header data.
  • Ideally, I should have put Asycn methods for the response and byte data functions, feel free to do this if that kind of thing turns you on.
  • Safe to say that this isn't production code and I'm sure ATT will not be overly happy with anyone using this service commercially.  To put it another way - you ain't seen me, right!

Have fun - M

 

Code Copy HideScrollFull
Imports System.Text
Imports
System.Net
Imports
System.IO

Public
Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.
    'Do not modify it using the code editor.
    Friend WithEvents txtSpeak As System.Windows.Forms.TextBox
    Friend WithEvents lblLabel1 As System.Windows.Forms.Label
    Friend WithEvents cmbVoice As System.Windows.Forms.ComboBox
    Friend WithEvents lblLabel2 As System.Windows.Forms.Label
    Friend WithEvents butConvert As System.Windows.Forms.Button
    Friend WithEvents prgDown As System.Windows.Forms.ProgressBar
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.txtSpeak = New System.Windows.Forms.TextBox
        Me.lblLabel1 = New System.Windows.Forms.Label
        Me.cmbVoice = New System.Windows.Forms.ComboBox
        Me.lblLabel2 = New System.Windows.Forms.Label
        Me.butConvert = New System.Windows.Forms.Button
        Me.prgDown = New System.Windows.Forms.ProgressBar
        Me.SuspendLayout()
        '
        'txtSpeak
        '
        Me.txtSpeak.Location = New System.Drawing.Point(120, 28)
        Me.txtSpeak.Name = "txtSpeak"
        Me.txtSpeak.Size = New System.Drawing.Size(416, 20)
        Me.txtSpeak.TabIndex = 0
        Me.txtSpeak.Text = "Drydo is a V B city God and everyone else is his hoes!"
        '
        'lblLabel1
        '
        Me.lblLabel1.Location = New System.Drawing.Point(36, 32)
        Me.lblLabel1.Name = "lblLabel1"
        Me.lblLabel1.Size = New System.Drawing.Size(76, 16)
        Me.lblLabel1.TabIndex = 1
        Me.lblLabel1.Text = "Text to speak:"
        '
        'cmbVoice
        '
        Me.cmbVoice.Location = New System.Drawing.Point(120, 56)
        Me.cmbVoice.Name = "cmbVoice"
        Me.cmbVoice.Size = New System.Drawing.Size(144, 21)
        Me.cmbVoice.TabIndex = 2
        '
        'lblLabel2
        '
        Me.lblLabel2.Location = New System.Drawing.Point(36, 60)
        Me.lblLabel2.Name = "lblLabel2"
        Me.lblLabel2.Size = New System.Drawing.Size(76, 16)
        Me.lblLabel2.TabIndex = 3
        Me.lblLabel2.Text = "Voice:"
        '
        'butConvert
        '
        Me.butConvert.Location = New System.Drawing.Point(120, 124)
        Me.butConvert.Name = "butConvert"
        Me.butConvert.Size = New System.Drawing.Size(340, 24)
        Me.butConvert.TabIndex = 4
        Me.butConvert.Text = "Speechify"
        '
        'prgDown
        '
        Me.prgDown.Location = New System.Drawing.Point(36, 92)
        Me.prgDown.Name = "prgDown"
        Me.prgDown.Size = New System.Drawing.Size(500, 16)
        Me.prgDown.TabIndex = 5
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.BackColor = System.Drawing.SystemColors.Control
        Me.ClientSize = New System.Drawing.Size(564, 161)
        Me.Controls.Add(Me.prgDown)
        Me.Controls.Add(Me.butConvert)
        Me.Controls.Add(Me.lblLabel2)
        Me.Controls.Add(Me.cmbVoice)
        Me.Controls.Add(Me.lblLabel1)
        Me.Controls.Add(Me.txtSpeak)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Declare Function sndPlaySound Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal lpszSoundName As Byte(), ByVal uFlags As Integer) As Integer

    Private Const SND_MEMORY As Integer = &H4
    Private Const SND_ASYNC As Integer = &H1

    Private Const PROCESS_DOMAIN As String = "http://hegel.research.att.com/"

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Add the voice values
        Dim dt As New DataTable
        ' Add the columns
        dt.Columns.Add("ID", GetType(String))
        dt.Columns.Add("Name", GetType(String))
        ' Accept
        dt.AcceptChanges()
        ' Add the entries
        Dim dr As DataRow
        dt.LoadDataRow(New Object() {"crystal", "Crystal ...... US English"}, False)
        dt.LoadDataRow(New Object() {"mike", "Mike ...... US English"}, False)
        dt.LoadDataRow(New Object() {"rich", "Rich ...... US English"}, False)
        dt.LoadDataRow(New Object() {"lauren", "Lauren .... US English"}, False)
        dt.LoadDataRow(New Object() {"claire", "Claire .... US English"}, False)
        dt.LoadDataRow(New Object() {"rosa", "Rosa ...... Latin Am. Spanish"}, False)
        dt.LoadDataRow(New Object() {"alberto", "Alberto ... Latin Am. Spanish"}, False)
        dt.LoadDataRow(New Object() {"klara", "Klara ..... German"}, False)
        dt.LoadDataRow(New Object() {"reiner", "Reiner .... German"}, False)
        dt.LoadDataRow(New Object() {"alain", "Alain ..... French"}, False)
        dt.LoadDataRow(New Object() {"juliette", "Juliette .. French"}, False)
        dt.LoadDataRow(New Object() {"charles", "Charles ... UK English"}, False)
        dt.LoadDataRow(New Object() {"audrey", "Audrey .... UK English"}, False)
        ' Bind to the combobox
        With Me.cmbVoice
            .DataSource = dt
            .DisplayMember = "Name"
            .ValueMember = "ID"
        End With
    End Sub

    Private Sub butConvert_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles butConvert.Click

        ' Generate the appropriate post data
        Dim postData As String
        postData = "txt=" & Me.txtSpeak.Text & "&voice=" & Me.cmbVoice.SelectedValue.ToString

        ' Generate the initial request and response objects
        Dim request As HttpWebRequest
        Dim response As HttpWebResponse
        request = CType(WebRequest.Create(PROCESS_DOMAIN & "/tts/cgi-bin/nph-talk"), HttpWebRequest)
        request.ContentType = "application/x-www-form-urlencoded"
        request.ContentLength = postData.Length
        request.Method = "POST"
        request.AllowAutoRedirect = False

        ' Perform the request
        Dim requestStream As Stream = request.GetRequestStream()
        Dim postBytes As Byte() = System.Text.Encoding.ASCII.GetBytes(postData)
        requestStream.Write(postBytes, 0, postBytes.Length)
        requestStream.Close()
        response = CType(request.GetResponse(), HttpWebResponse)

        ' Obtain the location of the WAV from the 'location' element of the header
        Dim WAVLocation As String = response.Headers.Item("Location").ToString()

        ' Close the previous response
        response.Close()
        request = Nothing
        response = Nothing

        ' Perform a second connection to obtain the WAV
        Dim WAVrequest As HttpWebRequest = WebRequest.Create(PROCESS_DOMAIN & WAVLocation)
        Dim WAVresponse As HttpWebResponse
        With WAVrequest
            .ContentType = "application/x-www-form-urlencoded"
            .Method = "GET"
        End With

        ' Obtain the byte response from the server
        WAVresponse = CType(WAVrequest.GetResponse(), HttpWebResponse)

        ' Then take the stream into its byte format
        Dim s As Stream = WAVresponse.GetResponseStream
        Dim buffer(WAVresponse.ContentLength - 1) As Byte
        Dim TotalRead As Integer = 0

        ' Set up the progressbar
        Me.prgDown.Maximum = WAVresponse.ContentLength
        Me.prgDown.Minimum = 1

        ' Read the stream data into a byte array
        Do
            TotalRead += s.Read(buffer, TotalRead, buffer.Length - TotalRead)
            Me.prgDown.Value = TotalRead
        Loop Until TotalRead = buffer.Length

        ' Cleanup
        s.Close()
        WAVresponse.Close()
        WAVrequest = Nothing
        WAVresponse = Nothing

        ' Finally, play the WAV as a byte stream
        sndPlaySound(buffer, SND_ASYNC Or SND_MEMORY).ToString()

    End Sub
End
Class
. . .
posted on Friday, June 03, 2005 10:10 AM