> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 客户端模式：Song（歌声合成） - VOICEVOX for Laravel

> 介绍在 VOICEVOX for Laravel 的客户端模式下通过 Score 与 Note 进行歌声合成的方法。

## 在客户端模式下让它唱歌

客户端模式的歌声合成使用官方 VOICEVOX 引擎的 `sing_frame_audio_query` 与 `frame_synthesis` API。

与 Talk 不同，需要先构建 `Score` 与 `Note`。

## 前置准备

```shell theme={null}
docker pull voicevox/voicevox_engine:cpu-latest
docker run --rm -p '127.0.0.1:50021:50021' voicevox/voicevox_engine:cpu-latest
```

## 构建 `Score` 与 `Note`

```php theme={null}
use Revolution\Voicevox\Song\Note;
use Revolution\Voicevox\Song\Score;

$score = Score::make([
    Note::make(length: 15),
    Note::make(length: Note::len(ticks: 480, bpm: 120), lyric: 'ド', key: 60),
    Note::make(length: Note::len(480, 120), lyric: 'レ', key: 62),
    Note::make(length: Note::len(960, 120), lyric: 'ミ', key: 64),
    Note::make(length: 2),
]);
```

| 参数       | 类型          | 说明                |
| -------- | ----------- | ----------------- |
| `length` | `int`       | 帧长                |
| `lyric`  | `string`    | 歌词。为空字符串或省略时表示休止符 |
| `key`    | `int\|null` | MIDI 音符编号         |

<Tip>
  使用 `Note::len($ticks, $bpm)` 可以从 MIDI 的 ticks 与 BPM 计算帧长。将四分音符视为 480 ticks 更易理解。
</Tip>

## 基本使用

```php theme={null}
use Revolution\Voicevox\Song\Note;
use Revolution\Voicevox\Song\Score;
use Revolution\Voicevox\Voicevox;

$score = Score::make([
    Note::make(length: 15),
    Note::make(length: Note::len(480, 120), lyric: 'ド', key: 60),
    Note::make(length: Note::len(480, 120), lyric: 'レ', key: 62),
    Note::make(length: Note::len(960, 120), lyric: 'ミ', key: 64),
    Note::make(length: 2),
]);

$response = Voicevox::song($score, teacher: 6000)
    ->generate(id: 3001);

$response->storeAs('client', 'song.wav');
```

### `teacher` 与 `id`

* `teacher`：传递给 `sing_frame_audio_query` 的 Style ID。目前只存在 6000 一个，因此默认为 6000。
* `generate(id:)`：传递给 `frame_synthesis` 的 Style ID

可通过 `singers()` 获取可用的歌声说话人列表。

```php theme={null}
use Revolution\Voicevox\Voicevox;

$singers = Voicevox::singers();
```

## 使用 `tap()` 调整 F0 与音量

在 Song 中，`tap()` 的用途尤为清晰，可以在调整 `SongAudioQuery` 后再传给 `generate()`。

```php theme={null}
use Revolution\Voicevox\Client\SongAudioQuery;
use Revolution\Voicevox\Voicevox;

$response = Voicevox::song($score, teacher: 6000)
    ->tap(function (SongAudioQuery $song) {
        $song->sync();
    })
    ->generate(id: 3001);
```

如需分别更新 F0 与音量，请按 **F0 → 音量** 的顺序执行。

```php theme={null}
->tap(function (SongAudioQuery $song) {
    $song->updateF0();
    $song->updateVolume();
})
```

修改 Score 后想重新同步时，`tap()` 也非常方便。

```php theme={null}
->tap(function (SongAudioQuery $song) {
    $song->score->notes[2] = Note::make(length: Note::len(480, 120), lyric: 'ファ', key: 65);
    $song->sync();
})
```

<Info>
  关于 `tap()` 的设计思路整理在 [tap() helper 与 Tappable trait](/zh/advanced/tap) 中。VOICEVOX for Laravel 是"不改变返回值、只调整中间对象"的典型案例。
</Info>

## 下一步阅读

<Columns cols={3}>
  <Card title="Score 与 Note 详解" href="/zh/packages/laravel-voicevox/song-score-note" icon="list-music">
    了解帧长计算与 JSON 管理模式。
  </Card>

  <Card title="原生 Song" href="/zh/packages/laravel-voicevox/native-song" icon="music">
    在通过 FFI 的原生模式下使用相同的 `Score`。
  </Card>

  <Card title="VOICEVOX Core for PHP 用法" href="/zh/packages/voicevox-core-php/usage" icon="library">
    了解仅使用核心库时的语音合成流程。
  </Card>
</Columns>


## Related topics

- [原生模式：Song（歌声合成） - VOICEVOX for Laravel](/zh/packages/laravel-voicevox/native-song.md)
- [客户端模式：Talk（文本语音合成） - VOICEVOX for Laravel](/zh/packages/laravel-voicevox/client-talk.md)
- [引擎 API 模式：Song（歌声合成） - VOICEVOX for Laravel](/zh/packages/laravel-voicevox/engine-song.md)
- [客户端模式 - 预设 - VOICEVOX for Laravel](/zh/packages/laravel-voicevox/client-presets.md)
- [客户端模式 - 用户词典 - VOICEVOX for Laravel](/zh/packages/laravel-voicevox/client-user-dict.md)
