Skip to content

Instantly share code, notes, and snippets.

@zet4
Created July 28, 2015 14:21
Show Gist options
  • Save zet4/fe8fb3a7b7c1a39f6081 to your computer and use it in GitHub Desktop.
Save zet4/fe8fb3a7b7c1a39f6081 to your computer and use it in GitHub Desktop.
MwwqKo
<div class="player">
<input type="file" id="file-open">
<audio id="audio"></audio>
<div class="backdrop">
<img src="https://i1.sndcdn.com/artworks-000108737757-qh5ga7-t500x500.jpg" alt="Cover Art" alt="backdrop">
</div>
<header class="main-header">
<div class="left">
<button id="open-file-button">
<span class="fa fa-folder-open-o"></span>
</button>
<button>
<span class="fa fa-list"></span>
</button>
</div>
<div class="center">
<div class="play-icon play material-click" id="play-pause-button">
<div class="first"></div>
<div class="second"></div>
</div>
</div>
<div class="right">
<button>
<span class="fa fa-close"></span>
</button>
</div>
</header>
<main>
<figure class="cover-art">
<canvas class="music-visuals"></canvas>
<img src="https://i1.sndcdn.com/artworks-000108737757-qh5ga7-t500x500.jpg" alt="Cover Art">
</figure>
<div class="song-info">
<span class="song-title">Godzilla 2015</span>
<span class="song-artist">K-391</span>
</div>
</main>
<footer class="controls">
<div class="waveform-wrap">
<div class="foreground-waveform" id="wav">
</div>
<div class="background-waveform">
</div>
</div>
</footer>
</div>
var audio = $('#audio')[0];
$('#play-pause-button').on('click', function() {
if (audio.paused) {
audio.play();
} else {
audio.pause();
}
});
$('#open-file-button').on('click', function() {
$('#file-open').click();
});
$('#audio').on('play', function() {
$('.play-icon').addClass('pause');
MusicVisuals.start();
});
$('#audio').on('pause', function() {
$('.play-icon').removeClass('pause');
MusicVisuals.stop();
});
$('#audio').on('timeupdate', function() {
var percentage = (audio.currentTime / audio.duration) * 100;
$('.foreground-waveform').css('width', 'calc(' + percentage + 'vw + 1.35px)');
});
$('.waveform-wrap').on('click', function(event) {
audio.currentTime = audio.duration * (event.pageX / window.innerWidth);
});
function setMetadata(title, artist, cover) {
$('.song-title').text(title);
$('.song-artist').text(title);
$('.cover-art img').attr('src', cover);
$('.backdrop img').attr('src', cover);
}
$('#file-open').on('change', function(event) {
var file = event.target.files[0];
audio.src = URL.createObjectURL(file);
audio.play();
var reader = new FileReader();
reader.onload = function(event) {
var settings = {
bar: {
align:'bottom',
width: 1,
gap: 0
},
waveform: {
color: '#fff',
width: window.innerWidth,
height: 50
}
};
new WaveformGenerator(event.target.result, settings).then(function(s) {
$('.background-waveform').html(s);
$('.foreground-waveform').html(s);
$('.foreground-waveform svg')[0].id = $('.foreground-waveform svg')[0].id + '2';
$('.foreground-waveform svg style').text('svg#'+$('.foreground-waveform svg')[0].id+' path{stroke: black}');
});
};
reader.readAsArrayBuffer(file);
var tagReader = new FileReader();
tagReader.onloadend = function(e) {
ID3.loadTags(file.urn, function() {
var tags = new ID3.getAllTags(file.urn);
var image = tags.picture;
var cover = '';
if (image) {
var base64String = '';
for (var i = 0; i < image.data.length; i++) {
base64String += String.fromCharCode(image.data[i]);
}
cover = "data:" + image.format + ";base64," + window.btoa(base64String);
}
setMetadata(tags.title, tags.artist, cover);
}, {
tags: ["title", "artist", "picture", "album", "year"],
dataReader: FileAPIReader(file)
});
};
tagReader.readAsDataURL(file);
});
// Start of Music Visuals
var canvas = document.getElementsByTagName('canvas')[0];
var canvasContext = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = 50;
var audioContext = new window.AudioContext();
var source = audioContext.createMediaElementSource(audio);
var analyser = audioContext.createAnalyser();
source.connect(analyser);
analyser.connect(audioContext.destination);
analyser.fftSize = 2048;
analyser.minDecibels = -90;
analyser.maxDecibels = 0;
var bufferLength = analyser.frequencyBinCount * 0.8;
var frequencyData = new Uint8Array(bufferLength);
var circle = document.querySelector('.cover-art img');
var ScaleBar = {
min: 0,
max: canvas.height,
sum: 0,
get: function(fromMin, fromMax, valueIn) {
var toMin = ScaleBar.min,
toMax = ScaleBar.max;
fromMin = ScaleBar.sum * fromMin;
fromMin = (fromMax * 0.5);
var result = ((toMax - toMin) * (valueIn - fromMin)) / (fromMax - fromMin) + toMin;
return result;
}
};
var MusicVisuals = {
call: null,
start: function() {
canvasContext.clearRect(0, 0, canvas.width, canvas.height);
analyser.getByteFrequencyData(frequencyData);
var frequencyWidth = (canvas.width / bufferLength) * 2, frequencyHeight = 0, x = 0, scales = [], shadows = [], fd = [];
var fdMin = Math.min.apply(Math,frequencyData);
var fdMax = Math.max.apply(Math,frequencyData);
for(var increment = 0; increment < bufferLength; increment++) {
frequencyHeight = frequencyData[increment] * (canvas.height / 250);
if (increment < 15) {
scales.push(frequencyHeight / 50);
} else if (increment > (bufferLength / 2)) {
shadows.push(frequencyHeight * 3);
}
fd.push(frequencyData[increment]);
frequencyHeight = ScaleBar.get(fdMin, fdMax, frequencyData[increment]);
canvasContext.fillStyle = 'rgba(255,255,255,.3)';
var y = canvas.height - frequencyHeight;
canvasContext.fillRect(x, y, frequencyWidth, frequencyHeight);
x += frequencyWidth-0.2;
}
var sc = scales.reduce(function(pv, cv) { return pv + cv; }, 0) / scales.length;
ScaleBar.sum = fd.reduce(function(pv, cv) { return pv + cv; }, 0) / fd.length;
circle.style.transform = 'scale('+ (sc > 1 ? sc : 1) +')';
circle.style.boxShadow = '0 0 ' + shadows.reduce(function(pv, cv) { return pv + cv; }, 0) / shadows.length + 'px white';
MusicVisuals.call = requestAnimationFrame(MusicVisuals.start);
},
stop: function() {
cancelAnimationFrame(MusicVisuals.call);
}
};
<script src="//cdnjs.cloudflare.com/ajax/libs/zepto/1.0/zepto.min.js"></script>
<script src="//cdn.rawgit.com/enjikaka/WaveformGenerator.js/master/dist/WaveformGenerator2.min.js"></script>
<script src="//cdn.rawgit.com/aadsm/JavaScript-ID3-Reader/master/dist/id3-minimized.js"></script>
<script src="https://cdn.rawgit.com/taylorhakes/promise-polyfill/master/Promise.min.js"></script>
body {
margin:0;
width:100%;
height:100%;
overflow:hidden;
font-family: 'Roboto', sans-serif;
}
.player {
width:100%;
height:100%;
overflow:hidden;
#file-open {
display:none;
}
}
.backdrop {
width:110%;
height:110%;
top:-5%;
left:-5%;
position:absolute;
z-index:-99;
background-color:#000;
img {
width:100%;
height:100%;
display:block;
filter:blur(15px);
opacity:0.6;
}
}
.main-header {
width:100%;
display:flex;
background-color:rgba(0,0,0,0.2);
.left, .right, .center {
flex:1;
display:flex;
padding:1rem;
justify-content:flex-start;
button {
display:block;
background:none;
border:none;
font-size:12pt;
outline:none;
color:white;
}
}
.right {
text-align:right;
justify-content:flex-end;
}
.center {
justify-content:center;
}
/*.play-icon {
cursor: pointer;
user-select: none;
width:12pt;
height:12pt;
clip-path: polygon(0% 0%, 100% 50%, 0% 100%);
transition: all 500ms ease;
display:flex;
flex-direction:column;
div {
background-color: #fff;
display: block;
flex:1;
transition: all 500ms ease;
}
&.pause {
clip-path:none;
transform: rotate(90deg);
div.first {
margin-bottom: 20%;
}
}
}*/
.play-icon {
$size: 12pt;
width:$size;
height:$size;
overflow:hidden;
display:flex;
position:relative;
clip-path:polygon(0% 0%, 100% 50%, 100% 50%, 0% 100%);
user-select:none;
appearance:none;
cursor:pointer;
&:active {
&:before, &:after {
transition: none;
}
}
&:before, &:after {
background-color:rgba(255,255,255,1);
display:block;
content:'';
height:100%;
width:50%;
}
&:after {
margin-left:0%;
}
&, &:after {
transition:all 250ms ease;
}
&.pause {
clip-path:polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
&:after {
margin-left:12.5%;
}
}
}
}
main {
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
.song-info {
margin:2rem 0;
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
color:white;
text-shadow:1px 1px 0 rgba(0,0,0,0.6);
text-align:center;
span {
display:block;
}
.song-title {
font-size:20pt;
}
.song-artist {
font-size:14pt;
margin-top:0.3rem;
}
}
.cover-art {
margin: 2rem auto;
width: 256px;
height: 256px;
position:relative;
.music-visuals {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 50px;
z-index: 99;
}
img {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 90;
display:block;
}
}
}
.controls {
position: relative;
.waveform-wrap {
width:100%;
height: 50px;
.background-waveform, .foreground-waveform {
position:absolute;
width:100%;
height:100%;
top:0;
left:0;
z-index:89;
overflow:hidden;
svg {
width:100vw;
height:50px;
}
}
.foreground-waveform {
width: 50%;
z-index:99;
}
}
}
@keyframes materialResponse {
0% {
width: 0;
height: 0;
margin: 0;
background: rgba(255,255,255,0.1);
}
100% {
width: 250%;
height: 250%;
margin: -125%;
background: rgba(255,255,255,0.4);
}
}
@media (max-width:450px) {
main .cover-art {
img {
margin:0 auto;
max-width:100%;
}
}
main .song-info {
margin:1.5rem 0;
}
}
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" />
<link href="http://fonts.googleapis.com/css?family=Roboto:400,300" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment