|
| 1 | +/** |
| 2 | + * Example: Apply a p5.EQ filter to a p5.Noise. |
| 3 | + * Visualize the sound with FFT. |
| 4 | + * Use control points to change the spline that shapes the soundwave |
| 5 | + */ |
| 6 | + |
| 7 | +var fft; |
| 8 | + |
| 9 | +var eq, eqSize; |
| 10 | + |
| 11 | +//Array to hold contrl points |
| 12 | +var cntrlPts = []; |
| 13 | +var ctrlPtRad, cntrlIndex; |
| 14 | + |
| 15 | +//Array to hold the spline vertices |
| 16 | +var splineVerts = []; |
| 17 | + |
| 18 | +var pressed; |
| 19 | +var description; |
| 20 | + |
| 21 | + |
| 22 | +var soundFile; |
| 23 | + |
| 24 | +function preload() { |
| 25 | + soundFormats('mp3', 'ogg'); |
| 26 | + soundFile = loadSound('../files/Soni_Ventorum_Wind_Quintet_-_08_-_Danzi_Wind_Quintet_Op_67_No_3_In_E-Flat_Major_4_Allegretto'); |
| 27 | +} |
| 28 | + |
| 29 | + |
| 30 | + |
| 31 | + |
| 32 | +function setup() { |
| 33 | + createCanvas(710, 256); |
| 34 | + //sound wave color |
| 35 | + fill(255, 40, 255); |
| 36 | + ctrlPtRad = 15; |
| 37 | + |
| 38 | + eqSize = 8; |
| 39 | + eq = new p5.EQ(eqSize); |
| 40 | + |
| 41 | + // Disconnect soundFile from master output. |
| 42 | + // Then, connect it to the EQ, so that we only hear the EQ'd sound |
| 43 | + soundFile.loop(); |
| 44 | + soundFile.disconnect(); |
| 45 | + soundFile.connect(eq); |
| 46 | + |
| 47 | + //use an fft to visualize the sound |
| 48 | + fft = new p5.FFT(); |
| 49 | + |
| 50 | + //Evenly spaced control points line up with logarithmically spaced |
| 51 | + //filter frequencies on the logarithmically drawn spectrum |
| 52 | + for (var i = 0; i < eqSize; i++) { |
| 53 | + cntrlPts[i] = new CntrlPt(i, |
| 54 | + //map(x, 0, Math.log(1024), 0, width), height/2); |
| 55 | + i + i*101, height/2); |
| 56 | + splineVerts[i] = [cntrlPts[i].x,cntrlPts[i].y]; |
| 57 | + |
| 58 | + } |
| 59 | + |
| 60 | + |
| 61 | + description = createDiv("p5.EQ:<br>"+ |
| 62 | + "Use the p5.EQ to shape a sound spectrum. The p5.EQ is "+ |
| 63 | + "built with Web Audio Biquad Filters (peaking mode) and can "+ |
| 64 | + "be set to use 3 or 8 bands."); |
| 65 | + description.position(10,300); |
| 66 | +} |
| 67 | + |
| 68 | +function draw() { |
| 69 | + background(30); |
| 70 | + |
| 71 | + // Draw every value in the FFT spectrum analysis where |
| 72 | + // x = lowest (10Hz) to highest (22050Hz) frequencies, |
| 73 | + // h = energy / amplitude at that frequency |
| 74 | + var spectrum = fft.analyze(); |
| 75 | + |
| 76 | + noStroke(); |
| 77 | + for (var i = 0; i< spectrum.length; i++){ |
| 78 | + //var x = map(i, 0, spectrum.length, 0, width); |
| 79 | + var x = map(Math.log((i+1)/8), 0, Math.log(spectrum.length/8), 0, width); |
| 80 | + var h = -height + map(spectrum[i], 0, 255, height, 0); |
| 81 | + rect(x, height, width/spectrum.length, h) ; |
| 82 | + |
| 83 | + } |
| 84 | + |
| 85 | + |
| 86 | + //When mouse is pressed, move relevant control point, then display all |
| 87 | + if (pressed) {cntrlPts[cntrlIndex].move();} |
| 88 | + |
| 89 | + for (var i = 0; i < cntrlPts.length; i++) { |
| 90 | + cntrlPts[i].display(); |
| 91 | + splineVerts[i] = [cntrlPts[i].x, cntrlPts[i].y]; |
| 92 | + } |
| 93 | + |
| 94 | + //Draw a spline to connect control points |
| 95 | + stroke(255,255,255); |
| 96 | + noFill(); |
| 97 | + beginShape(); |
| 98 | + curveVertex( splineVerts[0][0],splineVerts[0][1]) |
| 99 | + for (var i = 0; i < splineVerts.length; i++) { |
| 100 | + curveVertex( splineVerts[i][0],splineVerts[i][1]); |
| 101 | + } |
| 102 | + curveVertex( splineVerts[eqSize-1][0],splineVerts[eqSize-1][1]) |
| 103 | + endShape(); |
| 104 | +} |
| 105 | + |
| 106 | +//Class for each control point |
| 107 | +function CntrlPt(i,x,y){ |
| 108 | + this.c = color(255); |
| 109 | + this.x = x; |
| 110 | + this.y = y; |
| 111 | + this.index = i; |
| 112 | + |
| 113 | + this.display = function () { |
| 114 | + fill(this.c); |
| 115 | + ellipse(this.x,this.y,ctrlPtRad,ctrlPtRad); |
| 116 | + rectMode(CENTER); |
| 117 | + noStroke(); |
| 118 | + |
| 119 | + var upDown = this.index % 2 > 0 ? 1 : -1 |
| 120 | + var textY; |
| 121 | + var textX; |
| 122 | + if (this.index === 0) { |
| 123 | + textX = this.x + 10; |
| 124 | + } |
| 125 | + else if (this.index === eq.bands.length - 1){ |
| 126 | + textX = this.x - 70; |
| 127 | + } |
| 128 | + else{ |
| 129 | + textX = this.x - 18; |
| 130 | + } |
| 131 | + if (upDown > 0) { |
| 132 | + text("freq: " + eq.bands[this.index].freq(),textX,this.y + upDown*40); |
| 133 | + text("gain: " + eq.bands[this.index].gain(),textX,this.y + upDown *25); |
| 134 | + } else { |
| 135 | + text("gain: " + eq.bands[this.index].gain(),textX,this.y + upDown *40); |
| 136 | + text("freq: " + eq.bands[this.index].freq(),textX,this.y + upDown*25); |
| 137 | + } |
| 138 | + |
| 139 | + } |
| 140 | + |
| 141 | + this.move = function () { |
| 142 | + if (mouseX < 1) { this.x = 1;} |
| 143 | + else if (mouseX > width) {this.x = width -1;} |
| 144 | + else if (mouseY < 1) {this.y = 1;} |
| 145 | + else if (mouseY > height) {this.y = height - 1;} |
| 146 | + else { |
| 147 | + this.y = mouseY; |
| 148 | + eq.bands[this.index].biquad.gain.value = map(this.y, 0, height, 40, -40); |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + //Checks to see if mouse is ontop of control point |
| 153 | + this.mouseOver = function () { |
| 154 | + if (mouseX > this.x - ctrlPtRad && mouseX < this.x + ctrlPtRad |
| 155 | + && mouseY < this.y + ctrlPtRad && mouseY > this.y - ctrlPtRad){ |
| 156 | + return true; |
| 157 | + } else { |
| 158 | + return false; |
| 159 | + }s |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +function mousePressed(){ |
| 164 | + for (var i = 0; i < cntrlPts.length; i++) { |
| 165 | + if (cntrlPts[i].mouseOver()){ |
| 166 | + pressed = true; |
| 167 | + cntrlIndex = i; |
| 168 | + break; |
| 169 | + } |
| 170 | + } |
| 171 | +} |
| 172 | + |
| 173 | +function mouseReleased(){ |
| 174 | + pressed = false; |
| 175 | +} |
0 commit comments