Programación
Multimedia
RECONOCIMIENTO
DE VOZ (V)
Durante este mes
vamos a continuar con la segunda parte del listado que
dejamos pendiente. Correspondía al proyecto DictaPad, el
cual soportaba la funcionalidad de efectuar dictado y
leer las palabras reconocidas mediante el motor de texto
hablado.
Seguimos el listado con
el procedimiento Capitalizeword, el cual cambia de
minúsculas a mayúsculas y viceversa la primera letra de
una palabra seleccionada. Mediante el método FX
lograremos capitalizar la primera letra. Para ello, es
necesario establecer el valor 3 en su parámetro, tal y
como se muestra en el listado:
Private Sub capitalizeword_Click()
s = RichTextBox1.selstart
e = RichTextBox1.SelLength
Vdict1.Lock
Vdict1.FX (3)
Vdict1.Unlock
RichTextBox1.selstart = s
RichTextBox1.SelLength = e
End Sub
Los siguientes
procedimientos corresponden al botón de comienzo de
dictado de la barra de herramientas. Si se pulsa dicho
botón, se establecerá o eliminará el modo escucha para
el engine de dictado mediante la función Listen.
Private Sub listening_Click()
listen (1)
End Sub
Private Sub notlistening_Click()
listen (0)
End Sub
ReadDocument es la
opción de menú que permite al ordenador leer el texto
contenido en la caja Richtext. Esto es posible mediante
la utilización del engine de texto hablado. Si no hay un
engine de este tipo instalado en el ordenador, el
procedimiento no tendrá efecto. El objeto que representa
al engine de texto hablado es DirectSS1.
Private Sub ReadDocument_Click()
Dim ReadText As String
On Error Resume Next
Si al pulsar la opción
de menú el engine está hablando, lo paramos mediante el
procedimiento Stopreading_Click. Para comenzar a hablar,
seleccionaremos el comienzo del texto y utilizaremos el
método Speak del objeto DirectSS1.
If (DirectSS1.Speaking) Then
Stopreading_Click
Else
listen (0)
Toolbar1.Buttons(15).Value = tbrPressed
Toolbar1.Buttons(15).Image = 13
gReadStart = RichTextBox1.selstart
ReadText = Right$(RichTextBox1.Text, Len(RichTextBox1.Text) - RichTextBox1.selstart)
DirectSS1.Speak ReadText
End If
End Sub
Private Function isTextBreak(c As String, breakchars As String)
For i = 1 To Len(breakchars)
If c = Mid$(breakchars, i, 1) Then
isTextBreak = True
GoTo done
End If
Next i
isTextBreak = False
done:
End Function
La función
Findtextbreak se utiliza en conjunción con la función
anterior Istextbreak para reducir el parpadeo (flicker)
que se visualiza en la caja de texto Richtext cuando se
obtienen cadenas de caracteres. Para ello, es necesario
buscar la longitud de cada palabra mediante funciones
estándar de Visual Basic Len y Mid$. Estas funciones no
son necesarias para el funcionamiento del programa, pero
crean un mejor aspecto visual en la representación del
texto obtenido.
Private Function FindTextBreak
(direction As Integer, start As Integer,
breakchars As String)
If (RichTextBox1.Text = "") Then
FindTextBreak = 1
ElseIf (direction = 0) Then
For i = start To 1 Step -1
If (isTextBreak(Mid$
(RichTextBox1.Text, i, 1), breakchars))
Then
FindTextBreak = i
GoTo done
End If
Next i
FindTextBreak = i
GoTo done
Else
For i = start To Len(RichTextBox1.Text)
If (isTextBreak(Mid$
(RichTextBox1.Text, i + 1, 1), breakchars))
Then FindTextBreak = i
GoTo done
End If
Next i
FindTextBreak = i
End If
done:
End Function
El siguiente
procedimiento que vemos a continuación se ejecuta cuando
se pulsa con el ratón sobre la caja de texto y
normalmente se hace para seleccionar palabras. En la
variable breakstring se definen una serie de caracteres
que pueden delimitar la longitud de la palabra al ser
encontrados:
Private Sub RichTextBox1_Click()
Dim breakstring As String
If (Alwaysselect.Checked) Then
If RichTextBox1.selstart =
Len(RichTextBox1.Text) Then GoTo setsel
breakstring = " -_!@#$%^&*(),.[]+=`'"""
+ vbNewLine + vbCrLf + vbCr + vbLf
sStart = FindTextBreak(0, RichTextBox1
.selstart, breakstring)
If (sStart 0) Then
If (sStart = RichTextBox1.selstart And
(Not isTextBreak(Mid$(RichTextBox1.Text,
(sStart), 1), breakstring))) Then
sStart = sStart - 1
sEnd = sStart + 1
Else
GoTo findit
End If
Else
findit:
sEnd = FindTextBreak(1, RichTextBox1
.selstart + RichTextBox1.SelLength,
breakstring)
End If
RichTextBox1.selstart = sStart
RichTextBox1.SelLength = sEnd -
sStart
setsel:
On Error GoTo done
Como se ha hecho
anteriormente, para efectuar la selección de la palabra
será necesario proteger y desproteger el objeto Vdict1
mediante los métodos Lock y Unlock.
Vdict1.Lock
Vdict1.TextSelSet RichTextBox1.
selstart, RichTextBox1.SelLength
Vdict1.Unlock
done:
End If
End Sub
Cuando se selecciona
texto es necesario definir la posición de la selección
(método TextSelSet). TextSet cambia un texto
seleccionado definido por el comienzo y el número de
caracteres que tenga. El texto será reemplazado.
Private Sub SetText(newText As String,
ui As Boolean)
Vdict1.Lock
Vdict1.TextSelSet RichTextBox1.
selstart, 0
Vdict1.TextSet newText, RichTextBox1.
selstart, RichTextBox1.SelLength, 65536
Vdict1.Unlock
If (ui) Then
RichTextBox1.SelText = newText
End If
End Sub
La caja de texto que
representará los caracteres obtenidos de las palabras
del usuario debe incluir varios procedimientos que
permitan seleccionar palabras mal reconocidas para poder
editarlas posteriormente.
De este modo nosotros
gestionaremos este tipo de eventos cuando se levante el
dedo sobre el botón del ratón y cuando se presione
alguna tecla (MouseUp/Keypress).
Private Sub RichTextBox1_KeyPress
(KeyAscii As Integer)
Dim s As String
s = Chr$(KeyAscii)
SetText s, False
ShowCorrectionWindow (showcorrection.
Checked)
End Sub
Private Sub RichTextBox1_MouseUp(Button
As Integer, Shift As Integer,
x As Single, y As Single)
Vdict1.Lock
Vdict1.TextSelSet RichTextBox1.selstart,
RichTextBox1.SelLength
Vdict1.Unlock
ShowCorrectionWindow (showcorrection.Checked)
End Sub
Cuando se seleccione una
palabra debe aparecer una ventana de corrección
especializada. Para ello, visualizaremos este formulario
mediante ShowCorrectionWindow.
Private Sub showcorrection_Click()
If (showcorrection.Checked) Then
ShowCorrectionWindow (0)
Else
ShowCorrectionWindow (1)
End If
End Sub
Para parar la lectura
del documento obtenido debemos aplicar al objeto
DirectSS1 el método AudioReset. Recordemos que DirectSS1
es el objeto que representa al engine de texto hablado.
Private Sub Stopreading_Click()
DirectSS1.AudioReset
End Sub
TextChanged es uno de
los procedimientos más importantes del programa y se
llama de forma automática cada vez que se cambia el
texto por el objeto de dictado (no por el usuario). Si
cuando obtiene texto obtiene palabras erróneas,
intentará sustituirlas por otras que se asemejen
bastante.
También será necesario
proteger y desproteger el objeto Vdict1 (métodos Lock/
Un Lock) para no incurrir en errores de protección y
aplicar los cambios sin problemas.
Private Sub Vdict1_TextChanged
(ByVal reason As Long)
Dim newStart As Long
Dim newend As Long
Dim oldStart As Long
Dim oldEnd As Long
Dim selstart As Long
Dim sellen As Long
Dim theText As String
Vdict1.Lock
On Error GoTo spuriouserror
Mediante el método
GetChanges tomamos las diferencias y actualizamos la caja
Richtext que visualiza las palabras:
Vdict1.GetChanges newStart, newend,
oldStart, oldEnd
If (oldStart < oldEnd) Then
RichTextBox1.selstart = oldStart
RichTextBox1.SelLength = oldEnd -
oldStart
RichTextBox1.SelText = ""
End If
If (newend > newStart) Then
RichTextBox1.selstart = newStart
RichTextBox1.SelLength = 0
Vdict1.TextGet newStart, newend -
newStart, theText
RichTextBox1.SelText = theText
End If
ShowCorrectionWindow 2
spuriouserror:
Vdict1.Unlock
End Sub
Open_Click es llamado
cuando se carga un nuevo archivo de texto en la caja
RichText. Podemos seleccionar tres tipos de archivos:
| - |
TXT: archivo de texto |
| - |
MSD: archivo de Microsoft
Dictation |
| - |
RTF: archivo de tipo Richtext |
Private Sub open_Click()
Dim versionstring As String
Dim fn As String
Dim fs As Long
Dim fi As Long
Dim fb As Long
Dim fu As Long
Dim fst As Long
CommonDialog1.ShowOpen
If (CommonDialog1.filename "") Then
New_Click
gThisFile = CommonDialog1.filename
El método CreateStream
del objeto Vdict1 se utiliza para crear un nuevo
documento del tipo MSD. El segundo flag que se utiliza en
sus parámetros debe ser 18, ya que es el único valor
aceptado por la API hasta el momento.
If (Right(gThisFile, 3) = "msd") Then
hand = Vdict1.CreateDocFile
(gThisFile, 18)
stream2 = Vdict1.CreateStream
(hand, "Version", 18)
Vdict1.StreamRead stream2, versionstring, 36
Chequeamos si la
versión del archivo se corresponde a un fichero MSD:
If versionstring
"46FC730A-D849-11d0-AB8A-08002BE4E3B7" Then
dummy = MsgBox("Error. Formato inválido",
vbOK, "Formato inválido") En caso de no ser un
archivo MSD, utilizaremos el método CreateStream para la
carga del archivo. El primer parámetro dónde se
almacenará el archivo (handler), el segundo representa
el nombre de este handler para diferenciarlo. Por último
asignaremos el valor 18 al último parámetro tal y como
hemos hecho anteriormente.
Else
stream = Vdict1.CreateStream
(hand, "Header", 18)
Vdict1.ReadStreamFont stream,
fn, fs, fi, fb, fu, fst
Vdict1.ReleaseStream stream
Vdict1.SessionDeserialize hand
RichTextBox1.Font.Name = fn
If (fs < 0) Then
fs = -fs
End If
RichTextBox1.Font.Size = fs
RichTextBox1.Font.Italic = fi
RichTextBox1.Font.Bold = fb
RichTextBox1.Font.Underline = fu
End If
Finalmente, vaciamos el
handler utilizado y su objeto.
Vdict1.ReleaseStream stream2
Vdict1.ReleaseStore hand
Else
RichTextBox1.filename =
CommonDialog1.filename
gThisFile = RichTextBox1.filename
SetText RichTextBox1.Text, False
End If
End If
End Sub
Para cambiar las
opciones de dictado que permite el engine (cambio de
usuario, sensibilidad de reconocimiento, etc.)
utilizaremos el método GeneralDlg. En la siguiente
imagen se puede apreciar el formulario que se
visualizará al activar esta opción:
Private Sub Options_Click()
Vdict1.GeneralDlg Form5.hwnd, "Opciones de Dictado"
End Sub
Es necesario crear un
procedimiento para guardar el archivo con el que estamos
trabajando actualmente. Para ello, utilizaremos DoSave:
Private Sub DoSave()
Dim hand As Long
Dim fs As Long
Dim fi As Long
Dim fb As Long
Dim fu As Long
Dim fst As Long
Seguidamente crearemos
el código para la grabación de los archivos MSD:
If (Right(gThisFile, 3) = "msd") Then
fs = -RichTextBox1.Font.Size
fi = RichTextBox1.Font.Italic
fb = RichTextBox1.Font.Bold
fu = RichTextBox1.Font.Underline
fst = False
hand = Vdict1.CreateDocFile(gThisFile,
18)
stream = Vdict1.CreateStream(hand,
"Header", 18)
Vdict1.SetSize stream, 0
Vdict1.WriteStreamFont stream, RichTextBox1.
Font.Name, fs, fi, fb, fu, fst
SessionSerialize guarda
el estado actual del dictado al handler asignado (hand).
La información incluirá todo el texto del buffer, el
resultado de los objetos asociados con el texto y los
marcadores. Una aplicación puede volver a cargar una
sesión utilizando el método SessionDeSerialize.
Vdict1.SessionSerialize hand
stream2 = Vdict1.CreateStream
(hand, "Version", 18)
Vdict1.SetSize stream2, 0
Vdict1.StreamWrite stream2, "46FC730A-D849-11d0-AB8A-08002BE4E3B7"
Vdict1.ReleaseStream stream
Vdict1.ReleaseStream stream2
Vdict1.ReleaseStore hand
Creamos el código para
la grabación de archivos RTF:
ElseIf (Right(gThisFile, 3) = "rtf")
Then
Open gThisFile For Output As 1
Print #1, RichTextBox1.TextRTF
Close 1
Else
Creamos el código para
la grabación de archivos TXT:
Open gThisFile For Output As 1
Print #1, RichTextBox1.Text
Close 1
End If
End Sub
El procedimiento Listen
se utiliza para activar o desactivar la escucha del
engine de dictado sobre el usuario. Mediante el método
Mode se establece el estado de escucha utilizando alguno
de estos flags:
| - |
VSRMODE_DISABLED |
| |
Dictado y command and control
desactivados. |
| - |
VSRMODE_OFF |
| |
Speech desactivado. |
| - |
-VSRMODE_CMDPAUSED |
| |
Speech en pausa (a la escucha
para que un comando que lo despierte). |
| - |
VSRMODE_CMDONLY |
| |
Command and control activado.
Dictado desactivado. |
| - |
VSRMODE_DCTONLY |
| |
Dictado activado. Command and
control desactivado. |
| - |
VSRMODE_CMDANDDCT |
Los dos engines
activados al mismo tiempo. Esto sólo es posible si el en
Public Sub listen(op As Integer)
If (op = 1) Then
Stopreading_Click
Vdict1.Mode = 32
On Error GoTo NoActivate
Vdict1.Activate
NoActivate:
Else
Vdict1.Mode = 2
On Error GoTo NoDeactivate
Vdict1.Deactivate
NoDeactivate:
End If
ListenUI (op)
GoTo NoError
ErrorMessage:
MsgBox "ERROR. Debe haber
un engine instalado."
End
NoError:
End Sub
Finalizando el recorrido
por los procedimientos más importantes del programa,
llegamos al punto en el que nos encontramos con el
procedimiento encargado de gestionar la barra de estado
que contiene los botones de acceso rápido.
Podemos utilizar una
propiedad denominada Key de SelectCase para poder así
especificar la acción determinada que necesitamos
realizar en cada momento.
Private Sub toolbar1_ButtonClick(ByVal Button As Button)
Select Case Button.Key
Case Is = "cut"
Cut_Click
Case Is = "cutall"
SelectAll_Click
Cut_Click
Case Is = "copy"
Copy_Click
Case Is = "paste"
Paste_Click
Case Is = "new"
New_Click
Case Is = "save"
save_Click
Case Is = "open"
open_Click
Case Is = "listen"
If (listening.Checked) Then
listen (0)
Else
listen (1)
End If
Case Is = "showhide"
showcorrection_Click
Case Is = "capitalizeword"
capitalizeword_Click
Case Is = "addword"
Addword_Click
Case Is = "read"
ReadDocument_Click
End Select
End Sub
PRÓXIMAMENTE
En el siguiente número
de esta serie de reconocimiento de voz veremos un
programa sumamente útil de cara al usuario final.
Se trata de un programa
que nos avisará, hablando, de los nuevos e-mails que
hayamos recibido, diciéndonos el asunto del que trata el
mensaje de viva voz.
|