You are not recognized as the original poster of this topic.
/*
(2025-03-19 09:34) 01:57 remaining, thinking about additive harmonic synthesis.
Every online notepad is completely ad-ridden with GDPR cookie pop-ups, so I had to use Sublime Text…
(10:34) 00:57, almost done… (11:08) 00:23, I think I'm done…
*/
const TAU=Math.PI*2,
clamp=(x,mn=0,mx=1)=>Math.min(Math.max(x,mn),mx),
pointInRect=(x,y,rx,ry,rw,rh)=>x>=rx&&x<rx+rw&&y>=ry&&y<ry+rh,
sineHarm=(x,phase,n)=>Math.sin(TAU*(phase+n*x));
class Graph{
constructor(x,y,w,h,numBars=16){
this.x=x;this.y=y;this.w=w;this.h=h;
this.levels=Array(numBars).fill(0);
this.dragging=false;
this.fillColor=[255,255,255];this.bgColor=[16,16,16];
}
pressed(mx,my){
this.dragging=pointInRect(mouseX,mouseY,this.x,this.y,this.w,this.h);
if(this.dragging)this.drag(mx,my); //click
}
released(mx,my){
this.dragging=false;
}
drag(mx,my){
if(!this.dragging)return;
let l=this.levels.length,
i=Math.floor(clamp(((mx-this.x)/this.w)*l,0,l-1)),
y=1-clamp((my-this.y)/this.h,0,1);
this.levels[i]=y;
}
display(){
let l=this.levels.length;
fill(this.bgColor);stroke(this.dragging*4);
rect(this.x,this.y,this.w,this.h);
for(let i=1;i<l;i++){
let x=(this.w/l)*i;
line(this.x+x,this.y,this.x+x,this.y+this.h);
}
fill(this.fillColor);
for(let i=0;i<l;i++){
let h=clamp(this.levels[i],0,1)*this.h;
rect(this.x+i*(this.w/l),this.y+(this.h-h),this.w/l,h);
}
}
}
class Plot{
constructor(x,y,w,h,numPoints=16,color=[0,0,255]){
this.x=x;this.y=y;this.w=w;this.h=h;
this.points=Array(numPoints).fill(0);
this.bottomRange=-1;this.upperRange=1;
this.color=color;
}
display(){
stroke(0,64);noFill();
rect(this.x,this.y,this.w,this.h);
line(this.x,this.y+this.h*.5,this.x+this.w,this.y+this.h*.5);
let l=this.points.length,step=this.w/(l-1);
stroke(this.color);
beginShape();
for(let i=0;i<l;i++){
let x=this.x+i*step,
y=map(this.points[i],this.bottomRange,this.upperRange,this.y+this.h,this.y);
vertex(x,y);
}
endShape();
}
}
class Button{
constructor(x,y,w,h,label,onPress){
this.x=x;this.y=y;this.w=w;this.h=h;
this.label=label;
this.onPress=onPress;
}
display(){
let hover=pointInRect(mouseX,mouseY,this.x,this.y,this.w,this.h);
fill(hover?100:64);stroke(0);
rect(this.x,this.y,this.w,this.h);
fill(255);noStroke();
textSize(14);textAlign(CENTER,CENTER);
text(this.label,this.x+this.w*.5,this.y+this.h*.5);
}
pressed(mx,my){
if(pointInRect(mx,my,this.x,this.y,this.w,this.h)){
this.onPress();
return true;
}
return false;
}
}
let amp=new Graph(16,16,300,128,32),
phase=new Graph(amp.x,amp.y+amp.h,amp.w,amp.h,amp.levels.length),
waveform=new Plot(phase.x,phase.y+phase.h,phase.w,phase.h,phase.levels.length*4),
bW=120,bH=32,bS=3,buttons=[
{label:"Clear",onPress:()=>{
for(let i=0;i<amp.levels.length;i++)amp.levels[i]=0;
for(let i=0;i<phase.levels.length;i++)phase.levels[i]=0;
}},
{label:"Sine",onPress:()=>{
for(let i=0;i<amp.levels.length;i++)amp.levels[i]=0;
amp.levels[0]=1;
for(let i=0;i<phase.levels.length;i++)phase.levels[i]=0;
}},
{label:"Test",onPress:()=>{
let n=amp.levels.length;
for(let i=0;i<n;i++){
amp.levels[i]=i%2?TAU/(TAU*i):0;
phase.levels[i]=(i%4)<2?0:.5;
}
}},
{label:"Pulse",onPress:()=>{
for(let i=0;i<amp.levels.length;i++){
if(i%2===0){
amp.levels[i]=1/(i+1);
phase.levels[i]=0;
}else{
amp.levels[i]=0;
phase.levels[i]=0;
}
}
}},
{label:"Triangle",onPress:()=>{
for(let i=0;i<amp.levels.length;i++){
if(i%2===0){
amp.levels[i]=1/Math.pow(i+1,2);
let k=i/2;
phase.levels[i]=k%2===1?.5:0;
}else{
amp.levels[i]=0;
phase.levels[i]=0;
}
}
}}
].map((e,i)=>new Button(waveform.x+bW*(i%bS),waveform.y+waveform.h+16+Math.floor(i/bS)*bH,bW,bH,e.label,e.onPress));
amp.levels[0]=1;amp.bgColor=[51,82,59];amp.fillColor=[154,201,101];
phase.bgColor=[50,63,97];phase.fillColor=[91,174,222];
waveform.update=function(){
let l=this.points.length;
for(let i=0;i<l;i++){
let sum=0;
for(let j=0;j<amp.levels.length;j++)
sum+=sineHarm(i/l,phase.levels[j],1+j)*amp.levels[j];
this.points[i]=sum;
}
let minVal=Math.min(...this.points),maxVal=Math.max(...this.points),
allEqual=this.points.every((val,i,arr)=>val===arr[0]);
this.bottomRange=allEqual?this.points[0]-1:minVal;
this.upperRange=allEqual?this.points[0]+1:maxVal;
};
waveform.update();
function setup(){
createCanvas(windowWidth,windowHeight);
}
function draw(){
background(200);
for(let o of[amp,phase,waveform,...buttons])o.display();
}
function mousePressed(){
for(let o of[amp,phase,...buttons])o.pressed(mouseX,mouseY);
waveform.update();
}
function mouseDragged(){
for(let o of[amp,phase])o.drag(mouseX,mouseY);
waveform.update();
}
function mouseReleased(){
for(let o of[amp,phase])o.released(mouseX,mouseY);
}