Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Lecture synchrone

12 réponses
Avatar
TouTi
Bonsoir à tous

Voilà, je me bagarre avec la lecture d'un fichier *.Wav suivi de la lecture
d'un texte avec l'outil de voix(speechlib).
Tout ceci doit se faire durant l'éxécution du programme : Le mode asynchrone
est alors très utile

Pour la lecture du wav, j'utilise l'API sndPlaySound

Pour la lecture de la voix, j'utilise le librairie sapi.dll (Ms speech objet
library)
Public v As SpeechLib.SpVoice
Sub parle(ByVal Text As String)
On Error GoTo Speak_Error
v.Speak Text, SVSFlagsAsync
Exit Sub
Speak_Error:
End Sub

* Si je lance la lecture des éléments :
FichierSons$ = app.Path + "\son\annonce.wav"
res% = sndPlaySound(ByVal FichierSons$, SND_ASYNC Or SND_NODEFAULT)
parle "Attention le train rentre en gare"
Les sons se chevauchent mais le programme continu de tourner

* Si je change le mode de lecture du Wav (SND_SYNC ) cela se passe bien mais
le programme se fige durant la lecture du wav

Comment puis-je faire pour avoir la lecture du wav, puis du texte sans que
le programme se fige??

Merci


Guy

10 réponses

1 2
Avatar
Jacques93
Bonjour Touti,
TouTi a écrit :
Bonsoir à tous

Voilà, je me bagarre avec la lecture d'un fichier *.Wav suivi de la lecture
d'un texte avec l'outil de voix(speechlib).
Tout ceci doit se faire durant l'éxécution du programme : Le mode asynchrone
est alors très utile

Pour la lecture du wav, j'utilise l'API sndPlaySound

Pour la lecture de la voix, j'utilise le librairie sapi.dll (Ms speech objet
library)
Public v As SpeechLib.SpVoice
Sub parle(ByVal Text As String)
On Error GoTo Speak_Error
v.Speak Text, SVSFlagsAsync
Exit Sub
Speak_Error:
End Sub

* Si je lance la lecture des éléments :
FichierSons$ = app.Path + "sonannonce.wav"
res% = sndPlaySound(ByVal FichierSons$, SND_ASYNC Or SND_NODEFAULT)
parle "Attention le train rentre en gare"
Les sons se chevauchent mais le programme continu de tourner

* Si je change le mode de lecture du Wav (SND_SYNC ) cela se passe bien mais
le programme se fige durant la lecture du wav

Comment puis-je faire pour avoir la lecture du wav, puis du texte sans que
le programme se fige??

Merci


Guy



J'ai fait l'essai avec :

FichierSons$ = "C:WindowsMediaWindows XP Démarrage.wav"

le .wav et le texte s'enchaîne sans chevauchement, ni blocage ???

Qu'entends tu par le programme se fige ?

--
Cordialement,

Jacques.
Avatar
Jacques93
Jacques93 a écrit :
[...}

J'ai fait l'essai avec :

FichierSons$ = "C:WindowsMediaWindows XP Démarrage.wav"

le .wav et le texte s'enchaîne sans chevauchement, ni blocage ???

Qu'entends tu par le programme se fige ?




Question subsidiaire : comment crées tu l'instance de v (As
SpeechLib.SpeechLib.SpVoice)

Je ne vois ni :

Public v As New SpeechLib.SpVoice

ni

Public v As SpeechLib.SpVoice
Set v = New SpeechLib.SpVoice

auquel cas on débrancherait direct sur Speak_Error

Mais dans ce cas ça ne devrait jamais fonctionner, même en mode
SND_ASYNC ...


--
Cordialement,

Jacques.
Avatar
Jean-marc
"TouTi" <gelapplication[NsP]@tiscali.fr> a écrit dans le message de news:

Bonsoir à tous

Voilà, je me bagarre avec la lecture d'un fichier *.Wav suivi de la
lecture d'un texte avec l'outil de voix(speechlib).
Tout ceci doit se faire durant l'éxécution du programme : Le mode
asynchrone est alors très utile

Pour la lecture du wav, j'utilise l'API sndPlaySound

Pour la lecture de la voix, j'utilise le librairie sapi.dll (Ms speech
objet library)
Public v As SpeechLib.SpVoice
Sub parle(ByVal Text As String)
On Error GoTo Speak_Error
v.Speak Text, SVSFlagsAsync
Exit Sub
Speak_Error:
End Sub

* Si je lance la lecture des éléments :
FichierSons$ = app.Path + "sonannonce.wav"
res% = sndPlaySound(ByVal FichierSons$, SND_ASYNC Or SND_NODEFAULT)
parle "Attention le train rentre en gare"
Les sons se chevauchent mais le programme continu de tourner

* Si je change le mode de lecture du Wav (SND_SYNC ) cela se passe bien
mais le programme se fige durant la lecture du wav

Comment puis-je faire pour avoir la lecture du wav, puis du texte sans que
le programme se fige??



Hello,

J'ai bien une solution, mais c'est vraiment une bidouille, ceci
dit ça marchera. Voici:

- Tu lances la lecture du wav en Asynchrone
- // ici, je suppose que tu connais la durée de ton .wav, disons pour
l'exemple 2500 ms (2 secondes et demi)
- Tu initialises un timer avec cette durée (2500)
- Tu démarres le timer
- Dans l'évènement du timer, tu joues la lecture du texte
- Puis toujours dans le timer, tu invalides le timer (enabledúlse)

Et voila, le tour est joué.

Si tu as plusieurs .wav et plusieurs sons à jouer, je te conseille d'écrire
une fonction bien propre à laquelle tu passeras juste un index de tableau
qui contiendrait des choses du genre:
"Nom du wav", "durée du wav", "texte a dire"
C'est ta focntion qui se chargera d'initialiser le timer avec les bonnes
valeurs, etc.
Avec une variable globale (obligé, car pas moyen de passer un argument pour
Timer_Ontime), tout fonctionnera.

Astuce: si tu utilises un tableau global, tu peux même te passer de variable
globale supplémentaire en utilisant astucieusement la propriété "tag" de ton
objet timer pour stocker l'index.

Ainsi, un seul appel de la même fonction sera nécessaire. Il suffit
d'initialiser ton tableau avec les wav, les durées, etc.

Voici un exemple de code fonctionnel, à compléter avec les bonnes
déclarations pour SndPlaysoud et la sub Parle():

Option Explicit

Private Const NB_SEQ As Long = 3 ' par exemple

Private Type PlaySequence
wavFile As String
wavTime As Long
textToSpeech As String
End Type

Dim playseq(NB_SEQ) As PlaySequence

Private Sub Form_Load()
playseq(1).wavFile = "tchoutchou.wav"
playseq(1).wavTime = 2500 ' 2,5 seconds
playseq(1).textToSpeech = "Le train entre en gare"

playseq(2).wavFile = "cracboum.wav"
playseq(2).wavTime = 1400 ' 1,4 seconds
playseq(2).textToSpeech = "Le train deraille"

' par exemple, jouer la séquence 1
Call GenerSoundEvent(1)

End Sub

Private Sub GenerSoundEvent(ByVal idx As Long)

Timer1.Tag = idx
Timer1.Interval = playseq(idx).wavTime
Timer1.Enabled = True
' jouer le son avec sndPlaySound en asynchrone
' sndplaysound( playseq(idx).wavFile, etc...

End Sub

Private Sub Timer1_Timer()

Call parle(playseq(Timer1.Tag).textToSpeech)
Timer1.Enabled = False
End Sub

Private Sub parle()
' la procédure qui parle
End Sub



--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
mailto: remove '_no_spam_' ;
FAQ VB: http://faq.vb.free.fr/
Avatar
TouTi
Bonsoir Jacques

Question subsidiaire : comment crées tu l'instance de v (As
SpeechLib.SpeechLib.SpVoice)
Je ne vois ni :
Public v As New SpeechLib.SpVoice
ni
Public v As SpeechLib.SpVoice
Set v = New SpeechLib.SpVoice



J'ai contacté rapidement un projet exemple :

****************** 1 form avec 2 bouton, un timer, un label, deux
optionbutton

Public v As SpeechLib.SpVoice
Sub parle(ByVal Text As String)
On Error GoTo Speak_Error
If Not Text = "" Then v.Speak Text, SVSFlagsAsync
Exit Sub

Speak_Error:
'rien
End Sub

Private Sub Command1_Click()
Timer1.Enabled = True
If Option1(0).Value = False Then
modeson = SND_ASYNC Or SND_NODEFAULT
Else
modeson = SND_SYNC Or SND_NODEFAULT
End If
FichierSons$ = App.Path + "annonce.wav"
res% = sndPlaySound(ByVal FichierSons$, modeson)
parle "le train corail en provenance de lille rentre en gare"
End Sub

Private Sub Command2_Click()
Timer1.Enabled = False
End Sub

Private Sub Form_Load()
Set v = New SpVoice
End Sub

Private Sub Timer1_Timer()
Label1 = Val(Label1) + 200
End Sub


****************** 1 module
Declare Function sndPlaySound Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal
lpszSoundName As String, ByVal uFlags As Long) As Long
Public Const SND_ASYNC = &H1
Public Const SND_SYNC = &H0
Public Const SND_NODEFAULT = &H2
Public Const SND_NOSTOP = &H10
Public Const SVSFDefault = 0
Public Const SVSFlagsAsync = 1


Les options permettent de changer le mode (asyn/synchrone). En mode
Synchrone le timer est bloqué le programme se fige

Merci de ton aide


--
Guy
Avatar
TouTi
Salut jean marc

J'ai bien une solution, mais c'est vraiment une bidouille, ceci
dit ça marchera. Voici:


On est plus à une bidouille près... ;-)

- Tu lances la lecture du wav en Asynchrone
- // ici, je suppose que tu connais la durée de ton .wav, disons pour
l'exemple 2500 ms (2 secondes et demi)
- Tu initialises un timer avec cette durée (2500)
- Tu démarres le timer
- Dans l'évènement du timer, tu joues la lecture du texte
- Puis toujours dans le timer, tu invalides le timer (enabledúlse)



J'y avais songer mais le problème c'est la durée... Il faudrait que cela
fonctionne quel que soit la durée du WaV sans que l'on doive la déterminer
au préalable et sans devoir mémoriser (dans un fichier par exemple). J'en
demande beaucoup mais cela simplifierait grandement l'affaire.

Le tout serait de récupérer le moment où le son wav se termine : Tout en
restant asynchrone vis a vis du programme qui travaille déjà à partir d'un
timer. Le temps ne peut pas être interrompu par la lecture d'un son ou d'un
voix.

Bien cordialement

--
Guy
Avatar
Jean-marc
"TouTi" <gelapplication[NsP]@tiscali.fr> a écrit dans le message de news:

Salut jean marc

J'ai bien une solution, mais c'est vraiment une bidouille, ceci
dit ça marchera. Voici:


On est plus à une bidouille près... ;-)

- Tu lances la lecture du wav en Asynchrone
- // ici, je suppose que tu connais la durée de ton .wav, disons pour
l'exemple 2500 ms (2 secondes et demi)
- Tu initialises un timer avec cette durée (2500)
- Tu démarres le timer
- Dans l'évènement du timer, tu joues la lecture du texte
- Puis toujours dans le timer, tu invalides le timer (enabledúlse)



J'y avais songer mais le problème c'est la durée... Il faudrait que cela
fonctionne quel que soit la durée du WaV sans que l'on doive la déterminer
au préalable et sans devoir mémoriser (dans un fichier par exemple). J'en
demande beaucoup mais cela simplifierait grandement l'affaire.



Facile :-)

Il est très simple de récupérer la durée d'un fichier .wav:
http://www.codyx.org/snippet_duree-fichier-audio-ou-video_13.aspx

et voila :-)

--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
mailto: remove '_no_spam_' ;
FAQ VB: http://faq.vb.free.fr/
Avatar
TouTi
> Il est très simple de récupérer la durée d'un fichier .wav:
http://www.codyx.org/snippet_duree-fichier-audio-ou-video_13.aspx

et voila :-)



Comme tu dis et voilà.... ;-)

Merci

--
Guy
Avatar
Jacques93
Bonjour Jean-marc et Touti,
Jean-marc a écrit :
[...]

J'ai bien une solution, mais c'est vraiment une bidouille, ceci
dit ça marchera. Voici:

- Tu lances la lecture du wav en Asynchrone
- // ici, je suppose que tu connais la durée de ton .wav, disons pour
l'exemple 2500 ms (2 secondes et demi)
- Tu initialises un timer avec cette durée (2500)
- Tu démarres le timer
- Dans l'évènement du timer, tu joues la lecture du texte
- Puis toujours dans le timer, tu invalides le timer (enabledúlse)

Et voila, le tour est joué.




HALTE AUX BIDOUILLES !!! :-D

...
FichierSons$ = "C:WindowsMediaWindows XP Démarrage.wav"
res% = sndPlaySound(ByVal FichierSons$, SND_ASYNC Or SND_NODEFAULT)
Sleep 200
While sndPlaySound("JeSuisPasLa.wav", SND_NOSTOP Or _
SND_ASYNC Or _
SND_NODEFAULT) = 0
DoEvents
Wend

parle "le train corail en provenance de lille rentre en gare"

...

Devrait le faire aussi. Je dirai qu'il est "normal" que l'option
'SND_SYNC', bloquent les événements, notamment du Timer, vu qu'elle
est synchrone. Par curiosité, j'ai essayé avec le Timer de CCRP :

http://ccrp.mvps.org/index.html?controls/ccrptimer6.htm

C'est pareil.

Par contre l'option SND_NOSTOP :

If a sound is currently playing, the function immediately returns FALSE,
without playing the requested sound.

semble faites pour ça ...

Bon, d'accord il faut appeler Sleep avant la boucle, sinon une fois
compilé, ça ne passe pas à tous les coups. Juste une petite ...
bidouille ;-)

Bonne journée.
--
Cordialement,

Jacques.
Avatar
Jean-marc
"Jacques93" a écrit dans le message de news:
%23Trg$
Bonjour Jean-marc et Touti,
Jean-marc a écrit :
[...]

J'ai bien une solution, mais c'est vraiment une bidouille, ceci
dit ça marchera. Voici:

- Tu lances la lecture du wav en Asynchrone
- // ici, je suppose que tu connais la durée de ton .wav, disons pour
l'exemple 2500 ms (2 secondes et demi)
- Tu initialises un timer avec cette durée (2500)
- Tu démarres le timer
- Dans l'évènement du timer, tu joues la lecture du texte
- Puis toujours dans le timer, tu invalides le timer (enabledúlse)

Et voila, le tour est joué.




HALTE AUX BIDOUILLES !!! :-D

...
FichierSons$ = "C:WindowsMediaWindows XP Démarrage.wav"
res% = sndPlaySound(ByVal FichierSons$, SND_ASYNC Or SND_NODEFAULT)
Sleep 200
While sndPlaySound("JeSuisPasLa.wav", SND_NOSTOP Or _
SND_ASYNC Or _
SND_NODEFAULT) = 0
DoEvents
Wend

parle "le train corail en provenance de lille rentre en gare"

...

Devrait le faire aussi. Je dirai qu'il est "normal" que l'option
'SND_SYNC', bloquent les événements, notamment du Timer, vu qu'elle
est synchrone. Par curiosité, j'ai essayé avec le Timer de CCRP :

http://ccrp.mvps.org/index.html?controls/ccrptimer6.htm

C'est pareil.

Par contre l'option SND_NOSTOP :

If a sound is currently playing, the function immediately returns FALSE,
without playing the requested sound.

semble faites pour ça ...

Bon, d'accord il faut appeler Sleep avant la boucle, sinon une fois
compilé, ça ne passe pas à tous les coups. Juste une petite ...
bidouille ;-)



Ca semble très bien :-)

Donc si je comprends, on lance la lecture du "vrai" son en ASYNC
puis on fait un while avec le SND_NOSTOP juste dans le but d'attendre
la fin du "vrai son" (je suppose que le .wav à utiliser dans la boucle
while est juste la pour attendre la fin du "vrai", il doit être vide ?)
Puis on lance le parle "blah blah ..."

C'est bien l'idée?

--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
mailto: remove '_no_spam_' ;
FAQ VB: http://faq.vb.free.fr/
Avatar
Jacques93
Bonjour Jean-marc,
Jean-marc a écrit :
"Jacques93" a écrit dans le message de news:
%23Trg$
Bonjour Jean-marc et Touti,
Jean-marc a écrit :
[...]
J'ai bien une solution, mais c'est vraiment une bidouille, ceci
dit ça marchera. Voici:

- Tu lances la lecture du wav en Asynchrone
- // ici, je suppose que tu connais la durée de ton .wav, disons pour
l'exemple 2500 ms (2 secondes et demi)
- Tu initialises un timer avec cette durée (2500)
- Tu démarres le timer
- Dans l'évènement du timer, tu joues la lecture du texte
- Puis toujours dans le timer, tu invalides le timer (enabledúlse)

Et voila, le tour est joué.



HALTE AUX BIDOUILLES !!! :-D

...
FichierSons$ = "C:WindowsMediaWindows XP Démarrage.wav"
res% = sndPlaySound(ByVal FichierSons$, SND_ASYNC Or SND_NODEFAULT)
Sleep 200
While sndPlaySound("JeSuisPasLa.wav", SND_NOSTOP Or _
SND_ASYNC Or _
SND_NODEFAULT) = 0
DoEvents
Wend

parle "le train corail en provenance de lille rentre en gare"

...

Devrait le faire aussi. Je dirai qu'il est "normal" que l'option
'SND_SYNC', bloquent les événements, notamment du Timer, vu qu'elle
est synchrone. Par curiosité, j'ai essayé avec le Timer de CCRP :

http://ccrp.mvps.org/index.html?controls/ccrptimer6.htm

C'est pareil.

Par contre l'option SND_NOSTOP :

If a sound is currently playing, the function immediately returns FALSE,
without playing the requested sound.

semble faites pour ça ...

Bon, d'accord il faut appeler Sleep avant la boucle, sinon une fois
compilé, ça ne passe pas à tous les coups. Juste une petite ...
bidouille ;-)



Ca semble très bien :-)



:-)

Donc si je comprends, on lance la lecture du "vrai" son en ASYNC
puis on fait un while avec le SND_NOSTOP juste dans le but d'attendre
la fin du "vrai son" (je suppose que le .wav à utiliser dans la boucle
while est juste la pour attendre la fin du "vrai", il doit être vide ?)
Puis on lance le parle "blah blah ..."

C'est bien l'idée?




Oui, tout à fait. Le fichier utilisé dans la boucle n'a même pas besoin
d'exister (à condition de mettre également SND_NODEFAULT, sinon il y a
le son par défaut qui est joué, en l'occurrence le beep d'erreur). Si il
est vraiment vide (cad 0 octet), le format de fichier est invalide, et
on se retrouve dans le cas précédent : il faut mettre SND_NODEFAULT.

Créer un fichier .wav silencieux étant ici superflu, autant qu'il
n'existe pas, mais ce n'est que mon avis ;-)

Le seul inconvénient que je vois, est la nécessité du sleep entre le
début du "vrai" wav, et la boucle d'attente. Mais pas d'autre idée
pour l'instant.

NB : apparemment l'API sndPlaySound est conservée pour compatibilité
ascendante :

<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_sndplaysound.asp>

remplacée par PlaySound :

<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_playsound.asp>

mais cela ne change rien pour ce cas de figure.

--
Cordialement,

Jacques.
1 2