> ## 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 en Note in detail - VOICEVOX for Laravel

> Uitleg over het ontwerp van Score en Note voor Song-synthese in VOICEVOX for Laravel, framelengte-berekening en JSON-beheerpatronen.

## Doel

Deze pagina zet de specificaties van `Score` en `Note` op een rij, waar je bij Song-synthese makkelijk over kunt struikelen.

De basis voor de implementatie is de broncode van `Revolution\Voicevox\Song\Note` / `Score` / `SongAudioQuery`.

## De `Note`-klasse

Een `Note` stelt één noot (of rust) voor.

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

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

### Constructorargumenten

| Argument | Type           | Beschrijving                                                                            |
| -------- | -------------- | --------------------------------------------------------------------------------------- |
| `length` | `int`          | Framelengte. De waarde `seconden × 93.75`, afgerond naar een integer                    |
| `lyric`  | `string`       | Songtekst. Een rust is een lege string `''`                                             |
| `key`    | `int\|null`    | MIDI-nootnummer. Een rust is `null`                                                     |
| `id`     | `string\|null` | Hulp-ID dat bij het genereren van een `FrameAudioQuery` naar `note_id` wordt gekopieerd |

### Framelengte berekenen

`length` is in frames. Vanuit seconden bereken je het zo:

```text theme={null}
length = seconden × 93.75
```

Omdat deze waarde niet intuïtief is, is het praktischer om `Note::len()` te gebruiken als je bekend bent met MIDI.

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

* Gaat ervan uit dat een kwartnoot `480 ticks` is
* `125 BPM` is de standaard
* Intern wordt met `round()` naar een integer afgerond, dus bij lange nummers hopen afrondingsfouten zich geleidelijk op

```php theme={null}
Note::make(length: Note::len(480, 120), lyric: 'ド', key: 60);  // kwartnoot
Note::make(length: Note::len(960, 120), lyric: 'ミ', key: 64);  // halve noot
```

<Warning>
  `Note::len()` is handig, maar let bij langere composities op cumulatieve afrondingsfouten. Pas de lengtes indien nodig per sectie opnieuw aan.
</Warning>

### Een rust uitdrukken

Een rust is deze combinatie:

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

### Richtlijn voor MIDI-nootnummers

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

## De `Score`-klasse

Een `Score` is een partituurobject dat een array van `Note`-objecten bevat.

```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),
]);
```

### Belangrijke regel

De eerste noot moet altijd een rust zijn.

### Belangrijkste API

* Maken met `Score::make(array $notes)`
* Toevoegen met `add(Note $note)`
* Naar een JSON-string met `toJson()`

```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>
  De `Score`-constructor heeft een implementatie die bij array-invoer lege strings/`null` in `lyric` opvangt, waardoor ook formulierinvoer via de `ConvertEmptyStringsToNull`-middleware makkelijk te verwerken is.
</Info>

## Praktijkpatroon: beheer via JSON-bestanden (aanbevolen)

In echte producten is het praktischer om partituren niet hard in PHP te schrijven, maar als JSON te beheren.

1. Sla JSON in een eigen formaat op
2. Lees het in en converteer naar `Note` / `Score`
3. Geef het door aan `Voicevox::song()` en genereer

### JSON-voorbeeld

```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" }
  ]
}
```

### Inlezen en synthetiseren

```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');
```

## Gerelateerde pagina's

* [Client: song](/nl/packages/laravel-voicevox/client-song)
* [Native: song](/nl/packages/laravel-voicevox/native-song)
* [Engine API: song](/nl/packages/laravel-voicevox/engine-song)


## Related topics

- [Engine-API-modus: song (zangsynthese) - VOICEVOX for Laravel](/nl/packages/laravel-voicevox/engine-song.md)
- [Clientmodus: song (zangsynthese) - VOICEVOX for Laravel](/nl/packages/laravel-voicevox/client-song.md)
- [Specificatie van het .vvproj-bestand - VOICEVOX for Laravel](/nl/packages/laravel-voicevox/vvproj.md)
- [Ontwikkelgids voor apps met de engine-API - VOICEVOX for Laravel](/nl/packages/laravel-voicevox/app-guide.md)
- [Native modus: song (zangsynthese) - VOICEVOX for Laravel](/nl/packages/laravel-voicevox/native-song.md)
