# Audio Element

## 1. Shape

```ts
interface AudioClip extends BaseClip {
  type: "audio";
  src: string | { $ref: string };
  source?: MediaSource;
  volume?: number;
  loop?: boolean;
  playbackRate?: number;
  fadeIn?: number;
  fadeOut?: number;
  pan?: number;
  detune?: number;
  gainEnvelope?: AudioEnvelopePoint[];
  ducking?: AudioDucking;
}
```

## 2. Supported fields

### `src`
- Type: `string | { $ref: string }`
- Required: yes

### `source.start`
- Type: `number`
- Required: no
- Unit: seconds

### `source.end`
- Type: `number`
- Required: no
- Unit: seconds

### `volume`
- Type: `number`
- Required: no
- Default: `1`

### `loop`
- Type: `boolean`
- Required: no
- Default: `false`

### `playbackRate`
- Type: `number`
- Required: no
- Default: `1`

### `fadeIn`
- Type: `number`
- Required: no
- Unit: seconds

### `fadeOut`
- Type: `number`
- Required: no
- Unit: seconds

### `pan`
- Type: `number`
- Required: no
- Range: `-1` to `1`

### `detune`
- Type: `number`
- Required: no
- Unit: cents

### `gainEnvelope`
- Type: `{ time: number; volume: number; easing?: EasingFunction }[]`
- Required: no
- Times should be sorted ascending

### `ducking`
- Type: `{ targets: string[]; amount?: number; attack?: number; release?: number }`
- Required: no
- Use it to lower target audio tracks while this clip is active

## 3. Current runtime behavior

- `source.start` works
- `source.end` works
- `fadeIn` and `fadeOut` work
- `loop` works
- `playbackRate`, `detune`, `pan`, and `gainEnvelope` can automate playback and mix behavior
- Visual `transition` does not apply to audio clips

## 4. Example

```json
{
  "type": "audio",
  "start": 0,
  "duration": 10,
  "src": { "$ref": "bgm-main" },
  "volume": 0.6,
  "fadeIn": 1.2,
  "fadeOut": 1.5,
  "loop": true
}
```