# 生成 MIDI
> 从已有音频反推音符数据，异步任务
> 结果为结构化的乐器与音符，不一定是 .mid 文件
> 适合二次编曲与音色替换
`POST /v1/music/generations/midi`
## 认证
- `Authorization` (string / 必填) — 所有接口均使用 Bearer Token 进行认证。 获取 API Key：[访问控制台](https://api.oairoute.com/keys) 创建。 请求时在请求头中添加： ```http Authorization: Bearer YOUR_OAIRoute_KEY ```
## 请求参数
- `model` (string / 可选) — 音频模型，默认 `suno`，目前只有这一个取值。
- `task_id` (string / 必填) — 生成源音轨的那次任务的 task_id。缺失或无法定位源音轨时，提交时直接返回 400。
- `audio_index` (integer / 可选) — 指定引用源任务结果 `data.result.music[]` 中的第几首，默认 `1`，从 1 起始。 一次生成一般产出 2 首，索引 1 与 2。
本端点无版本维度，传 `version` 会被丢弃，也不影响计费。
## 响应
- `code` (integer) — 响应状态码，成功为 200。
- `data[].status` (string) — 任务状态，取值 `submitted`。
- `data[].task_id` (string) — 任务唯一标识，用于轮询 `GET /v1/music/tasks/{task_id}`。
## 结果结构
完成结果通常包含：
- `result.state` (string) — 解析状态。
- `result.instruments` (array) — 识别出的乐器数组。每个元素含 `notes[]`，提供音符数据。
> **Note:** 
> 当前**不保证**直接返回 `.mid` 文件 URL。拿到的是结构化的音符数据，需要自己转换成 MIDI 文件。这一点与多数人的预期不同，先确认返回结构再决定怎么用。
## 怎么把音符数据转成 MIDI
拿到 `result.instruments[].notes[]` 后，可以用任意 MIDI 库写出文件。Python 下 `mido` 最简单：
```python
import mido
from mido import Message, MidiFile, MidiTrack
def to_midi(instruments, path="out.mid", ticks_per_beat=480):
    mid = MidiFile(ticks_per_beat=ticks_per_beat)
    for inst in instruments:
        track = MidiTrack()
        mid.tracks.append(track)
        channel = inst.get("channel", 0) % 16
        program = inst.get("program", 0)
        track.append(Message("program_change", program=program, channel=channel, time=0))
        for note in inst.get("notes", []):
            pitch = int(note["pitch"])
            start = int(note["start"] * ticks_per_beat)
            dur = max(1, int(note.get("duration", 0.25) * ticks_per_beat))
            track.append(Message("note_on", note=pitch, velocity=80,
                                 channel=channel, time=start))
            track.append(Message("note_off", note=pitch, velocity=0,
                                 channel=channel, time=dur))
    mid.save(path)
    return path
```
字段名（`pitch`、`start`、`duration`）以实际返回为准，第一次接的时候先打印一条音符看结构。
## 用途
| 用途 | 说明 |
|---|---|
| 换音色 | 保留旋律，改用自己音源库里的钢琴或弦乐 |
| 二次编曲 | 在 DAW 里调整配器与和声 |
| 乐谱导出 | 转成 MusicXML 后生成五线谱 |
| 旋律分析 | 提取音高序列做统计或检索 |
> **Note:** 
> 从音频反推音符本身就是有损的。和弦密集、失真严重的段落，识别结果会有偏差。想要精确的 MIDI，最好从干净的乐器独奏开始。
## 错误码
错误响应的格式、状态码与重试建议见[错误码与限流](../../../support/errors.html)，常见报错的排查步骤见[常见问题](../../../support/faq.html)。
## 使用示例
提交一个任务并拿到 `task_id`：
> **Note:** 
> 提交成功只表示任务已受理。真正的产物要拿返回的 `task_id` 去任务查询接口轮询，`status` 变成 `completed` 之后才有结果。
**生成 MIDI{Generate MIDI}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/v1/music/generations/midi' \
  --header 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "suno",
    "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K",
    "audio_index": 1
  }'
```
**生成 MIDI{Generate MIDI}::Python**
```
import requests
res = requests.post(
    "https://api.oairoute.com/v1/music/generations/midi",
    headers={
        "Authorization": "Bearer YOUR_OAIRoute_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "suno",
        "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K",
        "audio_index": 1,
    },
)
print(res.json()["data"][0]["task_id"])
```
**生成 MIDI{Generate MIDI}::JavaScript**
```
const url = "https://api.oairoute.com/v1/music/generations/midi";
const options = {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "suno",
    "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K",
    "audio_index": 1
  }),
};
fetch(url, options)
  .then((res) => res.json())
  .then((json) => console.log(json))
  .catch((err) => console.error(err));
```
**200 生成 MIDI{Generate MIDI}**
```
{
  "code": 200,
  "data": {
    "id": "task_01K8D55M0HP1GJWBJYZMKX1XS1",
    "status": "completed",
    "progress": 100,
    "result": {
      "state": "ok",
      "instruments": [
        {
          "name": "piano",
          "notes": [
            { "pitch": 60, "start": 0.0, "duration": 0.5 },
            { "pitch": 64, "start": 0.5, "duration": 0.5 }
          ]
        }
      ]
    }
  }
}
```
