Results 1 to 16 of 16

Thread: Direct Text-To-Speech - Simultaneous Voices?

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Sep 2013
    Posts
    127

    Question Direct Text-To-Speech - Simultaneous Voices?

    Code:
    Private V As SpeechLib.SpVoice
     
    Private Sub Command1_Click()
      V.Speak (Text1.Text)
    End Sub
     
    Private Sub Form_Load()
      Set V = New SpeechLib.SpVoice
    End Sub
    Is there a way to incorporate text-to-speech with multiple voices talking at the same time? This code, along with others I've found, seem to force the application to wait for the speech to finish before speaking again.

  2. #2
    Addicted Member
    Join Date
    Jun 2018
    Posts
    189

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Hello,

    This is a quick answer and just an idea, tested on Win7, it works.
    The key is to using separate speech objects with asynchronous speaking.
    You might enhance the idea for your need, may be with events.

    Code:
    Option Explicit
    
    Private spv1 As SpeechLib.SpVoice
    Private spv2 As SpeechLib.SpVoice
    
    Private Sub Command1_Click()
        
        Set spv1 = New SpVoice
        Set spv1.Voice = spv1.GetVoices.Item(0) 'set your first voice
        spv1.Speak "Hello, Did you hear the second voice too?", SVSFlagsAsync
        
        
        Set spv2 = New SpVoice
        Set spv2.Voice = spv2.GetVoices.Item(0) 'set your second voice
        spv2.Speak "Hi, This is the second voice", SVSFlagsAsync
        
    End Sub
    Last edited by PGBSoft; Dec 12th, 2018 at 01:00 PM.

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Sep 2013
    Posts
    127

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Quote Originally Posted by PGBSoft View Post
    Hello,

    This is a quick answer and just an idea, tested on Win7, it works.
    The key is to using separate speech objects with asynchronous speaking.
    You might enhance the idea for your need, may be with events.

    Code:
    Option Explicit
    
    Private spv1 As SpeechLib.SpVoice
    Private spv2 As SpeechLib.SpVoice
    
    Private Sub Command1_Click()
        
        Set spv1 = New SpVoice
        Set spv1.Voice = spv1.GetVoices.Item(0) 'set your first voice
        spv1.Speak "Hello, Did you hear the second voice too?", SVSFlagsAsync
        
        
        Set spv2 = New SpVoice
        Set spv2.Voice = spv2.GetVoices.Item(0) 'set your second voice
        spv2.Speak "Hi, This is the second voice", SVSFlagsAsync
        
    End Sub
    This doesn't do what I need. This code speaks one after the other. It does not speak the text simultaneously, as is needed.

  4. #4
    Addicted Member
    Join Date
    Jun 2018
    Posts
    189

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Hi,

    Which OS are you using?
    It works as expected on Windows 7, which means, while speaking in voice1 you can hear the voice2 also.
    However, no idea how this works on Windows 10.

    EDIT:
    Can someone confirm that the code in #2 works as expected on Windows7?
    Last edited by PGBSoft; Dec 12th, 2018 at 01:58 PM.

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Sep 2013
    Posts
    127

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Quote Originally Posted by PGBSoft View Post
    Hi,

    Which OS are you using?
    It works as expected on Windows 7, which means, while speaking in voice1 you can hear the voice2 also.
    However, no idea how this works on Windows 10.

    EDIT:
    Can someone confirm that the code in #2 works as expected on Windows7?
    I am using Windows 10.

  6. #6
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,598

    Re: Direct Text-To-Speech - Simultaneous Voices?

    I don't know if it is Windows Version specific, or SAPI version specific, but I also have Windows 10, and they did not speak simultaneously.
    The interaction is asynchronous with the Gui, but the speech method calls get queued up and speak in turn.
    I modified the code a little for a test.
    Code:
    Private spv1 As New SpeechLib.SpVoice
    Private spv2 As New SpeechLib.SpVoice
    
    Private Sub Command1_Click()
    
        spv1.Speak "Hello, Did you hear the second voice too?", SVSFlagsAsync
        spv2.Speak "Hi, This is the second voice", SVSFlagsAsync
    
    End Sub
    
    
    Private Sub Form_Load()
        Set spv1.Voice = spv1.GetVoices.Item(0)  'set your first voice
        Set spv2.Voice = spv2.GetVoices.Item(1) 'set your second voice
    'End Sub
    So, I click the button and I expect a male voice to speak the first phrase, and a female voice to speak the second phrase.
    If I press the button three times in quick succession, I would expect the voices to be interlaced, repeating three times.
    What I get is the first voice repeats its phrase three times, followed by the second voice repeating its phrase three times. None of the voices overlap each other.

  7. #7
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,598

    Re: Direct Text-To-Speech - Simultaneous Voices?

    I guess if you use the speech to Stream capability to save the speech to a file, you can then use mci methods, or other methods, to play the two files at the same time.
    Code:
    Option Explicit
    
    Private Declare Function mciSendString Lib "winmm.dll" _
    Alias "mciSendStringA" _
    (ByVal lpstrCommand As String, _
    ByVal lpstrReturnString As String, _
    ByVal uReturnLength As Long, _
    ByVal hwndCallback As Long) As Long
    
    Private M As SpeechLib.SpVoice      'M is a male voice
    Private F As SpeechLib.SpVoice      'F is a female voice
    Private S As SpeechLib.SpFileStream
    
    Private Sub Command1_Click()
      
        mciSendString "Close wav1", 0, 0, 0
        mciSendString "Close wav2", 0, 0, 0
        
        'Build a local file path and open it as a stream
          Set S = New SpFileStream
          Call S.Open("C:\c\SpkStrm1.wav", SSFMCreateForWrite, False)
        
          'Female voice speaks into the file stream and creates a WAV file
          Set F.AudioOutputStream = S
          F.Speak "Hi, This is the second voice", SVSFNLPSpeakPunc
          S.Close
        
          Set S = New SpFileStream
          Call S.Open("C:\c\SpkStrm2.wav", SSFMCreateForWrite, False)
          'Male voice speaks into a stream and creates a WAV file
          Set M.AudioOutputStream = S
          M.Speak "i will now speak over top the female voice."
          S.Close
        
        mciSendString "Open C:\c\SpkStrm1.wav alias wav1", 0, 0, 0
        mciSendString "Open C:\c\SpkStrm2.wav alias wav2", 0, 0, 0
        
        mciSendString "play wav1", 0, 0, 0
        mciSendString "play wav2", 0, 0, 0
      
    End Sub
    
    Private Sub Form_Load()
    
        'Create voices
        Set F = New SpVoice
        Set F.Voice = F.GetVoices("gender=female").Item(0)
        Set M = New SpVoice
        Set M.Voice = M.GetVoices("gender=male").Item(0)
    
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        mciSendString "Close wav1", 0, 0, 0
        mciSendString "Close wav2", 0, 0, 0
    End Sub
    Last edited by passel; Dec 13th, 2018 at 01:36 AM.

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Sep 2013
    Posts
    127

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Very nice work-around, Passel! I'll leave this thread open for a day or two in case someone has a different idea. Thanks!

  9. #9
    Addicted Member
    Join Date
    Jun 2018
    Posts
    189

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Quote Originally Posted by mcoulter876 View Post
    This doesn't do what I need. This code speaks one after the other. It does not speak the text simultaneously, as is needed.
    Hello,

    How about the following then?

    Code:
    Option Explicit
    
    Private spv1 As SpeechLib.SpVoice
    Private spv2 As SpeechLib.SpVoice
    
    Private Sub Form_Load()
    
        Set spv1 = New SpVoice
        Set spv2 = New SpVoice
        spv2.Priority = SVPOver
        
        Set spv1.Voice = spv1.GetVoices.Item(0)  'male voice
        Set spv2.Voice = spv2.GetVoices.Item(1)  'female voice
    
    End Sub
    
    Private Sub Command1_Click()
        
        spv1.Speak "Hello, First voice goes here. Did you hear the second voice too?", SVSFlagsAsync
        spv2.Speak "Hi, This is second voice", SVSFlagsAsync
    
    End Sub
    Last edited by PGBSoft; Dec 13th, 2018 at 12:57 PM.

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Sep 2013
    Posts
    127

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Quote Originally Posted by PGBSoft View Post
    Hello,

    How about the following then?

    Code:
    Option Explicit
    
    Private spv1 As SpeechLib.SpVoice
    Private spv2 As SpeechLib.SpVoice
    
    Private Sub Form_Load()
    
        Set spv1 = New SpVoice
        Set spv2 = New SpVoice
        spv2.Priority = SVPOver
        
        Set spv1.Voice = spv1.GetVoices.Item(0)  'male voice
        Set spv2.Voice = spv2.GetVoices.Item(1)  'female voice
    
    End Sub
    
    Private Sub Command1_Click()
        
        spv1.Speak "Hello, First voice goes here. Did you hear the second voice too?", SVSFlagsAsync
        spv2.Speak "Hi, This is second voice", SVSFlagsAsync
    
    End Sub
    That did it. But how could I create an array of them, so that it's not needed to specify just 2? That way, it would keep creating new voices each time I clicked the command button. Example: When I quickly click the Command Button 5 times, it creates 5 new voices, all speaking over each other.

  11. #11
    Addicted Member
    Join Date
    Jun 2018
    Posts
    189

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Quote Originally Posted by mcoulter876 View Post
    That did it. But how could I create an array of them, so that it's not needed to specify just 2? That way, it would keep creating new voices each time I clicked the command button. Example: When I quickly click the Command Button 5 times, it creates 5 new voices, all speaking over each other.
    Then, you should experiment with the stuff bit.

    I don't know what's your actual idea behind this. However, just packing the stuff into a usercontrol and use it appropriately would be a better solution. Another would be to directly use a class module with the stuff, but may have problems with asynchronous speaking.

    The attached one is a small demonstration on the usercontrol approach, which you might adopt for your need. Just tested on both Win7 and Win10 and seems working well.
    Attached Files Attached Files

  12. #12

    Thread Starter
    Lively Member
    Join Date
    Sep 2013
    Posts
    127

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Quote Originally Posted by PGBSoft View Post
    Then, you should experiment with the stuff bit.

    I don't know what's your actual idea behind this. However, just packing the stuff into a usercontrol and use it appropriately would be a better solution. Another would be to directly use a class module with the stuff, but may have problems with asynchronous speaking.

    The attached one is a small demonstration on the usercontrol approach, which you might adopt for your need. Just tested on both Win7 and Win10 and seems working well.
    @PGBSoft: Is there any way to have the control unload itself once it has finished reading, instead of having to hit the "Reset" button?

  13. #13
    Addicted Member
    Join Date
    Jun 2018
    Posts
    189

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Quote Originally Posted by mcoulter876 View Post
    Is there any way to have the control unload itself once it has finished reading, instead of having to hit the "Reset" button?
    Hello,

    Yes, that's totally possible, if you consider the events of speech object. Just raise your own event at the completion of speaking and unload the UC in the event handler with its index and update the counter. I didn't consider such stuff since this is just a demo.

    However, I suggest you to try yourself first. If you can't, just let me know; I will try to give you an update.

  14. #14

    Thread Starter
    Lively Member
    Join Date
    Sep 2013
    Posts
    127

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Quote Originally Posted by PGBSoft View Post
    Hello,

    Yes, that's totally possible, if you consider the events of speech object. Just raise your own event at the completion of speaking and unload the UC in the event handler with its index and update the counter. I didn't consider such stuff since this is just a demo.

    However, I suggest you to try yourself first. If you can't, just let me know; I will try to give you an update.
    I think it's in the DoSpeak function. I've placed
    Code:
    Unload Form1.UserControl11
    before it Exits the Sub, but I'm not sure how I would know if it actually unloaded it or not or if that's even what I should be doing. I've never created my own control before and haven't a clue where to even begin raising an event to unload the specific array.

  15. #15
    Addicted Member
    Join Date
    Jun 2018
    Posts
    189

    Re: Direct Text-To-Speech - Simultaneous Voices?

    Quote Originally Posted by mcoulter876 View Post
    I think it's in the DoSpeak function. I've placed
    Code:
    Unload Form1.UserControl11
    You can not unload the UC even with its index inside the DoSpeak since you use asynchronous reading. You need to consider the event raised by the Speech object at the end of the stream and unload the UC in its event-handler. But, better to raise your own event here and handle it within the Form so that you can control the array index and the counter easily.

    An update is attached. Now, you can click the button any number of times in a row to produce voices.
    Attached Files Attached Files

  16. #16
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Direct Text-To-Speech - Simultaneous Voices?

    You can also do this with a naked Class rather than a UserControl with a little fiddling. While you can't have a WithEvents array we can easily use a late-bound callback method instead. Or if you create a callback Class then your hosting objects such as Forms could implement that if you want early binding.

    Form1.frm:
    Code:
    Option Explicit
    
    Private Const MAX_VOICES As Integer = 4
    
    'Create empty but valid array:
    Private Declare Function VoiceArray Lib "oleaut32" Alias "SafeArrayCreateVector" ( _
        Optional ByVal VT As VbVarType = vbObject, _
        Optional ByVal LB As Long = 0, _
        Optional ByVal cElements As Long = 0) As Voice()
    
    Private Voices() As Voice
    
    Public Sub EndStream(ByVal Index As Integer)
        Debug.Print "Voice"; Index; "EndStream"
        Command1.Enabled = True
    End Sub
    
    Private Sub Command1_Click()
        Dim I As Integer
    
        For I = 0 To UBound(Voices)
            If Voices(I).Idle Then Exit For
        Next
        If I > UBound(Voices) Then
            ReDim Preserve Voices(I)
            Set Voices(I) = New Voice
            Voices(I).Setup I, Me
            Command1.Enabled = I + 1 < MAX_VOICES
        End If
        Debug.Print "Voice"; I; "Speaking"
        Voices(I).Speak "Scooby-Dooby-Doo, where are you?  We got some work to do now.  " _
                      & "Scooby-Dooby-Doo, where are you?  We need some help from you now."
    End Sub
    
    Private Sub Form_Load()
        Voices = VoiceArray()
    End Sub
    Voice.cls:
    Code:
    Option Explicit
    
    Private Host As Object
    Private WithEvents SpVoice As SpeechLib.SpVoice
    
    Private mIdle As Boolean
    Private mIndex As Integer
    
    Public Property Get Idle() As Boolean
        Idle = mIdle
    End Property
    
    Public Property Get Index() As Integer
        Index = mIndex
    End Property
    
    Public Sub Setup(ByVal NewIndex As Integer, ByVal CallbackHost As Object)
        mIndex = NewIndex
        'Just in case somebody assigns this more than once we check:
        If SpVoice Is Nothing Then
            Set SpVoice = New SpeechLib.SpVoice
            With SpVoice.GetVoices()
                Set SpVoice.Voice = .Item(NewIndex Mod .Count)
            End With
            SpVoice.Priority = SVPOver
            SpVoice.Rate = -2
        End If
        Set Host = CallbackHost
    End Sub
    
    Public Sub Speak(ByVal Text As String)
        mIdle = False
        SpVoice.Speak Text, SVSFlagsAsync
    End Sub
    
    Private Sub Class_Initialize()
        mIdle = True
    End Sub
    
    Private Sub Class_Terminate()
        Set SpVoice = Nothing
        Set Host = Nothing
    End Sub
    
    Private Sub SpVoice_EndStream(ByVal StreamNumber As Long, ByVal StreamPosition As Variant)
        mIdle = True
        Host.EndStream mIndex
    End Sub
    Attached Files Attached Files

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width