Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hyperabsolute/3c565b1296732cb7667b2353c7389508 to your computer and use it in GitHub Desktop.
Save hyperabsolute/3c565b1296732cb7667b2353c7389508 to your computer and use it in GitHub Desktop.
Alien Music Sequencer | Virtual Space Remix

Alien Music Sequencer | Virtual Space Remix

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.

License.

- @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: "&#10006;",
hide: 200
});
$("#dialogLoad").dialog({
autoOpen: false,
buttons: [{
text: "Play",
click: function() {
importLoop($(this));
}
}],
modal: true,
closeText: "&#10006;",
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;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment