1var Engine = Matter.Engine, 2 Events = Matter.Events, 3 Render = Matter.Render, 4 Runner = Matter.Runner, 5 Composite = Matter.Composite, 6 Composites = Matter.Composites, 7 Common = Matter.Common, 8 MouseConstraint = Matter.MouseConstraint, 9 Mouse = Matter.Mouse, 10 World = Matter.World, 11 Bounds = Matter.Bounds, 12 Vertices = Matter.Vertices, 13 Bodies = Matter.Bodies, 14 Body = Matter.Body; 15 16// create engine 17var engine, world; 18 19var mouseBounds; 20 21var mouseStartX; 22var mouseStartY; 23 24var dripSamples = ["drip0", "drip1", "drip2"]; 25 26var drippers = []; 27var droplets = []; 28var bars = []; 29var waves = []; 30 31var reverb, delay; 32 33var collisionThreshold = 0.1; 34 35var tuneNotes = true; 36var keySig = [0, 2, 4, 5, 7, 9, 10]; 37var drawWaves = true; 38 39var zoneY = 50; 40 41var maxFreq = 100000; 42var modMultiplier = 3; 43var modIndex = 20; 44var widthRange = { 45 min: 50, 46 max: 1000, 47}; 48 49var backgroundColour; 50 51var tempo = 15; 52 53var isMobile = false; 54 55for (var i = 1; i <= 8; i++) { 56 setInterval(metronome, 60000 / tempo / i, i); 57} 58 59function preload() { 60 soundFormats("wav"); 61} 62 63function setup() { 64 engine = Engine.create({ 65 enableSleeping: true, 66 }); 67 world = engine.world; 68 reverb = new p5.Reverb(); 69 reverb.set(6, 2); 70 71 delay = new p5.Delay(); 72 delay.delayTime(0.5); 73 delay.feedback(0.5); 74 Engine.run(engine); 75 76 backgroundColour = color(19, 21, 23); 77 smooth(); 78 cursor(CROSS); 79 mouseBounds = Bounds.create(); 80 81 if ( 82 /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test( 83 navigator.userAgent 84 ) || 85 /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
86 navigator.userAgent.substr(0, 4) 87 ) 88 ) { 89 isMobile = true; 90 } 91 92 createCanvas(window.innerWidth, window.innerHeight); 93 94 drippers.push( 95 new Dripper(random(width * 0.33, width * 0.66), round(random(2, 4))) 96 ); 97} 98 99function draw() { 100 background(backgroundColour); 101 stroke(255); 102 strokeWeight(1); 103 line(0, zoneY, width, zoneY); 104 105 if (!isMobile || (isMobile && touches.length > 0)) checkMouseTarget(); 106 107 for (let w of waves) { 108 w.update(); 109 } 110 for (let d of droplets) { 111 d.update(); 112 } 113 for (let b of bars) { 114 b.update(); 115 } 116 for (let d of drippers) { 117 d.update(); 118 } 119} 120 121class Dripper { 122 constructor(x, rate) { 123 this.x = x; 124 this.rate = rate; 125 126 this.mouseOver = false; 127 this.readyToDelete = false; 128 129 this.mouseTarget = null; 130 this.transformMode = null; 131 132 this.rotation = Math.PI / 2; 133 134 this.dripSounds = []; 135 for (let i = 0; i < dripSamples.length; i++) { 136 this.dripSounds[i] = loadSound(dripSamples[i]); 137 this.dripSounds[i].amp(0.5); 138 this.dripSounds[i].connect(reverb); 139 } 140 } 141 142 update() { 143 if (this.rotation > Math.PI * 1.5) { 144 this.rotation = Math.PI / 2; 145 this.rate--; 146 } else if (this.rotation < Math.PI / 2) { 147 this.rotation = Math.PI * 1.5; 148 this.rate++; 149 } 150 this.rate = constrain(this.rate, 0, 8); 151 fill(255); 152 noStroke(); 153 textAlign(CENTER, CENTER); 154 text(this.rate, this.x, zoneY - 35); 155 fill(backgroundColour); 156 if (this.readyToDelete) stroke(255, 127); 157 else stroke(255); 158 if (this.mouseTarget == "Move" || this.transformMode == "Move") 159 strokeWeight(2); 160 else strokeWeight(1); 161 162 var phase = sin(this.rotation); 163 var xPositions = [ 164 map(phase, -1, 1, 25, 35), 165 map(phase, -1, 1, 15, 45), 166 map(phase, -1, 1, 35, 25), 167 map(phase, -1, 1, 45, 15), 168 ]; 169 fill(backgroundColour); 170 beginShape(); 171 vertex(this.x + 5, zoneY + 10); 172 vertex(this.x + 5, zoneY - 10); 173 vertex(this.x + 25, zoneY - 10); 174 vertex(this.x + 25, zoneY); 175 vertex(this.x + 35, zoneY); 176 vertex(this.x + 35, zoneY - 20); 177 vertex(this.x - 5, zoneY - 20); 178 vertex(this.x - 5, zoneY + 10); 179 endShape(CLOSE); 180 181 beginShape(); 182 vertex(this.x + 32, zoneY - 20); 183 vertex(this.x + 32, zoneY - 30); 184 vertex(this.x + 28, zoneY - 30); 185 vertex(this.x + 28, zoneY - 20); 186 endShape(CLOSE); 187 188 if (this.mouseTarget == "Turn" || this.transformMode == "Turn") 189 strokeWeight(2); 190 else if (this.mouseTarget == null && this.transformMode == null) 191 strokeWeight(1); 192 193 beginShape(); 194 vertex(this.x + xPositions[2], zoneY - 33); 195 vertex(this.x + xPositions[2], zoneY - 37); 196 vertex(this.x + xPositions[3], zoneY - 37); 197 vertex(this.x + xPositions[3], zoneY - 33); 198 endShape(CLOSE); 199 200 if (this.mouseTarget == null && this.transformMode == null) strokeWeight(1); 201 202 beginShape(); 203 vertex(this.x + 35, zoneY - 30); 204 vertex(this.x + 35, zoneY - 40); 205 vertex(this.x + 25, zoneY - 40); 206 vertex(this.x + 25, zoneY - 30); 207 endShape(CLOSE); 208 209 if (this.mouseTarget == "Turn" || this.transformMode == "Turn") 210 strokeWeight(2); 211 else if (this.mouseTarget == null && this.transformMode == null) 212 strokeWeight(1); 213 214 beginShape(); 215 vertex(this.x + xPositions[1], zoneY - 33); 216 vertex(this.x + xPositions[1], zoneY - 37); 217 vertex(this.x + xPositions[0], zoneY - 37); 218 vertex(this.x + xPositions[0], zoneY - 33); 219 endShape(CLOSE); 220 221 if (this.transformMode == "Move") { 222 if (!isMobile) this.x += mouseX - pmouseX; 223 else this.x = mouseX; 224 if (mouseX <= 5 || mouseX >= width - 5) this.readyToDelete = true; 225 else this.readyToDelete = false; 226 227 //this.dripSound.pan(map(this.x, 0, width, -1, 1)); 228 } 229 if (this.transformMode == "Turn") { 230 let delta = (mouseX - pmouseX) / -15; 231 if (!(delta < 0 && this.rate >= 8) && !(delta > 0 && this.rate <= 0)) 232 this.rotation += delta; 233 } 234 } 235 236 playDripSound() { 237 let dripSound = 238 this.dripSounds[Math.floor(Math.random() * this.dripSounds.length)]; 239 dripSound.rate(random(0.5, 1.5)); 240 dripSound.pan(map(this.x, 0, width, -1, 1)); 241 dripSound.play(); 242 } 243 244 checkMouseTarget() { 245 if (mouseX > this.x - 5 && mouseX < this.x + 45) { 246 if (mouseY < zoneY && mouseY > zoneY - 20) this.mouseTarget = "Move"; 247 else if (mouseY < zoneY - 20) this.mouseTarget = "Turn"; 248 else this.mouseTarget = null; 249 } else this.mouseTarget = null; 250 } 251 252 checkIfClicked() { 253 if (isMobile) this.checkMouseTarget(); 254 this.transformMode = this.mouseTarget; 255 if (this.transformMode != null) return true; 256 } 257 258 mouseUp() { 259 this.transformMode = null; 260 if (isMobile) this.mouseTarget = null; 261 if (this.readyToDelete) this.destroy(); 262 } 263 264 destroy() { 265 drippers.splice(drippers.indexOf(this), 1); 266 } 267 268 drip() { 269 droplets.push(new Droplet(this.x, zoneY, 6)); 270 this.playDripSound(); 271 } 272} 273 274class Droplet { 275 constructor(x, y, size) { 276 this.size = size; 277 this.trailX = []; 278 this.trailY = []; 279 this.body = Bodies.circle(x, y, size / 2, { 280 restitution: 1.0, 281 friction: 0.01, 282 collisionFilter: { 283 category: 0o1, 284 mask: 0o2, 285 }, 286 }); 287 World.add(world, this.body); 288 } 289 290 update() { 291 var pos = this.body.position; 292 293 this.trailX.unshift(pos.x); 294 this.trailY.unshift(pos.y); 295 if (this.trailX.length > this.size) this.trailX.pop(); 296 if (this.trailY.length > this.size) this.trailY.pop(); 297 298 var angle = this.body.angle; 299 300 for (let i = 1; i < this.trailX.length; i++) { 301 strokeWeight(this.size - i); 302 stroke(255, 255, 255, 127 - i * 20); 303 304 line( 305 this.trailX[i], 306 this.trailY[i], 307 this.trailX[i - 1], 308 this.trailY[i - 1] 309 ); 310 } 311 312 strokeWeight(this.size);
313 stroke(255); 314 point(pos.x, pos.y); 315 316 if (pos.y > height) this.destroy(); 317 if (this.body.isSleeping) this.destroy(); 318 } 319 320 destroy() { 321 World.remove(world, this.body); 322 droplets.splice(droplets.indexOf(this), 1); 323 } 324} 325 326class Bar { 327 constructor(x, y, w, h, a) { 328 this.w = w; 329 this.h = h; 330 this.a = a; 331 this.struck = 0.0; 332 333 this.mouseA; 334 this.pmouseA; 335 this.mouseMoveA; 336 337 //Main Envelope 338 this.env = new p5.Env(); 339 340 this.sound = loadSound("glockenspiel"); 341 this.sound.connect(reverb); 342 this.sound.connect(delay); 343 this.sound.amp(this.env); 344 345 //Main Oscillator 346 this.osc = new p5.Oscillator(); 347 this.osc.amp(this.env); 348 this.osc.connect(reverb); 349 this.osc.connect(delay); 350 this.osc.start(); 351 352 this.body = Bodies.rectangle(x, y, w, h, { 353 isStatic: true, 354 collisionFilter: { 355 category: 0o2, 356 }, 357 }); 358 359 Body.setAngle(this.body, a); 360 World.add(world, this.body); 361 362 this.vertices = this.body.vertices; 363 this.edges = [ 364 { 365 x0: this.vertices[0].x, 366 y0: this.vertices[0].y, 367 x1: this.vertices[1].x, 368 y1: this.vertices[1].y, 369 hovered: false, 370 }, 371 { 372 x0: this.vertices[1].x, 373 y0: this.vertices[1].y, 374 x1: this.vertices[2].x, 375 y1: this.vertices[2].y, 376 hovered: false, 377 }, 378 { 379 x0: this.vertices[2].x, 380 y0: this.vertices[2].y, 381 x1: this.vertices[3].x, 382 y1: this.vertices[3].y, 383 hovered: false, 384 }, 385 { 386 x0: this.vertices[3].x, 387 y0: this.vertices[3].y, 388 x1: this.vertices[0].x, 389 y1: this.vertices[0].y, 390 hovered: false, 391 }, 392 ]; 393 394 this.mouseOver = false; 395 this.mouseSelected = false; 396 this.transformMode = null; 397 this.mouseTarget = null; 398 this.readyToDelete = false; 399 400 this.startVertices = this.vertices; 401 this.newVertices = this.vertices; 402 403 this.updateParameters(); 404 } 405 406 updateParameters() { 407 var pos = Vertices.centre(this.body.vertices); 408 409 this.decay = map(this.h, 15, 50, 0.3, 0.75); 410 this.env.setADSR(0.01, this.decay, 0.0, this.decay); 411 this.freq = maxFreq / this.w; 412 if (tuneNotes) { 413 this.pitch = freqToMidi(this.freq); 414 this.pitch = tuneNote(this.pitch); 415 this.freq = midiToFreq(this.pitch); 416 } 417 418 this.osc.freq(this.freq); 419 this.osc.pan(map(pos.x, 0, width, -1, 1)); 420 this.sound.rate(this.freq / 523.25); 421 this.sound.pan(map(pos.x, 0, width, -1, 1)); 422 } 423 424 update() { 425 var colour = lerpColor(backgroundColour, color(255), this.struck); 426 this.vertices = this.body.vertices; 427 428 this.edges = [ 429 { 430 x0: this.vertices[0].x, 431 y0: this.vertices[0].y, 432 x1: this.vertices[1].x, 433 y1: this.vertices[1].y, 434 }, 435 { 436 x0: this.vertices[1].x, 437 y0: this.vertices[1].y, 438 x1: this.vertices[2].x, 439 y1: this.vertices[2].y, 440 }, 441 { 442 x0: this.vertices[2].x, 443 y0: this.vertices[2].y, 444 x1: this.vertices[3].x, 445 y1: this.vertices[3].y, 446 }, 447 { 448 x0: this.vertices[3].x, 449 y0: this.vertices[3].y, 450 x1: this.vertices[0].x, 451 y1: this.vertices[0].y, 452 }, 453 ]; 454 455 if (this.readyToDelete) stroke(255, 127); 456 else stroke(255); 457 strokeWeight(1); 458 459 strokeWeight(2); 460 if ( 461 this.mouseTarget == "ScaleHeight" || 462 this.transformMode == "ScaleHeight" 463 ) { 464 this.drawArrow("Top"); 465 this.drawArrow("Bottom"); 466 strokeWeight(1); 467 } else if ( 468 this.mouseTarget == "ScaleWidth" || 469 this.transformMode == "ScaleWidth" 470 ) { 471 this.drawArrow("Left"); 472 this.drawArrow("Right"); 473 strokeWeight(1); 474 } else if (this.mouseTarget == "Move" || this.transformMode == "Move") { 475 strokeWeight(2); 476 //this.drawArrow("Left"); 477 //this.drawArrow("Right"); 478 //this.drawArrow("Top"); 479 //this.drawArrow("Bottom"); 480 //strokeWeight(1); 481 } else if (this.mouseTarget == "Turn" || this.transformMode == "Turn") { 482 strokeWeight(2);
483 stroke(255); 484 noFill(); 485 this.drawArrow("Rotation"); 486 strokeWeight(1); 487 } else strokeWeight(1); 488 489 fill(colour); 490 beginShape(); 491 vertex(this.vertices[0].x, this.vertices[0].y); 492 vertex(this.vertices[1].x, this.vertices[1].y); 493 vertex(this.vertices[2].x, this.vertices[2].y); 494 vertex(this.vertices[3].x, this.vertices[3].y); 495 endShape(CLOSE); 496 497 if (this.struck > 0.0) { 498 this.struck -= 0.05; 499 } 500 501 for (let d of droplets) { 502 var collision = Matter.SAT.collides(this.body, d.body); 503 504 if (collision.collided) { 505 var magnitude = dotProduct(collision.normal, collision.bodyB.velocity); 506 if (magnitude < 0) magnitude *= -1; 507 508 this.strike( 509 magnitude, 510 collision.bodyB.position.x, 511 collision.bodyB.position.y 512 ); 513 } 514 } 515 } 516 517 checkMouseTarget() { 518 var centre = Vertices.centre(this.body.vertices); 519 var mouseDistance = dist(centre.x, centre.y, mouseX, mouseY); 520 if (this.transformMode == null) { 521 if (isMouseOnLine(this.edges[0], 6) || isMouseOnLine(this.edges[2], 6)) { 522 this.mouseTarget = "ScaleHeight"; 523 return true; 524 } else if ( 525 isMouseOnLine(this.edges[1], 6) || 526 isMouseOnLine(this.edges[3], 6) 527 ) { 528 this.mouseTarget = "ScaleWidth"; 529 return true; 530 } else if ( 531 Vertices.contains(this.body.vertices, { 532 x: mouseX, 533 y: mouseY, 534 }) 535 ) { 536 this.mouseTarget = "Move"; 537 return true; 538 } else if (mouseDistance < 75) { 539 strokeWeight(1); 540 stroke(255); 541 noFill(); 542 this.drawArrow("Rotation"); 543 if (mouseDistance < 57 && mouseDistance > 43) { 544 this.mouseTarget = "Turn"; 545 return true; 546 } else { 547 this.mouseTarget = null; 548 return true; 549 } 550 } else if (this.transformMode != null) { 551 this.mouseTarget = transformMode; 552 return true; 553 } else { 554 this.mouseTarget = null; 555 return false; 556 } 557 } else return false; 558 } 559 560 drawArrow(side) { 561 switch (side) { 562 case "Top": 563 line( 564 this.edges[0].x0, 565 this.edges[0].y0, 566 this.edges[0].x1, 567 this.edges[0].y1 568 ); 569 var midpoint = { 570 x: (this.edges[0].x0 + this.edges[0].x1) / 2, 571 y: (this.edges[0].y0 + this.edges[0].y1) / 2, 572 }; 573 var target = { 574 x: midpoint.x + 50 * cos(this.body.angle - Math.PI / 2), 575 y: midpoint.y + 50 * sin(this.body.angle - Math.PI / 2), 576 }; 577 line(midpoint.x, midpoint.y, target.x, target.y); 578 line( 579 target.x, 580 target.y, 581 target.x + 10 * cos(this.body.angle + Math.PI / 4), 582 target.y + 10 * sin(this.body.angle + Math.PI / 4) 583 ); 584 line( 585 target.x, 586 target.y, 587 target.x + 10 * cos(this.body.angle + (Math.PI / 4) * 3), 588 target.y + 10 * sin(this.body.angle + (Math.PI / 4) * 3) 589 ); 590 break; 591 case "Right": 592 line( 593 this.edges[1].x0, 594 this.edges[1].y0, 595 this.edges[1].x1, 596 this.edges[1].y1 597 ); 598 var midpoint = { 599 x: (this.edges[1].x0 + this.edges[1].x1) / 2, 600 y: (this.edges[1].y0 + this.edges[1].y1) / 2, 601 }; 602 var target = { 603 x: midpoint.x + 50 * cos(this.body.angle), 604 y: midpoint.y + 50 * sin(this.body.angle), 605 }; 606 line(midpoint.x, midpoint.y, target.x, target.y); 607 line( 608 target.x, 609 target.y, 610 target.x + 10 * cos(this.body.angle + (Math.PI / 4) * 5), 611 target.y + 10 * sin(this.body.angle + (Math.PI / 4) * 5) 612 ); 613 line( 614 target.x, 615 target.y, 616 target.x + 10 * cos(this.body.angle + (Math.PI / 4) * 3), 617 target.y + 10 * sin(this.body.angle + (Math.PI / 4) * 3) 618 ); 619 break; 620 case "Bottom": 621 line( 622 this.edges[2].x0, 623 this.edges[2].y0, 624 this.edges[2].x1, 625 this.edges[2].y1 626 ); 627 var midpoint = { 628 x: (this.edges[2].x0 + this.edges[2].x1) / 2, 629 y: (this.edges[2].y0 + this.edges[2].y1) / 2, 630 }; 631 var target = { 632 x: midpoint.x + 50 * cos(this.body.angle + Math.PI / 2), 633 y: midpoint.y + 50 * sin(this.body.angle + Math.PI / 2), 634 }; 635 line(midpoint.x, midpoint.y, target.x, target.y); 636 line( 637 target.x, 638 target.y, 639 target.x + 10 * cos(this.body.angle - Math.PI / 4), 640 target.y + 10 * sin(this.body.angle - Math.PI / 4) 641 ); 642 line( 643 target.x, 644 target.y, 645 target.x + 10 * cos(this.body.angle - (Math.PI / 4) * 3), 646 target.y + 10 * sin(this.body.angle - (Math.PI / 4) * 3) 647 ); 648 break; 649 case "Left": 650 line( 651 this.edges[3].x0, 652 this.edges[3].y0, 653 this.edges[3].x1, 654 this.edges[3].y1 655 ); 656 var midpoint = { 657 x: (this.edges[3].x0 + this.edges[3].x1) / 2, 658 y: (this.edges[3].y0 + this.edges[3].y1) / 2, 659 }; 660 var target = { 661 x: midpoint.x + 50 * cos(this.body.angle + Math.PI), 662 y: midpoint.y + 50 * sin(this.body.angle + Math.PI), 663 }; 664 line(midpoint.x, midpoint.y, target.x, target.y); 665 line( 666 target.x, 667 target.y, 668 target.x + 10 * cos(this.body.angle - (Math.PI / 4) * 7), 669 target.y + 10 * sin(this.body.angle - (Math.PI / 4) * 7) 670 ); 671 line( 672 target.x, 673 target.y, 674 target.x + 10 * cos(this.body.angle - Math.PI / 4), 675 target.y + 10 * sin(this.body.angle - Math.PI / 4) 676 ); 677 break; 678 case "Rotation": 679 var centre = Vertices.centre(this.body.vertices); 680 var arrowLength = Math.PI / 40; 681 ellipse(centre.x, centre.y, 100, 100); 682 5; 683 line( 684 centre.x + 50 * cos(this.body.angle - Math.PI / 2 + arrowLength), 685 centre.y + 50 * sin(this.body.angle - Math.PI / 2 + arrowLength), 686 centre.x + 57 * cos(this.body.angle - Math.PI / 2 - arrowLength), 687 centre.y + 57 * sin(this.body.angle - Math.PI / 2 - arrowLength) 688 ); 689 line( 690 centre.x + 50 * cos(this.body.angle - Math.PI / 2 + arrowLength), 691 centre.y + 50 * sin(this.body.angle - Math.PI / 2 + arrowLength), 692 centre.x + 43 * cos(this.body.angle - Math.PI / 2 - arrowLength), 693 centre.y + 43 * sin(this.body.angle - Math.PI / 2 - arrowLength) 694 ); 695 line( 696 centre.x + 50 * cos(this.body.angle + Math.PI / 2 + arrowLength), 697 centre.y + 50 * sin(this.body.angle + Math.PI / 2 + arrowLength), 698 centre.x + 57 * cos(this.body.angle + Math.PI / 2 - arrowLength), 699 centre.y + 57 * sin(this.body.angle + Math.PI / 2 - arrowLength) 700 ); 701 line( 702 centre.x + 50 * cos(this.body.angle + Math.PI / 2 + arrowLength), 703 centre.y + 50 * sin(this.body.angle + Math.PI / 2 + arrowLength), 704 centre.x + 43 * cos(this.body.angle + Math.PI / 2 - arrowLength), 705 centre.y + 43 * sin(this.body.angle + Math.PI / 2 - arrowLength) 706 ); 707 break; 708 } 709 } 710 711 updateTransform(mode) { 712 var mouseMoveX = mouseX - pmouseX; 713 var mouseMoveY = mouseY - pmouseY; 714 715 var centre = Vertices.centre(this.body.vertices); 716 717 this.mouseA = atan2(mouseY - centre.y, mouseX - centre.x); 718 if (this.pmouseA != undefined) this.mouseMoveA = this.mouseA - this.pmouseA; 719 else this.mouseMoveA = 0; 720 this.pmouseA = this.mouseA; 721 722 switch (mode) { 723 case "Move": 724 Body.setPosition(this.body, { 725 x: mouseX, 726 y: mouseY, 727 }); 728 if ( 729 mouseX <= 5 || 730 mouseX >= width - 5 || 731 mouseY <= zoneY || 732 mouseY >= height - 5 733 ) 734 this.readyToDelete = true; 735 else this.readyToDelete = false;
736 break; 737 case "ScaleHeight": 738 var nearestPoint = nearestPointOnLine({ 739 x0: (this.edges[3].x0 + this.edges[3].x1) / 2, 740 y0: (this.edges[3].y0 + this.edges[3].y1) / 2, 741 x1: (this.edges[1].x0 + this.edges[1].x1) / 2, 742 y1: (this.edges[1].y0 + this.edges[1].y1) / 2, 743 }); 744 this.h = dist(nearestPoint.x, nearestPoint.y, mouseX, mouseY) * 2; 745 //this.h -= mouseMoveY; 746 this.h = constrain(this.h, 15, 50); 747 var newX1 = 748 this.body.vertices[2].x + this.h * cos(this.body.angle - Math.PI / 2); 749 var newY1 = 750 this.body.vertices[2].y + this.h * sin(this.body.angle - Math.PI / 2); 751 var newX2 = 752 this.body.vertices[3].x + this.h * cos(this.body.angle - Math.PI / 2); 753 var newY2 = 754 this.body.vertices[3].y + this.h * sin(this.body.angle - Math.PI / 2); 755 756 Body.setVertices(this.body, [ 757 { 758 x: centre.x + newX2, 759 y: centre.y + newY2, 760 }, 761 { 762 x: centre.x + newX1, 763 y: centre.y + newY1, 764 }, 765 { 766 x: centre.x + this.body.vertices[2].x, 767 y: centre.y + this.body.vertices[2].y, 768 }, 769 { 770 x: centre.x + this.body.vertices[3].x, 771 y: centre.y + this.body.vertices[3].y, 772 }, 773 ]); 774 break; 775 case "ScaleWidth": 776 var nearestPoint = nearestPointOnLine({ 777 x0: (this.edges[0].x0 + this.edges[0].x1) / 2, 778 y0: (this.edges[0].y0 + this.edges[0].y1) / 2, 779 x1: (this.edges[2].x0 + this.edges[2].x1) / 2, 780 y1: (this.edges[2].y0 + this.edges[2].y1) / 2, 781 }); 782 this.w = dist(nearestPoint.x, nearestPoint.y, mouseX, mouseY) * 2; 783 this.w = constrain(this.w, widthRange.min, widthRange.max); 784 var newX1 = this.body.vertices[3].x + this.w * cos(this.body.angle); 785 var newY1 = this.body.vertices[3].y + this.w * sin(this.body.angle); 786 var newX2 = this.body.vertices[0].x + this.w * cos(this.body.angle); 787 var newY2 = this.body.vertices[0].y + this.w * sin(this.body.angle); 788 789 Body.setVertices(this.body, [ 790 { 791 x: centre.x + this.body.vertices[0].x, 792 y: centre.y + this.body.vertices[0].y, 793 }, 794 { 795 x: centre.x + newX2, 796 y: centre.y + newY2, 797 }, 798 { 799 x: centre.x + newX1, 800 y: centre.y + newY1, 801 }, 802 { 803 x: centre.x + this.body.vertices[3].x, 804 y: centre.y + this.body.vertices[3].y, 805 }, 806 ]); 807 break; 808 case "Turn": 809 Body.rotate(this.body, this.mouseMoveA); 810 break; 811 default: 812 break; 813 } 814 815 this.updateParameters(); 816 } 817 818 checkIfClicked() { 819 if (isMobile) this.checkMouseTarget(); 820 this.transformMode = this.mouseTarget; 821 this.mouseA = atan2( 822 mouseY - Vertices.centre(this.body.vertices).y, 823 mouseX - Vertices.centre(this.body.vertices).x 824 ); 825 //if (this.pmouseA != undefined) this.mouseMoveA = this.mouseA - this.pmouseA; 826 //else this.mouseMoveA = 0; 827 this.pmouseA = this.mouseA; 828 if (this.transformMode != null) return true; 829 } 830 831 mouseUp() { 832 this.transformMode = null; 833 if (isMobile) this.mouseTarget = null; 834 if (this.readyToDelete) this.destroy(); 835 } 836 837 strike(magnitude, x, y) { 838 if (magnitude > collisionThreshold) { 839 if (this.sound.isLoaded()) this.sound.play(); 840 this.env.setRange(map(magnitude, 0, 10, 0.1, 0.3), 0.0); 841 let attack = map(magnitude, 0, 2, 0.3, 0.01); 842 if (attack < 0.01) attack = 0.01; 843 if (attack <= 0.05) attack = 0.01; 844 this.env.setADSR(attack, this.decay, 0.0, this.decay); 845 this.env.play(); 846 //this.env2.play(); 847 this.struck = map(magnitude, 0, 20, 0.0, 1.0); 848 if (drawWaves) waves.push(new wave(x, y, magnitude)); 849 } 850 851 //Bug fix for magnitude 0 collisions when bar first spawns 852 else if (magnitude == 0) { 853 if (this.sound.isLoaded()) this.sound.play(); 854 this.env.setRange(0.15); 855 //this.pitchEnv.play(); 856 this.env.play(); 857 //this.env2.play(); 858 this.struck = 0.5; 859 if (drawWaves) waves.push(new wave(x, y, 10)); 860 } 861 } 862 863 destroy() { 864 World.remove(world, this.body); 865 this.osc.stop(); 866 bars.splice(bars.indexOf(this), 1); 867 } 868} 869 870class wave { 871 constructor(x, y, magnitude) { 872 this.x = x; 873 this.y = y; 874 this.size = 0; 875 this.alpha = map(magnitude, 0, 20, 0, 200); 876 } 877 878 update() { 879 if (this.alpha > 0) this.alpha -= 2; 880 else this.destroy(); 881 this.size += 10; 882 stroke(255, this.alpha); 883 noFill(); 884 ellipse(this.x, this.y, this.size, this.size); 885 } 886 887 destroy() { 888 waves.splice(waves.indexOf(this), 1); 889 } 890} 891 892function mousePressed() { 893 if ( 894 (!isMobile && mouseButton != RIGHT) || 895 (isMobile && event.type == "touchstart") 896 ) { 897 mouseStartX = mouseX; 898 mouseStartY = mouseY; 899 900 for (let b of bars) { 901 if (b.checkIfClicked()) return; 902 } 903 for (let d of drippers) { 904 if (d.checkIfClicked()) return; 905 } 906 907 if (mouseY < zoneY) { 908 drippers.push(new Dripper(mouseX, round(random(2, 6)))); 909 return; 910 } else { 911 bars.push( 912 new Bar( 913 mouseX, 914 mouseY, 915 pitchToWidth(findUnusedPitch()), 916 random(25, 50), 917 random(Math.PI / -4, Math.PI / 4) 918 ) 919 ); 920 return; 921 } 922 } 923} 924 925function mouseReleased() { 926 if (!isMobile || isMobile) { 927 for (let b of bars) { 928 b.mouseUp(); 929 } 930 for (let d of drippers) { 931 d.mouseUp(); 932 } 933 } 934} 935 936function touchMoved() { 937 for (let b of bars) { 938 if (b.transformMode != null) b.updateTransform(b.transformMode); 939 } 940} 941 942function checkMouseTarget() { 943 var selectedBar; 944 for (i = bars.length - 1; i >= 0; i--) { 945 bars[i].mouseTarget = null; 946 } 947 for (i = bars.length - 1; i >= 0; i--) { 948 if (bars[i].checkMouseTarget()) { 949 selectedBar = i; 950 break; 951 } 952 } 953 for (i = drippers.length - 1; i >= 0; i--) { 954 if (drippers[i].checkMouseTarget()) { 955 break; 956 } 957 } 958 return; 959} 960 961function keyPressed() { 962 if (keyCode == 66) { 963 //bars.push(new Bar(mouseX,mouseY,random(widthRange.min,widthRange.max/2),random(20,40),random(-0.5,0.5))); 964 bars.push( 965 new Bar( 966 mouseX, 967 mouseY, 968 random(50, 200), 969 random(20, 50), 970 random(Math.PI / -4, Math.PI / 4) 971 ) 972 ); 973 } 974 if (keyCode == 68) { 975 drippers.push(new Dripper(mouseX, round(random(2, 6)))); 976 } 977} 978 979function keyReleased() {} 980 981function isMouseOnLine(line, tolerance) { 982 // 983 lerp = function (a, b, x) { 984 return a + x * (b - a); 985 }; 986 var dx = line.x1 - line.x0; 987 var dy = line.y1 - line.y0; 988 var t = 989 ((mouseX - line.x0) * dx + (mouseY - line.y0) * dy) / (dx * dx + dy * dy); 990 t = constrain(t, 0, 1); 991 var lineX = lerp(line.x0, line.x1, t); 992 var lineY = lerp(line.y0, line.y1, t); 993 var dx = mouseX - lineX; 994 var dy = mouseY - lineY; 995 var distance = Math.abs(Math.sqrt(dx * dx + dy * dy)); 996 if (distance < tolerance) { 997 return true; 998 } else { 999 return false;
1000 } 1001} 1002 1003function nearestPointOnLine(line) { 1004 // 1005 lerp = function (a, b, x) { 1006 return a + x * (b - a); 1007 }; 1008 var dx = line.x1 - line.x0; 1009 var dy = line.y1 - line.y0; 1010 var t = 1011 ((mouseX - line.x0) * dx + (mouseY - line.y0) * dy) / (dx * dx + dy * dy); 1012 t = constrain(t, 0, 1); 1013 var lineX = lerp(line.x0, line.x1, t); 1014 var lineY = lerp(line.y0, line.y1, t); 1015 return { 1016 x: lineX, 1017 y: lineY, 1018 }; 1019} 1020 1021function metronome(step) { 1022 for (let d of drippers) { 1023 if (d.rate == step) d.drip(); 1024 } 1025} 1026 1027function printTotalObjects() { 1028 print("Bars: " + bars.length); 1029 print("Droplets: " + droplets.length); 1030 print("Drippers: " + drippers.length); 1031 print("Waves: " + waves.length); 1032 print( 1033 "Total: " + (bars.length + droplets.length + drippers.length + waves.length) 1034 ); 1035} 1036 1037function tuneNote(note) { 1038 var keys = keySig.slice(); 1039 var nearestA = Math.floor(note / 12) * 12; 1040 for (i = 0; i < keys.length; i++) { 1041 keys[i] += nearestA; 1042 } 1043 var closest = keys.reduce(function (prev, curr) { 1044 return Math.abs(curr - note) < Math.abs(prev - note) ? curr : prev; 1045 }); 1046 1047 return closest; 1048} 1049 1050function windowResized() { 1051 resizeCanvas(windowWidth, windowHeight); 1052} 1053 1054function dotProduct(vector1, vector2) { 1055 return (vector1.x * vector2.x + vector1.y * vector2.y) * -1; 1056} 1057 1058function findUnusedPitch() { 1059 let usedPitches = []; 1060 let attempts = 0; 1061 for (let i = 0; i < bars.length; i++) { 1062 usedPitches.push(bars[i].pitch); 1063 } 1064 let randomPitch; 1065 1066 while (attempts < 40) { 1067 randomPitch = random(60, 95); 1068 if (tuneNotes) randomPitch = tuneNote(randomPitch); 1069 if (!usedPitches.includes(randomPitch)) break; 1070 } 1071 1072 return randomPitch; 1073} 1074 1075function pitchToWidth(pitch) { 1076 let freq = midiToFreq(pitch); 1077 return maxFreq / freq; 1078}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.