Clayton BorgesDESENVOLVEDOR
← ← Todos os Projetos

ASA Player – Visualizador de Música ASCII

2025
Creative Web Application / Audio Visualization

Player de música retrô com analisador de espectro ASCII 140×16 em tempo real, sistema de qualidade adaptativo, medidores VU, osciloscópio e efeitos visuais glitch — tudo construído com Web Audio API e Next.js.

Mídia
Visão Geral

ASA Player é um player de música com estética retrô que renderiza análise de áudio em tempo real como um espectro ASCII em uma grade de 140×16 caracteres, inspirado em analisadores de hardware vintage. Transmite faixas de um catálogo de label musical, analisa dados de frequência com a Web Audio API, e mapeia bins FFT para caracteres ASCII de forma logarítmica — correspondendo à forma como o ouvido humano realmente percebe altura. Cinco modos de visualização distintos compartilham um AudioContext, com uma camada de efeitos glitch independente do loop de áudio.

Problema

Players de música web existentes mostram ou nenhum visualizador ou gráficos genéricos de barras em canvas que parecem todos iguais. O objetivo era construir um player com uma estética forte e distinta — arte ASCII retrô combinada com análise de áudio em tempo real — sem sacrificar a correção técnica. A visualização de frequências na web geralmente usa mapeamento linear, que desperdiça colunas em frequências inaudíveis e comprime a faixa de graves musicalmente importante. O projeto precisava de uma solução que correspondesse à percepção auditiva humana.

Objetivo

Construir um player de música web de qualidade de produção que: (1) renderize um analisador de espectro ASCII ao vivo com mapeamento logarítmico de frequências; (2) suporte múltiplos modos de visualização a partir de um único grafo de áudio; (3) degrade graciosamente em dispositivos mais lentos via sistema de qualidade adaptativo; (4) mantenha uma estética glitch retrô coesa sem sacrificar legibilidade ou performance.

Meu Papel
  • ◈Desenvolvedor solo — engenharia de áudio, design de visualização, frontend, deploy
Stack
Next.js 15React 19TypeScriptWeb Audio APITailwind CSSRadix UI
Decisões Técnicas
  1. 01Mapeamento logarítmico de frequências — 140 colunas ASCII são mapeadas para 20Hz–22kHz usando escala log10. O índice do bin FFT de cada coluna é calculado como pow(10, logMin + (logRange × i) / (cols − 1)). Isso corresponde à escala musical (cada oitava recebe o mesmo espaço visual) e é como analisadores de hardware analógico funcionam. Um mapeamento linear dedicaria 75% das colunas a frequências acima de 5kHz que carregam poucas informações musicais.
  2. 02Sistema de qualidade adaptativo — 4 níveis de qualidade (ultra/alto/médio/baixo) alteram o tamanho FFT (512 → 64 bins) e a taxa de frames de visualização (20fps → 4fps). O FPS é monitorado com um histórico de 10 amostras; o downgrade automático dispara abaixo de 30fps. Isso mantém o app utilizável em dispositivos de médio desempenho sem uma configuração de qualidade fixa.
  3. 03Camada glitch separada com AdditiveBlending — os efeitos de scanlines, RGB shift e ruído estático rodam em um componente dedicado (glitch-noise-overlay.tsx) completamente desacoplado do loop de renderização de áudio. Usando CSS mix-blend-difference para o RGB shift, a camada glitch composita corretamente sobre qualquer cor de fundo sem cálculos JavaScript pixel a pixel.
  4. 04Import dinâmico com skeletons de carregamento — cada um dos 5 componentes de visualização é code-split via dynamic() do Next.js. O bundle JS inicial é mínimo; o visualizador circular pesado com Three.js só carrega se o usuário mudar para esse modo. Cada componente mostra um skeleton de carregamento temático ASCII durante o import.
  5. 05Uint8Array em todo o pipeline — getByteFrequencyData() da Web Audio API retorna Uint8Array nativamente. Todo o pipeline de dados de frequência mantém esse tipo (zero-copy do browser para a visualização), evitando pressão no GC por alocações de array a cada frame de animação.
  6. 06crossOrigin='anonymous' no elemento de áudio — necessário para que createMediaElementSource() da Web Audio API acesse dados de áudio de uma URL cross-origin. Sem esse atributo, o AnalyserNode conecta mas getByteFrequencyData() retorna zeros por restrições de segurança CORS.
O Que Aprendi
  • →O mapeamento logarítmico de frequências é inegociável para visualizações musicais — um mapeamento linear tornava as frequências de graves invisíveis e as agudas dominantes. Mudar para escala log transformou o analisador de um display tecnicamente correto mas musicalmente inútil em algo que realmente parece música.
  • →Sistemas de qualidade adaptativa precisam de dados reais de uso para calibrar os limiares — os limiares iniciais de FPS eram muito agressivos, fazendo usuários em hardware decente verem avisos desnecessários. Uma média móvel de 10 amostras e um cooldown de 5 segundos para avisos reduziu significativamente os falsos positivos.
  • →Desacoplar efeitos visuais do processamento de áudio evita bugs sutis de timing — versões iniciais tinham o overlay glitch no mesmo loop de renderização do analisador ASCII, causando drops de frames de glitch quando a computação FFT era custosa. Separar os dois eliminou o acoplamento.
  • →Imports dinâmicos mudam significativamente o tempo de carga percebido — adicionar skeletons de carregamento para cada modo de visualização fez o app parecer instantâneo mesmo quando o Three.js ainda estava carregando.
Status

Ativo — publicado no GitHub Pages