Decoding with my own translation of libmad, loading and playback progress, next and prev songs
This commit is contained in:
parent
baa6f4ef23
commit
d6e22f6111
@ -3,12 +3,8 @@
|
|||||||
#include <mad.h>
|
#include <mad.h>
|
||||||
|
|
||||||
M::Audio::Audio(W::Blob* p_file, const W::Address& addr, QObject* parent):
|
M::Audio::Audio(W::Blob* p_file, const W::Address& addr, QObject* parent):
|
||||||
File(p_file, addr, parent),
|
File(p_file, addr, parent)
|
||||||
frames()
|
|
||||||
{
|
{
|
||||||
W::Handler* requestFrames = W::Handler::create(address + W::Address({u"requestFrames"}), this, &M::Audio::_h_requestFrames);
|
|
||||||
|
|
||||||
addHandler(requestFrames);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
M::Audio::~Audio()
|
M::Audio::~Audio()
|
||||||
@ -32,41 +28,18 @@ void M::Audio::initAdditional(const W::String& p_mime)
|
|||||||
|
|
||||||
uint64_t length = 0;
|
uint64_t length = 0;
|
||||||
uint64_t tBits = 0;
|
uint64_t tBits = 0;
|
||||||
|
uint64_t amount = 0;
|
||||||
while(stream.error != MAD_ERROR_BUFLEN) { //TODO handle other errors;
|
while(stream.error != MAD_ERROR_BUFLEN) { //TODO handle other errors;
|
||||||
|
|
||||||
int success = mad_header_decode(&header, &stream);
|
int success = mad_header_decode(&header, &stream);
|
||||||
if (success == 0) {
|
if (success == 0) {
|
||||||
frames.emplace_back(stream.this_frame - stream.buffer, stream.next_frame - stream.this_frame);
|
|
||||||
|
|
||||||
|
amount++;
|
||||||
length += header.duration.seconds * MAD_TIMER_RESOLUTION + header.duration.fraction;
|
length += header.duration.seconds * MAD_TIMER_RESOLUTION + header.duration.fraction;
|
||||||
tBits += header.bitrate;
|
tBits += header.bitrate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
additional.insert(u"duration", new W::Uint64(length / MAD_TIMER_RESOLUTION));
|
additional.insert(u"duration", new W::Uint64(length / MAD_TIMER_RESOLUTION));
|
||||||
additional.insert(u"bitrate", new W::Uint64(tBits / frames.size()));
|
additional.insert(u"bitrate", new W::Uint64(tBits / amount));
|
||||||
additional.insert(u"framesAmount", new W::Uint64(frames.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void M::Audio::h_requestFrames(const W::Event& ev)
|
|
||||||
{
|
|
||||||
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
|
|
||||||
const W::Uint64& index = static_cast<const W::Uint64&>(vc.at(u"index"));
|
|
||||||
const W::Uint64& amount = static_cast<const W::Uint64&>(vc.at(u"amount"));
|
|
||||||
|
|
||||||
W::Vocabulary* evc = new W::Vocabulary();
|
|
||||||
if (index + amount > frames.size()) {
|
|
||||||
evc->insert(u"result", new W::Uint64(1));
|
|
||||||
} else {
|
|
||||||
evc->insert(u"result", new W::Uint64(0));
|
|
||||||
W::Vector* vframes = new W::Vector();
|
|
||||||
for (int i = 0; i < amount; ++i) {
|
|
||||||
const std::pair<uint64_t, uint64_t>& pair = frames[index + i]; //TODO optimize?
|
|
||||||
vframes->push(file->slice(pair.first, pair.second));
|
|
||||||
}
|
|
||||||
|
|
||||||
evc->insert(u"frames", vframes);
|
|
||||||
}
|
|
||||||
|
|
||||||
response(evc, W::Address{u"responseFrames"}, ev);
|
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,6 @@ namespace M {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initAdditional(const W::String& p_mime) override;
|
void initAdditional(const W::String& p_mime) override;
|
||||||
|
|
||||||
handler(requestFrames);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::deque<std::pair<uint64_t, uint64_t>> frames;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,11 @@ M::File::File(W::Blob* p_file, const W::Address& addr, QObject* parent):
|
|||||||
{
|
{
|
||||||
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::File::_h_get);
|
W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::File::_h_get);
|
||||||
W::Handler* getAdditional = W::Handler::create(address + W::Address({u"getAdditional"}), this, &M::File::_h_getAdditional);
|
W::Handler* getAdditional = W::Handler::create(address + W::Address({u"getAdditional"}), this, &M::File::_h_getAdditional);
|
||||||
|
W::Handler* getSlice = W::Handler::create(address + W::Address({u"getSlice"}), this, &M::File::_h_getSlice);
|
||||||
|
|
||||||
addHandler(get);
|
addHandler(get);
|
||||||
addHandler(getAdditional);
|
addHandler(getAdditional);
|
||||||
|
addHandler(getSlice);
|
||||||
}
|
}
|
||||||
|
|
||||||
M::File::~File()
|
M::File::~File()
|
||||||
@ -35,7 +37,7 @@ void M::File::initAdditional(const W::String& p_mime)
|
|||||||
{
|
{
|
||||||
additional.clear();
|
additional.clear();
|
||||||
|
|
||||||
additional.insert(u"size", new W::Uint64(file->size()));
|
additional.insert(u"size", new W::Uint64(file->length()));
|
||||||
additional.insert(u"mimeType", p_mime);
|
additional.insert(u"mimeType", p_mime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,3 +108,21 @@ M::File * M::File::create(W::Blob* blob, const W::Address& addr, QObject* parent
|
|||||||
out->initAdditional(W::String(mime.toStdString()));
|
out->initAdditional(W::String(mime.toStdString()));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void M::File::h_getSlice(const W::Event& ev)
|
||||||
|
{
|
||||||
|
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
|
||||||
|
const W::Uint64& begin = static_cast<const W::Uint64&>(vc.at(u"begin"));
|
||||||
|
const W::Uint64& size = static_cast<const W::Uint64&>(vc.at(u"size"));
|
||||||
|
|
||||||
|
W::Vocabulary* evc = new W::Vocabulary();
|
||||||
|
if (begin > file->length() || begin + size > file->length()) {
|
||||||
|
evc->insert(u"result", new W::Uint64(1));
|
||||||
|
} else {
|
||||||
|
evc->insert(u"result", new W::Uint64(0));
|
||||||
|
evc->insert(u"slice", file->slice(begin, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
response(evc, W::Address{u"getSlice"}, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ namespace M {
|
|||||||
|
|
||||||
handler(get);
|
handler(get);
|
||||||
handler(getAdditional);
|
handler(getAdditional);
|
||||||
|
handler(getSlice);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
W::Vocabulary additional;
|
W::Vocabulary additional;
|
||||||
|
@ -9,79 +9,16 @@ var Audio = File.inherit({
|
|||||||
className: "Audio",
|
className: "Audio",
|
||||||
constructor: function Audio(addr) {
|
constructor: function Audio(addr) {
|
||||||
File.fn.constructor.call(this, addr);
|
File.fn.constructor.call(this, addr);
|
||||||
|
|
||||||
this._loadedFrames = 0;
|
|
||||||
this._totalFrames = 0;
|
|
||||||
this._waitingForFrames = false;
|
|
||||||
this._frames = new Vector();
|
|
||||||
|
|
||||||
this.addHandler("responseFrames");
|
|
||||||
},
|
|
||||||
destructor: function() {
|
|
||||||
this._frames.destructor();
|
|
||||||
|
|
||||||
File.fn.destructor.call(this);
|
|
||||||
},
|
},
|
||||||
hasMore: function() {
|
hasMore: function() {
|
||||||
return this._totalFrames > this._loadedFrames;
|
return this.getSize() > this.data.length();
|
||||||
},
|
},
|
||||||
_getAdditional: function(add) {
|
getBitrate: function() {
|
||||||
var ac = File.fn._getAdditional.call(this, add);
|
return this._additional.at("bitrate").valueOf();
|
||||||
|
|
||||||
if (ac) {
|
|
||||||
this._loadedFrames = 0;
|
|
||||||
this._totalFrames = this._additional.at("framesAmount").valueOf();
|
|
||||||
this._waitingForFrames = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ac;
|
|
||||||
},
|
},
|
||||||
_h_responseFrames: function(ev) {
|
getDuration: function() {
|
||||||
if (this._waitingForFrames === true) {
|
return this._additional.at("duration").valueOf();
|
||||||
var data = ev.getData();
|
|
||||||
|
|
||||||
var success = data.at("result").valueOf();
|
|
||||||
if (success === 0) {
|
|
||||||
var frames = data.at("frames");
|
|
||||||
var amount = frames.length();
|
|
||||||
var buffer = new ArrayBuffer(0);
|
|
||||||
|
|
||||||
for (var i = 0; i < amount; ++i) {
|
|
||||||
var blob = frames.at(i).clone();
|
|
||||||
this._frames.push(blob);
|
|
||||||
var frame = blob.valueOf();
|
|
||||||
|
|
||||||
var newArr = new Uint8Array(buffer.byteLength + frame.byteLength);
|
|
||||||
newArr.set(new Uint8Array(buffer), 0);
|
|
||||||
newArr.set(new Uint8Array(frame), buffer.byteLength);
|
|
||||||
buffer = newArr.buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this._loadedFrames += amount;
|
|
||||||
this._waitingForFrames = false;
|
|
||||||
this.trigger("newFrames", buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
requestMore: function() {
|
|
||||||
if (!this._waitingForFrames) {
|
|
||||||
if (this._registered && this._subscribed) {
|
|
||||||
var allowed = this._totalFrames - this._loadedFrames;
|
|
||||||
|
|
||||||
if (allowed > 0) {
|
|
||||||
var vc = new Vocabulary();
|
|
||||||
vc.insert("index", new Uint64(this._loadedFrames));
|
|
||||||
vc.insert("amount", new Uint64(Math.min(framePortion, allowed)));
|
|
||||||
|
|
||||||
this.send(vc, "requestFrames");
|
|
||||||
this._waitingForFrames = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var framePortion = 10;
|
|
||||||
|
|
||||||
module.exports = Audio;
|
module.exports = Audio;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
var Controller = require("../controller");
|
var Controller = require("../controller");
|
||||||
var WVocabulary = require("../../wType/vocabulary");
|
var WVocabulary = require("../../wType/vocabulary");
|
||||||
|
var Uint64 = require("../../wType/uint64");
|
||||||
|
var Blob = require("../../wType/blob");
|
||||||
|
|
||||||
var File = Controller.inherit({
|
var File = Controller.inherit({
|
||||||
"className": "File",
|
"className": "File",
|
||||||
@ -10,17 +12,17 @@ var File = Controller.inherit({
|
|||||||
|
|
||||||
this._hasData = false;
|
this._hasData = false;
|
||||||
this._hasAdditional = false;
|
this._hasAdditional = false;
|
||||||
this.data = null;
|
this.data = new Blob();
|
||||||
this._additional = null;
|
this._additional = null;
|
||||||
|
this._waitingForSlice = false;
|
||||||
this._need = 0;
|
this._need = 0;
|
||||||
|
|
||||||
this.addHandler("get");
|
this.addHandler("get");
|
||||||
this.addHandler("getAdditional");
|
this.addHandler("getAdditional");
|
||||||
|
this.addHandler("getSlice");
|
||||||
},
|
},
|
||||||
"destructor": function() {
|
"destructor": function() {
|
||||||
if (this._hasData) {
|
this.data.destructor();
|
||||||
this.data.destructor();
|
|
||||||
}
|
|
||||||
if (this._hasAdditional) {
|
if (this._hasAdditional) {
|
||||||
this._additional.destructor();
|
this._additional.destructor();
|
||||||
}
|
}
|
||||||
@ -46,6 +48,9 @@ var File = Controller.inherit({
|
|||||||
"getMimeType": function() {
|
"getMimeType": function() {
|
||||||
return this._additional.at("mimeType").toString();
|
return this._additional.at("mimeType").toString();
|
||||||
},
|
},
|
||||||
|
"getSize": function() {
|
||||||
|
return this._additional.at("size").valueOf();
|
||||||
|
},
|
||||||
"_h_get": function(ev) {
|
"_h_get": function(ev) {
|
||||||
var dt = ev.getData();
|
var dt = ev.getData();
|
||||||
|
|
||||||
@ -55,7 +60,9 @@ var File = Controller.inherit({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._hasData = true;
|
this._hasData = true;
|
||||||
|
var oldData = this.data;
|
||||||
this.data = dt.at("data").clone();
|
this.data = dt.at("data").clone();
|
||||||
|
oldData.destructor();
|
||||||
this.trigger("data");
|
this.trigger("data");
|
||||||
},
|
},
|
||||||
"_h_getAdditional": function(ev) {
|
"_h_getAdditional": function(ev) {
|
||||||
@ -69,6 +76,24 @@ var File = Controller.inherit({
|
|||||||
this.trigger("ready");
|
this.trigger("ready");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"_h_getSlice": function(ev) {
|
||||||
|
if (this._waitingForSlice) {
|
||||||
|
this._waitingForSlice = false;
|
||||||
|
var vc = ev.getData();
|
||||||
|
if (vc.at("result").valueOf() == 0) {
|
||||||
|
var slice = vc.at("slice");
|
||||||
|
this.data["+="](slice);
|
||||||
|
this.trigger("slice", slice);
|
||||||
|
|
||||||
|
if (this.getSize() === this.data.length()) {
|
||||||
|
this._hasData = true;
|
||||||
|
this.trigger("data");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.trigger("serviceMessage", "Error receiving slice from " + this._pairAddress.toString(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"needData": function() {
|
"needData": function() {
|
||||||
if (this._need === 0) {
|
if (this._need === 0) {
|
||||||
var vc = new WVocabulary();
|
var vc = new WVocabulary();
|
||||||
@ -77,6 +102,30 @@ var File = Controller.inherit({
|
|||||||
}
|
}
|
||||||
++this._need;
|
++this._need;
|
||||||
},
|
},
|
||||||
|
"requestSlice": function(size) {
|
||||||
|
if (this._hasAdditional) {
|
||||||
|
if (this._waitingForSlice) {
|
||||||
|
throw new Error("An attempt to request a slice of data from " + this._pairAddress.toString() + " while another request is in progress");
|
||||||
|
}
|
||||||
|
var begin = this.data.length();
|
||||||
|
var newSize = Math.min(size, this.getSize() - begin);
|
||||||
|
if (newSize !== size) {
|
||||||
|
//TODO may be inform the developer about that?
|
||||||
|
}
|
||||||
|
if (newSize === 0) {
|
||||||
|
return; //TODO may be inform the developer about that?
|
||||||
|
}
|
||||||
|
var vc = new WVocabulary();
|
||||||
|
vc.insert("begin", new Uint64(begin));
|
||||||
|
vc.insert("size", new Uint64(newSize));
|
||||||
|
|
||||||
|
this.send(vc, "getSlice");
|
||||||
|
this._waitingForSlice = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error("An attempt to request a slice of data from " + this._pairAddress.toString() + " before controller got initialized");
|
||||||
|
}
|
||||||
|
},
|
||||||
"subscribe": function() {
|
"subscribe": function() {
|
||||||
Controller.fn.subscribe.call(this);
|
Controller.fn.subscribe.call(this);
|
||||||
|
|
||||||
|
@ -8,16 +8,11 @@ var Button = require("./button");
|
|||||||
var ImageById = require("./imageById");
|
var ImageById = require("./imageById");
|
||||||
var Vocabulary = require("./vocabulary");
|
var Vocabulary = require("./vocabulary");
|
||||||
var Audio = require("./file/audio");
|
var Audio = require("./file/audio");
|
||||||
|
var Model = require("./localModel");
|
||||||
|
|
||||||
var Enum = require("../utils/enum");
|
var Enum = require("../utils/enum");
|
||||||
var StateMachine = require("../utils/stateMachine");
|
var StateMachine = require("../utils/stateMachine");
|
||||||
|
|
||||||
var Source = AV.EventEmitter.extend(function() {
|
|
||||||
this.prototype.start = function(){}
|
|
||||||
this.prototype.pause = function(){}
|
|
||||||
this.prototype.reset = function(){}
|
|
||||||
});
|
|
||||||
|
|
||||||
var Player = Controller.inherit({
|
var Player = Controller.inherit({
|
||||||
className: "Player",
|
className: "Player",
|
||||||
constructor: function(addr) {
|
constructor: function(addr) {
|
||||||
@ -26,6 +21,7 @@ var Player = Controller.inherit({
|
|||||||
this.controls = Object.create(null);
|
this.controls = Object.create(null);
|
||||||
this.views = Object.create(null);
|
this.views = Object.create(null);
|
||||||
this.mode = PlayerMode.straight.playback;
|
this.mode = PlayerMode.straight.playback;
|
||||||
|
this.progress = new ProgressModel();
|
||||||
this._audio = null;
|
this._audio = null;
|
||||||
this._createStateMachine();
|
this._createStateMachine();
|
||||||
this._createPlayingInfrastructure();
|
this._createPlayingInfrastructure();
|
||||||
@ -34,10 +30,14 @@ var Player = Controller.inherit({
|
|||||||
this.addHandler("viewsChange");
|
this.addHandler("viewsChange");
|
||||||
this.addHandler("play");
|
this.addHandler("play");
|
||||||
this.addHandler("pause");
|
this.addHandler("pause");
|
||||||
|
|
||||||
|
this._playbackInterval = setInterval(this._onInterval.bind(this), 250);
|
||||||
},
|
},
|
||||||
destructor: function() {
|
destructor: function() {
|
||||||
|
this._clearInterval(this._playbackInterval);
|
||||||
|
this._destroyPlayingInfrastructure();
|
||||||
this._fsm.destructor();
|
this._fsm.destructor();
|
||||||
this._player.stop();
|
this.progress.destructor();
|
||||||
|
|
||||||
Controller.fn.destructor.call(this);
|
Controller.fn.destructor.call(this);
|
||||||
},
|
},
|
||||||
@ -109,15 +109,16 @@ var Player = Controller.inherit({
|
|||||||
this.trigger("newElement", ctrl, t);
|
this.trigger("newElement", ctrl, t);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_createPlayingInfrastructure() {
|
_createPlayingInfrastructure: function() {
|
||||||
if (this._source) {
|
this._ctx = new AudioContext();
|
||||||
this._source.reset();
|
this._decoder = new Mp3Decoder();
|
||||||
this._asset.stop();
|
this._currentTime = 0;
|
||||||
this._player.stop();
|
|
||||||
}
|
this._ctx.suspend();
|
||||||
this._source = new Source();
|
},
|
||||||
this._asset = new AV.Asset(this._source);
|
_destroyPlayingInfrastructure: function() {
|
||||||
this._player = new AV.Player(this._asset);
|
this._ctx.close();
|
||||||
|
this._decoder.delete();
|
||||||
},
|
},
|
||||||
_createStateMachine: function() {
|
_createStateMachine: function() {
|
||||||
this._fsm = new StateMachine("initial", graphs[this.mode]);
|
this._fsm = new StateMachine("initial", graphs[this.mode]);
|
||||||
@ -177,13 +178,28 @@ var Player = Controller.inherit({
|
|||||||
this._addView(vc.at("type"), vc.at("address"));
|
this._addView(vc.at("type"), vc.at("address"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_onAudioNewFrames: function(frames) {
|
_onAudioNewSlice: function(frames) {
|
||||||
var data = new Uint8Array(frames);
|
var arr = new Uint8Array(frames.valueOf());
|
||||||
this._source.emit("data", new AV.Buffer(data));
|
this._decoder.addFragment(arr);
|
||||||
|
|
||||||
|
while (this._decoder.hasMore()) {
|
||||||
|
var sb = this._decoder.decode(9999);
|
||||||
|
if (sb === undefined) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
var src = this._ctx.createBufferSource();
|
||||||
|
src.buffer = sb;
|
||||||
|
src.connect(this._ctx.destination);
|
||||||
|
src.start(this._currentTime);
|
||||||
|
this._currentTime += sb.duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.progress.setLoad(this._currentTime / this._audio.getDuration());
|
||||||
|
|
||||||
this._fsm.manipulation("newFrames");
|
this._fsm.manipulation("newFrames");
|
||||||
if (this._audio.hasMore()) {
|
if (this._audio.hasMore()) {
|
||||||
this._audio.requestMore();
|
this._audio.requestSlice(audioPortion);
|
||||||
} else {
|
} else {
|
||||||
this._fsm.manipulation("noMoreFrames");
|
this._fsm.manipulation("noMoreFrames");
|
||||||
}
|
}
|
||||||
@ -191,6 +207,11 @@ var Player = Controller.inherit({
|
|||||||
_onControllerReady: function() {
|
_onControllerReady: function() {
|
||||||
this._fsm.manipulation("controllerReady");
|
this._fsm.manipulation("controllerReady");
|
||||||
},
|
},
|
||||||
|
_onInterval: function() {
|
||||||
|
if (this._audio && this._audio.initialized) {
|
||||||
|
this.progress.setPlayback(this._ctx.currentTime / this._audio.getDuration());
|
||||||
|
}
|
||||||
|
},
|
||||||
_onNewPlayBackElement: function(key, element) {
|
_onNewPlayBackElement: function(key, element) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "image":
|
case "image":
|
||||||
@ -202,7 +223,7 @@ var Player = Controller.inherit({
|
|||||||
if (this.mode === PlayerMode.straight.playback) {
|
if (this.mode === PlayerMode.straight.playback) {
|
||||||
this._audio = new Audio(new Address(["music", element.toString()]));
|
this._audio = new Audio(new Address(["music", element.toString()]));
|
||||||
this.addForeignController("Corax", this._audio);
|
this.addForeignController("Corax", this._audio);
|
||||||
this._audio.on("newFrames", this._onAudioNewFrames, this);
|
this._audio.on("slice", this._onAudioNewSlice, this);
|
||||||
this._audio.on("ready", this._onControllerReady, this);
|
this._audio.on("ready", this._onControllerReady, this);
|
||||||
this._fsm.manipulation("controller");
|
this._fsm.manipulation("controller");
|
||||||
}
|
}
|
||||||
@ -228,16 +249,18 @@ var Player = Controller.inherit({
|
|||||||
this.removeForeignController(this._audio);
|
this.removeForeignController(this._audio);
|
||||||
this._audio.destructor();
|
this._audio.destructor();
|
||||||
this._audio = null;
|
this._audio = null;
|
||||||
|
this._destroyPlayingInfrastructure();
|
||||||
this._createPlayingInfrastructure();
|
this._createPlayingInfrastructure();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "initialPlaying":
|
case "initialPlaying":
|
||||||
if (e.manipulation === "noController") {
|
if (e.manipulation === "noController") {
|
||||||
this._player.pause();
|
this._ctx.suspend();
|
||||||
|
|
||||||
this.removeForeignController(this._audio);
|
this.removeForeignController(this._audio);
|
||||||
this.audio.destructor();
|
this.audio.destructor();
|
||||||
this._audio = null;
|
this._audio = null;
|
||||||
|
this._destroyPlayingInfrastructure();
|
||||||
this._createPlayingInfrastructure();
|
this._createPlayingInfrastructure();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -249,9 +272,9 @@ var Player = Controller.inherit({
|
|||||||
break;
|
break;
|
||||||
case "hasControllerPlaying":
|
case "hasControllerPlaying":
|
||||||
if (this._audio.hasMore()) {
|
if (this._audio.hasMore()) {
|
||||||
this._audio.requestMore();
|
this._audio.requestSlice(audioPortion);
|
||||||
|
|
||||||
this._player.play(); //todo temporal
|
this._ctx.resume(); //todo temporal
|
||||||
} else {
|
} else {
|
||||||
this._fsm.manipulation("noMoreFrames");
|
this._fsm.manipulation("noMoreFrames");
|
||||||
}
|
}
|
||||||
@ -259,24 +282,24 @@ var Player = Controller.inherit({
|
|||||||
case "paused":
|
case "paused":
|
||||||
switch (e.oldState) {
|
switch (e.oldState) {
|
||||||
case "playing":
|
case "playing":
|
||||||
this._player.pause();
|
this._ctx.suspend();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "pausedAllLoaded":
|
case "pausedAllLoaded":
|
||||||
switch (e.oldState) {
|
switch (e.oldState) {
|
||||||
case "playingAllLoaded":
|
case "playingAllLoaded":
|
||||||
this._player.pause();
|
this._ctx.suspend();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "playing":
|
case "playing":
|
||||||
this._player.play();
|
this._ctx.resume();
|
||||||
break;
|
break;
|
||||||
case "playingAllLoaded":
|
case "playingAllLoaded":
|
||||||
switch (e.oldState) {
|
switch (e.oldState) {
|
||||||
case "pausedAllLoaded":
|
case "pausedAllLoaded":
|
||||||
this._player.play();
|
this._ctx.resume();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -371,4 +394,29 @@ graphs[PlayerMode.straight.playback] = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var audioPortion = 1024 * 50;
|
||||||
|
|
||||||
|
var ProgressModel = Model.inherit({
|
||||||
|
className: "ProgressModel",
|
||||||
|
constructor: function(properties) {
|
||||||
|
Model.fn.constructor.call(this, properties);
|
||||||
|
|
||||||
|
this.load = 0;
|
||||||
|
this.playback = 0;
|
||||||
|
this.initialized = true;
|
||||||
|
},
|
||||||
|
setLoad: function(l) {
|
||||||
|
if (l !== this.load) {
|
||||||
|
this.load = l;
|
||||||
|
this.trigger("load", l);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setPlayback: function(p) {
|
||||||
|
if (p !== this.playback) {
|
||||||
|
this.playback = p;
|
||||||
|
this.trigger("playback", p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = Player;
|
module.exports = Player;
|
||||||
|
@ -17,6 +17,36 @@ var Blob = Object.inherit({
|
|||||||
|
|
||||||
return this.size() == other.size(); //TODO let's pretend one shall never wish to compare blobs)
|
return this.size() == other.size(); //TODO let's pretend one shall never wish to compare blobs)
|
||||||
},
|
},
|
||||||
|
"+=": function(other) {
|
||||||
|
if (this.getType() !== other.getType()) {
|
||||||
|
throw new Error("An attempt to add and assign an " + other.className + " to " + this.className);
|
||||||
|
}
|
||||||
|
|
||||||
|
var newData = new ArrayBuffer(this._data.byteLength + other._data.byteLength);
|
||||||
|
var newView = new Uint8Array(newData);
|
||||||
|
var thisView = new Uint8Array(this._data);
|
||||||
|
var otherView = new Uint8Array(other._data);
|
||||||
|
|
||||||
|
newView.set(thisView, 0);
|
||||||
|
newView.set(otherView, this._data.byteLength);
|
||||||
|
|
||||||
|
this._data = newData;
|
||||||
|
},
|
||||||
|
"+": function(other) {
|
||||||
|
if (this.getType() !== other.getType()) {
|
||||||
|
throw new Error("An attempt to add an " + other.className + " to " + this.className);
|
||||||
|
}
|
||||||
|
|
||||||
|
var newData = new ArrayBuffer(this._data.byteLength + other._data.byteLength);
|
||||||
|
var newView = new Uint8Array(newData);
|
||||||
|
var thisView = new Uint8Array(this._data);
|
||||||
|
var otherView = new Uint8Array(other._data);
|
||||||
|
|
||||||
|
newView.set(thisView, 0);
|
||||||
|
newView.set(otherView, this._data.byteLength);
|
||||||
|
|
||||||
|
return new Blob(newData);
|
||||||
|
},
|
||||||
"base64": function() {
|
"base64": function() {
|
||||||
var arr = new Uint8Array(this._data);
|
var arr = new Uint8Array(this._data);
|
||||||
var bin = "";
|
var bin = "";
|
||||||
|
@ -3,8 +3,6 @@ cmake_minimum_required(VERSION 2.8.12)
|
|||||||
add_subdirectory(requirejs)
|
add_subdirectory(requirejs)
|
||||||
add_subdirectory(wSocket)
|
add_subdirectory(wSocket)
|
||||||
add_subdirectory(bintrees)
|
add_subdirectory(bintrees)
|
||||||
add_subdirectory(mp3)
|
|
||||||
add_subdirectory(aurora)
|
|
||||||
add_subdirectory(wContainer)
|
add_subdirectory(wContainer)
|
||||||
add_subdirectory(utils)
|
add_subdirectory(utils)
|
||||||
add_subdirectory(wType)
|
add_subdirectory(wType)
|
||||||
@ -12,3 +10,4 @@ add_subdirectory(wDispatcher)
|
|||||||
add_subdirectory(wTest)
|
add_subdirectory(wTest)
|
||||||
add_subdirectory(wController)
|
add_subdirectory(wController)
|
||||||
add_subdirectory(fonts)
|
add_subdirectory(fonts)
|
||||||
|
add_subdirectory(em)
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
|
||||||
|
|
||||||
configure_file(aurora.js aurora.js)
|
|
File diff suppressed because it is too large
Load Diff
4
lorgar/lib/em/CMakeLists.txt
Normal file
4
lorgar/lib/em/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
|
||||||
|
configure_file(wrapper.js wrapper.js)
|
||||||
|
configure_file(wrapper.wasm wrapper.wasm COPYONLY)
|
4
lorgar/lib/em/wrapper.js
Normal file
4
lorgar/lib/em/wrapper.js
Normal file
File diff suppressed because one or more lines are too long
BIN
lorgar/lib/em/wrapper.wasm
Normal file
BIN
lorgar/lib/em/wrapper.wasm
Normal file
Binary file not shown.
@ -1,3 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
|
||||||
|
|
||||||
configure_file(mp3.js mp3.js)
|
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
(function main_js() {
|
(function main_js() {
|
||||||
requirejs.config({
|
requirejs.config({
|
||||||
"baseUrl": "/",
|
"baseUrl": "/"
|
||||||
"shim": {
|
|
||||||
"lib/mp3/mp3": ["lib/aurora/aurora"]
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
requirejs.onError = function(e) {
|
requirejs.onError = function(e) {
|
||||||
throw e;
|
throw e;
|
||||||
@ -14,7 +11,8 @@
|
|||||||
defineArray.push("test/test");
|
defineArray.push("test/test");
|
||||||
defineArray.push("core/lorgar");
|
defineArray.push("core/lorgar");
|
||||||
defineArray.push("lib/utils/globalMethods");
|
defineArray.push("lib/utils/globalMethods");
|
||||||
defineArray.push("lib/mp3/mp3");
|
defineArray.push("lib/em/wrapper");
|
||||||
|
|
||||||
|
|
||||||
require(defineArray, function main_module() {
|
require(defineArray, function main_module() {
|
||||||
require("lib/utils/globalMethods");
|
require("lib/utils/globalMethods");
|
||||||
@ -24,6 +22,8 @@
|
|||||||
var Controller = require("lib/wController/controller");
|
var Controller = require("lib/wController/controller");
|
||||||
var View = require("views/view");
|
var View = require("views/view");
|
||||||
|
|
||||||
|
window.Mp3Decoder = Module.Decoder;
|
||||||
|
|
||||||
var waiter = {
|
var waiter = {
|
||||||
views: false,
|
views: false,
|
||||||
controllers: false,
|
controllers: false,
|
||||||
|
@ -14,5 +14,6 @@ configure_file(image.js image.js)
|
|||||||
configure_file(button.js button.js)
|
configure_file(button.js button.js)
|
||||||
configure_file(enumeration.js enumeration.js)
|
configure_file(enumeration.js enumeration.js)
|
||||||
configure_file(player.js player.js)
|
configure_file(player.js player.js)
|
||||||
|
configure_file(songProgress.js songProgress.js)
|
||||||
|
|
||||||
add_subdirectory(helpers)
|
add_subdirectory(helpers)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
deps.push("views/label");
|
deps.push("views/label");
|
||||||
deps.push("views/view");
|
deps.push("views/view");
|
||||||
deps.push("views/image");
|
deps.push("views/image");
|
||||||
|
deps.push("views/songProgress");
|
||||||
|
|
||||||
deps.push("lib/wController/localModel");
|
deps.push("lib/wController/localModel");
|
||||||
|
|
||||||
@ -19,6 +20,7 @@
|
|||||||
var Label = require("views/label");
|
var Label = require("views/label");
|
||||||
var View = require("views/view");
|
var View = require("views/view");
|
||||||
var Image = require("views/image");
|
var Image = require("views/image");
|
||||||
|
var SongProgress = require("views/songProgress");
|
||||||
|
|
||||||
var Model = require("lib/wController/localModel");
|
var Model = require("lib/wController/localModel");
|
||||||
|
|
||||||
@ -34,6 +36,7 @@
|
|||||||
this._next = null;
|
this._next = null;
|
||||||
this._picture = null;
|
this._picture = null;
|
||||||
this._cpbCtrl = null;
|
this._cpbCtrl = null;
|
||||||
|
|
||||||
this._infoModels = {
|
this._infoModels = {
|
||||||
artist: new Model(null, "artist: unknown"),
|
artist: new Model(null, "artist: unknown"),
|
||||||
album: new Model(null, "album: unknown"),
|
album: new Model(null, "album: unknown"),
|
||||||
@ -46,12 +49,14 @@
|
|||||||
var artist = new Label(this._infoModels.artist);
|
var artist = new Label(this._infoModels.artist);
|
||||||
var album = new Label(this._infoModels.album);
|
var album = new Label(this._infoModels.album);
|
||||||
var song = new Label(this._infoModels.song);
|
var song = new Label(this._infoModels.song);
|
||||||
var spacer = new View(helper);
|
var spacer = new View(helper, {maxWidth: 50});
|
||||||
|
var progress = new SongProgress(ctrl.progress);
|
||||||
|
|
||||||
this.append(artist, 0, 4, 1, 1, GridLayout.Aligment.LeftCenter);
|
this.append(artist, 0, 4, 1, 1, GridLayout.Aligment.LeftCenter);
|
||||||
this.append(song, 1, 4, 1, 1, GridLayout.Aligment.LeftCenter);
|
this.append(song, 1, 4, 1, 1, GridLayout.Aligment.LeftCenter);
|
||||||
this.append(album, 2, 4, 1, 1, GridLayout.Aligment.LeftCenter);
|
this.append(album, 2, 4, 1, 1, GridLayout.Aligment.LeftCenter);
|
||||||
this.append(spacer, 0, 5, 3, 1, GridLayout.Aligment.LeftCenter);
|
this.append(spacer, 0, 6, 3, 1, GridLayout.Aligment.LeftCenter);
|
||||||
|
this.append(progress, 1, 5, 1, 1, GridLayout.Aligment.CenterCenter);
|
||||||
|
|
||||||
this._uncyclic.push(this._infoModels.artist.destructor.bind(this._infoModels.artist));
|
this._uncyclic.push(this._infoModels.artist.destructor.bind(this._infoModels.artist));
|
||||||
this._uncyclic.push(this._infoModels.song.destructor.bind(this._infoModels.song));
|
this._uncyclic.push(this._infoModels.song.destructor.bind(this._infoModels.song));
|
||||||
|
76
lorgar/views/songProgress.js
Normal file
76
lorgar/views/songProgress.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
"use strict";
|
||||||
|
(function() {
|
||||||
|
var moduleName = "views/songProgress";
|
||||||
|
|
||||||
|
var deps = [];
|
||||||
|
deps.push("views/view");
|
||||||
|
|
||||||
|
define(moduleName, deps, function() {
|
||||||
|
var View = require("views/view");
|
||||||
|
|
||||||
|
var SongProgress = View.inherit({
|
||||||
|
className: "SongProgress",
|
||||||
|
constructor: function(controller, options) {
|
||||||
|
var base = {
|
||||||
|
minHeight: 10,
|
||||||
|
maxHeight: 10
|
||||||
|
};
|
||||||
|
W.extend(base, options)
|
||||||
|
var el = document.createElement("div");
|
||||||
|
this._createBars();
|
||||||
|
View.fn.constructor.call(this, controller, base, el);
|
||||||
|
|
||||||
|
this._f.on("load", this._onLoad, this);
|
||||||
|
this._f.on("playback", this._onPlayback, this);
|
||||||
|
|
||||||
|
this._e.style.backgroundColor = "#eeeeee";
|
||||||
|
this._e.appendChild(this._loadProgress);
|
||||||
|
this._e.appendChild(this._playbackProgress);
|
||||||
|
},
|
||||||
|
destructor: function() {
|
||||||
|
this._f.off("load", this._onLoad, this);
|
||||||
|
this._f.off("playback", this._onPlayback, this);
|
||||||
|
|
||||||
|
View.fn.destructor.call(this);
|
||||||
|
},
|
||||||
|
_createBars: function() {
|
||||||
|
|
||||||
|
this._loadProgress = document.createElement("div");
|
||||||
|
this._playbackProgress = document.createElement("div");
|
||||||
|
|
||||||
|
this._loadProgress.style.backgroundColor = View.theme.secondaryColor || "#ffff00";
|
||||||
|
this._loadProgress.style.height = "100%";
|
||||||
|
this._loadProgress.style.width = "0";
|
||||||
|
this._loadProgress.style.position = "absolute";
|
||||||
|
this._loadProgress.style.top = "0";
|
||||||
|
this._loadProgress.style.left = "0";
|
||||||
|
|
||||||
|
this._playbackProgress.style.backgroundColor = View.theme.primaryColor || "#ff0000";
|
||||||
|
this._playbackProgress.style.height = "100%";
|
||||||
|
this._playbackProgress.style.width = "0";
|
||||||
|
this._playbackProgress.style.position = "absolute";
|
||||||
|
this._playbackProgress.style.top = "0";
|
||||||
|
this._playbackProgress.style.left = "0";
|
||||||
|
},
|
||||||
|
_onData: function() {
|
||||||
|
this._onLoad(this._f.load);
|
||||||
|
this._onPlayback(this._f.playback);
|
||||||
|
},
|
||||||
|
_onLoad: function(load) {
|
||||||
|
this._loadProgress.style.width = load * 100 + "%";
|
||||||
|
},
|
||||||
|
_onPlayback: function(pb) {
|
||||||
|
this._playbackProgress.style.width = pb * 100 + "%";
|
||||||
|
},
|
||||||
|
_resetTheme: function() {
|
||||||
|
View.fn._resetTheme.call(this);
|
||||||
|
|
||||||
|
this._loadProgress.style.backgroundColor = View.theme.secondaryColor || "#ffff00"
|
||||||
|
this._playbackProgress.style.backgroundColor = View.theme.primaryColor || "#ff0000";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return SongProgress;
|
||||||
|
})
|
||||||
|
})();
|
||||||
|
|
@ -3,6 +3,8 @@ var morgan = require("morgan");
|
|||||||
var favicon = require("serve-favicon");
|
var favicon = require("serve-favicon");
|
||||||
var Magnus = require("./core/magnus");
|
var Magnus = require("./core/magnus");
|
||||||
|
|
||||||
|
express.static.mime.types.wasm = 'application/wasm';
|
||||||
|
|
||||||
require("./lib/utils/globalMethods");
|
require("./lib/utils/globalMethods");
|
||||||
|
|
||||||
var config = require("./config");
|
var config = require("./config");
|
||||||
|
Loading…
Reference in New Issue
Block a user