Ir al contenido principal

Usando Text-to-Speech


Una de las cosas que menos me gusta hacer es leer artículos de administración y es que son muy aburridos para mi que llevo ingeniería (hasta ética y filosofía es mucho mejor e importante, porque la administración es la forma de entretener a un montón de simios semi-calificados para que hagan el trabajo de unas horas en varias semanas), de eso ya tuve lo suficiente en el bachillerato (con opción en contaduría), por eso me decidí a crear una app para Android que me lea lo que yo no quiero leer, y que mejor momento que cuando voy en el autobus camino a la UTEC©


Bueno pero eso es lo de menos, vamos a trabajar un poco con la clase Text To Speech, es muy simple de usar y aplicar, en esta caso vamos a leer un archivo localizado en la carpeta raw para luego leerla con dicha clase.

Un vídeo dice mas que mil palabras (lo siento si lo ven antes de agregarle audio)



Antes de iniciar todo esto, necesitamos configurar el emulador o dispositivo, para que este en el idioma español, de lo contrario comenzara la lectura en ingles (por defecto). Para ello vamos a settings/keyboard and languages y hacemos la eleccion del idioma en español

Para comenzar agregamos un archivo en la carpeta raw, el cual debe de contener el archivo que deseamos que lea, recordemos que la carpeta raw no viene por defecto en el proyecto, asi que debemos de crearla y debe de quedar dentro de res/raw



Luego de eso trabajamos algo en el layout y lo dejamos de la siguiente manera




Como se logra observar, se trata de 2 botones y un TextView, el cual esta dentro de otro layout y a la vez dentro de un ScrollView (se vera mejor cuando ponga el codigo).


Trabajando el codigo

Luego de tener el layout que usaremos, comenzamos a tocar el codigo java, en el cual se comienza de la siguiente manera

public class TextoavozActivity extends Activity implements TextToSpeech.OnInitListener, OnClickListener{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
@Override
 public void onClick(View arg0) {
  // TODO Auto-generated method stub
 
@Override
public void onInit(int status) {
  // TODO Auto-generated method stub
     
 }
}


El codigo anterio funciona así, al iniciar la clase y extender de Activity se usan dos interfaces TextToSpeech.OnInitListener y OnClickListene, las cuales generan dos metodos que son:


onClick(View arg0)

Que sera usado para manejar los eventos de los botones y

onInit(int status)

Que se usara para manejar el evento del lector

Ahora necesitamos llamar a los componentes de layout, y como a mi me gusta usar siempre un metodo inicializar lo dejo a continuacion

private TextView mostrar;
private Button iniciar, parar;
private TextToSpeech miLector;


private void inicializar()
    {
     mostrar = (TextView) findViewById(R.id.mostrar);
  iniciar = (Button) findViewById(R.id.bIniciar);
  parar = (Button) findViewById(R.id.bParar);
  
  miLector = new TextToSpeech(this, this);
  miLector.isLanguageAvailable(new Locale("spa"));
  
  iniciar.setOnClickListener(this);
  parar.setOnClickListener(this);
    }


Como siempre este metodo se agrega al metodo onCreate(Bundle savedInstanceState), y si se preguntan que hace el método inicializar, a continuacion la explacion


primero inicializa las instancias o variables que se usan en todo el proyecto, ademas crea un objeto llamada miLector que hace uso de la clase Text To Speech y en el cual su constructor lleva 2 parámetros que son el contexto en donde estamos y el evento que genera, recordemos que estamos implementando TextToSpeech.OnInitListener, por esa razón queda de la siguiente manera



miLector = new TextToSpeech(this, this);


Ahora que conocemos la naturaleza de miLector, seria bueno saber que hace el metodo isLanguageAvailable(), lo que hace es preguntar si el lenguaje español esta disponible en el dispositivo.

Luego en los botones iniciar y parar, lo unico que se genera son los eventos de los botones

Ahora dentro del metodo onInit(int status) haremos lo siguiente
@Override
 public void onInit(int status) {
  // TODO Auto-generated method stub
     if(status == TextToSpeech.SUCCESS)
     {
      int result = TextToSpeech.LANG_COUNTRY_AVAILABLE;
      if(result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED)
      {
       Toast.makeText(getApplication(), "Lenguaje no soportado", Toast.LENGTH_LONG).show();
       iniciar.setEnabled(false);
      }
      else { 
       iniciar.setEnabled(true); 
       }
      
     }
 }

Lo que sucede dentro de onInit(int status) es lo siguiente

con un if preguntamos si el estado de la clase TextToSpeech esta generándose (sinceramente no se que valor devuelve, solo nos conformamos saber que devuelve un entero), luego le asignamos el valor de TextToSpeech.LANG_COUNTRY_AVAILABLE a una variable entera que la hemos nombrado result, esta variable contiene el valor que esperábamos de isLanguageAvailable(), luego en otro if preguntamos si ese lenguaje esta disponible en el dispositivo o si no es soportado, para el caso de no ser soportado o no contener el lenguaje, se desactiva el botón, de lo contrario es visible.

Ahora veamos que hace el método onClick(View arg0)

@Override
 public void onClick(View arg0) {
  // TODO Auto-generated method stub
  switch(arg0.getId())
     {
      case R.id.bIniciar:
       iniciarLectura();
       Toast.makeText(getApplication(), "Leyendo archivo", Toast.LENGTH_SHORT).show();
       break;
      case R.id.bParar:
       miLector.stop();
       Toast.makeText(getApplication(), "Deteniendo lectura", Toast.LENGTH_SHORT).show();
       break; 
     }


Lo que hace el método onClick(View arg0) es muy simple, hace uso de un switch para saber que se a presionado, si se presiona bParar, solamente se detiene la lectura y manda un mensaje al usuario  (ojo que esto lo detiene completamente) luego de saber si se presiono bIniciar se ejecuta el método iniciarlectura(), el cual muestro a continuación.
private void iniciarLectura() {
  // TODO Auto-generated method stub
  miLector.speak(mostrar.getText().toString(), TextToSpeech.QUEUE_ADD, null);
 }


¿muy simple verdad?, pero así es esto, lo complicado lo hace uno. Y para mostrar el texto del archivo en la carpeta raw se usa el siguiente metodo

private void mostrarTexto() {
  // TODO Auto-generated method stub
     try {
      int id = R.raw.linux;
   InputStreamReader insr = new InputStreamReader(this.getResources().openRawResource(id ));
   BufferedReader bf = new BufferedReader(insr);
   String linea;
   StringBuilder texto = new StringBuilder();
   while((linea = bf.readLine()) != null)
   {
     texto.append(linea);
     
     //la siguiente linea es por si son varias lineas de texto
     //texto.append("\n");
     
   }
   insr.close();
   bf.close();
   mostrar.setText(texto.toString());
     } catch(IOException e)
     {
      Toast.makeText(getApplication(), "No se pudo leer el archivo deseado", Toast.LENGTH_LONG).show();
     }
 }



Luego de eso hacemos lo mismo que con inicializar(), lo agregamos al método onCreate(Bundle savedInstanceState) y ya tendríamos una app casi completa, hay cosillas que podríamos mejorar, como por ejemplo indicarle a la app que en caso de no existir los archivos necesarios para usar Text To Speech, que los instale desde Google Play, para eso podriamos usar AlertDialog o Dialog, sea como sea son muy buenas sugerencias, en este ejemplo se oviaron por motivos de ser demostrativo.

Si quieren el codigo completo hagan clic aqui.

Un ejemplo de como agregar los paquetes necesarios esta en la pagina de Android Developers, al que lo solicite le puedo enviar el código completo  de como usar los paquetes faltantes en esta app.

Entradas populares de este blog

Northwind para Mysql y otras

Supongamos que necesitamos una base de datos para comenzar a hacer pruebas y a la vez necesitamos que esa base de datos contenga mucha información con la cual trabajar. En mis tiempos de universidad existía una base de datos que utilizábamos en los laboratorios con SQL Server y c# para mostrar los datos en algún formulario. El nombre era Northwind. El problema es que era solo para SQL Server, pero alguien en se dio a la tarea de exportar esa base de datos a MySql y es justo lo que te vengo a mostrar acá. Hace un tiempo atrás clone de los repositorios de Google Code   esa información (que como algunos de ustedes sabrá dejara de estar al servicio de todos en un tiempo). Modifique un poco la DB de Mysql para que se pudiera ejecutar el script sin ningún problema. Lo interesante de todo esto es que puedes utilizar los demás script para diferentes gestores de base de datos Se advierte que para poder usarlas adecuadamente hay que modificar los campos de tipo longblob y qu...

How to upload File from form data POST in Android with Retrofit 2

 The last day I explain how to upload a simple CSV file using node . And now I teach how to upload from android device. Get source code here:  GitHub This article is write in java... later I'll add the method for kotlin. The logic is not changed, only the format code. 1) Is necessary add the dependencies in gradle: module implementation 'com.google.code.gson:gson:2.8.6' // RETROFIT // implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.squareup.retrofit2:converter-scalars:2.5.0' 2) Add permissions in AndroidManifest.xml and modified the application for work with network security policy <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> in applitacion add ...

Como encriptar AES con Node JS

  Puedes descargar el proyecto desde este enlace El otro día surgió una necesidad para encriptar contenido bajo el algoritmo AES y es la que te vengo a mostrar a continuación en la cual use Node para solventar mi necesidad. Pude haber usando cualquier lenguaje que me viniera en gana pero no quería instalar nada mas. Dependencias: NodeJS >= 12 Crypto-JS Aplicaciones recomendadas: Git bash Visual Studio Code Lo primero que necesitamos es tener una clave única (KEY) y un vector de inicialización (IV). Este ultimo no es necesario pero agrega un extra de seguridad a nuestro contenido. Para lo cual usaremos el bash de git para utilizar openssl KEY openssl rand -base64 24 IV openssl rand -base64 12 Ahora que ya tenemos estas 2 cadenas únicas. Podemos proceder a escribir nuestro código. npm init -y Luego hacemos una modificación en el package.json para que admita módulos "type": "module", Instalamos la dependencia de Crypto-JS npm i crypto-js --save Ahora importamos l...