Síntese de voz em Python


Dando voz ao seu computador

Síntese de voz em Python

A possibilidade do computador nos transmitir informações através da fala abre todo um universo de opções interessantes para o usuário. Imagine por exemplo que você possa ficar tomando medidas de tensão elétrica em pontos de difícil acesso sem precisar desviar seus olhos para uma tela para saber o valor!. Ou que você quer passar um livro interessante para um amigo cego. ou que suas mensagens de e-email sejam ditadas a medida que vão chegando, ou… (sua vez, coloque aqui a aplicação que está visualizando agora).

Neste experimento utilizamos o Linux Mint 18.1, 64 bits e o Python 3.5. Mas a migração para outros SOs é simples, pois a maioria dos sistemas operacionais hoje disponibiliza sintetizadores de voz já na sua instalação (SAPI5 no Windows, NSSpeechSynthesizer no Mac OS X 10.5 (Leopard) and 10.6 (Snow Leopard) e espeak no Ubuntu). Além destas bibliotecas “residentes”, podemos também utilizar sintetizadores de voz disponíveis para acesso via internet. Não optamos por este caminho porque nem sempre podemos contar com internet nas aplicações que temos previsto para esta tecnologia.

Todos os arquivos necessários para estes experimentos, inclusive o código Arduino a que nos referimos em outro artigo, podem ser obtidos em https://cadernodelaboratorio.com.br/scripts-softwares-e-arquivos-de-configuracao/ , sob o nome pack170825.tar.gz.

Síntese de voz através do  espeak

O sintetizador mais utilizado no mundo Linux é o espeak. Vale a pena conhece-lo em mais detalhes, pois como vimos anteriormente, a biblioteca python será apenas uma interface com este sintetizador. Não deixe de experimentar com todos os comandos apresentados, pois isto lhe daŕa uma visão clara dos recursos que podemos contar com este sintetizador.

Digite em um terminal:

espeak –stdout “Bem vindo ao site do caderno de laboratorio.” | aplay

Aqui estamos informando ao espeak para enviar à saida padrão (stdout) o arquivo wave correspondente à frase “Bem vindo ao caderno de laboratório” e depois redirecionamos este arquivo wave gerado para o sistema de audio do computador, através do programa aplay.

Ao final uma descrição do que o aplay realizou é apresentado na tela.

Tocando WAVE ‘stdin’ : Signed 16 bit Little Endian, Taxa 22050 Hz, Mono

Está bem inteligível, mas o sotaque… Que tal deixar um pouco mais “aportuguesado”:

espeak -vpt –stdout “Bem vindo ao site do caderno de laboratorio.” | aplay

Bem melhor, não acha? Para obter uma lista de linguagens reconhecidas pelo espeak digite em um terminal: espeak –voices

Podemos também escolher entre diferentes vozes masculinas (\+m1,\+m2,\+m3,\+m4,\+m5,\+m6,\+m7.)

espeak -vpt+m7 –stdout “Bem vindo ao site do caderno de laboratorio.” | aplay

espeak -vpt+m5 –stdout “Bem vindo ao site do caderno de laboratorio.” | aplay

Ou entre diferentes vozes femininas (\+f1, \+f2, \+f3, \+f4)

espeak -vpt+f3 –stdout “Bem vindo ao site do caderno de laboratorio.” | aplay

Você pode solicitar que a voz seja um sussurro, com a chave whisper

espeak -vpt+whisper –stdout “Bem vindo ao site do caderno de laboratorio.” | aplay

A velocidade padrão do espeak é de 160 palavras por minuto, mas voce pode alterá-la utilizando a chave -s. Assim, tornar a voz um pouco mais lenta pode ser obtida com:

espeak -s 150 -vpt –stdout “Bem vindo ao site do caderno de laboratorio.” | aplay

O espeak pode ditar para você o conteúdo de um arquivo texto. Assegure-se de que é um texto puro, sem marcadores adicionais. Para isto use o comando na seguinte forma:

espeak -vpt –stdout -t meuArquivo.txt | aplay

Para salvar o resultado em um arquivo wave, ao invés de gerar o som no computador, utilize o seguinte comando:

espeak -vpt –stdout -t meuArquivo.txt -w meuAudio.wav

Com o espeak conhecido, vamos ver como ativá-lo a partir de um programa em python


Primeiro experimento- Frase simples

Copie o seguinte arquivo e o execute:

.sinteseVoz1.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  sinteseVoz1.py
#  Copyright 2017-08-22 tavares <tavares arroba cadernodelaboratorio.com.br>
#  0.1
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#   
#  
import os


def main(args):

    os.system("espeak -vpt --stdout 'Bem vindo ao site do caderno de laboratorio.' | aplay" )
   
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

Execute o programa através do comando python sinteseVoz1.py . Você deverá escutar uma voz idêntica à obtida através da chamada direta do programa espeak.

O mais interessante na síntese de voz é quando sintetizamos a partir do resultado de um programa, e não a partir de uma frase já definida, como no exemplo simples anterior. Vamos criar um programa que faça uma contagem regressiva de lançamento de um foguete:

Para este programa iremos utilizar a biblioteca python num2words, que converte valores numéricos em strings. Se você ainda não tem a biblioteca instalada execute o comando pip install num2words . Não se esqueça de manter um ambiente virtual separado para seus experimentos em python2 e python3. Isto evitara destruição mútua de bibliotecas.


Segundo experimento – Contagem regressiva

.sinteseVoz2.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  sinteseVoz2.py
#  Copyright 2017-08-22 tavares <tavares arroba cadernodelaboratorio.com.br>
#  0.1
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#   
#  
import os
import num2words


def main(args):
    inicio_cmd= 'espeak -vpt --stdout  '
    fim_cmd= ' | aplay' 
    inicio_contagem= 10
    
    os.system("espeak -vpt --stdout 'Iniciando contagem regresssiva' | aplay" )
    
    for nIndice in range(inicio_contagem,-1,-1): 
        valor_atual = num2words.num2words(nIndice,lang='pt_BR') 
        os.system(inicio_cmd + valor_atual + fim_cmd)
    
    os.system("espeak -vpt+whisper --stdout 'Funcionou' | aplay" )
   
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

E agora, um voltímetro que fala!

Iremos conectar um Arduino UNO com firmware de leitura de sinais analógicos e fazer com que as respostas do Arduino sejam faladas, e não apresentadas na tela. A descrição detalhada do software do Arduino você encontra em https://cadernodelaboratorio.com.br/2016/09/01/multimetro-multicanal-com-o-arduino/ . O arquivo de nome pack170825.tar.gz, disponível em
https://cadernodelaboratorio.com.br/scripts-softwares-e-arquivos-de-configuracao/ , contem todos arquivos .py e .ino utilizados neste artigo.

A comunicação entre o código Python e o código do Arduino irá utilizar a biblioteca pyserial, que é detalhada no artigo https://cadernodelaboratorio.com.br/2017/08/11/comunicacao-serial-pc-arduino-em-python/ .

.sinteseVoz3.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  sinteseVoz3.py
#  Copyright 2017-08-22 tavares <tavares arroba cadernodelaboratorio.com.br>
#  0.1
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#   
#  
import os
import num2words
import serial



def leSerial():
    if self.portaSerial.isOpen():
        while self.portaSerial.inWaiting() > 0:
            caracLido = self.portaSerial.read(1)
            
      



def main(args):
    inicio_cmd= 'espeak -vpt+f4 -g10 --stdout  '
    fim_cmd= ' | aplay' 
    total_leituras= 10
    
    idPorta= "/dev/ttyACM0"
    
    try:
        portaSerial = serial.Serial(idPorta,38400,timeout=10)   
  
    except serial.SerialException as e:
        msg = " Impossivel_abrir_porta__Vou_fechar_o_programa"
        os.system(inicio_cmd + msg + fim_cmd)
        sys.exit(1)     
         
    msg = "Operando_na_porta_" + idPorta
    os.system(inicio_cmd + msg + fim_cmd)
    
    comando = "1\n".encode()
    portaSerial.write(comando)
    stringLida= portaSerial.read(15).decode()

    
    if stringLida == "$1,Voltmeter 1.":
        strId= "Voltimetro_caderno_1.0"
    else:
        strId= "Hardware_não_identificado"
    os.system(inicio_cmd + strId + fim_cmd)
    
   
    for nIndice in range(total_leituras,-1,-1): 
        comando = "2,0\n".encode()
        portaSerial.write(comando)
        stringLida= portaSerial.read(10).decode()
        valor = stringLida.split(',')[-1]
        valor_atual = num2words.num2words(int(valor),lang='pt_BR') 
        os.system(inicio_cmd + valor_atual.replace(' ','_') + fim_cmd)
    
    
    os.system("espeak -vpt --stdout 'Fim de demostração' | aplay" )
    
    
   
    if portaSerial.isOpen():
        portaSerial.close()
   
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

Operação do programa

Execute o programa e ele irá realizar 10 medidas através do Arduíno, apresentando o resultado da leitura em português.Se quiser experimentar com outros idiomas, substitua o parâmetro lang= pt_BR pelo parâmetro desejado.

Lembrete final

Um lembrete  aos  nossos leitores que se utilizam do tradutor automático  para lerem em seus idiomas:

We realize that automatic translated services nowdays are terrible. Non portuguese speakers can have a hard time to understand parts of the translated text. If this is your case, you can ask us in english about anything in the blog. We will answer also in english.

Nos damos cuenta de que los textos traducidos automáticamente tienen sus limitaciones. Los que no hablan portugues pueden tener dificultades para entender parte del texto traducido. Si este es su caso, no dude en preguntarnos en español sobre cualquier informacion del blog. Responderemos también en español (or portuñol, estoy seguro que podremos llegar a entendernos).:-) ).

Até a próxima!

 

 

Deixe um comentário