Tone.js/examples/funkyShape.html
2017-03-26 16:39:19 -04:00

287 lines
7.4 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>VISUALIZING ENVELOPES</title>
<!--
Funky Shape
Using Tone.js and p5.js
example written by Seth Kranzler
https://github.com/polyrhythmatic
-->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" type="image/png" sizes="174x174" href="./style/favicon.png">
<script src="./scripts/p5.js"></script>
<script src="../build/Tone.js"></script>
<script src="./scripts/p5.Tone.js"></script>
<script src="./scripts/jquery.min.js"></script>
<script src="./scripts/draggabilly.js"></script>
<script src="./scripts/StartAudioContext.js"></script>
<script src="./scripts/Interface.js"></script>
<script src="https://tonejs.github.io/Logo/build/Logo.js"></script>
<link rel="stylesheet" type="text/css" href="./style/examples.css">
<script>
// jshint ignore: start
</script>
</head>
<body>
<style type="text/css">
canvas {
position: absolute;
top: 0px;
z-index: -1;
}
</style>
<div id="Content" class="FullScreen">
<div id="Title">Using p5</div>
<div id="Explanation">
By accessing the envelope's current value, we can create responsive visuals that are directly tied to what is heard.
<br><br>
This sketch uses <a href="https://p5js.org" target="_blank">p5.js</a> for visual components.
</div>
</div>
<script id="p5">
//creating our class name
function FunkyShape() {}
/*
FunkyShape init gives initial and offset values for
the perlin noise functions in update.
Giving different initial values ensures that
each funky shape follows its own funky path
*/
FunkyShape.prototype.init = function(xInc, yInc, xOff, yOff, radius) {
this.xInc = xInc;
this.yInc = yInc;
this.xOff = xOff;
this.yOff = yOff;
this.radius = radius;
this.xPos = 0;
this.yPos = 0;
}
//updates the x, y, and radius values of the shape
FunkyShape.prototype.update = function(envelope) {
this.xPos = noise(this.xOff) * width;
this.yPos = noise(this.yOff) * height;
this.xOff += this.xInc;
this.yOff += this.yInc;
this.sRadius = this.radius * envelope;
return {
"xPos": this.xPos,
"yPos": this.yPos,
"radius": this.sRadius
};
}
//using our FunkyShape class
//to create a funkyCircle class
var funkyCircle = new FunkyShape();
//creating an empty array
var funkySquare = [];
//and populating it with 3 FunkyShapes
for (var i = 0; i < 3; i++) {
funkySquare[i] = new FunkyShape();
}
function setup() {
//create a canvas width and height of the screen
createCanvas(windowWidth, windowHeight);
//no fill
fill(255);
strokeWeight(1);
rectMode(CENTER);
//initializing our funky circle
funkyCircle.init(0.01, 0.02, 0.0, 0.0, 400);
//initializing our squares with random values
//to ensure they don't follow the same path
for (var i = 0; i < 3; i++) {
var xInc = Math.random() / 10;
var yInc = Math.random() / 10;
funkySquare[i].init(xInc, yInc, 0, 0, 800);
}
}
var phase = 0;
function draw() {
background(255);
stroke(0);
//drawing the kick wave at the bottom
//it is composed of a simple sine wave that
//changes in height with the kick envelope
for (var i = 0; i < width; i++) {
//scaling kickEnvelope value by 200
//since default is 0-1
var kickValue = kickEnvelope.value * 200;
//multiplying this value to scale the sine wave
//depending on x position
var yDot = Math.sin((i / 60) + phase) * kickValue;
point(i, height -150 + yDot);
}
//increasing phase means that the kick wave will
//not be standing and looks more dynamic
phase += 1;
//updating circle and square positions with
//bass and bleep envelope values
var circlePos = funkyCircle.update(bassEnvelope.value);
//circlePos returns x and y positions as an object
ellipse(circlePos.xPos, circlePos.yPos, circlePos.radius, circlePos.radius);
stroke('red');
for (var i = 0; i < 3; i++) {
var squarePos = funkySquare[i].update(bleepEnvelope.value);
rect(squarePos.xPos, squarePos.yPos, squarePos.radius, squarePos.radius);
}
}
</script>
<script id="Song">
//HATS
//filtering the hi-hats a bit
//to make them sound nicer
var lowPass = new Tone.Filter({
"frequency": 14000,
}).toMaster();
//we can make our own hi hats with
//the noise synth and a sharp filter envelope
var openHiHat = new Tone.NoiseSynth({
"volume" : -10,
"filter": {
"Q": 1
},
"envelope": {
"attack": 0.01,
"decay": 0.3
},
"filterEnvelope": {
"attack": 0.01,
"decay": 0.03,
"baseFrequency": 4000,
"octaves": -2.5,
"exponent": 4,
}
}).connect(lowPass);
var openHiHatPart = new Tone.Part(function(time){
openHiHat.triggerAttack(time);
}, ["2*8n", "6*8n"]).start(0);
var closedHiHat = new Tone.NoiseSynth({
"volume" : -10,
"filter": {
"Q": 1
},
"envelope": {
"attack": 0.01,
"decay": 0.15
},
"filterEnvelope": {
"attack": 0.01,
"decay": 0.03,
"baseFrequency": 4000,
"octaves": -2.5,
"exponent": 4,
}
}).connect(lowPass);
var closedHatPart = new Tone.Part(function(time){
closedHiHat.triggerAttack(time);
}, ["0*8n", "1*16n", "1*8n", "3*8n", "4*8n", "5*8n", "7*8n", "8*8n"]).start(0);
//BASS
var bassEnvelope = new Tone.AmplitudeEnvelope({
"attack": 0.01,
"decay": 0.2,
"sustain": 0,
"release": 0,
}).toMaster();
var bassFilter = new Tone.Filter({
"frequency": 600,
"Q": 8
});
var bass = new Tone.PulseOscillator("A2", 0.4).chain(bassFilter, bassEnvelope);
bass.start();
var bassPart = new Tone.Part(function(time, note){
bass.frequency.setValueAtTime(note, time);
bassEnvelope.triggerAttack(time);
}, [["0:0", "A1"],
["0:2", "G1"],
["0:2:2", "C2"],
["0:3:2", "A1"]]).start(0);
//BLEEP
var bleepEnvelope = new Tone.AmplitudeEnvelope({
"attack": 0.01,
"decay": 0.4,
"sustain": 0,
"release": 0,
}).toMaster();
var bleep = new Tone.Oscillator("A4").connect(bleepEnvelope);
bleep.start();
var bleepLoop = new Tone.Loop(function(time){
bleepEnvelope.triggerAttack(time);
}, "2n").start(0);
//KICK
var kickEnvelope = new Tone.AmplitudeEnvelope({
"attack": 0.01,
"decay": 0.2,
"sustain": 0,
"release": 0
}).toMaster();
var kick = new Tone.Oscillator("A2").connect(kickEnvelope).start();
kickSnapEnv = new Tone.FrequencyEnvelope({
"attack": 0.005,
"decay": 0.01,
"sustain": 0,
"release": 0,
"baseFrequency": "A2",
"octaves": 2.7
}).connect(kick.frequency);
var kickPart = new Tone.Part(function(time){
kickEnvelope.triggerAttack(time);
kickSnapEnv.triggerAttack(time);
}, ["0", "0:0:3", "0:2:0", "0:3:1"]).start(0);
//TRANSPORT
Tone.Transport.loopStart = 0;
Tone.Transport.loopEnd = "1:0";
Tone.Transport.loop = true;
// GUI //
Interface.Button({
type : "toggle",
text : "Start",
activeText : "Stop",
start : function(){
Tone.Transport.start("+0.1");
},
end : function(){
Tone.Transport.stop();
}
});
</script>
</body>
</html>