miércoles, 29 de agosto de 2007

Animación+voz implementada y un problema

Ya he hecho una primera implementación del avatar moviendo la boca mientras dice algunas frases.

Para esta primera aproximación solo se muestran en la animación unos pocos visemas, que son los de las vocales y la letra 'm', que coinciden más o menos con la posición de la boca de las mallas del avatar que tengo ahora mismo. Si funciona bien, se pueden añadir más.

La forma de hacerlo es con la función de callback que comentaba en la entrada anterior. Cada vez que se pronuncia un fonema se indica su código IPA y de esa forma puedo saber cual es. He programado que se registren estos códigos en el fichero de log de la aplicación, y después he hecho que pronuncie palabras solo con la letra 'a', luego con la 'e', etc. y así he obtenido los de las cinco vocales. Curiosamente para cada una hay dos códigos distintos, aunque no me he fijado bien si unas veces sale uno cuando va acompañado de consonante, o cuando empieza o termina una palabra, etc..

Conocido el fonema ya se la malla que hay que representar, y lo indico en una variable para que en el próximo refresco de pantalla se pinte.

El problema que me he encontrado es que la sincronización entre la animación de la boca y el sonido no es precisamente buena, baste decir que a veces coincide lo que suena con lo que se ve en la pantalla de la PDA.

martes, 21 de agosto de 2007

Callbacks

La librería de Loquendo permite definir una función de callback, esto es, una función a la que se llama automáticamente cada vez que hay algún evento para hacer algo con él.

Entre estos eventos están por ejemplo: Comienzo de la reproducción del sonido, finalización, generación de un fonema, buffer de salida lleno, y similares. Estos eventos tiene un identificador de forma que en la función de callback podemos saber cual se ha disparado para hacer con él (si procede) lo que queramos. Uno muy interesante es el de la generación de fonemas. Cada vez que se genera uno se pasa a la función su código IPA y de esta forma se puede saber la forma de la boca que habría que dibujar. ¡En la propia documentación de Loquendo indica que de esta manera se pueden programar avatares!

sábado, 18 de agosto de 2007

Reproducción de voz bloqueante y no-bloqueante

He comenzado a incluir código para el TTS en el programa del avatar. De momento solo está la iniciación del sistema de síntesis de voz, y una frase que se dice al ejecutar la aplicación.

He estado mirando en el manual el tema de la reproducción del sonido bloqueante y no bloqueante. A mi la que me interesa es la segunda, que consiste simplemente en que la reproducción del sonido de la locución se hace en un thread separado del programa principal y de esa forma se pueden hacer otras cosas mientras.

Con las librerías de Loquendo hay dos formas de hacer esto. Una, la más simple, es usar un parámetro de la función que reproduce la voz, que hace que esta se ejecute en background hasta que termina. La otra forma consiste en hacer polling, es decir, se lanza la reproducción y a continuación se entra en un bucle en el que se va consultando si ha terminado o no.

Ahora tengo que ver cómo hago para que mientras suena la voz, se muestre la imagen adecuada del avatar con la boca en una u otra posición.

jueves, 16 de agosto de 2007

Problema con GLUT|ES. Solucionado

Me había quedado con un problema inquietante: Al compilar y ejecutar el avatar en el emulador del eVC, todo funcionaba perfectamente, pero al compilar para ejecutarlo sobre una PDA real, primero aparecían mensajes del linker, y cuando se conseguía generar el ejecutable no funcionaba como se suponía que debía hacerlo, es decir, el programa se abría pero no aparecía la imagen del avatar, aunque sí los menús.

Recordaba haber compilado el programa hace algunos meses para ser ejecutado en la PDA de verdad, y que había funcionado correctamente, así que como por suerte tenía alguna copia de seguridad las he utilizado para hacer unas pruebas. La más reciente era de justo el momento en que pasé de usar UG a GLUT|ES para los menús y las ventanas. La he compilado, y el resultado era el mismo que con el avatar, no se mostraba nada en la pantalla, aunque la aplicación se ejecutaba. He probado lo mismo con la copia más antigua, que era del momento justo anterior a que usara GLUT|ES, y al compilar el programa sí que ha funcionado.

Así que el problema parecía estar en esa librería. El día anterior probé varios ejemplos binarios descargados de la página de ZeusCMD para asegurarme de que funiconaba, y así era. Pero entonces he recordado los mensajes de advertencia del linker y todo lo que tuve que hacer para solucionarlos. Esos mensajes solo aparecían al compilar para ARM. He abierto los ejemplos de ZeusCMD y los he recompilado, copiándolos después a la PDA y ejecutándolos. Entonces se ha reproducido el error, la pantalla aparecía negra. Los ejemplos en formato binario que sí que funionaban ya venían compilados y linkados estáticamente, así que parece que el problema es la librería estática de GLUT|ES con la que se enlaza el ejecutable de mi programa al compilarlo.

De hecho, el mensaje de aviso que se muestra:

glutes_static.lib(seccook.obj) : warning LNK4078: multiple '.CRT' sections found with different attributes (40300040)
LINK : fatal error LNK1104: cannot open file 'LIBCMT.lib'

Al buscarlo en la ayuda del propio eVC, esto es lo que dice:

LINK found two or more sections that have the same name but different attributes.

Possible cause

An import library or exports file was created by a previous version of LINK or LIB.
Recreate the file and relink.


Es decir, para evitar que aparezca habría que recompilar desde los fuentes la librería de GLUT|ES, cosa nada fácil a priori.

He consultado la página de ZeusCMD, por si la forma de instalar GLUT|ES era incorrecta, y he encontrado un párrafo que había olvidado, que dice que al usar el binario o intentar recompilar los fuentes de la librería había personas que tenían problemas, y ofrece una versión recompilada de la susodicha librería estática. La he descargado y copiado en el lugar correspondiente, y una vez más he compilado el programa del avatar. Al ejecutarlo, ¡ha funcionado! Así que era eso, el binario de la librería estática de GLUT|ES para ARM no funciona bien con el Embedded Visual C++.

Después, solo por curiosidad, he deshecho los pasos que tuve que seguir para que no saliera el error del linker que he escrito antes, y he hecho de nuevo la prueba para asegurarme, confirmando el resultado:

  • Con la librería glutes_static.lib para ARM original: Mensajes de error y warnings del linker -> Necesidad de modificar parámetros de compilación -> La aplicación no funciona como debería.
  • Con la librería glutes_static.lib para ARM recompilada por ZeusCMD: No aparecen mensajes de error ni warnings -> La aplicación funciona correctamente.

Solucionado esto, espero poder ya de una vez integrar la librería de Loquendo en el programa del avatar.

jueves, 9 de agosto de 2007

Un avance y un retroceso

El avance: Me ha contestado el servicio técnico de Loquendo y me ha enviado otra licencia para activar su producto. La he instalado y he ejecutado uno de los pogramas de demostración, y esta vez ha funcionado como se esperaba. A continuación he compilado el programa de prueba, lo he ejecutado en la PDA y también ha funcionado, y he podido escuchar por el altavoz el texto escrito en el programa.

Con la síntesis de voz funcionando, he añadido al programa del avatar el código de ejemplo y de nuevo lo he compilado.

El retroceso: Al ejecutarlo en la PDA, la pantalla se queda de color negro y no sale la cabeza del avatar. En cambio, al ejecutarlo en el emulador funciona perfectamente. Al principio del desarrollo recuerdo que hice una prueba sobre el dispositivo real, y funcionaba. ¿Qué ha cambiado desde entonces? Lo único que se me ocurre es que para el manejo de las ventanas pasé de usar UG a GLUT|ES, así que he revisado este último.
No he encontrado nada raro. Para confirmar que funciona correctamente me he bajado algún ejemplo compilado de las lecciones de la página ZeusCMD y los he ejecutado en la PDA, todos correctamente.

Así que el problema tiene que estar en el código. Toca revisarlo, y no se por qué funciona bien en el emulador y mal en la PDA real.

miércoles, 8 de agosto de 2007

Problema extraño compilando para ARM

Mientras me contestan de Loquendo por el problema con la licencia estoy revisando el código de lo que llevo hecho hasta ahora. He probado a compilar el programa generando código para ARMV4, con el fin de ejecutarlo en una PDA real en vez de en el emulador.

Al construirlo, me sale un error del Linker:

LINK : fatal error LNK1104: cannot open file 'LIBCMT.lib'

Como es habitual, he dedicado el par de horas siguiente a buscar información sobre el susodicho, y como es habitual no he encontrado ninguna solución clara. Leyendo de aquí y de allá y probando diferentes cosas al final lo he solucionado. No se exactamente cual es el problema, pero lo he arreglado siguiendo los siguientes nada-triviales y nada-intuitivos pasos:

- En Project -> Settings -> Link -> Input, donde dice Ignore libraries, añadir a lo que haya exactamente lo siguiente:

,libcmt.lib,oldnames.lib

Es decir, el nombre de las dos librerías que dan problemas separadas por comas, si se utilizan espacios como en otras opciones que hay en el mismo cuadro de diálogo no funciona.

Después de hacer eso el programa se compila correctamente y se copia por ActiveSync a la PDA, donde se puede ejecutar sin más contratiempos.

martes, 7 de agosto de 2007

Problemillas con Loquendo

Me he encontrado con un par de problemas, aunque más que problemas yo diría que son inconvenientes o features:

- El ruido blanco que decía ayer que sonaba al ejecutar la aplicación de prueba en la PDA no era problema de licencia, sino de que usaba un formato de codificación de voz que no está disponible para la versión embebida del software. Sucede si se copia tal cual el programa de ejemplo que viene en la guía del usuario, en particular, hay que cambiar la línea de código

err = ttsNewVoice(&hVoice, hInstance, "Jorge", 16000, "l");

por

err = ttsNewVoice(&hVoice, hInstance, "Jorge", 16000, "loqmsx");

ya que según indica la guía para Windows CE:

the voice database encoding formats available are loqmsx (8 KHz and 16
KHz) and loq210 (16 KHz); linear, μ-law and a-law encodings are not
supported;


- El otro problema es precisamente el de la licencia. Tras hacer el cambio anterior una clara voz suena en el altavoz diciendo a los cuatro vientos que el producto necesita una licencia para funcionar. Mediante una utilidad obtengo un identificador de la PDA (con aspecto de dirección MAC), lo envío mediante la página del fabricante y me devuelve un txt y un exe. El txt contiene la licencia en formato 'registro de Windows', y el ejecutable al lanzarlo en el PC se conecta por ActiveSync a la PDA y un mensaje dice que lo registra correctamente. A continuación, vuelvo a lanzar el programa de prueba y la voz dice otra cosa diferente, pero sigue sin ser lo que debería. Esta vez dice que la licencia instalada no es válida para ese dispositivo. He mandado un mail al soporte técnico de Loquendo, y ahora estoy a la espera a ver si se puede solucionar.

lunes, 6 de agosto de 2007

Compilación usando Loquendo

He conseguido compilar y ejecutar un programa de prueba que usa la librería de Loquendo y casi-funciona sobre una PDA real.

Cosas que faltaban el último día para funcionar:

- Sobre el lío de arquitecturas ARMV4 y ARMV4i: La buena, la que funciona de verdad en mi PDA es la ARMV4, que según lo que ponía en el post anterior es la que se corresponde con PocketPC 2003 . La ARMV4i es más moderna, y se corresponde con Windows Mobile 5.0. No hay que cambiar a mano ningún parámentro con la arquitectura de salida, tal como se decía erroneamente en el susodicho post (*).

- Además de las voces (por ejemplo 'Jorge'), en la PDA hay que instalar también el SDK. En mi caso concreto, el fichero con extensión .CAB que hay dentro de Loquendo_Embedded_TTS_6-PPC2003_SDK_Distribution_6.6.17.zip

- El anterior instala unos ficheros en el directorio de la PDA \Archivos de Programa\Loquendo\Loquendo TTS. Dentro de él hay varias DLLs y pogramas de prueba. Por ejemplo, el que se llama LTTSDemoMSX permite seleccionar una voz, escribir un texto en la pantalla, y hacerlo sonar por el altavoz de la PDA. Como curiosidad, al no tenerlo licenciado en lugar del texto la voz dice que es necesario instalar la licencia antes de usarlo.

- Sobre el programa de prueba: Tras construirlo para ARMV4 (PocketPC 2003) se copia el ejecutable automáticamente al directorio raiz de la PDA. Si se intenta ejecutar sale un error que dice que no es posible hacerlo porque falta un componente. Mensaje completamente distinto al que decía que no es una aplicación válida PocketPC. Para que encuentre los componentes que le faltan (las DLLs, vamos) se puede copiar el ejecutable en el directorio de instalación de Loquendo mencionado en el punto anterior.

- Tras copiar el ejecutable donde están el resto de componentes, al hacer doble click con el puntero se ejecuta sin dar más errores. En lugar de una voz se oye un ruido blanco, posiblemente por el tema de la licencia que se mencionaba antes. Para conseguirla hay que ejecutar un programa llamado GetID, que devuelve un código que hay que enviar a Loquendo para que a su vez manden la licencia que permite hacerlo funcionar.

- Para averiguar lo anterior me ha venido muy bien una utilidad que tra el Embedded Visual C++ llamada 'Dependency Walker', situada en el subdirectorio Common\Tools de la instalación de eVC. Lo que hace es, a partir de un fichero .EXE, mostrar las librerías dinámicas y estáticas de las que depende. De esa forma, he podido ver que necesitaba una DLL llamada LOQTTS6.DLL que no se encontraba en mi PDA, y a partir de ello me he dado cuenta de que tenía que instalar el SDK.



(*) Entrada de la Wikipedia aclaratoria sobre los nombres de los sistemas embebidos de Microsoft: PocketPC
Diferencia entre ARMV4 y ARMV4i.

jueves, 2 de agosto de 2007

Loquendo y eVC

Llevo toda la semana luchando a brazo partido con la librería de Loquendo y el Embbeded Visual C++ para compilar un ejemplo sencillo que viene en la documentación.

Problemas que me he encontrado:

- Errores del tipo:

main.obj : error LNK2019: unresolved external symbol __imp_ttsDeleteInstance referenced in function main
main.obj : error LNK2019: unresolved external symbol __imp_ttsRead referenced in function main
(...)


Parece que no encuentra la librería para enlazar, a pesar de que está indicado en las propiedades del proyecto el directorio donde residen (Tools -> Options -> Directories). Dejan de producirse incluyendo en el código la siguiente línea:

#pragma comment(lib, "LoqTTS6.lib")

que especifica la librería concreta con la que quiero que se linke.



- Error del tipo:

corelibc.lib(pegwmain.obj) : error LNK2019: unresolved external symbol WinMain referenced in function WinMainCRTStartup


Que se soluciona en Project -> Settings -> Link -> Output, y cambiando el Entry-point symbol del valor WinMainCRTStartup a simplemente main



- Error del tipo:

LoqTTS6.lib(LoqTTS6.dll) : fatal error LNK1112: module machine type 'THUMB' conflicts with target machine type 'ARM'


Este ha sido más peliagudo. He encontrado esta página de un foro de Microsoft donde lo aclara un poco, abajo del todo dice esto:
You need to look at all of your compiler and linker inputs and outputs, and figure out whether you are being consistent in your code generation. Keep in mind that:

* PPC 2003 is ARMV4 --> linker switch/machine type = ARM
* PPC 5.0 is ARMV4I --> linker switch/machine type = THUMB

You can't mix and match compiled binaries for each platform. Thanks,


Así que, por probar, he ido de nuevo a Project -> Settings -> Link -> Output y en el cuadro de abajo donde sale la línea de comando del linker (Project Options) he buscado el parámetro /MACHINE y sustituido ARMV4 por THUMB. EDITADO:¡MAL HECHO!.

Después de eso el programa de prueba se puede construir (compilación + linkado) correctamente. La versión de la librería no se puede ejecutar en el emulador, así que copio el ejecutable a una PDA real. Lo lanzo y... error, dice que no es una aplicación para PocketPC válida.

Parece pues que la diferencia entre ARMV4 y ARMV4I es mucha, yo pensaba que no. Eso, o que me he pasado de listo al forzar la compilación. Creo que miraré a ver si hay alguna versión de la librería para ARMV4 "a secas".