Summary: Si presenta una breve introduzione alla programmazione visuale per mezzo del linguaggio Pure Data (PD)
Un linguaggio di programmazione visuale permette di specificare programmi mediante manipolazione di elementi grafici. I linguaggi più usati in ambito artistico e di produzione multimediale (tra questi Pure Data, MAX/MSP, vvvv, e Quartz Composer sono basati sul paradigma di calcolo dataflow, nel quale i dati (piuttosto che le sequenze di operazioni) sono al centro dell'attenzione. Le operazioni sono "scatole nere" che elaborano l'input, non appena questo è disponibile, producendo un output che può essere dato in input ad altre scatole di elaborazione. Un programma dataflow assomiglia ad una rete di catene di montaggio, esplicita in maniera intrinseca il parallelismo, e non nasconde uno stato. Oltre che prestarsi alla parallelizzazione automatica, i programmi dataflow sono in un certo senso "auto-documentati" e si prestano al debugging mediante sonde.
Pure
Data è un linguaggio di programmazione visuale
inizialmente concepito da Miller Puckette per la
computer music in tempo reale, poi esteso ad opera di una
comunità di programmatori ed oggi diffuso anche tra artisti
visuali, performer e interaction designer. Pure Data è un
software libero, ed ha uno stretto grado di parentela con
MAX/MSP.
Essendo nato per elaborare e controllare segnale audio, Pure
Data supporta la comunicazione dei dati da un operatore
all'altro a due rate: il sample rate che per default è di
44100 campioni al secondo, ed il control rate ad un
sessantaquattresimo del sample rate. Più precisamente, gli
operatori che elaborano segnale audio (caratterizzati dal
suffisso ~) prendono campioni di ingresso in
maniera sincrona ad audio rate e allo stesso rate producono
segnali di uscita. Tutti gli altri operatori elaborano dati
non appena questi sono disponibili (dataflow) ad un rate
massimo di circa 690 Hz (per default, un sessantaquattresimo
del sample rate). Tutti i calcoli sono effettuati su numeri
floating-point a 32 bit. La documentazione di Pure Data è
disponibile dalla voce Help del suo menu, oppure
è consultabile online. Questo
modulo è parzialmente basato su tale documentazione e sulle
lezioni
di Gary Scavone.
I programmi Pure Data sono chiamati patch
e si presentano come grafi di elaborazione di flussi di
dati. Ogni programma ha una finestra principale e può avere un
numero arbitrario di sottofinestre. Il software Pure Data ha una interfaccia
modale, in quanto ci sono due modi distinti di
operazione: run mode e edit mode. Si passa dall'uno all'altro
con command-E e il feedback sul modo corrente è
dato dalla forma del puntatore del mouse. I blocchi che si possono
connettere in forma di grafo di dataflow sono di tipo: object,
message, atom (number o symbol), GUI, e comment.
![]() |
x1: Hello World. Esso contiene due oggetti message (lato
destro concavo) ed un oggetto object (rettangolo con comando
print x1). L'oggetto object rapresenta un comando con
eventuali parametri di default. Il quadrato con cerchio all'interno è
uno speciale messaggio senza contenuto, chiamato
bang, che invia un evento ai blocchi ad esso
collegati.
![]() |
pipe (si veda Paragraph 14). Per quanto sia piccolo il parametro
ritardo di questo pipe (al limite anche nullo), esso
terrà memoria del dato in ingresso per consumarlo al ciclo
successivo di calcolo.
![]() |
Nella maggior parte degli oggetti, la inlet di sinistra è hot, nel senso che messaggi che ad essa arrivano scatenano messaggi in output. E' spesso desiderabile inviare messaggi a due o più inlet di un oggetto, ma il risultato dell'operazione può dipendere dall'ordine con cui si sono fatte le connessioni. Ciò mina l'efficacia semantica del programma visuale, in quanto potremmo avere due patch apparentemente identiche che però si comportano diversamente perché costruite con un ordine diverso. Ad esempio, si provi a fare la somma di un numero con sè stesso secondo la Figura 4.
![]() |
trigger che forza l'ordine di attivazione delle
outlet da destra a sinistra, come indicato in Figura 5.
![]() |
![]() |
metro che
stabilisce l'intervallo (di 500 millisecondi) tra due
bang. Il quadrato in alto è un elemento di GUI detto toggle
switch, in pratica un interruttore.
![]() |
![]() |
table istanzia l'array e crea un
subpatch che ne visualizza la rappresentazione
grafica. Questa rappresentazione è anche uno strumento
di input, in quanto i valori dell'array possono essere
"disegnati" con il mouse. Per leggere e scrivere i
singoli elementi dell'array si usano gli oggetti
tabread e
tabwrite. L'utilizzazione di
tabread per scandire un array è illustrata
in Figura 8.
![]() |
select attiva l'uscita di sinistra se l'ingresso
(inlet) è uguale al suo parametro,
altrimenti attiva l'uscita di destra.
![]() |
spigot trasmette messaggi dall'inlet di
sinistra all'outlet in dipendenza dallo stato
dell'ingresso (di controllo) di destra. In sostanza si
tratta di un gate con controllo di
apertura e chiusura. Invece, moses consente
di smistare alle uscite sinistra e destra i valori di
ingresso che sono rispettivamente minori o maggiori (o
uguali) del valore di controllo passato dalla inlet di
destra. Infine, route smista dei messaggi
ricevuti in ingresso sulla base del loro primo elemento,
mettendolo a confronto con gli argomenti. Un multiplexer si
può ottenere combinando la route con la
pack.
Realizzare un multiplexer e un demultiplexer utilizzando
gli oggetti pack, route e
spigot.
![]() |
delay ritarda un bang in ingresso di un numero
di millisecondi pari al suo argomento. Se si vuole ritardare
un flusso di dati bisogna usare la pipe, la
quale è realizzata come coda a buffer circolare.
![]() |
metro, timer, e
line. Quest'ultimo oggetto genera una rampa
lineare, da un valore iniziale a uno finale, in un certo
tempo.
Nel patch di Figura 8, si provi a
rimuovere e ripristinare i collegamenti che arrivano
alla inlet di destra dell'oggetto float, e
si verifichi che il reset dell'indice una volta
raggiunto il limite di 128 può non avere luogo. Perché?
Come si può introdurre in maniera deterministica il
reset dell'indice?
E' sufficiente introdurre un elemento di
disaccoppiamento (ad esempio, una pipe 0)
che imponga un ordine tra l'immissione del numero
incrementato e l'immissione di 0 nella inlet di destra.
Il funzionamento dataflow di Pure Data avviene mediante
pipe che corrispondono alle connessioni
tra oggetti. E' anche possibile operare in regime di message
passing, cioè ricevere (receive) e spedire (send) dati tra diverse parti di un
patch o tra patch diversi. Ciò è illustrato in Figura 13. Invece, l'oggetto value
realizza una sorta di variabile globale.
![]() |
Nella programmazione visuale la modularità si ottiene con i meccanismi di subpatching che, in Pure Data, sono di due tipi:
![]() |
![]() |