mirror of
https://github.com/Tonejs/Tone.js
synced 2024-12-27 03:53:07 +00:00
227 lines
5.8 KiB
HTML
227 lines
5.8 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>VISUALIZING ENVELOPES</title>
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
<link rel="icon" type="image/png" sizes="174x174" href="./favicon.png">
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.3/webcomponents-bundle.js"></script>
|
|
<link href="https://fonts.googleapis.com/css?family=Material+Icons&display=block" rel="stylesheet"/>
|
|
<script src="../build/Tone.js"></script>
|
|
<script src="./js/tone-ui.js"></script>
|
|
<script src="./js/components.js"></script>
|
|
</head>
|
|
<body>
|
|
<tone-example label="Tone with p5.js">
|
|
<div slot="explanation">
|
|
Access the envelopes current value to synchronize visuals. This sketch uses <a href="https://p5js.org" target="_blank">p5.js</a> for canvas rendering.
|
|
<br><br>
|
|
Example by <a href="https://github.com/polyrhythmatic">polyrhythmatic</a>
|
|
</div>
|
|
|
|
<div id="content">
|
|
<tone-play-toggle></tone-play-toggle>
|
|
</div>
|
|
</tone-example>
|
|
|
|
<script type="text/javascript">
|
|
new p5((p5) => {
|
|
|
|
p5.setup = () => {
|
|
// create a canvas width and height of the screen
|
|
// document.querySelector('canvas')
|
|
p5.createCanvas(300, 300);
|
|
// no fill
|
|
p5.fill(255);
|
|
p5.strokeWeight(1);
|
|
p5.rectMode(p5.CENTER);
|
|
};
|
|
|
|
let phase = 0;
|
|
|
|
p5.draw = () => {
|
|
p5.background(255);
|
|
p5.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 (let i = 0; i < p5.width; i++) {
|
|
// scaling kickEnvelope value by 200
|
|
// since default is 0-1
|
|
const kickValue = kickEnvelope.value * 200;
|
|
// multiplying this value to scale the sine wave
|
|
// depending on x position
|
|
const yDot = Math.sin((i / 60) + phase) * kickValue;
|
|
p5.point(i, p5.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 envelop visualizer
|
|
const bassRadius = p5.height * bassEnvelope.value;
|
|
p5.stroke("red");
|
|
const bassX = p5.noise(p5.millis() / 1000) * p5.width;
|
|
const bassY = p5.noise(phase / 100) * p5.height;
|
|
p5.ellipse(bassX, bassY, bassRadius, bassRadius);
|
|
|
|
// beep envelope viz
|
|
const beepX = p5.noise(p5.millis() / 500) * p5.width;
|
|
const beepY = p5.noise(phase / 50) * p5.height;
|
|
const beepSize = p5.height * bleepEnvelope.value;
|
|
p5.stroke("green");
|
|
p5.rect(beepX, beepY, beepSize, beepSize);
|
|
};
|
|
}, document.querySelector("#content"));
|
|
|
|
// filtering the hi-hats a bit
|
|
// to make them sound nicer
|
|
const lowPass = new Tone.Filter({
|
|
frequency: 14000,
|
|
}).toDestination();
|
|
|
|
// we can make our own hi hats with
|
|
// the noise synth and a sharp filter envelope
|
|
const openHiHat = new Tone.NoiseSynth({
|
|
volume: -10,
|
|
envelope: {
|
|
attack: 0.01,
|
|
decay: 0.3
|
|
},
|
|
}).connect(lowPass);
|
|
|
|
const openHiHatPart = new Tone.Part(((time) => {
|
|
openHiHat.triggerAttack(time);
|
|
}), [{ "8n": 2 }, { "8n": 6 }]).start(0);
|
|
|
|
const closedHiHat = new Tone.NoiseSynth({
|
|
volume: -10,
|
|
envelope: {
|
|
attack: 0.01,
|
|
decay: 0.15
|
|
},
|
|
}).connect(lowPass);
|
|
|
|
const closedHatPart = new Tone.Part(((time) => {
|
|
closedHiHat.triggerAttack(time);
|
|
}), [0, { "16n": 1 }, { "8n": 1 }, { "8n": 3 }, { "8n": 4 }, { "8n": 5 }, { "8n": 7 }, { "8n": 8 }]).start(0);
|
|
|
|
// BASS
|
|
const bassEnvelope = new Tone.AmplitudeEnvelope({
|
|
attack: 0.01,
|
|
decay: 0.2,
|
|
sustain: 0,
|
|
}).toDestination();
|
|
|
|
const bassFilter = new Tone.Filter({
|
|
frequency: 600,
|
|
Q: 8
|
|
});
|
|
|
|
const bass = new Tone.PulseOscillator("A2", 0.4).chain(bassFilter, bassEnvelope);
|
|
bass.start();
|
|
|
|
const bassPart = new Tone.Part(((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
|
|
const bleepEnvelope = new Tone.AmplitudeEnvelope({
|
|
attack: 0.01,
|
|
decay: 0.4,
|
|
sustain: 0,
|
|
}).toDestination();
|
|
|
|
const bleep = new Tone.Oscillator("A4").connect(bleepEnvelope);
|
|
bleep.start();
|
|
|
|
const bleepLoop = new Tone.Loop(((time) => {
|
|
bleepEnvelope.triggerAttack(time);
|
|
}), "2n").start(0);
|
|
|
|
// KICK
|
|
const kickEnvelope = new Tone.AmplitudeEnvelope({
|
|
attack: 0.01,
|
|
decay: 0.2,
|
|
sustain: 0,
|
|
}).toDestination();
|
|
|
|
const kick = new Tone.Oscillator("A2").connect(kickEnvelope).start();
|
|
|
|
const kickSnapEnv = new Tone.FrequencyEnvelope({
|
|
attack: 0.005,
|
|
decay: 0.01,
|
|
sustain: 0,
|
|
baseFrequency: "A2",
|
|
octaves: 2.7
|
|
}).connect(kick.frequency);
|
|
|
|
const kickPart = new Tone.Part(((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;
|
|
|
|
// bind the interface
|
|
document.querySelector("tone-play-toggle").addEventListener("start", e => Tone.Transport.start());
|
|
document.querySelector("tone-play-toggle").addEventListener("stop", e => Tone.Transport.stop());
|
|
|
|
const controls = drawer({
|
|
parent: document.body,
|
|
open: false,
|
|
});
|
|
|
|
controls.folder({
|
|
name: "Hihat"
|
|
}).add({
|
|
tone: lowPass,
|
|
}).add({
|
|
name: "Open Hihat",
|
|
tone: openHiHat,
|
|
}).add({
|
|
name: "Closed Hihat",
|
|
tone: closedHiHat
|
|
});
|
|
|
|
controls.folder({
|
|
name: "Bass"
|
|
}).add({
|
|
tone: bassFilter,
|
|
}).add({
|
|
tone: bass,
|
|
}).add({
|
|
tone: bassEnvelope
|
|
});
|
|
|
|
controls.folder({
|
|
name: "Bleep"
|
|
}).add({
|
|
tone: bleep,
|
|
}).add({
|
|
tone: bleepEnvelope,
|
|
});
|
|
|
|
controls.folder({
|
|
name: "Kick"
|
|
}).add({
|
|
tone: kick,
|
|
}).add({
|
|
tone: kickEnvelope,
|
|
}).add({
|
|
tone: kickSnapEnv,
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|