<main>
  <div id="tutorial-container">
    <div id="tutorial">
      <iframe width="711" height="400" src="https://www.youtube.com/embed/16IpkM7ueWU?rel=0&amp;showinfo=0" frameborder="0" allowfullscreen></iframe>
    </div>
    <p>Cerrar tutorial</p>
  </div>
  <div id="credits"><a href="http://www.michelacosta.com">Míchel Acosta</a></div>
  <div id="tutorial-button">
    <div>?</div>
  </div>  
  <section id="left">
    <div class="tempo-container"><div class="tempo"></div></div>
    <div class="load"></div>
    <div class="sync"></div>
    <div class="play"></div>
    <div class="less"></div>
    <div class="more"></div>
    <div class="jog paused">
      <div class="wave"></div>
    </div>
    <div class="volume-container"><div class="volume"></div></div>
    <div class="info">
      <div class="song"></div>
      <div class="info-time"></div>
      <div class="info-tempo"><span>TEMPO: </span><strong>±0.00<span> %</span></strong></div>
      <input type="range" min="0" max="0" value="0" step="1">
    </div>
  </section>
  <section id="right">
    <div class="tempo-container"><div class="tempo"></div></div>
    <div class="load"></div>
    <div class="sync"></div>
    <div class="play"></div>
    <div class="less"></div>
    <div class="more"></div>
    <div class="jog paused"></div>
    <div class="volume-container"><div class="volume"></div></div>
    <div class="info">
      <div class="song"></div>
      <div class="info-time"></div>
      <div class="info-tempo"><span>TEMPO: </span><strong>±0.00<span> %</span></strong></div>
      <input type="range" min="0" max="0" value="0" step="1">
    </div>
  </section>
  <section id="crossfade-container">
    <section id="crossfade"></section>
  </section>
</main>
<div id="songloader-container">
  <section id="songloader">
    <table>
      <thead>
        <tr>
          <th>Title</th>
          <th>Artist</th>
          <th>Duration</th>
          <th>BPM</th>
        </tr>
      </thead>
      <tbody>
        <tr onclick="setSong(1)">
          <td>Push [Mak & Pasteman Remix]</td>
          <td>A-Trak feat. Andrew Wyatt</td>
          <td>06:59</td>
          <td>126</td>
        </tr>
        <tr onclick="setSong(2)">
          <td>Thinking Of You [Original Mix]</td>
          <td>South Royston</td>
          <td>06:44</td>
          <td>124</td>
        </tr>
        <tr onclick="setSong(3)">
          <td>On A Ragga Tip [Original Mix]</td>
          <td>My Digital Enemy</td>
          <td>04:57</td>
          <td>125</td>
        </tr>
        <tr onclick="setSong(4)">
          <td>90's By Nature [Lucas & Steve Remix]</td>
          <td>Showtek feat MC Ambush</td>
          <td>04:37</td>
          <td>125</td>
        </tr>
      </tbody>
    </table>
  </section>
</div>
<p id="log"></p>
body {
  background-color:#000;
  overflow:hidden;
}

#tutorial-container {
  display:none;
  float:left;
  position:relative;
  background-color:#000;
  width:900px;
  height:499px;
  z-index:99999;
}

#tutorial-container p {
  text-align:center;  
  font-size:30px;
  font-family:'Nova Square';
  color:#fff;
  cursor:pointer;
}

#tutorial-container p:hover {
  text-shadow:0 0 10px #3FAEFD, 0 0 10px #3FAEFD;
}

#tutorial {
  position:relative;  
  box-shadow:0 0 30px #fff;
  border-radius:10px 10px 60px 60px;
  overflow:hidden;
  width:100%;
  height:499px;
}

#tutorial-button {  
  position:absolute;
  appearance:none;
  font-size:55px;
  top:160px;
  left:414px;
  margin:auto;    
}

#tutorial-button div {
  font-family:'Nova Square';
  font-size:50px;
  width:70px;
  height:63px;
  border:none;
  border-radius:50px;
  background-color:#333;
  color:#111;
  cursor:pointer;
  box-shadow:0 0 20px #000;
  font-weight:bold;
  text-align:center;
  padding-top:7px;  
}

#tutorial-button div:hover {
  box-shadow:0 0 50px #3FAEFD, 0 0 50px #3FAEFD;
  background-color:#000;
  color:#fff;
}

#credits {  
  position:absolute;
  font-size:55px;
  top:80px;
  left:352px;
  margin:auto;  
  font-family: 'Kristi', sans-serif;
}

#credits a {
  text-decoration:none;
  color:#ddd;
}

#credits:hover {
  text-shadow:0 0 10px #3FAEFD, 0 0 10px #3FAEFD;
}

main {
  position:relative;
  width:900px;
  height:499px;
  background-image:url(http://www.michelacosta.com/images/2qyIBfw.jpg);
  margin:150px auto 0 auto;
}

#songloader-container {
  width:100%;
  height:150px;
  position:fixed;
  top:0;
  margin:auto;
  overflow:hidden;
}

#songloader {
  width:600px;
  background-color:#000;
  height:150px;
  margin:auto;
  position:relative;
  top:150px;
  border-radius:20px 20px 0 0;
  border:6px solid #444;
  box-shadow:0px 0px 5px #3FAEFD inset;
  padding:5px;
}

#left .jog,
#left .tempo,
#left .play,
#left .volume,
#right .jog,
#right .tempo,
#right .play,
#right .volume,
#left .less,
#left .more,
#right .less,
#right .more,
#left .load,
#right .load,
#left .sync,
#right .sync,
#crossfade {
  position:absolute;
  float:left;
  background-repeat:no-repeat;
}

#left .tempo:hover,
#left .volume:hover,
#right .tempo:hover,
#right .volume:hover,
#left .play:hover,
#right .play:hover,
#left .less:hover,
#left .more:hover,
#right .less:hover,
#right .more:hover,
#left .load:hover,
#right .load:hover,
#left .sync:hover,
#right .sync:hover,
#crossfade:hover {
  box-shadow:0 0 15px #DF6165, 0 0 15px #DF6165;
  cursor:pointer;
}

#left .jog {
  width:262px;
  height:262px;
  background-image:url(http://www.michelacosta.com/images/eOI2jNr.png);
  left:77px;
  top:149px;
  animation: girar infinite linear;
  animation-duration: 5s;
}

.running {
  animation-play-state: running!important;
}

.paused {
  animation-play-state: paused!important;
}

#left .tempo {
  width:48px;
  height:20px;
  left:35px;
  top:91px;
  background-image:url(http://www.michelacosta.com/images/OBlswus.png);
}

#left .volume {
  width:48px;
  height:20px;
  left:389px;
  top:278px;
  background-image:url(http://www.michelacosta.com/images/OBlswus.png);
}

.info {
  position:absolute;
  width:270px;
  height:60px;
  background-color:#000;
  border-radius:5px;
  border:2px solid #333;
  box-shadow:0 0 10px #555 inset;
  overflow:hidden;
}

#left .info {
  left:90px;
  top:12px;
}

#right .info {
  right:90px;
  top:12px;
}

#left .sync {
  width:32px;
  height:32px;
  left:35px;
  top:187px;
  border-radius:0 0 10px 10px;
}

#right .sync {
  width:32px;
  height:32px;
  right:35px;
  top:187px;
  border-radius:0 0 10px 10px;
}

#left .play {
  width:46px;
  height:46px;
  left:85px;
  top:401px;
  border-radius:23px;
}

#left .less {
  width:33px;
  height:32px;
  left:146px;
  top:433px;
  border-radius:16px;
}

#left .more {
  width:33px;
  height:32px;
  left:192px;
  top:439px;
  border-radius:16px;
}

#left .load {
  width:32px;
  height:32px;
  left:372px;
  top:32px;
  border-radius:16px;
}

#right .load {
  width:32px;
  height:32px;
  left:495px;
  top:32px;
  border-radius:16px;
}

#right .less {
  width:33px;
  height:32px;
  left:630px;
  top:433px;
  border-radius:16px;
}

#right .more {
  width:33px;
  height:32px;
  left:675px;
  top:439px;
  border-radius:16px;
}

#right .jog {
  width:262px;
  height:262px;
  background-image:url(http://www.michelacosta.com/images/eOI2jNr.png);
  left:562px;
  top:149px;
  animation: girar infinite linear;
  animation-duration: 5s;
}

#right .tempo {
  width:48px;
  height:20px;
  left:818px;
  top:91px;
  background-image:url(http://www.michelacosta.com/images/OBlswus.png);
}

#right .volume {
  width:48px;
  height:20px;
  left:465px;
  top:278px;
  background-image:url(http://www.michelacosta.com/images/OBlswus.png);
}

#right .play {
  width:46px;
  height:46px;
  left:568px;
  top:401px;
  border-radius:23px;
}

.info-time {
  display:inline-block;
  position:absolute;
  bottom:7px;
  left:0;
  height:20px;
  font-family:'Nova Square', sans-serif;
  color:#3FAEFD;
  text-transform:uppercase;
  white-space:nowrap;
  padding:10px 10px 0 10px;
  width:120px;
  font-weight:bold;
}

input[type=range] {
  appearance:none;
  display:inline-block;
  position:absolute;  
  left:0;
  width:100%;
  height:3px;
  bottom:0;
}

/* Estilos para el input range copiados de css-tricks.com/styling-cross-browser-compatible-range-inputs-css */

input[type=range] {
  -webkit-appearance: none; /* Hides the slider so that custom slider can be made */
  width: 100%; /* Specific width is required for Firefox. */
}

input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
}

input[type=range]:focus {
  outline: none; /* Removes the blue border. You should probably do some kind of focus styling for accessibility reasons though. */
}

/* Special styling for WebKit/Blink */
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  border: 1px solid #000000;
  height: 11px;
  width: 10px;
  border-radius: 3px;
  background: #9a9a9a;
  cursor: pointer;
  margin-top: -4px; /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; /* Add cool effects to your sliders! */
}

input[type=range]::-webkit-slider-runnable-track {
  width: 100%;
  height: 3px;
  cursor: pointer;
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
  background: #3071a9;
  border-radius: 1.3px;
  border: 0.2px solid #010101;
}

input[type=range]:focus::-webkit-slider-runnable-track {
  background: #367ebd;
}

/* Estilos para el input range copiados de css-tricks.com/styling-cross-browser-compatible-range-inputs-css */

.info-tempo {
  display:inline-block;
  position:absolute;
  bottom:7px;
  right:0;
  height:20px;
  font-family:'Nova Square', sans-serif;
  color:#3FAEFD;
  text-transform:uppercase;
  white-space:nowrap;
  padding:10px 10px 0 10px;
  width:100px;
}

.info-tempo span {
  font-size:8px;
}

.song {
  display:inline-block;
  position:absolute;
  left:0;
  font-family:'Nova Square', sans-serif;
  color:#3FAEFD;
  text-transform:uppercase;
  white-space:nowrap;
  padding:10px;
}

#crossfade {
  width:24px;
  height:46px;
  left:57px;
  background-image:url(http://www.michelacosta.com/images/5bR284h.png);  
}

@keyframes girar {
  0% { 
    transform: rotate(0deg); 
  }
  100% {
    transform: rotate(360deg); 
  }
}

#crossfade-container {
  position:relative;
  left:380px;
  top:432px;
  width:138px;
  height:46px;
}

#log {
  color:#fff;
}

table {
  width:100%;
  font-family:'Nova Square', sans-serif;
  color:#3FAEFD;
}

th {
  border-bottom:1px solid #3FAEFD;
}

td {
  border-bottom:1px dotted #3FAEFD;
  font-size:14px;
}

td:nth-child(3), 
td:nth-child(4) {
  text-align:right;
}

tbody tr:hover {
  background-color:#3FAEFD;
  color:#000;
  cursor:pointer;
}

iframe {
  position:relative;
  left:96px;
  top:2px;
}
var tempoRange = 20;
var jogSpeed = 5;
var timeFactor = 0.1;

var song1 = new Audio('http://www.michelacosta.com/html5/push.mp3');
var song2 = new Audio('http://www.michelacosta.com/html5/royston.mp3');
var song3 = new Audio('http://www.michelacosta.com/html5/ragga.mp3');
var song4 = new Audio('http://www.michelacosta.com/html5/showtek.mp3');

var leftSong = null;
var rightSong = null;
var channel2load = '';

modVolumeLeft = 0;
modVolumeRight = 0;

rateLeft = 1;
rateRight = 1;

$('#left .play').click(function() {
  if (leftSong != null) {
    diff = (((($('#left .volume').offset().top-482)*-1)*0.5)/54);
    currentVolLeft = (0.5+diff) - (modVolumeLeft*(0.5+diff)/100);
    leftSong.volume = currentVolLeft.toFixed(2);  
    leftSong.playbackRate = rateLeft;
    if ($('#left .jog').hasClass('paused')) {
      $('#left .jog').removeClass('paused');
      $('#left .jog').addClass('running');
      marqueeLeft();
      leftSong.play();
    } else {
      $('#left .jog').removeClass('running');
      $('#left .jog').addClass('paused');
      marqueeLeftStop();
      leftSong.pause();
    }
  }
  else {
    requestSong();
  }
});

$('#right .play').click(function() {
  if (rightSong != null) {
    diff = (((($('#right .volume').offset().top-482)*-1)*0.5)/54);
    currentVolRight = (0.5+diff) - (modVolumeRight*(0.5+diff)/100);   
    rightSong.volume = currentVolRight.toFixed(2);
    rightSong.playbackRate = rateRight;
    if ($('#right .jog').hasClass('paused')) {
      $('#right .jog').removeClass('paused');
      $('#right .jog').addClass('running');
      marqueeRight();
      rightSong.play();
    } else {
      $('#right .jog').removeClass('running');
      $('#right .jog').addClass('paused');
      marqueeRightStop();
      rightSong.pause();
    }
  }
  else {
    requestSong();
  }
});

$('#left .load').click(function() {
  if ($('#left .jog').hasClass('paused')) {
  	toggleLoader('left');
  }
  else {
    askToPause();
  }
});

$('#right .load').click(function() {
  if ($('#right .jog').hasClass('paused')) {
		toggleLoader('right');
  }
  else {
    askToPause();
  }
});

$("#left .tempo").dblclick(function() {
  $('#left .tempo').animate({'top': 91}, 500, 'easeOutQuad');
  $('#left .info-tempo > strong').html('±0.00<span> %</span>');
  rateLeft = 1;    
});

$("#right .tempo").dblclick(function() {
  $('#right .tempo').animate({'top': 91}, 500, 'easeOutQuad');
  $('#right .info-tempo > strong').html('±0.00<span> %</span>');
  rateRight = 1;
});

$("#left .tempo").draggable({
  drag: dragLeftTempo,
  axis: "y",
  containment: [35, 187, 35, 294]
});

$("#right .tempo").draggable({
  drag: dragRightTempo,
  axis: "y",
  containment: [818, 187, 818, 294]
});

$("#left .volume").draggable({
  drag: dragLeftVolume,
  axis: "y",
  containment: [389, 428, 389, 536]
});

$("#right .volume").draggable({
  drag: dragRightVolume,
  axis: "y",
  containment: [465, 428, 465, 536]
});

$("#crossfade").draggable({
  drag: crossFade,
  axis: "x",
  containment: 'parent'
});

function marqueeLeft() {
  $('#left .song').css('left', '100%');
  $('#left .song').animate({ 'left': (0 - $('#left .song').width()) }, 5000, 'linear', marqueeLeft);
}

function marqueeRight() {
    $('#right .song').css('left', '100%');
    $('#right .song').animate({ 'left': (0 - $('#right .song').width()) }, 5000, 'linear', marqueeRight);
}

function marqueeRightStop() {
  $('#right .song').stop();
	$('#right .song').animate({'left': '0'});
}

function marqueeLeftStop() {
  $('#left .song').stop();
  $('#left .song').animate({'left': '0'});
}

function dragLeftTempo() {
  dragTempo('#left');
}

function dragRightTempo() {
  dragTempo('#right');
}

function dragLeftVolume() {
  if (leftSong != null) {  
    dragVolume('#left');
  }
}

function dragRightVolume() {
  if (rightSong != null) {      
    dragVolume('#right');
  }
}

function dragTempo(side) {
    val = (($(side+' .tempo').offset().top - 240.5) * tempoRange / 53.5).toFixed(2);
  	$(side+' .jog').css('animation-duration', jogSpeed-((jogSpeed*(val)/100))+'s');
    if (val > 0) {
      val = '+' + val;
    }
    $(side+' .info-tempo > strong').html(val+'<span> %</span>');
  switch(side) {
    case '#left':
      rateLeft = (1+(val/100)).toFixed(2);
      break;
    case '#right':
      rateRight = (1+(val/100)).toFixed(2);
      break;
  }  
}

function dragVolume(side) {
  diff = ((($(side+' .volume').offset().top-482)*-1)*0.5)/54;
  	switch(side) {
      case '#left':
	    	leftSong.volume = ((0.5+diff) - (modVolumeLeft*(0.5+diff)/100)).toFixed(2);
        break;
      case '#right':
        rightSong.volume = ((0.5+diff) - (modVolumeRight*(0.5+diff)/100)).toFixed(2);
        break;       
    }
}

function crossFade() {
  currentVolLeft = (0.5+((($('#left .volume').offset().top-482)*-1)*0.5)/54).toFixed(2);
  currentVolRight = (0.5+((($('#right .volume').offset().top-482)*-1)*0.5)/54).toFixed(2);  
  if ($('#crossfade').position().left-57 < 0) {
    modVolumeLeft = 0;
    modVolumeRight = (($('#crossfade').position().left-57)*100/-57).toFixed(2);
  }
  else if ($('#crossfade').position().left-57 > 0) {
    modVolumeRight = 0;
    modVolumeLeft = (($('#crossfade').position().left-57)*100/57).toFixed(2);
  }
  else {
    modVolumeLeft = 0;
    modVolumeRight = 0;
  }
  if (leftSong != null) {
    leftSong.volume = currentVolLeft - (modVolumeLeft*currentVolLeft/100).toFixed(2);
  }
  if (rightSong != null) {
  	rightSong.volume = currentVolRight - (modVolumeRight*currentVolRight/100).toFixed(2);
  }
}

$('#left .less').click(function() {
  if (leftSong != null) {    
  	leftSong.currentTime-=timeFactor;
  }
  else {
    requestSong();
  }
});

$('#left .more').click(function() {
  if (leftSong != null) {    
  	leftSong.currentTime+=timeFactor;
  }
  else {
    requestSong();
  }
});

$('#right .less').click(function() {
  if (rightSong != null) {    
  	rightSong.currentTime-=timeFactor;
  }
  else {
    requestSong();
  }
});

$('#right .more').click(function() {
  if (rightSong != null) {    
  	rightSong.currentTime+=timeFactor;
  }
  else {
    requestSong();
  }
});

function setSong(id) {
  $('#'+channel2load+' .info-time').html('00:00');
  $('#'+channel2load+' input').attr('max', 0);
  $('#'+channel2load+' input').val(0);
  switch(id) {
    case 1:      
      loader = song1;
      $('#'+channel2load+' .song').html('A-Trak feat. Andrew Wyatt - Push [Mak & Pasteman Remix]');
      toggleLoader(channel2load);
      break;
    case 2:
      loader = song2;
      $('#'+channel2load+' .song').html('South Royston - Thinking Of You [Original Mix]');
      toggleLoader(channel2load);
      break;
    case 3:
      loader = song3;
      $('#'+channel2load+' .song').html('My Digital Enemy - On A Ragga Tip [Original Mix]');
      toggleLoader(channel2load);
      break;
    case 4:
      loader = song4;
      $('#'+channel2load+' .song').html('Showtek feat MC Ambush	- 90s By Nature [Lucas & Steve Remix]');
      toggleLoader(channel2load);
      break;
  }  
  if (channel2load == 'left') {
		leftSong = loader;
    leftSong.ontimeupdate = null;
    leftSong.ontimeupdate = function() {updateLeftTime()};
  }
  else {
    rightSong = loader;
    rightSong.ontimeupdate = null;
    rightSong.ontimeupdate = function() {updateRightTime()};
  }
}

function updateLeftTime() {
  	leftSong.playbackRate = rateLeft;
    $('#left .info-time').html(getTime(leftSong.currentTime));
  	$('#left input').attr('max', leftSong.duration.toFixed(0));
  	$('#left input').val(leftSong.currentTime.toFixed(0));
}

function updateRightTime() {
  	rightSong.playbackRate = rateRight;
    $('#right .info-time').html(getTime(rightSong.currentTime));
  	$('#right input').attr('max', rightSong.duration.toFixed(0));
  	$('#right input').val(rightSong.currentTime.toFixed(0));
}

function requestSong() {
  title = '¡No has cargado una canción!';
  options = {
    body: 'Carga una canción en este canal pulsando el botón "LOAD"',
    icon: 'http://www.michelacosta.com/yo.png',
  }
  Notification.requestPermission(function(status) {
    new Notification(title, options);
  });
}

function askToPause() {
  title = '¡Tienes que parar la reproducción!';
  options = {
    body: 'Para la reproducción antes de cargar otro tema',
    icon: 'http://www.michelacosta.com/yo.png',
  }
  Notification.requestPermission(function(status) {
    new Notification(title, options);
  });
}

function dislike() {
  title = '¡Desprecio infinito!';
  options = {
    body: 'No nos gustan los DJs que usan el SYNC',
    icon: 'http://www.michelacosta.com/yo.png',
  }
  Notification.requestPermission(function(status) {
    new Notification(title, options);
  });
}

function toggleLoader(deck) {
  channel2load = deck;
  if ($('#songloader').position().top == 150) {
  	$('#songloader').animate({'top': 20}, 600, 'easeOutQuad');   
    $('#'+deck+' .info').css('background-color','#000033');
  }
  else {
    $('#songloader').animate({'top': 150}, 600, 'easeOutQuad');
    $('#'+deck+' .info').css('background-color','#000');
  }  
}

function getTime(seconds) {
  var hr  = Math.floor(seconds / 3600);
  var min = Math.floor((seconds - (hr * 3600))/60);
  var sec = Math.floor(seconds - (hr * 3600) - (min * 60));
  if (min < 10){ min = "0" + min; }
  if (sec < 10){ sec  = "0" + sec; }
  return min + ':' + sec;
}

$('#left input').change(function() {
  if (leftSong != null) {
  	leftSong.currentTime = $(this).val();
  }
});

$('#right input').change(function() {
  if (rightSong != null) {
  	rightSong.currentTime = $(this).val();
  }    
});

$('.sync').click(function() {
  dislike();
});

$('#tutorial-button>div').click(function() {
  $('#tutorial-container').show();
});

$('#tutorial-container>p').click(function() {
  $('#tutorial-container').hide();
});
Run Pen

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
  2. //cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js