WIP Merging basic player to master #6
@ -4,7 +4,7 @@ M::Player::Player(const W::Address& address, QObject* parent):
|
|||||||
M::Model(address, parent),
|
M::Model(address, parent),
|
||||||
controls(),
|
controls(),
|
||||||
views(),
|
views(),
|
||||||
playPauseBtn(new M::Button(address + W::Address{u"play"})),
|
playPauseBtn(new M::Button(address + W::Address{u"Play"})),
|
||||||
_queueView(new M::List(address + W::Address{u"queueView"})),
|
_queueView(new M::List(address + W::Address{u"queueView"})),
|
||||||
_queue(),
|
_queue(),
|
||||||
current(0),
|
current(0),
|
||||||
@ -93,7 +93,7 @@ void M::Player::h_get(const W::Event& ev)
|
|||||||
void M::Player::onPlayPauseBtn()
|
void M::Player::onPlayPauseBtn()
|
||||||
{
|
{
|
||||||
if (playing) {
|
if (playing) {
|
||||||
playPauseBtn->setLabel(W::String(u"Pause"));
|
playPauseBtn->setLabel(W::String(u"Play"));
|
||||||
playing = false;
|
playing = false;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@ -102,7 +102,7 @@ void M::Player::onPlayPauseBtn()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
playPauseBtn->setLabel(W::String(u"Play"));
|
playPauseBtn->setLabel(W::String(u"Pause"));
|
||||||
playing = true;
|
playing = true;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@ -135,6 +135,7 @@ void M::Player::h_queue(const W::Event& ev)
|
|||||||
res->insert(u"remove", new W::Vector());
|
res->insert(u"remove", new W::Vector());
|
||||||
|
|
||||||
broadcast(res, W::Address{u"viewsChange"});
|
broadcast(res, W::Address{u"viewsChange"});
|
||||||
|
playPauseBtn->setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
_queue.push_back(song);
|
_queue.push_back(song);
|
||||||
_queueView->push(song->getAddress());
|
_queueView->push(song->getAddress());
|
||||||
|
@ -16,6 +16,7 @@ set(HEADERS
|
|||||||
catalogue.h
|
catalogue.h
|
||||||
button.h
|
button.h
|
||||||
file/file.h
|
file/file.h
|
||||||
|
file/audio.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
@ -28,6 +29,7 @@ set(SOURCES
|
|||||||
catalogue.cpp
|
catalogue.cpp
|
||||||
button.cpp
|
button.cpp
|
||||||
file/file.cpp
|
file/file.cpp
|
||||||
|
file/audio.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(wModel STATIC ${HEADERS} ${SOURCES})
|
add_library(wModel STATIC ${HEADERS} ${SOURCES})
|
||||||
@ -36,3 +38,4 @@ target_link_libraries(wModel Qt5::Core)
|
|||||||
target_link_libraries(wModel wServerUtils)
|
target_link_libraries(wModel wServerUtils)
|
||||||
target_link_libraries(wModel wType)
|
target_link_libraries(wModel wType)
|
||||||
target_link_libraries(wModel wController)
|
target_link_libraries(wModel wController)
|
||||||
|
target_link_libraries(wModel mad)
|
||||||
|
@ -52,7 +52,7 @@ void M::Button::setEnabled(bool p_enabled)
|
|||||||
enabled = p_enabled;
|
enabled = p_enabled;
|
||||||
if (registered) {
|
if (registered) {
|
||||||
W::Vocabulary* vc = new W::Vocabulary();
|
W::Vocabulary* vc = new W::Vocabulary();
|
||||||
vc->insert(u"enable", new W::Boolean(enabled));
|
vc->insert(u"enabled", new W::Boolean(enabled));
|
||||||
broadcast(vc, W::Address{u"setEnabled"});
|
broadcast(vc, W::Address{u"setEnabled"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
80
lib/wModel/file/audio.cpp
Normal file
80
lib/wModel/file/audio.cpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#include "audio.h"
|
||||||
|
|
||||||
|
#include <mad.h>
|
||||||
|
|
||||||
|
M::Audio::Audio(W::Blob* p_file, const W::Address& addr, QObject* 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::Model::ModelType M::Audio::getType() const
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M::Audio::initAdditional(const W::String& p_mime)
|
||||||
|
{
|
||||||
|
File::initAdditional(p_mime); //TODO handle other than mp3 formats
|
||||||
|
|
||||||
|
mad_stream stream;
|
||||||
|
mad_header header;
|
||||||
|
mad_stream_init(&stream);
|
||||||
|
mad_header_init(&header);
|
||||||
|
|
||||||
|
mad_stream_buffer(&stream, file->uchar(), file->size());
|
||||||
|
|
||||||
|
uint64_t length = 0;
|
||||||
|
uint64_t tBits = 0;
|
||||||
|
while(stream.error != MAD_ERROR_BUFLEN) { //TODO handle other errors;
|
||||||
|
|
||||||
|
int success = mad_header_decode(&header, &stream);
|
||||||
|
if (success == 0) {
|
||||||
|
frames.emplace_back(stream.this_frame - stream.buffer, stream.next_frame - stream.this_frame);
|
||||||
|
|
||||||
|
length += header.duration.seconds * MAD_TIMER_RESOLUTION + header.duration.fraction;
|
||||||
|
tBits += header.bitrate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
additional.insert(u"duration", new W::Uint64(length / MAD_TIMER_RESOLUTION));
|
||||||
|
additional.insert(u"bitrate", new W::Uint64(tBits / frames.size()));
|
||||||
|
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));
|
||||||
|
uint64_t start = 0;
|
||||||
|
uint64_t size = 0;
|
||||||
|
bool first = true;
|
||||||
|
for (int i = 0; i < amount; ++i) {
|
||||||
|
const std::pair<uint64_t, uint64_t>& pair = frames[index + i];
|
||||||
|
if (first) {
|
||||||
|
start = pair.first;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
size += pair.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
evc->insert(u"data", file->slice(start, size));
|
||||||
|
evc->insert(u"amount", new W::Uint64(amount));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
response(evc, W::Address{u"responseFrames"}, ev);
|
||||||
|
}
|
36
lib/wModel/file/audio.h
Normal file
36
lib/wModel/file/audio.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef M_AUDIO_H
|
||||||
|
#define M_AUDIO_H
|
||||||
|
|
||||||
|
#include <wModel/file/file.h>
|
||||||
|
|
||||||
|
#include <wType/blob.h>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
namespace M {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo write docs
|
||||||
|
*/
|
||||||
|
class Audio : public File {
|
||||||
|
friend class File;
|
||||||
|
protected:
|
||||||
|
Audio(W::Blob* p_file, const W::Address& addr, QObject* parent = 0);
|
||||||
|
|
||||||
|
public:
|
||||||
|
~Audio();
|
||||||
|
|
||||||
|
M::Model::ModelType getType() const override;
|
||||||
|
static const M::Model::ModelType type = audio;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initAdditional(const W::String& p_mime) override;
|
||||||
|
|
||||||
|
handler(requestFrames);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::deque<std::pair<uint64_t, uint64_t>> frames;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // M_AUDIO_H
|
@ -1,7 +1,13 @@
|
|||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "audio.h"
|
||||||
|
|
||||||
QMimeDatabase M::File::mimeDB;
|
QMimeDatabase M::File::mimeDB;
|
||||||
|
const std::map<QString, M::Model::ModelType> M::File::mimeMap = {
|
||||||
|
{"image/jpeg", M::Model::file},
|
||||||
|
{"audio/mpeg", M::Model::audio}
|
||||||
|
};
|
||||||
|
|
||||||
M::File::File(W::Blob* p_file, const W::Address& addr, QObject* parent):
|
M::File::File(W::Blob* p_file, const W::Address& addr, QObject* parent):
|
||||||
M::Model(addr, parent),
|
M::Model(addr, parent),
|
||||||
@ -79,8 +85,24 @@ M::File * M::File::create(W::Blob* blob, const W::Address& addr, QObject* parent
|
|||||||
M::File* out;
|
M::File* out;
|
||||||
|
|
||||||
QMimeType mt = mimeDB.mimeTypeForData(blob->byteArray());
|
QMimeType mt = mimeDB.mimeTypeForData(blob->byteArray());
|
||||||
out = new File(blob, addr, parent);
|
|
||||||
|
|
||||||
out->initAdditional(W::String(mt.name().toStdString()));
|
const QString& mime = mt.name();
|
||||||
|
std::map<QString, M::Model::ModelType>::const_iterator itr = mimeMap.find(mime);
|
||||||
|
|
||||||
|
M::Model::ModelType modelType = M::Model::file;
|
||||||
|
if (itr != mimeMap.end()) {
|
||||||
|
modelType = itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (modelType) {
|
||||||
|
case Model::audio:
|
||||||
|
out = new Audio(blob, addr, parent);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out = new File(blob, addr, parent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->initAdditional(W::String(mime.toStdString()));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ namespace M {
|
|||||||
W::Blob* file;
|
W::Blob* file;
|
||||||
|
|
||||||
static QMimeDatabase mimeDB;
|
static QMimeDatabase mimeDB;
|
||||||
|
static const std::map<QString, M::Model::ModelType> mimeMap;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ namespace M {
|
|||||||
attributes = 50,
|
attributes = 50,
|
||||||
file,
|
file,
|
||||||
resourceCache,
|
resourceCache,
|
||||||
|
audio,
|
||||||
|
|
||||||
player = 107
|
player = 107
|
||||||
};
|
};
|
||||||
|
@ -144,3 +144,17 @@ const QByteArray & W::Blob::byteArray() const
|
|||||||
return qDataView;
|
return qDataView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unsigned char * W::Blob::uchar() const
|
||||||
|
{
|
||||||
|
return (unsigned char*) data;
|
||||||
|
}
|
||||||
|
|
||||||
|
W::Blob* W::Blob::slice(uint64_t start, uint64_t length) const
|
||||||
|
{
|
||||||
|
char* n_data = new char[length];
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
n_data[i] = data[start + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new W::Blob(length, n_data);
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ namespace W
|
|||||||
size_type size() const override;
|
size_type size() const override;
|
||||||
|
|
||||||
objectType getType() const override;
|
objectType getType() const override;
|
||||||
|
Blob* slice(uint64_t start, uint64_t length = 0) const;
|
||||||
|
|
||||||
bool operator==(const W::Object & other) const override;
|
bool operator==(const W::Object & other) const override;
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ namespace W
|
|||||||
static const objectType type = blob;
|
static const objectType type = blob;
|
||||||
|
|
||||||
const QByteArray& byteArray() const;
|
const QByteArray& byteArray() const;
|
||||||
|
const unsigned char* uchar() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool hasData;
|
bool hasData;
|
||||||
|
@ -4,3 +4,4 @@ configure_file(class.js class.js)
|
|||||||
configure_file(subscribable.js subscribable.js)
|
configure_file(subscribable.js subscribable.js)
|
||||||
configure_file(globalMethods.js globalMethods.js)
|
configure_file(globalMethods.js globalMethods.js)
|
||||||
configure_file(enum.js enum.js)
|
configure_file(enum.js enum.js)
|
||||||
|
configure_file(stateMachine.js stateMachine)
|
||||||
|
33
libjs/utils/stateMachine.js
Normal file
33
libjs/utils/stateMachine.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Subscribable = require("./subscribable");
|
||||||
|
|
||||||
|
var StateMachine = Subscribable.inherit({
|
||||||
|
className: "StateMachine",
|
||||||
|
constructor: function (initialState, graph) {
|
||||||
|
Subscribable.fn.constructor.call(this);
|
||||||
|
|
||||||
|
this._state = initialState;
|
||||||
|
this._graph = graph;
|
||||||
|
},
|
||||||
|
manipulation: function (name) {
|
||||||
|
var newState = this._graph[this._state][name];
|
||||||
|
if (newState) {
|
||||||
|
var oldState = this._state;
|
||||||
|
this._state = newState;
|
||||||
|
|
||||||
|
this.trigger("stateChanged", {
|
||||||
|
newState: newState,
|
||||||
|
manipulation: name,
|
||||||
|
oldState: oldState
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.trigger("stateMissed");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
state: function () {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = StateMachine;
|
@ -17,5 +17,6 @@ configure_file(localModel.js localModel.js)
|
|||||||
configure_file(catalogue.js catalogue.js)
|
configure_file(catalogue.js catalogue.js)
|
||||||
configure_file(imagePane.js imagePane.js)
|
configure_file(imagePane.js imagePane.js)
|
||||||
configure_file(file/file.js file/file.js)
|
configure_file(file/file.js file/file.js)
|
||||||
|
configure_file(file/audio.js file/audio.js)
|
||||||
configure_file(player.js player.js)
|
configure_file(player.js player.js)
|
||||||
configure_file(imageById.js imageById.js)
|
configure_file(imageById.js imageById.js)
|
||||||
|
69
libjs/wController/file/audio.js
Normal file
69
libjs/wController/file/audio.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var File = require("./file");
|
||||||
|
var Vocabulary = require("../../wType/vocabulary");
|
||||||
|
var Uint64 = require("../../wType/uint64");
|
||||||
|
|
||||||
|
var Audio = File.inherit({
|
||||||
|
className: "Audio",
|
||||||
|
constructor: function Audio(addr) {
|
||||||
|
File.fn.constructor.call(this, addr);
|
||||||
|
|
||||||
|
this._loadedFrames = 0;
|
||||||
|
this._totalFrames = 0;
|
||||||
|
this._waitingForFrames = false;
|
||||||
|
this._portions = [];
|
||||||
|
|
||||||
|
this.addHandler("responseFrames");
|
||||||
|
},
|
||||||
|
hasMore: function() {
|
||||||
|
return this._totalFrames > this._loadedFrames;
|
||||||
|
},
|
||||||
|
_getAdditional: function(add) {
|
||||||
|
var ac = File.fn._getAdditional.call(this, add);
|
||||||
|
|
||||||
|
if (ac) {
|
||||||
|
this._loadedFrames = 0;
|
||||||
|
this._totalFrames = this._additional.at("framesAmount").valueOf();
|
||||||
|
this._waitingForFrames = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initialized = true;
|
||||||
|
return ac;
|
||||||
|
},
|
||||||
|
_h_responseFrames: function(ev) {
|
||||||
|
if (this._waitingForFrames === true) {
|
||||||
|
var data = ev.getData();
|
||||||
|
|
||||||
|
var success = data.at("result").valueOf();
|
||||||
|
if (success === 0) {
|
||||||
|
var amount = data.at("amount").valueOf();
|
||||||
|
var blob = data.at("data").clone();
|
||||||
|
this._loadedFrames += amount;
|
||||||
|
this._waitingForFrames = false;
|
||||||
|
this._portions.push(blob);
|
||||||
|
this.trigger("newFrames", blob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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;
|
@ -7,7 +7,10 @@ var Controller = require("./controller");
|
|||||||
var Button = require("./button");
|
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 Enum = require("../utils/enum");
|
var Enum = require("../utils/enum");
|
||||||
|
var StateMachine = require("../utils/stateMachine");
|
||||||
|
|
||||||
var Player = Controller.inherit({
|
var Player = Controller.inherit({
|
||||||
className: "Player",
|
className: "Player",
|
||||||
@ -17,9 +20,24 @@ 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._audio = null;
|
||||||
|
this._sound = new window.Audio();
|
||||||
|
this._ctx = new AudioContext();
|
||||||
|
this._currentTime = 0;
|
||||||
|
this._createStateMachine();
|
||||||
|
this._proxySchedule = this._schedule.bind(this);
|
||||||
|
|
||||||
this.addHandler("get");
|
this.addHandler("get");
|
||||||
this.addHandler("viewsChange");
|
this.addHandler("viewsChange");
|
||||||
|
this.addHandler("play");
|
||||||
|
this.addHandler("pause");
|
||||||
|
},
|
||||||
|
destructor: function() {
|
||||||
|
this._fsm.destructor();
|
||||||
|
this._sound.pause();
|
||||||
|
this._ctx.close();
|
||||||
|
|
||||||
|
Controller.fn.destructor.call(this);
|
||||||
},
|
},
|
||||||
_addControl: function(type, address) {
|
_addControl: function(type, address) {
|
||||||
var t = type.valueOf();
|
var t = type.valueOf();
|
||||||
@ -87,6 +105,10 @@ var Player = Controller.inherit({
|
|||||||
this.trigger("newElement", ctrl, t);
|
this.trigger("newElement", ctrl, t);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
_createStateMachine: function() {
|
||||||
|
this._fsm = new StateMachine("initial", graphs[this.mode]);
|
||||||
|
this._fsm.on("stateChanged", this._onStateChanged, this);
|
||||||
|
},
|
||||||
_h_get: function(ev) {
|
_h_get: function(ev) {
|
||||||
var data = ev.getData();
|
var data = ev.getData();
|
||||||
|
|
||||||
@ -117,6 +139,12 @@ var Player = Controller.inherit({
|
|||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
this.trigger("data");
|
this.trigger("data");
|
||||||
},
|
},
|
||||||
|
_h_pause: function(ev) {
|
||||||
|
this._fsm.manipulation("plause");
|
||||||
|
},
|
||||||
|
_h_play: function(ev) {
|
||||||
|
this._fsm.manipulation("play");
|
||||||
|
},
|
||||||
_h_viewsChange: function(ev) {
|
_h_viewsChange: function(ev) {
|
||||||
var data = ev.getData();
|
var data = ev.getData();
|
||||||
|
|
||||||
@ -135,6 +163,15 @@ var Player = Controller.inherit({
|
|||||||
this._addView(vc.at("type"), vc.at("address"));
|
this._addView(vc.at("type"), vc.at("address"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
_onAudioNewFrames: function(frames) {
|
||||||
|
this._ctx.decodeAudioData(frames.valueOf(), this._proxySchedule);
|
||||||
|
this._fsm.manipulation("newFrames");
|
||||||
|
if (this._audio.hasMore()) {
|
||||||
|
this._audio.requestMore();
|
||||||
|
} else {
|
||||||
|
this._fsm.manipulation("noMoreFrames");
|
||||||
|
}
|
||||||
|
},
|
||||||
_onNewPlayBackElement: function(key, element) {
|
_onNewPlayBackElement: function(key, element) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "image":
|
case "image":
|
||||||
@ -142,6 +179,14 @@ var Player = Controller.inherit({
|
|||||||
this._addView(new Uint64(ItemType.straight.picture), address);
|
this._addView(new Uint64(ItemType.straight.picture), address);
|
||||||
address.destructor();
|
address.destructor();
|
||||||
break;
|
break;
|
||||||
|
case "audio":
|
||||||
|
if (this.mode === PlayerMode.straight.playback) {
|
||||||
|
this._audio = new Audio(new Address(["music", element.toString()]));
|
||||||
|
this.addForeignController("Corax", this._audio);
|
||||||
|
this._audio.on("newFrames", this._onAudioNewFrames, this);
|
||||||
|
this._fsm.manipulation("controller");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_onNewRemoveBackElement: function(key) {
|
_onNewRemoveBackElement: function(key) {
|
||||||
@ -149,6 +194,51 @@ var Player = Controller.inherit({
|
|||||||
case "image":
|
case "image":
|
||||||
this._removeView(new Uint64(ItemType.straight.picture));
|
this._removeView(new Uint64(ItemType.straight.picture));
|
||||||
break;
|
break;
|
||||||
|
case "audio":
|
||||||
|
this.removeForeignController(this._audio);
|
||||||
|
this._audio.destructor();
|
||||||
|
this._audio = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_onStateChanged: function(e) {
|
||||||
|
switch (e.newState) {
|
||||||
|
case "initial":
|
||||||
|
break;
|
||||||
|
case "initialPlaying":
|
||||||
|
break;
|
||||||
|
case "hasController":
|
||||||
|
break;
|
||||||
|
case "hasControllerPlaying":
|
||||||
|
if (this._audio.hasMore()) {
|
||||||
|
this._audio.requestMore();
|
||||||
|
} else {
|
||||||
|
this._fsm.manipulation("noMoreFrames");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "paused":
|
||||||
|
switch (e.oldState) {
|
||||||
|
case "playing":
|
||||||
|
this._sound.pause();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "pausedAllLoaded":
|
||||||
|
switch (e.oldState) {
|
||||||
|
case "playingAllLoaded":
|
||||||
|
this._sound.pause();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "playing":
|
||||||
|
this._sound.play();
|
||||||
|
break;
|
||||||
|
case "playingAllLoaded":
|
||||||
|
switch (e.oldState) {
|
||||||
|
case "pausedAllLoaded":
|
||||||
|
this._sound.play();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_removeControl: function(type) {
|
_removeControl: function(type) {
|
||||||
@ -156,6 +246,14 @@ var Player = Controller.inherit({
|
|||||||
},
|
},
|
||||||
_removeView: function(type) {
|
_removeView: function(type) {
|
||||||
//TODO
|
//TODO
|
||||||
|
},
|
||||||
|
_schedule: function(buffer) {
|
||||||
|
var source = this._ctx.createBufferSource();
|
||||||
|
source.buffer = buffer;
|
||||||
|
source.connect(this._ctx.destination);
|
||||||
|
|
||||||
|
source.start(this._currentTime);
|
||||||
|
this._currentTime += buffer.duration;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -170,4 +268,38 @@ PlayerMode.add("playback");
|
|||||||
|
|
||||||
Player.ItemType = ItemType;
|
Player.ItemType = ItemType;
|
||||||
|
|
||||||
|
var graphs = Object.create(null);
|
||||||
|
graphs[PlayerMode.straight.playback] = {
|
||||||
|
"initial": {
|
||||||
|
controller: "hasController",
|
||||||
|
play: "initialPlaying"
|
||||||
|
},
|
||||||
|
"initialPlaying": {
|
||||||
|
pause: "initial",
|
||||||
|
controller: "hasControllerPlaying"
|
||||||
|
},
|
||||||
|
"hasController": {
|
||||||
|
newFrames: "paused",
|
||||||
|
play: "hasControllerPlaying"
|
||||||
|
},
|
||||||
|
"hasControllerPlaying": {
|
||||||
|
newFrames: "playing",
|
||||||
|
pause: "hasController"
|
||||||
|
},
|
||||||
|
"paused": {
|
||||||
|
play: "playing",
|
||||||
|
noMoreFrames: "pausedAllLoaded"
|
||||||
|
},
|
||||||
|
"pausedAllLoaded": {
|
||||||
|
play: "playingAllLoaded"
|
||||||
|
},
|
||||||
|
"playing": {
|
||||||
|
pause: "pause",
|
||||||
|
noMoreFrames: "playingAllLoaded"
|
||||||
|
},
|
||||||
|
"playingAllLoaded": {
|
||||||
|
pause: "pausedAllLoaded"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = Player;
|
module.exports = Player;
|
||||||
|
@ -4,3 +4,4 @@ add_jslib(utils/class.js lib/utils/class ${LORGAR_DIR} browser)
|
|||||||
add_jslib(utils/subscribable.js lib/utils/subscribable ${LORGAR_DIR} browser)
|
add_jslib(utils/subscribable.js lib/utils/subscribable ${LORGAR_DIR} browser)
|
||||||
add_jslib(utils/globalMethods.js lib/utils/globalMethods ${LORGAR_DIR} browser)
|
add_jslib(utils/globalMethods.js lib/utils/globalMethods ${LORGAR_DIR} browser)
|
||||||
add_jslib(utils/enum.js lib/utils/enum ${LORGAR_DIR} browser)
|
add_jslib(utils/enum.js lib/utils/enum ${LORGAR_DIR} browser)
|
||||||
|
add_jslib(utils/stateMachine.js lib/utils/stateMachine ${LORGAR_DIR} browser)
|
||||||
|
@ -16,6 +16,7 @@ add_jslib(wController/attributes.js lib/wController/attributes ${LORGAR_DIR} bro
|
|||||||
add_jslib(wController/localModel.js lib/wController/localModel ${LORGAR_DIR} browser)
|
add_jslib(wController/localModel.js lib/wController/localModel ${LORGAR_DIR} browser)
|
||||||
add_jslib(wController/imagePane.js lib/wController/imagePane ${LORGAR_DIR} browser)
|
add_jslib(wController/imagePane.js lib/wController/imagePane ${LORGAR_DIR} browser)
|
||||||
add_jslib(wController/file/file.js lib/wController/file/file ${LORGAR_DIR} browser)
|
add_jslib(wController/file/file.js lib/wController/file/file ${LORGAR_DIR} browser)
|
||||||
|
add_jslib(wController/file/audio.js lib/wController/file/audio ${LORGAR_DIR} browser)
|
||||||
add_jslib(wController/image.js lib/wController/image ${LORGAR_DIR} browser)
|
add_jslib(wController/image.js lib/wController/image ${LORGAR_DIR} browser)
|
||||||
add_jslib(wController/button.js lib/wController/button ${LORGAR_DIR} browser)
|
add_jslib(wController/button.js lib/wController/button ${LORGAR_DIR} browser)
|
||||||
add_jslib(wController/player.js lib/wController/player ${LORGAR_DIR} browser)
|
add_jslib(wController/player.js lib/wController/player ${LORGAR_DIR} browser)
|
||||||
|
@ -58,10 +58,8 @@
|
|||||||
if (this._enabled !== enabled) {
|
if (this._enabled !== enabled) {
|
||||||
this._enabled = enabled;
|
this._enabled = enabled;
|
||||||
if (this._enabled) {
|
if (this._enabled) {
|
||||||
this.addClass("hoverable");
|
|
||||||
this.removeClass("disabled");
|
this.removeClass("disabled");
|
||||||
} else {
|
} else {
|
||||||
this.removeClass("hoverable");
|
|
||||||
this.addClass("disabled");
|
this.addClass("disabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,11 +78,7 @@
|
|||||||
Subscribable.fn.destructor.call(this);
|
Subscribable.fn.destructor.call(this);
|
||||||
},
|
},
|
||||||
"addClass": function(className) {
|
"addClass": function(className) {
|
||||||
var arr = this._e.className.split(" ");
|
this._e.classList.add(className);
|
||||||
if (arr.indexOf(className) === -1) {
|
|
||||||
arr.push(className);
|
|
||||||
this._e.className = arr.join(" ");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"_applyProperties": function() {
|
"_applyProperties": function() {
|
||||||
for (var i = 0; i < this._f.properties.length; ++i) {
|
for (var i = 0; i < this._f.properties.length; ++i) {
|
||||||
@ -141,17 +137,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"removeClass": function(className) {
|
"removeClass": function(className) {
|
||||||
var arr = this._e.className.split(" ");
|
this._e.classList.remove(className);
|
||||||
var index = arr.indexOf(className)
|
|
||||||
var toJoin = false;
|
|
||||||
while (index !== -1) {
|
|
||||||
arr.splice(index, 1);
|
|
||||||
index = arr.indexOf(className)
|
|
||||||
toJoin = true;
|
|
||||||
}
|
|
||||||
if (toJoin) {
|
|
||||||
this._e.className = arr.join(" ");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"_resetTheme": function() {
|
"_resetTheme": function() {
|
||||||
this._onClearProperties();
|
this._onClearProperties();
|
||||||
|
Loading…
Reference in New Issue
Block a user