Do sinal ao earcon: experimentando áudio generativo com Python

python
Áudio
Áudio Generativo
Processamento de Sinais
NumPY
SciPy
Processo de criação dos áudios que são utilizados no app Volto Já!
Author

Daniela Carvalho

Published

September 9, 2026

Depois de trabalhar com pipelines de dados e Machine Learning, este laboratório parte de outro tipo de problema computacional: como transformar uma intenção comunicacional em um pequeno artefato sonoro gerado por código?

O estudo de caso surgiu durante o desenvolvimento do Volto Já!, um aplicativo que utiliza um temporizador lúdico para representar para uma criança o período em que ela deverá aguardar o retorno de seu responsável.

Além dos elementos visuais, o aplicativo precisava de uma identidade sonora coerente com essa proposta.

O problema não era simplesmente adicionar sons à interface.

Era necessário pensar em sons que fossem breves, reconhecíveis e funcionais, mas que não fossem abruptos, excessivamente agudos ou estimulantes. Como o aplicativo possui dois temas visuais — Sun e Cloud — surgiu também a possibilidade de transportar parte dessa diferenciação para o domínio sonoro.

Em vez de procurar arquivos de áudio prontos, optei por desenvolver esses elementos de maneira procedural utilizando Python.

O objetivo deste laboratório passou a ser, portanto, experimentar a construção de earcons gerados computacionalmente.

O termo earcon foi formado em inglês por analogia a icon (ícone), substituindo a referência visual implícita no termo pelo ear (ouvido). A palavra designa, portanto, uma espécie de “ícone para o ouvido”: enquanto um ícone comunica visualmente uma ação, estado ou significado em uma interface, um earcon utiliza um breve elemento sonoro para desempenhar função semelhante. Assim, um som pode indicar que uma ação foi executada, que um processo terminou ou que determinado evento ocorreu. Mais do que ornamentação, o earcon integra a linguagem da interface, construindo significado pela associação entre som, evento e contexto de interação.

O processo acabou mostrando que gerar um sinal tecnicamente correto é apenas uma parte do problema.

Intenção comunicacional
          ↓
Referência sonora
          ↓
Parâmetros
          ↓
Síntese procedural
          ↓
Processamento do sinal
          ↓
Arquivo WAV
          ↓
Validação técnica
          ↓
Escuta
          ↓
Avaliação perceptiva
          ↓
     ┌────┴────┐
     │         │
  adequado   inadequado
     │         │
     ↓         └──────→ nova iteração
 Earcon v01

1. Estrutura do laboratório

O laboratório foi criado dentro do repositório Python Especialista, mantendo a organização dos experimentos anteriores.

labs/
└── lab-generative-audio/

O projeto utiliza uv para gerenciamento do ambiente Python e das dependências.

Sua estrutura evoluiu para:

lab-generative-audio/
├── outputs/
│   └── earcons/
│       ├── cloud/
│       │   └── completion_v01.wav
│       ├── sun/
│       │   └── completion_v01.wav
│       └── ui/
│           └── button_press_v01.wav
│
├── src/
│   └── lab_generative_audio/
│       ├── __init__.py
│       ├── synthesis.py
│       └── earcons/
│           ├── __init__.py
│           ├── completion.py
│           └── interaction.py
│
├── tests/
│   ├── test_completion_earcon.py
│   └── test_synthesis.py
│
├── main.py
├── pyproject.toml
├── README.md
└── uv.lock

A estrutura separa três responsabilidades.

O arquivo synthesis.py concentra as primitivas utilizadas para a geração e processamento dos sinais.

O diretório earcons/ contém as regras utilizadas para transformar essas primitivas em elementos sonoros associados a eventos da interface.

outputs/ recebe os artefatos WAV produzidos pelo código.

Assim, o arquivo de áudio não é simplesmente um recurso incorporado ao projeto.

Ele é o resultado de um processo:

Código
  ↓
Parâmetros
  ↓
Síntese
  ↓
Processamento
  ↓
WAV

Essa característica permite modificar a identidade sonora alterando parâmetros e algoritmos, mantendo o processo que a produziu documentado e reproduzível.

2. Bibliotecas utilizadas

As principais bibliotecas utilizadas no laboratório foram:

NumPy
SciPy
Matplotlib
Pytest

O NumPy fornece as estruturas numéricas utilizadas para representar e manipular as amostras dos sinais.

O SciPy complementa esse processamento com recursos como filtros e escrita dos arquivos WAV.

O Matplotlib pode ser utilizado para observar graficamente os sinais gerados.

O Pytest foi incorporado para validar programaticamente algumas propriedades dos sinais e das funções de síntese.

A frequência de amostragem adotada foi:

SAMPLE_RATE = 44_100

Isso significa que cada segundo de áudio é representado por 44.100 amostras. O que popularmente se chamava de “qualidade de CD” para alta qualidade sonora.

Antes de desenvolver qualquer earcon, entretanto, era necessário verificar se essa cadeia básica de geração estava funcionando.

3. O primeiro sinal: uma senoide de 440 Hz

O primeiro experimento foi propositalmente simples.

Foi criada uma função capaz de gerar uma onda senoidal:

def sine_tone(
    frequency,
    duration,
    amplitude=0.3,
):
    ...

Para validar o funcionamento, gerei uma senoide de 440 Hz.

O resultado foi salvo como:

outputs/earcons/test_440hz.wav

A intenção ainda não era criar um elemento de interface.

Esse primeiro experimento permitia verificar uma cadeia muito mais fundamental:

frequência + duração + amplitude
              ↓
            NumPy
              ↓
        sinal digital
              ↓
             PCM
              ↓
             WAV

Foi nessa etapa que apareceu o primeiro problema do laboratório.

4. Quando “não ouvir” não significa “não existir”

Ao tentar reproduzir o arquivo pelo preview do ambiente de desenvolvimento, inicialmente tive a impressão de que nenhum som havia sido produzido.

Seria fácil interpretar isso como um problema no algoritmo de síntese.

Antes de alterar o código, entretanto, examinei o arquivo gerado.

O sinal apresentava aproximadamente:

sample rate: 44100 Hz
samples:     44100
min:         -9830
max:          9830
RMS:          ~6714.8

O arquivo também foi identificado corretamente como:

RIFF WAVE
PCM 16-bit
mono
44100 Hz

Portanto, havia um sinal.

A reprodução diretamente pelo sistema operacional confirmou o resultado:

aplay outputs/earcons/test_440hz.wav

A senoide estava audível.

O problema não estava na geração do áudio, mas na forma como o arquivo estava sendo reproduzido no ambiente.

Esse pequeno problema introduziu uma distinção que se tornou recorrente durante o laboratório:

um problema percebido durante a escuta não necessariamente corresponde a um problema no sinal ou no algoritmo que o produziu.

Era necessário separar validação técnica de avaliação perceptiva.

5. Do tom ao evento sonoro: trabalhando com envelopes

Uma senoide contínua ainda está distante de um som adequado para uma interface.

Para que um sinal seja percebido como um pequeno evento sonoro, é necessário controlar também a evolução de sua amplitude no tempo.

Foi então criada uma função para aplicação de envelope:

apply_envelope(...)

De maneira simplificada:

Amplitude
   ▲
   │       /──────\
   │      /        \
   │     /          \
   │    /            \
   └────────────────────► tempo
       attack       release

O attack controla como o som aparece.

O release controla como ele desaparece.

Essas transições são importantes porque iniciar ou interromper uma forma de onda abruptamente pode introduzir uma percepção excessivamente mecânica ou pequenos clicks.

Nesse momento, o laboratório começava a deixar de tratar apenas da geração de sinais para trabalhar também com design sonoro procedural.

6. O primeiro earcon: conclusão do temporizador

Com as primitivas básicas funcionando, passei ao primeiro evento real do aplicativo.

O evento escolhido foi:

o temporizador terminou.

Foi criado um módulo específico:

src/lab_generative_audio/earcons/completion.py

A ideia era utilizar relações entre frequências para produzir um evento breve com sensação de conclusão.

Entre os experimentos realizados, uma relação mostrou-se adequada para o tema Sun:

C5 → E5

O resultado passou a ser gerado em:

outputs/earcons/sun/completion_v01.wav

A sequência ascendente produziu uma sensação mais clara e resolutiva, coerente com a atmosfera visual do tema.

Mas o aplicativo possuía ainda uma segunda atmosfera.

7. Sun e Cloud: uma mesma função, duas identidades

O Volto Já! possui dois temas visuais: Sun e Cloud.

A questão passou a ser se essa diferenciação visual também poderia aparecer na identidade sonora.

Para o tema Cloud, foi experimentada uma relação em uma região mais baixa:

G4 → C5

O resultado foi percebido como mais suave e acolhedor.

Os artefatos passaram então a ser organizados como:

completion
├── sun
│   └── completion_v01.wav
└── cloud
    └── completion_v01.wav

Conceitualmente, entretanto, os dois arquivos representam o mesmo evento:

                  COMPLETION
                  /        \
                 /          \
              SUN           CLOUD
               ↓              ↓
           C5 → E5        G4 → C5

A função comunicacional permanece a mesma: informar que o período terminou.

O que muda é a maneira como esse evento é sonoramente apresentado.

Essa experimentação também evidencia que a interpretação de um earcon não está necessariamente contida apenas no arquivo sonoro. Ela emerge da relação entre o som, o evento que representa e o contexto audiovisual em que ocorre.

8. Um segundo problema: o som da interação

Depois dos sons de conclusão, passei para um evento aparentemente mais simples:

pressionar um botão ou ícone.

Foi criado:

src/lab_generative_audio/earcons/interaction.py

A intenção era produzir um som muito breve e delicado.

Inicialmente imaginei algo semelhante a um pequeno:

"plac"

O primeiro caminho foi utilizar uma síntese do tipo soft_pluck.

Tecnicamente, o sinal era curto, possuía baixa amplitude e envelope controlado.

Perceptivamente, entretanto, havia um problema.

O resultado parecia um som de erro.

Essa avaliação alterou o desenvolvimento.

Não bastava diminuir o volume ou tornar o envelope matematicamente mais suave. Era necessário mudar a natureza do timbre.

9. Tentando produzir uma pequena onda

A tentativa seguinte abandonou o caráter excessivamente percussivo.

A referência passou a ser algo mais sereno, semelhante a uma pequena onda.

Foi experimentada uma combinação de:

senoide
   +
ruído
   +
filtro
   +
envelope

O ruído foi filtrado para retirar parte de seu conteúdo espectral e combinado a uma componente tonal.

O objetivo era produzir um movimento sonoro mais macio.

Novamente, entretanto, a avaliação perceptiva contrariou a intenção inicial.

O resultado lembrava um pequeno choque elétrico.

O sinal estava correto.

O processamento estava funcionando.

Mas a associação produzida durante a escuta estava distante da função pretendida.

10. Uma tentativa tonal de produzir o “plaaack”

A experiência seguinte voltou à ideia inicial do “plac”, mas eliminando o ruído.

Foi criada uma versão mais arredondada utilizando uma frequência fundamental e uma quinta com menor intensidade.

A intenção era produzir mais corpo tonal e reduzir o caráter eletrônico das experiências anteriores.

O resultado melhorou algumas propriedades acústicas, mas permaneceu associado a um som de erro.

Nesse momento, ficou evidente que o problema talvez não estivesse apenas nos parâmetros.

A própria referência sonora precisava mudar.

11. Do conceito abstrato para uma referência material

Até esse ponto, a referência utilizada era essencialmente verbal:

um som suave de botão.

Expressões como “suave”, “delicado” ou “sereno” descrevem uma intenção, mas não determinam necessariamente uma estrutura acústica.

A nova referência passou a ser muito mais concreta:

um chocalho de bebê, mas muito breve.

A mudança foi importante.

Em vez de tentar produzir um tom agradável, passei a buscar características de um pequeno objeto físico.

Foi criada então uma função:

baby_rattle(...)

Dessa vez, o elemento principal deixou de ser uma senoide.

O ponto de partida foi ruído:

noise = rng.normal(
    0.0,
    1.0,
    samples,
)

O ruído contém uma quantidade muito ampla de frequências. Por isso, ele foi submetido a um filtro passa-faixa.

sos = butter(
    2,
    [700, 2200],
    btype="bandpass",
    fs=SAMPLE_RATE,
    output="sos",
)

O filtro mantém principalmente uma região intermediária do espectro.

Depois, pequenas pulsações foram utilizadas para sugerir o movimento dos elementos internos de um chocalho.

O processo passou a ser aproximadamente:

ruído
  ↓
filtro passa-faixa
  ↓
modulação
  ↓
envelope
  ↓
normalização
  ↓
microchocalho

O som foi mantido deliberadamente curto:

duration=0.16

e com amplitude reduzida:

amplitude=0.045

Dessa vez, a referência material aproximou o resultado da intenção comunicacional.

O som foi adotado como primeira versão do earcon de interação.

12. A primeira identidade sonora

Ao final dessas iterações, o laboratório chegou a três artefatos principais:

outputs/earcons/
│
├── sun/
│   └── completion_v01.wav
│
├── cloud/
│   └── completion_v01.wav
│
└── ui/
    └── button_press_v01.wav

As decisões podem ser resumidas da seguinte forma:

Evento Solução Intenção
Conclusão — Sun C5 → E5 clara e resolutiva
Conclusão — Cloud G4 → C5 suave e acolhedora
Interação de UI microchocalho breve, orgânico e delicado

Esses sons foram congelados como versão 01.

Isso não significa que sejam versões definitivas.

A decisão de interromper temporariamente a experimentação também faz parte do processo.

Ouvir repetidamente um arquivo WAV isolado não reproduz a experiência real da interface. A próxima etapa de avaliação deve ocorrer no contexto do aplicativo, considerando elementos como volume do dispositivo, frequência de repetição, relação com a animação e coexistência com os demais sons.

13. Testando áudio generativo com Pytest

O laboratório também recebeu testes automatizados.

Durante a configuração inicial dos testes, apareceu o erro:

ModuleNotFoundError: No module named 'src'

O Pytest não estava encontrando corretamente os módulos do projeto.

A configuração foi adicionada ao pyproject.toml:

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["."]
addopts = "-v"

Depois disso, a suíte pôde ser executada com:

uv run pytest

obtendo:

3 passed

Os testes verificam propriedades objetivas da geração dos sinais.

Entre as características que podem ser verificadas programaticamente estão:

duração
número de amostras
amplitude
dimensionalidade
existência do sinal
estrutura do artefato gerado

Entretanto, surgiu uma limitação particularmente interessante.

O teste pode determinar se existe um sinal.

Ele pode verificar sua amplitude.

Pode verificar sua duração.

Pode inclusive analisar propriedades espectrais.

Mas ele não consegue determinar diretamente se aquele som será percebido como:

acolhedor
sereno
infantil
agressivo
erro
choque elétrico

Essas categorias pertencem a outra camada de avaliação.

14. Validação técnica e avaliação perceptiva

O desenvolvimento dos earcons acabou evidenciando duas formas diferentes de avaliação.

A primeira é técnica:

Sinal
  ↓
Existe?
  ↓
Possui duração correta?
  ↓
Amplitude está dentro dos limites?
  ↓
WAV foi produzido corretamente?

A segunda é perceptiva:

Som
  ↓
Como é percebido?
  ↓
Produz a associação pretendida?
  ↓
É coerente com o evento?
  ↓
É coerente com a interface?

Durante o laboratório, vários sinais passaram pela primeira avaliação e falharam na segunda.

O soft_pluck funcionava.

A pequena onda sintética funcionava.

O soft_plack funcionava.

Mas “funcionar” computacionalmente não significava atender à intenção comunicacional.

Foi somente quando a referência mudou para um objeto reconhecível — o chocalho — que o resultado se aproximou do comportamento desejado.

Isso transforma o processo em um ciclo:

Intenção
   ↓
Modelagem
   ↓
Síntese
   ↓
Sinal
   ↓
Validação técnica
   ↓
Escuta
   ↓
Avaliação perceptiva
   │
   ├── adequada ──────→ versão
   │
   └── inadequada
           ↓
     nova referência
           ↓
      novos parâmetros
           ↓
         síntese

15. Do áudio generativo ao design sonoro procedural

Inicialmente, este laboratório parecia tratar principalmente da geração de arquivos WAV com Python.

Durante o desenvolvimento, entretanto, o problema mostrou-se mais amplo.

Uma frequência é um parâmetro.

Uma duração é um parâmetro.

Um filtro possui parâmetros.

Um envelope também pode ser descrito matematicamente.

Mas o objetivo final não era produzir frequências, filtros ou envelopes.

Era produzir um evento sonoro capaz de desempenhar uma função dentro de uma interface.

O fluxo, portanto, não termina na geração do sinal:

Parâmetros computacionais
          ↓
     propriedades
       acústicas
          ↓
       percepção
          ↓
      significado
          ↓
função na interface

Essa relação também ajuda a explicar por que pequenas alterações de síntese podem modificar substancialmente a interpretação de um som.

Um sinal pode ser curto e de baixa amplitude e ainda parecer um erro.

Pode possuir envelope suave e ainda lembrar um choque elétrico.

Da mesma forma, um fragmento de ruído cuidadosamente filtrado pode produzir uma associação mais acolhedora do que uma sequência tonal harmonicamente organizada.

16. Um artefato computacional e comunicacional

Os arquivos WAV resultantes deste laboratório podem ser vistos como artefatos computacionais.

Eles são produzidos a partir de código, parâmetros, funções matemáticas e processamento digital de sinais.

Mas são também artefatos comunicacionais.

Código
  ↓
Sinal
  ↓
Som
  ↓
Percepção
  ↓
Significado
  ↓
Interação

É justamente nessa passagem entre o sinal produzido pela máquina e o significado construído durante a interação que o experimento se torna particularmente interessante.

No laboratório anterior, de Machine Learning, o fluxo podia ser resumido aproximadamente como:

dados
  ↓
transformação
  ↓
modelo
  ↓
previsão
  ↓
métricas
  ↓
visualização

Neste laboratório, a estrutura assume outra forma:

intenção
  ↓
parâmetros
  ↓
síntese
  ↓
sinal
  ↓
percepção
  ↓
avaliação
  ↓
nova iteração

Nos dois casos existe um fluxo computacional.

Mas, no áudio generativo, uma parte importante da avaliação retorna necessariamente ao domínio perceptivo.

O resultado não é apenas aquilo que o algoritmo gera.

É também aquilo que se escuta.

Reproduzindo o laboratório

O código-fonte deste experimento está disponível no repositório Python Especialista, no diretório: https://github.com/danicarvalhomf/python-especialista/tree/main/labs/lab-generative-audio

labs/lab-generative-audio

Para configurar o ambiente, gerar os arquivos de áudio e executar os testes, consulte o README.md do laboratório.

Os arquivos WAV são produzidos pelo próprio código e armazenados em outputs/earcons/, permitindo reproduzir os experimentos e modificar os parâmetros utilizados na síntese.

Para conhecer mais sobre áudio digital

Este laboratório parte de alguns conceitos fundamentais de áudio digital, como amostragem, representação numérica do sinal, PCM e arquivos WAV, que não foram aprofundados neste texto. Para quem quiser conhecer melhor esses fundamentos e sua relação com a circulação do áudio em ambientes digitais, o livro O Áudio na Internet está disponível para download gratuito no site Áudio na Internet — Download gratuito do livro.

Uso do áudio generativo

A primeira versão da identidade sonora contempla três situações:

Sun completion
Cloud completion
UI interaction

A etapa seguinte não foi, necessariamente, adicionar novos algoritmos de síntese.

Os earcons precisaram ser incorporados ao Volto Já! e avaliados no contexto em que efetivamente serão utilizados.

Essa etapa permitiu observar aspectos que não aparecem quando o WAV é escutado isoladamente:

  • relação entre som e animação;
  • intensidade percebida nos alto-falantes de um smartphone;
  • comportamento quando um botão é pressionado repetidamente;
  • diferença entre os temas Sun e Cloud;
  • coerência entre os diferentes eventos sonoros;
  • necessidade de ajustes de duração, amplitude e timbre.

A partir dessa avaliação, os parâmetros pode retornar ao laboratório para uma nova iteração.

Python
   ↓
Earcon
   ↓
Aplicativo
   ↓
Experiência
   ↓
Avaliação
   ↓
Python

O áudio generativo passa, assim, a integrar não apenas uma etapa de produção de assets, mas um processo iterativo entre síntese computacional, design sonoro e experiência de interação.