xxxxxxxxxx
276
//
// Fourier Transform Visualizer
// coded by Timo Hoogland
// 2022, www.timohoogland.com
//
// Inspired by 3Blue1Brown Video:
// https://www.youtube.com/watch?v=spUNpyF58BY&ab_channel=3Blue1Brown
//
var sig = [];
var block = 256;
var r;
var fSlider1;
var fSlider2;
var fSlider3;
var pSlider1;
var pSlider2;
var pSlider3;
var fInput1;
var fInput2;
var fInput3;
var wSlider;
var wInput;
var imagBtn;
var displayImag = false;
var magBtn;
var displayMag = false;
function setup() {
createCanvas(windowWidth, windowHeight);
r = height/4;
fSlider1 = createSlider(0, 10, 2, 0);
pSlider1 = createSlider(0, 1, 0, 0);
fInput1 = createInput('2');
fSlider1.position(10, 0);
pSlider1.position(10, 25);
fInput1.position(10, 50);
fSlider1.size(width/3*0.8);
//pSlider1.size(width/3*0.8);
fInput1.size(width/3*0.8);
fSlider1.mouseMoved(() => {
fInput1.value(fSlider1.value());
});
fInput1.input(() => {
fSlider1.value(fInput1.value());
});
fSlider2 = createSlider(0, 10, 4, 0);
pSlider2 = createSlider(0, 1, 0, 0);
fInput2 = createInput('4');
fSlider2.position(width/3, 0);
pSlider2.position(width/3, 25);
fInput2.position(width/3, 50);
fSlider2.size(width/3*0.8);
fInput2.size(width/3*0.8);
fSlider2.mouseMoved(() => {
fInput2.value(fSlider2.value());
});
fInput2.input(() => {
fSlider2.value(fInput2.value());
});
fSlider3 = createSlider(0, 10, 8, 0);
pSlider3 = createSlider(0, 1, 0, 0);
fInput3 = createInput('8');
fSlider3.position(width*2/3, 0);
pSlider3.position(width*2/3, 25);
fInput3.position(width*2/3, 50);
fSlider3.size(width/3*0.8);
fInput3.size(width/3*0.8);
fSlider3.mouseMoved(() => {
fInput3.value(fSlider3.value());
});
fInput3.input(() => {
fSlider3.value(fInput3.value());
});
wSlider = createSlider(0, 10, 2, 0);
wInput = createInput('2');
wSlider.position(10, height-25);
wInput.position(10, height-50);
wSlider.size(width*0.95);
wInput.input(() => {wSlider.value(wInput.value())});
wSlider.mouseMoved(() => {wInput.value(wSlider.value())});
imagBtn = createCheckbox('display imaginary');
imagBtn.position(width-150, height-70);
imagBtn.changed(() => { displayImag = !displayImag });
magBtn = createCheckbox('display magnitude');
magBtn.position(width-150, height-50);
magBtn.changed(() => { displayMag = !displayMag });
}
function draw() {
textAlign(RIGHT, CENTER);
background(255);
translate(width/16, height/4+20);
strokeWeight(2);
stroke(0, 150);
line(-width, 0, width, 0);
line(0, -height/6, 0, height/6);
var wX = width*14/16/wSlider.value();
var tX = wX;
while(tX < width){
line(tX, -height/6, tX, height/6);
tX += wX;
}
fill(0, 150);
textSize(16);
noStroke();
textAlign(LEFT);
text('amp / time', 15, -height/7);
textAlign(RIGHT);
text('1', -5, -height/7);
text('-1', -5, height/7);
for (var t=0; t<11; t++){
var iX = t/10*width*14/16;
noStroke();
text(t, iX-5, 15);
stroke(0, 20);
line(iX, -height/6, iX, height/6);
}
noFill();
strokeWeight(3);
stroke(0);
beginShape();
for (var i=0; i<block; i++){
let p = i/block*TWO_PI;
sig[i] = -cos(p*fSlider1.value()+pSlider1.value()*TWO_PI);
if (fSlider2.value() > 0){
sig[i] -= cos(p*fSlider2.value()+pSlider2.value()*TWO_PI);
}
if (fSlider3.value() > 0){
sig[i] -= cos(p*fSlider3.value()+pSlider3.value()*TWO_PI);
}
sig[i] *= 1/3;
vertex(i/block*width*14/16, sig[i]*r/2);
}
endShape();
translate(width*3/16, height/2.5);
noStroke();
fill(0, 150);
textAlign(LEFT);
text('real / imag', -width*3/16+15, -height/7);
textAlign(RIGHT);
text('i', -5, -height/7);
text('-i', -5, height/7);
text('0', -5, 15);
text('-1', -width/7, 15);
text('1', width/7, 15);
strokeWeight(2);
stroke(0, 100);
line(-width, 0, width, 0);
line(0, -height/6, 0, height/6);
var avgX = 0;
var avgY = 0;
noFill();
strokeWeight(3);
stroke(0);
beginShape();
for (var i=0; i<sig.length; i++){
var x = r * cos(i/block*TWO_PI*wSlider.value()) * sig[i];
var y = r * sin(i/block*TWO_PI*wSlider.value()) * sig[i];
avgX += x;
avgY += y;
vertex(-x, -y);
}
endShape();
avgX = avgX / r;
avgY = avgY / r;
stroke(255, 0, 0, 255);
strokeWeight(12);
point(-avgX, -avgY);
translate(width/4, 0);
strokeWeight(2);
stroke(0, 100);
line(0, -height/6, 0, height/6);
noStroke();
fill(0, 150);
textAlign(LEFT);
text('amp / freq', 15, -height/7);
strokeWeight(12);
if (displayImag){
stroke(0, 0, 255, 255);
point(wSlider.value()/10*width*7/16, avgY);
}
if (displayMag){
stroke(0, 255, 0, 255);
point(wSlider.value()/10*width*7/16, -sqrt(avgX*avgX+avgY*avgY))
}
stroke(255, 0, 0, 255)
point(wSlider.value()/10*width*7/16, avgX);
noFill();
strokeWeight(3);
stroke(0);
var xShape = [];
var yShape = [];
var mShape = [];
for (var i=0; i<block; i++){
avgX = 0;
avgY = 0;
for (var j=0; j<sig.length; j++){
var x = r * cos(j/block*TWO_PI*i/block*10) * sig[j];
var y = r * sin(j/block*TWO_PI*i/block*10) * sig[j];
avgX += x;
avgY += y;
}
xShape.push(avgX / r);
yShape.push(avgY / r);
mShape.push(-sqrt(avgX*avgX + avgY*avgY)/r);
}
if (displayImag) stroke(255, 0, 0);
beginShape();
for (var x=0; x<block; x++){
vertex(x/block*width*7/16, xShape[x]);
}
endShape();
if (displayImag){
stroke(0, 0, 255);
beginShape();
for (var y=0; y<block; y++){
vertex(y/block*width*7/16, yShape[y]);
}
endShape();
}
if (displayMag){
// translate(0, height/8);
stroke(0, 255, 0, 150);
beginShape();
for (var m=0; m<block; m++){
vertex(m/block*width*7/16, mShape[m]);
}
endShape();
}
}