This is a simple step sequencer that you will enjoy playing with on weekends, and on weekdays. Dig it. Love it. Thank John Galt, and Joe Harry, and the independents. Enjoy and share | Sander Nizni
A Pen by Sander Nizni on CodePen.
This is a simple step sequencer that you will enjoy playing with on weekends, and on weekdays. Dig it. Love it. Thank John Galt, and Joe Harry, and the independents. Enjoy and share | Sander Nizni
A Pen by Sander Nizni on CodePen.
- @buttons = 256 | |
- @rows = 16 | |
- def decidePitch (i) | |
- ((i/@rows.to_f).ceil)-1 | |
#aligner | |
%h1 ALIEN MUSIC SEQUENCER | |
/STEP SEQUENCER BOARD | |
#board.loading | |
- (1..@buttons).each do |i| | |
%span.holder{:data => {:note => (decidePitch i)} } | |
.note | |
.ripple | |
/BEAT MARKERS | |
#markers | |
- (1..@rows).each do |i| | |
- if (i % 4 === 1) | |
%span • | |
- else | |
%span ◦ | |
/CONTROLS | |
/All SVG icons from www.flaticon.com | |
/TODO: optimise the hell out of these | |
#controls | |
#audio.button | |
%svg{:version => "1.1", :xmlns => "http://www.w3.org/2000/svg", :viewBox => "0 0 513.32 513.32"} | |
%path{:d => "M139.023,128.33H42.777v256.66h96.247l85.553,128.33h74.859V0h-74.859L139.023,128.33z M256.66,42.777v427.767h-8.555l-85.553-128.33H85.553V171.107h76.998l85.553-128.33C248.104,42.777,256.66,42.777,256.66,42.777z"} | |
%rect{:x => "427.767", :y => "213.883", :width => "42.777", :height => "128.33"} | |
%rect{:x => "342.213", :y => "149.718", :width => "42.777", :height => "256.66"} | |
#reset.button | |
%svg{:version => "1.1", :xmlns => "http://www.w3.org/2000/svg", :viewBox => "0 0 16 16"} | |
%path{:d => "M8 0c-3 0-5.6 1.6-6.9 4.1l-1.1-1.1v4h4l-1.5-1.5c1-2 3.1-3.5 5.5-3.5 3.3 0 6 2.7 6 6s-2.7 6-6 6c-1.8 0-3.4-0.8-4.5-2.1l-1.5 1.3c1.4 1.7 3.6 2.8 6 2.8 4.4 0 8-3.6 8-8s-3.6-8-8-8z"} | |
/PIN & LOAD CONTROLS | |
#file-controls | |
#save.button.alt | |
%svg{:version => "1.1", :xmlns => "http://www.w3.org/2000/svg", :viewBox => "0 0 319 319"} | |
%path{:d => "M317.16,159.471c-16.197-16.199-41.195-24.41-74.307-24.41c-7.01,0-14.408,0.379-22.047,1.121l-79.729-75.346l19.04-19.035c3.529-3.531,3.529-9.252-0.003-12.785l-26.42-26.424c-3.39-3.391-9.394-3.391-12.784,0L2.648,120.863c-3.531,3.531-3.531,9.252-0.002,12.783l26.416,26.416c1.697,1.695,3.995,2.648,6.394,2.648c2.397,0,4.697-0.953,6.392-2.648l19.042-19.035l75.346,79.726c-3.048,31.352-1.057,72.018,23.284,96.358c1.766,1.766,4.079,2.648,6.391,2.648c2.314,0,4.629-0.884,6.395-2.648l66.035-66.041l50.578,50.582c1.768,1.766,4.08,2.648,6.395,2.648c2.312,0,4.629-0.884,6.393-2.648c3.531-3.531,3.531-9.254,0-12.785l-50.582-50.58l66.037-66.03C320.691,168.725,320.691,163.005,317.16,159.471z M166.505,297.334c-14.614-21.172-14.7-53.803-11.859-78.743c0.3-2.648-0.581-5.297-2.413-7.23l-84.589-89.516c-1.678-1.775-4.002-2.791-6.443-2.826c-0.042,0-0.086,0-0.128,0c-2.397,0-4.697,0.953-6.392,2.647l-19.225,19.221l-13.632-13.631L127.303,21.769l13.636,13.641L121.716,54.63c-1.726,1.73-2.68,4.0782.646,6.525c0.035,2.436,1.057,4.768,2.832,6.443l89.507,84.582c1.936,1.836,4.574,2.719,7.23,2.41c8.455-0.963,16.602-1.449,24.213-1.449c23.465,0,41.756,4.469,54.539,13.314L166.505,297.334z"} | |
#load.button.alt | |
%svg{:version => "1.1", :xmlns => "http://www.w3.org/2000/svg", :viewBox => "0 0 405 405"} | |
%path{:d => "M326.03,405.132H79.102C52.379,405.132,31,383.753,31,357.029V185.997c0-8.552,7.483-16.034,16.034-16.034s16.034,7.483,16.034,16.034v172.101c0,8.552,7.483,16.034,16.034,16.034H326.03c8.552,0,16.034-7.483,16.034-16.034V185.997c0-8.552,7.483-16.034,16.034-16.034c8.552,0,16.034,7.483,16.034,16.034v172.101C374.132,383.753,352.753,405.132,326.03,405.132z"} | |
%path{:d => "M110.102,125.067c-4.276,0-8.552-1.069-11.758-4.276c-6.414-6.414-6.414-16.034,0-22.448l92.999-92.999c6.414-6.414,16.034-6.414,22.448,0l92.999,92.999c6.414,6.414,6.414,16.034,0,22.448c-6.414,6.414-16.034,6.414-22.448,0l-81.24-81.24l-81.24,81.24C118.654,123.998,114.378,125.067,110.102,125.067z"} | |
%path{:d => "M202.031,304.651c-8.552,0-16.034-7.483-16.034-16.034V16.034C185.997,7.483,193.48,0,202.031,0s16.034,7.483,16.034,16.034v271.513C218.066,297.168,211.652,304.651,202.031,304.651z"} | |
/UI POPUPS | |
#ui-widget-overlay | |
.dialog#dialogSave{:title => "Save or share music"} | |
%p If you copy and save this code, you can return here and paste it to re-create your music loop. | |
%span.ui-helper-hidden-accessible | |
%input{:type => "text"} | |
%textarea#saveCode{:type => "text", :readonly => "readonly", :onfocus => "this.select()"} | |
.dialog#dialogLoad{:title => "Paste a music loop"} | |
%p | |
Your code should look like this: | |
%br [;24:1 ;37:1 ;80:1 ;84:1 ;7:1 ;3:1 ;15] | |
%textarea#importCode{:type => "text"} | |
/* | |
SANDER SAYS: | |
NO WARRANTIES EXPRESSED OR IMPLIED | |
FOR USING THIS CODE. ALL THIS HAS | |
HAPPENED BEFORE, AND IT WILL HAPPEN | |
AGAIN... BUT IT DOESN'T MATTER... | |
BECAUSE WE ARE IN THIS TOGETHER. | |
C'EST LA VIE. EVERYTHING COULD | |
HAVE BEEN ANYTHING ELSE, AND IT | |
WOULD HAVE JUST AS MUCH MEANING. | |
ENJOY. COMPLIMENTS? PARTY | |
INVITATIONS? RIGHT ON! CONTACT | |
@HYPERABSOLUTE ON TWITTER OR ON | |
UXRIG.COM | |
STAY AWESOME | HYPERABSOLUTE | |
*/ | |
social("codepen/sander-nizni", | |
"twitter/hyperabsolute", | |
"linkedin/sandernizni", | |
"instagram/hyperabsolute", | |
"facebook/sander.nizni", | |
"/sandernizni.wordpress.com", | |
"light", "Sander says... Try it in full screen, dawg."); | |
var buttons = 256, | |
rows = 16; | |
var cols = rows; | |
var wLoaded = false, | |
nLoaded = false; | |
$(document).ready(function() { | |
var holder = $('#board .holder'), | |
note = $('.note'); | |
var notes = []; | |
for (var i = 0; i < rows; i++) { | |
notes[i] = new Howl({ | |
urls: ['https://s3-us-west-2.amazonaws.com/s.cdpn.io/380275/' + i + '.mp3', | |
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/380275/' + i + '.ogg' | |
], | |
onload: loadCount(i + 1) | |
}); | |
} | |
$(window).load(function() { | |
bindUserActions(); | |
initControls(); | |
wLoaded = true; | |
if (nLoaded) | |
$('#board').removeClass('loading').addClass('forward'); | |
for (var i = 0; i < rows; i++) { | |
bindNote(i); | |
} | |
}); | |
function loadCount(i) { | |
if (i === rows) { | |
nLoaded = true; | |
if (wLoaded) | |
$('#board').removeClass('loading').addClass('forward'); | |
} | |
} | |
function bindNote(currNote) { | |
$('#board .holder:nth-child(' + cols + 'n + ' + currNote + ')') | |
.on('webkitAnimationIteration mozAnimationIteration animationiteration', | |
function() { | |
if ($(this).hasClass('active')) { | |
var currNote = $(this).attr('data-note'); | |
notes[currNote].play(); | |
$(this).find('.ripple').addClass('huzzar').delay(500).queue(function() { | |
$(this).removeClass('huzzar').dequeue(); | |
}); | |
} | |
}); | |
} | |
function bindUserActions() { | |
$(note).mousedown(function() { | |
$(this).toggleClass("active"); | |
$(this).parent().toggleClass("active"); | |
}); | |
$(document).mousedown(function() { | |
$(note).bind('mouseover', function() { | |
$(this).toggleClass("active"); | |
$(this).parent().toggleClass("active"); | |
}); | |
}).mouseup(function() { | |
$(note).unbind('mouseover'); | |
}); | |
$("#dialogSave").dialog({ | |
autoOpen: false, | |
modal: true, | |
closeText: "✖", | |
hide: 200 | |
}); | |
$("#dialogLoad").dialog({ | |
autoOpen: false, | |
buttons: [{ | |
text: "Play", | |
click: function() { | |
importLoop($(this)); | |
} | |
}], | |
modal: true, | |
closeText: "✖", | |
hide: 200 | |
}); | |
} | |
function initControls() { | |
$('#reset').on('click', function() { | |
$('.active').removeClass('active'); | |
}); | |
$('#audio').on('click', function() { | |
if ($(this).hasClass("mute")) | |
Howler.unmute(); | |
else | |
Howler.mute(); | |
$(this).toggleClass('mute'); | |
}); | |
$('#save').on('click', function() { | |
if ($(".dialog").dialog("isOpen") !== true) | |
exportLoop(); | |
}); | |
$('#load').on('click', function() { | |
if ($(".dialog").dialog("isOpen") !== true) | |
$("#dialogLoad").dialog("open"); | |
}); | |
$('.ui-dialog').on('dialogopen', function(event) { | |
$('body').addClass('no-overflow'); | |
Howler.volume(0.5); | |
$('#ui-widget-overlay').addClass('visible'); | |
}).on('dialogclose', function(event) { | |
$('body').removeClass('no-overflow'); | |
Howler.volume(1); | |
$('textarea#saveCode').val(''); | |
$('#ui-widget-overlay').removeClass('visible'); | |
}); | |
} | |
//:x represents ON //;x represents OFF | |
function exportLoop() { | |
var noteCode = "", | |
offCount = 0, | |
onCount = 0; | |
holder.each(function() { | |
if ($(this).hasClass('active')) { | |
if (offCount > 0) | |
noteCode = noteCode + ";" + offCount; | |
onCount++; | |
offCount = 0; | |
} else { | |
if (onCount > 0) | |
noteCode = noteCode + ":" + onCount + " "; | |
offCount++; | |
onCount = 0; | |
} | |
}); | |
if (offCount > 0) | |
noteCode = noteCode + ";" + offCount; | |
else if (onCount > 0) | |
noteCode = noteCode + ":" + onCount; | |
$("#saveCode").val("[" + noteCode + "]"); | |
$("#dialogSave").dialog("open"); | |
} | |
function importLoop(dialog) { | |
var noteCode = '', | |
noteState, | |
error = false, | |
note; | |
noteCode = dialog.find('textarea#importCode').val(); | |
dialog.dialog("close"); | |
noteCode = noteCode.replace("[", ""); | |
noteCode = noteCode.replace("]", ""); | |
if (noteCode.charAt(0) === ":") | |
noteState = 1; | |
else if (noteCode.charAt(0) === ";") | |
noteState = 0; | |
else { | |
alert("Your note code wasn't recognised"); | |
error = true; | |
} | |
if (!error) { | |
$('.active').removeClass('active'); | |
noteCode = noteCode.substr(1); | |
var splitCode = noteCode.split(/:|;/g); | |
var noteCounter = 0; | |
for (i = 0; i < splitCode.length; i++) { | |
var currNum = parseInt(splitCode[i]); | |
if (noteState) { | |
for (var n = 0; n < currNum; n++) { | |
noteCounter++; | |
note = $('#board span:nth-child(' + noteCounter + ')'); | |
note.addClass('active'); | |
note.children().addClass('active'); | |
} | |
} else { | |
noteCounter = noteCounter + currNum; | |
} | |
noteState = !noteState; | |
} | |
} | |
} | |
}); |
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/1.1.28/howler.min.js"></script> | |
<script src="http://codepen.io/Sander-Nizni/pen/mPoOjg"></script> |
$buttons: 256; | |
$rows: 16; | |
$speed: 3s; | |
//$speed: 2s; //Uncomment me to go faster! | |
$cols: $rows; | |
$noteSize: 24px; | |
$spacer: 6px; | |
$boardWidth: $cols * ($noteSize + $spacer); | |
$mobileNoteSize: 20px; | |
$mobileSpacer: 2px; | |
$mobileBoardWidth: $cols * ($mobileNoteSize + $mobileSpacer); | |
$_bg: #336699 #000; | |
$_default: #c3c3c3; | |
$_accent: #ff9900; | |
$_selected: #FFF; | |
html { | |
min-height: 100%; | |
font-family: Poppins, Helvetica, Arial, sans-serif; | |
background: nth($_bg, 1); | |
background: linear-gradient(to bottom right, nth($_bg, 1), nth($_bg, 2)); | |
} | |
body { | |
height: 100%; | |
margin: 0; | |
font-size: 16px; | |
} | |
body.no-overflow{ | |
overflow: hidden; | |
} | |
#aligner{ | |
height: 100%; | |
min-height: 99vh; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
flex-direction: column; | |
} | |
#aligner * { | |
user-select: none; | |
} | |
h1{ | |
font-weight: 600; | |
padding: 0; | |
margin: 0; | |
color: $_default; | |
letter-spacing: 10px; | |
} | |
#board { | |
margin: 10px 0 0 0; | |
position: relative; | |
flex: none; | |
width: $boardWidth; | |
font-size: 0; | |
background-color: transparent; | |
cursor: crosshair; | |
overflow: hidden; | |
} | |
.holder { | |
display: inline-block; | |
height: $noteSize; | |
width: $noteSize; | |
margin: $spacer / 2; | |
border-radius: 15px; | |
background-color: $_default; | |
} | |
.forward .holder { | |
animation: line $speed linear infinite; | |
@for $i from 0 through $cols { | |
&:nth-child(#{$cols}n + #{$i}) { | |
animation-delay: $speed*($i / $rows); | |
} | |
} | |
} | |
.loading .holder { | |
animation: pulse 3s infinite; | |
} | |
.note { | |
background-color: transparent; | |
border-radius: 0px; | |
width: 100%; | |
height: 100%; | |
transition: all 0.1s; | |
} | |
.note.active { | |
background-color: $_selected; | |
box-shadow: 0 0 5px $_selected; | |
} | |
#file-controls { | |
position: fixed; | |
background: rgba(255,255,255,0.1); | |
top: 0; | |
right: 0; | |
} | |
.button { | |
display: inline-block; | |
background-color: $_default; | |
width: 50px; | |
height: 50px; | |
border-radius: 2px; | |
text-align: center; | |
margin: 10px; | |
cursor: crosshair; | |
vertical-align: bottom; | |
transition: 0.1s all; | |
svg { | |
fill: rgba(255,255,255,0.5); | |
width: 20px; | |
height: 20px; | |
transform: translateY(15px); | |
} | |
&:hover { | |
background-color: $_accent; | |
} | |
&:active { | |
height: 45px; | |
} | |
&:hover > svg { | |
fill: nth($_bg, 2); | |
} | |
} | |
.alt { | |
margin: 0; | |
padding: 0; | |
background: transparent; | |
svg { | |
fill: $_accent; | |
width: 25px; | |
height: 25px; | |
opacity: 0.6; | |
transform: translateY(12px); | |
} | |
&:hover > svg { | |
opacity: 1; | |
} | |
} | |
#audio { | |
rect { | |
display: inline-block; | |
} | |
&.mute { | |
rect { | |
display: none; | |
} | |
} | |
} | |
.ripple { | |
position: absolute; | |
background:rgba(255, 255, 255, 0.35); | |
border-radius: 100%; | |
width: $noteSize; | |
height: $noteSize; | |
z-index: -1; | |
opacity: 1; | |
transform:scale(0); | |
} | |
.huzzar { | |
opacity: 0; | |
transform: scale(8); | |
transition: all 0.5s; | |
} | |
#markers { | |
text-align: center; | |
cursor: default; | |
margin: 10px 0 0 0; | |
position: relative; | |
flex: none; | |
width: $boardWidth; | |
font-size: 0; | |
span { | |
font-size: 2rem; | |
display: inline-block; | |
height: $noteSize; | |
width: $noteSize; | |
margin: $spacer / 2; | |
margin-bottom: 0; | |
background-color: none; | |
line-height: 8px; | |
color: $_default; | |
} | |
} | |
.ui-dialog { | |
z-index: 1001; | |
font-size: 1rem; | |
border-radius: 5px; | |
color: rgba(255,255,255,0.65); | |
background: nth($_bg, 1); | |
box-shadow: 0 50px 100px -25px rgba(0,0,0,0.4), 0 0 200px -50px rgba(255,255,255,0.4); | |
padding: 10px; | |
border: none; | |
outline: none; | |
textarea { | |
width: 100%; | |
height: 100%; | |
background: rgba( 0,0,0,0.4); | |
color: rgba(255,255,255,0.9); | |
outline: none; | |
border: none; | |
padding: 2px; | |
border-radius: 5px; | |
min-height: 150px; | |
resize: none; | |
cursor: text; | |
&::selection{ | |
background: rgba(98,191,237, 0.99); | |
color: #FFF; | |
} | |
} | |
} | |
.ui-dialog-titlebar { | |
cursor: move; | |
font-size: 1.4rem; | |
color: rgba(255,255,255,0.9); | |
} | |
.ui-dialog-titlebar-close { | |
height: 30px; | |
width: 30px; | |
line-height: 30px; | |
font-size: 30px; | |
background: transparent; | |
border: none; | |
outline: none; | |
float: right; | |
transition: 0.1s all; | |
&:hover { | |
color: #FFF; | |
} | |
} | |
.ui-dialog-buttonpane { | |
padding: 10px 0; | |
text-align: center; | |
} | |
.ui-dialog-buttonset{ | |
button { | |
border: none; | |
outline: none; | |
background: rgba(255,255,255,0.8); | |
color: nth($_bg, 1); | |
border-radius: 2px; | |
} | |
} | |
#ui-widget-overlay{ | |
position: fixed; | |
top: 0; left:0 ; right: 0; bottom: 0; | |
background-color: #000; | |
opacity: 0; | |
z-index:-1; | |
transition: z-index 0s 0.2s, opacity 0.2s; | |
} | |
#ui-widget-overlay.visible { | |
cursor: default; | |
opacity: 0.6; | |
z-index: 1000; | |
transition: z-index 0s, opacity 0.2s; | |
} | |
.ui-helper-hidden-accessible { | |
border: 0; | |
clip: rect(0 0 0 0); | |
height: 1px; | |
margin: -1px; | |
overflow: hidden; | |
padding: 0; | |
position: absolute; | |
width: 1px; | |
} | |
#social-container { | |
opacity: 0.6; | |
bottom: 5px; | |
right: 5px; | |
} | |
#social-container p{ | |
padding-bottom: 0; | |
margin-bottom: 0; | |
} | |
#social-container #social-links a { | |
font-size: 2rem; | |
} | |
#social-message { | |
font-size: 0.8rem; | |
} | |
@keyframes line { | |
0%{ | |
background: $_accent; | |
} | |
30%{ | |
background: $_default; | |
} | |
} | |
@keyframes pulse { | |
40%{ | |
background: $_accent; | |
} | |
} | |
@media (max-width: $boardWidth){ | |
#social-container #social-links, #social-container #tooltip { | |
display: none; | |
} | |
#board { | |
width: $mobileBoardWidth; | |
} | |
.holder { | |
height: $mobileNoteSize; | |
width: $mobileNoteSize; | |
margin: $mobileSpacer / 2; | |
border-radius: 0; | |
} | |
.note { | |
border-radius: 0; | |
} | |
.ripple { | |
height: $mobileNoteSize; | |
width: $mobileNoteSize; | |
} | |
#markers { | |
width: $mobileBoardWidth; | |
span { | |
height: $mobileNoteSize; | |
width: $mobileNoteSize; | |
margin: $mobileSpacer / 2; | |
} | |
} | |
} | |
@media (max-height: 700px) { | |
#aligner{ | |
justify-content: flex-start; | |
padding: 20px; | |
} | |
} |