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

# Score와 Note 상세 해설 - VOICEVOX for Laravel

> VOICEVOX for Laravel의 Song 합성에서 사용하는 Score와 Note의 설계, 프레임 길이 계산, JSON 관리 패턴을 해설합니다.

## 목적

Song 합성에서 헷갈리기 쉬운 `Score`와 `Note`의 사양을 정리합니다.

구현의 근거는 `Revolution\Voicevox\Song\Note` / `Score` / `SongAudioQuery`의 소스입니다.

## `Note` 클래스

`Note`는 1개의 음표 (또는 쉼표)를 나타냅니다.

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

$note = Note::make(
    length: 94,
    lyric: 'ド',
    key: 60,
    id: 'intro-1',
);
```

### 생성자 인수

| 인수       | 타입             | 설명                                           |
| -------- | -------------- | -------------------------------------------- |
| `length` | `int`          | 프레임 길이. `초 수 × 93.75`를 정수화한 값                |
| `lyric`  | `string`       | 가사. 쉼표는 빈 문자열 `''`                           |
| `key`    | `int\|null`    | MIDI 노트 번호. 쉼표는 `null`                       |
| `id`     | `string\|null` | `FrameAudioQuery` 생성 시 `note_id`로 복사되는 보조 ID |

### 프레임 길이 계산

`length`는 프레임 단위입니다. 초 수에서는 다음으로 구합니다.

```text theme={null}
length = 초 수 × 93.75
```

이 값은 직관적이지 않기 때문에, MIDI에 익숙한 경우에는 `Note::len()`을 사용하는 것이 실용적입니다.

```php theme={null}
Note::len(int $ticks, int $bpm = 125): int
```

* 4분음표를 `480 ticks`로 취급한다는 전제
* `125 BPM`이 기본값
* 내부에서 `round()`로 정수화하기 때문에 긴 곡에서는 반올림 오차가 서서히 누적됩니다

```php theme={null}
Note::make(length: Note::len(480, 120), lyric: 'ド', key: 60);  // 4분음표
Note::make(length: Note::len(960, 120), lyric: 'ミ', key: 64);  // 2분음표
```

<Warning>
  `Note::len()`은 편리하지만, 긴 악곡에서는 누적 오차에 주의하세요. 필요하면 섹션 단위로 길이를 재조정합니다.
</Warning>

### 쉼표 표현

쉼표는 다음 조합입니다.

```php theme={null}
Note::make(length: 15, lyric: '', key: null);
```

### MIDI 노트 번호의 기준

| Note | MIDI |
| ---- | ---- |
| C4   | 60   |
| D4   | 62   |
| E4   | 64   |
| F4   | 65   |
| G4   | 67   |
| A4   | 69   |
| B4   | 71   |
| C5   | 72   |

## `Score` 클래스

`Score`는 `Note`의 배열을 가진 악보 오브젝트입니다.

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

$score = Score::make([
    Note::make(length: 15, lyric: '', key: null),
    Note::make(length: Note::len(480, 120), lyric: 'ド', key: 60),
]);
```

### 중요 규칙

최초의 노트는 반드시 쉼표로 하세요.

### 주요 API

* `Score::make(array $notes)`로 생성
* `add(Note $note)`로 추가
* `toJson()`으로 JSON 문자열화

```php theme={null}
$score = Score::make([
    Note::make(length: 15, lyric: '', key: null),
]);

$score->add(Note::make(length: Note::len(480, 120), lyric: 'ド', key: 60));

$json = $score->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
```

<Info>
  `Score` 생성자는 배열 입력 시에 `lyric`의 빈 문자열/`null`을 흡수하는 구현이 있어, `ConvertEmptyStringsToNull` 미들웨어를 경유한 폼 입력에서도 다루기 쉽게 되어 있습니다.
</Info>

## 실전 패턴: JSON 파일 관리 (권장)

실제 프로덕트에서는 PHP에 악보를 직접 쓰지 말고 JSON으로 관리하는 편이 운영하기 쉽습니다.

1. 독자 포맷 JSON을 저장
2. 읽어와 `Note` / `Score`로 변환
3. `Voicevox::song()`에 전달해 생성

### JSON 예

```json theme={null}
{
  "teacher": 6000,
  "speaker": 3001,
  "bpm": 120,
  "notes": [
    { "ticks": 120, "lyric": "", "key": null, "id": "r0" },
    { "ticks": 480, "lyric": "ド", "key": 60, "id": "n1" },
    { "ticks": 480, "lyric": "レ", "key": 62, "id": "n2" },
    { "ticks": 960, "lyric": "ミ", "key": 64, "id": "n3" },
    { "ticks": 120, "lyric": "", "key": null, "id": "r1" }
  ]
}
```

### 읽어오기와 합성

```php theme={null}
use Illuminate\Support\Facades\Storage;
use Revolution\Voicevox\Song\Note;
use Revolution\Voicevox\Song\Score;
use Revolution\Voicevox\Voicevox;

$chart = json_decode(
    Storage::disk('local')->get('songs/sample.json'),
    true,
    flags: JSON_THROW_ON_ERROR,
);

$score = Score::make(
    collect($chart['notes'])
        ->map(fn (array $note) => Note::make(
            length: Note::len(ticks: $note['ticks'], bpm: $chart['bpm']),
            lyric: $note['lyric'] ?? '',
            key: $note['key'],
            id: $note['id'] ?? null,
        ))
        ->all(),
);

$response = Voicevox::song($score, teacher: $chart['teacher'])
    ->generate(id: $chart['speaker']);

$response->storeAs('songs', 'sample.wav');
```

## 관련 페이지

* [클라이언트: 송](/ko/packages/laravel-voicevox/client-song)
* [네이티브: 송](/ko/packages/laravel-voicevox/native-song)
* [엔진 API: 송](/ko/packages/laravel-voicevox/engine-song)


## Related topics

- [엔진 API 연동 앱 개발 가이드 - VOICEVOX for Laravel](/ko/packages/laravel-voicevox/app-guide.md)
- [엔진 API 모드: 송 (노래 음성 합성) - VOICEVOX for Laravel](/ko/packages/laravel-voicevox/engine-song.md)
- [.vvproj 파일 사양 - VOICEVOX for Laravel](/ko/packages/laravel-voicevox/vvproj.md)
- [클라이언트 모드: 송 (노래 음성 합성) - VOICEVOX for Laravel](/ko/packages/laravel-voicevox/client-song.md)
- [네이티브 모드: 송 (노래 음성 합성) - VOICEVOX for Laravel](/ko/packages/laravel-voicevox/native-song.md)
