<< Chapter < Page | Chapter >> Page > |
Si imponga un inviluppo di ampiezza sulla oscillazione generata, come se a vibrare fosse una corda vincolata alleestremità.
Quella che segue è la soluzione a
[link] con i vincoli aggiunti agli estremi:
int B = 256; // lunghezza di tabella (risoluzione)
int R = 20; // ratefloat f = 1.1; // frequenza in cicli al secondo
float[]buf = new float[B];int HEIGHT = 128; // altezza della finestra
float amp; // ampiezza della oscillazionefloat readPoint; // posizione orizzontale della cresta
float decayFactor = 0.92; // fattore di decadimento dell'ondafloat tempo;
float ampli=0;void setup() {
size(B,HEIGHT);stroke(255); strokeWeight(2);
for (int i = 0; i<buf.length; i++) buf[i] = sin(2*PI*(float)i/buf.length);}
void mousePressed() {tempo = millis();
}void mouseReleased() {
tempo = millis() - tempo; println(tempo);f = 500/tempo;
}void draw() {
background(0);if ((mouseX>= 0)&&(mouseX<B)&&(mousePressed)) {
amp = 2*(HEIGHT/2 - mouseY)/float(HEIGHT);readPoint = mouseX;}
for (int i = 0; i<buf.length; i++) {
if (i<readPoint) ampli += 1/(float)readPoint;
else ampli -= 1/(float)(B - readPoint);point(i, HEIGHT - HEIGHT/2 - HEIGHT/2*amp*ampli*buf[(i - round(readPoint) + B/4 + B)%B]);}
ampli = 0;amp = decayFactor*amp;
readPoint = (readPoint + (f*B/R))%B; // incremento dell'oscillatore}
Si renda l'oscillazione più fluida sostituendo
l'arrotondamento (
round()
) con
l'interpolazione lineare.
L'oscillatore tabellare può essere la struttura di riferimento anche per ripetizioni cicliche, a frequenza controllabile, diframmenti video. In questo caso la tabella da leggere ciclicamente contiene una sequenza di immagini.
In questo esempio, quando si manda in esecuzione il
programma un frammento di 4 secondi di video viene ripresodalla videocamera a 16 frame al secondo. Poi tale frammento
è riprodotto ciclicamente a 20 frame al secondo, con lapossibilità di controllare la velocità di riproduzione
(frequenza di oscillazione) cliccando in diverse posizioniorizzontali del mouse.
import processing.video.*;Capture myCapture;
int captureRate = 16;float f=1;
int B = 64;int R = 20;
PImage[]sequenza = new PImage[B];int i;
float j=0;float inc = f*B/R;
boolean via = false;void setup() {
for (int i=0; i<B; i++) sequenza[i]=loadImage("vetro.jpg"); // immagine dummy, per inizializzaresize(200, 200);
String s = "IIDC FireWire Video";myCapture = new Capture(this, width, height, s, 30);
myCapture.frameRate(captureRate);frameRate(R);
}void mousePressed(){f = float(mouseX)/width; inc = f*B/R;
}void draw() {
if (!via) {if(myCapture.available()) {
// Reads the new framemyCapture.read();
sequenza[i].copy(myCapture,0,0,myCapture.width,myCapture.height,0,0,sequenza[i].width,sequenza[i].height);
i = (i+1)%B;println(i);
if (i==0) via = true;}
}if (via) { image(sequenza[floor(j)], 0, 0,200,200);j = (j+inc); if (j>=B) j=j-B;
}}
Nel visual programming le oscillazioni tabellari spesso si
costruiscono utilizzando un segnale
sawtooth che consente di percorre ciclicamente gli indici dell'array,
ad una velocità dipendente dalla frequenza del segnale stesso.
In questo patch sono dichiarati due array
onda1
e
onda2
di 64 elementi ciascuno. Il segnale a dente
di sega viene generato ad una frequenza di 139 cicli alsecondo. Il suo range viene moltiplicato per 64 in maniera da
occupare tutto il campo degli indici (da 0 a 63) dell'array
onda1
. Ogni volta che si preme il bottone di
bang
, 64 campioni del segnale prodotto dalla
lettura della tabella
onda1
vengono scritti nella
tabella
onda2
. Il segnale prodotto dalla lettura
ciclica della tabella
onda1
è udibile attraverso
conversione da digitale ad analogico (
dac~
). Si
noti che in Pd tutti gli operatori che hanno il simbolo ditilde lavorano in maniera sincrona ad audio rate, e quindi la
lettura dalla tabella
onda1
fornisce campioni al
sample rate di funzionamento (per default 44100 Hz). Si notianche la scalinatura del segnale scritto nella tabella
onda2
, dovuto alla lettura non interpolata dei
campioni di
onda1
.
Come si può evitare la scalinatura nella forma d'onda prodotta dall'oscillatore tabellare di [link] ?
Basta sostituire
tabread~
con
tabread4~
, in questo modo facendo una lettura
interpolata di ordine 3. In altri termini, l'interpolatorefa passare un polinomio di terzo grado (una cubica) per quattro
punti contigui della tabella.
Nei sistemi interattivi c'è spesso la necessità di ritardare nel tempo un segnale, un processo, o un evento. Ad esempio, seci sono più flussi di video o audio in streaming, ciascuno viaggiante su canali indipendenti per i quali non è possibileavere lo stesso tempo di propagazione da trasmittente a fruitore, è opportuno ritardare diversamente ciascun flusso inmaniera da avere un riallineamento ed una sincronizzazione in ricezione. In campo audio, le linee di ritardo a lunghezza variabile sono alla base di molti effetti , quali sono echi e riverberazione.
La struttura di supporto per la realizzazione delle linee di
ritardo è il buffer circolare, cioè un array ai cui elementisi accede con aritmetica circolare dei puntatori. In
particolare, c'è una variabile
IN
, chiamata
puntatore di ingresso, che contiene l'indice dell'elementodell'array nel quale si va a scrivere. Una variabile
OUT
, chiamata puntatore di uscita, contiene
l'indice dell'elemento dell'array dal quale si va aleggere. Si tratta di incrementare i puntatori di accesso in
maniera circolare, mantenendo la loro distanza relativa parial numero di passi temporali di cui si vuole che sia fatto il
ritardo. Ad ogni passo temporale (o istante di campionamento)il segnale di ingresso è scritto nella locazione puntata da
IN
e letto dalla locazione puntata da
OUT
,
D
passi indietro. Quindi, i due
puntatori sono aggiornati con le operazioni
IN = (IN + 1) % B;
OUT = (OUT + 1) % B;
dove
B
è la lunghezza del buffer, scelta in
maniera da essere maggiore del più grande valore di ritardo
D
che si intende usare. Il ritardo
D
può variare dinamicamente, ad esempio oscillando tra un minimo
ed un massimo, ma è chiaro che se esso assume un valore nonintero bisognerà adottare una strategia di interpolazione per
la lettura del segnale ritardato. Ad esempio, si può ancorauna volta fare interpolazione lineare tra locazioni adiacenti,
oppure scegliere l'intero immediatamente inferiore a
D
.
Si costruisca un programma Processing che legge caratteri dalla tastiera e nefornisce una eco sulla finestra grafica con un ritardo crescente mano a mano che si aggiungono linee di testo.
PFont font;int B = 1000;
int INTERLINEA = 30;int xpos=0, ypos=INTERLINEA;
char[]buffer = new char[B];int OUT = 0;
int IN = 0;int D = 0;
char carattere;char inchar = '\0';
void setup() {size(800,800);
font = loadFont("Courier-48.vlw");textFont(font, 32);
frameRate(30);}
void keyReleased() {inchar = key;
}void draw() {
if (inchar=='\n') {D+=10;
IN = (OUT + D)%B;xpos = 0;
ypos += INTERLINEA;inchar='\0';
}else {
buffer[IN] = inchar;carattere = buffer[OUT];text(carattere, xpos, ypos);
xpos += textWidth(carattere);IN = (IN + 1)%B; OUT = (OUT + 1)%B;
}inchar = '\0';
}
Notification Switch
Would you like to follow the 'Programmazione di artefatti interattivi' conversation and receive update notifications?