> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/mei-ti/audio-analysis.md).

# 音频分析

读取场景中正在播放的音频的实时振幅和频率数据，以驱动响应式视觉效果。

该 `音频分析` 该组件从场景中正在播放的音频源实时读取数据，因此你可以用音乐驱动视觉效果。每一帧，它会报告一个整体的 **振幅** 值以及 **8 个频段** （从低到高），你可以用来缩放、着色或为实体添加动画。

常见用途：

* 随低音弹跳的立方体。
* 随节拍脉动的灯光。
* 均衡器风格的条形可视化。
* 与音乐同步反应的材质或缩放道具。

`音频分析` 是一个只读数据源——你的场景只会读取这些值，由运行时填充。它适用于通过一个 [AudioSource](/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/sounds.md)，一个 [AudioStream](/creator/content-creator-zh/chang-jing-sdk7/mei-ti/audio-streaming.md)，或一个 [VideoPlayer](/creator/content-creator-zh/chang-jing-sdk7/mei-ti/video-playing.md).

{% hint style="warning" %}
**📔 注意**: `音频分析` 目前仅受官方 Decentraland 桌面应用支持。在其他客户端中，该组件的值不会被填充，因此请确保即使数据始终未到达，你的场景也仍能正常运行。
{% endhint %}

## 最小示例

以下场景会播放一个声音，并将 `音频分析` 添加到同一个实体上，并在每一帧使用音频的振幅来缩放一个立方体。

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

export function main() {
  // 在实体上播放声音
  const audioEntity = engine.addEntity();
  Transform.create(audioEntity);
  AudioSource.create(audioEntity, {
    audioClipUrl: "sounds/music.mp3",
    playing: true,
    loop: true,
  });

  // 将 AudioAnalysis 附加到同一实体，以开始接收分析数据
  AudioAnalysis.createAudioAnalysis(audioEntity);

  // 组件会在每一帧写入的可复用视图对象
  const analysis: AudioAnalysisView = {
    amplitude: 0,
    bands: new Array<number>(8),
  };

  // 一个会随音频振幅脉动的立方体
  const cube = engine.addEntity();
  MeshRenderer.setBox(cube);
  Transform.create(cube, { position: Vector3.create(8, 1, 8) });

  // 每一帧读取最新的分析值并缩放立方体
  engine.addSystem(() => {
    AudioAnalysis.readIntoView(audioEntity, analysis);
    const s = 1 + analysis.amplitude * 10;
    Transform.getMutable(cube).scale = Vector3.create(s, s, s);
  });
}
```

关键调用如下：

1. `AudioAnalysis.createAudioAnalysis(entity)` ——将该组件附加到拥有该 `AudioSource`, `AudioStream`，或 `VideoPlayer`。默认使用对数模式（参见 [模式](#modes)).
2. `AudioAnalysis.readIntoView(entity, analysis)` ——复制最新的 `振幅` 以及 8 个 `频段` 值到你提供的视图对象中。

{% hint style="warning" %}
**📔 注意**：在调用 `频段` 数组之前，始终预先分配 **8 个元素** 后再调用 `readIntoView`。该组件不会为你调整数组大小。
{% endhint %}

## 每帧读取数据

`音频分析` 设计为在系统中每帧读取一次。推荐模式如下：

1. 只分配一个 `AudioAnalysisView` 对象即可。
2. 在系统中调用 `readIntoView` 来刷新它。
3. 直接使用这些值，或在多个系统之间共享该视图。

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

engine.addSystem(() => {
  AudioAnalysis.readIntoView(audioEntity, analysis);
  // analysis.amplitude 和 analysis.bands[0..7] 现在保存着最新值
});
```

如果被分析的实体可能尚未拥有一个 `音频分析` 组件（例如，它稍后才创建或被动态移除），请使用 `tryReadIntoView` 代替。它会在 `false` 当组件缺失时返回，且 `真` 当值被写入时返回。

```ts
engine.addSystem(() => {
  if (!AudioAnalysis.tryReadIntoView(audioEntity, analysis)) return;
  // 这里可以安全使用 analysis
});
```

{% hint style="info" %}
**💡 提示**：调用 `readIntoView` 一次并让多个系统共享同一个视图对象，比反复读取组件更省开销。
{% endhint %}

## 响应特定频段

这 8 个频段覆盖了从低到高的可听频谱。 `bands[0]` 是最低的（低音），而 `bands[7]` 是最高的（高音）。你可以用不同频段驱动不同实体，构建经典均衡器。

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

// 自定义组件，用于标记每个条形并记住它跟踪的是哪个频段
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),
  };

  // 创建 8 个条形，每个频段一个
  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() });
  }

  // 每帧读取一次
  engine.addSystem(() => {
    AudioAnalysis.readIntoView(audioEntity, analysis);
  });

  // 用各自的频段缩放每个条形
  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
      );
    }
  });
}
```

这与在 [音频可视化示例场景](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/88,-10-audio-visualization)中使用的模式相同，

## 模式

`音频分析` 支持两种分析模式，在创建组件时设置：

* `PBAudioAnalysisMode.MODE_LOGARITHMIC` （默认）：值会使用对数曲线缩放，这种感觉更接近人耳感知音量变化的方式。最适合视觉响应。
* `PBAudioAnalysisMode.MODE_RAW`：未处理的振幅和 FFT 频段值。如果你想应用自己的缩放方式，请使用此模式。

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

// 使用原始值
AudioAnalysis.createAudioAnalysis(audioEntity, PBAudioAnalysisMode.MODE_RAW);
```

### 调整对数模式

在对数模式下，你可以传入两个可选的增益倍数：

* `amplitudeGain` ——应用于整体振幅的乘数。默认为 `5`.
* `bandsGain` ——应用于全部 8 个频段的乘数。默认为 `0.05`.

较高的增益会让数值更灵敏；较低的增益会让它们更细腻。

```ts
// 更强的振幅响应，更柔和的频段响应
AudioAnalysis.createAudioAnalysis(
  audioEntity,
  PBAudioAnalysisMode.MODE_LOGARITHMIC,
  10, // amplitudeGain
  0.03 // bandsGain
);
```

{% hint style="warning" %}
**📔 注意**: `amplitudeGain` 和 `bandsGain` 仅在对数模式下生效。在原始模式下会被忽略。
{% endhint %}

## 替换现有组件

`createAudioAnalysis` 如果实体已经拥有一个 `音频分析` 组件，则会失败。要在运行时切换模式或增益，请使用 `createOrReplaceAudioAnalysis`，其签名相同。

```ts
// 在场景运行中切换到原始模式
AudioAnalysis.createOrReplaceAudioAnalysis(
  audioEntity,
  PBAudioAnalysisMode.MODE_RAW
);
```

## 组件参考

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

附加一个 `音频分析` 组件的 `实体`。如果已存在组件则失败。

* `实体` (`Entity`）：拥有该 `AudioSource`, `AudioStream`，或 `VideoPlayer` 你想要分析的实体。
* `模式` (`PBAudioAnalysisMode`，可选）： `MODE_LOGARITHMIC` （默认）或 `MODE_RAW`.
* `amplitudeGain` (`数字`，可选）：对数模式下的振幅乘数。默认为 `5`.
* `bandsGain` (`数字`，可选）：对数模式下的频段乘数。默认为 `0.05`.

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

与上面相同，但会替换已有的 `音频分析` 组件，而不是失败。

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

将最新值读取到 `out`。如果 `实体` 没有一个 `音频分析` 组件。

* `实体` (`Entity`）：带有该组件的实体。
* `out` (`AudioAnalysisView`）：你提供的视图对象。必须具有 `频段` 预先分配的 8 个数字。

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

与 `readIntoView`相同 `false` 如果实体没有 `音频分析` 组件时返回，而不是抛出异常。返回 `真` 当值被写入时返回。

### `AudioAnalysisView`

你分配的普通对象，用于接收分析数据：

```ts
type AudioAnalysisView = {
  amplitude: number; // 整体信号强度
  bands: number[]; // 8 个频段，从低（0）到高（7）
};
```

## 注意事项和限制

* **8 个频段，固定。** 频段数量固定为 8。没有 API 可以请求更多或更少的频段。
* **每次分析对应一个音频源。** 每个 `音频分析` 组件会分析它所附加到的实体的音频。要分析多个音频源，请为每个音频源附加 `音频分析` 到每一个上。
* **实时视频流不会被分析。** 存在一个已知问题，即 `音频分析` 当 `VideoPlayer` 音源是非渐进式流，例如一个 `.m3u8` HLS URL：流的音频会播放，但分析值保持为零。视频文件（例如 `.mp4`）则会被正确分析。
* **暂停的音频不会报告更新。** 当底层音频停止或暂停时，该组件的值会停止变化。在音频再次播放前，你最后一次读取的值会保留在视图对象中。
* **开销低，但并非完全免费。** 每帧分析被设计为开销较低（桌面端每个音频源低于毫秒级）。避免附加 `音频分析` 到太多音频源上，如果你并不需要这些数据。当可视化器不可见时，请移除该组件。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/mei-ti/audio-analysis.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
