ESTUDO SOBRE MÁSCARAS DE ÁUDIO PARA EMULAÇÃO DE...
Transcript of ESTUDO SOBRE MÁSCARAS DE ÁUDIO PARA EMULAÇÃO DE...
DA UNIVERSIDADE REGIONAL DE BLUMENAU
CENTRO DE CIÊNCIAS EXATAS E NATURAIS
CURSO DE CIÊNCIAS DA COMPUTAÇÃO – BACHARELADO
ESTUDO SOBRE MÁSCARAS DE ÁUDIO
PARA EMULAÇÃO DE VOZ
MARCOS RODRIGO DA SILVA
BLUMENAU
2009
2009/1-14
MARCOS RODRIGO DA SILVA
ESTUDO SOBRE MÁSCARAS DE ÁUDIO
PARA EMULAÇÃO DE VOZ
Trabalho de Conclusão de Curso submetido à
Universidade Regional de Blumenau para a
obtenção dos créditos na disciplina Trabalho
de Conclusão de Curso II do curso de Ciências
da Computação — Bacharelado.
Prof. Paulo César Rodacki Gomes - Orientador
BLUMENAU
2009
2009/1-14
ESTUDO SOBRE MÁSCARAS DE ÁUDIO
PARA EMULAÇÃO DE VOZ
Por
MARCOS RODRIGO DA SILVA
Trabalho aprovado para obtenção dos créditos
na disciplina de Trabalho de Conclusão de
Curso II, pela banca examinadora formada
por:
______________________________________________________
Presidente: Prof. Paulo César Rodacki Gomes – Orientador, FURB
______________________________________________________
Membro: Prof. Dalton Solano dos Reis, – FURB
______________________________________________________
Membro: Prof. Miguel Alexandre Wisintainer, – FURB
Blumenau, 07 de julho de 2009
Dedico este trabalho a todos os amigos,
especialmente aqueles que me ajudaram
diretamente na realização deste.
AGRADECIMENTOS
A Deus, por seu imenso amor e graça.
À minha família, pelo apoio e compreensão.
Aos meus amigos, pelas ideias e incentivos durante o decorrer do trabalho.
Aos professores, José Gil Fausto Zipf e Ricardo José de Oliveira Carvalho, e a Ciro
André Pitz, pelas explicações e ideias para a resolução do problema.
Ao meu orientador, Paulo César Rodacki Gomes, por ter acreditado na conclusão deste
trabalho.
A mente que se abre a uma nova ideia jamais
voltará ao seu tamanho original.
Albert Einstein
RESUMO
O presente trabalho faz um estudo sobre a emulação de áudios de voz humana. São utilizadas
técnicas de filtros digitais adaptativos, mais precisamente o LMS, para se gerar uma máscara
emuladora da diferença entre dois áudios de entrada. A ferramenta desenvolvida é capaz de
modificar um sinal de áudio, manipulando o timbre da voz de tal forma que este se aproxime
do timbre de voz de outra pessoa, porém ainda de forma muito superficial, generalizando
muitas das diferenças e obtendo assim um sinal muitas vezes errôneo.
Palavras-chave: Áudio. Emulação. Filtro. Máscara. Voz.
ABSTRACT
This work represents a study on the emulation of the human voice audio. Use techniques for
adaptive digital filters, specifically the LMS, to generate a mask emulator of the difference
between two audio input. The tool developed is able to modify an audio signal, manipulating
the letterhead of the voice so that it approaches the letterhead of voice of another person, but
even a very superficial, generalizing many of the differences and thereby obtaining a sign
often mistaken.
Key-words: Audio. Emulation. Filter. Mask. Voice.
LISTA DE ILUSTRAÇÕES
Figura 1 – Diagrama dos órgãos usados na produção da fala ................................................ 17
Figura 2 – Ondas senoidais .................................................................................................. 18
Quadro 1 – Fórmulas de relação entre a frequência e o período ............................................ 18
Figura 3 – Projeções senoidais com diferentes fases iniciais ................................................. 19
Quadro 2 – Fórmula da transformada discreta de Fourier ..................................................... 20
Figura 4 – FFT usando o método de Cooley-Tukey .............................................................. 21
Figura 5 – Exemplo de filtros sonoros .................................................................................. 22
Figura 6 – As partes de um neurônio .................................................................................... 22
Figura 7 – Modelo matemático de um neurônio .................................................................... 23
Figura 8 – Estrutura do filtro adaptativo ............................................................................... 24
Quadro 3 – Diferença entre os dois sinais ............................................................................. 24
Quadro 4 – Erro médio quadrático ....................................................................................... 25
Quadro 5 – Gradiente do erro ............................................................................................... 25
Quadro 6 – Fórmula do algoritmo LMS ............................................................................... 25
Quadro 7 – Condição de convergência ................................................................................. 26
Figura 9 – ADSR ................................................................................................................. 26
Figura 10 – Envelope em sinal de áudio ............................................................................... 27
Figura 11 – Representação de um arquivo de formato WAVE .............................................. 28
Figura 12 – Diagrama de atividades do fluxo da ferramenta ................................................. 31
Figura 13 – Diagrama de casos de uso das amostras ............................................................. 32
Quadro 8 – Caso de uso UC01 – Capturar áudio microfone ............................... 33
Quadro 9 – Casos de uso UC02 – Carregar áudio locutor e UC04 – Carregar
áudio personagem ..................................................................................... 33
Quadro 10 – Casos de uso UC03 – Reproduzir áudio locutor e UC05 –
Reproduzir áudio personagem ............................................................ 34
Figura 14 – Diagrama de casos de uso do filtro .................................................................... 34
Quadro 11 – Caso de uso UC06 – Gerar filtro ......................................................... 35
Quadro 12 – Caso de uso UC07 – Carregar filtro .................................................. 35
Quadro 13 – Caso de uso UC08 – Gravar filtro ...................................................... 35
Figura 15 – Diagrama de casos de uso da emulação ............................................................. 36
Quadro 14 – Caso de uso UC09 – Carregar áudio a emular ............................... 36
Quadro 15 – Caso de uso UC10 – Reproduzir áudio emulado ............................. 36
Quadro 16 – Caso de uso UC11 – Aplicar filtro .................................................... 37
Figura 16 – Diagrama de pacotes das camadas da ferramenta ............................................... 37
Figura 17 – Diagrama de classes da camada de interfaces .................................................... 38
Figura 18 – Diagrama de classes da camada de modelo ........................................................ 40
Figura 19 – Diagrama de classes da camada visual ............................................................... 41
Figura 20 – Diagrama de classes da camada de processamento............................................. 42
Figura 21 – Diagrama de classes da camada de acesso externo ............................................. 43
Figura 22 - Diagrama de sequência de funcionamento .......................................................... 45
Quadro 17 – Código fonte do método readAudioFile que obtém as amostras e o formato
de um arquivo de áudio ...................................................................................... 46
Quadro 18 – Código fonte do método convertByteToFloat que transforma um array de
bytes em um array de floats. .............................................................................. 47
Quadro 19 – Código fonte do método saveAudioFile que armazena um sinal de áudio em
arquivo .............................................................................................................. 47
Quadro 20 – Código fonte do método convertFloatToByte que transforma um array de
floats em um array de bytes ............................................................................... 48
Quadro 21 – Código fonte do método start que inicia a captura do áudio do microfone ... 49
Quadro 22 – Código fonte dos métodos start e play, responsáveis pela reprodução do
áudio .................................................................................................................. 50
Quadro 23 – Código fonte do método fft responsável pela conversão do sinal do domínio do
tempo para o domínio da frequência................................................................... 51
Quadro 24 – Código fonte do método fillToPowerOfTwo responsável por garantir um
tamanho exponencial de dois a um sinal ............................................................. 52
Quadro 25 – Código fonte do método createFilter que cria o filtro de áudio da
ferramenta.......................................................................................................... 53
Quadro 26 – Código fonte do método flowLineLeft que executa um left shift no array . 53
Quadro 27 – Código fonte do método dotProduct que calcula o produto escalar entre dois
vetores ............................................................................................................... 54
Quadro 28 – Código fonte do método adapteFilter que encapsula a fórmula do
algoritmo LMS .................................................................................................. 54
Quadro 29 – Código fonte do método apllyFilter que aplica o filtro sobre o sinal de
áudio .................................................................................................................. 54
Quadro 30 – Código fonte do método readFilterFile que realiza a leitura de arquivos
de filtro .............................................................................................................. 56
Quadro 31 – Código fonte do método saveAudioFilter que grava os filtros em arquivo
.......................................................................................................................... 56
Figura 23 – Abas da ferramenta............................................................................................ 57
Figura 24 – Barra de botões da ferramenta ........................................................................... 57
Figura 25 – Caixa de progresso da ferramenta ...................................................................... 57
Figura 26 – Arquivo de áudio inválido ................................................................................. 58
Figura 27 – Arquivo de filtro inválido .................................................................................. 58
Figura 28 – Representação das amostras de um sinal no domínio do tempo e da frequência . 58
Figura 29 – Representação do filtro de áudio ........................................................................ 59
Figura 30 – Tela de captura de microfone............................................................................. 60
Figura 31 - Configurações da captura ................................................................................... 61
Figura 32 – Configuração do filtro ....................................................................................... 62
Figura 33 - Botões de emulação ........................................................................................... 62
Figura 34 - Histograma senóide simples ............................................................................... 63
Figura 35 - Histograma senóide após mudar frequência ........................................................ 64
Figura 36 - Nota musical de uma harmônica ........................................................................ 64
Figura 37 - Histograma da vogal ―a‖ .................................................................................... 65
Figura 38 - Histograma de uma nota fá em um piano............................................................ 66
Figura 39 - Histograma de uma nota fá em uma guitarra elétrica .......................................... 66
LISTA DE TABELAS
Tabela 1 – Faixa de frequências audíveis.............................................................................. 18
Tabela 2 - Tempo necessário para a criação do filtro ............................................................ 67
LISTA DE SIGLAS
ADSR – Attack, Decay, Sustain, Release
DFT – Discrete Fourier Transform
FFT – Fast Fourier Transform
GMM – Gaussian Mixture Models
IFFT – Inverse Fast Fourier Transform
LMS – Least Mean Square
RNA – Rede Neural Artificial
LISTA DE SÍMBOLOS
f – frequência
T – período
Hz – Hertz
kHz – Quilohertz
SUMÁRIO
1 INTRODUÇÃO ............................................................................................................. 14
1.1 OBJETIVOS DO TRABALHO..................................................................................... 15
1.2 ESTRUTURA DO TRABALHO .................................................................................. 15
2 FUNDAMENTAÇÃO TEÓRICA................................................................................. 16
2.1 FONAÇÃO ................................................................................................................... 16
2.2 ONDAS SONORAS ..................................................................................................... 17
2.2.1 Frequência e período ................................................................................................... 18
2.2.2 Amplitude ................................................................................................................... 18
2.2.3 Fase ............................................................................................................................ 19
2.3 TRANSFORMADAS DE FOURIER ............................................................................ 19
2.4 FILTROS ACÚSTICOS................................................................................................ 21
2.5 REDES NEURAIS ........................................................................................................ 22
2.6 FILTROS ADAPTATIVOS .......................................................................................... 23
2.6.1 Algoritmo LMS .......................................................................................................... 24
2.7 ADSR ........................................................................................................................... 26
2.8 FORMATO WAVE ...................................................................................................... 27
2.9 TRABALHOS CORRELATOS .................................................................................... 28
3 DESENVOLVIMENTO DA FERRAMENTA ............................................................. 30
3.1 REQUISITOS PRINCIPAIS DO PROBLEMA A SER TRABALHADO ..................... 30
3.2 ESPECIFICAÇÃO ........................................................................................................ 31
3.2.1 Diagramas de casos de uso .......................................................................................... 32
3.2.1.1 Carregamento dos áudios de entrada ......................................................................... 32
3.2.1.2 Criação do filtro de áudio ......................................................................................... 34
3.2.1.3 Aplicação do filtro de áudio ...................................................................................... 35
3.2.2 Diagramas de classe .................................................................................................... 37
3.2.2.1 Camada de interfaces ................................................................................................ 38
3.2.2.2 Camada de modelo ................................................................................................... 39
3.2.2.3 Camada visual .......................................................................................................... 40
3.2.2.4 Camada de processamento ........................................................................................ 42
3.2.2.5 Camada de acesso externo ........................................................................................ 43
3.2.3 Diagrama de sequência ............................................................................................... 44
3.3 IMPLEMENTAÇÃO .................................................................................................... 45
3.3.1 Técnicas e ferramentas utilizadas ................................................................................ 45
3.3.1.1 Leitura e gravação de arquivos WAVE ..................................................................... 46
3.3.1.2 Captura de áudio pelo microfone .............................................................................. 48
3.3.1.3 Reprodução de áudio ................................................................................................ 49
3.3.1.4 Cálculo do histograma .............................................................................................. 50
3.3.1.5 Criação do filtro de áudio ......................................................................................... 52
3.3.1.6 Aplicação do filtro sobre outro sinal de voz .............................................................. 54
3.3.1.7 Leitura e gravação do filtro de áudio ......................................................................... 55
3.3.2 Operacionalidade da implementação ........................................................................... 56
3.3.2.1 Conceitos de utilização ............................................................................................. 57
3.3.2.2 Representação das amostras de áudio ........................................................................ 58
3.3.2.3 Representação do filtro de áudio ............................................................................... 59
3.3.2.4 Carregando uma amostra de áudio de um arquivo ..................................................... 59
3.3.2.5 Configuração de captura ........................................................................................... 60
3.3.2.6 Criação do filtro........................................................................................................ 61
3.3.2.7 Configuração do filtro............................................................................................... 61
3.3.2.8 Aplicação do filtro .................................................................................................... 62
3.4 RESULTADOS E DISCUSSÃO ................................................................................... 63
4 CONCLUSÕES ............................................................................................................. 69
4.1 EXTENSÕES ............................................................................................................... 69
REFERÊNCIAS BIBLIOGRÁFICAS .............................................................................. 71
14
1 INTRODUÇÃO
É cada vez mais comum o número de pessoas que fazem imitações de celebridades e
pessoas famosas, seja por diversão, ou profissionalmente. Algumas pessoas possuem um
timbre de voz comum, que pode ser facilmente imitado, porém existem timbres mais
complexos de serem imitados, timbres que são inconfundíveis, os quais se podem identificar a
pessoa por uma simples palavra ou frase. Com isso, associa-se a alguns personagens uma voz
característica, que o torna único. E o que fazer para imitar estas vozes, que não são tão fáceis,
inclusive para os melhores imitadores?
Com este trabalho, pretende-se criar uma ferramenta que analise o timbre de voz de um
personagem alvo e o timbre de voz de um locutor, obtendo informações a respeito da forma
como o sinal de áudio é gerado. Para isto, tentar-se-á usar o Attack, Decay, Sustain, Release
(ADSR) que é uma forma de se ―envelopar‖ o sinal (ADSR, 2008), ou seja, descobrir os
contornos do sinal (onde estão os picos, onde esse se mantém estável etc.). Estes contornos
definem a diferença entre os timbres de voz.
Feita a análise inicial, a ferramenta irá treinar uma Rede Neural Artificial (RNA) para
que esta aprenda como transformar a voz do locutor na voz do personagem alvo, ou seja,
como fazer com que o envelope da voz do locutor fique o mais próximo possível do envelope
da voz do personagem. Com isso, o locutor reproduzirá, de forma emulada, a voz deste
personagem.
Serão utilizados exemplos gravados de vozes (como a voz de uma criança, a voz de um
adulto, a voz de um idoso etc.) e com a ajuda das ferramentas Audacity (MAZZONI, 2008) e
WavePad Sound Editor (NHC SOFTWARE, 2007) verificar se os sinais gerados pela
ferramenta proposta assemelham-se aos sinais previamente gravados.
A análise das vozes pode ser considera uma tarefa árdua, devido ao fato de que as duas
vozes a serem analisadas não estarão necessariamente sincronizadas na reprodução da mesma
sílaba, ou seja, acontecerá em determinados momentos, de que as duas pessoas estarão
falando palavras (ou mesmo frases) diferentes. Assim, a RNA deve ser treinada com os
padrões da voz, ou seja, padrões dos ADSRs obtidos através das transformadas de Fourier, e
não somente com as amplitudes das frequências dos sinais durante o tempo, como fazem as
ferramentas de reconhecimento de voz. Isso porque não se espera identificar as palavras que
estão sendo pronunciadas, mas sim a forma como estas são proferidas, a forma como elas
crescem, se mantém e finalizam. Com isso, será permitido um estudo maior para a criação de
15
vozes artificiais, os chamados sintetizadores de voz, pois será possível verificar como
diferentes vozes são geradas.
1.1 OBJETIVOS DO TRABALHO
O objetivo deste trabalho é criar uma ferramenta que permita que uma pessoa possa
reproduzir de forma emulada a voz de outra pessoa.
Os objetivos específicos do trabalho são:
a) identificar os parâmetros de ADSR da voz do personagem alvo e do locutor,
através da aplicação de transformadas de Fourier;
b) treinar uma RNA com os padrões das ADSRs encontradas, gerando assim a
máscara das diferenças entre os padrões das duas vozes;
c) aplicar a máscara de áudio gerada na voz do locutor, reproduzindo de forma
emulada a voz do personagem.
1.2 ESTRUTURA DO TRABALHO
O presente trabalho está estruturado em quatro capítulos. O segundo capítulo contém a
fundamentação teórica necessária para o entendimento do trabalho. Nele são discutidos
tópicos relacionados sobre a fonação, ondas sonoras, transformadas de Fourier, filtros
acústicos, redes neurais, filtros adaptativos, ADSR e formato WAVE. Também são
comentados alguns trabalhos correlatos à ferramenta.
O terceiro capítulo comenta sobre o desenvolvimento da ferramenta, onde são
explanados os requisitos principais do problema trabalhado, a especificação contendo
diagramas de casos de uso, sequência e classes. Também são feitos comentários sobre a
implementação abrangendo as técnicas e ferramentas utilizadas, operacionalidade e por fim
são comentados os resultados e discussão.
O quarto capítulo refere-se às conclusões e extensões do trabalho.
16
2 FUNDAMENTAÇÃO TEÓRICA
A seção 2.1 apresenta os conceitos básicos sobre a fonação, que é a forma como os
seres humanos produzem a voz. Na seção 2.2 é apresentado o conceito de ondas sonoras. Por
sua vez, a seção 2.3 explana sobre as transformadas de Fourier enquanto que na seção 2.4 são
apresentados os filtros acústicos. A seção 2.5 explana a base das redes neurais e a seção 2.6
dos filtros adaptativos. Por fim, na seção 2.7 é apresentada a técnica do ADSR e na seção 2.8
o formato WAVE.
Redes neurais e ADSR formam a base inicial do estudo do presente trabalho, porém
com o decorrer do estudo outras técnicas foram utilizadas por se mostrarem mais eficazes.
2.1 FONAÇÃO
Segundo Russo (1999, p. 144-156), durante o processo de expiração (figura 1), a força
exercida pelo processo de abaixamento da caixa torácica contrai o volume do ar contido nos
pulmões, expelindo-o para fora. Ao passar pela traquéia, o ar proveniente dos pulmões
encontra resistência por parte dos tratos vocais1, fazendo com que a pressão do ar aumente.
Assim, ao atingir a laringe, o ar encontra duas lâminas denominadas de cordas vocais, que
fecham a passagem. Porém, devido à pressão acumulada na traquéia, o ar rompe a passagem
das cordas vocais, fazendo com que estas vibrem, produzindo assim um sinal sonoro.
Se as cordas vocais estiverem esticadas, assim como um elástico, produzirão um sinal
mais agudo, enquanto que se estiverem mais frouxas, produziram um sinal mais grave. Após o
sinal ter sido gerado, os lábios, a língua, os dentes, a faringe e até mesmo o nariz, interferem
na passagem do som, produzindo assim a voz (PEÑA CASANOVA, 1992, p. 65).
A pressão total exercida nas cordas vocais, também faz com que o sinal seja mais alto,
ou mais baixo, ou seja, quanto mais pressão maior será o volume da voz.
1 Trato vocal é o nome genérico dado à região compreendida entre a glote e os lábios, da qual participam várias
cavidades: laringe, faringe, cavidades oral e nasal (RUSSO, 1999, p. 151).
17
Fonte: Russo (1999, p. 144).
Figura 1 – Diagrama dos órgãos usados na produção da fala
2.2 ONDAS SONORAS
De forma genérica, uma onda ―é uma perturbação, abalo ou distúrbio transmitido
através do vácuo ou de um meio gasoso, líquido ou sólido‖ (RUSSO, 1999, p. 33).
Ondas podem ser senoidais (figura 2), ou seja, provenientes de uma relação que
contenha uma função de seno, ou então complexas, que são quaisquer ondas provenientes de
várias ondas senoidais com diferentes frequências, amplitudes e fases. As ondas podem ser
representadas no plano cartesiano, pelo domínio do tempo no eixo das abscissas e sua
respectiva amplitude no eixo das ordenas.
Uma onda sonora é um tipo de onda mecânica (necessita de um meio material para se
propagar) e tridimensional (pois se propaga em todas as direções no espaço) que é
reproduzida por um elemento vibrador ou fonte. Exemplos de fontes geradoras são os cristais,
18
cordas, tubos, membranas, e qualquer outro objeto que quando estimulado é capaz de produzir
perturbações no meio ao seu redor.
Fonte: Frequência (2009).
Figura 2 – Ondas senoidais
2.2.1 Frequência e período
Frequência (f) é a grandeza utilizada para indicar o número de revoluções (ciclos,
voltas, oscilações) em um período de tempo. Período (T) é a quantidade de tempo necessário
para que uma revolução seja completada. Assim a frequência é o inverso do período (Hz
conforme mostra o quadro 1.
𝑓 =1
𝑇 𝑇 =
1
𝑓
Quadro 1 – Fórmulas de relação entre a frequência e o período
Na teoria, um sinal sonoro pode ter qualquer frequência, porém nem todas as
frequências são audíveis conforme é apresentado na tabela 1 que relaciona as faixas de
frequência audíveis por humanos e outros animais. Sinais sonoros com frequências abaixo de
20 Hz são denominados de infra-sons e os sinais com frequências acima de 20 kHz são
chamadas de ultra-sons.
Tabela 1 – Faixa de frequências audíveis
Animal Menor Maior
Humanos 20 Hz 20 kHz
Gatos 10 Hz 60 kHz
Cães 15 Hz 50 kHz
Morcegos 10 Hz 120 kHz
Golfinhos 10 Hz 240 kHz Fonte: Russo (1999, p. 56).
2.2.2 Amplitude
Amplitude é a intensidade com que a fonte sonora gera o sinal, ou seja, a energia
transportada no sinal, permitindo-nos classificá-lo em uma escala de fraco a forte.
19
Resumidamente, amplitude é o volume de um sinal.
A amplitude máxima de uma onda senoidal é chamada de amplitude de pico e
corresponde aos ângulos de 90 º e 270 º da senóide.
2.2.3 Fase
Segundo Carvalho (2009), a fase de uma onda determina o ângulo inicial (em graus a
partir do 0º) no momento em que a vibração teve início, conforme pode ser visto na figura 3,
onde existem quatro ondas com fases diferentes (0º, 90º, 180º e 270º). Assim, duas ondas
iguais (mesma frequência, mesma amplitude e mesma fase) se somam, produzindo uma onda
de maior intensidade, enquanto duas ondas iguais, porém com uma diferença de fase de
exatamente 180º se anulam (ROEDERER, 2002, p. 123-127).
Fonte: adaptado de Russo (1999, p. 59).
Figura 3 – Projeções senoidais com diferentes fases iniciais
2.3 TRANSFORMADAS DE FOURIER
Jean Baptiste Joseph Fourier (1768-1839), matemático francês, demonstrou em 1801
que qualquer série de ondas pode ser dividida em uma série simples de ondas senoidais, e isso
representou um grande avanço, pois se mostrou que as ondas de uma nota musical possuíam
grande relação entre si, sendo cada qual um harmônico da sua nota fundamental (ROADS,
1996, p. 14-22).
A Transformada de Fourier, [...], é uma transformada integral que expressa uma
20
função em termos de funções de base sinusoidal, i.e., como soma ou integral de
funções sinusoidais multiplicadas por coeficientes ('amplitudes'). Existem diversas
variações directamente [sic] relacionadas desta transformada, dependendo do tipo de
função a transformar. (TRANSFORMADA..., 2008).
Utilizando-se de sequências discretas de 𝑁 números 𝑥 𝑘 , 𝑘 = 0,1, … , (𝑁 − 1), tem-se
a fórmula da Transformada Discreta de Fourier (Discrete Fourier Transform – DFT) (KHAN,
2005, p. 86) cuja fórmula é apresentada no quadro 2, onde 𝑊 = 𝑊𝑁−1 = 𝑒−𝑗
2𝑥
𝑁 , 𝑘 é
apresentado ao invés de 𝑘𝑇, 𝑛 é apresentado ao invés de 𝑛
𝑇0 e 𝑋(𝑛) é a representação de
𝐷𝑥 𝑛 = 𝐷𝐹𝑇(𝑥 𝑘 ).
𝐷𝐹𝑇 𝑥 𝑘 = 𝑥(𝑘)𝑊𝑛𝑘
𝑁−1
𝑘=0
= 𝑋(𝑛)
Fonte: Priemer (1999, p. 303).
Quadro 2 – Fórmula da transformada discreta de Fourier
A transformada mais comumente usada na computação é a Transformada Rápida de
Fourier (Fast Fourier Transform – FFT), que é uma variação da DFT, pois segundo Moser
(1997, p. 34), a idéia básica da FFT é quebrar a quantidade de amostras de 𝑁 em duas
sequências separadas (N/2), ficando assim, mais fácil de resolver computacionalmente.
O algoritmo FFT, funciona invertendo a ordenação dos bits das amostras, ou seja, uma
sequência composta pelas amostras 0, 1, 2, 3, 4, 5, 6, 7 cujos números binários são,
respectivamente, 000, 001, 010, 011, 100, 101, 110, 111, será invertida para a sequência
0, 4, 2, 6, 1, 5, 3, 7 (sequência binária igual a 000, 100, 010, 110, 001, 101, 011, 111).
Conforme Priemer (1999, p. 303-317), para executar esta inversão de bits, o algoritmo
FFT, subdivide as sequências de amostras em duas partes, onde a primeira parte é composta
pela primeira metade de cada sequência anterior, e a segunda parte é composta pela segunda
metade das sequências anteriores, conforme a figura 4. Este processo também é conhecido por
método de Cooley-Tukey, em homenagem aos seus criadores J.W. Cooley e John Tukey.
21
Fonte: adaptado de Priemer (1999, p. 314).
Figura 4 – FFT usando o método de Cooley-Tukey
2.4 FILTROS ACÚSTICOS
Denomina-se filtro acústico, todo e qualquer dispositivo, que reduza de forma seletiva
determinadas frequências de um sinal sonoro. Esta redução é feita baseada nos parâmetros do
filtro que são: a sua frequência central (amplitude de vibração máxima), sua frequência de
corte superior, sua frequência de corte inferior, sua largura de banda (a faixa de frequências
que o filtro abrange) e sua taxa de atenuação (taxa na qual as frequências serão atenuadas).
Com isso os filtros podem ser classificados em três tipos (figura 5):
a) filtro passa-baixo, que conforme o próprio nome diz, permitem a passagem das
frequências abaixo da frequência de corte e eliminando as frequências acima, ou
seja, filtrando os sons mais agudos;
b) filtro passa-alto, inverso ao passa-baixo, permite a passagem dos sons agudos
(altas frequências) e elimina os sons graves;
c) filtro passa-banda, é a combinação de um filtro passa-baixo com um filtro passa-
alto, eliminando as frequências que não se encontram entre duas frequências de
corte.
22
Fonte: Russo (1999, p. 141).
Figura 5 – Exemplo de filtros sonoros
2.5 REDES NEURAIS
As células nervosas do cérebro, os neurônios (figura 6), conectam-se umas às outras
através de junções chamadas sinapses. Com isso os sinais cerebrais se propagam de um
neurônio ao outro através de reações eletroquímicas. Estes sinais são responsáveis pelas
funções cognitivas, como por exemplo, a fala e a memória.
Fonte: Russell e Norvig (2004, p. 13).
Figura 6 – As partes de um neurônio
Baseados neste conhecimento sobre os neurônios, McCulloch e Pitts desenvolveram
em 1943 um modelo matemático simples do que seria um neurônio (figura 7), que ―’dispara’
quando uma combinação linear de suas entradas excede algum limiar‖ (RUSSEL; NORVIG,
2004, p. 713). Com a ligação destes modelos, assim como fazem os neurônios, pode-se formar
uma rede neural artificial, e uma de suas maiores propriedades é a capacidade de aprender.
23
Fonte: Russell e Norvig (2004, p. 714).
Figura 7 – Modelo matemático de um neurônio
Basicamente somam-se os valores dos vínculos de entradas, multiplicando-os por um
peso (que é onde ocorre o aprendizado) e se esta soma exceder uma faixa seja esta um simples
limiar ou mesmo uma função sigmóide, esta soma é propagada aos neurônios conectados aos
vínculos de saída.
No final, caso o resultado esperado não seja atingido, os pesos são ajustados para se
adequar a este resultado. Assim com o tempo, após muitos treinos, a rede é capaz de
reproduzir os resultados esperados, pois se ajustou ao seu padrão de funcionamento.
2.6 FILTROS ADAPTATIVOS
A ideia básica de qualquer filtro adaptativo é auto-ajustar sua função de transformada,
para adaptar um sinal de entrada num sinal esperado.
Assim, inicialmente os filtros possuem coeficientes não especificados, que vão se
adaptando ao sinal de entrada conforme este vai sendo amostrado. Um filtro possui
basicamente dois componentes principais, que são estes coeficientes do filtro, e o algoritmo
de adaptação que manipula estes coeficientes (figura 8).
24
Fonte: Begg, Lai e Palaniswami (2007, p. 64).
Figura 8 – Estrutura do filtro adaptativo
Seu funcionamento consiste em passar um sinal de ruído por um filtro digital, para que
o resultado deste filtro possa ser adicionado ao sinal original, de forma a corrigir o sinal de
origem ao um sinal esperado. Com o novo sinal obtido e com o ruído utilizado, o algoritmo
adaptativo recalcula os pesos do filtro, para que este possa a cada nova iteração, gerar um
sinal mais próximo do sinal desejado (PITZ, 2009).
Segundo Begg, Lai e Palaniswami (2007, p. 65), para uma estrutura com N
coeficientes, a estrutura de um filtro adaptativo é dado pela fórmula do quadro 3, onde
𝐰 = 𝑤1, 𝑤2 , … , 𝑤𝑁 é o vetor de coeficientes do filtro (também conhecido por weights, ou
pesos) e 𝐫 = 𝑟𝑘+1 , 𝑟𝑘 , … , 𝑟𝑁 é o sinal de referência.
𝑒𝑘 = 𝑠𝑘 − 𝑤𝑖𝑟𝑘−𝑖
𝑁
𝑖=1
= 𝑠𝑘 − 𝐰T𝐫𝑘
Fonte: Begg, Lai e Palaniswami (2007, p. 65).
Quadro 3 – Diferença entre os dois sinais
2.6.1 Algoritmo LMS
O algoritmo Least Mean Square2 (LMS) é um dos muitos tipos de algoritmo de filtro
adaptativo, e que foi desenvolvido em 1960 pelo professor Bernard Widrow e seu aluno, Ted
Hoff, na universidade de Stanford, visando superar alguns problemas da fórmula original de
Wiener-Hopf (LEAST MEAN SQUARES FILTER, 2009).
Baseado na fórmula do filtro adaptativo (quadro 3), o quadrado do erro é obtido,
elevando ao quadrado a fórmula, onde se obtém 𝑒𝑘2 = 𝑠𝑘
2 − 2𝑠𝑘𝐰T𝐫𝑘 + 𝐰T𝐫𝑘𝐰
T𝐫𝑘.
2 Em português, quadrado médio mínimo.
25
Assumindo que os sinais são conjuntamente estacionários, o erro médio quadrático
pode ser obtido tendo as expectativas de ambos os lados da equação, assim como a fórmula do
quadro 4, onde p é um vetor de correlação cruzada de N dimensões, 𝐀 uma matriz 𝑁 × 𝑁 de
auto-correlação, e 𝜎2 a variância de 𝑠𝑘 .
𝐽 = 𝐸 𝑒𝑘2
= 𝐸 𝑠𝑘2 − 2𝐸 𝑠𝑘𝐰
T𝐫𝑘 + 𝐸 𝐰T𝐫𝑘𝐰T𝐫𝑘
= 𝜎2 − 2𝐩T𝐰 + 𝐰T𝐀𝐰 Fonte: Begg, Lai e Palaniswami (2007, p. 66).
Quadro 4 – Erro médio quadrático
O gradiente3 do erro quadrático é dado pela equação diferencial do quadro 5.
d𝐽
d𝐰= −2𝐩T + 2𝐀𝐰
Fonte: Begg, Lai e Palaniswami (2007, p. 66).
Quadro 5 – Gradiente do erro
O melhor filtro é encontrado com a gradiente do erro sendo estacionário ou zero,
obtendo então 𝐰∗ = 𝐀−1𝐩, que é conhecido por equação de Wiener-Hopf.
Conforme Begg, Lai e Palaniswami (2007, p. 66), um filtro adaptativo assim é difícil
de implementar porque requer um conhecimento de 𝐀 e 𝐩, que não são conhecidos a priori.
Além disso, tendo-se o pressuposto de que os sinais são estacionários, se tem 𝐀 e 𝐩 mudando
continuamente no tempo, e assim 𝒘∗ necessitaria ser constantemente recalculado.
O algoritmo LMS faz com que a regra de atualização em cada instante 𝑡 da
amostragem defina-se conforme o quadro 6, ou seja, o valor do próximo peso é o valor do
peso anterior menos o dobro da taxa de convergência, multiplicado pela diferença entre a
saída obtida e a saída esperada que é multiplicada pelo valor do ruído utilizado.
𝐰𝑡+1 = 𝐰𝑡 − 2𝜇 𝑠𝑘 − 𝐰𝑡𝐫𝒌 𝐫𝑘 Fonte: Begg, Lai e Palaniswami (2007, p. 66).
Quadro 6 – Fórmula do algoritmo LMS
Este algoritmo utiliza ―estimativas instantâneas de 𝐀 e 𝐩 e, portanto, os coeficientes do
filtro 𝐰 obtidos também são estimados, mas estes pesos vão convergir para o melhor valor, tal
como o filtro aprenda as verdadeiras características do ruído‖ (BEGG; LAI;
PALANISWAMI, 2007, p. 66).
Porém, para isso existe uma condição de convergência, que pode ser vista no quadro 7,
onde 𝛾max é o maior autovalor da matriz de entrada de covariância.
3 Em cálculos vetoriais, o gradiente é a alteração no valor de uma quantidade por unidade de espaço.
26
𝜇 >1
𝛾max> 0
Fonte: Begg, Lai e Palaniswami (2007, p. 66).
Quadro 7 – Condição de convergência
Segundo Zipf (2009), na prática, o melhor valor 𝐰 nunca será alcançado, mas oscilará
em torno deste.
2.7 ADSR
ADSR é o acrônimo para Attack, Decay, Sustain, Release4 (ROADS, 1996, p. 97), que
é uma das formas de se aplicar um envelope ao sinal de áudio, dividindo cada nota em quatro
partes, cada uma nomeada com uma parte do acrônimo. Tem-se que:
a) attack: é a fase entre o silêncio e a intensidade total da nota;
b) decay: é muito pequeno e muitas vezes nem é perceptível. É o momento após o
attack em que a intensidade reduz um pouco antes de se manter estável;
c) sustain: é a parte do som que corresponde ao tempo de duração da nota.
Normalmente este tempo é mantido pelo executante, como por exemplo em um
instrumento de sopro;
d) release: é a última etapa da nota. É o momento em que a nota vai suavizando até
desaparecer por completo.
A figura 9 apresenta três exemplos de ADSRs diferentes, sendo o de um instrumento
de corda, um instrumento de sopro e um instrumento de percussão, respectivamente. Pode-se
notar que dependendo do instrumento (e assim do seu timbre), os tempos de cada uma das
fases são diferentes, sendo às vezes até mesmo nulo.
Fonte: adaptado de Adsr (2008).
Figura 9 – ADSR
Obtendo o ADSR de cada nota, pode-se criar um envelope para o sinal de áudio. A
4 Em português, ataque, decaimento, sustentação e repouso.
27
figura 10 apresenta três sinais de áudio, sem e com o envelope. O primeiro sinal é referente a
três notas de uma tabla (espécie de tambor indiano). O segundo sinal apresenta três notas de
uma trompa, enquanto o terceiro sinal apresenta uma longa nota de uma flauta.
Fonte: Adsr (2008).
Figura 10 – Envelope em sinal de áudio
2.8 FORMATO WAVE
O formato de arquivos WAVE é um formato nativo do sistema operacional Windows
para armazenamento de áudio digital. Tornou-se um dos formatos de áudio mais amplamente
suportados pelos computadores, devido à popularidade do sistema operacional Windows e do
enorme número de aplicações desenvolvidas para esta plataforma (THE SONIC SPOT, 2007).
Um arquivo WAVE não comprimido é consistido de três partes distintas de
informação (figura 11): a parte denominada RIFF, onde o arquivo é identificado como um
arquivo WAVE, a parte denominada fmt, que identifica os parâmetros do formato do arquivo,
como taxa de amostragem, número de canais, etc., e a parte denominada data, que contém os
dados do arquivo (amostras de áudio).
28
Fonte: adaptado de Rumsey (2006, p. 267).
Figura 11 – Representação de um arquivo de formato WAVE
Como em um arquivo WAVE é feita a representação digital de um sinal analógico,
existem alguns parâmetros no formato do arquivo que são essenciais:
a) channels, ou canais, indica quantos canais de áudio estão armazenados no arquivo;
b) bitrate, ou taxa de bits, que é a quantidade de bits usados para representar uma
única amostra. Funciona como a resolução da amostra, quanto mais bits forem
usados para representar uma amostra, maior será a precisão da transformação do
sinal analógico;
c) samplerate, ou taxa de amostragem, representa quantas amostras devem ser
executadas por segundo, ou seja, representa a frequência do som (em Hz).
Existem ainda outras partes que podem opcionalmente ser utilizadas para
armazenamento de informações, como a parte cue que armazena pontos de marcação na
amostra, permitindo a divisão do arquivo (em capítulos, por exemplo), ou a parte smpl que
armazena informações a respeito do autor.
2.9 TRABALHOS CORRELATOS
Existem trabalhos como o de Moser (1997) que elevou a capacidade de
reconhecimento de palavras isoladas, adicionando à rede neural artificial desenvolvida por
Tafner (1996), informações a respeito das frequências de um sinal ao longo de um
determinado tempo. Segundo Moser (1997, p.2), o trabalho original de Tafner utilizava-se de
29
uma rede neural de Kohonen5 e como resultado final gerou-se uma ferramenta capaz de
identificar palavras, desde que pronunciadas por um mesmo locutor. O que Moser fez foi
aplicar um tratamento aos sinais enviados a rede neural artificial, utilizando para tanto
transformadas de Fourier, melhorando assim a capacidade de reconhecimento da mesma.
Entre os vários produtos comercializados pela empresa Audio4Fun, existe uma
ferramenta chamada Voice Changer Software (AUDIO4FUN, 2008) que permite a
manipulação da voz do usuário. Além de poder equalizar a voz, distorcendo-a, também é
possível ―treinar‖ a aplicação com uma determinada voz, para que esta seja emulada. A
ferramenta possui ainda vozes conhecidas já gravadas, que podem ser utilizadas para testes, e
também efeitos que podem ser aplicados sobre o áudio original, como por exemplo, efeitos de
eco, efeito ―Radio AM‖6, entre outros.
Kain e Macon (1998) tentam converter vozes para a criação de sintetizadores de leitura
de texto (Text-to-Speech). Até então, a voz do locutor era mapeada frame por frame e a
frequência era ajustada baseada na média das frequências. Diante disto, Kain e Macon (1998)
mudaram a forma como se calculava a frequência desejada, aplicando transformações lineares
usando os Modelos de Mistura Gaussiana (Gaussian Mixture Models – GMM), melhorando
assim a forma como a voz do sintetizador era reproduzida, ficando mais parecida com a voz
que se tentava emular, pois o sinal gerado era ainda mais parecido com o sinal original ao
qual se tentava emular.
Sanjaume (2008) cria um sintetizador de voz humana para ser utilizado para canto, ou
seja, sintetizar uma voz cantando. Existem muitos sintetizadores de voz, mas a maioria
reproduz um som robotizado devido às características da reprodução e de leitura de texto. O
que Sanjaume fez foi manipular a entonação e o timbre da fala utilizando-se da partitura da
música como forma de diferenciação de entonação e timbre. Para isso, criou uma espécie de
banco de sons onde armazenou várias amostras de determinado cantor, e obteve assim os
padrões de voz daquele cantor. Por fim, adaptou um algoritmo de leitura de texto para que
este reproduzisse um som que utilizasse os padrões da voz do cantor.
5 Modelo de RNA em que os neurônios próximos ao neurônio ajustado também são afetados, criando um
estímulo para que possam responder também ao fato apresentado à rede (TAFNER; XERES; RODRIGUES
FILHO, 1995, p. 123).
6 Som abafado, com chiados agudos, semelhante a uma fita cassete velha e gasta.
30
3 DESENVOLVIMENTO DA FERRAMENTA
Este capítulo detalha as etapas do desenvolvimento da ferramenta. São ilustrados os
principais requisitos, a especificação, a implementação (mencionando técnicas e ferramentas
utilizadas, bem como a operacionalidade da ferramenta) e por fim são listados resultados e
discussão.
3.1 REQUISITOS PRINCIPAIS DO PROBLEMA A SER TRABALHADO
A ferramenta proposta deve basicamente receber duas amostras de voz, sendo uma do
locutor e a outra do personagem a ser emulado, e com base nestas amostras, criar uma
máscara que possa ser aplicada sobre a voz do locutor a fim de emular a voz do personagem.
Com base nestas informações foram identificados os seguintes requisitos:
a) permitir carregar arquivos de áudio no formato WAVE para ambas as vozes
(Requisito Funcional – RF);
b) permitir capturar áudio a partir de um microfone e gravar o mesmo em arquivo
WAVE (RF);
c) transformar um sinal carregado do domínio do tempo para o domínio da
frequência através da transformada de Fourier (RF);
d) obter a frequência do harmônico fundamental (RF);
e) armazenar o valor das amplitudes das harmônicos relevantes a detecção do timbre,
que são as frequências múltiplas do harmônico fundamental (RF);
f) calcular a máscara de diferença entre os harmônicos da amostra de voz do locutor
e a amostra de voz do personagem (RF);
g) aplicar a máscara calculada sobre um sinal de voz do locutor, gerando um terceiro
sinal que emule a voz do personagem (RF);
h) reproduzir qualquer um dos sinais de amostra ou o sinal emulado (RF);
i) implementar a ferramenta na linguagem Java (Requisito Não Funcional – RNF).
31
3.2 ESPECIFICAÇÃO
A especificação do presente trabalho foi desenvolvida utilizando a notação UML
(UML, 2002) em conjunto com a ferramenta Enterprise Architect (SPARXS SYSTEMS,
2008). A ferramenta recebeu o nome de AudioEmulator devido as suas características de
emulação de áudio.
Neste capítulo são explanados diagramas de atividades casos de uso, classes e
sequência. Alguns destes diagramas estão em sua forma resumida para melhor visualização.
A ferramenta segue um fluxo de atividades simples, conforme pode ser observado no
diagrama de atividades da figura 12.
Figura 12 – Diagrama de atividades do fluxo da ferramenta
Para o entendimento das etapas a serem executas, a seguir são apresentados três
diagramas de casos de usos, cada qual com uma parte da atividade de emulação.
32
3.2.1 Diagramas de casos de uso
Conforme mencionado anteriormente, a ferramenta se divide em basicamente três
tarefas distintas que estão separadas cada qual em um diagrama de casos de uso. Nota-se que
devido à flexibilidade de gravar os áudio/filtros em arquivos, algumas etapas não precisam ser
executadas na sequência apresentada a seguir.
3.2.1.1 Carregamento dos áudios de entrada
Caso nenhum arquivo de filtro tenha sido criado (ex: primeiro uso da ferramenta), é
necessário obter os áudios do locutor e do personagem. Assim, a figura 13 apresenta todas as
possíveis interações do usuário com a ferramenta no que diz respeito ao carregamento inicial
dos sinais de voz que serão utilizados.
Figura 13 – Diagrama de casos de uso das amostras
O caso de uso UC01 – Capturar Áudio Microfone (quadro 8) descreve como o
usuário interage com a ferramenta para capturar um sinal de áudio a partir do microfone e
armazenar o mesmo em arquivo. Este caso de uso apresenta somente um cenário principal,
não havendo cenários alternativos ou de exceção.
33
UC01 – Capturar áudio microfone: Captura a voz pelo microfone e armazena
em um arquivo.
Pré-condição O sistema deve ter detectado com sucesso o
dispositivo de captura do microfone.
Cenário principal
1) O usuário seleciona a opção de capturar o áudio
pelo microfone.
2) A ferramenta apresenta a tela de captura de
áudio.
3) O usuário seleciona a opção de iniciar a
captura.
4) A ferramenta capta o sinal do microfone e vai
armazenando internamente.
5) O usuário seleciona a opção de interromper a
captura.
6) A ferramenta para de captar o sinal.
7) O usuário seleciona a opção de gravar o áudio em
arquivo.
8) A ferramenta apresenta tela solicitando o nome
do arquivo.
9) O usuário escolhe a pasta e digita o nome do
arquivo.
10) A ferramenta cria um arquivo com o áudio
capturado.
Pós-condição O áudio é capturado com sucesso e armazenado em
arquivo.
Quadro 8 – Caso de uso UC01 – Capturar áudio microfone
Os casos de uso UC02 – Carregar áudio locutor e UC04 – Carregar áudio
personagem (quadro 9) definem como o usuário interage com a ferramenta para carregar um
arquivo de áudio. Os dois casos de uso são idênticos, diferindo somente na representação da
amostra, ou seja, se pertence ao locutor, ou ao personagem. Além dos cenários principais,
estes dois casos de uso possuem um fluxo de exceção responsável por informar caso um
arquivo não seja válido.
UC02 – Carregar áudio locutor e UC04 – Carregar áudio personagem: Carrega
um arquivo de áudio para a ferramenta.
Cenário principal
1) O usuário seleciona a opção de carregar o áudio
e seleciona o arquivo.
2) A ferramenta valida o arquivo e carrega as
informações.
Cenário exceção 1
No passo 2, caso o arquivo não seja válido,
apresenta mensagem informando que o arquivo é
inválido e retorna a tela principal da ferramenta
sem carregar nenhuma informação.
Pós-condição O áudio é carregado para a ferramenta.
Quadro 9 – Casos de uso UC02 – Carregar áudio locutor e UC04 – Carregar áudio personagem
Os casos de uso UC03 – Reproduzir áudio locutor e UC05 – Reproduzir áudio
personagem (quadro 10) explanam como o usuário interage com a ferramenta para reproduzir
o arquivo de áudio que foi carregado. Os dois casos de uso são idênticos, diferindo somente
na representação da amostra, ou seja, se pertence ao locutor, ou ao personagem. Estes casos
de uso apresentam somente um cenário principal, não havendo cenários alternativos ou de
34
exceção.
UC03 – Reproduzir áudio locutor e UC05 – Reproduzir áudio personagem:
Reproduz o áudio previamente carregado.
Pré-condição O arquivo de áudio já deve estar carregado.
Cenário principal 1) O usuário seleciona a opção de reproduzir o
áudio selecionado.
2) A ferramenta reproduz o áudio carregado.
Pós-condição O arquivo de áudio começa a ser reproduzido.
Quadro 10 – Casos de uso UC03 – Reproduzir áudio locutor e UC05 – Reproduzir áudio personagem
3.2.1.2 Criação do filtro de áudio
Uma segunda etapa da ferramenta se diz respeito ao filtro utilizado para a emulação,
que pode ser gerado caso os áudios do locutor e do personagem tenham sido carregados, ou
então carregado diretamente de um arquivo previamente salvo. A figura 14 apresenta todas as
interações do usuário com a ferramenta para a criação, armazenamento e carga deste filtro de
áudio.
Figura 14 – Diagrama de casos de uso do filtro
O caso de uso UC06 – Gerar filtro (quadro 11) descreve como o usuário interage
com a ferramenta para gerar o filtro entre as vozes do locutor e do personagem. Este caso de
uso apresenta somente um cenário principal, não havendo cenários alternativos ou de exceção.
35
UC06 – Gerar filtro: Cria um filtro da diferença entre as vozes do locutor
e do personagem.
Pré-condição Os arquivos com as amostras de voz do locutor e do
personagem devem estar carregadas.
Cenário principal
1) O usuário seleciona a opção de gerar o filtro.
2) A ferramenta calcula o filtro necessário e a
disponibiliza para uso.
Pós-condição O filtro entre as vozes do locutor e do personagem
é criado.
Quadro 11 – Caso de uso UC06 – Gerar filtro
O caso de uso UC07 - Carregar filtro (quadro 12) explana como o usuário
interage com a ferramenta para carregar um filtro de áudio previamente armazenado em
arquivo. Além do cenário principal, este caso de uso possui um fluxo de exceção responsável
por informar caso um arquivo não seja válido.
UC07 - Carregar filtro: Carrega um arquivo de filtro para a ferramenta.
Cenário principal
1) O usuário seleciona a opção de carregar o filtro
e seleciona o arquivo.
2) A ferramenta valida o arquivo e carrega as
informações.
Cenário exceção 1
No passo 2, caso o arquivo não seja válido,
apresenta mensagem informando que o arquivo é
inválido e retorna a tela principal da ferramenta
sem carregar nenhuma informação.
Pós-condição O filtro é carregado para a ferramenta.
Quadro 12 – Caso de uso UC07 – Carregar filtro
O caso de uso UC08 - Gravar filtro (quadro 13) descreve como o usuário interage
com a ferramenta para gravar em arquivo um filtro de áudio gerado. Este caso de uso
apresenta somente um cenário principal, não havendo cenários alternativos ou de exceção.
UC08 - Gravar filtro: Grava o filtro gerado em um arquivo.
Pré-condição O filtro de áudio deve ter sido criado.
Cenário principal
1) O usuário seleciona a opção de gravar o filtro
em arquivo.
2) A ferramenta apresenta tela solicitando o nome
do arquivo.
3) O usuário escolhe a pasta e digita o nome do
arquivo.
4) A ferramenta cria um arquivo com o filtro
gerado.
Pós-condição O filtro é armazenado em arquivo.
Quadro 13 – Caso de uso UC08 – Gravar filtro
3.2.1.3 Aplicação do filtro de áudio
Quando a ferramenta possuir o filtro de áudio, tendo sido carregado de um arquivo, ou
mesmo recém criado a partir dos áudios do locutor e do personagem, é possível aplicar este
filtro sobre um segundo áudio do locutor, para que seja emulada a voz do personagem. A
36
figura 15 apresenta todas as possíveis interações do usuário com a ferramenta para a emulação
da voz do personagem, a partir de um segundo áudio do locutor.
Figura 15 – Diagrama de casos de uso da emulação
O caso de uso UC09 – Carregar áudio a emular (quadro 14) descreve como o
usuário interage com a ferramenta para carregar o arquivo de áudio que será emulado. Além
do cenário principal, este caso de uso possui um fluxo de exceção responsável por informar
caso um arquivo não seja válido.
UC09 – Carregar áudio a emular: Carrega o áudio que será emulado.
Cenário principal
1) O usuário seleciona a opção de carregar o áudio
e seleciona o arquivo.
2) A ferramenta valida o arquivo e carrega as
informações.
Cenário exceção 1
No passo 2, caso o arquivo não seja válido,
apresenta mensagem informando que o arquivo é
inválido e retorna a tela principal da ferramenta
sem carregar nenhuma informação.
Pós-condição O áudio é carregado para a ferramenta.
Quadro 14 – Caso de uso UC09 – Carregar áudio a emular
O caso de uso UC10 – Reproduzir áudio emulado (quadro 15) descreve como o
usuário interage com a ferramenta para reproduzir o arquivo de áudio a ser emulado. Este
caso de uso apresenta somente um cenário principal, não havendo cenários alternativos ou de
exceção.
UC10 – Reproduzir áudio emulado: Reproduz o áudio previamente carregado.
Pré-condição O arquivo de áudio já deve estar carregado.
Cenário principal
1) O usuário seleciona a opção de reproduzir o
áudio selecionado.
2) A ferramenta reproduz o áudio carregado.
Pós-condição O arquivo de áudio começa a ser reproduzido.
Quadro 15 – Caso de uso UC10 – Reproduzir áudio emulado
O caso de uso UC11 – Aplicar filtro (quadro 16) descreve como o usuário interage
37
com a ferramenta para aplicar o filtro carregado sobre o sinal de áudio a ser reproduzido. Este
caso de uso apresenta somente um cenário principal, não havendo cenários alternativos ou de
exceção.
UC11 – Aplicar filtro: Aplica o filtro ao áudio carregado.
Pré-condição
O filtro já deve ter sido carregado.
O arquivo com as amostras de voz a ser emulada deve
estar carregado.
Cenário principal
1) O usuário seleciona a opção de aplicar o filtro.
2) A ferramenta aplica o filtro sobre o sinal de
áudio.
Pós-condição O sinal de áudio é alterado conforme o filtro.
Quadro 16 – Caso de uso UC11 – Aplicar filtro
3.2.2 Diagramas de classe
Para contemplar as atividades descritas e para uma melhor divisão das atribuições, a
ferramenta foi dividida em cinco camadas, que interagem através de ligações lógicas
conforme é apresentado no diagrama de pacotes na figura 16. A seguir são explanadas cada
uma das camadas e suas responsabilidades na ferramenta.
Figura 16 – Diagrama de pacotes das camadas da ferramenta
É importante lembrar que os diagramas a seguir estão num formato reduzido,
apresentando somente as operações e atributos fundamentais ao entendimento do problema.
38
3.2.2.1 Camada de interfaces
Armazena todas as interfaces necessárias para a conexão entras as camadas. A
instância dos objetos que implementam estas interfaces é feita na inicialização da ferramenta,
e depois cada camada é informada sobre o correspondente objeto da outra camada.
Assim, uma camada não faz requisições diretamente a outra camada, e sim a um objeto
que implementa estas camada, o que garante que, caso haja a necessidade de alterar o sistema
mudando completamente uma camada, as outras camadas continuem intactas.
A figura 17 mostra a forma como as interfaces das camadas se interconectam
formando uma rede de dependências.
Figura 17 – Diagrama de classes da camada de interfaces
Cada uma das interfaces possui um papel distinto na ferramenta, seja atuando como
uma interface de conexão entre duas camadas, ou simplesmente como um listener, para
39
receber determinados eventos e processá-los.
A seguir as principais funções das interfaces desta camada:
a) StatusListener: se encarrega de todas as interações por parte da ferramenta para
com o usuário. Assim, sempre que a ferramenta gera um evento que necessite um
feedback ao usuário, esta interface é solicitada;
b) CoreInterface: responsável pelas operações que envolvem os cálculos da
ferramenta. É a responsável por transformar os sinais de um domínio para o outro
e, principalmente, por criar e aplicar o filtro de áudio;
c) ActionsListener: interface que recebe as requisições do usuário sobre os
comandos da ferramenta. Qualquer evento que o usuário dispare, passa antes por
esta interface;
d) ExternalInterface: se responsabiliza por todo o acesso externo, seja a arquivos
ou dispositivos de áudio, tanto para a leitura quanto para a escrita;
e) ProgressListener: listener simples para a notificação do progresso de alguma
tarefa, como o carregamento dos arquivos, criação do filtro, ou aplicação do filtro
sobre o sinal de áudio;
f) CaptureListener: semelhante ao ProgressListener, porém voltado
exclusivamente ao processo de captura de áudio, recebe as amostras de áudio e
notificações do processo de captura.
3.2.2.2 Camada de modelo
Para armazenar os dados da ferramenta, como as amostras de áudio, os parâmetros do
filtro e os valores das configurações foi criada uma camada contendo classes de modelo. Estas
classes somente executam o papel de armazenamento de informações, não possuindo
nenhuma operação que altere e/ou afete outra classe. Esta camada é utilizada por todas as
outras camadas e seu diagrama pode ser visto na figura 18.
40
Figura 18 – Diagrama de classes da camada de modelo
A classe AudioSources é a classe mais utilizada, sendo ela responsável por armazenar
as informações das diversas fontes de áudio e é utilizada por todas as camadas como forma de
sincronia para os acessos a estes áudios. Armazena todos os tipos de informações referentes
ao estado atual da ferramenta, ou seja, as configurações de criação do filtro (FilterFormat),
além do próprio filtro criado (AudioFilter) e o mais importante, armazena as amostras de
áudio. Estas amostras de áudio são modeladas pela classe AudioFile, que armazena o sinal
de áudio, o arquivo onde foi lido a amostra e a taxa de amostragem do sinal, além de poder
armazenar o histograma (quando este for calculado).
Outra importante classe da camada de modelos é a classe Complex, que representa um
número complexo e é utilizada basicamente pelos algoritmos da transformada de Fourier. A
classe implementa também as operações matemáticas entre números complexos, e possui
recursos de acesso isolado ao valor real e o valor imaginário.
3.2.2.3 Camada visual
Na camada visual ficam todas as classes responsáveis pela interação visual com
usuário, ou seja, as telas do sistema, e estão apresentadas no diagrama de classes da figura 19.
41
Figura 19 – Diagrama de classes da camada visual
A classe PrincipalGUI, como o próprio nome já diz, se responsabiliza por criar a tela
principal da ferramenta. Como é possível visualizar pelo diagrama de classes, esta classe
implementa a interface StatusListener para poder informar ao usuário sobre qualquer
evento que ocorra, desde eventos que sinalizam o início e/ou término do carregamento de
arquivos de áudio, até possíveis mensagens de erro.
Conforme visto no diagrama de classes de interface (figura 17) a interface
StatusListener está diretamente ligada a interface ActionsListener, assim todas as ações
que são invocadas pelo usuário (ex: ações dos botões), estão ligadas a chamadas na interface
ActionsListener.
Por existirem processos que podem levar muito tempo para serem executadas, como
por exemplo, a criação do filtro ou a leitura de arquivos de áudio muito grandes, a classe
TaskProgressGUI se encarrega de implementar a interface ProgressListener, que notifica
o progresso de um processo qualquer, gerando assim um feedback ao usuário do andamento
de determinada tarefa.
Outras telas importantes são as telas de captura de áudio por meio de microfones que
estão implementadas na classe MicCaptureGUI, e as telas de configurações, como a
ConfigFilterGUI e ConfigCaptureGUI, onde é possível alterar as propriedades do filtro a
42
ser criado e do formato de captura do áudio, respectivamente.
3.2.2.4 Camada de processamento
Principal camada da aplicação. É a responsável por interconectar todas as camadas
(através das interfaces da camada de interfaces) entre si, repassar os eventos e chamados entre
estas. Conforme pode ser visto no diagrama de classes de processamento (figura 20), este
pacote possui somente três classes.
Figura 20 – Diagrama de classes da camada de processamento
A classe Emulator, que é classe que implementa a interface ActionsListener, prove
os acessos as ações da ferramenta, além de possuir acesso direto a interface de notificação do
estado da ferramenta (StatusListener), a interface de acesso externo (ExternalInterface)
e a interface de manipulação e processamento dos sinais de áudio (CoreInterface).
43
Implementando a interface CoreInterface, tem-se a classe Converter, que utiliza o
modelo AudioSources para obter acesso aos sinais de áudio e assim, criar e aplicar o filtro de
áudio. Além disso, como uma das funcionalidades da CoreInterface é converter um sinal do
domínio do tempo para o domínio da frequência, possui acesso a classe FFT, que implementa
o algoritmo FFT.
3.2.2.5 Camada de acesso externo
Esta camada realiza todas as interações da ferramenta com os dispositivos externos,
sejam eles dispositivos de reprodução e/ou captura de áudio, ou mesmo arquivos externos,
como arquivos WAVE e os arquivos de filtro gerados pela ferramenta. O diagrama de classes
da camada de acesso externo é apresentado na figura 21.
Figura 21 – Diagrama de classes da camada de acesso externo
Nesta camada está a classe DeviceController que implementa a interface
44
ExternalInterface, fornecendo assim acesso dos dispositivos as outras camadas da
ferramenta. Por questão de simplificação, as atribuições desta classe foram subdivididas entre
quatro classes, as quais são utilizadas pela classe DeviceController para responder a
implementação da interface:
a) MicrophoneCapture, que realiza todo o processo de obtenção do sinal de áudio
proveniente de microfones;
b) AudioFileReader, responsável por fazer a leitura dos arquivos de áudio e também
dos arquivos de filtro gerados pela ferramenta;
c) AudioFileWritter, que realiza a operação inversa da classe AudioFileReader,
promovendo o processo de gravação dos arquivos de áudio e arquivos de filtro
gerados pela ferramenta;
d) AudioPlayer, provê acesso ao dispositivo de reprodução de áudio, permitindo que
sejam reproduzidos os áudios obtidos pela ferramenta.
Esta camada é a única que utiliza diretamente a extensão JavaSound do Java para
realizar os acessos as informações dos áudios. Qualquer informação necessária as demais
camadas são obtidas pela camada de acesso externo e armazenadas nas devidas classes que
modelam tal informação.
3.2.3 Diagrama de sequência
Dado que a ferramenta foi desenvolvida em camadas, conforme já mencionado em
seções anteriores, todas as trocas de mensagens entre estas camadas são realizada pelas
interfaces que as representam. Na figura 22 é apresentado o diagrama de sequência do
funcionamento da ferramenta, com as principais mensagens utilizadas e suas sequências de
interações. É importante lembrar que somente as interfaces das camadas estão sendo
representadas, e que as classes que contém suas implementações possuem muito mais
mensagens e iterações, porém estas não se fazem necessárias ao entendimento do problema.
45
Figura 22 - Diagrama de sequência de funcionamento
3.3 IMPLEMENTAÇÃO
A seguir são exibidas as técnicas e ferramentas utilizadas e a operacionalidade da
implementação da ferramenta.
3.3.1 Técnicas e ferramentas utilizadas
Para a implementação da ferramenta foi utilizada a linguagem de programação Java,
contando com sua extensão JavaSound. O ambiente de desenvolvimento escolhido foi o
Eclipse (ECLIPSE, 2007).
Todo o código fonte utilizado na ferramenta foi produzido exclusivamente para o
corrente trabalho e foi escrito em inglês (inclusive os comentários) visando facilitar a
expansão do mesmo.
46
3.3.1.1 Leitura e gravação de arquivos WAVE
A leitura de arquivos no formato WAVE, realizada através das classes AudioSystem
que fornece o suporte ao dispositivo de áudio, e AudioInputStream, que possibilita a leitura
do stream de áudio, ambas fornecida pela JavaSound, permite que seja possível obter
informações de um arquivo WAVE, como a taxa de amostragem, número de canais, o formato
de ordenação dos bits utilizadas, bem como as próprias amostras do sinal de áudio.
Os acessos a estas classes da JavaSound são implementados na classe
AudioFileReader, que se responsabiliza por obter as informações do arquivo. Estas
informações são modelas pela classe AudioFormat, também da JavaSound, e o sinal
(amostras) na forma de um array de bytes. Tudo isso é então encapsulado em um objeto da
classe AudioFile, que será utilizado como referência para os processos de emulação.
Pelo quadro 17 é possível analisar o código fonte do método readAudioFile da classe
AudioFileReader que, através da JavaSound obtém as informações do áudio.
/**
* Read a wave file and obtain your data and format. This datas is storage
* in model <code>{@link AudioFile}</code> with is returned.
*
* @param file
* The WAVE file to be read.
* @return Return a <code>{@link AudioFile}</code> with the data and
* format of the readed file.
*/
public AudioFile readAudioFile(String file) {
AudioFile audioFile = null;
AudioInputStream stream = null;
AudioFormat format = null;
float[] data = null;
try {
stream = AudioSystem.getAudioInputStream(new File(file));
format = stream.getFormat();
byte[] buffer = new byte[stream.available()];
stream.read(buffer);
data = convertByteToFloat(buffer);
data = normalize(data);
audioFile = new AudioFile(data, format.getSampleRate(), file);
} catch (Exception e) {
audioFile = null;
}
return audioFile;
}
Quadro 17 – Código fonte do método readAudioFile que obtém as amostras e o formato de um
arquivo de áudio
Como a JavaSound fornece o sinal de áudio na forma de um array de bytes, é
necessário uma conversão para um tipo numérico, afim de que essa informação possa ser
interpretada nos cálculos do histograma e para que seja plotado de forma gráfica. Esta
conversão é realizada no momento da leitura de um arquivo pelo método
convertByteToFloat cujo código fonte pode ser visto no quadro 18.
47
/**
* Convert the buffer array of <code>bytes</code> into a buffer array of
* <code>float</code>, assuming a little endian order of bits. So, the
* new buffer array haves the half size of the original array.
*
* @return A new <code>float</code> array of the buffer.
*
* @param buffer
* The <code>byte</code> buffer to be converted.
*/
private float[] convertByteToFloat(byte[] buffer) {
// Half of the length
int length = buffer.length >> 1;
float[] data = new float[length];
for (int i = 0; i < length; i++) {
// Little endian order
data[i] = ((short) (((buffer[2 * i + 1] & 0xFF) << 8)
+ (buffer[2 * i] & 0xFF))) / ((float) Short.MAX_VALUE);
}
return data;
}
Quadro 18 – Código fonte do método convertByteToFloat que transforma um array de bytes em
um array de floats.
Para a gravação dos arquivos de áudio (ex: após ter sido capturado pelo microfone, ou
após ter sido aplicado o filtro), utiliza-se a classe AudioFileWritter, que também tem acesso
as classes da JavaSound. Assim, através do método saveAudioFile, é possível gravar um
sinal de áudio em arquivo, conforme pode-se ver no código fonte do método, apresentado no
quadro 19.
/**
* Create a new <code>.wav</code>, as the specified in the
* <code>{@link AudioFile}</code>, an save the sample data in the file.
*
* @param audioFile
* is the sample data and name of file to be created.
*/
public void saveAudioFile(AudioFile audioFile) {
byte[] data = convertFloatToByte(audioFile.getData());
try {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
AudioFormat format = new AudioFormat(audioFile.getSampleRate(), 16, 1, true,
false);
AudioInputStream ais = new AudioInputStream(bais, format, data.length >> 1);
File file = new File(audioFile.getFile());
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, file);
} catch (IOException e) {
e.printStackTrace();
}
}
Quadro 19 – Código fonte do método saveAudioFile que armazena um sinal de áudio em arquivo
Como na leitura foi necessário converter o array de bytes em um array de floats, na
gravação é necessário fazer o processo inverso, que é feito pelo método
convertFloatToByte, apresentado no quadro 20.
48
/**
* Converts a sample data signal, in a buffer os bytes, to be write in the
* file.
*
* @param sampleData
* original sample data.
* @return The signal, converted in a buffer of bytes
*/
private byte[] convertFloatToByte(float[] sampleData) {
byte[] data = new byte[sampleData.length << 1];
for (int i = 0; i < sampleData.length; i++) {
int temp = (short) (sampleData[i] * Short.MAX_VALUE);
data[i << 1] = (byte) temp;
data[(i << 1) + 1] = (byte) (temp >> 8);
}
return data;
}
Quadro 20 – Código fonte do método convertFloatToByte que transforma um array de floats em
um array de bytes
3.3.1.2 Captura de áudio pelo microfone
A captura do áudio do microfone é feita através da classe MicrophoneCapture que
utiliza a classe AudioInputStream da JavaSound para obter acesso as amostras do sinal de
áudio. O código fonte do método start pode ser visto no quadro 21.
A captura inicia quando o método start da classe MicrophoneCapture é chamado, e
só termina quando o método stop, também da classe MicrophoneCapture é chamado. Como
o processo necessita esperar até que o buffer de áudio seja preenchido, as chamadas a estes
métodos normalmente são realizadas em outra linha de execução (em outra thread).
Durante todo o processo de captura, sempre que o buffer fica cheio, um listener é
informado para que o buffer seja plotado, garantindo assim uma resposta visual do sinal de
áudio em tempo de execução.
49
/**
* Start the capture of the microphone. The read only will stop where the
* data line is stoped (called by <code>stop()</code> method).It's
* important make a call of this method in a new <code>Thread</code>,
* becase there is blocking method.
*
* @param captureListener
* The listener with be informed when a new audio is ready to be
* plotted.
* @param captureFormat
* The format with the audio is captured.
*/
public void start(CaptureListener captureListener, CaptureFormat captureFormat) {
this.captureListener = captureListener;
format = new AudioFormat(captureFormat.getSampleRate(), 16, 1, true, false);
try {
openAudioLine();
byte[] buffer = new byte[BUFFER_SAMPLES_SIZE];
signalVector = new Vector<Float>();
captureListener.newCaptureStarted(format.getSampleRate());
while (targetDataLine.isOpen()) {
while (audioInputStream.available() < buffer.length)
continue;
audioInputStream.read(buffer, 0, buffer.length);
float[] data = convertByteToFloat(buffer);
for (int i = 0; i < data.length; i++)
signalVector.add(data[i]);
captureListener.newValueCaptured(data);
}
} catch (Exception e) {
stop();
}
}
Quadro 21 – Código fonte do método start que inicia a captura do áudio do microfone
3.3.1.3 Reprodução de áudio
Toda a reprodução de áudio é feita através da classe AudioPlayer que se utiliza da
classe SourceDataLine da JavaSound para reproduzir um array de bytes. Para que um áudio
seja reproduzido, o método start é chamado, informando qual o formato de áudio será
reproduzido e em seguida é realizada a chamada ao método play, que reproduz o sinal de
áudio. Por fim o método stop é invocado, garantindo que o dispositivo de áudio seja liberado
corretamente. Os métodos start e play da classe AudioPlayer são apresentado no quadro
22.
50
/**
* Start the audio data line with the informed sample rate.
*
* @param sampleRate
* is the sample rate that the audio will play.
*/
public synchronized void start(float sampleRate) {
try {
AudioFormat format = new AudioFormat(sampleRate, 16, 1, true, false);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
dataLine = (SourceDataLine) AudioSystem.getLine(info);
dataLine.open(format, SAMPLE_BUFFER_SIZE);
dataLine.start();
} catch (LineUnavailableException e) {
if (dataLine != null)
dataLine.stop();
dataLine = null;
}
}
/**
* Reproduces the sample data informed, in the sample rate initialized.
*
* @param data
* is the sample data of signal that will be played.
*/
public void play(float[] data) {
if (dataLine != null) {
byte[] buffer = new byte[data.length << 1];
for (int i = 0; i < data.length; i++) {
short s = (short) (Short.MAX_VALUE * data[i]);
buffer[i << 1] = (byte) s;
buffer[(i << 1) + 1] = (byte) (s >> 8);
}
dataLine.write(buffer, 0, buffer.length);
} else {
throw new RuntimeException("The player has not been initialized");
}
}
Quadro 22 – Código fonte dos métodos start e play, responsáveis pela reprodução do áudio
3.3.1.4 Cálculo do histograma
Uma das formas de se calcular o histograma de qualquer sequência de dados, como por
exemplo, um sinal de áudio, é através das transformadas de Fourier que é implementada pela
classe FFT.
A transformada converte um sinal do domínio do tempo para o domínio da frequência,
utilizando para tanto número complexos. Estes números complexos e suas propriedades estão
modelados na classe Complex que é utilizada pela classe FFT.
Porém, para que um sinal seja convertido, quatro fatores devem ser observados:
a) o sinal de áudio obtido pela leitura do arquivo WAVE (item 3.3.1.1) e pela captura
do microfone (item 3.3.1.2) está em uma forma numérica simples, indicando
somente a amplitude no tempo, sendo necessário antes uma conversão para
números complexos;
b) a transformada rápida de Fourier trabalha com um número de amostras que deve
51
ser exponencial de dois, sendo assim necessário garantir que o sinal a ser
transformado esteja com um tamanho exponencial de dois;
c) o retorno da transformada é um array com o mesmo tamanho do sinal de entrada,
que representa na primeira metade, as frequências de zero até metade da taxa de
amostragem, porém, a outra metade do array, é um espelho destas frequências,
sendo assim desnecessárias;
d) o array fornecido pela transformada de Fourier é de número complexos, sendo
necessário obter o módulo deste número como forma de informação visual.
Para encapsular toda essas etapas, a interface FilterListener provê o método
toFrequencyDomain, que através de um sinal no domínio do tempo, informa os valores no
domínio da frequência. Este, e os outros método da FilterListener, são implementados
pela classe Converter.
O quadro 23 apresenta o código fonte do método fft, que é o responsável por executar
a transformada rápida de Fourier, transformando um sinal do domínio do tempo para o
domínio da frequência.
/**
* Compute the FFT of data, assuming its length is a power of 2
*
* @param data
* is the data to be calculed
*/
public Complex[] fft(Complex[] data) {
int N = data.length;
// base case
if (N == 1)
return new Complex[] { data[0] };
// radix 2 Cooley-Tukey FFT
if (N % 2 != 0)
throw new RuntimeException("N is not a power of 2");
// fft of even terms
Complex[] even = new Complex[N / 2];
for (int k = 0; k < N / 2; k++)
even[k] = data[2 * k];
Complex[] q = fft(even);
// fft of odd terms
Complex[] odd = even; // reuse the array
for (int k = 0; k < N / 2; k++)
odd[k] = data[2 * k + 1];
Complex[] r = fft(odd);
// combine
Complex[] y = new Complex[N];
for (int k = 0; k < N / 2; k++) {
double kth = -2 * k * Math.PI / N;
Complex wk = new Complex((float) Math.cos(kth), (float) Math.sin(kth));
y[k] = q[k].add(wk.mult(r[k]));
y[k + N / 2] = q[k].sub(wk.mult(r[k]));
}
return y;
}
Quadro 23 – Código fonte do método fft responsável pela conversão do sinal do domínio do tempo
para o domínio da frequência
O método interno, fillToPowerOfTwo se encarrega em garantir que o sinal tenha um
tamanho que seja exponencial de dois é apresentado no quadro 24.
52
/**
* Ensure that the sample data is power of two (to be used in FFT formula).
* If the size of the informed data, is not a power of two, create a new
* sample data, with the first size power of two biggest than the original
* size. After, fill with zeros the new positions. As a way to soften the
* difference, half of this new positions is created at the begin of the new
* sample data, and the other half, at the end of the sample data.
*
* @param data
* is the original sample data.
* @return a new sample data with size power of two
*/
private float[] fillToPowerOfTwo(float[] data) {
float[] resized = data;
if (data != null) {
int lenght = data.length;
// Calculate a new size power of two
int size = (int) Math.pow(2, Math.ceil(Math.log10(lenght) * 3.32));
if (size > lenght) {
resized = new float[size];
int halfDiference = (size - lenght) >> 1;
// Copy the original data and fill whith zero the new position
// Half of zeros at begin of array, and the other half at the
// end of array
for (int i = 0; i < size; i++) {
if (i < halfDiference || i > lenght + halfDiference - 1)
resized[i] = 0;
else
resized[i] = data[i - halfDiference];
}
}
}
return resized;
}
Quadro 24 – Código fonte do método fillToPowerOfTwo responsável por garantir um tamanho
exponencial de dois a um sinal
3.3.1.5 Criação do filtro de áudio
Conforme especificado no capítulo 3.2.2.4, a classe Converter implementando a
interface CoreInterface, se responsabiliza pela criação do filtro de áudio através do método
createFilter, cujo código fonte é apresentado no quadro 25.
53
@Override
public void createFilter() {
long time = System.currentTimeMillis();
AudioFilter audioFilter = new AudioFilter();
float[] filterWeights = new float[audioSources.getFilterFormat().getFilterSize()];
float[] sampleArray = new float[audioSources.getFilterFormat().getFilterSize()];
float[] speakerData = audioSources.getAudioData(Source.SPEAKER).getData();
float[] characterData = audioSources.getAudioData(Source.CHARACTER).getData();
int size = Math.min(speakerData.length, characterData.length);
progressListener.processStarted(audioSources.getFilterFormat().getAliasing(),
Constants.TEXT_PROGRESS_FILTER_CREATING);
float learningRate = ((float) audioSources.getFilterFormat().getLearningRate())
/ (1000 * FilterFormat.LEARNING_RATE_SCALE_MAX);
for (int c = 0; c < audioSources.getFilterFormat().getAliasing(); c++) {
for (int i = 0; i < size; i++) {
sampleArray = flowLineLeft(sampleArray, speakerData[i]);
filterWeights = adapteFilter(filterWeights, sampleArray, learningRate,
characterData[i] - dotProduct(filterWeights, sampleArray));
}
progressListener.nextStep();
}
progressListener.processFinished();
audioFilter.setWeights(filterWeights);
audioSources.setAudioFilter(audioFilter);
statusListener.filterCreated(System.currentTimeMillis() - time);
}
Quadro 25 – Código fonte do método createFilter que cria o filtro de áudio da ferramenta
Para cria o filtro, este método acessa as duas amostras de áudio que foram carregadas,
a amostra do locutor e a amostra do personagem, que estão armazenadas na instância de
AudioSources recebida pela interface.
A idéia é criar um buffer de filtro (com tamanho configurado pela FilterFormat) que
ajuste os pesos, comparando a saída que era esperada (áudio do personagem) com a entrada
informada (áudio do locutor). Assim, através da técnica do LMS, ajustam-se os pesos do filtro
para que este convirja o áudio de entrada no áudio de saída. Como o filtro é adaptativo a cada
nova interação, este processo é executado várias vezes (determinado pela configuração na
FilterFormat).
Para se obter a faixa de amostra utilizada na adaptação do filtro, utiliza-se o método
flowLineLeft, também da classe Converter, que adiciona a próxima amostra do sinal ao
final do buffer, empurrando as demais amostras para esquerda, processo muito conhecido na
computação por left shift, cujo código pode ser visto no quadro 26.
/**
* This method simulates a tapped delay line. It receives a reference to an
* array and a value. It discards the value at last index of the array,
* moves all the other values by one element to left, and inserts the new
* value at the final of the array.
*/
private float[] flowLineLeft(float[] array, float newValue) {
for (int i = 0; i < array.length - 1; i++)
array[i] = array[i + 1];
array[array.length - 1] = newValue;
return array;
}
Quadro 26 – Código fonte do método flowLineLeft que executa um left shift no array
Como o algoritmo LMS utiliza-se do produto escalar entre o vetor de pesos do filtro e
o vetor da faixa de amostras, utiliza-se o método dotProduct, também da classe Converter,
54
e cujo código fonte é apresentado no quadro 27.
/**
* This method receives two arrays, computes and returns the dot product of
* this two arrays.
*/
private float dotProduct(float[] array1, float[] array2) {
float result = 0;
if (array1.length == array2.length) {
for (int i = 0; i < array1.length; i++) {
result += array1[i] * array2[i];
}
}
return result;
}
Quadro 27 – Código fonte do método dotProduct que calcula o produto escalar entre dois vetores
O fórmula do algoritmo LMS, é encapsulado no método adapteFilter, e seu simples
código fonte é visto no quadro 28.
/**
* Apply the LMS algorithm in samples to correct the weights
*/
private float[] adapteFilter(float[] weights, float[] sampleArray, float learningRate, float
error) {
for (int i = 0; i < weights.length; i++)
weights[i] += learningRate * error * sampleArray[i];
return weights;
}
Quadro 28 – Código fonte do método adapteFilter que encapsula a fórmula do algoritmo LMS
3.3.1.6 Aplicação do filtro sobre outro sinal de voz
Outra responsabilidade da interface CoreInterface é a de aplicar o filtro
criado/carregado sobre um segundo áudio. Conforme visto anteriormente, a interface
CoreInterface é implementada pela classe Converter, e o método responsável pela
aplicação do filtro sobre o sinal de áudio é o método apllyFilter, cujo código fonte é
apresentado no quadro 29.
@Override
public void applyFilter() {
Source source = Source.EMULATED;
float[] output = audioSources.getAudioData(source).getData();
float[] newOutput = new float[output.length];
float[] weights = audioSources.getAudioFilter().getWeights();
float[] sampleArray = new float[weights.length];
progressListener.processStarted(output.length,Constants.TEXT_PROGRESS_FILTER_APPLYING);
for (int i = 0; i < output.length; i++) {
sampleArray = flowLineLeft(sampleArray, output[i]);
newOutput[i] = dotProduct(weights, sampleArray);
progressListener.nextStep();
}
progressListener.processFinished();
newOutput = normalize(newOutput);
float[] histogram = toFrequencyDomain(newOutput, true);
AudioFile audioFile = audioSources.getAudioData(source);
audioFile.setData(newOutput);
audioFile.setHistogram(histogram);
audioSources.setAudioData(source, audioFile);
}
Quadro 29 – Código fonte do método apllyFilter que aplica o filtro sobre o sinal de áudio
55
A aplicação do filtro se dá pelo mesmo princípio da criação do filtro. Como os pesos
foram ajustados para convergir o sinal de entrada (áudio do locutor) no sinal de saída (áudio
do personagem), basta simplesmente adotar a transformação que o filtro faz sobre os sinais
como sendo a versão emulada do sinal. Então, o método applyFilter acessa as amostras a
serem emuladas (armazenadas na instância de AudioSources da interface), e assume como
nova amostra do sinal de saída, o produto escalar entre os vetores do filtro e a faixa de
amostras de entrada (da mesma forma como o filtro é criado). O resultado é um sinal que
tenta convergir do sinal amostrado (segundo sinal do locutor) para o sinal desejado
(personagem).
3.3.1.7 Leitura e gravação do filtro de áudio
Para se realizar a leitura e/ou a gravação do filtro de áudio da ferramenta, é necessário
que todos os seus parâmetros sejam armazenados. Sendo a classe AudioFilter a responsável
por modelar o filtro de áudio da ferramenta, e esta implementar a interface Java,
Serializable, utiliza-se as mesmas classes responsáveis pela leitura e gravação dos sinais de
áudio (AudioFileReader e AudioFileWritter, respectivamente) para realizar a leitura e
gravação dos filtros de áudio, porém desta vez utilizando as classes ObjectInputStream e
ObjectOutputStream (ambas do Java) para acessar os dados.
O quadro 30 apresenta o código fonte do método readFilterFile da classe
AudioFileReader, que se responsabiliza pela leitura dos arquivos de filtro, enquanto o
quadro 31 apresenta o código fonte do método saveAudioFilter da classe
AudioFileWritter, que realiza a gravação dos arquivos.
56
/**
* Read a filter file and obtain your properties. This properties is storage
* in model <code>{@link AudioFilter}</code> with is returned.
*
* @param file
* The filter file to be read.
* @return Return a <code>{@link AudioFilter}</code> with the properties
* of the readed file.
*/
public AudioFilter readFilterFile(String file) {
AudioFilter filter = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(file);
ois = new ObjectInputStream(fis);
filter = (AudioFilter) ois.readObject();
} catch (Exception e) {
filter = null;
} finally {
try {
ois.close();
} catch (IOException e) {}
try {
fis.close();
} catch (IOException e) {}
}
return filter;
}
Quadro 30 – Código fonte do método readFilterFile que realiza a leitura de arquivos de filtro
/**
* create a new <code>.aef</code>, as the specified in the
* <code>{@link AudioFilter}</code>, an save the properties of the filter
* in the file.
*
* @param audioFilter
* is the properties of the filter and name of file to be
* created.
*/
public void saveAudioFilter(AudioFilter audioFilter) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
String fileName = audioFilter.getFile();
if (!fileName.endsWith(".aef"))
fileName += ".aef";
fos = new FileOutputStream(new File(fileName));
oos = new ObjectOutputStream(fos);
oos.writeObject(audioFilter);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
oos.close();
} catch (IOException e) {
}
try {
fos.close();
} catch (IOException e) {
}
}
}
Quadro 31 – Código fonte do método saveAudioFilter que grava os filtros em arquivo
3.3.2 Operacionalidade da implementação
Esta seção tem por objetivo mostrar a operacionalidade da implementação em nível de
57
usuário. Nas próximas seções serão abordadas todas as funcionalidades da ferramenta.
3.3.2.1 Conceitos de utilização
Visando facilitar a manipulação das amostras, a ferramenta foi dividida em quatro abas
(conforme a figura 23), uma para o áudio do locutor, uma para o áudio do personagem, uma
para o filtro de áudio e a última para o áudio emulado.
Figura 23 – Abas da ferramenta
A ferramenta possui diversos tipos de botões para suas operações e todos se localizam
na parte inferior das abas, como pode ser visto na figura 24. Nenhum botão da ferramenta
possui texto, somente uma imagem que expressa tal função, e um hint, que é apresentado ao
parar o mouse sobre o botão.
Figura 24 – Barra de botões da ferramenta
Sempre que uma tarefa é iniciada, uma caixa é apresentada (figura 25) informando o
progresso desta tarefa, bem como o tempo restante aproximado para a conclusão da mesma.
Esta caixa não pode ser fechada, sendo necessária a conclusão da tarefa antes de continuar a
utilizar a ferramenta.
Figura 25 – Caixa de progresso da ferramenta
Ao tentar carregar um arquivo (de áudio, ou de filtro), após o arquivo ter sido
selecionado, caso o arquivo não seja do tipo necessário (.wav para áudio e .aef para filtro),
será apresentado uma mensagem de erro. A figura 26 apresenta a mensagem de erro ao tentar
abrir um arquivo de áudio inválido, enquanto que a figura 27 apresenta a mensagem de
arquivo de filtro inválido.
58
Figura 26 – Arquivo de áudio inválido
Figura 27 – Arquivo de filtro inválido
3.3.2.2 Representação das amostras de áudio
Após um arquivo de áudio ter sido carregado, seu sinal será exibido de duas formas,
conforme a figura 28.
Figura 28 – Representação das amostras de um sinal no domínio do tempo e da frequência
Na parte superior, representado em verde, está o sinal representado no domínio do
tempo (forma mais conhecida de um sinal de áudio), onde também é possível visualizar a
duração total da amostra e o arquivo de onde esta amostra foi lida.
Na parte inferior, representado em azul, está o histograma do sinal, ou seja, sua
representação no domínio da frequência.
59
3.3.2.3 Representação do filtro de áudio
Como um filtro de áudio não passa de um vetor de coeficientes que serão
multiplicados ao sinal para modificá-lo, é praticamente impossível representar este de forma a
que possa ser visualizado sua real utilização. Assim o sinal apresentado é meramente
ilustrativo representando simplesmente os coeficientes do filtro e pode ser visto na figura 29.
Figura 29 – Representação do filtro de áudio
A única informação visível que pode ser obtida com esta representação é uma
aproximação do qual um sinal de áudio difere do outro, tendo em vista que com isto, os
coeficientes seriam gravemente alterados, resultando em uma representação com muitos picos
e vales.
3.3.2.4 Carregando uma amostra de áudio de um arquivo
Clicando sobre o ícone de carregar (segundo botão da figura 28) é aberta uma tela para
que o usuário selecione o arquivo que contenha as amostras de áudio (somente arquivos com
extensão .wav).
Outra forma de carregar uma amostra de áudio, é capturando diretamente do
60
microfone. Assim ao clicar sobre o ícone do microfone (primeiro botão da figura 28), é aberta
a tela de captura de microfone, que pode ser vista na figura 30.
Figura 30 – Tela de captura de microfone
Nesta tela, pode-se iniciar o processo de captura clicando sobre o primeiro botão. Isto
fará com que todo o áudio capturado pelo microfone seja armazenado internamente, para que
possa ser salvo depois. Sempre que o processo de captura é iniciado, tudo que havia sido
armazenado é descartado, ficando sempre com a última captura realizada.
Após o áudio ter sido capturado, será necessário salvar o mesmo em um arquivo, para
que a ferramenta possa ter acesso a todos os seus dados. Este processo de gravação pode ser
realizado clicando sobre o terceiro ícone da tela.
Após o arquivo ser salvo, a tela de captura será fechada e o sinal capturado será
carregado na ferramenta, como se tivesse sido recém carregado de um arquivo.
3.3.2.5 Configuração de captura
O único parâmetro de áudio que pode ser modificado para a captura do áudio na
ferramenta, é a taxa de amostragem (figura 31), que irá definir quantas amostras serão
capturadas em um único segundo.
61
Figura 31 - Configurações da captura
3.3.2.6 Criação do filtro
Para se criar um novo filtro de áudio, primeiramente é necessário que tanto o áudio do
locutor quanto o áudio do personagem já estejam previamente carregados. Será com base
nestes áudios que a ferramenta conseguirá determinar as diferenças entre eles, e assim criar o
filtro.
Após os áudios terem sido carregados, na aba do filtro, se localiza o botão de criação
de filtro (terceiro botão da figura 29). Caso os áudios não estejam carregados, este botão se
encontrará desabilitado. Ao ser pressionado, a tela de progresso será exibida informando o
tempo restante para a conclusão do filtro. Nota-se que o tempo necessário para a criação do
filtro é proporcional ao tamanho dos arquivos, e das configurações do filtro.
Outra forma de se obter um filtro é carregando este diretamente de um arquivo que
tenha sido previamente salvo pela ferramenta. Após a criação ou carregamento do filtro, será
possível aplicar o mesmo sobre um segundo arquivo de áudio, através da aba de emulação,
como mostra a seção 3.3.2.8.
3.3.2.7 Configuração do filtro
Atualmente na ferramenta, por utilizar o algoritmo LMS, existem três parâmetros que
podem ser configurados na tela de configuração de filtros (figura 32):
a) aliasing: também conhecido como serrilhamento. Define a quantidade de vezes
que o filtro será recalculado para que os pesos sejam mais bem definidos, fazendo
assim um amaciamento7 do sinal;
7 Processo conhecido por smoothing, deixando o sinal o mais senoidal possível.
62
b) tamanho do filtro: define a quantidade de pesos que o filtro utilizará. Uma maior
quantidade de pesos define uma maior abrangência das diferenças entre os sinais;
c) taxa de aprendizagem: define quanto o filtro deve convergir para o outro sinal.
Assim, uma baixa taxa fará com que o filtro tente convergir rapidamente ao outro
sinal, atingindo mais amostras, porém com a possibilidade de perder informações
no caminho. Da mesma forma, uma alta taxa fará com que o filtro convirja mais
devagar, porém levando em considerações mais detalhes nas diferenças entre os
dois sinais.
Figura 32 – Configuração do filtro
3.3.2.8 Aplicação do filtro
Após a criação/carregamento do filtro na aba do filtro, e o carregamento do segundo
arquivo de áudio na aba de emulação, é possível aplicar o filtro gerado/carregado sobre o
sinal. Para tanto, utiliza-se o botão de aplicação do filtro (quarto botão da figura 33) para
transformar o arquivo carregado em um novo sinal de áudio. A partir deste momento, pode-se
gravar o novo sinal de áudio, utilizando o botão correspondente.
Figura 33 - Botões de emulação
63
3.4 RESULTADOS E DISCUSSÃO
Segundo ROEDERER (2002), para a detecção do timbre humano necessita-se como
parâmetro somente de seis a oito harmônicos, ou seja, seria necessário encontrar a frequência
fundamental e em seguida os seus próximos harmônicos. No presente trabalho, após isto ter
sido feito, foram armazenados os pesos destas frequências, para que pudessem ser
comparadas com os pesos de outro sinal.
A ideia era comparar estes seis a oito valores de frequências, calcular a diferença, e
compensar esta diferença no primeiro histograma, para que pudesse ser aplicada uma IFFT, e
transformar o primeiro sinal no segundo.
Inicialmente foram realizados testes com a FFT para a obtenção das frequências
utilizadas em um sinal de áudio, para logo em seguida, aplicar-se a IFFT (processo inverso a
FFT, que traz novamente o sinal para o domínio do tempo) sobre o sinal. Esta simples
transformação ao domínio da frequência, e novamente ao domínio do tempo não apresentou
nenhuma perda de informações, uma vez que o algoritmo da FFT (e consequentemente da
IFFT) retorna um vetor de dados com a mesma quantidade de informações que o vetor de
entrada.
Para testar esta conjectura, foi utilizado o sintetizador da placa de som para gerar um
sinal de áudio bem comportado, cuja onda teria a forma senoidal. Assim, a aplicação da FFT
sobre esta onda senoidal simples, resultou em um histograma bem definido conforme era
esperado, com apenas uma das frequências com valor predominante, representando o
harmônico fundamental do sinal, sendo as outras tendendo a zero. A figura 34 ilustra este
caso.
Figura 34 - Histograma senóide simples
Em seguida, tentou-se reduzir o peso desta frequência principal e elevar o peso de
outra frequência, como se estivesse ―deslocando‖ o histograma, fazendo com que a senóide
64
que estava amostrada mudasse de frequência. O resultado pode ser visto na figura 35.
Figura 35 - Histograma senóide após mudar frequência
Com isso, após a aplicação da IFFT sobre este histograma, o resultado foi a criação de
uma nova onda senoidal com outra frequência (no caso a frequência que havia sido elevada a
amplitude), o que resultou em um som mais agudo quando se aumentava a frequência ou um
som mais grave quando se reduzia a frequência.
Utilizando ondas mais complexas, tendo uma frequência fundamental com peso
máximo, e seus harmônicos (frequências múltiplas da frequência fundamental) com pesos
menores, a aplicação da FFT, destacou exatamente as frequências utilizadas, ou seja, a
fundamental e suas frequências harmônicas (figura 36).
Figura 36 - Nota musical de uma harmônica
De forma análoga a uma senóide simples, em sinais complexos (com mais de uma
frequência) o histograma exibiu as frequências que estavam sendo utilizadas, porém agora
nem todas as frequências tendiam a zero. As frequências próximas aos picos de amplitude,
também possuíam um valor de amplitude elevada, fazendo com que gráfico do histograma
ficasse de certa forma mais suave (figura 37).
Isto resultou em um problema grande, pois agora ao invés de reduzir o peso das
frequências utilizadas e elevar o peso das frequências desejadas, tornou-se necessário
literalmente deslocar as frequências do histograma, fazendo com que estas frequências
próximas as frequências utilizadas também fossem alteradas.
65
Figura 37 - Histograma da vogal ―a‖
O problema de se fazer este deslocamento, é que se deslocarmos o histograma para a
direita, por exemplo, aumentando as frequências, as primeiras posições do vetor sumiam.
Assim, no novo sinal, tais frequências precisam ser criadas com peso zero. Além disso, as
últimas posições do vetor que guarda as frequências do histograma eram perdidas, pois eram
―sobrescritas‖ pelo deslocamento, e isso mudava o sinal resultante.
Com sinais de áudio de voz humana captada com microfone, na comparação entre dois
sinais diferentes (para se tentar encontrar uma forma de emular um sinal a partir do outro) o
problema encontrado foi o fato de as frequências fundamentais dos dois sinais normalmente
serem diferentes. Ou seja, enquanto o primeiro sinal possui uma frequência fundamental de,
por exemplo, 220 Hz (com os harmônicos em 440 Hz, 880 Hz, etc.), o segundo sinal poderia
conter uma frequência fundamental de, por exemplo, 300 Hz (com os harmônicos em 600 Hz,
900 Hz, etc.). Sendo as fundamentais diferentes, não se pode simplesmente guardar as
amplitudes de algumas frequências, sendo necessário trabalhar com todas.
Outro problema encontrado foi o fato de que para funcionar, a FFT necessita de um
vetor de amostras que tenha um tamanho exponencial de dois. Para que isso ocorra com todos
os sinais de áudio, os sinais cuja quantidade de amostras não se encaixe nesta regra precisa ter
o tamanho do seu vetor de amostras modificado, e estes novos espaços preenchidos com zero.
Para a apresentação do histograma, isso não gerava problemas, porém ao aplicar-se a IFFT
sobre este histograma, este trecho de silêncio aparece no sinal. Dependendo da quantidade de
amostras no sinal, o fato de completá-lo com zeros, pode fazer com que o sinal tenha um
longo período de silêncio, o que o torna algumas vezes muito diferente do sinal original. Por
exemplo, com um sinal original de 1025 amostras (210
+1 amostras), o sinal modificado deve
ter 2048 amostras (211
amostras) resultando num arquivo final com metade da sua duração em
silêncio. Nos testes realizados, a solução paleativa para contornar esse problema foi balancear
a inserção de amostras de valor zero, com metade sendo inserida no início e a outra metade no
final do vetor de amostras do sinal de áudio.
66
Com estes testes, a FFT se mostrou muito útil como forma de se verificar as
frequências utilizadas em sinal, porém para o caso do objetivo principal do presente trabalho,
em que foi manipular as amplitudes destas frequências, a IFFT não conseguiria resolver o
problema.
Em testes seguintes, numa tentativa de diminuir a diferença de tamanhos e frequências
fundamentais entre os dois sinais, foram usados áudios sintetizados de pianos, guitarras,
saxofones e violinos. Isto foi feito para minimizar a ocorrência de ruído externo, além do fato
de sons sintetizados geralmente terem formas de onda mais bem comportadas do que sinais de
áudio de voz humana. Isto foi comprovado empiricamente utilizando-se a ferramenta
implementada no presente trabalho. Para os testes subsequentes foram criados, por exemplo,
sinais de áudio da mesma nota musical em um piano (figura 38) e em uma guitarra elétrica
(figura 39), tendo assim as mesmas frequências, porém com o valor de peso de cada
frequência diferente em seus histogramas.
Figura 38 - Histograma de uma nota fá em um piano
Figura 39 - Histograma de uma nota fá em uma guitarra elétrica
Em todos os testes realizados, seja com áudios sintetizados, ou com áudio de vozes,
algum tipo de áudio foi gerado pela ferramenta, provando que o filtro manipulou o áudio e
gerou uma saída. Nos testes, pôde-se perceber a mudança do grave para o agudo e vice versa,
mostrando que o filtro leva para um caminho aproximado. Por exemplo, usando-se o som da
guitarra para gerar um filtro emulador, e submetendo o sinal de piano neste filtro, obteve-se
um sinal resultante com timbre mais agudo, portanto, tendendo a aproximar o timbre original
do piano ao timbre emulado da guitarra.
67
É importante ressaltar que os filtros são criados dinamicamente a partir de dois sinais
de entrada, o original, e o que se quer emular. O tempo de criação do filtro é diretamente
proporcional a dois parâmetros de criação de filtro na ferramenta, que são o aliasing e o
tamanho do filtro. O aliasing determina quantas iterações são requeridas para o algoritmo
gerador de filtro, recalculando e readaptando os seus pesos a cada nova iteração. O tamanho
do filtro indica quantos pesos diferentes são armazenados no filtro.
Em testes realizados, se utilizado as combinações de 100, 500 e 1000 iterações com
tamanhos de filtro de 100, 500 e 1000 espaços, em dois sinais de áudios quaisquer, cujo
menor áudio possuía uma duração de 13,66 segundos e ambos amostrados a 22 kHz
obtiveram-se os resultados apresentados na tabela 2.
Tabela 2 - Tempo necessário para a criação do filtro
Aliasing Tamanho Tempo
100 100 00 min 50 s
100 500 02 min 50 s
100 1000 05 min 40 s
500 100 03 min 00 s
500 500 14 min 40 s
500 1000 27 min 50 s
1000 100 05 min 50 s
1000 500 27 min 50 s
1000 1000 55 min 40 s
Os melhores resultados obtidos, aproximavam o primeiro sinal do sinal esperado,
porém o resultado não se mostrou ainda tão próximo ao ponto de não se conseguir distinguir o
sinal original do emulado. Já nos piores casos, o áudio resultante não se parecia nem com o
esperado, nem com o original.
Os testes realizados utilizando vozes sintetizadas mostraram que o filtro possui a
capacidade de convergir um timbre de voz em outro. Porém, devido às grandes diferenças
existentes entre os timbres de vozes, o sinal de voz depois de manipulado pelo filtro, ainda
não pode ser comparado a uma imitação. Isto acontece porque o filtro é adaptado a cada nova
iteração, e no decorrer desta adaptação, o próprio filtro acaba por generalizar algumas
diferenças entre os dois sinais de áudio, fazendo com que este se adapte acrescentando erro de
aproximação no processo, desconsiderando a real diferença entre os sinais. Isto pode ser
facilmente visualizado utilizando amostras de uma escala musical em dó maior completa (dó,
ré, mi, fá, sol, lá si). Devido à grande quantidade de frequências existentes, e
consequentemente a grande quantidade de diferenças, o filtro generaliza as diferenças, e o
resultado final quase sempre é um corte errôneo de algumas frequências que são necessárias
para a detecção do timbre daquele instrumento.
68
Porém, com amostras onde somente uma nota é emitida, existem poucas frequências
sendo utilizadas (a fundamental e suas harmônicas), fazendo com que o filtro não generalize
tanto as diferenças, e consiga obter um grau de aproximação maior.
Nos testes realizados com amostras de vozes humanas gravadas (não estando em um
ambiente controlado, como um estúdio), devido aos diferentes formatos de captura, tendo por
vezes nestes casos pequenos ruídos ao fundo, ou simplesmente uma baixa qualidade na
captura, somados a estas generalizações, o resultado muitas vezes é um som chiado, como em
uma transmissão de rádio. Isto porque o filtro acaba por eliminar algumas frequências
essenciais da produção da fala e elevar outras não tão importantes, como as do ruído do
ambiente.
Como o áudio gerado pela voz humana possui um número muito grande de variáveis,
incluindo características da dicção de cada pessoa e até do idioma falado, além do fato de que
a audição e a percepção humana são muito subjetivas, o grau de complexidade do trabalho é
elevado, fazendo com que o filtro criado pela ferramenta resolva somente partes do problema
de emulação de voz, ou seja, o filtro consegue generalizar se uma voz é mais grave ou aguda
que outra e de certa forma gerar esta diferenças, porém isto é feito de forma muito genérica
para todas as frequências, o que prejudica o resultado final. Porém, o presente trabalho mostra
que é possível manipular um sinal de áudio existente para alterar suas características de
identificação, ainda mantendo o sinal de áudio com características de voz humana.
69
4 CONCLUSÕES
Depois de estudada a problemática da detecção do timbre, verificou-se que os padrões
de ADSR somente contribuem na detecção do timbre da voz, da mesma forma como
contribuem para a afinação de instrumentos musicais.
A implementação da ferramenta contempla a comparação de dois sinais de áudio afim
de que seja utilizada a diferença entre os dois sinais como comparativo de erro com o sinal
desejado. Utilizando as ideias provenientes das redes neurais e dos filtros adaptativos (mais
especificamente, o LMS), criou-se um filtro onde o sinal desejado é um dos próprios sinais de
entrada, e ao invés de se remover um ruído (técnica LMS), utilizou-se o outro sinal de entrada
para obter a diferença, não a ser removida, e sim a ser somada, alterando o sinal para emular o
primeiro. Sendo isto arranjado de forma a executar várias vezes sobre os sinais, como se
fossem camadas de uma rede neural, foram criados filtros capazes de alterar o sinal original,
transformando seu timbre em outro.
Devido à grande dificuldade de se conseguir amostras de áudio com qualidade
profissional, ou seja, sem ruídos e sem música ambiente8, a ferramenta não pôde ser utilizada
em testes para a emulação de uma grande variedade de áudios diferentes, tais como áudios
infantis. Para isto seriam necessários arquivos gravados em estúdios de áudio especificamente
para o trabalho.
As ferramentas utilizadas se mostraram muito eficientes, principalmente o Eclipse
(ECLIPSE, 2007) onde todo o trabalho foi desenvolvido e o Enterprise Architect (SPARXS
SYSTEMS, 2008) que possibilitou a criação de grande parte do código fonte de forma
automática.
4.1 EXTENSÕES
Para futuras versões sugere-se o tratamento de dois sinais de áudio com diferentes
taxas de amostragem, abrangendo assim uma maior combinação de áudios de entrada para a
comparação e criação do filtro.
8 Em formato livre, somente foi encontrado arquivos de áudio com algum outro tipo de ruído ao fundo
70
Sugere-se também permitir a entrada de mais de uma fonte de sinal de uma mesma
voz, criando uma espécie de banco de vozes, possibilitando que o filtro possua uma maior
abrangência sobre o padrão de voz da pessoa em questão. Isto faria com que o filtro tendesse
a tratar melhor as diferenças entre os dois sinais de áudio.
Outra extensão seria utilizar mais de um filtro por emulação, dividindo-os, por
exemplo, em faixas de frequência, ou de amplitude do sinal. Isto objetiva fazer com que o
filtro não generalize as mudanças do padrão de voz e possa emular características como a
entonação da voz.
Outra possível melhoria é utilizar outros tipos de filtros adaptativos além do LMS,
permitindo assim que a ferramenta possa ser configurada da melhor forma para cada caso a
que esta é apresentada.
A aplicação do filtro em tempo real, para possibilitar que a voz seja emulada assim que
é capturada pelo microfone, podendo a ferramenta ser utilizada em conversas telefônicas e/ou
apresentações é outra extensão interessante.
Sugere-se também, a realização de testes com o locutor e o personagem lendo um texto
previamente preparado, possibilitando assim a captura específica das diferenças entre as
vozes.
Também se sugere a implementação dos cálculos de criação e aplicação do filtro por
hardware, utilizando DSPs por exemplo, para elevar a velocidade de processamento dos
sinais.
Por fim, sugere-se realizar testes em grande escala com amostras de áudio gravadas em
estúdio, de forma bem controlada, eliminando completamente qualquer tipo de ruído que
possa afetar o filtro, e utilizando vozes bem diferentes, como de crianças, idosos e outras.
71
REFERÊNCIAS BIBLIOGRÁFICAS
ADSR. In: WIKIPÉDIA, a enciclopédia livre. [S.l.]: Wikimedia Foundation, jan. 2008.
Disponível em: <http://pt.wikipedia.org/wiki/Adsr>. Acesso em: 23 ago. 2008.
AUDIO4FUN. Voice changer software. [S.l.], set. 2008. Disponível em:
<http://www.audio4fun.com/voice-over.htm>. Acesso em: 13 set. 2008.
BEGG, Rezaul; LAI, Daniel T. H.; PALANISWAMI, Marimuthu. Computational
intelligence in biomedical engineering. Boca Raton: CRC Press, 2007.
CARVALHO, Ricardo J. O. Blumenau, 31 mar. 2009. Entrevista concedida a Marcos
Rodrigo da Silva.
CATALDO, Edson; SAMPAIO, Rubens, NICOLATO, Lucas. Uma discussão sobre modelos
mecânicos de laringe para síntese de vogais. Engevista, Niterói, v. 6, n. 1, p. 47-57, abr. 2004.
Disponível em: <http://www.uff.br/engevista/11Engevista5.pdf>. Acesso em: 21 mar. 2009.
ECLIPSE FOUNDATION. Eclipse. Ottawa, 2007. Disponível em:
<http://www.eclipse.org/>. Acesso em: 1 fev. 2009.
FREQUÊNCIA. In: WIKIPÉDIA, a enciclopédia livre. [S.l]: Wikimedia Foundation, mar.
2009. Disponível em: <http://pt.wikipedia.org/wiki/Frequência>. Acesso em: 21 mar. 2009.
KAIN, Alexander; MACON, Michael W. Spectral voice conversion for text-to-speech
synthesis. In: THE INTERNATIONAL CONFERENCE ON ACOUSTICS, SPEECH, AND
SIGNAL PROCESSING, 1., 1998, Portland. Proceedings... Portland: Center for Spoken
Language Understanding, may 1998. p. 285-288. Disponível em:
<http://cslu.cse.ogi.edu/publications/ps/kain_ICASSP_98.pdf>. Acesso em: 21 set. 2008.
KHAN, Ashfaq A. Digital signal processing fundamentals. Hingham: Da Vinci Engineering
Press, 2005.
LEAST MEAN SQUARES FILTER. In WIKIPÉDIA, the free encyclopedia. [S.l.]:
Wikimedia Foundation, apr. 2009. Disponível em:
<http://en.wikipedia.org/wiki/Least_mean_squares_filter>. Acesso em: 03 abr. 2009.
MAZZONI, Dominic. Audacity. [S.l.], 2008. Disponível em:
<http://audacity.sourceforge.net/>. Acesso em: 13 set. 2008.
MOSER, Boris. Utilização da transformada de Fourier no tratamento de sinal para
utilização em uma rede neural. 1997. 58 f. Trabalho de Conclusão de Curso (Bacharelado
em Ciências da Computação) – Centro de Ciências Exatas e Naturais, Universidade Regional
de Blumenau, Blumenau.
72
NHC SOFTWARE. Wavepad sound editor. [S.l.], [2007?]. Disponível em:
<http://www.nch.com.au/wavepad/>. Acesso em: 13 set. 2008.
PEÑA CASANOVA, Jordã. Manual de fonoaudiologia. Porto Alegre: Artes Médicas, 1992.
PITZ, Ciro A. Blumenau, 7 abr. 2009. Entrevista concedida a Marcos Rodrigo da Silva.
PRIEMER, Roland. Introductory signal processing. Singapore: World Scientific, 1999.
ROADS, Curtis. The computer music tutorial. Cambridge: The MIT Press, 1996.
ROEDERER, Juan G. Introdução à física e psicofísica da música. Tradução Alberto Luis da
Cunha. São Paulo: Edusp, 2002.
RUMSEY, Francis; MCCORMICK, Tim. Sound and recording: an introduction. 5. ed.
Burlington: Focal Press, 2006.
RUSSELL, Stuart J.; NORVIG, Peter. Inteligência artificial. Rio de Janeiro: Campus, 2004.
RUSSO, Iêda C. P. Acústica e psicoacústica aplicadas à fonoaudiologia. 2. ed. São Paulo:
Lovise, 1999.
SANJAUME, Jordi B. Voice processing and synthesis by performance sampling and
spectral models. 2008. 251 f. Dissertation (Doctor per la Universitat Pompeo Fabra) -
Department of Information and Communication Technologies, Universitat Pompeo Fabra,
Barcelona. Disponível em: <http://www.mtg.upf.edu/static/media/PhD_jbonada.pdf>. Acesso
em: 23 fev. 2009.
SPARXS SYSTEMS. Enterprise Architect 7.0. Creswick, 2008. Disponível em:
<http://www.sparxsystems.com.au/>. Acesso em: 2 mar. 2009.
TAFNER, Malcon. Reconhecimento de palavras faladas isoladas usando redes neurais
artificiais. 1996. Não paginado. Dissertação (Mestrado em Engenharia de Produção) –
Programa de Pós-Graduação em Engenharia de Produção, Universidade Federal de Santa
Catarina, Florianópolis. Disponível em:
<http://www.eps.ufsc.br/disserta96/tafner/index/index.htm>. Acesso em: 27 out. 2008.
TAFNER, Malcon; XERES, Marcos; RODRIGUES FILHO, Ilson. Redes neurais artificiais:
introdução e princípios de neurocomputação. Blumenau: Editora da FURB, 1995.
TRANSFORMADA de Fourier. In: WIKIPÉDIA, a enciclopédia livre. [S.l.]: Wikimedia
Foundation, ago. 2008. Disponível em:
<http://pt.wikipedia.org/wiki/Transformada_de_Fourier>. Acesso em: 23 ago. 2008.
THE SONIC SPOT. Wave file format. [S.l.], [2007?]. Disponível em:
<http://www.sonicspot.com/guide/wavefiles.html>. Acesso em: 16 out. 2008.
73
UML. Unified modeling language specification: version 1.4. [S.l], 2002. Disponível em:
<http://www.omg.org>. Acesso em: 2 mar. 2009.
ZIPF, José G. F. Blumenau, 15 abr. 2009. Entrevista concedida a Marcos Rodrigo da Silva.