sequencer
by kthornbloom
HTML
<div id="sampler">
<div id="sampler-mode">
<div id="sampler-mode-a" class="sampler-mode-visible">A</div>
<div id="sampler-mode-b">B</div>
<div id="sampler-mode-c">C</div>
<div id="sampler-mode-d">D</div>
</div>
<div id="sampler-pad-wrap">
<div id="sampler-a" class="sampler-pad-visible"></div>
<div id="sampler-b"></div>
<div id="sampler-c"></div>
<div id="sampler-d"></div>
</div>
<div id="sampler-control">
<div>
START
</div>
</div>
</div>
<audio src="https://freesound.org/data/previews/183/183098_2394245-lq.mp3" id="sampler-a-audio"></audio>
<audio src="https://freesound.org/data/previews/35/35418_19852-lq.mp3" id="sampler-b-audio"></audio>
<audio src="https://freesound.org/data/previews/273/273186_4965320-lq.mp3" id="sampler-c-audio"></audio>
<audio src="https://freesound.org/data/previews/24/24787_165785-lq.mp3" id="sampler-d-audio"></audio>
SCSS
// parent
#sampler {
display: flex;
font-family: sans-serif;
}
// Instrument Selector
#sampler-mode {
background: #ccc;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
margin-right: 4px;
}
#sampler-mode:hover {
cursor: pointer;
background: #eee;
}
// CONTROLLER
#sampler-control {
height: 40px;
background: #ccc;
font-size: 11px;
border-radius: 3px;
padding: 0 4px;
display: flex;
align-items: center;
text-align: center;
hr {
margin: 0;
border: 0;
border-top: 1px solid rgba(0,0,0,.5);
width: 50px;
}
}
// Pad groups
#sampler-pad-wrap {
font-size: 0;
line-height: 0;
}
#sampler-pad-wrap > div,
#sampler-mode > div {
display: none;
}
// Pad buttons
.sequencer-pad {
border-radius: 2px;
display: inline-block;
width: 15px;
height: 30px;
background: #DF1402;
margin-right: 4px;
position: relative;
&:before {
content:'';
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background: linear-gradient(to bottom, transparent 20%, rgba(0, 0, 0, 0.25) 35%, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.1), transparent, rgba(255, 255, 255, 0.3));
border-radius: 2px;
box-shadow: inset 0 1px 0 rgba(255,255,255,.3), inset 0 -1px 0 rgba(0,0,0,.3), 0 0 0 1px #555, 0 6px 4px #bbb;
}
&:after {
content:'';
display: block;
width: 7px;
height: 7px;
background: radial-gradient(circle at 5px 2px, #fff, #963333 20%, #523838);
border-radius: 50%;
position: absolute;
top: 3px;
left: 50%;
margin-left: -4px;
}
}
.sequencer-pad:nth-child(1n + 3){background: #F47500;}
.sequencer-pad:nth-child(1n + 5){background: #E0DD04;}
.sequencer-pad:nth-child(1n + 7){background: #efeace;}
.pad-active {
&:after {
background:radial-gradient(circle at 5px 2px, #fff, red 20%, #ffa1b7);
box-shadow: 0 0 5px red, 0 0 6px red;
}
}
.selected {
&:after {
...
JavaScript
// Setup
const beats = 8;
var bpm = 200;
var runit = null;
bpm = (60000 / bpm) / 2; //convert to MS
const aContainer = document.getElementById('sampler-a');
const aAudio = document.getElementById('sampler-a-audio');
const bContainer = document.getElementById('sampler-b');
const bAudio = document.getElementById('sampler-b-audio');
const cContainer = document.getElementById('sampler-c');
const cAudio = document.getElementById('sampler-c-audio');
const dContainer = document.getElementById('sampler-d');
const dAudio = document.getElementById('sampler-d-audio');
var interval = 0;
var currentActive = null;
// Make Pads
for (i = 0; i < beats; i++) {
var aNode = document.createElement("DIV");
aNode.className = "sequencer-pad";
aContainer.appendChild(aNode);
var bNode = aNode.cloneNode(true);
bContainer.appendChild(bNode);
var cNode = aNode.cloneNode(true);
cContainer.appendChild(cNode);
var dNode = aNode.cloneNode(true);
dContainer.appendChild(dNode);
}
// Define Pad Groups
const aPads = document.querySelectorAll('#sampler-a .sequencer-pad');
const bPads = document.querySelectorAll('#sampler-b .sequencer-pad');
const cPads = document.querySelectorAll('#sampler-c .sequencer-pad');
const dPads = document.querySelectorAll('#sampler-d .sequencer-pad');
// Player
function player(container, beat, pads, audio){
var currentActive = container.querySelectorAll('.pad-active');
if(currentActive.length > 0){
currentActive[0].classList.remove('pad-active');
}
pads[beat].classList.add('pad-active');
if(pads[beat].classList.contains('selected')){
audio.currentTime = 0;
audio.play();
}
}
// Toggle Pads
var pads = document.querySelectorAll('.sequencer-pad');
Array.from(pads).forEach(function(pad) {
pad.addEventListener('click', function(){
this.classList.toggle('selected');
});
});
// Instrument Switcher
var samplerSwitch = document.getElementById('sampler-mode');
var maxSwitches = document.querySelectorAll('#sampler-mode >...