L'approccio più classico e versatile alla sintesi di forme
d'onda periodiche è la lettura ciclica di una tabella
contenente un periodo della forma d'onda periodica da
generare. Detto buf[] il buffer (è un array)
contenente la forma d'onda da generare, l'oscillatore
tabellare funziona per lettura ciclica della tabella, con un
passo di avanzamento
Esempio 1: Onda propagantesi
Per dare l'illusione di una onda prodotta da un gesto di
interazione e propagantesi in una certa direzione si può
fare uso dell'oscillatore tabellare. Nel codice che segue il
buffer viene precaricato con un periodo di sinusoide. Il
punto in cui l'utilizzatore clicca sulla finestra determina
la posizione iniziale della cresta, e viene generata una
oscillazione la cui frequenza è impostata tramite la
variabile f.
int B = 256; // lunghezza di tabella (risoluzione)
int R = 20; // rate
float f = 0.8; // frequenza in cicli al secondo
float[] buf = new float[B];
int HEIGHT = 128; // altezza della finestra
float amp; // ampiezza della oscillazione
int readPoint; // posizione orizzontale della cresta
float decayFactor = 0.95; // fattore di decadimento dell'onda
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 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++) {
point(i, HEIGHT - HEIGHT/2 - HEIGHT/2*amp*buf[(i - readPoint + B/4 + B)%B]);
}
amp = decayFactor*amp;
readPoint = (readPoint + round(f*B/R))%B; // incremento dell'oscillatore
}
Exercise 1
Si renda la frequenza di oscillazione dipendente dalla lunghezza dell'intervallo di tempo durante il quale il tasto del mouse viene tenuto premuto.
Solution
int B = 256; // lunghezza di tabella (risoluzione)
int R = 20; // rate
float f = 1.1; // frequenza in cicli al secondo
float[] buf = new float[B];
int HEIGHT = 128; // altezza della finestra
float amp; // ampiezza della oscillazione
float readPoint; // posizione orizzontale della cresta
float decayFactor = 0.92; // fattore di decadimento dell'onda
float tempo;
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++) {
point(i, HEIGHT - HEIGHT/2 - HEIGHT/2*amp*buf[(i - round(readPoint) + B/4 + B)%B]);
}
amp = decayFactor*amp;
readPoint = (readPoint + (f*B/R))%B; // incremento dell'oscillatore
}
Exercise 2
Si imponga un inviluppo di ampiezza sulla oscillazione generata, come se a vibrare fosse una corda vincolata alle estremità.
Solution
Quella che segue è la soluzione a Exercise 1 con i vincoli aggiunti agli estremi:
int B = 256; // lunghezza di tabella (risoluzione)
int R = 20; // rate
float f = 1.1; // frequenza in cicli al secondo
float[] buf = new float[B];
int HEIGHT = 128; // altezza della finestra
float amp; // ampiezza della oscillazione
float readPoint; // posizione orizzontale della cresta
float decayFactor = 0.92; // fattore di decadimento dell'onda
float 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
}
Exercise 3
Si renda l'oscillazione più fluida sostituendo
l'arrotondamento (round()) con
l'interpolazione lineare.





