Skip to content

Instantly share code, notes, and snippets.

@SleepTheGod
Created June 8, 2023 16:01
Show Gist options
  • Save SleepTheGod/d39da67fbfe2e709c128743d67619e32 to your computer and use it in GitHub Desktop.
Save SleepTheGod/d39da67fbfe2e709c128743d67619e32 to your computer and use it in GitHub Desktop.
Beat Maker - CSS

Click Me To Start

console.clear();
const ASSET_ROOT = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/111863/';
const CVS = document.querySelector('canvas'),
CTX = CVS.getContext('2d');
document.documentElement.addEventListener('mousedown', () => {
document.querySelector('button').remove();
if (Tone.context.state !== 'running') Tone.context.resume();
});
class Drum {
constructor(beat, sample) {
this.pattern = beat.split('').map(b => b === '1');
this.sampler = new Tone.Sampler({ 'C3': ASSET_ROOT + sample }, this.init.bind(this))
this.gain = new Tone.Gain(0.4);
this.analyser = Tone.context.createAnalyser();
this.analyser.fftSize = 512;
this.analyser.minDecibels = -80;
this.bufferLength = this.analyser.fftSize;
this.dataArray = new Uint8Array(this.bufferLength);
this.sampler.connect(this.analyser);
this.sampler.connect(this.gain);
this.gain.toMaster();
this.loaded = false;
this._tick = 0;
}
init() {
this.loaded = true;
}
tickResolution(time) {
if (this.loaded)
if (this.pattern[this._tick % this.pattern.length])
this.sampler.triggerAttack(Math.random() < 0.5 ? 'C3' : 'C#3', time);
this._tick++;
}
getData() {
this.analyser.getByteTimeDomainData(this.dataArray);
return this.dataArray;
}
}
const drums = {
ch: new Drum('10111010101010111010110010101011', 'ch-808.wav'),
sd: new Drum('00001000000010000000001000001000', 'sd-808.wav'),
kd: new Drum('10000000100000001000000000010010', 'kd-808.wav')
};
const DRUM_COUNT = Object.keys(drums).length;
Tone.Transport.scheduleRepeat(time => {
Object.values(drums).forEach(drum => drum.tickResolution(time));
}, '16n');
Tone.Transport.start();
animate();
function animate() {
window.requestAnimationFrame(animate);
let width = CVS.width = window.innerWidth,
height = CVS.height = window.innerHeight;
CTX.fillStyle = '#121212';
CTX.fillRect(0, 0, width, height);
let data = [];
Object.values(drums).forEach((drum, i) => {
data[i] = drum.getData();
});
let len = drums.ch.bufferLength,
stepX = width / len,
stepY = height / DRUM_COUNT,
maxH = height * 0.2,
cy = stepY * 0.5;
CTX.lineWidth = 3;
CTX.lineJoin = 'round';
CTX.lineCap = 'round';
CTX.strokeStyle = 'tomato';
for (let j = 0; j < DRUM_COUNT; j++) {
let x = stepX * 0.5;
CTX.beginPath();
for (let i = 0; i < len; i++) {
let rat = (data[j][i] - 128.0) / 128.0,
y = rat * maxH + cy;
if (i === 0 && j === 0) CTX.moveTo(x, y);
else CTX.lineTo(x, y);
x += stepX;
}
cy += stepY;
CTX.stroke();
}
}
html, body, canvas {
height: 100%;
width: 100%;
}
button {
appearance: none;
border: none;
color: white;
background: black;
font-size: 2rem;
position: absolute;
top: 50%;
left: 50%;
padding: 2rem;
transform: translate(-50%, -50%);
}
body { background: #121212; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment