|
|
@@ -0,0 +1,307 @@
|
|
|
+import controlP5.*;
|
|
|
+import netP5.*;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ControlP5 cp5;
|
|
|
+
|
|
|
+// === EQ bands (fixed centers/Q, draggable gains in dB) ===
|
|
|
+float band1Gain = 0;
|
|
|
+float band2Gain = 0;
|
|
|
+final float band1Center = 0.3;
|
|
|
+final float band2Center = 0.7;
|
|
|
+final float bandQ = 10;
|
|
|
+boolean draggingBand1 = false;
|
|
|
+boolean draggingBand2 = false;
|
|
|
+
|
|
|
+// === Other effect parameters ===
|
|
|
+float delayTime = 0.5;
|
|
|
+float delayFeedback = 0.4;
|
|
|
+float distortionAmount= 0.5;
|
|
|
+float distortionMix = 0.5;
|
|
|
+float chorusAmount = 0.5;
|
|
|
+float chorusDryWet = 0.5;
|
|
|
+
|
|
|
+void setup() {
|
|
|
+ size(1680, 780, P3D);
|
|
|
+ // Use orthographic projection to render a perfect cube without perspective distortion
|
|
|
+ ortho(0, width, height, 0, -1000, 1000);
|
|
|
+ frameRate(125);
|
|
|
+ background(21,21,30);
|
|
|
+ noStroke();
|
|
|
+ surface.setResizable(false);
|
|
|
+ surface.setLocation(100, 100);
|
|
|
+
|
|
|
+ cp5 = new ControlP5(this);
|
|
|
+
|
|
|
+ // Envelope knobs
|
|
|
+ cp5.addKnob("AmpAttack").setLabel("Attack").setRange(0,1).setValue(0.4)
|
|
|
+ .setPosition(85,350).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+ cp5.addKnob("AmpRelease").setLabel("Release").setRange(0,1).setValue(0.4)
|
|
|
+ .setPosition(215,350).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+ cp5.addKnob("FilterAttack").setLabel("Attack").setRange(0,1).setValue(0.4)
|
|
|
+ .setPosition(405,350).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+ cp5.addKnob("FilterRelease").setLabel("Release").setRange(0,1).setValue(0.4)
|
|
|
+ .setPosition(535,350).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+ cp5.addKnob("PitchAttack").setLabel("Attack").setRange(0,1).setValue(0.4)
|
|
|
+ .setPosition(725,350).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+ cp5.addKnob("PitchRelease").setLabel("Release").setRange(0,1).setValue(0.4)
|
|
|
+ .setPosition(855,350).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+
|
|
|
+ // Distortion knobs
|
|
|
+ cp5.addKnob("distortionAmount").setLabel("Amount").setRange(0,1).setValue(distortionAmount)
|
|
|
+ .setPosition(405,550).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+ cp5.addKnob("distortionMix").setLabel("Mix").setRange(0,1).setValue(distortionMix)
|
|
|
+ .setPosition(535,550).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+
|
|
|
+ // Chorus knobs
|
|
|
+ cp5.addKnob("chorusAmount").setLabel("Amount").setRange(0,1).setValue(chorusAmount)
|
|
|
+ .setPosition(725,550).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+ cp5.addKnob("chorusDryWet").setLabel("Dry/Wet").setRange(0,1).setValue(chorusDryWet)
|
|
|
+ .setPosition(855,550).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+
|
|
|
+ // Delay knobs
|
|
|
+ cp5.addKnob("delayTime").setLabel("Time").setRange(0,1).setValue(delayTime)
|
|
|
+ .setPosition(1045,550).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+ cp5.addKnob("delayFeedback").setLabel("Feedback").setRange(0,1).setValue(delayFeedback)
|
|
|
+ .setPosition(1175,550).setRadius(45).setViewStyle(Knob.ARC)
|
|
|
+ .setColorBackground(color(21,21,30)).setColorForeground(color(255,178,44))
|
|
|
+ .setColorActive(color(250,170,40)).setFont(createFont("Futura",15));
|
|
|
+}
|
|
|
+
|
|
|
+void draw() {
|
|
|
+ background(21,21,30);
|
|
|
+
|
|
|
+ // Panels grid
|
|
|
+ stroke(64); fill(12);
|
|
|
+ rect(50,100,300,180,8);
|
|
|
+ rect(370,100,300,180,8);
|
|
|
+ rect(690,100,300,180,8);
|
|
|
+ rect(1010,100,300,180,8);
|
|
|
+ rect(1330,100,300,180,8);
|
|
|
+ rect(50,300,300,180,8);
|
|
|
+ rect(370,300,300,180,8);
|
|
|
+ rect(690,300,300,180,8);
|
|
|
+ rect(50,500,300,180,8);
|
|
|
+ rect(370,500,300,180,8);
|
|
|
+ rect(690,500,300,180,8);
|
|
|
+ rect(1010,500,300,180,8);
|
|
|
+ rect(1330,500,300,180,8);
|
|
|
+
|
|
|
+ // Labels
|
|
|
+ textAlign(CENTER, TOP);
|
|
|
+ fill(255); textSize(18);
|
|
|
+ text("Oscillator #1", 200, 110);
|
|
|
+ text("Oscillator #2", 520, 110);
|
|
|
+ text("Oscillator #3", 840, 110);
|
|
|
+ text("Filter", 1160,110);
|
|
|
+ text("LFO", 1480,110);
|
|
|
+ text("Amp Env", 200, 330);
|
|
|
+ text("Filter Env", 520, 330);
|
|
|
+ text("Pitch Env", 840, 330);
|
|
|
+ text("EQ", 200, 530);
|
|
|
+ text("Distortion", 520, 530);
|
|
|
+ text("Chorus", 840, 530);
|
|
|
+ text("Delay", 1160, 530);
|
|
|
+ text("Reverb", 1480, 530);
|
|
|
+
|
|
|
+ // Waveforms & graphs
|
|
|
+ SinWave();
|
|
|
+ SawtoothWave();
|
|
|
+ TriangleWave();
|
|
|
+ drawFilterGraph();
|
|
|
+ drawLFOWaveform();
|
|
|
+ drawEQGraph();
|
|
|
+
|
|
|
+ // --- Reverb: smaller wireframe cube ---
|
|
|
+ pushMatrix();
|
|
|
+ translate(1480, 590, 0);
|
|
|
+ rotateX(frameCount * 0.01f);
|
|
|
+ rotateY(frameCount * 0.013f);
|
|
|
+ rotateZ(frameCount * 0.007f);
|
|
|
+ noFill();
|
|
|
+ stroke(255, 178, 44);
|
|
|
+ strokeWeight(2);
|
|
|
+
|
|
|
+ float s = 20; // half-edge length = 20 → full cube = 40
|
|
|
+
|
|
|
+ // front face (z = +s)
|
|
|
+ line(-s,-s, s, s,-s, s);
|
|
|
+ line( s,-s, s, s, s, s);
|
|
|
+ line( s, s, s, -s, s, s);
|
|
|
+ line(-s, s, s, -s,-s, s);
|
|
|
+
|
|
|
+ // back face (z = -s)
|
|
|
+ line(-s,-s,-s, s,-s,-s);
|
|
|
+ line( s,-s,-s, s, s,-s);
|
|
|
+ line( s, s,-s, -s, s,-s);
|
|
|
+ line(-s, s,-s, -s,-s,-s);
|
|
|
+
|
|
|
+ // side edges
|
|
|
+ line(-s,-s, s, -s,-s,-s);
|
|
|
+ line( s,-s, s, s,-s,-s);
|
|
|
+ line( s, s, s, s, s,-s);
|
|
|
+ line(-s, s, s, -s, s,-s);
|
|
|
+ popMatrix();
|
|
|
+}
|
|
|
+
|
|
|
+void drawEQGraph() {
|
|
|
+ int x0=50, y0=500, w=300, h=180;
|
|
|
+ int midY = y0 + h/2;
|
|
|
+ stroke(64); fill(12);
|
|
|
+ rect(x0,y0,w,h,8);
|
|
|
+ stroke(80); fill(255);
|
|
|
+ textSize(12); textAlign(RIGHT, CENTER);
|
|
|
+ for(int i=0; i<=4; i++){
|
|
|
+ float db = map(i, 0, 4, +20, -60);
|
|
|
+ float yy = y0 + i*(h/4);
|
|
|
+ line(x0-5, yy, x0, yy);
|
|
|
+ text(nf(db,1,0)+" dB", x0-8, yy);
|
|
|
+ }
|
|
|
+ fill(255,178,44); textSize(14);
|
|
|
+ textAlign(LEFT, BOTTOM);
|
|
|
+ text("Low Band: "+nf(band1Gain,1,1)+" dB", x0+8, y0+h-8);
|
|
|
+ textAlign(RIGHT, BOTTOM);
|
|
|
+ text("High Band: "+nf(band2Gain,1,1)+" dB", x0+w-8, y0+h-8);
|
|
|
+ noFill(); stroke(255,178,44);
|
|
|
+ beginShape();
|
|
|
+ float g1n = map(band1Gain, -60, 20, -1, 1);
|
|
|
+ float g2n = map(band2Gain, -60, 20, -1, 1);
|
|
|
+ for(int i=0; i<=w; i++){
|
|
|
+ float norm = i/(float)w;
|
|
|
+ float d1 = g1n * exp(-sq((norm-band1Center)*bandQ));
|
|
|
+ float d2 = g2n * exp(-sq((norm-band2Center)*bandQ));
|
|
|
+ float y = midY - (d1 + d2)*(h/2);
|
|
|
+ vertex(x0+i, y);
|
|
|
+ }
|
|
|
+ endShape();
|
|
|
+ noStroke(); fill(255,178,44);
|
|
|
+ float hx1 = x0 + band1Center*w;
|
|
|
+ float hy1 = midY - map(band1Gain,-60,20,-1,1)*(h/2);
|
|
|
+ ellipse(hx1, hy1, 12, 12);
|
|
|
+ float hx2 = x0 + band2Center*w;
|
|
|
+ float hy2 = midY - map(band2Gain,-60,20,-1,1)*(h/2);
|
|
|
+ ellipse(hx2, hy2, 12, 12);
|
|
|
+}
|
|
|
+
|
|
|
+void mousePressed() {
|
|
|
+ int x0=50, y0=500, w=300, h=180;
|
|
|
+ float hy1 = map(band1Gain, 20, -60, y0, y0+h);
|
|
|
+ float hy2 = map(band2Gain, 20, -60, y0, y0+h);
|
|
|
+ if (dist(mouseX, mouseY, x0+band1Center*w, hy1) < 10) draggingBand1 = true;
|
|
|
+ else if (dist(mouseX, mouseY, x0+band2Center*w, hy2) < 10) draggingBand2 = true;
|
|
|
+}
|
|
|
+
|
|
|
+void mouseDragged() {
|
|
|
+ int y0=500, h=180;
|
|
|
+ if (draggingBand1) {
|
|
|
+ float cy = constrain(mouseY, y0, y0+h);
|
|
|
+ band1Gain = map(cy, y0+h, y0, -60, 20);
|
|
|
+ }
|
|
|
+ if (draggingBand2) {
|
|
|
+ float cy = constrain(mouseY, y0, y0+h);
|
|
|
+ band2Gain = map(cy, y0+h, y0, -60, 20);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void mouseReleased() {
|
|
|
+ draggingBand1 = draggingBand2 = false;
|
|
|
+}
|
|
|
+
|
|
|
+// ControlP5 callbacks (no-op)
|
|
|
+void AmpAttack(float v) {}
|
|
|
+void AmpRelease(float v) {}
|
|
|
+void FilterAttack(float v) {}
|
|
|
+void FilterRelease(float v) {}
|
|
|
+void PitchAttack(float v) {}
|
|
|
+void PitchRelease(float v) {}
|
|
|
+void distortionAmount(float v){ distortionAmount = v; }
|
|
|
+void distortionMix(float v) { distortionMix = v; }
|
|
|
+void chorusAmount(float v) { chorusAmount = v; }
|
|
|
+void chorusDryWet(float v) { chorusDryWet = v; }
|
|
|
+void delayTime(float v) { delayTime = v; }
|
|
|
+void delayFeedback(float v) { delayFeedback = v; }
|
|
|
+
|
|
|
+// Waveform & helpers
|
|
|
+void SinWave() {
|
|
|
+ stroke(255,178,44); noFill();
|
|
|
+ float phase = frameCount * 0.025f;
|
|
|
+ int yBase=210, amp=60, x0=70, x1=330;
|
|
|
+ beginShape();
|
|
|
+ for(int x=x0; x<=x1; x++){
|
|
|
+ float t = map(x,x0,x1,0,TWO_PI*2);
|
|
|
+ vertex(x,yBase+sin(t+phase)*amp);
|
|
|
+ }
|
|
|
+ endShape();
|
|
|
+}
|
|
|
+
|
|
|
+void SawtoothWave() {
|
|
|
+ stroke(255,178,44); noFill();
|
|
|
+ float phase=frameCount*0.025f; int yBase=210, x0=390, x1=650;
|
|
|
+ beginShape();
|
|
|
+ for(int x=x0; x<=x1; x++){
|
|
|
+ float t=map(x,x0,x1,0,2)+phase, p=t-floor(t), v=-1+p*2;
|
|
|
+ vertex(x,yBase+v*60);
|
|
|
+ }
|
|
|
+ endShape();
|
|
|
+}
|
|
|
+
|
|
|
+void TriangleWave() {
|
|
|
+ stroke(255,178,44); noFill();
|
|
|
+ float phase=frameCount*0.04f; int yBase=210, amp=60, x0=710, x1=970;
|
|
|
+ beginShape();
|
|
|
+ for(int x=x0; x<=x1; x++){
|
|
|
+ float t=map(x,x0,x1,0,4)+phase; int s=floor(t); float f=t-s;
|
|
|
+ float v=(s%2==0)?-1+f*2:1-f*2;
|
|
|
+ vertex(x,yBase+v*amp);
|
|
|
+ }
|
|
|
+ endShape();
|
|
|
+}
|
|
|
+
|
|
|
+void drawFilterGraph() {
|
|
|
+ stroke(255,178,44); noFill();
|
|
|
+ int x0=1030, y0=140, w=260, h=180;
|
|
|
+ beginShape();
|
|
|
+ for(int i=0;i<=w;i++){
|
|
|
+ float n=i/(float)w, m=1/sqrt(1+pow(n/0.5f,2));
|
|
|
+ vertex(x0+i, y0+(1-m)*h);
|
|
|
+ }
|
|
|
+ endShape();
|
|
|
+}
|
|
|
+
|
|
|
+void drawLFOWaveform() {
|
|
|
+ stroke(255,178,44); noFill();
|
|
|
+ int x0=1330, y0=100, w=260, h=180, m=20;
|
|
|
+ float phase=frameCount*0.02f;
|
|
|
+ beginShape();
|
|
|
+ for(int i=0;i<=w;i++){
|
|
|
+ float a=map(i,0,w,0,TWO_PI);
|
|
|
+ vertex(x0+m+i, y0+h/2+sin(a)*(h/2-10));
|
|
|
+ }
|
|
|
+ endShape();
|
|
|
+ float p=(phase%TWO_PI)/TWO_PI;
|
|
|
+ noStroke(); fill(255,178,44);
|
|
|
+ ellipse(x0+m+p*w, y0+h/2+sin(phase)*(h/2-10), 12,12);
|
|
|
+}
|