# Análise de áudio

O `AudioAnalysis` componente lê dados em tempo real de uma fonte de áudio a tocar na sua Scene, para que você possa controlar os visuais com a música. A cada frame, ele informa um **amplitude** valor e **8 frequency bands** (de baixo para alto) que você pode usar para escalar, colorir ou animar entities.

Usos comuns:

* Cubos que saltam com o baixo.
* Luzes que pulsam com a batida.
* Visualizadores de barras em estilo equalizer.
* Materials reativos ou props dimensionados que acompanham a música.

`AudioAnalysis` é um feed somente leitura — a sua Scene apenas consome os valores, e o runtime os preenche. Funciona em entities que reproduzem áudio por meio de um [AudioSource](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/sounds.md), um [AudioStream](/creator/content-creator-pt/scenes-sdk7/media/audio-streaming.md), ou o áudio de um [VideoPlayer](/creator/content-creator-pt/scenes-sdk7/media/video-playing.md).

## Exemplo mínimo

A seguinte Scene reproduz um som, anexa `AudioAnalysis` à mesma entity e escala um cubo em cada frame usando a amplitude do áudio.

```ts
import {
  engine,
  Transform,
  MeshRenderer,
  AudioSource,
  AudioAnalysis,
  AudioAnalysisView,
} from "@dcl/sdk/ecs";
import { Vector3 } from "@dcl/sdk/math";

export function main() {
  // Reproduzir um som numa entity
  const audioEntity = engine.addEntity();
  Transform.create(audioEntity);
  AudioSource.create(audioEntity, {
    audioClipUrl: "sounds/music.mp3",
    playing: true,
    loop: true,
  });

  // Anexar AudioAnalysis à mesma entity para começar a receber dados de análise
  AudioAnalysis.createAudioAnalysis(audioEntity);

  // Um objeto de view reutilizável no qual o componente vai escrever a cada frame
  const analysis: AudioAnalysisView = {
    amplitude: 0,
    bands: new Array<number>(8),
  };

  // Um cubo que pulsa com a amplitude do áudio
  const cube = engine.addEntity();
  MeshRenderer.setBox(cube);
  Transform.create(cube, { position: Vector3.create(8, 1, 8) });

  // A cada frame, ler os valores de análise mais recentes e escalar o cubo
  engine.addSystem(() => {
    AudioAnalysis.readIntoView(audioEntity, analysis);
    const s = 1 + analysis.amplitude * 10;
    Transform.getMutable(cube).scale = Vector3.create(s, s, s);
  });
}
```

As chamadas principais são:

1. `AudioAnalysis.createAudioAnalysis(entity)` — anexa o componente à entity que possui o `AudioSource`, `AudioStream`ou `VideoPlayer`. O padrão é o modo logarithmic (veja [Modes](#modes)).
2. `AudioAnalysis.readIntoView(entity, analysis)` — copia a `amplitude` e as 8 `bands` mais recentes para um objeto de view que você fornece.

{% hint style="warning" %}
**📔 Nota**: Sempre pré-aloque o `bands` array com **8 elements** antes de chamar `readIntoView`. O componente não redimensiona o array para você.
{% endhint %}

## Ler os dados a cada frame

`AudioAnalysis` foi projetado para ser lido uma vez por frame a partir de um system. O padrão recomendado é:

1. Alocar um único objeto `AudioAnalysisView` uma vez.
2. Num system, chame `readIntoView` para atualizá-lo.
3. Use os valores diretamente ou partilhe a view entre vários systems.

```ts
const analysis: AudioAnalysisView = {
  amplitude: 0,
  bands: new Array<number>(8),
};

engine.addSystem(() => {
  AudioAnalysis.readIntoView(audioEntity, analysis);
  // analysis.amplitude e analysis.bands[0..7] agora contêm os valores mais recentes
});
```

Se a entity analisada ainda não tiver um componente `AudioAnalysis` (por exemplo, ele é criado mais tarde ou removido dinamicamente), use `tryReadIntoView` em vez disso. Ele retorna `false` quando o componente está em falta, e `true` quando os valores foram escritos.

```ts
engine.addSystem(() => {
  if (!AudioAnalysis.tryReadIntoView(audioEntity, analysis)) return;
  // seguro usar analysis aqui
});
```

{% hint style="info" %}
**💡 Dica**: É mais barato chamar `readIntoView` uma vez e deixar vários systems partilharem o mesmo objeto de view do que ler o componente repetidamente.
{% endhint %}

## Reagir a bandas de frequência específicas

As 8 bandas cobrem o espectro audível do baixo ao alto. `bands[0]` é a mais baixa (bass) e `bands[7]` é a mais alta (treble). Você pode controlar different entities a partir de diferentes bands para construir um equalizer clássico.

```ts
import {
  engine,
  Transform,
  MeshRenderer,
  Material,
  AudioSource,
  AudioAnalysis,
  AudioAnalysisView,
  Schemas,
} from "@dcl/sdk/ecs";
import { Color4, Vector3 } from "@dcl/sdk/math";

// Componente personalizado para marcar cada barra e lembrar que banda ela acompanha
const VisualBar = engine.defineComponent("visual-bar", {
  index: Schemas.Number,
});

const BARS_HEIGHT = 12;

export function main() {
  const audioEntity = engine.addEntity();
  Transform.create(audioEntity);
  AudioSource.create(audioEntity, {
    audioClipUrl: "sounds/music.mp3",
    playing: true,
    loop: true,
  });
  AudioAnalysis.createAudioAnalysis(audioEntity);

  const analysis: AudioAnalysisView = {
    amplitude: 0,
    bands: new Array<number>(8),
  };

  // Criar 8 barras, uma por banda
  for (let i = 0; i < 8; i++) {
    const bar = engine.addEntity();
    VisualBar.create(bar, { index: i });
    Transform.create(bar, { position: Vector3.create(4 + i, 0, 8) });
    MeshRenderer.setBox(bar);
    Material.setPbrMaterial(bar, { albedoColor: Color4.Yellow() });
  }

  // Ler uma vez por frame
  engine.addSystem(() => {
    AudioAnalysis.readIntoView(audioEntity, analysis);
  });

  // Escalar cada barra com a sua banda
  engine.addSystem(() => {
    for (const [entity] of engine.getEntitiesWith(VisualBar, Transform)) {
      const index = VisualBar.get(entity).index;
      const transform = Transform.getMutable(entity);
      transform.scale = Vector3.create(
        1,
        analysis.bands[index] * BARS_HEIGHT,
        1
      );
    }
  });
}
```

Este é o mesmo padrão usado na [audio-visualization example scene](https://github.com/decentraland/sdk7-goerli-plaza/tree/main/audio-visualization), reduzido ao essencial.

## Modes

`AudioAnalysis` suporta dois modos de análise, definidos quando você cria o componente:

* `PBAudioAnalysisMode.MODE_LOGARITHMIC` (padrão): os valores são escalados com uma curva logarítmica, o que se aproxima mais de como a audição humana percebe mudanças de volume. Melhor para reatividade visual.
* `PBAudioAnalysisMode.MODE_RAW`: a amplitude e os valores das bandas FFT não processados. Use isto se quiser aplicar a sua própria escala.

```ts
import { AudioAnalysis, PBAudioAnalysisMode } from "@dcl/sdk/ecs";

// Usar valores raw
AudioAnalysis.createAudioAnalysis(audioEntity, PBAudioAnalysisMode.MODE_RAW);
```

### Ajustando o modo logarithmic

No modo logarithmic você pode passar dois multiplicadores de ganho opcionais:

* `amplitudeGain` — multiplicador aplicado à amplitude geral. O padrão é `5`.
* `bandsGain` — multiplicador aplicado a todas as 8 bands. O padrão é `0.05`.

Ganhos mais altos tornam os valores mais reativos; ganhos mais baixos tornam-nos mais subtis.

```ts
// Reação de amplitude mais forte, reação das bandas mais suave
AudioAnalysis.createAudioAnalysis(
  audioEntity,
  PBAudioAnalysisMode.MODE_LOGARITHMIC,
  10, // amplitudeGain
  0.03 // bandsGain
);
```

{% hint style="warning" %}
**📔 Nota**: `amplitudeGain` e `bandsGain` só se aplicam no modo logarithmic. No modo raw são ignorados.
{% endhint %}

## Substituir um componente existente

`createAudioAnalysis` falha se a entity já tiver um `AudioAnalysis` componente. Para alternar modos ou ganhos em runtime, use `createOrReplaceAudioAnalysis`, que tem a mesma assinatura.

```ts
// Mudar para o modo raw no meio da Scene
AudioAnalysis.createOrReplaceAudioAnalysis(
  audioEntity,
  PBAudioAnalysisMode.MODE_RAW
);
```

## Referência do componente

### `AudioAnalysis.createAudioAnalysis(entity, mode?, amplitudeGain?, bandsGain?)`

Anexa um componente `AudioAnalysis` a `entity`. Falha se já houver um componente presente.

* `entity` (`Entity`): a entity que possui o `AudioSource`, `AudioStream`ou `VideoPlayer` que você quer analisar.
* `mode` (`PBAudioAnalysisMode`, opcional): `MODE_LOGARITHMIC` (padrão) ou `MODE_RAW`.
* `amplitudeGain` (`number`, opcional): multiplicador de amplitude no modo logarithmic. Padrão `5`.
* `bandsGain` (`number`, opcional): multiplicador das bands no modo logarithmic. Padrão `0.05`.

### `AudioAnalysis.createOrReplaceAudioAnalysis(entity, mode?, amplitudeGain?, bandsGain?)`

Igual ao acima, mas substitui um `AudioAnalysis` componente existente na entity em vez de falhar.

### `AudioAnalysis.readIntoView(entity, out)`

Lê os valores mais recentes para `out`. Lança erro se `entity` não tiver um `AudioAnalysis` componente.

* `entity` (`Entity`): a entity com o componente.
* `out` (`AudioAnalysisView`): um objeto de view que você fornece. Deve estar `bands` pré-alocado com 8 numbers.

### `AudioAnalysis.tryReadIntoView(entity, out): boolean`

Igual a `readIntoView`, mas retorna `false` se a entity não tiver um `AudioAnalysis` componente em vez de lançar erro. Retorna `true` quando os valores são escritos.

### `AudioAnalysisView`

Um objeto simples que você aloca para receber os dados de análise:

```ts
type AudioAnalysisView = {
  amplitude: number; // força geral do sinal
  bands: number[]; // 8 frequency bands, baixo (0) a alto (7)
};
```

## Notas e limitações

* **8 bands, fixas.** O número de frequency bands é fixo em 8. Não há API para solicitar mais ou menos bands.
* **Uma fonte de áudio por análise.** Cada `AudioAnalysis` componente analisa o áudio da entity à qual está anexado. Para analisar várias fontes, anexe `AudioAnalysis` a cada uma.
* **Áudio pausado não reporta atualizações.** Quando o áudio subjacente é parado ou pausado, os valores do componente param de mudar. Os últimos valores lidos permanecem no seu objeto de view até o áudio tocar novamente.
* **Barato, mas não gratuito.** A análise por frame foi projetada para ser barata (menos de um milissegundo por fonte no desktop). Evite anexar `AudioAnalysis` a muitas fontes ao mesmo tempo se você não precisar dos dados. Remova o componente quando um visualizer não estiver visível.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/media/audio-analysis.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
