Vai al contenuto principale

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).
use Revolution\Voicevox\Song\Note;

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

Argomenti del costruttore

ArgomentoTipoDescrizione
lengthintLunghezza in frame. Valore ottenuto arrotondando a intero secondi × 93.75
lyricstringTesto. Per la pausa stringa vuota ''
keyint|nullNumero di nota MIDI. Per la pausa null
idstring|nullID 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:
length = secondi × 93.75
Poiché questo valore non è intuitivo, se sei abituato a MIDI è più pratico usare Note::len().
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
Note::make(length: Note::len(480, 120), lyric: 'ド', key: 60);  // semiminima
Note::make(length: Note::len(960, 120), lyric: 'ミ', key: 64);  // minima
Note::len() è comodo, ma nei brani di lunga durata attenzione all’errore cumulativo. Se necessario riaggiusta le durate a livello di sezione.

Rappresentare una pausa

Una pausa è la seguente combinazione.
Note::make(length: 15, lyric: '', key: null);

Riferimento numeri di nota MIDI

NotaMIDI
C460
D462
E464
F465
G467
A469
B471
C572

Classe Score

Score è l’oggetto partitura che contiene un array di Note.
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
$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);
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.

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

{
  "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

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

Ultima modifica il 13 luglio 2026