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

# Explications détaillées sur Score et Note - VOICEVOX for Laravel

> Conception de Score et Note utilisés en synthèse Song de VOICEVOX for Laravel, calcul des longueurs en frames et patterns de gestion via JSON.

## Objectif

Cette page clarifie les spécifications de `Score` et `Note`, souvent sources de confusion en synthèse Song.

L'implémentation de référence est celle des sources de `Revolution\Voicevox\Song\Note` / `Score` / `SongAudioQuery`.

## Classe `Note`

`Note` représente une seule note (ou un silence).

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

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

### Arguments du constructeur

| Argument | Type           | Description                                                                 |
| -------- | -------------- | --------------------------------------------------------------------------- |
| `length` | `int`          | Longueur en frames. Valeur `secondes × 93.75` convertie en entier           |
| `lyric`  | `string`       | Paroles. Chaîne vide `''` pour un silence                                   |
| `key`    | `int\|null`    | Numéro de note MIDI. `null` pour un silence                                 |
| `id`     | `string\|null` | ID auxiliaire copié dans `note_id` lors de la création du `FrameAudioQuery` |

### Calcul de la longueur en frames

`length` est en frames. Elle se calcule à partir des secondes ainsi :

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

Cette valeur n'étant pas intuitive, si vous êtes habitué au MIDI, l'usage pratique consiste à utiliser `Note::len()`.

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

* Considère la noire comme valant `480 ticks`
* Par défaut, `125 BPM`
* Applique `round()` en interne pour retourner un entier : les erreurs d'arrondi s'accumulent sur les morceaux longs

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

<Warning>
  `Note::len()` est pratique, mais faites attention à l'erreur cumulée sur les morceaux longs. Réajustez au besoin les longueurs par section.
</Warning>

### Représentation d'un silence

Un silence s'exprime avec la combinaison suivante.

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

### Repères pour les numéros de note MIDI

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

## Classe `Score`

`Score` est un objet partition qui contient un tableau de `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),
]);
```

### Règle importante

La première note doit obligatoirement être un silence.

### Principales API

* Création via `Score::make(array $notes)`
* Ajout via `add(Note $note)`
* Conversion en chaîne JSON via `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>
  Le constructeur de `Score` inclut une implémentation qui absorbe les chaînes vides / `null` de `lyric` lors d'entrées en tableau, ce qui facilite aussi les entrées de formulaire passant par le middleware `ConvertEmptyStringsToNull`.
</Info>

## Pattern pratique : gestion via fichiers JSON (recommandé)

Dans un produit réel, plutôt que d'écrire la partition en dur dans le PHP, il est plus commode de la gérer en JSON.

1. Stocker un JSON dans un format personnalisé
2. Le lire et convertir en `Note` / `Score`
3. Le passer à `Voicevox::song()` pour générer

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

### Lecture et synthèse

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

## Pages associées

* [Client : Song](/fr/packages/laravel-voicevox/client-song)
* [Natif : Song](/fr/packages/laravel-voicevox/native-song)
* [API du moteur : Song](/fr/packages/laravel-voicevox/engine-song)


## Related topics

- [Guide de développement d'applications intégrées à l'API du moteur - VOICEVOX for Laravel](/fr/packages/laravel-voicevox/app-guide.md)
- [Installation et configuration - VOICEVOX for Laravel](/fr/packages/laravel-voicevox/installation.md)
- [Mode client : Song (synthèse vocale chantée) - VOICEVOX for Laravel](/fr/packages/laravel-voicevox/client-song.md)
- [Mode API du moteur : Song (synthèse vocale chantée) - VOICEVOX for Laravel](/fr/packages/laravel-voicevox/engine-song.md)
- [VOICEVOX for Laravel](/fr/packages/laravel-voicevox/index.md)
