mirror of
https://github.com/captbaritone/webamp.git
synced 2026-07-25 11:04:00 +00:00
Add first draft of sine wave visualization
This commit is contained in:
parent
275b210313
commit
b6f52424ce
5 changed files with 115 additions and 4 deletions
|
|
@ -32,7 +32,7 @@
|
|||
<div id='second-first-digit'></div>
|
||||
<div id='second-second-digit'></div>
|
||||
</div>
|
||||
<div id='visualization'></div>
|
||||
<canvas id='visualizer' width='150' height='32'></canvas>
|
||||
</div>
|
||||
<div class='media-info'>
|
||||
<div id='song-title' class='text'></div>
|
||||
|
|
@ -70,10 +70,10 @@
|
|||
<a id='about' target='_blank' href='https://github.com/captbaritone/winamp2-js'></a>
|
||||
</div>
|
||||
<p style="position: absolute; bottom: 0;">by <a href='https://twitter.com/captbaritone'>@captbaritone</a> - <a href='https://github.com/captbaritone/winamp2-js'>GitHub</a></p>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/2.4.0/jszip.min.js"></script>
|
||||
|
||||
<script src="file-manager.js"></script>
|
||||
<script src="visualizer.js"></script>
|
||||
<script src="media.js"></script>
|
||||
<script src="font.js"></script>
|
||||
<script src="skin.js"></script>
|
||||
|
|
|
|||
19
media.js
19
media.js
|
|
@ -7,6 +7,7 @@ Media = {
|
|||
waiting: function(){},
|
||||
playing: function(){},
|
||||
timeupdate: function(){},
|
||||
visualizerupdate: function(){},
|
||||
ended: function(){}
|
||||
},
|
||||
_startTime: 0,
|
||||
|
|
@ -17,6 +18,12 @@ Media = {
|
|||
|
||||
init: function() {
|
||||
this._gainNode = this._context.createGain();
|
||||
this._analyser = this._context.createAnalyser();
|
||||
|
||||
this._analyser.fftSize = 2048;
|
||||
this._bufferLength = this._analyser.frequencyBinCount;
|
||||
this._dataArray = new Uint8Array(this._bufferLength);
|
||||
this._analyser.getByteTimeDomainData(this._dataArray);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -73,7 +80,8 @@ Media = {
|
|||
this._source = this._context.createBufferSource();
|
||||
if(this._buffer) {
|
||||
this._source.buffer = this._buffer;
|
||||
this._source.connect(this._gainNode);
|
||||
this._source.connect(this._analyser);
|
||||
this._analyser.connect(this._gainNode);
|
||||
this._gainNode.connect(this._context.destination);
|
||||
|
||||
this._position = typeof position !== 'undefined' ? position : this._position;
|
||||
|
|
@ -94,7 +102,6 @@ Media = {
|
|||
stop: function() {
|
||||
this._silence();
|
||||
this._position = 0;
|
||||
this._callbacks.ended();
|
||||
},
|
||||
|
||||
_silence: function() {
|
||||
|
|
@ -137,10 +144,18 @@ Media = {
|
|||
this.play(time);
|
||||
},
|
||||
|
||||
// There is probably a more reasonable way to do this, rather than having
|
||||
// it always running.
|
||||
_draw: function() {
|
||||
if(this._playing) {
|
||||
this._updatePosition();
|
||||
this._callbacks.timeupdate();
|
||||
|
||||
// _updatePosition might have stoped the playing
|
||||
if(this._playing) {
|
||||
this._analyser.getByteTimeDomainData(this._dataArray);
|
||||
this._callbacks.visualizerupdate(this._bufferLength, this._dataArray);
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(this._draw.bind(this));
|
||||
},
|
||||
|
|
|
|||
68
visualizer.js
Normal file
68
visualizer.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* Use Canvas to recreate the simple Winamp visualizer */
|
||||
Visualizer = {
|
||||
init: function(canvasNode) {
|
||||
this.canvas = canvasNode;
|
||||
this.canvasCtx = this.canvas.getContext("2d");
|
||||
this.canvasCtx.imageSmoothingEnabled= false;
|
||||
this.canvasCtx.translate(1, 1); // http://stackoverflow.com/questions/13593527/canvas-make-the-line-thicker
|
||||
this.width = this.canvas.width;
|
||||
this.height = this.canvas.height;
|
||||
this.NONE = 0;
|
||||
this.OSCILLOSCOPE = 1;
|
||||
this.BAR = 2;
|
||||
return this;
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
// +/- is just there to deal with offset, meh if its right or not ;)
|
||||
this.canvasCtx.clearRect(-2, -2, this.width + 2, this.height + 2);
|
||||
},
|
||||
|
||||
paintFrame: function(type, bufferLength, dataArray) {
|
||||
this.clear();
|
||||
if(type == this.OSCILLOSCOPE) {
|
||||
return this._paintOscilloscopeFrame(bufferLength, dataArray);
|
||||
} else if(type == this.BAR) {
|
||||
return this._paintBarFrame(bufferLength, dataArray);
|
||||
}
|
||||
},
|
||||
|
||||
_paintOscilloscopeFrame: function(bufferLength, dataArray) {
|
||||
function avg() {
|
||||
var avg = 0;
|
||||
var count = 0;
|
||||
for (var l = lastIndex; l < index + 1; l++) {
|
||||
avg += dataArray[l];
|
||||
count++;
|
||||
}
|
||||
var v = avg / count;
|
||||
return h * v / 128;
|
||||
}
|
||||
|
||||
this.canvasCtx.lineWidth = 2; // 2 because were shrinking the canvas by 2
|
||||
this.canvasCtx.strokeStyle = 'rgba(255, 255, 255,1)';
|
||||
|
||||
this.canvasCtx.beginPath();
|
||||
|
||||
var sliceWidth = bufferLength / this.width * 1;
|
||||
var h = this.height / 2;
|
||||
|
||||
this.canvasCtx.moveTo(-2, h);
|
||||
var index = 0;
|
||||
var lastIndex = 0;
|
||||
for (var i = 0, iEnd = this.width * 1; i < iEnd; i += 2) {
|
||||
index = i * sliceWidth | 0;
|
||||
this.canvasCtx.lineTo(i, avg());
|
||||
lastIndex = index + 1;
|
||||
}
|
||||
lastIndex = index + 1;
|
||||
index = i * sliceWidth | 0;
|
||||
|
||||
this.canvasCtx.lineTo(this.width, avg());
|
||||
this.canvasCtx.stroke();
|
||||
},
|
||||
|
||||
_paintBarFrame: function(bufferLength, dataArray) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
|
@ -197,6 +197,14 @@ a:focus { outline: none; }
|
|||
width: 9px;
|
||||
}
|
||||
|
||||
#visualizer {
|
||||
position: absolute;
|
||||
width: 75px;
|
||||
height: 16px;
|
||||
top: 43px;
|
||||
left: 24px;
|
||||
}
|
||||
|
||||
|
||||
.text {
|
||||
position: absolute;
|
||||
|
|
|
|||
20
winamp.js
20
winamp.js
|
|
@ -4,6 +4,9 @@ function Winamp () {
|
|||
this.fileManager = FileManager;
|
||||
this.media = Media.init();
|
||||
this.skin = SkinManager;
|
||||
this.skinManager = SkinManager;
|
||||
this.visualizer = Visualizer.init(document.getElementById('visualizer'));
|
||||
this.visualizerStyle = this.visualizer.OSCILLOSCOPE;
|
||||
|
||||
this.nodes = {
|
||||
'option': document.getElementById('option'),
|
||||
|
|
@ -17,6 +20,7 @@ function Winamp () {
|
|||
'songTitle': document.getElementById('song-title'),
|
||||
'time': document.getElementById('time'),
|
||||
'shadeTime': document.getElementById('shade-time'),
|
||||
'visualizer': document.getElementById('visualizer'),
|
||||
'previous': document.getElementById('previous'),
|
||||
'play': document.getElementById('play'),
|
||||
'pause': document.getElementById('pause'),
|
||||
|
|
@ -103,7 +107,12 @@ function Winamp () {
|
|||
self.updateTime();
|
||||
});
|
||||
|
||||
this.media.addEventListener('visualizerupdate', function(bufferLength, dataArray) {
|
||||
self.visualizer.paintFrame(self.visualizerStyle, bufferLength, dataArray);
|
||||
});
|
||||
|
||||
this.media.addEventListener('ended', function() {
|
||||
self.visualizer.clear();
|
||||
self.setStatus('stop');
|
||||
});
|
||||
|
||||
|
|
@ -130,6 +139,17 @@ function Winamp () {
|
|||
self.updateTime();
|
||||
}
|
||||
|
||||
this.nodes.visualizer.onclick = function() {
|
||||
if(self.visualizerStyle == self.visualizer.NONE) {
|
||||
// self.visualizerStyle = self.visualizer.BAR;
|
||||
//} else if(self.visualizerStyle == self.visualizer.BAR) {
|
||||
self.visualizerStyle = self.visualizer.OSCILLOSCOPE;
|
||||
} else if(self.visualizerStyle == self.visualizer.OSCILLOSCOPE) {
|
||||
self.visualizerStyle = self.visualizer.NONE;
|
||||
}
|
||||
self.visualizer.clear();
|
||||
}
|
||||
|
||||
this.nodes.previous.onclick = function() {
|
||||
// Implement this when we support playlists
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue