Last active
August 29, 2015 14:27
-
-
Save reepush/57bb074ab874fbc9e8bd to your computer and use it in GitHub Desktop.
ШРИ-2015 (задание 3)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mixin info-item(name) | |
.item | |
span.name #{name}: | |
span(bind='app.info.#{name}') | |
.App(ondrop='app.loadFile(event)') | |
.container | |
label.load-file | |
span.fa.fa-music | |
input(onchange='app.loadFile(event)' type='file') | |
.info-container | |
.info | |
+info-item('file') | |
+info-item('artist') | |
+info-item('title') | |
+info-item('album') | |
.controls(bind-class='app.player.status') | |
a.play(onclick='app.player.play()' | |
class='fa fa-play') | |
a.pause(onclick='app.player.pause()' | |
class='fa fa-pause') | |
canvas.visualization |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function init() { | |
window.app = new App() | |
setupBindings() | |
app.loadFile({ | |
type: 'url', | |
data: { | |
file: 'Fleetwood Mac - Little Lies.mp3', | |
artist: 'Fleetwood Mac', | |
title: 'Little Lies', | |
album: 'Tango In The Night', | |
url: 'http://push.org.ru/grisha/files/Fleetwood Mac - Little Lies.mp3' | |
} | |
}) | |
} | |
function App() { | |
var canvas = $('canvas')[0] | |
var player = this.player = new Player(canvas) | |
this.info = {} | |
} | |
App.prototype.loadFile = function(event) { | |
var instance = this | |
var file, info, buffer | |
if (event.type != 'url') { | |
var reader = new FileReader() | |
var file = (event.type == 'change') | |
? event.target.files[0] | |
: event.dataTransfer.files[0] | |
this.player.getInfo(file, this.info) | |
this.info.file = file.name | |
reader.onload = function(event) { | |
instance.player.load(event.target.result) | |
} | |
reader.readAsArrayBuffer(file) | |
} else { | |
var data = event.data | |
this.info.file = data.file | |
this.info.artist = data.artist | |
this.info.title = data.title | |
this.info.album = data.album | |
request = new XMLHttpRequest() | |
request.open('GET', data.url, true) | |
request.responseType = 'arraybuffer' | |
request.onload = function() { | |
instance.player.load(request.response) | |
} | |
request.send() | |
} | |
return false | |
} | |
function Player(canvas) { | |
this.context = new AudioContext() | |
this.time = 0 | |
this.analyser = this.context.createAnalyser() | |
this.visualizer = new Visualizer(this.analyser, canvas) | |
this.status = 'playing' | |
} | |
Player.prototype.load = function(audioData) { | |
var context = this.context | |
var instance = this | |
this.pause() | |
context.decodeAudioData(audioData, function(buffer) { | |
instance.buffer = buffer | |
instance.time = 0 | |
instance.play() | |
}) | |
} | |
Player.prototype.pause = function() { | |
this.time = this.context.currentTime | |
this.status = 'paused' | |
this.source && this.source.stop() | |
this.visualizer.stop() | |
} | |
Player.prototype.play = function() { | |
var context = this.context | |
var source = this.source = context.createBufferSource() | |
source.buffer = this.buffer | |
source.loop = true | |
source.connect(this.analyser) | |
this.analyser.connect(context.destination) | |
this.status = 'playing' | |
source.start(0, this.time) | |
this.visualizer.start() | |
} | |
Player.prototype.getInfo = function(file, info) { | |
id3(file, function(err, tags) { | |
info.title = tags.title | |
info.artist = tags.artist | |
info.album = tags.album | |
}) | |
} | |
function Visualizer(analyser, canvas) { | |
this.width = canvas.width | |
this.height = canvas.height | |
this.canvas = canvas.getContext('2d') | |
this.analyser = analyser | |
this.RAF = undefined | |
} | |
Visualizer.prototype.start = function() { | |
var instance = this | |
var width = this.width | |
var height = this.height | |
var analyser = this.analyser | |
var canvas = this.canvas | |
analyser.fftSize = 512 | |
var bufferLength = analyser.frequencyBinCount | |
var dataArray = new Uint8Array(bufferLength) | |
canvas.clearRect(0, 0, width, height) | |
draw() | |
function draw() { | |
instance.RAF = requestAnimationFrame(draw) | |
analyser.getByteFrequencyData(dataArray) | |
canvas.fillStyle = 'rgb(255, 255, 255)' | |
canvas.fillRect(0, 0, width, height) | |
var barWidth = (width / bufferLength) * 2.5 | |
barWidth = Math.floor(barWidth) | |
var barHeight | |
var x = 0 | |
for (var i = 0; i < bufferLength; i++) { | |
barHeight = dataArray[i] | |
canvas.fillStyle = 'rgb(0, 0, 0)' | |
canvas.fillRect(x, height-barHeight/2, barWidth, barHeight/2) | |
x += barWidth + 1 | |
} | |
} | |
} | |
Visualizer.prototype.stop = function() { | |
cancelAnimationFrame(this.RAF) | |
} | |
function setupBindings() { | |
$('[ondrop]').on('drop dragover dragenter', function(event) { | |
event.preventDefault() | |
}) | |
function deepObject(object, properties) { | |
properties | |
.split('.') | |
.slice(0, -1) | |
.forEach(function(property) { | |
object = object[property] | |
}) | |
return { | |
object: object, | |
property: properties.split('.').slice(-1) | |
} | |
} | |
$('[bind]').each(function(index, bindable) { | |
var _value, _element = bindable | |
var variable = $(bindable).attr('bind') | |
var deep = deepObject(window, variable) | |
Object.defineProperty( | |
deep.object, | |
deep.property, { | |
set: function(value) { | |
_value = value | |
_element.innerHTML = value | |
}, | |
get: function() { | |
return _value | |
} | |
} | |
) | |
}) | |
$('[bind-class]').each(function(index, bindable) { | |
var _value, _element = bindable | |
var variable = $(bindable).attr('bind-class') | |
var deep = deepObject(window, variable) | |
var initial = deep.object[deep.property] | |
Object.defineProperty( | |
deep.object, | |
deep.property, { | |
set: function(value) { | |
$(_element) | |
.removeClass(_value) | |
.addClass(value) | |
_value = value | |
}, | |
get: function() { | |
return _value | |
} | |
} | |
) | |
deep.object[deep.property] = initial | |
}) | |
} | |
init() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* | |
box-sizing: border-box | |
a | |
cursor: pointer | |
html | |
font-family: 'VT323', monospace | |
font-size: 22px | |
text-transform: uppercase | |
body | |
background-color: white | |
color: black | |
.App | |
position: relative | |
min-height: 100vh | |
padding-bottom: 150px | |
.container | |
width: 80% | |
margin: auto | |
padding-top: 2em | |
canvas | |
position: absolute | |
width: 100% | |
height: 150px | |
bottom: 0 | |
.load-file | |
display: block | |
text-align: right | |
span | |
cursor: pointer | |
input[type='file'] | |
display: none | |
.controls | |
text-align: center | |
&.playing .play | |
display: none | |
&.paused .pause | |
display: none | |
.info | |
display: inline-block | |
&-container | |
text-align: center | |
margin-bottom: 2em | |
.item | |
text-align: left | |
.name | |
display: inline-block | |
width: 75px | |
.fa | |
font-size: 36px | |
&:hover | |
text-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment