> 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` 组件缺失时返回 `true` ，并在写入值时返回。

```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` 、你想分析的实体。
* `mode` (`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` 实体没有 `音频分析` 组件时返回，而不是抛出异常。返回 `true` 时会写入值。

### `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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
