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

174 lines
4.5 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Phasing</title>
<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="../build/Tone.js"></script>
<script src="./scripts/jquery.min.js"></script>
<script src="./scripts/draggabilly.js"></script>
<script src="https://tonejs.github.io/Logo/build/Logo.js"></script>
<script src="./scripts/StartAudioContext.js"></script>
<script src="./scripts/Interface.js"></script>
<link rel="stylesheet" type="text/css" href="./style/examples.css">
<script>
// jshint ignore: start
</script>
</head>
<body>
<style type="text/css">
#Left, #Right {
height: 200px;
width: 50%;
position: relative;
float: left;
margin-top: 5px;
margin-bottom: 5px;
}
.Button {
display: inline-block;
}
</style>
<div id="Content">
<div id="Title">Piano Phase</div>
<div id="Explanation">
By slightly slowing down the playbackRate of the Tone.Sequence in the right channel,
the two identical melodies phase against each other in interesting ways.
Composition by Steve Reich. Inspiration from Alexander Chen.
</div>
<canvas id="Left"></canvas>
<canvas id="Right"></canvas>
</div>
<script>
//set the bpm and time signature first
Tone.Transport.timeSignature = [6, 4];
Tone.Transport.bpm.value = 180;
//L/R channel merging
var merge = new Tone.Merge();
//a little reverb
var reverb = new Tone.Freeverb({
"roomSize" : 0.2,
"wet" : 0.3
});
merge.chain(reverb, Tone.Master);
//the synth settings
var synthSettings = {
"oscillator": {
"detune": 0,
"type": "custom",
"partials" : [2, 1, 2, 2],
"phase": 0,
"volume": 0
},
"envelope": {
"attack": 0.005,
"decay": 0.3,
"sustain": 0.2,
"release": 1,
},
"portamento": 0.01,
"volume": -20
};
//left and right synthesizers
var synthL = new Tone.Synth(synthSettings).connect(merge.left);
var synthR = new Tone.Synth(synthSettings).connect(merge.right);
//the two Tone.Sequences
var partL = new Tone.Sequence(function(time, note){
synthL.triggerAttackRelease(note, "8n", time);
}, ["E4", "F#4", "B4", "C#5", "D5", "F#4", "E4", "C#5", "B4", "F#4", "D5", "C#5"], "8n").start();
var partR = new Tone.Sequence(function(time, note){
synthR.triggerAttackRelease(note, "8n", time);
}, ["E4", "F#4", "B4", "C#5", "D5", "F#4", "E4", "C#5", "B4", "F#4", "D5", "C#5"], "8n").start("2m");
//set the playback rate of the right part to be slightly slower
partR.playbackRate = 0.985;
// GUI //
Interface.Button({
key : 32,
type : "toggle",
text : "Start",
activeText : "Stop",
start : function(){
Tone.Transport.start("+0.1");
},
end : function(){
Tone.Transport.stop();
}
});
//draw two circles
var leftCanvas = $("#Left");
var rightCanvas = $("#Right");
var leftContext = leftCanvas.get(0).getContext("2d");
var rightContext = rightCanvas.get(0).getContext("2d");
var canvasWidth = leftCanvas.width() * 2;
var canvasHeight = leftCanvas.height() * 2;
var radius = Math.min(canvasWidth, canvasHeight);
function sizeCanvas(){
canvasWidth = leftCanvas.width() * 2;
canvasHeight = leftCanvas.height() * 2;
radius = Math.min(canvasWidth, canvasHeight) * 0.8;
leftContext.canvas.width = canvasWidth;
leftContext.canvas.height = canvasHeight;
rightContext.canvas.width = canvasWidth;
rightContext.canvas.height = canvasHeight;
}
$(window).on("resize", sizeCanvas);
sizeCanvas();
var twoPi = Math.PI * 2;
function loop(){
requestAnimationFrame(loop);
leftContext.lineWidth = radius * 0.1;
rightContext.lineWidth = radius * 0.1;
//draw the left progress
leftContext.clearRect(0, 0, canvasWidth, canvasHeight);
leftContext.strokeStyle = "#7F33ED";
leftContext.save();
leftContext.translate(canvasWidth / 2, canvasHeight / 2);
leftContext.rotate(-Math.PI / 2);
leftContext.beginPath();
leftContext.arc(0, 0, radius/2, 0, twoPi * partL.progress, false);
leftContext.stroke();
leftContext.restore();
//draw the left progress
rightContext.clearRect(0, 0, canvasWidth, canvasHeight);
rightContext.strokeStyle = "#1EDF3E";
rightContext.save();
rightContext.translate(canvasWidth / 2, canvasHeight / 2);
rightContext.rotate(-Math.PI / 2);
rightContext.beginPath();
rightContext.arc(0, 0, radius/2, 0, twoPi * partR.progress, false);
rightContext.stroke();
rightContext.restore();
}
loop();
</script>
</body>
</html>