1.4 Costruzione del software

Questa sezione descrive alcune decisioni di programmazione prese durante la progettazione di LilyPond.


Rappresentazione della musica

Idealmente, il formato di input per qualsiasi sistema di formattazione ad alto livello consiste in una descrizione astratta del contenuto da formattare, che nel nostro caso è la musica stessa. La questione solleva un problema formidabile: in che modo possiamo definire che cos’è davvero la musica? Anziché tentare di trovare una risposta, abbiamo rovesciato la domanda. Scriviamo un programma in grado di produrre spartiti e rendiamone il formato il più snello possibile: quando non potremo ridurlo ulteriormente, ci ritroveremo per definizione con il contenuto in sé. Il nostro programma, dunque, serve a definire la forma di un contenuto musicale.

Anche la sintassi è un aspetto dell’interfaccia utente di LilyPond, quindi è semplice da scrivere:

{
  c'4 d'8
}

crea un do centrale da un quarto (C1) e un re da un’ottavo immediatamente sopra il do centrale (D1).

[image of music]

A scala microscopica, una sintassi simile si adopera facilmente. A una scala più larga, però, anche la sintassi ha bisogno di una struttura. In quale altro modo, altrimenti, sarebbe possibile scrivere brani complessi come sinfonie e opere liriche? La struttura è formata dal concetto di espressioni musicali: combinando minuscoli frammenti di musica in frammenti più consistenti, possiamo esprimere musica più complessa. Per esempio

f'4

[image of music]

Possiamo costruire note simultanee racchiudendole tra << e >>:

<<c4 d4 e4>>

[image of music]

Possiamo mettere in sequenza queste due espressioni racchiudendole tra parentesi graffe { … }:

{ f4 <<c4 d4 e4>> }

[image of music]

Anche quella qui sopra è un’espressione, perciò può essere ulteriormente combinata con un’altra espressione simultanea (una minima, in questo caso): <<, \\, e >>:

<< g2 \\ { f4 <<c4 d4 e4>> } >>

[image of music]

Strutture ricorsive come quelle appena esaminate possono essere specificate in modo pulito e formale in una grammatica indipendente dal contesto, la quale genera anche il codice di analisi. In altre parole, la sintassi di LilyPond è definita in modo chiaro e privo di ambiguità

Interfacce utente e sintassi sono gli elementi immediatamente visibili agli utenti e quelli con cui essi hanno più a che fare. Un po’ sono una questione di gusto, un po’ l’argomento di molte discussioni: non troppo produttive, però, nonostante qualche pregio ce l’abbiano. Nel quadro più ampio di LilyPond, la sintassi di input non è molto importante: inventare una sintassi pulita è facile; molto più difficile, invece, è scrivere un codice di formattazione decente. Contiamo le righe di codice destinate ai due componenti e troveremo la conferma di quanto abbiamo appena affermato: analisi e rappresentazione occupano meno del 10% del codice sorgente.

Nel progettare le strutture usate in LilyPond, abbiamo preso decisioni diverse da quelle che appaiono in altri programmi. Considerate la natura gerarchica della notazione musicale:

[image of music]

In questo caso, abbiamo altezze raggruppate in accordi che appartengono alle misure, le quali appartengono ai righi. La cosa assomiglia a una struttura ordinata di scatole annidate:

nestedboxes

Purtroppo, la struttura è ordinata perché si basa su alcuni presupposti troppo restrittivi, il che diventa evidente considerando un esempio musicale più complesso:

[image of music]

In quest’esempio, i righi si interrompono arbitrariamente, le voci saltano dall’uno all’altro e su ciascun pentagramma c’è un’indicazione di tempo diversa. Molti programmi avrebbero del filo da torcere per riprodurlo, proprio perché costruiti con una struttura a scatole annidate. Con LilyPond, d’altronde, abbiamo cercato di mantenere formato di input e struttura il più possibile flessibili.


Quali simboli incidere?

Il processo di formattazione decide dove mettere i simboli, tuttavia ciò può essere fatto solo dopo aver deciso quali simboli vanno stampati: in altre parole, dopo aver deciso quale notazione adoperare.

La comune notazione musicale è un sistema di registrazione della musica evolutosi nel corso degli ultimi mille anni. La forma normalmente adoperata oggi risale agli inizi del Rinascimento, e anche se nei princìpi di base è rimasta praticamente immutata (cioè testa delle note su un pentagramma di cinque linee), continua a modificarsi nei dettagli per permettere di esprimere le innovazioni introdotte dalla notazione contemporanea. Dunque, la comune notazione musicale comprende circa cinque secoli di musica, con applicazioni che spaziano dalle melodie monofoniche ai mostruosi contrappunti di una grande orchestra.

In che modo possiamo noi imbrigliare un simile mostro a sette teste e costringerlo entro i limiti di un programma per computer? La nostra soluzione è stata quella di spezzare il problema della notazione (al contrario dell’incisione, che riguarda la tipografia) in ‘bocconi’ digeribili e programmabili: ciascun tipo di simbolo è gestito da un modulo a sé, un cosiddetto plug-in, completamente modulare e indipendente, così da poter essere sviluppato e migliorato separatamente. Tali plug-in sono chiamati incisori per analogia con l’artigiano che traduce le idee musicali in simboli grafici.

Nell’esempio seguente, cominciamo con il plug-in per le teste delle note, il Note_heads_engraver.

[image of music]

Poi il Staff_symbol_engraver aggiunge il rigo,

[image of music]

il Clef_engraver definisce un punto di riferimento per il rigo,

[image of music]

e lo Stem_engraver aggiunge i gambi.

[image of music]

Ogni volta che il programma incontra una testa di nota (o più d’una, se si tratta di un accordo) leggendo il file sorgente, avvisa lo Stem_engraver, il quale crea un gambo e glielo unisce. Aggiungendo gli incisori per travature, legature, accenti, accidenti, stanghette di battuta, indicazioni di tempo e armature di chiave, otteniamo la notazione completa.

[image of music]

Questo sistema funziona bene per la musica monofonica, ma che succede con la polifonia? Nella notazione polifonica, voci diverse possono condividere lo stesso rigo:

[image of music]

Nell’esempio qui sopra, armatura di chiave e rigo sono condivisi, ma gambi, legature, travature, eccetera, appartengono in modo esclusivo a ciascuna voce, perciò gli incisori devono essere raggruppati. Quelli per teste delle note, gambi, legature, eccetera, vanno in un gruppo chiamato ‘contesto Voice’, mentre quelli per chiave, accidenti, misure, eccetera, in un gruppo chiamato ‘contesto Staff’. Nel caso della polifonia, un singolo contesto Staff contiene più di un contesto Voice. Analogamente, contesti Staff multipli possono essere messi in un singolo contesto Score. Il contesto Score rappresenta il contesto notazionale di livello massimo.

[image of music]

Vedi anche

Internals Reference: Contesti.


Architettura flessibile

Quando abbiamo cominciato, abbiamo scritto LilyPond interamente nel linguaggio di programmazione C++, scolpendo nella pietra le sue funzionalità. Per una serie di ragioni, però, la cosa si è rivelata insoddisfacente.

Abbiamo affrontato questi problemi integrando in LilyPond un interprete del linguaggio di programmazione Scheme e riscrivendoci parti del programma. Ora l’architettura di formattazione è costruita intorno alla nozione di oggetti grafici, descritti dalle variabili e dalle funzioni di Scheme, e comprende regole di formattazione, stile tipografico e decisioni di formattazione individuali. L’utente può accedere direttamente alla maggior parte di questi controlli.

Le variabili di Scheme controllano le decisioni in merito all’aspetto della pagina. Per esempio, molti oggetti grafici possidono una variabile di direzione che codifica la scelta tra su e giù (o tra destra e sinistra). Qui sotto vedete due accordi con accenti e arpeggi. Nel primo, tutti gli oggetti grafici hanno direzione giù (o sinistra), nel secondo, hanno direzione su (destra).

[image of music]

Il processo di formattazione di uno spartito consiste nel leggere e scrivere le variabili degli oggetti grafici, alcune delle quali hanno un valore predefinito. Per esempio, lo spessore di molte linee – una caratteristica dello stile tipografico – è una di queste. Siete liberi di modificare questo valore, donando al vostro spartito un’impressione tipografica diversa.

[image of music]

Anche le regole di formattazione sono variabili preimpostate: ogni oggetto possiede variabili contenenti procedure. Sono queste ultime a eseguire la formattazione vera e propria, e sostituendone di diverse, possiamo modificare l’aspetto degli oggetti. Nell’esempio seguente, la regola che governa quali oggetti sono adoperati per produrre il simbolo della testa di nota è cambiata nel corso del frammento.

[image of music]


LilyPond — Saggio sull’incisione musicale automatizzata v2.24.4 (ramo stabile).