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

# Dettagli di Score e Note - VOICEVOX for Laravel

> Progettazione, calcolo della lunghezza dei frame e pattern di gestione JSON per Score e Note usati nella sintesi Song di VOICEVOX for Laravel.

## Obiettivo

Chiarire le specifiche di `Score` e `Note`, spesso motivo di confusione nella sintesi Song.

I riferimenti implementativi si trovano nel codice di `Revolution\Voicevox\Song\Note` / `Score` / `SongAudioQuery`.

## Classe `Note`

`Note` rappresenta una singola nota (o una pausa).

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

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

### Argomenti del costruttore

| Argomento | Tipo           | Descrizione                                                                 |
| --------- | -------------- | --------------------------------------------------------------------------- |
| `length`  | `int`          | Lunghezza in frame. Valore ottenuto arrotondando a intero `secondi × 93.75` |
| `lyric`   | `string`       | Testo. Per la pausa stringa vuota `''`                                      |
| `key`     | `int\|null`    | Numero di nota MIDI. Per la pausa `null`                                    |
| `id`      | `string\|null` | ID ausiliario copiato in `note_id` quando si genera il `FrameAudioQuery`    |

### Calcolo della lunghezza in frame

`length` è in unità di frame. Da secondi si ricava con:

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

Poiché questo valore non è intuitivo, se sei abituato a MIDI è più pratico usare `Note::len()`.

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

* Considera la semiminima come `480 ticks`
* `125 BPM` è il valore predefinito
* Internamente esegue `round()` per arrotondare a intero, quindi in brani lunghi l'errore di arrotondamento si accumula gradualmente

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

<Warning>
  `Note::len()` è comodo, ma nei brani di lunga durata attenzione all'errore cumulativo. Se necessario riaggiusta le durate a livello di sezione.
</Warning>

### Rappresentare una pausa

Una pausa è la seguente combinazione.

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

### Riferimento numeri di nota MIDI

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

## Classe `Score`

`Score` è l'oggetto partitura che contiene un array di `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),
]);
```

### Regola importante

La prima nota deve sempre essere una pausa.

### API principali

* `Score::make(array $notes)` per creare
* `add(Note $note)` per aggiungere
* `toJson()` per convertire in stringa 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>
  Il costruttore di `Score`, in input array, gestisce stringa vuota/`null` per `lyric`, così da rendere agevole anche l'input via form passato attraverso il middleware `ConvertEmptyStringsToNull`.
</Info>

## Pattern pratico: gestione tramite file JSON (consigliato)

In prodotti reali è più gestibile mantenere le partiture in JSON invece di scriverle direttamente in PHP.

1. Salva un JSON in formato personalizzato
2. Caricalo e convertilo in `Note` / `Score`
3. Passalo a `Voicevox::song()` per generare

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

### Caricamento e sintesi

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

## Pagine correlate

* [Client: Song](/it/packages/laravel-voicevox/client-song)
* [Nativa: Song](/it/packages/laravel-voicevox/native-song)
* [API Engine: Song](/it/packages/laravel-voicevox/engine-song)


## Related topics

- [Modalità Engine API: Song (sintesi vocale cantata) - VOICEVOX for Laravel](/it/packages/laravel-voicevox/engine-song.md)
- [Specifica del file .vvproj - VOICEVOX for Laravel](/it/packages/laravel-voicevox/vvproj.md)
- [Modalità client: Song (sintesi vocale cantata) - VOICEVOX for Laravel](/it/packages/laravel-voicevox/client-song.md)
- [Modalità nativa: Song (sintesi vocale canora) - VOICEVOX for Laravel](/it/packages/laravel-voicevox/native-song.md)
- [Guida allo sviluppo di app con l'API del motore - VOICEVOX for Laravel](/it/packages/laravel-voicevox/app-guide.md)
