From 00f26c431ec2d516052dda225c781f0919eb969f Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 5 Aug 2018 00:52:16 +0300 Subject: [PATCH 01/16] initial player stuff --- corax/CMakeLists.txt | 5 +- corax/corax.cpp | 16 +-- corax/models/CMakeLists.txt | 21 ++++ corax/models/player.cpp | 121 +++++++++++++++++++++++ corax/models/player.h | 60 ++++++++++++ corax/models/proxysong.cpp | 135 ++++++++++++++++++++++++++ corax/models/proxysong.h | 47 +++++++++ lib/wController/controller.cpp | 5 + lib/wController/controller.h | 1 + lib/wDatabase/resourcecache.cpp | 2 +- lib/wModel/CMakeLists.txt | 6 +- lib/wModel/button.cpp | 113 +++++++++++++++++++++ lib/wModel/button.h | 52 ++++++++++ lib/wModel/model.cpp | 112 +++++++++++++++------ lib/wModel/model.h | 24 +++-- lib/wModel/vocabulary.h | 3 +- lib/wServerUtils/connector.cpp | 94 +++++++++++++++++- lib/wServerUtils/connector.h | 16 ++- lib/wSocket/server.cpp | 4 +- lib/wSocket/server.h | 2 +- lib/wType/object.cpp | 2 + libjs/wController/button.js | 69 +++++++++++++ libjs/wController/controller.js | 23 +++-- libjs/wController/link.js | 6 +- libjs/wModel/CMakeLists.txt | 1 + libjs/wModel/button.js | 90 +++++++++++++++++ libjs/wModel/model.js | 9 +- lorgar/css/main.css | 4 + lorgar/lib/wController/CMakeLists.txt | 1 + lorgar/main.js | 4 +- lorgar/views/CMakeLists.txt | 1 + lorgar/views/button.js | 95 ++++++++++++++++++ lorgar/views/layout.js | 4 + lorgar/views/view.js | 26 +++-- magnus/lib/wModel/CMakeLists.txt | 1 + magnus/pages/test.js | 11 +++ perturabo/CMakeLists.txt | 2 +- perturabo/perturabo.cpp | 12 +-- 38 files changed, 1107 insertions(+), 93 deletions(-) create mode 100644 corax/models/CMakeLists.txt create mode 100644 corax/models/player.cpp create mode 100644 corax/models/player.h create mode 100644 corax/models/proxysong.cpp create mode 100644 corax/models/proxysong.h create mode 100644 lib/wModel/button.cpp create mode 100644 lib/wModel/button.h create mode 100644 libjs/wController/button.js create mode 100644 libjs/wModel/button.js create mode 100644 lorgar/views/button.js diff --git a/corax/CMakeLists.txt b/corax/CMakeLists.txt index b0c6a34..a257c53 100644 --- a/corax/CMakeLists.txt +++ b/corax/CMakeLists.txt @@ -23,6 +23,7 @@ set(SOURCES ) add_executable(corax ${HEADERS} ${SOURCES}) +add_subdirectory(models) target_link_libraries(corax Qt5::Core) target_link_libraries(corax Qt5::Network) @@ -31,10 +32,10 @@ target_link_libraries(corax wSocket) target_link_libraries(corax wDispatcher) target_link_libraries(corax utils) target_link_libraries(corax wModel) -target_link_libraries(corax wController) -target_link_libraries(corax wServerUtils) target_link_libraries(corax wDatabase) target_link_libraries(corax tag) target_link_libraries(corax tools) +target_link_libraries(corax coraxModels) +target_link_libraries(corax wServerUtils) install(TARGETS corax RUNTIME DESTINATION bin) diff --git a/corax/corax.cpp b/corax/corax.cpp index 053b391..92c4145 100644 --- a/corax/corax.cpp +++ b/corax/corax.cpp @@ -90,11 +90,11 @@ void Corax::start() server->listen(8080); cout << "Registering models..." << endl; - attributes->registerModel(dispatcher, server); - commands->registerModel(dispatcher, server); + attributes->getRegistered(connector); + commands->getRegistered(connector); for (; beg != end; ++beg) { - beg->second->registerModel(dispatcher, server); + beg->second->getRegistered(connector); } cout << "Opening caches..." << endl; @@ -115,11 +115,11 @@ void Corax::stop() std::map::iterator end = caches.end(); cout << "Stopping corax..." << endl; - commands->unregisterModel(); - attributes->unregisterModel(); + commands->getUnregistered(); + attributes->getUnregistered(); for (; beg != end; ++beg) { - beg->second->unregisterModel(); + beg->second->getUnregistered(); } server->stop(); @@ -169,10 +169,10 @@ void Corax::h_parseDirectory(const W::Event& ev) if (itr != parsers.end()) { cout << "directory " << path.toString() << " is already being parsed" << endl; } else { - const W::Socket& socket = connector->getNodeSocket(W::String(u"Perturabo")); + const W::Socket* socket = connector->getNodeSocket(W::String(u"Perturabo")); ResourceCache* music = caches.at(W::String(u"music")); ResourceCache* images = caches.at(W::String(u"images")); - Parser* parser = new Parser(&socket, dispatcher, music, images); + Parser* parser = new Parser(socket, dispatcher, music, images); parsers.insert(std::make_pair(path, parser)); connect(parser, SIGNAL(serviceMessage(const QString&)), SLOT(onModelServiceMessage(const QString&))); diff --git a/corax/models/CMakeLists.txt b/corax/models/CMakeLists.txt new file mode 100644 index 0000000..fe7c92e --- /dev/null +++ b/corax/models/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.12) +project(coraxModels) + +find_package(Qt5Core REQUIRED) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +set(HEADERS + player.h + proxysong.h +) + +set(SOURCES + player.cpp + proxysong.cpp +) + +add_library(coraxModels STATIC ${HEADERS} ${SOURCES}) + +target_link_libraries(coraxModels wModel) diff --git a/corax/models/player.cpp b/corax/models/player.cpp new file mode 100644 index 0000000..9cc439f --- /dev/null +++ b/corax/models/player.cpp @@ -0,0 +1,121 @@ +#include "player.h" + +M::Player::Player(const W::Address& address, QObject* parent): + M::Model(address, parent), + controls(), + views(), + playPauseBtn(new M::Button(address + W::Address{u"play"})), + _queueView(new M::List(address + W::Address{u"queueView"})), + _queue(), + current(0) +{ + W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Player::_h_get); + W::Handler* hqueue = W::Handler::create(address + W::Address({u"queue"}), this, &M::Player::_h_queue); + addHandler(get); + addHandler(hqueue); + + playPauseBtn->setLabel(W::String(u"play")); + playPauseBtn->setEnabled(false); + connect(playPauseBtn, SIGNAL(activated()), this, SLOT(onPlayPauseBtn())); + + addModel(playPauseBtn); + addModel(_queueView); + + controls.insert(std::make_pair(playPause, playPauseBtn->getAddress())); + views.insert(std::make_pair(queue, _queueView->getAddress())); +} + +M::Player::~Player() +{ + +} + +void M::Player::set(const W::Object& value) +{ + throw 14; //what do you expect here? not implemented, and not sure it ever would be +} + +void M::Player::set(W::Object* value) +{ + set(*value); +} + +M::Model::ModelType M::Player::getType() const +{ + return M::Model::player; +} + +void M::Player::h_subscribe(const W::Event& ev) +{ + M::Model::h_subscribe(ev); + + h_get(ev); +} + + +void M::Player::h_get(const W::Event& ev) +{ + W::Vector* ctrls = new W::Vector(); + ItemMap::const_iterator citr = controls.begin(); + ItemMap::const_iterator cend = controls.end(); + + for (; citr != cend; ++citr) { + W::Vocabulary* cvc = new W::Vocabulary(); + cvc->insert(u"type", new W::Uint64(cend->first)); + cvc->insert(u"address", cend->second); + + ctrls->push(cvc); + } + + W::Vector* vws = new W::Vector(); + ItemMap::const_iterator vitr = views.begin(); + ItemMap::const_iterator vend = views.end(); + + for (; vitr != vend; ++vitr) { + W::Vocabulary* vvc = new W::Vocabulary(); + vvc->insert(u"type", new W::Uint64(vend->first)); + vvc->insert(u"address", vend->second); + + vws->push(vvc); + } + + W::Vocabulary* res = new W::Vocabulary(); + + res->insert(u"controls", ctrls); + res->insert(u"views", vws); + + response(res, W::Address({u"get"}), ev); +} + +void M::Player::onPlayPauseBtn() +{ + +} + +void M::Player::h_queue(const W::Event& ev) +{ + const W::Vocabulary& data = static_cast(ev.getData()); + + const W::Uint64& id = static_cast(data.at(u"id")); + ProxySong* song = new ProxySong(id, address + W::Address{u"currentPlayback"}); + addModel(song); + if (current == 0) { + current = song; + views.insert(std::make_pair(currentPlayback, song->getAddress())); + W::Vocabulary* avc = new W::Vocabulary(); + avc->insert(u"type", new W::Uint64(currentPlayback)); + avc->insert(u"address", song->getAddress()); + + W::Vector* add = new W::Vector(); + add->push(avc); + + W::Vocabulary* res = new W::Vocabulary(); + res->insert(u"add", add); + res->insert(u"remove", new W::Vector()); + + broadcast(res, W::Address{u"viewsChange"}); + } else { + _queue.push_back(song); + _queueView->push(song->getAddress()); + } +} diff --git a/corax/models/player.h b/corax/models/player.h new file mode 100644 index 0000000..d2b17a9 --- /dev/null +++ b/corax/models/player.h @@ -0,0 +1,60 @@ +#ifndef PLAYER_H +#define PLAYER_H + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "proxysong.h" +/** + * @todo write docs + */ +namespace M { + class Player : public M::Model { + Q_OBJECT + public: + Player(const W::Address& address, QObject* parent = 0); + ~Player(); + + void set(const W::Object & value) override; + void set(W::Object * value) override; + M::Model::ModelType getType() const override; + + enum ItemType { + playPause, + currentPlayback, + queue + }; + + protected: + void h_subscribe(const W::Event & ev) override; + + handler(get); + handler(queue); + + private: + typedef std::map ItemMap; + typedef std::deque Queue; + + ItemMap controls; + ItemMap views; + M::Button* playPauseBtn; + M::List* _queueView; + Queue _queue; + ProxySong* current; + + private slots: + void onPlayPauseBtn(); + + }; +} + +#endif // PLAYER_H diff --git a/corax/models/proxysong.cpp b/corax/models/proxysong.cpp new file mode 100644 index 0000000..8e742b8 --- /dev/null +++ b/corax/models/proxysong.cpp @@ -0,0 +1,135 @@ +#include "proxysong.h" + +ProxySong::ProxySong(const W::Uint64& p_id, const W::Address& p_address, QObject* parent): + M::Vocabulary(p_address, parent), + songCtrl(new C::Vocabulary(W::Address{u"songs", W::String(p_id.toString())})), + albumCtrl(0), + artistCtrl(0), + fileId(0), + _ready(false) +{ + addController(songCtrl, W::String(u"Perturabo")); + connect(songCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), SLOT(onSongNewElement(const W::String&, const W::Object&))); + connect(songCtrl, SIGNAL(removeElement(const W::String&)), SLOT(onSongRemoveElement(const W::String&))); + + insert(W::String(u"id"), p_id); + insert(W::String(u"artist"), new W::String(u"undefined")); + insert(W::String(u"album"), new W::String(u"undefined")); + insert(W::String(u"name"), new W::String(u"undefined")); + insert(W::String(u"image"), new W::Uint64(0)); +} + +bool ProxySong::isReady() const +{ + return _ready; +} + +ProxySong::~ProxySong() +{ +} + +void ProxySong::onSongNewElement(const W::String& key, const W::Object& element) +{ + if (key == u"name") { + insert(key, element); + } else if (key == u"audio") { + if (_ready) { + _ready = false; + emit notReady(); + } + + fileId = static_cast(element); + _ready = true; + emit ready(); + } else if (key == u"artist") { + if (artistCtrl != 0) { + removeController(artistCtrl); + disconnect(artistCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), this, SLOT(onArtistNewElement(const W::String&, const W::Object&))); + disconnect(artistCtrl, SIGNAL(removeElement(const W::String&)), this, SLOT(onAtristRemoveElement(const W::String&))); + artistCtrl->deleteLater(); + } + const W::Uint64& aid = static_cast(element); + artistCtrl = new C::Vocabulary(W::Address{u"artists", W::String(aid.toString())}); + addController(artistCtrl, W::String(u"Perturabo")); + connect(artistCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), SLOT(onArtistNewElement(const W::String&, const W::Object&))); + connect(artistCtrl, SIGNAL(removeElement(const W::String&)), SLOT(onAtristRemoveElement(const W::String&))); + } else if (key == u"album") { + if (albumCtrl != 0) { + removeController(albumCtrl); + disconnect(albumCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), this, SLOT(onAlbumNewElement(const W::String&, const W::Object&))); + disconnect(albumCtrl, SIGNAL(removeElement(const W::String&)), this, SLOT(onAlbumRemoveElement(const W::String&))); + albumCtrl->deleteLater(); + } + const W::Uint64& aid = static_cast(element); + albumCtrl = new C::Vocabulary(W::Address{u"albums", W::String(aid.toString())}); + addController(albumCtrl, W::String(u"Perturabo")); + connect(albumCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), SLOT(onAlbumNewElement(const W::String&, const W::Object&))); + connect(albumCtrl, SIGNAL(removeElement(const W::String&)), SLOT(onAlbumRemoveElement(const W::String&))); + } +} + +void ProxySong::onSongRemoveElement(const W::String& key) +{ + if (key == u"name") { + insert(key, new W::String(u"undefined")); + } else if (key == u"audio") { + if (_ready) { + _ready = false; + fileId = W::Uint64(0); + emit notReady(); + } + } else if (key == u"artist") { + if (artistCtrl != 0) { + removeController(artistCtrl); + disconnect(artistCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), this, SLOT(onArtistNewElement(const W::String&, const W::Object&))); + disconnect(artistCtrl, SIGNAL(removeElement(const W::String&)), this, SLOT(onAtristRemoveElement(const W::String&))); + artistCtrl->deleteLater(); + artistCtrl = 0; + } + } else if (key == u"album") { + if (albumCtrl != 0) { + removeController(albumCtrl); + disconnect(albumCtrl, SIGNAL(newElement(const W::String&, const W::Object&)), this, SLOT(onAlbumNewElement(const W::String&, const W::Object&))); + disconnect(albumCtrl, SIGNAL(removeElement(const W::String&)), this, SLOT(onAlbumRemoveElement(const W::String&))); + albumCtrl->deleteLater(); + albumCtrl = 0; + } + } +} + +void ProxySong::onAlbumNewElement(const W::String& key, const W::Object& element) +{ + if (key == u"name") { + insert(W::String(u"album"), element); + } else if (key == u"image") { + insert(key, element); + } +} + +void ProxySong::onAlbumRemoveElement(const W::String& key) +{ + if (key == u"name") { + insert(W::String(u"album"), new W::String(u"undefined")); + } else if (key == u"image") { + insert(key, new W::Uint64(0)); + } +} + +void ProxySong::onArtistNewElement(const W::String& key, const W::Object& element) +{ + if (key == u"name") { + insert(W::String(u"artist"), element); + } +} + +void ProxySong::onArtistRemoveElement(const W::String& key) +{ + if (key == u"name") { + insert(W::String(u"artist"), new W::String(u"undefined")); + } +} + +const W::Uint64 & ProxySong::getFileId() const +{ + return fileId; +} diff --git a/corax/models/proxysong.h b/corax/models/proxysong.h new file mode 100644 index 0000000..48aba44 --- /dev/null +++ b/corax/models/proxysong.h @@ -0,0 +1,47 @@ +#ifndef PROXYSONG_H +#define PROXYSONG_H + +/** + * @todo write docs + */ +#include +#include + +#include + +#include + +class ProxySong : public M::Vocabulary { + Q_OBJECT +public: + ProxySong(const W::Uint64& p_id, const W::Address& p_address, QObject* parent = 0); + ~ProxySong(); + + const W::Uint64& getFileId() const; + bool isReady() const; + +signals: + void ready(); + void notReady(); + +private: + C::Vocabulary* songCtrl; + C::Vocabulary* albumCtrl; + C::Vocabulary* artistCtrl; + + W::Uint64 fileId; + bool _ready; + +private slots: + void onSongNewElement(const W::String& key, const W::Object& element); + void onSongRemoveElement(const W::String& key); + + void onAlbumNewElement(const W::String& key, const W::Object& element); + void onAlbumRemoveElement(const W::String& key); + + void onArtistNewElement(const W::String& key, const W::Object& element); + void onArtistRemoveElement(const W::String& key); + +}; + +#endif // PROXYSONG_H diff --git a/lib/wController/controller.cpp b/lib/wController/controller.cpp index 5fe4572..6ac7c61 100644 --- a/lib/wController/controller.cpp +++ b/lib/wController/controller.cpp @@ -276,3 +276,8 @@ bool C::Controller::isSubscribed() { return subscribed; } + +const W::Address & C::Controller::getAddress() const +{ + return address; +} diff --git a/lib/wController/controller.h b/lib/wController/controller.h index 1749093..7372a2d 100644 --- a/lib/wController/controller.h +++ b/lib/wController/controller.h @@ -40,6 +40,7 @@ namespace C { void subscribe(); void unsubscribe(); bool isSubscribed(); + const W::Address& getAddress() const; void removeHandler(W::Handler* handler); void removeController(C::Controller* ctrl); diff --git a/lib/wDatabase/resourcecache.cpp b/lib/wDatabase/resourcecache.cpp index 64d383b..14014d6 100644 --- a/lib/wDatabase/resourcecache.cpp +++ b/lib/wDatabase/resourcecache.cpp @@ -215,7 +215,7 @@ void ResourceCache::h_subscribeMember(const W::Event& ev) M::File* modelRecord = M::File::create(readFile(*record), address + lastHops >> 1); delete record; addModel(modelRecord); - passToHandler(ev); + passToLocalHandler(ev); } catch (int err) { if (err == 3) { emit serviceMessage(QString("An attempt to create and subscribe record model in resourcecache, but it is not found. Event: ") + ev.toString().c_str()); diff --git a/lib/wModel/CMakeLists.txt b/lib/wModel/CMakeLists.txt index cd37fb7..fb70a7b 100644 --- a/lib/wModel/CMakeLists.txt +++ b/lib/wModel/CMakeLists.txt @@ -14,6 +14,7 @@ set(HEADERS attributes.h icatalogue.h catalogue.h + button.h file/file.h ) @@ -25,12 +26,13 @@ set(SOURCES attributes.cpp icatalogue.cpp catalogue.cpp + button.cpp file/file.cpp ) add_library(wModel STATIC ${HEADERS} ${SOURCES}) target_link_libraries(wModel Qt5::Core) -target_link_libraries(wModel wSocket) -target_link_libraries(wModel wDispatcher) +target_link_libraries(wModel wServerUtils) target_link_libraries(wModel wType) +target_link_libraries(wModel wController) diff --git a/lib/wModel/button.cpp b/lib/wModel/button.cpp new file mode 100644 index 0000000..16d103e --- /dev/null +++ b/lib/wModel/button.cpp @@ -0,0 +1,113 @@ +#include "button.h" + +M::Button::Button(const W::Address& address, QObject* parent): + M::Model(address, parent), + enabled(true), + hasImage(false), + hasLabel(false), + imageName(0), + label(0) +{ + W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Button::_h_get); + W::Handler* activate = W::Handler::create(address + W::Address({u"activate"}), this, &M::Button::_h_activate); + + addHandler(get); + addHandler(activate); +} + +M::Button::~Button() +{ + if (hasImage) { + delete imageName; + } +} + +void M::Button::setImage(const W::String& p_image) +{ + + if (hasImage) { + if (*imageName != p_image) { + imageName = static_cast(p_image.copy()); + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"image", p_image); + broadcast(vc, W::Address{u"changeImage"}); + } + } else { + imageName = static_cast(p_image.copy()); + hasImage = true; + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"image", p_image); + broadcast(vc, W::Address{u"setImage"}); + } + hasImage = true; +} + +void M::Button::setEnabled(bool p_enabled) +{ + if (enabled != p_enabled) { + enabled = p_enabled; + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"enable", new W::Boolean(enabled)); + broadcast(vc, W::Address{u"setEnabled"}); + } +} + +void M::Button::setLabel(const W::String& p_label) +{ + if (hasLabel) { + label->set(p_label); + } else { + label = new M::String(p_label, address + W::Address{u"label"}); + addModel(label); + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"hasLabel", new W::Boolean(true)); + vc->insert(u"label", label->getAddress()); + broadcast(vc, W::Address{u"setLabel"}); + hasLabel = true; + } +} + +void M::Button::h_subscribe(const W::Event& ev) +{ + M::Model::h_subscribe(ev); + + h_get(ev); +} + +void M::Button::h_get(const W::Event& ev) +{ + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"hasImage", new W::Boolean(hasImage)); + if (hasImage) { + vc->insert(u"image", imageName->copy()); + } + vc->insert(u"hasLabel", new W::Boolean(hasLabel)); + if (hasLabel) { + vc->insert(u"label", label->getAddress()); + } + vc->insert(u"enabled", new W::Boolean(enabled)); + + response(vc, W::Address({u"get"}), ev); +} + +void M::Button::h_activate(const W::Event& ev) +{ + if (enabled) { + emit activated(); + } +} + +M::Model::ModelType M::Button::getType() const +{ + return M::Model::button; +} + +void M::Button::set(const W::Object& value) +{ + throw 14; //what do you expect here? not implemented, and not sure it ever would be +} + +void M::Button::set(W::Object* value) +{ + set(*value); +} diff --git a/lib/wModel/button.h b/lib/wModel/button.h new file mode 100644 index 0000000..d73046d --- /dev/null +++ b/lib/wModel/button.h @@ -0,0 +1,52 @@ +#ifndef BUTTON_H +#define BUTTON_H + +#include +#include + +#include + +#include +#include +#include +#include + +/** + * @todo write docs + */ +namespace M { + class Button : public Model { + Q_OBJECT + public: + Button(const W::Address& address, QObject* parent = 0); + ~Button(); + + void setImage(const W::String& p_image); + void setLabel(const W::String& p_label); + void setEnabled(bool p_enabled); + + M::Model::ModelType getType() const override; + void set(const W::Object & value) override; + void set(W::Object * value) override; + + signals: + void activated() const; + + protected: + void h_subscribe(const W::Event & ev) override; + + handler(get); + handler(activate); + + protected: + bool enabled; + bool hasImage; + bool hasLabel; + + W::String* imageName; + M::String* label; + }; +} + + +#endif // BUTTON_H diff --git a/lib/wModel/model.cpp b/lib/wModel/model.cpp index d1168cd..dc1522e 100644 --- a/lib/wModel/model.cpp +++ b/lib/wModel/model.cpp @@ -5,12 +5,12 @@ M::Model::Model(const W::Address p_address, QObject* parent): address(p_address), registered(false), subscribers(new Map()), - dispatcher(0), - server(0), + connector(0), subscribersCount(0), handlers(new HList()), properties(new W::Vector()), - models(new MList()) + models(new MList()), + controllers(new Controllers()) { W::Handler* subscribe = W::Handler::create(address + W::Address({u"subscribe"}), this, &M::Model::_h_subscribe); W::Handler* unsubscribe = W::Handler::create(address + W::Address({u"unsubscribe"}), this, &M::Model::_h_unsubscribe); @@ -21,7 +21,7 @@ M::Model::Model(const W::Address p_address, QObject* parent): M::Model::~Model() { if (registered) { - unregisterModel(); + getUnregistered(); } MList::iterator itr = models->begin(); @@ -37,11 +37,19 @@ M::Model::~Model() for (; hItr != hEnd; ++hItr) { delete *hItr; } + + Controllers::iterator cItr = controllers->begin(); + Controllers::iterator cEnd = controllers->end(); + + for (; cItr != cEnd; ++cItr) { + delete cItr->first; + } delete subscribers; delete properties; delete handlers; delete models; + delete controllers; } void M::Model::addModel(M::Model* model) @@ -49,7 +57,7 @@ void M::Model::addModel(M::Model* model) models->push_back(model); connect(model, SIGNAL(serviceMessage(const QString&)), SIGNAL(serviceMessage(const QString&))); if (registered) { - model->registerModel(dispatcher, server); + model->getRegistered(connector); } } @@ -57,7 +65,7 @@ void M::Model::addHandler(W::Handler* handler) { handlers->push_back(handler); if (registered) { - dispatcher->registerHandler(handler); + connector->registerHandler(handler); } } @@ -83,21 +91,20 @@ W::Address M::Model::getAddress() const } -void M::Model::registerModel(W::Dispatcher* dp, W::Server* srv) +void M::Model::getRegistered(U::Connector* cn) { if (registered) { emit serviceMessage(QString("Model ") + address.toString().c_str() + " is already registered"); throw 1; } else { - dispatcher = dp; - server = srv; + connector = cn; MList::iterator itr = models->begin(); MList::iterator end = models->end(); for (; itr != end; ++itr) { M::Model* model = *itr; - model->registerModel(dispatcher, server); + model->getRegistered(connector); } HList::iterator hItr = handlers->begin(); @@ -105,14 +112,21 @@ void M::Model::registerModel(W::Dispatcher* dp, W::Server* srv) for (; hItr != hEnd; ++hItr) { W::Handler* handler = *hItr; - dispatcher->registerHandler(handler); + connector->registerHandler(handler); + } + + Controllers::iterator cItr = controllers->begin(); + Controllers::iterator cEnd = controllers->end(); + + for (; cItr != cEnd; ++cItr) { + connector->registerController(cItr->first, cItr->second); } registered = true; } } -void M::Model::unregisterModel() +void M::Model::getUnregistered() { if (!registered) { emit serviceMessage(QString("Model ") + address.toString().c_str() + " is not registered"); @@ -123,7 +137,7 @@ void M::Model::unregisterModel() for (; itr != end; ++itr) { Model* model = *itr; - model->unregisterModel(); + model->getUnregistered(); } HList::iterator hItr = handlers->begin(); @@ -131,21 +145,27 @@ void M::Model::unregisterModel() for (; hItr != hEnd; ++hItr) { W::Handler* handler = *hItr; - dispatcher->unregisterHandler(handler); + connector->unregisterHandler(handler); } Map::iterator sItr = subscribers->begin(); Map::iterator sEnd = subscribers->end(); for (; sItr != sEnd; ++sItr) { - const W::Socket& socket = server->getConnection(sItr->first); - disconnect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); + const W::Socket* socket = connector->getConnection(sItr->first); + disconnect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); } subscribers->clear(); subscribersCount = 0; - dispatcher = 0; - server = 0; + Controllers::iterator cItr = controllers->begin(); + Controllers::iterator cEnd = controllers->end(); + + for (; cItr != cEnd; ++cItr) { + connector->unregisterController(cItr->first, cItr->second); + } + + connector = 0; registered = false; } @@ -162,7 +182,6 @@ void M::Model::h_subscribe(const W::Event& ev) params = static_cast(vc.at(u"params")); } - Map::iterator sItr = subscribers->find(id); if (sItr == subscribers->end()) { @@ -171,8 +190,8 @@ void M::Model::h_subscribe(const W::Event& ev) emit serviceMessage(QString("Model ") + address.toString().c_str() + ": something completely wrong happened"); throw 3; } - const W::Socket& socket = server->getConnection(id); - connect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); + const W::Socket* socket = connector->getConnection(id); + connect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); sItr = pair.first; } SMap::const_iterator oItr = sItr->second.find(source); @@ -238,8 +257,8 @@ void M::Model::h_unsubscribe(const W::Event& ev) smap.erase(sItr); if (smap.size() == 0) { - const W::Socket& socket = server->getConnection(itr->first); - disconnect(&socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); + const W::Socket* socket = connector->getConnection(itr->first); + disconnect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); subscribers->erase(itr); } --subscribersCount; @@ -256,7 +275,7 @@ void M::Model::send(W::Vocabulary* vc, const W::Address& destination, uint64_t c } W::Event ev(destination, vc); ev.setSenderId(connectionId); - server->getConnection(connectionId).send(ev); + connector->getConnection(connectionId)->send(ev); } void M::Model::response(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Event& src) @@ -272,7 +291,7 @@ void M::Model::response(W::Vocabulary* vc, const W::Address& handlerAddress, con W::Event ev(source + handlerAddress, vc); ev.setSenderId(id); - server->getConnection(id).send(ev); + connector->getConnection(id)->send(ev); } void M::Model::fakeResponse(W::Vocabulary* vc, const W::Address& handlerAddress, const W::Address& sourceAddress, const W::Event& src) @@ -288,7 +307,7 @@ void M::Model::fakeResponse(W::Vocabulary* vc, const W::Address& handlerAddress, W::Event ev(source + handlerAddress, vc); ev.setSenderId(id); - server->getConnection(id).send(ev); + connector->getConnection(id)->send(ev); } void M::Model::broadcast(W::Vocabulary* vc, const W::Address& handlerAddress) @@ -307,7 +326,7 @@ void M::Model::broadcast(W::Vocabulary* vc, const W::Address& handlerAddress) for (;oItr != oEnd; ++oItr) { W::Event ev(oItr->first + handlerAddress, vc->copy()); ev.setSenderId(itr->first); - server->getConnection(itr->first).send(ev); + connector->getConnection(itr->first)->send(ev); } } delete vc; @@ -317,23 +336,54 @@ void M::Model::removeHandler(W::Handler* handler) { handlers->erase(handler); if (registered) { - dispatcher->unregisterHandler(handler); + connector->unregisterHandler(handler); } } void M::Model::removeModel(M::Model* model) { models->erase(model); + disconnect(model, SIGNAL(serviceMessage(const QString&)), this, SIGNAL(serviceMessage(const QString&))); if (registered) { - model->unregisterModel(); + model->getUnregistered(); } } -void M::Model::passToHandler(const W::Event& event) const +void M::Model::passToLocalHandler(const W::Event& event) const { if (registered) { - dispatcher->pass(event); + connector->passThroughDispatcher(event); } else { emit serviceMessage(QString("An attempt to pass event to dispatcher from unregistered model\nModel address ") + address.toString().c_str()); } } + +void M::Model::addController(C::Controller* ctrl, const W::String& nodeName) +{ + Controllers::const_iterator itr = controllers->find(ctrl); + if (itr != controllers->end()) { + emit serviceMessage(QString("An attempt to add controller ") + ctrl->getAddress().toString().c_str() + QString(" for the second time in model ") + address.toString().c_str()); + throw 9; + } + controllers->insert(std::make_pair(ctrl, nodeName)); + connect(ctrl, SIGNAL(serviceMessage(const QString&)), SIGNAL(serviceMessage(const QString&))); + if (registered) { + connector->registerController(ctrl, nodeName);; + } +} + +void M::Model::removeController(C::Controller* ctrl) +{ + Controllers::const_iterator itr = controllers->find(ctrl); + if (itr == controllers->end()) { + emit serviceMessage(QString("An attempt to remove absent controller ") + ctrl->getAddress().toString().c_str() + QString(" from the model ") + address.toString().c_str()); + throw 10; + } + + disconnect(ctrl, SIGNAL(serviceMessage(const QString&)), this, SIGNAL(serviceMessage(const QString&))); + if (registered) { + connector->unregisterController(itr->first, itr->second); + } + controllers->erase(itr); +} + diff --git a/lib/wModel/model.h b/lib/wModel/model.h index 8b44fc9..c10b173 100644 --- a/lib/wModel/model.h +++ b/lib/wModel/model.h @@ -13,10 +13,10 @@ #include #include #include -#include -#include #include #include +#include +#include namespace M { @@ -29,10 +29,15 @@ namespace M { list, vocabulary, catalogue, + image, + button, + model, attributes = 50, file, - resourceCache + resourceCache, + + player = 107 }; Model(const W::Address p_address, QObject* parent = 0); @@ -46,13 +51,15 @@ namespace M { void addModel(M::Model* model); void addHandler(W::Handler* handler); void addProperty(const W::String& value, const W::String& name); + void addController(C::Controller* ctrl, const W::String& nodeName); W::Address getAddress() const; - void registerModel(W::Dispatcher* dp, W::Server* srv); - void unregisterModel(); + void getRegistered(U::Connector* connector); + void getUnregistered(); void removeHandler(W::Handler* handler); void removeModel(M::Model* model); - void passToHandler(const W::Event& event) const; + void removeController(C::Controller* ctrl); + void passToLocalHandler(const W::Event& event) const; signals: void serviceMessage(const QString& msg) const; @@ -76,13 +83,14 @@ namespace M { private: typedef W::Order HList; typedef W::Order MList; + typedef std::map Controllers; - W::Dispatcher* dispatcher; - W::Server* server; + U::Connector* connector; uint64_t subscribersCount; HList* handlers; W::Vector* properties; MList* models; + Controllers* controllers; private slots: void onSocketDisconnected(); diff --git a/lib/wModel/vocabulary.h b/lib/wModel/vocabulary.h index 5ddb250..bcbb08d 100644 --- a/lib/wModel/vocabulary.h +++ b/lib/wModel/vocabulary.h @@ -12,8 +12,7 @@ namespace M { class ICatalogue; - class Vocabulary : public M::Model - { + class Vocabulary : public M::Model { friend class ICatalogue; public: Vocabulary(const W::Address p_address, QObject* parent = 0); diff --git a/lib/wServerUtils/connector.cpp b/lib/wServerUtils/connector.cpp index 77b1211..724df6e 100644 --- a/lib/wServerUtils/connector.cpp +++ b/lib/wServerUtils/connector.cpp @@ -1,4 +1,5 @@ #include "connector.h" +#include "commands.h" U::Connector::Connector(W::Dispatcher* dp, W::Server* srv, U::Commands* cmds, QObject* parent): QObject(parent), @@ -6,7 +7,8 @@ U::Connector::Connector(W::Dispatcher* dp, W::Server* srv, U::Commands* cmds, QO server(srv), commands(cmds), nodes(), - ignoredNodes() + ignoredNodes(), + controllers() { connect(server, SIGNAL(newConnection(const W::Socket&)), SLOT(onNewConnection(const W::Socket&))); connect(server, SIGNAL(closedConnection(const W::Socket&)), SLOT(onClosedConnection(const W::Socket&))); @@ -30,6 +32,17 @@ U::Connector::~Connector() for (; itr != end; ++itr) { commands->removeCommand(dc + itr->first); } + + std::multimap::const_iterator cbeg = controllers.begin(); + std::multimap::const_iterator cend = controllers.end(); + + for (; cbeg != cend; ++cbeg) { + C::Controller* ctrl = cbeg->second; + if (ctrl->isSubscribed()) { + ctrl->unsubscribe(); + ctrl->unregisterController(); + } + } } void U::Connector::addIgnoredNode(const W::String& name) @@ -43,7 +56,7 @@ void U::Connector::sendTo(const W::String& name, const W::Event& event) if (itr != nodes.end()) { throw new NodeAccessError(name); } else { - server->getConnection(itr->second).send(event); + server->getConnection(itr->second)->send(event); } } @@ -69,6 +82,14 @@ void U::Connector::onNewConnection(const W::Socket& socket) emit serviceMessage(QString("New connection, id: ") + socket.getId().toString().c_str()); connect(&socket, SIGNAL(message(const W::Event&)), dispatcher, SLOT(pass(const W::Event&))); + std::multimap::const_iterator beg = controllers.lower_bound(name); + std::multimap::const_iterator end = controllers.upper_bound(name); + + for (; beg != end; ++beg) { + beg->second->registerController(dispatcher, &socket); + beg->second->subscribe(); + } + emit nodeConnected(name); } } else { @@ -90,6 +111,14 @@ void U::Connector::onClosedConnection(const W::Socket& socket) if (ign == ignoredNodes.end()) { Map::const_iterator itr = nodes.find(name); if (itr != nodes.end()) { + std::multimap::const_iterator beg = controllers.lower_bound(name); + std::multimap::const_iterator end = controllers.upper_bound(name); + + for (; beg != end; ++beg) { + beg->second->unsubscribe(); + beg->second->unregisterController(); + } + emit nodeDisconnected(name); commands->removeCommand(W::String(u"disconnect") + name); nodes.erase(itr); @@ -114,7 +143,7 @@ void U::Connector::h_disconnect(const W::Event& ev) server->closeConnection(itr->second); } -const W::Socket& U::Connector::getNodeSocket(const W::String& name) +const W::Socket* U::Connector::getNodeSocket(const W::String& name) { Map::const_iterator itr = nodes.find(name); if (itr == nodes.end()) { @@ -122,3 +151,62 @@ const W::Socket& U::Connector::getNodeSocket(const W::String& name) } return server->getConnection(itr->second); } + +void U::Connector::registerHandler(W::Handler* handler) +{ + dispatcher->registerHandler(handler); +} + +void U::Connector::unregisterHandler(W::Handler* handler) +{ + dispatcher->unregisterHandler(handler); +} + +const W::Socket * U::Connector::getConnection(uint64_t p_id) const +{ + return server->getConnection(p_id); +} + +void U::Connector::passThroughDispatcher(const W::Event& ev) const +{ + dispatcher->pass(ev); +} + +void U::Connector::registerController(C::Controller* ctrl, const W::String& node) +{ + std::set::const_iterator iitr = ignoredNodes.find(node); + if (iitr != ignoredNodes.end()) { + throw 3; //this means you're trying to receive something from one of ignored nodes, which never going to be handled in connector, most probably it's a mistake + } + controllers.insert(std::make_pair(node, ctrl)); + Map::const_iterator itr = nodes.find(node); + if (itr != nodes.end()) { + ctrl->registerController(dispatcher, server->getConnection(itr->second)); + ctrl->subscribe(); //let's say I always need them subscribed, for now at least + } +} + +void U::Connector::unregisterController(C::Controller* ctrl, const W::String& node) +{ + bool found = false; + std::multimap::const_iterator beg = controllers.lower_bound(node); + std::multimap::const_iterator end = controllers.upper_bound(node); + + for (; beg != end; ++beg) { + if (beg->second == ctrl) { + found = true; //TODO make a proper way to store 'em + break; + } + } + + if (!found) { + throw 4; + } + + if (ctrl->isSubscribed()) { + ctrl->unsubscribe(); + ctrl->unregisterController(); + } + controllers.erase(beg); +} + diff --git a/lib/wServerUtils/connector.h b/lib/wServerUtils/connector.h index 4ba0a48..e6ff2f8 100644 --- a/lib/wServerUtils/connector.h +++ b/lib/wServerUtils/connector.h @@ -1,11 +1,14 @@ #ifndef CONNECTOR_H #define CONNECTOR_H +#include + #include #include #include #include +#include #include #include @@ -16,9 +19,11 @@ #include -#include "commands.h" +#include namespace U { + class Commands; + class Connector : public QObject { Q_OBJECT @@ -29,7 +34,13 @@ namespace U { void addIgnoredNode(const W::String& name); void sendTo(const W::String& name, const W::Event& event); - const W::Socket& getNodeSocket(const W::String& name); + const W::Socket* getNodeSocket(const W::String& name); + void registerHandler(W::Handler* handler); + void unregisterHandler(W::Handler* handler); + const W::Socket* getConnection(uint64_t p_id) const; + void passThroughDispatcher(const W::Event& ev) const; + void registerController(C::Controller* ctrl, const W::String& node); + void unregisterController(C::Controller* ctrl, const W::String& node); signals: void serviceMessage(const QString& msg); @@ -42,6 +53,7 @@ namespace U { U::Commands* commands; Map nodes; std::set ignoredNodes; + std::multimap controllers; protected: handler(connect); diff --git a/lib/wSocket/server.cpp b/lib/wSocket/server.cpp index ec44bc3..9b7f6ad 100644 --- a/lib/wSocket/server.cpp +++ b/lib/wSocket/server.cpp @@ -44,14 +44,14 @@ void W::Server::stop() } } -const W::Socket& W::Server::getConnection(uint64_t p_id) const +const W::Socket* W::Server::getConnection(uint64_t p_id) const { std::map::const_iterator itr = connections.find(p_id); if (itr == connections.end()) { throw new SocketAccessError(); } - return *(itr->second); + return itr->second; } uint64_t W::Server::getConnectionsCount() const diff --git a/lib/wSocket/server.h b/lib/wSocket/server.h index 7981a71..eeeb7b1 100644 --- a/lib/wSocket/server.h +++ b/lib/wSocket/server.h @@ -27,7 +27,7 @@ namespace W void listen(uint16_t port); void stop(); - const Socket& getConnection(uint64_t p_id) const; + const Socket* getConnection(uint64_t p_id) const; uint64_t getConnectionsCount() const; void closeConnection(uint64_t p_id); void openConnection(const String& addr, const Uint64& port); diff --git a/lib/wType/object.cpp b/lib/wType/object.cpp index d567867..40507ec 100644 --- a/lib/wType/object.cpp +++ b/lib/wType/object.cpp @@ -102,5 +102,7 @@ W::Object::StdStr W::Object::getTypeName(W::Object::objectType type) case blob: return "Blob"; } + + throw 5; } diff --git a/libjs/wController/button.js b/libjs/wController/button.js new file mode 100644 index 0000000..e98534c --- /dev/null +++ b/libjs/wController/button.js @@ -0,0 +1,69 @@ +"use strict"; + +var Controller = require("./controller"); +var String = require("./string"); +var Vocabulary = require("../wType/vocabulary"); + +var Button = Controller.inherit({ + "className": "Button", + "constructor": function(addr) { + Controller.fn.constructor.call(this, addr); + + this.enabled = false; + this.hasLabel = false; + + this.addHandler("get"); + this.addHandler("setLabel"); + this.addHandler("setImage"); + this.addHandler("setEnabled"); + this.addHandler("changeImage"); + }, + "destructor": function() { + + Controller.fn.destructor.call(this); + }, + "activate": function() { + if (this.enabled) { + this.send(new Vocabulary, "activate"); + } + }, + "_h_changeImage": function(ev) { + + }, + "_h_get": function(ev) { + this._h_setLabel(ev); + this._h_setImage(ev); + this._h_setEnabled(ev); + }, + "_h_setEnabled": function(ev) { + var data = ev.getData(); + + var enabled = data.at("enabled").valueOf(); + if (this.enabled !== enabled) { + this.enabled = enabled; + this.trigger("setEnabled", this.enabled); + } + }, + "_h_setLabel": function(ev) { + var data = ev.getData(); + var hasLabel = data.at("hasLabel").valueOf(); + + if (hasLabel !== this.hasLabel) { + this.hasLabel = hasLabel; + if (hasLabel) { + this.label = new String(data.at("label").clone()); + this.addController(this.label); + this.trigger("setLabel", true, this.label); + } else { + this.trigger("setLabel", false); + this.removeController(this.label); + this.label.destructor(); + } + } + }, + "_h_setImage": function(ev) { + + } +}); + +module.exports = Button; diff --git a/libjs/wController/controller.js b/libjs/wController/controller.js index ece32b7..268f67d 100644 --- a/libjs/wController/controller.js +++ b/libjs/wController/controller.js @@ -328,8 +328,10 @@ Controller.ModelType = { String: 0, List: 1, Vocabulary: 2, - Image: 3, - Controller: 4, + Catalogue: 3, + Image: 4, + Button: 5, + Controller: 6, Attributes: 50, @@ -339,15 +341,18 @@ Controller.ModelType = { PageStorage: 103, PanesList: 104, Theme: 105, - ThemeStorage: 106 + ThemeStorage: 106, + Player: 107 }; Controller.ReversedModelType = { "0": "String", "1": "List", "2": "Vocabulary", - "3": "Image", - "4": "Controller", + "3": "Catalogue", + "4": "Image", + "5": "Button", + "6": "Controller", "50": "Attributes", @@ -357,7 +362,8 @@ Controller.ReversedModelType = { "103": "PageStorage", "104": "PanesList", "105": "Theme", - "106": "ThemeStorage" + "106": "ThemeStorage", + "107": "Player" }; Controller.ModelTypesPaths = { @@ -372,7 +378,10 @@ Controller.ModelTypesPaths = { PanesList: "./panesList", //resolve as dependency Theme: "./theme", //resolve as dependency ThemeStorage: "./themeStorage", //resolve as dependency - Image: "./image" //resolve as dependency + Image: "./image", //resolve as dependency + Button: "./button", //resolve as dependency + Catalogue: "./catalogue", //resolve as dependency + Player: "./player" //resolve as dependency }; Controller.constructors = { diff --git a/libjs/wController/link.js b/libjs/wController/link.js index 1ba0ee2..2babdb3 100644 --- a/libjs/wController/link.js +++ b/libjs/wController/link.js @@ -10,16 +10,12 @@ var Link = Controller.inherit({ "constructor": function(addr) { Controller.fn.constructor.call(this, addr); - var hop = new Address(["label"]); - this.targetAddress = new Address([]); this.label = new String(addr['+'](hop)); this.addController(this.label); this.addHandler("get"); - - hop.destructor(); }, "destructor": function() { this.targetAddress.destructor(); @@ -35,4 +31,6 @@ var Link = Controller.inherit({ } }); +var hop = new Address(["label"]); + module.exports = Link; diff --git a/libjs/wModel/CMakeLists.txt b/libjs/wModel/CMakeLists.txt index b06a09c..d0bd7cc 100644 --- a/libjs/wModel/CMakeLists.txt +++ b/libjs/wModel/CMakeLists.txt @@ -13,5 +13,6 @@ configure_file(themeStorage.js themeStorage.js) configure_file(vocabulary.js vocabulary.js) configure_file(attributes.js attributes.js) configure_file(image.js image.js) +configure_file(button.js button.js) add_subdirectory(proxy) diff --git a/libjs/wModel/button.js b/libjs/wModel/button.js new file mode 100644 index 0000000..276f51f --- /dev/null +++ b/libjs/wModel/button.js @@ -0,0 +1,90 @@ +"use strict"; + +var Model = require("./model"); +var ModelString = require("./string"); + +var Vocabulary = require("../wType/vocabulary"); +var Boolean = require("../wType/boolean"); +var Address = require("../wType/address"); +var String = require("../wType/string"); + +var Button = Model.inherit({ + "className": "Button", + "constructor": function(address) { + Model.fn.constructor.call(this, address); + + this._enabled = true; + this._hasImage = false; + this._hasLabel =false; + this._imageName = undefined; + this._label = undefined; + + this.addHandler("get"); + this.addHandler("activate"); + }, + "setImage": function(name) { + if (this._hasImage) { + if (this._imageName !== name) { + this._image = name; + var vc = new Vocabulary(); + vc.insert("image", new String(this._imageName)); + this.broadcast(vc, "changeImage"); + } + } else { + this._image = name; + this._hasImage = true; + var vc = new Vocabulary(); + vc.insert("image", new String(this._imageName)); + this.broadcast(vc, "setImage"); + } + }, + "setEnabled": function(enabled) { + if (enabled !== this._enabled) { + this._enabled = enabled; + var vc = new Vocabulary(); + vc.insert("enabled", new Boolean(this._enabled)); + this.broadcast(vc, "setEnabled"); + } + }, + "setLabel": function(text) { + if (this._hasLabel) { + this._label.set(text); + } else { + this._label = new ModelString(this._address["+"](labelHop), text); + this.addModel(this._label); + var vc = new Vocabulary(); + vc.insert("hasLabel", new Boolean(true)); + vc.insert("label", this._label.getAddress()); + this.broadcast(vc, "setLabel"); + this._hasLabel = true; + } + }, + "_h_subscribe": function(ev) { + Model.fn._h_subscribe.call(this, ev); + + this._h_get(ev); + }, + "_h_get": function(ev) { + var vc = new Vocabulary(); + vc.insert("hasImage", new Boolean(this._hasImage)); + if (this._hasImage) { + vc.insert("image", new String(this._imageName)); + } + vc.insert("hasLabel", new Boolean(this._hasLabel)); + if (this._hasLabel) { + vc.insert("label", this._label.getAddress()); + } + vc.insert("enabled", new Boolean(this._enabled)); + + this.response(vc, "get", ev); + }, + "_h_activate": function() { + if (this._enabled) { + this.trigger("activated"); + } + } +}); + +var labelHop = new Address(["label"]); + +module.exports = Button; diff --git a/libjs/wModel/model.js b/libjs/wModel/model.js index d5f68a1..e5643b5 100644 --- a/libjs/wModel/model.js +++ b/libjs/wModel/model.js @@ -299,8 +299,10 @@ Model.ModelType = { String: 0, List: 1, Vocabulary: 2, - Image: 3, - Model: 4, + //Catalogue: 3, + Image: 4, + Button: 5, + Model: 6, Attributes: 50, @@ -310,7 +312,8 @@ Model.ModelType = { PageStorage: 103, PanesList: 104, Theme: 105, - ThemeStorage: 106 + ThemeStorage: 106, + Player: 107 }; module.exports = Model; diff --git a/lorgar/css/main.css b/lorgar/css/main.css index 4a92774..26e4c65 100644 --- a/lorgar/css/main.css +++ b/lorgar/css/main.css @@ -45,3 +45,7 @@ div.dragging .draggable { cursor: -moz-grabbing; cursor: grabbing; } + +.disabled { + opacity: 0.7; +} diff --git a/lorgar/lib/wController/CMakeLists.txt b/lorgar/lib/wController/CMakeLists.txt index 79ca778..c758a1e 100644 --- a/lorgar/lib/wController/CMakeLists.txt +++ b/lorgar/lib/wController/CMakeLists.txt @@ -17,3 +17,4 @@ add_jslib(wController/localModel.js lib/wController/localModel ${LORGAR_DIR} bro 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/image.js lib/wController/image ${LORGAR_DIR} browser) +add_jslib(wController/button.js lib/wController/button ${LORGAR_DIR} browser) diff --git a/lorgar/main.js b/lorgar/main.js index 286a597..e5aa4fc 100644 --- a/lorgar/main.js +++ b/lorgar/main.js @@ -36,8 +36,8 @@ } } - Controller.initialize(["String", "List", "Vocabulary", "Page", "PanesList", "Link", "Image"], waiter.check.bind(waiter, "controllers")); - View.initialize(["Label", "Page", "PanesList", "Nav", "Image"], waiter.check.bind(waiter, "views")); + Controller.initialize(["String", "List", "Vocabulary", "Page", "PanesList", "Link", "Image", "Button"], waiter.check.bind(waiter, "controllers")); + View.initialize(["Label", "Page", "PanesList", "Nav", "Image", "Button"], waiter.check.bind(waiter, "views")); var test = new Test(); test.run(); diff --git a/lorgar/views/CMakeLists.txt b/lorgar/views/CMakeLists.txt index c656448..2a4393b 100644 --- a/lorgar/views/CMakeLists.txt +++ b/lorgar/views/CMakeLists.txt @@ -11,5 +11,6 @@ configure_file(mainLayout.js mainLayout.js) configure_file(page.js page.js) configure_file(pane.js pane.js) configure_file(image.js image.js) +configure_file(button.js button.js) add_subdirectory(helpers) diff --git a/lorgar/views/button.js b/lorgar/views/button.js new file mode 100644 index 0000000..7dbeaf5 --- /dev/null +++ b/lorgar/views/button.js @@ -0,0 +1,95 @@ +"use strict"; +(function() { + var moduleName = "views/button"; + + var deps = []; + deps.push("views/layout"); + deps.push("views/label"); + + define(moduleName, deps, function() { + var Layout = require("views/layout"); + var Label = require("views/label"); + + var Button = Layout.inherit({ + "className": "Button", + "constructor": function(controller, options) { + var base = { + padding: 5 + }; + W.extend(base, options) + Layout.fn.constructor.call(this, controller, base); + + this.addClass("hoverable"); + this._enabled = true; + this._hasLabel = false; + this._e.addEventListener("click", this._onClick.bind(this), false); + + controller.on("setEnabled", this._onSetEnabled, this); + controller.on("setLabel", this._onSetLabel, this); + }, + "destructor": function() { + this._f.off("setEnabled", this._onSetEnabled, this); + this._f.off("setLabel", this._onSetLabel, this); + + Layout.fn.destructor.call(this); + }, + "append": function(child, aligment, index) { + this._updateLimits(); + + Layout.fn.append.call(this, child, aligment, index); + }, + "_onChildChangeLimits": function(child) { + this._updateLimits(); + + Layout.fn._onChildChangeLimits.call(this, child); + }, + "_onClick": function() { + if (this._enabled) { + this._f.activate(); + } + }, + "_onSetEnabled": function(enabled) { + if (this._enabled !== enabled) { + this._enabled = enabled; + if (this._enabled) { + this.addClass("hoverable"); + this.removeClass("disabled"); + } else { + this.removeClass("hoverable"); + this.addClass("disabled"); + } + } + }, + "_onSetLabel": function(hasLabel, label) { + if (this._hasLabel !== hasLabel) { + this._hasLabel = hasLabel; + if (this._hasLabel) { + this._label = new Label(label); + this.append(this._label, Layout.Aligment.CenterCenter); + } else { + this._label.destructor(); + delete this._label(); + } + } + }, + "_updateLimits": function() { + var minWidth = this._o.padding * 2; + var maxWidth = this._o.padding * 2; + var minHeight = this._o.padding * 2; + var maxHeight = this._o.padding * 2; + + if (this._hasLabel) { + minWidth += this._label._o.minWidth; + minHeight += this._label._o.minHeight; + maxWidth += this._label._o.maxWidth; + maxHeight += this._label._o.maxHeight; + } + + this._setLimits(minWidth, minHeight, maxWidth, maxHeight); + } + }); + + return Button; + }) +})(); + diff --git a/lorgar/views/layout.js b/lorgar/views/layout.js index c54feba..f41c45c 100644 --- a/lorgar/views/layout.js +++ b/lorgar/views/layout.js @@ -76,8 +76,12 @@ } } + if (this._w !== undefined && this._h !== undefined) { child.setSize(this._w, this._h); + index = index || this._c.length - 1; + var c = this._c[index]; + this._positionElement(c); } }, "clear": function() { diff --git a/lorgar/views/view.js b/lorgar/views/view.js index efe9125..ba4231f 100644 --- a/lorgar/views/view.js +++ b/lorgar/views/view.js @@ -191,9 +191,12 @@ } if (needToTell) { this.trigger("changeLimits", this); + if (this._w !== undefined && this._h !== undefined) { + this.setSize(this._w, this._h); + } } - return needToTell && this._events.changeLimits && this._events.changeLimits.length; //to see if someone actually going to listen that event + return needToTell && this._events.changeLimits && this._events.changeLimits.length; //to see if someone actually going to listen that event, if not - return result }, "setMaxSize": function(w, h) { this._o.maxWidth = w; @@ -284,22 +287,27 @@ View.ViewType = { Label: 0, - Image: 3, - View: 4, + Image: 4, + Button: 5, + View: 6, Page: 102, - PanesList: 104 + PanesList: 104, + Player: 107 }; View.ReversedViewType = { "0": "Label", - "3": "Image", - "4": "View", + "4": "Image", + "5": "Button", + "6": "View", "101": "Nav", "102": "Page", - "104": "PanesList" + "104": "PanesList", + + "107": "Player" }; View.ViewTypesPaths = { @@ -307,7 +315,9 @@ Nav: "views/nav", Page: "views/page", PanesList: "views/panesList", - Image: "views/image" + Image: "views/image", + Button: "views/button", + Player: "views/player" }; View.constructors = { diff --git a/magnus/lib/wModel/CMakeLists.txt b/magnus/lib/wModel/CMakeLists.txt index 01c6b6a..fdff702 100644 --- a/magnus/lib/wModel/CMakeLists.txt +++ b/magnus/lib/wModel/CMakeLists.txt @@ -13,5 +13,6 @@ add_jslib(wModel/themeStorage.js lib/wModel/themeStorage ${MAGNUS_DIR} node) add_jslib(wModel/vocabulary.js lib/wModel/vocabulary ${MAGNUS_DIR} node) add_jslib(wModel/attributes.js lib/wModel/attributes ${MAGNUS_DIR} node) add_jslib(wModel/image.js lib/wModel/image ${MAGNUS_DIR} node) +add_jslib(wModel/button.js lib/wModel/button ${MAGNUS_DIR} node) add_subdirectory(proxy) diff --git a/magnus/pages/test.js b/magnus/pages/test.js index 584493e..99fa73f 100644 --- a/magnus/pages/test.js +++ b/magnus/pages/test.js @@ -2,6 +2,7 @@ var Page = require("../lib/wModel/page"); var String = require("../lib/wModel/string"); +var Button = require("../lib/wModel/button"); var Address = require("../lib/wType/address"); @@ -13,6 +14,16 @@ var TestPage = Page.inherit({ var header = new String(this._address["+"](new Address(["message"])), "This is a test page"); header.addProperty("fontFamily", "casualFont"); this.addItem(header, 0, 0, 1, 1, Page.Aligment.CenterTop); + + this._button = new Button(this._address["+"](new Address(["testButton"]))); + this._button.setLabel("Push me"); + this._button.on("activated", this._onActivate, this); + this.addItem(this._button, 1, 0, 1, 1, Page.Aligment.CenterTop); + }, + "_onActivate": function() { + this.trigger("serviceMessage", "Button works!"); + this._button.setEnabled(false); + setTimeout(this._button.setEnabled.bind(this._button, true), 3000); } }); diff --git a/perturabo/CMakeLists.txt b/perturabo/CMakeLists.txt index 82b4d97..c37ac4f 100644 --- a/perturabo/CMakeLists.txt +++ b/perturabo/CMakeLists.txt @@ -25,7 +25,7 @@ target_link_libraries(perturabo wSocket) target_link_libraries(perturabo wDispatcher) target_link_libraries(perturabo utils) target_link_libraries(perturabo wModel) -target_link_libraries(perturabo wServerUtils) target_link_libraries(perturabo wDatabase) +target_link_libraries(perturabo wServerUtils) install(TARGETS perturabo RUNTIME DESTINATION bin) diff --git a/perturabo/perturabo.cpp b/perturabo/perturabo.cpp index 4d5917d..7231262 100644 --- a/perturabo/perturabo.cpp +++ b/perturabo/perturabo.cpp @@ -86,11 +86,11 @@ void Perturabo::start() server->listen(8082); cout << "Registering models..." << endl; - attributes->registerModel(dispatcher, server); - commands->registerModel(dispatcher, server); + attributes->getRegistered(connector); + commands->getRegistered(connector); for (; beg != end; ++beg) { - beg->second->registerModel(dispatcher, server); + beg->second->getRegistered(connector); } cout << "Opening and indexing databases..." << endl; @@ -115,11 +115,11 @@ void Perturabo::stop() commands->enableCommand(W::String(u"clearDatabase"), false); for (; beg != end; ++beg) { - beg->second->unregisterModel(); + beg->second->getUnregistered(); } - commands->unregisterModel(); - attributes->unregisterModel(); + commands->getUnregistered(); + attributes->getUnregistered(); server->stop(); } From fe1b55bb39e3b1ba888c6e5fc110fa5ad25e387f Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 12 Aug 2018 01:11:33 +0300 Subject: [PATCH 02/16] a handler to add players in Corax --- corax/corax.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++---- corax/corax.h | 4 +++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/corax/corax.cpp b/corax/corax.cpp index 92c4145..3bcc4df 100644 --- a/corax/corax.cpp +++ b/corax/corax.cpp @@ -9,6 +9,7 @@ Corax* Corax::corax = 0; Corax::Corax(QObject *parent): QObject(parent), + started(false) server(new W::Server(W::String(u"Corax"), this)), logger(new W::Logger()), parentReporter(new W::ParentReporter()), @@ -17,7 +18,8 @@ Corax::Corax(QObject *parent): connector(0), dispatcher(new W::Dispatcher()), caches(), - parsers() + parsers(), + players() { if (corax != 0) { @@ -42,6 +44,7 @@ Corax::Corax(QObject *parent): attributes->addAttribute(W::String(u"connectionsCount"), new M::String(W::String(u"0"), W::Address({u"attributes", u"connectionCount"}))); attributes->addAttribute(W::String(u"name"), new M::String(W::String(u"Corax"), W::Address({u"attributes", u"name"}))); attributes->addAttribute(W::String(u"version"), new M::String(W::String(u"0.0.2"), W::Address({u"attributes", u"version"}))); + attributes->addAttribute(W::String(u"players"), new M::String(W::String(u"0"), W::Address({u"attributes", u"players"}))); createCaches(); createHandlers(); @@ -49,20 +52,27 @@ Corax::Corax(QObject *parent): Corax::~Corax() { - std::map::iterator pbeg = parsers.begin(); - std::map::iterator pend = parsers.end(); + std::map::const_iterator pbeg = parsers.begin(); + std::map::const_iterator pend = parsers.end(); for (; pbeg != pend; ++pbeg) { delete pbeg->second; } - std::map::iterator beg = caches.begin(); - std::map::iterator end = caches.end(); + std::map::const_iterator beg = caches.begin(); + std::map::const_iterator end = caches.end(); for (; beg != end; ++beg) { delete beg->second; } + std::map::const_iterator plit = players.begin(); + std::map::const_iterator plend = players.end(); + + for (; plit != plend; ++plit) { + delete plit->second; + } + delete connector; dispatcher->unregisterDefaultHandler(logger); @@ -83,6 +93,9 @@ void Corax::onConnectionCountChanged(uint64_t count) void Corax::start() { + if (started) { + throw 3; + } std::map::iterator beg = caches.begin(); std::map::iterator end = caches.end(); @@ -97,6 +110,13 @@ void Corax::start() beg->second->getRegistered(connector); } + std::map::const_iterator plit = players.begin(); + std::map::const_iterator plend = players.end(); + + for (; plit != plend; ++plit) { + plit->second->getRegistered(connector);; + } + cout << "Opening caches..." << endl; beg = caches.begin(); @@ -106,11 +126,16 @@ void Corax::start() commands->enableCommand(W::String(u"clearCache"), true); + started = true; cout << "Corax is ready" << endl; } void Corax::stop() { + if (!started) { + throw 3; + } + std::map::iterator beg = caches.begin(); std::map::iterator end = caches.end(); @@ -122,7 +147,17 @@ void Corax::stop() beg->second->getUnregistered(); } + std::map::const_iterator plit = players.begin(); + std::map::const_iterator plend = players.end(); + + for (; plit != plend; ++plit) { + plit->second->getUnregistered(); + } + server->stop(); + + started = false; + cout << "Corax is stopped" << endl; } void Corax::onModelServiceMessage(const QString& msg) @@ -202,6 +237,9 @@ void Corax::createHandlers() W::Vocabulary parseArgs; parseArgs.insert(u"path", W::Uint64(W::Object::string)); commands->addCommand(W::String(u"parseDirectory"), parseDirectory, parseArgs); + + W::Handler* givePlayer = W::Handler::create(W::Address({u"management", u"givePlayer"}), this, &Corax::_h_givePlayer); + commands->addCommand(W::String(u"givePlayer"), givePlayer, W::Vocabulary()); } void Corax::onParserDone(const W::String& path) @@ -234,3 +272,28 @@ void Corax::onNodeDisconnected(const W::String& name) commands->enableCommand(W::String(u"parseDirectory"), false); } } + +void Corax::h_givePlayer(const W::Event& ev) +{ + W::String num(std::to_string(players.size())); + W::Address addr{u"players", num}; + M::Player* pl = new M::Player(addr); + connect(pl, SIGNAL(serviceMessage(const QString&)), SLOT(onModelServiceMessage(const QString&))); + players.insert(std::make_pair(addr, pl)); + + attributes->setAttribute(W::String(u"players"), W::String(std::to_string(players.size()))); + pl->getRegistered(connector); //it's a handler, so I assume corax is started here; + + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"address", addr); + + const W::Vocabulary& svc = static_cast(ev.getData()); + const W::Address& source = static_cast(svc.at(u"source")); + uint64_t id = ev.getSenderId(); + vc->insert(u"source", W::Address{u"management"}); //TODO think about it, may be Corax should be a model? + + W::Event res(source + W::Address{u"getPlayer"}, vc); + res.setSenderId(id); + connector->getConnection(id)->send(ev); +} + diff --git a/corax/corax.h b/corax/corax.h index 179df14..aa5cf9c 100644 --- a/corax/corax.h +++ b/corax/corax.h @@ -30,6 +30,7 @@ #include #include "tools/parser.h" +#include "models/player.h" class Corax: public QObject { @@ -42,6 +43,7 @@ public: static Corax* corax; private: + bool started; W::Server *server; W::Logger *logger; W::ParentReporter* parentReporter; @@ -53,9 +55,11 @@ private: std::map caches; std::map parsers; + std::map players; handler(clearCache); handler(parseDirectory); + handler(givePlayer); public slots: void start(); From ca67a8e8bc21794ed0964b8893e64a7be080de48 Mon Sep 17 00:00:00 2001 From: blue Date: Wed, 29 Aug 2018 22:54:18 +0300 Subject: [PATCH 03/16] a new oblect utils - enum, enum view, refactoring of mainLayout, debugging, states for sockets --- corax/corax.cpp | 6 ++- lib/wModel/button.cpp | 34 +++++++----- lib/wSsh/CMakeLists.txt | 2 +- libjs/utils/CMakeLists.txt | 3 +- libjs/utils/enum.js | 69 ++++++++++++++++++++++++ libjs/wController/localModel.js | 1 + lorgar/core/lorgar.js | 95 ++++++++++++++++++++++----------- lorgar/lib/utils/CMakeLists.txt | 3 +- lorgar/main.js | 2 +- lorgar/views/CMakeLists.txt | 1 + lorgar/views/enumeration.js | 53 ++++++++++++++++++ lorgar/views/mainLayout.js | 41 +++++++++++--- lorgar/views/view.js | 5 +- magnus/lib/log.js | 2 +- 14 files changed, 260 insertions(+), 57 deletions(-) create mode 100644 libjs/utils/enum.js create mode 100644 lorgar/views/enumeration.js diff --git a/corax/corax.cpp b/corax/corax.cpp index 3bcc4df..2183914 100644 --- a/corax/corax.cpp +++ b/corax/corax.cpp @@ -9,7 +9,7 @@ Corax* Corax::corax = 0; Corax::Corax(QObject *parent): QObject(parent), - started(false) + started(false), server(new W::Server(W::String(u"Corax"), this)), logger(new W::Logger()), parentReporter(new W::ParentReporter()), @@ -262,6 +262,7 @@ void Corax::onNodeConnected(const W::String& name) cout << "connected node " << name.toString() << endl; if (name == u"Perturabo") { commands->enableCommand(W::String(u"parseDirectory"), true); + commands->enableCommand(W::String(u"givePlayer"), true); } } @@ -270,6 +271,7 @@ void Corax::onNodeDisconnected(const W::String& name) cout << "disconnected node " << name.toString() << endl; if (name == u"Perturabo") { commands->enableCommand(W::String(u"parseDirectory"), false); + commands->enableCommand(W::String(u"givePlayer"), false); } } @@ -294,6 +296,6 @@ void Corax::h_givePlayer(const W::Event& ev) W::Event res(source + W::Address{u"getPlayer"}, vc); res.setSenderId(id); - connector->getConnection(id)->send(ev); + connector->getConnection(id)->send(res); } diff --git a/lib/wModel/button.cpp b/lib/wModel/button.cpp index 16d103e..649f999 100644 --- a/lib/wModel/button.cpp +++ b/lib/wModel/button.cpp @@ -28,16 +28,20 @@ void M::Button::setImage(const W::String& p_image) if (hasImage) { if (*imageName != p_image) { imageName = static_cast(p_image.copy()); - W::Vocabulary* vc = new W::Vocabulary(); - vc->insert(u"image", p_image); - broadcast(vc, W::Address{u"changeImage"}); + if (registered) { + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"image", p_image); + broadcast(vc, W::Address{u"changeImage"}); + } } } else { imageName = static_cast(p_image.copy()); hasImage = true; - W::Vocabulary* vc = new W::Vocabulary(); - vc->insert(u"image", p_image); - broadcast(vc, W::Address{u"setImage"}); + if (registered) { + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"image", p_image); + broadcast(vc, W::Address{u"setImage"}); + } } hasImage = true; } @@ -46,9 +50,11 @@ void M::Button::setEnabled(bool p_enabled) { if (enabled != p_enabled) { enabled = p_enabled; - W::Vocabulary* vc = new W::Vocabulary(); - vc->insert(u"enable", new W::Boolean(enabled)); - broadcast(vc, W::Address{u"setEnabled"}); + if (registered) { + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"enable", new W::Boolean(enabled)); + broadcast(vc, W::Address{u"setEnabled"}); + } } } @@ -59,10 +65,12 @@ void M::Button::setLabel(const W::String& p_label) } else { label = new M::String(p_label, address + W::Address{u"label"}); addModel(label); - W::Vocabulary* vc = new W::Vocabulary(); - vc->insert(u"hasLabel", new W::Boolean(true)); - vc->insert(u"label", label->getAddress()); - broadcast(vc, W::Address{u"setLabel"}); + if (registered) { + W::Vocabulary* vc = new W::Vocabulary(); + vc->insert(u"hasLabel", new W::Boolean(true)); + vc->insert(u"label", label->getAddress()); + broadcast(vc, W::Address{u"setLabel"}); + } hasLabel = true; } } diff --git a/lib/wSsh/CMakeLists.txt b/lib/wSsh/CMakeLists.txt index 167eb7d..fa56fa8 100644 --- a/lib/wSsh/CMakeLists.txt +++ b/lib/wSsh/CMakeLists.txt @@ -20,4 +20,4 @@ add_library(wSsh ${HEADERS} ${SOURCES}) target_link_libraries(wSsh Qt5::Core) target_link_libraries(wSsh ssh) -target_link_libraries(wSsh ssh_threads) +#target_link_libraries(wSsh ssh_threads) diff --git a/libjs/utils/CMakeLists.txt b/libjs/utils/CMakeLists.txt index 2d5d83b..a0018e8 100644 --- a/libjs/utils/CMakeLists.txt +++ b/libjs/utils/CMakeLists.txt @@ -2,4 +2,5 @@ cmake_minimum_required(VERSION 2.8.12) configure_file(class.js class.js) configure_file(subscribable.js subscribable.js) -configure_file(globalMethods.js globalMethods.js) \ No newline at end of file +configure_file(globalMethods.js globalMethods.js) +configure_file(enum.js enum.js) diff --git a/libjs/utils/enum.js b/libjs/utils/enum.js new file mode 100644 index 0000000..9f1215c --- /dev/null +++ b/libjs/utils/enum.js @@ -0,0 +1,69 @@ +"use strict"; + +var Class = require("./class"); + +var Enum = Class.inherit({ + className: "Enum", + constructor: function(name, additional) { + if (typeof name !== "string" || name.length === 0) { + throw new Error("An attempt to register enum with wrong or empty name"); + } + + if (storage[name]) { + throw new Error("An attempt to register enum " + name + " for the second time"); + } + + Class.fn.constructor.call(this); + + this.name = name; + + this.straight = Object.create(null); + this.reversed = Object.create(null); + + this.additional = Object.create(null); + this._additionals = additional || []; + + this._lastId = 0; + + storage[name] = this; + }, + add: function(name, additional, id) { + if (typeof name !== "string" || name.length === 0) { + throw new Error("An attempt to add an entry with invalid name to enum " + name); + } + + if (!id) { + id = this._lastId + 1; + } + if (this.straight[id] !== undefined) { + throw new Error("Id duplication in enum " + this.name + " during an attempt to add entry " + name); + } + + if (this.reversed[name] !== undefined) { + throw new Error("Name duplication in enum " + this.name + " during an attempt to add entry " + name); + } + + this.straight[name] = id; + this.reversed[id] = name; + this.additional[id] = Object.create(null); + + for (var i = 0; i < this._additionals.length; ++i) { + var key = this._additionals[i]; + var aVal = additional[key]; + if (aVal === undefined) { + throw new Error("An attempt to add an entry " + name + " into enum " + this.name + " without providing additional value " + key); + } + this.additional[id][key] = aVal; + } + + this._lastId = id; + }, + hasAdditional: function(name) { + return this._additionals.indexOf(name) !== -1; + } +}); + +var storage = Object.create(null); +Enum.storage = storage; + +module.exports = Enum; diff --git a/libjs/wController/localModel.js b/libjs/wController/localModel.js index 8b1b786..f556396 100644 --- a/libjs/wController/localModel.js +++ b/libjs/wController/localModel.js @@ -21,6 +21,7 @@ var LocalModel = Subscribable.inherit({ }, "setData": function(data) { this.data = data; + this.initialized = true; this.trigger("data"); } }); diff --git a/lorgar/core/lorgar.js b/lorgar/core/lorgar.js index bc19b87..ea02cb0 100644 --- a/lorgar/core/lorgar.js +++ b/lorgar/core/lorgar.js @@ -4,6 +4,7 @@ var defineArray = []; defineArray.push("lib/utils/class"); + defineArray.push("lib/utils/enum"); defineArray.push("lib/wSocket/socket"); defineArray.push("lib/wDispatcher/dispatcher"); defineArray.push("lib/wDispatcher/handler"); @@ -27,6 +28,7 @@ define(moduleName, defineArray, function lorgar_module() { var Class = require("lib/utils/class"); + var Enum = require("lib/utils/enum"); var Socket = require("lib/wSocket/socket"); var Dispatcher = require("lib/wDispatcher/dispatcher"); var Handler = require("lib/wDispatcher/handler"); @@ -53,16 +55,18 @@ "constructor": function() { Class.fn.constructor.call(this); + this._playerCtl = undefined; this._currentPageCtl = undefined; this._nodes = Object.create(null); this._initDispatcher(); + this._initModels(); + this._initViews(); this._prepareNode("Magnus", "localhost", 8081); this._prepareNode("Corax", "localhost", 8080); - this._initModels(); - this._initViews(); + this._registerModels(); this.connectNode("Magnus"); this.connectNode("Corax"); @@ -70,6 +74,8 @@ }, "destructor": function() { window.onpopstate = undefined; + this._unregisterModels(); + if (this._currentPageCtl) { this._currentPage.destructor(); this._currentPageCtl.destructor(); @@ -77,16 +83,17 @@ this._gc.destructor(); this._ps.destructor(); - this._mainColorHelper.destructor(); this._emptyHelper.destructor(); this._body.destructor(); this.coraxSocket.close(); + this.dispatcher.unregisterHandler(this._playerResponseHandler); this.dispatcher.unregisterDefaultHandler(this._logger); this._logger.destructor(); this.dispatcher.destructor(); + this._playerResponseHandler.destructor(); //this.magnusSocket.destructor(); //this.coraxSocket.destructor(); @@ -106,31 +113,34 @@ } node.socket.open(node.address, node.port); + node.state.setData(SocketState.straight.connecting); }, - "_initCoraxSocket": function() { - this.coraxSocket = new Socket("Lorgar"); - this.coraxSocket.on("connected", this._coraxSocketConnected, this); - this.coraxSocket.on("disconnected", this._coraxSocketDisconnected, this); - this.coraxSocket.on("error", this._coraxSocketError, this); - this.coraxSocket.on("message", this.dispatcher.pass, this.dispatcher); + _registerModels: function () { + this._gc.register(this.dispatcher, this._nodes.Magnus.socket); + this._ps.register(this.dispatcher, this._nodes.Magnus.socket); + }, + _unregisterModels: function() { + if (this._currentPageCtl) { + this._currentPageCtl.unregister(); + } + + this._gc.unregister(); + this._ps.unregister(); }, "_initDispatcher": function() { this.dispatcher = new Dispatcher(); this._logger = new Logger(); + this._playerResponseHandler = new Handler(new Address(["getPlayer"]), this, this._responsePlayer); this.dispatcher.registerDefaultHandler(this._logger); + this.dispatcher.registerHandler(this._playerResponseHandler); }, "_initModels": function() { this._gc = new GlobalControls(new Address(["magnus", "gc"])); this._ps = new PageStorage(new Address(["magnus", "ps"])); - this._mainColorHelper = new LocalModel({backgroundColor: "mainColor"}); this._emptyHelper = new LocalModel(); this._gc.on("themeSelected", this.setTheme, this); - - this._gc.register(this.dispatcher, this._nodes.Magnus.socket); - this._ps.register(this.dispatcher, this._nodes.Magnus.socket); - this._ps.on("pageName", this._onPageName, this); }, "_initPageController": function(addr) { @@ -150,18 +160,10 @@ document.body.innerHTML = ""; document.body.appendChild(this._body._e); - window.addEventListener("resize",this._onWindowResize.bind(this) ,false); + window.addEventListener("resize", this._onWindowResize.bind(this), false); this._body.setSize(document.body.offsetWidth, document.body.offsetHeight); this._body.append(this._mainLayout); - var spacerL = new View(this._mainColorHelper, { - maxWidth: 50 - }); - var spacerR = new View(this._mainColorHelper, { - maxWidth: 50 - }); - this._mainLayout.append(spacerL, 1, 0, 1, 1); - this._mainLayout.append(spacerR, 1, 2, 1, 1); }, "_onHistoryPopState": function(e) { this._initPageController(new Address(e.state.address)); @@ -175,6 +177,7 @@ console.log(name + " socket connected"); var node = this._nodes[name]; node.connected = true; + node.state.setData(SocketState.straight.connected); for (var id in node.foreigns) { if (node.foreigns[id].subscribed) { @@ -182,13 +185,18 @@ } } - if (name === "Magnus") { - this._gc.subscribe(); + switch (name) { + case "Magnus": + this._gc.subscribe(); - if (!this._currentPageCtl) { - this._ps.getPageAddress(location.pathname); - this._ps.one("pageAddress", this._initPageController, this); - } + if (!this._currentPageCtl) { + this._ps.getPageAddress(location.pathname); + this._ps.one("pageAddress", this._initPageController, this); + } + break; + case "Corax": + this._requestPlayer(); + break; } }, "_onSocketDisconnected": function(name) { @@ -201,8 +209,9 @@ node.foreigns[id].controller._onSocketDisconnected; } } + node.state.setData(SocketState.straight.disconnected); }, - "_onSocketError": function(name) { + "_onSocketError": function(name, e) { console.log(name + " socket error: "); console.log(e); }, @@ -220,12 +229,17 @@ obj.socket = new Socket("Lorgar"); obj.connected = false; obj.foreigns = Object.create(null); + obj.state = new LocalModel({fontFamily: "casualFont"}); + obj.state.enum = SocketState; + obj.state.setData(SocketState.straight.disconnected); obj.socket.on("connected", this._onSocketConnected.bind(this, name)); obj.socket.on("disconnected", this._onSocketDisconnected.bind(this, name)); obj.socket.on("error", this._onSocketError.bind(this, name)); obj.socket.on("message", this.dispatcher.pass, this.dispatcher); + this._mainLayout.addState(name, obj.state); + this._nodes[name] = obj; }, "registerForeignController": function(node, controller) { @@ -243,6 +257,22 @@ node.foreigns[controller.id] = obj; controller.register(this.dispatcher, node.socket); }, + "_requestPlayer": function() { + var vc = new Vocabulary(); + vc.insert("source", new Address([])); + + var ev = new Event(new Address(["management", "givePlayer"]), vc); + + var socket = this._nodes.Corax.socket; + ev.setSenderId(socket.getId().clone()); + socket.send(ev); + ev.destructor(); + }, + "_responsePlayer": function(ev) { + var data = ev.getData(); + + console.log('Received player address: ' + data.at("address").toString()); + }, "setTheme": function(theme) { View.setTheme(theme); }, @@ -284,6 +314,11 @@ } }); + var SocketState = new Enum("SocketState", ["description"]); + SocketState.add("disconnected", {description: "Socket is disconnected"}); + SocketState.add("connecting", {description: "Socket is connecting to remote host"}); + SocketState.add("connected", {description: "Socket is connected"}); + return Lorgar; }); })(); diff --git a/lorgar/lib/utils/CMakeLists.txt b/lorgar/lib/utils/CMakeLists.txt index b06c48f..fc6a3f2 100644 --- a/lorgar/lib/utils/CMakeLists.txt +++ b/lorgar/lib/utils/CMakeLists.txt @@ -2,4 +2,5 @@ cmake_minimum_required(VERSION 2.8.12) 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/globalMethods.js lib/utils/globalMethods ${LORGAR_DIR} browser) \ No newline at end of file +add_jslib(utils/globalMethods.js lib/utils/globalMethods ${LORGAR_DIR} browser) +add_jslib(utils/enum.js lib/utils/enum ${LORGAR_DIR} browser) diff --git a/lorgar/main.js b/lorgar/main.js index e5aa4fc..a328497 100644 --- a/lorgar/main.js +++ b/lorgar/main.js @@ -37,7 +37,7 @@ } Controller.initialize(["String", "List", "Vocabulary", "Page", "PanesList", "Link", "Image", "Button"], waiter.check.bind(waiter, "controllers")); - View.initialize(["Label", "Page", "PanesList", "Nav", "Image", "Button"], waiter.check.bind(waiter, "views")); + View.initialize(["Label", "Page", "PanesList", "Nav", "Image", "Button", "Enumeration"], waiter.check.bind(waiter, "views")); var test = new Test(); test.run(); diff --git a/lorgar/views/CMakeLists.txt b/lorgar/views/CMakeLists.txt index 2a4393b..840b699 100644 --- a/lorgar/views/CMakeLists.txt +++ b/lorgar/views/CMakeLists.txt @@ -12,5 +12,6 @@ configure_file(page.js page.js) configure_file(pane.js pane.js) configure_file(image.js image.js) configure_file(button.js button.js) +configure_file(enumeration.js enumeration.js) add_subdirectory(helpers) diff --git a/lorgar/views/enumeration.js b/lorgar/views/enumeration.js new file mode 100644 index 0000000..3400372 --- /dev/null +++ b/lorgar/views/enumeration.js @@ -0,0 +1,53 @@ +"use strict"; +(function view_enumeration_js() { + var moduleName = "views/enumeration"; + + var deps = []; + deps.push("views/gridLayout"); + deps.push("views/label"); + deps.push("lib/wController/localModel"); + + define(moduleName, deps, function view_enumeration_module() { + var GridLayout = require("views/gridLayout"); + var Label = require("views/label"); + var LocalModel = require("lib/wController/localModel"); + + var Enumeration = GridLayout.inherit({ + className: "Enumeration", + constructor: function(controller, options) { + var base = {}; + W.extend(base, options) + + this._lm = new LocalModel(); + GridLayout.fn.constructor.call(this, controller, base); + + this._lv = new Label(this._lm); + this.append(this._lv, 0, 0, 1, 1, GridLayout.Aligment.CenterCenter); + + this._uncyclic.push(this._lm.destructor.bind(this._lm)); + }, + _onData: function() { + if (this._f.initialized) { + var e = this._f.enum; + var value = this._f.data; + var title; + if (e.hasAdditional("title")) { + title = e.additional[value].title; + } else { + title = e.reversed[value]; + } + + var desc = ""; + if (e.hasAdditional("description")) { + desc = e.additional[value].description; + } + + this._lm.setData(title); + this._e.setAttribute("title", desc); + } + } + }); + + return Enumeration; + }) +})(); diff --git a/lorgar/views/mainLayout.js b/lorgar/views/mainLayout.js index 8571ea9..b7876b0 100644 --- a/lorgar/views/mainLayout.js +++ b/lorgar/views/mainLayout.js @@ -5,19 +5,43 @@ var defineArray = []; defineArray.push("views/gridLayout"); defineArray.push("views/label"); + defineArray.push("views/view"); defineArray.push("views/navigationPanel"); defineArray.push("views/layout"); + defineArray.push("views/enumeration"); defineArray.push("lib/wController/localModel"); define(moduleName, defineArray, function mainLayout_module() { var GridLayout = require("views/gridLayout"); var ViewLabel = require("views/label"); + var View = require("views/view"); var ViewNavigationPanel = require("views/navigationPanel"); var Layout = require("views/layout"); + var Enumeration = require("views/enumeration"); var LocalModel = require("lib/wController/localModel"); var MainLayout = GridLayout.inherit({ "className": "MainLayout", + "constructor": function(controller, options) { + GridLayout.fn.constructor.call(this, controller, options); + + this._statusBarPosition = 2; + + this._mainColorHelper = new LocalModel({backgroundColor: "mainColor"}); + this._statusBarModel = new LocalModel({backgroundColor: "secondaryColor"}); + + this._uncyclic.push(this._statusBarModel.destructor.bind(this._statusBarModel)); + this._uncyclic.push(this._mainColorHelper.destructor.bind(this._mainColorHelper)); + + var spacerL = new View(this._mainColorHelper, {maxWidth: 50}); + var spacerR = new View(this._mainColorHelper, {maxWidth: 50}); + this.append(spacerL, 1, 0, 1, 1); + this.append(spacerR, 1, 2, 1, 1); + + this._statusBar = new GridLayout(this._statusBarModel); + this._statusBar.append(new View(this._statusBarModel), 0, 1, 1, 1); + this.append(this._statusBar, 3, 0, 1, 3); + }, "_onNewController": function(controller) { GridLayout.fn._onNewController.call(this, controller); @@ -25,13 +49,8 @@ switch (controller.name) { case "version": - var lm = new LocalModel({ - backgroundColor: "secondaryColor" - }); - var lay = new Layout(lm, {maxHeight: 15}) view = new ViewLabel(controller); - lay.append(view, Layout.Aligment.RightCenter); - this.append(lay, 2, 0, 1, 3); + this._statusBar.append(view, 0, 0, 1, 1, Layout.Aligment.LeftCenter); break; case "navigationPanel": view = new ViewNavigationPanel(controller); @@ -43,6 +62,16 @@ //this.trigger("serviceMessage", "Unsupported view: " + name + " (" + type + ")", 1); break; } + }, + addState: function(name, state) { + var lm = new LocalModel({fontFamily: "casualFont"}); + lm.setData(name + ": "); + var lv = new ViewLabel(lm); + var e = new Enumeration(state); + this._statusBar.append(lv, 0, this._statusBarPosition++, 1, 1, Layout.Aligment.LeftCenter); + this._statusBar.append(e, 0, this._statusBarPosition++, 1, 1, Layout.Aligment.LeftCenter); + + this._uncyclic.push(lm.destructor.bind(lm)); } }); diff --git a/lorgar/views/view.js b/lorgar/views/view.js index ba4231f..6a9222b 100644 --- a/lorgar/views/view.js +++ b/lorgar/views/view.js @@ -290,6 +290,7 @@ Image: 4, Button: 5, View: 6, + Enumeration: 7, Page: 102, PanesList: 104, @@ -302,6 +303,7 @@ "4": "Image", "5": "Button", "6": "View", + "7": "Enumeration", "101": "Nav", "102": "Page", @@ -317,7 +319,8 @@ PanesList: "views/panesList", Image: "views/image", Button: "views/button", - Player: "views/player" + Player: "views/player", + Enumeration: "views/enumeration" }; View.constructors = { diff --git a/magnus/lib/log.js b/magnus/lib/log.js index 51778e4..f983ea7 100644 --- a/magnus/lib/log.js +++ b/magnus/lib/log.js @@ -5,7 +5,7 @@ var ENV = config.get('build'); function getLogger(module) { var path = module.filename.split('/').slice(-2).join('/'); - return new Winston.Logger({ + return Winston.createLogger({ transports: [ new Winston.transports.Console({ colorize: true, From 46560924cefedf8f1db2c5f13177f2e08b5f37a9 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 2 Sep 2018 22:22:28 +0300 Subject: [PATCH 04/16] A draft of player controller in libjs --- libjs/wController/CMakeLists.txt | 1 + libjs/wController/player.js | 118 +++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 libjs/wController/player.js diff --git a/libjs/wController/CMakeLists.txt b/libjs/wController/CMakeLists.txt index 96b4f71..7f30e50 100644 --- a/libjs/wController/CMakeLists.txt +++ b/libjs/wController/CMakeLists.txt @@ -17,3 +17,4 @@ configure_file(localModel.js localModel.js) configure_file(catalogue.js catalogue.js) configure_file(imagePane.js imagePane.js) configure_file(file/file.js file/file.js) +configure_file(player.js player.js) diff --git a/libjs/wController/player.js b/libjs/wController/player.js new file mode 100644 index 0000000..ccb015f --- /dev/null +++ b/libjs/wController/player.js @@ -0,0 +1,118 @@ +"use strict"; + +var Controller = require("./controller"); +var Button = require("./button"); +var Vocabulary = require("./vocabulary"); +var Enum = require("../utils/enum"); + +var Player = Controller.inherit({ + className: "Player", + constructor: function(addr) { + Controller.fn.constructor.call(this, addr); + + this.controls = Object.create(null); + this.views = Object.create(null); + + this.addHandler("get"); + this.addHandler("viewsChange"); + }, + _addControl: function(type, address) { + var t = type.valueOf(); + + if (this.controls[t] !== undefined) { + throw new Error("An attempt to add multiple instances of " + ItemType.reversed[t] + " into Player"); + } + + if (ItemType.reversed[t] !== undefined) { + switch (t) { + case ItemType.straight.playPause: + var btn = new Button(address.clone()); + btn.itemType = t; + this.controls[t] = btn; + this.addController(btn); + break; + default: + this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to controls of the Player, but it's not qualified to be a control"); + } + } else { + this.trigger("serviceMessage", "An unrecgnized item ItemType in Player: " + t); + } + }, + _addView: function(type, address) { + var t = type.valueOf(); + + if (this.views[t] !== undefined) { + throw new Error("An attempt to add multiple instances of " + ItemType.reversed[t] + " into Player"); + } + + if (ItemType.reversed[t] !== undefined) { + switch (t) { + case ItemType.straight.queue: + this.trigger("serviceMessage", "Queue is not supported yet in Player"); + break; + case ItemType.straight.currentPlayback: + var cpb = new Vocabulary(address.clone()); + cpb.ItemType = t; + this.views[t] = cpb; + this.addController(cpb); + default: + this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to views of the Player, but it's not qualified to be a view"); + } + } else { + this.trigger("serviceMessage", "An unrecgnized item ItemType in Player: " + t); + } + }, + _h_get: function(ev) { + var data = ev.getData(); + + var controls = data.at("controls"); + var views = data.at("views"); + var size, i, vc; + + size = controls.length(); + for (i = 0; i < size; ++i) { + vc = controls.at(i); + this._addControl(vc.at("type"), vc.at("address")); + } + + size = views.length(); + for (i = 0; i < size; ++i) { + vc = views.at(i); + this._addview(vc.at("type"), vc.at("address")); + } + }, + _h_viewsChange: function(ev) { + var data = ev.getData(); + + var add = data.at("add"); + var remove = data.at("remove"); + var size, i, vc; + + size = remove.length(); + for (i = 0; i < size; ++i) { + this._removeView(remove.at(i)); + } + + size = add.length(); + for (i = 0; i < size; ++i) { + vc = add.at(i); + this._addview(vc.at("type"), vc.at("address")); + } + }, + _removeControl: function(type) { + //TODO + }, + _removeView: function(type) { + //TODO + } + +}); + +var ItemType = new Enum("ItemType"); +ItemType.add("playPause"); +ItemType.add("currentPlayback"); +ItemType.add("queue"); + +Player.ItemType = ItemType; + +module.exports = Player; From c8b432fe579fdb9382ae86457ae10ad3526d2427 Mon Sep 17 00:00:00 2001 From: blue Date: Mon, 29 Oct 2018 00:32:44 +0300 Subject: [PATCH 05/16] a draft of player view, debug --- corax/corax.cpp | 3 +- corax/models/player.cpp | 14 ++-- corax/models/player.h | 3 +- libjs/utils/enum.js | 2 +- libjs/wController/button.js | 2 + libjs/wController/localModel.js | 7 +- libjs/wController/player.js | 10 ++- lorgar/core/lorgar.js | 52 +++++++++----- lorgar/lib/wController/CMakeLists.txt | 1 + lorgar/views/CMakeLists.txt | 1 + lorgar/views/mainLayout.js | 18 +++++ lorgar/views/player.js | 99 +++++++++++++++++++++++++++ lorgar/views/view.js | 4 +- 13 files changed, 183 insertions(+), 33 deletions(-) create mode 100644 lorgar/views/player.js diff --git a/corax/corax.cpp b/corax/corax.cpp index 2183914..742ef81 100644 --- a/corax/corax.cpp +++ b/corax/corax.cpp @@ -125,6 +125,7 @@ void Corax::start() } commands->enableCommand(W::String(u"clearCache"), true); + commands->enableCommand(W::String(u"givePlayer"), true); started = true; cout << "Corax is ready" << endl; @@ -262,7 +263,6 @@ void Corax::onNodeConnected(const W::String& name) cout << "connected node " << name.toString() << endl; if (name == u"Perturabo") { commands->enableCommand(W::String(u"parseDirectory"), true); - commands->enableCommand(W::String(u"givePlayer"), true); } } @@ -271,7 +271,6 @@ void Corax::onNodeDisconnected(const W::String& name) cout << "disconnected node " << name.toString() << endl; if (name == u"Perturabo") { commands->enableCommand(W::String(u"parseDirectory"), false); - commands->enableCommand(W::String(u"givePlayer"), false); } } diff --git a/corax/models/player.cpp b/corax/models/player.cpp index 9cc439f..e9c8457 100644 --- a/corax/models/player.cpp +++ b/corax/models/player.cpp @@ -7,7 +7,8 @@ M::Player::Player(const W::Address& address, QObject* parent): playPauseBtn(new M::Button(address + W::Address{u"play"})), _queueView(new M::List(address + W::Address{u"queueView"})), _queue(), - current(0) + current(0), + counter(0) { W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Player::_h_get); W::Handler* hqueue = W::Handler::create(address + W::Address({u"queue"}), this, &M::Player::_h_queue); @@ -52,7 +53,6 @@ void M::Player::h_subscribe(const W::Event& ev) h_get(ev); } - void M::Player::h_get(const W::Event& ev) { W::Vector* ctrls = new W::Vector(); @@ -61,8 +61,8 @@ void M::Player::h_get(const W::Event& ev) for (; citr != cend; ++citr) { W::Vocabulary* cvc = new W::Vocabulary(); - cvc->insert(u"type", new W::Uint64(cend->first)); - cvc->insert(u"address", cend->second); + cvc->insert(u"type", new W::Uint64(citr->first)); + cvc->insert(u"address", citr->second); ctrls->push(cvc); } @@ -73,8 +73,8 @@ void M::Player::h_get(const W::Event& ev) for (; vitr != vend; ++vitr) { W::Vocabulary* vvc = new W::Vocabulary(); - vvc->insert(u"type", new W::Uint64(vend->first)); - vvc->insert(u"address", vend->second); + vvc->insert(u"type", new W::Uint64(vitr->first)); + vvc->insert(u"address", vitr->second); vws->push(vvc); } @@ -97,7 +97,7 @@ void M::Player::h_queue(const W::Event& ev) const W::Vocabulary& data = static_cast(ev.getData()); const W::Uint64& id = static_cast(data.at(u"id")); - ProxySong* song = new ProxySong(id, address + W::Address{u"currentPlayback"}); + ProxySong* song = new ProxySong(id, address + W::Address{W::String(W::Uint64(counter++).toString())}); addModel(song); if (current == 0) { current = song; diff --git a/corax/models/player.h b/corax/models/player.h index d2b17a9..b80109a 100644 --- a/corax/models/player.h +++ b/corax/models/player.h @@ -41,7 +41,7 @@ namespace M { handler(queue); private: - typedef std::map ItemMap; + typedef std::map ItemMap; typedef std::deque Queue; ItemMap controls; @@ -50,6 +50,7 @@ namespace M { M::List* _queueView; Queue _queue; ProxySong* current; + uint64_t counter; private slots: void onPlayPauseBtn(); diff --git a/libjs/utils/enum.js b/libjs/utils/enum.js index 9f1215c..c843529 100644 --- a/libjs/utils/enum.js +++ b/libjs/utils/enum.js @@ -23,7 +23,7 @@ var Enum = Class.inherit({ this.additional = Object.create(null); this._additionals = additional || []; - this._lastId = 0; + this._lastId = -1; storage[name] = this; }, diff --git a/libjs/wController/button.js b/libjs/wController/button.js index e98534c..2124928 100644 --- a/libjs/wController/button.js +++ b/libjs/wController/button.js @@ -34,6 +34,8 @@ var Button = Controller.inherit({ this._h_setLabel(ev); this._h_setImage(ev); this._h_setEnabled(ev); + + this.initialized = true; }, "_h_setEnabled": function(ev) { var data = ev.getData(); diff --git a/libjs/wController/localModel.js b/libjs/wController/localModel.js index f556396..46b1901 100644 --- a/libjs/wController/localModel.js +++ b/libjs/wController/localModel.js @@ -4,7 +4,7 @@ var Subscribable = require("../utils/subscribable"); var LocalModel = Subscribable.inherit({ "className": "LocalModel", - "constructor": function(properties) { + "constructor": function(properties, data) { Subscribable.fn.constructor.call(this); this.properties = []; @@ -18,6 +18,11 @@ var LocalModel = Subscribable.inherit({ } } } + + if (data !== undefined) { + this.data = data; + this.initialized = true; + } }, "setData": function(data) { this.data = data; diff --git a/libjs/wController/player.js b/libjs/wController/player.js index ccb015f..c65d5ac 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -30,6 +30,7 @@ var Player = Controller.inherit({ btn.itemType = t; this.controls[t] = btn; this.addController(btn); + this.trigger("newElement", btn, t); break; default: this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to controls of the Player, but it's not qualified to be a control"); @@ -55,6 +56,8 @@ var Player = Controller.inherit({ cpb.ItemType = t; this.views[t] = cpb; this.addController(cpb); + this.trigger("newElement", cpb, t); + break; default: this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to views of the Player, but it's not qualified to be a view"); } @@ -78,8 +81,11 @@ var Player = Controller.inherit({ size = views.length(); for (i = 0; i < size; ++i) { vc = views.at(i); - this._addview(vc.at("type"), vc.at("address")); + this._addView(vc.at("type"), vc.at("address")); } + + this.initialized = true; + this.trigger("data"); }, _h_viewsChange: function(ev) { var data = ev.getData(); @@ -96,7 +102,7 @@ var Player = Controller.inherit({ size = add.length(); for (i = 0; i < size; ++i) { vc = add.at(i); - this._addview(vc.at("type"), vc.at("address")); + this._addView(vc.at("type"), vc.at("address")); } }, _removeControl: function(type) { diff --git a/lorgar/core/lorgar.js b/lorgar/core/lorgar.js index ea02cb0..bb7099c 100644 --- a/lorgar/core/lorgar.js +++ b/lorgar/core/lorgar.js @@ -19,6 +19,7 @@ defineArray.push("lib/wController/pageStorage"); defineArray.push("lib/wController/page"); defineArray.push("lib/wController/localModel"); + defineArray.push("lib/wController/player"); defineArray.push("views/view"); defineArray.push("views/layout"); @@ -43,6 +44,7 @@ var PageStorage = require("lib/wController/pageStorage"); var PageController = require("lib/wController/page"); var LocalModel = require("lib/wController/localModel"); + var PlayerModel = require("lib/wController/player"); var View = require("views/view"); var Layout = require("views/layout"); @@ -204,9 +206,20 @@ var node = this._nodes[name]; node.connected = false; + switch (name) { + case "Corax": + if (this._playerCtl) { + this._mainLayout.removePlayer(); + this._playerCtl._onSocketDisconnected(); + this._playerCtl.uneregister(); + this._playerCtl.destructor(); + this._playerCtl = undefined; + } + } + for (var id in node.foreigns) { if (node.foreigns[id].subscribed) { - node.foreigns[id].controller._onSocketDisconnected; + node.foreigns[id].controller._onSocketDisconnected(); } } node.state.setData(SocketState.straight.disconnected); @@ -242,14 +255,14 @@ this._nodes[name] = obj; }, - "registerForeignController": function(node, controller) { - var node = this._nodes[node]; + "registerForeignController": function(nodeName, controller) { + var node = this._nodes[nodeName]; if (node === undefined) { - throw new Error("An attempt to register controller to an unknown node " + node); + throw new Error("An attempt to register controller to an unknown node " + nodeName); } if (node.foreigns[controller.id] !== undefined) { - throw new Error("An attempt to register a controller under node " + node + " for a second time"); + throw new Error("An attempt to register a controller under node " + nodeName + " for a second time"); } var obj = Object.create(null); obj.controller = controller; @@ -271,43 +284,46 @@ "_responsePlayer": function(ev) { var data = ev.getData(); - console.log('Received player address: ' + data.at("address").toString()); + this._playerCtl = new PlayerModel(data.at("address").clone()); + this._playerCtl.register(this.dispatcher, this._nodes["Corax"].socket); + this._playerCtl.subscribe(); + this._mainLayout.appendPlayer(this._playerCtl); }, "setTheme": function(theme) { View.setTheme(theme); }, - "subscribeForeignController": function(node, controller) { - var node = this._nodes[node]; + "subscribeForeignController": function(nodeName, controller) { + var node = this._nodes[nodeName]; if (node === undefined) { - throw new Error("An attempt to subscribe a controller to an unknown node " + node); + throw new Error("An attempt to subscribe a controller to an unknown node " + nodeName); } if (node.foreigns[controller.id] === undefined) { - throw new Error("An attempt to subscribe not registered controller to node " + node); + throw new Error("An attempt to subscribe not registered controller to node " + nodeName); } node.foreigns[controller.id].subscribed = true; controller.subscribe(); }, - "unregisterForeignController": function(node, controller) { - var node = this._nodes[node]; + "unregisterForeignController": function(nodeName, controller) { + var node = this._nodes[nodeName]; if (node === undefined) { - throw new Error("An attempt to unregister a controller from an unknown node " + node); + throw new Error("An attempt to unregister a controller from an unknown node " + nodeName); } if (node.foreigns[controller.id] === undefined) { - throw new Error("An attempt to unregister not registered controller from node " + node); + throw new Error("An attempt to unregister not registered controller from node " + nodeName); } delete node.foreigns[controller.id]; controller.unregister(); }, - "unsubscribeForeignController": function(node, controller) { - var node = this._nodes[node]; + "unsubscribeForeignController": function(nodeName, controller) { + var node = this._nodes[nodeName]; if (node === undefined) { - throw new Error("An attempt to unsubscribe a controller from an unknown node " + node); + throw new Error("An attempt to unsubscribe a controller from an unknown node " + nodeName); } if (node.foreigns[controller.id] === undefined) { - throw new Error("An attempt to unsubscribe not registered controller from node " + node); + throw new Error("An attempt to unsubscribe not registered controller from node " + nodeName); } node.foreigns[controller.id].subscribed = false; controller.unsubscribe(); diff --git a/lorgar/lib/wController/CMakeLists.txt b/lorgar/lib/wController/CMakeLists.txt index c758a1e..01a0205 100644 --- a/lorgar/lib/wController/CMakeLists.txt +++ b/lorgar/lib/wController/CMakeLists.txt @@ -18,3 +18,4 @@ add_jslib(wController/imagePane.js lib/wController/imagePane ${LORGAR_DIR} brows add_jslib(wController/file/file.js lib/wController/file/file ${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/player.js lib/wController/player ${LORGAR_DIR} browser) diff --git a/lorgar/views/CMakeLists.txt b/lorgar/views/CMakeLists.txt index 840b699..d8df8e5 100644 --- a/lorgar/views/CMakeLists.txt +++ b/lorgar/views/CMakeLists.txt @@ -13,5 +13,6 @@ configure_file(pane.js pane.js) configure_file(image.js image.js) configure_file(button.js button.js) configure_file(enumeration.js enumeration.js) +configure_file(player.js player.js) add_subdirectory(helpers) diff --git a/lorgar/views/mainLayout.js b/lorgar/views/mainLayout.js index b7876b0..89c2bda 100644 --- a/lorgar/views/mainLayout.js +++ b/lorgar/views/mainLayout.js @@ -9,6 +9,7 @@ defineArray.push("views/navigationPanel"); defineArray.push("views/layout"); defineArray.push("views/enumeration"); + defineArray.push("views/player"); defineArray.push("lib/wController/localModel"); define(moduleName, defineArray, function mainLayout_module() { @@ -18,6 +19,7 @@ var ViewNavigationPanel = require("views/navigationPanel"); var Layout = require("views/layout"); var Enumeration = require("views/enumeration"); + var Player = require("views/player"); var LocalModel = require("lib/wController/localModel"); var MainLayout = GridLayout.inherit({ @@ -26,6 +28,7 @@ GridLayout.fn.constructor.call(this, controller, options); this._statusBarPosition = 2; + this._player = undefined; this._mainColorHelper = new LocalModel({backgroundColor: "mainColor"}); this._statusBarModel = new LocalModel({backgroundColor: "secondaryColor"}); @@ -72,6 +75,21 @@ this._statusBar.append(e, 0, this._statusBarPosition++, 1, 1, Layout.Aligment.LeftCenter); this._uncyclic.push(lm.destructor.bind(lm)); + }, + appendPlayer: function(playerModel) { + if (this._player !== undefined) { + throw new Error("An attempt to add player to main layout for the second time"); + } + this._player = new Player(playerModel); + this.append(this._player, 2, 0, 1, 3); + }, + removePlayer: function() { + if (this._player === undefined) { + throw new Error("An attempt to remove non existing player from mainLayout"); + } + this.removeChild(this._player); + this._player.destructor(); + this._player = undefined; } }); diff --git a/lorgar/views/player.js b/lorgar/views/player.js new file mode 100644 index 0000000..df01552 --- /dev/null +++ b/lorgar/views/player.js @@ -0,0 +1,99 @@ +"use strict"; +(function() { + var moduleName = "views/player" + + var deps = []; + deps.push("views/gridLayout"); + deps.push("views/button"); + deps.push("views/label"); + + deps.push("lib/wController/localModel"); + + deps.push("lib/utils/enum"); + + define(moduleName, deps, function() { + var GridLayout = require("views/gridLayout"); + var Button = require("views/button"); + var Label = require("views/label"); + + var Model = require("lib/wController/localModel"); + + var Enum = require("lib/utils/enum"); + + var Player = GridLayout.inherit({ + className: "Player", + constructor: function(ctrl, options) { + GridLayout.fn.constructor.call(this, ctrl, options); + + this._playPause = null; + this._cpbCtrl = null; + this._infoModels = { + artist: new Model(null, "artist: unknown"), + album: new Model(null, "album: unknown"), + song: new Model(null, "song: unknown") + } + + ctrl.on("newElement", this._onNewElement, this); + + var artist = new Label(this._infoModels.artist); + var album = new Label(this._infoModels.album); + var song = new Label(this._infoModels.song); + + this.append(artist, 0, 2, 1, 1) + this.append(song, 1, 2, 1, 1) + this.append(album, 2, 2, 1, 1) + + 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.album.destructor.bind(this._infoModels.album)); + }, + destructor: function() { + this._f.off("newElement", this._onNewElement, this); + this._clearCpbCtrl(); + + GridLayout.fn.destructor.call(this); + }, + _clearCpbCtrl: function() { + if (this._cpbCtrl !== null) { + this._cpbCtrl.off("newElement", this._onCpbNewElement, this); + this._cpbCtrl.off("removeElement", this._onCpbRemoveElement, this); + this._cpbCtrl = null; + } + }, + _onNewElement: function(ctrl, type) { + var ItemType = Enum.storage["ItemType"]; + + switch (type) { + case ItemType.straight.playPause: + this._playPause = new Button(ctrl); + this.append(this._playPause, 0, 1, 3, 1); + break; + case ItemType.straight.queue: + break; + case ItemType.straight.currentPlayback: + this._clearCpbCtrl(); + this._cpbCtrl = ctrl; + this._cpbCtrl.on("newElement", this._onCpbNewElement, this); + this._cpbCtrl.on("removeElement", this._onCpbRemoveElement, this); + break; + } + }, + _onCpbNewElement: function(key, value) { + var model = this._infoModels[key]; + + if (model) { + model.setData(key + ": " + value.toString()); + } + }, + _onCpbRemoveElement: function(key) { + var model = this._infoModels[key]; + + if (model) { + model.setData(key + ": unknown"); + } + } + }); + + return Player; + }); +})() diff --git a/lorgar/views/view.js b/lorgar/views/view.js index 6a9222b..70a624c 100644 --- a/lorgar/views/view.js +++ b/lorgar/views/view.js @@ -54,7 +54,9 @@ for (var i = 0; i < this._f._controllers.length; ++i) { this._onNewController(this._f._controllers[i]); } - this._onData(this._f); + //if (this._f.initialized) { + this._onData(this._f); + //} View.collection[this._id] = this; this._applyProperties(); From ec349d9bb4a94dce688edc283c44c9d65432a8a6 Mon Sep 17 00:00:00 2001 From: blue Date: Wed, 28 Nov 2018 09:54:14 +0300 Subject: [PATCH 06/16] an ability to create panes actions, player frontend draft --- libjs/wController/imagePane.js | 90 ++++++++++++++++++++++++-- libjs/wController/localModel.js | 10 +++ libjs/wController/panesList.js | 40 +++++++++++- lorgar/core/lorgar.js | 3 + lorgar/main.js | 1 + lorgar/views/button.js | 5 ++ lorgar/views/pane.js | 16 ++++- lorgar/views/panesList.js | 6 +- lorgar/views/player.js | 6 ++ magnus/lib/wModel/proxy/CMakeLists.txt | 1 + magnus/lib/wModel/proxy/pane.js | 39 ++++++++++- magnus/lib/wModel/proxy/panesList.js | 66 +++++++++++++++++++ magnus/pages/album.js | 11 ++-- magnus/pages/artist.js | 13 ++-- magnus/pages/list.js | 15 +++-- magnus/pages/music.js | 10 ++- 16 files changed, 304 insertions(+), 28 deletions(-) create mode 100644 magnus/lib/wModel/proxy/panesList.js diff --git a/libjs/wController/imagePane.js b/libjs/wController/imagePane.js index 077e2c1..a421784 100644 --- a/libjs/wController/imagePane.js +++ b/libjs/wController/imagePane.js @@ -4,26 +4,97 @@ var Address = require("../wType/address"); var Vocabulary = require("./vocabulary"); var File = require("./file/file"); +var LM = require("./localModel"); var ImagePane = Vocabulary.inherit({ "className": "ImagePane", "constructor": function(addr) { Vocabulary.fn.constructor.call(this, addr); + this._actions = []; + this._hasPageLink = false; this._hasImage = false; this.image = null; }, - "addElement": function(key, element) { - if (key === "image" && !this._hasImage) { - this._hasImage = true; - this.image = new File(new Address(["images", element.toString()])); - this.addForeignController("Corax", this.image); + "_actionActivate": function(name) { + var actObj = standardActions[name]; + + actObj.handler(this); + }, + "addAction": function(action) { + var type = action.at("type").valueOf(); + var obj = Object.create(null); + var supported = true; + + obj.type = type; + + switch (type) { + case 0: + var act = action.at("action").toString(); + var actObj = standardActions[act]; + if (actObj === undefined) { + this.trigger("seviceMessage", "Action " + act + " is not supported in ImagePanel, skipping"); + supported = false; + } + var model = new LM(""); + model.enabled = true; + model.hasLabel = true; + model.label = new LM(actObj.name); + model.addController(model.label); + model.activate = this._actionActivate.bind(this, act); + + obj.model = model; + obj.action = act; + break; } + + if (supported) { + this._actions.push(obj); + this.trigger("addAction", obj.model); + } + }, + "addElement": function(key, element) { + switch (key) { + case "image": + if (!this._hasImage) { + this._hasImage = true; + this.image = new File(new Address(["images", element.toString()])); + this.addForeignController("Corax", this.image); + } + break; + case "hasPageLink": + this._hasPageLink = element.valueOf(); + break; + case "actions": + var size = element.length(); + for (var i = 0; i < size; ++i) { + this.addAction(element.at(i)); + } + } + Vocabulary.fn.addElement.call(this, key, element); }, + "getActions": function() { + var models = []; + for (var i = 0; i < this._actions.length; ++i) { + models.push(this._actions[i].model); + } + + return models; + }, + "getPageLink": function() { + if (this._hasPageLink) { + return this.data.at("pageLink").clone(); + } else { + throw new Error("An attempt to request a page link from pane which doesn't have it"); + } + }, "hasImage": function() { return this._hasImage; }, + "hasPageLink": function() { + return this._hasPageLink; + }, "removeElement": function(key) { Vocabulary.fn.removeElement.call(this, key); @@ -37,4 +108,13 @@ var ImagePane = Vocabulary.inherit({ } }); +var standardActions = { + "play": { + handler: function (obj) { + window.play(obj); + }, + name: "Play" + } +}; + module.exports = ImagePane; diff --git a/libjs/wController/localModel.js b/libjs/wController/localModel.js index 46b1901..3343a6f 100644 --- a/libjs/wController/localModel.js +++ b/libjs/wController/localModel.js @@ -24,6 +24,16 @@ var LocalModel = Subscribable.inherit({ this.initialized = true; } }, + "destructor": function() { + for (var i = 0; i < this._controllers.length; ++i) { + this._controllers[i].destructor(); + } + + Subscribable.fn.destructor.call(this); + }, + "addController": function(ctrl) { + this._controllers.push(ctrl); + }, "setData": function(data) { this.data = data; this.initialized = true; diff --git a/libjs/wController/panesList.js b/libjs/wController/panesList.js index 00a8213..1454e4a 100644 --- a/libjs/wController/panesList.js +++ b/libjs/wController/panesList.js @@ -9,15 +9,28 @@ var PanesList = List.inherit({ "constructor": function PanesListModel(addr) { List.fn.constructor.call(this, addr); + this.actions = null; + this._subscriptionStart = 0; this._subscriptionEnd = Infinity; }, + "destructor": function() { + if (this.initialized) { + this.actions.destructor(); + } + + List.fn.destructor.call(this); + }, "addElement": function(element) { var size = this.data.length(); List.fn.addElement.call(this, element); if (size >= this._subscriptionStart && size < this._subscriptionEnd) { var controller = new ImagePane(this._pairAddress["+"](new Address([element.toString()]))); + var size = this.actions.length(); + for (var i = 0; i < size; ++i) { + controller.addAction(this.actions.at(i)); + } this.addController(controller); } }, @@ -25,6 +38,24 @@ var PanesList = List.inherit({ List.fn.clear.call(this); this.clearChildren(); }, + "_h_get": function(ev) { + this.clear(); + + var root = ev.getData(); + var data = root.at("data"); + + if (this.initialized) { + this.actions.destructor(); + } + this.actions = root.at("actions").clone(); + + var size = data.length(); + for (var i = 0; i < size; ++i) { + this.addElement(data.at(i).clone()); + } + this.initialized = true; + this.trigger("data"); + }, "setSubscriptionRange": function(s, e) { var needStart = s !== this._subscriptionStart; var needEnd = e !== this._subscriptionEnd; @@ -33,7 +64,8 @@ var PanesList = List.inherit({ var oe = this._subscriptionEnd; this._subscriptionStart = s; this._subscriptionEnd = e; - if (this._subscribed) { + if (this._subscribed && this.initialized) { + var size = this.actions.length(); this.trigger("rangeStart"); if (needStart) { if (s > os) { @@ -47,6 +79,9 @@ var PanesList = List.inherit({ var limit = Math.min(os, e) - s; for (var i = 0; i < limit; ++i) { var ctrl = new ImagePane(this._pairAddress["+"](new Address([this.data.at(i + s).toString()]))); + for (var a = 0; a < size; ++a) { + ctrl.addAction(this.actions.at(a)); + } this.addController(ctrl, i); } } @@ -59,6 +94,9 @@ var PanesList = List.inherit({ var amount = ce - start; //it can be negative, it's fine for (var i = 0; i < amount; ++i) { var ctrl = new ImagePane(this._pairAddress["+"](new Address([this.data.at(start + i).toString()]))); + for (var a = 0; a < size; ++a) { + ctrl.addAction(this.actions.at(a)); + } this.addController(ctrl); } } else if (ce < coe) { diff --git a/lorgar/core/lorgar.js b/lorgar/core/lorgar.js index bb7099c..801d0ca 100644 --- a/lorgar/core/lorgar.js +++ b/lorgar/core/lorgar.js @@ -231,6 +231,9 @@ "_onWindowResize": function() { this._body.setSize(document.body.offsetWidth, document.body.offsetHeight); }, + "play": function(id) { + console.log("Need to play " + id.toString()); + }, "_prepareNode": function(name, address, port) { if (this._nodes[name]) { throw new Error("An attempt to prepeare node " + name + " for the second time"); diff --git a/lorgar/main.js b/lorgar/main.js index a328497..31e06cb 100644 --- a/lorgar/main.js +++ b/lorgar/main.js @@ -32,6 +32,7 @@ window.unregisterForeignController = window.lorgar.unregisterForeignController.bind(window.lorgar); window.subscribeForeignController = window.lorgar.subscribeForeignController.bind(window.lorgar); window.unsubscribeForeignController = window.lorgar.unsubscribeForeignController.bind(window.lorgar); + window.play = window.lorgar.play.bind(window.lorgar); } } } diff --git a/lorgar/views/button.js b/lorgar/views/button.js index 7dbeaf5..6e00151 100644 --- a/lorgar/views/button.js +++ b/lorgar/views/button.js @@ -26,6 +26,11 @@ controller.on("setEnabled", this._onSetEnabled, this); controller.on("setLabel", this._onSetLabel, this); + + if (controller.initialized) { + this._onSetEnabled(controller.enabled); + this._onSetLabel(controller.hasLabel, controller.label); + } }, "destructor": function() { this._f.off("setEnabled", this._onSetEnabled, this); diff --git a/lorgar/views/pane.js b/lorgar/views/pane.js index 2e33e7c..ce4dd50 100644 --- a/lorgar/views/pane.js +++ b/lorgar/views/pane.js @@ -8,6 +8,7 @@ defineArray.push("views/layout"); defineArray.push("views/label"); defineArray.push("views/image"); + defineArray.push("views/button"); defineArray.push("lib/wController/localModel"); define(moduleName, defineArray, function() { @@ -15,6 +16,7 @@ var Layout = require("views/layout"); var Label = require("views/label"); var Image = require("views/image"); + var Button = require("views/button"); var LM = require("lib/wController/localModel"); var Pane = Layout.inherit({ @@ -46,6 +48,12 @@ this._f.on("newElement", this._onNewElement, this); this._f.on("removeElement", this._onRemoveElement, this); + this._f.on("addAction", this._onAddAction, this); + + var acts = this._f.getActions(); + for (var i = 0; i < acts.length; ++i) { + this._onAddAction(acts[i]); + } this._uncyclic.push(function() { lm.destructor(); @@ -56,6 +64,10 @@ Layout.fn.destructor.call(this); }, + "_onAddAction": function(model) { + var view = new Button(model); + this.append(view, Layout.Aligment.LeftTop) + }, "_applyProperties": function() { this._onAddProperty("secondaryColor", "background"); @@ -67,8 +79,8 @@ }; }, "_onClick": function() { - if (this._f.data.at("hasPageLink").valueOf() === true) { - this.trigger("activate", this._f.data.at("pageLink").clone()); + if (this._f.hasPageLink()) { + this.trigger("activate", this._f.getPageLink()); } }, "_onLabelChangeLimits": function(label) { diff --git a/lorgar/views/panesList.js b/lorgar/views/panesList.js index 08dac91..af62199 100644 --- a/lorgar/views/panesList.js +++ b/lorgar/views/panesList.js @@ -50,15 +50,13 @@ this._f.setSubscriptionRange(0, 0); }, "append": function(child, index) { - var model = new LM(); - var nest = new Layout(model, { + var nest = new Layout(helper, { minHeight: this._o.nestHeight, maxHeight: this._o.nestHeight, minWidth: this._o.nestWidth, minWidth: this._o.nestWidth, scrollable: Layout.Scroll.None }); - nest._uncyclic.push(function() {model.destructor()}); nest.append(child); child.on("activate", this._onChildActivate, this); //todo need to remove handler on deletion this._addChild(nest, 0, index); @@ -184,6 +182,8 @@ } }); + var helper = new LM(); + return PanesList; }); })(); diff --git a/lorgar/views/player.js b/lorgar/views/player.js index df01552..2c7cbef 100644 --- a/lorgar/views/player.js +++ b/lorgar/views/player.js @@ -6,6 +6,7 @@ deps.push("views/gridLayout"); deps.push("views/button"); deps.push("views/label"); + deps.push("views/view"); deps.push("lib/wController/localModel"); @@ -15,6 +16,7 @@ var GridLayout = require("views/gridLayout"); var Button = require("views/button"); var Label = require("views/label"); + var View = require("views/view"); var Model = require("lib/wController/localModel"); @@ -38,10 +40,12 @@ var artist = new Label(this._infoModels.artist); var album = new Label(this._infoModels.album); var song = new Label(this._infoModels.song); + var spacer = new View(helper); this.append(artist, 0, 2, 1, 1) this.append(song, 1, 2, 1, 1) this.append(album, 2, 2, 1, 1) + this.append(spacer, 0, 3, 3, 1); this._uncyclic.push(this._infoModels.artist.destructor.bind(this._infoModels.artist)); this._uncyclic.push(this._infoModels.song.destructor.bind(this._infoModels.song)); @@ -94,6 +98,8 @@ } }); + var helper = new Model(); + return Player; }); })() diff --git a/magnus/lib/wModel/proxy/CMakeLists.txt b/magnus/lib/wModel/proxy/CMakeLists.txt index 2ef4f4b..14b2608 100644 --- a/magnus/lib/wModel/proxy/CMakeLists.txt +++ b/magnus/lib/wModel/proxy/CMakeLists.txt @@ -6,3 +6,4 @@ add_jslib(wModel/proxy/vocabulary.js lib/wModel/proxy/vocabulary ${MAGNUS_DIR} n add_jslib(wModel/proxy/catalogue.js lib/wModel/proxy/catalogue ${MAGNUS_DIR} node) configure_file(pane.js pane.js) +configure_file(panesList.js panesList.js) diff --git a/magnus/lib/wModel/proxy/pane.js b/magnus/lib/wModel/proxy/pane.js index 5bc8b91..f3c4e4a 100644 --- a/magnus/lib/wModel/proxy/pane.js +++ b/magnus/lib/wModel/proxy/pane.js @@ -4,12 +4,18 @@ var MVocabulary = require("./vocabulary"); var Address = require("../../wType/address"); var Boolean = require("../../wType/boolean"); +var Uint64 = require("../../wType/uint64"); +var String = require("../../wType/string"); +var Vocabulary = require("../../wType/vocabulary"); +var Vector = require("../../wType/vector"); var Pane = MVocabulary.inherit({ "className": "Pane", - "constructor": function(address, controllerAddress, socket) { + "constructor": function(address, controllerAddress, socket, actions) { MVocabulary.fn.constructor.call(this, address, controllerAddress, socket); + this._actions = new Vector(); + this._createActions(actions || []); if (this.constructor.pageAddress) { this.hasPageLink = true; @@ -17,14 +23,45 @@ var Pane = MVocabulary.inherit({ this._pageLink = this.constructor.pageAddress["+"](new Address([id.toString()])); } }, + "destructor": function() { + this._actions.destructor(); + if (this.hasPageLink) { + this._pageLink.destructor(); + } + + MVocabulary.fn.destructor.call(this); + }, + "_createActions": function(actions) { + for (var i = 0; i < actions.length; ++i) { + var action = actions[i]; + var actionVC = new Vocabulary(); + actionVC.insert("type", new Uint64(action.type)); + var supported = false; + + switch (action.type) { + case 0: //this type of actions has only action itself, no additional arguments, what to do is desctibed in the view + actionVC.insert("action", new String(action.action)); + supported = true; + break; + } + + if (supported) { + this._actions.push(actionVC); + } else { + actionVC.destructor(); + } + } + }, "_getAllData": function() { var vc = this.controller.data.clone(); vc.insert("hasPageLink", new Boolean(this.hasPageLink)); + vc.insert("actions", this._actions.clone()); if (this.hasPageLink) { vc.insert("pageLink", this._pageLink.clone()); } + return vc; } }); diff --git a/magnus/lib/wModel/proxy/panesList.js b/magnus/lib/wModel/proxy/panesList.js new file mode 100644 index 0000000..cda0f8a --- /dev/null +++ b/magnus/lib/wModel/proxy/panesList.js @@ -0,0 +1,66 @@ +"use strict"; + +var Vocabulary = require("../../wType/vocabulary"); +var Uint64 = require("../../wType/uint64"); +var String = require("../../wType/string"); +var Vector = require("../../wType/vector"); + +var Catalogue = require("./catalogue"); + +var PanesList = Catalogue.inherit({ + "className": "PanesList", + "constructor": function(address, ctrlAddr, ctrlOpts, socket, actions) { + Catalogue.fn.constructor.call(this, address, ctrlAddr, ctrlOpts, socket); + + this._actions = new Vector(); + this._createActions(actions || []); + }, + "destructor": function() { + this._actions.destructor(); + + Catalogue.fn.destructor.call(this); + }, + "_createActions": function(actions) { + for (var i = 0; i < actions.length; ++i) { + var action = actions[i]; + var actionVC = new Vocabulary(); + actionVC.insert("type", new Uint64(action.type)); + var supported = false; + + switch (action.type) { + case 0: //this type of actions has only action itself, no additional arguments, what to do is desctibed in the view + actionVC.insert("action", new String(action.action)); + supported = true; + break; + } + + if (supported) { + this._actions.push(actionVC); + } else { + actionVC.destructor(); + } + } + }, + "_h_get": function(ev) { + if (this.ready) { + var vc = new Vocabulary(); + + vc.insert("data", this._getAllData()); + vc.insert("actions", this._actions.clone()); + this.response(vc, "get", ev); + } else { + this._waitingEvents.push(ev.clone()); + } + }, + "_onRemoteData": function() { + this.setReady(true); + + var vc = new Vocabulary(); + vc.insert("data", this._getAllData()); + vc.insert("actions", this._actions.clone()); + + this.broadcast(vc, "get") + } +}); + +module.exports = PanesList; diff --git a/magnus/pages/album.js b/magnus/pages/album.js index 62146a5..cf36d4f 100644 --- a/magnus/pages/album.js +++ b/magnus/pages/album.js @@ -2,7 +2,7 @@ var TempPage = require("./tempPage"); var String = require("../lib/wModel/string"); -var ProxyCatModel = require("../lib/wModel/proxy/catalogue"); +var PanesList = require("../lib/wModel/proxy/panesList"); var PaneModel = require("../lib/wModel/proxy/pane"); var Image = require("../lib/wModel/image"); var Model = require("../lib/wModel/model"); @@ -41,16 +41,19 @@ var AlbumPage = TempPage.inherit({ var spacer = new Model(this._address["+"](new Address(["spacer"]))); this.addItem(spacer, 0, 2, 2, 1); - this._songs = new ProxyCatModel( + this._songs = new PanesList( this._address["+"](new Address(["songs"])), new Address(["songs"]), { sorting: {ascending: true, field: "name"}, filter: {album: id.clone()} }, - proxySocket + proxySocket, + [{ + type: 0, + action: "play" + }] ); - this._songs.className = "PanesList"; var PaneClass = PaneModel.Songs; this._songs.setChildrenClass(PaneClass); this.addItem(this._songs, 2, 0, 1, 3, TempPage.Aligment.CenterTop); diff --git a/magnus/pages/artist.js b/magnus/pages/artist.js index ef496c7..b87aab6 100644 --- a/magnus/pages/artist.js +++ b/magnus/pages/artist.js @@ -2,7 +2,7 @@ var TempPage = require("./tempPage"); var String = require("../lib/wModel/string"); -var ProxyCatModel = require("../lib/wModel/proxy/catalogue"); +var PanesList = require("../lib/wModel/proxy/panesList"); var PaneModel = require("../lib/wModel/proxy/pane"); var VCController = require("../lib/wController/vocabulary"); @@ -22,7 +22,7 @@ var ArtistPage = TempPage.inherit({ header.addProperty("fontFamily", "casualFont"); this.addItem(header, 0, 0, 1, 1, TempPage.Aligment.CenterTop); - this._albums = new ProxyCatModel( + this._albums = new PanesList( this._address["+"](new Address(["albums"])), new Address(["albums"]), { @@ -36,16 +36,19 @@ var ArtistPage = TempPage.inherit({ this._albums.setChildrenClass(PaneClass); this.addItem(this._albums, 1, 0, 1, 1, TempPage.Aligment.CenterTop); - this._songs = new ProxyCatModel( + this._songs = new PanesList( this._address["+"](new Address(["songs"])), new Address(["songs"]), { sorting: {ascending: true, field: "name"}, filter: {artist: id.clone()} }, - proxySocket + proxySocket, + [{ + type: 0, + action: "play" + }] ); - this._songs.className = "PanesList"; var PaneClass = PaneModel.Songs; this._songs.setChildrenClass(PaneClass); this.addItem(this._songs, 2, 0, 1, 1, TempPage.Aligment.CenterTop); diff --git a/magnus/pages/list.js b/magnus/pages/list.js index e4c91d9..1e494c5 100644 --- a/magnus/pages/list.js +++ b/magnus/pages/list.js @@ -2,42 +2,45 @@ var Page = require("../lib/wModel/page"); var String = require("../lib/wModel/string"); -var ProxyCatModel = require("../lib/wModel/proxy/catalogue"); +var PanesList = require("../lib/wModel/proxy/panesList"); var PaneModel = require("../lib/wModel/proxy/pane"); var Address = require("../lib/wType/address"); var Uint64 = require("../lib/wType/uint64"); +var Vocabulary = require("../lib/wType/vocabulary"); var Handler = require("../lib/wDispatcher/handler"); var List = Page.inherit({ "className": "ListPage", - "constructor": function(address, name, remoteAddress, socket, ChildClass) { + "constructor": function(address, name, remoteAddress, socket, ChildClass, listOptions, paneActions) { Page.fn.constructor.call(this, address, name); this._proxySocket = socket; this._ChildClass = ChildClass; + this._listOptions = listOptions || new Vocabulary() var header = new String(this._address["+"](new Address(["header"])), name); header.addProperty("fontFamily", "casualFont"); this.addItem(header, 0, 0, 1, 1, Page.Aligment.CenterTop); - this._list = new ProxyCatModel( + this._list = new PanesList( this._address["+"](new Address(["list"])), remoteAddress, { sorting: {ascending: true, field: "name"} }, - socket + socket, + paneActions ); - this._list.className = "PanesList"; var PaneClass = PaneModel[name]; if (!PaneClass) { PaneClass = PaneModel.inherit({}); PaneClass.pageAddress = address; + PaneModel[name] = PaneClass; } this._list.setChildrenClass(PaneClass); - this.addItem(this._list, 1, 0, 1, 1, Page.Aligment.CenterTop); + this.addItem(this._list, 1, 0, 1, 1, Page.Aligment.CenterTop, new Uint64(List.getModelTypeId(this._list)), listOptions); this._reporterHandler = new Handler(this._address["+"](new Address(["subscribeMember"])), this, this._h_subscribeMember); }, diff --git a/magnus/pages/music.js b/magnus/pages/music.js index 50296c4..ef49732 100644 --- a/magnus/pages/music.js +++ b/magnus/pages/music.js @@ -7,6 +7,7 @@ var PanesList = require("../lib/wModel/panesList"); var Address = require("../lib/wType/address"); var Vocabulary = require("../lib/wType/vocabulary"); var Boolean = require("../lib/wType/boolean"); +var Uint64 = require("../lib/wType/uint64"); var Link = require("../lib/wModel/link"); @@ -135,12 +136,19 @@ var MusicPage = Page.inherit({ this._albumsLink.label.addProperty("color", "primaryFontColor"); this._albumsLink.addProperty("backgroundColor", "primaryColor"); + var lOpts = new Vocabulary(); + lOpts.insert("nestWidth", new Uint64(300)); this._songs = new List( this._addresses.songs.local.clone(), "Songs", this._addresses.songs.remote.clone(), socket, - Song + Song, + lOpts, + [{ + type: 0, + action: "play" + }] ); this._songsLink = new Link(this._address["+"](new Address(["songsLink"])), "Songs", this._addresses.songs.local.clone()); this._songsLink.label.addProperty("fontSize", "largeFontSize"); From fd255bad0a797116b818b438b068b864bc3ddac9 Mon Sep 17 00:00:00 2001 From: blue Date: Thu, 29 Nov 2018 22:41:53 +0300 Subject: [PATCH 07/16] actually finally send an event to queue a song, tested, debugged --- corax/models/proxysong.cpp | 4 ++-- libjs/wController/imagePane.js | 17 ++++++++++++++--- lorgar/core/lorgar.js | 14 +++++++++++++- lorgar/views/button.js | 3 ++- lorgar/views/player.js | 8 ++++---- 5 files changed, 35 insertions(+), 11 deletions(-) diff --git a/corax/models/proxysong.cpp b/corax/models/proxysong.cpp index 8e742b8..64ba4ab 100644 --- a/corax/models/proxysong.cpp +++ b/corax/models/proxysong.cpp @@ -15,7 +15,7 @@ ProxySong::ProxySong(const W::Uint64& p_id, const W::Address& p_address, QObject insert(W::String(u"id"), p_id); insert(W::String(u"artist"), new W::String(u"undefined")); insert(W::String(u"album"), new W::String(u"undefined")); - insert(W::String(u"name"), new W::String(u"undefined")); + insert(W::String(u"song"), new W::String(u"undefined")); insert(W::String(u"image"), new W::Uint64(0)); } @@ -31,7 +31,7 @@ ProxySong::~ProxySong() void ProxySong::onSongNewElement(const W::String& key, const W::Object& element) { if (key == u"name") { - insert(key, element); + insert(W::String(u"song"), element); } else if (key == u"audio") { if (_ready) { _ready = false; diff --git a/libjs/wController/imagePane.js b/libjs/wController/imagePane.js index a421784..46f9f68 100644 --- a/libjs/wController/imagePane.js +++ b/libjs/wController/imagePane.js @@ -36,10 +36,10 @@ var ImagePane = Vocabulary.inherit({ this.trigger("seviceMessage", "Action " + act + " is not supported in ImagePanel, skipping"); supported = false; } - var model = new LM(""); + var model = new LM(actionProps, ""); model.enabled = true; model.hasLabel = true; - model.label = new LM(actObj.name); + model.label = new LM(actionLabelProps, actObj.name); model.addController(model.label); model.activate = this._actionActivate.bind(this, act); @@ -111,10 +111,21 @@ var ImagePane = Vocabulary.inherit({ var standardActions = { "play": { handler: function (obj) { - window.play(obj); + var id = obj._pairAddress.back(); //todo it's a kind of crutch, need to do something about it in the future + window.play(id); + id.destructor(); }, name: "Play" } }; +var actionProps = { + "backgroundColor": "primaryColor" +}; +var actionLabelProps = { + "fontFamily": "casualFont", + "fontSize": "casualFontSize", + "color": "primaryFontColor" +} + module.exports = ImagePane; diff --git a/lorgar/core/lorgar.js b/lorgar/core/lorgar.js index 801d0ca..d37c040 100644 --- a/lorgar/core/lorgar.js +++ b/lorgar/core/lorgar.js @@ -232,7 +232,17 @@ this._body.setSize(document.body.offsetWidth, document.body.offsetHeight); }, "play": function(id) { - console.log("Need to play " + id.toString()); + if (this._nodes.Corax && this._nodes.Corax.connected) { + var vc = new Vocabulary(); + vc.insert("id", id.clone()); + + var ev = new Event(this._playerCtl.getPairAddress()["+="](queue), vc); + + var socket = this._nodes.Corax.socket; + ev.setSenderId(socket.getId().clone()); + socket.send(ev); + ev.destructor(); + } }, "_prepareNode": function(name, address, port) { if (this._nodes[name]) { @@ -338,6 +348,8 @@ SocketState.add("connecting", {description: "Socket is connecting to remote host"}); SocketState.add("connected", {description: "Socket is connected"}); + var queue = new Address(["queue"]); + return Lorgar; }); })(); diff --git a/lorgar/views/button.js b/lorgar/views/button.js index 6e00151..d417da2 100644 --- a/lorgar/views/button.js +++ b/lorgar/views/button.js @@ -48,10 +48,11 @@ Layout.fn._onChildChangeLimits.call(this, child); }, - "_onClick": function() { + "_onClick": function(e) { if (this._enabled) { this._f.activate(); } + e.stopPropagation(); }, "_onSetEnabled": function(enabled) { if (this._enabled !== enabled) { diff --git a/lorgar/views/player.js b/lorgar/views/player.js index 2c7cbef..e98fe33 100644 --- a/lorgar/views/player.js +++ b/lorgar/views/player.js @@ -42,10 +42,10 @@ var song = new Label(this._infoModels.song); var spacer = new View(helper); - this.append(artist, 0, 2, 1, 1) - this.append(song, 1, 2, 1, 1) - this.append(album, 2, 2, 1, 1) - this.append(spacer, 0, 3, 3, 1); + this.append(artist, 0, 2, 1, 1, GridLayout.Aligment.LeftCenter); + this.append(song, 1, 2, 1, 1, GridLayout.Aligment.LeftCenter); + this.append(album, 2, 2, 1, 1, GridLayout.Aligment.LeftCenter); + this.append(spacer, 0, 3, 3, 1, GridLayout.Aligment.LeftCenter); this._uncyclic.push(this._infoModels.artist.destructor.bind(this._infoModels.artist)); this._uncyclic.push(this._infoModels.song.destructor.bind(this._infoModels.song)); From 2a4dce3616d3904dbda6de8dcbb40f1241b27224 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 2 Dec 2018 18:07:43 +0300 Subject: [PATCH 08/16] an image to player, first ideas to make a playback --- corax/models/player.cpp | 25 ++++++++++- corax/models/player.h | 9 +++- corax/models/proxysong.cpp | 3 ++ libjs/wController/CMakeLists.txt | 1 + libjs/wController/imageById.js | 46 ++++++++++++++++++++ libjs/wController/localModel.js | 44 +++++++++++++++++++ libjs/wController/player.js | 61 ++++++++++++++++++++++++--- lorgar/core/lorgar.js | 2 +- lorgar/lib/wController/CMakeLists.txt | 1 + lorgar/views/player.js | 10 +++++ 10 files changed, 192 insertions(+), 10 deletions(-) create mode 100644 libjs/wController/imageById.js diff --git a/corax/models/player.cpp b/corax/models/player.cpp index e9c8457..1f480e5 100644 --- a/corax/models/player.cpp +++ b/corax/models/player.cpp @@ -8,7 +8,9 @@ M::Player::Player(const W::Address& address, QObject* parent): _queueView(new M::List(address + W::Address{u"queueView"})), _queue(), current(0), - counter(0) + counter(0), + mode(playBack), + playing(false) { W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Player::_h_get); W::Handler* hqueue = W::Handler::create(address + W::Address({u"queue"}), this, &M::Player::_h_queue); @@ -83,13 +85,32 @@ void M::Player::h_get(const W::Event& ev) res->insert(u"controls", ctrls); res->insert(u"views", vws); + res->insert(u"mode", new W::Uint64(mode)); response(res, W::Address({u"get"}), ev); } void M::Player::onPlayPauseBtn() { - + if (playing) { + playPauseBtn->setLabel(W::String(u"Pause")); + playing = false; + + switch (mode) { + case playBack: + broadcast(new W::Vocabulary(), W::Address{u"pause"}); + break; + } + } else { + playPauseBtn->setLabel(W::String(u"Play")); + playing = true; + + switch (mode) { + case playBack: + broadcast(new W::Vocabulary(), W::Address{u"play"}); + break; + } + } } void M::Player::h_queue(const W::Event& ev) diff --git a/corax/models/player.h b/corax/models/player.h index b80109a..4265af9 100644 --- a/corax/models/player.h +++ b/corax/models/player.h @@ -31,7 +31,12 @@ namespace M { enum ItemType { playPause, currentPlayback, - queue + queue, + picture + }; + + enum Mode { + playBack }; protected: @@ -51,6 +56,8 @@ namespace M { Queue _queue; ProxySong* current; uint64_t counter; + Mode mode; + bool playing; private slots: void onPlayPauseBtn(); diff --git a/corax/models/proxysong.cpp b/corax/models/proxysong.cpp index 64ba4ab..d8d1377 100644 --- a/corax/models/proxysong.cpp +++ b/corax/models/proxysong.cpp @@ -17,6 +17,7 @@ ProxySong::ProxySong(const W::Uint64& p_id, const W::Address& p_address, QObject insert(W::String(u"album"), new W::String(u"undefined")); insert(W::String(u"song"), new W::String(u"undefined")); insert(W::String(u"image"), new W::Uint64(0)); + insert(W::String(u"audio"), new W::Uint64(0)); } bool ProxySong::isReady() const @@ -39,6 +40,7 @@ void ProxySong::onSongNewElement(const W::String& key, const W::Object& element) } fileId = static_cast(element); + insert(key, element); _ready = true; emit ready(); } else if (key == u"artist") { @@ -73,6 +75,7 @@ void ProxySong::onSongRemoveElement(const W::String& key) if (key == u"name") { insert(key, new W::String(u"undefined")); } else if (key == u"audio") { + insert(key, new W::Uint64(0)); if (_ready) { _ready = false; fileId = W::Uint64(0); diff --git a/libjs/wController/CMakeLists.txt b/libjs/wController/CMakeLists.txt index 7f30e50..8ecb88b 100644 --- a/libjs/wController/CMakeLists.txt +++ b/libjs/wController/CMakeLists.txt @@ -18,3 +18,4 @@ configure_file(catalogue.js catalogue.js) configure_file(imagePane.js imagePane.js) configure_file(file/file.js file/file.js) configure_file(player.js player.js) +configure_file(imageById.js imageById.js) diff --git a/libjs/wController/imageById.js b/libjs/wController/imageById.js new file mode 100644 index 0000000..54598af --- /dev/null +++ b/libjs/wController/imageById.js @@ -0,0 +1,46 @@ +"use strict"; + +var LocalModel = require("./localModel"); +var File = require("./file/file"); + +var Address = require("../wType/address"); + +var ImageById = LocalModel.inherit({ + className: "ImageById", + constructor: function(properties, id) { + LocalModel.fn.constructor.call(this, properties); + + this._imageId = id; + this._fileCtrl = new File(new Address(["images", this._imageId.toString()])); + this._need = 0; + + this._fileCtrl.on("data", this._onControllerData, this); + + this.addForeignController("Corax", this._fileCtrl); + }, + dontNeedData: function() { + --this._need; + if (this._need === 0) { + this._fileCtrl.dontNeedData(); + } + }, + getMimeType: function () { + return this._fileCtrl.getMimeType(); + }, + hasData: function() { + return this._fileCtrl.hasData(); + }, + needData: function() { + if (this._need === 0) { + this._fileCtrl.needData(); + } + ++this._need; + }, + _onControllerData: function() { + this.data = this._fileCtrl.data; + + this.trigger("data"); + } +}); + +module.exports = ImageById; diff --git a/libjs/wController/localModel.js b/libjs/wController/localModel.js index 3343a6f..b728c2a 100644 --- a/libjs/wController/localModel.js +++ b/libjs/wController/localModel.js @@ -1,6 +1,7 @@ "use strict"; var counter = 0; var Subscribable = require("../utils/subscribable"); +var Controller = require("./controller"); var LocalModel = Subscribable.inherit({ "className": "LocalModel", @@ -9,6 +10,7 @@ var LocalModel = Subscribable.inherit({ this.properties = []; this._controllers = []; + this._foreignControllers = []; if (properties) { for (var key in properties) { @@ -25,6 +27,14 @@ var LocalModel = Subscribable.inherit({ } }, "destructor": function() { + for (i = 0; i < this._foreignControllers.length; ++i) { + var pair = this._foreignControllers[i]; + global.unsubscribeForeignController(pair.n, pair.c); + global.registerForeignController(pair.n, pair.c); + + pair.c.destructor(); + } + for (var i = 0; i < this._controllers.length; ++i) { this._controllers[i].destructor(); } @@ -34,6 +44,40 @@ var LocalModel = Subscribable.inherit({ "addController": function(ctrl) { this._controllers.push(ctrl); }, + "addForeignController": function(nodeName, ctrl) { + if (!(ctrl instanceof Controller)) { + throw new Error("An attempt to add not a controller into " + this.className); + } + + this._foreignControllers.push({n: nodeName, c: ctrl}); + ctrl.on("serviceMessage", this._onControllerServiceMessage, this); + + global.registerForeignController(nodeName, ctrl); + global.subscribeForeignController(nodeName, ctrl); + }, + "_onControllerServiceMessage": Controller.fn._onControllerServiceMessage, + "removeForeignController": function(ctrl) { + if (!(ctrl instanceof Controller)) { + throw new Error("An attempt to remove not a controller from " + this.className); + } + for (var i = 0; i < this._foreignControllers.length; ++i) { + if (this._foreignControllers[i].c === ctrl) { + break; + } + } + + if (i === this._foreignControllers.length) { + throw new Error("An attempt to remove not not existing controller from " + this.className); + } else { + var pair = this._foreignControllers[i]; + global.unsubscribeForeignController(pair.n, pair.c); + global.registerForeignController(pair.n, pair.c); + + pair.c.off("serviceMessage", this._onControllerServiceMessage, this); + + this._foreignControllers.splice(i, 1); + } + }, "setData": function(data) { this.data = data; this.initialized = true; diff --git a/libjs/wController/player.js b/libjs/wController/player.js index c65d5ac..d7bea05 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -1,7 +1,11 @@ "use strict"; +var Uint64 = require("../wType/uint64"); +var Address = require("../wType/address"); + var Controller = require("./controller"); var Button = require("./button"); +var ImageById = require("./imageById"); var Vocabulary = require("./vocabulary"); var Enum = require("../utils/enum"); @@ -12,6 +16,7 @@ var Player = Controller.inherit({ this.controls = Object.create(null); this.views = Object.create(null); + this.mode = PlayerMode.straight.playback; this.addHandler("get"); this.addHandler("viewsChange"); @@ -41,6 +46,8 @@ var Player = Controller.inherit({ }, _addView: function(type, address) { var t = type.valueOf(); + var ctrl; + var supported = false; if (this.views[t] !== undefined) { throw new Error("An attempt to add multiple instances of " + ItemType.reversed[t] + " into Player"); @@ -52,11 +59,18 @@ var Player = Controller.inherit({ this.trigger("serviceMessage", "Queue is not supported yet in Player"); break; case ItemType.straight.currentPlayback: - var cpb = new Vocabulary(address.clone()); - cpb.ItemType = t; - this.views[t] = cpb; - this.addController(cpb); - this.trigger("newElement", cpb, t); + ctrl = new Vocabulary(address.clone()); + ctrl.on("newElement", this._onNewPlayBackElement, this); + ctrl.on("removeElement", this._onNewRemoveBackElement, this); + supported = true; + break; + case ItemType.straight.picture: + ctrl = new ImageById(null, address.back()); + ctrl.ItemType = t; + this.views[t] = ctrl; + + this.trigger("newElement", ctrl, t); + supported = false; //just to avoid adding with addController, since ImageById is not a controller break; default: this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to views of the Player, but it's not qualified to be a view"); @@ -64,12 +78,21 @@ var Player = Controller.inherit({ } else { this.trigger("serviceMessage", "An unrecgnized item ItemType in Player: " + t); } + + if (supported) { + ctrl.ItemType = t; + this.views[t] = ctrl; + this.addController(ctrl); + + this.trigger("newElement", ctrl, t); + } }, _h_get: function(ev) { var data = ev.getData(); var controls = data.at("controls"); var views = data.at("views"); + var mode = data.at("mode").valueOf(); var size, i, vc; size = controls.length(); @@ -84,6 +107,13 @@ var Player = Controller.inherit({ this._addView(vc.at("type"), vc.at("address")); } + if (this.mode !== mode) { + if (PlayerMode.reversed[mode] === undefined) { + throw new Error("Unsupported mode of player: " + mode); + } + this.mode = mode; + } + this.initialized = true; this.trigger("data"); }, @@ -105,19 +135,38 @@ var Player = Controller.inherit({ this._addView(vc.at("type"), vc.at("address")); } }, + _onNewPlayBackElement: function(key, element) { + switch (key) { + case "image": + var address = new Address(["images", element.toString()]); + this._addView(new Uint64(ItemType.straight.picture), address); + address.destructor(); + break; + } + }, + _onNewRemoveBackElement: function(key) { + switch (key) { + case "image": + this._removeView(new Uint64(ItemType.straight.picture)); + break; + } + }, _removeControl: function(type) { //TODO }, _removeView: function(type) { //TODO } - }); var ItemType = new Enum("ItemType"); ItemType.add("playPause"); ItemType.add("currentPlayback"); ItemType.add("queue"); +ItemType.add("picture"); + +var PlayerMode = new Enum("PlayerMode"); +PlayerMode.add("playback"); Player.ItemType = ItemType; diff --git a/lorgar/core/lorgar.js b/lorgar/core/lorgar.js index d37c040..be3b0af 100644 --- a/lorgar/core/lorgar.js +++ b/lorgar/core/lorgar.js @@ -211,7 +211,7 @@ if (this._playerCtl) { this._mainLayout.removePlayer(); this._playerCtl._onSocketDisconnected(); - this._playerCtl.uneregister(); + this._playerCtl.unregister(); this._playerCtl.destructor(); this._playerCtl = undefined; } diff --git a/lorgar/lib/wController/CMakeLists.txt b/lorgar/lib/wController/CMakeLists.txt index 01a0205..ad3451b 100644 --- a/lorgar/lib/wController/CMakeLists.txt +++ b/lorgar/lib/wController/CMakeLists.txt @@ -19,3 +19,4 @@ add_jslib(wController/file/file.js lib/wController/file/file ${LORGAR_DIR} brows 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/player.js lib/wController/player ${LORGAR_DIR} browser) +add_jslib(wController/imageById.js lib/wController/imageById ${LORGAR_DIR} browser) diff --git a/lorgar/views/player.js b/lorgar/views/player.js index e98fe33..4bb27a7 100644 --- a/lorgar/views/player.js +++ b/lorgar/views/player.js @@ -7,6 +7,7 @@ deps.push("views/button"); deps.push("views/label"); deps.push("views/view"); + deps.push("views/image"); deps.push("lib/wController/localModel"); @@ -17,6 +18,7 @@ var Button = require("views/button"); var Label = require("views/label"); var View = require("views/view"); + var Image = require("views/image"); var Model = require("lib/wController/localModel"); @@ -28,6 +30,7 @@ GridLayout.fn.constructor.call(this, ctrl, options); this._playPause = null; + this._picture = null; this._cpbCtrl = null; this._infoModels = { artist: new Model(null, "artist: unknown"), @@ -80,6 +83,13 @@ this._cpbCtrl.on("newElement", this._onCpbNewElement, this); this._cpbCtrl.on("removeElement", this._onCpbRemoveElement, this); break; + case ItemType.straight.picture: + this._picture = new Image(ctrl, { + maxWidth: 100, + maxHeight: 100 + }); + this.append(this._picture, 0, 0, 3, 1); + break; } }, _onCpbNewElement: function(key, value) { From 85a14b51015a7dd4a792f99b785eb3fdf5c96f4a Mon Sep 17 00:00:00 2001 From: blue Date: Mon, 17 Dec 2018 20:15:58 +0300 Subject: [PATCH 09/16] Barely working basic playback --- corax/models/player.cpp | 7 +- lib/wModel/CMakeLists.txt | 3 + lib/wModel/button.cpp | 2 +- lib/wModel/file/audio.cpp | 80 ++++++++++++++++ lib/wModel/file/audio.h | 36 +++++++ lib/wModel/file/file.cpp | 26 ++++- lib/wModel/file/file.h | 1 + lib/wModel/model.h | 1 + lib/wType/blob.cpp | 14 +++ lib/wType/blob.h | 2 + libjs/utils/CMakeLists.txt | 1 + libjs/utils/stateMachine.js | 33 +++++++ libjs/wController/CMakeLists.txt | 1 + libjs/wController/file/audio.js | 69 ++++++++++++++ libjs/wController/player.js | 132 ++++++++++++++++++++++++++ lorgar/lib/utils/CMakeLists.txt | 1 + lorgar/lib/wController/CMakeLists.txt | 1 + lorgar/views/button.js | 2 - lorgar/views/view.js | 18 +--- 19 files changed, 406 insertions(+), 24 deletions(-) create mode 100644 lib/wModel/file/audio.cpp create mode 100644 lib/wModel/file/audio.h create mode 100644 libjs/utils/stateMachine.js create mode 100644 libjs/wController/file/audio.js diff --git a/corax/models/player.cpp b/corax/models/player.cpp index 1f480e5..4c58204 100644 --- a/corax/models/player.cpp +++ b/corax/models/player.cpp @@ -4,7 +4,7 @@ M::Player::Player(const W::Address& address, QObject* parent): M::Model(address, parent), controls(), 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"})), _queue(), current(0), @@ -93,7 +93,7 @@ void M::Player::h_get(const W::Event& ev) void M::Player::onPlayPauseBtn() { if (playing) { - playPauseBtn->setLabel(W::String(u"Pause")); + playPauseBtn->setLabel(W::String(u"Play")); playing = false; switch (mode) { @@ -102,7 +102,7 @@ void M::Player::onPlayPauseBtn() break; } } else { - playPauseBtn->setLabel(W::String(u"Play")); + playPauseBtn->setLabel(W::String(u"Pause")); playing = true; switch (mode) { @@ -135,6 +135,7 @@ void M::Player::h_queue(const W::Event& ev) res->insert(u"remove", new W::Vector()); broadcast(res, W::Address{u"viewsChange"}); + playPauseBtn->setEnabled(true); } else { _queue.push_back(song); _queueView->push(song->getAddress()); diff --git a/lib/wModel/CMakeLists.txt b/lib/wModel/CMakeLists.txt index fb70a7b..cc83c8f 100644 --- a/lib/wModel/CMakeLists.txt +++ b/lib/wModel/CMakeLists.txt @@ -16,6 +16,7 @@ set(HEADERS catalogue.h button.h file/file.h + file/audio.h ) set(SOURCES @@ -28,6 +29,7 @@ set(SOURCES catalogue.cpp button.cpp file/file.cpp + file/audio.cpp ) 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 wType) target_link_libraries(wModel wController) +target_link_libraries(wModel mad) diff --git a/lib/wModel/button.cpp b/lib/wModel/button.cpp index 649f999..9f22ea4 100644 --- a/lib/wModel/button.cpp +++ b/lib/wModel/button.cpp @@ -52,7 +52,7 @@ void M::Button::setEnabled(bool p_enabled) enabled = p_enabled; if (registered) { 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"}); } } diff --git a/lib/wModel/file/audio.cpp b/lib/wModel/file/audio.cpp new file mode 100644 index 0000000..86fb0e1 --- /dev/null +++ b/lib/wModel/file/audio.cpp @@ -0,0 +1,80 @@ +#include "audio.h" + +#include + +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(ev.getData()); + const W::Uint64& index = static_cast(vc.at(u"index")); + const W::Uint64& amount = static_cast(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& 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); +} diff --git a/lib/wModel/file/audio.h b/lib/wModel/file/audio.h new file mode 100644 index 0000000..070e31c --- /dev/null +++ b/lib/wModel/file/audio.h @@ -0,0 +1,36 @@ +#ifndef M_AUDIO_H +#define M_AUDIO_H + +#include + +#include +#include + +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> frames; + }; + +} + +#endif // M_AUDIO_H diff --git a/lib/wModel/file/file.cpp b/lib/wModel/file/file.cpp index 083ec62..5efa9bd 100644 --- a/lib/wModel/file/file.cpp +++ b/lib/wModel/file/file.cpp @@ -1,7 +1,13 @@ #include "file.h" #include +#include "audio.h" + QMimeDatabase M::File::mimeDB; +const std::map 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::Model(addr, parent), @@ -79,8 +85,24 @@ M::File * M::File::create(W::Blob* blob, const W::Address& addr, QObject* parent M::File* out; 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::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; } diff --git a/lib/wModel/file/file.h b/lib/wModel/file/file.h index 7a3d79d..8c50440 100644 --- a/lib/wModel/file/file.h +++ b/lib/wModel/file/file.h @@ -38,6 +38,7 @@ namespace M { W::Blob* file; static QMimeDatabase mimeDB; + static const std::map mimeMap; }; } diff --git a/lib/wModel/model.h b/lib/wModel/model.h index c10b173..e7f9742 100644 --- a/lib/wModel/model.h +++ b/lib/wModel/model.h @@ -36,6 +36,7 @@ namespace M { attributes = 50, file, resourceCache, + audio, player = 107 }; diff --git a/lib/wType/blob.cpp b/lib/wType/blob.cpp index 02991c2..9c08382 100644 --- a/lib/wType/blob.cpp +++ b/lib/wType/blob.cpp @@ -144,3 +144,17 @@ const QByteArray & W::Blob::byteArray() const 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); +} diff --git a/lib/wType/blob.h b/lib/wType/blob.h index e8fdb55..8995974 100644 --- a/lib/wType/blob.h +++ b/lib/wType/blob.h @@ -22,6 +22,7 @@ namespace W size_type size() const override; objectType getType() const override; + Blob* slice(uint64_t start, uint64_t length = 0) const; bool operator==(const W::Object & other) const override; @@ -33,6 +34,7 @@ namespace W static const objectType type = blob; const QByteArray& byteArray() const; + const unsigned char* uchar() const; protected: bool hasData; diff --git a/libjs/utils/CMakeLists.txt b/libjs/utils/CMakeLists.txt index a0018e8..7ec6696 100644 --- a/libjs/utils/CMakeLists.txt +++ b/libjs/utils/CMakeLists.txt @@ -4,3 +4,4 @@ configure_file(class.js class.js) configure_file(subscribable.js subscribable.js) configure_file(globalMethods.js globalMethods.js) configure_file(enum.js enum.js) +configure_file(stateMachine.js stateMachine) diff --git a/libjs/utils/stateMachine.js b/libjs/utils/stateMachine.js new file mode 100644 index 0000000..b15f0cd --- /dev/null +++ b/libjs/utils/stateMachine.js @@ -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; diff --git a/libjs/wController/CMakeLists.txt b/libjs/wController/CMakeLists.txt index 8ecb88b..f51dfbb 100644 --- a/libjs/wController/CMakeLists.txt +++ b/libjs/wController/CMakeLists.txt @@ -17,5 +17,6 @@ configure_file(localModel.js localModel.js) configure_file(catalogue.js catalogue.js) configure_file(imagePane.js imagePane.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(imageById.js imageById.js) diff --git a/libjs/wController/file/audio.js b/libjs/wController/file/audio.js new file mode 100644 index 0000000..1b77cf3 --- /dev/null +++ b/libjs/wController/file/audio.js @@ -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; diff --git a/libjs/wController/player.js b/libjs/wController/player.js index d7bea05..32021bf 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -7,7 +7,10 @@ var Controller = require("./controller"); var Button = require("./button"); var ImageById = require("./imageById"); var Vocabulary = require("./vocabulary"); +var Audio = require("./file/audio"); + var Enum = require("../utils/enum"); +var StateMachine = require("../utils/stateMachine"); var Player = Controller.inherit({ className: "Player", @@ -17,9 +20,24 @@ var Player = Controller.inherit({ this.controls = Object.create(null); this.views = Object.create(null); 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("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) { var t = type.valueOf(); @@ -87,6 +105,10 @@ var Player = Controller.inherit({ 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) { var data = ev.getData(); @@ -117,6 +139,12 @@ var Player = Controller.inherit({ this.initialized = true; this.trigger("data"); }, + _h_pause: function(ev) { + this._fsm.manipulation("plause"); + }, + _h_play: function(ev) { + this._fsm.manipulation("play"); + }, _h_viewsChange: function(ev) { var data = ev.getData(); @@ -135,6 +163,15 @@ var Player = Controller.inherit({ 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) { switch (key) { case "image": @@ -142,6 +179,14 @@ var Player = Controller.inherit({ this._addView(new Uint64(ItemType.straight.picture), address); address.destructor(); 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) { @@ -149,6 +194,51 @@ var Player = Controller.inherit({ case "image": this._removeView(new Uint64(ItemType.straight.picture)); 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) { @@ -156,6 +246,14 @@ var Player = Controller.inherit({ }, _removeView: function(type) { //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; +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; diff --git a/lorgar/lib/utils/CMakeLists.txt b/lorgar/lib/utils/CMakeLists.txt index fc6a3f2..c988215 100644 --- a/lorgar/lib/utils/CMakeLists.txt +++ b/lorgar/lib/utils/CMakeLists.txt @@ -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/globalMethods.js lib/utils/globalMethods ${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) diff --git a/lorgar/lib/wController/CMakeLists.txt b/lorgar/lib/wController/CMakeLists.txt index ad3451b..7ed96b3 100644 --- a/lorgar/lib/wController/CMakeLists.txt +++ b/lorgar/lib/wController/CMakeLists.txt @@ -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/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/audio.js lib/wController/file/audio ${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/player.js lib/wController/player ${LORGAR_DIR} browser) diff --git a/lorgar/views/button.js b/lorgar/views/button.js index d417da2..05bb72a 100644 --- a/lorgar/views/button.js +++ b/lorgar/views/button.js @@ -58,10 +58,8 @@ if (this._enabled !== enabled) { this._enabled = enabled; if (this._enabled) { - this.addClass("hoverable"); this.removeClass("disabled"); } else { - this.removeClass("hoverable"); this.addClass("disabled"); } } diff --git a/lorgar/views/view.js b/lorgar/views/view.js index 70a624c..8016b1f 100644 --- a/lorgar/views/view.js +++ b/lorgar/views/view.js @@ -78,11 +78,7 @@ Subscribable.fn.destructor.call(this); }, "addClass": function(className) { - var arr = this._e.className.split(" "); - if (arr.indexOf(className) === -1) { - arr.push(className); - this._e.className = arr.join(" "); - } + this._e.classList.add(className); }, "_applyProperties": function() { for (var i = 0; i < this._f.properties.length; ++i) { @@ -141,17 +137,7 @@ } }, "removeClass": function(className) { - var arr = this._e.className.split(" "); - 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(" "); - } + this._e.classList.remove(className); }, "_resetTheme": function() { this._onClearProperties(); From 7fdcb657a4d560d811656b83bad282b3b735c350 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 22 Dec 2018 00:21:12 +0300 Subject: [PATCH 10/16] handled audio playback with aurora library --- lib/wModel/file/audio.cpp | 16 +- libjs/wController/file/audio.js | 29 +- libjs/wController/player.js | 41 +- libjs/wController/vocabulary.js | 2 +- lorgar/index.html | 2 +- lorgar/lib/CMakeLists.txt | 2 + lorgar/lib/aurora/CMakeLists.txt | 3 + lorgar/lib/aurora/aurora.js | 3938 ++++++++++++++ lorgar/lib/bintrees/CMakeLists.txt | 2 +- lorgar/lib/mp3/CMakeLists.txt | 3 + lorgar/lib/mp3/mp3.js | 7706 ++++++++++++++++++++++++++++ lorgar/main.js | 7 + test/CMakeLists.txt | 1 + 13 files changed, 11711 insertions(+), 41 deletions(-) create mode 100644 lorgar/lib/aurora/CMakeLists.txt create mode 100644 lorgar/lib/aurora/aurora.js create mode 100644 lorgar/lib/mp3/CMakeLists.txt create mode 100644 lorgar/lib/mp3/mp3.js diff --git a/lib/wModel/file/audio.cpp b/lib/wModel/file/audio.cpp index 86fb0e1..6a0987f 100644 --- a/lib/wModel/file/audio.cpp +++ b/lib/wModel/file/audio.cpp @@ -59,21 +59,13 @@ void M::Audio::h_requestFrames(const W::Event& ev) 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; + W::Vector* vframes = new W::Vector(); for (int i = 0; i < amount; ++i) { - const std::pair& pair = frames[index + i]; - if (first) { - start = pair.first; - first = false; - } - size += pair.second; + const std::pair& pair = frames[index + i]; //TODO optimize? + vframes->push(file->slice(pair.first, pair.second)); } - evc->insert(u"data", file->slice(start, size)); - evc->insert(u"amount", new W::Uint64(amount)); - + evc->insert(u"frames", vframes); } response(evc, W::Address{u"responseFrames"}, ev); diff --git a/libjs/wController/file/audio.js b/libjs/wController/file/audio.js index 1b77cf3..17c6951 100644 --- a/libjs/wController/file/audio.js +++ b/libjs/wController/file/audio.js @@ -2,6 +2,7 @@ var File = require("./file"); var Vocabulary = require("../../wType/vocabulary"); +var Vector = require("../../wType/vector"); var Uint64 = require("../../wType/uint64"); var Audio = File.inherit({ @@ -12,10 +13,15 @@ var Audio = File.inherit({ this._loadedFrames = 0; this._totalFrames = 0; this._waitingForFrames = false; - this._portions = []; + this._frames = new Vector(); this.addHandler("responseFrames"); }, + destructor: function() { + this._frames.destructor(); + + File.fn.destructor.call(this); + }, hasMore: function() { return this._totalFrames > this._loadedFrames; }, @@ -37,12 +43,25 @@ var Audio = File.inherit({ var success = data.at("result").valueOf(); if (success === 0) { - var amount = data.at("amount").valueOf(); - var blob = data.at("data").clone(); + 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._portions.push(blob); - this.trigger("newFrames", blob); + this.trigger("newFrames", buffer); } } }, diff --git a/libjs/wController/player.js b/libjs/wController/player.js index 32021bf..bae734a 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -12,6 +12,12 @@ var Audio = require("./file/audio"); var Enum = require("../utils/enum"); 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({ className: "Player", constructor: function(addr) { @@ -21,11 +27,11 @@ var Player = Controller.inherit({ this.views = Object.create(null); this.mode = PlayerMode.straight.playback; this._audio = null; - this._sound = new window.Audio(); - this._ctx = new AudioContext(); - this._currentTime = 0; + this._source = new Source(); + this._asset = new AV.Asset(this._source); + this._player = new AV.Player(this._asset); + this._player.play(); this._createStateMachine(); - this._proxySchedule = this._schedule.bind(this); this.addHandler("get"); this.addHandler("viewsChange"); @@ -34,8 +40,7 @@ var Player = Controller.inherit({ }, destructor: function() { this._fsm.destructor(); - this._sound.pause(); - this._ctx.close(); + this._player.stop(); Controller.fn.destructor.call(this); }, @@ -140,7 +145,7 @@ var Player = Controller.inherit({ this.trigger("data"); }, _h_pause: function(ev) { - this._fsm.manipulation("plause"); + this._fsm.manipulation("pause"); }, _h_play: function(ev) { this._fsm.manipulation("play"); @@ -164,7 +169,9 @@ var Player = Controller.inherit({ } }, _onAudioNewFrames: function(frames) { - this._ctx.decodeAudioData(frames.valueOf(), this._proxySchedule); + var data = new Uint8Array(frames); + this._source.emit("data", new AV.Buffer(data)); + this._fsm.manipulation("newFrames"); if (this._audio.hasMore()) { this._audio.requestMore(); @@ -218,24 +225,24 @@ var Player = Controller.inherit({ case "paused": switch (e.oldState) { case "playing": - this._sound.pause(); + this._player.pause(); break; } break; case "pausedAllLoaded": switch (e.oldState) { case "playingAllLoaded": - this._sound.pause(); + this._player.pause(); break; } break; case "playing": - this._sound.play(); + this._player.play(); break; case "playingAllLoaded": switch (e.oldState) { case "pausedAllLoaded": - this._sound.play(); + this._player.play(); break; } break; @@ -246,14 +253,6 @@ var Player = Controller.inherit({ }, _removeView: function(type) { //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; } }); @@ -294,7 +293,7 @@ graphs[PlayerMode.straight.playback] = { play: "playingAllLoaded" }, "playing": { - pause: "pause", + pause: "paused", noMoreFrames: "playingAllLoaded" }, "playingAllLoaded": { diff --git a/libjs/wController/vocabulary.js b/libjs/wController/vocabulary.js index 9905909..afe4379 100644 --- a/libjs/wController/vocabulary.js +++ b/libjs/wController/vocabulary.js @@ -45,7 +45,7 @@ var Vocabulary = Controller.inherit({ var keys = insert.getKeys(); for (var j = 0; j < keys.length; ++j) { - key = keys[i]; + key = keys[j]; this.addElement(key, insert.at(key).clone()); } this.trigger("change", data.clone()); diff --git a/lorgar/index.html b/lorgar/index.html index 7b5c210..bef6be6 100644 --- a/lorgar/index.html +++ b/lorgar/index.html @@ -10,4 +10,4 @@

I am

- \ No newline at end of file + diff --git a/lorgar/lib/CMakeLists.txt b/lorgar/lib/CMakeLists.txt index b10b75c..41d77e0 100644 --- a/lorgar/lib/CMakeLists.txt +++ b/lorgar/lib/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 2.8.12) add_subdirectory(requirejs) add_subdirectory(wSocket) add_subdirectory(bintrees) +add_subdirectory(mp3) +add_subdirectory(aurora) add_subdirectory(wContainer) add_subdirectory(utils) add_subdirectory(wType) diff --git a/lorgar/lib/aurora/CMakeLists.txt b/lorgar/lib/aurora/CMakeLists.txt new file mode 100644 index 0000000..b286c2e --- /dev/null +++ b/lorgar/lib/aurora/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12) + +configure_file(aurora.js aurora.js) diff --git a/lorgar/lib/aurora/aurora.js b/lorgar/lib/aurora/aurora.js new file mode 100644 index 0000000..fd356b2 --- /dev/null +++ b/lorgar/lib/aurora/aurora.js @@ -0,0 +1,3938 @@ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.AV=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o> 3); + return this.bitPosition = pos & 7; + }; + + Bitstream.prototype.rewind = function(bits) { + var pos; + pos = this.bitPosition - bits; + this.stream.rewind(Math.abs(pos >> 3)); + return this.bitPosition = pos & 7; + }; + + Bitstream.prototype.seek = function(offset) { + var curOffset; + curOffset = this.offset(); + if (offset > curOffset) { + return this.advance(offset - curOffset); + } else if (offset < curOffset) { + return this.rewind(curOffset - offset); + } + }; + + Bitstream.prototype.align = function() { + if (this.bitPosition !== 0) { + this.bitPosition = 0; + return this.stream.advance(1); + } + }; + + Bitstream.prototype.read = function(bits, signed) { + var a, a0, a1, a2, a3, a4, mBits; + if (bits === 0) { + return 0; + } + mBits = bits + this.bitPosition; + if (mBits <= 8) { + a = ((this.stream.peekUInt8() << this.bitPosition) & 0xff) >>> (8 - bits); + } else if (mBits <= 16) { + a = ((this.stream.peekUInt16() << this.bitPosition) & 0xffff) >>> (16 - bits); + } else if (mBits <= 24) { + a = ((this.stream.peekUInt24() << this.bitPosition) & 0xffffff) >>> (24 - bits); + } else if (mBits <= 32) { + a = (this.stream.peekUInt32() << this.bitPosition) >>> (32 - bits); + } else if (mBits <= 40) { + a0 = this.stream.peekUInt8(0) * 0x0100000000; + a1 = this.stream.peekUInt8(1) << 24 >>> 0; + a2 = this.stream.peekUInt8(2) << 16; + a3 = this.stream.peekUInt8(3) << 8; + a4 = this.stream.peekUInt8(4); + a = a0 + a1 + a2 + a3 + a4; + a %= Math.pow(2, 40 - this.bitPosition); + a = Math.floor(a / Math.pow(2, 40 - this.bitPosition - bits)); + } else { + throw new Error("Too many bits!"); + } + if (signed) { + if (mBits < 32) { + if (a >>> (bits - 1)) { + a = ((1 << bits >>> 0) - a) * -1; + } + } else { + if (a / Math.pow(2, bits - 1) | 0) { + a = (Math.pow(2, bits) - a) * -1; + } + } + } + this.advance(bits); + return a; + }; + + Bitstream.prototype.peek = function(bits, signed) { + var a, a0, a1, a2, a3, a4, mBits; + if (bits === 0) { + return 0; + } + mBits = bits + this.bitPosition; + if (mBits <= 8) { + a = ((this.stream.peekUInt8() << this.bitPosition) & 0xff) >>> (8 - bits); + } else if (mBits <= 16) { + a = ((this.stream.peekUInt16() << this.bitPosition) & 0xffff) >>> (16 - bits); + } else if (mBits <= 24) { + a = ((this.stream.peekUInt24() << this.bitPosition) & 0xffffff) >>> (24 - bits); + } else if (mBits <= 32) { + a = (this.stream.peekUInt32() << this.bitPosition) >>> (32 - bits); + } else if (mBits <= 40) { + a0 = this.stream.peekUInt8(0) * 0x0100000000; + a1 = this.stream.peekUInt8(1) << 24 >>> 0; + a2 = this.stream.peekUInt8(2) << 16; + a3 = this.stream.peekUInt8(3) << 8; + a4 = this.stream.peekUInt8(4); + a = a0 + a1 + a2 + a3 + a4; + a %= Math.pow(2, 40 - this.bitPosition); + a = Math.floor(a / Math.pow(2, 40 - this.bitPosition - bits)); + } else { + throw new Error("Too many bits!"); + } + if (signed) { + if (mBits < 32) { + if (a >>> (bits - 1)) { + a = ((1 << bits >>> 0) - a) * -1; + } + } else { + if (a / Math.pow(2, bits - 1) | 0) { + a = (Math.pow(2, bits) - a) * -1; + } + } + } + return a; + }; + + Bitstream.prototype.readLSB = function(bits, signed) { + var a, mBits; + if (bits === 0) { + return 0; + } + if (bits > 40) { + throw new Error("Too many bits!"); + } + mBits = bits + this.bitPosition; + a = (this.stream.peekUInt8(0)) >>> this.bitPosition; + if (mBits > 8) { + a |= (this.stream.peekUInt8(1)) << (8 - this.bitPosition); + } + if (mBits > 16) { + a |= (this.stream.peekUInt8(2)) << (16 - this.bitPosition); + } + if (mBits > 24) { + a += (this.stream.peekUInt8(3)) << (24 - this.bitPosition) >>> 0; + } + if (mBits > 32) { + a += (this.stream.peekUInt8(4)) * Math.pow(2, 32 - this.bitPosition); + } + if (mBits >= 32) { + a %= Math.pow(2, bits); + } else { + a &= (1 << bits) - 1; + } + if (signed) { + if (mBits < 32) { + if (a >>> (bits - 1)) { + a = ((1 << bits >>> 0) - a) * -1; + } + } else { + if (a / Math.pow(2, bits - 1) | 0) { + a = (Math.pow(2, bits) - a) * -1; + } + } + } + this.advance(bits); + return a; + }; + + Bitstream.prototype.peekLSB = function(bits, signed) { + var a, mBits; + if (bits === 0) { + return 0; + } + if (bits > 40) { + throw new Error("Too many bits!"); + } + mBits = bits + this.bitPosition; + a = (this.stream.peekUInt8(0)) >>> this.bitPosition; + if (mBits > 8) { + a |= (this.stream.peekUInt8(1)) << (8 - this.bitPosition); + } + if (mBits > 16) { + a |= (this.stream.peekUInt8(2)) << (16 - this.bitPosition); + } + if (mBits > 24) { + a += (this.stream.peekUInt8(3)) << (24 - this.bitPosition) >>> 0; + } + if (mBits > 32) { + a += (this.stream.peekUInt8(4)) * Math.pow(2, 32 - this.bitPosition); + } + if (mBits >= 32) { + a %= Math.pow(2, bits); + } else { + a &= (1 << bits) - 1; + } + if (signed) { + if (mBits < 32) { + if (a >>> (bits - 1)) { + a = ((1 << bits >>> 0) - a) * -1; + } + } else { + if (a / Math.pow(2, bits - 1) | 0) { + a = (Math.pow(2, bits) - a) * -1; + } + } + } + return a; + }; + + return Bitstream; + +})(); + +module.exports = Bitstream; + + +},{}],7:[function(_dereq_,module,exports){ +(function (global){ +var AVBuffer; + +AVBuffer = (function() { + var BlobBuilder, URL; + + function AVBuffer(input) { + var _ref; + if (input instanceof Uint8Array) { + this.data = input; + } else if (input instanceof ArrayBuffer || Array.isArray(input) || typeof input === 'number' || ((_ref = global.Buffer) != null ? _ref.isBuffer(input) : void 0)) { + this.data = new Uint8Array(input); + } else if (input.buffer instanceof ArrayBuffer) { + this.data = new Uint8Array(input.buffer, input.byteOffset, input.length * input.BYTES_PER_ELEMENT); + } else if (input instanceof AVBuffer) { + this.data = input.data; + } else { + throw new Error("Constructing buffer with unknown type."); + } + this.length = this.data.length; + this.next = null; + this.prev = null; + } + + AVBuffer.allocate = function(size) { + return new AVBuffer(size); + }; + + AVBuffer.prototype.copy = function() { + return new AVBuffer(new Uint8Array(this.data)); + }; + + AVBuffer.prototype.slice = function(position, length) { + if (length == null) { + length = this.length; + } + if (position === 0 && length >= this.length) { + return new AVBuffer(this.data); + } else { + return new AVBuffer(this.data.subarray(position, position + length)); + } + }; + + BlobBuilder = global.BlobBuilder || global.MozBlobBuilder || global.WebKitBlobBuilder; + + URL = global.URL || global.webkitURL || global.mozURL; + + AVBuffer.makeBlob = function(data, type) { + var bb; + if (type == null) { + type = 'application/octet-stream'; + } + try { + return new Blob([data], { + type: type + }); + } catch (_error) {} + if (BlobBuilder != null) { + bb = new BlobBuilder; + bb.append(data); + return bb.getBlob(type); + } + return null; + }; + + AVBuffer.makeBlobURL = function(data, type) { + return URL != null ? URL.createObjectURL(this.makeBlob(data, type)) : void 0; + }; + + AVBuffer.revokeBlobURL = function(url) { + return URL != null ? URL.revokeObjectURL(url) : void 0; + }; + + AVBuffer.prototype.toBlob = function() { + return AVBuffer.makeBlob(this.data.buffer); + }; + + AVBuffer.prototype.toBlobURL = function() { + return AVBuffer.makeBlobURL(this.data.buffer); + }; + + return AVBuffer; + +})(); + +module.exports = AVBuffer; + + +}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],8:[function(_dereq_,module,exports){ +var BufferList; + +BufferList = (function() { + function BufferList() { + this.first = null; + this.last = null; + this.numBuffers = 0; + this.availableBytes = 0; + this.availableBuffers = 0; + } + + BufferList.prototype.copy = function() { + var result; + result = new BufferList; + result.first = this.first; + result.last = this.last; + result.numBuffers = this.numBuffers; + result.availableBytes = this.availableBytes; + result.availableBuffers = this.availableBuffers; + return result; + }; + + BufferList.prototype.append = function(buffer) { + var _ref; + buffer.prev = this.last; + if ((_ref = this.last) != null) { + _ref.next = buffer; + } + this.last = buffer; + if (this.first == null) { + this.first = buffer; + } + this.availableBytes += buffer.length; + this.availableBuffers++; + return this.numBuffers++; + }; + + BufferList.prototype.advance = function() { + if (this.first) { + this.availableBytes -= this.first.length; + this.availableBuffers--; + this.first = this.first.next; + return this.first != null; + } + return false; + }; + + BufferList.prototype.rewind = function() { + var _ref; + if (this.first && !this.first.prev) { + return false; + } + this.first = ((_ref = this.first) != null ? _ref.prev : void 0) || this.last; + if (this.first) { + this.availableBytes += this.first.length; + this.availableBuffers++; + } + return this.first != null; + }; + + BufferList.prototype.reset = function() { + var _results; + _results = []; + while (this.rewind()) { + continue; + } + return _results; + }; + + return BufferList; + +})(); + +module.exports = BufferList; + + +},{}],9:[function(_dereq_,module,exports){ +var Base, EventEmitter, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + __slice = [].slice; + +Base = _dereq_('./base'); + +EventEmitter = (function(_super) { + __extends(EventEmitter, _super); + + function EventEmitter() { + return EventEmitter.__super__.constructor.apply(this, arguments); + } + + EventEmitter.prototype.on = function(event, fn) { + var _base; + if (this.events == null) { + this.events = {}; + } + if ((_base = this.events)[event] == null) { + _base[event] = []; + } + return this.events[event].push(fn); + }; + + EventEmitter.prototype.off = function(event, fn) { + var index, _ref; + if (!((_ref = this.events) != null ? _ref[event] : void 0)) { + return; + } + index = this.events[event].indexOf(fn); + if (~index) { + return this.events[event].splice(index, 1); + } + }; + + EventEmitter.prototype.once = function(event, fn) { + var cb; + return this.on(event, cb = function() { + this.off(event, cb); + return fn.apply(this, arguments); + }); + }; + + EventEmitter.prototype.emit = function() { + var args, event, fn, _i, _len, _ref, _ref1; + event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + if (!((_ref = this.events) != null ? _ref[event] : void 0)) { + return; + } + _ref1 = this.events[event].slice(); + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + fn = _ref1[_i]; + fn.apply(this, args); + } + }; + + return EventEmitter; + +})(Base); + +module.exports = EventEmitter; + + +},{"./base":5}],10:[function(_dereq_,module,exports){ +var AVBuffer, BufferList, Stream, UnderflowError; + +BufferList = _dereq_('./bufferlist'); + +AVBuffer = _dereq_('./buffer'); + +UnderflowError = _dereq_('./underflow'); + +Stream = (function() { + var buf, decodeString, float32, float64, float64Fallback, float80, int16, int32, int8, nativeEndian, uint16, uint32, uint8; + + buf = new ArrayBuffer(16); + + uint8 = new Uint8Array(buf); + + int8 = new Int8Array(buf); + + uint16 = new Uint16Array(buf); + + int16 = new Int16Array(buf); + + uint32 = new Uint32Array(buf); + + int32 = new Int32Array(buf); + + float32 = new Float32Array(buf); + + if (typeof Float64Array !== "undefined" && Float64Array !== null) { + float64 = new Float64Array(buf); + } + + nativeEndian = new Uint16Array(new Uint8Array([0x12, 0x34]).buffer)[0] === 0x3412; + + function Stream(list) { + this.list = list; + this.localOffset = 0; + this.offset = 0; + } + + Stream.fromBuffer = function(buffer) { + var list; + list = new BufferList; + list.append(buffer); + return new Stream(list); + }; + + Stream.prototype.copy = function() { + var result; + result = new Stream(this.list.copy()); + result.localOffset = this.localOffset; + result.offset = this.offset; + return result; + }; + + Stream.prototype.available = function(bytes) { + return bytes <= this.list.availableBytes - this.localOffset; + }; + + Stream.prototype.remainingBytes = function() { + return this.list.availableBytes - this.localOffset; + }; + + Stream.prototype.advance = function(bytes) { + if (!this.available(bytes)) { + throw new UnderflowError(); + } + this.localOffset += bytes; + this.offset += bytes; + while (this.list.first && this.localOffset >= this.list.first.length) { + this.localOffset -= this.list.first.length; + this.list.advance(); + } + return this; + }; + + Stream.prototype.rewind = function(bytes) { + if (bytes > this.offset) { + throw new UnderflowError(); + } + if (!this.list.first) { + this.list.rewind(); + this.localOffset = this.list.first.length; + } + this.localOffset -= bytes; + this.offset -= bytes; + while (this.list.first.prev && this.localOffset < 0) { + this.list.rewind(); + this.localOffset += this.list.first.length; + } + return this; + }; + + Stream.prototype.seek = function(position) { + if (position > this.offset) { + return this.advance(position - this.offset); + } else if (position < this.offset) { + return this.rewind(this.offset - position); + } + }; + + Stream.prototype.readUInt8 = function() { + var a; + if (!this.available(1)) { + throw new UnderflowError(); + } + a = this.list.first.data[this.localOffset]; + this.localOffset += 1; + this.offset += 1; + if (this.localOffset === this.list.first.length) { + this.localOffset = 0; + this.list.advance(); + } + return a; + }; + + Stream.prototype.peekUInt8 = function(offset) { + var buffer; + if (offset == null) { + offset = 0; + } + if (!this.available(offset + 1)) { + throw new UnderflowError(); + } + offset = this.localOffset + offset; + buffer = this.list.first; + while (buffer) { + if (buffer.length > offset) { + return buffer.data[offset]; + } + offset -= buffer.length; + buffer = buffer.next; + } + return 0; + }; + + Stream.prototype.read = function(bytes, littleEndian) { + var i, _i, _j, _ref; + if (littleEndian == null) { + littleEndian = false; + } + if (littleEndian === nativeEndian) { + for (i = _i = 0; _i < bytes; i = _i += 1) { + uint8[i] = this.readUInt8(); + } + } else { + for (i = _j = _ref = bytes - 1; _j >= 0; i = _j += -1) { + uint8[i] = this.readUInt8(); + } + } + }; + + Stream.prototype.peek = function(bytes, offset, littleEndian) { + var i, _i, _j; + if (littleEndian == null) { + littleEndian = false; + } + if (littleEndian === nativeEndian) { + for (i = _i = 0; _i < bytes; i = _i += 1) { + uint8[i] = this.peekUInt8(offset + i); + } + } else { + for (i = _j = 0; _j < bytes; i = _j += 1) { + uint8[bytes - i - 1] = this.peekUInt8(offset + i); + } + } + }; + + Stream.prototype.readInt8 = function() { + this.read(1); + return int8[0]; + }; + + Stream.prototype.peekInt8 = function(offset) { + if (offset == null) { + offset = 0; + } + this.peek(1, offset); + return int8[0]; + }; + + Stream.prototype.readUInt16 = function(littleEndian) { + this.read(2, littleEndian); + return uint16[0]; + }; + + Stream.prototype.peekUInt16 = function(offset, littleEndian) { + if (offset == null) { + offset = 0; + } + this.peek(2, offset, littleEndian); + return uint16[0]; + }; + + Stream.prototype.readInt16 = function(littleEndian) { + this.read(2, littleEndian); + return int16[0]; + }; + + Stream.prototype.peekInt16 = function(offset, littleEndian) { + if (offset == null) { + offset = 0; + } + this.peek(2, offset, littleEndian); + return int16[0]; + }; + + Stream.prototype.readUInt24 = function(littleEndian) { + if (littleEndian) { + return this.readUInt16(true) + (this.readUInt8() << 16); + } else { + return (this.readUInt16() << 8) + this.readUInt8(); + } + }; + + Stream.prototype.peekUInt24 = function(offset, littleEndian) { + if (offset == null) { + offset = 0; + } + if (littleEndian) { + return this.peekUInt16(offset, true) + (this.peekUInt8(offset + 2) << 16); + } else { + return (this.peekUInt16(offset) << 8) + this.peekUInt8(offset + 2); + } + }; + + Stream.prototype.readInt24 = function(littleEndian) { + if (littleEndian) { + return this.readUInt16(true) + (this.readInt8() << 16); + } else { + return (this.readInt16() << 8) + this.readUInt8(); + } + }; + + Stream.prototype.peekInt24 = function(offset, littleEndian) { + if (offset == null) { + offset = 0; + } + if (littleEndian) { + return this.peekUInt16(offset, true) + (this.peekInt8(offset + 2) << 16); + } else { + return (this.peekInt16(offset) << 8) + this.peekUInt8(offset + 2); + } + }; + + Stream.prototype.readUInt32 = function(littleEndian) { + this.read(4, littleEndian); + return uint32[0]; + }; + + Stream.prototype.peekUInt32 = function(offset, littleEndian) { + if (offset == null) { + offset = 0; + } + this.peek(4, offset, littleEndian); + return uint32[0]; + }; + + Stream.prototype.readInt32 = function(littleEndian) { + this.read(4, littleEndian); + return int32[0]; + }; + + Stream.prototype.peekInt32 = function(offset, littleEndian) { + if (offset == null) { + offset = 0; + } + this.peek(4, offset, littleEndian); + return int32[0]; + }; + + Stream.prototype.readFloat32 = function(littleEndian) { + this.read(4, littleEndian); + return float32[0]; + }; + + Stream.prototype.peekFloat32 = function(offset, littleEndian) { + if (offset == null) { + offset = 0; + } + this.peek(4, offset, littleEndian); + return float32[0]; + }; + + Stream.prototype.readFloat64 = function(littleEndian) { + this.read(8, littleEndian); + if (float64) { + return float64[0]; + } else { + return float64Fallback(); + } + }; + + float64Fallback = function() { + var exp, frac, high, low, out, sign; + low = uint32[0], high = uint32[1]; + if (!high || high === 0x80000000) { + return 0.0; + } + sign = 1 - (high >>> 31) * 2; + exp = (high >>> 20) & 0x7ff; + frac = high & 0xfffff; + if (exp === 0x7ff) { + if (frac) { + return NaN; + } + return sign * Infinity; + } + exp -= 1023; + out = (frac | 0x100000) * Math.pow(2, exp - 20); + out += low * Math.pow(2, exp - 52); + return sign * out; + }; + + Stream.prototype.peekFloat64 = function(offset, littleEndian) { + if (offset == null) { + offset = 0; + } + this.peek(8, offset, littleEndian); + if (float64) { + return float64[0]; + } else { + return float64Fallback(); + } + }; + + Stream.prototype.readFloat80 = function(littleEndian) { + this.read(10, littleEndian); + return float80(); + }; + + float80 = function() { + var a0, a1, exp, high, low, out, sign; + high = uint32[0], low = uint32[1]; + a0 = uint8[9]; + a1 = uint8[8]; + sign = 1 - (a0 >>> 7) * 2; + exp = ((a0 & 0x7F) << 8) | a1; + if (exp === 0 && low === 0 && high === 0) { + return 0; + } + if (exp === 0x7fff) { + if (low === 0 && high === 0) { + return sign * Infinity; + } + return NaN; + } + exp -= 16383; + out = low * Math.pow(2, exp - 31); + out += high * Math.pow(2, exp - 63); + return sign * out; + }; + + Stream.prototype.peekFloat80 = function(offset, littleEndian) { + if (offset == null) { + offset = 0; + } + this.peek(10, offset, littleEndian); + return float80(); + }; + + Stream.prototype.readBuffer = function(length) { + var i, result, to, _i; + result = AVBuffer.allocate(length); + to = result.data; + for (i = _i = 0; _i < length; i = _i += 1) { + to[i] = this.readUInt8(); + } + return result; + }; + + Stream.prototype.peekBuffer = function(offset, length) { + var i, result, to, _i; + if (offset == null) { + offset = 0; + } + result = AVBuffer.allocate(length); + to = result.data; + for (i = _i = 0; _i < length; i = _i += 1) { + to[i] = this.peekUInt8(offset + i); + } + return result; + }; + + Stream.prototype.readSingleBuffer = function(length) { + var result; + result = this.list.first.slice(this.localOffset, length); + this.advance(result.length); + return result; + }; + + Stream.prototype.peekSingleBuffer = function(offset, length) { + var result; + result = this.list.first.slice(this.localOffset + offset, length); + return result; + }; + + Stream.prototype.readString = function(length, encoding) { + if (encoding == null) { + encoding = 'ascii'; + } + return decodeString.call(this, 0, length, encoding, true); + }; + + Stream.prototype.peekString = function(offset, length, encoding) { + if (offset == null) { + offset = 0; + } + if (encoding == null) { + encoding = 'ascii'; + } + return decodeString.call(this, offset, length, encoding, false); + }; + + decodeString = function(offset, length, encoding, advance) { + var b1, b2, b3, b4, bom, c, end, littleEndian, nullEnd, pt, result, w1, w2; + encoding = encoding.toLowerCase(); + nullEnd = length === null ? 0 : -1; + if (length == null) { + length = Infinity; + } + end = offset + length; + result = ''; + switch (encoding) { + case 'ascii': + case 'latin1': + while (offset < end && (c = this.peekUInt8(offset++)) !== nullEnd) { + result += String.fromCharCode(c); + } + break; + case 'utf8': + case 'utf-8': + while (offset < end && (b1 = this.peekUInt8(offset++)) !== nullEnd) { + if ((b1 & 0x80) === 0) { + result += String.fromCharCode(b1); + } else if ((b1 & 0xe0) === 0xc0) { + b2 = this.peekUInt8(offset++) & 0x3f; + result += String.fromCharCode(((b1 & 0x1f) << 6) | b2); + } else if ((b1 & 0xf0) === 0xe0) { + b2 = this.peekUInt8(offset++) & 0x3f; + b3 = this.peekUInt8(offset++) & 0x3f; + result += String.fromCharCode(((b1 & 0x0f) << 12) | (b2 << 6) | b3); + } else if ((b1 & 0xf8) === 0xf0) { + b2 = this.peekUInt8(offset++) & 0x3f; + b3 = this.peekUInt8(offset++) & 0x3f; + b4 = this.peekUInt8(offset++) & 0x3f; + pt = (((b1 & 0x0f) << 18) | (b2 << 12) | (b3 << 6) | b4) - 0x10000; + result += String.fromCharCode(0xd800 + (pt >> 10), 0xdc00 + (pt & 0x3ff)); + } + } + break; + case 'utf16-be': + case 'utf16be': + case 'utf16le': + case 'utf16-le': + case 'utf16bom': + case 'utf16-bom': + switch (encoding) { + case 'utf16be': + case 'utf16-be': + littleEndian = false; + break; + case 'utf16le': + case 'utf16-le': + littleEndian = true; + break; + case 'utf16bom': + case 'utf16-bom': + if (length < 2 || (bom = this.peekUInt16(offset)) === nullEnd) { + if (advance) { + this.advance(offset += 2); + } + return result; + } + littleEndian = bom === 0xfffe; + offset += 2; + } + while (offset < end && (w1 = this.peekUInt16(offset, littleEndian)) !== nullEnd) { + offset += 2; + if (w1 < 0xd800 || w1 > 0xdfff) { + result += String.fromCharCode(w1); + } else { + if (w1 > 0xdbff) { + throw new Error("Invalid utf16 sequence."); + } + w2 = this.peekUInt16(offset, littleEndian); + if (w2 < 0xdc00 || w2 > 0xdfff) { + throw new Error("Invalid utf16 sequence."); + } + result += String.fromCharCode(w1, w2); + offset += 2; + } + } + if (w1 === nullEnd) { + offset += 2; + } + break; + default: + throw new Error("Unknown encoding: " + encoding); + } + if (advance) { + this.advance(offset); + } + return result; + }; + + return Stream; + +})(); + +module.exports = Stream; + + +},{"./buffer":7,"./bufferlist":8,"./underflow":11}],11:[function(_dereq_,module,exports){ +var UnderflowError, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +UnderflowError = (function(_super) { + __extends(UnderflowError, _super); + + function UnderflowError() { + UnderflowError.__super__.constructor.apply(this, arguments); + this.name = 'UnderflowError'; + this.stack = new Error().stack; + } + + return UnderflowError; + +})(Error); + +module.exports = UnderflowError; + + +},{}],12:[function(_dereq_,module,exports){ +var Bitstream, BufferList, Decoder, EventEmitter, Stream, UnderflowError, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('./core/events'); + +BufferList = _dereq_('./core/bufferlist'); + +Stream = _dereq_('./core/stream'); + +Bitstream = _dereq_('./core/bitstream'); + +UnderflowError = _dereq_('./core/underflow'); + +Decoder = (function(_super) { + var codecs; + + __extends(Decoder, _super); + + function Decoder(demuxer, format) { + var list; + this.demuxer = demuxer; + this.format = format; + list = new BufferList; + this.stream = new Stream(list); + this.bitstream = new Bitstream(this.stream); + this.receivedFinalBuffer = false; + this.waiting = false; + this.demuxer.on('cookie', (function(_this) { + return function(cookie) { + var error; + try { + return _this.setCookie(cookie); + } catch (_error) { + error = _error; + return _this.emit('error', error); + } + }; + })(this)); + this.demuxer.on('data', (function(_this) { + return function(chunk) { + list.append(chunk); + if (_this.waiting) { + return _this.decode(); + } + }; + })(this)); + this.demuxer.on('end', (function(_this) { + return function() { + _this.receivedFinalBuffer = true; + if (_this.waiting) { + return _this.decode(); + } + }; + })(this)); + this.init(); + } + + Decoder.prototype.init = function() {}; + + Decoder.prototype.setCookie = function(cookie) {}; + + Decoder.prototype.readChunk = function() {}; + + Decoder.prototype.decode = function() { + var error, offset, packet; + this.waiting = false; + offset = this.bitstream.offset(); + try { + packet = this.readChunk(); + } catch (_error) { + error = _error; + if (!(error instanceof UnderflowError)) { + this.emit('error', error); + return false; + } + } + if (packet) { + this.emit('data', packet); + return true; + } else if (!this.receivedFinalBuffer) { + this.bitstream.seek(offset); + this.waiting = true; + } else { + this.emit('end'); + } + return false; + }; + + Decoder.prototype.seek = function(timestamp) { + var seekPoint; + seekPoint = this.demuxer.seek(timestamp); + this.stream.seek(seekPoint.offset); + return seekPoint.timestamp; + }; + + codecs = {}; + + Decoder.register = function(id, decoder) { + return codecs[id] = decoder; + }; + + Decoder.find = function(id) { + return codecs[id] || null; + }; + + return Decoder; + +})(EventEmitter); + +module.exports = Decoder; + + +},{"./core/bitstream":6,"./core/bufferlist":8,"./core/events":9,"./core/stream":10,"./core/underflow":11}],13:[function(_dereq_,module,exports){ +var Decoder, LPCMDecoder, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +Decoder = _dereq_('../decoder'); + +LPCMDecoder = (function(_super) { + __extends(LPCMDecoder, _super); + + function LPCMDecoder() { + this.readChunk = __bind(this.readChunk, this); + return LPCMDecoder.__super__.constructor.apply(this, arguments); + } + + Decoder.register('lpcm', LPCMDecoder); + + LPCMDecoder.prototype.readChunk = function() { + var chunkSize, i, littleEndian, output, samples, stream, _i, _j, _k, _l, _m, _n; + stream = this.stream; + littleEndian = this.format.littleEndian; + chunkSize = Math.min(4096, stream.remainingBytes()); + samples = chunkSize / (this.format.bitsPerChannel / 8) | 0; + if (chunkSize < this.format.bitsPerChannel / 8) { + return null; + } + if (this.format.floatingPoint) { + switch (this.format.bitsPerChannel) { + case 32: + output = new Float32Array(samples); + for (i = _i = 0; _i < samples; i = _i += 1) { + output[i] = stream.readFloat32(littleEndian); + } + break; + case 64: + output = new Float64Array(samples); + for (i = _j = 0; _j < samples; i = _j += 1) { + output[i] = stream.readFloat64(littleEndian); + } + break; + default: + throw new Error('Unsupported bit depth.'); + } + } else { + switch (this.format.bitsPerChannel) { + case 8: + output = new Int8Array(samples); + for (i = _k = 0; _k < samples; i = _k += 1) { + output[i] = stream.readInt8(); + } + break; + case 16: + output = new Int16Array(samples); + for (i = _l = 0; _l < samples; i = _l += 1) { + output[i] = stream.readInt16(littleEndian); + } + break; + case 24: + output = new Int32Array(samples); + for (i = _m = 0; _m < samples; i = _m += 1) { + output[i] = stream.readInt24(littleEndian); + } + break; + case 32: + output = new Int32Array(samples); + for (i = _n = 0; _n < samples; i = _n += 1) { + output[i] = stream.readInt32(littleEndian); + } + break; + default: + throw new Error('Unsupported bit depth.'); + } + } + return output; + }; + + return LPCMDecoder; + +})(Decoder); + + +},{"../decoder":12}],14:[function(_dereq_,module,exports){ +var Decoder, XLAWDecoder, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +Decoder = _dereq_('../decoder'); + +XLAWDecoder = (function(_super) { + var BIAS, QUANT_MASK, SEG_MASK, SEG_SHIFT, SIGN_BIT; + + __extends(XLAWDecoder, _super); + + function XLAWDecoder() { + this.readChunk = __bind(this.readChunk, this); + return XLAWDecoder.__super__.constructor.apply(this, arguments); + } + + Decoder.register('ulaw', XLAWDecoder); + + Decoder.register('alaw', XLAWDecoder); + + SIGN_BIT = 0x80; + + QUANT_MASK = 0xf; + + SEG_SHIFT = 4; + + SEG_MASK = 0x70; + + BIAS = 0x84; + + XLAWDecoder.prototype.init = function() { + var i, seg, t, table, val, _i, _j; + this.format.bitsPerChannel = 16; + this.table = table = new Int16Array(256); + if (this.format.formatID === 'ulaw') { + for (i = _i = 0; _i < 256; i = ++_i) { + val = ~i; + t = ((val & QUANT_MASK) << 3) + BIAS; + t <<= (val & SEG_MASK) >>> SEG_SHIFT; + table[i] = val & SIGN_BIT ? BIAS - t : t - BIAS; + } + } else { + for (i = _j = 0; _j < 256; i = ++_j) { + val = i ^ 0x55; + t = val & QUANT_MASK; + seg = (val & SEG_MASK) >>> SEG_SHIFT; + if (seg) { + t = (t + t + 1 + 32) << (seg + 2); + } else { + t = (t + t + 1) << 3; + } + table[i] = val & SIGN_BIT ? t : -t; + } + } + }; + + XLAWDecoder.prototype.readChunk = function() { + var i, output, samples, stream, table, _i; + stream = this.stream, table = this.table; + samples = Math.min(4096, this.stream.remainingBytes()); + if (samples === 0) { + return; + } + output = new Int16Array(samples); + for (i = _i = 0; _i < samples; i = _i += 1) { + output[i] = table[stream.readUInt8()]; + } + return output; + }; + + return XLAWDecoder; + +})(Decoder); + + +},{"../decoder":12}],15:[function(_dereq_,module,exports){ +var BufferList, Demuxer, EventEmitter, Stream, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('./core/events'); + +BufferList = _dereq_('./core/bufferlist'); + +Stream = _dereq_('./core/stream'); + +Demuxer = (function(_super) { + var formats; + + __extends(Demuxer, _super); + + Demuxer.probe = function(buffer) { + return false; + }; + + function Demuxer(source, chunk) { + var list, received; + list = new BufferList; + list.append(chunk); + this.stream = new Stream(list); + received = false; + source.on('data', (function(_this) { + return function(chunk) { + received = true; + list.append(chunk); + return _this.readChunk(chunk); + }; + })(this)); + source.on('error', (function(_this) { + return function(err) { + return _this.emit('error', err); + }; + })(this)); + source.on('end', (function(_this) { + return function() { + if (!received) { + _this.readChunk(chunk); + } + return _this.emit('end'); + }; + })(this)); + this.seekPoints = []; + this.init(); + } + + Demuxer.prototype.init = function() {}; + + Demuxer.prototype.readChunk = function(chunk) {}; + + Demuxer.prototype.addSeekPoint = function(offset, timestamp) { + var index; + index = this.searchTimestamp(timestamp); + return this.seekPoints.splice(index, 0, { + offset: offset, + timestamp: timestamp + }); + }; + + Demuxer.prototype.searchTimestamp = function(timestamp, backward) { + var high, low, mid, time; + low = 0; + high = this.seekPoints.length; + if (high > 0 && this.seekPoints[high - 1].timestamp < timestamp) { + return high; + } + while (low < high) { + mid = (low + high) >> 1; + time = this.seekPoints[mid].timestamp; + if (time < timestamp) { + low = mid + 1; + } else if (time >= timestamp) { + high = mid; + } + } + if (high > this.seekPoints.length) { + high = this.seekPoints.length; + } + return high; + }; + + Demuxer.prototype.seek = function(timestamp) { + var index, seekPoint; + if (this.format && this.format.framesPerPacket > 0 && this.format.bytesPerPacket > 0) { + seekPoint = { + timestamp: timestamp, + offset: this.format.bytesPerPacket * timestamp / this.format.framesPerPacket + }; + return seekPoint; + } else { + index = this.searchTimestamp(timestamp); + return this.seekPoints[index]; + } + }; + + formats = []; + + Demuxer.register = function(demuxer) { + return formats.push(demuxer); + }; + + Demuxer.find = function(buffer) { + var e, format, offset, stream, _i, _len; + stream = Stream.fromBuffer(buffer); + for (_i = 0, _len = formats.length; _i < _len; _i++) { + format = formats[_i]; + offset = stream.offset; + try { + if (format.probe(stream)) { + return format; + } + } catch (_error) { + e = _error; + } + stream.seek(offset); + } + return null; + }; + + return Demuxer; + +})(EventEmitter); + +module.exports = Demuxer; + + +},{"./core/bufferlist":8,"./core/events":9,"./core/stream":10}],16:[function(_dereq_,module,exports){ +var AIFFDemuxer, Demuxer, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +Demuxer = _dereq_('../demuxer'); + +AIFFDemuxer = (function(_super) { + __extends(AIFFDemuxer, _super); + + function AIFFDemuxer() { + return AIFFDemuxer.__super__.constructor.apply(this, arguments); + } + + Demuxer.register(AIFFDemuxer); + + AIFFDemuxer.probe = function(buffer) { + var _ref; + return buffer.peekString(0, 4) === 'FORM' && ((_ref = buffer.peekString(8, 4)) === 'AIFF' || _ref === 'AIFC'); + }; + + AIFFDemuxer.prototype.readChunk = function() { + var buffer, format, offset, _ref; + if (!this.readStart && this.stream.available(12)) { + if (this.stream.readString(4) !== 'FORM') { + return this.emit('error', 'Invalid AIFF.'); + } + this.fileSize = this.stream.readUInt32(); + this.fileType = this.stream.readString(4); + this.readStart = true; + if ((_ref = this.fileType) !== 'AIFF' && _ref !== 'AIFC') { + return this.emit('error', 'Invalid AIFF.'); + } + } + while (this.stream.available(1)) { + if (!this.readHeaders && this.stream.available(8)) { + this.type = this.stream.readString(4); + this.len = this.stream.readUInt32(); + } + switch (this.type) { + case 'COMM': + if (!this.stream.available(this.len)) { + return; + } + this.format = { + formatID: 'lpcm', + channelsPerFrame: this.stream.readUInt16(), + sampleCount: this.stream.readUInt32(), + bitsPerChannel: this.stream.readUInt16(), + sampleRate: this.stream.readFloat80(), + framesPerPacket: 1, + littleEndian: false, + floatingPoint: false + }; + this.format.bytesPerPacket = (this.format.bitsPerChannel / 8) * this.format.channelsPerFrame; + if (this.fileType === 'AIFC') { + format = this.stream.readString(4); + this.format.littleEndian = format === 'sowt' && this.format.bitsPerChannel > 8; + this.format.floatingPoint = format === 'fl32' || format === 'fl64'; + if (format === 'twos' || format === 'sowt' || format === 'fl32' || format === 'fl64' || format === 'NONE') { + format = 'lpcm'; + } + this.format.formatID = format; + this.len -= 4; + } + this.stream.advance(this.len - 18); + this.emit('format', this.format); + this.emit('duration', this.format.sampleCount / this.format.sampleRate * 1000 | 0); + break; + case 'SSND': + if (!(this.readSSNDHeader && this.stream.available(4))) { + offset = this.stream.readUInt32(); + this.stream.advance(4); + this.stream.advance(offset); + this.readSSNDHeader = true; + } + buffer = this.stream.readSingleBuffer(this.len); + this.len -= buffer.length; + this.readHeaders = this.len > 0; + this.emit('data', buffer); + break; + default: + if (!this.stream.available(this.len)) { + return; + } + this.stream.advance(this.len); + } + if (this.type !== 'SSND') { + this.readHeaders = false; + } + } + }; + + return AIFFDemuxer; + +})(Demuxer); + + +},{"../demuxer":15}],17:[function(_dereq_,module,exports){ +var AUDemuxer, Demuxer, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +Demuxer = _dereq_('../demuxer'); + +AUDemuxer = (function(_super) { + var bps, formats; + + __extends(AUDemuxer, _super); + + function AUDemuxer() { + return AUDemuxer.__super__.constructor.apply(this, arguments); + } + + Demuxer.register(AUDemuxer); + + AUDemuxer.probe = function(buffer) { + return buffer.peekString(0, 4) === '.snd'; + }; + + bps = [8, 8, 16, 24, 32, 32, 64]; + + bps[26] = 8; + + formats = { + 1: 'ulaw', + 27: 'alaw' + }; + + AUDemuxer.prototype.readChunk = function() { + var bytes, dataSize, encoding, size; + if (!this.readHeader && this.stream.available(24)) { + if (this.stream.readString(4) !== '.snd') { + return this.emit('error', 'Invalid AU file.'); + } + size = this.stream.readUInt32(); + dataSize = this.stream.readUInt32(); + encoding = this.stream.readUInt32(); + this.format = { + formatID: formats[encoding] || 'lpcm', + littleEndian: false, + floatingPoint: encoding === 6 || encoding === 7, + bitsPerChannel: bps[encoding - 1], + sampleRate: this.stream.readUInt32(), + channelsPerFrame: this.stream.readUInt32(), + framesPerPacket: 1 + }; + if (this.format.bitsPerChannel == null) { + return this.emit('error', 'Unsupported encoding in AU file.'); + } + this.format.bytesPerPacket = (this.format.bitsPerChannel / 8) * this.format.channelsPerFrame; + if (dataSize !== 0xffffffff) { + bytes = this.format.bitsPerChannel / 8; + this.emit('duration', dataSize / bytes / this.format.channelsPerFrame / this.format.sampleRate * 1000 | 0); + } + this.emit('format', this.format); + this.readHeader = true; + } + if (this.readHeader) { + while (this.stream.available(1)) { + this.emit('data', this.stream.readSingleBuffer(this.stream.remainingBytes())); + } + } + }; + + return AUDemuxer; + +})(Demuxer); + + +},{"../demuxer":15}],18:[function(_dereq_,module,exports){ +var CAFDemuxer, Demuxer, M4ADemuxer, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +Demuxer = _dereq_('../demuxer'); + +M4ADemuxer = _dereq_('./m4a'); + +CAFDemuxer = (function(_super) { + __extends(CAFDemuxer, _super); + + function CAFDemuxer() { + return CAFDemuxer.__super__.constructor.apply(this, arguments); + } + + Demuxer.register(CAFDemuxer); + + CAFDemuxer.probe = function(buffer) { + return buffer.peekString(0, 4) === 'caff'; + }; + + CAFDemuxer.prototype.readChunk = function() { + var buffer, byteOffset, cookie, entries, flags, i, key, metadata, offset, sampleOffset, value, _i, _j, _ref; + if (!this.format && this.stream.available(64)) { + if (this.stream.readString(4) !== 'caff') { + return this.emit('error', "Invalid CAF, does not begin with 'caff'"); + } + this.stream.advance(4); + if (this.stream.readString(4) !== 'desc') { + return this.emit('error', "Invalid CAF, 'caff' is not followed by 'desc'"); + } + if (!(this.stream.readUInt32() === 0 && this.stream.readUInt32() === 32)) { + return this.emit('error', "Invalid 'desc' size, should be 32"); + } + this.format = {}; + this.format.sampleRate = this.stream.readFloat64(); + this.format.formatID = this.stream.readString(4); + flags = this.stream.readUInt32(); + if (this.format.formatID === 'lpcm') { + this.format.floatingPoint = Boolean(flags & 1); + this.format.littleEndian = Boolean(flags & 2); + } + this.format.bytesPerPacket = this.stream.readUInt32(); + this.format.framesPerPacket = this.stream.readUInt32(); + this.format.channelsPerFrame = this.stream.readUInt32(); + this.format.bitsPerChannel = this.stream.readUInt32(); + this.emit('format', this.format); + } + while (this.stream.available(1)) { + if (!this.headerCache) { + this.headerCache = { + type: this.stream.readString(4), + oversize: this.stream.readUInt32() !== 0, + size: this.stream.readUInt32() + }; + if (this.headerCache.oversize) { + return this.emit('error', "Holy Shit, an oversized file, not supported in JS"); + } + } + switch (this.headerCache.type) { + case 'kuki': + if (this.stream.available(this.headerCache.size)) { + if (this.format.formatID === 'aac ') { + offset = this.stream.offset + this.headerCache.size; + if (cookie = M4ADemuxer.readEsds(this.stream)) { + this.emit('cookie', cookie); + } + this.stream.seek(offset); + } else { + buffer = this.stream.readBuffer(this.headerCache.size); + this.emit('cookie', buffer); + } + this.headerCache = null; + } + break; + case 'pakt': + if (this.stream.available(this.headerCache.size)) { + if (this.stream.readUInt32() !== 0) { + return this.emit('error', 'Sizes greater than 32 bits are not supported.'); + } + this.numPackets = this.stream.readUInt32(); + if (this.stream.readUInt32() !== 0) { + return this.emit('error', 'Sizes greater than 32 bits are not supported.'); + } + this.numFrames = this.stream.readUInt32(); + this.primingFrames = this.stream.readUInt32(); + this.remainderFrames = this.stream.readUInt32(); + this.emit('duration', this.numFrames / this.format.sampleRate * 1000 | 0); + this.sentDuration = true; + byteOffset = 0; + sampleOffset = 0; + for (i = _i = 0, _ref = this.numPackets; _i < _ref; i = _i += 1) { + this.addSeekPoint(byteOffset, sampleOffset); + byteOffset += this.format.bytesPerPacket || M4ADemuxer.readDescrLen(this.stream); + sampleOffset += this.format.framesPerPacket || M4ADemuxer.readDescrLen(this.stream); + } + this.headerCache = null; + } + break; + case 'info': + entries = this.stream.readUInt32(); + metadata = {}; + for (i = _j = 0; 0 <= entries ? _j < entries : _j > entries; i = 0 <= entries ? ++_j : --_j) { + key = this.stream.readString(null); + value = this.stream.readString(null); + metadata[key] = value; + } + this.emit('metadata', metadata); + this.headerCache = null; + break; + case 'data': + if (!this.sentFirstDataChunk) { + this.stream.advance(4); + this.headerCache.size -= 4; + if (this.format.bytesPerPacket !== 0 && !this.sentDuration) { + this.numFrames = this.headerCache.size / this.format.bytesPerPacket; + this.emit('duration', this.numFrames / this.format.sampleRate * 1000 | 0); + } + this.sentFirstDataChunk = true; + } + buffer = this.stream.readSingleBuffer(this.headerCache.size); + this.headerCache.size -= buffer.length; + this.emit('data', buffer); + if (this.headerCache.size <= 0) { + this.headerCache = null; + } + break; + default: + if (this.stream.available(this.headerCache.size)) { + this.stream.advance(this.headerCache.size); + this.headerCache = null; + } + } + } + }; + + return CAFDemuxer; + +})(Demuxer); + + +},{"../demuxer":15,"./m4a":19}],19:[function(_dereq_,module,exports){ +var Demuxer, M4ADemuxer, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +Demuxer = _dereq_('../demuxer'); + +M4ADemuxer = (function(_super) { + var BITS_PER_CHANNEL, TYPES, after, atom, atoms, bool, containers, diskTrack, genres, meta, string; + + __extends(M4ADemuxer, _super); + + function M4ADemuxer() { + return M4ADemuxer.__super__.constructor.apply(this, arguments); + } + + Demuxer.register(M4ADemuxer); + + TYPES = ['M4A ', 'M4P ', 'M4B ', 'M4V ', 'isom', 'mp42', 'qt ']; + + M4ADemuxer.probe = function(buffer) { + var _ref; + return buffer.peekString(4, 4) === 'ftyp' && (_ref = buffer.peekString(8, 4), __indexOf.call(TYPES, _ref) >= 0); + }; + + M4ADemuxer.prototype.init = function() { + this.atoms = []; + this.offsets = []; + this.track = null; + return this.tracks = []; + }; + + atoms = {}; + + containers = {}; + + atom = function(name, fn) { + var c, container, _i, _len, _ref; + c = []; + _ref = name.split('.').slice(0, -1); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + container = _ref[_i]; + c.push(container); + containers[c.join('.')] = true; + } + if (atoms[name] == null) { + atoms[name] = {}; + } + return atoms[name].fn = fn; + }; + + after = function(name, fn) { + if (atoms[name] == null) { + atoms[name] = {}; + } + return atoms[name].after = fn; + }; + + M4ADemuxer.prototype.readChunk = function() { + var handler, path, type; + this["break"] = false; + while (this.stream.available(1) && !this["break"]) { + if (!this.readHeaders) { + if (!this.stream.available(8)) { + return; + } + this.len = this.stream.readUInt32() - 8; + this.type = this.stream.readString(4); + if (this.len === 0) { + continue; + } + this.atoms.push(this.type); + this.offsets.push(this.stream.offset + this.len); + this.readHeaders = true; + } + path = this.atoms.join('.'); + handler = atoms[path]; + if (handler != null ? handler.fn : void 0) { + if (!(this.stream.available(this.len) || path === 'mdat')) { + return; + } + handler.fn.call(this); + if (path in containers) { + this.readHeaders = false; + } + } else if (path in containers) { + this.readHeaders = false; + } else { + if (!this.stream.available(this.len)) { + return; + } + this.stream.advance(this.len); + } + while (this.stream.offset >= this.offsets[this.offsets.length - 1]) { + handler = atoms[this.atoms.join('.')]; + if (handler != null ? handler.after : void 0) { + handler.after.call(this); + } + type = this.atoms.pop(); + this.offsets.pop(); + this.readHeaders = false; + } + } + }; + + atom('ftyp', function() { + var _ref; + if (_ref = this.stream.readString(4), __indexOf.call(TYPES, _ref) < 0) { + return this.emit('error', 'Not a valid M4A file.'); + } + return this.stream.advance(this.len - 4); + }); + + atom('moov.trak', function() { + this.track = {}; + return this.tracks.push(this.track); + }); + + atom('moov.trak.tkhd', function() { + this.stream.advance(4); + this.stream.advance(8); + this.track.id = this.stream.readUInt32(); + return this.stream.advance(this.len - 16); + }); + + atom('moov.trak.mdia.hdlr', function() { + this.stream.advance(4); + this.stream.advance(4); + this.track.type = this.stream.readString(4); + this.stream.advance(12); + return this.stream.advance(this.len - 24); + }); + + atom('moov.trak.mdia.mdhd', function() { + this.stream.advance(4); + this.stream.advance(8); + this.track.timeScale = this.stream.readUInt32(); + this.track.duration = this.stream.readUInt32(); + return this.stream.advance(4); + }); + + BITS_PER_CHANNEL = { + ulaw: 8, + alaw: 8, + in24: 24, + in32: 32, + fl32: 32, + fl64: 64 + }; + + atom('moov.trak.mdia.minf.stbl.stsd', function() { + var format, numEntries, version, _ref, _ref1; + this.stream.advance(4); + numEntries = this.stream.readUInt32(); + if (this.track.type !== 'soun') { + return this.stream.advance(this.len - 8); + } + if (numEntries !== 1) { + return this.emit('error', "Only expecting one entry in sample description atom!"); + } + this.stream.advance(4); + format = this.track.format = {}; + format.formatID = this.stream.readString(4); + this.stream.advance(6); + this.stream.advance(2); + version = this.stream.readUInt16(); + this.stream.advance(6); + format.channelsPerFrame = this.stream.readUInt16(); + format.bitsPerChannel = this.stream.readUInt16(); + this.stream.advance(4); + format.sampleRate = this.stream.readUInt16(); + this.stream.advance(2); + if (version === 1) { + format.framesPerPacket = this.stream.readUInt32(); + this.stream.advance(4); + format.bytesPerFrame = this.stream.readUInt32(); + this.stream.advance(4); + } else if (version !== 0) { + this.emit('error', 'Unknown version in stsd atom'); + } + if (BITS_PER_CHANNEL[format.formatID] != null) { + format.bitsPerChannel = BITS_PER_CHANNEL[format.formatID]; + } + format.floatingPoint = (_ref = format.formatID) === 'fl32' || _ref === 'fl64'; + format.littleEndian = format.formatID === 'sowt' && format.bitsPerChannel > 8; + if ((_ref1 = format.formatID) === 'twos' || _ref1 === 'sowt' || _ref1 === 'in24' || _ref1 === 'in32' || _ref1 === 'fl32' || _ref1 === 'fl64' || _ref1 === 'raw ' || _ref1 === 'NONE') { + return format.formatID = 'lpcm'; + } + }); + + atom('moov.trak.mdia.minf.stbl.stsd.alac', function() { + this.stream.advance(4); + return this.track.cookie = this.stream.readBuffer(this.len - 4); + }); + + atom('moov.trak.mdia.minf.stbl.stsd.esds', function() { + var offset; + offset = this.stream.offset + this.len; + this.track.cookie = M4ADemuxer.readEsds(this.stream); + return this.stream.seek(offset); + }); + + atom('moov.trak.mdia.minf.stbl.stsd.wave.enda', function() { + return this.track.format.littleEndian = !!this.stream.readUInt16(); + }); + + M4ADemuxer.readDescrLen = function(stream) { + var c, count, len; + len = 0; + count = 4; + while (count--) { + c = stream.readUInt8(); + len = (len << 7) | (c & 0x7f); + if (!(c & 0x80)) { + break; + } + } + return len; + }; + + M4ADemuxer.readEsds = function(stream) { + var codec_id, flags, len, tag; + stream.advance(4); + tag = stream.readUInt8(); + len = M4ADemuxer.readDescrLen(stream); + if (tag === 0x03) { + stream.advance(2); + flags = stream.readUInt8(); + if (flags & 0x80) { + stream.advance(2); + } + if (flags & 0x40) { + stream.advance(stream.readUInt8()); + } + if (flags & 0x20) { + stream.advance(2); + } + } else { + stream.advance(2); + } + tag = stream.readUInt8(); + len = M4ADemuxer.readDescrLen(stream); + if (tag === 0x04) { + codec_id = stream.readUInt8(); + stream.advance(1); + stream.advance(3); + stream.advance(4); + stream.advance(4); + tag = stream.readUInt8(); + len = M4ADemuxer.readDescrLen(stream); + if (tag === 0x05) { + return stream.readBuffer(len); + } + } + return null; + }; + + atom('moov.trak.mdia.minf.stbl.stts', function() { + var entries, i, _i; + this.stream.advance(4); + entries = this.stream.readUInt32(); + this.track.stts = []; + for (i = _i = 0; _i < entries; i = _i += 1) { + this.track.stts[i] = { + count: this.stream.readUInt32(), + duration: this.stream.readUInt32() + }; + } + return this.setupSeekPoints(); + }); + + atom('moov.trak.mdia.minf.stbl.stsc', function() { + var entries, i, _i; + this.stream.advance(4); + entries = this.stream.readUInt32(); + this.track.stsc = []; + for (i = _i = 0; _i < entries; i = _i += 1) { + this.track.stsc[i] = { + first: this.stream.readUInt32(), + count: this.stream.readUInt32(), + id: this.stream.readUInt32() + }; + } + return this.setupSeekPoints(); + }); + + atom('moov.trak.mdia.minf.stbl.stsz', function() { + var entries, i, _i; + this.stream.advance(4); + this.track.sampleSize = this.stream.readUInt32(); + entries = this.stream.readUInt32(); + if (this.track.sampleSize === 0 && entries > 0) { + this.track.sampleSizes = []; + for (i = _i = 0; _i < entries; i = _i += 1) { + this.track.sampleSizes[i] = this.stream.readUInt32(); + } + } + return this.setupSeekPoints(); + }); + + atom('moov.trak.mdia.minf.stbl.stco', function() { + var entries, i, _i; + this.stream.advance(4); + entries = this.stream.readUInt32(); + this.track.chunkOffsets = []; + for (i = _i = 0; _i < entries; i = _i += 1) { + this.track.chunkOffsets[i] = this.stream.readUInt32(); + } + return this.setupSeekPoints(); + }); + + atom('moov.trak.tref.chap', function() { + var entries, i, _i; + entries = this.len >> 2; + this.track.chapterTracks = []; + for (i = _i = 0; _i < entries; i = _i += 1) { + this.track.chapterTracks[i] = this.stream.readUInt32(); + } + }); + + M4ADemuxer.prototype.setupSeekPoints = function() { + var i, j, offset, position, sampleIndex, size, stscIndex, sttsIndex, sttsSample, timestamp, _i, _j, _len, _ref, _ref1, _results; + if (!((this.track.chunkOffsets != null) && (this.track.stsc != null) && (this.track.sampleSize != null) && (this.track.stts != null))) { + return; + } + stscIndex = 0; + sttsIndex = 0; + sttsIndex = 0; + sttsSample = 0; + sampleIndex = 0; + offset = 0; + timestamp = 0; + this.track.seekPoints = []; + _ref = this.track.chunkOffsets; + _results = []; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + position = _ref[i]; + for (j = _j = 0, _ref1 = this.track.stsc[stscIndex].count; _j < _ref1; j = _j += 1) { + this.track.seekPoints.push({ + offset: offset, + position: position, + timestamp: timestamp + }); + size = this.track.sampleSize || this.track.sampleSizes[sampleIndex++]; + offset += size; + position += size; + timestamp += this.track.stts[sttsIndex].duration; + if (sttsIndex + 1 < this.track.stts.length && ++sttsSample === this.track.stts[sttsIndex].count) { + sttsSample = 0; + sttsIndex++; + } + } + if (stscIndex + 1 < this.track.stsc.length && i + 1 === this.track.stsc[stscIndex + 1].first) { + _results.push(stscIndex++); + } else { + _results.push(void 0); + } + } + return _results; + }; + + after('moov', function() { + var track, _i, _len, _ref; + if (this.mdatOffset != null) { + this.stream.seek(this.mdatOffset - 8); + } + _ref = this.tracks; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + track = _ref[_i]; + if (!(track.type === 'soun')) { + continue; + } + this.track = track; + break; + } + if (this.track.type !== 'soun') { + this.track = null; + return this.emit('error', 'No audio tracks in m4a file.'); + } + this.emit('format', this.track.format); + this.emit('duration', this.track.duration / this.track.timeScale * 1000 | 0); + if (this.track.cookie) { + this.emit('cookie', this.track.cookie); + } + return this.seekPoints = this.track.seekPoints; + }); + + atom('mdat', function() { + var bytes, chunkSize, length, numSamples, offset, sample, size, _i; + if (!this.startedData) { + if (this.mdatOffset == null) { + this.mdatOffset = this.stream.offset; + } + if (this.tracks.length === 0) { + bytes = Math.min(this.stream.remainingBytes(), this.len); + this.stream.advance(bytes); + this.len -= bytes; + return; + } + this.chunkIndex = 0; + this.stscIndex = 0; + this.sampleIndex = 0; + this.tailOffset = 0; + this.tailSamples = 0; + this.startedData = true; + } + if (!this.readChapters) { + this.readChapters = this.parseChapters(); + if (this["break"] = !this.readChapters) { + return; + } + this.stream.seek(this.mdatOffset); + } + offset = this.track.chunkOffsets[this.chunkIndex] + this.tailOffset; + length = 0; + if (!this.stream.available(offset - this.stream.offset)) { + this["break"] = true; + return; + } + this.stream.seek(offset); + while (this.chunkIndex < this.track.chunkOffsets.length) { + numSamples = this.track.stsc[this.stscIndex].count - this.tailSamples; + chunkSize = 0; + for (sample = _i = 0; _i < numSamples; sample = _i += 1) { + size = this.track.sampleSize || this.track.sampleSizes[this.sampleIndex]; + if (!this.stream.available(length + size)) { + break; + } + length += size; + chunkSize += size; + this.sampleIndex++; + } + if (sample < numSamples) { + this.tailOffset += chunkSize; + this.tailSamples += sample; + break; + } else { + this.chunkIndex++; + this.tailOffset = 0; + this.tailSamples = 0; + if (this.stscIndex + 1 < this.track.stsc.length && this.chunkIndex + 1 === this.track.stsc[this.stscIndex + 1].first) { + this.stscIndex++; + } + if (offset + length !== this.track.chunkOffsets[this.chunkIndex]) { + break; + } + } + } + if (length > 0) { + this.emit('data', this.stream.readBuffer(length)); + return this["break"] = this.chunkIndex === this.track.chunkOffsets.length; + } else { + return this["break"] = true; + } + }); + + M4ADemuxer.prototype.parseChapters = function() { + var bom, id, len, nextTimestamp, point, title, track, _i, _len, _ref, _ref1, _ref2, _ref3; + if (!(((_ref = this.track.chapterTracks) != null ? _ref.length : void 0) > 0)) { + return true; + } + id = this.track.chapterTracks[0]; + _ref1 = this.tracks; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + track = _ref1[_i]; + if (track.id === id) { + break; + } + } + if (track.id !== id) { + this.emit('error', 'Chapter track does not exist.'); + } + if (this.chapters == null) { + this.chapters = []; + } + while (this.chapters.length < track.seekPoints.length) { + point = track.seekPoints[this.chapters.length]; + if (!this.stream.available(point.position - this.stream.offset + 32)) { + return false; + } + this.stream.seek(point.position); + len = this.stream.readUInt16(); + title = null; + if (!this.stream.available(len)) { + return false; + } + if (len > 2) { + bom = this.stream.peekUInt16(); + if (bom === 0xfeff || bom === 0xfffe) { + title = this.stream.readString(len, 'utf16-bom'); + } + } + if (title == null) { + title = this.stream.readString(len, 'utf8'); + } + nextTimestamp = (_ref2 = (_ref3 = track.seekPoints[this.chapters.length + 1]) != null ? _ref3.timestamp : void 0) != null ? _ref2 : track.duration; + this.chapters.push({ + title: title, + timestamp: point.timestamp / track.timeScale * 1000 | 0, + duration: (nextTimestamp - point.timestamp) / track.timeScale * 1000 | 0 + }); + } + this.emit('chapters', this.chapters); + return true; + }; + + atom('moov.udta.meta', function() { + this.metadata = {}; + return this.stream.advance(4); + }); + + after('moov.udta.meta', function() { + return this.emit('metadata', this.metadata); + }); + + meta = function(field, name, fn) { + return atom("moov.udta.meta.ilst." + field + ".data", function() { + this.stream.advance(8); + this.len -= 8; + return fn.call(this, name); + }); + }; + + string = function(field) { + return this.metadata[field] = this.stream.readString(this.len, 'utf8'); + }; + + meta('©alb', 'album', string); + + meta('©arg', 'arranger', string); + + meta('©art', 'artist', string); + + meta('©ART', 'artist', string); + + meta('aART', 'albumArtist', string); + + meta('catg', 'category', string); + + meta('©com', 'composer', string); + + meta('©cpy', 'copyright', string); + + meta('cprt', 'copyright', string); + + meta('©cmt', 'comments', string); + + meta('©day', 'releaseDate', string); + + meta('desc', 'description', string); + + meta('©gen', 'genre', string); + + meta('©grp', 'grouping', string); + + meta('©isr', 'ISRC', string); + + meta('keyw', 'keywords', string); + + meta('©lab', 'recordLabel', string); + + meta('ldes', 'longDescription', string); + + meta('©lyr', 'lyrics', string); + + meta('©nam', 'title', string); + + meta('©phg', 'recordingCopyright', string); + + meta('©prd', 'producer', string); + + meta('©prf', 'performers', string); + + meta('purd', 'purchaseDate', string); + + meta('purl', 'podcastURL', string); + + meta('©swf', 'songwriter', string); + + meta('©too', 'encoder', string); + + meta('©wrt', 'composer', string); + + meta('covr', 'coverArt', function(field) { + return this.metadata[field] = this.stream.readBuffer(this.len); + }); + + genres = ["Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A Capella", "Euro-House", "Dance Hall"]; + + meta('gnre', 'genre', function(field) { + return this.metadata[field] = genres[this.stream.readUInt16() - 1]; + }); + + meta('tmpo', 'tempo', function(field) { + return this.metadata[field] = this.stream.readUInt16(); + }); + + meta('rtng', 'rating', function(field) { + var rating; + rating = this.stream.readUInt8(); + return this.metadata[field] = rating === 2 ? 'Clean' : rating !== 0 ? 'Explicit' : 'None'; + }); + + diskTrack = function(field) { + this.stream.advance(2); + this.metadata[field] = this.stream.readUInt16() + ' of ' + this.stream.readUInt16(); + return this.stream.advance(this.len - 6); + }; + + meta('disk', 'diskNumber', diskTrack); + + meta('trkn', 'trackNumber', diskTrack); + + bool = function(field) { + return this.metadata[field] = this.stream.readUInt8() === 1; + }; + + meta('cpil', 'compilation', bool); + + meta('pcst', 'podcast', bool); + + meta('pgap', 'gapless', bool); + + return M4ADemuxer; + +})(Demuxer); + +module.exports = M4ADemuxer; + + +},{"../demuxer":15}],20:[function(_dereq_,module,exports){ +var Demuxer, WAVEDemuxer, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +Demuxer = _dereq_('../demuxer'); + +WAVEDemuxer = (function(_super) { + var formats; + + __extends(WAVEDemuxer, _super); + + function WAVEDemuxer() { + return WAVEDemuxer.__super__.constructor.apply(this, arguments); + } + + Demuxer.register(WAVEDemuxer); + + WAVEDemuxer.probe = function(buffer) { + return buffer.peekString(0, 4) === 'RIFF' && buffer.peekString(8, 4) === 'WAVE'; + }; + + formats = { + 0x0001: 'lpcm', + 0x0003: 'lpcm', + 0x0006: 'alaw', + 0x0007: 'ulaw' + }; + + WAVEDemuxer.prototype.readChunk = function() { + var buffer, bytes, encoding; + if (!this.readStart && this.stream.available(12)) { + if (this.stream.readString(4) !== 'RIFF') { + return this.emit('error', 'Invalid WAV file.'); + } + this.fileSize = this.stream.readUInt32(true); + this.readStart = true; + if (this.stream.readString(4) !== 'WAVE') { + return this.emit('error', 'Invalid WAV file.'); + } + } + while (this.stream.available(1)) { + if (!this.readHeaders && this.stream.available(8)) { + this.type = this.stream.readString(4); + this.len = this.stream.readUInt32(true); + } + switch (this.type) { + case 'fmt ': + encoding = this.stream.readUInt16(true); + if (!(encoding in formats)) { + return this.emit('error', 'Unsupported format in WAV file.'); + } + this.format = { + formatID: formats[encoding], + floatingPoint: encoding === 0x0003, + littleEndian: formats[encoding] === 'lpcm', + channelsPerFrame: this.stream.readUInt16(true), + sampleRate: this.stream.readUInt32(true), + framesPerPacket: 1 + }; + this.stream.advance(4); + this.stream.advance(2); + this.format.bitsPerChannel = this.stream.readUInt16(true); + this.format.bytesPerPacket = (this.format.bitsPerChannel / 8) * this.format.channelsPerFrame; + this.emit('format', this.format); + this.stream.advance(this.len - 16); + break; + case 'data': + if (!this.sentDuration) { + bytes = this.format.bitsPerChannel / 8; + this.emit('duration', this.len / bytes / this.format.channelsPerFrame / this.format.sampleRate * 1000 | 0); + this.sentDuration = true; + } + buffer = this.stream.readSingleBuffer(this.len); + this.len -= buffer.length; + this.readHeaders = this.len > 0; + this.emit('data', buffer); + break; + default: + if (!this.stream.available(this.len)) { + return; + } + this.stream.advance(this.len); + } + if (this.type !== 'data') { + this.readHeaders = false; + } + } + }; + + return WAVEDemuxer; + +})(Demuxer); + + +},{"../demuxer":15}],21:[function(_dereq_,module,exports){ +var AudioDevice, EventEmitter, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('./core/events'); + +AudioDevice = (function(_super) { + var devices; + + __extends(AudioDevice, _super); + + function AudioDevice(sampleRate, channels) { + this.sampleRate = sampleRate; + this.channels = channels; + this.updateTime = __bind(this.updateTime, this); + this.playing = false; + this.currentTime = 0; + this._lastTime = 0; + } + + AudioDevice.prototype.start = function() { + if (this.playing) { + return; + } + this.playing = true; + if (this.device == null) { + this.device = AudioDevice.create(this.sampleRate, this.channels); + } + if (!this.device) { + throw new Error("No supported audio device found."); + } + this._lastTime = this.device.getDeviceTime(); + this._timer = setInterval(this.updateTime, 200); + return this.device.on('refill', this.refill = (function(_this) { + return function(buffer) { + return _this.emit('refill', buffer); + }; + })(this)); + }; + + AudioDevice.prototype.stop = function() { + if (!this.playing) { + return; + } + this.playing = false; + this.device.off('refill', this.refill); + return clearInterval(this._timer); + }; + + AudioDevice.prototype.destroy = function() { + this.stop(); + return this.device.destroy(); + }; + + AudioDevice.prototype.seek = function(currentTime) { + this.currentTime = currentTime; + if (this.playing) { + this._lastTime = this.device.getDeviceTime(); + } + return this.emit('timeUpdate', this.currentTime); + }; + + AudioDevice.prototype.updateTime = function() { + var time; + time = this.device.getDeviceTime(); + this.currentTime += (time - this._lastTime) / this.device.sampleRate * 1000 | 0; + this._lastTime = time; + return this.emit('timeUpdate', this.currentTime); + }; + + devices = []; + + AudioDevice.register = function(device) { + return devices.push(device); + }; + + AudioDevice.create = function(sampleRate, channels) { + var device, _i, _len; + for (_i = 0, _len = devices.length; _i < _len; _i++) { + device = devices[_i]; + if (device.supported) { + return new device(sampleRate, channels); + } + } + return null; + }; + + return AudioDevice; + +})(EventEmitter); + +module.exports = AudioDevice; + + +},{"./core/events":9}],22:[function(_dereq_,module,exports){ +var AVBuffer, AudioDevice, EventEmitter, MozillaAudioDevice, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('../core/events'); + +AudioDevice = _dereq_('../device'); + +AVBuffer = _dereq_('../core/buffer'); + +MozillaAudioDevice = (function(_super) { + var createTimer, destroyTimer; + + __extends(MozillaAudioDevice, _super); + + AudioDevice.register(MozillaAudioDevice); + + MozillaAudioDevice.supported = (typeof Audio !== "undefined" && Audio !== null) && 'mozWriteAudio' in new Audio; + + function MozillaAudioDevice(sampleRate, channels) { + this.sampleRate = sampleRate; + this.channels = channels; + this.refill = __bind(this.refill, this); + this.audio = new Audio; + this.audio.mozSetup(this.channels, this.sampleRate); + this.writePosition = 0; + this.prebufferSize = this.sampleRate / 2; + this.tail = null; + this.timer = createTimer(this.refill, 100); + } + + MozillaAudioDevice.prototype.refill = function() { + var available, buffer, currentPosition, written; + if (this.tail) { + written = this.audio.mozWriteAudio(this.tail); + this.writePosition += written; + if (this.writePosition < this.tail.length) { + this.tail = this.tail.subarray(written); + } else { + this.tail = null; + } + } + currentPosition = this.audio.mozCurrentSampleOffset(); + available = currentPosition + this.prebufferSize - this.writePosition; + if (available > 0) { + buffer = new Float32Array(available); + this.emit('refill', buffer); + written = this.audio.mozWriteAudio(buffer); + if (written < buffer.length) { + this.tail = buffer.subarray(written); + } + this.writePosition += written; + } + }; + + MozillaAudioDevice.prototype.destroy = function() { + return destroyTimer(this.timer); + }; + + MozillaAudioDevice.prototype.getDeviceTime = function() { + return this.audio.mozCurrentSampleOffset() / this.channels; + }; + + createTimer = function(fn, interval) { + var url, worker; + url = AVBuffer.makeBlobURL("setInterval(function() { postMessage('ping'); }, " + interval + ");"); + if (url == null) { + return setInterval(fn, interval); + } + worker = new Worker(url); + worker.onmessage = fn; + worker.url = url; + return worker; + }; + + destroyTimer = function(timer) { + if (timer.terminate) { + timer.terminate(); + return URL.revokeObjectURL(timer.url); + } else { + return clearInterval(timer); + } + }; + + return MozillaAudioDevice; + +})(EventEmitter); + + +},{"../core/buffer":7,"../core/events":9,"../device":21}],23:[function(_dereq_,module,exports){ +/* + * This resampler is from XAudioJS: https://github.com/grantgalitz/XAudioJS + * Planned to be replaced with src.js, eventually: https://github.com/jussi-kalliokoski/src.js + */ + +//JavaScript Audio Resampler (c) 2011 - Grant Galitz +function Resampler(fromSampleRate, toSampleRate, channels, outputBufferSize, noReturn) { + this.fromSampleRate = fromSampleRate; + this.toSampleRate = toSampleRate; + this.channels = channels | 0; + this.outputBufferSize = outputBufferSize; + this.noReturn = !!noReturn; + this.initialize(); +} + +Resampler.prototype.initialize = function () { + //Perform some checks: + if (this.fromSampleRate > 0 && this.toSampleRate > 0 && this.channels > 0) { + if (this.fromSampleRate == this.toSampleRate) { + //Setup a resampler bypass: + this.resampler = this.bypassResampler; //Resampler just returns what was passed through. + this.ratioWeight = 1; + } + else { + if (this.fromSampleRate < this.toSampleRate) { + /* + Use generic linear interpolation if upsampling, + as linear interpolation produces a gradient that we want + and works fine with two input sample points per output in this case. + */ + this.compileLinearInterpolationFunction(); + this.lastWeight = 1; + } + else { + /* + Custom resampler I wrote that doesn't skip samples + like standard linear interpolation in high downsampling. + This is more accurate than linear interpolation on downsampling. + */ + this.compileMultiTapFunction(); + this.tailExists = false; + this.lastWeight = 0; + } + this.ratioWeight = this.fromSampleRate / this.toSampleRate; + this.initializeBuffers(); + } + } + else { + throw(new Error("Invalid settings specified for the resampler.")); + } +}; + +Resampler.prototype.compileLinearInterpolationFunction = function () { + var toCompile = "var bufferLength = buffer.length;\ + var outLength = this.outputBufferSize;\ + if ((bufferLength % " + this.channels + ") == 0) {\ + if (bufferLength > 0) {\ + var ratioWeight = this.ratioWeight;\ + var weight = this.lastWeight;\ + var firstWeight = 0;\ + var secondWeight = 0;\ + var sourceOffset = 0;\ + var outputOffset = 0;\ + var outputBuffer = this.outputBuffer;\ + for (; weight < 1; weight += ratioWeight) {\ + secondWeight = weight % 1;\ + firstWeight = 1 - secondWeight;"; + for (var channel = 0; channel < this.channels; ++channel) { + toCompile += "outputBuffer[outputOffset++] = (this.lastOutput[" + channel + "] * firstWeight) + (buffer[" + channel + "] * secondWeight);"; + } + toCompile += "}\ + weight -= 1;\ + for (bufferLength -= " + this.channels + ", sourceOffset = Math.floor(weight) * " + this.channels + "; outputOffset < outLength && sourceOffset < bufferLength;) {\ + secondWeight = weight % 1;\ + firstWeight = 1 - secondWeight;"; + for (var channel = 0; channel < this.channels; ++channel) { + toCompile += "outputBuffer[outputOffset++] = (buffer[sourceOffset" + ((channel > 0) ? (" + " + channel) : "") + "] * firstWeight) + (buffer[sourceOffset + " + (this.channels + channel) + "] * secondWeight);"; + } + toCompile += "weight += ratioWeight;\ + sourceOffset = Math.floor(weight) * " + this.channels + ";\ + }"; + for (var channel = 0; channel < this.channels; ++channel) { + toCompile += "this.lastOutput[" + channel + "] = buffer[sourceOffset++];"; + } + toCompile += "this.lastWeight = weight % 1;\ + return this.bufferSlice(outputOffset);\ + }\ + else {\ + return (this.noReturn) ? 0 : [];\ + }\ + }\ + else {\ + throw(new Error(\"Buffer was of incorrect sample length.\"));\ + }"; + this.resampler = Function("buffer", toCompile); +}; + +Resampler.prototype.compileMultiTapFunction = function () { + var toCompile = "var bufferLength = buffer.length;\ + var outLength = this.outputBufferSize;\ + if ((bufferLength % " + this.channels + ") == 0) {\ + if (bufferLength > 0) {\ + var ratioWeight = this.ratioWeight;\ + var weight = 0;"; + for (var channel = 0; channel < this.channels; ++channel) { + toCompile += "var output" + channel + " = 0;" + } + toCompile += "var actualPosition = 0;\ + var amountToNext = 0;\ + var alreadyProcessedTail = !this.tailExists;\ + this.tailExists = false;\ + var outputBuffer = this.outputBuffer;\ + var outputOffset = 0;\ + var currentPosition = 0;\ + do {\ + if (alreadyProcessedTail) {\ + weight = ratioWeight;"; + for (channel = 0; channel < this.channels; ++channel) { + toCompile += "output" + channel + " = 0;" + } + toCompile += "}\ + else {\ + weight = this.lastWeight;"; + for (channel = 0; channel < this.channels; ++channel) { + toCompile += "output" + channel + " = this.lastOutput[" + channel + "];" + } + toCompile += "alreadyProcessedTail = true;\ + }\ + while (weight > 0 && actualPosition < bufferLength) {\ + amountToNext = 1 + actualPosition - currentPosition;\ + if (weight >= amountToNext) {"; + for (channel = 0; channel < this.channels; ++channel) { + toCompile += "output" + channel + " += buffer[actualPosition++] * amountToNext;" + } + toCompile += "currentPosition = actualPosition;\ + weight -= amountToNext;\ + }\ + else {"; + for (channel = 0; channel < this.channels; ++channel) { + toCompile += "output" + channel + " += buffer[actualPosition" + ((channel > 0) ? (" + " + channel) : "") + "] * weight;" + } + toCompile += "currentPosition += weight;\ + weight = 0;\ + break;\ + }\ + }\ + if (weight == 0) {"; + for (channel = 0; channel < this.channels; ++channel) { + toCompile += "outputBuffer[outputOffset++] = output" + channel + " / ratioWeight;" + } + toCompile += "}\ + else {\ + this.lastWeight = weight;"; + for (channel = 0; channel < this.channels; ++channel) { + toCompile += "this.lastOutput[" + channel + "] = output" + channel + ";" + } + toCompile += "this.tailExists = true;\ + break;\ + }\ + } while (actualPosition < bufferLength && outputOffset < outLength);\ + return this.bufferSlice(outputOffset);\ + }\ + else {\ + return (this.noReturn) ? 0 : [];\ + }\ + }\ + else {\ + throw(new Error(\"Buffer was of incorrect sample length.\"));\ + }"; + this.resampler = Function("buffer", toCompile); +}; + +Resampler.prototype.bypassResampler = function (buffer) { + if (this.noReturn) { + //Set the buffer passed as our own, as we don't need to resample it: + this.outputBuffer = buffer; + return buffer.length; + } + else { + //Just return the buffer passsed: + return buffer; + } +}; + +Resampler.prototype.bufferSlice = function (sliceAmount) { + if (this.noReturn) { + //If we're going to access the properties directly from this object: + return sliceAmount; + } + else { + //Typed array and normal array buffer section referencing: + try { + return this.outputBuffer.subarray(0, sliceAmount); + } + catch (error) { + try { + //Regular array pass: + this.outputBuffer.length = sliceAmount; + return this.outputBuffer; + } + catch (error) { + //Nightly Firefox 4 used to have the subarray function named as slice: + return this.outputBuffer.slice(0, sliceAmount); + } + } + } +}; + +Resampler.prototype.initializeBuffers = function () { + //Initialize the internal buffer: + try { + this.outputBuffer = new Float32Array(this.outputBufferSize); + this.lastOutput = new Float32Array(this.channels); + } + catch (error) { + this.outputBuffer = []; + this.lastOutput = []; + } +}; + +module.exports = Resampler; + +},{}],24:[function(_dereq_,module,exports){ +(function (global){ +var AudioDevice, EventEmitter, Resampler, WebAudioDevice, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('../core/events'); + +AudioDevice = _dereq_('../device'); + +Resampler = _dereq_('./resampler'); + +WebAudioDevice = (function(_super) { + var AudioContext, createProcessor, sharedContext; + + __extends(WebAudioDevice, _super); + + AudioDevice.register(WebAudioDevice); + + AudioContext = global.AudioContext || global.webkitAudioContext; + + WebAudioDevice.supported = AudioContext && (typeof AudioContext.prototype[createProcessor = 'createScriptProcessor'] === 'function' || typeof AudioContext.prototype[createProcessor = 'createJavaScriptNode'] === 'function'); + + sharedContext = null; + + function WebAudioDevice(sampleRate, channels) { + this.sampleRate = sampleRate; + this.channels = channels; + this.refill = __bind(this.refill, this); + this.context = sharedContext != null ? sharedContext : sharedContext = new AudioContext; + this.deviceSampleRate = this.context.sampleRate; + this.bufferSize = Math.ceil(4096 / (this.deviceSampleRate / this.sampleRate) * this.channels); + this.bufferSize += this.bufferSize % this.channels; + if (this.deviceSampleRate !== this.sampleRate) { + this.resampler = new Resampler(this.sampleRate, this.deviceSampleRate, this.channels, 4096 * this.channels); + } + this.node = this.context[createProcessor](4096, this.channels, this.channels); + this.node.onaudioprocess = this.refill; + this.node.connect(this.context.destination); + } + + WebAudioDevice.prototype.refill = function(event) { + var channelCount, channels, data, i, n, outputBuffer, _i, _j, _k, _ref; + outputBuffer = event.outputBuffer; + channelCount = outputBuffer.numberOfChannels; + channels = new Array(channelCount); + for (i = _i = 0; _i < channelCount; i = _i += 1) { + channels[i] = outputBuffer.getChannelData(i); + } + data = new Float32Array(this.bufferSize); + this.emit('refill', data); + if (this.resampler) { + data = this.resampler.resampler(data); + } + for (i = _j = 0, _ref = outputBuffer.length; _j < _ref; i = _j += 1) { + for (n = _k = 0; _k < channelCount; n = _k += 1) { + channels[n][i] = data[i * channelCount + n]; + } + } + }; + + WebAudioDevice.prototype.destroy = function() { + return this.node.disconnect(0); + }; + + WebAudioDevice.prototype.getDeviceTime = function() { + return this.context.currentTime * this.sampleRate; + }; + + return WebAudioDevice; + +})(EventEmitter); + + +}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../core/events":9,"../device":21,"./resampler":23}],25:[function(_dereq_,module,exports){ +var Filter; + +Filter = (function() { + function Filter(context, key) { + if (context && key) { + Object.defineProperty(this, 'value', { + get: function() { + return context[key]; + } + }); + } + } + + Filter.prototype.process = function(buffer) {}; + + return Filter; + +})(); + +module.exports = Filter; + + +},{}],26:[function(_dereq_,module,exports){ +var BalanceFilter, Filter, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +Filter = _dereq_('../filter'); + +BalanceFilter = (function(_super) { + __extends(BalanceFilter, _super); + + function BalanceFilter() { + return BalanceFilter.__super__.constructor.apply(this, arguments); + } + + BalanceFilter.prototype.process = function(buffer) { + var i, pan, _i, _ref; + if (this.value === 0) { + return; + } + pan = Math.max(-50, Math.min(50, this.value)); + for (i = _i = 0, _ref = buffer.length; _i < _ref; i = _i += 2) { + buffer[i] *= Math.min(1, (50 - pan) / 50); + buffer[i + 1] *= Math.min(1, (50 + pan) / 50); + } + }; + + return BalanceFilter; + +})(Filter); + +module.exports = BalanceFilter; + + +},{"../filter":25}],27:[function(_dereq_,module,exports){ +var Filter, VolumeFilter, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +Filter = _dereq_('../filter'); + +VolumeFilter = (function(_super) { + __extends(VolumeFilter, _super); + + function VolumeFilter() { + return VolumeFilter.__super__.constructor.apply(this, arguments); + } + + VolumeFilter.prototype.process = function(buffer) { + var i, vol, _i, _ref; + if (this.value >= 100) { + return; + } + vol = Math.max(0, Math.min(100, this.value)) / 100; + for (i = _i = 0, _ref = buffer.length; _i < _ref; i = _i += 1) { + buffer[i] *= vol; + } + }; + + return VolumeFilter; + +})(Filter); + +module.exports = VolumeFilter; + + +},{"../filter":25}],28:[function(_dereq_,module,exports){ +var Asset, AudioDevice, BalanceFilter, EventEmitter, Player, Queue, VolumeFilter, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('./core/events'); + +Asset = _dereq_('./asset'); + +VolumeFilter = _dereq_('./filters/volume'); + +BalanceFilter = _dereq_('./filters/balance'); + +Queue = _dereq_('./queue'); + +AudioDevice = _dereq_('./device'); + +Player = (function(_super) { + __extends(Player, _super); + + function Player(asset) { + this.asset = asset; + this.startPlaying = __bind(this.startPlaying, this); + this.playing = false; + this.buffered = 0; + this.currentTime = 0; + this.duration = 0; + this.volume = 100; + this.pan = 0; + this.metadata = {}; + this.filters = [new VolumeFilter(this, 'volume'), new BalanceFilter(this, 'pan')]; + this.asset.on('buffer', (function(_this) { + return function(buffered) { + _this.buffered = buffered; + return _this.emit('buffer', _this.buffered); + }; + })(this)); + this.asset.on('decodeStart', (function(_this) { + return function() { + _this.queue = new Queue(_this.asset); + return _this.queue.once('ready', _this.startPlaying); + }; + })(this)); + this.asset.on('format', (function(_this) { + return function(format) { + _this.format = format; + return _this.emit('format', _this.format); + }; + })(this)); + this.asset.on('metadata', (function(_this) { + return function(metadata) { + _this.metadata = metadata; + return _this.emit('metadata', _this.metadata); + }; + })(this)); + this.asset.on('duration', (function(_this) { + return function(duration) { + _this.duration = duration; + return _this.emit('duration', _this.duration); + }; + })(this)); + this.asset.on('error', (function(_this) { + return function(error) { + return _this.emit('error', error); + }; + })(this)); + } + + Player.fromURL = function(url) { + return new Player(Asset.fromURL(url)); + }; + + Player.fromFile = function(file) { + return new Player(Asset.fromFile(file)); + }; + + Player.fromBuffer = function(buffer) { + return new Player(Asset.fromBuffer(buffer)); + }; + + Player.prototype.preload = function() { + if (!this.asset) { + return; + } + this.startedPreloading = true; + return this.asset.start(false); + }; + + Player.prototype.play = function() { + var _ref; + if (this.playing) { + return; + } + if (!this.startedPreloading) { + this.preload(); + } + this.playing = true; + return (_ref = this.device) != null ? _ref.start() : void 0; + }; + + Player.prototype.pause = function() { + var _ref; + if (!this.playing) { + return; + } + this.playing = false; + return (_ref = this.device) != null ? _ref.stop() : void 0; + }; + + Player.prototype.togglePlayback = function() { + if (this.playing) { + return this.pause(); + } else { + return this.play(); + } + }; + + Player.prototype.stop = function() { + var _ref; + this.pause(); + this.asset.stop(); + return (_ref = this.device) != null ? _ref.destroy() : void 0; + }; + + Player.prototype.seek = function(timestamp) { + var _ref; + if ((_ref = this.device) != null) { + _ref.stop(); + } + this.queue.once('ready', (function(_this) { + return function() { + var _ref1, _ref2; + if ((_ref1 = _this.device) != null) { + _ref1.seek(_this.currentTime); + } + if (_this.playing) { + return (_ref2 = _this.device) != null ? _ref2.start() : void 0; + } + }; + })(this)); + timestamp = (timestamp / 1000) * this.format.sampleRate; + timestamp = this.asset.decoder.seek(timestamp); + this.currentTime = timestamp / this.format.sampleRate * 1000 | 0; + this.queue.reset(); + return this.currentTime; + }; + + Player.prototype.startPlaying = function() { + var frame, frameOffset; + frame = this.queue.read(); + frameOffset = 0; + this.device = new AudioDevice(this.format.sampleRate, this.format.channelsPerFrame); + this.device.on('timeUpdate', (function(_this) { + return function(currentTime) { + _this.currentTime = currentTime; + return _this.emit('progress', _this.currentTime); + }; + })(this)); + this.refill = (function(_this) { + return function(buffer) { + var bufferOffset, filter, i, max, _i, _j, _len, _ref; + if (!_this.playing) { + return; + } + if (!frame) { + frame = _this.queue.read(); + frameOffset = 0; + } + bufferOffset = 0; + while (frame && bufferOffset < buffer.length) { + max = Math.min(frame.length - frameOffset, buffer.length - bufferOffset); + for (i = _i = 0; _i < max; i = _i += 1) { + buffer[bufferOffset++] = frame[frameOffset++]; + } + if (frameOffset === frame.length) { + frame = _this.queue.read(); + frameOffset = 0; + } + } + _ref = _this.filters; + for (_j = 0, _len = _ref.length; _j < _len; _j++) { + filter = _ref[_j]; + filter.process(buffer); + } + if (!frame) { + if (_this.queue.ended) { + _this.currentTime = _this.duration; + _this.emit('progress', _this.currentTime); + _this.emit('end'); + _this.stop(); + } else { + _this.device.stop(); + } + } + }; + })(this); + this.device.on('refill', this.refill); + if (this.playing) { + this.device.start(); + } + return this.emit('ready'); + }; + + return Player; + +})(EventEmitter); + +module.exports = Player; + + +},{"./asset":2,"./core/events":9,"./device":21,"./filters/balance":26,"./filters/volume":27,"./queue":29}],29:[function(_dereq_,module,exports){ +var EventEmitter, Queue, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('./core/events'); + +Queue = (function(_super) { + __extends(Queue, _super); + + function Queue(asset) { + this.asset = asset; + this.write = __bind(this.write, this); + this.readyMark = 64; + this.finished = false; + this.buffering = true; + this.ended = false; + this.buffers = []; + this.asset.on('data', this.write); + this.asset.on('end', (function(_this) { + return function() { + return _this.ended = true; + }; + })(this)); + this.asset.decodePacket(); + } + + Queue.prototype.write = function(buffer) { + if (buffer) { + this.buffers.push(buffer); + } + if (this.buffering) { + if (this.buffers.length >= this.readyMark || this.ended) { + this.buffering = false; + return this.emit('ready'); + } else { + return this.asset.decodePacket(); + } + } + }; + + Queue.prototype.read = function() { + if (this.buffers.length === 0) { + return null; + } + this.asset.decodePacket(); + return this.buffers.shift(); + }; + + Queue.prototype.reset = function() { + this.buffers.length = 0; + this.buffering = true; + return this.asset.decodePacket(); + }; + + return Queue; + +})(EventEmitter); + +module.exports = Queue; + + +},{"./core/events":9}],30:[function(_dereq_,module,exports){ +var AVBuffer, EventEmitter, FileSource, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('../../core/events'); + +AVBuffer = _dereq_('../../core/buffer'); + +FileSource = (function(_super) { + __extends(FileSource, _super); + + function FileSource(file) { + this.file = file; + if (typeof FileReader === "undefined" || FileReader === null) { + return this.emit('error', 'This browser does not have FileReader support.'); + } + this.offset = 0; + this.length = this.file.size; + this.chunkSize = 1 << 20; + this.file[this.slice = 'slice'] || this.file[this.slice = 'webkitSlice'] || this.file[this.slice = 'mozSlice']; + } + + FileSource.prototype.start = function() { + if (this.reader) { + if (!this.active) { + return this.loop(); + } + } + this.reader = new FileReader; + this.active = true; + this.reader.onload = (function(_this) { + return function(e) { + var buf; + buf = new AVBuffer(new Uint8Array(e.target.result)); + _this.offset += buf.length; + _this.emit('data', buf); + _this.active = false; + if (_this.offset < _this.length) { + return _this.loop(); + } + }; + })(this); + this.reader.onloadend = (function(_this) { + return function() { + if (_this.offset === _this.length) { + _this.emit('end'); + return _this.reader = null; + } + }; + })(this); + this.reader.onerror = (function(_this) { + return function(e) { + return _this.emit('error', e); + }; + })(this); + this.reader.onprogress = (function(_this) { + return function(e) { + return _this.emit('progress', (_this.offset + e.loaded) / _this.length * 100); + }; + })(this); + return this.loop(); + }; + + FileSource.prototype.loop = function() { + var blob, endPos; + this.active = true; + endPos = Math.min(this.offset + this.chunkSize, this.length); + blob = this.file[this.slice](this.offset, endPos); + return this.reader.readAsArrayBuffer(blob); + }; + + FileSource.prototype.pause = function() { + var _ref; + this.active = false; + try { + return (_ref = this.reader) != null ? _ref.abort() : void 0; + } catch (_error) {} + }; + + FileSource.prototype.reset = function() { + this.pause(); + return this.offset = 0; + }; + + return FileSource; + +})(EventEmitter); + +module.exports = FileSource; + + +},{"../../core/buffer":7,"../../core/events":9}],31:[function(_dereq_,module,exports){ +var AVBuffer, EventEmitter, HTTPSource, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('../../core/events'); + +AVBuffer = _dereq_('../../core/buffer'); + +HTTPSource = (function(_super) { + __extends(HTTPSource, _super); + + function HTTPSource(url) { + this.url = url; + this.chunkSize = 1 << 20; + this.inflight = false; + this.reset(); + } + + HTTPSource.prototype.start = function() { + if (this.length) { + if (!this.inflight) { + return this.loop(); + } + } + this.inflight = true; + this.xhr = new XMLHttpRequest(); + this.xhr.onload = (function(_this) { + return function(event) { + _this.length = parseInt(_this.xhr.getResponseHeader("Content-Length")); + _this.inflight = false; + return _this.loop(); + }; + })(this); + this.xhr.onerror = (function(_this) { + return function(err) { + _this.pause(); + return _this.emit('error', err); + }; + })(this); + this.xhr.onabort = (function(_this) { + return function(event) { + return _this.inflight = false; + }; + })(this); + this.xhr.open("HEAD", this.url, true); + return this.xhr.send(null); + }; + + HTTPSource.prototype.loop = function() { + var endPos; + if (this.inflight || !this.length) { + return this.emit('error', 'Something is wrong in HTTPSource.loop'); + } + this.inflight = true; + this.xhr = new XMLHttpRequest(); + this.xhr.onload = (function(_this) { + return function(event) { + var buf, buffer, i, txt, _i, _ref; + if (_this.xhr.response) { + buf = new Uint8Array(_this.xhr.response); + } else { + txt = _this.xhr.responseText; + buf = new Uint8Array(txt.length); + for (i = _i = 0, _ref = txt.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { + buf[i] = txt.charCodeAt(i) & 0xff; + } + } + buffer = new AVBuffer(buf); + _this.offset += buffer.length; + _this.emit('data', buffer); + if (_this.offset >= _this.length) { + _this.emit('end'); + } + _this.inflight = false; + if (!(_this.offset >= _this.length)) { + return _this.loop(); + } + }; + })(this); + this.xhr.onprogress = (function(_this) { + return function(event) { + return _this.emit('progress', (_this.offset + event.loaded) / _this.length * 100); + }; + })(this); + this.xhr.onerror = (function(_this) { + return function(err) { + _this.emit('error', err); + return _this.pause(); + }; + })(this); + this.xhr.onabort = (function(_this) { + return function(event) { + return _this.inflight = false; + }; + })(this); + this.xhr.open("GET", this.url, true); + this.xhr.responseType = "arraybuffer"; + endPos = Math.min(this.offset + this.chunkSize, this.length); + this.xhr.setRequestHeader("Range", "bytes=" + this.offset + "-" + endPos); + this.xhr.overrideMimeType('text/plain; charset=x-user-defined'); + return this.xhr.send(null); + }; + + HTTPSource.prototype.pause = function() { + var _ref; + this.inflight = false; + return (_ref = this.xhr) != null ? _ref.abort() : void 0; + }; + + HTTPSource.prototype.reset = function() { + this.pause(); + return this.offset = 0; + }; + + return HTTPSource; + +})(EventEmitter); + +module.exports = HTTPSource; + + +},{"../../core/buffer":7,"../../core/events":9}],32:[function(_dereq_,module,exports){ +(function (global){ +var AVBuffer, BufferList, BufferSource, EventEmitter, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +EventEmitter = _dereq_('../core/events'); + +BufferList = _dereq_('../core/bufferlist'); + +AVBuffer = _dereq_('../core/buffer'); + +BufferSource = (function(_super) { + var clearImmediate, setImmediate; + + __extends(BufferSource, _super); + + function BufferSource(input) { + this.loop = __bind(this.loop, this); + if (input instanceof BufferList) { + this.list = input; + } else { + this.list = new BufferList; + this.list.append(new AVBuffer(input)); + } + this.paused = true; + } + + setImmediate = global.setImmediate || function(fn) { + return global.setTimeout(fn, 0); + }; + + clearImmediate = global.clearImmediate || function(timer) { + return global.clearTimeout(timer); + }; + + BufferSource.prototype.start = function() { + this.paused = false; + return this._timer = setImmediate(this.loop); + }; + + BufferSource.prototype.loop = function() { + this.emit('progress', (this.list.numBuffers - this.list.availableBuffers + 1) / this.list.numBuffers * 100 | 0); + this.emit('data', this.list.first); + if (this.list.advance()) { + return setImmediate(this.loop); + } else { + return this.emit('end'); + } + }; + + BufferSource.prototype.pause = function() { + clearImmediate(this._timer); + return this.paused = true; + }; + + BufferSource.prototype.reset = function() { + this.pause(); + return this.list.rewind(); + }; + + return BufferSource; + +})(EventEmitter); + +module.exports = BufferSource; + + +}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../core/buffer":7,"../core/bufferlist":8,"../core/events":9}]},{},[1]) + +(1) +}); + +//# sourceMappingURL=aurora.js.map diff --git a/lorgar/lib/bintrees/CMakeLists.txt b/lorgar/lib/bintrees/CMakeLists.txt index 346394a..548677a 100644 --- a/lorgar/lib/bintrees/CMakeLists.txt +++ b/lorgar/lib/bintrees/CMakeLists.txt @@ -1,3 +1,3 @@ cmake_minimum_required(VERSION 2.8.12) -configure_file(index.js index.js) \ No newline at end of file +configure_file(index.js index.js) diff --git a/lorgar/lib/mp3/CMakeLists.txt b/lorgar/lib/mp3/CMakeLists.txt new file mode 100644 index 0000000..19576d4 --- /dev/null +++ b/lorgar/lib/mp3/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12) + +configure_file(mp3.js mp3.js) diff --git a/lorgar/lib/mp3/mp3.js b/lorgar/lib/mp3/mp3.js new file mode 100644 index 0000000..8631e7d --- /dev/null +++ b/lorgar/lib/mp3/mp3.js @@ -0,0 +1,7706 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { + timestamp = this._super(timestamp); + offset = this.stream.offset; + } else { + offset = timestamp * this.format.bitrate / 8 / this.format.sampleRate; + } + + this.mp3_stream.reset(offset); + + // try to find 3 consecutive valid frame headers in a row + for (var i = 0; i < 4096; i++) { + var pos = offset + i; + for (var j = 0; j < 3; j++) { + this.mp3_stream.reset(pos); + + try { + var header = MP3FrameHeader.decode(this.mp3_stream); + } catch (e) { + break; + } + + // skip the rest of the frame + var size = header.framesize(); + if (size == null) + break; + + pos += size; + } + + // check if we're done + if (j === 3) + break; + } + + // if we didn't find 3 frames, just try the first one and hope for the best + if (j !== 3) + i = 0; + + this.mp3_stream.reset(offset + i); + + // if we guesstimated, update the timestamp to another estimate of where we actually seeked to + if (this.demuxer.seekPoints.length === 0) + timestamp = this.stream.offset / (this.format.bitrate / 8) * this.format.sampleRate; + + this.seeking = true; + return timestamp; + }; +}); + +module.exports = MP3Decoder; + +},{"./frame":4,"./header":5,"./layer1":9,"./layer2":10,"./layer3":11,"./stream":12,"./synth":13}],3:[function(require,module,exports){ +var AV = (window.AV); +var ID3v23Stream = require('./id3').ID3v23Stream; +var ID3v22Stream = require('./id3').ID3v22Stream; +var MP3FrameHeader = require('./header'); +var MP3Stream = require('./stream'); + +var MP3Demuxer = AV.Demuxer.extend(function() { + AV.Demuxer.register(this); + + this.probe = function(stream) { + var off = stream.offset; + + // skip id3 metadata if it exists + var id3header = MP3Demuxer.getID3v2Header(stream); + if (id3header) + stream.advance(10 + id3header.length); + + // attempt to read the header of the first audio frame + var s = new MP3Stream(new AV.Bitstream(stream)); + var header = null; + + try { + header = MP3FrameHeader.decode(s); + } catch (e) {}; + + // go back to the beginning, for other probes + stream.seek(off); + + return !!header; + }; + + this.getID3v2Header = function(stream) { + if (stream.peekString(0, 3) == 'ID3') { + stream = AV.Stream.fromBuffer(stream.peekBuffer(0, 10)); + stream.advance(3); // 'ID3' + + var major = stream.readUInt8(); + var minor = stream.readUInt8(); + var flags = stream.readUInt8(); + var bytes = stream.readBuffer(4).data; + var length = (bytes[0] << 21) | (bytes[1] << 14) | (bytes[2] << 7) | bytes[3]; + + return { + version: '2.' + major + '.' + minor, + major: major, + minor: minor, + flags: flags, + length: length + }; + } + + return null; + }; + + const XING_OFFSETS = [[32, 17], [17, 9]]; + this.prototype.parseDuration = function(header) { + var stream = this.stream; + var frames; + + var offset = stream.offset; + if (!header || header.layer !== 3) + return false; + + // Check for Xing/Info tag + stream.advance(XING_OFFSETS[header.flags & MP3FrameHeader.FLAGS.LSF_EXT ? 1 : 0][header.nchannels() === 1 ? 1 : 0]); + var tag = stream.readString(4); + if (tag === 'Xing' || tag === 'Info') { + var flags = stream.readUInt32(); + if (flags & 1) + frames = stream.readUInt32(); + + if (flags & 2) + var size = stream.readUInt32(); + + if (flags & 4 && frames && size) { + for (var i = 0; i < 100; i++) { + var b = stream.readUInt8(); + var pos = b / 256 * size | 0; + var time = i / 100 * (frames * header.nbsamples() * 32) | 0; + this.addSeekPoint(pos, time); + } + } + + if (flags & 8) + stream.advance(4); + + } else { + // Check for VBRI tag (always 32 bytes after end of mpegaudio header) + stream.seek(offset + 4 + 32); + tag = stream.readString(4); + if (tag == 'VBRI' && stream.readUInt16() === 1) { // Check tag version + stream.advance(4); // skip delay and quality + stream.advance(4); // skip size + frames = stream.readUInt32(); + + var entries = stream.readUInt16(); + var scale = stream.readUInt16(); + var bytesPerEntry = stream.readUInt16(); + var framesPerEntry = stream.readUInt16(); + var fn = 'readUInt' + (bytesPerEntry * 8); + + var pos = 0; + for (var i = 0; i < entries; i++) { + this.addSeekPoint(pos, framesPerEntry * i); + pos += stream[fn](); + } + } + } + + if (!frames) + return false; + + this.emit('duration', (frames * header.nbsamples() * 32) / header.samplerate * 1000 | 0); + return true; + }; + + this.prototype.readChunk = function() { + var stream = this.stream; + + if (!this.sentInfo) { + // read id3 metadata if it exists + var id3header = MP3Demuxer.getID3v2Header(stream); + if (id3header) { + stream.advance(10); + + if (id3header.major > 2) { + var id3 = new ID3v23Stream(id3header, stream); + } else { + var id3 = new ID3v22Stream(id3header, stream); + } + + this.emit('metadata', id3.read()); + } + + // read the header of the first audio frame + var off = stream.offset; + var s = new MP3Stream(new AV.Bitstream(stream)); + + var header = MP3FrameHeader.decode(s); + if (!header) + return this.emit('error', 'Could not find first frame.'); + + this.emit('format', { + formatID: 'mp3', + sampleRate: header.samplerate, + channelsPerFrame: header.nchannels(), + bitrate: header.bitrate, + floatingPoint: true + }); + + var sentDuration = this.parseDuration(header); + stream.advance(off - stream.offset); + + // if there were no Xing/VBRI tags, guesstimate the duration based on data size and bitrate + this.dataSize = 0; + if (!sentDuration) { + this.on('end', function() { + this.emit('duration', this.dataSize * 8 / header.bitrate * 1000 | 0); + }); + } + + this.sentInfo = true; + } + + while (stream.available(1)) { + var buffer = stream.readSingleBuffer(stream.remainingBytes()); + this.dataSize += buffer.length; + this.emit('data', buffer); + } + }; +}); + +module.exports = MP3Demuxer; + +},{"./header":5,"./id3":7,"./stream":12}],4:[function(require,module,exports){ +var MP3FrameHeader = require('./header'); +var utils = require('./utils'); + +function MP3Frame() { + this.header = null; // MPEG audio header + this.options = 0; // decoding options (from stream) + this.sbsample = utils.makeArray([2, 36, 32]); // synthesis subband filter samples + this.overlap = utils.makeArray([2, 32, 18]); // Layer III block overlap data + this.decoders = []; +} + +// included layer decoders are registered here +MP3Frame.layers = []; + +MP3Frame.prototype.decode = function(stream) { + if (!this.header || !(this.header.flags & MP3FrameHeader.FLAGS.INCOMPLETE)) + this.header = MP3FrameHeader.decode(stream); + + this.header.flags &= ~MP3FrameHeader.FLAGS.INCOMPLETE; + + // make an instance of the decoder for this layer if needed + var decoder = this.decoders[this.header.layer - 1]; + if (!decoder) { + var Layer = MP3Frame.layers[this.header.layer]; + if (!Layer) + throw new Error("Layer " + this.header.layer + " is not supported."); + + decoder = this.decoders[this.header.layer - 1] = new Layer(); + } + + decoder.decode(stream, this); +}; + +module.exports = MP3Frame; + +},{"./header":5,"./utils":15}],5:[function(require,module,exports){ +var AV = (window.AV); + +function MP3FrameHeader() { + this.layer = 0; // audio layer (1, 2, or 3) + this.mode = 0; // channel mode (see above) + this.mode_extension = 0; // additional mode info + this.emphasis = 0; // de-emphasis to use (see above) + + this.bitrate = 0; // stream bitrate (bps) + this.samplerate = 0; // sampling frequency (Hz) + + this.crc_check = 0; // frame CRC accumulator + this.crc_target = 0; // final target CRC checksum + + this.flags = 0; // flags (see above) + this.private_bits = 0; // private bits +} + +const BITRATES = [ + // MPEG-1 + [ 0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, // Layer I + 256000, 288000, 320000, 352000, 384000, 416000, 448000 ], + [ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, // Layer II + 128000, 160000, 192000, 224000, 256000, 320000, 384000 ], + [ 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, // Layer III + 112000, 128000, 160000, 192000, 224000, 256000, 320000 ], + + // MPEG-2 LSF + [ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, // Layer I + 128000, 144000, 160000, 176000, 192000, 224000, 256000 ], + [ 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, // Layers + 64000, 80000, 96000, 112000, 128000, 144000, 160000 ] // II & III +]; + +const SAMPLERATES = [ + 44100, 48000, 32000 +]; + +MP3FrameHeader.FLAGS = { + NPRIVATE_III: 0x0007, // number of Layer III private bits + INCOMPLETE : 0x0008, // header but not data is decoded + + PROTECTION : 0x0010, // frame has CRC protection + COPYRIGHT : 0x0020, // frame is copyright + ORIGINAL : 0x0040, // frame is original (else copy) + PADDING : 0x0080, // frame has additional slot + + I_STEREO : 0x0100, // uses intensity joint stereo + MS_STEREO : 0x0200, // uses middle/side joint stereo + FREEFORMAT : 0x0400, // uses free format bitrate + + LSF_EXT : 0x1000, // lower sampling freq. extension + MC_EXT : 0x2000, // multichannel audio extension + MPEG_2_5_EXT: 0x4000 // MPEG 2.5 (unofficial) extension +}; + +const PRIVATE = { + HEADER : 0x0100, // header private bit + III : 0x001f // Layer III private bits (up to 5) +}; + +MP3FrameHeader.MODE = { + SINGLE_CHANNEL: 0, // single channel + DUAL_CHANNEL : 1, // dual channel + JOINT_STEREO : 2, // joint (MS/intensity) stereo + STEREO : 3 // normal LR stereo +}; + +const EMPHASIS = { + NONE : 0, // no emphasis + _50_15_US : 1, // 50/15 microseconds emphasis + CCITT_J_17: 3, // CCITT J.17 emphasis + RESERVED : 2 // unknown emphasis +}; + +MP3FrameHeader.BUFFER_GUARD = 8; +MP3FrameHeader.BUFFER_MDLEN = (511 + 2048 + MP3FrameHeader.BUFFER_GUARD); + +MP3FrameHeader.prototype.copy = function() { + var clone = new MP3FrameHeader(); + var keys = Object.keys(this); + + for (var key in keys) { + clone[key] = this[key]; + } + + return clone; +} + +MP3FrameHeader.prototype.nchannels = function () { + return this.mode === 0 ? 1 : 2; +}; + +MP3FrameHeader.prototype.nbsamples = function() { + return (this.layer === 1 ? 12 : ((this.layer === 3 && (this.flags & MP3FrameHeader.FLAGS.LSF_EXT)) ? 18 : 36)); +}; + +MP3FrameHeader.prototype.framesize = function() { + if (this.bitrate === 0) + return null; + + var padding = (this.flags & MP3FrameHeader.FLAGS.PADDING ? 1 : 0); + switch (this.layer) { + case 1: + var size = (this.bitrate * 12) / this.samplerate | 0; + return (size + padding) * 4; + + case 2: + var size = (this.bitrate * 144) / this.samplerate | 0; + return size + padding; + + case 3: + default: + var lsf = this.flags & MP3FrameHeader.FLAGS.LSF_EXT ? 1 : 0; + var size = (this.bitrate * 144) / (this.samplerate << lsf) | 0; + return size + padding; + } +}; + +MP3FrameHeader.prototype.decode = function(stream) { + this.flags = 0; + this.private_bits = 0; + + // syncword + stream.advance(11); + + // MPEG 2.5 indicator (really part of syncword) + if (stream.read(1) === 0) + this.flags |= MP3FrameHeader.FLAGS.MPEG_2_5_EXT; + + // ID + if (stream.read(1) === 0) { + this.flags |= MP3FrameHeader.FLAGS.LSF_EXT; + } else if (this.flags & MP3FrameHeader.FLAGS.MPEG_2_5_EXT) { + throw new AV.UnderflowError(); // LOSTSYNC + } + + // layer + this.layer = 4 - stream.read(2); + + if (this.layer === 4) + throw new Error('Invalid layer'); + + // protection_bit + if (stream.read(1) === 0) + this.flags |= MP3FrameHeader.FLAGS.PROTECTION; + + // bitrate_index + var index = stream.read(4); + if (index === 15) + throw new Error('Invalid bitrate'); + + if (this.flags & MP3FrameHeader.FLAGS.LSF_EXT) { + this.bitrate = BITRATES[3 + (this.layer >> 1)][index]; + } else { + this.bitrate = BITRATES[this.layer - 1][index]; + } + + // sampling_frequency + index = stream.read(2); + if (index === 3) + throw new Error('Invalid sampling frequency'); + + this.samplerate = SAMPLERATES[index]; + + if (this.flags & MP3FrameHeader.FLAGS.LSF_EXT) { + this.samplerate /= 2; + + if (this.flags & MP3FrameHeader.FLAGS.MPEG_2_5_EXT) + this.samplerate /= 2; + } + + // padding_bit + if (stream.read(1)) + this.flags |= MP3FrameHeader.FLAGS.PADDING; + + // private_bit + if (stream.read(1)) + this.private_bits |= PRIVATE.HEADER; + + // mode + this.mode = 3 - stream.read(2); + + // mode_extension + this.mode_extension = stream.read(2); + + // copyright + if (stream.read(1)) + this.flags |= MP3FrameHeader.FLAGS.COPYRIGHT; + + // original/copy + if (stream.read(1)) + this.flags |= MP3FrameHeader.FLAGS.ORIGINAL; + + // emphasis + this.emphasis = stream.read(2); + + // crc_check + if (this.flags & MP3FrameHeader.FLAGS.PROTECTION) + this.crc_target = stream.read(16); +}; + +MP3FrameHeader.decode = function(stream) { + // synchronize + var ptr = stream.next_frame; + var syncing = true; + var header = null; + + while (syncing) { + syncing = false; + + if (stream.sync) { + if (!stream.available(MP3FrameHeader.BUFFER_GUARD)) { + stream.next_frame = ptr; + throw new AV.UnderflowError(); + } else if (!(stream.getU8(ptr) === 0xff && (stream.getU8(ptr + 1) & 0xe0) === 0xe0)) { + // mark point where frame sync word was expected + stream.this_frame = ptr; + stream.next_frame = ptr + 1; + throw new AV.UnderflowError(); // LOSTSYNC + } + } else { + stream.seek(ptr * 8); + if (!stream.doSync()) + throw new AV.UnderflowError(); + + ptr = stream.nextByte(); + } + + // begin processing + stream.this_frame = ptr; + stream.next_frame = ptr + 1; // possibly bogus sync word + + stream.seek(stream.this_frame * 8); + + header = new MP3FrameHeader(); + header.decode(stream); + + if (header.bitrate === 0) { + if (stream.freerate === 0 || !stream.sync || (header.layer === 3 && stream.freerate > 640000)) + MP3FrameHeader.free_bitrate(stream, header); + + header.bitrate = stream.freerate; + header.flags |= MP3FrameHeader.FLAGS.FREEFORMAT; + } + + // calculate beginning of next frame + var pad_slot = (header.flags & MP3FrameHeader.FLAGS.PADDING) ? 1 : 0; + + if (header.layer === 1) { + var N = (((12 * header.bitrate / header.samplerate) << 0) + pad_slot) * 4; + } else { + var slots_per_frame = (header.layer === 3 && (header.flags & MP3FrameHeader.FLAGS.LSF_EXT)) ? 72 : 144; + var N = ((slots_per_frame * header.bitrate / header.samplerate) << 0) + pad_slot; + } + + // verify there is enough data left in buffer to decode this frame + if (!stream.available(N + MP3FrameHeader.BUFFER_GUARD)) { + stream.next_frame = stream.this_frame; + throw new AV.UnderflowError(); + } + + stream.next_frame = stream.this_frame + N; + + if (!stream.sync) { + // check that a valid frame header follows this frame + ptr = stream.next_frame; + + if (!(stream.getU8(ptr) === 0xff && (stream.getU8(ptr + 1) & 0xe0) === 0xe0)) { + ptr = stream.next_frame = stream.this_frame + 1; + + // emulating 'goto sync' + syncing = true; + continue; + } + + stream.sync = true; + } + } + + header.flags |= MP3FrameHeader.FLAGS.INCOMPLETE; + return header; +}; + +MP3FrameHeader.free_bitrate = function(stream, header) { + var pad_slot = header.flags & MP3FrameHeader.FLAGS.PADDING ? 1 : 0, + slots_per_frame = header.layer === 3 && header.flags & MP3FrameHeader.FLAGS.LSF_EXT ? 72 : 144; + + var start = stream.offset(); + var rate = 0; + + while (stream.doSync()) { + var peek_header = header.copy(); + var peek_stream = stream.copy(); + + if (peek_header.decode(peek_stream) && peek_header.layer === header.layer && peek_header.samplerate === header.samplerate) { + var N = stream.nextByte() - stream.this_frame; + + if (header.layer === 1) { + rate = header.samplerate * (N - 4 * pad_slot + 4) / 48 / 1000 | 0; + } else { + rate = header.samplerate * (N - pad_slot + 1) / slots_per_frame / 1000 | 0; + } + + if (rate >= 8) + break; + } + + stream.advance(8); + } + + stream.seek(start); + + if (rate < 8 || (header.layer === 3 && rate > 640)) + throw new AV.UnderflowError(); // LOSTSYNC + + stream.freerate = rate * 1000; +}; + +module.exports = MP3FrameHeader; + +},{}],6:[function(require,module,exports){ +/* + * These are the Huffman code words for Layer III. + * The data for these tables are derived from Table B.7 of ISO/IEC 11172-3. + * + * These tables support decoding up to 4 Huffman code bits at a time. + */ + +var PTR = function(offs, bits) { + return { + final: 0, + ptr: { + bits: bits, + offset: offs + } + }; +}; + +var huffquad_V = function (v, w, x, y, hlen) { + return { + final: 1, + value: { + v: v, + w: w, + x: x, + y: y, + hlen: hlen + } + }; +}; + +const hufftabA = [ + /* 0000 */ PTR(16, 2), + /* 0001 */ PTR(20, 2), + /* 0010 */ PTR(24, 1), + /* 0011 */ PTR(26, 1), + /* 0100 */ huffquad_V(0, 0, 1, 0, 4), + /* 0101 */ huffquad_V(0, 0, 0, 1, 4), + /* 0110 */ huffquad_V(0, 1, 0, 0, 4), + /* 0111 */ huffquad_V(1, 0, 0, 0, 4), + /* 1000 */ huffquad_V(0, 0, 0, 0, 1), + /* 1001 */ huffquad_V(0, 0, 0, 0, 1), + /* 1010 */ huffquad_V(0, 0, 0, 0, 1), + /* 1011 */ huffquad_V(0, 0, 0, 0, 1), + /* 1100 */ huffquad_V(0, 0, 0, 0, 1), + /* 1101 */ huffquad_V(0, 0, 0, 0, 1), + /* 1110 */ huffquad_V(0, 0, 0, 0, 1), + /* 1111 */ huffquad_V(0, 0, 0, 0, 1), + + /* 0000 ... */ + /* 00 */ huffquad_V(1, 0, 1, 1, 2), /* 16 */ + /* 01 */ huffquad_V(1, 1, 1, 1, 2), + /* 10 */ huffquad_V(1, 1, 0, 1, 2), + /* 11 */ huffquad_V(1, 1, 1, 0, 2), + + /* 0001 ... */ + /* 00 */ huffquad_V(0, 1, 1, 1, 2), /* 20 */ + /* 01 */ huffquad_V(0, 1, 0, 1, 2), + /* 10 */ huffquad_V(1, 0, 0, 1, 1), + /* 11 */ huffquad_V(1, 0, 0, 1, 1), + + /* 0010 ... */ + /* 0 */ huffquad_V(0, 1, 1, 0, 1), /* 24 */ + /* 1 */ huffquad_V(0, 0, 1, 1, 1), + + /* 0011 ... */ + /* 0 */ huffquad_V(1, 0, 1, 0, 1), /* 26 */ + /* 1 */ huffquad_V(1, 1, 0, 0, 1) +]; + +const hufftabB = [ + /* 0000 */ huffquad_V(1, 1, 1, 1, 4), + /* 0001 */ huffquad_V(1, 1, 1, 0, 4), + /* 0010 */ huffquad_V(1, 1, 0, 1, 4), + /* 0011 */ huffquad_V(1, 1, 0, 0, 4), + /* 0100 */ huffquad_V(1, 0, 1, 1, 4), + /* 0101 */ huffquad_V(1, 0, 1, 0, 4), + /* 0110 */ huffquad_V(1, 0, 0, 1, 4), + /* 0111 */ huffquad_V(1, 0, 0, 0, 4), + /* 1000 */ huffquad_V(0, 1, 1, 1, 4), + /* 1001 */ huffquad_V(0, 1, 1, 0, 4), + /* 1010 */ huffquad_V(0, 1, 0, 1, 4), + /* 1011 */ huffquad_V(0, 1, 0, 0, 4), + /* 1100 */ huffquad_V(0, 0, 1, 1, 4), + /* 1101 */ huffquad_V(0, 0, 1, 0, 4), + /* 1110 */ huffquad_V(0, 0, 0, 1, 4), + /* 1111 */ huffquad_V(0, 0, 0, 0, 4) +]; + +var V = function (x, y, hlen) { + return { + final: 1, + value: { + x: x, + y: y, + hlen: hlen + } + }; +}; + +const hufftab0 = [ + /* */ V(0, 0, 0) +]; + +const hufftab1 = [ + /* 000 */ V(1, 1, 3), + /* 001 */ V(0, 1, 3), + /* 010 */ V(1, 0, 2), + /* 011 */ V(1, 0, 2), + /* 100 */ V(0, 0, 1), + /* 101 */ V(0, 0, 1), + /* 110 */ V(0, 0, 1), + /* 111 */ V(0, 0, 1) +]; + +const hufftab2 = [ + /* 000 */ PTR(8, 3), + /* 001 */ V(1, 1, 3), + /* 010 */ V(0, 1, 3), + /* 011 */ V(1, 0, 3), + /* 100 */ V(0, 0, 1), + /* 101 */ V(0, 0, 1), + /* 110 */ V(0, 0, 1), + /* 111 */ V(0, 0, 1), + + /* 000 ... */ + /* 000 */ V(2, 2, 3), /* 8 */ + /* 001 */ V(0, 2, 3), + /* 010 */ V(1, 2, 2), + /* 011 */ V(1, 2, 2), + /* 100 */ V(2, 1, 2), + /* 101 */ V(2, 1, 2), + /* 110 */ V(2, 0, 2), + /* 111 */ V(2, 0, 2) +]; + +const hufftab3 = [ + /* 000 */ PTR(8, 3), + /* 001 */ V(1, 0, 3), + /* 010 */ V(1, 1, 2), + /* 011 */ V(1, 1, 2), + /* 100 */ V(0, 1, 2), + /* 101 */ V(0, 1, 2), + /* 110 */ V(0, 0, 2), + /* 111 */ V(0, 0, 2), + + /* 000 ... */ + /* 000 */ V(2, 2, 3), /* 8 */ + /* 001 */ V(0, 2, 3), + /* 010 */ V(1, 2, 2), + /* 011 */ V(1, 2, 2), + /* 100 */ V(2, 1, 2), + /* 101 */ V(2, 1, 2), + /* 110 */ V(2, 0, 2), + /* 111 */ V(2, 0, 2) +]; + +const hufftab5 = [ + /* 000 */ PTR(8, 4), + /* 001 */ V(1, 1, 3), + /* 010 */ V(0, 1, 3), + /* 011 */ V(1, 0, 3), + /* 100 */ V(0, 0, 1), + /* 101 */ V(0, 0, 1), + /* 110 */ V(0, 0, 1), + /* 111 */ V(0, 0, 1), + + /* 000 ... */ + /* 0000 */ PTR(24, 1), /* 8 */ + /* 0001 */ V(3, 2, 4), + /* 0010 */ V(3, 1, 3), + /* 0011 */ V(3, 1, 3), + /* 0100 */ V(1, 3, 4), + /* 0101 */ V(0, 3, 4), + /* 0110 */ V(3, 0, 4), + /* 0111 */ V(2, 2, 4), + /* 1000 */ V(1, 2, 3), + /* 1001 */ V(1, 2, 3), + /* 1010 */ V(2, 1, 3), + /* 1011 */ V(2, 1, 3), + /* 1100 */ V(0, 2, 3), + /* 1101 */ V(0, 2, 3), + /* 1110 */ V(2, 0, 3), + /* 1111 */ V(2, 0, 3), + + /* 000 0000 ... */ + /* 0 */ V(3, 3, 1), /* 24 */ + /* 1 */ V(2, 3, 1) +]; + +const hufftab6 = [ + /* 0000 */ PTR(16, 3), + /* 0001 */ PTR(24, 1), + /* 0010 */ PTR(26, 1), + /* 0011 */ V(1, 2, 4), + /* 0100 */ V(2, 1, 4), + /* 0101 */ V(2, 0, 4), + /* 0110 */ V(0, 1, 3), + /* 0111 */ V(0, 1, 3), + /* 1000 */ V(1, 1, 2), + /* 1001 */ V(1, 1, 2), + /* 1010 */ V(1, 1, 2), + /* 1011 */ V(1, 1, 2), + /* 1100 */ V(1, 0, 3), + /* 1101 */ V(1, 0, 3), + /* 1110 */ V(0, 0, 3), + /* 1111 */ V(0, 0, 3), + + /* 0000 ... */ + /* 000 */ V(3, 3, 3), /* 16 */ + /* 001 */ V(0, 3, 3), + /* 010 */ V(2, 3, 2), + /* 011 */ V(2, 3, 2), + /* 100 */ V(3, 2, 2), + /* 101 */ V(3, 2, 2), + /* 110 */ V(3, 0, 2), + /* 111 */ V(3, 0, 2), + + /* 0001 ... */ + /* 0 */ V(1, 3, 1), /* 24 */ + /* 1 */ V(3, 1, 1), + + /* 0010 ... */ + /* 0 */ V(2, 2, 1), /* 26 */ + /* 1 */ V(0, 2, 1) +]; + +const hufftab7 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 2), + /* 0011 */ V(1, 1, 4), + /* 0100 */ V(0, 1, 3), + /* 0101 */ V(0, 1, 3), + /* 0110 */ V(1, 0, 3), + /* 0111 */ V(1, 0, 3), + /* 1000 */ V(0, 0, 1), + /* 1001 */ V(0, 0, 1), + /* 1010 */ V(0, 0, 1), + /* 1011 */ V(0, 0, 1), + /* 1100 */ V(0, 0, 1), + /* 1101 */ V(0, 0, 1), + /* 1110 */ V(0, 0, 1), + /* 1111 */ V(0, 0, 1), + + /* 0000 ... */ + /* 0000 */ PTR(52, 2), /* 16 */ + /* 0001 */ PTR(56, 1), + /* 0010 */ PTR(58, 1), + /* 0011 */ V(1, 5, 4), + /* 0100 */ V(5, 1, 4), + /* 0101 */ PTR(60, 1), + /* 0110 */ V(5, 0, 4), + /* 0111 */ PTR(62, 1), + /* 1000 */ V(2, 4, 4), + /* 1001 */ V(4, 2, 4), + /* 1010 */ V(1, 4, 3), + /* 1011 */ V(1, 4, 3), + /* 1100 */ V(4, 1, 3), + /* 1101 */ V(4, 1, 3), + /* 1110 */ V(4, 0, 3), + /* 1111 */ V(4, 0, 3), + + /* 0001 ... */ + /* 0000 */ V(0, 4, 4), /* 32 */ + /* 0001 */ V(2, 3, 4), + /* 0010 */ V(3, 2, 4), + /* 0011 */ V(0, 3, 4), + /* 0100 */ V(1, 3, 3), + /* 0101 */ V(1, 3, 3), + /* 0110 */ V(3, 1, 3), + /* 0111 */ V(3, 1, 3), + /* 1000 */ V(3, 0, 3), + /* 1001 */ V(3, 0, 3), + /* 1010 */ V(2, 2, 3), + /* 1011 */ V(2, 2, 3), + /* 1100 */ V(1, 2, 2), + /* 1101 */ V(1, 2, 2), + /* 1110 */ V(1, 2, 2), + /* 1111 */ V(1, 2, 2), + + /* 0010 ... */ + /* 00 */ V(2, 1, 1), /* 48 */ + /* 01 */ V(2, 1, 1), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 00 */ V(5, 5, 2), /* 52 */ + /* 01 */ V(4, 5, 2), + /* 10 */ V(5, 4, 2), + /* 11 */ V(5, 3, 2), + + /* 0000 0001 ... */ + /* 0 */ V(3, 5, 1), /* 56 */ + /* 1 */ V(4, 4, 1), + + /* 0000 0010 ... */ + /* 0 */ V(2, 5, 1), /* 58 */ + /* 1 */ V(5, 2, 1), + + /* 0000 0101 ... */ + /* 0 */ V(0, 5, 1), /* 60 */ + /* 1 */ V(3, 4, 1), + + /* 0000 0111 ... */ + /* 0 */ V(4, 3, 1), /* 62 */ + /* 1 */ V(3, 3, 1) +]; + +const hufftab8 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ V(1, 2, 4), + /* 0011 */ V(2, 1, 4), + /* 0100 */ V(1, 1, 2), + /* 0101 */ V(1, 1, 2), + /* 0110 */ V(1, 1, 2), + /* 0111 */ V(1, 1, 2), + /* 1000 */ V(0, 1, 3), + /* 1001 */ V(0, 1, 3), + /* 1010 */ V(1, 0, 3), + /* 1011 */ V(1, 0, 3), + /* 1100 */ V(0, 0, 2), + /* 1101 */ V(0, 0, 2), + /* 1110 */ V(0, 0, 2), + /* 1111 */ V(0, 0, 2), + + /* 0000 ... */ + /* 0000 */ PTR(48, 3), /* 16 */ + /* 0001 */ PTR(56, 2), + /* 0010 */ PTR(60, 1), + /* 0011 */ V(1, 5, 4), + /* 0100 */ V(5, 1, 4), + /* 0101 */ PTR(62, 1), + /* 0110 */ PTR(64, 1), + /* 0111 */ V(2, 4, 4), + /* 1000 */ V(4, 2, 4), + /* 1001 */ V(1, 4, 4), + /* 1010 */ V(4, 1, 3), + /* 1011 */ V(4, 1, 3), + /* 1100 */ V(0, 4, 4), + /* 1101 */ V(4, 0, 4), + /* 1110 */ V(2, 3, 4), + /* 1111 */ V(3, 2, 4), + + /* 0001 ... */ + /* 0000 */ V(1, 3, 4), /* 32 */ + /* 0001 */ V(3, 1, 4), + /* 0010 */ V(0, 3, 4), + /* 0011 */ V(3, 0, 4), + /* 0100 */ V(2, 2, 2), + /* 0101 */ V(2, 2, 2), + /* 0110 */ V(2, 2, 2), + /* 0111 */ V(2, 2, 2), + /* 1000 */ V(0, 2, 2), + /* 1001 */ V(0, 2, 2), + /* 1010 */ V(0, 2, 2), + /* 1011 */ V(0, 2, 2), + /* 1100 */ V(2, 0, 2), + /* 1101 */ V(2, 0, 2), + /* 1110 */ V(2, 0, 2), + /* 1111 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 000 */ V(5, 5, 3), /* 48 */ + /* 001 */ V(5, 4, 3), + /* 010 */ V(4, 5, 2), + /* 011 */ V(4, 5, 2), + /* 100 */ V(5, 3, 1), + /* 101 */ V(5, 3, 1), + /* 110 */ V(5, 3, 1), + /* 111 */ V(5, 3, 1), + + /* 0000 0001 ... */ + /* 00 */ V(3, 5, 2), /* 56 */ + /* 01 */ V(4, 4, 2), + /* 10 */ V(2, 5, 1), + /* 11 */ V(2, 5, 1), + + /* 0000 0010 ... */ + /* 0 */ V(5, 2, 1), /* 60 */ + /* 1 */ V(0, 5, 1), + + /* 0000 0101 ... */ + /* 0 */ V(3, 4, 1), /* 62 */ + /* 1 */ V(4, 3, 1), + + /* 0000 0110 ... */ + /* 0 */ V(5, 0, 1), /* 64 */ + /* 1 */ V(3, 3, 1) +]; + +const hufftab9 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 3), + /* 0010 */ PTR(40, 2), + /* 0011 */ PTR(44, 2), + /* 0100 */ PTR(48, 1), + /* 0101 */ V(1, 2, 4), + /* 0110 */ V(2, 1, 4), + /* 0111 */ V(2, 0, 4), + /* 1000 */ V(1, 1, 3), + /* 1001 */ V(1, 1, 3), + /* 1010 */ V(0, 1, 3), + /* 1011 */ V(0, 1, 3), + /* 1100 */ V(1, 0, 3), + /* 1101 */ V(1, 0, 3), + /* 1110 */ V(0, 0, 3), + /* 1111 */ V(0, 0, 3), + + /* 0000 ... */ + /* 0000 */ PTR(50, 1), /* 16 */ + /* 0001 */ V(3, 5, 4), + /* 0010 */ V(5, 3, 4), + /* 0011 */ PTR(52, 1), + /* 0100 */ V(4, 4, 4), + /* 0101 */ V(2, 5, 4), + /* 0110 */ V(5, 2, 4), + /* 0111 */ V(1, 5, 4), + /* 1000 */ V(5, 1, 3), + /* 1001 */ V(5, 1, 3), + /* 1010 */ V(3, 4, 3), + /* 1011 */ V(3, 4, 3), + /* 1100 */ V(4, 3, 3), + /* 1101 */ V(4, 3, 3), + /* 1110 */ V(5, 0, 4), + /* 1111 */ V(0, 4, 4), + + /* 0001 ... */ + /* 000 */ V(2, 4, 3), /* 32 */ + /* 001 */ V(4, 2, 3), + /* 010 */ V(3, 3, 3), + /* 011 */ V(4, 0, 3), + /* 100 */ V(1, 4, 2), + /* 101 */ V(1, 4, 2), + /* 110 */ V(4, 1, 2), + /* 111 */ V(4, 1, 2), + + /* 0010 ... */ + /* 00 */ V(2, 3, 2), /* 40 */ + /* 01 */ V(3, 2, 2), + /* 10 */ V(1, 3, 1), + /* 11 */ V(1, 3, 1), + + /* 0011 ... */ + /* 00 */ V(3, 1, 1), /* 44 */ + /* 01 */ V(3, 1, 1), + /* 10 */ V(0, 3, 2), + /* 11 */ V(3, 0, 2), + + /* 0100 ... */ + /* 0 */ V(2, 2, 1), /* 48 */ + /* 1 */ V(0, 2, 1), + + /* 0000 0000 ... */ + /* 0 */ V(5, 5, 1), /* 50 */ + /* 1 */ V(4, 5, 1), + + /* 0000 0011 ... */ + /* 0 */ V(5, 4, 1), /* 52 */ + /* 1 */ V(0, 5, 1) +]; + +const hufftab10 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 2), + /* 0011 */ V(1, 1, 4), + /* 0100 */ V(0, 1, 3), + /* 0101 */ V(0, 1, 3), + /* 0110 */ V(1, 0, 3), + /* 0111 */ V(1, 0, 3), + /* 1000 */ V(0, 0, 1), + /* 1001 */ V(0, 0, 1), + /* 1010 */ V(0, 0, 1), + /* 1011 */ V(0, 0, 1), + /* 1100 */ V(0, 0, 1), + /* 1101 */ V(0, 0, 1), + /* 1110 */ V(0, 0, 1), + /* 1111 */ V(0, 0, 1), + + /* 0000 ... */ + /* 0000 */ PTR(52, 3), /* 16 */ + /* 0001 */ PTR(60, 2), + /* 0010 */ PTR(64, 3), + /* 0011 */ PTR(72, 1), + /* 0100 */ PTR(74, 2), + /* 0101 */ PTR(78, 2), + /* 0110 */ PTR(82, 2), + /* 0111 */ V(1, 7, 4), + /* 1000 */ V(7, 1, 4), + /* 1001 */ PTR(86, 1), + /* 1010 */ PTR(88, 2), + /* 1011 */ PTR(92, 2), + /* 1100 */ V(1, 6, 4), + /* 1101 */ V(6, 1, 4), + /* 1110 */ V(6, 0, 4), + /* 1111 */ PTR(96, 1), + + /* 0001 ... */ + /* 0000 */ PTR(98, 1), /* 32 */ + /* 0001 */ PTR(100, 1), + /* 0010 */ V(1, 4, 4), + /* 0011 */ V(4, 1, 4), + /* 0100 */ V(4, 0, 4), + /* 0101 */ V(2, 3, 4), + /* 0110 */ V(3, 2, 4), + /* 0111 */ V(0, 3, 4), + /* 1000 */ V(1, 3, 3), + /* 1001 */ V(1, 3, 3), + /* 1010 */ V(3, 1, 3), + /* 1011 */ V(3, 1, 3), + /* 1100 */ V(3, 0, 3), + /* 1101 */ V(3, 0, 3), + /* 1110 */ V(2, 2, 3), + /* 1111 */ V(2, 2, 3), + + /* 0010 ... */ + /* 00 */ V(1, 2, 2), /* 48 */ + /* 01 */ V(2, 1, 2), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 000 */ V(7, 7, 3), /* 52 */ + /* 001 */ V(6, 7, 3), + /* 010 */ V(7, 6, 3), + /* 011 */ V(5, 7, 3), + /* 100 */ V(7, 5, 3), + /* 101 */ V(6, 6, 3), + /* 110 */ V(4, 7, 2), + /* 111 */ V(4, 7, 2), + + /* 0000 0001 ... */ + /* 00 */ V(7, 4, 2), /* 60 */ + /* 01 */ V(5, 6, 2), + /* 10 */ V(6, 5, 2), + /* 11 */ V(3, 7, 2), + + /* 0000 0010 ... */ + /* 000 */ V(7, 3, 2), /* 64 */ + /* 001 */ V(7, 3, 2), + /* 010 */ V(4, 6, 2), + /* 011 */ V(4, 6, 2), + /* 100 */ V(5, 5, 3), + /* 101 */ V(5, 4, 3), + /* 110 */ V(6, 3, 2), + /* 111 */ V(6, 3, 2), + + /* 0000 0011 ... */ + /* 0 */ V(2, 7, 1), /* 72 */ + /* 1 */ V(7, 2, 1), + + /* 0000 0100 ... */ + /* 00 */ V(6, 4, 2), /* 74 */ + /* 01 */ V(0, 7, 2), + /* 10 */ V(7, 0, 1), + /* 11 */ V(7, 0, 1), + + /* 0000 0101 ... */ + /* 00 */ V(6, 2, 1), /* 78 */ + /* 01 */ V(6, 2, 1), + /* 10 */ V(4, 5, 2), + /* 11 */ V(3, 5, 2), + + /* 0000 0110 ... */ + /* 00 */ V(0, 6, 1), /* 82 */ + /* 01 */ V(0, 6, 1), + /* 10 */ V(5, 3, 2), + /* 11 */ V(4, 4, 2), + + /* 0000 1001 ... */ + /* 0 */ V(3, 6, 1), /* 86 */ + /* 1 */ V(2, 6, 1), + + /* 0000 1010 ... */ + /* 00 */ V(2, 5, 2), /* 88 */ + /* 01 */ V(5, 2, 2), + /* 10 */ V(1, 5, 1), + /* 11 */ V(1, 5, 1), + + /* 0000 1011 ... */ + /* 00 */ V(5, 1, 1), /* 92 */ + /* 01 */ V(5, 1, 1), + /* 10 */ V(3, 4, 2), + /* 11 */ V(4, 3, 2), + + /* 0000 1111 ... */ + /* 0 */ V(0, 5, 1), /* 96 */ + /* 1 */ V(5, 0, 1), + + /* 0001 0000 ... */ + /* 0 */ V(2, 4, 1), /* 98 */ + /* 1 */ V(4, 2, 1), + + /* 0001 0001 ... */ + /* 0 */ V(3, 3, 1), /* 100 */ + /* 1 */ V(0, 4, 1) +]; + +const hufftab11 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 3), + /* 0100 */ V(1, 2, 4), + /* 0101 */ PTR(72, 1), + /* 0110 */ V(1, 1, 3), + /* 0111 */ V(1, 1, 3), + /* 1000 */ V(0, 1, 3), + /* 1001 */ V(0, 1, 3), + /* 1010 */ V(1, 0, 3), + /* 1011 */ V(1, 0, 3), + /* 1100 */ V(0, 0, 2), + /* 1101 */ V(0, 0, 2), + /* 1110 */ V(0, 0, 2), + /* 1111 */ V(0, 0, 2), + + /* 0000 ... */ + /* 0000 */ PTR(74, 2), /* 16 */ + /* 0001 */ PTR(78, 3), + /* 0010 */ PTR(86, 2), + /* 0011 */ PTR(90, 1), + /* 0100 */ PTR(92, 2), + /* 0101 */ V(2, 7, 4), + /* 0110 */ V(7, 2, 4), + /* 0111 */ PTR(96, 1), + /* 1000 */ V(7, 1, 3), + /* 1001 */ V(7, 1, 3), + /* 1010 */ V(1, 7, 4), + /* 1011 */ V(7, 0, 4), + /* 1100 */ V(3, 6, 4), + /* 1101 */ V(6, 3, 4), + /* 1110 */ V(6, 0, 4), + /* 1111 */ PTR(98, 1), + + /* 0001 ... */ + /* 0000 */ PTR(100, 1), /* 32 */ + /* 0001 */ V(1, 5, 4), + /* 0010 */ V(6, 2, 3), + /* 0011 */ V(6, 2, 3), + /* 0100 */ V(2, 6, 4), + /* 0101 */ V(0, 6, 4), + /* 0110 */ V(1, 6, 3), + /* 0111 */ V(1, 6, 3), + /* 1000 */ V(6, 1, 3), + /* 1001 */ V(6, 1, 3), + /* 1010 */ V(5, 1, 4), + /* 1011 */ V(3, 4, 4), + /* 1100 */ V(5, 0, 4), + /* 1101 */ PTR(102, 1), + /* 1110 */ V(2, 4, 4), + /* 1111 */ V(4, 2, 4), + + /* 0010 ... */ + /* 0000 */ V(1, 4, 4), /* 48 */ + /* 0001 */ V(4, 1, 4), + /* 0010 */ V(0, 4, 4), + /* 0011 */ V(4, 0, 4), + /* 0100 */ V(2, 3, 3), + /* 0101 */ V(2, 3, 3), + /* 0110 */ V(3, 2, 3), + /* 0111 */ V(3, 2, 3), + /* 1000 */ V(1, 3, 2), + /* 1001 */ V(1, 3, 2), + /* 1010 */ V(1, 3, 2), + /* 1011 */ V(1, 3, 2), + /* 1100 */ V(3, 1, 2), + /* 1101 */ V(3, 1, 2), + /* 1110 */ V(3, 1, 2), + /* 1111 */ V(3, 1, 2), + + /* 0011 ... */ + /* 000 */ V(0, 3, 3), /* 64 */ + /* 001 */ V(3, 0, 3), + /* 010 */ V(2, 2, 2), + /* 011 */ V(2, 2, 2), + /* 100 */ V(2, 1, 1), + /* 101 */ V(2, 1, 1), + /* 110 */ V(2, 1, 1), + /* 111 */ V(2, 1, 1), + + /* 0101 ... */ + /* 0 */ V(0, 2, 1), /* 72 */ + /* 1 */ V(2, 0, 1), + + /* 0000 0000 ... */ + /* 00 */ V(7, 7, 2), /* 74 */ + /* 01 */ V(6, 7, 2), + /* 10 */ V(7, 6, 2), + /* 11 */ V(7, 5, 2), + + /* 0000 0001 ... */ + /* 000 */ V(6, 6, 2), /* 78 */ + /* 001 */ V(6, 6, 2), + /* 010 */ V(4, 7, 2), + /* 011 */ V(4, 7, 2), + /* 100 */ V(7, 4, 2), + /* 101 */ V(7, 4, 2), + /* 110 */ V(5, 7, 3), + /* 111 */ V(5, 5, 3), + + /* 0000 0010 ... */ + /* 00 */ V(5, 6, 2), /* 86 */ + /* 01 */ V(6, 5, 2), + /* 10 */ V(3, 7, 1), + /* 11 */ V(3, 7, 1), + + /* 0000 0011 ... */ + /* 0 */ V(7, 3, 1), /* 90 */ + /* 1 */ V(4, 6, 1), + + /* 0000 0100 ... */ + /* 00 */ V(4, 5, 2), /* 92 */ + /* 01 */ V(5, 4, 2), + /* 10 */ V(3, 5, 2), + /* 11 */ V(5, 3, 2), + + /* 0000 0111 ... */ + /* 0 */ V(6, 4, 1), /* 96 */ + /* 1 */ V(0, 7, 1), + + /* 0000 1111 ... */ + /* 0 */ V(4, 4, 1), /* 98 */ + /* 1 */ V(2, 5, 1), + + /* 0001 0000 ... */ + /* 0 */ V(5, 2, 1), /* 100 */ + /* 1 */ V(0, 5, 1), + + /* 0001 1101 ... */ + /* 0 */ V(4, 3, 1), /* 102 */ + /* 1 */ V(3, 3, 1) +]; + +const hufftab12 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 2), + /* 0100 */ PTR(68, 3), + /* 0101 */ PTR(76, 1), + /* 0110 */ V(1, 2, 4), + /* 0111 */ V(2, 1, 4), + /* 1000 */ PTR(78, 1), + /* 1001 */ V(0, 0, 4), + /* 1010 */ V(1, 1, 3), + /* 1011 */ V(1, 1, 3), + /* 1100 */ V(0, 1, 3), + /* 1101 */ V(0, 1, 3), + /* 1110 */ V(1, 0, 3), + /* 1111 */ V(1, 0, 3), + + /* 0000 ... */ + /* 0000 */ PTR(80, 2), /* 16 */ + /* 0001 */ PTR(84, 1), + /* 0010 */ PTR(86, 1), + /* 0011 */ PTR(88, 1), + /* 0100 */ V(5, 6, 4), + /* 0101 */ V(3, 7, 4), + /* 0110 */ PTR(90, 1), + /* 0111 */ V(2, 7, 4), + /* 1000 */ V(7, 2, 4), + /* 1001 */ V(4, 6, 4), + /* 1010 */ V(6, 4, 4), + /* 1011 */ V(1, 7, 4), + /* 1100 */ V(7, 1, 4), + /* 1101 */ PTR(92, 1), + /* 1110 */ V(3, 6, 4), + /* 1111 */ V(6, 3, 4), + + /* 0001 ... */ + /* 0000 */ V(4, 5, 4), /* 32 */ + /* 0001 */ V(5, 4, 4), + /* 0010 */ V(4, 4, 4), + /* 0011 */ PTR(94, 1), + /* 0100 */ V(2, 6, 3), + /* 0101 */ V(2, 6, 3), + /* 0110 */ V(6, 2, 3), + /* 0111 */ V(6, 2, 3), + /* 1000 */ V(6, 1, 3), + /* 1001 */ V(6, 1, 3), + /* 1010 */ V(1, 6, 4), + /* 1011 */ V(6, 0, 4), + /* 1100 */ V(3, 5, 4), + /* 1101 */ V(5, 3, 4), + /* 1110 */ V(2, 5, 4), + /* 1111 */ V(5, 2, 4), + + /* 0010 ... */ + /* 0000 */ V(1, 5, 3), /* 48 */ + /* 0001 */ V(1, 5, 3), + /* 0010 */ V(5, 1, 3), + /* 0011 */ V(5, 1, 3), + /* 0100 */ V(3, 4, 3), + /* 0101 */ V(3, 4, 3), + /* 0110 */ V(4, 3, 3), + /* 0111 */ V(4, 3, 3), + /* 1000 */ V(5, 0, 4), + /* 1001 */ V(0, 4, 4), + /* 1010 */ V(2, 4, 3), + /* 1011 */ V(2, 4, 3), + /* 1100 */ V(4, 2, 3), + /* 1101 */ V(4, 2, 3), + /* 1110 */ V(1, 4, 3), + /* 1111 */ V(1, 4, 3), + + /* 0011 ... */ + /* 00 */ V(3, 3, 2), /* 64 */ + /* 01 */ V(4, 1, 2), + /* 10 */ V(2, 3, 2), + /* 11 */ V(3, 2, 2), + + /* 0100 ... */ + /* 000 */ V(4, 0, 3), /* 68 */ + /* 001 */ V(0, 3, 3), + /* 010 */ V(3, 0, 2), + /* 011 */ V(3, 0, 2), + /* 100 */ V(1, 3, 1), + /* 101 */ V(1, 3, 1), + /* 110 */ V(1, 3, 1), + /* 111 */ V(1, 3, 1), + + /* 0101 ... */ + /* 0 */ V(3, 1, 1), /* 76 */ + /* 1 */ V(2, 2, 1), + + /* 1000 ... */ + /* 0 */ V(0, 2, 1), /* 78 */ + /* 1 */ V(2, 0, 1), + + /* 0000 0000 ... */ + /* 00 */ V(7, 7, 2), /* 80 */ + /* 01 */ V(6, 7, 2), + /* 10 */ V(7, 6, 1), + /* 11 */ V(7, 6, 1), + + /* 0000 0001 ... */ + /* 0 */ V(5, 7, 1), /* 84 */ + /* 1 */ V(7, 5, 1), + + /* 0000 0010 ... */ + /* 0 */ V(6, 6, 1), /* 86 */ + /* 1 */ V(4, 7, 1), + + /* 0000 0011 ... */ + /* 0 */ V(7, 4, 1), /* 88 */ + /* 1 */ V(6, 5, 1), + + /* 0000 0110 ... */ + /* 0 */ V(7, 3, 1), /* 90 */ + /* 1 */ V(5, 5, 1), + + /* 0000 1101 ... */ + /* 0 */ V(0, 7, 1), /* 92 */ + /* 1 */ V(7, 0, 1), + + /* 0001 0011 ... */ + /* 0 */ V(0, 6, 1), /* 94 */ + /* 1 */ V(0, 5, 1) +]; + +const hufftab13 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 2), + /* 0100 */ V(1, 1, 4), + /* 0101 */ V(0, 1, 4), + /* 0110 */ V(1, 0, 3), + /* 0111 */ V(1, 0, 3), + /* 1000 */ V(0, 0, 1), + /* 1001 */ V(0, 0, 1), + /* 1010 */ V(0, 0, 1), + /* 1011 */ V(0, 0, 1), + /* 1100 */ V(0, 0, 1), + /* 1101 */ V(0, 0, 1), + /* 1110 */ V(0, 0, 1), + /* 1111 */ V(0, 0, 1), + + /* 0000 ... */ + /* 0000 */ PTR(68, 4), /* 16 */ + /* 0001 */ PTR(84, 4), + /* 0010 */ PTR(100, 4), + /* 0011 */ PTR(116, 4), + /* 0100 */ PTR(132, 4), + /* 0101 */ PTR(148, 4), + /* 0110 */ PTR(164, 3), + /* 0111 */ PTR(172, 3), + /* 1000 */ PTR(180, 3), + /* 1001 */ PTR(188, 3), + /* 1010 */ PTR(196, 3), + /* 1011 */ PTR(204, 3), + /* 1100 */ PTR(212, 1), + /* 1101 */ PTR(214, 2), + /* 1110 */ PTR(218, 3), + /* 1111 */ PTR(226, 1), + + /* 0001 ... */ + /* 0000 */ PTR(228, 2), /* 32 */ + /* 0001 */ PTR(232, 2), + /* 0010 */ PTR(236, 2), + /* 0011 */ PTR(240, 2), + /* 0100 */ V(8, 1, 4), + /* 0101 */ PTR(244, 1), + /* 0110 */ PTR(246, 1), + /* 0111 */ PTR(248, 1), + /* 1000 */ PTR(250, 2), + /* 1001 */ PTR(254, 1), + /* 1010 */ V(1, 5, 4), + /* 1011 */ V(5, 1, 4), + /* 1100 */ PTR(256, 1), + /* 1101 */ PTR(258, 1), + /* 1110 */ PTR(260, 1), + /* 1111 */ V(1, 4, 4), + + /* 0010 ... */ + /* 0000 */ V(4, 1, 3), /* 48 */ + /* 0001 */ V(4, 1, 3), + /* 0010 */ V(0, 4, 4), + /* 0011 */ V(4, 0, 4), + /* 0100 */ V(2, 3, 4), + /* 0101 */ V(3, 2, 4), + /* 0110 */ V(1, 3, 3), + /* 0111 */ V(1, 3, 3), + /* 1000 */ V(3, 1, 3), + /* 1001 */ V(3, 1, 3), + /* 1010 */ V(0, 3, 3), + /* 1011 */ V(0, 3, 3), + /* 1100 */ V(3, 0, 3), + /* 1101 */ V(3, 0, 3), + /* 1110 */ V(2, 2, 3), + /* 1111 */ V(2, 2, 3), + + /* 0011 ... */ + /* 00 */ V(1, 2, 2), /* 64 */ + /* 01 */ V(2, 1, 2), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 0000 */ PTR(262, 4), /* 68 */ + /* 0001 */ PTR(278, 4), + /* 0010 */ PTR(294, 4), + /* 0011 */ PTR(310, 3), + /* 0100 */ PTR(318, 2), + /* 0101 */ PTR(322, 2), + /* 0110 */ PTR(326, 3), + /* 0111 */ PTR(334, 2), + /* 1000 */ PTR(338, 1), + /* 1001 */ PTR(340, 2), + /* 1010 */ PTR(344, 2), + /* 1011 */ PTR(348, 2), + /* 1100 */ PTR(352, 2), + /* 1101 */ PTR(356, 2), + /* 1110 */ V(1, 15, 4), + /* 1111 */ V(15, 1, 4), + + /* 0000 0001 ... */ + /* 0000 */ V(15, 0, 4), /* 84 */ + /* 0001 */ PTR(360, 1), + /* 0010 */ PTR(362, 1), + /* 0011 */ PTR(364, 1), + /* 0100 */ V(14, 2, 4), + /* 0101 */ PTR(366, 1), + /* 0110 */ V(1, 14, 4), + /* 0111 */ V(14, 1, 4), + /* 1000 */ PTR(368, 1), + /* 1001 */ PTR(370, 1), + /* 1010 */ PTR(372, 1), + /* 1011 */ PTR(374, 1), + /* 1100 */ PTR(376, 1), + /* 1101 */ PTR(378, 1), + /* 1110 */ V(12, 6, 4), + /* 1111 */ V(3, 13, 4), + + /* 0000 0010 ... */ + /* 0000 */ PTR(380, 1), /* 100 */ + /* 0001 */ V(2, 13, 4), + /* 0010 */ V(13, 2, 4), + /* 0011 */ V(1, 13, 4), + /* 0100 */ V(11, 7, 4), + /* 0101 */ PTR(382, 1), + /* 0110 */ PTR(384, 1), + /* 0111 */ V(12, 3, 4), + /* 1000 */ PTR(386, 1), + /* 1001 */ V(4, 11, 4), + /* 1010 */ V(13, 1, 3), + /* 1011 */ V(13, 1, 3), + /* 1100 */ V(0, 13, 4), + /* 1101 */ V(13, 0, 4), + /* 1110 */ V(8, 10, 4), + /* 1111 */ V(10, 8, 4), + + /* 0000 0011 ... */ + /* 0000 */ V(4, 12, 4), /* 116 */ + /* 0001 */ V(12, 4, 4), + /* 0010 */ V(6, 11, 4), + /* 0011 */ V(11, 6, 4), + /* 0100 */ V(3, 12, 3), + /* 0101 */ V(3, 12, 3), + /* 0110 */ V(2, 12, 3), + /* 0111 */ V(2, 12, 3), + /* 1000 */ V(12, 2, 3), + /* 1001 */ V(12, 2, 3), + /* 1010 */ V(5, 11, 3), + /* 1011 */ V(5, 11, 3), + /* 1100 */ V(11, 5, 4), + /* 1101 */ V(8, 9, 4), + /* 1110 */ V(1, 12, 3), + /* 1111 */ V(1, 12, 3), + + /* 0000 0100 ... */ + /* 0000 */ V(12, 1, 3), /* 132 */ + /* 0001 */ V(12, 1, 3), + /* 0010 */ V(9, 8, 4), + /* 0011 */ V(0, 12, 4), + /* 0100 */ V(12, 0, 3), + /* 0101 */ V(12, 0, 3), + /* 0110 */ V(11, 4, 4), + /* 0111 */ V(6, 10, 4), + /* 1000 */ V(10, 6, 4), + /* 1001 */ V(7, 9, 4), + /* 1010 */ V(3, 11, 3), + /* 1011 */ V(3, 11, 3), + /* 1100 */ V(11, 3, 3), + /* 1101 */ V(11, 3, 3), + /* 1110 */ V(8, 8, 4), + /* 1111 */ V(5, 10, 4), + + /* 0000 0101 ... */ + /* 0000 */ V(2, 11, 3), /* 148 */ + /* 0001 */ V(2, 11, 3), + /* 0010 */ V(10, 5, 4), + /* 0011 */ V(6, 9, 4), + /* 0100 */ V(10, 4, 3), + /* 0101 */ V(10, 4, 3), + /* 0110 */ V(7, 8, 4), + /* 0111 */ V(8, 7, 4), + /* 1000 */ V(9, 4, 3), + /* 1001 */ V(9, 4, 3), + /* 1010 */ V(7, 7, 4), + /* 1011 */ V(7, 6, 4), + /* 1100 */ V(11, 2, 2), + /* 1101 */ V(11, 2, 2), + /* 1110 */ V(11, 2, 2), + /* 1111 */ V(11, 2, 2), + + /* 0000 0110 ... */ + /* 000 */ V(1, 11, 2), /* 164 */ + /* 001 */ V(1, 11, 2), + /* 010 */ V(11, 1, 2), + /* 011 */ V(11, 1, 2), + /* 100 */ V(0, 11, 3), + /* 101 */ V(11, 0, 3), + /* 110 */ V(9, 6, 3), + /* 111 */ V(4, 10, 3), + + /* 0000 0111 ... */ + /* 000 */ V(3, 10, 3), /* 172 */ + /* 001 */ V(10, 3, 3), + /* 010 */ V(5, 9, 3), + /* 011 */ V(9, 5, 3), + /* 100 */ V(2, 10, 2), + /* 101 */ V(2, 10, 2), + /* 110 */ V(10, 2, 2), + /* 111 */ V(10, 2, 2), + + /* 0000 1000 ... */ + /* 000 */ V(1, 10, 2), /* 180 */ + /* 001 */ V(1, 10, 2), + /* 010 */ V(10, 1, 2), + /* 011 */ V(10, 1, 2), + /* 100 */ V(0, 10, 3), + /* 101 */ V(6, 8, 3), + /* 110 */ V(10, 0, 2), + /* 111 */ V(10, 0, 2), + + /* 0000 1001 ... */ + /* 000 */ V(8, 6, 3), /* 188 */ + /* 001 */ V(4, 9, 3), + /* 010 */ V(9, 3, 2), + /* 011 */ V(9, 3, 2), + /* 100 */ V(3, 9, 3), + /* 101 */ V(5, 8, 3), + /* 110 */ V(8, 5, 3), + /* 111 */ V(6, 7, 3), + + /* 0000 1010 ... */ + /* 000 */ V(2, 9, 2), /* 196 */ + /* 001 */ V(2, 9, 2), + /* 010 */ V(9, 2, 2), + /* 011 */ V(9, 2, 2), + /* 100 */ V(5, 7, 3), + /* 101 */ V(7, 5, 3), + /* 110 */ V(3, 8, 2), + /* 111 */ V(3, 8, 2), + + /* 0000 1011 ... */ + /* 000 */ V(8, 3, 2), /* 204 */ + /* 001 */ V(8, 3, 2), + /* 010 */ V(6, 6, 3), + /* 011 */ V(4, 7, 3), + /* 100 */ V(7, 4, 3), + /* 101 */ V(5, 6, 3), + /* 110 */ V(6, 5, 3), + /* 111 */ V(7, 3, 3), + + /* 0000 1100 ... */ + /* 0 */ V(1, 9, 1), /* 212 */ + /* 1 */ V(9, 1, 1), + + /* 0000 1101 ... */ + /* 00 */ V(0, 9, 2), /* 214 */ + /* 01 */ V(9, 0, 2), + /* 10 */ V(4, 8, 2), + /* 11 */ V(8, 4, 2), + + /* 0000 1110 ... */ + /* 000 */ V(7, 2, 2), /* 218 */ + /* 001 */ V(7, 2, 2), + /* 010 */ V(4, 6, 3), + /* 011 */ V(6, 4, 3), + /* 100 */ V(2, 8, 1), + /* 101 */ V(2, 8, 1), + /* 110 */ V(2, 8, 1), + /* 111 */ V(2, 8, 1), + + /* 0000 1111 ... */ + /* 0 */ V(8, 2, 1), /* 226 */ + /* 1 */ V(1, 8, 1), + + /* 0001 0000 ... */ + /* 00 */ V(3, 7, 2), /* 228 */ + /* 01 */ V(2, 7, 2), + /* 10 */ V(1, 7, 1), + /* 11 */ V(1, 7, 1), + + /* 0001 0001 ... */ + /* 00 */ V(7, 1, 1), /* 232 */ + /* 01 */ V(7, 1, 1), + /* 10 */ V(5, 5, 2), + /* 11 */ V(0, 7, 2), + + /* 0001 0010 ... */ + /* 00 */ V(7, 0, 2), /* 236 */ + /* 01 */ V(3, 6, 2), + /* 10 */ V(6, 3, 2), + /* 11 */ V(4, 5, 2), + + /* 0001 0011 ... */ + /* 00 */ V(5, 4, 2), /* 240 */ + /* 01 */ V(2, 6, 2), + /* 10 */ V(6, 2, 2), + /* 11 */ V(3, 5, 2), + + /* 0001 0101 ... */ + /* 0 */ V(0, 8, 1), /* 244 */ + /* 1 */ V(8, 0, 1), + + /* 0001 0110 ... */ + /* 0 */ V(1, 6, 1), /* 246 */ + /* 1 */ V(6, 1, 1), + + /* 0001 0111 ... */ + /* 0 */ V(0, 6, 1), /* 248 */ + /* 1 */ V(6, 0, 1), + + /* 0001 1000 ... */ + /* 00 */ V(5, 3, 2), /* 250 */ + /* 01 */ V(4, 4, 2), + /* 10 */ V(2, 5, 1), + /* 11 */ V(2, 5, 1), + + /* 0001 1001 ... */ + /* 0 */ V(5, 2, 1), /* 254 */ + /* 1 */ V(0, 5, 1), + + /* 0001 1100 ... */ + /* 0 */ V(3, 4, 1), /* 256 */ + /* 1 */ V(4, 3, 1), + + /* 0001 1101 ... */ + /* 0 */ V(5, 0, 1), /* 258 */ + /* 1 */ V(2, 4, 1), + + /* 0001 1110 ... */ + /* 0 */ V(4, 2, 1), /* 260 */ + /* 1 */ V(3, 3, 1), + + /* 0000 0000 0000 ... */ + /* 0000 */ PTR(388, 3), /* 262 */ + /* 0001 */ V(15, 15, 4), + /* 0010 */ V(14, 15, 4), + /* 0011 */ V(13, 15, 4), + /* 0100 */ V(14, 14, 4), + /* 0101 */ V(12, 15, 4), + /* 0110 */ V(13, 14, 4), + /* 0111 */ V(11, 15, 4), + /* 1000 */ V(15, 11, 4), + /* 1001 */ V(12, 14, 4), + /* 1010 */ V(13, 12, 4), + /* 1011 */ PTR(396, 1), + /* 1100 */ V(14, 12, 3), + /* 1101 */ V(14, 12, 3), + /* 1110 */ V(13, 13, 3), + /* 1111 */ V(13, 13, 3), + + /* 0000 0000 0001 ... */ + /* 0000 */ V(15, 10, 4), /* 278 */ + /* 0001 */ V(12, 13, 4), + /* 0010 */ V(11, 14, 3), + /* 0011 */ V(11, 14, 3), + /* 0100 */ V(14, 11, 3), + /* 0101 */ V(14, 11, 3), + /* 0110 */ V(9, 15, 3), + /* 0111 */ V(9, 15, 3), + /* 1000 */ V(15, 9, 3), + /* 1001 */ V(15, 9, 3), + /* 1010 */ V(14, 10, 3), + /* 1011 */ V(14, 10, 3), + /* 1100 */ V(11, 13, 3), + /* 1101 */ V(11, 13, 3), + /* 1110 */ V(13, 11, 3), + /* 1111 */ V(13, 11, 3), + + /* 0000 0000 0010 ... */ + /* 0000 */ V(8, 15, 3), /* 294 */ + /* 0001 */ V(8, 15, 3), + /* 0010 */ V(15, 8, 3), + /* 0011 */ V(15, 8, 3), + /* 0100 */ V(12, 12, 3), + /* 0101 */ V(12, 12, 3), + /* 0110 */ V(10, 14, 4), + /* 0111 */ V(9, 14, 4), + /* 1000 */ V(8, 14, 3), + /* 1001 */ V(8, 14, 3), + /* 1010 */ V(7, 15, 4), + /* 1011 */ V(7, 14, 4), + /* 1100 */ V(15, 7, 2), + /* 1101 */ V(15, 7, 2), + /* 1110 */ V(15, 7, 2), + /* 1111 */ V(15, 7, 2), + + /* 0000 0000 0011 ... */ + /* 000 */ V(13, 10, 2), /* 310 */ + /* 001 */ V(13, 10, 2), + /* 010 */ V(10, 13, 3), + /* 011 */ V(11, 12, 3), + /* 100 */ V(12, 11, 3), + /* 101 */ V(15, 6, 3), + /* 110 */ V(6, 15, 2), + /* 111 */ V(6, 15, 2), + + /* 0000 0000 0100 ... */ + /* 00 */ V(14, 8, 2), /* 318 */ + /* 01 */ V(5, 15, 2), + /* 10 */ V(9, 13, 2), + /* 11 */ V(13, 9, 2), + + /* 0000 0000 0101 ... */ + /* 00 */ V(15, 5, 2), /* 322 */ + /* 01 */ V(14, 7, 2), + /* 10 */ V(10, 12, 2), + /* 11 */ V(11, 11, 2), + + /* 0000 0000 0110 ... */ + /* 000 */ V(4, 15, 2), /* 326 */ + /* 001 */ V(4, 15, 2), + /* 010 */ V(15, 4, 2), + /* 011 */ V(15, 4, 2), + /* 100 */ V(12, 10, 3), + /* 101 */ V(14, 6, 3), + /* 110 */ V(15, 3, 2), + /* 111 */ V(15, 3, 2), + + /* 0000 0000 0111 ... */ + /* 00 */ V(3, 15, 1), /* 334 */ + /* 01 */ V(3, 15, 1), + /* 10 */ V(8, 13, 2), + /* 11 */ V(13, 8, 2), + + /* 0000 0000 1000 ... */ + /* 0 */ V(2, 15, 1), /* 338 */ + /* 1 */ V(15, 2, 1), + + /* 0000 0000 1001 ... */ + /* 00 */ V(6, 14, 2), /* 340 */ + /* 01 */ V(9, 12, 2), + /* 10 */ V(0, 15, 1), + /* 11 */ V(0, 15, 1), + + /* 0000 0000 1010 ... */ + /* 00 */ V(12, 9, 2), /* 344 */ + /* 01 */ V(5, 14, 2), + /* 10 */ V(10, 11, 1), + /* 11 */ V(10, 11, 1), + + /* 0000 0000 1011 ... */ + /* 00 */ V(7, 13, 2), /* 348 */ + /* 01 */ V(13, 7, 2), + /* 10 */ V(4, 14, 1), + /* 11 */ V(4, 14, 1), + + /* 0000 0000 1100 ... */ + /* 00 */ V(12, 8, 2), /* 352 */ + /* 01 */ V(13, 6, 2), + /* 10 */ V(3, 14, 1), + /* 11 */ V(3, 14, 1), + + /* 0000 0000 1101 ... */ + /* 00 */ V(11, 9, 1), /* 356 */ + /* 01 */ V(11, 9, 1), + /* 10 */ V(9, 11, 2), + /* 11 */ V(10, 10, 2), + + /* 0000 0001 0001 ... */ + /* 0 */ V(11, 10, 1), /* 360 */ + /* 1 */ V(14, 5, 1), + + /* 0000 0001 0010 ... */ + /* 0 */ V(14, 4, 1), /* 362 */ + /* 1 */ V(8, 12, 1), + + /* 0000 0001 0011 ... */ + /* 0 */ V(6, 13, 1), /* 364 */ + /* 1 */ V(14, 3, 1), + + /* 0000 0001 0101 ... */ + /* 0 */ V(2, 14, 1), /* 366 */ + /* 1 */ V(0, 14, 1), + + /* 0000 0001 1000 ... */ + /* 0 */ V(14, 0, 1), /* 368 */ + /* 1 */ V(5, 13, 1), + + /* 0000 0001 1001 ... */ + /* 0 */ V(13, 5, 1), /* 370 */ + /* 1 */ V(7, 12, 1), + + /* 0000 0001 1010 ... */ + /* 0 */ V(12, 7, 1), /* 372 */ + /* 1 */ V(4, 13, 1), + + /* 0000 0001 1011 ... */ + /* 0 */ V(8, 11, 1), /* 374 */ + /* 1 */ V(11, 8, 1), + + /* 0000 0001 1100 ... */ + /* 0 */ V(13, 4, 1), /* 376 */ + /* 1 */ V(9, 10, 1), + + /* 0000 0001 1101 ... */ + /* 0 */ V(10, 9, 1), /* 378 */ + /* 1 */ V(6, 12, 1), + + /* 0000 0010 0000 ... */ + /* 0 */ V(13, 3, 1), /* 380 */ + /* 1 */ V(7, 11, 1), + + /* 0000 0010 0101 ... */ + /* 0 */ V(5, 12, 1), /* 382 */ + /* 1 */ V(12, 5, 1), + + /* 0000 0010 0110 ... */ + /* 0 */ V(9, 9, 1), /* 384 */ + /* 1 */ V(7, 10, 1), + + /* 0000 0010 1000 ... */ + /* 0 */ V(10, 7, 1), /* 386 */ + /* 1 */ V(9, 7, 1), + + /* 0000 0000 0000 0000 ... */ + /* 000 */ V(15, 14, 3), /* 388 */ + /* 001 */ V(15, 12, 3), + /* 010 */ V(15, 13, 2), + /* 011 */ V(15, 13, 2), + /* 100 */ V(14, 13, 1), + /* 101 */ V(14, 13, 1), + /* 110 */ V(14, 13, 1), + /* 111 */ V(14, 13, 1), + + /* 0000 0000 0000 1011 ... */ + /* 0 */ V(10, 15, 1), /* 396 */ + /* 1 */ V(14, 9, 1) +]; + +const hufftab15 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 4), + /* 0100 */ PTR(80, 4), + /* 0101 */ PTR(96, 3), + /* 0110 */ PTR(104, 3), + /* 0111 */ PTR(112, 2), + /* 1000 */ PTR(116, 1), + /* 1001 */ PTR(118, 1), + /* 1010 */ V(1, 1, 3), + /* 1011 */ V(1, 1, 3), + /* 1100 */ V(0, 1, 4), + /* 1101 */ V(1, 0, 4), + /* 1110 */ V(0, 0, 3), + /* 1111 */ V(0, 0, 3), + + /* 0000 ... */ + /* 0000 */ PTR(120, 4), /* 16 */ + /* 0001 */ PTR(136, 4), + /* 0010 */ PTR(152, 4), + /* 0011 */ PTR(168, 4), + /* 0100 */ PTR(184, 4), + /* 0101 */ PTR(200, 3), + /* 0110 */ PTR(208, 3), + /* 0111 */ PTR(216, 4), + /* 1000 */ PTR(232, 3), + /* 1001 */ PTR(240, 3), + /* 1010 */ PTR(248, 3), + /* 1011 */ PTR(256, 3), + /* 1100 */ PTR(264, 2), + /* 1101 */ PTR(268, 3), + /* 1110 */ PTR(276, 3), + /* 1111 */ PTR(284, 2), + + /* 0001 ... */ + /* 0000 */ PTR(288, 2), /* 32 */ + /* 0001 */ PTR(292, 2), + /* 0010 */ PTR(296, 2), + /* 0011 */ PTR(300, 2), + /* 0100 */ PTR(304, 2), + /* 0101 */ PTR(308, 2), + /* 0110 */ PTR(312, 2), + /* 0111 */ PTR(316, 2), + /* 1000 */ PTR(320, 1), + /* 1001 */ PTR(322, 1), + /* 1010 */ PTR(324, 1), + /* 1011 */ PTR(326, 2), + /* 1100 */ PTR(330, 1), + /* 1101 */ PTR(332, 1), + /* 1110 */ PTR(334, 2), + /* 1111 */ PTR(338, 1), + + /* 0010 ... */ + /* 0000 */ PTR(340, 1), /* 48 */ + /* 0001 */ PTR(342, 1), + /* 0010 */ V(9, 1, 4), + /* 0011 */ PTR(344, 1), + /* 0100 */ PTR(346, 1), + /* 0101 */ PTR(348, 1), + /* 0110 */ PTR(350, 1), + /* 0111 */ PTR(352, 1), + /* 1000 */ V(2, 8, 4), + /* 1001 */ V(8, 2, 4), + /* 1010 */ V(1, 8, 4), + /* 1011 */ V(8, 1, 4), + /* 1100 */ PTR(354, 1), + /* 1101 */ PTR(356, 1), + /* 1110 */ PTR(358, 1), + /* 1111 */ PTR(360, 1), + + /* 0011 ... */ + /* 0000 */ V(2, 7, 4), /* 64 */ + /* 0001 */ V(7, 2, 4), + /* 0010 */ V(6, 4, 4), + /* 0011 */ V(1, 7, 4), + /* 0100 */ V(5, 5, 4), + /* 0101 */ V(7, 1, 4), + /* 0110 */ PTR(362, 1), + /* 0111 */ V(3, 6, 4), + /* 1000 */ V(6, 3, 4), + /* 1001 */ V(4, 5, 4), + /* 1010 */ V(5, 4, 4), + /* 1011 */ V(2, 6, 4), + /* 1100 */ V(6, 2, 4), + /* 1101 */ V(1, 6, 4), + /* 1110 */ PTR(364, 1), + /* 1111 */ V(3, 5, 4), + + /* 0100 ... */ + /* 0000 */ V(6, 1, 3), /* 80 */ + /* 0001 */ V(6, 1, 3), + /* 0010 */ V(5, 3, 4), + /* 0011 */ V(4, 4, 4), + /* 0100 */ V(2, 5, 3), + /* 0101 */ V(2, 5, 3), + /* 0110 */ V(5, 2, 3), + /* 0111 */ V(5, 2, 3), + /* 1000 */ V(1, 5, 3), + /* 1001 */ V(1, 5, 3), + /* 1010 */ V(5, 1, 3), + /* 1011 */ V(5, 1, 3), + /* 1100 */ V(0, 5, 4), + /* 1101 */ V(5, 0, 4), + /* 1110 */ V(3, 4, 3), + /* 1111 */ V(3, 4, 3), + + /* 0101 ... */ + /* 000 */ V(4, 3, 3), /* 96 */ + /* 001 */ V(2, 4, 3), + /* 010 */ V(4, 2, 3), + /* 011 */ V(3, 3, 3), + /* 100 */ V(4, 1, 2), + /* 101 */ V(4, 1, 2), + /* 110 */ V(1, 4, 3), + /* 111 */ V(0, 4, 3), + + /* 0110 ... */ + /* 000 */ V(2, 3, 2), /* 104 */ + /* 001 */ V(2, 3, 2), + /* 010 */ V(3, 2, 2), + /* 011 */ V(3, 2, 2), + /* 100 */ V(4, 0, 3), + /* 101 */ V(0, 3, 3), + /* 110 */ V(1, 3, 2), + /* 111 */ V(1, 3, 2), + + /* 0111 ... */ + /* 00 */ V(3, 1, 2), /* 112 */ + /* 01 */ V(3, 0, 2), + /* 10 */ V(2, 2, 1), + /* 11 */ V(2, 2, 1), + + /* 1000 ... */ + /* 0 */ V(1, 2, 1), /* 116 */ + /* 1 */ V(2, 1, 1), + + /* 1001 ... */ + /* 0 */ V(0, 2, 1), /* 118 */ + /* 1 */ V(2, 0, 1), + + /* 0000 0000 ... */ + /* 0000 */ PTR(366, 1), /* 120 */ + /* 0001 */ PTR(368, 1), + /* 0010 */ V(14, 14, 4), + /* 0011 */ PTR(370, 1), + /* 0100 */ PTR(372, 1), + /* 0101 */ PTR(374, 1), + /* 0110 */ V(15, 11, 4), + /* 0111 */ PTR(376, 1), + /* 1000 */ V(13, 13, 4), + /* 1001 */ V(10, 15, 4), + /* 1010 */ V(15, 10, 4), + /* 1011 */ V(11, 14, 4), + /* 1100 */ V(14, 11, 4), + /* 1101 */ V(12, 13, 4), + /* 1110 */ V(13, 12, 4), + /* 1111 */ V(9, 15, 4), + + /* 0000 0001 ... */ + /* 0000 */ V(15, 9, 4), /* 136 */ + /* 0001 */ V(14, 10, 4), + /* 0010 */ V(11, 13, 4), + /* 0011 */ V(13, 11, 4), + /* 0100 */ V(8, 15, 4), + /* 0101 */ V(15, 8, 4), + /* 0110 */ V(12, 12, 4), + /* 0111 */ V(9, 14, 4), + /* 1000 */ V(14, 9, 4), + /* 1001 */ V(7, 15, 4), + /* 1010 */ V(15, 7, 4), + /* 1011 */ V(10, 13, 4), + /* 1100 */ V(13, 10, 4), + /* 1101 */ V(11, 12, 4), + /* 1110 */ V(6, 15, 4), + /* 1111 */ PTR(378, 1), + + /* 0000 0010 ... */ + /* 0000 */ V(12, 11, 3), /* 152 */ + /* 0001 */ V(12, 11, 3), + /* 0010 */ V(15, 6, 3), + /* 0011 */ V(15, 6, 3), + /* 0100 */ V(8, 14, 4), + /* 0101 */ V(14, 8, 4), + /* 0110 */ V(5, 15, 4), + /* 0111 */ V(9, 13, 4), + /* 1000 */ V(15, 5, 3), + /* 1001 */ V(15, 5, 3), + /* 1010 */ V(7, 14, 3), + /* 1011 */ V(7, 14, 3), + /* 1100 */ V(14, 7, 3), + /* 1101 */ V(14, 7, 3), + /* 1110 */ V(10, 12, 3), + /* 1111 */ V(10, 12, 3), + + /* 0000 0011 ... */ + /* 0000 */ V(12, 10, 3), /* 168 */ + /* 0001 */ V(12, 10, 3), + /* 0010 */ V(11, 11, 3), + /* 0011 */ V(11, 11, 3), + /* 0100 */ V(13, 9, 4), + /* 0101 */ V(8, 13, 4), + /* 0110 */ V(4, 15, 3), + /* 0111 */ V(4, 15, 3), + /* 1000 */ V(15, 4, 3), + /* 1001 */ V(15, 4, 3), + /* 1010 */ V(3, 15, 3), + /* 1011 */ V(3, 15, 3), + /* 1100 */ V(15, 3, 3), + /* 1101 */ V(15, 3, 3), + /* 1110 */ V(13, 8, 3), + /* 1111 */ V(13, 8, 3), + + /* 0000 0100 ... */ + /* 0000 */ V(14, 6, 3), /* 184 */ + /* 0001 */ V(14, 6, 3), + /* 0010 */ V(2, 15, 3), + /* 0011 */ V(2, 15, 3), + /* 0100 */ V(15, 2, 3), + /* 0101 */ V(15, 2, 3), + /* 0110 */ V(6, 14, 4), + /* 0111 */ V(15, 0, 4), + /* 1000 */ V(1, 15, 3), + /* 1001 */ V(1, 15, 3), + /* 1010 */ V(15, 1, 3), + /* 1011 */ V(15, 1, 3), + /* 1100 */ V(9, 12, 3), + /* 1101 */ V(9, 12, 3), + /* 1110 */ V(12, 9, 3), + /* 1111 */ V(12, 9, 3), + + /* 0000 0101 ... */ + /* 000 */ V(5, 14, 3), /* 200 */ + /* 001 */ V(10, 11, 3), + /* 010 */ V(11, 10, 3), + /* 011 */ V(14, 5, 3), + /* 100 */ V(7, 13, 3), + /* 101 */ V(13, 7, 3), + /* 110 */ V(4, 14, 3), + /* 111 */ V(14, 4, 3), + + /* 0000 0110 ... */ + /* 000 */ V(8, 12, 3), /* 208 */ + /* 001 */ V(12, 8, 3), + /* 010 */ V(3, 14, 3), + /* 011 */ V(6, 13, 3), + /* 100 */ V(13, 6, 3), + /* 101 */ V(14, 3, 3), + /* 110 */ V(9, 11, 3), + /* 111 */ V(11, 9, 3), + + /* 0000 0111 ... */ + /* 0000 */ V(2, 14, 3), /* 216 */ + /* 0001 */ V(2, 14, 3), + /* 0010 */ V(10, 10, 3), + /* 0011 */ V(10, 10, 3), + /* 0100 */ V(14, 2, 3), + /* 0101 */ V(14, 2, 3), + /* 0110 */ V(1, 14, 3), + /* 0111 */ V(1, 14, 3), + /* 1000 */ V(14, 1, 3), + /* 1001 */ V(14, 1, 3), + /* 1010 */ V(0, 14, 4), + /* 1011 */ V(14, 0, 4), + /* 1100 */ V(5, 13, 3), + /* 1101 */ V(5, 13, 3), + /* 1110 */ V(13, 5, 3), + /* 1111 */ V(13, 5, 3), + + /* 0000 1000 ... */ + /* 000 */ V(7, 12, 3), /* 232 */ + /* 001 */ V(12, 7, 3), + /* 010 */ V(4, 13, 3), + /* 011 */ V(8, 11, 3), + /* 100 */ V(13, 4, 2), + /* 101 */ V(13, 4, 2), + /* 110 */ V(11, 8, 3), + /* 111 */ V(9, 10, 3), + + /* 0000 1001 ... */ + /* 000 */ V(10, 9, 3), /* 240 */ + /* 001 */ V(6, 12, 3), + /* 010 */ V(12, 6, 3), + /* 011 */ V(3, 13, 3), + /* 100 */ V(13, 3, 2), + /* 101 */ V(13, 3, 2), + /* 110 */ V(13, 2, 2), + /* 111 */ V(13, 2, 2), + + /* 0000 1010 ... */ + /* 000 */ V(2, 13, 3), /* 248 */ + /* 001 */ V(0, 13, 3), + /* 010 */ V(1, 13, 2), + /* 011 */ V(1, 13, 2), + /* 100 */ V(7, 11, 2), + /* 101 */ V(7, 11, 2), + /* 110 */ V(11, 7, 2), + /* 111 */ V(11, 7, 2), + + /* 0000 1011 ... */ + /* 000 */ V(13, 1, 2), /* 256 */ + /* 001 */ V(13, 1, 2), + /* 010 */ V(5, 12, 3), + /* 011 */ V(13, 0, 3), + /* 100 */ V(12, 5, 2), + /* 101 */ V(12, 5, 2), + /* 110 */ V(8, 10, 2), + /* 111 */ V(8, 10, 2), + + /* 0000 1100 ... */ + /* 00 */ V(10, 8, 2), /* 264 */ + /* 01 */ V(4, 12, 2), + /* 10 */ V(12, 4, 2), + /* 11 */ V(6, 11, 2), + + /* 0000 1101 ... */ + /* 000 */ V(11, 6, 2), /* 268 */ + /* 001 */ V(11, 6, 2), + /* 010 */ V(9, 9, 3), + /* 011 */ V(0, 12, 3), + /* 100 */ V(3, 12, 2), + /* 101 */ V(3, 12, 2), + /* 110 */ V(12, 3, 2), + /* 111 */ V(12, 3, 2), + + /* 0000 1110 ... */ + /* 000 */ V(7, 10, 2), /* 276 */ + /* 001 */ V(7, 10, 2), + /* 010 */ V(10, 7, 2), + /* 011 */ V(10, 7, 2), + /* 100 */ V(10, 6, 2), + /* 101 */ V(10, 6, 2), + /* 110 */ V(12, 0, 3), + /* 111 */ V(0, 11, 3), + + /* 0000 1111 ... */ + /* 00 */ V(12, 2, 1), /* 284 */ + /* 01 */ V(12, 2, 1), + /* 10 */ V(2, 12, 2), + /* 11 */ V(5, 11, 2), + + /* 0001 0000 ... */ + /* 00 */ V(11, 5, 2), /* 288 */ + /* 01 */ V(1, 12, 2), + /* 10 */ V(8, 9, 2), + /* 11 */ V(9, 8, 2), + + /* 0001 0001 ... */ + /* 00 */ V(12, 1, 2), /* 292 */ + /* 01 */ V(4, 11, 2), + /* 10 */ V(11, 4, 2), + /* 11 */ V(6, 10, 2), + + /* 0001 0010 ... */ + /* 00 */ V(3, 11, 2), /* 296 */ + /* 01 */ V(7, 9, 2), + /* 10 */ V(11, 3, 1), + /* 11 */ V(11, 3, 1), + + /* 0001 0011 ... */ + /* 00 */ V(9, 7, 2), /* 300 */ + /* 01 */ V(8, 8, 2), + /* 10 */ V(2, 11, 2), + /* 11 */ V(5, 10, 2), + + /* 0001 0100 ... */ + /* 00 */ V(11, 2, 1), /* 304 */ + /* 01 */ V(11, 2, 1), + /* 10 */ V(10, 5, 2), + /* 11 */ V(1, 11, 2), + + /* 0001 0101 ... */ + /* 00 */ V(11, 1, 1), /* 308 */ + /* 01 */ V(11, 1, 1), + /* 10 */ V(11, 0, 2), + /* 11 */ V(6, 9, 2), + + /* 0001 0110 ... */ + /* 00 */ V(9, 6, 2), /* 312 */ + /* 01 */ V(4, 10, 2), + /* 10 */ V(10, 4, 2), + /* 11 */ V(7, 8, 2), + + /* 0001 0111 ... */ + /* 00 */ V(8, 7, 2), /* 316 */ + /* 01 */ V(3, 10, 2), + /* 10 */ V(10, 3, 1), + /* 11 */ V(10, 3, 1), + + /* 0001 1000 ... */ + /* 0 */ V(5, 9, 1), /* 320 */ + /* 1 */ V(9, 5, 1), + + /* 0001 1001 ... */ + /* 0 */ V(2, 10, 1), /* 322 */ + /* 1 */ V(10, 2, 1), + + /* 0001 1010 ... */ + /* 0 */ V(1, 10, 1), /* 324 */ + /* 1 */ V(10, 1, 1), + + /* 0001 1011 ... */ + /* 00 */ V(0, 10, 2), /* 326 */ + /* 01 */ V(10, 0, 2), + /* 10 */ V(6, 8, 1), + /* 11 */ V(6, 8, 1), + + /* 0001 1100 ... */ + /* 0 */ V(8, 6, 1), /* 330 */ + /* 1 */ V(4, 9, 1), + + /* 0001 1101 ... */ + /* 0 */ V(9, 4, 1), /* 332 */ + /* 1 */ V(3, 9, 1), + + /* 0001 1110 ... */ + /* 00 */ V(9, 3, 1), /* 334 */ + /* 01 */ V(9, 3, 1), + /* 10 */ V(7, 7, 2), + /* 11 */ V(0, 9, 2), + + /* 0001 1111 ... */ + /* 0 */ V(5, 8, 1), /* 338 */ + /* 1 */ V(8, 5, 1), + + /* 0010 0000 ... */ + /* 0 */ V(2, 9, 1), /* 340 */ + /* 1 */ V(6, 7, 1), + + /* 0010 0001 ... */ + /* 0 */ V(7, 6, 1), /* 342 */ + /* 1 */ V(9, 2, 1), + + /* 0010 0011 ... */ + /* 0 */ V(1, 9, 1), /* 344 */ + /* 1 */ V(9, 0, 1), + + /* 0010 0100 ... */ + /* 0 */ V(4, 8, 1), /* 346 */ + /* 1 */ V(8, 4, 1), + + /* 0010 0101 ... */ + /* 0 */ V(5, 7, 1), /* 348 */ + /* 1 */ V(7, 5, 1), + + /* 0010 0110 ... */ + /* 0 */ V(3, 8, 1), /* 350 */ + /* 1 */ V(8, 3, 1), + + /* 0010 0111 ... */ + /* 0 */ V(6, 6, 1), /* 352 */ + /* 1 */ V(4, 7, 1), + + /* 0010 1100 ... */ + /* 0 */ V(7, 4, 1), /* 354 */ + /* 1 */ V(0, 8, 1), + + /* 0010 1101 ... */ + /* 0 */ V(8, 0, 1), /* 356 */ + /* 1 */ V(5, 6, 1), + + /* 0010 1110 ... */ + /* 0 */ V(6, 5, 1), /* 358 */ + /* 1 */ V(3, 7, 1), + + /* 0010 1111 ... */ + /* 0 */ V(7, 3, 1), /* 360 */ + /* 1 */ V(4, 6, 1), + + /* 0011 0110 ... */ + /* 0 */ V(0, 7, 1), /* 362 */ + /* 1 */ V(7, 0, 1), + + /* 0011 1110 ... */ + /* 0 */ V(0, 6, 1), /* 364 */ + /* 1 */ V(6, 0, 1), + + /* 0000 0000 0000 ... */ + /* 0 */ V(15, 15, 1), /* 366 */ + /* 1 */ V(14, 15, 1), + + /* 0000 0000 0001 ... */ + /* 0 */ V(15, 14, 1), /* 368 */ + /* 1 */ V(13, 15, 1), + + /* 0000 0000 0011 ... */ + /* 0 */ V(15, 13, 1), /* 370 */ + /* 1 */ V(12, 15, 1), + + /* 0000 0000 0100 ... */ + /* 0 */ V(15, 12, 1), /* 372 */ + /* 1 */ V(13, 14, 1), + + /* 0000 0000 0101 ... */ + /* 0 */ V(14, 13, 1), /* 374 */ + /* 1 */ V(11, 15, 1), + + /* 0000 0000 0111 ... */ + /* 0 */ V(12, 14, 1), /* 376 */ + /* 1 */ V(14, 12, 1), + + /* 0000 0001 1111 ... */ + /* 0 */ V(10, 14, 1), /* 378 */ + /* 1 */ V(0, 15, 1) +]; + +const hufftab16 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 2), + /* 0100 */ V(1, 1, 4), + /* 0101 */ V(0, 1, 4), + /* 0110 */ V(1, 0, 3), + /* 0111 */ V(1, 0, 3), + /* 1000 */ V(0, 0, 1), + /* 1001 */ V(0, 0, 1), + /* 1010 */ V(0, 0, 1), + /* 1011 */ V(0, 0, 1), + /* 1100 */ V(0, 0, 1), + /* 1101 */ V(0, 0, 1), + /* 1110 */ V(0, 0, 1), + /* 1111 */ V(0, 0, 1), + + /* 0000 ... */ + /* 0000 */ PTR(68, 3), /* 16 */ + /* 0001 */ PTR(76, 3), + /* 0010 */ PTR(84, 2), + /* 0011 */ V(15, 15, 4), + /* 0100 */ PTR(88, 2), + /* 0101 */ PTR(92, 1), + /* 0110 */ PTR(94, 4), + /* 0111 */ V(15, 2, 4), + /* 1000 */ PTR(110, 1), + /* 1001 */ V(1, 15, 4), + /* 1010 */ V(15, 1, 4), + /* 1011 */ PTR(112, 4), + /* 1100 */ PTR(128, 4), + /* 1101 */ PTR(144, 4), + /* 1110 */ PTR(160, 4), + /* 1111 */ PTR(176, 4), + + /* 0001 ... */ + /* 0000 */ PTR(192, 4), /* 32 */ + /* 0001 */ PTR(208, 3), + /* 0010 */ PTR(216, 3), + /* 0011 */ PTR(224, 3), + /* 0100 */ PTR(232, 3), + /* 0101 */ PTR(240, 3), + /* 0110 */ PTR(248, 3), + /* 0111 */ PTR(256, 3), + /* 1000 */ PTR(264, 2), + /* 1001 */ PTR(268, 2), + /* 1010 */ PTR(272, 1), + /* 1011 */ PTR(274, 2), + /* 1100 */ PTR(278, 2), + /* 1101 */ PTR(282, 1), + /* 1110 */ V(5, 1, 4), + /* 1111 */ PTR(284, 1), + + /* 0010 ... */ + /* 0000 */ PTR(286, 1), /* 48 */ + /* 0001 */ PTR(288, 1), + /* 0010 */ PTR(290, 1), + /* 0011 */ V(1, 4, 4), + /* 0100 */ V(4, 1, 4), + /* 0101 */ PTR(292, 1), + /* 0110 */ V(2, 3, 4), + /* 0111 */ V(3, 2, 4), + /* 1000 */ V(1, 3, 3), + /* 1001 */ V(1, 3, 3), + /* 1010 */ V(3, 1, 3), + /* 1011 */ V(3, 1, 3), + /* 1100 */ V(0, 3, 4), + /* 1101 */ V(3, 0, 4), + /* 1110 */ V(2, 2, 3), + /* 1111 */ V(2, 2, 3), + + /* 0011 ... */ + /* 00 */ V(1, 2, 2), /* 64 */ + /* 01 */ V(2, 1, 2), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 000 */ V(14, 15, 3), /* 68 */ + /* 001 */ V(15, 14, 3), + /* 010 */ V(13, 15, 3), + /* 011 */ V(15, 13, 3), + /* 100 */ V(12, 15, 3), + /* 101 */ V(15, 12, 3), + /* 110 */ V(11, 15, 3), + /* 111 */ V(15, 11, 3), + + /* 0000 0001 ... */ + /* 000 */ V(10, 15, 2), /* 76 */ + /* 001 */ V(10, 15, 2), + /* 010 */ V(15, 10, 3), + /* 011 */ V(9, 15, 3), + /* 100 */ V(15, 9, 3), + /* 101 */ V(15, 8, 3), + /* 110 */ V(8, 15, 2), + /* 111 */ V(8, 15, 2), + + /* 0000 0010 ... */ + /* 00 */ V(7, 15, 2), /* 84 */ + /* 01 */ V(15, 7, 2), + /* 10 */ V(6, 15, 2), + /* 11 */ V(15, 6, 2), + + /* 0000 0100 ... */ + /* 00 */ V(5, 15, 2), /* 88 */ + /* 01 */ V(15, 5, 2), + /* 10 */ V(4, 15, 1), + /* 11 */ V(4, 15, 1), + + /* 0000 0101 ... */ + /* 0 */ V(15, 4, 1), /* 92 */ + /* 1 */ V(15, 3, 1), + + /* 0000 0110 ... */ + /* 0000 */ V(15, 0, 1), /* 94 */ + /* 0001 */ V(15, 0, 1), + /* 0010 */ V(15, 0, 1), + /* 0011 */ V(15, 0, 1), + /* 0100 */ V(15, 0, 1), + /* 0101 */ V(15, 0, 1), + /* 0110 */ V(15, 0, 1), + /* 0111 */ V(15, 0, 1), + /* 1000 */ V(3, 15, 2), + /* 1001 */ V(3, 15, 2), + /* 1010 */ V(3, 15, 2), + /* 1011 */ V(3, 15, 2), + /* 1100 */ PTR(294, 4), + /* 1101 */ PTR(310, 3), + /* 1110 */ PTR(318, 3), + /* 1111 */ PTR(326, 3), + + /* 0000 1000 ... */ + /* 0 */ V(2, 15, 1), /* 110 */ + /* 1 */ V(0, 15, 1), + + /* 0000 1011 ... */ + /* 0000 */ PTR(334, 2), /* 112 */ + /* 0001 */ PTR(338, 2), + /* 0010 */ PTR(342, 2), + /* 0011 */ PTR(346, 1), + /* 0100 */ PTR(348, 2), + /* 0101 */ PTR(352, 2), + /* 0110 */ PTR(356, 1), + /* 0111 */ PTR(358, 2), + /* 1000 */ PTR(362, 2), + /* 1001 */ PTR(366, 2), + /* 1010 */ PTR(370, 2), + /* 1011 */ V(14, 3, 4), + /* 1100 */ PTR(374, 1), + /* 1101 */ PTR(376, 1), + /* 1110 */ PTR(378, 1), + /* 1111 */ PTR(380, 1), + + /* 0000 1100 ... */ + /* 0000 */ PTR(382, 1), /* 128 */ + /* 0001 */ PTR(384, 1), + /* 0010 */ PTR(386, 1), + /* 0011 */ V(0, 13, 4), + /* 0100 */ PTR(388, 1), + /* 0101 */ PTR(390, 1), + /* 0110 */ PTR(392, 1), + /* 0111 */ V(3, 12, 4), + /* 1000 */ PTR(394, 1), + /* 1001 */ V(1, 12, 4), + /* 1010 */ V(12, 0, 4), + /* 1011 */ PTR(396, 1), + /* 1100 */ V(14, 2, 3), + /* 1101 */ V(14, 2, 3), + /* 1110 */ V(2, 14, 4), + /* 1111 */ V(1, 14, 4), + + /* 0000 1101 ... */ + /* 0000 */ V(13, 3, 4), /* 144 */ + /* 0001 */ V(2, 13, 4), + /* 0010 */ V(13, 2, 4), + /* 0011 */ V(13, 1, 4), + /* 0100 */ V(3, 11, 4), + /* 0101 */ PTR(398, 1), + /* 0110 */ V(1, 13, 3), + /* 0111 */ V(1, 13, 3), + /* 1000 */ V(12, 4, 4), + /* 1001 */ V(6, 11, 4), + /* 1010 */ V(12, 3, 4), + /* 1011 */ V(10, 7, 4), + /* 1100 */ V(2, 12, 3), + /* 1101 */ V(2, 12, 3), + /* 1110 */ V(12, 2, 4), + /* 1111 */ V(11, 5, 4), + + /* 0000 1110 ... */ + /* 0000 */ V(12, 1, 4), /* 160 */ + /* 0001 */ V(0, 12, 4), + /* 0010 */ V(4, 11, 4), + /* 0011 */ V(11, 4, 4), + /* 0100 */ V(6, 10, 4), + /* 0101 */ V(10, 6, 4), + /* 0110 */ V(11, 3, 3), + /* 0111 */ V(11, 3, 3), + /* 1000 */ V(5, 10, 4), + /* 1001 */ V(10, 5, 4), + /* 1010 */ V(2, 11, 3), + /* 1011 */ V(2, 11, 3), + /* 1100 */ V(11, 2, 3), + /* 1101 */ V(11, 2, 3), + /* 1110 */ V(1, 11, 3), + /* 1111 */ V(1, 11, 3), + + /* 0000 1111 ... */ + /* 0000 */ V(11, 1, 3), /* 176 */ + /* 0001 */ V(11, 1, 3), + /* 0010 */ V(0, 11, 4), + /* 0011 */ V(11, 0, 4), + /* 0100 */ V(6, 9, 4), + /* 0101 */ V(9, 6, 4), + /* 0110 */ V(4, 10, 4), + /* 0111 */ V(10, 4, 4), + /* 1000 */ V(7, 8, 4), + /* 1001 */ V(8, 7, 4), + /* 1010 */ V(10, 3, 3), + /* 1011 */ V(10, 3, 3), + /* 1100 */ V(3, 10, 4), + /* 1101 */ V(5, 9, 4), + /* 1110 */ V(2, 10, 3), + /* 1111 */ V(2, 10, 3), + + /* 0001 0000 ... */ + /* 0000 */ V(9, 5, 4), /* 192 */ + /* 0001 */ V(6, 8, 4), + /* 0010 */ V(10, 1, 3), + /* 0011 */ V(10, 1, 3), + /* 0100 */ V(8, 6, 4), + /* 0101 */ V(7, 7, 4), + /* 0110 */ V(9, 4, 3), + /* 0111 */ V(9, 4, 3), + /* 1000 */ V(4, 9, 4), + /* 1001 */ V(5, 7, 4), + /* 1010 */ V(6, 7, 3), + /* 1011 */ V(6, 7, 3), + /* 1100 */ V(10, 2, 2), + /* 1101 */ V(10, 2, 2), + /* 1110 */ V(10, 2, 2), + /* 1111 */ V(10, 2, 2), + + /* 0001 0001 ... */ + /* 000 */ V(1, 10, 2), /* 208 */ + /* 001 */ V(1, 10, 2), + /* 010 */ V(0, 10, 3), + /* 011 */ V(10, 0, 3), + /* 100 */ V(3, 9, 3), + /* 101 */ V(9, 3, 3), + /* 110 */ V(5, 8, 3), + /* 111 */ V(8, 5, 3), + + /* 0001 0010 ... */ + /* 000 */ V(2, 9, 2), /* 216 */ + /* 001 */ V(2, 9, 2), + /* 010 */ V(9, 2, 2), + /* 011 */ V(9, 2, 2), + /* 100 */ V(7, 6, 3), + /* 101 */ V(0, 9, 3), + /* 110 */ V(1, 9, 2), + /* 111 */ V(1, 9, 2), + + /* 0001 0011 ... */ + /* 000 */ V(9, 1, 2), /* 224 */ + /* 001 */ V(9, 1, 2), + /* 010 */ V(9, 0, 3), + /* 011 */ V(4, 8, 3), + /* 100 */ V(8, 4, 3), + /* 101 */ V(7, 5, 3), + /* 110 */ V(3, 8, 3), + /* 111 */ V(8, 3, 3), + + /* 0001 0100 ... */ + /* 000 */ V(6, 6, 3), /* 232 */ + /* 001 */ V(2, 8, 3), + /* 010 */ V(8, 2, 2), + /* 011 */ V(8, 2, 2), + /* 100 */ V(4, 7, 3), + /* 101 */ V(7, 4, 3), + /* 110 */ V(1, 8, 2), + /* 111 */ V(1, 8, 2), + + /* 0001 0101 ... */ + /* 000 */ V(8, 1, 2), /* 240 */ + /* 001 */ V(8, 1, 2), + /* 010 */ V(8, 0, 2), + /* 011 */ V(8, 0, 2), + /* 100 */ V(0, 8, 3), + /* 101 */ V(5, 6, 3), + /* 110 */ V(3, 7, 2), + /* 111 */ V(3, 7, 2), + + /* 0001 0110 ... */ + /* 000 */ V(7, 3, 2), /* 248 */ + /* 001 */ V(7, 3, 2), + /* 010 */ V(6, 5, 3), + /* 011 */ V(4, 6, 3), + /* 100 */ V(2, 7, 2), + /* 101 */ V(2, 7, 2), + /* 110 */ V(7, 2, 2), + /* 111 */ V(7, 2, 2), + + /* 0001 0111 ... */ + /* 000 */ V(6, 4, 3), /* 256 */ + /* 001 */ V(5, 5, 3), + /* 010 */ V(0, 7, 2), + /* 011 */ V(0, 7, 2), + /* 100 */ V(1, 7, 1), + /* 101 */ V(1, 7, 1), + /* 110 */ V(1, 7, 1), + /* 111 */ V(1, 7, 1), + + /* 0001 1000 ... */ + /* 00 */ V(7, 1, 1), /* 264 */ + /* 01 */ V(7, 1, 1), + /* 10 */ V(7, 0, 2), + /* 11 */ V(3, 6, 2), + + /* 0001 1001 ... */ + /* 00 */ V(6, 3, 2), /* 268 */ + /* 01 */ V(4, 5, 2), + /* 10 */ V(5, 4, 2), + /* 11 */ V(2, 6, 2), + + /* 0001 1010 ... */ + /* 0 */ V(6, 2, 1), /* 272 */ + /* 1 */ V(1, 6, 1), + + /* 0001 1011 ... */ + /* 00 */ V(6, 1, 1), /* 274 */ + /* 01 */ V(6, 1, 1), + /* 10 */ V(0, 6, 2), + /* 11 */ V(6, 0, 2), + + /* 0001 1100 ... */ + /* 00 */ V(5, 3, 1), /* 278 */ + /* 01 */ V(5, 3, 1), + /* 10 */ V(3, 5, 2), + /* 11 */ V(4, 4, 2), + + /* 0001 1101 ... */ + /* 0 */ V(2, 5, 1), /* 282 */ + /* 1 */ V(5, 2, 1), + + /* 0001 1111 ... */ + /* 0 */ V(1, 5, 1), /* 284 */ + /* 1 */ V(0, 5, 1), + + /* 0010 0000 ... */ + /* 0 */ V(3, 4, 1), /* 286 */ + /* 1 */ V(4, 3, 1), + + /* 0010 0001 ... */ + /* 0 */ V(5, 0, 1), /* 288 */ + /* 1 */ V(2, 4, 1), + + /* 0010 0010 ... */ + /* 0 */ V(4, 2, 1), /* 290 */ + /* 1 */ V(3, 3, 1), + + /* 0010 0101 ... */ + /* 0 */ V(0, 4, 1), /* 292 */ + /* 1 */ V(4, 0, 1), + + /* 0000 0110 1100 ... */ + /* 0000 */ V(12, 14, 4), /* 294 */ + /* 0001 */ PTR(400, 1), + /* 0010 */ V(13, 14, 3), + /* 0011 */ V(13, 14, 3), + /* 0100 */ V(14, 9, 3), + /* 0101 */ V(14, 9, 3), + /* 0110 */ V(14, 10, 4), + /* 0111 */ V(13, 9, 4), + /* 1000 */ V(14, 14, 2), + /* 1001 */ V(14, 14, 2), + /* 1010 */ V(14, 14, 2), + /* 1011 */ V(14, 14, 2), + /* 1100 */ V(14, 13, 3), + /* 1101 */ V(14, 13, 3), + /* 1110 */ V(14, 11, 3), + /* 1111 */ V(14, 11, 3), + + /* 0000 0110 1101 ... */ + /* 000 */ V(11, 14, 2), /* 310 */ + /* 001 */ V(11, 14, 2), + /* 010 */ V(12, 13, 2), + /* 011 */ V(12, 13, 2), + /* 100 */ V(13, 12, 3), + /* 101 */ V(13, 11, 3), + /* 110 */ V(10, 14, 2), + /* 111 */ V(10, 14, 2), + + /* 0000 0110 1110 ... */ + /* 000 */ V(12, 12, 2), /* 318 */ + /* 001 */ V(12, 12, 2), + /* 010 */ V(10, 13, 3), + /* 011 */ V(13, 10, 3), + /* 100 */ V(7, 14, 3), + /* 101 */ V(10, 12, 3), + /* 110 */ V(12, 10, 2), + /* 111 */ V(12, 10, 2), + + /* 0000 0110 1111 ... */ + /* 000 */ V(12, 9, 3), /* 326 */ + /* 001 */ V(7, 13, 3), + /* 010 */ V(5, 14, 2), + /* 011 */ V(5, 14, 2), + /* 100 */ V(11, 13, 1), + /* 101 */ V(11, 13, 1), + /* 110 */ V(11, 13, 1), + /* 111 */ V(11, 13, 1), + + /* 0000 1011 0000 ... */ + /* 00 */ V(9, 14, 1), /* 334 */ + /* 01 */ V(9, 14, 1), + /* 10 */ V(11, 12, 2), + /* 11 */ V(12, 11, 2), + + /* 0000 1011 0001 ... */ + /* 00 */ V(8, 14, 2), /* 338 */ + /* 01 */ V(14, 8, 2), + /* 10 */ V(9, 13, 2), + /* 11 */ V(14, 7, 2), + + /* 0000 1011 0010 ... */ + /* 00 */ V(11, 11, 2), /* 342 */ + /* 01 */ V(8, 13, 2), + /* 10 */ V(13, 8, 2), + /* 11 */ V(6, 14, 2), + + /* 0000 1011 0011 ... */ + /* 0 */ V(14, 6, 1), /* 346 */ + /* 1 */ V(9, 12, 1), + + /* 0000 1011 0100 ... */ + /* 00 */ V(10, 11, 2), /* 348 */ + /* 01 */ V(11, 10, 2), + /* 10 */ V(14, 5, 2), + /* 11 */ V(13, 7, 2), + + /* 0000 1011 0101 ... */ + /* 00 */ V(4, 14, 1), /* 352 */ + /* 01 */ V(4, 14, 1), + /* 10 */ V(14, 4, 2), + /* 11 */ V(8, 12, 2), + + /* 0000 1011 0110 ... */ + /* 0 */ V(12, 8, 1), /* 356 */ + /* 1 */ V(3, 14, 1), + + /* 0000 1011 0111 ... */ + /* 00 */ V(6, 13, 1), /* 358 */ + /* 01 */ V(6, 13, 1), + /* 10 */ V(13, 6, 2), + /* 11 */ V(9, 11, 2), + + /* 0000 1011 1000 ... */ + /* 00 */ V(11, 9, 2), /* 362 */ + /* 01 */ V(10, 10, 2), + /* 10 */ V(14, 1, 1), + /* 11 */ V(14, 1, 1), + + /* 0000 1011 1001 ... */ + /* 00 */ V(13, 4, 1), /* 366 */ + /* 01 */ V(13, 4, 1), + /* 10 */ V(11, 8, 2), + /* 11 */ V(10, 9, 2), + + /* 0000 1011 1010 ... */ + /* 00 */ V(7, 11, 1), /* 370 */ + /* 01 */ V(7, 11, 1), + /* 10 */ V(11, 7, 2), + /* 11 */ V(13, 0, 2), + + /* 0000 1011 1100 ... */ + /* 0 */ V(0, 14, 1), /* 374 */ + /* 1 */ V(14, 0, 1), + + /* 0000 1011 1101 ... */ + /* 0 */ V(5, 13, 1), /* 376 */ + /* 1 */ V(13, 5, 1), + + /* 0000 1011 1110 ... */ + /* 0 */ V(7, 12, 1), /* 378 */ + /* 1 */ V(12, 7, 1), + + /* 0000 1011 1111 ... */ + /* 0 */ V(4, 13, 1), /* 380 */ + /* 1 */ V(8, 11, 1), + + /* 0000 1100 0000 ... */ + /* 0 */ V(9, 10, 1), /* 382 */ + /* 1 */ V(6, 12, 1), + + /* 0000 1100 0001 ... */ + /* 0 */ V(12, 6, 1), /* 384 */ + /* 1 */ V(3, 13, 1), + + /* 0000 1100 0010 ... */ + /* 0 */ V(5, 12, 1), /* 386 */ + /* 1 */ V(12, 5, 1), + + /* 0000 1100 0100 ... */ + /* 0 */ V(8, 10, 1), /* 388 */ + /* 1 */ V(10, 8, 1), + + /* 0000 1100 0101 ... */ + /* 0 */ V(9, 9, 1), /* 390 */ + /* 1 */ V(4, 12, 1), + + /* 0000 1100 0110 ... */ + /* 0 */ V(11, 6, 1), /* 392 */ + /* 1 */ V(7, 10, 1), + + /* 0000 1100 1000 ... */ + /* 0 */ V(5, 11, 1), /* 394 */ + /* 1 */ V(8, 9, 1), + + /* 0000 1100 1011 ... */ + /* 0 */ V(9, 8, 1), /* 396 */ + /* 1 */ V(7, 9, 1), + + /* 0000 1101 0101 ... */ + /* 0 */ V(9, 7, 1), /* 398 */ + /* 1 */ V(8, 8, 1), + + /* 0000 0110 1100 0001 ... */ + /* 0 */ V(14, 12, 1), /* 400 */ + /* 1 */ V(13, 13, 1) +]; + +const hufftab24 = [ + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ V(15, 15, 4), + /* 0100 */ PTR(64, 4), + /* 0101 */ PTR(80, 4), + /* 0110 */ PTR(96, 4), + /* 0111 */ PTR(112, 4), + /* 1000 */ PTR(128, 4), + /* 1001 */ PTR(144, 4), + /* 1010 */ PTR(160, 3), + /* 1011 */ PTR(168, 2), + /* 1100 */ V(1, 1, 4), + /* 1101 */ V(0, 1, 4), + /* 1110 */ V(1, 0, 4), + /* 1111 */ V(0, 0, 4), + + /* 0000 ... */ + /* 0000 */ V(14, 15, 4), /* 16 */ + /* 0001 */ V(15, 14, 4), + /* 0010 */ V(13, 15, 4), + /* 0011 */ V(15, 13, 4), + /* 0100 */ V(12, 15, 4), + /* 0101 */ V(15, 12, 4), + /* 0110 */ V(11, 15, 4), + /* 0111 */ V(15, 11, 4), + /* 1000 */ V(15, 10, 3), + /* 1001 */ V(15, 10, 3), + /* 1010 */ V(10, 15, 4), + /* 1011 */ V(9, 15, 4), + /* 1100 */ V(15, 9, 3), + /* 1101 */ V(15, 9, 3), + /* 1110 */ V(15, 8, 3), + /* 1111 */ V(15, 8, 3), + + /* 0001 ... */ + /* 0000 */ V(8, 15, 4), /* 32 */ + /* 0001 */ V(7, 15, 4), + /* 0010 */ V(15, 7, 3), + /* 0011 */ V(15, 7, 3), + /* 0100 */ V(6, 15, 3), + /* 0101 */ V(6, 15, 3), + /* 0110 */ V(15, 6, 3), + /* 0111 */ V(15, 6, 3), + /* 1000 */ V(5, 15, 3), + /* 1001 */ V(5, 15, 3), + /* 1010 */ V(15, 5, 3), + /* 1011 */ V(15, 5, 3), + /* 1100 */ V(4, 15, 3), + /* 1101 */ V(4, 15, 3), + /* 1110 */ V(15, 4, 3), + /* 1111 */ V(15, 4, 3), + + /* 0010 ... */ + /* 0000 */ V(3, 15, 3), /* 48 */ + /* 0001 */ V(3, 15, 3), + /* 0010 */ V(15, 3, 3), + /* 0011 */ V(15, 3, 3), + /* 0100 */ V(2, 15, 3), + /* 0101 */ V(2, 15, 3), + /* 0110 */ V(15, 2, 3), + /* 0111 */ V(15, 2, 3), + /* 1000 */ V(15, 1, 3), + /* 1001 */ V(15, 1, 3), + /* 1010 */ V(1, 15, 4), + /* 1011 */ V(15, 0, 4), + /* 1100 */ PTR(172, 3), + /* 1101 */ PTR(180, 3), + /* 1110 */ PTR(188, 3), + /* 1111 */ PTR(196, 3), + + /* 0100 ... */ + /* 0000 */ PTR(204, 4), /* 64 */ + /* 0001 */ PTR(220, 3), + /* 0010 */ PTR(228, 3), + /* 0011 */ PTR(236, 3), + /* 0100 */ PTR(244, 2), + /* 0101 */ PTR(248, 2), + /* 0110 */ PTR(252, 2), + /* 0111 */ PTR(256, 2), + /* 1000 */ PTR(260, 2), + /* 1001 */ PTR(264, 2), + /* 1010 */ PTR(268, 2), + /* 1011 */ PTR(272, 2), + /* 1100 */ PTR(276, 2), + /* 1101 */ PTR(280, 3), + /* 1110 */ PTR(288, 2), + /* 1111 */ PTR(292, 2), + + /* 0101 ... */ + /* 0000 */ PTR(296, 2), /* 80 */ + /* 0001 */ PTR(300, 3), + /* 0010 */ PTR(308, 2), + /* 0011 */ PTR(312, 3), + /* 0100 */ PTR(320, 1), + /* 0101 */ PTR(322, 2), + /* 0110 */ PTR(326, 2), + /* 0111 */ PTR(330, 1), + /* 1000 */ PTR(332, 2), + /* 1001 */ PTR(336, 1), + /* 1010 */ PTR(338, 1), + /* 1011 */ PTR(340, 1), + /* 1100 */ PTR(342, 1), + /* 1101 */ PTR(344, 1), + /* 1110 */ PTR(346, 1), + /* 1111 */ PTR(348, 1), + + /* 0110 ... */ + /* 0000 */ PTR(350, 1), /* 96 */ + /* 0001 */ PTR(352, 1), + /* 0010 */ PTR(354, 1), + /* 0011 */ PTR(356, 1), + /* 0100 */ PTR(358, 1), + /* 0101 */ PTR(360, 1), + /* 0110 */ PTR(362, 1), + /* 0111 */ PTR(364, 1), + /* 1000 */ PTR(366, 1), + /* 1001 */ PTR(368, 1), + /* 1010 */ PTR(370, 2), + /* 1011 */ PTR(374, 1), + /* 1100 */ PTR(376, 2), + /* 1101 */ V(7, 3, 4), + /* 1110 */ PTR(380, 1), + /* 1111 */ V(7, 2, 4), + + /* 0111 ... */ + /* 0000 */ V(4, 6, 4), /* 112 */ + /* 0001 */ V(6, 4, 4), + /* 0010 */ V(5, 5, 4), + /* 0011 */ V(7, 1, 4), + /* 0100 */ V(3, 6, 4), + /* 0101 */ V(6, 3, 4), + /* 0110 */ V(4, 5, 4), + /* 0111 */ V(5, 4, 4), + /* 1000 */ V(2, 6, 4), + /* 1001 */ V(6, 2, 4), + /* 1010 */ V(1, 6, 4), + /* 1011 */ V(6, 1, 4), + /* 1100 */ PTR(382, 1), + /* 1101 */ V(3, 5, 4), + /* 1110 */ V(5, 3, 4), + /* 1111 */ V(4, 4, 4), + + /* 1000 ... */ + /* 0000 */ V(2, 5, 4), /* 128 */ + /* 0001 */ V(5, 2, 4), + /* 0010 */ V(1, 5, 4), + /* 0011 */ PTR(384, 1), + /* 0100 */ V(5, 1, 3), + /* 0101 */ V(5, 1, 3), + /* 0110 */ V(3, 4, 4), + /* 0111 */ V(4, 3, 4), + /* 1000 */ V(2, 4, 3), + /* 1001 */ V(2, 4, 3), + /* 1010 */ V(4, 2, 3), + /* 1011 */ V(4, 2, 3), + /* 1100 */ V(3, 3, 3), + /* 1101 */ V(3, 3, 3), + /* 1110 */ V(1, 4, 3), + /* 1111 */ V(1, 4, 3), + + /* 1001 ... */ + /* 0000 */ V(4, 1, 3), /* 144 */ + /* 0001 */ V(4, 1, 3), + /* 0010 */ V(0, 4, 4), + /* 0011 */ V(4, 0, 4), + /* 0100 */ V(2, 3, 3), + /* 0101 */ V(2, 3, 3), + /* 0110 */ V(3, 2, 3), + /* 0111 */ V(3, 2, 3), + /* 1000 */ V(1, 3, 2), + /* 1001 */ V(1, 3, 2), + /* 1010 */ V(1, 3, 2), + /* 1011 */ V(1, 3, 2), + /* 1100 */ V(3, 1, 2), + /* 1101 */ V(3, 1, 2), + /* 1110 */ V(3, 1, 2), + /* 1111 */ V(3, 1, 2), + + /* 1010 ... */ + /* 000 */ V(0, 3, 3), /* 160 */ + /* 001 */ V(3, 0, 3), + /* 010 */ V(2, 2, 2), + /* 011 */ V(2, 2, 2), + /* 100 */ V(1, 2, 1), + /* 101 */ V(1, 2, 1), + /* 110 */ V(1, 2, 1), + /* 111 */ V(1, 2, 1), + + /* 1011 ... */ + /* 00 */ V(2, 1, 1), /* 168 */ + /* 01 */ V(2, 1, 1), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0010 1100 ... */ + /* 000 */ V(0, 15, 1), /* 172 */ + /* 001 */ V(0, 15, 1), + /* 010 */ V(0, 15, 1), + /* 011 */ V(0, 15, 1), + /* 100 */ V(14, 14, 3), + /* 101 */ V(13, 14, 3), + /* 110 */ V(14, 13, 3), + /* 111 */ V(12, 14, 3), + + /* 0010 1101 ... */ + /* 000 */ V(14, 12, 3), /* 180 */ + /* 001 */ V(13, 13, 3), + /* 010 */ V(11, 14, 3), + /* 011 */ V(14, 11, 3), + /* 100 */ V(12, 13, 3), + /* 101 */ V(13, 12, 3), + /* 110 */ V(10, 14, 3), + /* 111 */ V(14, 10, 3), + + /* 0010 1110 ... */ + /* 000 */ V(11, 13, 3), /* 188 */ + /* 001 */ V(13, 11, 3), + /* 010 */ V(12, 12, 3), + /* 011 */ V(9, 14, 3), + /* 100 */ V(14, 9, 3), + /* 101 */ V(10, 13, 3), + /* 110 */ V(13, 10, 3), + /* 111 */ V(11, 12, 3), + + /* 0010 1111 ... */ + /* 000 */ V(12, 11, 3), /* 196 */ + /* 001 */ V(8, 14, 3), + /* 010 */ V(14, 8, 3), + /* 011 */ V(9, 13, 3), + /* 100 */ V(13, 9, 3), + /* 101 */ V(7, 14, 3), + /* 110 */ V(14, 7, 3), + /* 111 */ V(10, 12, 3), + + /* 0100 0000 ... */ + /* 0000 */ V(12, 10, 3), /* 204 */ + /* 0001 */ V(12, 10, 3), + /* 0010 */ V(11, 11, 3), + /* 0011 */ V(11, 11, 3), + /* 0100 */ V(8, 13, 3), + /* 0101 */ V(8, 13, 3), + /* 0110 */ V(13, 8, 3), + /* 0111 */ V(13, 8, 3), + /* 1000 */ V(0, 14, 4), + /* 1001 */ V(14, 0, 4), + /* 1010 */ V(0, 13, 3), + /* 1011 */ V(0, 13, 3), + /* 1100 */ V(14, 6, 2), + /* 1101 */ V(14, 6, 2), + /* 1110 */ V(14, 6, 2), + /* 1111 */ V(14, 6, 2), + + /* 0100 0001 ... */ + /* 000 */ V(6, 14, 3), /* 220 */ + /* 001 */ V(9, 12, 3), + /* 010 */ V(12, 9, 2), + /* 011 */ V(12, 9, 2), + /* 100 */ V(5, 14, 2), + /* 101 */ V(5, 14, 2), + /* 110 */ V(11, 10, 2), + /* 111 */ V(11, 10, 2), + + /* 0100 0010 ... */ + /* 000 */ V(14, 5, 2), /* 228 */ + /* 001 */ V(14, 5, 2), + /* 010 */ V(10, 11, 3), + /* 011 */ V(7, 13, 3), + /* 100 */ V(13, 7, 2), + /* 101 */ V(13, 7, 2), + /* 110 */ V(14, 4, 2), + /* 111 */ V(14, 4, 2), + + /* 0100 0011 ... */ + /* 000 */ V(8, 12, 2), /* 236 */ + /* 001 */ V(8, 12, 2), + /* 010 */ V(12, 8, 2), + /* 011 */ V(12, 8, 2), + /* 100 */ V(4, 14, 3), + /* 101 */ V(2, 14, 3), + /* 110 */ V(3, 14, 2), + /* 111 */ V(3, 14, 2), + + /* 0100 0100 ... */ + /* 00 */ V(6, 13, 2), /* 244 */ + /* 01 */ V(13, 6, 2), + /* 10 */ V(14, 3, 2), + /* 11 */ V(9, 11, 2), + + /* 0100 0101 ... */ + /* 00 */ V(11, 9, 2), /* 248 */ + /* 01 */ V(10, 10, 2), + /* 10 */ V(14, 2, 2), + /* 11 */ V(1, 14, 2), + + /* 0100 0110 ... */ + /* 00 */ V(14, 1, 2), /* 252 */ + /* 01 */ V(5, 13, 2), + /* 10 */ V(13, 5, 2), + /* 11 */ V(7, 12, 2), + + /* 0100 0111 ... */ + /* 00 */ V(12, 7, 2), /* 256 */ + /* 01 */ V(4, 13, 2), + /* 10 */ V(8, 11, 2), + /* 11 */ V(11, 8, 2), + + /* 0100 1000 ... */ + /* 00 */ V(13, 4, 2), /* 260 */ + /* 01 */ V(9, 10, 2), + /* 10 */ V(10, 9, 2), + /* 11 */ V(6, 12, 2), + + /* 0100 1001 ... */ + /* 00 */ V(12, 6, 2), /* 264 */ + /* 01 */ V(3, 13, 2), + /* 10 */ V(13, 3, 2), + /* 11 */ V(2, 13, 2), + + /* 0100 1010 ... */ + /* 00 */ V(13, 2, 2), /* 268 */ + /* 01 */ V(1, 13, 2), + /* 10 */ V(7, 11, 2), + /* 11 */ V(11, 7, 2), + + /* 0100 1011 ... */ + /* 00 */ V(13, 1, 2), /* 272 */ + /* 01 */ V(5, 12, 2), + /* 10 */ V(12, 5, 2), + /* 11 */ V(8, 10, 2), + + /* 0100 1100 ... */ + /* 00 */ V(10, 8, 2), /* 276 */ + /* 01 */ V(9, 9, 2), + /* 10 */ V(4, 12, 2), + /* 11 */ V(12, 4, 2), + + /* 0100 1101 ... */ + /* 000 */ V(6, 11, 2), /* 280 */ + /* 001 */ V(6, 11, 2), + /* 010 */ V(11, 6, 2), + /* 011 */ V(11, 6, 2), + /* 100 */ V(13, 0, 3), + /* 101 */ V(0, 12, 3), + /* 110 */ V(3, 12, 2), + /* 111 */ V(3, 12, 2), + + /* 0100 1110 ... */ + /* 00 */ V(12, 3, 2), /* 288 */ + /* 01 */ V(7, 10, 2), + /* 10 */ V(10, 7, 2), + /* 11 */ V(2, 12, 2), + + /* 0100 1111 ... */ + /* 00 */ V(12, 2, 2), /* 292 */ + /* 01 */ V(5, 11, 2), + /* 10 */ V(11, 5, 2), + /* 11 */ V(1, 12, 2), + + /* 0101 0000 ... */ + /* 00 */ V(8, 9, 2), /* 296 */ + /* 01 */ V(9, 8, 2), + /* 10 */ V(12, 1, 2), + /* 11 */ V(4, 11, 2), + + /* 0101 0001 ... */ + /* 000 */ V(12, 0, 3), /* 300 */ + /* 001 */ V(0, 11, 3), + /* 010 */ V(3, 11, 2), + /* 011 */ V(3, 11, 2), + /* 100 */ V(11, 0, 3), + /* 101 */ V(0, 10, 3), + /* 110 */ V(1, 10, 2), + /* 111 */ V(1, 10, 2), + + /* 0101 0010 ... */ + /* 00 */ V(11, 4, 1), /* 308 */ + /* 01 */ V(11, 4, 1), + /* 10 */ V(6, 10, 2), + /* 11 */ V(10, 6, 2), + + /* 0101 0011 ... */ + /* 000 */ V(7, 9, 2), /* 312 */ + /* 001 */ V(7, 9, 2), + /* 010 */ V(9, 7, 2), + /* 011 */ V(9, 7, 2), + /* 100 */ V(10, 0, 3), + /* 101 */ V(0, 9, 3), + /* 110 */ V(9, 0, 2), + /* 111 */ V(9, 0, 2), + + /* 0101 0100 ... */ + /* 0 */ V(11, 3, 1), /* 320 */ + /* 1 */ V(8, 8, 1), + + /* 0101 0101 ... */ + /* 00 */ V(2, 11, 2), /* 322 */ + /* 01 */ V(5, 10, 2), + /* 10 */ V(11, 2, 1), + /* 11 */ V(11, 2, 1), + + /* 0101 0110 ... */ + /* 00 */ V(10, 5, 2), /* 326 */ + /* 01 */ V(1, 11, 2), + /* 10 */ V(11, 1, 2), + /* 11 */ V(6, 9, 2), + + /* 0101 0111 ... */ + /* 0 */ V(9, 6, 1), /* 330 */ + /* 1 */ V(10, 4, 1), + + /* 0101 1000 ... */ + /* 00 */ V(4, 10, 2), /* 332 */ + /* 01 */ V(7, 8, 2), + /* 10 */ V(8, 7, 1), + /* 11 */ V(8, 7, 1), + + /* 0101 1001 ... */ + /* 0 */ V(3, 10, 1), /* 336 */ + /* 1 */ V(10, 3, 1), + + /* 0101 1010 ... */ + /* 0 */ V(5, 9, 1), /* 338 */ + /* 1 */ V(9, 5, 1), + + /* 0101 1011 ... */ + /* 0 */ V(2, 10, 1), /* 340 */ + /* 1 */ V(10, 2, 1), + + /* 0101 1100 ... */ + /* 0 */ V(10, 1, 1), /* 342 */ + /* 1 */ V(6, 8, 1), + + /* 0101 1101 ... */ + /* 0 */ V(8, 6, 1), /* 344 */ + /* 1 */ V(7, 7, 1), + + /* 0101 1110 ... */ + /* 0 */ V(4, 9, 1), /* 346 */ + /* 1 */ V(9, 4, 1), + + /* 0101 1111 ... */ + /* 0 */ V(3, 9, 1), /* 348 */ + /* 1 */ V(9, 3, 1), + + /* 0110 0000 ... */ + /* 0 */ V(5, 8, 1), /* 350 */ + /* 1 */ V(8, 5, 1), + + /* 0110 0001 ... */ + /* 0 */ V(2, 9, 1), /* 352 */ + /* 1 */ V(6, 7, 1), + + /* 0110 0010 ... */ + /* 0 */ V(7, 6, 1), /* 354 */ + /* 1 */ V(9, 2, 1), + + /* 0110 0011 ... */ + /* 0 */ V(1, 9, 1), /* 356 */ + /* 1 */ V(9, 1, 1), + + /* 0110 0100 ... */ + /* 0 */ V(4, 8, 1), /* 358 */ + /* 1 */ V(8, 4, 1), + + /* 0110 0101 ... */ + /* 0 */ V(5, 7, 1), /* 360 */ + /* 1 */ V(7, 5, 1), + + /* 0110 0110 ... */ + /* 0 */ V(3, 8, 1), /* 362 */ + /* 1 */ V(8, 3, 1), + + /* 0110 0111 ... */ + /* 0 */ V(6, 6, 1), /* 364 */ + /* 1 */ V(2, 8, 1), + + /* 0110 1000 ... */ + /* 0 */ V(8, 2, 1), /* 366 */ + /* 1 */ V(1, 8, 1), + + /* 0110 1001 ... */ + /* 0 */ V(4, 7, 1), /* 368 */ + /* 1 */ V(7, 4, 1), + + /* 0110 1010 ... */ + /* 00 */ V(8, 1, 1), /* 370 */ + /* 01 */ V(8, 1, 1), + /* 10 */ V(0, 8, 2), + /* 11 */ V(8, 0, 2), + + /* 0110 1011 ... */ + /* 0 */ V(5, 6, 1), /* 374 */ + /* 1 */ V(6, 5, 1), + + /* 0110 1100 ... */ + /* 00 */ V(1, 7, 1), /* 376 */ + /* 01 */ V(1, 7, 1), + /* 10 */ V(0, 7, 2), + /* 11 */ V(7, 0, 2), + + /* 0110 1110 ... */ + /* 0 */ V(3, 7, 1), /* 380 */ + /* 1 */ V(2, 7, 1), + + /* 0111 1100 ... */ + /* 0 */ V(0, 6, 1), /* 382 */ + /* 1 */ V(6, 0, 1), + + /* 1000 0011 ... */ + /* 0 */ V(0, 5, 1), /* 384 */ + /* 1 */ V(5, 0, 1) +]; + +/* hufftable constructor */ +function MP3Hufftable(table, linbits, startbits) { + this.table = table; + this.linbits = linbits; + this.startbits = startbits; +}; + +/* external tables */ +exports.huff_quad_table = [ hufftabA, hufftabB ]; +exports.huff_pair_table = [ + /* 0 */ new MP3Hufftable(hufftab0, 0, 0), + /* 1 */ new MP3Hufftable(hufftab1, 0, 3), + /* 2 */ new MP3Hufftable(hufftab2, 0, 3), + /* 3 */ new MP3Hufftable(hufftab3, 0, 3), + /* 4 */ null, //new MP3Hufftable(0 /* not used */), + /* 5 */ new MP3Hufftable(hufftab5, 0, 3), + /* 6 */ new MP3Hufftable(hufftab6, 0, 4), + /* 7 */ new MP3Hufftable(hufftab7, 0, 4), + /* 8 */ new MP3Hufftable(hufftab8, 0, 4), + /* 9 */ new MP3Hufftable(hufftab9, 0, 4), + /* 10 */ new MP3Hufftable(hufftab10, 0, 4), + /* 11 */ new MP3Hufftable(hufftab11, 0, 4), + /* 12 */ new MP3Hufftable(hufftab12, 0, 4), + /* 13 */ new MP3Hufftable(hufftab13, 0, 4), + /* 14 */ null, //new MP3Hufftable(0 /* not used */), + /* 15 */ new MP3Hufftable(hufftab15, 0, 4), + /* 16 */ new MP3Hufftable(hufftab16, 1, 4), + /* 17 */ new MP3Hufftable(hufftab16, 2, 4), + /* 18 */ new MP3Hufftable(hufftab16, 3, 4), + /* 19 */ new MP3Hufftable(hufftab16, 4, 4), + /* 20 */ new MP3Hufftable(hufftab16, 6, 4), + /* 21 */ new MP3Hufftable(hufftab16, 8, 4), + /* 22 */ new MP3Hufftable(hufftab16, 10, 4), + /* 23 */ new MP3Hufftable(hufftab16, 13, 4), + /* 24 */ new MP3Hufftable(hufftab24, 4, 4), + /* 25 */ new MP3Hufftable(hufftab24, 5, 4), + /* 26 */ new MP3Hufftable(hufftab24, 6, 4), + /* 27 */ new MP3Hufftable(hufftab24, 7, 4), + /* 28 */ new MP3Hufftable(hufftab24, 8, 4), + /* 29 */ new MP3Hufftable(hufftab24, 9, 4), + /* 30 */ new MP3Hufftable(hufftab24, 11, 4), + /* 31 */ new MP3Hufftable(hufftab24, 13, 4) +]; + +},{}],7:[function(require,module,exports){ +var AV = (window.AV); + +const ENCODINGS = ['latin1', 'utf16-bom', 'utf16-be', 'utf8']; + +var ID3Stream = AV.Base.extend({ + constructor: function(header, stream) { + this.header = header; + this.stream = stream; + this.offset = 0; + }, + + read: function() { + if (!this.data) { + this.data = {}; + + // read all frames + var frame; + while (frame = this.readFrame()) { + // if we already have an instance of this key, add it to an array + if (frame.key in this.data) { + if (!Array.isArray(this.data[frame.key])) + this.data[frame.key] = [this.data[frame.key]]; + + this.data[frame.key].push(frame.value); + } else { + this.data[frame.key] = frame.value; + } + } + } + + return this.data; + }, + + readFrame: function() { + if (this.offset >= this.header.length) + return null; + + // get the header + var header = this.readHeader(); + var decoder = header.identifier; + + if (header.identifier.charCodeAt(0) === 0) { + this.offset += this.header.length + 1; + return null; + } + + // map common frame names to a single type + if (!this.frameTypes[decoder]) { + for (var key in this.map) { + if (this.map[key].indexOf(decoder) !== -1) { + decoder = key; + break; + } + } + } + + if (this.frameTypes[decoder]) { + // decode the frame + var frame = this.decodeFrame(header, this.frameTypes[decoder]), + keys = Object.keys(frame); + + // if it only returned one key, use that as the value + if (keys.length === 1) + frame = frame[keys[0]]; + + var result = { + value: frame + }; + + } else { + // No frame type found, treat it as binary + var result = { + value: this.stream.readBuffer(Math.min(header.length, this.header.length - this.offset)) + }; + } + + result.key = this.names[header.identifier] ? this.names[header.identifier] : header.identifier; + + // special sauce for cover art, which should just be a buffer + if (result.key === 'coverArt') + result.value = result.value.data; + + this.offset += 10 + header.length; + return result; + }, + + decodeFrame: function(header, fields) { + var stream = this.stream, + start = stream.offset; + + var encoding = 0, ret = {}; + var len = Object.keys(fields).length, i = 0; + + for (var key in fields) { + var type = fields[key]; + var rest = header.length - (stream.offset - start); + i++; + + // check for special field names + switch (key) { + case 'encoding': + encoding = stream.readUInt8(); + continue; + + case 'language': + ret.language = stream.readString(3); + continue; + } + + // check types + switch (type) { + case 'latin1': + ret[key] = stream.readString(i === len ? rest : null, 'latin1'); + break; + + case 'string': + ret[key] = stream.readString(i === len ? rest : null, ENCODINGS[encoding]); + break; + + case 'binary': + ret[key] = stream.readBuffer(rest) + break; + + case 'int16': + ret[key] = stream.readInt16(); + break; + + case 'int8': + ret[key] = stream.readInt8(); + break; + + case 'int24': + ret[key] = stream.readInt24(); + break; + + case 'int32': + ret[key] = stream.readInt32(); + break; + + case 'int32+': + ret[key] = stream.readInt32(); + if (rest > 4) + throw new Error('Seriously dude? Stop playing this song and get a life!'); + + break; + + case 'date': + var val = stream.readString(8); + ret[key] = new Date(val.slice(0, 4), val.slice(4, 6) - 1, val.slice(6, 8)); + break; + + case 'frame_id': + ret[key] = stream.readString(4); + break; + + default: + throw new Error('Unknown key type ' + type); + } + } + + // Just in case something went wrong... + var rest = header.length - (stream.offset - start); + if (rest > 0) + stream.advance(rest); + + return ret; + } +}); + +// ID3 v2.3 and v2.4 support +exports.ID3v23Stream = ID3Stream.extend({ + readHeader: function() { + var identifier = this.stream.readString(4); + var length = 0; + + if (this.header.major === 4) { + for (var i = 0; i < 4; i++) + length = (length << 7) + (this.stream.readUInt8() & 0x7f); + } else { + length = this.stream.readUInt32(); + } + + return { + identifier: identifier, + length: length, + flags: this.stream.readUInt16() + }; + }, + + map: { + text: [ + // Identification Frames + 'TIT1', 'TIT2', 'TIT3', 'TALB', 'TOAL', 'TRCK', 'TPOS', 'TSST', 'TSRC', + + // Involved Persons Frames + 'TPE1', 'TPE2', 'TPE3', 'TPE4', 'TOPE', 'TEXT', 'TOLY', 'TCOM', 'TMCL', 'TIPL', 'TENC', + + // Derived and Subjective Properties Frames + 'TBPM', 'TLEN', 'TKEY', 'TLAN', 'TCON', 'TFLT', 'TMED', 'TMOO', + + // Rights and Licence Frames + 'TCOP', 'TPRO', 'TPUB', 'TOWN', 'TRSN', 'TRSO', + + // Other Text Frames + 'TOFN', 'TDLY', 'TDEN', 'TDOR', 'TDRC', 'TDRL', 'TDTG', 'TSSE', 'TSOA', 'TSOP', 'TSOT', + + // Deprecated Text Frames + 'TDAT', 'TIME', 'TORY', 'TRDA', 'TSIZ', 'TYER', + + // Non-standard iTunes Frames + 'TCMP', 'TSO2', 'TSOC' + ], + + url: [ + 'WCOM', 'WCOP', 'WOAF', 'WOAR', 'WOAS', 'WORS', 'WPAY', 'WPUB' + ] + }, + + frameTypes: { + text: { + encoding: 1, + value: 'string' + }, + + url: { + value: 'latin1' + }, + + TXXX: { + encoding: 1, + description: 'string', + value: 'string' + }, + + WXXX: { + encoding: 1, + description: 'string', + value: 'latin1', + }, + + USLT: { + encoding: 1, + language: 1, + description: 'string', + value: 'string' + }, + + COMM: { + encoding: 1, + language: 1, + description: 'string', + value: 'string' + }, + + APIC: { + encoding: 1, + mime: 'latin1', + type: 'int8', + description: 'string', + data: 'binary' + }, + + UFID: { + owner: 'latin1', + identifier: 'binary' + }, + + MCDI: { + value: 'binary' + }, + + PRIV: { + owner: 'latin1', + value: 'binary' + }, + + GEOB: { + encoding: 1, + mime: 'latin1', + filename: 'string', + description: 'string', + data: 'binary' + }, + + PCNT: { + value: 'int32+' + }, + + POPM: { + email: 'latin1', + rating: 'int8', + counter: 'int32+' + }, + + AENC: { + owner: 'latin1', + previewStart: 'int16', + previewLength: 'int16', + encryptionInfo: 'binary' + }, + + ETCO: { + format: 'int8', + data: 'binary' // TODO + }, + + MLLT: { + framesBetweenReference: 'int16', + bytesBetweenReference: 'int24', + millisecondsBetweenReference: 'int24', + bitsForBytesDeviation: 'int8', + bitsForMillisecondsDev: 'int8', + data: 'binary' // TODO + }, + + SYTC: { + format: 'int8', + tempoData: 'binary' // TODO + }, + + SYLT: { + encoding: 1, + language: 1, + format: 'int8', + contentType: 'int8', + description: 'string', + data: 'binary' // TODO + }, + + RVA2: { + identification: 'latin1', + data: 'binary' // TODO + }, + + EQU2: { + interpolationMethod: 'int8', + identification: 'latin1', + data: 'binary' // TODO + }, + + RVRB: { + left: 'int16', + right: 'int16', + bouncesLeft: 'int8', + bouncesRight: 'int8', + feedbackLL: 'int8', + feedbackLR: 'int8', + feedbackRR: 'int8', + feedbackRL: 'int8', + premixLR: 'int8', + premixRL: 'int8' + }, + + RBUF: { + size: 'int24', + flag: 'int8', + offset: 'int32' + }, + + LINK: { + identifier: 'frame_id', + url: 'latin1', + data: 'binary' // TODO stringlist? + }, + + POSS: { + format: 'int8', + position: 'binary' // TODO + }, + + USER: { + encoding: 1, + language: 1, + value: 'string' + }, + + OWNE: { + encoding: 1, + price: 'latin1', + purchaseDate: 'date', + seller: 'string' + }, + + COMR: { + encoding: 1, + price: 'latin1', + validUntil: 'date', + contactURL: 'latin1', + receivedAs: 'int8', + seller: 'string', + description: 'string', + logoMime: 'latin1', + logo: 'binary' + }, + + ENCR: { + owner: 'latin1', + methodSymbol: 'int8', + data: 'binary' + }, + + GRID: { + owner: 'latin1', + groupSymbol: 'int8', + data: 'binary' + }, + + SIGN: { + groupSymbol: 'int8', + signature: 'binary' + }, + + SEEK: { + value: 'int32' + }, + + ASPI: { + dataStart: 'int32', + dataLength: 'int32', + numPoints: 'int16', + bitsPerPoint: 'int8', + data: 'binary' // TODO + }, + + // Deprecated ID3 v2.3 frames + IPLS: { + encoding: 1, + value: 'string' // list? + }, + + RVAD: { + adjustment: 'int8', + bits: 'int8', + data: 'binary' // TODO + }, + + EQUA: { + adjustmentBits: 'int8', + data: 'binary' // TODO + } + }, + + names: { + // Identification Frames + 'TIT1': 'grouping', + 'TIT2': 'title', + 'TIT3': 'subtitle', + 'TALB': 'album', + 'TOAL': 'originalAlbumTitle', + 'TRCK': 'trackNumber', + 'TPOS': 'diskNumber', + 'TSST': 'setSubtitle', + 'TSRC': 'ISRC', + + // Involved Persons Frames + 'TPE1': 'artist', + 'TPE2': 'albumArtist', + 'TPE3': 'conductor', + 'TPE4': 'modifiedBy', + 'TOPE': 'originalArtist', + 'TEXT': 'lyricist', + 'TOLY': 'originalLyricist', + 'TCOM': 'composer', + 'TMCL': 'musicianCreditsList', + 'TIPL': 'involvedPeopleList', + 'TENC': 'encodedBy', + + // Derived and Subjective Properties Frames + 'TBPM': 'tempo', + 'TLEN': 'length', + 'TKEY': 'initialKey', + 'TLAN': 'language', + 'TCON': 'genre', + 'TFLT': 'fileType', + 'TMED': 'mediaType', + 'TMOO': 'mood', + + // Rights and Licence Frames + 'TCOP': 'copyright', + 'TPRO': 'producedNotice', + 'TPUB': 'publisher', + 'TOWN': 'fileOwner', + 'TRSN': 'internetRadioStationName', + 'TRSO': 'internetRadioStationOwner', + + // Other Text Frames + 'TOFN': 'originalFilename', + 'TDLY': 'playlistDelay', + 'TDEN': 'encodingTime', + 'TDOR': 'originalReleaseTime', + 'TDRC': 'recordingTime', + 'TDRL': 'releaseTime', + 'TDTG': 'taggingTime', + 'TSSE': 'encodedWith', + 'TSOA': 'albumSortOrder', + 'TSOP': 'performerSortOrder', + 'TSOT': 'titleSortOrder', + + // User defined text information + 'TXXX': 'userText', + + // Unsynchronised lyrics/text transcription + 'USLT': 'lyrics', + + // Attached Picture Frame + 'APIC': 'coverArt', + + // Unique Identifier Frame + 'UFID': 'uniqueIdentifier', + + // Music CD Identifier Frame + 'MCDI': 'CDIdentifier', + + // Comment Frame + 'COMM': 'comments', + + // URL link frames + 'WCOM': 'commercialInformation', + 'WCOP': 'copyrightInformation', + 'WOAF': 'officialAudioFileWebpage', + 'WOAR': 'officialArtistWebpage', + 'WOAS': 'officialAudioSourceWebpage', + 'WORS': 'officialInternetRadioStationHomepage', + 'WPAY': 'payment', + 'WPUB': 'officialPublisherWebpage', + + // User Defined URL Link Frame + 'WXXX': 'url', + + 'PRIV': 'private', + 'GEOB': 'generalEncapsulatedObject', + 'PCNT': 'playCount', + 'POPM': 'rating', + 'AENC': 'audioEncryption', + 'ETCO': 'eventTimingCodes', + 'MLLT': 'MPEGLocationLookupTable', + 'SYTC': 'synchronisedTempoCodes', + 'SYLT': 'synchronisedLyrics', + 'RVA2': 'volumeAdjustment', + 'EQU2': 'equalization', + 'RVRB': 'reverb', + 'RBUF': 'recommendedBufferSize', + 'LINK': 'link', + 'POSS': 'positionSynchronisation', + 'USER': 'termsOfUse', + 'OWNE': 'ownership', + 'COMR': 'commercial', + 'ENCR': 'encryption', + 'GRID': 'groupIdentifier', + 'SIGN': 'signature', + 'SEEK': 'seek', + 'ASPI': 'audioSeekPointIndex', + + // Deprecated ID3 v2.3 frames + 'TDAT': 'date', + 'TIME': 'time', + 'TORY': 'originalReleaseYear', + 'TRDA': 'recordingDates', + 'TSIZ': 'size', + 'TYER': 'year', + 'IPLS': 'involvedPeopleList', + 'RVAD': 'volumeAdjustment', + 'EQUA': 'equalization', + + // Non-standard iTunes frames + 'TCMP': 'compilation', + 'TSO2': 'albumArtistSortOrder', + 'TSOC': 'composerSortOrder' + } +}); + +// ID3 v2.2 support +exports.ID3v22Stream = exports.ID3v23Stream.extend({ + readHeader: function() { + var id = this.stream.readString(3); + + if (this.frameReplacements[id] && !this.frameTypes[id]) + this.frameTypes[id] = this.frameReplacements[id]; + + return { + identifier: this.replacements[id] || id, + length: this.stream.readUInt24() + }; + }, + + // map 3 char ID3 v2.2 names to 4 char ID3 v2.3/4 names + replacements: { + 'UFI': 'UFID', + 'TT1': 'TIT1', + 'TT2': 'TIT2', + 'TT3': 'TIT3', + 'TP1': 'TPE1', + 'TP2': 'TPE2', + 'TP3': 'TPE3', + 'TP4': 'TPE4', + 'TCM': 'TCOM', + 'TXT': 'TEXT', + 'TLA': 'TLAN', + 'TCO': 'TCON', + 'TAL': 'TALB', + 'TPA': 'TPOS', + 'TRK': 'TRCK', + 'TRC': 'TSRC', + 'TYE': 'TYER', + 'TDA': 'TDAT', + 'TIM': 'TIME', + 'TRD': 'TRDA', + 'TMT': 'TMED', + 'TFT': 'TFLT', + 'TBP': 'TBPM', + 'TCR': 'TCOP', + 'TPB': 'TPUB', + 'TEN': 'TENC', + 'TSS': 'TSSE', + 'TOF': 'TOFN', + 'TLE': 'TLEN', + 'TSI': 'TSIZ', + 'TDY': 'TDLY', + 'TKE': 'TKEY', + 'TOT': 'TOAL', + 'TOA': 'TOPE', + 'TOL': 'TOLY', + 'TOR': 'TORY', + 'TXX': 'TXXX', + + 'WAF': 'WOAF', + 'WAR': 'WOAR', + 'WAS': 'WOAS', + 'WCM': 'WCOM', + 'WCP': 'WCOP', + 'WPB': 'WPUB', + 'WXX': 'WXXX', + + 'IPL': 'IPLS', + 'MCI': 'MCDI', + 'ETC': 'ETCO', + 'MLL': 'MLLT', + 'STC': 'SYTC', + 'ULT': 'USLT', + 'SLT': 'SYLT', + 'COM': 'COMM', + 'RVA': 'RVAD', + 'EQU': 'EQUA', + 'REV': 'RVRB', + + 'GEO': 'GEOB', + 'CNT': 'PCNT', + 'POP': 'POPM', + 'BUF': 'RBUF', + 'CRA': 'AENC', + 'LNK': 'LINK', + + // iTunes stuff + 'TST': 'TSOT', + 'TSP': 'TSOP', + 'TSA': 'TSOA', + 'TCP': 'TCMP', + 'TS2': 'TSO2', + 'TSC': 'TSOC' + }, + + // replacements for ID3 v2.3/4 frames + frameReplacements: { + PIC: { + encoding: 1, + format: 'int24', + type: 'int8', + description: 'string', + data: 'binary' + }, + + CRM: { + owner: 'latin1', + description: 'latin1', + data: 'binary' + } + } +}); +},{}],8:[function(require,module,exports){ +function IMDCT() { + this.tmp_imdct36 = new Float64Array(18); + this.tmp_dctIV = new Float64Array(18); + this.tmp_sdctII = new Float64Array(9); +} + +// perform X[18]->x[36] IMDCT using Szu-Wei Lee's fast algorithm +IMDCT.prototype.imdct36 = function(x, y) { + var tmp = this.tmp_imdct36; + + /* DCT-IV */ + this.dctIV(x, tmp); + + // convert 18-point DCT-IV to 36-point IMDCT + for (var i = 0; i < 9; ++i) { + y[i] = tmp[9 + i]; + } + for (var i = 9; i < 27; ++i) { + y[i] = -tmp[36 - (9 + i) - 1]; + } + for (var i = 27; i < 36; ++i) { + y[i] = -tmp[i - 27]; + } +}; + +var dctIV_scale = []; +for(i = 0; i < 18; i++) { + dctIV_scale[i] = 2 * Math.cos(Math.PI * (2 * i + 1) / (4 * 18)); +} + +IMDCT.prototype.dctIV = function(y, X) { + var tmp = this.tmp_dctIV; + + // scaling + for (var i = 0; i < 18; ++i) { + tmp[i] = y[i] * dctIV_scale[i]; + } + + // SDCT-II + this.sdctII(tmp, X); + + // scale reduction and output accumulation + X[0] /= 2; + for (var i = 1; i < 18; ++i) { + X[i] = X[i] / 2 - X[i - 1]; + } +}; + +var sdctII_scale = []; +for (var i = 0; i < 9; ++i) { + sdctII_scale[i] = 2 * Math.cos(Math.PI * (2 * i + 1) / (2 * 18)); +} + +IMDCT.prototype.sdctII = function(x, X) { + // divide the 18-point SDCT-II into two 9-point SDCT-IIs + var tmp = this.tmp_sdctII; + + // even input butterfly + for (var i = 0; i < 9; ++i) { + tmp[i] = x[i] + x[18 - i - 1]; + } + + fastsdct(tmp, X, 0); + + // odd input butterfly and scaling + for (var i = 0; i < 9; ++i) { + tmp[i] = (x[i] - x[18 - i - 1]) * sdctII_scale[i]; + } + + fastsdct(tmp, X, 1); + + // output accumulation + for (var i = 3; i < 18; i += 2) { + X[i] -= X[i - 2]; + } +}; + +var c0 = 2 * Math.cos( 1 * Math.PI / 18); +var c1 = 2 * Math.cos( 3 * Math.PI / 18); +var c2 = 2 * Math.cos( 4 * Math.PI / 18); +var c3 = 2 * Math.cos( 5 * Math.PI / 18); +var c4 = 2 * Math.cos( 7 * Math.PI / 18); +var c5 = 2 * Math.cos( 8 * Math.PI / 18); +var c6 = 2 * Math.cos(16 * Math.PI / 18); + +function fastsdct(x, y, offset) { + var a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12; + var a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25; + var m0, m1, m2, m3, m4, m5, m6, m7; + + a0 = x[3] + x[5]; + a1 = x[3] - x[5]; + a2 = x[6] + x[2]; + a3 = x[6] - x[2]; + a4 = x[1] + x[7]; + a5 = x[1] - x[7]; + a6 = x[8] + x[0]; + a7 = x[8] - x[0]; + + a8 = a0 + a2; + a9 = a0 - a2; + a10 = a0 - a6; + a11 = a2 - a6; + a12 = a8 + a6; + a13 = a1 - a3; + a14 = a13 + a7; + a15 = a3 + a7; + a16 = a1 - a7; + a17 = a1 + a3; + + m0 = a17 * -c3; + m1 = a16 * -c0; + m2 = a15 * -c4; + m3 = a14 * -c1; + m4 = a5 * -c1; + m5 = a11 * -c6; + m6 = a10 * -c5; + m7 = a9 * -c2; + + a18 = x[4] + a4; + a19 = 2 * x[4] - a4; + a20 = a19 + m5; + a21 = a19 - m5; + a22 = a19 + m6; + a23 = m4 + m2; + a24 = m4 - m2; + a25 = m4 + m1; + + // output to every other slot for convenience + y[offset + 0] = a18 + a12; + y[offset + 2] = m0 - a25; + y[offset + 4] = m7 - a20; + y[offset + 6] = m3; + y[offset + 8] = a21 - m6; + y[offset + 10] = a24 - m1; + y[offset + 12] = a12 - 2 * a18; + y[offset + 14] = a23 + m0; + y[offset + 16] = a22 + m7; +} + +IMDCT.S = [ + /* 0 */ [ 0.608761429, + -0.923879533, + -0.130526192, + 0.991444861, + -0.382683432, + -0.793353340 ], + + /* 6 */ [ -0.793353340, + 0.382683432, + 0.991444861, + 0.130526192, + -0.923879533, + -0.608761429 ], + + /* 1 */ [ 0.382683432, + -0.923879533, + 0.923879533, + -0.382683432, + -0.382683432, + 0.923879533 ], + + /* 7 */ [ -0.923879533, + -0.382683432, + 0.382683432, + 0.923879533, + 0.923879533, + 0.382683432 ], + + /* 2 */ [ 0.130526192, + -0.382683432, + 0.608761429, + -0.793353340, + 0.923879533, + -0.991444861 ], + + /* 8 */ [ -0.991444861, + -0.923879533, + -0.793353340, + -0.608761429, + -0.382683432, + -0.130526192 ] +]; + +module.exports = IMDCT; + +},{}],9:[function(require,module,exports){ +var tables = require('./tables'); +var MP3FrameHeader = require('./header'); +var MP3Frame = require('./frame'); +var utils = require('./utils'); + +function Layer1() { + this.allocation = utils.makeArray([2, 32], Uint8Array); + this.scalefactor = utils.makeArray([2, 32], Uint8Array); +} + +MP3Frame.layers[1] = Layer1; + +// linear scaling table +const LINEAR_TABLE = new Float32Array([ + 1.33333333333333, 1.14285714285714, 1.06666666666667, + 1.03225806451613, 1.01587301587302, 1.00787401574803, + 1.00392156862745, 1.00195694716243, 1.00097751710655, + 1.00048851978505, 1.00024420024420, 1.00012208521548, + 1.00006103888177, 1.00003051850948 +]); + +Layer1.prototype.decode = function(stream, frame) { + var header = frame.header; + var nch = header.nchannels(); + + var bound = 32; + if (header.mode === MP3FrameHeader.MODE.JOINT_STEREO) { + header.flags |= MP3FrameHeader.FLAGS.I_STEREO; + bound = 4 + header.mode_extension * 4; + } + + if (header.flags & MP3FrameHeader.FLAGS.PROTECTION) { + // TODO: crc check + } + + // decode bit allocations + var allocation = this.allocation; + for (var sb = 0; sb < bound; sb++) { + for (var ch = 0; ch < nch; ch++) { + var nb = stream.read(4); + if (nb === 15) + throw new Error("forbidden bit allocation value"); + + allocation[ch][sb] = nb ? nb + 1 : 0; + } + } + + for (var sb = bound; sb < 32; sb++) { + var nb = stream.read(4); + if (nb === 15) + throw new Error("forbidden bit allocation value"); + + allocation[0][sb] = + allocation[1][sb] = nb ? nb + 1 : 0; + } + + // decode scalefactors + var scalefactor = this.scalefactor; + for (var sb = 0; sb < 32; sb++) { + for (var ch = 0; ch < nch; ch++) { + if (allocation[ch][sb]) { + scalefactor[ch][sb] = stream.read(6); + + /* + * Scalefactor index 63 does not appear in Table B.1 of + * ISO/IEC 11172-3. Nonetheless, other implementations accept it, + * so we do as well + */ + } + } + } + + // decode samples + for (var s = 0; s < 12; s++) { + for (var sb = 0; sb < bound; sb++) { + for (var ch = 0; ch < nch; ch++) { + var nb = allocation[ch][sb]; + frame.sbsample[ch][s][sb] = nb ? this.sample(stream, nb) * tables.SF_TABLE[scalefactor[ch][sb]] : 0; + } + } + + for (var sb = bound; sb < 32; sb++) { + var nb = allocation[0][sb]; + if (nb) { + var sample = this.sample(stream, nb); + + for (var ch = 0; ch < nch; ch++) { + frame.sbsample[ch][s][sb] = sample * tables.SF_TABLE[scalefactor[ch][sb]]; + } + } else { + for (var ch = 0; ch < nch; ch++) { + frame.sbsample[ch][s][sb] = 0; + } + } + } + } +}; + +Layer1.prototype.sample = function(stream, nb) { + var sample = stream.read(nb); + + // invert most significant bit, and form a 2's complement sample + sample ^= 1 << (nb - 1); + sample |= -(sample & (1 << (nb - 1))); + sample /= (1 << (nb - 1)); + + // requantize the sample + // s'' = (2^nb / (2^nb - 1)) * (s''' + 2^(-nb + 1)) + sample += 1 >> (nb - 1); + return sample * LINEAR_TABLE[nb - 2]; +}; + +module.exports = Layer1; + +},{"./frame":4,"./header":5,"./tables":14,"./utils":15}],10:[function(require,module,exports){ +var tables = require('./tables'); +var MP3FrameHeader = require('./header'); +var MP3Frame = require('./frame'); +var utils = require('./utils'); + +function Layer2() { + this.samples = new Float64Array(3); + this.allocation = utils.makeArray([2, 32], Uint8Array); + this.scfsi = utils.makeArray([2, 32], Uint8Array); + this.scalefactor = utils.makeArray([2, 32, 3], Uint8Array); +} + +MP3Frame.layers[2] = Layer2; + +// possible quantization per subband table +const SBQUANT = [ + // ISO/IEC 11172-3 Table B.2a + { sblimit: 27, offsets: + [ 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 ] }, + + // ISO/IEC 11172-3 Table B.2b + { sblimit: 30, offsets: + [ 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 ] }, + + // ISO/IEC 11172-3 Table B.2c + { sblimit: 8, offsets: + [ 5, 5, 2, 2, 2, 2, 2, 2 ] }, + + // ISO/IEC 11172-3 Table B.2d + { sblimit: 12, offsets: + [ 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ] }, + + // ISO/IEC 13818-3 Table B.1 + { sblimit: 30, offsets: + [ 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ] } +]; + +// bit allocation table +const BITALLOC = [ + { nbal: 2, offset: 0 }, // 0 + { nbal: 2, offset: 3 }, // 1 + { nbal: 3, offset: 3 }, // 2 + { nbal: 3, offset: 1 }, // 3 + { nbal: 4, offset: 2 }, // 4 + { nbal: 4, offset: 3 }, // 5 + { nbal: 4, offset: 4 }, // 6 + { nbal: 4, offset: 5 } // 7 +]; + +// offsets into quantization class table +const OFFSETS = [ + [ 0, 1, 16 ], // 0 + [ 0, 1, 2, 3, 4, 5, 16 ], // 1 + [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ], // 2 + [ 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], // 3 + [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 ], // 4 + [ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ] // 5 +]; + + + +/* + * These are the Layer II classes of quantization. + * The table is derived from Table B.4 of ISO/IEC 11172-3. + */ +const QC_TABLE = [ + { nlevels: 3, group: 2, bits: 5, C: 1.33333333333, D: 0.50000000000 }, + { nlevels: 5, group: 3, bits: 7, C: 1.60000000000, D: 0.50000000000 }, + { nlevels: 7, group: 0, bits: 3, C: 1.14285714286, D: 0.25000000000 }, + { nlevels: 9, group: 4, bits: 10, C: 1.77777777777, D: 0.50000000000 }, + { nlevels: 15, group: 0, bits: 4, C: 1.06666666666, D: 0.12500000000 }, + { nlevels: 31, group: 0, bits: 5, C: 1.03225806452, D: 0.06250000000 }, + { nlevels: 63, group: 0, bits: 6, C: 1.01587301587, D: 0.03125000000 }, + { nlevels: 127, group: 0, bits: 7, C: 1.00787401575, D: 0.01562500000 }, + { nlevels: 255, group: 0, bits: 8, C: 1.00392156863, D: 0.00781250000 }, + { nlevels: 511, group: 0, bits: 9, C: 1.00195694716, D: 0.00390625000 }, + { nlevels: 1023, group: 0, bits: 10, C: 1.00097751711, D: 0.00195312500 }, + { nlevels: 2047, group: 0, bits: 11, C: 1.00048851979, D: 0.00097656250 }, + { nlevels: 4095, group: 0, bits: 12, C: 1.00024420024, D: 0.00048828125 }, + { nlevels: 8191, group: 0, bits: 13, C: 1.00012208522, D: 0.00024414063 }, + { nlevels: 16383, group: 0, bits: 14, C: 1.00006103888, D: 0.00012207031 }, + { nlevels: 32767, group: 0, bits: 15, C: 1.00003051851, D: 0.00006103516 }, + { nlevels: 65535, group: 0, bits: 16, C: 1.00001525902, D: 0.00003051758 } +]; + +Layer2.prototype.decode = function(stream, frame) { + var header = frame.header; + var nch = header.nchannels(); + var index; + + if (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) { + index = 4; + } else if (header.flags & MP3FrameHeader.FLAGS.FREEFORMAT) { + index = header.samplerate === 48000 ? 0 : 1; + } else { + var bitrate_per_channel = header.bitrate; + + if (nch === 2) { + bitrate_per_channel /= 2; + + /* + * ISO/IEC 11172-3 allows only single channel mode for 32, 48, 56, and + * 80 kbps bitrates in Layer II, but some encoders ignore this + * restriction, so we ignore it as well. + */ + } else { + /* + * ISO/IEC 11172-3 does not allow single channel mode for 224, 256, + * 320, or 384 kbps bitrates in Layer II. + */ + if (bitrate_per_channel > 192000) + throw new Error('bad bitrate/mode combination'); + } + + if (bitrate_per_channel <= 48000) + index = header.samplerate === 32000 ? 3 : 2; + else if (bitrate_per_channel <= 80000) + index = 0; + else + index = header.samplerate === 48000 ? 0 : 1; + } + + var sblimit = SBQUANT[index].sblimit; + var offsets = SBQUANT[index].offsets; + + var bound = 32; + if (header.mode === MP3FrameHeader.MODE.JOINT_STEREO) { + header.flags |= MP3FrameHeader.FLAGS.I_STEREO; + bound = 4 + header.mode_extension * 4; + } + + if (bound > sblimit) + bound = sblimit; + + // decode bit allocations + var allocation = this.allocation; + for (var sb = 0; sb < bound; sb++) { + var nbal = BITALLOC[offsets[sb]].nbal; + + for (var ch = 0; ch < nch; ch++) + allocation[ch][sb] = stream.read(nbal); + } + + for (var sb = bound; sb < sblimit; sb++) { + var nbal = BITALLOC[offsets[sb]].nbal; + + allocation[0][sb] = + allocation[1][sb] = stream.read(nbal); + } + + // decode scalefactor selection info + var scfsi = this.scfsi; + for (var sb = 0; sb < sblimit; sb++) { + for (var ch = 0; ch < nch; ch++) { + if (allocation[ch][sb]) + scfsi[ch][sb] = stream.read(2); + } + } + + if (header.flags & MP3FrameHeader.FLAGS.PROTECTION) { + // TODO: crc check + } + + // decode scalefactors + var scalefactor = this.scalefactor; + for (var sb = 0; sb < sblimit; sb++) { + for (var ch = 0; ch < nch; ch++) { + if (allocation[ch][sb]) { + scalefactor[ch][sb][0] = stream.read(6); + + switch (scfsi[ch][sb]) { + case 2: + scalefactor[ch][sb][2] = + scalefactor[ch][sb][1] = scalefactor[ch][sb][0]; + break; + + case 0: + scalefactor[ch][sb][1] = stream.read(6); + // fall through + + case 1: + case 3: + scalefactor[ch][sb][2] = stream.read(6); + } + + if (scfsi[ch][sb] & 1) + scalefactor[ch][sb][1] = scalefactor[ch][sb][scfsi[ch][sb] - 1]; + + /* + * Scalefactor index 63 does not appear in Table B.1 of + * ISO/IEC 11172-3. Nonetheless, other implementations accept it, + * so we do as well. + */ + } + } + } + + // decode samples + for (var gr = 0; gr < 12; gr++) { + // normal + for (var sb = 0; sb < bound; sb++) { + for (var ch = 0; ch < nch; ch++) { + if (index = allocation[ch][sb]) { + index = OFFSETS[BITALLOC[offsets[sb]].offset][index - 1]; + this.decodeSamples(stream, QC_TABLE[index]); + + var scale = tables.SF_TABLE[scalefactor[ch][sb][gr >> 2]]; + for (var s = 0; s < 3; s++) { + frame.sbsample[ch][3 * gr + s][sb] = this.samples[s] * scale; + } + } else { + for (var s = 0; s < 3; s++) { + frame.sbsample[ch][3 * gr + s][sb] = 0; + } + } + } + } + + // joint stereo + for (var sb = bound; sb < sblimit; sb++) { + if (index = allocation[0][sb]) { + index = OFFSETS[BITALLOC[offsets[sb]].offset][index - 1]; + this.decodeSamples(stream, QC_TABLE[index]); + + for (var ch = 0; ch < nch; ch++) { + var scale = tables.SF_TABLE[scalefactor[ch][sb][gr >> 2]]; + for (var s = 0; s < 3; s++) { + frame.sbsample[ch][3 * gr + s][sb] = this.samples[s] * scale; + } + } + } else { + for (var ch = 0; ch < nch; ch++) { + for (var s = 0; s < 3; s++) { + frame.sbsample[ch][3 * gr + s][sb] = 0; + } + } + } + } + + // the rest + for (var ch = 0; ch < nch; ch++) { + for (var s = 0; s < 3; s++) { + for (var sb = sblimit; sb < 32; sb++) { + frame.sbsample[ch][3 * gr + s][sb] = 0; + } + } + } + } +}; + +Layer2.prototype.decodeSamples = function(stream, quantclass) { + var sample = this.samples; + var nb = quantclass.group; + + if (nb) { + // degrouping + var c = stream.read(quantclass.bits); + var nlevels = quantclass.nlevels; + + for (var s = 0; s < 3; s++) { + sample[s] = c % nlevels; + c = c / nlevels | 0; + } + } else { + nb = quantclass.bits; + for (var s = 0; s < 3; s++) { + sample[s] = stream.read(nb); + } + } + + for (var s = 0; s < 3; s++) { + // invert most significant bit, and form a 2's complement sample + var requantized = sample[s] ^ (1 << (nb - 1)); + requantized |= -(requantized & (1 << (nb - 1))); + requantized /= (1 << (nb - 1)); + + // requantize the sample + sample[s] = (requantized + quantclass.D) * quantclass.C; + } +}; + +module.exports = Layer2; + +},{"./frame":4,"./header":5,"./tables":14,"./utils":15}],11:[function(require,module,exports){ +var AV = (window.AV); +var tables = require('./tables'); +var MP3FrameHeader = require('./header'); +var MP3Frame = require('./frame'); +var huffman = require('./huffman'); +var IMDCT = require('./imdct'); +var utils = require('./utils'); + +function MP3SideInfo() { + this.main_data_begin = null; + this.private_bits = null; + this.gr = [new MP3Granule(), new MP3Granule()]; + this.scfsi = new Uint8Array(2); +} + +function MP3Granule() { + this.ch = [new MP3Channel(), new MP3Channel()]; +} + +function MP3Channel() { + // from side info + this.part2_3_length = null; + this.big_values = null; + this.global_gain = null; + this.scalefac_compress = null; + + this.flags = null; + this.block_type = null; + this.table_select = new Uint8Array(3); + this.subblock_gain = new Uint8Array(3); + this.region0_count = null; + this.region1_count = null; + + // from main_data + this.scalefac = new Uint8Array(39); +} + +function Layer3() { + this.imdct = new IMDCT(); + this.si = new MP3SideInfo(); + + // preallocate reusable typed arrays for performance + this.xr = [new Float64Array(576), new Float64Array(576)]; + this._exponents = new Int32Array(39); + this.reqcache = new Float64Array(16); + this.modes = new Int16Array(39); + this.output = new Float64Array(36); + + this.tmp = utils.makeArray([32, 3, 6]); + this.tmp2 = new Float64Array(32 * 3 * 6); +} + +MP3Frame.layers[3] = Layer3; + +Layer3.prototype.decode = function(stream, frame) { + var header = frame.header; + var next_md_begin = 0; + var md_len = 0; + + var nch = header.nchannels(); + var si_len = (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) ? (nch === 1 ? 9 : 17) : (nch === 1 ? 17 : 32); + + // check frame sanity + if (stream.next_frame - stream.nextByte() < si_len) { + stream.md_len = 0; + throw new Error('Bad frame length'); + } + + // check CRC word + if (header.flags & MP3FrameHeader.FLAGS.PROTECTION) { + // TODO: crc check + } + + // decode frame side information + var sideInfo = this.sideInfo(stream, nch, header.flags & MP3FrameHeader.FLAGS.LSF_EXT); + var si = sideInfo.si; + var data_bitlen = sideInfo.data_bitlen; + var priv_bitlen = sideInfo.priv_bitlen; + + header.flags |= priv_bitlen; + header.private_bits |= si.private_bits; + + // find main_data of next frame + var peek = stream.copy(); + peek.seek(stream.next_frame * 8); + + var nextHeader = peek.read(16); + if ((nextHeader & 0xffe6) === 0xffe2) { // syncword | layer + if ((nextHeader & 1) === 0) // protection bit + peek.advance(16); // crc check + + peek.advance(16); // skip the rest of the header + next_md_begin = peek.read((nextHeader & 8) ? 9 : 8); + } + + // find main_data of this frame + var frame_space = stream.next_frame - stream.nextByte(); + + if (next_md_begin > si.main_data_begin + frame_space) + next_md_begin = 0; + + var md_len = si.main_data_begin + frame_space - next_md_begin; + var frame_used = 0; + var ptr; + + if (si.main_data_begin === 0) { + ptr = stream.stream; + stream.md_len = 0; + frame_used = md_len; + } else { + if (si.main_data_begin > stream.md_len) { + throw new Error('bad main_data_begin pointer'); + } else { + var old_md_len = stream.md_len; + + if (md_len > si.main_data_begin) { + if (stream.md_len + md_len - si.main_data_begin > MP3FrameHeader.BUFFER_MDLEN) { + throw new Error("Assertion failed: (stream.md_len + md_len - si.main_data_begin <= MAD_MP3FrameHeader.BUFFER_MDLEN)"); + } + + frame_used = md_len - si.main_data_begin; + this.memcpy(stream.main_data, stream.md_len, stream.stream.stream, stream.nextByte(), frame_used); + stream.md_len += frame_used; + } + + ptr = new AV.Bitstream(AV.Stream.fromBuffer(new AV.Buffer(stream.main_data))); + ptr.advance((old_md_len - si.main_data_begin) * 8); + } + } + + var frame_free = frame_space - frame_used; + + // decode main_data + this.decodeMainData(ptr, frame, si, nch); + + // preload main_data buffer with up to 511 bytes for next frame(s) + if (frame_free >= next_md_begin) { + this.memcpy(stream.main_data, 0, stream.stream.stream, stream.next_frame - next_md_begin, next_md_begin); + stream.md_len = next_md_begin; + } else { + if (md_len < si.main_data_begin) { + var extra = si.main_data_begin - md_len; + if (extra + frame_free > next_md_begin) + extra = next_md_begin - frame_free; + + if (extra < stream.md_len) { + this.memcpy(stream.main_data, 0, stream.main_data, stream.md_len - extra, extra); + stream.md_len = extra; + } + } else { + stream.md_len = 0; + } + + this.memcpy(stream.main_data, stream.md_len, stream.stream.stream, stream.next_frame - frame_free, frame_free); + stream.md_len += frame_free; + } +}; + +Layer3.prototype.memcpy = function(dst, dstOffset, pSrc, srcOffset, length) { + var subarr; + if (pSrc.subarray) + subarr = pSrc.subarray(srcOffset, srcOffset + length); + else + subarr = pSrc.peekBuffer(srcOffset - pSrc.offset, length).data; + + // oh my, memcpy actually exists in JavaScript? + dst.set(subarr, dstOffset); + return dst; +}; + +Layer3.prototype.sideInfo = function(stream, nch, lsf) { + var si = this.si; + var data_bitlen = 0; + var priv_bitlen = lsf ? ((nch === 1) ? 1 : 2) : ((nch === 1) ? 5 : 3); + + si.main_data_begin = stream.read(lsf ? 8 : 9); + si.private_bits = stream.read(priv_bitlen); + + var ngr = 1; + if (!lsf) { + ngr = 2; + for (var ch = 0; ch < nch; ++ch) + si.scfsi[ch] = stream.read(4); + } + + for (var gr = 0; gr < ngr; gr++) { + var granule = si.gr[gr]; + + for (var ch = 0; ch < nch; ch++) { + var channel = granule.ch[ch]; + + channel.part2_3_length = stream.read(12); + channel.big_values = stream.read(9); + channel.global_gain = stream.read(8); + channel.scalefac_compress = stream.read(lsf ? 9 : 4); + + data_bitlen += channel.part2_3_length; + + if (channel.big_values > 288) + throw new Error('bad big_values count'); + + channel.flags = 0; + + // window_switching_flag + if (stream.read(1)) { + channel.block_type = stream.read(2); + + if (channel.block_type === 0) + throw new Error('reserved block_type'); + + if (!lsf && channel.block_type === 2 && si.scfsi[ch]) + throw new Error('bad scalefactor selection info'); + + channel.region0_count = 7; + channel.region1_count = 36; + + if (stream.read(1)) + channel.flags |= tables.MIXED_BLOCK_FLAG; + else if (channel.block_type === 2) + channel.region0_count = 8; + + for (var i = 0; i < 2; i++) + channel.table_select[i] = stream.read(5); + + for (var i = 0; i < 3; i++) + channel.subblock_gain[i] = stream.read(3); + } else { + channel.block_type = 0; + + for (var i = 0; i < 3; i++) + channel.table_select[i] = stream.read(5); + + channel.region0_count = stream.read(4); + channel.region1_count = stream.read(3); + } + + // [preflag,] scalefac_scale, count1table_select + channel.flags |= stream.read(lsf ? 2 : 3); + } + } + + return { + si: si, + data_bitlen: data_bitlen, + priv_bitlen: priv_bitlen + }; +}; + +Layer3.prototype.decodeMainData = function(stream, frame, si, nch) { + var header = frame.header; + var sfreq = header.samplerate; + + if (header.flags & MP3FrameHeader.FLAGS.MPEG_2_5_EXT) + sfreq *= 2; + + // 48000 => 0, 44100 => 1, 32000 => 2, + // 24000 => 3, 22050 => 4, 16000 => 5 + var sfreqi = ((sfreq >> 7) & 0x000f) + ((sfreq >> 15) & 0x0001) - 8; + + if (header.flags & MP3FrameHeader.FLAGS.MPEG_2_5_EXT) + sfreqi += 3; + + // scalefactors, Huffman decoding, requantization + var ngr = (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) ? 1 : 2; + var xr = this.xr; + + for (var gr = 0; gr < ngr; ++gr) { + var granule = si.gr[gr]; + var sfbwidth = []; + var l = 0; + + for (var ch = 0; ch < nch; ++ch) { + var channel = granule.ch[ch]; + var part2_length; + + sfbwidth[ch] = tables.SFBWIDTH_TABLE[sfreqi].l; + if (channel.block_type === 2) { + sfbwidth[ch] = (channel.flags & tables.MIXED_BLOCK_FLAG) ? tables.SFBWIDTH_TABLE[sfreqi].m : tables.SFBWIDTH_TABLE[sfreqi].s; + } + + if (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) { + part2_length = this.scalefactors_lsf(stream, channel, ch === 0 ? 0 : si.gr[1].ch[1], header.mode_extension); + } else { + part2_length = this.scalefactors(stream, channel, si.gr[0].ch[ch], gr === 0 ? 0 : si.scfsi[ch]); + } + + this.huffmanDecode(stream, xr[ch], channel, sfbwidth[ch], part2_length); + } + + // joint stereo processing + if (header.mode === MP3FrameHeader.MODE.JOINT_STEREO && header.mode_extension !== 0) + this.stereo(xr, si.gr, gr, header, sfbwidth[0]); + + // reordering, alias reduction, IMDCT, overlap-add, frequency inversion + for (var ch = 0; ch < nch; ch++) { + var channel = granule.ch[ch]; + var sample = frame.sbsample[ch].slice(18 * gr); + + var sb, l = 0, i, sblimit; + var output = this.output; + + if (channel.block_type === 2) { + this.reorder(xr[ch], channel, sfbwidth[ch]); + + /* + * According to ISO/IEC 11172-3, "Alias reduction is not applied for + * granules with block_type === 2 (short block)." However, other + * sources suggest alias reduction should indeed be performed on the + * lower two subbands of mixed blocks. Most other implementations do + * this, so by default we will too. + */ + if (channel.flags & tables.MIXED_BLOCK_FLAG) + this.aliasreduce(xr[ch], 36); + } else { + this.aliasreduce(xr[ch], 576); + } + + // subbands 0-1 + if (channel.block_type !== 2 || (channel.flags & tables.MIXED_BLOCK_FLAG)) { + var block_type = channel.block_type; + if (channel.flags & tables.MIXED_BLOCK_FLAG) + block_type = 0; + + // long blocks + for (var sb = 0; sb < 2; ++sb, l += 18) { + this.imdct_l(xr[ch].subarray(l, l + 18), output, block_type); + this.overlap(output, frame.overlap[ch][sb], sample, sb); + } + } else { + // short blocks + for (var sb = 0; sb < 2; ++sb, l += 18) { + this.imdct_s(xr[ch].subarray(l, l + 18), output); + this.overlap(output, frame.overlap[ch][sb], sample, sb); + } + } + + this.freqinver(sample, 1); + + // (nonzero) subbands 2-31 + var i = 576; + while (i > 36 && xr[ch][i - 1] === 0) { + --i; + } + + sblimit = 32 - (((576 - i) / 18) << 0); + + if (channel.block_type !== 2) { + // long blocks + for (var sb = 2; sb < sblimit; ++sb, l += 18) { + this.imdct_l(xr[ch].subarray(l, l + 18), output, channel.block_type); + this.overlap(output, frame.overlap[ch][sb], sample, sb); + + if (sb & 1) + this.freqinver(sample, sb); + } + } else { + // short blocks + for (var sb = 2; sb < sblimit; ++sb, l += 18) { + this.imdct_s(xr[ch].subarray(l, l + 18), output); + this.overlap(output, frame.overlap[ch][sb], sample, sb); + + if (sb & 1) + this.freqinver(sample, sb); + } + } + + // remaining (zero) subbands + for (var sb = sblimit; sb < 32; ++sb) { + this.overlap_z(frame.overlap[ch][sb], sample, sb); + + if (sb & 1) + this.freqinver(sample, sb); + } + } + } +}; + +Layer3.prototype.scalefactors = function(stream, channel, gr0ch, scfsi) { + var start = stream.offset(); + var slen1 = tables.SFLEN_TABLE[channel.scalefac_compress].slen1; + var slen2 = tables.SFLEN_TABLE[channel.scalefac_compress].slen2; + var sfbi; + + if (channel.block_type === 2) { + sfbi = 0; + + var nsfb = (channel.flags & tables.MIXED_BLOCK_FLAG) ? 8 + 3 * 3 : 6 * 3; + while (nsfb--) + channel.scalefac[sfbi++] = stream.read(slen1); + + nsfb = 6 * 3; + while (nsfb--) + channel.scalefac[sfbi++] = stream.read(slen2); + + nsfb = 1 * 3; + while (nsfb--) + channel.scalefac[sfbi++] = 0; + } else { + if (scfsi & 0x8) { + for (var sfbi = 0; sfbi < 6; ++sfbi) + channel.scalefac[sfbi] = gr0ch.scalefac[sfbi]; + } else { + for (var sfbi = 0; sfbi < 6; ++sfbi) + channel.scalefac[sfbi] = stream.read(slen1); + } + + if (scfsi & 0x4) { + for (var sfbi = 6; sfbi < 11; ++sfbi) + channel.scalefac[sfbi] = gr0ch.scalefac[sfbi]; + } else { + for (var sfbi = 6; sfbi < 11; ++sfbi) + channel.scalefac[sfbi] = stream.read(slen1); + } + + if (scfsi & 0x2) { + for (var sfbi = 11; sfbi < 16; ++sfbi) + channel.scalefac[sfbi] = gr0ch.scalefac[sfbi]; + } else { + for (var sfbi = 11; sfbi < 16; ++sfbi) + channel.scalefac[sfbi] = stream.read(slen2); + } + + if (scfsi & 0x1) { + for (var sfbi = 16; sfbi < 21; ++sfbi) + channel.scalefac[sfbi] = gr0ch.scalefac[sfbi]; + } else { + for (var sfbi = 16; sfbi < 21; ++sfbi) + channel.scalefac[sfbi] = stream.read(slen2); + } + + channel.scalefac[21] = 0; + } + + return stream.offset() - start; +}; + +Layer3.prototype.scalefactors_lsf = function(stream, channel, gr1ch, mode_extension) { + var start = stream.offset(); + var scalefac_compress = channel.scalefac_compress; + var index = channel.block_type === 2 ? (channel.flags & tables.MIXED_BLOCK_FLAG ? 2 : 1) : 0; + var slen = new Int32Array(4); + var nsfb; + + if (!((mode_extension & tables.I_STEREO) && gr1ch)) { + if (scalefac_compress < 400) { + slen[0] = (scalefac_compress >>> 4) / 5; + slen[1] = (scalefac_compress >>> 4) % 5; + slen[2] = (scalefac_compress % 16) >>> 2; + slen[3] = scalefac_compress % 4; + + nsfb = tables.NSFB_TABLE[0][index]; + } else if (scalefac_compress < 500) { + scalefac_compress -= 400; + + slen[0] = (scalefac_compress >>> 2) / 5; + slen[1] = (scalefac_compress >>> 2) % 5; + slen[2] = scalefac_compress % 4; + slen[3] = 0; + + nsfb = tables.NSFB_TABLE[1][index]; + } else { + scalefac_compress -= 500; + + slen[0] = scalefac_compress / 3; + slen[1] = scalefac_compress % 3; + slen[2] = 0; + slen[3] = 0; + + channel.flags |= tables.PREFLAG; + nsfb = tables.NSFB_TABLE[2][index]; + } + + var n = 0; + for (var part = 0; part < 4; part++) { + for (var i = 0; i < nsfb[part]; i++) { + channel.scalefac[n++] = stream.read(slen[part]); + } + } + + while (n < 39) { + channel.scalefac[n++] = 0; + } + } else { // (mode_extension & tables.I_STEREO) && gr1ch (i.e. ch == 1) + scalefac_compress >>>= 1; + + if (scalefac_compress < 180) { + slen[0] = scalefac_compress / 36; + slen[1] = (scalefac_compress % 36) / 6; + slen[2] = (scalefac_compress % 36) % 6; + slen[3] = 0; + + nsfb = tables.NSFB_TABLE[3][index]; + } else if (scalefac_compress < 244) { + scalefac_compress -= 180; + + slen[0] = (scalefac_compress % 64) >>> 4; + slen[1] = (scalefac_compress % 16) >>> 2; + slen[2] = scalefac_compress % 4; + slen[3] = 0; + + nsfb = tables.NSFB_TABLE[4][index]; + } else { + scalefac_compress -= 244; + + slen[0] = scalefac_compress / 3; + slen[1] = scalefac_compress % 3; + slen[2] = 0; + slen[3] = 0; + + nsfb = tables.NSFB_TABLE[5][index]; + } + + var n = 0; + for (var part = 0; part < 4; ++part) { + var max = (1 << slen[part]) - 1; + for (var i = 0; i < nsfb[part]; ++i) { + var is_pos = stream.read(slen[part]); + + channel.scalefac[n] = is_pos; + gr1ch.scalefac[n++] = is_pos === max ? 1 : 0; + } + } + + while (n < 39) { + channel.scalefac[n] = 0; + gr1ch.scalefac[n++] = 0; // apparently not illegal + } + } + + return stream.offset() - start; +}; + +Layer3.prototype.huffmanDecode = function(stream, xr, channel, sfbwidth, part2_length) { + var exponents = this._exponents; + var sfbwidthptr = 0; + + var bits_left = channel.part2_3_length - part2_length; + if (bits_left < 0) + throw new Error('bad audio data length'); + + this.exponents(channel, sfbwidth, exponents); + + var peek = stream.copy(); + stream.advance(bits_left); + + /* align bit reads to byte boundaries */ + var cachesz = 8 - peek.bitPosition; + cachesz += ((32 - 1 - 24) + (24 - cachesz)) & ~7; + + var bitcache = peek.read(cachesz); + bits_left -= cachesz; + + var xrptr = 0; + + // big_values + var region = 0; + var reqcache = this.reqcache; + + var sfbound = xrptr + sfbwidth[sfbwidthptr++]; + var rcount = channel.region0_count + 1; + + var entry = huffman.huff_pair_table[channel.table_select[region]]; + var table = entry.table; + var linbits = entry.linbits; + var startbits = entry.startbits; + + if (typeof table === 'undefined') + throw new Error('bad Huffman table select'); + + var expptr = 0; + var exp = exponents[expptr++]; + var reqhits = 0; + var big_values = channel.big_values; + + while (big_values-- && cachesz + bits_left > 0) { + if (xrptr === sfbound) { + sfbound += sfbwidth[sfbwidthptr++]; + + // change table if region boundary + if (--rcount === 0) { + if (region === 0) + rcount = channel.region1_count + 1; + else + rcount = 0; // all remaining + + entry = huffman.huff_pair_table[channel.table_select[++region]]; + table = entry.table; + linbits = entry.linbits; + startbits = entry.startbits; + + if (typeof table === 'undefined') + throw new Error('bad Huffman table select'); + } + + if (exp !== exponents[expptr]) { + exp = exponents[expptr]; + reqhits = 0; + } + + ++expptr; + } + + if (cachesz < 21) { + var bits = ((32 - 1 - 21) + (21 - cachesz)) & ~7; + bitcache = (bitcache << bits) | peek.read(bits); + cachesz += bits; + bits_left -= bits; + } + + var clumpsz = startbits; + var pair = table[ (((bitcache) >> ((cachesz) - (clumpsz))) & ((1 << (clumpsz)) - 1))]; + + while (!pair.final) { + cachesz -= clumpsz; + clumpsz = pair.ptr.bits; + pair = table[pair.ptr.offset + (((bitcache) >> ((cachesz) - (clumpsz))) & ((1 << (clumpsz)) - 1))]; + } + + cachesz -= pair.value.hlen; + + if (linbits) { + var value = pair.value.x; + var x_final = false; + + switch (value) { + case 0: + xr[xrptr] = 0; + break; + + case 15: + if (cachesz < linbits + 2) { + bitcache = (bitcache << 16) | peek.read(16); + cachesz += 16; + bits_left -= 16; + } + + value += (((bitcache) >> ((cachesz) - (linbits))) & ((1 << (linbits)) - 1)); + cachesz -= linbits; + + requantized = this.requantize(value, exp); + x_final = true; // simulating goto, yay + break; + + default: + if (reqhits & (1 << value)) { + requantized = reqcache[value]; + } else { + reqhits |= (1 << value); + requantized = reqcache[value] = this.requantize(value, exp); + } + + x_final = true; + } + + if(x_final) { + xr[xrptr] = ((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized; + } + + value = pair.value.y; + var y_final = false; + + switch (value) { + case 0: + xr[xrptr + 1] = 0; + break; + + case 15: + if (cachesz < linbits + 1) { + bitcache = (bitcache << 16) | peek.read(16); + cachesz += 16; + bits_left -= 16; + } + + value += (((bitcache) >> ((cachesz) - (linbits))) & ((1 << (linbits)) - 1)); + cachesz -= linbits; + + requantized = this.requantize(value, exp); + y_final = true; + break; // simulating goto, yayzor + + default: + if (reqhits & (1 << value)) { + requantized = reqcache[value]; + } else { + reqhits |= (1 << value); + reqcache[value] = this.requantize(value, exp); + requantized = reqcache[value]; + } + + y_final = true; + } + + if(y_final) { + xr[xrptr + 1] = ((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized; + } + + } else { + var value = pair.value.x; + + if (value === 0) { + xr[xrptr] = 0; + } else { + if (reqhits & (1 << value)) + requantized = reqcache[value]; + else { + reqhits |= (1 << value); + requantized = reqcache[value] = this.requantize(value, exp); + } + + xr[xrptr] = ((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized; + } + + value = pair.value.y; + + if (value === 0) { + xr[xrptr + 1] = 0; + } else { + if (reqhits & (1 << value)) + requantized = reqcache[value]; + else { + reqhits |= (1 << value); + requantized = reqcache[value] = this.requantize(value, exp); + } + + xr[xrptr + 1] = ((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized; + } + } + + xrptr += 2; + } + + if (cachesz + bits_left < 0) + throw new Error('Huffman data overrun'); + + // count1 + var table = huffman.huff_quad_table[channel.flags & tables.COUNT1TABLE_SELECT]; + var requantized = this.requantize(1, exp); + + while (cachesz + bits_left > 0 && xrptr <= 572) { + if (cachesz < 10) { + bitcache = (bitcache << 16) | peek.read(16); + cachesz += 16; + bits_left -= 16; + } + + var quad = table[(((bitcache) >> ((cachesz) - (4))) & ((1 << (4)) - 1))]; + + // quad tables guaranteed to have at most one extra lookup + if (!quad.final) { + cachesz -= 4; + quad = table[quad.ptr.offset + (((bitcache) >> ((cachesz) - (quad.ptr.bits))) & ((1 << (quad.ptr.bits)) - 1))]; + } + + cachesz -= quad.value.hlen; + + if (xrptr === sfbound) { + sfbound += sfbwidth[sfbwidthptr++]; + + if (exp !== exponents[expptr]) { + exp = exponents[expptr]; + requantized = this.requantize(1, exp); + } + + ++expptr; + } + + // v (0..1) + xr[xrptr] = quad.value.v ? (((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0; + + // w (0..1) + xr[xrptr + 1] = quad.value.w ? (((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0; + + xrptr += 2; + if (xrptr === sfbound) { + sfbound += sfbwidth[sfbwidthptr++]; + + if (exp !== exponents[expptr]) { + exp = exponents[expptr]; + requantized = this.requantize(1, exp); + } + + ++expptr; + } + + // x (0..1) + xr[xrptr] = quad.value.x ? (((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0; + + // y (0..1) + xr[xrptr + 1] = quad.value.y ? (((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0; + + xrptr += 2; + + if (cachesz + bits_left < 0) { + // technically the bitstream is misformatted, but apparently + // some encoders are just a bit sloppy with stuffing bits + xrptr -= 4; + } + } + + if (-bits_left > MP3FrameHeader.BUFFER_GUARD * 8) { + throw new Error("assertion failed: (-bits_left <= MP3FrameHeader.BUFFER_GUARD * CHAR_BIT)"); + } + + // rzero + while (xrptr < 576) { + xr[xrptr] = 0; + xr[xrptr + 1] = 0; + xrptr += 2; + } +}; + +Layer3.prototype.requantize = function(value, exp) { + // usual (x >> 0) tricks to make sure frac and exp stay integers + var frac = (exp % 4) >> 0; // assumes sign(frac) === sign(exp) + exp = (exp / 4) >> 0; + + var requantized = Math.pow(value, 4.0 / 3.0); + requantized *= Math.pow(2.0, (exp / 4.0)); + + if (frac) { + requantized *= Math.pow(2.0, (frac / 4.0)); + } + + if (exp < 0) { + requantized /= Math.pow(2.0, -exp * (3.0 / 4.0)); + } + + return requantized; +}; + +Layer3.prototype.exponents = function(channel, sfbwidth, exponents) { + var gain = channel.global_gain - 210; + var scalefac_multiplier = (channel.flags & tables.SCALEFAC_SCALE) ? 2 : 1; + + if (channel.block_type === 2) { + var sfbi = 0, l = 0; + + if (channel.flags & tables.MIXED_BLOCK_FLAG) { + var premask = (channel.flags & tables.PREFLAG) ? ~0 : 0; + + // long block subbands 0-1 + while (l < 36) { + exponents[sfbi] = gain - ((channel.scalefac[sfbi] + (tables.PRETAB[sfbi] & premask)) << scalefac_multiplier); + l += sfbwidth[sfbi++]; + } + } + + // this is probably wrong for 8000 Hz short/mixed blocks + var gain0 = gain - 8 * channel.subblock_gain[0]; + var gain1 = gain - 8 * channel.subblock_gain[1]; + var gain2 = gain - 8 * channel.subblock_gain[2]; + + while (l < 576) { + exponents[sfbi + 0] = gain0 - (channel.scalefac[sfbi + 0] << scalefac_multiplier); + exponents[sfbi + 1] = gain1 - (channel.scalefac[sfbi + 1] << scalefac_multiplier); + exponents[sfbi + 2] = gain2 - (channel.scalefac[sfbi + 2] << scalefac_multiplier); + + l += 3 * sfbwidth[sfbi]; + sfbi += 3; + } + } else { + if (channel.flags & tables.PREFLAG) { + for (var sfbi = 0; sfbi < 22; sfbi++) { + exponents[sfbi] = gain - ((channel.scalefac[sfbi] + tables.PRETAB[sfbi]) << scalefac_multiplier); + } + } else { + for (var sfbi = 0; sfbi < 22; sfbi++) { + exponents[sfbi] = gain - (channel.scalefac[sfbi] << scalefac_multiplier); + } + } + } +}; + +Layer3.prototype.stereo = function(xr, granules, gr, header, sfbwidth) { + var granule = granules[gr]; + var modes = this.modes; + var sfbi, l, n, i; + + if (granule.ch[0].block_type !== granule.ch[1].block_type || (granule.ch[0].flags & tables.MIXED_BLOCK_FLAG) !== (granule.ch[1].flags & tables.MIXED_BLOCK_FLAG)) + throw new Error('incompatible stereo block_type'); + + for (var i = 0; i < 39; i++) + modes[i] = header.mode_extension; + + // intensity stereo + if (header.mode_extension & tables.I_STEREO) { + var right_ch = granule.ch[1]; + var right_xr = xr[1]; + + header.flags |= MP3FrameHeader.FLAGS.tables.I_STEREO; + + // first determine which scalefactor bands are to be processed + if (right_ch.block_type === 2) { + var lower, start, max, bound = new Uint32Array(3), w; + + lower = start = max = bound[0] = bound[1] = bound[2] = 0; + sfbi = l = 0; + + if (right_ch.flags & tables.MIXED_BLOCK_FLAG) { + while (l < 36) { + n = sfbwidth[sfbi++]; + + for (var i = 0; i < n; ++i) { + if (right_xr[i]) { + lower = sfbi; + break; + } + } + + right_xr += n; + l += n; + } + + start = sfbi; + } + + var w = 0; + while (l < 576) { + n = sfbwidth[sfbi++]; + + for (i = 0; i < n; ++i) { + if (right_xr[i]) { + max = bound[w] = sfbi; + break; + } + } + + right_xr += n; + l += n; + w = (w + 1) % 3; + } + + if (max) + lower = start; + + // long blocks + for (i = 0; i < lower; ++i) + modes[i] = header.mode_extension & ~tables.I_STEREO; + + // short blocks + w = 0; + for (i = start; i < max; ++i) { + if (i < bound[w]) + modes[i] = header.mode_extension & ~tables.I_STEREO; + + w = (w + 1) % 3; + } + } else { + var bound = 0; + for (sfbi = l = 0; l < 576; l += n) { + n = sfbwidth[sfbi++]; + + for (i = 0; i < n; ++i) { + if (right_xr[i]) { + bound = sfbi; + break; + } + } + + right_xr += n; + } + + for (i = 0; i < bound; ++i) + modes[i] = header.mode_extension & ~tables.I_STEREO; + } + + // now do the actual processing + if (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) { + var illegal_pos = granules[gr + 1].ch[1].scalefac; + + // intensity_scale + var lsf_scale = IS_Ltables.SF_TABLE[right_ch.scalefac_compress & 0x1]; + + for (sfbi = l = 0; l < 576; ++sfbi, l += n) { + n = sfbwidth[sfbi]; + + if (!(modes[sfbi] & tables.I_STEREO)) + continue; + + if (illegal_pos[sfbi]) { + modes[sfbi] &= ~tables.I_STEREO; + continue; + } + + is_pos = right_ch.scalefac[sfbi]; + + for (i = 0; i < n; ++i) { + var left = xr[0][l + i]; + + if (is_pos === 0) { + xr[1][l + i] = left; + } else { + var opposite = left * lsf_scale[(is_pos - 1) / 2]; + + if (is_pos & 1) { + xr[0][l + i] = opposite; + xr[1][l + i] = left; + } + else { + xr[1][l + i] = opposite; + } + } + } + } + } else { + for (sfbi = l = 0; l < 576; ++sfbi, l += n) { + n = sfbwidth[sfbi]; + + if (!(modes[sfbi] & tables.I_STEREO)) + continue; + + is_pos = right_ch.scalefac[sfbi]; + + if (is_pos >= 7) { // illegal intensity position + modes[sfbi] &= ~tables.I_STEREO; + continue; + } + + for (i = 0; i < n; ++i) { + var left = xr[0][l + i]; + xr[0][l + i] = left * tables.IS_TABLE[is_pos]; + xr[1][l + i] = left * tables.IS_TABLE[6 - is_pos]; + } + } + } + } + + // middle/side stereo + if (header.mode_extension & tables.MS_STEREO) { + header.flags |= tables.MS_STEREO; + + var invsqrt2 = tables.ROOT_TABLE[3 + -2]; + + for (sfbi = l = 0; l < 576; ++sfbi, l += n) { + n = sfbwidth[sfbi]; + + if (modes[sfbi] !== tables.MS_STEREO) + continue; + + for (i = 0; i < n; ++i) { + var m = xr[0][l + i]; + var s = xr[1][l + i]; + + xr[0][l + i] = (m + s) * invsqrt2; // l = (m + s) / sqrt(2) + xr[1][l + i] = (m - s) * invsqrt2; // r = (m - s) / sqrt(2) + } + } + } +}; + +Layer3.prototype.aliasreduce = function(xr, lines) { + for (var xrPointer = 18; xrPointer < lines; xrPointer += 18) { + for (var i = 0; i < 8; ++i) { + var a = xr[xrPointer - i - 1]; + var b = xr[xrPointer + i]; + + xr[xrPointer - i - 1] = a * tables.CS[i] - b * tables.CA[i]; + xr[xrPointer + i] = b * tables.CS[i] + a * tables.CA[i]; + } + } +}; + +// perform IMDCT and windowing for long blocks +Layer3.prototype.imdct_l = function (X, z, block_type) { + // IMDCT + this.imdct.imdct36(X, z); + + // windowing + switch (block_type) { + case 0: // normal window + for (var i = 0; i < 36; ++i) z[i] = z[i] * tables.WINDOW_L[i]; + break; + + case 1: // start block + for (var i = 0; i < 18; ++i) z[i] = z[i] * tables.WINDOW_L[i]; + for (var i = 24; i < 30; ++i) z[i] = z[i] * tables.WINDOW_S[i - 18]; + for (var i = 30; i < 36; ++i) z[i] = 0; + break; + + case 3: // stop block + for (var i = 0; i < 6; ++i) z[i] = 0; + for (var i = 6; i < 12; ++i) z[i] = z[i] * tables.WINDOW_S[i - 6]; + for (var i = 18; i < 36; ++i) z[i] = z[i] * tables.WINDOW_L[i]; + break; + } +}; + +/* + * perform IMDCT and windowing for short blocks + */ +Layer3.prototype.imdct_s = function (X, z) { + var yptr = 0; + var wptr; + var Xptr = 0; + + var y = new Float64Array(36); + var hi, lo; + + // IMDCT + for (var w = 0; w < 3; ++w) { + var sptr = 0; + + for (var i = 0; i < 3; ++i) { + lo = X[Xptr + 0] * IMDCT.S[sptr][0] + + X[Xptr + 1] * IMDCT.S[sptr][1] + + X[Xptr + 2] * IMDCT.S[sptr][2] + + X[Xptr + 3] * IMDCT.S[sptr][3] + + X[Xptr + 4] * IMDCT.S[sptr][4] + + X[Xptr + 5] * IMDCT.S[sptr][5]; + + + y[yptr + i + 0] = lo; + y[yptr + 5 - i] = -y[yptr + i + 0]; + + ++sptr; + + lo = X[Xptr + 0] * IMDCT.S[sptr][0] + + X[Xptr + 1] * IMDCT.S[sptr][1] + + X[Xptr + 2] * IMDCT.S[sptr][2] + + X[Xptr + 3] * IMDCT.S[sptr][3] + + X[Xptr + 4] * IMDCT.S[sptr][4] + + X[Xptr + 5] * IMDCT.S[sptr][5]; + + y[yptr + i + 6] = lo; + y[yptr + 11 - i] = y[yptr + i + 6]; + + ++sptr; + } + + yptr += 12; + Xptr += 6; + } + + // windowing, overlapping and concatenation + yptr = 0; + var wptr = 0; + + for (var i = 0; i < 6; ++i) { + z[i + 0] = 0; + z[i + 6] = y[yptr + 0 + 0] * tables.WINDOW_S[wptr + 0]; + + lo = y[yptr + 0 + 6] * tables.WINDOW_S[wptr + 6] + + y[yptr + 12 + 0] * tables.WINDOW_S[wptr + 0]; + + z[i + 12] = lo; + + lo = y[yptr + 12 + 6] * tables.WINDOW_S[wptr + 6] + + y[yptr + 24 + 0] * tables.WINDOW_S[wptr + 0]; + + z[i + 18] = lo; + z[i + 24] = y[yptr + 24 + 6] * tables.WINDOW_S[wptr + 6]; + z[i + 30] = 0; + + ++yptr; + ++wptr; + } +}; + +Layer3.prototype.overlap = function (output, overlap, sample, sb) { + for (var i = 0; i < 18; ++i) { + sample[i][sb] = output[i] + overlap[i]; + overlap[i] = output[i + 18]; + } +}; + +Layer3.prototype.freqinver = function (sample, sb) { + for (var i = 1; i < 18; i += 2) + sample[i][sb] = -sample[i][sb]; +}; + +Layer3.prototype.overlap_z = function (overlap, sample, sb) { + for (var i = 0; i < 18; ++i) { + sample[i][sb] = overlap[i]; + overlap[i] = 0; + } +}; + +Layer3.prototype.reorder = function (xr, channel, sfbwidth) { + var sfbwidthPointer = 0; + var tmp = this.tmp; + var sbw = new Uint32Array(3); + var sw = new Uint32Array(3); + + // this is probably wrong for 8000 Hz mixed blocks + + var sb = 0; + if (channel.flags & tables.MIXED_BLOCK_FLAG) { + var sb = 2; + + var l = 0; + while (l < 36) + l += sfbwidth[sfbwidthPointer++]; + } + + for (var w = 0; w < 3; ++w) { + sbw[w] = sb; + sw[w] = 0; + } + + f = sfbwidth[sfbwidthPointer++]; + w = 0; + + for (var l = 18 * sb; l < 576; ++l) { + if (f-- === 0) { + f = sfbwidth[sfbwidthPointer++] - 1; + w = (w + 1) % 3; + } + + tmp[sbw[w]][w][sw[w]++] = xr[l]; + + if (sw[w] === 6) { + sw[w] = 0; + ++sbw[w]; + } + } + + var tmp2 = this.tmp2; + var ptr = 0; + + for (var i = 0; i < 32; i++) { + for (var j = 0; j < 3; j++) { + for (var k = 0; k < 6; k++) { + tmp2[ptr++] = tmp[i][j][k]; + } + } + } + + var len = (576 - 18 * sb); + for (var i = 0; i < len; i++) { + xr[18 * sb + i] = tmp2[sb + i]; + } +}; + +module.exports = Layer3; + +},{"./frame":4,"./header":5,"./huffman":6,"./imdct":8,"./tables":14,"./utils":15}],12:[function(require,module,exports){ +var AV = (window.AV); +var MP3FrameHeader = require('./header'); + +function MP3Stream(stream) { + this.stream = stream; // actual bitstream + this.sync = false; // stream sync found + this.freerate = 0; // free bitrate (fixed) + this.this_frame = stream.stream.offset; // start of current frame + this.next_frame = stream.stream.offset; // start of next frame + + this.main_data = new Uint8Array(MP3FrameHeader.BUFFER_MDLEN); // actual audio data + this.md_len = 0; // length of main data + + // copy methods from actual stream + for (var key in stream) { + if (typeof stream[key] === 'function') + this[key] = stream[key].bind(stream); + } +} + +MP3Stream.prototype.getU8 = function(offset) { + var stream = this.stream.stream; + return stream.peekUInt8(offset - stream.offset); +}; + +MP3Stream.prototype.nextByte = function() { + var stream = this.stream; + return stream.bitPosition === 0 ? stream.stream.offset : stream.stream.offset + 1; +}; + +MP3Stream.prototype.doSync = function() { + var stream = this.stream.stream; + this.align(); + + while (this.available(16) && !(stream.peekUInt8(0) === 0xff && (stream.peekUInt8(1) & 0xe0) === 0xe0)) { + this.advance(8); + } + + if (!this.available(MP3FrameHeader.BUFFER_GUARD)) + return false; + + return true; +}; + +MP3Stream.prototype.reset = function(byteOffset) { + this.seek(byteOffset * 8); + this.next_frame = byteOffset; + this.sync = true; +}; + +module.exports = MP3Stream; + +},{"./header":5}],13:[function(require,module,exports){ +var utils = require('./utils'); + +function MP3Synth() { + this.filter = utils.makeArray([2, 2, 2, 16, 8]); // polyphase filterbank outputs + this.phase = 0; + + this.pcm = { + samplerate: 0, + channels: 0, + length: 0, + samples: [new Float64Array(1152), new Float64Array(1152)] + }; +} + +/* costab[i] = cos(PI / (2 * 32) * i) */ +const costab1 = 0.998795456; +const costab2 = 0.995184727; +const costab3 = 0.989176510; +const costab4 = 0.980785280; +const costab5 = 0.970031253; +const costab6 = 0.956940336; +const costab7 = 0.941544065; +const costab8 = 0.923879533; +const costab9 = 0.903989293; +const costab10 = 0.881921264; +const costab11 = 0.857728610; +const costab12 = 0.831469612; +const costab13 = 0.803207531; +const costab14 = 0.773010453; +const costab15 = 0.740951125; +const costab16 = 0.707106781; +const costab17 = 0.671558955; +const costab18 = 0.634393284; +const costab19 = 0.595699304; +const costab20 = 0.555570233; +const costab21 = 0.514102744; +const costab22 = 0.471396737; +const costab23 = 0.427555093; +const costab24 = 0.382683432; +const costab25 = 0.336889853; +const costab26 = 0.290284677; +const costab27 = 0.242980180; +const costab28 = 0.195090322; +const costab29 = 0.146730474; +const costab30 = 0.098017140; +const costab31 = 0.049067674; + +/* + * NAME: dct32() + * DESCRIPTION: perform fast in[32].out[32] DCT + */ +MP3Synth.dct32 = function (_in, slot, lo, hi) { + var t0, t1, t2, t3, t4, t5, t6, t7; + var t8, t9, t10, t11, t12, t13, t14, t15; + var t16, t17, t18, t19, t20, t21, t22, t23; + var t24, t25, t26, t27, t28, t29, t30, t31; + var t32, t33, t34, t35, t36, t37, t38, t39; + var t40, t41, t42, t43, t44, t45, t46, t47; + var t48, t49, t50, t51, t52, t53, t54, t55; + var t56, t57, t58, t59, t60, t61, t62, t63; + var t64, t65, t66, t67, t68, t69, t70, t71; + var t72, t73, t74, t75, t76, t77, t78, t79; + var t80, t81, t82, t83, t84, t85, t86, t87; + var t88, t89, t90, t91, t92, t93, t94, t95; + var t96, t97, t98, t99, t100, t101, t102, t103; + var t104, t105, t106, t107, t108, t109, t110, t111; + var t112, t113, t114, t115, t116, t117, t118, t119; + var t120, t121, t122, t123, t124, t125, t126, t127; + var t128, t129, t130, t131, t132, t133, t134, t135; + var t136, t137, t138, t139, t140, t141, t142, t143; + var t144, t145, t146, t147, t148, t149, t150, t151; + var t152, t153, t154, t155, t156, t157, t158, t159; + var t160, t161, t162, t163, t164, t165, t166, t167; + var t168, t169, t170, t171, t172, t173, t174, t175; + var t176; + + t0 = _in[0] + _in[31]; t16 = ((_in[0] - _in[31]) * (costab1)); + t1 = _in[15] + _in[16]; t17 = ((_in[15] - _in[16]) * (costab31)); + + t41 = t16 + t17; + t59 = ((t16 - t17) * (costab2)); + t33 = t0 + t1; + t50 = ((t0 - t1) * ( costab2)); + + t2 = _in[7] + _in[24]; t18 = ((_in[7] - _in[24]) * (costab15)); + t3 = _in[8] + _in[23]; t19 = ((_in[8] - _in[23]) * (costab17)); + + t42 = t18 + t19; + t60 = ((t18 - t19) * (costab30)); + t34 = t2 + t3; + t51 = ((t2 - t3) * ( costab30)); + + t4 = _in[3] + _in[28]; t20 = ((_in[3] - _in[28]) * (costab7)); + t5 = _in[12] + _in[19]; t21 = ((_in[12] - _in[19]) * (costab25)); + + t43 = t20 + t21; + t61 = ((t20 - t21) * (costab14)); + t35 = t4 + t5; + t52 = ((t4 - t5) * ( costab14)); + + t6 = _in[4] + _in[27]; t22 = ((_in[4] - _in[27]) * (costab9)); + t7 = _in[11] + _in[20]; t23 = ((_in[11] - _in[20]) * (costab23)); + + t44 = t22 + t23; + t62 = ((t22 - t23) * (costab18)); + t36 = t6 + t7; + t53 = ((t6 - t7) * ( costab18)); + + t8 = _in[1] + _in[30]; t24 = ((_in[1] - _in[30]) * (costab3)); + t9 = _in[14] + _in[17]; t25 = ((_in[14] - _in[17]) * (costab29)); + + t45 = t24 + t25; + t63 = ((t24 - t25) * (costab6)); + t37 = t8 + t9; + t54 = ((t8 - t9) * ( costab6)); + + t10 = _in[6] + _in[25]; t26 = ((_in[6] - _in[25]) * (costab13)); + t11 = _in[9] + _in[22]; t27 = ((_in[9] - _in[22]) * (costab19)); + + t46 = t26 + t27; + t64 = ((t26 - t27) * (costab26)); + t38 = t10 + t11; + t55 = ((t10 - t11) * (costab26)); + + t12 = _in[2] + _in[29]; t28 = ((_in[2] - _in[29]) * (costab5)); + t13 = _in[13] + _in[18]; t29 = ((_in[13] - _in[18]) * (costab27)); + + t47 = t28 + t29; + t65 = ((t28 - t29) * (costab10)); + t39 = t12 + t13; + t56 = ((t12 - t13) * (costab10)); + + t14 = _in[5] + _in[26]; t30 = ((_in[5] - _in[26]) * (costab11)); + t15 = _in[10] + _in[21]; t31 = ((_in[10] - _in[21]) * (costab21)); + + t48 = t30 + t31; + t66 = ((t30 - t31) * (costab22)); + t40 = t14 + t15; + t57 = ((t14 - t15) * (costab22)); + + t69 = t33 + t34; t89 = ((t33 - t34) * (costab4)); + t70 = t35 + t36; t90 = ((t35 - t36) * (costab28)); + t71 = t37 + t38; t91 = ((t37 - t38) * (costab12)); + t72 = t39 + t40; t92 = ((t39 - t40) * (costab20)); + t73 = t41 + t42; t94 = ((t41 - t42) * (costab4)); + t74 = t43 + t44; t95 = ((t43 - t44) * (costab28)); + t75 = t45 + t46; t96 = ((t45 - t46) * (costab12)); + t76 = t47 + t48; t97 = ((t47 - t48) * (costab20)); + + t78 = t50 + t51; t100 = ((t50 - t51) * (costab4)); + t79 = t52 + t53; t101 = ((t52 - t53) * (costab28)); + t80 = t54 + t55; t102 = ((t54 - t55) * (costab12)); + t81 = t56 + t57; t103 = ((t56 - t57) * (costab20)); + + t83 = t59 + t60; t106 = ((t59 - t60) * (costab4)); + t84 = t61 + t62; t107 = ((t61 - t62) * (costab28)); + t85 = t63 + t64; t108 = ((t63 - t64) * (costab12)); + t86 = t65 + t66; t109 = ((t65 - t66) * (costab20)); + + t113 = t69 + t70; + t114 = t71 + t72; + + /* 0 */ hi[15][slot] = t113 + t114; + /* 16 */ lo[ 0][slot] = ((t113 - t114) * (costab16)); + + t115 = t73 + t74; + t116 = t75 + t76; + + t32 = t115 + t116; + + /* 1 */ hi[14][slot] = t32; + + t118 = t78 + t79; + t119 = t80 + t81; + + t58 = t118 + t119; + + /* 2 */ hi[13][slot] = t58; + + t121 = t83 + t84; + t122 = t85 + t86; + + t67 = t121 + t122; + + t49 = (t67 * 2) - t32; + + /* 3 */ hi[12][slot] = t49; + + t125 = t89 + t90; + t126 = t91 + t92; + + t93 = t125 + t126; + + /* 4 */ hi[11][slot] = t93; + + t128 = t94 + t95; + t129 = t96 + t97; + + t98 = t128 + t129; + + t68 = (t98 * 2) - t49; + + /* 5 */ hi[10][slot] = t68; + + t132 = t100 + t101; + t133 = t102 + t103; + + t104 = t132 + t133; + + t82 = (t104 * 2) - t58; + + /* 6 */ hi[ 9][slot] = t82; + + t136 = t106 + t107; + t137 = t108 + t109; + + t110 = t136 + t137; + + t87 = (t110 * 2) - t67; + + t77 = (t87 * 2) - t68; + + /* 7 */ hi[ 8][slot] = t77; + + t141 = ((t69 - t70) * (costab8)); + t142 = ((t71 - t72) * (costab24)); + t143 = t141 + t142; + + /* 8 */ hi[ 7][slot] = t143; + /* 24 */ lo[ 8][slot] = + (((t141 - t142) * (costab16) * 2)) - t143; + + t144 = ((t73 - t74) * (costab8)); + t145 = ((t75 - t76) * (costab24)); + t146 = t144 + t145; + + t88 = (t146 * 2) - t77; + + /* 9 */ hi[ 6][slot] = t88; + + t148 = ((t78 - t79) * (costab8)); + t149 = ((t80 - t81) * (costab24)); + t150 = t148 + t149; + + t105 = (t150 * 2) - t82; + + /* 10 */ hi[ 5][slot] = t105; + + t152 = ((t83 - t84) * (costab8)); + t153 = ((t85 - t86) * (costab24)); + t154 = t152 + t153; + + t111 = (t154 * 2) - t87; + + t99 = (t111 * 2) - t88; + + /* 11 */ hi[ 4][slot] = t99; + + t157 = ((t89 - t90) * (costab8)); + t158 = ((t91 - t92) * (costab24)); + t159 = t157 + t158; + + t127 = (t159 * 2) - t93; + + /* 12 */ hi[ 3][slot] = t127; + + t160 = (((t125 - t126) * (costab16) * 2)) - t127; + + /* 20 */ lo[ 4][slot] = t160; + /* 28 */ lo[12][slot] = + (((((t157 - t158) * (costab16) * 2) - t159) * 2)) - t160; + + t161 = ((t94 - t95) * (costab8)); + t162 = ((t96 - t97) * (costab24)); + t163 = t161 + t162; + + t130 = (t163 * 2) - t98; + + t112 = (t130 * 2) - t99; + + /* 13 */ hi[ 2][slot] = t112; + + t164 = (((t128 - t129) * (costab16) * 2)) - t130; + + t166 = ((t100 - t101) * (costab8)); + t167 = ((t102 - t103) * (costab24)); + t168 = t166 + t167; + + t134 = (t168 * 2) - t104; + + t120 = (t134 * 2) - t105; + + /* 14 */ hi[ 1][slot] = t120; + + t135 = (((t118 - t119) * (costab16) * 2)) - t120; + + /* 18 */ lo[ 2][slot] = t135; + + t169 = (((t132 - t133) * (costab16) * 2)) - t134; + + t151 = (t169 * 2) - t135; + + /* 22 */ lo[ 6][slot] = t151; + + t170 = (((((t148 - t149) * (costab16) * 2) - t150) * 2)) - t151; + + /* 26 */ lo[10][slot] = t170; + /* 30 */ lo[14][slot] = + (((((((t166 - t167) * (costab16)) * 2 - + t168) * 2) - t169) * 2) - t170); + + t171 = ((t106 - t107) * (costab8)); + t172 = ((t108 - t109) * (costab24)); + t173 = t171 + t172; + + t138 = (t173 * 2) - t110; + t123 = (t138 * 2) - t111; + t139 = (((t121 - t122) * (costab16) * 2)) - t123; + t117 = (t123 * 2) - t112; + + /* 15 */ hi[ 0][slot] = t117; + + t124 = (((t115 - t116) * (costab16) * 2)) - t117; + + /* 17 */ lo[ 1][slot] = t124; + + t131 = (t139 * 2) - t124; + + /* 19 */ lo[ 3][slot] = t131; + + t140 = (t164 * 2) - t131; + + /* 21 */ lo[ 5][slot] = t140; + + t174 = (((t136 - t137) * (costab16) * 2)) - t138; + t155 = (t174 * 2) - t139; + t147 = (t155 * 2) - t140; + + /* 23 */ lo[ 7][slot] = t147; + + t156 = (((((t144 - t145) * (costab16) * 2) - t146) * 2)) - t147; + + /* 25 */ lo[ 9][slot] = t156; + + t175 = (((((t152 - t153) * (costab16) * 2) - t154) * 2)) - t155; + t165 = (t175 * 2) - t156; + + /* 27 */ lo[11][slot] = t165; + + t176 = (((((((t161 - t162) * (costab16) * 2)) - + t163) * 2) - t164) * 2) - t165; + + /* 29 */ lo[13][slot] = t176; + /* 31 */ lo[15][slot] = + (((((((((t171 - t172) * (costab16)) * 2 - + t173) * 2) - t174) * 2) - t175) * 2) - t176); + + /* + * Totals: + * 80 multiplies + * 80 additions + * 119 subtractions + * 49 shifts (not counting SSO) + */ +}; + +/* + * These are the coefficients for the subband synthesis window. This is a + * reordered version of Table B.3 from ISO/IEC 11172-3. + */ +const D = [ + [ 0.000000000, /* 0 */ + -0.000442505, + 0.003250122, + -0.007003784, + 0.031082153, + -0.078628540, + 0.100311279, + -0.572036743, + 1.144989014, + 0.572036743, + 0.100311279, + 0.078628540, + 0.031082153, + 0.007003784, + 0.003250122, + 0.000442505, + + 0.000000000, + -0.000442505, + 0.003250122, + -0.007003784, + 0.031082153, + -0.078628540, + 0.100311279, + -0.572036743, + 1.144989014, + 0.572036743, + 0.100311279, + 0.078628540, + 0.031082153, + 0.007003784, + 0.003250122, + 0.000442505 ], + + [ -0.000015259, /* 1 */ + -0.000473022, + 0.003326416, + -0.007919312, + 0.030517578, + -0.084182739, + 0.090927124, + -0.600219727, + 1.144287109, + 0.543823242, + 0.108856201, + 0.073059082, + 0.031478882, + 0.006118774, + 0.003173828, + 0.000396729, + + -0.000015259, + -0.000473022, + 0.003326416, + -0.007919312, + 0.030517578, + -0.084182739, + 0.090927124, + -0.600219727, + 1.144287109, + 0.543823242, + 0.108856201, + 0.073059082, + 0.031478882, + 0.006118774, + 0.003173828, + 0.000396729 ], + + [ -0.000015259, /* 2 */ + -0.000534058, + 0.003387451, + -0.008865356, + 0.029785156, + -0.089706421, + 0.080688477, + -0.628295898, + 1.142211914, + 0.515609741, + 0.116577148, + 0.067520142, + 0.031738281, + 0.005294800, + 0.003082275, + 0.000366211, + + -0.000015259, + -0.000534058, + 0.003387451, + -0.008865356, + 0.029785156, + -0.089706421, + 0.080688477, + -0.628295898, + 1.142211914, + 0.515609741, + 0.116577148, + 0.067520142, + 0.031738281, + 0.005294800, + 0.003082275, + 0.000366211 ], + + [ -0.000015259, /* 3 */ + -0.000579834, + 0.003433228, + -0.009841919, + 0.028884888, + -0.095169067, + 0.069595337, + -0.656219482, + 1.138763428, + 0.487472534, + 0.123474121, + 0.061996460, + 0.031845093, + 0.004486084, + 0.002990723, + 0.000320435, + + -0.000015259, + -0.000579834, + 0.003433228, + -0.009841919, + 0.028884888, + -0.095169067, + 0.069595337, + -0.656219482, + 1.138763428, + 0.487472534, + 0.123474121, + 0.061996460, + 0.031845093, + 0.004486084, + 0.002990723, + 0.000320435 ], + + [ -0.000015259, /* 4 */ + -0.000625610, + 0.003463745, + -0.010848999, + 0.027801514, + -0.100540161, + 0.057617187, + -0.683914185, + 1.133926392, + 0.459472656, + 0.129577637, + 0.056533813, + 0.031814575, + 0.003723145, + 0.002899170, + 0.000289917, + + -0.000015259, + -0.000625610, + 0.003463745, + -0.010848999, + 0.027801514, + -0.100540161, + 0.057617187, + -0.683914185, + 1.133926392, + 0.459472656, + 0.129577637, + 0.056533813, + 0.031814575, + 0.003723145, + 0.002899170, + 0.000289917 ], + + [ -0.000015259, /* 5 */ + -0.000686646, + 0.003479004, + -0.011886597, + 0.026535034, + -0.105819702, + 0.044784546, + -0.711318970, + 1.127746582, + 0.431655884, + 0.134887695, + 0.051132202, + 0.031661987, + 0.003005981, + 0.002792358, + 0.000259399, + + -0.000015259, + -0.000686646, + 0.003479004, + -0.011886597, + 0.026535034, + -0.105819702, + 0.044784546, + -0.711318970, + 1.127746582, + 0.431655884, + 0.134887695, + 0.051132202, + 0.031661987, + 0.003005981, + 0.002792358, + 0.000259399 ], + + [ -0.000015259, /* 6 */ + -0.000747681, + 0.003479004, + -0.012939453, + 0.025085449, + -0.110946655, + 0.031082153, + -0.738372803, + 1.120223999, + 0.404083252, + 0.139450073, + 0.045837402, + 0.031387329, + 0.002334595, + 0.002685547, + 0.000244141, + + -0.000015259, + -0.000747681, + 0.003479004, + -0.012939453, + 0.025085449, + -0.110946655, + 0.031082153, + -0.738372803, + 1.120223999, + 0.404083252, + 0.139450073, + 0.045837402, + 0.031387329, + 0.002334595, + 0.002685547, + 0.000244141 ], + + [ -0.000030518, /* 7 */ + -0.000808716, + 0.003463745, + -0.014022827, + 0.023422241, + -0.115921021, + 0.016510010, + -0.765029907, + 1.111373901, + 0.376800537, + 0.143264771, + 0.040634155, + 0.031005859, + 0.001693726, + 0.002578735, + 0.000213623, + + -0.000030518, + -0.000808716, + 0.003463745, + -0.014022827, + 0.023422241, + -0.115921021, + 0.016510010, + -0.765029907, + 1.111373901, + 0.376800537, + 0.143264771, + 0.040634155, + 0.031005859, + 0.001693726, + 0.002578735, + 0.000213623 ], + + [ -0.000030518, /* 8 */ + -0.000885010, + 0.003417969, + -0.015121460, + 0.021575928, + -0.120697021, + 0.001068115, + -0.791213989, + 1.101211548, + 0.349868774, + 0.146362305, + 0.035552979, + 0.030532837, + 0.001098633, + 0.002456665, + 0.000198364, + + -0.000030518, + -0.000885010, + 0.003417969, + -0.015121460, + 0.021575928, + -0.120697021, + 0.001068115, + -0.791213989, + 1.101211548, + 0.349868774, + 0.146362305, + 0.035552979, + 0.030532837, + 0.001098633, + 0.002456665, + 0.000198364 ], + + [ -0.000030518, /* 9 */ + -0.000961304, + 0.003372192, + -0.016235352, + 0.019531250, + -0.125259399, + -0.015228271, + -0.816864014, + 1.089782715, + 0.323318481, + 0.148773193, + 0.030609131, + 0.029937744, + 0.000549316, + 0.002349854, + 0.000167847, + + -0.000030518, + -0.000961304, + 0.003372192, + -0.016235352, + 0.019531250, + -0.125259399, + -0.015228271, + -0.816864014, + 1.089782715, + 0.323318481, + 0.148773193, + 0.030609131, + 0.029937744, + 0.000549316, + 0.002349854, + 0.000167847 ], + + [ -0.000030518, /* 10 */ + -0.001037598, + 0.003280640, + -0.017349243, + 0.017257690, + -0.129562378, + -0.032379150, + -0.841949463, + 1.077117920, + 0.297210693, + 0.150497437, + 0.025817871, + 0.029281616, + 0.000030518, + 0.002243042, + 0.000152588, + + -0.000030518, + -0.001037598, + 0.003280640, + -0.017349243, + 0.017257690, + -0.129562378, + -0.032379150, + -0.841949463, + 1.077117920, + 0.297210693, + 0.150497437, + 0.025817871, + 0.029281616, + 0.000030518, + 0.002243042, + 0.000152588 ], + + [ -0.000045776, /* 11 */ + -0.001113892, + 0.003173828, + -0.018463135, + 0.014801025, + -0.133590698, + -0.050354004, + -0.866363525, + 1.063217163, + 0.271591187, + 0.151596069, + 0.021179199, + 0.028533936, + -0.000442505, + 0.002120972, + 0.000137329, + + -0.000045776, + -0.001113892, + 0.003173828, + -0.018463135, + 0.014801025, + -0.133590698, + -0.050354004, + -0.866363525, + 1.063217163, + 0.271591187, + 0.151596069, + 0.021179199, + 0.028533936, + -0.000442505, + 0.002120972, + 0.000137329 ], + + [ -0.000045776, /* 12 */ + -0.001205444, + 0.003051758, + -0.019577026, + 0.012115479, + -0.137298584, + -0.069168091, + -0.890090942, + 1.048156738, + 0.246505737, + 0.152069092, + 0.016708374, + 0.027725220, + -0.000869751, + 0.002014160, + 0.000122070, + + -0.000045776, + -0.001205444, + 0.003051758, + -0.019577026, + 0.012115479, + -0.137298584, + -0.069168091, + -0.890090942, + 1.048156738, + 0.246505737, + 0.152069092, + 0.016708374, + 0.027725220, + -0.000869751, + 0.002014160, + 0.000122070 ], + + [ -0.000061035, /* 13 */ + -0.001296997, + 0.002883911, + -0.020690918, + 0.009231567, + -0.140670776, + -0.088775635, + -0.913055420, + 1.031936646, + 0.221984863, + 0.151962280, + 0.012420654, + 0.026840210, + -0.001266479, + 0.001907349, + 0.000106812, + + -0.000061035, + -0.001296997, + 0.002883911, + -0.020690918, + 0.009231567, + -0.140670776, + -0.088775635, + -0.913055420, + 1.031936646, + 0.221984863, + 0.151962280, + 0.012420654, + 0.026840210, + -0.001266479, + 0.001907349, + 0.000106812 ], + + [ -0.000061035, /* 14 */ + -0.001388550, + 0.002700806, + -0.021789551, + 0.006134033, + -0.143676758, + -0.109161377, + -0.935195923, + 1.014617920, + 0.198059082, + 0.151306152, + 0.008316040, + 0.025909424, + -0.001617432, + 0.001785278, + 0.000106812, + + -0.000061035, + -0.001388550, + 0.002700806, + -0.021789551, + 0.006134033, + -0.143676758, + -0.109161377, + -0.935195923, + 1.014617920, + 0.198059082, + 0.151306152, + 0.008316040, + 0.025909424, + -0.001617432, + 0.001785278, + 0.000106812 ], + + [ -0.000076294, /* 15 */ + -0.001480103, + 0.002487183, + -0.022857666, + 0.002822876, + -0.146255493, + -0.130310059, + -0.956481934, + 0.996246338, + 0.174789429, + 0.150115967, + 0.004394531, + 0.024932861, + -0.001937866, + 0.001693726, + 0.000091553, + + -0.000076294, + -0.001480103, + 0.002487183, + -0.022857666, + 0.002822876, + -0.146255493, + -0.130310059, + -0.956481934, + 0.996246338, + 0.174789429, + 0.150115967, + 0.004394531, + 0.024932861, + -0.001937866, + 0.001693726, + 0.000091553 ], + + [ -0.000076294, /* 16 */ + -0.001586914, + 0.002227783, + -0.023910522, + -0.000686646, + -0.148422241, + -0.152206421, + -0.976852417, + 0.976852417, + 0.152206421, + 0.148422241, + 0.000686646, + 0.023910522, + -0.002227783, + 0.001586914, + 0.000076294, + + -0.000076294, + -0.001586914, + 0.002227783, + -0.023910522, + -0.000686646, + -0.148422241, + -0.152206421, + -0.976852417, + 0.976852417, + 0.152206421, + 0.148422241, + 0.000686646, + 0.023910522, + -0.002227783, + 0.001586914, + 0.000076294 ] +]; + +/* + * perform full frequency PCM synthesis + */ +MP3Synth.prototype.full = function(frame, nch, ns) { + var Dptr, hi, lo, ptr; + + for (var ch = 0; ch < nch; ++ch) { + var sbsample = frame.sbsample[ch]; + var filter = this.filter[ch]; + var phase = this.phase; + var pcm = this.pcm.samples[ch]; + var pcm1Ptr = 0; + var pcm2Ptr = 0; + + for (var s = 0; s < ns; ++s) { + MP3Synth.dct32(sbsample[s], phase >> 1, filter[0][phase & 1], filter[1][phase & 1]); + + var pe = phase & ~1; + var po = ((phase - 1) & 0xf) | 1; + + /* calculate 32 samples */ + var fe = filter[0][ phase & 1]; + var fx = filter[0][~phase & 1]; + var fo = filter[1][~phase & 1]; + + var fePtr = 0; + var fxPtr = 0; + var foPtr = 0; + + Dptr = 0; + + ptr = D[Dptr]; + _fx = fx[fxPtr]; + _fe = fe[fePtr]; + + lo = _fx[0] * ptr[po + 0]; + lo += _fx[1] * ptr[po + 14]; + lo += _fx[2] * ptr[po + 12]; + lo += _fx[3] * ptr[po + 10]; + lo += _fx[4] * ptr[po + 8]; + lo += _fx[5] * ptr[po + 6]; + lo += _fx[6] * ptr[po + 4]; + lo += _fx[7] * ptr[po + 2]; + lo = -lo; + + lo += _fe[0] * ptr[pe + 0]; + lo += _fe[1] * ptr[pe + 14]; + lo += _fe[2] * ptr[pe + 12]; + lo += _fe[3] * ptr[pe + 10]; + lo += _fe[4] * ptr[pe + 8]; + lo += _fe[5] * ptr[pe + 6]; + lo += _fe[6] * ptr[pe + 4]; + lo += _fe[7] * ptr[pe + 2]; + + pcm[pcm1Ptr++] = lo; + pcm2Ptr = pcm1Ptr + 30; + + for (var sb = 1; sb < 16; ++sb) { + ++fePtr; + ++Dptr; + + /* D[32 - sb][i] === -D[sb][31 - i] */ + + ptr = D[Dptr]; + _fo = fo[foPtr]; + _fe = fe[fePtr]; + + lo = _fo[0] * ptr[po + 0]; + lo += _fo[1] * ptr[po + 14]; + lo += _fo[2] * ptr[po + 12]; + lo += _fo[3] * ptr[po + 10]; + lo += _fo[4] * ptr[po + 8]; + lo += _fo[5] * ptr[po + 6]; + lo += _fo[6] * ptr[po + 4]; + lo += _fo[7] * ptr[po + 2]; + lo = -lo; + + lo += _fe[7] * ptr[pe + 2]; + lo += _fe[6] * ptr[pe + 4]; + lo += _fe[5] * ptr[pe + 6]; + lo += _fe[4] * ptr[pe + 8]; + lo += _fe[3] * ptr[pe + 10]; + lo += _fe[2] * ptr[pe + 12]; + lo += _fe[1] * ptr[pe + 14]; + lo += _fe[0] * ptr[pe + 0]; + + pcm[pcm1Ptr++] = lo; + + lo = _fe[0] * ptr[-pe + 31 - 16]; + lo += _fe[1] * ptr[-pe + 31 - 14]; + lo += _fe[2] * ptr[-pe + 31 - 12]; + lo += _fe[3] * ptr[-pe + 31 - 10]; + lo += _fe[4] * ptr[-pe + 31 - 8]; + lo += _fe[5] * ptr[-pe + 31 - 6]; + lo += _fe[6] * ptr[-pe + 31 - 4]; + lo += _fe[7] * ptr[-pe + 31 - 2]; + + lo += _fo[7] * ptr[-po + 31 - 2]; + lo += _fo[6] * ptr[-po + 31 - 4]; + lo += _fo[5] * ptr[-po + 31 - 6]; + lo += _fo[4] * ptr[-po + 31 - 8]; + lo += _fo[3] * ptr[-po + 31 - 10]; + lo += _fo[2] * ptr[-po + 31 - 12]; + lo += _fo[1] * ptr[-po + 31 - 14]; + lo += _fo[0] * ptr[-po + 31 - 16]; + + pcm[pcm2Ptr--] = lo; + ++foPtr; + } + + ++Dptr; + + ptr = D[Dptr]; + _fo = fo[foPtr]; + + lo = _fo[0] * ptr[po + 0]; + lo += _fo[1] * ptr[po + 14]; + lo += _fo[2] * ptr[po + 12]; + lo += _fo[3] * ptr[po + 10]; + lo += _fo[4] * ptr[po + 8]; + lo += _fo[5] * ptr[po + 6]; + lo += _fo[6] * ptr[po + 4]; + lo += _fo[7] * ptr[po + 2]; + + pcm[pcm1Ptr] = -lo; + pcm1Ptr += 16; + phase = (phase + 1) % 16; + } + } +}; + +// TODO: synth.half() + +/* + * NAME: synth.frame() + * DESCRIPTION: perform PCM synthesis of frame subband samples + */ +MP3Synth.prototype.frame = function (frame) { + var nch = frame.header.nchannels(); + var ns = frame.header.nbsamples(); + + this.pcm.samplerate = frame.header.samplerate; + this.pcm.channels = nch; + this.pcm.length = 32 * ns; + + /* + if (frame.options & Mad.Option.HALFSAMPLERATE) { + this.pcm.samplerate /= 2; + this.pcm.length /= 2; + + throw new Error("HALFSAMPLERATE is not supported. What do you think? As if I have the time for this"); + } + */ + + this.full(frame, nch, ns); + this.phase = (this.phase + ns) % 16; +}; + +module.exports = MP3Synth; + +},{"./utils":15}],14:[function(require,module,exports){ +/* + * These are the scalefactor values for Layer I and Layer II. + * The values are from Table B.1 of ISO/IEC 11172-3. + * + * Strictly speaking, Table B.1 has only 63 entries (0-62), thus a strict + * interpretation of ISO/IEC 11172-3 would suggest that a scalefactor index of + * 63 is invalid. However, for better compatibility with current practices, we + * add a 64th entry. + */ +exports.SF_TABLE = new Float32Array([ + 2.000000000000, 1.587401051968, 1.259921049895, 1.000000000000, + 0.793700525984, 0.629960524947, 0.500000000000, 0.396850262992, + 0.314980262474, 0.250000000000, 0.198425131496, 0.157490131237, + 0.125000000000, 0.099212565748, 0.078745065618, 0.062500000000, + 0.049606282874, 0.039372532809, 0.031250000000, 0.024803141437, + 0.019686266405, 0.015625000000, 0.012401570719, 0.009843133202, + 0.007812500000, 0.006200785359, 0.004921566601, 0.003906250000, + 0.003100392680, 0.002460783301, 0.001953125000, 0.001550196340, + 0.001230391650, 0.000976562500, 0.000775098170, 0.000615195825, + 0.000488281250, 0.000387549085, 0.000307597913, 0.000244140625, + 0.000193774542, 0.000153798956, 0.000122070313, 0.000096887271, + 0.000076899478, 0.000061035156, 0.000048443636, 0.000038449739, + 0.000030517578, 0.000024221818, 0.000019224870, 0.000015258789, + 0.000012110909, 0.000009612435, 0.000007629395, 0.000006055454, + 0.000004806217, 0.000003814697, 0.000003027727, 0.000002403109, + 0.000001907349, 0.000001513864, 0.000001201554, 0.000000000000 +]); + +/* + * MPEG-1 scalefactor band widths + * derived from Table B.8 of ISO/IEC 11172-3 + */ +const SFB_48000_LONG = new Uint8Array([ + 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10, + 12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192 +]); + +const SFB_44100_LONG = new Uint8Array([ + 4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, + 12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158 +]); + +const SFB_32000_LONG = new Uint8Array([ + 4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12, + 16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26 +]); + +const SFB_48000_SHORT = new Uint8Array([ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, + 6, 6, 6, 6, 6, 10, 10, 10, 12, 12, 12, 14, 14, + 14, 16, 16, 16, 20, 20, 20, 26, 26, 26, 66, 66, 66 +]); + +const SFB_44100_SHORT = new Uint8Array([ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, + 6, 6, 8, 8, 8, 10, 10, 10, 12, 12, 12, 14, 14, + 14, 18, 18, 18, 22, 22, 22, 30, 30, 30, 56, 56, 56 +]); + +const SFB_32000_SHORT = new Uint8Array([ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, + 6, 6, 8, 8, 8, 12, 12, 12, 16, 16, 16, 20, 20, + 20, 26, 26, 26, 34, 34, 34, 42, 42, 42, 12, 12, 12 +]); + +const SFB_48000_MIXED = new Uint8Array([ + /* long */ 4, 4, 4, 4, 4, 4, 6, 6, + /* short */ 4, 4, 4, 6, 6, 6, 6, 6, 6, 10, + 10, 10, 12, 12, 12, 14, 14, 14, 16, 16, + 16, 20, 20, 20, 26, 26, 26, 66, 66, 66 +]); + +const SFB_44100_MIXED = new Uint8Array([ + /* long */ 4, 4, 4, 4, 4, 4, 6, 6, + /* short */ 4, 4, 4, 6, 6, 6, 8, 8, 8, 10, + 10, 10, 12, 12, 12, 14, 14, 14, 18, 18, + 18, 22, 22, 22, 30, 30, 30, 56, 56, 56 +]); + +const SFB_32000_MIXED = new Uint8Array([ + /* long */ 4, 4, 4, 4, 4, 4, 6, 6, + /* short */ 4, 4, 4, 6, 6, 6, 8, 8, 8, 12, + 12, 12, 16, 16, 16, 20, 20, 20, 26, 26, + 26, 34, 34, 34, 42, 42, 42, 12, 12, 12 +]); + +/* + * MPEG-2 scalefactor band widths + * derived from Table B.2 of ISO/IEC 13818-3 + */ +const SFB_24000_LONG = new Uint8Array([ + 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, + 18, 22, 26, 32, 38, 46, 54, 62, 70, 76, 36 +]); + +const SFB_22050_LONG = new Uint8Array([ + 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, + 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 +]); + +const SFB_16000_LONG = SFB_22050_LONG; + +const SFB_24000_SHORT = new Uint8Array([ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, + 8, 8, 10, 10, 10, 12, 12, 12, 14, 14, 14, 18, 18, + 18, 24, 24, 24, 32, 32, 32, 44, 44, 44, 12, 12, 12 +]); + +const SFB_22050_SHORT = new Uint8Array([ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, + 6, 6, 8, 8, 8, 10, 10, 10, 14, 14, 14, 18, 18, + 18, 26, 26, 26, 32, 32, 32, 42, 42, 42, 18, 18, 18 +]); + +const SFB_16000_SHORT = new Uint8Array([ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, + 8, 8, 10, 10, 10, 12, 12, 12, 14, 14, 14, 18, 18, + 18, 24, 24, 24, 30, 30, 30, 40, 40, 40, 18, 18, 18 +]); + +const SFB_24000_MIXED = new Uint8Array([ + /* long */ 6, 6, 6, 6, 6, 6, + /* short */ 6, 6, 6, 8, 8, 8, 10, 10, 10, 12, + 12, 12, 14, 14, 14, 18, 18, 18, 24, 24, + 24, 32, 32, 32, 44, 44, 44, 12, 12, 12 +]); + +const SFB_22050_MIXED = new Uint8Array([ + /* long */ 6, 6, 6, 6, 6, 6, + /* short */ 6, 6, 6, 6, 6, 6, 8, 8, 8, 10, + 10, 10, 14, 14, 14, 18, 18, 18, 26, 26, + 26, 32, 32, 32, 42, 42, 42, 18, 18, 18 +]); + +const SFB_16000_MIXED = new Uint8Array([ + /* long */ 6, 6, 6, 6, 6, 6, + /* short */ 6, 6, 6, 8, 8, 8, 10, 10, 10, 12, + 12, 12, 14, 14, 14, 18, 18, 18, 24, 24, + 24, 30, 30, 30, 40, 40, 40, 18, 18, 18 +]); + +/* + * MPEG 2.5 scalefactor band widths + * derived from public sources + */ +const SFB_12000_LONG = SFB_16000_LONG; +const SFB_11025_LONG = SFB_12000_LONG; + +const SFB_8000_LONG = new Uint8Array([ + 12, 12, 12, 12, 12, 12, 16, 20, 24, 28, 32, + 40, 48, 56, 64, 76, 90, 2, 2, 2, 2, 2 +]); + +const SFB_12000_SHORT = SFB_16000_SHORT; +const SFB_11025_SHORT = SFB_12000_SHORT; + +const SFB_8000_SHORT = new Uint8Array([ + 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 16, + 16, 16, 20, 20, 20, 24, 24, 24, 28, 28, 28, 36, 36, + 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26 +]); + +const SFB_12000_MIXED = SFB_16000_MIXED; +const SFB_11025_MIXED = SFB_12000_MIXED; + +/* the 8000 Hz short block scalefactor bands do not break after + the first 36 frequency lines, so this is probably wrong */ +const SFB_8000_MIXED = new Uint8Array([ + /* long */ 12, 12, 12, + /* short */ 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16, + 20, 20, 20, 24, 24, 24, 28, 28, 28, 36, 36, 36, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26 +]); + +exports.SFBWIDTH_TABLE = [ + { l: SFB_48000_LONG, s: SFB_48000_SHORT, m: SFB_48000_MIXED }, + { l: SFB_44100_LONG, s: SFB_44100_SHORT, m: SFB_44100_MIXED }, + { l: SFB_32000_LONG, s: SFB_32000_SHORT, m: SFB_32000_MIXED }, + { l: SFB_24000_LONG, s: SFB_24000_SHORT, m: SFB_24000_MIXED }, + { l: SFB_22050_LONG, s: SFB_22050_SHORT, m: SFB_22050_MIXED }, + { l: SFB_16000_LONG, s: SFB_16000_SHORT, m: SFB_16000_MIXED }, + { l: SFB_12000_LONG, s: SFB_12000_SHORT, m: SFB_12000_MIXED }, + { l: SFB_11025_LONG, s: SFB_11025_SHORT, m: SFB_11025_MIXED }, + { l: SFB_8000_LONG, s: SFB_8000_SHORT, m: SFB_8000_MIXED } +]; + +exports.PRETAB = new Uint8Array([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 +]); + +/* + * fractional powers of two + * used for requantization and joint stereo decoding + * + * ROOT_TABLE[3 + x] = 2^(x/4) + */ +exports.ROOT_TABLE = new Float32Array([ + /* 2^(-3/4) */ 0.59460355750136, + /* 2^(-2/4) */ 0.70710678118655, + /* 2^(-1/4) */ 0.84089641525371, + /* 2^( 0/4) */ 1.00000000000000, + /* 2^(+1/4) */ 1.18920711500272, + /* 2^(+2/4) */ 1.41421356237310, + /* 2^(+3/4) */ 1.68179283050743 +]); + +exports.CS = new Float32Array([ + +0.857492926 , +0.881741997, + +0.949628649 , +0.983314592, + +0.995517816 , +0.999160558, + +0.999899195 , +0.999993155 +]); + +exports.CA = new Float32Array([ + -0.514495755, -0.471731969, + -0.313377454, -0.181913200, + -0.094574193, -0.040965583, + -0.014198569, -0.003699975 +]); + +exports.COUNT1TABLE_SELECT = 0x01; +exports.SCALEFAC_SCALE = 0x02; +exports.PREFLAG = 0x04; +exports.MIXED_BLOCK_FLAG = 0x08; + +exports.I_STEREO = 0x1; +exports.MS_STEREO = 0x2; + +/* + * windowing coefficients for long blocks + * derived from section 2.4.3.4.10.3 of ISO/IEC 11172-3 + * + * WINDOW_L[i] = sin((PI / 36) * (i + 1/2)) + */ +exports.WINDOW_L = new Float32Array([ + 0.043619387, 0.130526192, + 0.216439614, 0.300705800, + 0.382683432, 0.461748613, + 0.537299608, 0.608761429, + 0.675590208, 0.737277337, + 0.793353340, 0.843391446, + + 0.887010833, 0.923879533, + 0.953716951, 0.976296007, + 0.991444861, 0.999048222, + 0.999048222, 0.991444861, + 0.976296007, 0.953716951, + 0.923879533, 0.887010833, + + 0.843391446, 0.793353340, + 0.737277337, 0.675590208, + 0.608761429, 0.537299608, + 0.461748613, 0.382683432, + 0.300705800, 0.216439614, + 0.130526192, 0.043619387 +]); + +/* + * windowing coefficients for short blocks + * derived from section 2.4.3.4.10.3 of ISO/IEC 11172-3 + * + * WINDOW_S[i] = sin((PI / 12) * (i + 1/2)) + */ +exports.WINDOW_S = new Float32Array([ + 0.130526192, 0.382683432, + 0.608761429, 0.793353340, + 0.923879533, 0.991444861, + 0.991444861, 0.923879533, + 0.793353340, 0.608761429, + 0.382683432, 0.130526192 +]); + +/* + * coefficients for intensity stereo processing + * derived from section 2.4.3.4.9.3 of ISO/IEC 11172-3 + * + * is_ratio[i] = tan(i * (PI / 12)) + * IS_TABLE[i] = is_ratio[i] / (1 + is_ratio[i]) + */ +exports.IS_TABLE = new Float32Array([ + 0.000000000, + 0.211324865, + 0.366025404, + 0.500000000, + 0.633974596, + 0.788675135, + 1.000000000 +]); + +/* + * coefficients for LSF intensity stereo processing + * derived from section 2.4.3.2 of ISO/IEC 13818-3 + * + * IS_LSF_TABLE[0][i] = (1 / sqrt(sqrt(2)))^(i + 1) + * IS_LSF_TABLE[1][i] = (1 / sqrt(2)) ^(i + 1) + */ +exports.IS_LSF_TABLE = [ + new Float32Array([ + 0.840896415, + 0.707106781, + 0.594603558, + 0.500000000, + 0.420448208, + 0.353553391, + 0.297301779, + 0.250000000, + 0.210224104, + 0.176776695, + 0.148650889, + 0.125000000, + 0.105112052, + 0.088388348, + 0.074325445 + ]), + new Float32Array([ + 0.707106781, + 0.500000000, + 0.353553391, + 0.250000000, + 0.176776695, + 0.125000000, + 0.088388348, + 0.062500000, + 0.044194174, + 0.031250000, + 0.022097087, + 0.015625000, + 0.011048543, + 0.007812500, + 0.005524272 + ]) +]; + +/* + * scalefactor bit lengths + * derived from section 2.4.2.7 of ISO/IEC 11172-3 + */ +exports.SFLEN_TABLE = [ + { slen1: 0, slen2: 0 }, { slen1: 0, slen2: 1 }, { slen1: 0, slen2: 2 }, { slen1: 0, slen2: 3 }, + { slen1: 3, slen2: 0 }, { slen1: 1, slen2: 1 }, { slen1: 1, slen2: 2 }, { slen1: 1, slen2: 3 }, + { slen1: 2, slen2: 1 }, { slen1: 2, slen2: 2 }, { slen1: 2, slen2: 3 }, { slen1: 3, slen2: 1 }, + { slen1: 3, slen2: 2 }, { slen1: 3, slen2: 3 }, { slen1: 4, slen2: 2 }, { slen1: 4, slen2: 3 } +]; + +/* + * number of LSF scalefactor band values + * derived from section 2.4.3.2 of ISO/IEC 13818-3 + */ +exports.NSFB_TABLE = [ + [ [ 6, 5, 5, 5 ], + [ 9, 9, 9, 9 ], + [ 6, 9, 9, 9 ] ], + + [ [ 6, 5, 7, 3 ], + [ 9, 9, 12, 6 ], + [ 6, 9, 12, 6 ] ], + + [ [ 11, 10, 0, 0 ], + [ 18, 18, 0, 0 ], + [ 15, 18, 0, 0 ] ], + + [ [ 7, 7, 7, 0 ], + [ 12, 12, 12, 0 ], + [ 6, 15, 12, 0 ] ], + + [ [ 6, 6, 6, 3 ], + [ 12, 9, 9, 6 ], + [ 6, 12, 9, 6 ] ], + + [ [ 8, 8, 5, 0 ], + [ 15, 12, 9, 0 ], + [ 6, 18, 9, 0 ] ] +]; + +},{}],15:[function(require,module,exports){ +/** + * Makes a multidimensional array + */ +exports.makeArray = function(lengths, Type) { + if (!Type) Type = Float64Array; + + if (lengths.length === 1) { + return new Type(lengths[0]); + } + + var ret = [], + len = lengths[0]; + + for (var j = 0; j < len; j++) { + ret[j] = exports.makeArray(lengths.slice(1), Type); + } + + return ret; +}; + +},{}]},{},[1]) + + +//# sourceMappingURL=mp3.js.map \ No newline at end of file diff --git a/lorgar/main.js b/lorgar/main.js index 31e06cb..7627ece 100644 --- a/lorgar/main.js +++ b/lorgar/main.js @@ -1,5 +1,11 @@ "use strict"; (function main_js() { + requirejs.config({ + "baseUrl": "/", + "shim": { + "lib/mp3/mp3": ["lib/aurora/aurora"] + } + }); requirejs.onError = function(e) { throw e; } @@ -8,6 +14,7 @@ defineArray.push("test/test"); defineArray.push("core/lorgar"); defineArray.push("lib/utils/globalMethods"); + defineArray.push("lib/mp3/mp3"); require(defineArray, function main_module() { require("lib/utils/globalMethods"); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5fa9f00..df2f755 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 2.8.12) project(test) find_package(CxxTest) +cmake_policy(SET CMP0071 NEW) if(CXXTEST_FOUND) include_directories(${CXXTEST_INCLUDE_DIR}) enable_testing() From baa6f4ef23f01a7b4d436df19e5639b3212005da Mon Sep 17 00:00:00 2001 From: blue Date: Thu, 3 Jan 2019 03:26:42 +0300 Subject: [PATCH 11/16] Next and Prev buttons for Corax and Lorgar, debugging --- corax/corax.cpp | 2 +- corax/models/player.cpp | 226 ++++++++++++++++++++++++++------ corax/models/player.h | 18 ++- lib/wDatabase/database.cpp | 2 + lib/wModel/icatalogue.cpp | 9 ++ libjs/wController/controller.js | 2 +- libjs/wController/file/audio.js | 1 - libjs/wController/file/file.js | 5 + libjs/wController/localModel.js | 2 +- libjs/wController/player.js | 110 +++++++++++++--- lorgar/core/lorgar.js | 23 ++++ lorgar/css/main.css | 10 +- lorgar/views/button.js | 7 +- lorgar/views/player.js | 49 ++++++- 14 files changed, 394 insertions(+), 72 deletions(-) diff --git a/corax/corax.cpp b/corax/corax.cpp index 742ef81..1365ba3 100644 --- a/corax/corax.cpp +++ b/corax/corax.cpp @@ -43,7 +43,7 @@ Corax::Corax(QObject *parent): attributes->addAttribute(W::String(u"connectionsCount"), new M::String(W::String(u"0"), W::Address({u"attributes", u"connectionCount"}))); attributes->addAttribute(W::String(u"name"), new M::String(W::String(u"Corax"), W::Address({u"attributes", u"name"}))); - attributes->addAttribute(W::String(u"version"), new M::String(W::String(u"0.0.2"), W::Address({u"attributes", u"version"}))); + attributes->addAttribute(W::String(u"version"), new M::String(W::String(u"0.0.3"), W::Address({u"attributes", u"version"}))); attributes->addAttribute(W::String(u"players"), new M::String(W::String(u"0"), W::Address({u"attributes", u"players"}))); createCaches(); diff --git a/corax/models/player.cpp b/corax/models/player.cpp index 4c58204..5533af5 100644 --- a/corax/models/player.cpp +++ b/corax/models/player.cpp @@ -4,27 +4,43 @@ M::Player::Player(const W::Address& address, QObject* parent): M::Model(address, parent), controls(), views(), - playPauseBtn(new M::Button(address + W::Address{u"Play"})), + playPauseBtn(new M::Button(address + W::Address{u"play"})), + nextBtn(new M::Button(address + W::Address{u"next"})), + prevBtn(new M::Button(address + W::Address{u"prev"})), _queueView(new M::List(address + W::Address{u"queueView"})), _queue(), current(0), counter(0), + currentIndex(0), mode(playBack), - playing(false) + playing(false), + scheduledToplay(false) { W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Player::_h_get); W::Handler* hqueue = W::Handler::create(address + W::Address({u"queue"}), this, &M::Player::_h_queue); addHandler(get); addHandler(hqueue); - playPauseBtn->setLabel(W::String(u"play")); + playPauseBtn->setLabel(W::String(u"Play")); playPauseBtn->setEnabled(false); connect(playPauseBtn, SIGNAL(activated()), this, SLOT(onPlayPauseBtn())); + nextBtn->setLabel(W::String(u"Next")); + nextBtn->setEnabled(false); + connect(nextBtn, SIGNAL(activated()), this, SLOT(onNextBtn())); + + prevBtn->setLabel(W::String(u"Prev")); + prevBtn->setEnabled(false); + connect(prevBtn, SIGNAL(activated()), this, SLOT(onPrevBtn())); + addModel(playPauseBtn); + addModel(nextBtn); + addModel(prevBtn); addModel(_queueView); controls.insert(std::make_pair(playPause, playPauseBtn->getAddress())); + controls.insert(std::make_pair(next, nextBtn->getAddress())); + controls.insert(std::make_pair(prev, prevBtn->getAddress())); views.insert(std::make_pair(queue, _queueView->getAddress())); } @@ -93,23 +109,9 @@ void M::Player::h_get(const W::Event& ev) void M::Player::onPlayPauseBtn() { if (playing) { - playPauseBtn->setLabel(W::String(u"Play")); - playing = false; - - switch (mode) { - case playBack: - broadcast(new W::Vocabulary(), W::Address{u"pause"}); - break; - } + pause(); } else { - playPauseBtn->setLabel(W::String(u"Pause")); - playing = true; - - switch (mode) { - case playBack: - broadcast(new W::Vocabulary(), W::Address{u"play"}); - break; - } + play(); } } @@ -120,24 +122,174 @@ void M::Player::h_queue(const W::Event& ev) const W::Uint64& id = static_cast(data.at(u"id")); ProxySong* song = new ProxySong(id, address + W::Address{W::String(W::Uint64(counter++).toString())}); addModel(song); + _queue.push_back(song); + _queueView->push(song->getAddress()); + if (current == 0) { - current = song; - views.insert(std::make_pair(currentPlayback, song->getAddress())); - W::Vocabulary* avc = new W::Vocabulary(); - avc->insert(u"type", new W::Uint64(currentPlayback)); - avc->insert(u"address", song->getAddress()); - - W::Vector* add = new W::Vector(); - add->push(avc); - - W::Vocabulary* res = new W::Vocabulary(); - res->insert(u"add", add); - res->insert(u"remove", new W::Vector()); - - broadcast(res, W::Address{u"viewsChange"}); - playPauseBtn->setEnabled(true); - } else { - _queue.push_back(song); - _queueView->push(song->getAddress()); + scheduledToplay = true; + setActive(song); + } + + if (currentIndex + 1 < _queue.size()) { + nextBtn->setEnabled(true); } } + +void M::Player::play() +{ + if (!playing) { + playPauseBtn->setLabel(W::String(u"Pause")); + playing = true; + + switch (mode) { + case playBack: + if (current == 0) { + scheduledToplay = true; + } else { + if (current->isReady()) { + scheduledToplay = false; + broadcast(new W::Vocabulary(), W::Address{u"play"}); + break; + } else { + scheduledToplay = true; + } + } + } + } +} + +void M::Player::pause() +{ + if (playing) { + playPauseBtn->setLabel(W::String(u"Play")); + playing = false; + + switch (mode) { + case playBack: + scheduledToplay = false; + broadcast(new W::Vocabulary(), W::Address{u"pause"}); + break; + } + } +} + +void M::Player::onSongReady() +{ + emit serviceMessage("Song is ready"); + playPauseBtn->setEnabled(true); + if (scheduledToplay) { + scheduledToplay = false; + if (playing) { + scheduledToplay = false; + broadcast(new W::Vocabulary(), W::Address{u"play"}); + } else { + play(); + } + } +} + +void M::Player::onSongNotReady() +{ + playPauseBtn->setEnabled(false); + emit serviceMessage("Something happend to the current song, not sure yet what to do"); +} + +void M::Player::onNextBtn() +{ + if (currentIndex + 1 < _queue.size()) { + if (playing) { + pause(); + scheduledToplay = true; + } + setActive(currentIndex + 1); + } +} + +void M::Player::onPrevBtn() +{ + if (currentIndex > 0) { + if (playing) { + pause(); + scheduledToplay = true; + } + setActive(currentIndex - 1); + } +} + +void M::Player::setActive(ProxySong* song) +{ + if (current == song) { + return; + } + + bool found = false; + int index; + for (index = 0; index < _queue.size(); ++index) { + if (_queue.at(index) == song) { + found = true; + break; + } + } + + if (found) { + setActive(index); + } else { + emit serviceMessage("An attempt to set active a song which is no in the queue, not supposed to happen"); + return; + } +} + +void M::Player::setActive(uint64_t index) +{ + if (index >= _queue.size()) { + emit serviceMessage("An attempt to set active a song which is no in the queue, not supposed to happen"); + return; + } + + ProxySong* song = _queue.at(index); + currentIndex = index; + if (currentIndex + 1 < _queue.size()) { + nextBtn->setEnabled(true); + } else { + nextBtn->setEnabled(false); + } + + if (currentIndex > 0) { + prevBtn->setEnabled(true); + } else { + prevBtn->setEnabled(false); + } + + W::Vocabulary* res = new W::Vocabulary(); + W::Vector* add = new W::Vector(); + W::Vector* remove = new W::Vector(); + if (current != 0) { + disconnect(current, SIGNAL(ready()), this, SLOT(onSongReady())); + disconnect(current, SIGNAL(notReady()), this, SLOT(onSongNotReady())); + remove->push(new W::Uint64(currentPlayback)); + } + current = song; + connect(song, SIGNAL(ready()), this, SLOT(onSongReady())); + connect(song, SIGNAL(notReady()), this, SLOT(onSongNotReady())); + views.insert(std::make_pair(currentPlayback, song->getAddress())); + W::Vocabulary* avc = new W::Vocabulary(); + avc->insert(u"type", new W::Uint64(currentPlayback)); + avc->insert(u"address", song->getAddress()); + + add->push(avc); + + res->insert(u"add", add); + res->insert(u"remove", remove); + + + broadcast(res, W::Address{u"viewsChange"}); + if (song->isReady()) { + playPauseBtn->setEnabled(true); + if (scheduledToplay) { + play(); + } + } else { + playPauseBtn->setEnabled(false); + } +} + diff --git a/corax/models/player.h b/corax/models/player.h index 4265af9..eb1e096 100644 --- a/corax/models/player.h +++ b/corax/models/player.h @@ -32,13 +32,18 @@ namespace M { playPause, currentPlayback, queue, - picture + picture, + prev, + next }; enum Mode { playBack }; + void play(); + void pause(); + protected: void h_subscribe(const W::Event & ev) override; @@ -52,15 +57,26 @@ namespace M { ItemMap controls; ItemMap views; M::Button* playPauseBtn; + M::Button* nextBtn; + M::Button* prevBtn; M::List* _queueView; Queue _queue; ProxySong* current; uint64_t counter; + uint64_t currentIndex; Mode mode; bool playing; + bool scheduledToplay; + + void setActive(ProxySong* song); + void setActive(uint64_t index); private slots: void onPlayPauseBtn(); + void onNextBtn(); + void onPrevBtn(); + void onSongReady(); + void onSongNotReady(); }; } diff --git a/lib/wDatabase/database.cpp b/lib/wDatabase/database.cpp index 0a230e8..05d0307 100644 --- a/lib/wDatabase/database.cpp +++ b/lib/wDatabase/database.cpp @@ -175,6 +175,8 @@ void Database::clear() lmdb::txn transaction = lmdb::txn::begin(environment); dbi.drop(transaction); transaction.commit(); + + elements.clear(); } void Database::addModel(M::Model* model) diff --git a/lib/wModel/icatalogue.cpp b/lib/wModel/icatalogue.cpp index 3eb4401..2733c07 100644 --- a/lib/wModel/icatalogue.cpp +++ b/lib/wModel/icatalogue.cpp @@ -44,6 +44,15 @@ void M::ICatalogue::clear() broadcast(new W::Vocabulary(), W::Address{u"clear"}); } + + std::map::iterator aItr = activeChildren.begin(); + std::map::iterator aEnd = activeChildren.end(); + for (; aItr != aEnd; ++aItr) { + removeModel(aItr->second); + aItr->second->deleteLater(); + } + activeChildren.clear(); + emit countChange(0); } diff --git a/libjs/wController/controller.js b/libjs/wController/controller.js index 268f67d..acaf370 100644 --- a/libjs/wController/controller.js +++ b/libjs/wController/controller.js @@ -188,7 +188,7 @@ var Controller = Subscribable.inherit({ } if (this._registered) { - global.registerForeignController(pair.n, pair.c); + global.unregisterForeignController(pair.n, pair.c); } pair.c.off("serviceMessage", this._onControllerServiceMessage, this); diff --git a/libjs/wController/file/audio.js b/libjs/wController/file/audio.js index 17c6951..deb316c 100644 --- a/libjs/wController/file/audio.js +++ b/libjs/wController/file/audio.js @@ -34,7 +34,6 @@ var Audio = File.inherit({ this._waitingForFrames = false; } - this.initialized = true; return ac; }, _h_responseFrames: function(ev) { diff --git a/libjs/wController/file/file.js b/libjs/wController/file/file.js index c922e4e..f220558 100644 --- a/libjs/wController/file/file.js +++ b/libjs/wController/file/file.js @@ -63,6 +63,11 @@ var File = Controller.inherit({ if (ac) { this.trigger("additionalChange"); } + + if (!this.initialized) { + this.initialized = true; + this.trigger("ready"); + } }, "needData": function() { if (this._need === 0) { diff --git a/libjs/wController/localModel.js b/libjs/wController/localModel.js index b728c2a..4a67050 100644 --- a/libjs/wController/localModel.js +++ b/libjs/wController/localModel.js @@ -30,7 +30,7 @@ var LocalModel = Subscribable.inherit({ for (i = 0; i < this._foreignControllers.length; ++i) { var pair = this._foreignControllers[i]; global.unsubscribeForeignController(pair.n, pair.c); - global.registerForeignController(pair.n, pair.c); + global.unregisterForeignController(pair.n, pair.c); pair.c.destructor(); } diff --git a/libjs/wController/player.js b/libjs/wController/player.js index bae734a..10b8aa7 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -27,11 +27,8 @@ var Player = Controller.inherit({ this.views = Object.create(null); this.mode = PlayerMode.straight.playback; this._audio = null; - this._source = new Source(); - this._asset = new AV.Asset(this._source); - this._player = new AV.Player(this._asset); - this._player.play(); this._createStateMachine(); + this._createPlayingInfrastructure(); this.addHandler("get"); this.addHandler("viewsChange"); @@ -54,6 +51,8 @@ var Player = Controller.inherit({ if (ItemType.reversed[t] !== undefined) { switch (t) { case ItemType.straight.playPause: + case ItemType.straight.prev: + case ItemType.straight.next: var btn = new Button(address.clone()); btn.itemType = t; this.controls[t] = btn; @@ -61,10 +60,10 @@ var Player = Controller.inherit({ this.trigger("newElement", btn, t); break; default: - this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to controls of the Player, but it's not qualified to be a control"); + this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to controls of the Player, but it's not qualified to be a control", 1); } } else { - this.trigger("serviceMessage", "An unrecgnized item ItemType in Player: " + t); + this.trigger("serviceMessage", "An unrecgnized item ItemType in Player: " + t, 1); } }, _addView: function(type, address) { @@ -79,7 +78,7 @@ var Player = Controller.inherit({ if (ItemType.reversed[t] !== undefined) { switch (t) { case ItemType.straight.queue: - this.trigger("serviceMessage", "Queue is not supported yet in Player"); + this.trigger("serviceMessage", "Queue is not supported yet in Player", 1); break; case ItemType.straight.currentPlayback: ctrl = new Vocabulary(address.clone()); @@ -96,10 +95,10 @@ var Player = Controller.inherit({ supported = false; //just to avoid adding with addController, since ImageById is not a controller break; default: - this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to views of the Player, but it's not qualified to be a view"); + this.trigger("serviceMessage", "An attempt to add ItemType " + ItemType.reversed[t] + " to views of the Player, but it's not qualified to be a view", 1); } } else { - this.trigger("serviceMessage", "An unrecgnized item ItemType in Player: " + t); + this.trigger("serviceMessage", "An unrecognized item ItemType in Player: " + t, 1); } if (supported) { @@ -110,6 +109,16 @@ var Player = Controller.inherit({ this.trigger("newElement", ctrl, t); } }, + _createPlayingInfrastructure() { + if (this._source) { + this._source.reset(); + this._asset.stop(); + this._player.stop(); + } + this._source = new Source(); + this._asset = new AV.Asset(this._source); + this._player = new AV.Player(this._asset); + }, _createStateMachine: function() { this._fsm = new StateMachine("initial", graphs[this.mode]); this._fsm.on("stateChanged", this._onStateChanged, this); @@ -159,7 +168,7 @@ var Player = Controller.inherit({ size = remove.length(); for (i = 0; i < size; ++i) { - this._removeView(remove.at(i)); + this._removeView(remove.at(i).valueOf()); } size = add.length(); @@ -179,6 +188,9 @@ var Player = Controller.inherit({ this._fsm.manipulation("noMoreFrames"); } }, + _onControllerReady: function() { + this._fsm.manipulation("controllerReady"); + }, _onNewPlayBackElement: function(key, element) { switch (key) { case "image": @@ -191,6 +203,7 @@ var Player = Controller.inherit({ this._audio = new Audio(new Address(["music", element.toString()])); this.addForeignController("Corax", this._audio); this._audio.on("newFrames", this._onAudioNewFrames, this); + this._audio.on("ready", this._onControllerReady, this); this._fsm.manipulation("controller"); } break; @@ -199,7 +212,7 @@ var Player = Controller.inherit({ _onNewRemoveBackElement: function(key) { switch (key) { case "image": - this._removeView(new Uint64(ItemType.straight.picture)); + this._removeView(ItemType.straight.picture); break; case "audio": this.removeForeignController(this._audio); @@ -210,14 +223,35 @@ var Player = Controller.inherit({ _onStateChanged: function(e) { switch (e.newState) { case "initial": + if (e.manipulation === "noController") { + + this.removeForeignController(this._audio); + this._audio.destructor(); + this._audio = null; + this._createPlayingInfrastructure(); + } break; case "initialPlaying": + if (e.manipulation === "noController") { + this._player.pause(); + + this.removeForeignController(this._audio); + this.audio.destructor(); + this._audio = null; + this._createPlayingInfrastructure(); + } break; + case "controllerNotReady": + break + case "controllerNotReadyPlaying": + break case "hasController": break; case "hasControllerPlaying": if (this._audio.hasMore()) { this._audio.requestMore(); + + this._player.play(); //todo temporal } else { this._fsm.manipulation("noMoreFrames"); } @@ -249,10 +283,30 @@ var Player = Controller.inherit({ } }, _removeControl: function(type) { - //TODO + var ctrl = this.controls[type]; + if (ctrl !== undefined) { + this.trigger("removeElement", type); + this.removeController(ctrl); + ctrl.destructor(); + } }, _removeView: function(type) { - //TODO + var view = this.views[type]; + if (view !== undefined) { + this.trigger("removeElement", type); + + if (type !== ItemType.straight.picture) { + this.removeController(view); + } + if (type === ItemType.straight.currentPlayback) { + if (this.views[ItemType.straight.picture]) { + this._removeView(ItemType.straight.picture); + } + this._fsm.manipulation("noController"); + } + delete this.views[type]; + view.destructor(); + } } }); @@ -261,6 +315,8 @@ ItemType.add("playPause"); ItemType.add("currentPlayback"); ItemType.add("queue"); ItemType.add("picture"); +ItemType.add("prev"); +ItemType.add("next"); var PlayerMode = new Enum("PlayerMode"); PlayerMode.add("playback"); @@ -270,34 +326,48 @@ Player.ItemType = ItemType; var graphs = Object.create(null); graphs[PlayerMode.straight.playback] = { "initial": { - controller: "hasController", + controller: "controllerNotReady", play: "initialPlaying" }, "initialPlaying": { pause: "initial", - controller: "hasControllerPlaying" + controller: "controllerNotReadyPlaying" + }, + "controllerNotReady": { + play: "controllerNotReadyPlaying", + controllerReady: "hasController" + }, + "controllerNotReadyPlaying": { + pause: "controllerNotReady", + controllerReady: "hasControllerPlaying" }, "hasController": { newFrames: "paused", - play: "hasControllerPlaying" + play: "hasControllerPlaying", + noController: "initial" }, "hasControllerPlaying": { newFrames: "playing", - pause: "hasController" + pause: "hasController", + noController: "initialPlaying" }, "paused": { play: "playing", + noController: "initial", noMoreFrames: "pausedAllLoaded" }, "pausedAllLoaded": { - play: "playingAllLoaded" + play: "playingAllLoaded", + noController: "initial" }, "playing": { pause: "paused", - noMoreFrames: "playingAllLoaded" + noMoreFrames: "playingAllLoaded", + noController: "initialPlaying" }, "playingAllLoaded": { - pause: "pausedAllLoaded" + pause: "pausedAllLoaded", + noController: "initialPlaying" } } diff --git a/lorgar/core/lorgar.js b/lorgar/core/lorgar.js index be3b0af..85082e6 100644 --- a/lorgar/core/lorgar.js +++ b/lorgar/core/lorgar.js @@ -142,6 +142,9 @@ this._emptyHelper = new LocalModel(); + this._gc.on("serviceMessage", this._onServiceMessage, this); + this._ps.on("serviceMessage", this._onServiceMessage, this); + this._gc.on("themeSelected", this.setTheme, this); this._ps.on("pageName", this._onPageName, this); }, @@ -175,6 +178,24 @@ address: this._currentPageCtl.getPairAddress().toArray() }, "", name); }, + "_onServiceMessage": function(text, severity) { + var fn; + + switch (severity) { + case 2: + fn = console.error; + break; + case 1: + fn = console.warn; + break; + case 0: + default: + fn = console.info; + break; + } + + fn(text); + }, "_onSocketConnected": function(name) { console.log(name + " socket connected"); var node = this._nodes[name]; @@ -301,6 +322,8 @@ this._playerCtl.register(this.dispatcher, this._nodes["Corax"].socket); this._playerCtl.subscribe(); this._mainLayout.appendPlayer(this._playerCtl); + + this._playerCtl.on("serviceMessage", this._onServiceMessage, this); }, "setTheme": function(theme) { View.setTheme(theme); diff --git a/lorgar/css/main.css b/lorgar/css/main.css index 26e4c65..96402ed 100644 --- a/lorgar/css/main.css +++ b/lorgar/css/main.css @@ -47,5 +47,13 @@ div.dragging .draggable { } .disabled { - opacity: 0.7; + opacity: 0.5; +} + +.button { + cursor: pointer +} + +.button.disabled { + cursor: not-allowed } diff --git a/lorgar/views/button.js b/lorgar/views/button.js index 05bb72a..db915f7 100644 --- a/lorgar/views/button.js +++ b/lorgar/views/button.js @@ -20,6 +20,7 @@ Layout.fn.constructor.call(this, controller, base); this.addClass("hoverable"); + this.addClass("button"); this._enabled = true; this._hasLabel = false; this._e.addEventListener("click", this._onClick.bind(this), false); @@ -27,10 +28,8 @@ controller.on("setEnabled", this._onSetEnabled, this); controller.on("setLabel", this._onSetLabel, this); - if (controller.initialized) { - this._onSetEnabled(controller.enabled); - this._onSetLabel(controller.hasLabel, controller.label); - } + this._onSetEnabled(controller.enabled); + this._onSetLabel(controller.hasLabel, controller.label); }, "destructor": function() { this._f.off("setEnabled", this._onSetEnabled, this); diff --git a/lorgar/views/player.js b/lorgar/views/player.js index 4bb27a7..160333c 100644 --- a/lorgar/views/player.js +++ b/lorgar/views/player.js @@ -30,6 +30,8 @@ GridLayout.fn.constructor.call(this, ctrl, options); this._playPause = null; + this._prev = null; + this._next = null; this._picture = null; this._cpbCtrl = null; this._infoModels = { @@ -39,16 +41,17 @@ } ctrl.on("newElement", this._onNewElement, this); + ctrl.on("removeElement", this._onRemoveElement, this); var artist = new Label(this._infoModels.artist); var album = new Label(this._infoModels.album); var song = new Label(this._infoModels.song); var spacer = new View(helper); - this.append(artist, 0, 2, 1, 1, GridLayout.Aligment.LeftCenter); - this.append(song, 1, 2, 1, 1, GridLayout.Aligment.LeftCenter); - this.append(album, 2, 2, 1, 1, GridLayout.Aligment.LeftCenter); - this.append(spacer, 0, 3, 3, 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(album, 2, 4, 1, 1, GridLayout.Aligment.LeftCenter); + this.append(spacer, 0, 5, 3, 1, GridLayout.Aligment.LeftCenter); this._uncyclic.push(this._infoModels.artist.destructor.bind(this._infoModels.artist)); this._uncyclic.push(this._infoModels.song.destructor.bind(this._infoModels.song)); @@ -56,6 +59,7 @@ }, destructor: function() { this._f.off("newElement", this._onNewElement, this); + this._f.off("removeElement", this._onRemoveElement, this); this._clearCpbCtrl(); GridLayout.fn.destructor.call(this); @@ -73,7 +77,15 @@ switch (type) { case ItemType.straight.playPause: this._playPause = new Button(ctrl); - this.append(this._playPause, 0, 1, 3, 1); + this.append(this._playPause, 0, 2, 3, 1); + break; + case ItemType.straight.prev: + this._prev = new Button(ctrl); + this.append(this._prev, 0, 1, 3, 1); + break; + case ItemType.straight.next: + this._next = new Button(ctrl); + this.append(this._next, 0, 3, 3, 1); break; case ItemType.straight.queue: break; @@ -92,6 +104,33 @@ break; } }, + _onRemoveElement: function(type) { + var ItemType = Enum.storage["ItemType"]; + + switch (type) { + case ItemType.straight.playPause: + this._playPause.destructor(); + this._playPause = null; + break; + case ItemType.straight.prev: + this._prev.destructor(); + this._prev = null; + break; + case ItemType.straight.next: + this._next.destructor(); + this._next = null; + break; + case ItemType.straight.queue: + break; + case ItemType.straight.currentPlayback: + this._clearCpbCtrl(); + break; + case ItemType.straight.picture: + this._picture.destructor(); + this._picture = null; + break; + } + }, _onCpbNewElement: function(key, value) { var model = this._infoModels[key]; From d6e22f6111ce38ae302ab308da8675cdf42d406e Mon Sep 17 00:00:00 2001 From: blue Date: Thu, 24 Jan 2019 22:54:16 +0300 Subject: [PATCH 12/16] Decoding with my own translation of libmad, loading and playback progress, next and prev songs --- lib/wModel/file/audio.cpp | 35 +- lib/wModel/file/audio.h | 5 - lib/wModel/file/file.cpp | 22 +- lib/wModel/file/file.h | 1 + libjs/wController/file/audio.js | 73 +- libjs/wController/file/file.js | 57 +- libjs/wController/player.js | 104 +- libjs/wType/blob.js | 30 + lorgar/lib/CMakeLists.txt | 3 +- lorgar/lib/aurora/CMakeLists.txt | 3 - lorgar/lib/aurora/aurora.js | 3938 --------------- lorgar/lib/em/CMakeLists.txt | 4 + lorgar/lib/em/wrapper.js | 4 + lorgar/lib/em/wrapper.wasm | Bin 0 -> 256902 bytes lorgar/lib/mp3/CMakeLists.txt | 3 - lorgar/lib/mp3/mp3.js | 7706 ------------------------------ lorgar/main.js | 10 +- lorgar/views/CMakeLists.txt | 1 + lorgar/views/player.js | 9 +- lorgar/views/songProgress.js | 76 + magnus/app.js | 2 + 21 files changed, 290 insertions(+), 11796 deletions(-) delete mode 100644 lorgar/lib/aurora/CMakeLists.txt delete mode 100644 lorgar/lib/aurora/aurora.js create mode 100644 lorgar/lib/em/CMakeLists.txt create mode 100644 lorgar/lib/em/wrapper.js create mode 100644 lorgar/lib/em/wrapper.wasm delete mode 100644 lorgar/lib/mp3/CMakeLists.txt delete mode 100644 lorgar/lib/mp3/mp3.js create mode 100644 lorgar/views/songProgress.js diff --git a/lib/wModel/file/audio.cpp b/lib/wModel/file/audio.cpp index 6a0987f..a46d754 100644 --- a/lib/wModel/file/audio.cpp +++ b/lib/wModel/file/audio.cpp @@ -3,12 +3,8 @@ #include M::Audio::Audio(W::Blob* p_file, const W::Address& addr, QObject* parent): - File(p_file, addr, parent), - frames() + File(p_file, addr, parent) { - W::Handler* requestFrames = W::Handler::create(address + W::Address({u"requestFrames"}), this, &M::Audio::_h_requestFrames); - - addHandler(requestFrames); } M::Audio::~Audio() @@ -32,41 +28,18 @@ void M::Audio::initAdditional(const W::String& p_mime) uint64_t length = 0; uint64_t tBits = 0; + uint64_t amount = 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); + amount++; 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(ev.getData()); - const W::Uint64& index = static_cast(vc.at(u"index")); - const W::Uint64& amount = static_cast(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& 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); + additional.insert(u"bitrate", new W::Uint64(tBits / amount)); } diff --git a/lib/wModel/file/audio.h b/lib/wModel/file/audio.h index 070e31c..805e0eb 100644 --- a/lib/wModel/file/audio.h +++ b/lib/wModel/file/audio.h @@ -24,11 +24,6 @@ namespace M { protected: void initAdditional(const W::String& p_mime) override; - - handler(requestFrames); - - private: - std::deque> frames; }; } diff --git a/lib/wModel/file/file.cpp b/lib/wModel/file/file.cpp index 5efa9bd..e28caf4 100644 --- a/lib/wModel/file/file.cpp +++ b/lib/wModel/file/file.cpp @@ -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* 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(getAdditional); + addHandler(getSlice); } M::File::~File() @@ -35,7 +37,7 @@ void M::File::initAdditional(const W::String& p_mime) { 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); } @@ -106,3 +108,21 @@ M::File * M::File::create(W::Blob* blob, const W::Address& addr, QObject* parent out->initAdditional(W::String(mime.toStdString())); return out; } + +void M::File::h_getSlice(const W::Event& ev) +{ + const W::Vocabulary& vc = static_cast(ev.getData()); + const W::Uint64& begin = static_cast(vc.at(u"begin")); + const W::Uint64& size = static_cast(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); +} + diff --git a/lib/wModel/file/file.h b/lib/wModel/file/file.h index 8c50440..5eeab4e 100644 --- a/lib/wModel/file/file.h +++ b/lib/wModel/file/file.h @@ -32,6 +32,7 @@ namespace M { handler(get); handler(getAdditional); + handler(getSlice); protected: W::Vocabulary additional; diff --git a/libjs/wController/file/audio.js b/libjs/wController/file/audio.js index deb316c..9d8474e 100644 --- a/libjs/wController/file/audio.js +++ b/libjs/wController/file/audio.js @@ -9,79 +9,16 @@ 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._frames = new Vector(); - - this.addHandler("responseFrames"); - }, - destructor: function() { - this._frames.destructor(); - - File.fn.destructor.call(this); }, hasMore: function() { - return this._totalFrames > this._loadedFrames; + return this.getSize() > this.data.length(); }, - _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; - } - - return ac; + getBitrate: function() { + return this._additional.at("bitrate").valueOf(); }, - _h_responseFrames: function(ev) { - if (this._waitingForFrames === true) { - 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; - } - } - } + getDuration: function() { + return this._additional.at("duration").valueOf(); } }); -var framePortion = 10; - module.exports = Audio; diff --git a/libjs/wController/file/file.js b/libjs/wController/file/file.js index f220558..57e9941 100644 --- a/libjs/wController/file/file.js +++ b/libjs/wController/file/file.js @@ -2,6 +2,8 @@ var Controller = require("../controller"); var WVocabulary = require("../../wType/vocabulary"); +var Uint64 = require("../../wType/uint64"); +var Blob = require("../../wType/blob"); var File = Controller.inherit({ "className": "File", @@ -10,17 +12,17 @@ var File = Controller.inherit({ this._hasData = false; this._hasAdditional = false; - this.data = null; + this.data = new Blob(); this._additional = null; + this._waitingForSlice = false; this._need = 0; this.addHandler("get"); this.addHandler("getAdditional"); + this.addHandler("getSlice"); }, "destructor": function() { - if (this._hasData) { - this.data.destructor(); - } + this.data.destructor(); if (this._hasAdditional) { this._additional.destructor(); } @@ -46,6 +48,9 @@ var File = Controller.inherit({ "getMimeType": function() { return this._additional.at("mimeType").toString(); }, + "getSize": function() { + return this._additional.at("size").valueOf(); + }, "_h_get": function(ev) { var dt = ev.getData(); @@ -55,7 +60,9 @@ var File = Controller.inherit({ } this._hasData = true; + var oldData = this.data; this.data = dt.at("data").clone(); + oldData.destructor(); this.trigger("data"); }, "_h_getAdditional": function(ev) { @@ -69,6 +76,24 @@ var File = Controller.inherit({ 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() { if (this._need === 0) { var vc = new WVocabulary(); @@ -77,6 +102,30 @@ var File = Controller.inherit({ } ++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() { Controller.fn.subscribe.call(this); diff --git a/libjs/wController/player.js b/libjs/wController/player.js index 10b8aa7..e434890 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -8,16 +8,11 @@ var Button = require("./button"); var ImageById = require("./imageById"); var Vocabulary = require("./vocabulary"); var Audio = require("./file/audio"); +var Model = require("./localModel"); var Enum = require("../utils/enum"); 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({ className: "Player", constructor: function(addr) { @@ -26,6 +21,7 @@ var Player = Controller.inherit({ this.controls = Object.create(null); this.views = Object.create(null); this.mode = PlayerMode.straight.playback; + this.progress = new ProgressModel(); this._audio = null; this._createStateMachine(); this._createPlayingInfrastructure(); @@ -34,10 +30,14 @@ var Player = Controller.inherit({ this.addHandler("viewsChange"); this.addHandler("play"); this.addHandler("pause"); + + this._playbackInterval = setInterval(this._onInterval.bind(this), 250); }, destructor: function() { + this._clearInterval(this._playbackInterval); + this._destroyPlayingInfrastructure(); this._fsm.destructor(); - this._player.stop(); + this.progress.destructor(); Controller.fn.destructor.call(this); }, @@ -109,15 +109,16 @@ var Player = Controller.inherit({ this.trigger("newElement", ctrl, t); } }, - _createPlayingInfrastructure() { - if (this._source) { - this._source.reset(); - this._asset.stop(); - this._player.stop(); - } - this._source = new Source(); - this._asset = new AV.Asset(this._source); - this._player = new AV.Player(this._asset); + _createPlayingInfrastructure: function() { + this._ctx = new AudioContext(); + this._decoder = new Mp3Decoder(); + this._currentTime = 0; + + this._ctx.suspend(); + }, + _destroyPlayingInfrastructure: function() { + this._ctx.close(); + this._decoder.delete(); }, _createStateMachine: function() { this._fsm = new StateMachine("initial", graphs[this.mode]); @@ -177,13 +178,28 @@ var Player = Controller.inherit({ this._addView(vc.at("type"), vc.at("address")); } }, - _onAudioNewFrames: function(frames) { - var data = new Uint8Array(frames); - this._source.emit("data", new AV.Buffer(data)); + _onAudioNewSlice: function(frames) { + var arr = new Uint8Array(frames.valueOf()); + 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"); if (this._audio.hasMore()) { - this._audio.requestMore(); + this._audio.requestSlice(audioPortion); } else { this._fsm.manipulation("noMoreFrames"); } @@ -191,6 +207,11 @@ var Player = Controller.inherit({ _onControllerReady: function() { 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) { switch (key) { case "image": @@ -202,7 +223,7 @@ var Player = Controller.inherit({ 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._audio.on("slice", this._onAudioNewSlice, this); this._audio.on("ready", this._onControllerReady, this); this._fsm.manipulation("controller"); } @@ -228,16 +249,18 @@ var Player = Controller.inherit({ this.removeForeignController(this._audio); this._audio.destructor(); this._audio = null; + this._destroyPlayingInfrastructure(); this._createPlayingInfrastructure(); } break; case "initialPlaying": if (e.manipulation === "noController") { - this._player.pause(); + this._ctx.suspend(); this.removeForeignController(this._audio); this.audio.destructor(); this._audio = null; + this._destroyPlayingInfrastructure(); this._createPlayingInfrastructure(); } break; @@ -249,9 +272,9 @@ var Player = Controller.inherit({ break; case "hasControllerPlaying": if (this._audio.hasMore()) { - this._audio.requestMore(); + this._audio.requestSlice(audioPortion); - this._player.play(); //todo temporal + this._ctx.resume(); //todo temporal } else { this._fsm.manipulation("noMoreFrames"); } @@ -259,24 +282,24 @@ var Player = Controller.inherit({ case "paused": switch (e.oldState) { case "playing": - this._player.pause(); + this._ctx.suspend(); break; } break; case "pausedAllLoaded": switch (e.oldState) { case "playingAllLoaded": - this._player.pause(); + this._ctx.suspend(); break; } break; case "playing": - this._player.play(); + this._ctx.resume(); break; case "playingAllLoaded": switch (e.oldState) { case "pausedAllLoaded": - this._player.play(); + this._ctx.resume(); 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; diff --git a/libjs/wType/blob.js b/libjs/wType/blob.js index 3aa38de..5a33d19 100644 --- a/libjs/wType/blob.js +++ b/libjs/wType/blob.js @@ -17,6 +17,36 @@ var Blob = Object.inherit({ 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() { var arr = new Uint8Array(this._data); var bin = ""; diff --git a/lorgar/lib/CMakeLists.txt b/lorgar/lib/CMakeLists.txt index 41d77e0..9e87652 100644 --- a/lorgar/lib/CMakeLists.txt +++ b/lorgar/lib/CMakeLists.txt @@ -3,8 +3,6 @@ cmake_minimum_required(VERSION 2.8.12) add_subdirectory(requirejs) add_subdirectory(wSocket) add_subdirectory(bintrees) -add_subdirectory(mp3) -add_subdirectory(aurora) add_subdirectory(wContainer) add_subdirectory(utils) add_subdirectory(wType) @@ -12,3 +10,4 @@ add_subdirectory(wDispatcher) add_subdirectory(wTest) add_subdirectory(wController) add_subdirectory(fonts) +add_subdirectory(em) diff --git a/lorgar/lib/aurora/CMakeLists.txt b/lorgar/lib/aurora/CMakeLists.txt deleted file mode 100644 index b286c2e..0000000 --- a/lorgar/lib/aurora/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -cmake_minimum_required(VERSION 2.8.12) - -configure_file(aurora.js aurora.js) diff --git a/lorgar/lib/aurora/aurora.js b/lorgar/lib/aurora/aurora.js deleted file mode 100644 index fd356b2..0000000 --- a/lorgar/lib/aurora/aurora.js +++ /dev/null @@ -1,3938 +0,0 @@ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.AV=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o> 3); - return this.bitPosition = pos & 7; - }; - - Bitstream.prototype.rewind = function(bits) { - var pos; - pos = this.bitPosition - bits; - this.stream.rewind(Math.abs(pos >> 3)); - return this.bitPosition = pos & 7; - }; - - Bitstream.prototype.seek = function(offset) { - var curOffset; - curOffset = this.offset(); - if (offset > curOffset) { - return this.advance(offset - curOffset); - } else if (offset < curOffset) { - return this.rewind(curOffset - offset); - } - }; - - Bitstream.prototype.align = function() { - if (this.bitPosition !== 0) { - this.bitPosition = 0; - return this.stream.advance(1); - } - }; - - Bitstream.prototype.read = function(bits, signed) { - var a, a0, a1, a2, a3, a4, mBits; - if (bits === 0) { - return 0; - } - mBits = bits + this.bitPosition; - if (mBits <= 8) { - a = ((this.stream.peekUInt8() << this.bitPosition) & 0xff) >>> (8 - bits); - } else if (mBits <= 16) { - a = ((this.stream.peekUInt16() << this.bitPosition) & 0xffff) >>> (16 - bits); - } else if (mBits <= 24) { - a = ((this.stream.peekUInt24() << this.bitPosition) & 0xffffff) >>> (24 - bits); - } else if (mBits <= 32) { - a = (this.stream.peekUInt32() << this.bitPosition) >>> (32 - bits); - } else if (mBits <= 40) { - a0 = this.stream.peekUInt8(0) * 0x0100000000; - a1 = this.stream.peekUInt8(1) << 24 >>> 0; - a2 = this.stream.peekUInt8(2) << 16; - a3 = this.stream.peekUInt8(3) << 8; - a4 = this.stream.peekUInt8(4); - a = a0 + a1 + a2 + a3 + a4; - a %= Math.pow(2, 40 - this.bitPosition); - a = Math.floor(a / Math.pow(2, 40 - this.bitPosition - bits)); - } else { - throw new Error("Too many bits!"); - } - if (signed) { - if (mBits < 32) { - if (a >>> (bits - 1)) { - a = ((1 << bits >>> 0) - a) * -1; - } - } else { - if (a / Math.pow(2, bits - 1) | 0) { - a = (Math.pow(2, bits) - a) * -1; - } - } - } - this.advance(bits); - return a; - }; - - Bitstream.prototype.peek = function(bits, signed) { - var a, a0, a1, a2, a3, a4, mBits; - if (bits === 0) { - return 0; - } - mBits = bits + this.bitPosition; - if (mBits <= 8) { - a = ((this.stream.peekUInt8() << this.bitPosition) & 0xff) >>> (8 - bits); - } else if (mBits <= 16) { - a = ((this.stream.peekUInt16() << this.bitPosition) & 0xffff) >>> (16 - bits); - } else if (mBits <= 24) { - a = ((this.stream.peekUInt24() << this.bitPosition) & 0xffffff) >>> (24 - bits); - } else if (mBits <= 32) { - a = (this.stream.peekUInt32() << this.bitPosition) >>> (32 - bits); - } else if (mBits <= 40) { - a0 = this.stream.peekUInt8(0) * 0x0100000000; - a1 = this.stream.peekUInt8(1) << 24 >>> 0; - a2 = this.stream.peekUInt8(2) << 16; - a3 = this.stream.peekUInt8(3) << 8; - a4 = this.stream.peekUInt8(4); - a = a0 + a1 + a2 + a3 + a4; - a %= Math.pow(2, 40 - this.bitPosition); - a = Math.floor(a / Math.pow(2, 40 - this.bitPosition - bits)); - } else { - throw new Error("Too many bits!"); - } - if (signed) { - if (mBits < 32) { - if (a >>> (bits - 1)) { - a = ((1 << bits >>> 0) - a) * -1; - } - } else { - if (a / Math.pow(2, bits - 1) | 0) { - a = (Math.pow(2, bits) - a) * -1; - } - } - } - return a; - }; - - Bitstream.prototype.readLSB = function(bits, signed) { - var a, mBits; - if (bits === 0) { - return 0; - } - if (bits > 40) { - throw new Error("Too many bits!"); - } - mBits = bits + this.bitPosition; - a = (this.stream.peekUInt8(0)) >>> this.bitPosition; - if (mBits > 8) { - a |= (this.stream.peekUInt8(1)) << (8 - this.bitPosition); - } - if (mBits > 16) { - a |= (this.stream.peekUInt8(2)) << (16 - this.bitPosition); - } - if (mBits > 24) { - a += (this.stream.peekUInt8(3)) << (24 - this.bitPosition) >>> 0; - } - if (mBits > 32) { - a += (this.stream.peekUInt8(4)) * Math.pow(2, 32 - this.bitPosition); - } - if (mBits >= 32) { - a %= Math.pow(2, bits); - } else { - a &= (1 << bits) - 1; - } - if (signed) { - if (mBits < 32) { - if (a >>> (bits - 1)) { - a = ((1 << bits >>> 0) - a) * -1; - } - } else { - if (a / Math.pow(2, bits - 1) | 0) { - a = (Math.pow(2, bits) - a) * -1; - } - } - } - this.advance(bits); - return a; - }; - - Bitstream.prototype.peekLSB = function(bits, signed) { - var a, mBits; - if (bits === 0) { - return 0; - } - if (bits > 40) { - throw new Error("Too many bits!"); - } - mBits = bits + this.bitPosition; - a = (this.stream.peekUInt8(0)) >>> this.bitPosition; - if (mBits > 8) { - a |= (this.stream.peekUInt8(1)) << (8 - this.bitPosition); - } - if (mBits > 16) { - a |= (this.stream.peekUInt8(2)) << (16 - this.bitPosition); - } - if (mBits > 24) { - a += (this.stream.peekUInt8(3)) << (24 - this.bitPosition) >>> 0; - } - if (mBits > 32) { - a += (this.stream.peekUInt8(4)) * Math.pow(2, 32 - this.bitPosition); - } - if (mBits >= 32) { - a %= Math.pow(2, bits); - } else { - a &= (1 << bits) - 1; - } - if (signed) { - if (mBits < 32) { - if (a >>> (bits - 1)) { - a = ((1 << bits >>> 0) - a) * -1; - } - } else { - if (a / Math.pow(2, bits - 1) | 0) { - a = (Math.pow(2, bits) - a) * -1; - } - } - } - return a; - }; - - return Bitstream; - -})(); - -module.exports = Bitstream; - - -},{}],7:[function(_dereq_,module,exports){ -(function (global){ -var AVBuffer; - -AVBuffer = (function() { - var BlobBuilder, URL; - - function AVBuffer(input) { - var _ref; - if (input instanceof Uint8Array) { - this.data = input; - } else if (input instanceof ArrayBuffer || Array.isArray(input) || typeof input === 'number' || ((_ref = global.Buffer) != null ? _ref.isBuffer(input) : void 0)) { - this.data = new Uint8Array(input); - } else if (input.buffer instanceof ArrayBuffer) { - this.data = new Uint8Array(input.buffer, input.byteOffset, input.length * input.BYTES_PER_ELEMENT); - } else if (input instanceof AVBuffer) { - this.data = input.data; - } else { - throw new Error("Constructing buffer with unknown type."); - } - this.length = this.data.length; - this.next = null; - this.prev = null; - } - - AVBuffer.allocate = function(size) { - return new AVBuffer(size); - }; - - AVBuffer.prototype.copy = function() { - return new AVBuffer(new Uint8Array(this.data)); - }; - - AVBuffer.prototype.slice = function(position, length) { - if (length == null) { - length = this.length; - } - if (position === 0 && length >= this.length) { - return new AVBuffer(this.data); - } else { - return new AVBuffer(this.data.subarray(position, position + length)); - } - }; - - BlobBuilder = global.BlobBuilder || global.MozBlobBuilder || global.WebKitBlobBuilder; - - URL = global.URL || global.webkitURL || global.mozURL; - - AVBuffer.makeBlob = function(data, type) { - var bb; - if (type == null) { - type = 'application/octet-stream'; - } - try { - return new Blob([data], { - type: type - }); - } catch (_error) {} - if (BlobBuilder != null) { - bb = new BlobBuilder; - bb.append(data); - return bb.getBlob(type); - } - return null; - }; - - AVBuffer.makeBlobURL = function(data, type) { - return URL != null ? URL.createObjectURL(this.makeBlob(data, type)) : void 0; - }; - - AVBuffer.revokeBlobURL = function(url) { - return URL != null ? URL.revokeObjectURL(url) : void 0; - }; - - AVBuffer.prototype.toBlob = function() { - return AVBuffer.makeBlob(this.data.buffer); - }; - - AVBuffer.prototype.toBlobURL = function() { - return AVBuffer.makeBlobURL(this.data.buffer); - }; - - return AVBuffer; - -})(); - -module.exports = AVBuffer; - - -}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],8:[function(_dereq_,module,exports){ -var BufferList; - -BufferList = (function() { - function BufferList() { - this.first = null; - this.last = null; - this.numBuffers = 0; - this.availableBytes = 0; - this.availableBuffers = 0; - } - - BufferList.prototype.copy = function() { - var result; - result = new BufferList; - result.first = this.first; - result.last = this.last; - result.numBuffers = this.numBuffers; - result.availableBytes = this.availableBytes; - result.availableBuffers = this.availableBuffers; - return result; - }; - - BufferList.prototype.append = function(buffer) { - var _ref; - buffer.prev = this.last; - if ((_ref = this.last) != null) { - _ref.next = buffer; - } - this.last = buffer; - if (this.first == null) { - this.first = buffer; - } - this.availableBytes += buffer.length; - this.availableBuffers++; - return this.numBuffers++; - }; - - BufferList.prototype.advance = function() { - if (this.first) { - this.availableBytes -= this.first.length; - this.availableBuffers--; - this.first = this.first.next; - return this.first != null; - } - return false; - }; - - BufferList.prototype.rewind = function() { - var _ref; - if (this.first && !this.first.prev) { - return false; - } - this.first = ((_ref = this.first) != null ? _ref.prev : void 0) || this.last; - if (this.first) { - this.availableBytes += this.first.length; - this.availableBuffers++; - } - return this.first != null; - }; - - BufferList.prototype.reset = function() { - var _results; - _results = []; - while (this.rewind()) { - continue; - } - return _results; - }; - - return BufferList; - -})(); - -module.exports = BufferList; - - -},{}],9:[function(_dereq_,module,exports){ -var Base, EventEmitter, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - __slice = [].slice; - -Base = _dereq_('./base'); - -EventEmitter = (function(_super) { - __extends(EventEmitter, _super); - - function EventEmitter() { - return EventEmitter.__super__.constructor.apply(this, arguments); - } - - EventEmitter.prototype.on = function(event, fn) { - var _base; - if (this.events == null) { - this.events = {}; - } - if ((_base = this.events)[event] == null) { - _base[event] = []; - } - return this.events[event].push(fn); - }; - - EventEmitter.prototype.off = function(event, fn) { - var index, _ref; - if (!((_ref = this.events) != null ? _ref[event] : void 0)) { - return; - } - index = this.events[event].indexOf(fn); - if (~index) { - return this.events[event].splice(index, 1); - } - }; - - EventEmitter.prototype.once = function(event, fn) { - var cb; - return this.on(event, cb = function() { - this.off(event, cb); - return fn.apply(this, arguments); - }); - }; - - EventEmitter.prototype.emit = function() { - var args, event, fn, _i, _len, _ref, _ref1; - event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - if (!((_ref = this.events) != null ? _ref[event] : void 0)) { - return; - } - _ref1 = this.events[event].slice(); - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - fn = _ref1[_i]; - fn.apply(this, args); - } - }; - - return EventEmitter; - -})(Base); - -module.exports = EventEmitter; - - -},{"./base":5}],10:[function(_dereq_,module,exports){ -var AVBuffer, BufferList, Stream, UnderflowError; - -BufferList = _dereq_('./bufferlist'); - -AVBuffer = _dereq_('./buffer'); - -UnderflowError = _dereq_('./underflow'); - -Stream = (function() { - var buf, decodeString, float32, float64, float64Fallback, float80, int16, int32, int8, nativeEndian, uint16, uint32, uint8; - - buf = new ArrayBuffer(16); - - uint8 = new Uint8Array(buf); - - int8 = new Int8Array(buf); - - uint16 = new Uint16Array(buf); - - int16 = new Int16Array(buf); - - uint32 = new Uint32Array(buf); - - int32 = new Int32Array(buf); - - float32 = new Float32Array(buf); - - if (typeof Float64Array !== "undefined" && Float64Array !== null) { - float64 = new Float64Array(buf); - } - - nativeEndian = new Uint16Array(new Uint8Array([0x12, 0x34]).buffer)[0] === 0x3412; - - function Stream(list) { - this.list = list; - this.localOffset = 0; - this.offset = 0; - } - - Stream.fromBuffer = function(buffer) { - var list; - list = new BufferList; - list.append(buffer); - return new Stream(list); - }; - - Stream.prototype.copy = function() { - var result; - result = new Stream(this.list.copy()); - result.localOffset = this.localOffset; - result.offset = this.offset; - return result; - }; - - Stream.prototype.available = function(bytes) { - return bytes <= this.list.availableBytes - this.localOffset; - }; - - Stream.prototype.remainingBytes = function() { - return this.list.availableBytes - this.localOffset; - }; - - Stream.prototype.advance = function(bytes) { - if (!this.available(bytes)) { - throw new UnderflowError(); - } - this.localOffset += bytes; - this.offset += bytes; - while (this.list.first && this.localOffset >= this.list.first.length) { - this.localOffset -= this.list.first.length; - this.list.advance(); - } - return this; - }; - - Stream.prototype.rewind = function(bytes) { - if (bytes > this.offset) { - throw new UnderflowError(); - } - if (!this.list.first) { - this.list.rewind(); - this.localOffset = this.list.first.length; - } - this.localOffset -= bytes; - this.offset -= bytes; - while (this.list.first.prev && this.localOffset < 0) { - this.list.rewind(); - this.localOffset += this.list.first.length; - } - return this; - }; - - Stream.prototype.seek = function(position) { - if (position > this.offset) { - return this.advance(position - this.offset); - } else if (position < this.offset) { - return this.rewind(this.offset - position); - } - }; - - Stream.prototype.readUInt8 = function() { - var a; - if (!this.available(1)) { - throw new UnderflowError(); - } - a = this.list.first.data[this.localOffset]; - this.localOffset += 1; - this.offset += 1; - if (this.localOffset === this.list.first.length) { - this.localOffset = 0; - this.list.advance(); - } - return a; - }; - - Stream.prototype.peekUInt8 = function(offset) { - var buffer; - if (offset == null) { - offset = 0; - } - if (!this.available(offset + 1)) { - throw new UnderflowError(); - } - offset = this.localOffset + offset; - buffer = this.list.first; - while (buffer) { - if (buffer.length > offset) { - return buffer.data[offset]; - } - offset -= buffer.length; - buffer = buffer.next; - } - return 0; - }; - - Stream.prototype.read = function(bytes, littleEndian) { - var i, _i, _j, _ref; - if (littleEndian == null) { - littleEndian = false; - } - if (littleEndian === nativeEndian) { - for (i = _i = 0; _i < bytes; i = _i += 1) { - uint8[i] = this.readUInt8(); - } - } else { - for (i = _j = _ref = bytes - 1; _j >= 0; i = _j += -1) { - uint8[i] = this.readUInt8(); - } - } - }; - - Stream.prototype.peek = function(bytes, offset, littleEndian) { - var i, _i, _j; - if (littleEndian == null) { - littleEndian = false; - } - if (littleEndian === nativeEndian) { - for (i = _i = 0; _i < bytes; i = _i += 1) { - uint8[i] = this.peekUInt8(offset + i); - } - } else { - for (i = _j = 0; _j < bytes; i = _j += 1) { - uint8[bytes - i - 1] = this.peekUInt8(offset + i); - } - } - }; - - Stream.prototype.readInt8 = function() { - this.read(1); - return int8[0]; - }; - - Stream.prototype.peekInt8 = function(offset) { - if (offset == null) { - offset = 0; - } - this.peek(1, offset); - return int8[0]; - }; - - Stream.prototype.readUInt16 = function(littleEndian) { - this.read(2, littleEndian); - return uint16[0]; - }; - - Stream.prototype.peekUInt16 = function(offset, littleEndian) { - if (offset == null) { - offset = 0; - } - this.peek(2, offset, littleEndian); - return uint16[0]; - }; - - Stream.prototype.readInt16 = function(littleEndian) { - this.read(2, littleEndian); - return int16[0]; - }; - - Stream.prototype.peekInt16 = function(offset, littleEndian) { - if (offset == null) { - offset = 0; - } - this.peek(2, offset, littleEndian); - return int16[0]; - }; - - Stream.prototype.readUInt24 = function(littleEndian) { - if (littleEndian) { - return this.readUInt16(true) + (this.readUInt8() << 16); - } else { - return (this.readUInt16() << 8) + this.readUInt8(); - } - }; - - Stream.prototype.peekUInt24 = function(offset, littleEndian) { - if (offset == null) { - offset = 0; - } - if (littleEndian) { - return this.peekUInt16(offset, true) + (this.peekUInt8(offset + 2) << 16); - } else { - return (this.peekUInt16(offset) << 8) + this.peekUInt8(offset + 2); - } - }; - - Stream.prototype.readInt24 = function(littleEndian) { - if (littleEndian) { - return this.readUInt16(true) + (this.readInt8() << 16); - } else { - return (this.readInt16() << 8) + this.readUInt8(); - } - }; - - Stream.prototype.peekInt24 = function(offset, littleEndian) { - if (offset == null) { - offset = 0; - } - if (littleEndian) { - return this.peekUInt16(offset, true) + (this.peekInt8(offset + 2) << 16); - } else { - return (this.peekInt16(offset) << 8) + this.peekUInt8(offset + 2); - } - }; - - Stream.prototype.readUInt32 = function(littleEndian) { - this.read(4, littleEndian); - return uint32[0]; - }; - - Stream.prototype.peekUInt32 = function(offset, littleEndian) { - if (offset == null) { - offset = 0; - } - this.peek(4, offset, littleEndian); - return uint32[0]; - }; - - Stream.prototype.readInt32 = function(littleEndian) { - this.read(4, littleEndian); - return int32[0]; - }; - - Stream.prototype.peekInt32 = function(offset, littleEndian) { - if (offset == null) { - offset = 0; - } - this.peek(4, offset, littleEndian); - return int32[0]; - }; - - Stream.prototype.readFloat32 = function(littleEndian) { - this.read(4, littleEndian); - return float32[0]; - }; - - Stream.prototype.peekFloat32 = function(offset, littleEndian) { - if (offset == null) { - offset = 0; - } - this.peek(4, offset, littleEndian); - return float32[0]; - }; - - Stream.prototype.readFloat64 = function(littleEndian) { - this.read(8, littleEndian); - if (float64) { - return float64[0]; - } else { - return float64Fallback(); - } - }; - - float64Fallback = function() { - var exp, frac, high, low, out, sign; - low = uint32[0], high = uint32[1]; - if (!high || high === 0x80000000) { - return 0.0; - } - sign = 1 - (high >>> 31) * 2; - exp = (high >>> 20) & 0x7ff; - frac = high & 0xfffff; - if (exp === 0x7ff) { - if (frac) { - return NaN; - } - return sign * Infinity; - } - exp -= 1023; - out = (frac | 0x100000) * Math.pow(2, exp - 20); - out += low * Math.pow(2, exp - 52); - return sign * out; - }; - - Stream.prototype.peekFloat64 = function(offset, littleEndian) { - if (offset == null) { - offset = 0; - } - this.peek(8, offset, littleEndian); - if (float64) { - return float64[0]; - } else { - return float64Fallback(); - } - }; - - Stream.prototype.readFloat80 = function(littleEndian) { - this.read(10, littleEndian); - return float80(); - }; - - float80 = function() { - var a0, a1, exp, high, low, out, sign; - high = uint32[0], low = uint32[1]; - a0 = uint8[9]; - a1 = uint8[8]; - sign = 1 - (a0 >>> 7) * 2; - exp = ((a0 & 0x7F) << 8) | a1; - if (exp === 0 && low === 0 && high === 0) { - return 0; - } - if (exp === 0x7fff) { - if (low === 0 && high === 0) { - return sign * Infinity; - } - return NaN; - } - exp -= 16383; - out = low * Math.pow(2, exp - 31); - out += high * Math.pow(2, exp - 63); - return sign * out; - }; - - Stream.prototype.peekFloat80 = function(offset, littleEndian) { - if (offset == null) { - offset = 0; - } - this.peek(10, offset, littleEndian); - return float80(); - }; - - Stream.prototype.readBuffer = function(length) { - var i, result, to, _i; - result = AVBuffer.allocate(length); - to = result.data; - for (i = _i = 0; _i < length; i = _i += 1) { - to[i] = this.readUInt8(); - } - return result; - }; - - Stream.prototype.peekBuffer = function(offset, length) { - var i, result, to, _i; - if (offset == null) { - offset = 0; - } - result = AVBuffer.allocate(length); - to = result.data; - for (i = _i = 0; _i < length; i = _i += 1) { - to[i] = this.peekUInt8(offset + i); - } - return result; - }; - - Stream.prototype.readSingleBuffer = function(length) { - var result; - result = this.list.first.slice(this.localOffset, length); - this.advance(result.length); - return result; - }; - - Stream.prototype.peekSingleBuffer = function(offset, length) { - var result; - result = this.list.first.slice(this.localOffset + offset, length); - return result; - }; - - Stream.prototype.readString = function(length, encoding) { - if (encoding == null) { - encoding = 'ascii'; - } - return decodeString.call(this, 0, length, encoding, true); - }; - - Stream.prototype.peekString = function(offset, length, encoding) { - if (offset == null) { - offset = 0; - } - if (encoding == null) { - encoding = 'ascii'; - } - return decodeString.call(this, offset, length, encoding, false); - }; - - decodeString = function(offset, length, encoding, advance) { - var b1, b2, b3, b4, bom, c, end, littleEndian, nullEnd, pt, result, w1, w2; - encoding = encoding.toLowerCase(); - nullEnd = length === null ? 0 : -1; - if (length == null) { - length = Infinity; - } - end = offset + length; - result = ''; - switch (encoding) { - case 'ascii': - case 'latin1': - while (offset < end && (c = this.peekUInt8(offset++)) !== nullEnd) { - result += String.fromCharCode(c); - } - break; - case 'utf8': - case 'utf-8': - while (offset < end && (b1 = this.peekUInt8(offset++)) !== nullEnd) { - if ((b1 & 0x80) === 0) { - result += String.fromCharCode(b1); - } else if ((b1 & 0xe0) === 0xc0) { - b2 = this.peekUInt8(offset++) & 0x3f; - result += String.fromCharCode(((b1 & 0x1f) << 6) | b2); - } else if ((b1 & 0xf0) === 0xe0) { - b2 = this.peekUInt8(offset++) & 0x3f; - b3 = this.peekUInt8(offset++) & 0x3f; - result += String.fromCharCode(((b1 & 0x0f) << 12) | (b2 << 6) | b3); - } else if ((b1 & 0xf8) === 0xf0) { - b2 = this.peekUInt8(offset++) & 0x3f; - b3 = this.peekUInt8(offset++) & 0x3f; - b4 = this.peekUInt8(offset++) & 0x3f; - pt = (((b1 & 0x0f) << 18) | (b2 << 12) | (b3 << 6) | b4) - 0x10000; - result += String.fromCharCode(0xd800 + (pt >> 10), 0xdc00 + (pt & 0x3ff)); - } - } - break; - case 'utf16-be': - case 'utf16be': - case 'utf16le': - case 'utf16-le': - case 'utf16bom': - case 'utf16-bom': - switch (encoding) { - case 'utf16be': - case 'utf16-be': - littleEndian = false; - break; - case 'utf16le': - case 'utf16-le': - littleEndian = true; - break; - case 'utf16bom': - case 'utf16-bom': - if (length < 2 || (bom = this.peekUInt16(offset)) === nullEnd) { - if (advance) { - this.advance(offset += 2); - } - return result; - } - littleEndian = bom === 0xfffe; - offset += 2; - } - while (offset < end && (w1 = this.peekUInt16(offset, littleEndian)) !== nullEnd) { - offset += 2; - if (w1 < 0xd800 || w1 > 0xdfff) { - result += String.fromCharCode(w1); - } else { - if (w1 > 0xdbff) { - throw new Error("Invalid utf16 sequence."); - } - w2 = this.peekUInt16(offset, littleEndian); - if (w2 < 0xdc00 || w2 > 0xdfff) { - throw new Error("Invalid utf16 sequence."); - } - result += String.fromCharCode(w1, w2); - offset += 2; - } - } - if (w1 === nullEnd) { - offset += 2; - } - break; - default: - throw new Error("Unknown encoding: " + encoding); - } - if (advance) { - this.advance(offset); - } - return result; - }; - - return Stream; - -})(); - -module.exports = Stream; - - -},{"./buffer":7,"./bufferlist":8,"./underflow":11}],11:[function(_dereq_,module,exports){ -var UnderflowError, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -UnderflowError = (function(_super) { - __extends(UnderflowError, _super); - - function UnderflowError() { - UnderflowError.__super__.constructor.apply(this, arguments); - this.name = 'UnderflowError'; - this.stack = new Error().stack; - } - - return UnderflowError; - -})(Error); - -module.exports = UnderflowError; - - -},{}],12:[function(_dereq_,module,exports){ -var Bitstream, BufferList, Decoder, EventEmitter, Stream, UnderflowError, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('./core/events'); - -BufferList = _dereq_('./core/bufferlist'); - -Stream = _dereq_('./core/stream'); - -Bitstream = _dereq_('./core/bitstream'); - -UnderflowError = _dereq_('./core/underflow'); - -Decoder = (function(_super) { - var codecs; - - __extends(Decoder, _super); - - function Decoder(demuxer, format) { - var list; - this.demuxer = demuxer; - this.format = format; - list = new BufferList; - this.stream = new Stream(list); - this.bitstream = new Bitstream(this.stream); - this.receivedFinalBuffer = false; - this.waiting = false; - this.demuxer.on('cookie', (function(_this) { - return function(cookie) { - var error; - try { - return _this.setCookie(cookie); - } catch (_error) { - error = _error; - return _this.emit('error', error); - } - }; - })(this)); - this.demuxer.on('data', (function(_this) { - return function(chunk) { - list.append(chunk); - if (_this.waiting) { - return _this.decode(); - } - }; - })(this)); - this.demuxer.on('end', (function(_this) { - return function() { - _this.receivedFinalBuffer = true; - if (_this.waiting) { - return _this.decode(); - } - }; - })(this)); - this.init(); - } - - Decoder.prototype.init = function() {}; - - Decoder.prototype.setCookie = function(cookie) {}; - - Decoder.prototype.readChunk = function() {}; - - Decoder.prototype.decode = function() { - var error, offset, packet; - this.waiting = false; - offset = this.bitstream.offset(); - try { - packet = this.readChunk(); - } catch (_error) { - error = _error; - if (!(error instanceof UnderflowError)) { - this.emit('error', error); - return false; - } - } - if (packet) { - this.emit('data', packet); - return true; - } else if (!this.receivedFinalBuffer) { - this.bitstream.seek(offset); - this.waiting = true; - } else { - this.emit('end'); - } - return false; - }; - - Decoder.prototype.seek = function(timestamp) { - var seekPoint; - seekPoint = this.demuxer.seek(timestamp); - this.stream.seek(seekPoint.offset); - return seekPoint.timestamp; - }; - - codecs = {}; - - Decoder.register = function(id, decoder) { - return codecs[id] = decoder; - }; - - Decoder.find = function(id) { - return codecs[id] || null; - }; - - return Decoder; - -})(EventEmitter); - -module.exports = Decoder; - - -},{"./core/bitstream":6,"./core/bufferlist":8,"./core/events":9,"./core/stream":10,"./core/underflow":11}],13:[function(_dereq_,module,exports){ -var Decoder, LPCMDecoder, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -Decoder = _dereq_('../decoder'); - -LPCMDecoder = (function(_super) { - __extends(LPCMDecoder, _super); - - function LPCMDecoder() { - this.readChunk = __bind(this.readChunk, this); - return LPCMDecoder.__super__.constructor.apply(this, arguments); - } - - Decoder.register('lpcm', LPCMDecoder); - - LPCMDecoder.prototype.readChunk = function() { - var chunkSize, i, littleEndian, output, samples, stream, _i, _j, _k, _l, _m, _n; - stream = this.stream; - littleEndian = this.format.littleEndian; - chunkSize = Math.min(4096, stream.remainingBytes()); - samples = chunkSize / (this.format.bitsPerChannel / 8) | 0; - if (chunkSize < this.format.bitsPerChannel / 8) { - return null; - } - if (this.format.floatingPoint) { - switch (this.format.bitsPerChannel) { - case 32: - output = new Float32Array(samples); - for (i = _i = 0; _i < samples; i = _i += 1) { - output[i] = stream.readFloat32(littleEndian); - } - break; - case 64: - output = new Float64Array(samples); - for (i = _j = 0; _j < samples; i = _j += 1) { - output[i] = stream.readFloat64(littleEndian); - } - break; - default: - throw new Error('Unsupported bit depth.'); - } - } else { - switch (this.format.bitsPerChannel) { - case 8: - output = new Int8Array(samples); - for (i = _k = 0; _k < samples; i = _k += 1) { - output[i] = stream.readInt8(); - } - break; - case 16: - output = new Int16Array(samples); - for (i = _l = 0; _l < samples; i = _l += 1) { - output[i] = stream.readInt16(littleEndian); - } - break; - case 24: - output = new Int32Array(samples); - for (i = _m = 0; _m < samples; i = _m += 1) { - output[i] = stream.readInt24(littleEndian); - } - break; - case 32: - output = new Int32Array(samples); - for (i = _n = 0; _n < samples; i = _n += 1) { - output[i] = stream.readInt32(littleEndian); - } - break; - default: - throw new Error('Unsupported bit depth.'); - } - } - return output; - }; - - return LPCMDecoder; - -})(Decoder); - - -},{"../decoder":12}],14:[function(_dereq_,module,exports){ -var Decoder, XLAWDecoder, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -Decoder = _dereq_('../decoder'); - -XLAWDecoder = (function(_super) { - var BIAS, QUANT_MASK, SEG_MASK, SEG_SHIFT, SIGN_BIT; - - __extends(XLAWDecoder, _super); - - function XLAWDecoder() { - this.readChunk = __bind(this.readChunk, this); - return XLAWDecoder.__super__.constructor.apply(this, arguments); - } - - Decoder.register('ulaw', XLAWDecoder); - - Decoder.register('alaw', XLAWDecoder); - - SIGN_BIT = 0x80; - - QUANT_MASK = 0xf; - - SEG_SHIFT = 4; - - SEG_MASK = 0x70; - - BIAS = 0x84; - - XLAWDecoder.prototype.init = function() { - var i, seg, t, table, val, _i, _j; - this.format.bitsPerChannel = 16; - this.table = table = new Int16Array(256); - if (this.format.formatID === 'ulaw') { - for (i = _i = 0; _i < 256; i = ++_i) { - val = ~i; - t = ((val & QUANT_MASK) << 3) + BIAS; - t <<= (val & SEG_MASK) >>> SEG_SHIFT; - table[i] = val & SIGN_BIT ? BIAS - t : t - BIAS; - } - } else { - for (i = _j = 0; _j < 256; i = ++_j) { - val = i ^ 0x55; - t = val & QUANT_MASK; - seg = (val & SEG_MASK) >>> SEG_SHIFT; - if (seg) { - t = (t + t + 1 + 32) << (seg + 2); - } else { - t = (t + t + 1) << 3; - } - table[i] = val & SIGN_BIT ? t : -t; - } - } - }; - - XLAWDecoder.prototype.readChunk = function() { - var i, output, samples, stream, table, _i; - stream = this.stream, table = this.table; - samples = Math.min(4096, this.stream.remainingBytes()); - if (samples === 0) { - return; - } - output = new Int16Array(samples); - for (i = _i = 0; _i < samples; i = _i += 1) { - output[i] = table[stream.readUInt8()]; - } - return output; - }; - - return XLAWDecoder; - -})(Decoder); - - -},{"../decoder":12}],15:[function(_dereq_,module,exports){ -var BufferList, Demuxer, EventEmitter, Stream, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('./core/events'); - -BufferList = _dereq_('./core/bufferlist'); - -Stream = _dereq_('./core/stream'); - -Demuxer = (function(_super) { - var formats; - - __extends(Demuxer, _super); - - Demuxer.probe = function(buffer) { - return false; - }; - - function Demuxer(source, chunk) { - var list, received; - list = new BufferList; - list.append(chunk); - this.stream = new Stream(list); - received = false; - source.on('data', (function(_this) { - return function(chunk) { - received = true; - list.append(chunk); - return _this.readChunk(chunk); - }; - })(this)); - source.on('error', (function(_this) { - return function(err) { - return _this.emit('error', err); - }; - })(this)); - source.on('end', (function(_this) { - return function() { - if (!received) { - _this.readChunk(chunk); - } - return _this.emit('end'); - }; - })(this)); - this.seekPoints = []; - this.init(); - } - - Demuxer.prototype.init = function() {}; - - Demuxer.prototype.readChunk = function(chunk) {}; - - Demuxer.prototype.addSeekPoint = function(offset, timestamp) { - var index; - index = this.searchTimestamp(timestamp); - return this.seekPoints.splice(index, 0, { - offset: offset, - timestamp: timestamp - }); - }; - - Demuxer.prototype.searchTimestamp = function(timestamp, backward) { - var high, low, mid, time; - low = 0; - high = this.seekPoints.length; - if (high > 0 && this.seekPoints[high - 1].timestamp < timestamp) { - return high; - } - while (low < high) { - mid = (low + high) >> 1; - time = this.seekPoints[mid].timestamp; - if (time < timestamp) { - low = mid + 1; - } else if (time >= timestamp) { - high = mid; - } - } - if (high > this.seekPoints.length) { - high = this.seekPoints.length; - } - return high; - }; - - Demuxer.prototype.seek = function(timestamp) { - var index, seekPoint; - if (this.format && this.format.framesPerPacket > 0 && this.format.bytesPerPacket > 0) { - seekPoint = { - timestamp: timestamp, - offset: this.format.bytesPerPacket * timestamp / this.format.framesPerPacket - }; - return seekPoint; - } else { - index = this.searchTimestamp(timestamp); - return this.seekPoints[index]; - } - }; - - formats = []; - - Demuxer.register = function(demuxer) { - return formats.push(demuxer); - }; - - Demuxer.find = function(buffer) { - var e, format, offset, stream, _i, _len; - stream = Stream.fromBuffer(buffer); - for (_i = 0, _len = formats.length; _i < _len; _i++) { - format = formats[_i]; - offset = stream.offset; - try { - if (format.probe(stream)) { - return format; - } - } catch (_error) { - e = _error; - } - stream.seek(offset); - } - return null; - }; - - return Demuxer; - -})(EventEmitter); - -module.exports = Demuxer; - - -},{"./core/bufferlist":8,"./core/events":9,"./core/stream":10}],16:[function(_dereq_,module,exports){ -var AIFFDemuxer, Demuxer, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -Demuxer = _dereq_('../demuxer'); - -AIFFDemuxer = (function(_super) { - __extends(AIFFDemuxer, _super); - - function AIFFDemuxer() { - return AIFFDemuxer.__super__.constructor.apply(this, arguments); - } - - Demuxer.register(AIFFDemuxer); - - AIFFDemuxer.probe = function(buffer) { - var _ref; - return buffer.peekString(0, 4) === 'FORM' && ((_ref = buffer.peekString(8, 4)) === 'AIFF' || _ref === 'AIFC'); - }; - - AIFFDemuxer.prototype.readChunk = function() { - var buffer, format, offset, _ref; - if (!this.readStart && this.stream.available(12)) { - if (this.stream.readString(4) !== 'FORM') { - return this.emit('error', 'Invalid AIFF.'); - } - this.fileSize = this.stream.readUInt32(); - this.fileType = this.stream.readString(4); - this.readStart = true; - if ((_ref = this.fileType) !== 'AIFF' && _ref !== 'AIFC') { - return this.emit('error', 'Invalid AIFF.'); - } - } - while (this.stream.available(1)) { - if (!this.readHeaders && this.stream.available(8)) { - this.type = this.stream.readString(4); - this.len = this.stream.readUInt32(); - } - switch (this.type) { - case 'COMM': - if (!this.stream.available(this.len)) { - return; - } - this.format = { - formatID: 'lpcm', - channelsPerFrame: this.stream.readUInt16(), - sampleCount: this.stream.readUInt32(), - bitsPerChannel: this.stream.readUInt16(), - sampleRate: this.stream.readFloat80(), - framesPerPacket: 1, - littleEndian: false, - floatingPoint: false - }; - this.format.bytesPerPacket = (this.format.bitsPerChannel / 8) * this.format.channelsPerFrame; - if (this.fileType === 'AIFC') { - format = this.stream.readString(4); - this.format.littleEndian = format === 'sowt' && this.format.bitsPerChannel > 8; - this.format.floatingPoint = format === 'fl32' || format === 'fl64'; - if (format === 'twos' || format === 'sowt' || format === 'fl32' || format === 'fl64' || format === 'NONE') { - format = 'lpcm'; - } - this.format.formatID = format; - this.len -= 4; - } - this.stream.advance(this.len - 18); - this.emit('format', this.format); - this.emit('duration', this.format.sampleCount / this.format.sampleRate * 1000 | 0); - break; - case 'SSND': - if (!(this.readSSNDHeader && this.stream.available(4))) { - offset = this.stream.readUInt32(); - this.stream.advance(4); - this.stream.advance(offset); - this.readSSNDHeader = true; - } - buffer = this.stream.readSingleBuffer(this.len); - this.len -= buffer.length; - this.readHeaders = this.len > 0; - this.emit('data', buffer); - break; - default: - if (!this.stream.available(this.len)) { - return; - } - this.stream.advance(this.len); - } - if (this.type !== 'SSND') { - this.readHeaders = false; - } - } - }; - - return AIFFDemuxer; - -})(Demuxer); - - -},{"../demuxer":15}],17:[function(_dereq_,module,exports){ -var AUDemuxer, Demuxer, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -Demuxer = _dereq_('../demuxer'); - -AUDemuxer = (function(_super) { - var bps, formats; - - __extends(AUDemuxer, _super); - - function AUDemuxer() { - return AUDemuxer.__super__.constructor.apply(this, arguments); - } - - Demuxer.register(AUDemuxer); - - AUDemuxer.probe = function(buffer) { - return buffer.peekString(0, 4) === '.snd'; - }; - - bps = [8, 8, 16, 24, 32, 32, 64]; - - bps[26] = 8; - - formats = { - 1: 'ulaw', - 27: 'alaw' - }; - - AUDemuxer.prototype.readChunk = function() { - var bytes, dataSize, encoding, size; - if (!this.readHeader && this.stream.available(24)) { - if (this.stream.readString(4) !== '.snd') { - return this.emit('error', 'Invalid AU file.'); - } - size = this.stream.readUInt32(); - dataSize = this.stream.readUInt32(); - encoding = this.stream.readUInt32(); - this.format = { - formatID: formats[encoding] || 'lpcm', - littleEndian: false, - floatingPoint: encoding === 6 || encoding === 7, - bitsPerChannel: bps[encoding - 1], - sampleRate: this.stream.readUInt32(), - channelsPerFrame: this.stream.readUInt32(), - framesPerPacket: 1 - }; - if (this.format.bitsPerChannel == null) { - return this.emit('error', 'Unsupported encoding in AU file.'); - } - this.format.bytesPerPacket = (this.format.bitsPerChannel / 8) * this.format.channelsPerFrame; - if (dataSize !== 0xffffffff) { - bytes = this.format.bitsPerChannel / 8; - this.emit('duration', dataSize / bytes / this.format.channelsPerFrame / this.format.sampleRate * 1000 | 0); - } - this.emit('format', this.format); - this.readHeader = true; - } - if (this.readHeader) { - while (this.stream.available(1)) { - this.emit('data', this.stream.readSingleBuffer(this.stream.remainingBytes())); - } - } - }; - - return AUDemuxer; - -})(Demuxer); - - -},{"../demuxer":15}],18:[function(_dereq_,module,exports){ -var CAFDemuxer, Demuxer, M4ADemuxer, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -Demuxer = _dereq_('../demuxer'); - -M4ADemuxer = _dereq_('./m4a'); - -CAFDemuxer = (function(_super) { - __extends(CAFDemuxer, _super); - - function CAFDemuxer() { - return CAFDemuxer.__super__.constructor.apply(this, arguments); - } - - Demuxer.register(CAFDemuxer); - - CAFDemuxer.probe = function(buffer) { - return buffer.peekString(0, 4) === 'caff'; - }; - - CAFDemuxer.prototype.readChunk = function() { - var buffer, byteOffset, cookie, entries, flags, i, key, metadata, offset, sampleOffset, value, _i, _j, _ref; - if (!this.format && this.stream.available(64)) { - if (this.stream.readString(4) !== 'caff') { - return this.emit('error', "Invalid CAF, does not begin with 'caff'"); - } - this.stream.advance(4); - if (this.stream.readString(4) !== 'desc') { - return this.emit('error', "Invalid CAF, 'caff' is not followed by 'desc'"); - } - if (!(this.stream.readUInt32() === 0 && this.stream.readUInt32() === 32)) { - return this.emit('error', "Invalid 'desc' size, should be 32"); - } - this.format = {}; - this.format.sampleRate = this.stream.readFloat64(); - this.format.formatID = this.stream.readString(4); - flags = this.stream.readUInt32(); - if (this.format.formatID === 'lpcm') { - this.format.floatingPoint = Boolean(flags & 1); - this.format.littleEndian = Boolean(flags & 2); - } - this.format.bytesPerPacket = this.stream.readUInt32(); - this.format.framesPerPacket = this.stream.readUInt32(); - this.format.channelsPerFrame = this.stream.readUInt32(); - this.format.bitsPerChannel = this.stream.readUInt32(); - this.emit('format', this.format); - } - while (this.stream.available(1)) { - if (!this.headerCache) { - this.headerCache = { - type: this.stream.readString(4), - oversize: this.stream.readUInt32() !== 0, - size: this.stream.readUInt32() - }; - if (this.headerCache.oversize) { - return this.emit('error', "Holy Shit, an oversized file, not supported in JS"); - } - } - switch (this.headerCache.type) { - case 'kuki': - if (this.stream.available(this.headerCache.size)) { - if (this.format.formatID === 'aac ') { - offset = this.stream.offset + this.headerCache.size; - if (cookie = M4ADemuxer.readEsds(this.stream)) { - this.emit('cookie', cookie); - } - this.stream.seek(offset); - } else { - buffer = this.stream.readBuffer(this.headerCache.size); - this.emit('cookie', buffer); - } - this.headerCache = null; - } - break; - case 'pakt': - if (this.stream.available(this.headerCache.size)) { - if (this.stream.readUInt32() !== 0) { - return this.emit('error', 'Sizes greater than 32 bits are not supported.'); - } - this.numPackets = this.stream.readUInt32(); - if (this.stream.readUInt32() !== 0) { - return this.emit('error', 'Sizes greater than 32 bits are not supported.'); - } - this.numFrames = this.stream.readUInt32(); - this.primingFrames = this.stream.readUInt32(); - this.remainderFrames = this.stream.readUInt32(); - this.emit('duration', this.numFrames / this.format.sampleRate * 1000 | 0); - this.sentDuration = true; - byteOffset = 0; - sampleOffset = 0; - for (i = _i = 0, _ref = this.numPackets; _i < _ref; i = _i += 1) { - this.addSeekPoint(byteOffset, sampleOffset); - byteOffset += this.format.bytesPerPacket || M4ADemuxer.readDescrLen(this.stream); - sampleOffset += this.format.framesPerPacket || M4ADemuxer.readDescrLen(this.stream); - } - this.headerCache = null; - } - break; - case 'info': - entries = this.stream.readUInt32(); - metadata = {}; - for (i = _j = 0; 0 <= entries ? _j < entries : _j > entries; i = 0 <= entries ? ++_j : --_j) { - key = this.stream.readString(null); - value = this.stream.readString(null); - metadata[key] = value; - } - this.emit('metadata', metadata); - this.headerCache = null; - break; - case 'data': - if (!this.sentFirstDataChunk) { - this.stream.advance(4); - this.headerCache.size -= 4; - if (this.format.bytesPerPacket !== 0 && !this.sentDuration) { - this.numFrames = this.headerCache.size / this.format.bytesPerPacket; - this.emit('duration', this.numFrames / this.format.sampleRate * 1000 | 0); - } - this.sentFirstDataChunk = true; - } - buffer = this.stream.readSingleBuffer(this.headerCache.size); - this.headerCache.size -= buffer.length; - this.emit('data', buffer); - if (this.headerCache.size <= 0) { - this.headerCache = null; - } - break; - default: - if (this.stream.available(this.headerCache.size)) { - this.stream.advance(this.headerCache.size); - this.headerCache = null; - } - } - } - }; - - return CAFDemuxer; - -})(Demuxer); - - -},{"../demuxer":15,"./m4a":19}],19:[function(_dereq_,module,exports){ -var Demuxer, M4ADemuxer, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - -Demuxer = _dereq_('../demuxer'); - -M4ADemuxer = (function(_super) { - var BITS_PER_CHANNEL, TYPES, after, atom, atoms, bool, containers, diskTrack, genres, meta, string; - - __extends(M4ADemuxer, _super); - - function M4ADemuxer() { - return M4ADemuxer.__super__.constructor.apply(this, arguments); - } - - Demuxer.register(M4ADemuxer); - - TYPES = ['M4A ', 'M4P ', 'M4B ', 'M4V ', 'isom', 'mp42', 'qt ']; - - M4ADemuxer.probe = function(buffer) { - var _ref; - return buffer.peekString(4, 4) === 'ftyp' && (_ref = buffer.peekString(8, 4), __indexOf.call(TYPES, _ref) >= 0); - }; - - M4ADemuxer.prototype.init = function() { - this.atoms = []; - this.offsets = []; - this.track = null; - return this.tracks = []; - }; - - atoms = {}; - - containers = {}; - - atom = function(name, fn) { - var c, container, _i, _len, _ref; - c = []; - _ref = name.split('.').slice(0, -1); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - container = _ref[_i]; - c.push(container); - containers[c.join('.')] = true; - } - if (atoms[name] == null) { - atoms[name] = {}; - } - return atoms[name].fn = fn; - }; - - after = function(name, fn) { - if (atoms[name] == null) { - atoms[name] = {}; - } - return atoms[name].after = fn; - }; - - M4ADemuxer.prototype.readChunk = function() { - var handler, path, type; - this["break"] = false; - while (this.stream.available(1) && !this["break"]) { - if (!this.readHeaders) { - if (!this.stream.available(8)) { - return; - } - this.len = this.stream.readUInt32() - 8; - this.type = this.stream.readString(4); - if (this.len === 0) { - continue; - } - this.atoms.push(this.type); - this.offsets.push(this.stream.offset + this.len); - this.readHeaders = true; - } - path = this.atoms.join('.'); - handler = atoms[path]; - if (handler != null ? handler.fn : void 0) { - if (!(this.stream.available(this.len) || path === 'mdat')) { - return; - } - handler.fn.call(this); - if (path in containers) { - this.readHeaders = false; - } - } else if (path in containers) { - this.readHeaders = false; - } else { - if (!this.stream.available(this.len)) { - return; - } - this.stream.advance(this.len); - } - while (this.stream.offset >= this.offsets[this.offsets.length - 1]) { - handler = atoms[this.atoms.join('.')]; - if (handler != null ? handler.after : void 0) { - handler.after.call(this); - } - type = this.atoms.pop(); - this.offsets.pop(); - this.readHeaders = false; - } - } - }; - - atom('ftyp', function() { - var _ref; - if (_ref = this.stream.readString(4), __indexOf.call(TYPES, _ref) < 0) { - return this.emit('error', 'Not a valid M4A file.'); - } - return this.stream.advance(this.len - 4); - }); - - atom('moov.trak', function() { - this.track = {}; - return this.tracks.push(this.track); - }); - - atom('moov.trak.tkhd', function() { - this.stream.advance(4); - this.stream.advance(8); - this.track.id = this.stream.readUInt32(); - return this.stream.advance(this.len - 16); - }); - - atom('moov.trak.mdia.hdlr', function() { - this.stream.advance(4); - this.stream.advance(4); - this.track.type = this.stream.readString(4); - this.stream.advance(12); - return this.stream.advance(this.len - 24); - }); - - atom('moov.trak.mdia.mdhd', function() { - this.stream.advance(4); - this.stream.advance(8); - this.track.timeScale = this.stream.readUInt32(); - this.track.duration = this.stream.readUInt32(); - return this.stream.advance(4); - }); - - BITS_PER_CHANNEL = { - ulaw: 8, - alaw: 8, - in24: 24, - in32: 32, - fl32: 32, - fl64: 64 - }; - - atom('moov.trak.mdia.minf.stbl.stsd', function() { - var format, numEntries, version, _ref, _ref1; - this.stream.advance(4); - numEntries = this.stream.readUInt32(); - if (this.track.type !== 'soun') { - return this.stream.advance(this.len - 8); - } - if (numEntries !== 1) { - return this.emit('error', "Only expecting one entry in sample description atom!"); - } - this.stream.advance(4); - format = this.track.format = {}; - format.formatID = this.stream.readString(4); - this.stream.advance(6); - this.stream.advance(2); - version = this.stream.readUInt16(); - this.stream.advance(6); - format.channelsPerFrame = this.stream.readUInt16(); - format.bitsPerChannel = this.stream.readUInt16(); - this.stream.advance(4); - format.sampleRate = this.stream.readUInt16(); - this.stream.advance(2); - if (version === 1) { - format.framesPerPacket = this.stream.readUInt32(); - this.stream.advance(4); - format.bytesPerFrame = this.stream.readUInt32(); - this.stream.advance(4); - } else if (version !== 0) { - this.emit('error', 'Unknown version in stsd atom'); - } - if (BITS_PER_CHANNEL[format.formatID] != null) { - format.bitsPerChannel = BITS_PER_CHANNEL[format.formatID]; - } - format.floatingPoint = (_ref = format.formatID) === 'fl32' || _ref === 'fl64'; - format.littleEndian = format.formatID === 'sowt' && format.bitsPerChannel > 8; - if ((_ref1 = format.formatID) === 'twos' || _ref1 === 'sowt' || _ref1 === 'in24' || _ref1 === 'in32' || _ref1 === 'fl32' || _ref1 === 'fl64' || _ref1 === 'raw ' || _ref1 === 'NONE') { - return format.formatID = 'lpcm'; - } - }); - - atom('moov.trak.mdia.minf.stbl.stsd.alac', function() { - this.stream.advance(4); - return this.track.cookie = this.stream.readBuffer(this.len - 4); - }); - - atom('moov.trak.mdia.minf.stbl.stsd.esds', function() { - var offset; - offset = this.stream.offset + this.len; - this.track.cookie = M4ADemuxer.readEsds(this.stream); - return this.stream.seek(offset); - }); - - atom('moov.trak.mdia.minf.stbl.stsd.wave.enda', function() { - return this.track.format.littleEndian = !!this.stream.readUInt16(); - }); - - M4ADemuxer.readDescrLen = function(stream) { - var c, count, len; - len = 0; - count = 4; - while (count--) { - c = stream.readUInt8(); - len = (len << 7) | (c & 0x7f); - if (!(c & 0x80)) { - break; - } - } - return len; - }; - - M4ADemuxer.readEsds = function(stream) { - var codec_id, flags, len, tag; - stream.advance(4); - tag = stream.readUInt8(); - len = M4ADemuxer.readDescrLen(stream); - if (tag === 0x03) { - stream.advance(2); - flags = stream.readUInt8(); - if (flags & 0x80) { - stream.advance(2); - } - if (flags & 0x40) { - stream.advance(stream.readUInt8()); - } - if (flags & 0x20) { - stream.advance(2); - } - } else { - stream.advance(2); - } - tag = stream.readUInt8(); - len = M4ADemuxer.readDescrLen(stream); - if (tag === 0x04) { - codec_id = stream.readUInt8(); - stream.advance(1); - stream.advance(3); - stream.advance(4); - stream.advance(4); - tag = stream.readUInt8(); - len = M4ADemuxer.readDescrLen(stream); - if (tag === 0x05) { - return stream.readBuffer(len); - } - } - return null; - }; - - atom('moov.trak.mdia.minf.stbl.stts', function() { - var entries, i, _i; - this.stream.advance(4); - entries = this.stream.readUInt32(); - this.track.stts = []; - for (i = _i = 0; _i < entries; i = _i += 1) { - this.track.stts[i] = { - count: this.stream.readUInt32(), - duration: this.stream.readUInt32() - }; - } - return this.setupSeekPoints(); - }); - - atom('moov.trak.mdia.minf.stbl.stsc', function() { - var entries, i, _i; - this.stream.advance(4); - entries = this.stream.readUInt32(); - this.track.stsc = []; - for (i = _i = 0; _i < entries; i = _i += 1) { - this.track.stsc[i] = { - first: this.stream.readUInt32(), - count: this.stream.readUInt32(), - id: this.stream.readUInt32() - }; - } - return this.setupSeekPoints(); - }); - - atom('moov.trak.mdia.minf.stbl.stsz', function() { - var entries, i, _i; - this.stream.advance(4); - this.track.sampleSize = this.stream.readUInt32(); - entries = this.stream.readUInt32(); - if (this.track.sampleSize === 0 && entries > 0) { - this.track.sampleSizes = []; - for (i = _i = 0; _i < entries; i = _i += 1) { - this.track.sampleSizes[i] = this.stream.readUInt32(); - } - } - return this.setupSeekPoints(); - }); - - atom('moov.trak.mdia.minf.stbl.stco', function() { - var entries, i, _i; - this.stream.advance(4); - entries = this.stream.readUInt32(); - this.track.chunkOffsets = []; - for (i = _i = 0; _i < entries; i = _i += 1) { - this.track.chunkOffsets[i] = this.stream.readUInt32(); - } - return this.setupSeekPoints(); - }); - - atom('moov.trak.tref.chap', function() { - var entries, i, _i; - entries = this.len >> 2; - this.track.chapterTracks = []; - for (i = _i = 0; _i < entries; i = _i += 1) { - this.track.chapterTracks[i] = this.stream.readUInt32(); - } - }); - - M4ADemuxer.prototype.setupSeekPoints = function() { - var i, j, offset, position, sampleIndex, size, stscIndex, sttsIndex, sttsSample, timestamp, _i, _j, _len, _ref, _ref1, _results; - if (!((this.track.chunkOffsets != null) && (this.track.stsc != null) && (this.track.sampleSize != null) && (this.track.stts != null))) { - return; - } - stscIndex = 0; - sttsIndex = 0; - sttsIndex = 0; - sttsSample = 0; - sampleIndex = 0; - offset = 0; - timestamp = 0; - this.track.seekPoints = []; - _ref = this.track.chunkOffsets; - _results = []; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - position = _ref[i]; - for (j = _j = 0, _ref1 = this.track.stsc[stscIndex].count; _j < _ref1; j = _j += 1) { - this.track.seekPoints.push({ - offset: offset, - position: position, - timestamp: timestamp - }); - size = this.track.sampleSize || this.track.sampleSizes[sampleIndex++]; - offset += size; - position += size; - timestamp += this.track.stts[sttsIndex].duration; - if (sttsIndex + 1 < this.track.stts.length && ++sttsSample === this.track.stts[sttsIndex].count) { - sttsSample = 0; - sttsIndex++; - } - } - if (stscIndex + 1 < this.track.stsc.length && i + 1 === this.track.stsc[stscIndex + 1].first) { - _results.push(stscIndex++); - } else { - _results.push(void 0); - } - } - return _results; - }; - - after('moov', function() { - var track, _i, _len, _ref; - if (this.mdatOffset != null) { - this.stream.seek(this.mdatOffset - 8); - } - _ref = this.tracks; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - track = _ref[_i]; - if (!(track.type === 'soun')) { - continue; - } - this.track = track; - break; - } - if (this.track.type !== 'soun') { - this.track = null; - return this.emit('error', 'No audio tracks in m4a file.'); - } - this.emit('format', this.track.format); - this.emit('duration', this.track.duration / this.track.timeScale * 1000 | 0); - if (this.track.cookie) { - this.emit('cookie', this.track.cookie); - } - return this.seekPoints = this.track.seekPoints; - }); - - atom('mdat', function() { - var bytes, chunkSize, length, numSamples, offset, sample, size, _i; - if (!this.startedData) { - if (this.mdatOffset == null) { - this.mdatOffset = this.stream.offset; - } - if (this.tracks.length === 0) { - bytes = Math.min(this.stream.remainingBytes(), this.len); - this.stream.advance(bytes); - this.len -= bytes; - return; - } - this.chunkIndex = 0; - this.stscIndex = 0; - this.sampleIndex = 0; - this.tailOffset = 0; - this.tailSamples = 0; - this.startedData = true; - } - if (!this.readChapters) { - this.readChapters = this.parseChapters(); - if (this["break"] = !this.readChapters) { - return; - } - this.stream.seek(this.mdatOffset); - } - offset = this.track.chunkOffsets[this.chunkIndex] + this.tailOffset; - length = 0; - if (!this.stream.available(offset - this.stream.offset)) { - this["break"] = true; - return; - } - this.stream.seek(offset); - while (this.chunkIndex < this.track.chunkOffsets.length) { - numSamples = this.track.stsc[this.stscIndex].count - this.tailSamples; - chunkSize = 0; - for (sample = _i = 0; _i < numSamples; sample = _i += 1) { - size = this.track.sampleSize || this.track.sampleSizes[this.sampleIndex]; - if (!this.stream.available(length + size)) { - break; - } - length += size; - chunkSize += size; - this.sampleIndex++; - } - if (sample < numSamples) { - this.tailOffset += chunkSize; - this.tailSamples += sample; - break; - } else { - this.chunkIndex++; - this.tailOffset = 0; - this.tailSamples = 0; - if (this.stscIndex + 1 < this.track.stsc.length && this.chunkIndex + 1 === this.track.stsc[this.stscIndex + 1].first) { - this.stscIndex++; - } - if (offset + length !== this.track.chunkOffsets[this.chunkIndex]) { - break; - } - } - } - if (length > 0) { - this.emit('data', this.stream.readBuffer(length)); - return this["break"] = this.chunkIndex === this.track.chunkOffsets.length; - } else { - return this["break"] = true; - } - }); - - M4ADemuxer.prototype.parseChapters = function() { - var bom, id, len, nextTimestamp, point, title, track, _i, _len, _ref, _ref1, _ref2, _ref3; - if (!(((_ref = this.track.chapterTracks) != null ? _ref.length : void 0) > 0)) { - return true; - } - id = this.track.chapterTracks[0]; - _ref1 = this.tracks; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - track = _ref1[_i]; - if (track.id === id) { - break; - } - } - if (track.id !== id) { - this.emit('error', 'Chapter track does not exist.'); - } - if (this.chapters == null) { - this.chapters = []; - } - while (this.chapters.length < track.seekPoints.length) { - point = track.seekPoints[this.chapters.length]; - if (!this.stream.available(point.position - this.stream.offset + 32)) { - return false; - } - this.stream.seek(point.position); - len = this.stream.readUInt16(); - title = null; - if (!this.stream.available(len)) { - return false; - } - if (len > 2) { - bom = this.stream.peekUInt16(); - if (bom === 0xfeff || bom === 0xfffe) { - title = this.stream.readString(len, 'utf16-bom'); - } - } - if (title == null) { - title = this.stream.readString(len, 'utf8'); - } - nextTimestamp = (_ref2 = (_ref3 = track.seekPoints[this.chapters.length + 1]) != null ? _ref3.timestamp : void 0) != null ? _ref2 : track.duration; - this.chapters.push({ - title: title, - timestamp: point.timestamp / track.timeScale * 1000 | 0, - duration: (nextTimestamp - point.timestamp) / track.timeScale * 1000 | 0 - }); - } - this.emit('chapters', this.chapters); - return true; - }; - - atom('moov.udta.meta', function() { - this.metadata = {}; - return this.stream.advance(4); - }); - - after('moov.udta.meta', function() { - return this.emit('metadata', this.metadata); - }); - - meta = function(field, name, fn) { - return atom("moov.udta.meta.ilst." + field + ".data", function() { - this.stream.advance(8); - this.len -= 8; - return fn.call(this, name); - }); - }; - - string = function(field) { - return this.metadata[field] = this.stream.readString(this.len, 'utf8'); - }; - - meta('©alb', 'album', string); - - meta('©arg', 'arranger', string); - - meta('©art', 'artist', string); - - meta('©ART', 'artist', string); - - meta('aART', 'albumArtist', string); - - meta('catg', 'category', string); - - meta('©com', 'composer', string); - - meta('©cpy', 'copyright', string); - - meta('cprt', 'copyright', string); - - meta('©cmt', 'comments', string); - - meta('©day', 'releaseDate', string); - - meta('desc', 'description', string); - - meta('©gen', 'genre', string); - - meta('©grp', 'grouping', string); - - meta('©isr', 'ISRC', string); - - meta('keyw', 'keywords', string); - - meta('©lab', 'recordLabel', string); - - meta('ldes', 'longDescription', string); - - meta('©lyr', 'lyrics', string); - - meta('©nam', 'title', string); - - meta('©phg', 'recordingCopyright', string); - - meta('©prd', 'producer', string); - - meta('©prf', 'performers', string); - - meta('purd', 'purchaseDate', string); - - meta('purl', 'podcastURL', string); - - meta('©swf', 'songwriter', string); - - meta('©too', 'encoder', string); - - meta('©wrt', 'composer', string); - - meta('covr', 'coverArt', function(field) { - return this.metadata[field] = this.stream.readBuffer(this.len); - }); - - genres = ["Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A Capella", "Euro-House", "Dance Hall"]; - - meta('gnre', 'genre', function(field) { - return this.metadata[field] = genres[this.stream.readUInt16() - 1]; - }); - - meta('tmpo', 'tempo', function(field) { - return this.metadata[field] = this.stream.readUInt16(); - }); - - meta('rtng', 'rating', function(field) { - var rating; - rating = this.stream.readUInt8(); - return this.metadata[field] = rating === 2 ? 'Clean' : rating !== 0 ? 'Explicit' : 'None'; - }); - - diskTrack = function(field) { - this.stream.advance(2); - this.metadata[field] = this.stream.readUInt16() + ' of ' + this.stream.readUInt16(); - return this.stream.advance(this.len - 6); - }; - - meta('disk', 'diskNumber', diskTrack); - - meta('trkn', 'trackNumber', diskTrack); - - bool = function(field) { - return this.metadata[field] = this.stream.readUInt8() === 1; - }; - - meta('cpil', 'compilation', bool); - - meta('pcst', 'podcast', bool); - - meta('pgap', 'gapless', bool); - - return M4ADemuxer; - -})(Demuxer); - -module.exports = M4ADemuxer; - - -},{"../demuxer":15}],20:[function(_dereq_,module,exports){ -var Demuxer, WAVEDemuxer, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -Demuxer = _dereq_('../demuxer'); - -WAVEDemuxer = (function(_super) { - var formats; - - __extends(WAVEDemuxer, _super); - - function WAVEDemuxer() { - return WAVEDemuxer.__super__.constructor.apply(this, arguments); - } - - Demuxer.register(WAVEDemuxer); - - WAVEDemuxer.probe = function(buffer) { - return buffer.peekString(0, 4) === 'RIFF' && buffer.peekString(8, 4) === 'WAVE'; - }; - - formats = { - 0x0001: 'lpcm', - 0x0003: 'lpcm', - 0x0006: 'alaw', - 0x0007: 'ulaw' - }; - - WAVEDemuxer.prototype.readChunk = function() { - var buffer, bytes, encoding; - if (!this.readStart && this.stream.available(12)) { - if (this.stream.readString(4) !== 'RIFF') { - return this.emit('error', 'Invalid WAV file.'); - } - this.fileSize = this.stream.readUInt32(true); - this.readStart = true; - if (this.stream.readString(4) !== 'WAVE') { - return this.emit('error', 'Invalid WAV file.'); - } - } - while (this.stream.available(1)) { - if (!this.readHeaders && this.stream.available(8)) { - this.type = this.stream.readString(4); - this.len = this.stream.readUInt32(true); - } - switch (this.type) { - case 'fmt ': - encoding = this.stream.readUInt16(true); - if (!(encoding in formats)) { - return this.emit('error', 'Unsupported format in WAV file.'); - } - this.format = { - formatID: formats[encoding], - floatingPoint: encoding === 0x0003, - littleEndian: formats[encoding] === 'lpcm', - channelsPerFrame: this.stream.readUInt16(true), - sampleRate: this.stream.readUInt32(true), - framesPerPacket: 1 - }; - this.stream.advance(4); - this.stream.advance(2); - this.format.bitsPerChannel = this.stream.readUInt16(true); - this.format.bytesPerPacket = (this.format.bitsPerChannel / 8) * this.format.channelsPerFrame; - this.emit('format', this.format); - this.stream.advance(this.len - 16); - break; - case 'data': - if (!this.sentDuration) { - bytes = this.format.bitsPerChannel / 8; - this.emit('duration', this.len / bytes / this.format.channelsPerFrame / this.format.sampleRate * 1000 | 0); - this.sentDuration = true; - } - buffer = this.stream.readSingleBuffer(this.len); - this.len -= buffer.length; - this.readHeaders = this.len > 0; - this.emit('data', buffer); - break; - default: - if (!this.stream.available(this.len)) { - return; - } - this.stream.advance(this.len); - } - if (this.type !== 'data') { - this.readHeaders = false; - } - } - }; - - return WAVEDemuxer; - -})(Demuxer); - - -},{"../demuxer":15}],21:[function(_dereq_,module,exports){ -var AudioDevice, EventEmitter, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('./core/events'); - -AudioDevice = (function(_super) { - var devices; - - __extends(AudioDevice, _super); - - function AudioDevice(sampleRate, channels) { - this.sampleRate = sampleRate; - this.channels = channels; - this.updateTime = __bind(this.updateTime, this); - this.playing = false; - this.currentTime = 0; - this._lastTime = 0; - } - - AudioDevice.prototype.start = function() { - if (this.playing) { - return; - } - this.playing = true; - if (this.device == null) { - this.device = AudioDevice.create(this.sampleRate, this.channels); - } - if (!this.device) { - throw new Error("No supported audio device found."); - } - this._lastTime = this.device.getDeviceTime(); - this._timer = setInterval(this.updateTime, 200); - return this.device.on('refill', this.refill = (function(_this) { - return function(buffer) { - return _this.emit('refill', buffer); - }; - })(this)); - }; - - AudioDevice.prototype.stop = function() { - if (!this.playing) { - return; - } - this.playing = false; - this.device.off('refill', this.refill); - return clearInterval(this._timer); - }; - - AudioDevice.prototype.destroy = function() { - this.stop(); - return this.device.destroy(); - }; - - AudioDevice.prototype.seek = function(currentTime) { - this.currentTime = currentTime; - if (this.playing) { - this._lastTime = this.device.getDeviceTime(); - } - return this.emit('timeUpdate', this.currentTime); - }; - - AudioDevice.prototype.updateTime = function() { - var time; - time = this.device.getDeviceTime(); - this.currentTime += (time - this._lastTime) / this.device.sampleRate * 1000 | 0; - this._lastTime = time; - return this.emit('timeUpdate', this.currentTime); - }; - - devices = []; - - AudioDevice.register = function(device) { - return devices.push(device); - }; - - AudioDevice.create = function(sampleRate, channels) { - var device, _i, _len; - for (_i = 0, _len = devices.length; _i < _len; _i++) { - device = devices[_i]; - if (device.supported) { - return new device(sampleRate, channels); - } - } - return null; - }; - - return AudioDevice; - -})(EventEmitter); - -module.exports = AudioDevice; - - -},{"./core/events":9}],22:[function(_dereq_,module,exports){ -var AVBuffer, AudioDevice, EventEmitter, MozillaAudioDevice, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('../core/events'); - -AudioDevice = _dereq_('../device'); - -AVBuffer = _dereq_('../core/buffer'); - -MozillaAudioDevice = (function(_super) { - var createTimer, destroyTimer; - - __extends(MozillaAudioDevice, _super); - - AudioDevice.register(MozillaAudioDevice); - - MozillaAudioDevice.supported = (typeof Audio !== "undefined" && Audio !== null) && 'mozWriteAudio' in new Audio; - - function MozillaAudioDevice(sampleRate, channels) { - this.sampleRate = sampleRate; - this.channels = channels; - this.refill = __bind(this.refill, this); - this.audio = new Audio; - this.audio.mozSetup(this.channels, this.sampleRate); - this.writePosition = 0; - this.prebufferSize = this.sampleRate / 2; - this.tail = null; - this.timer = createTimer(this.refill, 100); - } - - MozillaAudioDevice.prototype.refill = function() { - var available, buffer, currentPosition, written; - if (this.tail) { - written = this.audio.mozWriteAudio(this.tail); - this.writePosition += written; - if (this.writePosition < this.tail.length) { - this.tail = this.tail.subarray(written); - } else { - this.tail = null; - } - } - currentPosition = this.audio.mozCurrentSampleOffset(); - available = currentPosition + this.prebufferSize - this.writePosition; - if (available > 0) { - buffer = new Float32Array(available); - this.emit('refill', buffer); - written = this.audio.mozWriteAudio(buffer); - if (written < buffer.length) { - this.tail = buffer.subarray(written); - } - this.writePosition += written; - } - }; - - MozillaAudioDevice.prototype.destroy = function() { - return destroyTimer(this.timer); - }; - - MozillaAudioDevice.prototype.getDeviceTime = function() { - return this.audio.mozCurrentSampleOffset() / this.channels; - }; - - createTimer = function(fn, interval) { - var url, worker; - url = AVBuffer.makeBlobURL("setInterval(function() { postMessage('ping'); }, " + interval + ");"); - if (url == null) { - return setInterval(fn, interval); - } - worker = new Worker(url); - worker.onmessage = fn; - worker.url = url; - return worker; - }; - - destroyTimer = function(timer) { - if (timer.terminate) { - timer.terminate(); - return URL.revokeObjectURL(timer.url); - } else { - return clearInterval(timer); - } - }; - - return MozillaAudioDevice; - -})(EventEmitter); - - -},{"../core/buffer":7,"../core/events":9,"../device":21}],23:[function(_dereq_,module,exports){ -/* - * This resampler is from XAudioJS: https://github.com/grantgalitz/XAudioJS - * Planned to be replaced with src.js, eventually: https://github.com/jussi-kalliokoski/src.js - */ - -//JavaScript Audio Resampler (c) 2011 - Grant Galitz -function Resampler(fromSampleRate, toSampleRate, channels, outputBufferSize, noReturn) { - this.fromSampleRate = fromSampleRate; - this.toSampleRate = toSampleRate; - this.channels = channels | 0; - this.outputBufferSize = outputBufferSize; - this.noReturn = !!noReturn; - this.initialize(); -} - -Resampler.prototype.initialize = function () { - //Perform some checks: - if (this.fromSampleRate > 0 && this.toSampleRate > 0 && this.channels > 0) { - if (this.fromSampleRate == this.toSampleRate) { - //Setup a resampler bypass: - this.resampler = this.bypassResampler; //Resampler just returns what was passed through. - this.ratioWeight = 1; - } - else { - if (this.fromSampleRate < this.toSampleRate) { - /* - Use generic linear interpolation if upsampling, - as linear interpolation produces a gradient that we want - and works fine with two input sample points per output in this case. - */ - this.compileLinearInterpolationFunction(); - this.lastWeight = 1; - } - else { - /* - Custom resampler I wrote that doesn't skip samples - like standard linear interpolation in high downsampling. - This is more accurate than linear interpolation on downsampling. - */ - this.compileMultiTapFunction(); - this.tailExists = false; - this.lastWeight = 0; - } - this.ratioWeight = this.fromSampleRate / this.toSampleRate; - this.initializeBuffers(); - } - } - else { - throw(new Error("Invalid settings specified for the resampler.")); - } -}; - -Resampler.prototype.compileLinearInterpolationFunction = function () { - var toCompile = "var bufferLength = buffer.length;\ - var outLength = this.outputBufferSize;\ - if ((bufferLength % " + this.channels + ") == 0) {\ - if (bufferLength > 0) {\ - var ratioWeight = this.ratioWeight;\ - var weight = this.lastWeight;\ - var firstWeight = 0;\ - var secondWeight = 0;\ - var sourceOffset = 0;\ - var outputOffset = 0;\ - var outputBuffer = this.outputBuffer;\ - for (; weight < 1; weight += ratioWeight) {\ - secondWeight = weight % 1;\ - firstWeight = 1 - secondWeight;"; - for (var channel = 0; channel < this.channels; ++channel) { - toCompile += "outputBuffer[outputOffset++] = (this.lastOutput[" + channel + "] * firstWeight) + (buffer[" + channel + "] * secondWeight);"; - } - toCompile += "}\ - weight -= 1;\ - for (bufferLength -= " + this.channels + ", sourceOffset = Math.floor(weight) * " + this.channels + "; outputOffset < outLength && sourceOffset < bufferLength;) {\ - secondWeight = weight % 1;\ - firstWeight = 1 - secondWeight;"; - for (var channel = 0; channel < this.channels; ++channel) { - toCompile += "outputBuffer[outputOffset++] = (buffer[sourceOffset" + ((channel > 0) ? (" + " + channel) : "") + "] * firstWeight) + (buffer[sourceOffset + " + (this.channels + channel) + "] * secondWeight);"; - } - toCompile += "weight += ratioWeight;\ - sourceOffset = Math.floor(weight) * " + this.channels + ";\ - }"; - for (var channel = 0; channel < this.channels; ++channel) { - toCompile += "this.lastOutput[" + channel + "] = buffer[sourceOffset++];"; - } - toCompile += "this.lastWeight = weight % 1;\ - return this.bufferSlice(outputOffset);\ - }\ - else {\ - return (this.noReturn) ? 0 : [];\ - }\ - }\ - else {\ - throw(new Error(\"Buffer was of incorrect sample length.\"));\ - }"; - this.resampler = Function("buffer", toCompile); -}; - -Resampler.prototype.compileMultiTapFunction = function () { - var toCompile = "var bufferLength = buffer.length;\ - var outLength = this.outputBufferSize;\ - if ((bufferLength % " + this.channels + ") == 0) {\ - if (bufferLength > 0) {\ - var ratioWeight = this.ratioWeight;\ - var weight = 0;"; - for (var channel = 0; channel < this.channels; ++channel) { - toCompile += "var output" + channel + " = 0;" - } - toCompile += "var actualPosition = 0;\ - var amountToNext = 0;\ - var alreadyProcessedTail = !this.tailExists;\ - this.tailExists = false;\ - var outputBuffer = this.outputBuffer;\ - var outputOffset = 0;\ - var currentPosition = 0;\ - do {\ - if (alreadyProcessedTail) {\ - weight = ratioWeight;"; - for (channel = 0; channel < this.channels; ++channel) { - toCompile += "output" + channel + " = 0;" - } - toCompile += "}\ - else {\ - weight = this.lastWeight;"; - for (channel = 0; channel < this.channels; ++channel) { - toCompile += "output" + channel + " = this.lastOutput[" + channel + "];" - } - toCompile += "alreadyProcessedTail = true;\ - }\ - while (weight > 0 && actualPosition < bufferLength) {\ - amountToNext = 1 + actualPosition - currentPosition;\ - if (weight >= amountToNext) {"; - for (channel = 0; channel < this.channels; ++channel) { - toCompile += "output" + channel + " += buffer[actualPosition++] * amountToNext;" - } - toCompile += "currentPosition = actualPosition;\ - weight -= amountToNext;\ - }\ - else {"; - for (channel = 0; channel < this.channels; ++channel) { - toCompile += "output" + channel + " += buffer[actualPosition" + ((channel > 0) ? (" + " + channel) : "") + "] * weight;" - } - toCompile += "currentPosition += weight;\ - weight = 0;\ - break;\ - }\ - }\ - if (weight == 0) {"; - for (channel = 0; channel < this.channels; ++channel) { - toCompile += "outputBuffer[outputOffset++] = output" + channel + " / ratioWeight;" - } - toCompile += "}\ - else {\ - this.lastWeight = weight;"; - for (channel = 0; channel < this.channels; ++channel) { - toCompile += "this.lastOutput[" + channel + "] = output" + channel + ";" - } - toCompile += "this.tailExists = true;\ - break;\ - }\ - } while (actualPosition < bufferLength && outputOffset < outLength);\ - return this.bufferSlice(outputOffset);\ - }\ - else {\ - return (this.noReturn) ? 0 : [];\ - }\ - }\ - else {\ - throw(new Error(\"Buffer was of incorrect sample length.\"));\ - }"; - this.resampler = Function("buffer", toCompile); -}; - -Resampler.prototype.bypassResampler = function (buffer) { - if (this.noReturn) { - //Set the buffer passed as our own, as we don't need to resample it: - this.outputBuffer = buffer; - return buffer.length; - } - else { - //Just return the buffer passsed: - return buffer; - } -}; - -Resampler.prototype.bufferSlice = function (sliceAmount) { - if (this.noReturn) { - //If we're going to access the properties directly from this object: - return sliceAmount; - } - else { - //Typed array and normal array buffer section referencing: - try { - return this.outputBuffer.subarray(0, sliceAmount); - } - catch (error) { - try { - //Regular array pass: - this.outputBuffer.length = sliceAmount; - return this.outputBuffer; - } - catch (error) { - //Nightly Firefox 4 used to have the subarray function named as slice: - return this.outputBuffer.slice(0, sliceAmount); - } - } - } -}; - -Resampler.prototype.initializeBuffers = function () { - //Initialize the internal buffer: - try { - this.outputBuffer = new Float32Array(this.outputBufferSize); - this.lastOutput = new Float32Array(this.channels); - } - catch (error) { - this.outputBuffer = []; - this.lastOutput = []; - } -}; - -module.exports = Resampler; - -},{}],24:[function(_dereq_,module,exports){ -(function (global){ -var AudioDevice, EventEmitter, Resampler, WebAudioDevice, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('../core/events'); - -AudioDevice = _dereq_('../device'); - -Resampler = _dereq_('./resampler'); - -WebAudioDevice = (function(_super) { - var AudioContext, createProcessor, sharedContext; - - __extends(WebAudioDevice, _super); - - AudioDevice.register(WebAudioDevice); - - AudioContext = global.AudioContext || global.webkitAudioContext; - - WebAudioDevice.supported = AudioContext && (typeof AudioContext.prototype[createProcessor = 'createScriptProcessor'] === 'function' || typeof AudioContext.prototype[createProcessor = 'createJavaScriptNode'] === 'function'); - - sharedContext = null; - - function WebAudioDevice(sampleRate, channels) { - this.sampleRate = sampleRate; - this.channels = channels; - this.refill = __bind(this.refill, this); - this.context = sharedContext != null ? sharedContext : sharedContext = new AudioContext; - this.deviceSampleRate = this.context.sampleRate; - this.bufferSize = Math.ceil(4096 / (this.deviceSampleRate / this.sampleRate) * this.channels); - this.bufferSize += this.bufferSize % this.channels; - if (this.deviceSampleRate !== this.sampleRate) { - this.resampler = new Resampler(this.sampleRate, this.deviceSampleRate, this.channels, 4096 * this.channels); - } - this.node = this.context[createProcessor](4096, this.channels, this.channels); - this.node.onaudioprocess = this.refill; - this.node.connect(this.context.destination); - } - - WebAudioDevice.prototype.refill = function(event) { - var channelCount, channels, data, i, n, outputBuffer, _i, _j, _k, _ref; - outputBuffer = event.outputBuffer; - channelCount = outputBuffer.numberOfChannels; - channels = new Array(channelCount); - for (i = _i = 0; _i < channelCount; i = _i += 1) { - channels[i] = outputBuffer.getChannelData(i); - } - data = new Float32Array(this.bufferSize); - this.emit('refill', data); - if (this.resampler) { - data = this.resampler.resampler(data); - } - for (i = _j = 0, _ref = outputBuffer.length; _j < _ref; i = _j += 1) { - for (n = _k = 0; _k < channelCount; n = _k += 1) { - channels[n][i] = data[i * channelCount + n]; - } - } - }; - - WebAudioDevice.prototype.destroy = function() { - return this.node.disconnect(0); - }; - - WebAudioDevice.prototype.getDeviceTime = function() { - return this.context.currentTime * this.sampleRate; - }; - - return WebAudioDevice; - -})(EventEmitter); - - -}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../core/events":9,"../device":21,"./resampler":23}],25:[function(_dereq_,module,exports){ -var Filter; - -Filter = (function() { - function Filter(context, key) { - if (context && key) { - Object.defineProperty(this, 'value', { - get: function() { - return context[key]; - } - }); - } - } - - Filter.prototype.process = function(buffer) {}; - - return Filter; - -})(); - -module.exports = Filter; - - -},{}],26:[function(_dereq_,module,exports){ -var BalanceFilter, Filter, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -Filter = _dereq_('../filter'); - -BalanceFilter = (function(_super) { - __extends(BalanceFilter, _super); - - function BalanceFilter() { - return BalanceFilter.__super__.constructor.apply(this, arguments); - } - - BalanceFilter.prototype.process = function(buffer) { - var i, pan, _i, _ref; - if (this.value === 0) { - return; - } - pan = Math.max(-50, Math.min(50, this.value)); - for (i = _i = 0, _ref = buffer.length; _i < _ref; i = _i += 2) { - buffer[i] *= Math.min(1, (50 - pan) / 50); - buffer[i + 1] *= Math.min(1, (50 + pan) / 50); - } - }; - - return BalanceFilter; - -})(Filter); - -module.exports = BalanceFilter; - - -},{"../filter":25}],27:[function(_dereq_,module,exports){ -var Filter, VolumeFilter, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -Filter = _dereq_('../filter'); - -VolumeFilter = (function(_super) { - __extends(VolumeFilter, _super); - - function VolumeFilter() { - return VolumeFilter.__super__.constructor.apply(this, arguments); - } - - VolumeFilter.prototype.process = function(buffer) { - var i, vol, _i, _ref; - if (this.value >= 100) { - return; - } - vol = Math.max(0, Math.min(100, this.value)) / 100; - for (i = _i = 0, _ref = buffer.length; _i < _ref; i = _i += 1) { - buffer[i] *= vol; - } - }; - - return VolumeFilter; - -})(Filter); - -module.exports = VolumeFilter; - - -},{"../filter":25}],28:[function(_dereq_,module,exports){ -var Asset, AudioDevice, BalanceFilter, EventEmitter, Player, Queue, VolumeFilter, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('./core/events'); - -Asset = _dereq_('./asset'); - -VolumeFilter = _dereq_('./filters/volume'); - -BalanceFilter = _dereq_('./filters/balance'); - -Queue = _dereq_('./queue'); - -AudioDevice = _dereq_('./device'); - -Player = (function(_super) { - __extends(Player, _super); - - function Player(asset) { - this.asset = asset; - this.startPlaying = __bind(this.startPlaying, this); - this.playing = false; - this.buffered = 0; - this.currentTime = 0; - this.duration = 0; - this.volume = 100; - this.pan = 0; - this.metadata = {}; - this.filters = [new VolumeFilter(this, 'volume'), new BalanceFilter(this, 'pan')]; - this.asset.on('buffer', (function(_this) { - return function(buffered) { - _this.buffered = buffered; - return _this.emit('buffer', _this.buffered); - }; - })(this)); - this.asset.on('decodeStart', (function(_this) { - return function() { - _this.queue = new Queue(_this.asset); - return _this.queue.once('ready', _this.startPlaying); - }; - })(this)); - this.asset.on('format', (function(_this) { - return function(format) { - _this.format = format; - return _this.emit('format', _this.format); - }; - })(this)); - this.asset.on('metadata', (function(_this) { - return function(metadata) { - _this.metadata = metadata; - return _this.emit('metadata', _this.metadata); - }; - })(this)); - this.asset.on('duration', (function(_this) { - return function(duration) { - _this.duration = duration; - return _this.emit('duration', _this.duration); - }; - })(this)); - this.asset.on('error', (function(_this) { - return function(error) { - return _this.emit('error', error); - }; - })(this)); - } - - Player.fromURL = function(url) { - return new Player(Asset.fromURL(url)); - }; - - Player.fromFile = function(file) { - return new Player(Asset.fromFile(file)); - }; - - Player.fromBuffer = function(buffer) { - return new Player(Asset.fromBuffer(buffer)); - }; - - Player.prototype.preload = function() { - if (!this.asset) { - return; - } - this.startedPreloading = true; - return this.asset.start(false); - }; - - Player.prototype.play = function() { - var _ref; - if (this.playing) { - return; - } - if (!this.startedPreloading) { - this.preload(); - } - this.playing = true; - return (_ref = this.device) != null ? _ref.start() : void 0; - }; - - Player.prototype.pause = function() { - var _ref; - if (!this.playing) { - return; - } - this.playing = false; - return (_ref = this.device) != null ? _ref.stop() : void 0; - }; - - Player.prototype.togglePlayback = function() { - if (this.playing) { - return this.pause(); - } else { - return this.play(); - } - }; - - Player.prototype.stop = function() { - var _ref; - this.pause(); - this.asset.stop(); - return (_ref = this.device) != null ? _ref.destroy() : void 0; - }; - - Player.prototype.seek = function(timestamp) { - var _ref; - if ((_ref = this.device) != null) { - _ref.stop(); - } - this.queue.once('ready', (function(_this) { - return function() { - var _ref1, _ref2; - if ((_ref1 = _this.device) != null) { - _ref1.seek(_this.currentTime); - } - if (_this.playing) { - return (_ref2 = _this.device) != null ? _ref2.start() : void 0; - } - }; - })(this)); - timestamp = (timestamp / 1000) * this.format.sampleRate; - timestamp = this.asset.decoder.seek(timestamp); - this.currentTime = timestamp / this.format.sampleRate * 1000 | 0; - this.queue.reset(); - return this.currentTime; - }; - - Player.prototype.startPlaying = function() { - var frame, frameOffset; - frame = this.queue.read(); - frameOffset = 0; - this.device = new AudioDevice(this.format.sampleRate, this.format.channelsPerFrame); - this.device.on('timeUpdate', (function(_this) { - return function(currentTime) { - _this.currentTime = currentTime; - return _this.emit('progress', _this.currentTime); - }; - })(this)); - this.refill = (function(_this) { - return function(buffer) { - var bufferOffset, filter, i, max, _i, _j, _len, _ref; - if (!_this.playing) { - return; - } - if (!frame) { - frame = _this.queue.read(); - frameOffset = 0; - } - bufferOffset = 0; - while (frame && bufferOffset < buffer.length) { - max = Math.min(frame.length - frameOffset, buffer.length - bufferOffset); - for (i = _i = 0; _i < max; i = _i += 1) { - buffer[bufferOffset++] = frame[frameOffset++]; - } - if (frameOffset === frame.length) { - frame = _this.queue.read(); - frameOffset = 0; - } - } - _ref = _this.filters; - for (_j = 0, _len = _ref.length; _j < _len; _j++) { - filter = _ref[_j]; - filter.process(buffer); - } - if (!frame) { - if (_this.queue.ended) { - _this.currentTime = _this.duration; - _this.emit('progress', _this.currentTime); - _this.emit('end'); - _this.stop(); - } else { - _this.device.stop(); - } - } - }; - })(this); - this.device.on('refill', this.refill); - if (this.playing) { - this.device.start(); - } - return this.emit('ready'); - }; - - return Player; - -})(EventEmitter); - -module.exports = Player; - - -},{"./asset":2,"./core/events":9,"./device":21,"./filters/balance":26,"./filters/volume":27,"./queue":29}],29:[function(_dereq_,module,exports){ -var EventEmitter, Queue, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('./core/events'); - -Queue = (function(_super) { - __extends(Queue, _super); - - function Queue(asset) { - this.asset = asset; - this.write = __bind(this.write, this); - this.readyMark = 64; - this.finished = false; - this.buffering = true; - this.ended = false; - this.buffers = []; - this.asset.on('data', this.write); - this.asset.on('end', (function(_this) { - return function() { - return _this.ended = true; - }; - })(this)); - this.asset.decodePacket(); - } - - Queue.prototype.write = function(buffer) { - if (buffer) { - this.buffers.push(buffer); - } - if (this.buffering) { - if (this.buffers.length >= this.readyMark || this.ended) { - this.buffering = false; - return this.emit('ready'); - } else { - return this.asset.decodePacket(); - } - } - }; - - Queue.prototype.read = function() { - if (this.buffers.length === 0) { - return null; - } - this.asset.decodePacket(); - return this.buffers.shift(); - }; - - Queue.prototype.reset = function() { - this.buffers.length = 0; - this.buffering = true; - return this.asset.decodePacket(); - }; - - return Queue; - -})(EventEmitter); - -module.exports = Queue; - - -},{"./core/events":9}],30:[function(_dereq_,module,exports){ -var AVBuffer, EventEmitter, FileSource, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('../../core/events'); - -AVBuffer = _dereq_('../../core/buffer'); - -FileSource = (function(_super) { - __extends(FileSource, _super); - - function FileSource(file) { - this.file = file; - if (typeof FileReader === "undefined" || FileReader === null) { - return this.emit('error', 'This browser does not have FileReader support.'); - } - this.offset = 0; - this.length = this.file.size; - this.chunkSize = 1 << 20; - this.file[this.slice = 'slice'] || this.file[this.slice = 'webkitSlice'] || this.file[this.slice = 'mozSlice']; - } - - FileSource.prototype.start = function() { - if (this.reader) { - if (!this.active) { - return this.loop(); - } - } - this.reader = new FileReader; - this.active = true; - this.reader.onload = (function(_this) { - return function(e) { - var buf; - buf = new AVBuffer(new Uint8Array(e.target.result)); - _this.offset += buf.length; - _this.emit('data', buf); - _this.active = false; - if (_this.offset < _this.length) { - return _this.loop(); - } - }; - })(this); - this.reader.onloadend = (function(_this) { - return function() { - if (_this.offset === _this.length) { - _this.emit('end'); - return _this.reader = null; - } - }; - })(this); - this.reader.onerror = (function(_this) { - return function(e) { - return _this.emit('error', e); - }; - })(this); - this.reader.onprogress = (function(_this) { - return function(e) { - return _this.emit('progress', (_this.offset + e.loaded) / _this.length * 100); - }; - })(this); - return this.loop(); - }; - - FileSource.prototype.loop = function() { - var blob, endPos; - this.active = true; - endPos = Math.min(this.offset + this.chunkSize, this.length); - blob = this.file[this.slice](this.offset, endPos); - return this.reader.readAsArrayBuffer(blob); - }; - - FileSource.prototype.pause = function() { - var _ref; - this.active = false; - try { - return (_ref = this.reader) != null ? _ref.abort() : void 0; - } catch (_error) {} - }; - - FileSource.prototype.reset = function() { - this.pause(); - return this.offset = 0; - }; - - return FileSource; - -})(EventEmitter); - -module.exports = FileSource; - - -},{"../../core/buffer":7,"../../core/events":9}],31:[function(_dereq_,module,exports){ -var AVBuffer, EventEmitter, HTTPSource, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('../../core/events'); - -AVBuffer = _dereq_('../../core/buffer'); - -HTTPSource = (function(_super) { - __extends(HTTPSource, _super); - - function HTTPSource(url) { - this.url = url; - this.chunkSize = 1 << 20; - this.inflight = false; - this.reset(); - } - - HTTPSource.prototype.start = function() { - if (this.length) { - if (!this.inflight) { - return this.loop(); - } - } - this.inflight = true; - this.xhr = new XMLHttpRequest(); - this.xhr.onload = (function(_this) { - return function(event) { - _this.length = parseInt(_this.xhr.getResponseHeader("Content-Length")); - _this.inflight = false; - return _this.loop(); - }; - })(this); - this.xhr.onerror = (function(_this) { - return function(err) { - _this.pause(); - return _this.emit('error', err); - }; - })(this); - this.xhr.onabort = (function(_this) { - return function(event) { - return _this.inflight = false; - }; - })(this); - this.xhr.open("HEAD", this.url, true); - return this.xhr.send(null); - }; - - HTTPSource.prototype.loop = function() { - var endPos; - if (this.inflight || !this.length) { - return this.emit('error', 'Something is wrong in HTTPSource.loop'); - } - this.inflight = true; - this.xhr = new XMLHttpRequest(); - this.xhr.onload = (function(_this) { - return function(event) { - var buf, buffer, i, txt, _i, _ref; - if (_this.xhr.response) { - buf = new Uint8Array(_this.xhr.response); - } else { - txt = _this.xhr.responseText; - buf = new Uint8Array(txt.length); - for (i = _i = 0, _ref = txt.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - buf[i] = txt.charCodeAt(i) & 0xff; - } - } - buffer = new AVBuffer(buf); - _this.offset += buffer.length; - _this.emit('data', buffer); - if (_this.offset >= _this.length) { - _this.emit('end'); - } - _this.inflight = false; - if (!(_this.offset >= _this.length)) { - return _this.loop(); - } - }; - })(this); - this.xhr.onprogress = (function(_this) { - return function(event) { - return _this.emit('progress', (_this.offset + event.loaded) / _this.length * 100); - }; - })(this); - this.xhr.onerror = (function(_this) { - return function(err) { - _this.emit('error', err); - return _this.pause(); - }; - })(this); - this.xhr.onabort = (function(_this) { - return function(event) { - return _this.inflight = false; - }; - })(this); - this.xhr.open("GET", this.url, true); - this.xhr.responseType = "arraybuffer"; - endPos = Math.min(this.offset + this.chunkSize, this.length); - this.xhr.setRequestHeader("Range", "bytes=" + this.offset + "-" + endPos); - this.xhr.overrideMimeType('text/plain; charset=x-user-defined'); - return this.xhr.send(null); - }; - - HTTPSource.prototype.pause = function() { - var _ref; - this.inflight = false; - return (_ref = this.xhr) != null ? _ref.abort() : void 0; - }; - - HTTPSource.prototype.reset = function() { - this.pause(); - return this.offset = 0; - }; - - return HTTPSource; - -})(EventEmitter); - -module.exports = HTTPSource; - - -},{"../../core/buffer":7,"../../core/events":9}],32:[function(_dereq_,module,exports){ -(function (global){ -var AVBuffer, BufferList, BufferSource, EventEmitter, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -EventEmitter = _dereq_('../core/events'); - -BufferList = _dereq_('../core/bufferlist'); - -AVBuffer = _dereq_('../core/buffer'); - -BufferSource = (function(_super) { - var clearImmediate, setImmediate; - - __extends(BufferSource, _super); - - function BufferSource(input) { - this.loop = __bind(this.loop, this); - if (input instanceof BufferList) { - this.list = input; - } else { - this.list = new BufferList; - this.list.append(new AVBuffer(input)); - } - this.paused = true; - } - - setImmediate = global.setImmediate || function(fn) { - return global.setTimeout(fn, 0); - }; - - clearImmediate = global.clearImmediate || function(timer) { - return global.clearTimeout(timer); - }; - - BufferSource.prototype.start = function() { - this.paused = false; - return this._timer = setImmediate(this.loop); - }; - - BufferSource.prototype.loop = function() { - this.emit('progress', (this.list.numBuffers - this.list.availableBuffers + 1) / this.list.numBuffers * 100 | 0); - this.emit('data', this.list.first); - if (this.list.advance()) { - return setImmediate(this.loop); - } else { - return this.emit('end'); - } - }; - - BufferSource.prototype.pause = function() { - clearImmediate(this._timer); - return this.paused = true; - }; - - BufferSource.prototype.reset = function() { - this.pause(); - return this.list.rewind(); - }; - - return BufferSource; - -})(EventEmitter); - -module.exports = BufferSource; - - -}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../core/buffer":7,"../core/bufferlist":8,"../core/events":9}]},{},[1]) - -(1) -}); - -//# sourceMappingURL=aurora.js.map diff --git a/lorgar/lib/em/CMakeLists.txt b/lorgar/lib/em/CMakeLists.txt new file mode 100644 index 0000000..36f775e --- /dev/null +++ b/lorgar/lib/em/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 2.8.12) + +configure_file(wrapper.js wrapper.js) +configure_file(wrapper.wasm wrapper.wasm COPYONLY) diff --git a/lorgar/lib/em/wrapper.js b/lorgar/lib/em/wrapper.js new file mode 100644 index 0000000..1c75774 --- /dev/null +++ b/lorgar/lib/em/wrapper.js @@ -0,0 +1,4 @@ +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=(function(status,toThrow){throw toThrow});Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}else{return scriptDirectory+path}}if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}Module["read"]=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)};Module["setWindowTitle"]=(function(title){document.title=title})}else{}var out=Module["print"]||(typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null);var err=Module["printErr"]||(typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||out);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var asm2wasmImports={"f64-rem":(function(x,y){return x%y}),"debugger":(function(){debugger})};var functionPointers=new Array(0);var GLOBAL_BASE=1024;var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx){var endPtr=idx;while(u8Array[endPtr])++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(1){var u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|u8Array[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}}function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){++len}else if(u<=2047){len+=2}else if(u<=65535){len+=3}else if(u<=2097151){len+=4}else if(u<=67108863){len+=5}else{len+=6}}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function allocateUTF8(str){var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8Array(str,HEAP8,ret,size);return ret}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var STATIC_BASE=1024,DYNAMIC_BASE=5316240,DYNAMICTOP_PTR=73104;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}var TOTAL_STACK=5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(TOTAL_MEMORY>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="wrapper.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function mergeMemory(newBuffer){var oldBuffer=Module["buffer"];if(newBuffer.byteLength0);info.refcount--;if(info.refcount===0&&!info.rethrown){if(info.destructor){Module["dynCall_vi"](info.destructor,ptr)}delete EXCEPTIONS.infos[ptr];___cxa_free_exception(ptr)}}),clearRef:(function(ptr){if(!ptr)return;var info=EXCEPTIONS.infos[ptr];info.refcount=0})};function ___cxa_throw(ptr,type,destructor){EXCEPTIONS.infos[ptr]={ptr:ptr,adjusted:[ptr],type:type,destructor:destructor,refcount:0,caught:false,rethrown:false};EXCEPTIONS.last=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exception=1}else{__ZSt18uncaught_exceptionv.uncaught_exception++}throw ptr+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch."}function ___cxa_uncaught_exception(){return!!__ZSt18uncaught_exceptionv.uncaught_exception}function ___lock(){}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}function ___map_file(pathname,size){___setErrNo(1);return-1}var SYSCALLS={buffers:[null,[],[]],printChar:(function(stream,curr){var buffer=SYSCALLS.buffers[stream];assert(buffer);if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}}),varargs:0,get:(function(varargs){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret}),getStr:(function(){var ret=UTF8ToString(SYSCALLS.get());return ret}),get64:(function(){var low=SYSCALLS.get(),high=SYSCALLS.get();if(low>=0)assert(high===0);else assert(high===-1);return low}),getZero:(function(){assert(SYSCALLS.get()===0)})};function ___syscall140(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),offset_high=SYSCALLS.get(),offset_low=SYSCALLS.get(),result=SYSCALLS.get(),whence=SYSCALLS.get();var offset=offset_low;FS.llseek(stream,offset,whence);HEAP32[result>>2]=stream.position;if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall145(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),iov=SYSCALLS.get(),iovcnt=SYSCALLS.get();return SYSCALLS.doReadv(stream,iov,iovcnt)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall146(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.get(),iov=SYSCALLS.get(),iovcnt=SYSCALLS.get();var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];for(var j=0;j>2])}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return(new Function("body","return function "+name+"() {\n"+' "use strict";'+" return body.apply(this, arguments);\n"+"};\n"))(body)}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,(function(message){this.name=errorName;this.message=message;var stack=(new Error(message)).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}}));errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=(function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}});return errorClass}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach((function(type){typeDependencies[type]=dependentTypes}));function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i>shift])}),destructorFunction:null})}function ClassHandle_isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right}function shallowCopyInternalPointer(o){return{count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType}}function throwInstanceAlreadyDeleted(obj){function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")}function ClassHandle_clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}});clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}}function runDestructor(handle){var $$=handle.$$;if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}}function ClassHandle_delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}this.$$.count.value-=1;var toDelete=0===this.$$.count.value;if(toDelete){runDestructor(this)}if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}}function ClassHandle_isDeleted(){return!this.$$.ptr}var delayFunction=undefined;var deletionQueue=[];function flushPendingDeletes(){while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}}function ClassHandle_deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}function init_ClassHandle(){ClassHandle.prototype["isAliasOf"]=ClassHandle_isAliasOf;ClassHandle.prototype["clone"]=ClassHandle_clone;ClassHandle.prototype["delete"]=ClassHandle_delete;ClassHandle.prototype["isDeleted"]=ClassHandle_isDeleted;ClassHandle.prototype["deleteLater"]=ClassHandle_deleteLater}function ClassHandle(){}var registeredPointers={};function ensureOverloadTable(proto,methodName,humanName){if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=(function(){if(!proto[methodName].overloadTable.hasOwnProperty(arguments.length)){throwBindingError("Function '"+humanName+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+proto[methodName].overloadTable+")!")}return proto[methodName].overloadTable[arguments.length].apply(this,arguments)});proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}}function exposePublicSymbol(name,value,numArguments){if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError("Cannot register public name '"+name+"' twice")}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError("Cannot register multiple overloads of a function with the same number of arguments ("+numArguments+")!")}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}}function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}function upcastPointer(ptr,ptrClass,desiredClass){while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError("Expected null or instance of "+desiredClass.name+", got an instance of "+ptrClass.name)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr}function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,__emval_register((function(){clonedHandle["delete"]()})));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+handle.$$.ptrType.name+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function RegisteredPointer_getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr}function RegisteredPointer_destructor(ptr){if(this.rawDestructor){this.rawDestructor(ptr)}}function RegisteredPointer_deleteObject(handle){if(handle!==null){handle["delete"]()}}function downcastPointer(ptr,ptrClass,desiredClass){if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)}function getInheritedInstanceCount(){return Object.keys(registeredInstances).length}function getLiveInheritedInstances(){var rv=[];for(var k in registeredInstances){if(registeredInstances.hasOwnProperty(k)){rv.push(registeredInstances[k])}}return rv}function setDelayFunction(fn){delayFunction=fn;if(deletionQueue.length&&delayFunction){delayFunction(flushPendingDeletes)}}function init_embind(){Module["getInheritedInstanceCount"]=getInheritedInstanceCount;Module["getLiveInheritedInstances"]=getLiveInheritedInstances;Module["flushPendingDeletes"]=flushPendingDeletes;Module["setDelayFunction"]=setDelayFunction}var registeredInstances={};function getBasestPointer(class_,ptr){if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr}function getInheritedInstance(class_,ptr){ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]}function makeClassHandle(prototype,record){if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return Object.create(prototype,{$$:{value:record}})}function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr:ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}function init_RegisteredPointer(){RegisteredPointer.prototype.getPointee=RegisteredPointer_getPointee;RegisteredPointer.prototype.destructor=RegisteredPointer_destructor;RegisteredPointer.prototype["argPackAdvance"]=8;RegisteredPointer.prototype["readValueFromPointer"]=simpleReadValueFromPointer;RegisteredPointer.prototype["deleteObject"]=RegisteredPointer_deleteObject;RegisteredPointer.prototype["fromWireType"]=RegisteredPointer_fromWireType}function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var args=[];for(var i=1;i>2)+i])}return array}function __embind_register_class_constructor(rawClassType,argCount,rawArgTypesAddr,invokerSignature,invoker,rawConstructor){var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],(function(classType){classType=classType[0];var humanName="constructor "+classType.name;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError("Cannot register multiple constructors with identical number of parameters ("+(argCount-1)+") for class '"+classType.name+"'! Overload resolution is currently only performed using the parameter count, not actual type info!")}classType.registeredClass.constructor_body[argCount-1]=function unboundTypeHandler(){throwUnboundTypeError("Cannot construct "+classType.name+" due to unbound types",rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,(function(argTypes){classType.registeredClass.constructor_body[argCount-1]=function constructor_body(){if(arguments.length!==argCount-1){throwBindingError(humanName+" called with "+arguments.length+" arguments, expected "+(argCount-1))}var destructors=[];var args=new Array(argCount);args[0]=rawConstructor;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i>1])});case 2:return(function(pointer){var heap=signed?HEAP32:HEAPU32;return this["fromWireType"](heap[pointer>>2])});default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_enum(rawType,name,size,isSigned){var shift=getShiftFromSize(size);name=readLatin1String(name);function ctor(){}ctor.values={};registerType(rawType,{name:name,constructor:ctor,"fromWireType":(function(c){return this.constructor.values[c]}),"toWireType":(function(destructors,c){return c.value}),"argPackAdvance":8,"readValueFromPointer":enumReadValueFromPointer(name,shift,isSigned),destructorFunction:null});exposePublicSymbol(name,ctor)}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __embind_register_enum_value(rawEnumType,name,enumValue){var enumType=requireRegisteredType(rawEnumType,"enum");name=readLatin1String(name);var Enum=enumType.constructor;var Value=Object.create(enumType.constructor.prototype,{value:{value:enumValue},constructor:{value:createNamedFunction(enumType.name+"_"+name,(function(){}))}});Enum.values[enumValue]=Value;Enum[name]=Value}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return(function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])});case 3:return(function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])});default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":(function(value){return value}),"toWireType":(function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value}),"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn){var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,(function(){throwUnboundTypeError("Cannot call "+name+" due to unbound types",argTypes)}),argCount-1);whenDependentTypesAreResolved([],argTypes,(function(argTypes){var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn),argCount-1);return[]}))}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=(function(value){return value});if(minRange===0){var bitshift=32-8*size;fromWireType=(function(value){return value<>>bitshift})}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":(function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(valuemaxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0}),"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap["buffer"],data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":(function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var endChar=HEAPU8[value+4+length];var endCharSwap=0;if(endChar!=0){endCharSwap=endChar;HEAPU8[value+4+length]=0}var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0){var stringSegment=UTF8ToString(decodeStartPtr);if(str===undefined)str=stringSegment;else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}if(endCharSwap!=0)HEAPU8[value+4+length]=endCharSwap}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i>2];var a=new Array(length);var start=value+4>>shift;for(var i=0;i>2]=length;var start=ptr+4>>shift;for(var i=0;i>2]=rd;return returnType["toWireType"](destructors,handle)}function __emval_allocateDestructors(destructorsRef){var destructors=[];HEAP32[destructorsRef>>2]=__emval_register(destructors);return destructors}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}else{return symbol}}var emval_methodCallers=[];function __emval_call_method(caller,handle,methodName,destructorsRef,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);return caller(handle,methodName,__emval_allocateDestructors(destructorsRef),args)}function __emval_call_void_method(caller,handle,methodName,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)}function emval_get_global(){return(function(){return Function})()("return this")()}function __emval_get_global(name){if(name===0){return __emval_register(emval_get_global())}else{name=getStringOrSymbol(name);return __emval_register(emval_get_global()[name])}}function __emval_addMethodCaller(caller){var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id}function __emval_lookupTypes(argCount,argTypes,argWireTypes){var a=new Array(argCount);for(var i=0;i>2)+i],"parameter "+i)}return a}function __emval_get_method_caller(argCount,argTypes){var types=__emval_lookupTypes(argCount,argTypes);var retType=types[0];var signatureName=retType.name+"_$"+types.slice(1).map((function(t){return t.name})).join("_")+"$";var params=["retType"];var args=[retType];var argsList="";for(var i=0;i4){emval_handle_array[handle].refcount+=1}}function craftEmvalAllocator(argCount){var argsList="";for(var i=0;i> 2) + "+i+'], "parameter '+i+'");\n'+"var arg"+i+" = argType"+i+".readValueFromPointer(args);\n"+"args += argType"+i+"['argPackAdvance'];\n"}functionBody+="var obj = new constructor("+argsList+");\n"+"return __emval_register(obj);\n"+"}\n";return(new Function("requireRegisteredType","Module","__emval_register",functionBody))(requireRegisteredType,Module,__emval_register)}var emval_newers={};function __emval_new(handle,argCount,argTypes,args){handle=requireHandle(handle);var newer=emval_newers[argCount];if(!newer){newer=craftEmvalAllocator(argCount);emval_newers[argCount]=newer}return newer(handle,argTypes,args)}function __emval_new_cstring(v){return __emval_register(getStringOrSymbol(v))}function __emval_run_destructors(handle){var destructors=emval_handle_array[handle].value;runDestructors(destructors);__emval_decref(handle)}function __emval_set_property(handle,key,value){handle=requireHandle(handle);key=requireHandle(key);value=requireHandle(value);handle[key]=value}function __emval_take_value(type,argv){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](argv);return __emval_register(v)}function _abort(){Module["abort"]()}function _emscripten_get_heap_size(){return TOTAL_MEMORY}function _emscripten_resize_heap(requestedSize){abortOnCannotGrowMemory()}var ENV={};function _getenv(name){if(name===0)return 0;name=UTF8ToString(name);if(!ENV.hasOwnProperty(name))return 0;if(_getenv.ret)_free(_getenv.ret);_getenv.ret=allocateUTF8(ENV[name]);return _getenv.ret}function _llvm_stackrestore(p){var self=_llvm_stacksave;var ret=self.LLVM_SAVEDSTACKS[p];self.LLVM_SAVEDSTACKS.splice(p,1);stackRestore(ret)}function _llvm_stacksave(){var self=_llvm_stacksave;if(!self.LLVM_SAVEDSTACKS){self.LLVM_SAVEDSTACKS=[]}self.LLVM_SAVEDSTACKS.push(stackSave());return self.LLVM_SAVEDSTACKS.length-1}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}function _pthread_cond_wait(){return 0}var PTHREAD_SPECIFIC={};function _pthread_getspecific(key){return PTHREAD_SPECIFIC[key]||0}var PTHREAD_SPECIFIC_NEXT_KEY=1;var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};function _pthread_key_create(key,destructor){if(key==0){return ERRNO_CODES.EINVAL}HEAP32[key>>2]=PTHREAD_SPECIFIC_NEXT_KEY;PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY]=0;PTHREAD_SPECIFIC_NEXT_KEY++;return 0}function _pthread_once(ptr,func){if(!_pthread_once.seen)_pthread_once.seen={};if(ptr in _pthread_once.seen)return;Module["dynCall_v"](func);_pthread_once.seen[ptr]=1}function _pthread_setspecific(key,value){if(!(key in PTHREAD_SPECIFIC)){return ERRNO_CODES.EINVAL}PTHREAD_SPECIFIC[key]=value;return 0}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]);return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":(function(date){return WEEKDAYS[date.tm_wday].substring(0,3)}),"%A":(function(date){return WEEKDAYS[date.tm_wday]}),"%b":(function(date){return MONTHS[date.tm_mon].substring(0,3)}),"%B":(function(date){return MONTHS[date.tm_mon]}),"%C":(function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)}),"%d":(function(date){return leadingNulls(date.tm_mday,2)}),"%e":(function(date){return leadingSomething(date.tm_mday,2," ")}),"%g":(function(date){return getWeekBasedYear(date).toString().substring(2)}),"%G":(function(date){return getWeekBasedYear(date)}),"%H":(function(date){return leadingNulls(date.tm_hour,2)}),"%I":(function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)}),"%j":(function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)}),"%m":(function(date){return leadingNulls(date.tm_mon+1,2)}),"%M":(function(date){return leadingNulls(date.tm_min,2)}),"%n":(function(){return"\n"}),"%p":(function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}}),"%S":(function(date){return leadingNulls(date.tm_sec,2)}),"%t":(function(){return"\t"}),"%u":(function(date){var day=new Date(date.tm_year+1900,date.tm_mon+1,date.tm_mday,0,0,0,0);return day.getDay()||7}),"%U":(function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"}),"%V":(function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)}),"%Z":(function(date){return date.tm_zone}),"%%":(function(){return"%"})};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}InternalError=Module["InternalError"]=extendError(Error,"InternalError");embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");init_ClassHandle();init_RegisteredPointer();init_embind();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["wasmTableSize"]=736;Module["wasmMaxTableSize"]=736;var asmGlobalArg={};Module.asmLibraryArg={"d":abort,"ga":abortOnCannotGrowMemory,"u":___assert_fail,"D":___cxa_allocate_exception,"A":___cxa_throw,"Q":___cxa_uncaught_exception,"x":___lock,"I":___map_file,"w":___setErrNo,"H":___syscall140,"fa":___syscall145,"G":___syscall146,"ea":___syscall54,"da":___syscall6,"ca":___syscall91,"v":___unlock,"ba":__embind_finalize_value_object,"aa":__embind_register_bool,"h":__embind_register_class,"m":__embind_register_class_constructor,"f":__embind_register_class_function,"c":__embind_register_class_property,"$":__embind_register_emval,"r":__embind_register_enum,"q":__embind_register_enum_value,"F":__embind_register_float,"l":__embind_register_function,"i":__embind_register_integer,"g":__embind_register_memory_view,"E":__embind_register_std_string,"_":__embind_register_std_wstring,"Z":__embind_register_value_object,"C":__embind_register_value_object_field,"Y":__embind_register_void,"t":__emval_as,"B":__emval_call_method,"X":__emval_call_void_method,"e":__emval_decref,"W":__emval_get_global,"s":__emval_get_method_caller,"z":__emval_get_property,"y":__emval_incref,"V":__emval_new,"U":__emval_new_cstring,"o":__emval_run_destructors,"T":__emval_set_property,"n":__emval_take_value,"b":_abort,"S":_emscripten_get_heap_size,"R":_emscripten_memcpy_big,"P":_emscripten_resize_heap,"p":_getenv,"k":_llvm_stackrestore,"j":_llvm_stacksave,"O":_pthread_cond_wait,"N":_pthread_getspecific,"M":_pthread_key_create,"L":_pthread_once,"K":_pthread_setspecific,"J":_strftime_l,"a":DYNAMICTOP_PTR};var asm=Module["asm"](asmGlobalArg,Module.asmLibraryArg,buffer);Module["asm"]=asm;var __GLOBAL__sub_I_bind_cpp=Module["__GLOBAL__sub_I_bind_cpp"]=(function(){return Module["asm"]["ha"].apply(null,arguments)});var __GLOBAL__sub_I_iostream_cpp=Module["__GLOBAL__sub_I_iostream_cpp"]=(function(){return Module["asm"]["ia"].apply(null,arguments)});var __GLOBAL__sub_I_wrapper_cpp=Module["__GLOBAL__sub_I_wrapper_cpp"]=(function(){return Module["asm"]["ja"].apply(null,arguments)});var __ZSt18uncaught_exceptionv=Module["__ZSt18uncaught_exceptionv"]=(function(){return Module["asm"]["ka"].apply(null,arguments)});var ___getTypeName=Module["___getTypeName"]=(function(){return Module["asm"]["la"].apply(null,arguments)});var _free=Module["_free"]=(function(){return Module["asm"]["ma"].apply(null,arguments)});var _malloc=Module["_malloc"]=(function(){return Module["asm"]["na"].apply(null,arguments)});var stackRestore=Module["stackRestore"]=(function(){return Module["asm"]["Ia"].apply(null,arguments)});var stackSave=Module["stackSave"]=(function(){return Module["asm"]["Ja"].apply(null,arguments)});var dynCall_i=Module["dynCall_i"]=(function(){return Module["asm"]["oa"].apply(null,arguments)});var dynCall_ii=Module["dynCall_ii"]=(function(){return Module["asm"]["pa"].apply(null,arguments)});var dynCall_iii=Module["dynCall_iii"]=(function(){return Module["asm"]["qa"].apply(null,arguments)});var dynCall_iiii=Module["dynCall_iiii"]=(function(){return Module["asm"]["ra"].apply(null,arguments)});var dynCall_iiiii=Module["dynCall_iiiii"]=(function(){return Module["asm"]["sa"].apply(null,arguments)});var dynCall_iiiiid=Module["dynCall_iiiiid"]=(function(){return Module["asm"]["ta"].apply(null,arguments)});var dynCall_iiiiii=Module["dynCall_iiiiii"]=(function(){return Module["asm"]["ua"].apply(null,arguments)});var dynCall_iiiiiid=Module["dynCall_iiiiiid"]=(function(){return Module["asm"]["va"].apply(null,arguments)});var dynCall_iiiiiii=Module["dynCall_iiiiiii"]=(function(){return Module["asm"]["wa"].apply(null,arguments)});var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=(function(){return Module["asm"]["xa"].apply(null,arguments)});var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=(function(){return Module["asm"]["ya"].apply(null,arguments)});var dynCall_iiiiij=Module["dynCall_iiiiij"]=(function(){return Module["asm"]["za"].apply(null,arguments)});var dynCall_v=Module["dynCall_v"]=(function(){return Module["asm"]["Aa"].apply(null,arguments)});var dynCall_vi=Module["dynCall_vi"]=(function(){return Module["asm"]["Ba"].apply(null,arguments)});var dynCall_vii=Module["dynCall_vii"]=(function(){return Module["asm"]["Ca"].apply(null,arguments)});var dynCall_viii=Module["dynCall_viii"]=(function(){return Module["asm"]["Da"].apply(null,arguments)});var dynCall_viiii=Module["dynCall_viiii"]=(function(){return Module["asm"]["Ea"].apply(null,arguments)});var dynCall_viiiii=Module["dynCall_viiiii"]=(function(){return Module["asm"]["Fa"].apply(null,arguments)});var dynCall_viiiiii=Module["dynCall_viiiiii"]=(function(){return Module["asm"]["Ga"].apply(null,arguments)});var dynCall_viijii=Module["dynCall_viijii"]=(function(){return Module["asm"]["Ha"].apply(null,arguments)});Module["asm"]=asm;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=run;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){out(what);err(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run() + + + diff --git a/lorgar/lib/em/wrapper.wasm b/lorgar/lib/em/wrapper.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a80529cf3ae15835b4d4f8fe2c355e668ee6e245 GIT binary patch literal 256902 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
Ht9_H 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�nCCM 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 E0Tc)@DF6Tf literal 0 HcmV?d00001 diff --git a/lorgar/lib/mp3/CMakeLists.txt b/lorgar/lib/mp3/CMakeLists.txt deleted file mode 100644 index 19576d4..0000000 --- a/lorgar/lib/mp3/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -cmake_minimum_required(VERSION 2.8.12) - -configure_file(mp3.js mp3.js) diff --git a/lorgar/lib/mp3/mp3.js b/lorgar/lib/mp3/mp3.js deleted file mode 100644 index 8631e7d..0000000 --- a/lorgar/lib/mp3/mp3.js +++ /dev/null @@ -1,7706 +0,0 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { - timestamp = this._super(timestamp); - offset = this.stream.offset; - } else { - offset = timestamp * this.format.bitrate / 8 / this.format.sampleRate; - } - - this.mp3_stream.reset(offset); - - // try to find 3 consecutive valid frame headers in a row - for (var i = 0; i < 4096; i++) { - var pos = offset + i; - for (var j = 0; j < 3; j++) { - this.mp3_stream.reset(pos); - - try { - var header = MP3FrameHeader.decode(this.mp3_stream); - } catch (e) { - break; - } - - // skip the rest of the frame - var size = header.framesize(); - if (size == null) - break; - - pos += size; - } - - // check if we're done - if (j === 3) - break; - } - - // if we didn't find 3 frames, just try the first one and hope for the best - if (j !== 3) - i = 0; - - this.mp3_stream.reset(offset + i); - - // if we guesstimated, update the timestamp to another estimate of where we actually seeked to - if (this.demuxer.seekPoints.length === 0) - timestamp = this.stream.offset / (this.format.bitrate / 8) * this.format.sampleRate; - - this.seeking = true; - return timestamp; - }; -}); - -module.exports = MP3Decoder; - -},{"./frame":4,"./header":5,"./layer1":9,"./layer2":10,"./layer3":11,"./stream":12,"./synth":13}],3:[function(require,module,exports){ -var AV = (window.AV); -var ID3v23Stream = require('./id3').ID3v23Stream; -var ID3v22Stream = require('./id3').ID3v22Stream; -var MP3FrameHeader = require('./header'); -var MP3Stream = require('./stream'); - -var MP3Demuxer = AV.Demuxer.extend(function() { - AV.Demuxer.register(this); - - this.probe = function(stream) { - var off = stream.offset; - - // skip id3 metadata if it exists - var id3header = MP3Demuxer.getID3v2Header(stream); - if (id3header) - stream.advance(10 + id3header.length); - - // attempt to read the header of the first audio frame - var s = new MP3Stream(new AV.Bitstream(stream)); - var header = null; - - try { - header = MP3FrameHeader.decode(s); - } catch (e) {}; - - // go back to the beginning, for other probes - stream.seek(off); - - return !!header; - }; - - this.getID3v2Header = function(stream) { - if (stream.peekString(0, 3) == 'ID3') { - stream = AV.Stream.fromBuffer(stream.peekBuffer(0, 10)); - stream.advance(3); // 'ID3' - - var major = stream.readUInt8(); - var minor = stream.readUInt8(); - var flags = stream.readUInt8(); - var bytes = stream.readBuffer(4).data; - var length = (bytes[0] << 21) | (bytes[1] << 14) | (bytes[2] << 7) | bytes[3]; - - return { - version: '2.' + major + '.' + minor, - major: major, - minor: minor, - flags: flags, - length: length - }; - } - - return null; - }; - - const XING_OFFSETS = [[32, 17], [17, 9]]; - this.prototype.parseDuration = function(header) { - var stream = this.stream; - var frames; - - var offset = stream.offset; - if (!header || header.layer !== 3) - return false; - - // Check for Xing/Info tag - stream.advance(XING_OFFSETS[header.flags & MP3FrameHeader.FLAGS.LSF_EXT ? 1 : 0][header.nchannels() === 1 ? 1 : 0]); - var tag = stream.readString(4); - if (tag === 'Xing' || tag === 'Info') { - var flags = stream.readUInt32(); - if (flags & 1) - frames = stream.readUInt32(); - - if (flags & 2) - var size = stream.readUInt32(); - - if (flags & 4 && frames && size) { - for (var i = 0; i < 100; i++) { - var b = stream.readUInt8(); - var pos = b / 256 * size | 0; - var time = i / 100 * (frames * header.nbsamples() * 32) | 0; - this.addSeekPoint(pos, time); - } - } - - if (flags & 8) - stream.advance(4); - - } else { - // Check for VBRI tag (always 32 bytes after end of mpegaudio header) - stream.seek(offset + 4 + 32); - tag = stream.readString(4); - if (tag == 'VBRI' && stream.readUInt16() === 1) { // Check tag version - stream.advance(4); // skip delay and quality - stream.advance(4); // skip size - frames = stream.readUInt32(); - - var entries = stream.readUInt16(); - var scale = stream.readUInt16(); - var bytesPerEntry = stream.readUInt16(); - var framesPerEntry = stream.readUInt16(); - var fn = 'readUInt' + (bytesPerEntry * 8); - - var pos = 0; - for (var i = 0; i < entries; i++) { - this.addSeekPoint(pos, framesPerEntry * i); - pos += stream[fn](); - } - } - } - - if (!frames) - return false; - - this.emit('duration', (frames * header.nbsamples() * 32) / header.samplerate * 1000 | 0); - return true; - }; - - this.prototype.readChunk = function() { - var stream = this.stream; - - if (!this.sentInfo) { - // read id3 metadata if it exists - var id3header = MP3Demuxer.getID3v2Header(stream); - if (id3header) { - stream.advance(10); - - if (id3header.major > 2) { - var id3 = new ID3v23Stream(id3header, stream); - } else { - var id3 = new ID3v22Stream(id3header, stream); - } - - this.emit('metadata', id3.read()); - } - - // read the header of the first audio frame - var off = stream.offset; - var s = new MP3Stream(new AV.Bitstream(stream)); - - var header = MP3FrameHeader.decode(s); - if (!header) - return this.emit('error', 'Could not find first frame.'); - - this.emit('format', { - formatID: 'mp3', - sampleRate: header.samplerate, - channelsPerFrame: header.nchannels(), - bitrate: header.bitrate, - floatingPoint: true - }); - - var sentDuration = this.parseDuration(header); - stream.advance(off - stream.offset); - - // if there were no Xing/VBRI tags, guesstimate the duration based on data size and bitrate - this.dataSize = 0; - if (!sentDuration) { - this.on('end', function() { - this.emit('duration', this.dataSize * 8 / header.bitrate * 1000 | 0); - }); - } - - this.sentInfo = true; - } - - while (stream.available(1)) { - var buffer = stream.readSingleBuffer(stream.remainingBytes()); - this.dataSize += buffer.length; - this.emit('data', buffer); - } - }; -}); - -module.exports = MP3Demuxer; - -},{"./header":5,"./id3":7,"./stream":12}],4:[function(require,module,exports){ -var MP3FrameHeader = require('./header'); -var utils = require('./utils'); - -function MP3Frame() { - this.header = null; // MPEG audio header - this.options = 0; // decoding options (from stream) - this.sbsample = utils.makeArray([2, 36, 32]); // synthesis subband filter samples - this.overlap = utils.makeArray([2, 32, 18]); // Layer III block overlap data - this.decoders = []; -} - -// included layer decoders are registered here -MP3Frame.layers = []; - -MP3Frame.prototype.decode = function(stream) { - if (!this.header || !(this.header.flags & MP3FrameHeader.FLAGS.INCOMPLETE)) - this.header = MP3FrameHeader.decode(stream); - - this.header.flags &= ~MP3FrameHeader.FLAGS.INCOMPLETE; - - // make an instance of the decoder for this layer if needed - var decoder = this.decoders[this.header.layer - 1]; - if (!decoder) { - var Layer = MP3Frame.layers[this.header.layer]; - if (!Layer) - throw new Error("Layer " + this.header.layer + " is not supported."); - - decoder = this.decoders[this.header.layer - 1] = new Layer(); - } - - decoder.decode(stream, this); -}; - -module.exports = MP3Frame; - -},{"./header":5,"./utils":15}],5:[function(require,module,exports){ -var AV = (window.AV); - -function MP3FrameHeader() { - this.layer = 0; // audio layer (1, 2, or 3) - this.mode = 0; // channel mode (see above) - this.mode_extension = 0; // additional mode info - this.emphasis = 0; // de-emphasis to use (see above) - - this.bitrate = 0; // stream bitrate (bps) - this.samplerate = 0; // sampling frequency (Hz) - - this.crc_check = 0; // frame CRC accumulator - this.crc_target = 0; // final target CRC checksum - - this.flags = 0; // flags (see above) - this.private_bits = 0; // private bits -} - -const BITRATES = [ - // MPEG-1 - [ 0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, // Layer I - 256000, 288000, 320000, 352000, 384000, 416000, 448000 ], - [ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, // Layer II - 128000, 160000, 192000, 224000, 256000, 320000, 384000 ], - [ 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, // Layer III - 112000, 128000, 160000, 192000, 224000, 256000, 320000 ], - - // MPEG-2 LSF - [ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, // Layer I - 128000, 144000, 160000, 176000, 192000, 224000, 256000 ], - [ 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, // Layers - 64000, 80000, 96000, 112000, 128000, 144000, 160000 ] // II & III -]; - -const SAMPLERATES = [ - 44100, 48000, 32000 -]; - -MP3FrameHeader.FLAGS = { - NPRIVATE_III: 0x0007, // number of Layer III private bits - INCOMPLETE : 0x0008, // header but not data is decoded - - PROTECTION : 0x0010, // frame has CRC protection - COPYRIGHT : 0x0020, // frame is copyright - ORIGINAL : 0x0040, // frame is original (else copy) - PADDING : 0x0080, // frame has additional slot - - I_STEREO : 0x0100, // uses intensity joint stereo - MS_STEREO : 0x0200, // uses middle/side joint stereo - FREEFORMAT : 0x0400, // uses free format bitrate - - LSF_EXT : 0x1000, // lower sampling freq. extension - MC_EXT : 0x2000, // multichannel audio extension - MPEG_2_5_EXT: 0x4000 // MPEG 2.5 (unofficial) extension -}; - -const PRIVATE = { - HEADER : 0x0100, // header private bit - III : 0x001f // Layer III private bits (up to 5) -}; - -MP3FrameHeader.MODE = { - SINGLE_CHANNEL: 0, // single channel - DUAL_CHANNEL : 1, // dual channel - JOINT_STEREO : 2, // joint (MS/intensity) stereo - STEREO : 3 // normal LR stereo -}; - -const EMPHASIS = { - NONE : 0, // no emphasis - _50_15_US : 1, // 50/15 microseconds emphasis - CCITT_J_17: 3, // CCITT J.17 emphasis - RESERVED : 2 // unknown emphasis -}; - -MP3FrameHeader.BUFFER_GUARD = 8; -MP3FrameHeader.BUFFER_MDLEN = (511 + 2048 + MP3FrameHeader.BUFFER_GUARD); - -MP3FrameHeader.prototype.copy = function() { - var clone = new MP3FrameHeader(); - var keys = Object.keys(this); - - for (var key in keys) { - clone[key] = this[key]; - } - - return clone; -} - -MP3FrameHeader.prototype.nchannels = function () { - return this.mode === 0 ? 1 : 2; -}; - -MP3FrameHeader.prototype.nbsamples = function() { - return (this.layer === 1 ? 12 : ((this.layer === 3 && (this.flags & MP3FrameHeader.FLAGS.LSF_EXT)) ? 18 : 36)); -}; - -MP3FrameHeader.prototype.framesize = function() { - if (this.bitrate === 0) - return null; - - var padding = (this.flags & MP3FrameHeader.FLAGS.PADDING ? 1 : 0); - switch (this.layer) { - case 1: - var size = (this.bitrate * 12) / this.samplerate | 0; - return (size + padding) * 4; - - case 2: - var size = (this.bitrate * 144) / this.samplerate | 0; - return size + padding; - - case 3: - default: - var lsf = this.flags & MP3FrameHeader.FLAGS.LSF_EXT ? 1 : 0; - var size = (this.bitrate * 144) / (this.samplerate << lsf) | 0; - return size + padding; - } -}; - -MP3FrameHeader.prototype.decode = function(stream) { - this.flags = 0; - this.private_bits = 0; - - // syncword - stream.advance(11); - - // MPEG 2.5 indicator (really part of syncword) - if (stream.read(1) === 0) - this.flags |= MP3FrameHeader.FLAGS.MPEG_2_5_EXT; - - // ID - if (stream.read(1) === 0) { - this.flags |= MP3FrameHeader.FLAGS.LSF_EXT; - } else if (this.flags & MP3FrameHeader.FLAGS.MPEG_2_5_EXT) { - throw new AV.UnderflowError(); // LOSTSYNC - } - - // layer - this.layer = 4 - stream.read(2); - - if (this.layer === 4) - throw new Error('Invalid layer'); - - // protection_bit - if (stream.read(1) === 0) - this.flags |= MP3FrameHeader.FLAGS.PROTECTION; - - // bitrate_index - var index = stream.read(4); - if (index === 15) - throw new Error('Invalid bitrate'); - - if (this.flags & MP3FrameHeader.FLAGS.LSF_EXT) { - this.bitrate = BITRATES[3 + (this.layer >> 1)][index]; - } else { - this.bitrate = BITRATES[this.layer - 1][index]; - } - - // sampling_frequency - index = stream.read(2); - if (index === 3) - throw new Error('Invalid sampling frequency'); - - this.samplerate = SAMPLERATES[index]; - - if (this.flags & MP3FrameHeader.FLAGS.LSF_EXT) { - this.samplerate /= 2; - - if (this.flags & MP3FrameHeader.FLAGS.MPEG_2_5_EXT) - this.samplerate /= 2; - } - - // padding_bit - if (stream.read(1)) - this.flags |= MP3FrameHeader.FLAGS.PADDING; - - // private_bit - if (stream.read(1)) - this.private_bits |= PRIVATE.HEADER; - - // mode - this.mode = 3 - stream.read(2); - - // mode_extension - this.mode_extension = stream.read(2); - - // copyright - if (stream.read(1)) - this.flags |= MP3FrameHeader.FLAGS.COPYRIGHT; - - // original/copy - if (stream.read(1)) - this.flags |= MP3FrameHeader.FLAGS.ORIGINAL; - - // emphasis - this.emphasis = stream.read(2); - - // crc_check - if (this.flags & MP3FrameHeader.FLAGS.PROTECTION) - this.crc_target = stream.read(16); -}; - -MP3FrameHeader.decode = function(stream) { - // synchronize - var ptr = stream.next_frame; - var syncing = true; - var header = null; - - while (syncing) { - syncing = false; - - if (stream.sync) { - if (!stream.available(MP3FrameHeader.BUFFER_GUARD)) { - stream.next_frame = ptr; - throw new AV.UnderflowError(); - } else if (!(stream.getU8(ptr) === 0xff && (stream.getU8(ptr + 1) & 0xe0) === 0xe0)) { - // mark point where frame sync word was expected - stream.this_frame = ptr; - stream.next_frame = ptr + 1; - throw new AV.UnderflowError(); // LOSTSYNC - } - } else { - stream.seek(ptr * 8); - if (!stream.doSync()) - throw new AV.UnderflowError(); - - ptr = stream.nextByte(); - } - - // begin processing - stream.this_frame = ptr; - stream.next_frame = ptr + 1; // possibly bogus sync word - - stream.seek(stream.this_frame * 8); - - header = new MP3FrameHeader(); - header.decode(stream); - - if (header.bitrate === 0) { - if (stream.freerate === 0 || !stream.sync || (header.layer === 3 && stream.freerate > 640000)) - MP3FrameHeader.free_bitrate(stream, header); - - header.bitrate = stream.freerate; - header.flags |= MP3FrameHeader.FLAGS.FREEFORMAT; - } - - // calculate beginning of next frame - var pad_slot = (header.flags & MP3FrameHeader.FLAGS.PADDING) ? 1 : 0; - - if (header.layer === 1) { - var N = (((12 * header.bitrate / header.samplerate) << 0) + pad_slot) * 4; - } else { - var slots_per_frame = (header.layer === 3 && (header.flags & MP3FrameHeader.FLAGS.LSF_EXT)) ? 72 : 144; - var N = ((slots_per_frame * header.bitrate / header.samplerate) << 0) + pad_slot; - } - - // verify there is enough data left in buffer to decode this frame - if (!stream.available(N + MP3FrameHeader.BUFFER_GUARD)) { - stream.next_frame = stream.this_frame; - throw new AV.UnderflowError(); - } - - stream.next_frame = stream.this_frame + N; - - if (!stream.sync) { - // check that a valid frame header follows this frame - ptr = stream.next_frame; - - if (!(stream.getU8(ptr) === 0xff && (stream.getU8(ptr + 1) & 0xe0) === 0xe0)) { - ptr = stream.next_frame = stream.this_frame + 1; - - // emulating 'goto sync' - syncing = true; - continue; - } - - stream.sync = true; - } - } - - header.flags |= MP3FrameHeader.FLAGS.INCOMPLETE; - return header; -}; - -MP3FrameHeader.free_bitrate = function(stream, header) { - var pad_slot = header.flags & MP3FrameHeader.FLAGS.PADDING ? 1 : 0, - slots_per_frame = header.layer === 3 && header.flags & MP3FrameHeader.FLAGS.LSF_EXT ? 72 : 144; - - var start = stream.offset(); - var rate = 0; - - while (stream.doSync()) { - var peek_header = header.copy(); - var peek_stream = stream.copy(); - - if (peek_header.decode(peek_stream) && peek_header.layer === header.layer && peek_header.samplerate === header.samplerate) { - var N = stream.nextByte() - stream.this_frame; - - if (header.layer === 1) { - rate = header.samplerate * (N - 4 * pad_slot + 4) / 48 / 1000 | 0; - } else { - rate = header.samplerate * (N - pad_slot + 1) / slots_per_frame / 1000 | 0; - } - - if (rate >= 8) - break; - } - - stream.advance(8); - } - - stream.seek(start); - - if (rate < 8 || (header.layer === 3 && rate > 640)) - throw new AV.UnderflowError(); // LOSTSYNC - - stream.freerate = rate * 1000; -}; - -module.exports = MP3FrameHeader; - -},{}],6:[function(require,module,exports){ -/* - * These are the Huffman code words for Layer III. - * The data for these tables are derived from Table B.7 of ISO/IEC 11172-3. - * - * These tables support decoding up to 4 Huffman code bits at a time. - */ - -var PTR = function(offs, bits) { - return { - final: 0, - ptr: { - bits: bits, - offset: offs - } - }; -}; - -var huffquad_V = function (v, w, x, y, hlen) { - return { - final: 1, - value: { - v: v, - w: w, - x: x, - y: y, - hlen: hlen - } - }; -}; - -const hufftabA = [ - /* 0000 */ PTR(16, 2), - /* 0001 */ PTR(20, 2), - /* 0010 */ PTR(24, 1), - /* 0011 */ PTR(26, 1), - /* 0100 */ huffquad_V(0, 0, 1, 0, 4), - /* 0101 */ huffquad_V(0, 0, 0, 1, 4), - /* 0110 */ huffquad_V(0, 1, 0, 0, 4), - /* 0111 */ huffquad_V(1, 0, 0, 0, 4), - /* 1000 */ huffquad_V(0, 0, 0, 0, 1), - /* 1001 */ huffquad_V(0, 0, 0, 0, 1), - /* 1010 */ huffquad_V(0, 0, 0, 0, 1), - /* 1011 */ huffquad_V(0, 0, 0, 0, 1), - /* 1100 */ huffquad_V(0, 0, 0, 0, 1), - /* 1101 */ huffquad_V(0, 0, 0, 0, 1), - /* 1110 */ huffquad_V(0, 0, 0, 0, 1), - /* 1111 */ huffquad_V(0, 0, 0, 0, 1), - - /* 0000 ... */ - /* 00 */ huffquad_V(1, 0, 1, 1, 2), /* 16 */ - /* 01 */ huffquad_V(1, 1, 1, 1, 2), - /* 10 */ huffquad_V(1, 1, 0, 1, 2), - /* 11 */ huffquad_V(1, 1, 1, 0, 2), - - /* 0001 ... */ - /* 00 */ huffquad_V(0, 1, 1, 1, 2), /* 20 */ - /* 01 */ huffquad_V(0, 1, 0, 1, 2), - /* 10 */ huffquad_V(1, 0, 0, 1, 1), - /* 11 */ huffquad_V(1, 0, 0, 1, 1), - - /* 0010 ... */ - /* 0 */ huffquad_V(0, 1, 1, 0, 1), /* 24 */ - /* 1 */ huffquad_V(0, 0, 1, 1, 1), - - /* 0011 ... */ - /* 0 */ huffquad_V(1, 0, 1, 0, 1), /* 26 */ - /* 1 */ huffquad_V(1, 1, 0, 0, 1) -]; - -const hufftabB = [ - /* 0000 */ huffquad_V(1, 1, 1, 1, 4), - /* 0001 */ huffquad_V(1, 1, 1, 0, 4), - /* 0010 */ huffquad_V(1, 1, 0, 1, 4), - /* 0011 */ huffquad_V(1, 1, 0, 0, 4), - /* 0100 */ huffquad_V(1, 0, 1, 1, 4), - /* 0101 */ huffquad_V(1, 0, 1, 0, 4), - /* 0110 */ huffquad_V(1, 0, 0, 1, 4), - /* 0111 */ huffquad_V(1, 0, 0, 0, 4), - /* 1000 */ huffquad_V(0, 1, 1, 1, 4), - /* 1001 */ huffquad_V(0, 1, 1, 0, 4), - /* 1010 */ huffquad_V(0, 1, 0, 1, 4), - /* 1011 */ huffquad_V(0, 1, 0, 0, 4), - /* 1100 */ huffquad_V(0, 0, 1, 1, 4), - /* 1101 */ huffquad_V(0, 0, 1, 0, 4), - /* 1110 */ huffquad_V(0, 0, 0, 1, 4), - /* 1111 */ huffquad_V(0, 0, 0, 0, 4) -]; - -var V = function (x, y, hlen) { - return { - final: 1, - value: { - x: x, - y: y, - hlen: hlen - } - }; -}; - -const hufftab0 = [ - /* */ V(0, 0, 0) -]; - -const hufftab1 = [ - /* 000 */ V(1, 1, 3), - /* 001 */ V(0, 1, 3), - /* 010 */ V(1, 0, 2), - /* 011 */ V(1, 0, 2), - /* 100 */ V(0, 0, 1), - /* 101 */ V(0, 0, 1), - /* 110 */ V(0, 0, 1), - /* 111 */ V(0, 0, 1) -]; - -const hufftab2 = [ - /* 000 */ PTR(8, 3), - /* 001 */ V(1, 1, 3), - /* 010 */ V(0, 1, 3), - /* 011 */ V(1, 0, 3), - /* 100 */ V(0, 0, 1), - /* 101 */ V(0, 0, 1), - /* 110 */ V(0, 0, 1), - /* 111 */ V(0, 0, 1), - - /* 000 ... */ - /* 000 */ V(2, 2, 3), /* 8 */ - /* 001 */ V(0, 2, 3), - /* 010 */ V(1, 2, 2), - /* 011 */ V(1, 2, 2), - /* 100 */ V(2, 1, 2), - /* 101 */ V(2, 1, 2), - /* 110 */ V(2, 0, 2), - /* 111 */ V(2, 0, 2) -]; - -const hufftab3 = [ - /* 000 */ PTR(8, 3), - /* 001 */ V(1, 0, 3), - /* 010 */ V(1, 1, 2), - /* 011 */ V(1, 1, 2), - /* 100 */ V(0, 1, 2), - /* 101 */ V(0, 1, 2), - /* 110 */ V(0, 0, 2), - /* 111 */ V(0, 0, 2), - - /* 000 ... */ - /* 000 */ V(2, 2, 3), /* 8 */ - /* 001 */ V(0, 2, 3), - /* 010 */ V(1, 2, 2), - /* 011 */ V(1, 2, 2), - /* 100 */ V(2, 1, 2), - /* 101 */ V(2, 1, 2), - /* 110 */ V(2, 0, 2), - /* 111 */ V(2, 0, 2) -]; - -const hufftab5 = [ - /* 000 */ PTR(8, 4), - /* 001 */ V(1, 1, 3), - /* 010 */ V(0, 1, 3), - /* 011 */ V(1, 0, 3), - /* 100 */ V(0, 0, 1), - /* 101 */ V(0, 0, 1), - /* 110 */ V(0, 0, 1), - /* 111 */ V(0, 0, 1), - - /* 000 ... */ - /* 0000 */ PTR(24, 1), /* 8 */ - /* 0001 */ V(3, 2, 4), - /* 0010 */ V(3, 1, 3), - /* 0011 */ V(3, 1, 3), - /* 0100 */ V(1, 3, 4), - /* 0101 */ V(0, 3, 4), - /* 0110 */ V(3, 0, 4), - /* 0111 */ V(2, 2, 4), - /* 1000 */ V(1, 2, 3), - /* 1001 */ V(1, 2, 3), - /* 1010 */ V(2, 1, 3), - /* 1011 */ V(2, 1, 3), - /* 1100 */ V(0, 2, 3), - /* 1101 */ V(0, 2, 3), - /* 1110 */ V(2, 0, 3), - /* 1111 */ V(2, 0, 3), - - /* 000 0000 ... */ - /* 0 */ V(3, 3, 1), /* 24 */ - /* 1 */ V(2, 3, 1) -]; - -const hufftab6 = [ - /* 0000 */ PTR(16, 3), - /* 0001 */ PTR(24, 1), - /* 0010 */ PTR(26, 1), - /* 0011 */ V(1, 2, 4), - /* 0100 */ V(2, 1, 4), - /* 0101 */ V(2, 0, 4), - /* 0110 */ V(0, 1, 3), - /* 0111 */ V(0, 1, 3), - /* 1000 */ V(1, 1, 2), - /* 1001 */ V(1, 1, 2), - /* 1010 */ V(1, 1, 2), - /* 1011 */ V(1, 1, 2), - /* 1100 */ V(1, 0, 3), - /* 1101 */ V(1, 0, 3), - /* 1110 */ V(0, 0, 3), - /* 1111 */ V(0, 0, 3), - - /* 0000 ... */ - /* 000 */ V(3, 3, 3), /* 16 */ - /* 001 */ V(0, 3, 3), - /* 010 */ V(2, 3, 2), - /* 011 */ V(2, 3, 2), - /* 100 */ V(3, 2, 2), - /* 101 */ V(3, 2, 2), - /* 110 */ V(3, 0, 2), - /* 111 */ V(3, 0, 2), - - /* 0001 ... */ - /* 0 */ V(1, 3, 1), /* 24 */ - /* 1 */ V(3, 1, 1), - - /* 0010 ... */ - /* 0 */ V(2, 2, 1), /* 26 */ - /* 1 */ V(0, 2, 1) -]; - -const hufftab7 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 4), - /* 0010 */ PTR(48, 2), - /* 0011 */ V(1, 1, 4), - /* 0100 */ V(0, 1, 3), - /* 0101 */ V(0, 1, 3), - /* 0110 */ V(1, 0, 3), - /* 0111 */ V(1, 0, 3), - /* 1000 */ V(0, 0, 1), - /* 1001 */ V(0, 0, 1), - /* 1010 */ V(0, 0, 1), - /* 1011 */ V(0, 0, 1), - /* 1100 */ V(0, 0, 1), - /* 1101 */ V(0, 0, 1), - /* 1110 */ V(0, 0, 1), - /* 1111 */ V(0, 0, 1), - - /* 0000 ... */ - /* 0000 */ PTR(52, 2), /* 16 */ - /* 0001 */ PTR(56, 1), - /* 0010 */ PTR(58, 1), - /* 0011 */ V(1, 5, 4), - /* 0100 */ V(5, 1, 4), - /* 0101 */ PTR(60, 1), - /* 0110 */ V(5, 0, 4), - /* 0111 */ PTR(62, 1), - /* 1000 */ V(2, 4, 4), - /* 1001 */ V(4, 2, 4), - /* 1010 */ V(1, 4, 3), - /* 1011 */ V(1, 4, 3), - /* 1100 */ V(4, 1, 3), - /* 1101 */ V(4, 1, 3), - /* 1110 */ V(4, 0, 3), - /* 1111 */ V(4, 0, 3), - - /* 0001 ... */ - /* 0000 */ V(0, 4, 4), /* 32 */ - /* 0001 */ V(2, 3, 4), - /* 0010 */ V(3, 2, 4), - /* 0011 */ V(0, 3, 4), - /* 0100 */ V(1, 3, 3), - /* 0101 */ V(1, 3, 3), - /* 0110 */ V(3, 1, 3), - /* 0111 */ V(3, 1, 3), - /* 1000 */ V(3, 0, 3), - /* 1001 */ V(3, 0, 3), - /* 1010 */ V(2, 2, 3), - /* 1011 */ V(2, 2, 3), - /* 1100 */ V(1, 2, 2), - /* 1101 */ V(1, 2, 2), - /* 1110 */ V(1, 2, 2), - /* 1111 */ V(1, 2, 2), - - /* 0010 ... */ - /* 00 */ V(2, 1, 1), /* 48 */ - /* 01 */ V(2, 1, 1), - /* 10 */ V(0, 2, 2), - /* 11 */ V(2, 0, 2), - - /* 0000 0000 ... */ - /* 00 */ V(5, 5, 2), /* 52 */ - /* 01 */ V(4, 5, 2), - /* 10 */ V(5, 4, 2), - /* 11 */ V(5, 3, 2), - - /* 0000 0001 ... */ - /* 0 */ V(3, 5, 1), /* 56 */ - /* 1 */ V(4, 4, 1), - - /* 0000 0010 ... */ - /* 0 */ V(2, 5, 1), /* 58 */ - /* 1 */ V(5, 2, 1), - - /* 0000 0101 ... */ - /* 0 */ V(0, 5, 1), /* 60 */ - /* 1 */ V(3, 4, 1), - - /* 0000 0111 ... */ - /* 0 */ V(4, 3, 1), /* 62 */ - /* 1 */ V(3, 3, 1) -]; - -const hufftab8 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 4), - /* 0010 */ V(1, 2, 4), - /* 0011 */ V(2, 1, 4), - /* 0100 */ V(1, 1, 2), - /* 0101 */ V(1, 1, 2), - /* 0110 */ V(1, 1, 2), - /* 0111 */ V(1, 1, 2), - /* 1000 */ V(0, 1, 3), - /* 1001 */ V(0, 1, 3), - /* 1010 */ V(1, 0, 3), - /* 1011 */ V(1, 0, 3), - /* 1100 */ V(0, 0, 2), - /* 1101 */ V(0, 0, 2), - /* 1110 */ V(0, 0, 2), - /* 1111 */ V(0, 0, 2), - - /* 0000 ... */ - /* 0000 */ PTR(48, 3), /* 16 */ - /* 0001 */ PTR(56, 2), - /* 0010 */ PTR(60, 1), - /* 0011 */ V(1, 5, 4), - /* 0100 */ V(5, 1, 4), - /* 0101 */ PTR(62, 1), - /* 0110 */ PTR(64, 1), - /* 0111 */ V(2, 4, 4), - /* 1000 */ V(4, 2, 4), - /* 1001 */ V(1, 4, 4), - /* 1010 */ V(4, 1, 3), - /* 1011 */ V(4, 1, 3), - /* 1100 */ V(0, 4, 4), - /* 1101 */ V(4, 0, 4), - /* 1110 */ V(2, 3, 4), - /* 1111 */ V(3, 2, 4), - - /* 0001 ... */ - /* 0000 */ V(1, 3, 4), /* 32 */ - /* 0001 */ V(3, 1, 4), - /* 0010 */ V(0, 3, 4), - /* 0011 */ V(3, 0, 4), - /* 0100 */ V(2, 2, 2), - /* 0101 */ V(2, 2, 2), - /* 0110 */ V(2, 2, 2), - /* 0111 */ V(2, 2, 2), - /* 1000 */ V(0, 2, 2), - /* 1001 */ V(0, 2, 2), - /* 1010 */ V(0, 2, 2), - /* 1011 */ V(0, 2, 2), - /* 1100 */ V(2, 0, 2), - /* 1101 */ V(2, 0, 2), - /* 1110 */ V(2, 0, 2), - /* 1111 */ V(2, 0, 2), - - /* 0000 0000 ... */ - /* 000 */ V(5, 5, 3), /* 48 */ - /* 001 */ V(5, 4, 3), - /* 010 */ V(4, 5, 2), - /* 011 */ V(4, 5, 2), - /* 100 */ V(5, 3, 1), - /* 101 */ V(5, 3, 1), - /* 110 */ V(5, 3, 1), - /* 111 */ V(5, 3, 1), - - /* 0000 0001 ... */ - /* 00 */ V(3, 5, 2), /* 56 */ - /* 01 */ V(4, 4, 2), - /* 10 */ V(2, 5, 1), - /* 11 */ V(2, 5, 1), - - /* 0000 0010 ... */ - /* 0 */ V(5, 2, 1), /* 60 */ - /* 1 */ V(0, 5, 1), - - /* 0000 0101 ... */ - /* 0 */ V(3, 4, 1), /* 62 */ - /* 1 */ V(4, 3, 1), - - /* 0000 0110 ... */ - /* 0 */ V(5, 0, 1), /* 64 */ - /* 1 */ V(3, 3, 1) -]; - -const hufftab9 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 3), - /* 0010 */ PTR(40, 2), - /* 0011 */ PTR(44, 2), - /* 0100 */ PTR(48, 1), - /* 0101 */ V(1, 2, 4), - /* 0110 */ V(2, 1, 4), - /* 0111 */ V(2, 0, 4), - /* 1000 */ V(1, 1, 3), - /* 1001 */ V(1, 1, 3), - /* 1010 */ V(0, 1, 3), - /* 1011 */ V(0, 1, 3), - /* 1100 */ V(1, 0, 3), - /* 1101 */ V(1, 0, 3), - /* 1110 */ V(0, 0, 3), - /* 1111 */ V(0, 0, 3), - - /* 0000 ... */ - /* 0000 */ PTR(50, 1), /* 16 */ - /* 0001 */ V(3, 5, 4), - /* 0010 */ V(5, 3, 4), - /* 0011 */ PTR(52, 1), - /* 0100 */ V(4, 4, 4), - /* 0101 */ V(2, 5, 4), - /* 0110 */ V(5, 2, 4), - /* 0111 */ V(1, 5, 4), - /* 1000 */ V(5, 1, 3), - /* 1001 */ V(5, 1, 3), - /* 1010 */ V(3, 4, 3), - /* 1011 */ V(3, 4, 3), - /* 1100 */ V(4, 3, 3), - /* 1101 */ V(4, 3, 3), - /* 1110 */ V(5, 0, 4), - /* 1111 */ V(0, 4, 4), - - /* 0001 ... */ - /* 000 */ V(2, 4, 3), /* 32 */ - /* 001 */ V(4, 2, 3), - /* 010 */ V(3, 3, 3), - /* 011 */ V(4, 0, 3), - /* 100 */ V(1, 4, 2), - /* 101 */ V(1, 4, 2), - /* 110 */ V(4, 1, 2), - /* 111 */ V(4, 1, 2), - - /* 0010 ... */ - /* 00 */ V(2, 3, 2), /* 40 */ - /* 01 */ V(3, 2, 2), - /* 10 */ V(1, 3, 1), - /* 11 */ V(1, 3, 1), - - /* 0011 ... */ - /* 00 */ V(3, 1, 1), /* 44 */ - /* 01 */ V(3, 1, 1), - /* 10 */ V(0, 3, 2), - /* 11 */ V(3, 0, 2), - - /* 0100 ... */ - /* 0 */ V(2, 2, 1), /* 48 */ - /* 1 */ V(0, 2, 1), - - /* 0000 0000 ... */ - /* 0 */ V(5, 5, 1), /* 50 */ - /* 1 */ V(4, 5, 1), - - /* 0000 0011 ... */ - /* 0 */ V(5, 4, 1), /* 52 */ - /* 1 */ V(0, 5, 1) -]; - -const hufftab10 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 4), - /* 0010 */ PTR(48, 2), - /* 0011 */ V(1, 1, 4), - /* 0100 */ V(0, 1, 3), - /* 0101 */ V(0, 1, 3), - /* 0110 */ V(1, 0, 3), - /* 0111 */ V(1, 0, 3), - /* 1000 */ V(0, 0, 1), - /* 1001 */ V(0, 0, 1), - /* 1010 */ V(0, 0, 1), - /* 1011 */ V(0, 0, 1), - /* 1100 */ V(0, 0, 1), - /* 1101 */ V(0, 0, 1), - /* 1110 */ V(0, 0, 1), - /* 1111 */ V(0, 0, 1), - - /* 0000 ... */ - /* 0000 */ PTR(52, 3), /* 16 */ - /* 0001 */ PTR(60, 2), - /* 0010 */ PTR(64, 3), - /* 0011 */ PTR(72, 1), - /* 0100 */ PTR(74, 2), - /* 0101 */ PTR(78, 2), - /* 0110 */ PTR(82, 2), - /* 0111 */ V(1, 7, 4), - /* 1000 */ V(7, 1, 4), - /* 1001 */ PTR(86, 1), - /* 1010 */ PTR(88, 2), - /* 1011 */ PTR(92, 2), - /* 1100 */ V(1, 6, 4), - /* 1101 */ V(6, 1, 4), - /* 1110 */ V(6, 0, 4), - /* 1111 */ PTR(96, 1), - - /* 0001 ... */ - /* 0000 */ PTR(98, 1), /* 32 */ - /* 0001 */ PTR(100, 1), - /* 0010 */ V(1, 4, 4), - /* 0011 */ V(4, 1, 4), - /* 0100 */ V(4, 0, 4), - /* 0101 */ V(2, 3, 4), - /* 0110 */ V(3, 2, 4), - /* 0111 */ V(0, 3, 4), - /* 1000 */ V(1, 3, 3), - /* 1001 */ V(1, 3, 3), - /* 1010 */ V(3, 1, 3), - /* 1011 */ V(3, 1, 3), - /* 1100 */ V(3, 0, 3), - /* 1101 */ V(3, 0, 3), - /* 1110 */ V(2, 2, 3), - /* 1111 */ V(2, 2, 3), - - /* 0010 ... */ - /* 00 */ V(1, 2, 2), /* 48 */ - /* 01 */ V(2, 1, 2), - /* 10 */ V(0, 2, 2), - /* 11 */ V(2, 0, 2), - - /* 0000 0000 ... */ - /* 000 */ V(7, 7, 3), /* 52 */ - /* 001 */ V(6, 7, 3), - /* 010 */ V(7, 6, 3), - /* 011 */ V(5, 7, 3), - /* 100 */ V(7, 5, 3), - /* 101 */ V(6, 6, 3), - /* 110 */ V(4, 7, 2), - /* 111 */ V(4, 7, 2), - - /* 0000 0001 ... */ - /* 00 */ V(7, 4, 2), /* 60 */ - /* 01 */ V(5, 6, 2), - /* 10 */ V(6, 5, 2), - /* 11 */ V(3, 7, 2), - - /* 0000 0010 ... */ - /* 000 */ V(7, 3, 2), /* 64 */ - /* 001 */ V(7, 3, 2), - /* 010 */ V(4, 6, 2), - /* 011 */ V(4, 6, 2), - /* 100 */ V(5, 5, 3), - /* 101 */ V(5, 4, 3), - /* 110 */ V(6, 3, 2), - /* 111 */ V(6, 3, 2), - - /* 0000 0011 ... */ - /* 0 */ V(2, 7, 1), /* 72 */ - /* 1 */ V(7, 2, 1), - - /* 0000 0100 ... */ - /* 00 */ V(6, 4, 2), /* 74 */ - /* 01 */ V(0, 7, 2), - /* 10 */ V(7, 0, 1), - /* 11 */ V(7, 0, 1), - - /* 0000 0101 ... */ - /* 00 */ V(6, 2, 1), /* 78 */ - /* 01 */ V(6, 2, 1), - /* 10 */ V(4, 5, 2), - /* 11 */ V(3, 5, 2), - - /* 0000 0110 ... */ - /* 00 */ V(0, 6, 1), /* 82 */ - /* 01 */ V(0, 6, 1), - /* 10 */ V(5, 3, 2), - /* 11 */ V(4, 4, 2), - - /* 0000 1001 ... */ - /* 0 */ V(3, 6, 1), /* 86 */ - /* 1 */ V(2, 6, 1), - - /* 0000 1010 ... */ - /* 00 */ V(2, 5, 2), /* 88 */ - /* 01 */ V(5, 2, 2), - /* 10 */ V(1, 5, 1), - /* 11 */ V(1, 5, 1), - - /* 0000 1011 ... */ - /* 00 */ V(5, 1, 1), /* 92 */ - /* 01 */ V(5, 1, 1), - /* 10 */ V(3, 4, 2), - /* 11 */ V(4, 3, 2), - - /* 0000 1111 ... */ - /* 0 */ V(0, 5, 1), /* 96 */ - /* 1 */ V(5, 0, 1), - - /* 0001 0000 ... */ - /* 0 */ V(2, 4, 1), /* 98 */ - /* 1 */ V(4, 2, 1), - - /* 0001 0001 ... */ - /* 0 */ V(3, 3, 1), /* 100 */ - /* 1 */ V(0, 4, 1) -]; - -const hufftab11 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 4), - /* 0010 */ PTR(48, 4), - /* 0011 */ PTR(64, 3), - /* 0100 */ V(1, 2, 4), - /* 0101 */ PTR(72, 1), - /* 0110 */ V(1, 1, 3), - /* 0111 */ V(1, 1, 3), - /* 1000 */ V(0, 1, 3), - /* 1001 */ V(0, 1, 3), - /* 1010 */ V(1, 0, 3), - /* 1011 */ V(1, 0, 3), - /* 1100 */ V(0, 0, 2), - /* 1101 */ V(0, 0, 2), - /* 1110 */ V(0, 0, 2), - /* 1111 */ V(0, 0, 2), - - /* 0000 ... */ - /* 0000 */ PTR(74, 2), /* 16 */ - /* 0001 */ PTR(78, 3), - /* 0010 */ PTR(86, 2), - /* 0011 */ PTR(90, 1), - /* 0100 */ PTR(92, 2), - /* 0101 */ V(2, 7, 4), - /* 0110 */ V(7, 2, 4), - /* 0111 */ PTR(96, 1), - /* 1000 */ V(7, 1, 3), - /* 1001 */ V(7, 1, 3), - /* 1010 */ V(1, 7, 4), - /* 1011 */ V(7, 0, 4), - /* 1100 */ V(3, 6, 4), - /* 1101 */ V(6, 3, 4), - /* 1110 */ V(6, 0, 4), - /* 1111 */ PTR(98, 1), - - /* 0001 ... */ - /* 0000 */ PTR(100, 1), /* 32 */ - /* 0001 */ V(1, 5, 4), - /* 0010 */ V(6, 2, 3), - /* 0011 */ V(6, 2, 3), - /* 0100 */ V(2, 6, 4), - /* 0101 */ V(0, 6, 4), - /* 0110 */ V(1, 6, 3), - /* 0111 */ V(1, 6, 3), - /* 1000 */ V(6, 1, 3), - /* 1001 */ V(6, 1, 3), - /* 1010 */ V(5, 1, 4), - /* 1011 */ V(3, 4, 4), - /* 1100 */ V(5, 0, 4), - /* 1101 */ PTR(102, 1), - /* 1110 */ V(2, 4, 4), - /* 1111 */ V(4, 2, 4), - - /* 0010 ... */ - /* 0000 */ V(1, 4, 4), /* 48 */ - /* 0001 */ V(4, 1, 4), - /* 0010 */ V(0, 4, 4), - /* 0011 */ V(4, 0, 4), - /* 0100 */ V(2, 3, 3), - /* 0101 */ V(2, 3, 3), - /* 0110 */ V(3, 2, 3), - /* 0111 */ V(3, 2, 3), - /* 1000 */ V(1, 3, 2), - /* 1001 */ V(1, 3, 2), - /* 1010 */ V(1, 3, 2), - /* 1011 */ V(1, 3, 2), - /* 1100 */ V(3, 1, 2), - /* 1101 */ V(3, 1, 2), - /* 1110 */ V(3, 1, 2), - /* 1111 */ V(3, 1, 2), - - /* 0011 ... */ - /* 000 */ V(0, 3, 3), /* 64 */ - /* 001 */ V(3, 0, 3), - /* 010 */ V(2, 2, 2), - /* 011 */ V(2, 2, 2), - /* 100 */ V(2, 1, 1), - /* 101 */ V(2, 1, 1), - /* 110 */ V(2, 1, 1), - /* 111 */ V(2, 1, 1), - - /* 0101 ... */ - /* 0 */ V(0, 2, 1), /* 72 */ - /* 1 */ V(2, 0, 1), - - /* 0000 0000 ... */ - /* 00 */ V(7, 7, 2), /* 74 */ - /* 01 */ V(6, 7, 2), - /* 10 */ V(7, 6, 2), - /* 11 */ V(7, 5, 2), - - /* 0000 0001 ... */ - /* 000 */ V(6, 6, 2), /* 78 */ - /* 001 */ V(6, 6, 2), - /* 010 */ V(4, 7, 2), - /* 011 */ V(4, 7, 2), - /* 100 */ V(7, 4, 2), - /* 101 */ V(7, 4, 2), - /* 110 */ V(5, 7, 3), - /* 111 */ V(5, 5, 3), - - /* 0000 0010 ... */ - /* 00 */ V(5, 6, 2), /* 86 */ - /* 01 */ V(6, 5, 2), - /* 10 */ V(3, 7, 1), - /* 11 */ V(3, 7, 1), - - /* 0000 0011 ... */ - /* 0 */ V(7, 3, 1), /* 90 */ - /* 1 */ V(4, 6, 1), - - /* 0000 0100 ... */ - /* 00 */ V(4, 5, 2), /* 92 */ - /* 01 */ V(5, 4, 2), - /* 10 */ V(3, 5, 2), - /* 11 */ V(5, 3, 2), - - /* 0000 0111 ... */ - /* 0 */ V(6, 4, 1), /* 96 */ - /* 1 */ V(0, 7, 1), - - /* 0000 1111 ... */ - /* 0 */ V(4, 4, 1), /* 98 */ - /* 1 */ V(2, 5, 1), - - /* 0001 0000 ... */ - /* 0 */ V(5, 2, 1), /* 100 */ - /* 1 */ V(0, 5, 1), - - /* 0001 1101 ... */ - /* 0 */ V(4, 3, 1), /* 102 */ - /* 1 */ V(3, 3, 1) -]; - -const hufftab12 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 4), - /* 0010 */ PTR(48, 4), - /* 0011 */ PTR(64, 2), - /* 0100 */ PTR(68, 3), - /* 0101 */ PTR(76, 1), - /* 0110 */ V(1, 2, 4), - /* 0111 */ V(2, 1, 4), - /* 1000 */ PTR(78, 1), - /* 1001 */ V(0, 0, 4), - /* 1010 */ V(1, 1, 3), - /* 1011 */ V(1, 1, 3), - /* 1100 */ V(0, 1, 3), - /* 1101 */ V(0, 1, 3), - /* 1110 */ V(1, 0, 3), - /* 1111 */ V(1, 0, 3), - - /* 0000 ... */ - /* 0000 */ PTR(80, 2), /* 16 */ - /* 0001 */ PTR(84, 1), - /* 0010 */ PTR(86, 1), - /* 0011 */ PTR(88, 1), - /* 0100 */ V(5, 6, 4), - /* 0101 */ V(3, 7, 4), - /* 0110 */ PTR(90, 1), - /* 0111 */ V(2, 7, 4), - /* 1000 */ V(7, 2, 4), - /* 1001 */ V(4, 6, 4), - /* 1010 */ V(6, 4, 4), - /* 1011 */ V(1, 7, 4), - /* 1100 */ V(7, 1, 4), - /* 1101 */ PTR(92, 1), - /* 1110 */ V(3, 6, 4), - /* 1111 */ V(6, 3, 4), - - /* 0001 ... */ - /* 0000 */ V(4, 5, 4), /* 32 */ - /* 0001 */ V(5, 4, 4), - /* 0010 */ V(4, 4, 4), - /* 0011 */ PTR(94, 1), - /* 0100 */ V(2, 6, 3), - /* 0101 */ V(2, 6, 3), - /* 0110 */ V(6, 2, 3), - /* 0111 */ V(6, 2, 3), - /* 1000 */ V(6, 1, 3), - /* 1001 */ V(6, 1, 3), - /* 1010 */ V(1, 6, 4), - /* 1011 */ V(6, 0, 4), - /* 1100 */ V(3, 5, 4), - /* 1101 */ V(5, 3, 4), - /* 1110 */ V(2, 5, 4), - /* 1111 */ V(5, 2, 4), - - /* 0010 ... */ - /* 0000 */ V(1, 5, 3), /* 48 */ - /* 0001 */ V(1, 5, 3), - /* 0010 */ V(5, 1, 3), - /* 0011 */ V(5, 1, 3), - /* 0100 */ V(3, 4, 3), - /* 0101 */ V(3, 4, 3), - /* 0110 */ V(4, 3, 3), - /* 0111 */ V(4, 3, 3), - /* 1000 */ V(5, 0, 4), - /* 1001 */ V(0, 4, 4), - /* 1010 */ V(2, 4, 3), - /* 1011 */ V(2, 4, 3), - /* 1100 */ V(4, 2, 3), - /* 1101 */ V(4, 2, 3), - /* 1110 */ V(1, 4, 3), - /* 1111 */ V(1, 4, 3), - - /* 0011 ... */ - /* 00 */ V(3, 3, 2), /* 64 */ - /* 01 */ V(4, 1, 2), - /* 10 */ V(2, 3, 2), - /* 11 */ V(3, 2, 2), - - /* 0100 ... */ - /* 000 */ V(4, 0, 3), /* 68 */ - /* 001 */ V(0, 3, 3), - /* 010 */ V(3, 0, 2), - /* 011 */ V(3, 0, 2), - /* 100 */ V(1, 3, 1), - /* 101 */ V(1, 3, 1), - /* 110 */ V(1, 3, 1), - /* 111 */ V(1, 3, 1), - - /* 0101 ... */ - /* 0 */ V(3, 1, 1), /* 76 */ - /* 1 */ V(2, 2, 1), - - /* 1000 ... */ - /* 0 */ V(0, 2, 1), /* 78 */ - /* 1 */ V(2, 0, 1), - - /* 0000 0000 ... */ - /* 00 */ V(7, 7, 2), /* 80 */ - /* 01 */ V(6, 7, 2), - /* 10 */ V(7, 6, 1), - /* 11 */ V(7, 6, 1), - - /* 0000 0001 ... */ - /* 0 */ V(5, 7, 1), /* 84 */ - /* 1 */ V(7, 5, 1), - - /* 0000 0010 ... */ - /* 0 */ V(6, 6, 1), /* 86 */ - /* 1 */ V(4, 7, 1), - - /* 0000 0011 ... */ - /* 0 */ V(7, 4, 1), /* 88 */ - /* 1 */ V(6, 5, 1), - - /* 0000 0110 ... */ - /* 0 */ V(7, 3, 1), /* 90 */ - /* 1 */ V(5, 5, 1), - - /* 0000 1101 ... */ - /* 0 */ V(0, 7, 1), /* 92 */ - /* 1 */ V(7, 0, 1), - - /* 0001 0011 ... */ - /* 0 */ V(0, 6, 1), /* 94 */ - /* 1 */ V(0, 5, 1) -]; - -const hufftab13 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 4), - /* 0010 */ PTR(48, 4), - /* 0011 */ PTR(64, 2), - /* 0100 */ V(1, 1, 4), - /* 0101 */ V(0, 1, 4), - /* 0110 */ V(1, 0, 3), - /* 0111 */ V(1, 0, 3), - /* 1000 */ V(0, 0, 1), - /* 1001 */ V(0, 0, 1), - /* 1010 */ V(0, 0, 1), - /* 1011 */ V(0, 0, 1), - /* 1100 */ V(0, 0, 1), - /* 1101 */ V(0, 0, 1), - /* 1110 */ V(0, 0, 1), - /* 1111 */ V(0, 0, 1), - - /* 0000 ... */ - /* 0000 */ PTR(68, 4), /* 16 */ - /* 0001 */ PTR(84, 4), - /* 0010 */ PTR(100, 4), - /* 0011 */ PTR(116, 4), - /* 0100 */ PTR(132, 4), - /* 0101 */ PTR(148, 4), - /* 0110 */ PTR(164, 3), - /* 0111 */ PTR(172, 3), - /* 1000 */ PTR(180, 3), - /* 1001 */ PTR(188, 3), - /* 1010 */ PTR(196, 3), - /* 1011 */ PTR(204, 3), - /* 1100 */ PTR(212, 1), - /* 1101 */ PTR(214, 2), - /* 1110 */ PTR(218, 3), - /* 1111 */ PTR(226, 1), - - /* 0001 ... */ - /* 0000 */ PTR(228, 2), /* 32 */ - /* 0001 */ PTR(232, 2), - /* 0010 */ PTR(236, 2), - /* 0011 */ PTR(240, 2), - /* 0100 */ V(8, 1, 4), - /* 0101 */ PTR(244, 1), - /* 0110 */ PTR(246, 1), - /* 0111 */ PTR(248, 1), - /* 1000 */ PTR(250, 2), - /* 1001 */ PTR(254, 1), - /* 1010 */ V(1, 5, 4), - /* 1011 */ V(5, 1, 4), - /* 1100 */ PTR(256, 1), - /* 1101 */ PTR(258, 1), - /* 1110 */ PTR(260, 1), - /* 1111 */ V(1, 4, 4), - - /* 0010 ... */ - /* 0000 */ V(4, 1, 3), /* 48 */ - /* 0001 */ V(4, 1, 3), - /* 0010 */ V(0, 4, 4), - /* 0011 */ V(4, 0, 4), - /* 0100 */ V(2, 3, 4), - /* 0101 */ V(3, 2, 4), - /* 0110 */ V(1, 3, 3), - /* 0111 */ V(1, 3, 3), - /* 1000 */ V(3, 1, 3), - /* 1001 */ V(3, 1, 3), - /* 1010 */ V(0, 3, 3), - /* 1011 */ V(0, 3, 3), - /* 1100 */ V(3, 0, 3), - /* 1101 */ V(3, 0, 3), - /* 1110 */ V(2, 2, 3), - /* 1111 */ V(2, 2, 3), - - /* 0011 ... */ - /* 00 */ V(1, 2, 2), /* 64 */ - /* 01 */ V(2, 1, 2), - /* 10 */ V(0, 2, 2), - /* 11 */ V(2, 0, 2), - - /* 0000 0000 ... */ - /* 0000 */ PTR(262, 4), /* 68 */ - /* 0001 */ PTR(278, 4), - /* 0010 */ PTR(294, 4), - /* 0011 */ PTR(310, 3), - /* 0100 */ PTR(318, 2), - /* 0101 */ PTR(322, 2), - /* 0110 */ PTR(326, 3), - /* 0111 */ PTR(334, 2), - /* 1000 */ PTR(338, 1), - /* 1001 */ PTR(340, 2), - /* 1010 */ PTR(344, 2), - /* 1011 */ PTR(348, 2), - /* 1100 */ PTR(352, 2), - /* 1101 */ PTR(356, 2), - /* 1110 */ V(1, 15, 4), - /* 1111 */ V(15, 1, 4), - - /* 0000 0001 ... */ - /* 0000 */ V(15, 0, 4), /* 84 */ - /* 0001 */ PTR(360, 1), - /* 0010 */ PTR(362, 1), - /* 0011 */ PTR(364, 1), - /* 0100 */ V(14, 2, 4), - /* 0101 */ PTR(366, 1), - /* 0110 */ V(1, 14, 4), - /* 0111 */ V(14, 1, 4), - /* 1000 */ PTR(368, 1), - /* 1001 */ PTR(370, 1), - /* 1010 */ PTR(372, 1), - /* 1011 */ PTR(374, 1), - /* 1100 */ PTR(376, 1), - /* 1101 */ PTR(378, 1), - /* 1110 */ V(12, 6, 4), - /* 1111 */ V(3, 13, 4), - - /* 0000 0010 ... */ - /* 0000 */ PTR(380, 1), /* 100 */ - /* 0001 */ V(2, 13, 4), - /* 0010 */ V(13, 2, 4), - /* 0011 */ V(1, 13, 4), - /* 0100 */ V(11, 7, 4), - /* 0101 */ PTR(382, 1), - /* 0110 */ PTR(384, 1), - /* 0111 */ V(12, 3, 4), - /* 1000 */ PTR(386, 1), - /* 1001 */ V(4, 11, 4), - /* 1010 */ V(13, 1, 3), - /* 1011 */ V(13, 1, 3), - /* 1100 */ V(0, 13, 4), - /* 1101 */ V(13, 0, 4), - /* 1110 */ V(8, 10, 4), - /* 1111 */ V(10, 8, 4), - - /* 0000 0011 ... */ - /* 0000 */ V(4, 12, 4), /* 116 */ - /* 0001 */ V(12, 4, 4), - /* 0010 */ V(6, 11, 4), - /* 0011 */ V(11, 6, 4), - /* 0100 */ V(3, 12, 3), - /* 0101 */ V(3, 12, 3), - /* 0110 */ V(2, 12, 3), - /* 0111 */ V(2, 12, 3), - /* 1000 */ V(12, 2, 3), - /* 1001 */ V(12, 2, 3), - /* 1010 */ V(5, 11, 3), - /* 1011 */ V(5, 11, 3), - /* 1100 */ V(11, 5, 4), - /* 1101 */ V(8, 9, 4), - /* 1110 */ V(1, 12, 3), - /* 1111 */ V(1, 12, 3), - - /* 0000 0100 ... */ - /* 0000 */ V(12, 1, 3), /* 132 */ - /* 0001 */ V(12, 1, 3), - /* 0010 */ V(9, 8, 4), - /* 0011 */ V(0, 12, 4), - /* 0100 */ V(12, 0, 3), - /* 0101 */ V(12, 0, 3), - /* 0110 */ V(11, 4, 4), - /* 0111 */ V(6, 10, 4), - /* 1000 */ V(10, 6, 4), - /* 1001 */ V(7, 9, 4), - /* 1010 */ V(3, 11, 3), - /* 1011 */ V(3, 11, 3), - /* 1100 */ V(11, 3, 3), - /* 1101 */ V(11, 3, 3), - /* 1110 */ V(8, 8, 4), - /* 1111 */ V(5, 10, 4), - - /* 0000 0101 ... */ - /* 0000 */ V(2, 11, 3), /* 148 */ - /* 0001 */ V(2, 11, 3), - /* 0010 */ V(10, 5, 4), - /* 0011 */ V(6, 9, 4), - /* 0100 */ V(10, 4, 3), - /* 0101 */ V(10, 4, 3), - /* 0110 */ V(7, 8, 4), - /* 0111 */ V(8, 7, 4), - /* 1000 */ V(9, 4, 3), - /* 1001 */ V(9, 4, 3), - /* 1010 */ V(7, 7, 4), - /* 1011 */ V(7, 6, 4), - /* 1100 */ V(11, 2, 2), - /* 1101 */ V(11, 2, 2), - /* 1110 */ V(11, 2, 2), - /* 1111 */ V(11, 2, 2), - - /* 0000 0110 ... */ - /* 000 */ V(1, 11, 2), /* 164 */ - /* 001 */ V(1, 11, 2), - /* 010 */ V(11, 1, 2), - /* 011 */ V(11, 1, 2), - /* 100 */ V(0, 11, 3), - /* 101 */ V(11, 0, 3), - /* 110 */ V(9, 6, 3), - /* 111 */ V(4, 10, 3), - - /* 0000 0111 ... */ - /* 000 */ V(3, 10, 3), /* 172 */ - /* 001 */ V(10, 3, 3), - /* 010 */ V(5, 9, 3), - /* 011 */ V(9, 5, 3), - /* 100 */ V(2, 10, 2), - /* 101 */ V(2, 10, 2), - /* 110 */ V(10, 2, 2), - /* 111 */ V(10, 2, 2), - - /* 0000 1000 ... */ - /* 000 */ V(1, 10, 2), /* 180 */ - /* 001 */ V(1, 10, 2), - /* 010 */ V(10, 1, 2), - /* 011 */ V(10, 1, 2), - /* 100 */ V(0, 10, 3), - /* 101 */ V(6, 8, 3), - /* 110 */ V(10, 0, 2), - /* 111 */ V(10, 0, 2), - - /* 0000 1001 ... */ - /* 000 */ V(8, 6, 3), /* 188 */ - /* 001 */ V(4, 9, 3), - /* 010 */ V(9, 3, 2), - /* 011 */ V(9, 3, 2), - /* 100 */ V(3, 9, 3), - /* 101 */ V(5, 8, 3), - /* 110 */ V(8, 5, 3), - /* 111 */ V(6, 7, 3), - - /* 0000 1010 ... */ - /* 000 */ V(2, 9, 2), /* 196 */ - /* 001 */ V(2, 9, 2), - /* 010 */ V(9, 2, 2), - /* 011 */ V(9, 2, 2), - /* 100 */ V(5, 7, 3), - /* 101 */ V(7, 5, 3), - /* 110 */ V(3, 8, 2), - /* 111 */ V(3, 8, 2), - - /* 0000 1011 ... */ - /* 000 */ V(8, 3, 2), /* 204 */ - /* 001 */ V(8, 3, 2), - /* 010 */ V(6, 6, 3), - /* 011 */ V(4, 7, 3), - /* 100 */ V(7, 4, 3), - /* 101 */ V(5, 6, 3), - /* 110 */ V(6, 5, 3), - /* 111 */ V(7, 3, 3), - - /* 0000 1100 ... */ - /* 0 */ V(1, 9, 1), /* 212 */ - /* 1 */ V(9, 1, 1), - - /* 0000 1101 ... */ - /* 00 */ V(0, 9, 2), /* 214 */ - /* 01 */ V(9, 0, 2), - /* 10 */ V(4, 8, 2), - /* 11 */ V(8, 4, 2), - - /* 0000 1110 ... */ - /* 000 */ V(7, 2, 2), /* 218 */ - /* 001 */ V(7, 2, 2), - /* 010 */ V(4, 6, 3), - /* 011 */ V(6, 4, 3), - /* 100 */ V(2, 8, 1), - /* 101 */ V(2, 8, 1), - /* 110 */ V(2, 8, 1), - /* 111 */ V(2, 8, 1), - - /* 0000 1111 ... */ - /* 0 */ V(8, 2, 1), /* 226 */ - /* 1 */ V(1, 8, 1), - - /* 0001 0000 ... */ - /* 00 */ V(3, 7, 2), /* 228 */ - /* 01 */ V(2, 7, 2), - /* 10 */ V(1, 7, 1), - /* 11 */ V(1, 7, 1), - - /* 0001 0001 ... */ - /* 00 */ V(7, 1, 1), /* 232 */ - /* 01 */ V(7, 1, 1), - /* 10 */ V(5, 5, 2), - /* 11 */ V(0, 7, 2), - - /* 0001 0010 ... */ - /* 00 */ V(7, 0, 2), /* 236 */ - /* 01 */ V(3, 6, 2), - /* 10 */ V(6, 3, 2), - /* 11 */ V(4, 5, 2), - - /* 0001 0011 ... */ - /* 00 */ V(5, 4, 2), /* 240 */ - /* 01 */ V(2, 6, 2), - /* 10 */ V(6, 2, 2), - /* 11 */ V(3, 5, 2), - - /* 0001 0101 ... */ - /* 0 */ V(0, 8, 1), /* 244 */ - /* 1 */ V(8, 0, 1), - - /* 0001 0110 ... */ - /* 0 */ V(1, 6, 1), /* 246 */ - /* 1 */ V(6, 1, 1), - - /* 0001 0111 ... */ - /* 0 */ V(0, 6, 1), /* 248 */ - /* 1 */ V(6, 0, 1), - - /* 0001 1000 ... */ - /* 00 */ V(5, 3, 2), /* 250 */ - /* 01 */ V(4, 4, 2), - /* 10 */ V(2, 5, 1), - /* 11 */ V(2, 5, 1), - - /* 0001 1001 ... */ - /* 0 */ V(5, 2, 1), /* 254 */ - /* 1 */ V(0, 5, 1), - - /* 0001 1100 ... */ - /* 0 */ V(3, 4, 1), /* 256 */ - /* 1 */ V(4, 3, 1), - - /* 0001 1101 ... */ - /* 0 */ V(5, 0, 1), /* 258 */ - /* 1 */ V(2, 4, 1), - - /* 0001 1110 ... */ - /* 0 */ V(4, 2, 1), /* 260 */ - /* 1 */ V(3, 3, 1), - - /* 0000 0000 0000 ... */ - /* 0000 */ PTR(388, 3), /* 262 */ - /* 0001 */ V(15, 15, 4), - /* 0010 */ V(14, 15, 4), - /* 0011 */ V(13, 15, 4), - /* 0100 */ V(14, 14, 4), - /* 0101 */ V(12, 15, 4), - /* 0110 */ V(13, 14, 4), - /* 0111 */ V(11, 15, 4), - /* 1000 */ V(15, 11, 4), - /* 1001 */ V(12, 14, 4), - /* 1010 */ V(13, 12, 4), - /* 1011 */ PTR(396, 1), - /* 1100 */ V(14, 12, 3), - /* 1101 */ V(14, 12, 3), - /* 1110 */ V(13, 13, 3), - /* 1111 */ V(13, 13, 3), - - /* 0000 0000 0001 ... */ - /* 0000 */ V(15, 10, 4), /* 278 */ - /* 0001 */ V(12, 13, 4), - /* 0010 */ V(11, 14, 3), - /* 0011 */ V(11, 14, 3), - /* 0100 */ V(14, 11, 3), - /* 0101 */ V(14, 11, 3), - /* 0110 */ V(9, 15, 3), - /* 0111 */ V(9, 15, 3), - /* 1000 */ V(15, 9, 3), - /* 1001 */ V(15, 9, 3), - /* 1010 */ V(14, 10, 3), - /* 1011 */ V(14, 10, 3), - /* 1100 */ V(11, 13, 3), - /* 1101 */ V(11, 13, 3), - /* 1110 */ V(13, 11, 3), - /* 1111 */ V(13, 11, 3), - - /* 0000 0000 0010 ... */ - /* 0000 */ V(8, 15, 3), /* 294 */ - /* 0001 */ V(8, 15, 3), - /* 0010 */ V(15, 8, 3), - /* 0011 */ V(15, 8, 3), - /* 0100 */ V(12, 12, 3), - /* 0101 */ V(12, 12, 3), - /* 0110 */ V(10, 14, 4), - /* 0111 */ V(9, 14, 4), - /* 1000 */ V(8, 14, 3), - /* 1001 */ V(8, 14, 3), - /* 1010 */ V(7, 15, 4), - /* 1011 */ V(7, 14, 4), - /* 1100 */ V(15, 7, 2), - /* 1101 */ V(15, 7, 2), - /* 1110 */ V(15, 7, 2), - /* 1111 */ V(15, 7, 2), - - /* 0000 0000 0011 ... */ - /* 000 */ V(13, 10, 2), /* 310 */ - /* 001 */ V(13, 10, 2), - /* 010 */ V(10, 13, 3), - /* 011 */ V(11, 12, 3), - /* 100 */ V(12, 11, 3), - /* 101 */ V(15, 6, 3), - /* 110 */ V(6, 15, 2), - /* 111 */ V(6, 15, 2), - - /* 0000 0000 0100 ... */ - /* 00 */ V(14, 8, 2), /* 318 */ - /* 01 */ V(5, 15, 2), - /* 10 */ V(9, 13, 2), - /* 11 */ V(13, 9, 2), - - /* 0000 0000 0101 ... */ - /* 00 */ V(15, 5, 2), /* 322 */ - /* 01 */ V(14, 7, 2), - /* 10 */ V(10, 12, 2), - /* 11 */ V(11, 11, 2), - - /* 0000 0000 0110 ... */ - /* 000 */ V(4, 15, 2), /* 326 */ - /* 001 */ V(4, 15, 2), - /* 010 */ V(15, 4, 2), - /* 011 */ V(15, 4, 2), - /* 100 */ V(12, 10, 3), - /* 101 */ V(14, 6, 3), - /* 110 */ V(15, 3, 2), - /* 111 */ V(15, 3, 2), - - /* 0000 0000 0111 ... */ - /* 00 */ V(3, 15, 1), /* 334 */ - /* 01 */ V(3, 15, 1), - /* 10 */ V(8, 13, 2), - /* 11 */ V(13, 8, 2), - - /* 0000 0000 1000 ... */ - /* 0 */ V(2, 15, 1), /* 338 */ - /* 1 */ V(15, 2, 1), - - /* 0000 0000 1001 ... */ - /* 00 */ V(6, 14, 2), /* 340 */ - /* 01 */ V(9, 12, 2), - /* 10 */ V(0, 15, 1), - /* 11 */ V(0, 15, 1), - - /* 0000 0000 1010 ... */ - /* 00 */ V(12, 9, 2), /* 344 */ - /* 01 */ V(5, 14, 2), - /* 10 */ V(10, 11, 1), - /* 11 */ V(10, 11, 1), - - /* 0000 0000 1011 ... */ - /* 00 */ V(7, 13, 2), /* 348 */ - /* 01 */ V(13, 7, 2), - /* 10 */ V(4, 14, 1), - /* 11 */ V(4, 14, 1), - - /* 0000 0000 1100 ... */ - /* 00 */ V(12, 8, 2), /* 352 */ - /* 01 */ V(13, 6, 2), - /* 10 */ V(3, 14, 1), - /* 11 */ V(3, 14, 1), - - /* 0000 0000 1101 ... */ - /* 00 */ V(11, 9, 1), /* 356 */ - /* 01 */ V(11, 9, 1), - /* 10 */ V(9, 11, 2), - /* 11 */ V(10, 10, 2), - - /* 0000 0001 0001 ... */ - /* 0 */ V(11, 10, 1), /* 360 */ - /* 1 */ V(14, 5, 1), - - /* 0000 0001 0010 ... */ - /* 0 */ V(14, 4, 1), /* 362 */ - /* 1 */ V(8, 12, 1), - - /* 0000 0001 0011 ... */ - /* 0 */ V(6, 13, 1), /* 364 */ - /* 1 */ V(14, 3, 1), - - /* 0000 0001 0101 ... */ - /* 0 */ V(2, 14, 1), /* 366 */ - /* 1 */ V(0, 14, 1), - - /* 0000 0001 1000 ... */ - /* 0 */ V(14, 0, 1), /* 368 */ - /* 1 */ V(5, 13, 1), - - /* 0000 0001 1001 ... */ - /* 0 */ V(13, 5, 1), /* 370 */ - /* 1 */ V(7, 12, 1), - - /* 0000 0001 1010 ... */ - /* 0 */ V(12, 7, 1), /* 372 */ - /* 1 */ V(4, 13, 1), - - /* 0000 0001 1011 ... */ - /* 0 */ V(8, 11, 1), /* 374 */ - /* 1 */ V(11, 8, 1), - - /* 0000 0001 1100 ... */ - /* 0 */ V(13, 4, 1), /* 376 */ - /* 1 */ V(9, 10, 1), - - /* 0000 0001 1101 ... */ - /* 0 */ V(10, 9, 1), /* 378 */ - /* 1 */ V(6, 12, 1), - - /* 0000 0010 0000 ... */ - /* 0 */ V(13, 3, 1), /* 380 */ - /* 1 */ V(7, 11, 1), - - /* 0000 0010 0101 ... */ - /* 0 */ V(5, 12, 1), /* 382 */ - /* 1 */ V(12, 5, 1), - - /* 0000 0010 0110 ... */ - /* 0 */ V(9, 9, 1), /* 384 */ - /* 1 */ V(7, 10, 1), - - /* 0000 0010 1000 ... */ - /* 0 */ V(10, 7, 1), /* 386 */ - /* 1 */ V(9, 7, 1), - - /* 0000 0000 0000 0000 ... */ - /* 000 */ V(15, 14, 3), /* 388 */ - /* 001 */ V(15, 12, 3), - /* 010 */ V(15, 13, 2), - /* 011 */ V(15, 13, 2), - /* 100 */ V(14, 13, 1), - /* 101 */ V(14, 13, 1), - /* 110 */ V(14, 13, 1), - /* 111 */ V(14, 13, 1), - - /* 0000 0000 0000 1011 ... */ - /* 0 */ V(10, 15, 1), /* 396 */ - /* 1 */ V(14, 9, 1) -]; - -const hufftab15 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 4), - /* 0010 */ PTR(48, 4), - /* 0011 */ PTR(64, 4), - /* 0100 */ PTR(80, 4), - /* 0101 */ PTR(96, 3), - /* 0110 */ PTR(104, 3), - /* 0111 */ PTR(112, 2), - /* 1000 */ PTR(116, 1), - /* 1001 */ PTR(118, 1), - /* 1010 */ V(1, 1, 3), - /* 1011 */ V(1, 1, 3), - /* 1100 */ V(0, 1, 4), - /* 1101 */ V(1, 0, 4), - /* 1110 */ V(0, 0, 3), - /* 1111 */ V(0, 0, 3), - - /* 0000 ... */ - /* 0000 */ PTR(120, 4), /* 16 */ - /* 0001 */ PTR(136, 4), - /* 0010 */ PTR(152, 4), - /* 0011 */ PTR(168, 4), - /* 0100 */ PTR(184, 4), - /* 0101 */ PTR(200, 3), - /* 0110 */ PTR(208, 3), - /* 0111 */ PTR(216, 4), - /* 1000 */ PTR(232, 3), - /* 1001 */ PTR(240, 3), - /* 1010 */ PTR(248, 3), - /* 1011 */ PTR(256, 3), - /* 1100 */ PTR(264, 2), - /* 1101 */ PTR(268, 3), - /* 1110 */ PTR(276, 3), - /* 1111 */ PTR(284, 2), - - /* 0001 ... */ - /* 0000 */ PTR(288, 2), /* 32 */ - /* 0001 */ PTR(292, 2), - /* 0010 */ PTR(296, 2), - /* 0011 */ PTR(300, 2), - /* 0100 */ PTR(304, 2), - /* 0101 */ PTR(308, 2), - /* 0110 */ PTR(312, 2), - /* 0111 */ PTR(316, 2), - /* 1000 */ PTR(320, 1), - /* 1001 */ PTR(322, 1), - /* 1010 */ PTR(324, 1), - /* 1011 */ PTR(326, 2), - /* 1100 */ PTR(330, 1), - /* 1101 */ PTR(332, 1), - /* 1110 */ PTR(334, 2), - /* 1111 */ PTR(338, 1), - - /* 0010 ... */ - /* 0000 */ PTR(340, 1), /* 48 */ - /* 0001 */ PTR(342, 1), - /* 0010 */ V(9, 1, 4), - /* 0011 */ PTR(344, 1), - /* 0100 */ PTR(346, 1), - /* 0101 */ PTR(348, 1), - /* 0110 */ PTR(350, 1), - /* 0111 */ PTR(352, 1), - /* 1000 */ V(2, 8, 4), - /* 1001 */ V(8, 2, 4), - /* 1010 */ V(1, 8, 4), - /* 1011 */ V(8, 1, 4), - /* 1100 */ PTR(354, 1), - /* 1101 */ PTR(356, 1), - /* 1110 */ PTR(358, 1), - /* 1111 */ PTR(360, 1), - - /* 0011 ... */ - /* 0000 */ V(2, 7, 4), /* 64 */ - /* 0001 */ V(7, 2, 4), - /* 0010 */ V(6, 4, 4), - /* 0011 */ V(1, 7, 4), - /* 0100 */ V(5, 5, 4), - /* 0101 */ V(7, 1, 4), - /* 0110 */ PTR(362, 1), - /* 0111 */ V(3, 6, 4), - /* 1000 */ V(6, 3, 4), - /* 1001 */ V(4, 5, 4), - /* 1010 */ V(5, 4, 4), - /* 1011 */ V(2, 6, 4), - /* 1100 */ V(6, 2, 4), - /* 1101 */ V(1, 6, 4), - /* 1110 */ PTR(364, 1), - /* 1111 */ V(3, 5, 4), - - /* 0100 ... */ - /* 0000 */ V(6, 1, 3), /* 80 */ - /* 0001 */ V(6, 1, 3), - /* 0010 */ V(5, 3, 4), - /* 0011 */ V(4, 4, 4), - /* 0100 */ V(2, 5, 3), - /* 0101 */ V(2, 5, 3), - /* 0110 */ V(5, 2, 3), - /* 0111 */ V(5, 2, 3), - /* 1000 */ V(1, 5, 3), - /* 1001 */ V(1, 5, 3), - /* 1010 */ V(5, 1, 3), - /* 1011 */ V(5, 1, 3), - /* 1100 */ V(0, 5, 4), - /* 1101 */ V(5, 0, 4), - /* 1110 */ V(3, 4, 3), - /* 1111 */ V(3, 4, 3), - - /* 0101 ... */ - /* 000 */ V(4, 3, 3), /* 96 */ - /* 001 */ V(2, 4, 3), - /* 010 */ V(4, 2, 3), - /* 011 */ V(3, 3, 3), - /* 100 */ V(4, 1, 2), - /* 101 */ V(4, 1, 2), - /* 110 */ V(1, 4, 3), - /* 111 */ V(0, 4, 3), - - /* 0110 ... */ - /* 000 */ V(2, 3, 2), /* 104 */ - /* 001 */ V(2, 3, 2), - /* 010 */ V(3, 2, 2), - /* 011 */ V(3, 2, 2), - /* 100 */ V(4, 0, 3), - /* 101 */ V(0, 3, 3), - /* 110 */ V(1, 3, 2), - /* 111 */ V(1, 3, 2), - - /* 0111 ... */ - /* 00 */ V(3, 1, 2), /* 112 */ - /* 01 */ V(3, 0, 2), - /* 10 */ V(2, 2, 1), - /* 11 */ V(2, 2, 1), - - /* 1000 ... */ - /* 0 */ V(1, 2, 1), /* 116 */ - /* 1 */ V(2, 1, 1), - - /* 1001 ... */ - /* 0 */ V(0, 2, 1), /* 118 */ - /* 1 */ V(2, 0, 1), - - /* 0000 0000 ... */ - /* 0000 */ PTR(366, 1), /* 120 */ - /* 0001 */ PTR(368, 1), - /* 0010 */ V(14, 14, 4), - /* 0011 */ PTR(370, 1), - /* 0100 */ PTR(372, 1), - /* 0101 */ PTR(374, 1), - /* 0110 */ V(15, 11, 4), - /* 0111 */ PTR(376, 1), - /* 1000 */ V(13, 13, 4), - /* 1001 */ V(10, 15, 4), - /* 1010 */ V(15, 10, 4), - /* 1011 */ V(11, 14, 4), - /* 1100 */ V(14, 11, 4), - /* 1101 */ V(12, 13, 4), - /* 1110 */ V(13, 12, 4), - /* 1111 */ V(9, 15, 4), - - /* 0000 0001 ... */ - /* 0000 */ V(15, 9, 4), /* 136 */ - /* 0001 */ V(14, 10, 4), - /* 0010 */ V(11, 13, 4), - /* 0011 */ V(13, 11, 4), - /* 0100 */ V(8, 15, 4), - /* 0101 */ V(15, 8, 4), - /* 0110 */ V(12, 12, 4), - /* 0111 */ V(9, 14, 4), - /* 1000 */ V(14, 9, 4), - /* 1001 */ V(7, 15, 4), - /* 1010 */ V(15, 7, 4), - /* 1011 */ V(10, 13, 4), - /* 1100 */ V(13, 10, 4), - /* 1101 */ V(11, 12, 4), - /* 1110 */ V(6, 15, 4), - /* 1111 */ PTR(378, 1), - - /* 0000 0010 ... */ - /* 0000 */ V(12, 11, 3), /* 152 */ - /* 0001 */ V(12, 11, 3), - /* 0010 */ V(15, 6, 3), - /* 0011 */ V(15, 6, 3), - /* 0100 */ V(8, 14, 4), - /* 0101 */ V(14, 8, 4), - /* 0110 */ V(5, 15, 4), - /* 0111 */ V(9, 13, 4), - /* 1000 */ V(15, 5, 3), - /* 1001 */ V(15, 5, 3), - /* 1010 */ V(7, 14, 3), - /* 1011 */ V(7, 14, 3), - /* 1100 */ V(14, 7, 3), - /* 1101 */ V(14, 7, 3), - /* 1110 */ V(10, 12, 3), - /* 1111 */ V(10, 12, 3), - - /* 0000 0011 ... */ - /* 0000 */ V(12, 10, 3), /* 168 */ - /* 0001 */ V(12, 10, 3), - /* 0010 */ V(11, 11, 3), - /* 0011 */ V(11, 11, 3), - /* 0100 */ V(13, 9, 4), - /* 0101 */ V(8, 13, 4), - /* 0110 */ V(4, 15, 3), - /* 0111 */ V(4, 15, 3), - /* 1000 */ V(15, 4, 3), - /* 1001 */ V(15, 4, 3), - /* 1010 */ V(3, 15, 3), - /* 1011 */ V(3, 15, 3), - /* 1100 */ V(15, 3, 3), - /* 1101 */ V(15, 3, 3), - /* 1110 */ V(13, 8, 3), - /* 1111 */ V(13, 8, 3), - - /* 0000 0100 ... */ - /* 0000 */ V(14, 6, 3), /* 184 */ - /* 0001 */ V(14, 6, 3), - /* 0010 */ V(2, 15, 3), - /* 0011 */ V(2, 15, 3), - /* 0100 */ V(15, 2, 3), - /* 0101 */ V(15, 2, 3), - /* 0110 */ V(6, 14, 4), - /* 0111 */ V(15, 0, 4), - /* 1000 */ V(1, 15, 3), - /* 1001 */ V(1, 15, 3), - /* 1010 */ V(15, 1, 3), - /* 1011 */ V(15, 1, 3), - /* 1100 */ V(9, 12, 3), - /* 1101 */ V(9, 12, 3), - /* 1110 */ V(12, 9, 3), - /* 1111 */ V(12, 9, 3), - - /* 0000 0101 ... */ - /* 000 */ V(5, 14, 3), /* 200 */ - /* 001 */ V(10, 11, 3), - /* 010 */ V(11, 10, 3), - /* 011 */ V(14, 5, 3), - /* 100 */ V(7, 13, 3), - /* 101 */ V(13, 7, 3), - /* 110 */ V(4, 14, 3), - /* 111 */ V(14, 4, 3), - - /* 0000 0110 ... */ - /* 000 */ V(8, 12, 3), /* 208 */ - /* 001 */ V(12, 8, 3), - /* 010 */ V(3, 14, 3), - /* 011 */ V(6, 13, 3), - /* 100 */ V(13, 6, 3), - /* 101 */ V(14, 3, 3), - /* 110 */ V(9, 11, 3), - /* 111 */ V(11, 9, 3), - - /* 0000 0111 ... */ - /* 0000 */ V(2, 14, 3), /* 216 */ - /* 0001 */ V(2, 14, 3), - /* 0010 */ V(10, 10, 3), - /* 0011 */ V(10, 10, 3), - /* 0100 */ V(14, 2, 3), - /* 0101 */ V(14, 2, 3), - /* 0110 */ V(1, 14, 3), - /* 0111 */ V(1, 14, 3), - /* 1000 */ V(14, 1, 3), - /* 1001 */ V(14, 1, 3), - /* 1010 */ V(0, 14, 4), - /* 1011 */ V(14, 0, 4), - /* 1100 */ V(5, 13, 3), - /* 1101 */ V(5, 13, 3), - /* 1110 */ V(13, 5, 3), - /* 1111 */ V(13, 5, 3), - - /* 0000 1000 ... */ - /* 000 */ V(7, 12, 3), /* 232 */ - /* 001 */ V(12, 7, 3), - /* 010 */ V(4, 13, 3), - /* 011 */ V(8, 11, 3), - /* 100 */ V(13, 4, 2), - /* 101 */ V(13, 4, 2), - /* 110 */ V(11, 8, 3), - /* 111 */ V(9, 10, 3), - - /* 0000 1001 ... */ - /* 000 */ V(10, 9, 3), /* 240 */ - /* 001 */ V(6, 12, 3), - /* 010 */ V(12, 6, 3), - /* 011 */ V(3, 13, 3), - /* 100 */ V(13, 3, 2), - /* 101 */ V(13, 3, 2), - /* 110 */ V(13, 2, 2), - /* 111 */ V(13, 2, 2), - - /* 0000 1010 ... */ - /* 000 */ V(2, 13, 3), /* 248 */ - /* 001 */ V(0, 13, 3), - /* 010 */ V(1, 13, 2), - /* 011 */ V(1, 13, 2), - /* 100 */ V(7, 11, 2), - /* 101 */ V(7, 11, 2), - /* 110 */ V(11, 7, 2), - /* 111 */ V(11, 7, 2), - - /* 0000 1011 ... */ - /* 000 */ V(13, 1, 2), /* 256 */ - /* 001 */ V(13, 1, 2), - /* 010 */ V(5, 12, 3), - /* 011 */ V(13, 0, 3), - /* 100 */ V(12, 5, 2), - /* 101 */ V(12, 5, 2), - /* 110 */ V(8, 10, 2), - /* 111 */ V(8, 10, 2), - - /* 0000 1100 ... */ - /* 00 */ V(10, 8, 2), /* 264 */ - /* 01 */ V(4, 12, 2), - /* 10 */ V(12, 4, 2), - /* 11 */ V(6, 11, 2), - - /* 0000 1101 ... */ - /* 000 */ V(11, 6, 2), /* 268 */ - /* 001 */ V(11, 6, 2), - /* 010 */ V(9, 9, 3), - /* 011 */ V(0, 12, 3), - /* 100 */ V(3, 12, 2), - /* 101 */ V(3, 12, 2), - /* 110 */ V(12, 3, 2), - /* 111 */ V(12, 3, 2), - - /* 0000 1110 ... */ - /* 000 */ V(7, 10, 2), /* 276 */ - /* 001 */ V(7, 10, 2), - /* 010 */ V(10, 7, 2), - /* 011 */ V(10, 7, 2), - /* 100 */ V(10, 6, 2), - /* 101 */ V(10, 6, 2), - /* 110 */ V(12, 0, 3), - /* 111 */ V(0, 11, 3), - - /* 0000 1111 ... */ - /* 00 */ V(12, 2, 1), /* 284 */ - /* 01 */ V(12, 2, 1), - /* 10 */ V(2, 12, 2), - /* 11 */ V(5, 11, 2), - - /* 0001 0000 ... */ - /* 00 */ V(11, 5, 2), /* 288 */ - /* 01 */ V(1, 12, 2), - /* 10 */ V(8, 9, 2), - /* 11 */ V(9, 8, 2), - - /* 0001 0001 ... */ - /* 00 */ V(12, 1, 2), /* 292 */ - /* 01 */ V(4, 11, 2), - /* 10 */ V(11, 4, 2), - /* 11 */ V(6, 10, 2), - - /* 0001 0010 ... */ - /* 00 */ V(3, 11, 2), /* 296 */ - /* 01 */ V(7, 9, 2), - /* 10 */ V(11, 3, 1), - /* 11 */ V(11, 3, 1), - - /* 0001 0011 ... */ - /* 00 */ V(9, 7, 2), /* 300 */ - /* 01 */ V(8, 8, 2), - /* 10 */ V(2, 11, 2), - /* 11 */ V(5, 10, 2), - - /* 0001 0100 ... */ - /* 00 */ V(11, 2, 1), /* 304 */ - /* 01 */ V(11, 2, 1), - /* 10 */ V(10, 5, 2), - /* 11 */ V(1, 11, 2), - - /* 0001 0101 ... */ - /* 00 */ V(11, 1, 1), /* 308 */ - /* 01 */ V(11, 1, 1), - /* 10 */ V(11, 0, 2), - /* 11 */ V(6, 9, 2), - - /* 0001 0110 ... */ - /* 00 */ V(9, 6, 2), /* 312 */ - /* 01 */ V(4, 10, 2), - /* 10 */ V(10, 4, 2), - /* 11 */ V(7, 8, 2), - - /* 0001 0111 ... */ - /* 00 */ V(8, 7, 2), /* 316 */ - /* 01 */ V(3, 10, 2), - /* 10 */ V(10, 3, 1), - /* 11 */ V(10, 3, 1), - - /* 0001 1000 ... */ - /* 0 */ V(5, 9, 1), /* 320 */ - /* 1 */ V(9, 5, 1), - - /* 0001 1001 ... */ - /* 0 */ V(2, 10, 1), /* 322 */ - /* 1 */ V(10, 2, 1), - - /* 0001 1010 ... */ - /* 0 */ V(1, 10, 1), /* 324 */ - /* 1 */ V(10, 1, 1), - - /* 0001 1011 ... */ - /* 00 */ V(0, 10, 2), /* 326 */ - /* 01 */ V(10, 0, 2), - /* 10 */ V(6, 8, 1), - /* 11 */ V(6, 8, 1), - - /* 0001 1100 ... */ - /* 0 */ V(8, 6, 1), /* 330 */ - /* 1 */ V(4, 9, 1), - - /* 0001 1101 ... */ - /* 0 */ V(9, 4, 1), /* 332 */ - /* 1 */ V(3, 9, 1), - - /* 0001 1110 ... */ - /* 00 */ V(9, 3, 1), /* 334 */ - /* 01 */ V(9, 3, 1), - /* 10 */ V(7, 7, 2), - /* 11 */ V(0, 9, 2), - - /* 0001 1111 ... */ - /* 0 */ V(5, 8, 1), /* 338 */ - /* 1 */ V(8, 5, 1), - - /* 0010 0000 ... */ - /* 0 */ V(2, 9, 1), /* 340 */ - /* 1 */ V(6, 7, 1), - - /* 0010 0001 ... */ - /* 0 */ V(7, 6, 1), /* 342 */ - /* 1 */ V(9, 2, 1), - - /* 0010 0011 ... */ - /* 0 */ V(1, 9, 1), /* 344 */ - /* 1 */ V(9, 0, 1), - - /* 0010 0100 ... */ - /* 0 */ V(4, 8, 1), /* 346 */ - /* 1 */ V(8, 4, 1), - - /* 0010 0101 ... */ - /* 0 */ V(5, 7, 1), /* 348 */ - /* 1 */ V(7, 5, 1), - - /* 0010 0110 ... */ - /* 0 */ V(3, 8, 1), /* 350 */ - /* 1 */ V(8, 3, 1), - - /* 0010 0111 ... */ - /* 0 */ V(6, 6, 1), /* 352 */ - /* 1 */ V(4, 7, 1), - - /* 0010 1100 ... */ - /* 0 */ V(7, 4, 1), /* 354 */ - /* 1 */ V(0, 8, 1), - - /* 0010 1101 ... */ - /* 0 */ V(8, 0, 1), /* 356 */ - /* 1 */ V(5, 6, 1), - - /* 0010 1110 ... */ - /* 0 */ V(6, 5, 1), /* 358 */ - /* 1 */ V(3, 7, 1), - - /* 0010 1111 ... */ - /* 0 */ V(7, 3, 1), /* 360 */ - /* 1 */ V(4, 6, 1), - - /* 0011 0110 ... */ - /* 0 */ V(0, 7, 1), /* 362 */ - /* 1 */ V(7, 0, 1), - - /* 0011 1110 ... */ - /* 0 */ V(0, 6, 1), /* 364 */ - /* 1 */ V(6, 0, 1), - - /* 0000 0000 0000 ... */ - /* 0 */ V(15, 15, 1), /* 366 */ - /* 1 */ V(14, 15, 1), - - /* 0000 0000 0001 ... */ - /* 0 */ V(15, 14, 1), /* 368 */ - /* 1 */ V(13, 15, 1), - - /* 0000 0000 0011 ... */ - /* 0 */ V(15, 13, 1), /* 370 */ - /* 1 */ V(12, 15, 1), - - /* 0000 0000 0100 ... */ - /* 0 */ V(15, 12, 1), /* 372 */ - /* 1 */ V(13, 14, 1), - - /* 0000 0000 0101 ... */ - /* 0 */ V(14, 13, 1), /* 374 */ - /* 1 */ V(11, 15, 1), - - /* 0000 0000 0111 ... */ - /* 0 */ V(12, 14, 1), /* 376 */ - /* 1 */ V(14, 12, 1), - - /* 0000 0001 1111 ... */ - /* 0 */ V(10, 14, 1), /* 378 */ - /* 1 */ V(0, 15, 1) -]; - -const hufftab16 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 4), - /* 0010 */ PTR(48, 4), - /* 0011 */ PTR(64, 2), - /* 0100 */ V(1, 1, 4), - /* 0101 */ V(0, 1, 4), - /* 0110 */ V(1, 0, 3), - /* 0111 */ V(1, 0, 3), - /* 1000 */ V(0, 0, 1), - /* 1001 */ V(0, 0, 1), - /* 1010 */ V(0, 0, 1), - /* 1011 */ V(0, 0, 1), - /* 1100 */ V(0, 0, 1), - /* 1101 */ V(0, 0, 1), - /* 1110 */ V(0, 0, 1), - /* 1111 */ V(0, 0, 1), - - /* 0000 ... */ - /* 0000 */ PTR(68, 3), /* 16 */ - /* 0001 */ PTR(76, 3), - /* 0010 */ PTR(84, 2), - /* 0011 */ V(15, 15, 4), - /* 0100 */ PTR(88, 2), - /* 0101 */ PTR(92, 1), - /* 0110 */ PTR(94, 4), - /* 0111 */ V(15, 2, 4), - /* 1000 */ PTR(110, 1), - /* 1001 */ V(1, 15, 4), - /* 1010 */ V(15, 1, 4), - /* 1011 */ PTR(112, 4), - /* 1100 */ PTR(128, 4), - /* 1101 */ PTR(144, 4), - /* 1110 */ PTR(160, 4), - /* 1111 */ PTR(176, 4), - - /* 0001 ... */ - /* 0000 */ PTR(192, 4), /* 32 */ - /* 0001 */ PTR(208, 3), - /* 0010 */ PTR(216, 3), - /* 0011 */ PTR(224, 3), - /* 0100 */ PTR(232, 3), - /* 0101 */ PTR(240, 3), - /* 0110 */ PTR(248, 3), - /* 0111 */ PTR(256, 3), - /* 1000 */ PTR(264, 2), - /* 1001 */ PTR(268, 2), - /* 1010 */ PTR(272, 1), - /* 1011 */ PTR(274, 2), - /* 1100 */ PTR(278, 2), - /* 1101 */ PTR(282, 1), - /* 1110 */ V(5, 1, 4), - /* 1111 */ PTR(284, 1), - - /* 0010 ... */ - /* 0000 */ PTR(286, 1), /* 48 */ - /* 0001 */ PTR(288, 1), - /* 0010 */ PTR(290, 1), - /* 0011 */ V(1, 4, 4), - /* 0100 */ V(4, 1, 4), - /* 0101 */ PTR(292, 1), - /* 0110 */ V(2, 3, 4), - /* 0111 */ V(3, 2, 4), - /* 1000 */ V(1, 3, 3), - /* 1001 */ V(1, 3, 3), - /* 1010 */ V(3, 1, 3), - /* 1011 */ V(3, 1, 3), - /* 1100 */ V(0, 3, 4), - /* 1101 */ V(3, 0, 4), - /* 1110 */ V(2, 2, 3), - /* 1111 */ V(2, 2, 3), - - /* 0011 ... */ - /* 00 */ V(1, 2, 2), /* 64 */ - /* 01 */ V(2, 1, 2), - /* 10 */ V(0, 2, 2), - /* 11 */ V(2, 0, 2), - - /* 0000 0000 ... */ - /* 000 */ V(14, 15, 3), /* 68 */ - /* 001 */ V(15, 14, 3), - /* 010 */ V(13, 15, 3), - /* 011 */ V(15, 13, 3), - /* 100 */ V(12, 15, 3), - /* 101 */ V(15, 12, 3), - /* 110 */ V(11, 15, 3), - /* 111 */ V(15, 11, 3), - - /* 0000 0001 ... */ - /* 000 */ V(10, 15, 2), /* 76 */ - /* 001 */ V(10, 15, 2), - /* 010 */ V(15, 10, 3), - /* 011 */ V(9, 15, 3), - /* 100 */ V(15, 9, 3), - /* 101 */ V(15, 8, 3), - /* 110 */ V(8, 15, 2), - /* 111 */ V(8, 15, 2), - - /* 0000 0010 ... */ - /* 00 */ V(7, 15, 2), /* 84 */ - /* 01 */ V(15, 7, 2), - /* 10 */ V(6, 15, 2), - /* 11 */ V(15, 6, 2), - - /* 0000 0100 ... */ - /* 00 */ V(5, 15, 2), /* 88 */ - /* 01 */ V(15, 5, 2), - /* 10 */ V(4, 15, 1), - /* 11 */ V(4, 15, 1), - - /* 0000 0101 ... */ - /* 0 */ V(15, 4, 1), /* 92 */ - /* 1 */ V(15, 3, 1), - - /* 0000 0110 ... */ - /* 0000 */ V(15, 0, 1), /* 94 */ - /* 0001 */ V(15, 0, 1), - /* 0010 */ V(15, 0, 1), - /* 0011 */ V(15, 0, 1), - /* 0100 */ V(15, 0, 1), - /* 0101 */ V(15, 0, 1), - /* 0110 */ V(15, 0, 1), - /* 0111 */ V(15, 0, 1), - /* 1000 */ V(3, 15, 2), - /* 1001 */ V(3, 15, 2), - /* 1010 */ V(3, 15, 2), - /* 1011 */ V(3, 15, 2), - /* 1100 */ PTR(294, 4), - /* 1101 */ PTR(310, 3), - /* 1110 */ PTR(318, 3), - /* 1111 */ PTR(326, 3), - - /* 0000 1000 ... */ - /* 0 */ V(2, 15, 1), /* 110 */ - /* 1 */ V(0, 15, 1), - - /* 0000 1011 ... */ - /* 0000 */ PTR(334, 2), /* 112 */ - /* 0001 */ PTR(338, 2), - /* 0010 */ PTR(342, 2), - /* 0011 */ PTR(346, 1), - /* 0100 */ PTR(348, 2), - /* 0101 */ PTR(352, 2), - /* 0110 */ PTR(356, 1), - /* 0111 */ PTR(358, 2), - /* 1000 */ PTR(362, 2), - /* 1001 */ PTR(366, 2), - /* 1010 */ PTR(370, 2), - /* 1011 */ V(14, 3, 4), - /* 1100 */ PTR(374, 1), - /* 1101 */ PTR(376, 1), - /* 1110 */ PTR(378, 1), - /* 1111 */ PTR(380, 1), - - /* 0000 1100 ... */ - /* 0000 */ PTR(382, 1), /* 128 */ - /* 0001 */ PTR(384, 1), - /* 0010 */ PTR(386, 1), - /* 0011 */ V(0, 13, 4), - /* 0100 */ PTR(388, 1), - /* 0101 */ PTR(390, 1), - /* 0110 */ PTR(392, 1), - /* 0111 */ V(3, 12, 4), - /* 1000 */ PTR(394, 1), - /* 1001 */ V(1, 12, 4), - /* 1010 */ V(12, 0, 4), - /* 1011 */ PTR(396, 1), - /* 1100 */ V(14, 2, 3), - /* 1101 */ V(14, 2, 3), - /* 1110 */ V(2, 14, 4), - /* 1111 */ V(1, 14, 4), - - /* 0000 1101 ... */ - /* 0000 */ V(13, 3, 4), /* 144 */ - /* 0001 */ V(2, 13, 4), - /* 0010 */ V(13, 2, 4), - /* 0011 */ V(13, 1, 4), - /* 0100 */ V(3, 11, 4), - /* 0101 */ PTR(398, 1), - /* 0110 */ V(1, 13, 3), - /* 0111 */ V(1, 13, 3), - /* 1000 */ V(12, 4, 4), - /* 1001 */ V(6, 11, 4), - /* 1010 */ V(12, 3, 4), - /* 1011 */ V(10, 7, 4), - /* 1100 */ V(2, 12, 3), - /* 1101 */ V(2, 12, 3), - /* 1110 */ V(12, 2, 4), - /* 1111 */ V(11, 5, 4), - - /* 0000 1110 ... */ - /* 0000 */ V(12, 1, 4), /* 160 */ - /* 0001 */ V(0, 12, 4), - /* 0010 */ V(4, 11, 4), - /* 0011 */ V(11, 4, 4), - /* 0100 */ V(6, 10, 4), - /* 0101 */ V(10, 6, 4), - /* 0110 */ V(11, 3, 3), - /* 0111 */ V(11, 3, 3), - /* 1000 */ V(5, 10, 4), - /* 1001 */ V(10, 5, 4), - /* 1010 */ V(2, 11, 3), - /* 1011 */ V(2, 11, 3), - /* 1100 */ V(11, 2, 3), - /* 1101 */ V(11, 2, 3), - /* 1110 */ V(1, 11, 3), - /* 1111 */ V(1, 11, 3), - - /* 0000 1111 ... */ - /* 0000 */ V(11, 1, 3), /* 176 */ - /* 0001 */ V(11, 1, 3), - /* 0010 */ V(0, 11, 4), - /* 0011 */ V(11, 0, 4), - /* 0100 */ V(6, 9, 4), - /* 0101 */ V(9, 6, 4), - /* 0110 */ V(4, 10, 4), - /* 0111 */ V(10, 4, 4), - /* 1000 */ V(7, 8, 4), - /* 1001 */ V(8, 7, 4), - /* 1010 */ V(10, 3, 3), - /* 1011 */ V(10, 3, 3), - /* 1100 */ V(3, 10, 4), - /* 1101 */ V(5, 9, 4), - /* 1110 */ V(2, 10, 3), - /* 1111 */ V(2, 10, 3), - - /* 0001 0000 ... */ - /* 0000 */ V(9, 5, 4), /* 192 */ - /* 0001 */ V(6, 8, 4), - /* 0010 */ V(10, 1, 3), - /* 0011 */ V(10, 1, 3), - /* 0100 */ V(8, 6, 4), - /* 0101 */ V(7, 7, 4), - /* 0110 */ V(9, 4, 3), - /* 0111 */ V(9, 4, 3), - /* 1000 */ V(4, 9, 4), - /* 1001 */ V(5, 7, 4), - /* 1010 */ V(6, 7, 3), - /* 1011 */ V(6, 7, 3), - /* 1100 */ V(10, 2, 2), - /* 1101 */ V(10, 2, 2), - /* 1110 */ V(10, 2, 2), - /* 1111 */ V(10, 2, 2), - - /* 0001 0001 ... */ - /* 000 */ V(1, 10, 2), /* 208 */ - /* 001 */ V(1, 10, 2), - /* 010 */ V(0, 10, 3), - /* 011 */ V(10, 0, 3), - /* 100 */ V(3, 9, 3), - /* 101 */ V(9, 3, 3), - /* 110 */ V(5, 8, 3), - /* 111 */ V(8, 5, 3), - - /* 0001 0010 ... */ - /* 000 */ V(2, 9, 2), /* 216 */ - /* 001 */ V(2, 9, 2), - /* 010 */ V(9, 2, 2), - /* 011 */ V(9, 2, 2), - /* 100 */ V(7, 6, 3), - /* 101 */ V(0, 9, 3), - /* 110 */ V(1, 9, 2), - /* 111 */ V(1, 9, 2), - - /* 0001 0011 ... */ - /* 000 */ V(9, 1, 2), /* 224 */ - /* 001 */ V(9, 1, 2), - /* 010 */ V(9, 0, 3), - /* 011 */ V(4, 8, 3), - /* 100 */ V(8, 4, 3), - /* 101 */ V(7, 5, 3), - /* 110 */ V(3, 8, 3), - /* 111 */ V(8, 3, 3), - - /* 0001 0100 ... */ - /* 000 */ V(6, 6, 3), /* 232 */ - /* 001 */ V(2, 8, 3), - /* 010 */ V(8, 2, 2), - /* 011 */ V(8, 2, 2), - /* 100 */ V(4, 7, 3), - /* 101 */ V(7, 4, 3), - /* 110 */ V(1, 8, 2), - /* 111 */ V(1, 8, 2), - - /* 0001 0101 ... */ - /* 000 */ V(8, 1, 2), /* 240 */ - /* 001 */ V(8, 1, 2), - /* 010 */ V(8, 0, 2), - /* 011 */ V(8, 0, 2), - /* 100 */ V(0, 8, 3), - /* 101 */ V(5, 6, 3), - /* 110 */ V(3, 7, 2), - /* 111 */ V(3, 7, 2), - - /* 0001 0110 ... */ - /* 000 */ V(7, 3, 2), /* 248 */ - /* 001 */ V(7, 3, 2), - /* 010 */ V(6, 5, 3), - /* 011 */ V(4, 6, 3), - /* 100 */ V(2, 7, 2), - /* 101 */ V(2, 7, 2), - /* 110 */ V(7, 2, 2), - /* 111 */ V(7, 2, 2), - - /* 0001 0111 ... */ - /* 000 */ V(6, 4, 3), /* 256 */ - /* 001 */ V(5, 5, 3), - /* 010 */ V(0, 7, 2), - /* 011 */ V(0, 7, 2), - /* 100 */ V(1, 7, 1), - /* 101 */ V(1, 7, 1), - /* 110 */ V(1, 7, 1), - /* 111 */ V(1, 7, 1), - - /* 0001 1000 ... */ - /* 00 */ V(7, 1, 1), /* 264 */ - /* 01 */ V(7, 1, 1), - /* 10 */ V(7, 0, 2), - /* 11 */ V(3, 6, 2), - - /* 0001 1001 ... */ - /* 00 */ V(6, 3, 2), /* 268 */ - /* 01 */ V(4, 5, 2), - /* 10 */ V(5, 4, 2), - /* 11 */ V(2, 6, 2), - - /* 0001 1010 ... */ - /* 0 */ V(6, 2, 1), /* 272 */ - /* 1 */ V(1, 6, 1), - - /* 0001 1011 ... */ - /* 00 */ V(6, 1, 1), /* 274 */ - /* 01 */ V(6, 1, 1), - /* 10 */ V(0, 6, 2), - /* 11 */ V(6, 0, 2), - - /* 0001 1100 ... */ - /* 00 */ V(5, 3, 1), /* 278 */ - /* 01 */ V(5, 3, 1), - /* 10 */ V(3, 5, 2), - /* 11 */ V(4, 4, 2), - - /* 0001 1101 ... */ - /* 0 */ V(2, 5, 1), /* 282 */ - /* 1 */ V(5, 2, 1), - - /* 0001 1111 ... */ - /* 0 */ V(1, 5, 1), /* 284 */ - /* 1 */ V(0, 5, 1), - - /* 0010 0000 ... */ - /* 0 */ V(3, 4, 1), /* 286 */ - /* 1 */ V(4, 3, 1), - - /* 0010 0001 ... */ - /* 0 */ V(5, 0, 1), /* 288 */ - /* 1 */ V(2, 4, 1), - - /* 0010 0010 ... */ - /* 0 */ V(4, 2, 1), /* 290 */ - /* 1 */ V(3, 3, 1), - - /* 0010 0101 ... */ - /* 0 */ V(0, 4, 1), /* 292 */ - /* 1 */ V(4, 0, 1), - - /* 0000 0110 1100 ... */ - /* 0000 */ V(12, 14, 4), /* 294 */ - /* 0001 */ PTR(400, 1), - /* 0010 */ V(13, 14, 3), - /* 0011 */ V(13, 14, 3), - /* 0100 */ V(14, 9, 3), - /* 0101 */ V(14, 9, 3), - /* 0110 */ V(14, 10, 4), - /* 0111 */ V(13, 9, 4), - /* 1000 */ V(14, 14, 2), - /* 1001 */ V(14, 14, 2), - /* 1010 */ V(14, 14, 2), - /* 1011 */ V(14, 14, 2), - /* 1100 */ V(14, 13, 3), - /* 1101 */ V(14, 13, 3), - /* 1110 */ V(14, 11, 3), - /* 1111 */ V(14, 11, 3), - - /* 0000 0110 1101 ... */ - /* 000 */ V(11, 14, 2), /* 310 */ - /* 001 */ V(11, 14, 2), - /* 010 */ V(12, 13, 2), - /* 011 */ V(12, 13, 2), - /* 100 */ V(13, 12, 3), - /* 101 */ V(13, 11, 3), - /* 110 */ V(10, 14, 2), - /* 111 */ V(10, 14, 2), - - /* 0000 0110 1110 ... */ - /* 000 */ V(12, 12, 2), /* 318 */ - /* 001 */ V(12, 12, 2), - /* 010 */ V(10, 13, 3), - /* 011 */ V(13, 10, 3), - /* 100 */ V(7, 14, 3), - /* 101 */ V(10, 12, 3), - /* 110 */ V(12, 10, 2), - /* 111 */ V(12, 10, 2), - - /* 0000 0110 1111 ... */ - /* 000 */ V(12, 9, 3), /* 326 */ - /* 001 */ V(7, 13, 3), - /* 010 */ V(5, 14, 2), - /* 011 */ V(5, 14, 2), - /* 100 */ V(11, 13, 1), - /* 101 */ V(11, 13, 1), - /* 110 */ V(11, 13, 1), - /* 111 */ V(11, 13, 1), - - /* 0000 1011 0000 ... */ - /* 00 */ V(9, 14, 1), /* 334 */ - /* 01 */ V(9, 14, 1), - /* 10 */ V(11, 12, 2), - /* 11 */ V(12, 11, 2), - - /* 0000 1011 0001 ... */ - /* 00 */ V(8, 14, 2), /* 338 */ - /* 01 */ V(14, 8, 2), - /* 10 */ V(9, 13, 2), - /* 11 */ V(14, 7, 2), - - /* 0000 1011 0010 ... */ - /* 00 */ V(11, 11, 2), /* 342 */ - /* 01 */ V(8, 13, 2), - /* 10 */ V(13, 8, 2), - /* 11 */ V(6, 14, 2), - - /* 0000 1011 0011 ... */ - /* 0 */ V(14, 6, 1), /* 346 */ - /* 1 */ V(9, 12, 1), - - /* 0000 1011 0100 ... */ - /* 00 */ V(10, 11, 2), /* 348 */ - /* 01 */ V(11, 10, 2), - /* 10 */ V(14, 5, 2), - /* 11 */ V(13, 7, 2), - - /* 0000 1011 0101 ... */ - /* 00 */ V(4, 14, 1), /* 352 */ - /* 01 */ V(4, 14, 1), - /* 10 */ V(14, 4, 2), - /* 11 */ V(8, 12, 2), - - /* 0000 1011 0110 ... */ - /* 0 */ V(12, 8, 1), /* 356 */ - /* 1 */ V(3, 14, 1), - - /* 0000 1011 0111 ... */ - /* 00 */ V(6, 13, 1), /* 358 */ - /* 01 */ V(6, 13, 1), - /* 10 */ V(13, 6, 2), - /* 11 */ V(9, 11, 2), - - /* 0000 1011 1000 ... */ - /* 00 */ V(11, 9, 2), /* 362 */ - /* 01 */ V(10, 10, 2), - /* 10 */ V(14, 1, 1), - /* 11 */ V(14, 1, 1), - - /* 0000 1011 1001 ... */ - /* 00 */ V(13, 4, 1), /* 366 */ - /* 01 */ V(13, 4, 1), - /* 10 */ V(11, 8, 2), - /* 11 */ V(10, 9, 2), - - /* 0000 1011 1010 ... */ - /* 00 */ V(7, 11, 1), /* 370 */ - /* 01 */ V(7, 11, 1), - /* 10 */ V(11, 7, 2), - /* 11 */ V(13, 0, 2), - - /* 0000 1011 1100 ... */ - /* 0 */ V(0, 14, 1), /* 374 */ - /* 1 */ V(14, 0, 1), - - /* 0000 1011 1101 ... */ - /* 0 */ V(5, 13, 1), /* 376 */ - /* 1 */ V(13, 5, 1), - - /* 0000 1011 1110 ... */ - /* 0 */ V(7, 12, 1), /* 378 */ - /* 1 */ V(12, 7, 1), - - /* 0000 1011 1111 ... */ - /* 0 */ V(4, 13, 1), /* 380 */ - /* 1 */ V(8, 11, 1), - - /* 0000 1100 0000 ... */ - /* 0 */ V(9, 10, 1), /* 382 */ - /* 1 */ V(6, 12, 1), - - /* 0000 1100 0001 ... */ - /* 0 */ V(12, 6, 1), /* 384 */ - /* 1 */ V(3, 13, 1), - - /* 0000 1100 0010 ... */ - /* 0 */ V(5, 12, 1), /* 386 */ - /* 1 */ V(12, 5, 1), - - /* 0000 1100 0100 ... */ - /* 0 */ V(8, 10, 1), /* 388 */ - /* 1 */ V(10, 8, 1), - - /* 0000 1100 0101 ... */ - /* 0 */ V(9, 9, 1), /* 390 */ - /* 1 */ V(4, 12, 1), - - /* 0000 1100 0110 ... */ - /* 0 */ V(11, 6, 1), /* 392 */ - /* 1 */ V(7, 10, 1), - - /* 0000 1100 1000 ... */ - /* 0 */ V(5, 11, 1), /* 394 */ - /* 1 */ V(8, 9, 1), - - /* 0000 1100 1011 ... */ - /* 0 */ V(9, 8, 1), /* 396 */ - /* 1 */ V(7, 9, 1), - - /* 0000 1101 0101 ... */ - /* 0 */ V(9, 7, 1), /* 398 */ - /* 1 */ V(8, 8, 1), - - /* 0000 0110 1100 0001 ... */ - /* 0 */ V(14, 12, 1), /* 400 */ - /* 1 */ V(13, 13, 1) -]; - -const hufftab24 = [ - /* 0000 */ PTR(16, 4), - /* 0001 */ PTR(32, 4), - /* 0010 */ PTR(48, 4), - /* 0011 */ V(15, 15, 4), - /* 0100 */ PTR(64, 4), - /* 0101 */ PTR(80, 4), - /* 0110 */ PTR(96, 4), - /* 0111 */ PTR(112, 4), - /* 1000 */ PTR(128, 4), - /* 1001 */ PTR(144, 4), - /* 1010 */ PTR(160, 3), - /* 1011 */ PTR(168, 2), - /* 1100 */ V(1, 1, 4), - /* 1101 */ V(0, 1, 4), - /* 1110 */ V(1, 0, 4), - /* 1111 */ V(0, 0, 4), - - /* 0000 ... */ - /* 0000 */ V(14, 15, 4), /* 16 */ - /* 0001 */ V(15, 14, 4), - /* 0010 */ V(13, 15, 4), - /* 0011 */ V(15, 13, 4), - /* 0100 */ V(12, 15, 4), - /* 0101 */ V(15, 12, 4), - /* 0110 */ V(11, 15, 4), - /* 0111 */ V(15, 11, 4), - /* 1000 */ V(15, 10, 3), - /* 1001 */ V(15, 10, 3), - /* 1010 */ V(10, 15, 4), - /* 1011 */ V(9, 15, 4), - /* 1100 */ V(15, 9, 3), - /* 1101 */ V(15, 9, 3), - /* 1110 */ V(15, 8, 3), - /* 1111 */ V(15, 8, 3), - - /* 0001 ... */ - /* 0000 */ V(8, 15, 4), /* 32 */ - /* 0001 */ V(7, 15, 4), - /* 0010 */ V(15, 7, 3), - /* 0011 */ V(15, 7, 3), - /* 0100 */ V(6, 15, 3), - /* 0101 */ V(6, 15, 3), - /* 0110 */ V(15, 6, 3), - /* 0111 */ V(15, 6, 3), - /* 1000 */ V(5, 15, 3), - /* 1001 */ V(5, 15, 3), - /* 1010 */ V(15, 5, 3), - /* 1011 */ V(15, 5, 3), - /* 1100 */ V(4, 15, 3), - /* 1101 */ V(4, 15, 3), - /* 1110 */ V(15, 4, 3), - /* 1111 */ V(15, 4, 3), - - /* 0010 ... */ - /* 0000 */ V(3, 15, 3), /* 48 */ - /* 0001 */ V(3, 15, 3), - /* 0010 */ V(15, 3, 3), - /* 0011 */ V(15, 3, 3), - /* 0100 */ V(2, 15, 3), - /* 0101 */ V(2, 15, 3), - /* 0110 */ V(15, 2, 3), - /* 0111 */ V(15, 2, 3), - /* 1000 */ V(15, 1, 3), - /* 1001 */ V(15, 1, 3), - /* 1010 */ V(1, 15, 4), - /* 1011 */ V(15, 0, 4), - /* 1100 */ PTR(172, 3), - /* 1101 */ PTR(180, 3), - /* 1110 */ PTR(188, 3), - /* 1111 */ PTR(196, 3), - - /* 0100 ... */ - /* 0000 */ PTR(204, 4), /* 64 */ - /* 0001 */ PTR(220, 3), - /* 0010 */ PTR(228, 3), - /* 0011 */ PTR(236, 3), - /* 0100 */ PTR(244, 2), - /* 0101 */ PTR(248, 2), - /* 0110 */ PTR(252, 2), - /* 0111 */ PTR(256, 2), - /* 1000 */ PTR(260, 2), - /* 1001 */ PTR(264, 2), - /* 1010 */ PTR(268, 2), - /* 1011 */ PTR(272, 2), - /* 1100 */ PTR(276, 2), - /* 1101 */ PTR(280, 3), - /* 1110 */ PTR(288, 2), - /* 1111 */ PTR(292, 2), - - /* 0101 ... */ - /* 0000 */ PTR(296, 2), /* 80 */ - /* 0001 */ PTR(300, 3), - /* 0010 */ PTR(308, 2), - /* 0011 */ PTR(312, 3), - /* 0100 */ PTR(320, 1), - /* 0101 */ PTR(322, 2), - /* 0110 */ PTR(326, 2), - /* 0111 */ PTR(330, 1), - /* 1000 */ PTR(332, 2), - /* 1001 */ PTR(336, 1), - /* 1010 */ PTR(338, 1), - /* 1011 */ PTR(340, 1), - /* 1100 */ PTR(342, 1), - /* 1101 */ PTR(344, 1), - /* 1110 */ PTR(346, 1), - /* 1111 */ PTR(348, 1), - - /* 0110 ... */ - /* 0000 */ PTR(350, 1), /* 96 */ - /* 0001 */ PTR(352, 1), - /* 0010 */ PTR(354, 1), - /* 0011 */ PTR(356, 1), - /* 0100 */ PTR(358, 1), - /* 0101 */ PTR(360, 1), - /* 0110 */ PTR(362, 1), - /* 0111 */ PTR(364, 1), - /* 1000 */ PTR(366, 1), - /* 1001 */ PTR(368, 1), - /* 1010 */ PTR(370, 2), - /* 1011 */ PTR(374, 1), - /* 1100 */ PTR(376, 2), - /* 1101 */ V(7, 3, 4), - /* 1110 */ PTR(380, 1), - /* 1111 */ V(7, 2, 4), - - /* 0111 ... */ - /* 0000 */ V(4, 6, 4), /* 112 */ - /* 0001 */ V(6, 4, 4), - /* 0010 */ V(5, 5, 4), - /* 0011 */ V(7, 1, 4), - /* 0100 */ V(3, 6, 4), - /* 0101 */ V(6, 3, 4), - /* 0110 */ V(4, 5, 4), - /* 0111 */ V(5, 4, 4), - /* 1000 */ V(2, 6, 4), - /* 1001 */ V(6, 2, 4), - /* 1010 */ V(1, 6, 4), - /* 1011 */ V(6, 1, 4), - /* 1100 */ PTR(382, 1), - /* 1101 */ V(3, 5, 4), - /* 1110 */ V(5, 3, 4), - /* 1111 */ V(4, 4, 4), - - /* 1000 ... */ - /* 0000 */ V(2, 5, 4), /* 128 */ - /* 0001 */ V(5, 2, 4), - /* 0010 */ V(1, 5, 4), - /* 0011 */ PTR(384, 1), - /* 0100 */ V(5, 1, 3), - /* 0101 */ V(5, 1, 3), - /* 0110 */ V(3, 4, 4), - /* 0111 */ V(4, 3, 4), - /* 1000 */ V(2, 4, 3), - /* 1001 */ V(2, 4, 3), - /* 1010 */ V(4, 2, 3), - /* 1011 */ V(4, 2, 3), - /* 1100 */ V(3, 3, 3), - /* 1101 */ V(3, 3, 3), - /* 1110 */ V(1, 4, 3), - /* 1111 */ V(1, 4, 3), - - /* 1001 ... */ - /* 0000 */ V(4, 1, 3), /* 144 */ - /* 0001 */ V(4, 1, 3), - /* 0010 */ V(0, 4, 4), - /* 0011 */ V(4, 0, 4), - /* 0100 */ V(2, 3, 3), - /* 0101 */ V(2, 3, 3), - /* 0110 */ V(3, 2, 3), - /* 0111 */ V(3, 2, 3), - /* 1000 */ V(1, 3, 2), - /* 1001 */ V(1, 3, 2), - /* 1010 */ V(1, 3, 2), - /* 1011 */ V(1, 3, 2), - /* 1100 */ V(3, 1, 2), - /* 1101 */ V(3, 1, 2), - /* 1110 */ V(3, 1, 2), - /* 1111 */ V(3, 1, 2), - - /* 1010 ... */ - /* 000 */ V(0, 3, 3), /* 160 */ - /* 001 */ V(3, 0, 3), - /* 010 */ V(2, 2, 2), - /* 011 */ V(2, 2, 2), - /* 100 */ V(1, 2, 1), - /* 101 */ V(1, 2, 1), - /* 110 */ V(1, 2, 1), - /* 111 */ V(1, 2, 1), - - /* 1011 ... */ - /* 00 */ V(2, 1, 1), /* 168 */ - /* 01 */ V(2, 1, 1), - /* 10 */ V(0, 2, 2), - /* 11 */ V(2, 0, 2), - - /* 0010 1100 ... */ - /* 000 */ V(0, 15, 1), /* 172 */ - /* 001 */ V(0, 15, 1), - /* 010 */ V(0, 15, 1), - /* 011 */ V(0, 15, 1), - /* 100 */ V(14, 14, 3), - /* 101 */ V(13, 14, 3), - /* 110 */ V(14, 13, 3), - /* 111 */ V(12, 14, 3), - - /* 0010 1101 ... */ - /* 000 */ V(14, 12, 3), /* 180 */ - /* 001 */ V(13, 13, 3), - /* 010 */ V(11, 14, 3), - /* 011 */ V(14, 11, 3), - /* 100 */ V(12, 13, 3), - /* 101 */ V(13, 12, 3), - /* 110 */ V(10, 14, 3), - /* 111 */ V(14, 10, 3), - - /* 0010 1110 ... */ - /* 000 */ V(11, 13, 3), /* 188 */ - /* 001 */ V(13, 11, 3), - /* 010 */ V(12, 12, 3), - /* 011 */ V(9, 14, 3), - /* 100 */ V(14, 9, 3), - /* 101 */ V(10, 13, 3), - /* 110 */ V(13, 10, 3), - /* 111 */ V(11, 12, 3), - - /* 0010 1111 ... */ - /* 000 */ V(12, 11, 3), /* 196 */ - /* 001 */ V(8, 14, 3), - /* 010 */ V(14, 8, 3), - /* 011 */ V(9, 13, 3), - /* 100 */ V(13, 9, 3), - /* 101 */ V(7, 14, 3), - /* 110 */ V(14, 7, 3), - /* 111 */ V(10, 12, 3), - - /* 0100 0000 ... */ - /* 0000 */ V(12, 10, 3), /* 204 */ - /* 0001 */ V(12, 10, 3), - /* 0010 */ V(11, 11, 3), - /* 0011 */ V(11, 11, 3), - /* 0100 */ V(8, 13, 3), - /* 0101 */ V(8, 13, 3), - /* 0110 */ V(13, 8, 3), - /* 0111 */ V(13, 8, 3), - /* 1000 */ V(0, 14, 4), - /* 1001 */ V(14, 0, 4), - /* 1010 */ V(0, 13, 3), - /* 1011 */ V(0, 13, 3), - /* 1100 */ V(14, 6, 2), - /* 1101 */ V(14, 6, 2), - /* 1110 */ V(14, 6, 2), - /* 1111 */ V(14, 6, 2), - - /* 0100 0001 ... */ - /* 000 */ V(6, 14, 3), /* 220 */ - /* 001 */ V(9, 12, 3), - /* 010 */ V(12, 9, 2), - /* 011 */ V(12, 9, 2), - /* 100 */ V(5, 14, 2), - /* 101 */ V(5, 14, 2), - /* 110 */ V(11, 10, 2), - /* 111 */ V(11, 10, 2), - - /* 0100 0010 ... */ - /* 000 */ V(14, 5, 2), /* 228 */ - /* 001 */ V(14, 5, 2), - /* 010 */ V(10, 11, 3), - /* 011 */ V(7, 13, 3), - /* 100 */ V(13, 7, 2), - /* 101 */ V(13, 7, 2), - /* 110 */ V(14, 4, 2), - /* 111 */ V(14, 4, 2), - - /* 0100 0011 ... */ - /* 000 */ V(8, 12, 2), /* 236 */ - /* 001 */ V(8, 12, 2), - /* 010 */ V(12, 8, 2), - /* 011 */ V(12, 8, 2), - /* 100 */ V(4, 14, 3), - /* 101 */ V(2, 14, 3), - /* 110 */ V(3, 14, 2), - /* 111 */ V(3, 14, 2), - - /* 0100 0100 ... */ - /* 00 */ V(6, 13, 2), /* 244 */ - /* 01 */ V(13, 6, 2), - /* 10 */ V(14, 3, 2), - /* 11 */ V(9, 11, 2), - - /* 0100 0101 ... */ - /* 00 */ V(11, 9, 2), /* 248 */ - /* 01 */ V(10, 10, 2), - /* 10 */ V(14, 2, 2), - /* 11 */ V(1, 14, 2), - - /* 0100 0110 ... */ - /* 00 */ V(14, 1, 2), /* 252 */ - /* 01 */ V(5, 13, 2), - /* 10 */ V(13, 5, 2), - /* 11 */ V(7, 12, 2), - - /* 0100 0111 ... */ - /* 00 */ V(12, 7, 2), /* 256 */ - /* 01 */ V(4, 13, 2), - /* 10 */ V(8, 11, 2), - /* 11 */ V(11, 8, 2), - - /* 0100 1000 ... */ - /* 00 */ V(13, 4, 2), /* 260 */ - /* 01 */ V(9, 10, 2), - /* 10 */ V(10, 9, 2), - /* 11 */ V(6, 12, 2), - - /* 0100 1001 ... */ - /* 00 */ V(12, 6, 2), /* 264 */ - /* 01 */ V(3, 13, 2), - /* 10 */ V(13, 3, 2), - /* 11 */ V(2, 13, 2), - - /* 0100 1010 ... */ - /* 00 */ V(13, 2, 2), /* 268 */ - /* 01 */ V(1, 13, 2), - /* 10 */ V(7, 11, 2), - /* 11 */ V(11, 7, 2), - - /* 0100 1011 ... */ - /* 00 */ V(13, 1, 2), /* 272 */ - /* 01 */ V(5, 12, 2), - /* 10 */ V(12, 5, 2), - /* 11 */ V(8, 10, 2), - - /* 0100 1100 ... */ - /* 00 */ V(10, 8, 2), /* 276 */ - /* 01 */ V(9, 9, 2), - /* 10 */ V(4, 12, 2), - /* 11 */ V(12, 4, 2), - - /* 0100 1101 ... */ - /* 000 */ V(6, 11, 2), /* 280 */ - /* 001 */ V(6, 11, 2), - /* 010 */ V(11, 6, 2), - /* 011 */ V(11, 6, 2), - /* 100 */ V(13, 0, 3), - /* 101 */ V(0, 12, 3), - /* 110 */ V(3, 12, 2), - /* 111 */ V(3, 12, 2), - - /* 0100 1110 ... */ - /* 00 */ V(12, 3, 2), /* 288 */ - /* 01 */ V(7, 10, 2), - /* 10 */ V(10, 7, 2), - /* 11 */ V(2, 12, 2), - - /* 0100 1111 ... */ - /* 00 */ V(12, 2, 2), /* 292 */ - /* 01 */ V(5, 11, 2), - /* 10 */ V(11, 5, 2), - /* 11 */ V(1, 12, 2), - - /* 0101 0000 ... */ - /* 00 */ V(8, 9, 2), /* 296 */ - /* 01 */ V(9, 8, 2), - /* 10 */ V(12, 1, 2), - /* 11 */ V(4, 11, 2), - - /* 0101 0001 ... */ - /* 000 */ V(12, 0, 3), /* 300 */ - /* 001 */ V(0, 11, 3), - /* 010 */ V(3, 11, 2), - /* 011 */ V(3, 11, 2), - /* 100 */ V(11, 0, 3), - /* 101 */ V(0, 10, 3), - /* 110 */ V(1, 10, 2), - /* 111 */ V(1, 10, 2), - - /* 0101 0010 ... */ - /* 00 */ V(11, 4, 1), /* 308 */ - /* 01 */ V(11, 4, 1), - /* 10 */ V(6, 10, 2), - /* 11 */ V(10, 6, 2), - - /* 0101 0011 ... */ - /* 000 */ V(7, 9, 2), /* 312 */ - /* 001 */ V(7, 9, 2), - /* 010 */ V(9, 7, 2), - /* 011 */ V(9, 7, 2), - /* 100 */ V(10, 0, 3), - /* 101 */ V(0, 9, 3), - /* 110 */ V(9, 0, 2), - /* 111 */ V(9, 0, 2), - - /* 0101 0100 ... */ - /* 0 */ V(11, 3, 1), /* 320 */ - /* 1 */ V(8, 8, 1), - - /* 0101 0101 ... */ - /* 00 */ V(2, 11, 2), /* 322 */ - /* 01 */ V(5, 10, 2), - /* 10 */ V(11, 2, 1), - /* 11 */ V(11, 2, 1), - - /* 0101 0110 ... */ - /* 00 */ V(10, 5, 2), /* 326 */ - /* 01 */ V(1, 11, 2), - /* 10 */ V(11, 1, 2), - /* 11 */ V(6, 9, 2), - - /* 0101 0111 ... */ - /* 0 */ V(9, 6, 1), /* 330 */ - /* 1 */ V(10, 4, 1), - - /* 0101 1000 ... */ - /* 00 */ V(4, 10, 2), /* 332 */ - /* 01 */ V(7, 8, 2), - /* 10 */ V(8, 7, 1), - /* 11 */ V(8, 7, 1), - - /* 0101 1001 ... */ - /* 0 */ V(3, 10, 1), /* 336 */ - /* 1 */ V(10, 3, 1), - - /* 0101 1010 ... */ - /* 0 */ V(5, 9, 1), /* 338 */ - /* 1 */ V(9, 5, 1), - - /* 0101 1011 ... */ - /* 0 */ V(2, 10, 1), /* 340 */ - /* 1 */ V(10, 2, 1), - - /* 0101 1100 ... */ - /* 0 */ V(10, 1, 1), /* 342 */ - /* 1 */ V(6, 8, 1), - - /* 0101 1101 ... */ - /* 0 */ V(8, 6, 1), /* 344 */ - /* 1 */ V(7, 7, 1), - - /* 0101 1110 ... */ - /* 0 */ V(4, 9, 1), /* 346 */ - /* 1 */ V(9, 4, 1), - - /* 0101 1111 ... */ - /* 0 */ V(3, 9, 1), /* 348 */ - /* 1 */ V(9, 3, 1), - - /* 0110 0000 ... */ - /* 0 */ V(5, 8, 1), /* 350 */ - /* 1 */ V(8, 5, 1), - - /* 0110 0001 ... */ - /* 0 */ V(2, 9, 1), /* 352 */ - /* 1 */ V(6, 7, 1), - - /* 0110 0010 ... */ - /* 0 */ V(7, 6, 1), /* 354 */ - /* 1 */ V(9, 2, 1), - - /* 0110 0011 ... */ - /* 0 */ V(1, 9, 1), /* 356 */ - /* 1 */ V(9, 1, 1), - - /* 0110 0100 ... */ - /* 0 */ V(4, 8, 1), /* 358 */ - /* 1 */ V(8, 4, 1), - - /* 0110 0101 ... */ - /* 0 */ V(5, 7, 1), /* 360 */ - /* 1 */ V(7, 5, 1), - - /* 0110 0110 ... */ - /* 0 */ V(3, 8, 1), /* 362 */ - /* 1 */ V(8, 3, 1), - - /* 0110 0111 ... */ - /* 0 */ V(6, 6, 1), /* 364 */ - /* 1 */ V(2, 8, 1), - - /* 0110 1000 ... */ - /* 0 */ V(8, 2, 1), /* 366 */ - /* 1 */ V(1, 8, 1), - - /* 0110 1001 ... */ - /* 0 */ V(4, 7, 1), /* 368 */ - /* 1 */ V(7, 4, 1), - - /* 0110 1010 ... */ - /* 00 */ V(8, 1, 1), /* 370 */ - /* 01 */ V(8, 1, 1), - /* 10 */ V(0, 8, 2), - /* 11 */ V(8, 0, 2), - - /* 0110 1011 ... */ - /* 0 */ V(5, 6, 1), /* 374 */ - /* 1 */ V(6, 5, 1), - - /* 0110 1100 ... */ - /* 00 */ V(1, 7, 1), /* 376 */ - /* 01 */ V(1, 7, 1), - /* 10 */ V(0, 7, 2), - /* 11 */ V(7, 0, 2), - - /* 0110 1110 ... */ - /* 0 */ V(3, 7, 1), /* 380 */ - /* 1 */ V(2, 7, 1), - - /* 0111 1100 ... */ - /* 0 */ V(0, 6, 1), /* 382 */ - /* 1 */ V(6, 0, 1), - - /* 1000 0011 ... */ - /* 0 */ V(0, 5, 1), /* 384 */ - /* 1 */ V(5, 0, 1) -]; - -/* hufftable constructor */ -function MP3Hufftable(table, linbits, startbits) { - this.table = table; - this.linbits = linbits; - this.startbits = startbits; -}; - -/* external tables */ -exports.huff_quad_table = [ hufftabA, hufftabB ]; -exports.huff_pair_table = [ - /* 0 */ new MP3Hufftable(hufftab0, 0, 0), - /* 1 */ new MP3Hufftable(hufftab1, 0, 3), - /* 2 */ new MP3Hufftable(hufftab2, 0, 3), - /* 3 */ new MP3Hufftable(hufftab3, 0, 3), - /* 4 */ null, //new MP3Hufftable(0 /* not used */), - /* 5 */ new MP3Hufftable(hufftab5, 0, 3), - /* 6 */ new MP3Hufftable(hufftab6, 0, 4), - /* 7 */ new MP3Hufftable(hufftab7, 0, 4), - /* 8 */ new MP3Hufftable(hufftab8, 0, 4), - /* 9 */ new MP3Hufftable(hufftab9, 0, 4), - /* 10 */ new MP3Hufftable(hufftab10, 0, 4), - /* 11 */ new MP3Hufftable(hufftab11, 0, 4), - /* 12 */ new MP3Hufftable(hufftab12, 0, 4), - /* 13 */ new MP3Hufftable(hufftab13, 0, 4), - /* 14 */ null, //new MP3Hufftable(0 /* not used */), - /* 15 */ new MP3Hufftable(hufftab15, 0, 4), - /* 16 */ new MP3Hufftable(hufftab16, 1, 4), - /* 17 */ new MP3Hufftable(hufftab16, 2, 4), - /* 18 */ new MP3Hufftable(hufftab16, 3, 4), - /* 19 */ new MP3Hufftable(hufftab16, 4, 4), - /* 20 */ new MP3Hufftable(hufftab16, 6, 4), - /* 21 */ new MP3Hufftable(hufftab16, 8, 4), - /* 22 */ new MP3Hufftable(hufftab16, 10, 4), - /* 23 */ new MP3Hufftable(hufftab16, 13, 4), - /* 24 */ new MP3Hufftable(hufftab24, 4, 4), - /* 25 */ new MP3Hufftable(hufftab24, 5, 4), - /* 26 */ new MP3Hufftable(hufftab24, 6, 4), - /* 27 */ new MP3Hufftable(hufftab24, 7, 4), - /* 28 */ new MP3Hufftable(hufftab24, 8, 4), - /* 29 */ new MP3Hufftable(hufftab24, 9, 4), - /* 30 */ new MP3Hufftable(hufftab24, 11, 4), - /* 31 */ new MP3Hufftable(hufftab24, 13, 4) -]; - -},{}],7:[function(require,module,exports){ -var AV = (window.AV); - -const ENCODINGS = ['latin1', 'utf16-bom', 'utf16-be', 'utf8']; - -var ID3Stream = AV.Base.extend({ - constructor: function(header, stream) { - this.header = header; - this.stream = stream; - this.offset = 0; - }, - - read: function() { - if (!this.data) { - this.data = {}; - - // read all frames - var frame; - while (frame = this.readFrame()) { - // if we already have an instance of this key, add it to an array - if (frame.key in this.data) { - if (!Array.isArray(this.data[frame.key])) - this.data[frame.key] = [this.data[frame.key]]; - - this.data[frame.key].push(frame.value); - } else { - this.data[frame.key] = frame.value; - } - } - } - - return this.data; - }, - - readFrame: function() { - if (this.offset >= this.header.length) - return null; - - // get the header - var header = this.readHeader(); - var decoder = header.identifier; - - if (header.identifier.charCodeAt(0) === 0) { - this.offset += this.header.length + 1; - return null; - } - - // map common frame names to a single type - if (!this.frameTypes[decoder]) { - for (var key in this.map) { - if (this.map[key].indexOf(decoder) !== -1) { - decoder = key; - break; - } - } - } - - if (this.frameTypes[decoder]) { - // decode the frame - var frame = this.decodeFrame(header, this.frameTypes[decoder]), - keys = Object.keys(frame); - - // if it only returned one key, use that as the value - if (keys.length === 1) - frame = frame[keys[0]]; - - var result = { - value: frame - }; - - } else { - // No frame type found, treat it as binary - var result = { - value: this.stream.readBuffer(Math.min(header.length, this.header.length - this.offset)) - }; - } - - result.key = this.names[header.identifier] ? this.names[header.identifier] : header.identifier; - - // special sauce for cover art, which should just be a buffer - if (result.key === 'coverArt') - result.value = result.value.data; - - this.offset += 10 + header.length; - return result; - }, - - decodeFrame: function(header, fields) { - var stream = this.stream, - start = stream.offset; - - var encoding = 0, ret = {}; - var len = Object.keys(fields).length, i = 0; - - for (var key in fields) { - var type = fields[key]; - var rest = header.length - (stream.offset - start); - i++; - - // check for special field names - switch (key) { - case 'encoding': - encoding = stream.readUInt8(); - continue; - - case 'language': - ret.language = stream.readString(3); - continue; - } - - // check types - switch (type) { - case 'latin1': - ret[key] = stream.readString(i === len ? rest : null, 'latin1'); - break; - - case 'string': - ret[key] = stream.readString(i === len ? rest : null, ENCODINGS[encoding]); - break; - - case 'binary': - ret[key] = stream.readBuffer(rest) - break; - - case 'int16': - ret[key] = stream.readInt16(); - break; - - case 'int8': - ret[key] = stream.readInt8(); - break; - - case 'int24': - ret[key] = stream.readInt24(); - break; - - case 'int32': - ret[key] = stream.readInt32(); - break; - - case 'int32+': - ret[key] = stream.readInt32(); - if (rest > 4) - throw new Error('Seriously dude? Stop playing this song and get a life!'); - - break; - - case 'date': - var val = stream.readString(8); - ret[key] = new Date(val.slice(0, 4), val.slice(4, 6) - 1, val.slice(6, 8)); - break; - - case 'frame_id': - ret[key] = stream.readString(4); - break; - - default: - throw new Error('Unknown key type ' + type); - } - } - - // Just in case something went wrong... - var rest = header.length - (stream.offset - start); - if (rest > 0) - stream.advance(rest); - - return ret; - } -}); - -// ID3 v2.3 and v2.4 support -exports.ID3v23Stream = ID3Stream.extend({ - readHeader: function() { - var identifier = this.stream.readString(4); - var length = 0; - - if (this.header.major === 4) { - for (var i = 0; i < 4; i++) - length = (length << 7) + (this.stream.readUInt8() & 0x7f); - } else { - length = this.stream.readUInt32(); - } - - return { - identifier: identifier, - length: length, - flags: this.stream.readUInt16() - }; - }, - - map: { - text: [ - // Identification Frames - 'TIT1', 'TIT2', 'TIT3', 'TALB', 'TOAL', 'TRCK', 'TPOS', 'TSST', 'TSRC', - - // Involved Persons Frames - 'TPE1', 'TPE2', 'TPE3', 'TPE4', 'TOPE', 'TEXT', 'TOLY', 'TCOM', 'TMCL', 'TIPL', 'TENC', - - // Derived and Subjective Properties Frames - 'TBPM', 'TLEN', 'TKEY', 'TLAN', 'TCON', 'TFLT', 'TMED', 'TMOO', - - // Rights and Licence Frames - 'TCOP', 'TPRO', 'TPUB', 'TOWN', 'TRSN', 'TRSO', - - // Other Text Frames - 'TOFN', 'TDLY', 'TDEN', 'TDOR', 'TDRC', 'TDRL', 'TDTG', 'TSSE', 'TSOA', 'TSOP', 'TSOT', - - // Deprecated Text Frames - 'TDAT', 'TIME', 'TORY', 'TRDA', 'TSIZ', 'TYER', - - // Non-standard iTunes Frames - 'TCMP', 'TSO2', 'TSOC' - ], - - url: [ - 'WCOM', 'WCOP', 'WOAF', 'WOAR', 'WOAS', 'WORS', 'WPAY', 'WPUB' - ] - }, - - frameTypes: { - text: { - encoding: 1, - value: 'string' - }, - - url: { - value: 'latin1' - }, - - TXXX: { - encoding: 1, - description: 'string', - value: 'string' - }, - - WXXX: { - encoding: 1, - description: 'string', - value: 'latin1', - }, - - USLT: { - encoding: 1, - language: 1, - description: 'string', - value: 'string' - }, - - COMM: { - encoding: 1, - language: 1, - description: 'string', - value: 'string' - }, - - APIC: { - encoding: 1, - mime: 'latin1', - type: 'int8', - description: 'string', - data: 'binary' - }, - - UFID: { - owner: 'latin1', - identifier: 'binary' - }, - - MCDI: { - value: 'binary' - }, - - PRIV: { - owner: 'latin1', - value: 'binary' - }, - - GEOB: { - encoding: 1, - mime: 'latin1', - filename: 'string', - description: 'string', - data: 'binary' - }, - - PCNT: { - value: 'int32+' - }, - - POPM: { - email: 'latin1', - rating: 'int8', - counter: 'int32+' - }, - - AENC: { - owner: 'latin1', - previewStart: 'int16', - previewLength: 'int16', - encryptionInfo: 'binary' - }, - - ETCO: { - format: 'int8', - data: 'binary' // TODO - }, - - MLLT: { - framesBetweenReference: 'int16', - bytesBetweenReference: 'int24', - millisecondsBetweenReference: 'int24', - bitsForBytesDeviation: 'int8', - bitsForMillisecondsDev: 'int8', - data: 'binary' // TODO - }, - - SYTC: { - format: 'int8', - tempoData: 'binary' // TODO - }, - - SYLT: { - encoding: 1, - language: 1, - format: 'int8', - contentType: 'int8', - description: 'string', - data: 'binary' // TODO - }, - - RVA2: { - identification: 'latin1', - data: 'binary' // TODO - }, - - EQU2: { - interpolationMethod: 'int8', - identification: 'latin1', - data: 'binary' // TODO - }, - - RVRB: { - left: 'int16', - right: 'int16', - bouncesLeft: 'int8', - bouncesRight: 'int8', - feedbackLL: 'int8', - feedbackLR: 'int8', - feedbackRR: 'int8', - feedbackRL: 'int8', - premixLR: 'int8', - premixRL: 'int8' - }, - - RBUF: { - size: 'int24', - flag: 'int8', - offset: 'int32' - }, - - LINK: { - identifier: 'frame_id', - url: 'latin1', - data: 'binary' // TODO stringlist? - }, - - POSS: { - format: 'int8', - position: 'binary' // TODO - }, - - USER: { - encoding: 1, - language: 1, - value: 'string' - }, - - OWNE: { - encoding: 1, - price: 'latin1', - purchaseDate: 'date', - seller: 'string' - }, - - COMR: { - encoding: 1, - price: 'latin1', - validUntil: 'date', - contactURL: 'latin1', - receivedAs: 'int8', - seller: 'string', - description: 'string', - logoMime: 'latin1', - logo: 'binary' - }, - - ENCR: { - owner: 'latin1', - methodSymbol: 'int8', - data: 'binary' - }, - - GRID: { - owner: 'latin1', - groupSymbol: 'int8', - data: 'binary' - }, - - SIGN: { - groupSymbol: 'int8', - signature: 'binary' - }, - - SEEK: { - value: 'int32' - }, - - ASPI: { - dataStart: 'int32', - dataLength: 'int32', - numPoints: 'int16', - bitsPerPoint: 'int8', - data: 'binary' // TODO - }, - - // Deprecated ID3 v2.3 frames - IPLS: { - encoding: 1, - value: 'string' // list? - }, - - RVAD: { - adjustment: 'int8', - bits: 'int8', - data: 'binary' // TODO - }, - - EQUA: { - adjustmentBits: 'int8', - data: 'binary' // TODO - } - }, - - names: { - // Identification Frames - 'TIT1': 'grouping', - 'TIT2': 'title', - 'TIT3': 'subtitle', - 'TALB': 'album', - 'TOAL': 'originalAlbumTitle', - 'TRCK': 'trackNumber', - 'TPOS': 'diskNumber', - 'TSST': 'setSubtitle', - 'TSRC': 'ISRC', - - // Involved Persons Frames - 'TPE1': 'artist', - 'TPE2': 'albumArtist', - 'TPE3': 'conductor', - 'TPE4': 'modifiedBy', - 'TOPE': 'originalArtist', - 'TEXT': 'lyricist', - 'TOLY': 'originalLyricist', - 'TCOM': 'composer', - 'TMCL': 'musicianCreditsList', - 'TIPL': 'involvedPeopleList', - 'TENC': 'encodedBy', - - // Derived and Subjective Properties Frames - 'TBPM': 'tempo', - 'TLEN': 'length', - 'TKEY': 'initialKey', - 'TLAN': 'language', - 'TCON': 'genre', - 'TFLT': 'fileType', - 'TMED': 'mediaType', - 'TMOO': 'mood', - - // Rights and Licence Frames - 'TCOP': 'copyright', - 'TPRO': 'producedNotice', - 'TPUB': 'publisher', - 'TOWN': 'fileOwner', - 'TRSN': 'internetRadioStationName', - 'TRSO': 'internetRadioStationOwner', - - // Other Text Frames - 'TOFN': 'originalFilename', - 'TDLY': 'playlistDelay', - 'TDEN': 'encodingTime', - 'TDOR': 'originalReleaseTime', - 'TDRC': 'recordingTime', - 'TDRL': 'releaseTime', - 'TDTG': 'taggingTime', - 'TSSE': 'encodedWith', - 'TSOA': 'albumSortOrder', - 'TSOP': 'performerSortOrder', - 'TSOT': 'titleSortOrder', - - // User defined text information - 'TXXX': 'userText', - - // Unsynchronised lyrics/text transcription - 'USLT': 'lyrics', - - // Attached Picture Frame - 'APIC': 'coverArt', - - // Unique Identifier Frame - 'UFID': 'uniqueIdentifier', - - // Music CD Identifier Frame - 'MCDI': 'CDIdentifier', - - // Comment Frame - 'COMM': 'comments', - - // URL link frames - 'WCOM': 'commercialInformation', - 'WCOP': 'copyrightInformation', - 'WOAF': 'officialAudioFileWebpage', - 'WOAR': 'officialArtistWebpage', - 'WOAS': 'officialAudioSourceWebpage', - 'WORS': 'officialInternetRadioStationHomepage', - 'WPAY': 'payment', - 'WPUB': 'officialPublisherWebpage', - - // User Defined URL Link Frame - 'WXXX': 'url', - - 'PRIV': 'private', - 'GEOB': 'generalEncapsulatedObject', - 'PCNT': 'playCount', - 'POPM': 'rating', - 'AENC': 'audioEncryption', - 'ETCO': 'eventTimingCodes', - 'MLLT': 'MPEGLocationLookupTable', - 'SYTC': 'synchronisedTempoCodes', - 'SYLT': 'synchronisedLyrics', - 'RVA2': 'volumeAdjustment', - 'EQU2': 'equalization', - 'RVRB': 'reverb', - 'RBUF': 'recommendedBufferSize', - 'LINK': 'link', - 'POSS': 'positionSynchronisation', - 'USER': 'termsOfUse', - 'OWNE': 'ownership', - 'COMR': 'commercial', - 'ENCR': 'encryption', - 'GRID': 'groupIdentifier', - 'SIGN': 'signature', - 'SEEK': 'seek', - 'ASPI': 'audioSeekPointIndex', - - // Deprecated ID3 v2.3 frames - 'TDAT': 'date', - 'TIME': 'time', - 'TORY': 'originalReleaseYear', - 'TRDA': 'recordingDates', - 'TSIZ': 'size', - 'TYER': 'year', - 'IPLS': 'involvedPeopleList', - 'RVAD': 'volumeAdjustment', - 'EQUA': 'equalization', - - // Non-standard iTunes frames - 'TCMP': 'compilation', - 'TSO2': 'albumArtistSortOrder', - 'TSOC': 'composerSortOrder' - } -}); - -// ID3 v2.2 support -exports.ID3v22Stream = exports.ID3v23Stream.extend({ - readHeader: function() { - var id = this.stream.readString(3); - - if (this.frameReplacements[id] && !this.frameTypes[id]) - this.frameTypes[id] = this.frameReplacements[id]; - - return { - identifier: this.replacements[id] || id, - length: this.stream.readUInt24() - }; - }, - - // map 3 char ID3 v2.2 names to 4 char ID3 v2.3/4 names - replacements: { - 'UFI': 'UFID', - 'TT1': 'TIT1', - 'TT2': 'TIT2', - 'TT3': 'TIT3', - 'TP1': 'TPE1', - 'TP2': 'TPE2', - 'TP3': 'TPE3', - 'TP4': 'TPE4', - 'TCM': 'TCOM', - 'TXT': 'TEXT', - 'TLA': 'TLAN', - 'TCO': 'TCON', - 'TAL': 'TALB', - 'TPA': 'TPOS', - 'TRK': 'TRCK', - 'TRC': 'TSRC', - 'TYE': 'TYER', - 'TDA': 'TDAT', - 'TIM': 'TIME', - 'TRD': 'TRDA', - 'TMT': 'TMED', - 'TFT': 'TFLT', - 'TBP': 'TBPM', - 'TCR': 'TCOP', - 'TPB': 'TPUB', - 'TEN': 'TENC', - 'TSS': 'TSSE', - 'TOF': 'TOFN', - 'TLE': 'TLEN', - 'TSI': 'TSIZ', - 'TDY': 'TDLY', - 'TKE': 'TKEY', - 'TOT': 'TOAL', - 'TOA': 'TOPE', - 'TOL': 'TOLY', - 'TOR': 'TORY', - 'TXX': 'TXXX', - - 'WAF': 'WOAF', - 'WAR': 'WOAR', - 'WAS': 'WOAS', - 'WCM': 'WCOM', - 'WCP': 'WCOP', - 'WPB': 'WPUB', - 'WXX': 'WXXX', - - 'IPL': 'IPLS', - 'MCI': 'MCDI', - 'ETC': 'ETCO', - 'MLL': 'MLLT', - 'STC': 'SYTC', - 'ULT': 'USLT', - 'SLT': 'SYLT', - 'COM': 'COMM', - 'RVA': 'RVAD', - 'EQU': 'EQUA', - 'REV': 'RVRB', - - 'GEO': 'GEOB', - 'CNT': 'PCNT', - 'POP': 'POPM', - 'BUF': 'RBUF', - 'CRA': 'AENC', - 'LNK': 'LINK', - - // iTunes stuff - 'TST': 'TSOT', - 'TSP': 'TSOP', - 'TSA': 'TSOA', - 'TCP': 'TCMP', - 'TS2': 'TSO2', - 'TSC': 'TSOC' - }, - - // replacements for ID3 v2.3/4 frames - frameReplacements: { - PIC: { - encoding: 1, - format: 'int24', - type: 'int8', - description: 'string', - data: 'binary' - }, - - CRM: { - owner: 'latin1', - description: 'latin1', - data: 'binary' - } - } -}); -},{}],8:[function(require,module,exports){ -function IMDCT() { - this.tmp_imdct36 = new Float64Array(18); - this.tmp_dctIV = new Float64Array(18); - this.tmp_sdctII = new Float64Array(9); -} - -// perform X[18]->x[36] IMDCT using Szu-Wei Lee's fast algorithm -IMDCT.prototype.imdct36 = function(x, y) { - var tmp = this.tmp_imdct36; - - /* DCT-IV */ - this.dctIV(x, tmp); - - // convert 18-point DCT-IV to 36-point IMDCT - for (var i = 0; i < 9; ++i) { - y[i] = tmp[9 + i]; - } - for (var i = 9; i < 27; ++i) { - y[i] = -tmp[36 - (9 + i) - 1]; - } - for (var i = 27; i < 36; ++i) { - y[i] = -tmp[i - 27]; - } -}; - -var dctIV_scale = []; -for(i = 0; i < 18; i++) { - dctIV_scale[i] = 2 * Math.cos(Math.PI * (2 * i + 1) / (4 * 18)); -} - -IMDCT.prototype.dctIV = function(y, X) { - var tmp = this.tmp_dctIV; - - // scaling - for (var i = 0; i < 18; ++i) { - tmp[i] = y[i] * dctIV_scale[i]; - } - - // SDCT-II - this.sdctII(tmp, X); - - // scale reduction and output accumulation - X[0] /= 2; - for (var i = 1; i < 18; ++i) { - X[i] = X[i] / 2 - X[i - 1]; - } -}; - -var sdctII_scale = []; -for (var i = 0; i < 9; ++i) { - sdctII_scale[i] = 2 * Math.cos(Math.PI * (2 * i + 1) / (2 * 18)); -} - -IMDCT.prototype.sdctII = function(x, X) { - // divide the 18-point SDCT-II into two 9-point SDCT-IIs - var tmp = this.tmp_sdctII; - - // even input butterfly - for (var i = 0; i < 9; ++i) { - tmp[i] = x[i] + x[18 - i - 1]; - } - - fastsdct(tmp, X, 0); - - // odd input butterfly and scaling - for (var i = 0; i < 9; ++i) { - tmp[i] = (x[i] - x[18 - i - 1]) * sdctII_scale[i]; - } - - fastsdct(tmp, X, 1); - - // output accumulation - for (var i = 3; i < 18; i += 2) { - X[i] -= X[i - 2]; - } -}; - -var c0 = 2 * Math.cos( 1 * Math.PI / 18); -var c1 = 2 * Math.cos( 3 * Math.PI / 18); -var c2 = 2 * Math.cos( 4 * Math.PI / 18); -var c3 = 2 * Math.cos( 5 * Math.PI / 18); -var c4 = 2 * Math.cos( 7 * Math.PI / 18); -var c5 = 2 * Math.cos( 8 * Math.PI / 18); -var c6 = 2 * Math.cos(16 * Math.PI / 18); - -function fastsdct(x, y, offset) { - var a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12; - var a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25; - var m0, m1, m2, m3, m4, m5, m6, m7; - - a0 = x[3] + x[5]; - a1 = x[3] - x[5]; - a2 = x[6] + x[2]; - a3 = x[6] - x[2]; - a4 = x[1] + x[7]; - a5 = x[1] - x[7]; - a6 = x[8] + x[0]; - a7 = x[8] - x[0]; - - a8 = a0 + a2; - a9 = a0 - a2; - a10 = a0 - a6; - a11 = a2 - a6; - a12 = a8 + a6; - a13 = a1 - a3; - a14 = a13 + a7; - a15 = a3 + a7; - a16 = a1 - a7; - a17 = a1 + a3; - - m0 = a17 * -c3; - m1 = a16 * -c0; - m2 = a15 * -c4; - m3 = a14 * -c1; - m4 = a5 * -c1; - m5 = a11 * -c6; - m6 = a10 * -c5; - m7 = a9 * -c2; - - a18 = x[4] + a4; - a19 = 2 * x[4] - a4; - a20 = a19 + m5; - a21 = a19 - m5; - a22 = a19 + m6; - a23 = m4 + m2; - a24 = m4 - m2; - a25 = m4 + m1; - - // output to every other slot for convenience - y[offset + 0] = a18 + a12; - y[offset + 2] = m0 - a25; - y[offset + 4] = m7 - a20; - y[offset + 6] = m3; - y[offset + 8] = a21 - m6; - y[offset + 10] = a24 - m1; - y[offset + 12] = a12 - 2 * a18; - y[offset + 14] = a23 + m0; - y[offset + 16] = a22 + m7; -} - -IMDCT.S = [ - /* 0 */ [ 0.608761429, - -0.923879533, - -0.130526192, - 0.991444861, - -0.382683432, - -0.793353340 ], - - /* 6 */ [ -0.793353340, - 0.382683432, - 0.991444861, - 0.130526192, - -0.923879533, - -0.608761429 ], - - /* 1 */ [ 0.382683432, - -0.923879533, - 0.923879533, - -0.382683432, - -0.382683432, - 0.923879533 ], - - /* 7 */ [ -0.923879533, - -0.382683432, - 0.382683432, - 0.923879533, - 0.923879533, - 0.382683432 ], - - /* 2 */ [ 0.130526192, - -0.382683432, - 0.608761429, - -0.793353340, - 0.923879533, - -0.991444861 ], - - /* 8 */ [ -0.991444861, - -0.923879533, - -0.793353340, - -0.608761429, - -0.382683432, - -0.130526192 ] -]; - -module.exports = IMDCT; - -},{}],9:[function(require,module,exports){ -var tables = require('./tables'); -var MP3FrameHeader = require('./header'); -var MP3Frame = require('./frame'); -var utils = require('./utils'); - -function Layer1() { - this.allocation = utils.makeArray([2, 32], Uint8Array); - this.scalefactor = utils.makeArray([2, 32], Uint8Array); -} - -MP3Frame.layers[1] = Layer1; - -// linear scaling table -const LINEAR_TABLE = new Float32Array([ - 1.33333333333333, 1.14285714285714, 1.06666666666667, - 1.03225806451613, 1.01587301587302, 1.00787401574803, - 1.00392156862745, 1.00195694716243, 1.00097751710655, - 1.00048851978505, 1.00024420024420, 1.00012208521548, - 1.00006103888177, 1.00003051850948 -]); - -Layer1.prototype.decode = function(stream, frame) { - var header = frame.header; - var nch = header.nchannels(); - - var bound = 32; - if (header.mode === MP3FrameHeader.MODE.JOINT_STEREO) { - header.flags |= MP3FrameHeader.FLAGS.I_STEREO; - bound = 4 + header.mode_extension * 4; - } - - if (header.flags & MP3FrameHeader.FLAGS.PROTECTION) { - // TODO: crc check - } - - // decode bit allocations - var allocation = this.allocation; - for (var sb = 0; sb < bound; sb++) { - for (var ch = 0; ch < nch; ch++) { - var nb = stream.read(4); - if (nb === 15) - throw new Error("forbidden bit allocation value"); - - allocation[ch][sb] = nb ? nb + 1 : 0; - } - } - - for (var sb = bound; sb < 32; sb++) { - var nb = stream.read(4); - if (nb === 15) - throw new Error("forbidden bit allocation value"); - - allocation[0][sb] = - allocation[1][sb] = nb ? nb + 1 : 0; - } - - // decode scalefactors - var scalefactor = this.scalefactor; - for (var sb = 0; sb < 32; sb++) { - for (var ch = 0; ch < nch; ch++) { - if (allocation[ch][sb]) { - scalefactor[ch][sb] = stream.read(6); - - /* - * Scalefactor index 63 does not appear in Table B.1 of - * ISO/IEC 11172-3. Nonetheless, other implementations accept it, - * so we do as well - */ - } - } - } - - // decode samples - for (var s = 0; s < 12; s++) { - for (var sb = 0; sb < bound; sb++) { - for (var ch = 0; ch < nch; ch++) { - var nb = allocation[ch][sb]; - frame.sbsample[ch][s][sb] = nb ? this.sample(stream, nb) * tables.SF_TABLE[scalefactor[ch][sb]] : 0; - } - } - - for (var sb = bound; sb < 32; sb++) { - var nb = allocation[0][sb]; - if (nb) { - var sample = this.sample(stream, nb); - - for (var ch = 0; ch < nch; ch++) { - frame.sbsample[ch][s][sb] = sample * tables.SF_TABLE[scalefactor[ch][sb]]; - } - } else { - for (var ch = 0; ch < nch; ch++) { - frame.sbsample[ch][s][sb] = 0; - } - } - } - } -}; - -Layer1.prototype.sample = function(stream, nb) { - var sample = stream.read(nb); - - // invert most significant bit, and form a 2's complement sample - sample ^= 1 << (nb - 1); - sample |= -(sample & (1 << (nb - 1))); - sample /= (1 << (nb - 1)); - - // requantize the sample - // s'' = (2^nb / (2^nb - 1)) * (s''' + 2^(-nb + 1)) - sample += 1 >> (nb - 1); - return sample * LINEAR_TABLE[nb - 2]; -}; - -module.exports = Layer1; - -},{"./frame":4,"./header":5,"./tables":14,"./utils":15}],10:[function(require,module,exports){ -var tables = require('./tables'); -var MP3FrameHeader = require('./header'); -var MP3Frame = require('./frame'); -var utils = require('./utils'); - -function Layer2() { - this.samples = new Float64Array(3); - this.allocation = utils.makeArray([2, 32], Uint8Array); - this.scfsi = utils.makeArray([2, 32], Uint8Array); - this.scalefactor = utils.makeArray([2, 32, 3], Uint8Array); -} - -MP3Frame.layers[2] = Layer2; - -// possible quantization per subband table -const SBQUANT = [ - // ISO/IEC 11172-3 Table B.2a - { sblimit: 27, offsets: - [ 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 ] }, - - // ISO/IEC 11172-3 Table B.2b - { sblimit: 30, offsets: - [ 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 ] }, - - // ISO/IEC 11172-3 Table B.2c - { sblimit: 8, offsets: - [ 5, 5, 2, 2, 2, 2, 2, 2 ] }, - - // ISO/IEC 11172-3 Table B.2d - { sblimit: 12, offsets: - [ 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ] }, - - // ISO/IEC 13818-3 Table B.1 - { sblimit: 30, offsets: - [ 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ] } -]; - -// bit allocation table -const BITALLOC = [ - { nbal: 2, offset: 0 }, // 0 - { nbal: 2, offset: 3 }, // 1 - { nbal: 3, offset: 3 }, // 2 - { nbal: 3, offset: 1 }, // 3 - { nbal: 4, offset: 2 }, // 4 - { nbal: 4, offset: 3 }, // 5 - { nbal: 4, offset: 4 }, // 6 - { nbal: 4, offset: 5 } // 7 -]; - -// offsets into quantization class table -const OFFSETS = [ - [ 0, 1, 16 ], // 0 - [ 0, 1, 2, 3, 4, 5, 16 ], // 1 - [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ], // 2 - [ 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], // 3 - [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 ], // 4 - [ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ] // 5 -]; - - - -/* - * These are the Layer II classes of quantization. - * The table is derived from Table B.4 of ISO/IEC 11172-3. - */ -const QC_TABLE = [ - { nlevels: 3, group: 2, bits: 5, C: 1.33333333333, D: 0.50000000000 }, - { nlevels: 5, group: 3, bits: 7, C: 1.60000000000, D: 0.50000000000 }, - { nlevels: 7, group: 0, bits: 3, C: 1.14285714286, D: 0.25000000000 }, - { nlevels: 9, group: 4, bits: 10, C: 1.77777777777, D: 0.50000000000 }, - { nlevels: 15, group: 0, bits: 4, C: 1.06666666666, D: 0.12500000000 }, - { nlevels: 31, group: 0, bits: 5, C: 1.03225806452, D: 0.06250000000 }, - { nlevels: 63, group: 0, bits: 6, C: 1.01587301587, D: 0.03125000000 }, - { nlevels: 127, group: 0, bits: 7, C: 1.00787401575, D: 0.01562500000 }, - { nlevels: 255, group: 0, bits: 8, C: 1.00392156863, D: 0.00781250000 }, - { nlevels: 511, group: 0, bits: 9, C: 1.00195694716, D: 0.00390625000 }, - { nlevels: 1023, group: 0, bits: 10, C: 1.00097751711, D: 0.00195312500 }, - { nlevels: 2047, group: 0, bits: 11, C: 1.00048851979, D: 0.00097656250 }, - { nlevels: 4095, group: 0, bits: 12, C: 1.00024420024, D: 0.00048828125 }, - { nlevels: 8191, group: 0, bits: 13, C: 1.00012208522, D: 0.00024414063 }, - { nlevels: 16383, group: 0, bits: 14, C: 1.00006103888, D: 0.00012207031 }, - { nlevels: 32767, group: 0, bits: 15, C: 1.00003051851, D: 0.00006103516 }, - { nlevels: 65535, group: 0, bits: 16, C: 1.00001525902, D: 0.00003051758 } -]; - -Layer2.prototype.decode = function(stream, frame) { - var header = frame.header; - var nch = header.nchannels(); - var index; - - if (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) { - index = 4; - } else if (header.flags & MP3FrameHeader.FLAGS.FREEFORMAT) { - index = header.samplerate === 48000 ? 0 : 1; - } else { - var bitrate_per_channel = header.bitrate; - - if (nch === 2) { - bitrate_per_channel /= 2; - - /* - * ISO/IEC 11172-3 allows only single channel mode for 32, 48, 56, and - * 80 kbps bitrates in Layer II, but some encoders ignore this - * restriction, so we ignore it as well. - */ - } else { - /* - * ISO/IEC 11172-3 does not allow single channel mode for 224, 256, - * 320, or 384 kbps bitrates in Layer II. - */ - if (bitrate_per_channel > 192000) - throw new Error('bad bitrate/mode combination'); - } - - if (bitrate_per_channel <= 48000) - index = header.samplerate === 32000 ? 3 : 2; - else if (bitrate_per_channel <= 80000) - index = 0; - else - index = header.samplerate === 48000 ? 0 : 1; - } - - var sblimit = SBQUANT[index].sblimit; - var offsets = SBQUANT[index].offsets; - - var bound = 32; - if (header.mode === MP3FrameHeader.MODE.JOINT_STEREO) { - header.flags |= MP3FrameHeader.FLAGS.I_STEREO; - bound = 4 + header.mode_extension * 4; - } - - if (bound > sblimit) - bound = sblimit; - - // decode bit allocations - var allocation = this.allocation; - for (var sb = 0; sb < bound; sb++) { - var nbal = BITALLOC[offsets[sb]].nbal; - - for (var ch = 0; ch < nch; ch++) - allocation[ch][sb] = stream.read(nbal); - } - - for (var sb = bound; sb < sblimit; sb++) { - var nbal = BITALLOC[offsets[sb]].nbal; - - allocation[0][sb] = - allocation[1][sb] = stream.read(nbal); - } - - // decode scalefactor selection info - var scfsi = this.scfsi; - for (var sb = 0; sb < sblimit; sb++) { - for (var ch = 0; ch < nch; ch++) { - if (allocation[ch][sb]) - scfsi[ch][sb] = stream.read(2); - } - } - - if (header.flags & MP3FrameHeader.FLAGS.PROTECTION) { - // TODO: crc check - } - - // decode scalefactors - var scalefactor = this.scalefactor; - for (var sb = 0; sb < sblimit; sb++) { - for (var ch = 0; ch < nch; ch++) { - if (allocation[ch][sb]) { - scalefactor[ch][sb][0] = stream.read(6); - - switch (scfsi[ch][sb]) { - case 2: - scalefactor[ch][sb][2] = - scalefactor[ch][sb][1] = scalefactor[ch][sb][0]; - break; - - case 0: - scalefactor[ch][sb][1] = stream.read(6); - // fall through - - case 1: - case 3: - scalefactor[ch][sb][2] = stream.read(6); - } - - if (scfsi[ch][sb] & 1) - scalefactor[ch][sb][1] = scalefactor[ch][sb][scfsi[ch][sb] - 1]; - - /* - * Scalefactor index 63 does not appear in Table B.1 of - * ISO/IEC 11172-3. Nonetheless, other implementations accept it, - * so we do as well. - */ - } - } - } - - // decode samples - for (var gr = 0; gr < 12; gr++) { - // normal - for (var sb = 0; sb < bound; sb++) { - for (var ch = 0; ch < nch; ch++) { - if (index = allocation[ch][sb]) { - index = OFFSETS[BITALLOC[offsets[sb]].offset][index - 1]; - this.decodeSamples(stream, QC_TABLE[index]); - - var scale = tables.SF_TABLE[scalefactor[ch][sb][gr >> 2]]; - for (var s = 0; s < 3; s++) { - frame.sbsample[ch][3 * gr + s][sb] = this.samples[s] * scale; - } - } else { - for (var s = 0; s < 3; s++) { - frame.sbsample[ch][3 * gr + s][sb] = 0; - } - } - } - } - - // joint stereo - for (var sb = bound; sb < sblimit; sb++) { - if (index = allocation[0][sb]) { - index = OFFSETS[BITALLOC[offsets[sb]].offset][index - 1]; - this.decodeSamples(stream, QC_TABLE[index]); - - for (var ch = 0; ch < nch; ch++) { - var scale = tables.SF_TABLE[scalefactor[ch][sb][gr >> 2]]; - for (var s = 0; s < 3; s++) { - frame.sbsample[ch][3 * gr + s][sb] = this.samples[s] * scale; - } - } - } else { - for (var ch = 0; ch < nch; ch++) { - for (var s = 0; s < 3; s++) { - frame.sbsample[ch][3 * gr + s][sb] = 0; - } - } - } - } - - // the rest - for (var ch = 0; ch < nch; ch++) { - for (var s = 0; s < 3; s++) { - for (var sb = sblimit; sb < 32; sb++) { - frame.sbsample[ch][3 * gr + s][sb] = 0; - } - } - } - } -}; - -Layer2.prototype.decodeSamples = function(stream, quantclass) { - var sample = this.samples; - var nb = quantclass.group; - - if (nb) { - // degrouping - var c = stream.read(quantclass.bits); - var nlevels = quantclass.nlevels; - - for (var s = 0; s < 3; s++) { - sample[s] = c % nlevels; - c = c / nlevels | 0; - } - } else { - nb = quantclass.bits; - for (var s = 0; s < 3; s++) { - sample[s] = stream.read(nb); - } - } - - for (var s = 0; s < 3; s++) { - // invert most significant bit, and form a 2's complement sample - var requantized = sample[s] ^ (1 << (nb - 1)); - requantized |= -(requantized & (1 << (nb - 1))); - requantized /= (1 << (nb - 1)); - - // requantize the sample - sample[s] = (requantized + quantclass.D) * quantclass.C; - } -}; - -module.exports = Layer2; - -},{"./frame":4,"./header":5,"./tables":14,"./utils":15}],11:[function(require,module,exports){ -var AV = (window.AV); -var tables = require('./tables'); -var MP3FrameHeader = require('./header'); -var MP3Frame = require('./frame'); -var huffman = require('./huffman'); -var IMDCT = require('./imdct'); -var utils = require('./utils'); - -function MP3SideInfo() { - this.main_data_begin = null; - this.private_bits = null; - this.gr = [new MP3Granule(), new MP3Granule()]; - this.scfsi = new Uint8Array(2); -} - -function MP3Granule() { - this.ch = [new MP3Channel(), new MP3Channel()]; -} - -function MP3Channel() { - // from side info - this.part2_3_length = null; - this.big_values = null; - this.global_gain = null; - this.scalefac_compress = null; - - this.flags = null; - this.block_type = null; - this.table_select = new Uint8Array(3); - this.subblock_gain = new Uint8Array(3); - this.region0_count = null; - this.region1_count = null; - - // from main_data - this.scalefac = new Uint8Array(39); -} - -function Layer3() { - this.imdct = new IMDCT(); - this.si = new MP3SideInfo(); - - // preallocate reusable typed arrays for performance - this.xr = [new Float64Array(576), new Float64Array(576)]; - this._exponents = new Int32Array(39); - this.reqcache = new Float64Array(16); - this.modes = new Int16Array(39); - this.output = new Float64Array(36); - - this.tmp = utils.makeArray([32, 3, 6]); - this.tmp2 = new Float64Array(32 * 3 * 6); -} - -MP3Frame.layers[3] = Layer3; - -Layer3.prototype.decode = function(stream, frame) { - var header = frame.header; - var next_md_begin = 0; - var md_len = 0; - - var nch = header.nchannels(); - var si_len = (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) ? (nch === 1 ? 9 : 17) : (nch === 1 ? 17 : 32); - - // check frame sanity - if (stream.next_frame - stream.nextByte() < si_len) { - stream.md_len = 0; - throw new Error('Bad frame length'); - } - - // check CRC word - if (header.flags & MP3FrameHeader.FLAGS.PROTECTION) { - // TODO: crc check - } - - // decode frame side information - var sideInfo = this.sideInfo(stream, nch, header.flags & MP3FrameHeader.FLAGS.LSF_EXT); - var si = sideInfo.si; - var data_bitlen = sideInfo.data_bitlen; - var priv_bitlen = sideInfo.priv_bitlen; - - header.flags |= priv_bitlen; - header.private_bits |= si.private_bits; - - // find main_data of next frame - var peek = stream.copy(); - peek.seek(stream.next_frame * 8); - - var nextHeader = peek.read(16); - if ((nextHeader & 0xffe6) === 0xffe2) { // syncword | layer - if ((nextHeader & 1) === 0) // protection bit - peek.advance(16); // crc check - - peek.advance(16); // skip the rest of the header - next_md_begin = peek.read((nextHeader & 8) ? 9 : 8); - } - - // find main_data of this frame - var frame_space = stream.next_frame - stream.nextByte(); - - if (next_md_begin > si.main_data_begin + frame_space) - next_md_begin = 0; - - var md_len = si.main_data_begin + frame_space - next_md_begin; - var frame_used = 0; - var ptr; - - if (si.main_data_begin === 0) { - ptr = stream.stream; - stream.md_len = 0; - frame_used = md_len; - } else { - if (si.main_data_begin > stream.md_len) { - throw new Error('bad main_data_begin pointer'); - } else { - var old_md_len = stream.md_len; - - if (md_len > si.main_data_begin) { - if (stream.md_len + md_len - si.main_data_begin > MP3FrameHeader.BUFFER_MDLEN) { - throw new Error("Assertion failed: (stream.md_len + md_len - si.main_data_begin <= MAD_MP3FrameHeader.BUFFER_MDLEN)"); - } - - frame_used = md_len - si.main_data_begin; - this.memcpy(stream.main_data, stream.md_len, stream.stream.stream, stream.nextByte(), frame_used); - stream.md_len += frame_used; - } - - ptr = new AV.Bitstream(AV.Stream.fromBuffer(new AV.Buffer(stream.main_data))); - ptr.advance((old_md_len - si.main_data_begin) * 8); - } - } - - var frame_free = frame_space - frame_used; - - // decode main_data - this.decodeMainData(ptr, frame, si, nch); - - // preload main_data buffer with up to 511 bytes for next frame(s) - if (frame_free >= next_md_begin) { - this.memcpy(stream.main_data, 0, stream.stream.stream, stream.next_frame - next_md_begin, next_md_begin); - stream.md_len = next_md_begin; - } else { - if (md_len < si.main_data_begin) { - var extra = si.main_data_begin - md_len; - if (extra + frame_free > next_md_begin) - extra = next_md_begin - frame_free; - - if (extra < stream.md_len) { - this.memcpy(stream.main_data, 0, stream.main_data, stream.md_len - extra, extra); - stream.md_len = extra; - } - } else { - stream.md_len = 0; - } - - this.memcpy(stream.main_data, stream.md_len, stream.stream.stream, stream.next_frame - frame_free, frame_free); - stream.md_len += frame_free; - } -}; - -Layer3.prototype.memcpy = function(dst, dstOffset, pSrc, srcOffset, length) { - var subarr; - if (pSrc.subarray) - subarr = pSrc.subarray(srcOffset, srcOffset + length); - else - subarr = pSrc.peekBuffer(srcOffset - pSrc.offset, length).data; - - // oh my, memcpy actually exists in JavaScript? - dst.set(subarr, dstOffset); - return dst; -}; - -Layer3.prototype.sideInfo = function(stream, nch, lsf) { - var si = this.si; - var data_bitlen = 0; - var priv_bitlen = lsf ? ((nch === 1) ? 1 : 2) : ((nch === 1) ? 5 : 3); - - si.main_data_begin = stream.read(lsf ? 8 : 9); - si.private_bits = stream.read(priv_bitlen); - - var ngr = 1; - if (!lsf) { - ngr = 2; - for (var ch = 0; ch < nch; ++ch) - si.scfsi[ch] = stream.read(4); - } - - for (var gr = 0; gr < ngr; gr++) { - var granule = si.gr[gr]; - - for (var ch = 0; ch < nch; ch++) { - var channel = granule.ch[ch]; - - channel.part2_3_length = stream.read(12); - channel.big_values = stream.read(9); - channel.global_gain = stream.read(8); - channel.scalefac_compress = stream.read(lsf ? 9 : 4); - - data_bitlen += channel.part2_3_length; - - if (channel.big_values > 288) - throw new Error('bad big_values count'); - - channel.flags = 0; - - // window_switching_flag - if (stream.read(1)) { - channel.block_type = stream.read(2); - - if (channel.block_type === 0) - throw new Error('reserved block_type'); - - if (!lsf && channel.block_type === 2 && si.scfsi[ch]) - throw new Error('bad scalefactor selection info'); - - channel.region0_count = 7; - channel.region1_count = 36; - - if (stream.read(1)) - channel.flags |= tables.MIXED_BLOCK_FLAG; - else if (channel.block_type === 2) - channel.region0_count = 8; - - for (var i = 0; i < 2; i++) - channel.table_select[i] = stream.read(5); - - for (var i = 0; i < 3; i++) - channel.subblock_gain[i] = stream.read(3); - } else { - channel.block_type = 0; - - for (var i = 0; i < 3; i++) - channel.table_select[i] = stream.read(5); - - channel.region0_count = stream.read(4); - channel.region1_count = stream.read(3); - } - - // [preflag,] scalefac_scale, count1table_select - channel.flags |= stream.read(lsf ? 2 : 3); - } - } - - return { - si: si, - data_bitlen: data_bitlen, - priv_bitlen: priv_bitlen - }; -}; - -Layer3.prototype.decodeMainData = function(stream, frame, si, nch) { - var header = frame.header; - var sfreq = header.samplerate; - - if (header.flags & MP3FrameHeader.FLAGS.MPEG_2_5_EXT) - sfreq *= 2; - - // 48000 => 0, 44100 => 1, 32000 => 2, - // 24000 => 3, 22050 => 4, 16000 => 5 - var sfreqi = ((sfreq >> 7) & 0x000f) + ((sfreq >> 15) & 0x0001) - 8; - - if (header.flags & MP3FrameHeader.FLAGS.MPEG_2_5_EXT) - sfreqi += 3; - - // scalefactors, Huffman decoding, requantization - var ngr = (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) ? 1 : 2; - var xr = this.xr; - - for (var gr = 0; gr < ngr; ++gr) { - var granule = si.gr[gr]; - var sfbwidth = []; - var l = 0; - - for (var ch = 0; ch < nch; ++ch) { - var channel = granule.ch[ch]; - var part2_length; - - sfbwidth[ch] = tables.SFBWIDTH_TABLE[sfreqi].l; - if (channel.block_type === 2) { - sfbwidth[ch] = (channel.flags & tables.MIXED_BLOCK_FLAG) ? tables.SFBWIDTH_TABLE[sfreqi].m : tables.SFBWIDTH_TABLE[sfreqi].s; - } - - if (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) { - part2_length = this.scalefactors_lsf(stream, channel, ch === 0 ? 0 : si.gr[1].ch[1], header.mode_extension); - } else { - part2_length = this.scalefactors(stream, channel, si.gr[0].ch[ch], gr === 0 ? 0 : si.scfsi[ch]); - } - - this.huffmanDecode(stream, xr[ch], channel, sfbwidth[ch], part2_length); - } - - // joint stereo processing - if (header.mode === MP3FrameHeader.MODE.JOINT_STEREO && header.mode_extension !== 0) - this.stereo(xr, si.gr, gr, header, sfbwidth[0]); - - // reordering, alias reduction, IMDCT, overlap-add, frequency inversion - for (var ch = 0; ch < nch; ch++) { - var channel = granule.ch[ch]; - var sample = frame.sbsample[ch].slice(18 * gr); - - var sb, l = 0, i, sblimit; - var output = this.output; - - if (channel.block_type === 2) { - this.reorder(xr[ch], channel, sfbwidth[ch]); - - /* - * According to ISO/IEC 11172-3, "Alias reduction is not applied for - * granules with block_type === 2 (short block)." However, other - * sources suggest alias reduction should indeed be performed on the - * lower two subbands of mixed blocks. Most other implementations do - * this, so by default we will too. - */ - if (channel.flags & tables.MIXED_BLOCK_FLAG) - this.aliasreduce(xr[ch], 36); - } else { - this.aliasreduce(xr[ch], 576); - } - - // subbands 0-1 - if (channel.block_type !== 2 || (channel.flags & tables.MIXED_BLOCK_FLAG)) { - var block_type = channel.block_type; - if (channel.flags & tables.MIXED_BLOCK_FLAG) - block_type = 0; - - // long blocks - for (var sb = 0; sb < 2; ++sb, l += 18) { - this.imdct_l(xr[ch].subarray(l, l + 18), output, block_type); - this.overlap(output, frame.overlap[ch][sb], sample, sb); - } - } else { - // short blocks - for (var sb = 0; sb < 2; ++sb, l += 18) { - this.imdct_s(xr[ch].subarray(l, l + 18), output); - this.overlap(output, frame.overlap[ch][sb], sample, sb); - } - } - - this.freqinver(sample, 1); - - // (nonzero) subbands 2-31 - var i = 576; - while (i > 36 && xr[ch][i - 1] === 0) { - --i; - } - - sblimit = 32 - (((576 - i) / 18) << 0); - - if (channel.block_type !== 2) { - // long blocks - for (var sb = 2; sb < sblimit; ++sb, l += 18) { - this.imdct_l(xr[ch].subarray(l, l + 18), output, channel.block_type); - this.overlap(output, frame.overlap[ch][sb], sample, sb); - - if (sb & 1) - this.freqinver(sample, sb); - } - } else { - // short blocks - for (var sb = 2; sb < sblimit; ++sb, l += 18) { - this.imdct_s(xr[ch].subarray(l, l + 18), output); - this.overlap(output, frame.overlap[ch][sb], sample, sb); - - if (sb & 1) - this.freqinver(sample, sb); - } - } - - // remaining (zero) subbands - for (var sb = sblimit; sb < 32; ++sb) { - this.overlap_z(frame.overlap[ch][sb], sample, sb); - - if (sb & 1) - this.freqinver(sample, sb); - } - } - } -}; - -Layer3.prototype.scalefactors = function(stream, channel, gr0ch, scfsi) { - var start = stream.offset(); - var slen1 = tables.SFLEN_TABLE[channel.scalefac_compress].slen1; - var slen2 = tables.SFLEN_TABLE[channel.scalefac_compress].slen2; - var sfbi; - - if (channel.block_type === 2) { - sfbi = 0; - - var nsfb = (channel.flags & tables.MIXED_BLOCK_FLAG) ? 8 + 3 * 3 : 6 * 3; - while (nsfb--) - channel.scalefac[sfbi++] = stream.read(slen1); - - nsfb = 6 * 3; - while (nsfb--) - channel.scalefac[sfbi++] = stream.read(slen2); - - nsfb = 1 * 3; - while (nsfb--) - channel.scalefac[sfbi++] = 0; - } else { - if (scfsi & 0x8) { - for (var sfbi = 0; sfbi < 6; ++sfbi) - channel.scalefac[sfbi] = gr0ch.scalefac[sfbi]; - } else { - for (var sfbi = 0; sfbi < 6; ++sfbi) - channel.scalefac[sfbi] = stream.read(slen1); - } - - if (scfsi & 0x4) { - for (var sfbi = 6; sfbi < 11; ++sfbi) - channel.scalefac[sfbi] = gr0ch.scalefac[sfbi]; - } else { - for (var sfbi = 6; sfbi < 11; ++sfbi) - channel.scalefac[sfbi] = stream.read(slen1); - } - - if (scfsi & 0x2) { - for (var sfbi = 11; sfbi < 16; ++sfbi) - channel.scalefac[sfbi] = gr0ch.scalefac[sfbi]; - } else { - for (var sfbi = 11; sfbi < 16; ++sfbi) - channel.scalefac[sfbi] = stream.read(slen2); - } - - if (scfsi & 0x1) { - for (var sfbi = 16; sfbi < 21; ++sfbi) - channel.scalefac[sfbi] = gr0ch.scalefac[sfbi]; - } else { - for (var sfbi = 16; sfbi < 21; ++sfbi) - channel.scalefac[sfbi] = stream.read(slen2); - } - - channel.scalefac[21] = 0; - } - - return stream.offset() - start; -}; - -Layer3.prototype.scalefactors_lsf = function(stream, channel, gr1ch, mode_extension) { - var start = stream.offset(); - var scalefac_compress = channel.scalefac_compress; - var index = channel.block_type === 2 ? (channel.flags & tables.MIXED_BLOCK_FLAG ? 2 : 1) : 0; - var slen = new Int32Array(4); - var nsfb; - - if (!((mode_extension & tables.I_STEREO) && gr1ch)) { - if (scalefac_compress < 400) { - slen[0] = (scalefac_compress >>> 4) / 5; - slen[1] = (scalefac_compress >>> 4) % 5; - slen[2] = (scalefac_compress % 16) >>> 2; - slen[3] = scalefac_compress % 4; - - nsfb = tables.NSFB_TABLE[0][index]; - } else if (scalefac_compress < 500) { - scalefac_compress -= 400; - - slen[0] = (scalefac_compress >>> 2) / 5; - slen[1] = (scalefac_compress >>> 2) % 5; - slen[2] = scalefac_compress % 4; - slen[3] = 0; - - nsfb = tables.NSFB_TABLE[1][index]; - } else { - scalefac_compress -= 500; - - slen[0] = scalefac_compress / 3; - slen[1] = scalefac_compress % 3; - slen[2] = 0; - slen[3] = 0; - - channel.flags |= tables.PREFLAG; - nsfb = tables.NSFB_TABLE[2][index]; - } - - var n = 0; - for (var part = 0; part < 4; part++) { - for (var i = 0; i < nsfb[part]; i++) { - channel.scalefac[n++] = stream.read(slen[part]); - } - } - - while (n < 39) { - channel.scalefac[n++] = 0; - } - } else { // (mode_extension & tables.I_STEREO) && gr1ch (i.e. ch == 1) - scalefac_compress >>>= 1; - - if (scalefac_compress < 180) { - slen[0] = scalefac_compress / 36; - slen[1] = (scalefac_compress % 36) / 6; - slen[2] = (scalefac_compress % 36) % 6; - slen[3] = 0; - - nsfb = tables.NSFB_TABLE[3][index]; - } else if (scalefac_compress < 244) { - scalefac_compress -= 180; - - slen[0] = (scalefac_compress % 64) >>> 4; - slen[1] = (scalefac_compress % 16) >>> 2; - slen[2] = scalefac_compress % 4; - slen[3] = 0; - - nsfb = tables.NSFB_TABLE[4][index]; - } else { - scalefac_compress -= 244; - - slen[0] = scalefac_compress / 3; - slen[1] = scalefac_compress % 3; - slen[2] = 0; - slen[3] = 0; - - nsfb = tables.NSFB_TABLE[5][index]; - } - - var n = 0; - for (var part = 0; part < 4; ++part) { - var max = (1 << slen[part]) - 1; - for (var i = 0; i < nsfb[part]; ++i) { - var is_pos = stream.read(slen[part]); - - channel.scalefac[n] = is_pos; - gr1ch.scalefac[n++] = is_pos === max ? 1 : 0; - } - } - - while (n < 39) { - channel.scalefac[n] = 0; - gr1ch.scalefac[n++] = 0; // apparently not illegal - } - } - - return stream.offset() - start; -}; - -Layer3.prototype.huffmanDecode = function(stream, xr, channel, sfbwidth, part2_length) { - var exponents = this._exponents; - var sfbwidthptr = 0; - - var bits_left = channel.part2_3_length - part2_length; - if (bits_left < 0) - throw new Error('bad audio data length'); - - this.exponents(channel, sfbwidth, exponents); - - var peek = stream.copy(); - stream.advance(bits_left); - - /* align bit reads to byte boundaries */ - var cachesz = 8 - peek.bitPosition; - cachesz += ((32 - 1 - 24) + (24 - cachesz)) & ~7; - - var bitcache = peek.read(cachesz); - bits_left -= cachesz; - - var xrptr = 0; - - // big_values - var region = 0; - var reqcache = this.reqcache; - - var sfbound = xrptr + sfbwidth[sfbwidthptr++]; - var rcount = channel.region0_count + 1; - - var entry = huffman.huff_pair_table[channel.table_select[region]]; - var table = entry.table; - var linbits = entry.linbits; - var startbits = entry.startbits; - - if (typeof table === 'undefined') - throw new Error('bad Huffman table select'); - - var expptr = 0; - var exp = exponents[expptr++]; - var reqhits = 0; - var big_values = channel.big_values; - - while (big_values-- && cachesz + bits_left > 0) { - if (xrptr === sfbound) { - sfbound += sfbwidth[sfbwidthptr++]; - - // change table if region boundary - if (--rcount === 0) { - if (region === 0) - rcount = channel.region1_count + 1; - else - rcount = 0; // all remaining - - entry = huffman.huff_pair_table[channel.table_select[++region]]; - table = entry.table; - linbits = entry.linbits; - startbits = entry.startbits; - - if (typeof table === 'undefined') - throw new Error('bad Huffman table select'); - } - - if (exp !== exponents[expptr]) { - exp = exponents[expptr]; - reqhits = 0; - } - - ++expptr; - } - - if (cachesz < 21) { - var bits = ((32 - 1 - 21) + (21 - cachesz)) & ~7; - bitcache = (bitcache << bits) | peek.read(bits); - cachesz += bits; - bits_left -= bits; - } - - var clumpsz = startbits; - var pair = table[ (((bitcache) >> ((cachesz) - (clumpsz))) & ((1 << (clumpsz)) - 1))]; - - while (!pair.final) { - cachesz -= clumpsz; - clumpsz = pair.ptr.bits; - pair = table[pair.ptr.offset + (((bitcache) >> ((cachesz) - (clumpsz))) & ((1 << (clumpsz)) - 1))]; - } - - cachesz -= pair.value.hlen; - - if (linbits) { - var value = pair.value.x; - var x_final = false; - - switch (value) { - case 0: - xr[xrptr] = 0; - break; - - case 15: - if (cachesz < linbits + 2) { - bitcache = (bitcache << 16) | peek.read(16); - cachesz += 16; - bits_left -= 16; - } - - value += (((bitcache) >> ((cachesz) - (linbits))) & ((1 << (linbits)) - 1)); - cachesz -= linbits; - - requantized = this.requantize(value, exp); - x_final = true; // simulating goto, yay - break; - - default: - if (reqhits & (1 << value)) { - requantized = reqcache[value]; - } else { - reqhits |= (1 << value); - requantized = reqcache[value] = this.requantize(value, exp); - } - - x_final = true; - } - - if(x_final) { - xr[xrptr] = ((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized; - } - - value = pair.value.y; - var y_final = false; - - switch (value) { - case 0: - xr[xrptr + 1] = 0; - break; - - case 15: - if (cachesz < linbits + 1) { - bitcache = (bitcache << 16) | peek.read(16); - cachesz += 16; - bits_left -= 16; - } - - value += (((bitcache) >> ((cachesz) - (linbits))) & ((1 << (linbits)) - 1)); - cachesz -= linbits; - - requantized = this.requantize(value, exp); - y_final = true; - break; // simulating goto, yayzor - - default: - if (reqhits & (1 << value)) { - requantized = reqcache[value]; - } else { - reqhits |= (1 << value); - reqcache[value] = this.requantize(value, exp); - requantized = reqcache[value]; - } - - y_final = true; - } - - if(y_final) { - xr[xrptr + 1] = ((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized; - } - - } else { - var value = pair.value.x; - - if (value === 0) { - xr[xrptr] = 0; - } else { - if (reqhits & (1 << value)) - requantized = reqcache[value]; - else { - reqhits |= (1 << value); - requantized = reqcache[value] = this.requantize(value, exp); - } - - xr[xrptr] = ((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized; - } - - value = pair.value.y; - - if (value === 0) { - xr[xrptr + 1] = 0; - } else { - if (reqhits & (1 << value)) - requantized = reqcache[value]; - else { - reqhits |= (1 << value); - requantized = reqcache[value] = this.requantize(value, exp); - } - - xr[xrptr + 1] = ((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized; - } - } - - xrptr += 2; - } - - if (cachesz + bits_left < 0) - throw new Error('Huffman data overrun'); - - // count1 - var table = huffman.huff_quad_table[channel.flags & tables.COUNT1TABLE_SELECT]; - var requantized = this.requantize(1, exp); - - while (cachesz + bits_left > 0 && xrptr <= 572) { - if (cachesz < 10) { - bitcache = (bitcache << 16) | peek.read(16); - cachesz += 16; - bits_left -= 16; - } - - var quad = table[(((bitcache) >> ((cachesz) - (4))) & ((1 << (4)) - 1))]; - - // quad tables guaranteed to have at most one extra lookup - if (!quad.final) { - cachesz -= 4; - quad = table[quad.ptr.offset + (((bitcache) >> ((cachesz) - (quad.ptr.bits))) & ((1 << (quad.ptr.bits)) - 1))]; - } - - cachesz -= quad.value.hlen; - - if (xrptr === sfbound) { - sfbound += sfbwidth[sfbwidthptr++]; - - if (exp !== exponents[expptr]) { - exp = exponents[expptr]; - requantized = this.requantize(1, exp); - } - - ++expptr; - } - - // v (0..1) - xr[xrptr] = quad.value.v ? (((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0; - - // w (0..1) - xr[xrptr + 1] = quad.value.w ? (((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0; - - xrptr += 2; - if (xrptr === sfbound) { - sfbound += sfbwidth[sfbwidthptr++]; - - if (exp !== exponents[expptr]) { - exp = exponents[expptr]; - requantized = this.requantize(1, exp); - } - - ++expptr; - } - - // x (0..1) - xr[xrptr] = quad.value.x ? (((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0; - - // y (0..1) - xr[xrptr + 1] = quad.value.y ? (((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0; - - xrptr += 2; - - if (cachesz + bits_left < 0) { - // technically the bitstream is misformatted, but apparently - // some encoders are just a bit sloppy with stuffing bits - xrptr -= 4; - } - } - - if (-bits_left > MP3FrameHeader.BUFFER_GUARD * 8) { - throw new Error("assertion failed: (-bits_left <= MP3FrameHeader.BUFFER_GUARD * CHAR_BIT)"); - } - - // rzero - while (xrptr < 576) { - xr[xrptr] = 0; - xr[xrptr + 1] = 0; - xrptr += 2; - } -}; - -Layer3.prototype.requantize = function(value, exp) { - // usual (x >> 0) tricks to make sure frac and exp stay integers - var frac = (exp % 4) >> 0; // assumes sign(frac) === sign(exp) - exp = (exp / 4) >> 0; - - var requantized = Math.pow(value, 4.0 / 3.0); - requantized *= Math.pow(2.0, (exp / 4.0)); - - if (frac) { - requantized *= Math.pow(2.0, (frac / 4.0)); - } - - if (exp < 0) { - requantized /= Math.pow(2.0, -exp * (3.0 / 4.0)); - } - - return requantized; -}; - -Layer3.prototype.exponents = function(channel, sfbwidth, exponents) { - var gain = channel.global_gain - 210; - var scalefac_multiplier = (channel.flags & tables.SCALEFAC_SCALE) ? 2 : 1; - - if (channel.block_type === 2) { - var sfbi = 0, l = 0; - - if (channel.flags & tables.MIXED_BLOCK_FLAG) { - var premask = (channel.flags & tables.PREFLAG) ? ~0 : 0; - - // long block subbands 0-1 - while (l < 36) { - exponents[sfbi] = gain - ((channel.scalefac[sfbi] + (tables.PRETAB[sfbi] & premask)) << scalefac_multiplier); - l += sfbwidth[sfbi++]; - } - } - - // this is probably wrong for 8000 Hz short/mixed blocks - var gain0 = gain - 8 * channel.subblock_gain[0]; - var gain1 = gain - 8 * channel.subblock_gain[1]; - var gain2 = gain - 8 * channel.subblock_gain[2]; - - while (l < 576) { - exponents[sfbi + 0] = gain0 - (channel.scalefac[sfbi + 0] << scalefac_multiplier); - exponents[sfbi + 1] = gain1 - (channel.scalefac[sfbi + 1] << scalefac_multiplier); - exponents[sfbi + 2] = gain2 - (channel.scalefac[sfbi + 2] << scalefac_multiplier); - - l += 3 * sfbwidth[sfbi]; - sfbi += 3; - } - } else { - if (channel.flags & tables.PREFLAG) { - for (var sfbi = 0; sfbi < 22; sfbi++) { - exponents[sfbi] = gain - ((channel.scalefac[sfbi] + tables.PRETAB[sfbi]) << scalefac_multiplier); - } - } else { - for (var sfbi = 0; sfbi < 22; sfbi++) { - exponents[sfbi] = gain - (channel.scalefac[sfbi] << scalefac_multiplier); - } - } - } -}; - -Layer3.prototype.stereo = function(xr, granules, gr, header, sfbwidth) { - var granule = granules[gr]; - var modes = this.modes; - var sfbi, l, n, i; - - if (granule.ch[0].block_type !== granule.ch[1].block_type || (granule.ch[0].flags & tables.MIXED_BLOCK_FLAG) !== (granule.ch[1].flags & tables.MIXED_BLOCK_FLAG)) - throw new Error('incompatible stereo block_type'); - - for (var i = 0; i < 39; i++) - modes[i] = header.mode_extension; - - // intensity stereo - if (header.mode_extension & tables.I_STEREO) { - var right_ch = granule.ch[1]; - var right_xr = xr[1]; - - header.flags |= MP3FrameHeader.FLAGS.tables.I_STEREO; - - // first determine which scalefactor bands are to be processed - if (right_ch.block_type === 2) { - var lower, start, max, bound = new Uint32Array(3), w; - - lower = start = max = bound[0] = bound[1] = bound[2] = 0; - sfbi = l = 0; - - if (right_ch.flags & tables.MIXED_BLOCK_FLAG) { - while (l < 36) { - n = sfbwidth[sfbi++]; - - for (var i = 0; i < n; ++i) { - if (right_xr[i]) { - lower = sfbi; - break; - } - } - - right_xr += n; - l += n; - } - - start = sfbi; - } - - var w = 0; - while (l < 576) { - n = sfbwidth[sfbi++]; - - for (i = 0; i < n; ++i) { - if (right_xr[i]) { - max = bound[w] = sfbi; - break; - } - } - - right_xr += n; - l += n; - w = (w + 1) % 3; - } - - if (max) - lower = start; - - // long blocks - for (i = 0; i < lower; ++i) - modes[i] = header.mode_extension & ~tables.I_STEREO; - - // short blocks - w = 0; - for (i = start; i < max; ++i) { - if (i < bound[w]) - modes[i] = header.mode_extension & ~tables.I_STEREO; - - w = (w + 1) % 3; - } - } else { - var bound = 0; - for (sfbi = l = 0; l < 576; l += n) { - n = sfbwidth[sfbi++]; - - for (i = 0; i < n; ++i) { - if (right_xr[i]) { - bound = sfbi; - break; - } - } - - right_xr += n; - } - - for (i = 0; i < bound; ++i) - modes[i] = header.mode_extension & ~tables.I_STEREO; - } - - // now do the actual processing - if (header.flags & MP3FrameHeader.FLAGS.LSF_EXT) { - var illegal_pos = granules[gr + 1].ch[1].scalefac; - - // intensity_scale - var lsf_scale = IS_Ltables.SF_TABLE[right_ch.scalefac_compress & 0x1]; - - for (sfbi = l = 0; l < 576; ++sfbi, l += n) { - n = sfbwidth[sfbi]; - - if (!(modes[sfbi] & tables.I_STEREO)) - continue; - - if (illegal_pos[sfbi]) { - modes[sfbi] &= ~tables.I_STEREO; - continue; - } - - is_pos = right_ch.scalefac[sfbi]; - - for (i = 0; i < n; ++i) { - var left = xr[0][l + i]; - - if (is_pos === 0) { - xr[1][l + i] = left; - } else { - var opposite = left * lsf_scale[(is_pos - 1) / 2]; - - if (is_pos & 1) { - xr[0][l + i] = opposite; - xr[1][l + i] = left; - } - else { - xr[1][l + i] = opposite; - } - } - } - } - } else { - for (sfbi = l = 0; l < 576; ++sfbi, l += n) { - n = sfbwidth[sfbi]; - - if (!(modes[sfbi] & tables.I_STEREO)) - continue; - - is_pos = right_ch.scalefac[sfbi]; - - if (is_pos >= 7) { // illegal intensity position - modes[sfbi] &= ~tables.I_STEREO; - continue; - } - - for (i = 0; i < n; ++i) { - var left = xr[0][l + i]; - xr[0][l + i] = left * tables.IS_TABLE[is_pos]; - xr[1][l + i] = left * tables.IS_TABLE[6 - is_pos]; - } - } - } - } - - // middle/side stereo - if (header.mode_extension & tables.MS_STEREO) { - header.flags |= tables.MS_STEREO; - - var invsqrt2 = tables.ROOT_TABLE[3 + -2]; - - for (sfbi = l = 0; l < 576; ++sfbi, l += n) { - n = sfbwidth[sfbi]; - - if (modes[sfbi] !== tables.MS_STEREO) - continue; - - for (i = 0; i < n; ++i) { - var m = xr[0][l + i]; - var s = xr[1][l + i]; - - xr[0][l + i] = (m + s) * invsqrt2; // l = (m + s) / sqrt(2) - xr[1][l + i] = (m - s) * invsqrt2; // r = (m - s) / sqrt(2) - } - } - } -}; - -Layer3.prototype.aliasreduce = function(xr, lines) { - for (var xrPointer = 18; xrPointer < lines; xrPointer += 18) { - for (var i = 0; i < 8; ++i) { - var a = xr[xrPointer - i - 1]; - var b = xr[xrPointer + i]; - - xr[xrPointer - i - 1] = a * tables.CS[i] - b * tables.CA[i]; - xr[xrPointer + i] = b * tables.CS[i] + a * tables.CA[i]; - } - } -}; - -// perform IMDCT and windowing for long blocks -Layer3.prototype.imdct_l = function (X, z, block_type) { - // IMDCT - this.imdct.imdct36(X, z); - - // windowing - switch (block_type) { - case 0: // normal window - for (var i = 0; i < 36; ++i) z[i] = z[i] * tables.WINDOW_L[i]; - break; - - case 1: // start block - for (var i = 0; i < 18; ++i) z[i] = z[i] * tables.WINDOW_L[i]; - for (var i = 24; i < 30; ++i) z[i] = z[i] * tables.WINDOW_S[i - 18]; - for (var i = 30; i < 36; ++i) z[i] = 0; - break; - - case 3: // stop block - for (var i = 0; i < 6; ++i) z[i] = 0; - for (var i = 6; i < 12; ++i) z[i] = z[i] * tables.WINDOW_S[i - 6]; - for (var i = 18; i < 36; ++i) z[i] = z[i] * tables.WINDOW_L[i]; - break; - } -}; - -/* - * perform IMDCT and windowing for short blocks - */ -Layer3.prototype.imdct_s = function (X, z) { - var yptr = 0; - var wptr; - var Xptr = 0; - - var y = new Float64Array(36); - var hi, lo; - - // IMDCT - for (var w = 0; w < 3; ++w) { - var sptr = 0; - - for (var i = 0; i < 3; ++i) { - lo = X[Xptr + 0] * IMDCT.S[sptr][0] + - X[Xptr + 1] * IMDCT.S[sptr][1] + - X[Xptr + 2] * IMDCT.S[sptr][2] + - X[Xptr + 3] * IMDCT.S[sptr][3] + - X[Xptr + 4] * IMDCT.S[sptr][4] + - X[Xptr + 5] * IMDCT.S[sptr][5]; - - - y[yptr + i + 0] = lo; - y[yptr + 5 - i] = -y[yptr + i + 0]; - - ++sptr; - - lo = X[Xptr + 0] * IMDCT.S[sptr][0] + - X[Xptr + 1] * IMDCT.S[sptr][1] + - X[Xptr + 2] * IMDCT.S[sptr][2] + - X[Xptr + 3] * IMDCT.S[sptr][3] + - X[Xptr + 4] * IMDCT.S[sptr][4] + - X[Xptr + 5] * IMDCT.S[sptr][5]; - - y[yptr + i + 6] = lo; - y[yptr + 11 - i] = y[yptr + i + 6]; - - ++sptr; - } - - yptr += 12; - Xptr += 6; - } - - // windowing, overlapping and concatenation - yptr = 0; - var wptr = 0; - - for (var i = 0; i < 6; ++i) { - z[i + 0] = 0; - z[i + 6] = y[yptr + 0 + 0] * tables.WINDOW_S[wptr + 0]; - - lo = y[yptr + 0 + 6] * tables.WINDOW_S[wptr + 6] + - y[yptr + 12 + 0] * tables.WINDOW_S[wptr + 0]; - - z[i + 12] = lo; - - lo = y[yptr + 12 + 6] * tables.WINDOW_S[wptr + 6] + - y[yptr + 24 + 0] * tables.WINDOW_S[wptr + 0]; - - z[i + 18] = lo; - z[i + 24] = y[yptr + 24 + 6] * tables.WINDOW_S[wptr + 6]; - z[i + 30] = 0; - - ++yptr; - ++wptr; - } -}; - -Layer3.prototype.overlap = function (output, overlap, sample, sb) { - for (var i = 0; i < 18; ++i) { - sample[i][sb] = output[i] + overlap[i]; - overlap[i] = output[i + 18]; - } -}; - -Layer3.prototype.freqinver = function (sample, sb) { - for (var i = 1; i < 18; i += 2) - sample[i][sb] = -sample[i][sb]; -}; - -Layer3.prototype.overlap_z = function (overlap, sample, sb) { - for (var i = 0; i < 18; ++i) { - sample[i][sb] = overlap[i]; - overlap[i] = 0; - } -}; - -Layer3.prototype.reorder = function (xr, channel, sfbwidth) { - var sfbwidthPointer = 0; - var tmp = this.tmp; - var sbw = new Uint32Array(3); - var sw = new Uint32Array(3); - - // this is probably wrong for 8000 Hz mixed blocks - - var sb = 0; - if (channel.flags & tables.MIXED_BLOCK_FLAG) { - var sb = 2; - - var l = 0; - while (l < 36) - l += sfbwidth[sfbwidthPointer++]; - } - - for (var w = 0; w < 3; ++w) { - sbw[w] = sb; - sw[w] = 0; - } - - f = sfbwidth[sfbwidthPointer++]; - w = 0; - - for (var l = 18 * sb; l < 576; ++l) { - if (f-- === 0) { - f = sfbwidth[sfbwidthPointer++] - 1; - w = (w + 1) % 3; - } - - tmp[sbw[w]][w][sw[w]++] = xr[l]; - - if (sw[w] === 6) { - sw[w] = 0; - ++sbw[w]; - } - } - - var tmp2 = this.tmp2; - var ptr = 0; - - for (var i = 0; i < 32; i++) { - for (var j = 0; j < 3; j++) { - for (var k = 0; k < 6; k++) { - tmp2[ptr++] = tmp[i][j][k]; - } - } - } - - var len = (576 - 18 * sb); - for (var i = 0; i < len; i++) { - xr[18 * sb + i] = tmp2[sb + i]; - } -}; - -module.exports = Layer3; - -},{"./frame":4,"./header":5,"./huffman":6,"./imdct":8,"./tables":14,"./utils":15}],12:[function(require,module,exports){ -var AV = (window.AV); -var MP3FrameHeader = require('./header'); - -function MP3Stream(stream) { - this.stream = stream; // actual bitstream - this.sync = false; // stream sync found - this.freerate = 0; // free bitrate (fixed) - this.this_frame = stream.stream.offset; // start of current frame - this.next_frame = stream.stream.offset; // start of next frame - - this.main_data = new Uint8Array(MP3FrameHeader.BUFFER_MDLEN); // actual audio data - this.md_len = 0; // length of main data - - // copy methods from actual stream - for (var key in stream) { - if (typeof stream[key] === 'function') - this[key] = stream[key].bind(stream); - } -} - -MP3Stream.prototype.getU8 = function(offset) { - var stream = this.stream.stream; - return stream.peekUInt8(offset - stream.offset); -}; - -MP3Stream.prototype.nextByte = function() { - var stream = this.stream; - return stream.bitPosition === 0 ? stream.stream.offset : stream.stream.offset + 1; -}; - -MP3Stream.prototype.doSync = function() { - var stream = this.stream.stream; - this.align(); - - while (this.available(16) && !(stream.peekUInt8(0) === 0xff && (stream.peekUInt8(1) & 0xe0) === 0xe0)) { - this.advance(8); - } - - if (!this.available(MP3FrameHeader.BUFFER_GUARD)) - return false; - - return true; -}; - -MP3Stream.prototype.reset = function(byteOffset) { - this.seek(byteOffset * 8); - this.next_frame = byteOffset; - this.sync = true; -}; - -module.exports = MP3Stream; - -},{"./header":5}],13:[function(require,module,exports){ -var utils = require('./utils'); - -function MP3Synth() { - this.filter = utils.makeArray([2, 2, 2, 16, 8]); // polyphase filterbank outputs - this.phase = 0; - - this.pcm = { - samplerate: 0, - channels: 0, - length: 0, - samples: [new Float64Array(1152), new Float64Array(1152)] - }; -} - -/* costab[i] = cos(PI / (2 * 32) * i) */ -const costab1 = 0.998795456; -const costab2 = 0.995184727; -const costab3 = 0.989176510; -const costab4 = 0.980785280; -const costab5 = 0.970031253; -const costab6 = 0.956940336; -const costab7 = 0.941544065; -const costab8 = 0.923879533; -const costab9 = 0.903989293; -const costab10 = 0.881921264; -const costab11 = 0.857728610; -const costab12 = 0.831469612; -const costab13 = 0.803207531; -const costab14 = 0.773010453; -const costab15 = 0.740951125; -const costab16 = 0.707106781; -const costab17 = 0.671558955; -const costab18 = 0.634393284; -const costab19 = 0.595699304; -const costab20 = 0.555570233; -const costab21 = 0.514102744; -const costab22 = 0.471396737; -const costab23 = 0.427555093; -const costab24 = 0.382683432; -const costab25 = 0.336889853; -const costab26 = 0.290284677; -const costab27 = 0.242980180; -const costab28 = 0.195090322; -const costab29 = 0.146730474; -const costab30 = 0.098017140; -const costab31 = 0.049067674; - -/* - * NAME: dct32() - * DESCRIPTION: perform fast in[32].out[32] DCT - */ -MP3Synth.dct32 = function (_in, slot, lo, hi) { - var t0, t1, t2, t3, t4, t5, t6, t7; - var t8, t9, t10, t11, t12, t13, t14, t15; - var t16, t17, t18, t19, t20, t21, t22, t23; - var t24, t25, t26, t27, t28, t29, t30, t31; - var t32, t33, t34, t35, t36, t37, t38, t39; - var t40, t41, t42, t43, t44, t45, t46, t47; - var t48, t49, t50, t51, t52, t53, t54, t55; - var t56, t57, t58, t59, t60, t61, t62, t63; - var t64, t65, t66, t67, t68, t69, t70, t71; - var t72, t73, t74, t75, t76, t77, t78, t79; - var t80, t81, t82, t83, t84, t85, t86, t87; - var t88, t89, t90, t91, t92, t93, t94, t95; - var t96, t97, t98, t99, t100, t101, t102, t103; - var t104, t105, t106, t107, t108, t109, t110, t111; - var t112, t113, t114, t115, t116, t117, t118, t119; - var t120, t121, t122, t123, t124, t125, t126, t127; - var t128, t129, t130, t131, t132, t133, t134, t135; - var t136, t137, t138, t139, t140, t141, t142, t143; - var t144, t145, t146, t147, t148, t149, t150, t151; - var t152, t153, t154, t155, t156, t157, t158, t159; - var t160, t161, t162, t163, t164, t165, t166, t167; - var t168, t169, t170, t171, t172, t173, t174, t175; - var t176; - - t0 = _in[0] + _in[31]; t16 = ((_in[0] - _in[31]) * (costab1)); - t1 = _in[15] + _in[16]; t17 = ((_in[15] - _in[16]) * (costab31)); - - t41 = t16 + t17; - t59 = ((t16 - t17) * (costab2)); - t33 = t0 + t1; - t50 = ((t0 - t1) * ( costab2)); - - t2 = _in[7] + _in[24]; t18 = ((_in[7] - _in[24]) * (costab15)); - t3 = _in[8] + _in[23]; t19 = ((_in[8] - _in[23]) * (costab17)); - - t42 = t18 + t19; - t60 = ((t18 - t19) * (costab30)); - t34 = t2 + t3; - t51 = ((t2 - t3) * ( costab30)); - - t4 = _in[3] + _in[28]; t20 = ((_in[3] - _in[28]) * (costab7)); - t5 = _in[12] + _in[19]; t21 = ((_in[12] - _in[19]) * (costab25)); - - t43 = t20 + t21; - t61 = ((t20 - t21) * (costab14)); - t35 = t4 + t5; - t52 = ((t4 - t5) * ( costab14)); - - t6 = _in[4] + _in[27]; t22 = ((_in[4] - _in[27]) * (costab9)); - t7 = _in[11] + _in[20]; t23 = ((_in[11] - _in[20]) * (costab23)); - - t44 = t22 + t23; - t62 = ((t22 - t23) * (costab18)); - t36 = t6 + t7; - t53 = ((t6 - t7) * ( costab18)); - - t8 = _in[1] + _in[30]; t24 = ((_in[1] - _in[30]) * (costab3)); - t9 = _in[14] + _in[17]; t25 = ((_in[14] - _in[17]) * (costab29)); - - t45 = t24 + t25; - t63 = ((t24 - t25) * (costab6)); - t37 = t8 + t9; - t54 = ((t8 - t9) * ( costab6)); - - t10 = _in[6] + _in[25]; t26 = ((_in[6] - _in[25]) * (costab13)); - t11 = _in[9] + _in[22]; t27 = ((_in[9] - _in[22]) * (costab19)); - - t46 = t26 + t27; - t64 = ((t26 - t27) * (costab26)); - t38 = t10 + t11; - t55 = ((t10 - t11) * (costab26)); - - t12 = _in[2] + _in[29]; t28 = ((_in[2] - _in[29]) * (costab5)); - t13 = _in[13] + _in[18]; t29 = ((_in[13] - _in[18]) * (costab27)); - - t47 = t28 + t29; - t65 = ((t28 - t29) * (costab10)); - t39 = t12 + t13; - t56 = ((t12 - t13) * (costab10)); - - t14 = _in[5] + _in[26]; t30 = ((_in[5] - _in[26]) * (costab11)); - t15 = _in[10] + _in[21]; t31 = ((_in[10] - _in[21]) * (costab21)); - - t48 = t30 + t31; - t66 = ((t30 - t31) * (costab22)); - t40 = t14 + t15; - t57 = ((t14 - t15) * (costab22)); - - t69 = t33 + t34; t89 = ((t33 - t34) * (costab4)); - t70 = t35 + t36; t90 = ((t35 - t36) * (costab28)); - t71 = t37 + t38; t91 = ((t37 - t38) * (costab12)); - t72 = t39 + t40; t92 = ((t39 - t40) * (costab20)); - t73 = t41 + t42; t94 = ((t41 - t42) * (costab4)); - t74 = t43 + t44; t95 = ((t43 - t44) * (costab28)); - t75 = t45 + t46; t96 = ((t45 - t46) * (costab12)); - t76 = t47 + t48; t97 = ((t47 - t48) * (costab20)); - - t78 = t50 + t51; t100 = ((t50 - t51) * (costab4)); - t79 = t52 + t53; t101 = ((t52 - t53) * (costab28)); - t80 = t54 + t55; t102 = ((t54 - t55) * (costab12)); - t81 = t56 + t57; t103 = ((t56 - t57) * (costab20)); - - t83 = t59 + t60; t106 = ((t59 - t60) * (costab4)); - t84 = t61 + t62; t107 = ((t61 - t62) * (costab28)); - t85 = t63 + t64; t108 = ((t63 - t64) * (costab12)); - t86 = t65 + t66; t109 = ((t65 - t66) * (costab20)); - - t113 = t69 + t70; - t114 = t71 + t72; - - /* 0 */ hi[15][slot] = t113 + t114; - /* 16 */ lo[ 0][slot] = ((t113 - t114) * (costab16)); - - t115 = t73 + t74; - t116 = t75 + t76; - - t32 = t115 + t116; - - /* 1 */ hi[14][slot] = t32; - - t118 = t78 + t79; - t119 = t80 + t81; - - t58 = t118 + t119; - - /* 2 */ hi[13][slot] = t58; - - t121 = t83 + t84; - t122 = t85 + t86; - - t67 = t121 + t122; - - t49 = (t67 * 2) - t32; - - /* 3 */ hi[12][slot] = t49; - - t125 = t89 + t90; - t126 = t91 + t92; - - t93 = t125 + t126; - - /* 4 */ hi[11][slot] = t93; - - t128 = t94 + t95; - t129 = t96 + t97; - - t98 = t128 + t129; - - t68 = (t98 * 2) - t49; - - /* 5 */ hi[10][slot] = t68; - - t132 = t100 + t101; - t133 = t102 + t103; - - t104 = t132 + t133; - - t82 = (t104 * 2) - t58; - - /* 6 */ hi[ 9][slot] = t82; - - t136 = t106 + t107; - t137 = t108 + t109; - - t110 = t136 + t137; - - t87 = (t110 * 2) - t67; - - t77 = (t87 * 2) - t68; - - /* 7 */ hi[ 8][slot] = t77; - - t141 = ((t69 - t70) * (costab8)); - t142 = ((t71 - t72) * (costab24)); - t143 = t141 + t142; - - /* 8 */ hi[ 7][slot] = t143; - /* 24 */ lo[ 8][slot] = - (((t141 - t142) * (costab16) * 2)) - t143; - - t144 = ((t73 - t74) * (costab8)); - t145 = ((t75 - t76) * (costab24)); - t146 = t144 + t145; - - t88 = (t146 * 2) - t77; - - /* 9 */ hi[ 6][slot] = t88; - - t148 = ((t78 - t79) * (costab8)); - t149 = ((t80 - t81) * (costab24)); - t150 = t148 + t149; - - t105 = (t150 * 2) - t82; - - /* 10 */ hi[ 5][slot] = t105; - - t152 = ((t83 - t84) * (costab8)); - t153 = ((t85 - t86) * (costab24)); - t154 = t152 + t153; - - t111 = (t154 * 2) - t87; - - t99 = (t111 * 2) - t88; - - /* 11 */ hi[ 4][slot] = t99; - - t157 = ((t89 - t90) * (costab8)); - t158 = ((t91 - t92) * (costab24)); - t159 = t157 + t158; - - t127 = (t159 * 2) - t93; - - /* 12 */ hi[ 3][slot] = t127; - - t160 = (((t125 - t126) * (costab16) * 2)) - t127; - - /* 20 */ lo[ 4][slot] = t160; - /* 28 */ lo[12][slot] = - (((((t157 - t158) * (costab16) * 2) - t159) * 2)) - t160; - - t161 = ((t94 - t95) * (costab8)); - t162 = ((t96 - t97) * (costab24)); - t163 = t161 + t162; - - t130 = (t163 * 2) - t98; - - t112 = (t130 * 2) - t99; - - /* 13 */ hi[ 2][slot] = t112; - - t164 = (((t128 - t129) * (costab16) * 2)) - t130; - - t166 = ((t100 - t101) * (costab8)); - t167 = ((t102 - t103) * (costab24)); - t168 = t166 + t167; - - t134 = (t168 * 2) - t104; - - t120 = (t134 * 2) - t105; - - /* 14 */ hi[ 1][slot] = t120; - - t135 = (((t118 - t119) * (costab16) * 2)) - t120; - - /* 18 */ lo[ 2][slot] = t135; - - t169 = (((t132 - t133) * (costab16) * 2)) - t134; - - t151 = (t169 * 2) - t135; - - /* 22 */ lo[ 6][slot] = t151; - - t170 = (((((t148 - t149) * (costab16) * 2) - t150) * 2)) - t151; - - /* 26 */ lo[10][slot] = t170; - /* 30 */ lo[14][slot] = - (((((((t166 - t167) * (costab16)) * 2 - - t168) * 2) - t169) * 2) - t170); - - t171 = ((t106 - t107) * (costab8)); - t172 = ((t108 - t109) * (costab24)); - t173 = t171 + t172; - - t138 = (t173 * 2) - t110; - t123 = (t138 * 2) - t111; - t139 = (((t121 - t122) * (costab16) * 2)) - t123; - t117 = (t123 * 2) - t112; - - /* 15 */ hi[ 0][slot] = t117; - - t124 = (((t115 - t116) * (costab16) * 2)) - t117; - - /* 17 */ lo[ 1][slot] = t124; - - t131 = (t139 * 2) - t124; - - /* 19 */ lo[ 3][slot] = t131; - - t140 = (t164 * 2) - t131; - - /* 21 */ lo[ 5][slot] = t140; - - t174 = (((t136 - t137) * (costab16) * 2)) - t138; - t155 = (t174 * 2) - t139; - t147 = (t155 * 2) - t140; - - /* 23 */ lo[ 7][slot] = t147; - - t156 = (((((t144 - t145) * (costab16) * 2) - t146) * 2)) - t147; - - /* 25 */ lo[ 9][slot] = t156; - - t175 = (((((t152 - t153) * (costab16) * 2) - t154) * 2)) - t155; - t165 = (t175 * 2) - t156; - - /* 27 */ lo[11][slot] = t165; - - t176 = (((((((t161 - t162) * (costab16) * 2)) - - t163) * 2) - t164) * 2) - t165; - - /* 29 */ lo[13][slot] = t176; - /* 31 */ lo[15][slot] = - (((((((((t171 - t172) * (costab16)) * 2 - - t173) * 2) - t174) * 2) - t175) * 2) - t176); - - /* - * Totals: - * 80 multiplies - * 80 additions - * 119 subtractions - * 49 shifts (not counting SSO) - */ -}; - -/* - * These are the coefficients for the subband synthesis window. This is a - * reordered version of Table B.3 from ISO/IEC 11172-3. - */ -const D = [ - [ 0.000000000, /* 0 */ - -0.000442505, - 0.003250122, - -0.007003784, - 0.031082153, - -0.078628540, - 0.100311279, - -0.572036743, - 1.144989014, - 0.572036743, - 0.100311279, - 0.078628540, - 0.031082153, - 0.007003784, - 0.003250122, - 0.000442505, - - 0.000000000, - -0.000442505, - 0.003250122, - -0.007003784, - 0.031082153, - -0.078628540, - 0.100311279, - -0.572036743, - 1.144989014, - 0.572036743, - 0.100311279, - 0.078628540, - 0.031082153, - 0.007003784, - 0.003250122, - 0.000442505 ], - - [ -0.000015259, /* 1 */ - -0.000473022, - 0.003326416, - -0.007919312, - 0.030517578, - -0.084182739, - 0.090927124, - -0.600219727, - 1.144287109, - 0.543823242, - 0.108856201, - 0.073059082, - 0.031478882, - 0.006118774, - 0.003173828, - 0.000396729, - - -0.000015259, - -0.000473022, - 0.003326416, - -0.007919312, - 0.030517578, - -0.084182739, - 0.090927124, - -0.600219727, - 1.144287109, - 0.543823242, - 0.108856201, - 0.073059082, - 0.031478882, - 0.006118774, - 0.003173828, - 0.000396729 ], - - [ -0.000015259, /* 2 */ - -0.000534058, - 0.003387451, - -0.008865356, - 0.029785156, - -0.089706421, - 0.080688477, - -0.628295898, - 1.142211914, - 0.515609741, - 0.116577148, - 0.067520142, - 0.031738281, - 0.005294800, - 0.003082275, - 0.000366211, - - -0.000015259, - -0.000534058, - 0.003387451, - -0.008865356, - 0.029785156, - -0.089706421, - 0.080688477, - -0.628295898, - 1.142211914, - 0.515609741, - 0.116577148, - 0.067520142, - 0.031738281, - 0.005294800, - 0.003082275, - 0.000366211 ], - - [ -0.000015259, /* 3 */ - -0.000579834, - 0.003433228, - -0.009841919, - 0.028884888, - -0.095169067, - 0.069595337, - -0.656219482, - 1.138763428, - 0.487472534, - 0.123474121, - 0.061996460, - 0.031845093, - 0.004486084, - 0.002990723, - 0.000320435, - - -0.000015259, - -0.000579834, - 0.003433228, - -0.009841919, - 0.028884888, - -0.095169067, - 0.069595337, - -0.656219482, - 1.138763428, - 0.487472534, - 0.123474121, - 0.061996460, - 0.031845093, - 0.004486084, - 0.002990723, - 0.000320435 ], - - [ -0.000015259, /* 4 */ - -0.000625610, - 0.003463745, - -0.010848999, - 0.027801514, - -0.100540161, - 0.057617187, - -0.683914185, - 1.133926392, - 0.459472656, - 0.129577637, - 0.056533813, - 0.031814575, - 0.003723145, - 0.002899170, - 0.000289917, - - -0.000015259, - -0.000625610, - 0.003463745, - -0.010848999, - 0.027801514, - -0.100540161, - 0.057617187, - -0.683914185, - 1.133926392, - 0.459472656, - 0.129577637, - 0.056533813, - 0.031814575, - 0.003723145, - 0.002899170, - 0.000289917 ], - - [ -0.000015259, /* 5 */ - -0.000686646, - 0.003479004, - -0.011886597, - 0.026535034, - -0.105819702, - 0.044784546, - -0.711318970, - 1.127746582, - 0.431655884, - 0.134887695, - 0.051132202, - 0.031661987, - 0.003005981, - 0.002792358, - 0.000259399, - - -0.000015259, - -0.000686646, - 0.003479004, - -0.011886597, - 0.026535034, - -0.105819702, - 0.044784546, - -0.711318970, - 1.127746582, - 0.431655884, - 0.134887695, - 0.051132202, - 0.031661987, - 0.003005981, - 0.002792358, - 0.000259399 ], - - [ -0.000015259, /* 6 */ - -0.000747681, - 0.003479004, - -0.012939453, - 0.025085449, - -0.110946655, - 0.031082153, - -0.738372803, - 1.120223999, - 0.404083252, - 0.139450073, - 0.045837402, - 0.031387329, - 0.002334595, - 0.002685547, - 0.000244141, - - -0.000015259, - -0.000747681, - 0.003479004, - -0.012939453, - 0.025085449, - -0.110946655, - 0.031082153, - -0.738372803, - 1.120223999, - 0.404083252, - 0.139450073, - 0.045837402, - 0.031387329, - 0.002334595, - 0.002685547, - 0.000244141 ], - - [ -0.000030518, /* 7 */ - -0.000808716, - 0.003463745, - -0.014022827, - 0.023422241, - -0.115921021, - 0.016510010, - -0.765029907, - 1.111373901, - 0.376800537, - 0.143264771, - 0.040634155, - 0.031005859, - 0.001693726, - 0.002578735, - 0.000213623, - - -0.000030518, - -0.000808716, - 0.003463745, - -0.014022827, - 0.023422241, - -0.115921021, - 0.016510010, - -0.765029907, - 1.111373901, - 0.376800537, - 0.143264771, - 0.040634155, - 0.031005859, - 0.001693726, - 0.002578735, - 0.000213623 ], - - [ -0.000030518, /* 8 */ - -0.000885010, - 0.003417969, - -0.015121460, - 0.021575928, - -0.120697021, - 0.001068115, - -0.791213989, - 1.101211548, - 0.349868774, - 0.146362305, - 0.035552979, - 0.030532837, - 0.001098633, - 0.002456665, - 0.000198364, - - -0.000030518, - -0.000885010, - 0.003417969, - -0.015121460, - 0.021575928, - -0.120697021, - 0.001068115, - -0.791213989, - 1.101211548, - 0.349868774, - 0.146362305, - 0.035552979, - 0.030532837, - 0.001098633, - 0.002456665, - 0.000198364 ], - - [ -0.000030518, /* 9 */ - -0.000961304, - 0.003372192, - -0.016235352, - 0.019531250, - -0.125259399, - -0.015228271, - -0.816864014, - 1.089782715, - 0.323318481, - 0.148773193, - 0.030609131, - 0.029937744, - 0.000549316, - 0.002349854, - 0.000167847, - - -0.000030518, - -0.000961304, - 0.003372192, - -0.016235352, - 0.019531250, - -0.125259399, - -0.015228271, - -0.816864014, - 1.089782715, - 0.323318481, - 0.148773193, - 0.030609131, - 0.029937744, - 0.000549316, - 0.002349854, - 0.000167847 ], - - [ -0.000030518, /* 10 */ - -0.001037598, - 0.003280640, - -0.017349243, - 0.017257690, - -0.129562378, - -0.032379150, - -0.841949463, - 1.077117920, - 0.297210693, - 0.150497437, - 0.025817871, - 0.029281616, - 0.000030518, - 0.002243042, - 0.000152588, - - -0.000030518, - -0.001037598, - 0.003280640, - -0.017349243, - 0.017257690, - -0.129562378, - -0.032379150, - -0.841949463, - 1.077117920, - 0.297210693, - 0.150497437, - 0.025817871, - 0.029281616, - 0.000030518, - 0.002243042, - 0.000152588 ], - - [ -0.000045776, /* 11 */ - -0.001113892, - 0.003173828, - -0.018463135, - 0.014801025, - -0.133590698, - -0.050354004, - -0.866363525, - 1.063217163, - 0.271591187, - 0.151596069, - 0.021179199, - 0.028533936, - -0.000442505, - 0.002120972, - 0.000137329, - - -0.000045776, - -0.001113892, - 0.003173828, - -0.018463135, - 0.014801025, - -0.133590698, - -0.050354004, - -0.866363525, - 1.063217163, - 0.271591187, - 0.151596069, - 0.021179199, - 0.028533936, - -0.000442505, - 0.002120972, - 0.000137329 ], - - [ -0.000045776, /* 12 */ - -0.001205444, - 0.003051758, - -0.019577026, - 0.012115479, - -0.137298584, - -0.069168091, - -0.890090942, - 1.048156738, - 0.246505737, - 0.152069092, - 0.016708374, - 0.027725220, - -0.000869751, - 0.002014160, - 0.000122070, - - -0.000045776, - -0.001205444, - 0.003051758, - -0.019577026, - 0.012115479, - -0.137298584, - -0.069168091, - -0.890090942, - 1.048156738, - 0.246505737, - 0.152069092, - 0.016708374, - 0.027725220, - -0.000869751, - 0.002014160, - 0.000122070 ], - - [ -0.000061035, /* 13 */ - -0.001296997, - 0.002883911, - -0.020690918, - 0.009231567, - -0.140670776, - -0.088775635, - -0.913055420, - 1.031936646, - 0.221984863, - 0.151962280, - 0.012420654, - 0.026840210, - -0.001266479, - 0.001907349, - 0.000106812, - - -0.000061035, - -0.001296997, - 0.002883911, - -0.020690918, - 0.009231567, - -0.140670776, - -0.088775635, - -0.913055420, - 1.031936646, - 0.221984863, - 0.151962280, - 0.012420654, - 0.026840210, - -0.001266479, - 0.001907349, - 0.000106812 ], - - [ -0.000061035, /* 14 */ - -0.001388550, - 0.002700806, - -0.021789551, - 0.006134033, - -0.143676758, - -0.109161377, - -0.935195923, - 1.014617920, - 0.198059082, - 0.151306152, - 0.008316040, - 0.025909424, - -0.001617432, - 0.001785278, - 0.000106812, - - -0.000061035, - -0.001388550, - 0.002700806, - -0.021789551, - 0.006134033, - -0.143676758, - -0.109161377, - -0.935195923, - 1.014617920, - 0.198059082, - 0.151306152, - 0.008316040, - 0.025909424, - -0.001617432, - 0.001785278, - 0.000106812 ], - - [ -0.000076294, /* 15 */ - -0.001480103, - 0.002487183, - -0.022857666, - 0.002822876, - -0.146255493, - -0.130310059, - -0.956481934, - 0.996246338, - 0.174789429, - 0.150115967, - 0.004394531, - 0.024932861, - -0.001937866, - 0.001693726, - 0.000091553, - - -0.000076294, - -0.001480103, - 0.002487183, - -0.022857666, - 0.002822876, - -0.146255493, - -0.130310059, - -0.956481934, - 0.996246338, - 0.174789429, - 0.150115967, - 0.004394531, - 0.024932861, - -0.001937866, - 0.001693726, - 0.000091553 ], - - [ -0.000076294, /* 16 */ - -0.001586914, - 0.002227783, - -0.023910522, - -0.000686646, - -0.148422241, - -0.152206421, - -0.976852417, - 0.976852417, - 0.152206421, - 0.148422241, - 0.000686646, - 0.023910522, - -0.002227783, - 0.001586914, - 0.000076294, - - -0.000076294, - -0.001586914, - 0.002227783, - -0.023910522, - -0.000686646, - -0.148422241, - -0.152206421, - -0.976852417, - 0.976852417, - 0.152206421, - 0.148422241, - 0.000686646, - 0.023910522, - -0.002227783, - 0.001586914, - 0.000076294 ] -]; - -/* - * perform full frequency PCM synthesis - */ -MP3Synth.prototype.full = function(frame, nch, ns) { - var Dptr, hi, lo, ptr; - - for (var ch = 0; ch < nch; ++ch) { - var sbsample = frame.sbsample[ch]; - var filter = this.filter[ch]; - var phase = this.phase; - var pcm = this.pcm.samples[ch]; - var pcm1Ptr = 0; - var pcm2Ptr = 0; - - for (var s = 0; s < ns; ++s) { - MP3Synth.dct32(sbsample[s], phase >> 1, filter[0][phase & 1], filter[1][phase & 1]); - - var pe = phase & ~1; - var po = ((phase - 1) & 0xf) | 1; - - /* calculate 32 samples */ - var fe = filter[0][ phase & 1]; - var fx = filter[0][~phase & 1]; - var fo = filter[1][~phase & 1]; - - var fePtr = 0; - var fxPtr = 0; - var foPtr = 0; - - Dptr = 0; - - ptr = D[Dptr]; - _fx = fx[fxPtr]; - _fe = fe[fePtr]; - - lo = _fx[0] * ptr[po + 0]; - lo += _fx[1] * ptr[po + 14]; - lo += _fx[2] * ptr[po + 12]; - lo += _fx[3] * ptr[po + 10]; - lo += _fx[4] * ptr[po + 8]; - lo += _fx[5] * ptr[po + 6]; - lo += _fx[6] * ptr[po + 4]; - lo += _fx[7] * ptr[po + 2]; - lo = -lo; - - lo += _fe[0] * ptr[pe + 0]; - lo += _fe[1] * ptr[pe + 14]; - lo += _fe[2] * ptr[pe + 12]; - lo += _fe[3] * ptr[pe + 10]; - lo += _fe[4] * ptr[pe + 8]; - lo += _fe[5] * ptr[pe + 6]; - lo += _fe[6] * ptr[pe + 4]; - lo += _fe[7] * ptr[pe + 2]; - - pcm[pcm1Ptr++] = lo; - pcm2Ptr = pcm1Ptr + 30; - - for (var sb = 1; sb < 16; ++sb) { - ++fePtr; - ++Dptr; - - /* D[32 - sb][i] === -D[sb][31 - i] */ - - ptr = D[Dptr]; - _fo = fo[foPtr]; - _fe = fe[fePtr]; - - lo = _fo[0] * ptr[po + 0]; - lo += _fo[1] * ptr[po + 14]; - lo += _fo[2] * ptr[po + 12]; - lo += _fo[3] * ptr[po + 10]; - lo += _fo[4] * ptr[po + 8]; - lo += _fo[5] * ptr[po + 6]; - lo += _fo[6] * ptr[po + 4]; - lo += _fo[7] * ptr[po + 2]; - lo = -lo; - - lo += _fe[7] * ptr[pe + 2]; - lo += _fe[6] * ptr[pe + 4]; - lo += _fe[5] * ptr[pe + 6]; - lo += _fe[4] * ptr[pe + 8]; - lo += _fe[3] * ptr[pe + 10]; - lo += _fe[2] * ptr[pe + 12]; - lo += _fe[1] * ptr[pe + 14]; - lo += _fe[0] * ptr[pe + 0]; - - pcm[pcm1Ptr++] = lo; - - lo = _fe[0] * ptr[-pe + 31 - 16]; - lo += _fe[1] * ptr[-pe + 31 - 14]; - lo += _fe[2] * ptr[-pe + 31 - 12]; - lo += _fe[3] * ptr[-pe + 31 - 10]; - lo += _fe[4] * ptr[-pe + 31 - 8]; - lo += _fe[5] * ptr[-pe + 31 - 6]; - lo += _fe[6] * ptr[-pe + 31 - 4]; - lo += _fe[7] * ptr[-pe + 31 - 2]; - - lo += _fo[7] * ptr[-po + 31 - 2]; - lo += _fo[6] * ptr[-po + 31 - 4]; - lo += _fo[5] * ptr[-po + 31 - 6]; - lo += _fo[4] * ptr[-po + 31 - 8]; - lo += _fo[3] * ptr[-po + 31 - 10]; - lo += _fo[2] * ptr[-po + 31 - 12]; - lo += _fo[1] * ptr[-po + 31 - 14]; - lo += _fo[0] * ptr[-po + 31 - 16]; - - pcm[pcm2Ptr--] = lo; - ++foPtr; - } - - ++Dptr; - - ptr = D[Dptr]; - _fo = fo[foPtr]; - - lo = _fo[0] * ptr[po + 0]; - lo += _fo[1] * ptr[po + 14]; - lo += _fo[2] * ptr[po + 12]; - lo += _fo[3] * ptr[po + 10]; - lo += _fo[4] * ptr[po + 8]; - lo += _fo[5] * ptr[po + 6]; - lo += _fo[6] * ptr[po + 4]; - lo += _fo[7] * ptr[po + 2]; - - pcm[pcm1Ptr] = -lo; - pcm1Ptr += 16; - phase = (phase + 1) % 16; - } - } -}; - -// TODO: synth.half() - -/* - * NAME: synth.frame() - * DESCRIPTION: perform PCM synthesis of frame subband samples - */ -MP3Synth.prototype.frame = function (frame) { - var nch = frame.header.nchannels(); - var ns = frame.header.nbsamples(); - - this.pcm.samplerate = frame.header.samplerate; - this.pcm.channels = nch; - this.pcm.length = 32 * ns; - - /* - if (frame.options & Mad.Option.HALFSAMPLERATE) { - this.pcm.samplerate /= 2; - this.pcm.length /= 2; - - throw new Error("HALFSAMPLERATE is not supported. What do you think? As if I have the time for this"); - } - */ - - this.full(frame, nch, ns); - this.phase = (this.phase + ns) % 16; -}; - -module.exports = MP3Synth; - -},{"./utils":15}],14:[function(require,module,exports){ -/* - * These are the scalefactor values for Layer I and Layer II. - * The values are from Table B.1 of ISO/IEC 11172-3. - * - * Strictly speaking, Table B.1 has only 63 entries (0-62), thus a strict - * interpretation of ISO/IEC 11172-3 would suggest that a scalefactor index of - * 63 is invalid. However, for better compatibility with current practices, we - * add a 64th entry. - */ -exports.SF_TABLE = new Float32Array([ - 2.000000000000, 1.587401051968, 1.259921049895, 1.000000000000, - 0.793700525984, 0.629960524947, 0.500000000000, 0.396850262992, - 0.314980262474, 0.250000000000, 0.198425131496, 0.157490131237, - 0.125000000000, 0.099212565748, 0.078745065618, 0.062500000000, - 0.049606282874, 0.039372532809, 0.031250000000, 0.024803141437, - 0.019686266405, 0.015625000000, 0.012401570719, 0.009843133202, - 0.007812500000, 0.006200785359, 0.004921566601, 0.003906250000, - 0.003100392680, 0.002460783301, 0.001953125000, 0.001550196340, - 0.001230391650, 0.000976562500, 0.000775098170, 0.000615195825, - 0.000488281250, 0.000387549085, 0.000307597913, 0.000244140625, - 0.000193774542, 0.000153798956, 0.000122070313, 0.000096887271, - 0.000076899478, 0.000061035156, 0.000048443636, 0.000038449739, - 0.000030517578, 0.000024221818, 0.000019224870, 0.000015258789, - 0.000012110909, 0.000009612435, 0.000007629395, 0.000006055454, - 0.000004806217, 0.000003814697, 0.000003027727, 0.000002403109, - 0.000001907349, 0.000001513864, 0.000001201554, 0.000000000000 -]); - -/* - * MPEG-1 scalefactor band widths - * derived from Table B.8 of ISO/IEC 11172-3 - */ -const SFB_48000_LONG = new Uint8Array([ - 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10, - 12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192 -]); - -const SFB_44100_LONG = new Uint8Array([ - 4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, - 12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158 -]); - -const SFB_32000_LONG = new Uint8Array([ - 4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12, - 16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26 -]); - -const SFB_48000_SHORT = new Uint8Array([ - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, - 6, 6, 6, 6, 6, 10, 10, 10, 12, 12, 12, 14, 14, - 14, 16, 16, 16, 20, 20, 20, 26, 26, 26, 66, 66, 66 -]); - -const SFB_44100_SHORT = new Uint8Array([ - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, - 6, 6, 8, 8, 8, 10, 10, 10, 12, 12, 12, 14, 14, - 14, 18, 18, 18, 22, 22, 22, 30, 30, 30, 56, 56, 56 -]); - -const SFB_32000_SHORT = new Uint8Array([ - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, - 6, 6, 8, 8, 8, 12, 12, 12, 16, 16, 16, 20, 20, - 20, 26, 26, 26, 34, 34, 34, 42, 42, 42, 12, 12, 12 -]); - -const SFB_48000_MIXED = new Uint8Array([ - /* long */ 4, 4, 4, 4, 4, 4, 6, 6, - /* short */ 4, 4, 4, 6, 6, 6, 6, 6, 6, 10, - 10, 10, 12, 12, 12, 14, 14, 14, 16, 16, - 16, 20, 20, 20, 26, 26, 26, 66, 66, 66 -]); - -const SFB_44100_MIXED = new Uint8Array([ - /* long */ 4, 4, 4, 4, 4, 4, 6, 6, - /* short */ 4, 4, 4, 6, 6, 6, 8, 8, 8, 10, - 10, 10, 12, 12, 12, 14, 14, 14, 18, 18, - 18, 22, 22, 22, 30, 30, 30, 56, 56, 56 -]); - -const SFB_32000_MIXED = new Uint8Array([ - /* long */ 4, 4, 4, 4, 4, 4, 6, 6, - /* short */ 4, 4, 4, 6, 6, 6, 8, 8, 8, 12, - 12, 12, 16, 16, 16, 20, 20, 20, 26, 26, - 26, 34, 34, 34, 42, 42, 42, 12, 12, 12 -]); - -/* - * MPEG-2 scalefactor band widths - * derived from Table B.2 of ISO/IEC 13818-3 - */ -const SFB_24000_LONG = new Uint8Array([ - 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, - 18, 22, 26, 32, 38, 46, 54, 62, 70, 76, 36 -]); - -const SFB_22050_LONG = new Uint8Array([ - 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, - 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 -]); - -const SFB_16000_LONG = SFB_22050_LONG; - -const SFB_24000_SHORT = new Uint8Array([ - 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, - 8, 8, 10, 10, 10, 12, 12, 12, 14, 14, 14, 18, 18, - 18, 24, 24, 24, 32, 32, 32, 44, 44, 44, 12, 12, 12 -]); - -const SFB_22050_SHORT = new Uint8Array([ - 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, - 6, 6, 8, 8, 8, 10, 10, 10, 14, 14, 14, 18, 18, - 18, 26, 26, 26, 32, 32, 32, 42, 42, 42, 18, 18, 18 -]); - -const SFB_16000_SHORT = new Uint8Array([ - 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, - 8, 8, 10, 10, 10, 12, 12, 12, 14, 14, 14, 18, 18, - 18, 24, 24, 24, 30, 30, 30, 40, 40, 40, 18, 18, 18 -]); - -const SFB_24000_MIXED = new Uint8Array([ - /* long */ 6, 6, 6, 6, 6, 6, - /* short */ 6, 6, 6, 8, 8, 8, 10, 10, 10, 12, - 12, 12, 14, 14, 14, 18, 18, 18, 24, 24, - 24, 32, 32, 32, 44, 44, 44, 12, 12, 12 -]); - -const SFB_22050_MIXED = new Uint8Array([ - /* long */ 6, 6, 6, 6, 6, 6, - /* short */ 6, 6, 6, 6, 6, 6, 8, 8, 8, 10, - 10, 10, 14, 14, 14, 18, 18, 18, 26, 26, - 26, 32, 32, 32, 42, 42, 42, 18, 18, 18 -]); - -const SFB_16000_MIXED = new Uint8Array([ - /* long */ 6, 6, 6, 6, 6, 6, - /* short */ 6, 6, 6, 8, 8, 8, 10, 10, 10, 12, - 12, 12, 14, 14, 14, 18, 18, 18, 24, 24, - 24, 30, 30, 30, 40, 40, 40, 18, 18, 18 -]); - -/* - * MPEG 2.5 scalefactor band widths - * derived from public sources - */ -const SFB_12000_LONG = SFB_16000_LONG; -const SFB_11025_LONG = SFB_12000_LONG; - -const SFB_8000_LONG = new Uint8Array([ - 12, 12, 12, 12, 12, 12, 16, 20, 24, 28, 32, - 40, 48, 56, 64, 76, 90, 2, 2, 2, 2, 2 -]); - -const SFB_12000_SHORT = SFB_16000_SHORT; -const SFB_11025_SHORT = SFB_12000_SHORT; - -const SFB_8000_SHORT = new Uint8Array([ - 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 16, - 16, 16, 20, 20, 20, 24, 24, 24, 28, 28, 28, 36, 36, - 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26 -]); - -const SFB_12000_MIXED = SFB_16000_MIXED; -const SFB_11025_MIXED = SFB_12000_MIXED; - -/* the 8000 Hz short block scalefactor bands do not break after - the first 36 frequency lines, so this is probably wrong */ -const SFB_8000_MIXED = new Uint8Array([ - /* long */ 12, 12, 12, - /* short */ 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16, - 20, 20, 20, 24, 24, 24, 28, 28, 28, 36, 36, 36, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26 -]); - -exports.SFBWIDTH_TABLE = [ - { l: SFB_48000_LONG, s: SFB_48000_SHORT, m: SFB_48000_MIXED }, - { l: SFB_44100_LONG, s: SFB_44100_SHORT, m: SFB_44100_MIXED }, - { l: SFB_32000_LONG, s: SFB_32000_SHORT, m: SFB_32000_MIXED }, - { l: SFB_24000_LONG, s: SFB_24000_SHORT, m: SFB_24000_MIXED }, - { l: SFB_22050_LONG, s: SFB_22050_SHORT, m: SFB_22050_MIXED }, - { l: SFB_16000_LONG, s: SFB_16000_SHORT, m: SFB_16000_MIXED }, - { l: SFB_12000_LONG, s: SFB_12000_SHORT, m: SFB_12000_MIXED }, - { l: SFB_11025_LONG, s: SFB_11025_SHORT, m: SFB_11025_MIXED }, - { l: SFB_8000_LONG, s: SFB_8000_SHORT, m: SFB_8000_MIXED } -]; - -exports.PRETAB = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 -]); - -/* - * fractional powers of two - * used for requantization and joint stereo decoding - * - * ROOT_TABLE[3 + x] = 2^(x/4) - */ -exports.ROOT_TABLE = new Float32Array([ - /* 2^(-3/4) */ 0.59460355750136, - /* 2^(-2/4) */ 0.70710678118655, - /* 2^(-1/4) */ 0.84089641525371, - /* 2^( 0/4) */ 1.00000000000000, - /* 2^(+1/4) */ 1.18920711500272, - /* 2^(+2/4) */ 1.41421356237310, - /* 2^(+3/4) */ 1.68179283050743 -]); - -exports.CS = new Float32Array([ - +0.857492926 , +0.881741997, - +0.949628649 , +0.983314592, - +0.995517816 , +0.999160558, - +0.999899195 , +0.999993155 -]); - -exports.CA = new Float32Array([ - -0.514495755, -0.471731969, - -0.313377454, -0.181913200, - -0.094574193, -0.040965583, - -0.014198569, -0.003699975 -]); - -exports.COUNT1TABLE_SELECT = 0x01; -exports.SCALEFAC_SCALE = 0x02; -exports.PREFLAG = 0x04; -exports.MIXED_BLOCK_FLAG = 0x08; - -exports.I_STEREO = 0x1; -exports.MS_STEREO = 0x2; - -/* - * windowing coefficients for long blocks - * derived from section 2.4.3.4.10.3 of ISO/IEC 11172-3 - * - * WINDOW_L[i] = sin((PI / 36) * (i + 1/2)) - */ -exports.WINDOW_L = new Float32Array([ - 0.043619387, 0.130526192, - 0.216439614, 0.300705800, - 0.382683432, 0.461748613, - 0.537299608, 0.608761429, - 0.675590208, 0.737277337, - 0.793353340, 0.843391446, - - 0.887010833, 0.923879533, - 0.953716951, 0.976296007, - 0.991444861, 0.999048222, - 0.999048222, 0.991444861, - 0.976296007, 0.953716951, - 0.923879533, 0.887010833, - - 0.843391446, 0.793353340, - 0.737277337, 0.675590208, - 0.608761429, 0.537299608, - 0.461748613, 0.382683432, - 0.300705800, 0.216439614, - 0.130526192, 0.043619387 -]); - -/* - * windowing coefficients for short blocks - * derived from section 2.4.3.4.10.3 of ISO/IEC 11172-3 - * - * WINDOW_S[i] = sin((PI / 12) * (i + 1/2)) - */ -exports.WINDOW_S = new Float32Array([ - 0.130526192, 0.382683432, - 0.608761429, 0.793353340, - 0.923879533, 0.991444861, - 0.991444861, 0.923879533, - 0.793353340, 0.608761429, - 0.382683432, 0.130526192 -]); - -/* - * coefficients for intensity stereo processing - * derived from section 2.4.3.4.9.3 of ISO/IEC 11172-3 - * - * is_ratio[i] = tan(i * (PI / 12)) - * IS_TABLE[i] = is_ratio[i] / (1 + is_ratio[i]) - */ -exports.IS_TABLE = new Float32Array([ - 0.000000000, - 0.211324865, - 0.366025404, - 0.500000000, - 0.633974596, - 0.788675135, - 1.000000000 -]); - -/* - * coefficients for LSF intensity stereo processing - * derived from section 2.4.3.2 of ISO/IEC 13818-3 - * - * IS_LSF_TABLE[0][i] = (1 / sqrt(sqrt(2)))^(i + 1) - * IS_LSF_TABLE[1][i] = (1 / sqrt(2)) ^(i + 1) - */ -exports.IS_LSF_TABLE = [ - new Float32Array([ - 0.840896415, - 0.707106781, - 0.594603558, - 0.500000000, - 0.420448208, - 0.353553391, - 0.297301779, - 0.250000000, - 0.210224104, - 0.176776695, - 0.148650889, - 0.125000000, - 0.105112052, - 0.088388348, - 0.074325445 - ]), - new Float32Array([ - 0.707106781, - 0.500000000, - 0.353553391, - 0.250000000, - 0.176776695, - 0.125000000, - 0.088388348, - 0.062500000, - 0.044194174, - 0.031250000, - 0.022097087, - 0.015625000, - 0.011048543, - 0.007812500, - 0.005524272 - ]) -]; - -/* - * scalefactor bit lengths - * derived from section 2.4.2.7 of ISO/IEC 11172-3 - */ -exports.SFLEN_TABLE = [ - { slen1: 0, slen2: 0 }, { slen1: 0, slen2: 1 }, { slen1: 0, slen2: 2 }, { slen1: 0, slen2: 3 }, - { slen1: 3, slen2: 0 }, { slen1: 1, slen2: 1 }, { slen1: 1, slen2: 2 }, { slen1: 1, slen2: 3 }, - { slen1: 2, slen2: 1 }, { slen1: 2, slen2: 2 }, { slen1: 2, slen2: 3 }, { slen1: 3, slen2: 1 }, - { slen1: 3, slen2: 2 }, { slen1: 3, slen2: 3 }, { slen1: 4, slen2: 2 }, { slen1: 4, slen2: 3 } -]; - -/* - * number of LSF scalefactor band values - * derived from section 2.4.3.2 of ISO/IEC 13818-3 - */ -exports.NSFB_TABLE = [ - [ [ 6, 5, 5, 5 ], - [ 9, 9, 9, 9 ], - [ 6, 9, 9, 9 ] ], - - [ [ 6, 5, 7, 3 ], - [ 9, 9, 12, 6 ], - [ 6, 9, 12, 6 ] ], - - [ [ 11, 10, 0, 0 ], - [ 18, 18, 0, 0 ], - [ 15, 18, 0, 0 ] ], - - [ [ 7, 7, 7, 0 ], - [ 12, 12, 12, 0 ], - [ 6, 15, 12, 0 ] ], - - [ [ 6, 6, 6, 3 ], - [ 12, 9, 9, 6 ], - [ 6, 12, 9, 6 ] ], - - [ [ 8, 8, 5, 0 ], - [ 15, 12, 9, 0 ], - [ 6, 18, 9, 0 ] ] -]; - -},{}],15:[function(require,module,exports){ -/** - * Makes a multidimensional array - */ -exports.makeArray = function(lengths, Type) { - if (!Type) Type = Float64Array; - - if (lengths.length === 1) { - return new Type(lengths[0]); - } - - var ret = [], - len = lengths[0]; - - for (var j = 0; j < len; j++) { - ret[j] = exports.makeArray(lengths.slice(1), Type); - } - - return ret; -}; - -},{}]},{},[1]) - - -//# sourceMappingURL=mp3.js.map \ No newline at end of file diff --git a/lorgar/main.js b/lorgar/main.js index 7627ece..2dbe195 100644 --- a/lorgar/main.js +++ b/lorgar/main.js @@ -1,10 +1,7 @@ "use strict"; (function main_js() { requirejs.config({ - "baseUrl": "/", - "shim": { - "lib/mp3/mp3": ["lib/aurora/aurora"] - } + "baseUrl": "/" }); requirejs.onError = function(e) { throw e; @@ -14,7 +11,8 @@ defineArray.push("test/test"); defineArray.push("core/lorgar"); defineArray.push("lib/utils/globalMethods"); - defineArray.push("lib/mp3/mp3"); + defineArray.push("lib/em/wrapper"); + require(defineArray, function main_module() { require("lib/utils/globalMethods"); @@ -24,6 +22,8 @@ var Controller = require("lib/wController/controller"); var View = require("views/view"); + window.Mp3Decoder = Module.Decoder; + var waiter = { views: false, controllers: false, diff --git a/lorgar/views/CMakeLists.txt b/lorgar/views/CMakeLists.txt index d8df8e5..7e9ad6f 100644 --- a/lorgar/views/CMakeLists.txt +++ b/lorgar/views/CMakeLists.txt @@ -14,5 +14,6 @@ configure_file(image.js image.js) configure_file(button.js button.js) configure_file(enumeration.js enumeration.js) configure_file(player.js player.js) +configure_file(songProgress.js songProgress.js) add_subdirectory(helpers) diff --git a/lorgar/views/player.js b/lorgar/views/player.js index 160333c..9013cac 100644 --- a/lorgar/views/player.js +++ b/lorgar/views/player.js @@ -8,6 +8,7 @@ deps.push("views/label"); deps.push("views/view"); deps.push("views/image"); + deps.push("views/songProgress"); deps.push("lib/wController/localModel"); @@ -19,6 +20,7 @@ var Label = require("views/label"); var View = require("views/view"); var Image = require("views/image"); + var SongProgress = require("views/songProgress"); var Model = require("lib/wController/localModel"); @@ -34,6 +36,7 @@ this._next = null; this._picture = null; this._cpbCtrl = null; + this._infoModels = { artist: new Model(null, "artist: unknown"), album: new Model(null, "album: unknown"), @@ -46,12 +49,14 @@ var artist = new Label(this._infoModels.artist); var album = new Label(this._infoModels.album); 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(song, 1, 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.song.destructor.bind(this._infoModels.song)); diff --git a/lorgar/views/songProgress.js b/lorgar/views/songProgress.js new file mode 100644 index 0000000..02c153d --- /dev/null +++ b/lorgar/views/songProgress.js @@ -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; + }) +})(); + diff --git a/magnus/app.js b/magnus/app.js index 389ab9c..451dcfe 100644 --- a/magnus/app.js +++ b/magnus/app.js @@ -3,6 +3,8 @@ var morgan = require("morgan"); var favicon = require("serve-favicon"); var Magnus = require("./core/magnus"); +express.static.mime.types.wasm = 'application/wasm'; + require("./lib/utils/globalMethods"); var config = require("./config"); From 3f660239ec4651a297a19e7fa80393925ed56df0 Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 26 Jan 2019 21:54:22 +0300 Subject: [PATCH 13/16] seeking, autonext song --- lib/wModel/file/audio.cpp | 2 +- libjs/utils/globalMethods.js | 35 ++++++ libjs/wController/file/audio.js | 2 +- libjs/wController/player.js | 199 ++++++++++++++++++++++++++---- lorgar/views/helpers/draggable.js | 47 +------ lorgar/views/songProgress.js | 59 +++++++++ lorgar/views/view.js | 16 +++ 7 files changed, 294 insertions(+), 66 deletions(-) diff --git a/lib/wModel/file/audio.cpp b/lib/wModel/file/audio.cpp index a46d754..d018231 100644 --- a/lib/wModel/file/audio.cpp +++ b/lib/wModel/file/audio.cpp @@ -40,6 +40,6 @@ void M::Audio::initAdditional(const W::String& p_mime) } } - additional.insert(u"duration", new W::Uint64(length / MAD_TIMER_RESOLUTION)); + additional.insert(u"duration", new W::Uint64(length * 1000 / MAD_TIMER_RESOLUTION)); additional.insert(u"bitrate", new W::Uint64(tBits / amount)); } diff --git a/libjs/utils/globalMethods.js b/libjs/utils/globalMethods.js index c104d9a..da47d1e 100644 --- a/libjs/utils/globalMethods.js +++ b/libjs/utils/globalMethods.js @@ -65,5 +65,40 @@ global.W = { // Return the modified object return lTarget; + }, + touchToMouse: function (e) { + e.preventDefault(); + if (e.touches.length > 1 || (e.type == "touchend" && e.touches.length > 0)) + return; + + var type = null; + var touch = null; + var src = e.currentTarget; + switch (e.type) { + case "touchstart": + type = "mousedown"; + touch = e.changedTouches[0]; + + break; + case "touchmove": + type = "mousemove"; + touch = e.changedTouches[0]; + src = window; + break; + case "touchend": + type = "mouseup"; + touch = e.changedTouches[0]; + src = window; + break; + } + + var event = new MouseEvent(type, { + button: 0, + screenX: touch.screenX, + screenY: touch.screenY, + clientX: touch.clientX, + clientY: touch.clientY + }); + src.dispatchEvent(event); } }; diff --git a/libjs/wController/file/audio.js b/libjs/wController/file/audio.js index 9d8474e..77b4d1b 100644 --- a/libjs/wController/file/audio.js +++ b/libjs/wController/file/audio.js @@ -17,7 +17,7 @@ var Audio = File.inherit({ return this._additional.at("bitrate").valueOf(); }, getDuration: function() { - return this._additional.at("duration").valueOf(); + return this._additional.at("duration").valueOf() / 1000; } }); diff --git a/libjs/wController/player.js b/libjs/wController/player.js index e434890..f4f3e8c 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -22,6 +22,9 @@ var Player = Controller.inherit({ this.views = Object.create(null); this.mode = PlayerMode.straight.playback; this.progress = new ProgressModel(); + this.progress.on("seekingStart", this._onSeekingStart, this); + this.progress.on("seekingEnd", this._onSeekingEnd, this); + this.progress.on("seek", this._onSeek, this); this._audio = null; this._createStateMachine(); this._createPlayingInfrastructure(); @@ -31,7 +34,7 @@ var Player = Controller.inherit({ this.addHandler("play"); this.addHandler("pause"); - this._playbackInterval = setInterval(this._onInterval.bind(this), 250); + this._playbackInterval = setInterval(this._onInterval.bind(this), intervalPrecision); }, destructor: function() { this._clearInterval(this._playbackInterval); @@ -82,8 +85,8 @@ var Player = Controller.inherit({ break; case ItemType.straight.currentPlayback: ctrl = new Vocabulary(address.clone()); - ctrl.on("newElement", this._onNewPlayBackElement, this); - ctrl.on("removeElement", this._onNewRemoveBackElement, this); + ctrl.on("newElement", this._onNewPlaybackElement, this); + ctrl.on("removeElement", this._onRemovePlaybackElement, this); supported = true; break; case ItemType.straight.picture: @@ -109,20 +112,34 @@ var Player = Controller.inherit({ this.trigger("newElement", ctrl, t); } }, + _checkIfEnough: function() { + var diff = this._currentTime - this._seekingTime - this._ctx.currentTime; + if (diff > threshold) { + this._fsm.manipulation("enough"); + } else { + this._fsm.manipulation("notEnough"); + } + }, _createPlayingInfrastructure: function() { this._ctx = new AudioContext(); this._decoder = new Mp3Decoder(); this._currentTime = 0; + this._seekingTime = 0; + this._buffers = []; + this._sources = []; this._ctx.suspend(); }, + _createStateMachine: function() { + this._fsm = new StateMachine("initial", graphs[this.mode]); + this._fsm.on("stateChanged", this._onStateChanged, this); + }, _destroyPlayingInfrastructure: function() { this._ctx.close(); this._decoder.delete(); }, - _createStateMachine: function() { - this._fsm = new StateMachine("initial", graphs[this.mode]); - this._fsm.on("stateChanged", this._onStateChanged, this); + getCurrentPlaybackTime: function() { + return this._ctx.currentTime + this._seekingTime; }, _h_get: function(ev) { var data = ev.getData(); @@ -187,10 +204,26 @@ var Player = Controller.inherit({ if (sb === undefined) { break; } else { - var src = this._ctx.createBufferSource(); - src.buffer = sb; - src.connect(this._ctx.destination); - src.start(this._currentTime); + this._buffers.push(sb); + + var startTime = this._currentTime - this._seekingTime; + if (startTime < this._ctx.currentTime) { + var offset = startTime - this._ctx.currentTime + sb.duration; + if (offset > 0) { + var src = this._ctx.createBufferSource(); + src.buffer = sb; + src.connect(this._ctx.destination); + src.start(0, Math.abs(startTime - this._ctx.currentTime)); + this._sources.push(src); + } + } else { + var src = this._ctx.createBufferSource(); + src.buffer = sb; + src.connect(this._ctx.destination); + src.start(startTime); + this._sources.push(src); + } + this._currentTime += sb.duration; } } @@ -208,11 +241,22 @@ var Player = Controller.inherit({ this._fsm.manipulation("controllerReady"); }, _onInterval: function() { - if (this._audio && this._audio.initialized) { - this.progress.setPlayback(this._ctx.currentTime / this._audio.getDuration()); + if (this._audio && this._audio.initialized && seekingStates.indexOf(this._fsm.state()) === -1) { + var duration = this._audio.getDuration(); + this.progress.setPlayback(this.getCurrentPlaybackTime() / duration); + this._checkIfEnough(); + + if (this.progress.playback >= 0.9999) { + var next = this.controls[ItemType.straight.next]; + if (next && next.enabled) { + next.activate(); + } else { + //todo kinda stop state? + } + } } }, - _onNewPlayBackElement: function(key, element) { + _onNewPlaybackElement: function(key, element) { switch (key) { case "image": var address = new Address(["images", element.toString()]); @@ -230,7 +274,7 @@ var Player = Controller.inherit({ break; } }, - _onNewRemoveBackElement: function(key) { + _onRemovePlaybackElement: function(key) { switch (key) { case "image": this._removeView(ItemType.straight.picture); @@ -241,6 +285,53 @@ var Player = Controller.inherit({ this._audio = null; } }, + _onSeek: function(progress) { + if (seekingStates.indexOf(this._fsm.state()) !== -1) { + this.progress.setPlayback(progress); + } + }, + _onSeekingStart: function() { + this._fsm.manipulation("startSeeking"); + }, + _onSeekingEnd: function(progress) { + if (seekingStates.indexOf(this._fsm.state()) !== -1) { + for (var i = 0; i < this._sources.length; ++i) { + this._sources[i].stop(); + } + this._sources = []; + + var ct = this.getCurrentPlaybackTime(); + var duration = this._audio.getDuration(); + var targetTime = duration * progress; + this._seekingTime += targetTime - ct; + + var nc = 0; + + for (var i = 0; i < this._buffers.length; ++i) { + var buffer = this._buffers[i]; + var startTime = nc - targetTime; + if (startTime < 0) { + var offset = startTime + buffer.duration; + if (offset > 0) { + var src = this._ctx.createBufferSource(); + src.buffer = buffer; + src.connect(this._ctx.destination); + src.start(0, Math.abs(startTime)); + this._sources.push(src); + } + } else { + var src = this._ctx.createBufferSource(); + src.buffer = buffer; + src.connect(this._ctx.destination); + src.start(this._ctx.currentTime + startTime); + this._sources.push(src); + } + + nc += buffer.duration; + } + } + this._fsm.manipulation("stopSeeking"); + }, _onStateChanged: function(e) { switch (e.newState) { case "initial": @@ -273,12 +364,31 @@ var Player = Controller.inherit({ case "hasControllerPlaying": if (this._audio.hasMore()) { this._audio.requestSlice(audioPortion); - - this._ctx.resume(); //todo temporal } else { this._fsm.manipulation("noMoreFrames"); } break; + case "buffering": + break; + case "bufferingPlaying": + if (e.oldState === "playing") { + this._ctx.suspend(); + } + break; + case "seeking": + break; + case "seekingPlaying": + if (e.oldState === "playing") { + this._ctx.suspend(); + } + break; + case "seekingAllLoaded": + break; + case "seekingPlayingAllLoaded": + if (e.oldState === "playingAllLoaded") { + this._ctx.suspend(); + } + break; case "paused": switch (e.oldState) { case "playing": @@ -299,6 +409,8 @@ var Player = Controller.inherit({ case "playingAllLoaded": switch (e.oldState) { case "pausedAllLoaded": + case "bufferingPlaying": + case "seekingPlayingAllLoaded": this._ctx.resume(); break; } @@ -365,36 +477,77 @@ graphs[PlayerMode.straight.playback] = { controllerReady: "hasControllerPlaying" }, "hasController": { - newFrames: "paused", + newFrames: "bufferingPlaying", play: "hasControllerPlaying", noController: "initial" }, "hasControllerPlaying": { - newFrames: "playing", + newFrames: "bufferingPlaying", pause: "hasController", noController: "initialPlaying" }, + "buffering": { + play: "bufferingPlaying", + enough: "paused", + noMoreFrames: "pausedAllLoaded", + startSeeking: "seeking", + noController: "initial" + }, + "bufferingPlaying": { + pause: "buffering", + enough: "playing", + noMoreFrames: "playingAllLoaded", + startSeeking: "seekingPlaying", + noController: "initialPlaying" + }, + "seeking": { + stopSeeking: "buffering", + noMoreFrames: "seekingAllLoaded", + noController: "initial" + }, + "seekingPlaying": { + stopSeeking: "bufferingPlaying", + noMoreFrames: "playingAllLoaded", + noController: "initialPlaying" + }, + "seekingAllLoaded": { + stopSeeking: "pausedAllLoaded", + noController: "initial" + }, + "seekingPlayingAllLoaded": { + stopSeeking: "playingAllLoaded", + noController: "initialPlaying" + }, "paused": { play: "playing", + notEnough: "buffering", noController: "initial", - noMoreFrames: "pausedAllLoaded" + noMoreFrames: "pausedAllLoaded", + startSeeking: "seeking" }, "pausedAllLoaded": { play: "playingAllLoaded", - noController: "initial" + noController: "initial", + startSeeking: "seekingAllLoaded" }, "playing": { pause: "paused", + notEnough: "bufferingPlaying", noMoreFrames: "playingAllLoaded", - noController: "initialPlaying" + noController: "initialPlaying", + startSeeking: "seekingPlaying" }, "playingAllLoaded": { pause: "pausedAllLoaded", - noController: "initialPlaying" + noController: "initialPlaying", + startSeeking: "seekingPlayingAllLoaded" } } +var seekingStates = ["seeking", "seekingPlaying", "seekingAllLoaded", "seekingPlayingAllLoaded"] -var audioPortion = 1024 * 50; +var audioPortion = 1024 * 50; //bytes to download for each portion +var threshold = 2; //seconds to buffer before playing +var intervalPrecision = 100; //millisecond of how often to check the playback var ProgressModel = Model.inherit({ className: "ProgressModel", diff --git a/lorgar/views/helpers/draggable.js b/lorgar/views/helpers/draggable.js index 173b4ad..f55eca2 100644 --- a/lorgar/views/helpers/draggable.js +++ b/lorgar/views/helpers/draggable.js @@ -30,9 +30,9 @@ this._y = 0; this._e.addEventListener("mousedown", this._proxy.onMouseDown, false); - this._e.addEventListener("touchstart", this._touch, false); - this._e.addEventListener("touchmove", this._touch, false); - this._e.addEventListener("touchend", this._touch, false); + this._e.addEventListener("touchstart", W.touchToMouse, false); + this._e.addEventListener("touchmove", W.touchToMouse, false); + this._e.addEventListener("touchend", W.touchToMouse, false); }, "destructor": function () { if (this._dragging) { @@ -45,9 +45,9 @@ } this._e.removeEventListener("mousedown", this._proxy.onMouseDown); - this._e.removeEventListener("touchstart", this._touch); - this._e.removeEventListener("touchmove", this._touch); - this._e.removeEventListener("touchend", this._touch); + this._e.removeEventListener("touchstart", W.touchToMouse); + this._e.removeEventListener("touchmove", W.touchToMouse); + this._e.removeEventListener("touchend", W.touchToMouse); Subscribable.fn.destructor.call(this); }, @@ -105,41 +105,6 @@ this._v.trigger("dragEnd"); return false; } - }, - "_touch": function (e) { - e.preventDefault(); - if (e.touches.length > 1 || (e.type == "touchend" && e.touches.length > 0)) - return; - - var type = null; - var touch = null; - var src = e.currentTarget; - switch (e.type) { - case "touchstart": - type = "mousedown"; - touch = e.changedTouches[0]; - - break; - case "touchmove": - type = "mousemove"; - touch = e.changedTouches[0]; - src = window; - break; - case "touchend": - type = "mouseup"; - touch = e.changedTouches[0]; - src = window; - break; - } - - var event = new MouseEvent(type, { - button: 0, - screenX: touch.screenX, - screenY: touch.screenY, - clientX: touch.clientX, - clientY: touch.clientY - }); - src.dispatchEvent(event); } }); diff --git a/lorgar/views/songProgress.js b/lorgar/views/songProgress.js index 02c153d..2f4fc44 100644 --- a/lorgar/views/songProgress.js +++ b/lorgar/views/songProgress.js @@ -20,14 +20,32 @@ this._createBars(); View.fn.constructor.call(this, controller, base, el); + this._seeking = false; + this._createProxy(); + 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); + + this._e.addEventListener("mousedown", this._proxy.onMouseDown, false); + this._e.addEventListener("touchstart", W.touchToMouse, false); + this._e.addEventListener("touchmove", W.touchToMouse, false); + this._e.addEventListener("touchend", W.touchToMouse, false); }, destructor: function() { + if (this._seeking) { + window.removeEventListener("mouseup", this._proxy.onMouseUp); + window.removeEventListener("mousemove", this._proxy.onMouseMove); + } + + this._e.removeEventListener("mousedown", this._proxy.onMouseDown); + this._e.removeEventListener("touchstart", W.touchToMouse); + this._e.removeEventListener("touchmove", W.touchToMouse); + this._e.removeEventListener("touchend", W.touchToMouse); + this._f.off("load", this._onLoad, this); this._f.off("playback", this._onPlayback, this); @@ -52,6 +70,13 @@ this._playbackProgress.style.top = "0"; this._playbackProgress.style.left = "0"; }, + _createProxy: function () { + this._proxy = { + onMouseDown: this._onMouseDown.bind(this), + onMouseUp: this._onMouseUp.bind(this), + onMouseMove: this._onMouseMove.bind(this) + } + }, _onData: function() { this._onLoad(this._f.load); this._onPlayback(this._f.playback); @@ -59,6 +84,40 @@ _onLoad: function(load) { this._loadProgress.style.width = load * 100 + "%"; }, + _onMouseDown: function(e) { + if (e.which === 1) { + window.addEventListener("mouseup", this._proxy.onMouseUp); + window.addEventListener("mousemove", this._proxy.onMouseMove); + this._seeking = true; + + this._f.trigger("seekingStart"); + + this._ap = this.getAbsolutePosition(); + var seek = Math.max(Math.min(e.pageX - this._ap.x, this._w), 0); + var nSeek = seek / this._w; + if (this._seek !== nSeek) { + this._seek = nSeek; + this._f.trigger("seek", this._seek); + } + } + }, + _onMouseMove: function(e) { + var seek = Math.max(Math.min(e.pageX - this._ap.x, this._w), 0); + var nSeek = seek / this._w; + if (this._seek !== nSeek) { + this._seek = nSeek; + this._f.trigger("seek", this._seek); + } + }, + _onMouseUp: function() { + delete this._ap; + delete this._seek; + this._f.trigger("seekingEnd", this._f.playback); + + this._seeking = false; + window.removeEventListener("mouseup", this._proxy.onMouseUp); + window.removeEventListener("mousemove", this._proxy.onMouseMove); + }, _onPlayback: function(pb) { this._playbackProgress.style.width = pb * 100 + "%"; }, diff --git a/lorgar/views/view.js b/lorgar/views/view.js index 8016b1f..cc3e745 100644 --- a/lorgar/views/view.js +++ b/lorgar/views/view.js @@ -98,6 +98,21 @@ return w; }, + "getAbsolutePosition": function() { + var pp; + if (this._p) { + pp = this._p.getAbsolutePosition(); + } else { + pp = Object.create(null); + pp.x = 0; + pp.y = 0; + } + + pp.x += this._x; + pp.y += this._y; + + return pp; + }, "_initDraggable": function() { this._dg = new Draggable(this, { snapDistance: this._o.snapDistance @@ -134,6 +149,7 @@ "remove": function() { if (this._p) { this._p.removeChild(this); + delete this._p; //just to make sure } }, "removeClass": function(className) { From 5082139e038069905d7b707f3e53e371dffd2e2a Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 27 Jan 2019 20:32:19 +0300 Subject: [PATCH 14/16] something that looks like stopping in the end of playlist, grid layout visual vix --- libjs/wController/player.js | 6 ++- lorgar/views/gridLayout.js | 100 +++++++++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/libjs/wController/player.js b/libjs/wController/player.js index f4f3e8c..4a9d42d 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -251,7 +251,11 @@ var Player = Controller.inherit({ if (next && next.enabled) { next.activate(); } else { - //todo kinda stop state? + this._fsm.manipulation("pause"); + this._onSeekingStart(); + this._onSeek(0); + this._onSeekingEnd(0); + this.controls[ItemType.straight.playPause].activate(); } } } diff --git a/lorgar/views/gridLayout.js b/lorgar/views/gridLayout.js index cb44ebb..712001c 100644 --- a/lorgar/views/gridLayout.js +++ b/lorgar/views/gridLayout.js @@ -250,20 +250,52 @@ var target = pos + span; var minSize = 0; var maxSize = 0; + var flexibleColls = []; for (j = pos; j < target; ++j) { minSize += this._cols[j].min; maxSize += this._cols[j].max; - } - if (e.child._o.minWidth > minSize) { - var portion = (e.child._o.minWidth - minSize) / span; - for (j = pos; j < target; ++j) { - this._cols[j].min += portion; + if (this._cols[j].min < this._cols[j].max) { + flexibleColls.push(this._cols[j]); } } - if (e.child._o.maxWidth < maxSize) { - var portion = (maxSize - e.child._o.maxWidth) / span; - for (j = pos; j < target; ++j) { - this._cols[j].max -= portion; + + var leftMin = e.child._o.minWidth - minSize; + if (leftMin > 0) { + while (leftMin > 0 && flexibleColls.length > 0) { + var portion = leftMin / flexibleColls.length; + + for (j = 0; j < flexibleColls.length; ++j) { + var lPortion = Math.min(flexibleColls[j].max, portion); + flexibleColls[j].min += lPortion; + leftMin -= lPortion; + if (flexibleColls[j].min === flexibleColls[j].max) { + flexibleColls.splice(j, 1); + break; + } + } + if (leftMin < 1) { + leftMin = 0; + } + } + } + var leftMax = maxSize - e.child._o.maxWidth + if (leftMax > 0) { + while (leftMax > 0 && flexibleColls.length > 0) { + var portion = leftMax / flexibleColls.length; + + for (j = 0; j < flexibleColls.length; ++j) { + var lPortion = Math.max(flexibleColls[j].min, portion); + flexibleColls[j].max -= lPortion; + leftMax -= lPortion; + if (flexibleColls[j].min === flexibleColls[j].max) { + flexibleColls.splice(j, 1); + break; + } + } + + if (leftMax < 1) { + leftMax = 0; + } } } } @@ -275,20 +307,52 @@ var target = pos + span; var minSize = 0; var maxSize = 0; + var flexibleRows = []; for (j = pos; j < target; ++j) { minSize += this._rows[j].min; maxSize += this._rows[j].max; - } - if (e.child._o.minHeight > minSize) { - var portion = (e.child._o.minHeight - minSize) / span; - for (j = pos; j < target; ++j) { - this._rows[j].min += portion; + if (this._rows[j].min < this._rows[j].max) { + flexibleRows.push(this._rows[j]); } } - if (e.child._o.maxHeight < maxSize) { - var portion = (maxSize - e.child._o.maxHeight) / span; - for (j = pos; j < target; ++j) { - this._rows[j].max -= portion; + var leftMin = e.child._o.minHeigh - minSize; + if (leftMin > 0) { + while (leftMin > 0 && flexibleRows.length > 0) { + var portion = leftMin / flexibleRows.length; + + for (j = 0; j < flexibleRows.length; ++j) { + var lPortion = Math.min(flexibleRows[j].max, portion); + flexibleRows[j].min += lPortion; + leftMin -= lPortion; + if (flexibleRows[j].min === flexibleRows[j].max) { + flexibleRows.splice(j, 1); + break; + } + } + + if (leftMin < 1) { + leftMin = 0; + } + } + } + var leftMax = maxSize - e.child._o.maxHeigh + if (leftMax > 0) { + while (leftMax > 0 && flexibleRows.length > 0) { + var portion = leftMax / flexibleRows.length; + + for (j = 0; j < flexibleRows.length; ++j) { + var lPortion = Math.max(flexibleRows[j].min, portion); + flexibleRows[j].max -= lPortion; + leftMax -= lPortion; + if (flexibleRows[j].min === flexibleRows[j].max) { + flexibleRows.splice(j, 1); + break; + } + } + + if (leftMax < 1) { + leftMax = 0; + } } } } From 2f8226d406e405e27a0a1f03d6fe3e4ba6505afa Mon Sep 17 00:00:00 2001 From: blue Date: Wed, 30 Jan 2019 23:36:33 +0300 Subject: [PATCH 15/16] slider and volume ctrl --- libjs/wController/player.js | 71 ++++++++++++------ lorgar/views/CMakeLists.txt | 1 + lorgar/views/player.js | 6 +- lorgar/views/slider.js | 137 +++++++++++++++++++++++++++++++++++ lorgar/views/songProgress.js | 95 ++++-------------------- 5 files changed, 206 insertions(+), 104 deletions(-) create mode 100644 lorgar/views/slider.js diff --git a/libjs/wController/player.js b/libjs/wController/player.js index 4a9d42d..aa376be 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -22,9 +22,12 @@ var Player = Controller.inherit({ this.views = Object.create(null); this.mode = PlayerMode.straight.playback; this.progress = new ProgressModel(); + this.volume = new Slider(); + this.volume.setValue(1); this.progress.on("seekingStart", this._onSeekingStart, this); this.progress.on("seekingEnd", this._onSeekingEnd, this); - this.progress.on("seek", this._onSeek, this); + this.progress.enable(false); + this.volume.on("value", this._onVolume, this); this._audio = null; this._createStateMachine(); this._createPlayingInfrastructure(); @@ -123,6 +126,8 @@ var Player = Controller.inherit({ _createPlayingInfrastructure: function() { this._ctx = new AudioContext(); this._decoder = new Mp3Decoder(); + this._gainNode = this._ctx.createGain(); + this._gainNode.connect(this._ctx.destination); this._currentTime = 0; this._seekingTime = 0; this._buffers = []; @@ -212,14 +217,14 @@ var Player = Controller.inherit({ if (offset > 0) { var src = this._ctx.createBufferSource(); src.buffer = sb; - src.connect(this._ctx.destination); + src.connect(this._gainNode); src.start(0, Math.abs(startTime - this._ctx.currentTime)); this._sources.push(src); } } else { var src = this._ctx.createBufferSource(); src.buffer = sb; - src.connect(this._ctx.destination); + src.connect(this._gainNode); src.start(startTime); this._sources.push(src); } @@ -243,10 +248,10 @@ var Player = Controller.inherit({ _onInterval: function() { if (this._audio && this._audio.initialized && seekingStates.indexOf(this._fsm.state()) === -1) { var duration = this._audio.getDuration(); - this.progress.setPlayback(this.getCurrentPlaybackTime() / duration); + this.progress.setValue(this.getCurrentPlaybackTime() / duration); this._checkIfEnough(); - if (this.progress.playback >= 0.9999) { + if (this.progress.value >= 0.9999) { var next = this.controls[ItemType.straight.next]; if (next && next.enabled) { next.activate(); @@ -289,11 +294,6 @@ var Player = Controller.inherit({ this._audio = null; } }, - _onSeek: function(progress) { - if (seekingStates.indexOf(this._fsm.state()) !== -1) { - this.progress.setPlayback(progress); - } - }, _onSeekingStart: function() { this._fsm.manipulation("startSeeking"); }, @@ -319,14 +319,14 @@ var Player = Controller.inherit({ if (offset > 0) { var src = this._ctx.createBufferSource(); src.buffer = buffer; - src.connect(this._ctx.destination); + src.connect(this._gainNode); src.start(0, Math.abs(startTime)); this._sources.push(src); } } else { var src = this._ctx.createBufferSource(); src.buffer = buffer; - src.connect(this._ctx.destination); + src.connect(this._gainNode); src.start(this._ctx.currentTime + startTime); this._sources.push(src); } @@ -340,7 +340,7 @@ var Player = Controller.inherit({ switch (e.newState) { case "initial": if (e.manipulation === "noController") { - + this.progress.enable(false); this.removeForeignController(this._audio); this._audio.destructor(); this._audio = null; @@ -350,6 +350,7 @@ var Player = Controller.inherit({ break; case "initialPlaying": if (e.manipulation === "noController") { + this.progress.enable(false); this._ctx.suspend(); this.removeForeignController(this._audio); @@ -373,10 +374,15 @@ var Player = Controller.inherit({ } break; case "buffering": + if (e.oldState === "hasController") { + this.progress.enable(true); + } break; case "bufferingPlaying": if (e.oldState === "playing") { this._ctx.suspend(); + } else if (e.oldState === "hasControllerPlaying") { + this.progress.enable(true); } break; case "seeking": @@ -421,6 +427,10 @@ var Player = Controller.inherit({ break; } }, + _onVolume: function(volume) { + this._gainNode.gain.cancelScheduledValues(this._ctx.currentTime); + this._gainNode.gain.exponentialRampToValueAtTime(volume, this._ctx.currentTime + 0.01); + }, _removeControl: function(type) { var ctrl = this.controls[type]; if (ctrl !== undefined) { @@ -553,26 +563,41 @@ var audioPortion = 1024 * 50; //bytes to download for each portion var threshold = 2; //seconds to buffer before playing var intervalPrecision = 100; //millisecond of how often to check the playback -var ProgressModel = Model.inherit({ - className: "ProgressModel", +var Slider = Model.inherit({ + className: "Slider", constructor: function(properties) { Model.fn.constructor.call(this, properties); - this.load = 0; - this.playback = 0; + this.enabled = true; + this.value = 0; this.initialized = true; }, + enable: function(en) { + if (en !== this.enabled) { + this.enabled = en; + this.trigger("enabled", en); + } + }, + setValue: function(p) { + if (p !== this.value) { + this.value = p; + this.trigger("value", p); + } + } +}); + +var ProgressModel = Slider.inherit({ + className: "ProgressModel", + constructor: function(properties) { + Slider.fn.constructor.call(this, properties); + + this.value = 0; + }, 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); - } } }); diff --git a/lorgar/views/CMakeLists.txt b/lorgar/views/CMakeLists.txt index 7e9ad6f..aedfc2c 100644 --- a/lorgar/views/CMakeLists.txt +++ b/lorgar/views/CMakeLists.txt @@ -14,6 +14,7 @@ configure_file(image.js image.js) configure_file(button.js button.js) configure_file(enumeration.js enumeration.js) configure_file(player.js player.js) +configure_file(slider.js slider.js) configure_file(songProgress.js songProgress.js) add_subdirectory(helpers) diff --git a/lorgar/views/player.js b/lorgar/views/player.js index 9013cac..4b42cb9 100644 --- a/lorgar/views/player.js +++ b/lorgar/views/player.js @@ -9,6 +9,7 @@ deps.push("views/view"); deps.push("views/image"); deps.push("views/songProgress"); + deps.push("views/slider"); deps.push("lib/wController/localModel"); @@ -21,6 +22,7 @@ var View = require("views/view"); var Image = require("views/image"); var SongProgress = require("views/songProgress"); + var Slider = require("views/slider"); var Model = require("lib/wController/localModel"); @@ -49,14 +51,16 @@ var artist = new Label(this._infoModels.artist); var album = new Label(this._infoModels.album); var song = new Label(this._infoModels.song); - var spacer = new View(helper, {maxWidth: 50}); + var spacer = new View(helper, {maxWidth: 10}); var progress = new SongProgress(ctrl.progress); + var volume = new Slider(ctrl.volume, {maxWidth: 100}); this.append(artist, 0, 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(spacer, 0, 6, 3, 1, GridLayout.Aligment.LeftCenter); this.append(progress, 1, 5, 1, 1, GridLayout.Aligment.CenterCenter); + this.append(volume, 1, 7, 1, 1, GridLayout.Aligment.CenterCenter); this._uncyclic.push(this._infoModels.artist.destructor.bind(this._infoModels.artist)); this._uncyclic.push(this._infoModels.song.destructor.bind(this._infoModels.song)); diff --git a/lorgar/views/slider.js b/lorgar/views/slider.js new file mode 100644 index 0000000..328947f --- /dev/null +++ b/lorgar/views/slider.js @@ -0,0 +1,137 @@ +"use strict"; +(function() { + var moduleName = "views/slider"; + + var deps = []; + deps.push("views/view"); + + define(moduleName, deps, function() { + var View = require("views/view"); + + var Slider = View.inherit({ + className: "Slider", + 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._seeking = false; + this._createProxy(); + + this._f.on("value", this._onValue, this); + this._f.on("enabled", this._onEnabled, this); + + this._e.style.backgroundColor = "#eeeeee"; + this._e.appendChild(this._value); + + if (this._f.enabled) { + this._e.addEventListener("mousedown", this._proxy.onMouseDown, false); + this._e.addEventListener("touchstart", W.touchToMouse, false); + this._e.addEventListener("touchmove", W.touchToMouse, false); + this._e.addEventListener("touchend", W.touchToMouse, false); + } + }, + destructor: function() { + if (this._seeking) { + window.removeEventListener("mouseup", this._proxy.onMouseUp); + window.removeEventListener("mousemove", this._proxy.onMouseMove); + } + if (this._f.enabled) { + this._e.removeEventListener("mousedown", this._proxy.onMouseDown); + this._e.removeEventListener("touchstart", W.touchToMouse); + this._e.removeEventListener("touchmove", W.touchToMouse); + this._e.removeEventListener("touchend", W.touchToMouse); + } + + this._f.off("value", this._value, this); + this._f.off("enabled", this._onEnabled, this); + + View.fn.destructor.call(this); + }, + _createBars: function() { + this._value = document.createElement("div"); + + this._value.style.backgroundColor = View.theme.primaryColor || "#ff0000"; + this._value.style.height = "100%"; + this._value.style.width = "0"; + this._value.style.position = "absolute"; + this._value.style.top = "0"; + this._value.style.left = "0"; + }, + _createProxy: function () { + this._proxy = { + onMouseDown: this._onMouseDown.bind(this), + onMouseUp: this._onMouseUp.bind(this), + onMouseMove: this._onMouseMove.bind(this) + } + }, + _onData: function() { + this._onValue(this._f.value); + }, + _onEnabled: function(enabled) { + if (enabled) { + this._e.addEventListener("mousedown", this._proxy.onMouseDown, false); + this._e.addEventListener("touchstart", W.touchToMouse, false); + this._e.addEventListener("touchmove", W.touchToMouse, false); + this._e.addEventListener("touchend", W.touchToMouse, false); + } else { + if (this._seeking) { + this._onMouseUp(); + } + + this._e.removeEventListener("mousedown", this._proxy.onMouseDown); + this._e.removeEventListener("touchstart", W.touchToMouse); + this._e.removeEventListener("touchmove", W.touchToMouse); + this._e.removeEventListener("touchend", W.touchToMouse); + } + }, + _onMouseDown: function(e) { + if (e.which === 1) { + window.addEventListener("mouseup", this._proxy.onMouseUp); + window.addEventListener("mousemove", this._proxy.onMouseMove); + this._seeking = true; + + this._ap = this.getAbsolutePosition(); + var seek = Math.max(Math.min(e.pageX - this._ap.x, this._w), 0); + var nSeek = seek / this._w; + if (this._seek !== nSeek) { + this._seek = nSeek; + this._f.setValue(this._seek); + } + } + }, + _onMouseMove: function(e) { + var seek = Math.max(Math.min(e.pageX - this._ap.x, this._w), 0); + var nSeek = seek / this._w; + if (this._seek !== nSeek) { + this._seek = nSeek; + this._f.setValue(this._seek); + } + }, + _onMouseUp: function() { + delete this._ap; + delete this._seek; + + this._seeking = false; + window.removeEventListener("mouseup", this._proxy.onMouseUp); + window.removeEventListener("mousemove", this._proxy.onMouseMove); + }, + _onValue: function(pb) { + this._value.style.width = pb * 100 + "%"; + }, + _resetTheme: function() { + View.fn._resetTheme.call(this); + + this._value.style.backgroundColor = View.theme.primaryColor || "#ff0000"; + } + }); + + return Slider; + }) +})(); + diff --git a/lorgar/views/songProgress.js b/lorgar/views/songProgress.js index 2f4fc44..0639b07 100644 --- a/lorgar/views/songProgress.js +++ b/lorgar/views/songProgress.js @@ -3,12 +3,12 @@ var moduleName = "views/songProgress"; var deps = []; - deps.push("views/view"); + deps.push("views/slider"); define(moduleName, deps, function() { - var View = require("views/view"); + var Slider = require("views/slider"); - var SongProgress = View.inherit({ + var SongProgress = Slider.inherit({ className: "SongProgress", constructor: function(controller, options) { var base = { @@ -16,116 +16,51 @@ maxHeight: 10 }; W.extend(base, options) - var el = document.createElement("div"); - this._createBars(); - View.fn.constructor.call(this, controller, base, el); - - this._seeking = false; - this._createProxy(); + Slider.fn.constructor.call(this, controller, base); 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); - - this._e.addEventListener("mousedown", this._proxy.onMouseDown, false); - this._e.addEventListener("touchstart", W.touchToMouse, false); - this._e.addEventListener("touchmove", W.touchToMouse, false); - this._e.addEventListener("touchend", W.touchToMouse, false); + this._e.insertBefore(this._loadProgress, this._value); }, destructor: function() { - if (this._seeking) { - window.removeEventListener("mouseup", this._proxy.onMouseUp); - window.removeEventListener("mousemove", this._proxy.onMouseMove); - } - - this._e.removeEventListener("mousedown", this._proxy.onMouseDown); - this._e.removeEventListener("touchstart", W.touchToMouse); - this._e.removeEventListener("touchmove", W.touchToMouse); - this._e.removeEventListener("touchend", W.touchToMouse); - this._f.off("load", this._onLoad, this); - this._f.off("playback", this._onPlayback, this); - View.fn.destructor.call(this); + Slider.fn.destructor.call(this); }, _createBars: function() { + Slider.fn._createBars.call(this); this._loadProgress = document.createElement("div"); - this._playbackProgress = document.createElement("div"); - this._loadProgress.style.backgroundColor = View.theme.secondaryColor || "#ffff00"; + this._loadProgress.style.backgroundColor = Slider.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"; - }, - _createProxy: function () { - this._proxy = { - onMouseDown: this._onMouseDown.bind(this), - onMouseUp: this._onMouseUp.bind(this), - onMouseMove: this._onMouseMove.bind(this) - } }, _onData: function() { + Slider.fn._onData.call(this); this._onLoad(this._f.load); - this._onPlayback(this._f.playback); }, _onLoad: function(load) { this._loadProgress.style.width = load * 100 + "%"; }, _onMouseDown: function(e) { if (e.which === 1) { - window.addEventListener("mouseup", this._proxy.onMouseUp); - window.addEventListener("mousemove", this._proxy.onMouseMove); - this._seeking = true; - this._f.trigger("seekingStart"); - - this._ap = this.getAbsolutePosition(); - var seek = Math.max(Math.min(e.pageX - this._ap.x, this._w), 0); - var nSeek = seek / this._w; - if (this._seek !== nSeek) { - this._seek = nSeek; - this._f.trigger("seek", this._seek); - } } - }, - _onMouseMove: function(e) { - var seek = Math.max(Math.min(e.pageX - this._ap.x, this._w), 0); - var nSeek = seek / this._w; - if (this._seek !== nSeek) { - this._seek = nSeek; - this._f.trigger("seek", this._seek); - } - }, - _onMouseUp: function() { - delete this._ap; - delete this._seek; - this._f.trigger("seekingEnd", this._f.playback); - this._seeking = false; - window.removeEventListener("mouseup", this._proxy.onMouseUp); - window.removeEventListener("mousemove", this._proxy.onMouseMove); + Slider.fn._onMouseDown.call(this, e); }, - _onPlayback: function(pb) { - this._playbackProgress.style.width = pb * 100 + "%"; + _onMouseUp: function(e) { + Slider.fn._onMouseUp.call(this, e); + this._f.trigger("seekingEnd", this._f.value); }, _resetTheme: function() { - View.fn._resetTheme.call(this); + Slider.fn._resetTheme.call(this); - this._loadProgress.style.backgroundColor = View.theme.secondaryColor || "#ffff00" - this._playbackProgress.style.backgroundColor = View.theme.primaryColor || "#ff0000"; + this._loadProgress.style.backgroundColor = Slider.theme.secondaryColor || "#ffff00" } }); From 7713110129672f05f59a1e4421ce6dbf11c277eb Mon Sep 17 00:00:00 2001 From: blue Date: Sat, 2 Feb 2019 01:24:09 +0300 Subject: [PATCH 16/16] volume control, schedule button, VBR decoder fix, reduced debug in decoder, added decoder source --- corax/models/player.cpp | 20 +- corax/models/player.h | 1 + libjs/wController/imagePane.js | 8 + libjs/wController/player.js | 3 +- lorgar/core/lorgar.js | 16 +- lorgar/lib/em/CMakeLists.txt | 12 +- lorgar/lib/em/decoder.cpp | 347 ++++++++++++ lorgar/lib/em/decoder.h | 79 +++ lorgar/lib/em/libmad.bc | Bin 0 -> 247868 bytes lorgar/lib/em/mad.h | 964 +++++++++++++++++++++++++++++++++ lorgar/lib/em/wrapper.js | 4 - lorgar/lib/em/wrapper.wasm | Bin 256902 -> 0 bytes lorgar/main.js | 1 + lorgar/views/pane.js | 26 +- lorgar/views/slider.js | 5 + magnus/pages/album.js | 4 + magnus/pages/artist.js | 4 + magnus/pages/music.js | 4 + 18 files changed, 1486 insertions(+), 12 deletions(-) create mode 100644 lorgar/lib/em/decoder.cpp create mode 100644 lorgar/lib/em/decoder.h create mode 100644 lorgar/lib/em/libmad.bc create mode 100644 lorgar/lib/em/mad.h delete mode 100644 lorgar/lib/em/wrapper.js delete mode 100644 lorgar/lib/em/wrapper.wasm diff --git a/corax/models/player.cpp b/corax/models/player.cpp index 5533af5..0b92806 100644 --- a/corax/models/player.cpp +++ b/corax/models/player.cpp @@ -18,8 +18,10 @@ M::Player::Player(const W::Address& address, QObject* parent): { W::Handler* get = W::Handler::create(address + W::Address({u"get"}), this, &M::Player::_h_get); W::Handler* hqueue = W::Handler::create(address + W::Address({u"queue"}), this, &M::Player::_h_queue); + W::Handler* hplay = W::Handler::create(address + W::Address({u"play"}), this, &M::Player::_h_play); addHandler(get); addHandler(hqueue); + addHandler(hplay); playPauseBtn->setLabel(W::String(u"Play")); playPauseBtn->setEnabled(false); @@ -126,7 +128,6 @@ void M::Player::h_queue(const W::Event& ev) _queueView->push(song->getAddress()); if (current == 0) { - scheduledToplay = true; setActive(song); } @@ -293,3 +294,20 @@ void M::Player::setActive(uint64_t index) } } +void M::Player::h_play(const W::Event& ev) +{ + const W::Vocabulary& data = static_cast(ev.getData()); + + const W::Uint64& id = static_cast(data.at(u"id")); + ProxySong* song = new ProxySong(id, address + W::Address{W::String(W::Uint64(counter++).toString())}); + addModel(song); + _queue.push_back(song); + _queueView->push(song->getAddress()); + + scheduledToplay = true; + setActive(song); + + if (currentIndex + 1 < _queue.size()) { + nextBtn->setEnabled(true); + } +} diff --git a/corax/models/player.h b/corax/models/player.h index eb1e096..dfa016c 100644 --- a/corax/models/player.h +++ b/corax/models/player.h @@ -49,6 +49,7 @@ namespace M { handler(get); handler(queue); + handler(play); private: typedef std::map ItemMap; diff --git a/libjs/wController/imagePane.js b/libjs/wController/imagePane.js index 46f9f68..91360ad 100644 --- a/libjs/wController/imagePane.js +++ b/libjs/wController/imagePane.js @@ -116,6 +116,14 @@ var standardActions = { id.destructor(); }, name: "Play" + }, + "scheduledToPlay": { + handler: function(obj) { + var id = obj._pairAddress.back(); //todo it's a kind of crutch, need to do something about it in the future + window.scheduleToPlay(id); + id.destructor(); + }, + name: "Schedule" } }; diff --git a/libjs/wController/player.js b/libjs/wController/player.js index aa376be..2987fd3 100644 --- a/libjs/wController/player.js +++ b/libjs/wController/player.js @@ -258,7 +258,6 @@ var Player = Controller.inherit({ } else { this._fsm.manipulation("pause"); this._onSeekingStart(); - this._onSeek(0); this._onSeekingEnd(0); this.controls[ItemType.straight.playPause].activate(); } @@ -354,7 +353,7 @@ var Player = Controller.inherit({ this._ctx.suspend(); this.removeForeignController(this._audio); - this.audio.destructor(); + this._audio.destructor(); this._audio = null; this._destroyPlayingInfrastructure(); this._createPlayingInfrastructure(); diff --git a/lorgar/core/lorgar.js b/lorgar/core/lorgar.js index 85082e6..f0af7aa 100644 --- a/lorgar/core/lorgar.js +++ b/lorgar/core/lorgar.js @@ -257,7 +257,7 @@ var vc = new Vocabulary(); vc.insert("id", id.clone()); - var ev = new Event(this._playerCtl.getPairAddress()["+="](queue), vc); + var ev = new Event(this._playerCtl.getPairAddress()["+="](play), vc); var socket = this._nodes.Corax.socket; ev.setSenderId(socket.getId().clone()); @@ -325,6 +325,19 @@ this._playerCtl.on("serviceMessage", this._onServiceMessage, this); }, + "scheduleToPlay": function(id) { + if (this._nodes.Corax && this._nodes.Corax.connected) { + var vc = new Vocabulary(); + vc.insert("id", id.clone()); + + var ev = new Event(this._playerCtl.getPairAddress()["+="](queue), vc); + + var socket = this._nodes.Corax.socket; + ev.setSenderId(socket.getId().clone()); + socket.send(ev); + ev.destructor(); + } + }, "setTheme": function(theme) { View.setTheme(theme); }, @@ -372,6 +385,7 @@ SocketState.add("connected", {description: "Socket is connected"}); var queue = new Address(["queue"]); + var play = new Address(["play"]); return Lorgar; }); diff --git a/lorgar/lib/em/CMakeLists.txt b/lorgar/lib/em/CMakeLists.txt index 36f775e..42c93c9 100644 --- a/lorgar/lib/em/CMakeLists.txt +++ b/lorgar/lib/em/CMakeLists.txt @@ -1,4 +1,12 @@ cmake_minimum_required(VERSION 2.8.12) -configure_file(wrapper.js wrapper.js) -configure_file(wrapper.wasm wrapper.wasm COPYONLY) +execute_process(COMMAND + emcc --bind + ${CMAKE_CURRENT_SOURCE_DIR}/libmad.bc + ${CMAKE_CURRENT_SOURCE_DIR}/decoder.cpp + -o ${CMAKE_CURRENT_BINARY_DIR}/wrapper.js + -s FILESYSTEM=0 + -s ENVIRONMENT=web + -O3 + --llvm-lto 1 + ) diff --git a/lorgar/lib/em/decoder.cpp b/lorgar/lib/em/decoder.cpp new file mode 100644 index 0000000..8ee7e74 --- /dev/null +++ b/lorgar/lib/em/decoder.cpp @@ -0,0 +1,347 @@ +#include "decoder.h" +#include + +Decoder::Decoder(): +state(empty), +sampleRate(0), +channels(0), +cachedLength(0), +samplesPerFrame(0), +glue(new uint8_t[GLUE_LENGTH]), +cachedNext(NULL), +cachedThis(NULL), +cachedError(MAD_ERROR_NONE), +cached(false), +synth(new mad_synth()), +stream(new mad_stream()), +frame(new mad_frame()), +context(0), +pending() +{ + for (int i = 0; i < GLUE_LENGTH; ++i) { + glue[i] = 0; + } + + mad_frame_init(frame); + mad_stream_init(stream); + mad_synth_init(synth); + + emscripten::val AudioContext = emscripten::val::global("AudioContext"); + if (!AudioContext.as()) { + AudioContext = emscripten::val::global("webkitAudioContext"); + } + + context = AudioContext.new_(); +} + +Decoder::~Decoder() +{ + context.call("close"); + + mad_synth_finish(synth); + mad_stream_finish(stream); + mad_frame_finish(frame); + + delete synth; + delete stream; + delete frame; + + delete[] glue; +} + +void Decoder::addFragment(const emscripten::val& array) +{ + uint32_t length = array["length"].as(); + + if (length < GLUE_LENGTH / 2) { + std::cout << "Error: an attempt to add fragment smaller then half of the glue buffer, ignoring"; + return; + } + uint8_t* buffer = new uint8_t[length]; + + for (int i = 0; i < length; ++i) { + buffer[i] = array[std::to_string(i)].as(); + } + + RawBuffer rb = {buffer, length}; + pending.push_back(rb); + + switch (state) { + case empty: + mad_stream_buffer(stream, buffer, length); + + for (int i = 0; i < GLUE_LENGTH/2; ++i) { + glue[i] = buffer[length - GLUE_LENGTH/2 + i]; + } + + state = onBufferHalf; + prepareNextBuffer(); + break; + case onBufferHalf: + for (int i = 0; i < GLUE_LENGTH/2; ++i) { + glue[GLUE_LENGTH/2 + i] = buffer[i]; + } + + state = onBufferFull; + break; + case onBufferFull: + break; + case onGlueHalf: + for (int i = 0; i < GLUE_LENGTH/2; ++i) { + glue[GLUE_LENGTH/2 + i] = buffer[i]; + } + + state = onGlueFull; + cached = false; + prepareNextBuffer(); + break; + case onGlueFull: + break; + } +} + +emscripten::val Decoder::decode(uint32_t count) +{ + emscripten::val ret = emscripten::val::undefined(); + + int available = framesLeft(count); + int success = 0; + if (available > 0) { + ret = context.call("createBuffer", channels, available * samplesPerFrame, sampleRate); + + std::vector chans(channels, emscripten::val::undefined()); + for (int i = 0; i < channels; ++i) { + chans[i] = ret.call("getChannelData", i); + } + + for (int i = 0; success < available; ++i) { + int res = mad_frame_decode(frame, stream); + + if (res != 0) { + if (MAD_RECOVERABLE(stream->error)) { + + std::cout << "Unexpected error during the decoding process: " << mad_stream_errorstr(stream) << std::endl; + continue; + } else { + break; + } + } + + mad_synth_frame(synth, frame); + + for (int j = 0; j < samplesPerFrame; ++j) { + for (int k = 0; k < channels; ++k) { + float value = mad_f_todouble(synth->pcm.samples[k][j]); + chans[k].set(std::to_string(success * samplesPerFrame + j), emscripten::val(value)); + } + } + ++success; + } + + cachedLength -= available; +#if DEBUGGING + std::cout << "Processed " << available << " frames, " << success << " successfully, last error " << mad_stream_errorstr(stream) << std::endl; +#endif + if (cachedLength == 0) { + cached = false; + prepareNextBuffer(); + } + } + + return ret; +} + +bool Decoder::hasMore() const +{ + if (pending.size() == 1) { + return stream->error != MAD_ERROR_BUFLEN; + } else { + return true; + } +} + +uint32_t Decoder::framesLeft(uint32_t max) +{ + if (state == empty || state == onGlueHalf) { + return 0; + } + + if (cached == false) { + mad_stream probe; + mad_header ph; + initializeProbe(probe); + mad_header_init(&ph); + sampleRate = 0; + + while (cachedLength < max) { + if (mad_header_decode(&ph, &probe) == 0) { + if (sampleRate == 0) { + sampleRate = ph.samplerate; + channels = MAD_NCHANNELS(&ph); + samplesPerFrame = MAD_NSBSAMPLES(&ph) * 32; //not sure why 32, it's in libmad source + } else { + if (sampleRate != ph.samplerate || channels != MAD_NCHANNELS(&ph) || samplesPerFrame != MAD_NSBSAMPLES(&ph) * 32) { + if (cachedLength > 0) { +#if DEBUGGING + std::cout << "sample rate " << sampleRate << " -> " << ph.samplerate << std::endl; + std::cout << "channels " << channels << " -> " << MAD_NCHANNELS(&ph) << std::endl; + std::cout << "samples per frame " << samplesPerFrame << " -> " << MAD_NSBSAMPLES(&ph) * 32 << std::endl; +#endif + probe.next_frame = probe.this_frame; + break; + } + } + } + if (probe.next_frame > probe.this_frame) { + ++cachedLength; + } + } else { +#if DEBUGGING + std::cout << "framesLeft error: " << mad_stream_errorstr(&probe) << std::endl; +#endif + if (!MAD_RECOVERABLE(probe.error)) { + break; + } + } + } + + cachedNext = probe.next_frame; + cachedThis = probe.this_frame; + cachedError = probe.error; + mad_header_finish(&ph); + mad_stream_finish(&probe); +#if DEBUGGING + std::cout << cachedLength << " frames are available for decoding" << std::endl; +#endif + cached = true; + } + + return std::min(cachedLength, max); +} + +void Decoder::pullBuffer() +{ + if (cached == false) { + std::cout << "Error in pullBuffer method!" << std::endl; + } + stream->this_frame = cachedThis; + stream->next_frame = cachedNext; + stream->error = cachedError; +} + +void Decoder::changeBuffer() +{ + switch (state) { + case empty: + std::cout << "Wrong state on switchBuffer method - empty, aborting" << std::endl; + case onBufferHalf: + switchToGlue(); + state = onGlueHalf; + break; + case onBufferFull: + switchToGlue(); + state = onGlueFull; + break; + case onGlueHalf: + std::cout << "Wrong state on switchBuffer method - onGlueHalf, aborting" << std::endl; + break; + case onGlueFull: +#if DEBUGGING + std::cout << "Having another fragment " << pending[0].length << " bytes long" << std::endl; +#endif + + switchBuffer(pending[0].ptr, pending[0].length); + + for (int i = 0; i < GLUE_LENGTH/2; ++i) { + glue[i] = pending[0].ptr[pending[0].length - GLUE_LENGTH/2 + i]; + } + + state = onBufferHalf; + + if (pending.size() > 1) { + for (int i = 0; i < GLUE_LENGTH/2; ++i) { + glue[GLUE_LENGTH/2 + i] = pending[1].ptr[i]; + } + + state = onBufferFull; + } + } + + cached = false; +} + +void Decoder::prepareNextBuffer() +{ + bool shift; + do { + shift = false; + framesLeft(); + if (cachedLength == 0 && state != empty && state != onGlueHalf) { + pullBuffer(); + changeBuffer(); + shift = true; + } + } while (shift); +} + +void Decoder::initializeProbe(mad_stream& probe) +{ + mad_stream_init(&probe); + + probe.buffer = stream->buffer; + probe.bufend = stream->bufend; + probe.skiplen = stream->skiplen; + //probe.sync = stream->sync; + //probe.freerate = stream->freerate; + //probe.this_frame = stream->this_frame; + probe.next_frame = stream->next_frame; + //probe.ptr.byte = stream->ptr.byte; + //probe.ptr.cache = stream->ptr.cache; + //probe.ptr.cache = stream->ptr.cache; + //probe.anc_ptr.byte = stream->anc_ptr.byte; + //probe.anc_ptr.cache = stream->anc_ptr.cache; + //probe.anc_ptr.cache = stream->anc_ptr.cache; + //probe.anc_bitlen = stream->anc_bitlen; + //probe.main_data = stream.main_data; + //probe.md_len = stream.md_len; + //probe.options = stream->options; + //probe.error = stream->error; +} + +void Decoder::switchToGlue() +{ +#if DEBUGGING + std::cout << "Switching to glue" << std::endl; +#endif + switchBuffer(glue, GLUE_LENGTH); + +#if DEBUGGING + std::cout << "Freeing the drained fragment" << std::endl; +#endif + delete[] pending[0].ptr; + pending.pop_front(); +} + +void Decoder::switchBuffer(uint8_t* bufferPtr, uint32_t length) +{ + uint32_t left; + + if (stream->error != MAD_ERROR_BUFLEN) { + std::cout << "WARNING: Switching buffers while the previous one is not drained, last error: " << mad_stream_errorstr(stream) << std::endl; + } + if (stream->next_frame != NULL) { + left = stream->bufend - stream->next_frame; + } else { + std::cout << "WARNING: not supposed to happen" << std::endl; + } + + if (left > GLUE_LENGTH / 2) { + std::cout << "Error: bytes to read in the buffer are more then glue buffer can fit (" << left << ")" << std::endl; + throw 1; + } + + mad_stream_buffer(stream, bufferPtr + GLUE_LENGTH / 2 - left, length - (GLUE_LENGTH / 2 - left)); + stream->error = MAD_ERROR_NONE; + + while (mad_header_decode(&frame->header, stream) != 0 && stream->error != MAD_ERROR_BUFLEN) {} +} diff --git a/lorgar/lib/em/decoder.h b/lorgar/lib/em/decoder.h new file mode 100644 index 0000000..95d9a1d --- /dev/null +++ b/lorgar/lib/em/decoder.h @@ -0,0 +1,79 @@ +#ifndef DECODER_H +#define DECODER_H + +/** + * @todo write docs + */ +#include + +#include +#include +#include "mad.h" + +#define GLUE_LENGTH 6000 + +#define DEBUGGING false + +class Decoder { +public: + Decoder(); + ~Decoder(); + + void addFragment(const emscripten::val& array); + emscripten::val decode(uint32_t count = UINT32_MAX); + bool hasMore() const; + uint32_t framesLeft(uint32_t max = UINT32_MAX); + +private: + + enum State { + empty, + onBufferHalf, + onBufferFull, + onGlueHalf, + onGlueFull + }; + + struct RawBuffer { + uint8_t* ptr; + uint32_t length; + }; + + State state; + + uint32_t sampleRate; + uint8_t channels; + uint32_t cachedLength; + uint16_t samplesPerFrame; + uint8_t* glue; + uint8_t const* cachedNext; + uint8_t const* cachedThis; + mad_error cachedError; + bool cached; + + mad_synth* synth; + mad_stream* stream; + mad_frame* frame; + emscripten::val context; + + std::deque pending; + +private: + void pullBuffer(); + void changeBuffer(); + void prepareNextBuffer(); + void initializeProbe(mad_stream& probe); + void switchToGlue(); + void switchBuffer(uint8_t* bufferPtr, uint32_t length); +}; + +EMSCRIPTEN_BINDINGS(jsmad) { + emscripten::class_("Decoder") + .constructor<>() + .function("addFragment", &Decoder::addFragment) + .function("hasMore", &Decoder::hasMore) + .function("framesLeft", &Decoder::framesLeft) + .function("decode", &Decoder::decode); +} + +#endif // DECODER_H diff --git a/lorgar/lib/em/libmad.bc b/lorgar/lib/em/libmad.bc new file mode 100644 index 0000000000000000000000000000000000000000..6e9d1e68608295a6892573c822e06ba23213e826 GIT binary patch literal 247868 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
    52x1i%5A99} z{|oZ&-btx(@DEN92rhm=8_PGZe0-slFg2VSNtzH%WSVAiQe=t-Pt358xRjWL$OKJT zd{T6fCS5qei3_os + */ + +# ifdef __cplusplus +extern "C" { +# endif + +# define FPM_64BIT + + + +# define SIZEOF_INT 4 +# define SIZEOF_LONG 4 +# define SIZEOF_LONG_LONG 8 + + +/* Id: version.h,v 1.26 2004/01/23 09:41:33 rob Exp */ + +# ifndef LIBMAD_VERSION_H +# define LIBMAD_VERSION_H + +# define MAD_VERSION_MAJOR 0 +# define MAD_VERSION_MINOR 15 +# define MAD_VERSION_PATCH 1 +# define MAD_VERSION_EXTRA " (beta)" + +# define MAD_VERSION_STRINGIZE(str) #str +# define MAD_VERSION_STRING(num) MAD_VERSION_STRINGIZE(num) + +# define MAD_VERSION MAD_VERSION_STRING(MAD_VERSION_MAJOR) "." \ + MAD_VERSION_STRING(MAD_VERSION_MINOR) "." \ + MAD_VERSION_STRING(MAD_VERSION_PATCH) \ + MAD_VERSION_EXTRA + +# define MAD_PUBLISHYEAR "2000-2004" +# define MAD_AUTHOR "Underbit Technologies, Inc." +# define MAD_EMAIL "info@underbit.com" + +extern char const mad_version[]; +extern char const mad_copyright[]; +extern char const mad_author[]; +extern char const mad_build[]; + +# endif + +/* Id: fixed.h,v 1.38 2004/02/17 02:02:03 rob Exp */ + +# ifndef LIBMAD_FIXED_H +# define LIBMAD_FIXED_H + +# if SIZEOF_INT >= 4 +typedef signed int mad_fixed_t; + +typedef signed int mad_fixed64hi_t; +typedef unsigned int mad_fixed64lo_t; +# else +typedef signed long mad_fixed_t; + +typedef signed long mad_fixed64hi_t; +typedef unsigned long mad_fixed64lo_t; +# endif + +# if defined(_MSC_VER) +# define mad_fixed64_t signed __int64 +# elif 1 || defined(__GNUC__) +# define mad_fixed64_t signed long long +# endif + +# if defined(FPM_FLOAT) +typedef double mad_sample_t; +# else +typedef mad_fixed_t mad_sample_t; +# endif + +/* + * Fixed-point format: 0xABBBBBBB + * A == whole part (sign + 3 bits) + * B == fractional part (28 bits) + * + * Values are signed two's complement, so the effective range is: + * 0x80000000 to 0x7fffffff + * -8.0 to +7.9999999962747097015380859375 + * + * The smallest representable value is: + * 0x00000001 == 0.0000000037252902984619140625 (i.e. about 3.725e-9) + * + * 28 bits of fractional accuracy represent about + * 8.6 digits of decimal accuracy. + * + * Fixed-point numbers can be added or subtracted as normal + * integers, but multiplication requires shifting the 64-bit result + * from 56 fractional bits back to 28 (and rounding.) + * + * Changing the definition of MAD_F_FRACBITS is only partially + * supported, and must be done with care. + */ + +# define MAD_F_FRACBITS 28 + +# if MAD_F_FRACBITS == 28 +# define MAD_F(x) ((mad_fixed_t) (x##L)) +# else +# if MAD_F_FRACBITS < 28 +# warning "MAD_F_FRACBITS < 28" +# define MAD_F(x) ((mad_fixed_t) \ + (((x##L) + \ + (1L << (28 - MAD_F_FRACBITS - 1))) >> \ + (28 - MAD_F_FRACBITS))) +# elif MAD_F_FRACBITS > 28 +# error "MAD_F_FRACBITS > 28 not currently supported" +# define MAD_F(x) ((mad_fixed_t) \ + ((x##L) << (MAD_F_FRACBITS - 28))) +# endif +# endif + +# define MAD_F_MIN ((mad_fixed_t) -0x80000000L) +# define MAD_F_MAX ((mad_fixed_t) +0x7fffffffL) + +# define MAD_F_ONE MAD_F(0x10000000) + +# define mad_f_tofixed(x) ((mad_fixed_t) \ + ((x) * (double) (1L << MAD_F_FRACBITS) + 0.5)) +# define mad_f_todouble(x) ((double) \ + ((x) / (double) (1L << MAD_F_FRACBITS))) + +# define mad_f_intpart(x) ((x) >> MAD_F_FRACBITS) +# define mad_f_fracpart(x) ((x) & ((1L << MAD_F_FRACBITS) - 1)) + /* (x should be positive) */ + +# define mad_f_fromint(x) ((x) << MAD_F_FRACBITS) + +# define mad_f_add(x, y) ((x) + (y)) +# define mad_f_sub(x, y) ((x) - (y)) + +# if defined(FPM_FLOAT) +# error "FPM_FLOAT not yet supported" + +# undef MAD_F +# define MAD_F(x) mad_f_todouble(x) + +# define mad_f_mul(x, y) ((x) * (y)) +# define mad_f_scale64 + +# undef ASO_ZEROCHECK + +# elif defined(FPM_64BIT) + +/* + * This version should be the most accurate if 64-bit types are supported by + * the compiler, although it may not be the most efficient. + */ +# if defined(OPT_ACCURACY) +# define mad_f_mul(x, y) \ + ((mad_fixed_t) \ + ((((mad_fixed64_t) (x) * (y)) + \ + (1L << (MAD_F_SCALEBITS - 1))) >> MAD_F_SCALEBITS)) +# else +# define mad_f_mul(x, y) \ + ((mad_fixed_t) (((mad_fixed64_t) (x) * (y)) >> MAD_F_SCALEBITS)) +# endif + +# define MAD_F_SCALEBITS MAD_F_FRACBITS + +/* --- Intel --------------------------------------------------------------- */ + +# elif defined(FPM_INTEL) + +# if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4035) /* no return value */ +static __forceinline +mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y) +{ + enum { + fracbits = MAD_F_FRACBITS + }; + + __asm { + mov eax, x + imul y + shrd eax, edx, fracbits + } + + /* implicit return of eax */ +} +# pragma warning(pop) + +# define mad_f_mul mad_f_mul_inline +# define mad_f_scale64 +# else +/* + * This Intel version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("imull %3" \ + : "=a" (lo), "=d" (hi) \ + : "%a" (x), "rm" (y) \ + : "cc") + +# if defined(OPT_ACCURACY) +/* + * This gives best accuracy but is not very fast. + */ +# define MAD_F_MLA(hi, lo, x, y) \ + ({ mad_fixed64hi_t __hi; \ + mad_fixed64lo_t __lo; \ + MAD_F_MLX(__hi, __lo, (x), (y)); \ + asm ("addl %2,%0\n\t" \ + "adcl %3,%1" \ + : "=rm" (lo), "=rm" (hi) \ + : "r" (__lo), "r" (__hi), "0" (lo), "1" (hi) \ + : "cc"); \ + }) +# endif /* OPT_ACCURACY */ + +# if defined(OPT_ACCURACY) +/* + * Surprisingly, this is faster than SHRD followed by ADC. + */ +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed64hi_t __hi_; \ + mad_fixed64lo_t __lo_; \ + mad_fixed_t __result; \ + asm ("addl %4,%2\n\t" \ + "adcl %5,%3" \ + : "=rm" (__lo_), "=rm" (__hi_) \ + : "0" (lo), "1" (hi), \ + "ir" (1L << (MAD_F_SCALEBITS - 1)), "ir" (0) \ + : "cc"); \ + asm ("shrdl %3,%2,%1" \ + : "=rm" (__result) \ + : "0" (__lo_), "r" (__hi_), "I" (MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# elif defined(OPT_INTEL) +/* + * Alternate Intel scaling that may or may not perform better. + */ +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("shrl %3,%1\n\t" \ + "shll %4,%2\n\t" \ + "orl %2,%1" \ + : "=rm" (__result) \ + : "0" (lo), "r" (hi), \ + "I" (MAD_F_SCALEBITS), "I" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# else +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("shrdl %3,%2,%1" \ + : "=rm" (__result) \ + : "0" (lo), "r" (hi), "I" (MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# endif /* OPT_ACCURACY */ + +# define MAD_F_SCALEBITS MAD_F_FRACBITS +# endif + +/* --- ARM ----------------------------------------------------------------- */ + +# elif defined(FPM_ARM) + +/* + * This ARM V4 version is as accurate as FPM_64BIT but much faster. The + * least significant bit is properly rounded at no CPU cycle cost! + */ +# if 1 +/* + * This is faster than the default implementation via MAD_F_MLX() and + * mad_f_scale64(). + */ +# define mad_f_mul(x, y) \ + ({ mad_fixed64hi_t __hi; \ + mad_fixed64lo_t __lo; \ + mad_fixed_t __result; \ + asm ("smull %0, %1, %3, %4\n\t" \ + "movs %0, %0, lsr %5\n\t" \ + "adc %2, %0, %1, lsl %6" \ + : "=&r" (__lo), "=&r" (__hi), "=r" (__result) \ + : "%r" (x), "r" (y), \ + "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# endif + +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("smull %0, %1, %2, %3" \ + : "=&r" (lo), "=&r" (hi) \ + : "%r" (x), "r" (y)) + +# define MAD_F_MLA(hi, lo, x, y) \ + asm ("smlal %0, %1, %2, %3" \ + : "+r" (lo), "+r" (hi) \ + : "%r" (x), "r" (y)) + +# define MAD_F_MLN(hi, lo) \ + asm ("rsbs %0, %2, #0\n\t" \ + "rsc %1, %3, #0" \ + : "=r" (lo), "=r" (hi) \ + : "0" (lo), "1" (hi) \ + : "cc") + +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("movs %0, %1, lsr %3\n\t" \ + "adc %0, %0, %2, lsl %4" \ + : "=&r" (__result) \ + : "r" (lo), "r" (hi), \ + "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) + +# define MAD_F_SCALEBITS MAD_F_FRACBITS + +/* --- MIPS ---------------------------------------------------------------- */ + +# elif defined(FPM_MIPS) + +/* + * This MIPS version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("mult %2,%3" \ + : "=l" (lo), "=h" (hi) \ + : "%r" (x), "r" (y)) + +# if defined(HAVE_MADD_ASM) +# define MAD_F_MLA(hi, lo, x, y) \ + asm ("madd %2,%3" \ + : "+l" (lo), "+h" (hi) \ + : "%r" (x), "r" (y)) +# elif defined(HAVE_MADD16_ASM) +/* + * This loses significant accuracy due to the 16-bit integer limit in the + * multiply/accumulate instruction. + */ +# define MAD_F_ML0(hi, lo, x, y) \ + asm ("mult %2,%3" \ + : "=l" (lo), "=h" (hi) \ + : "%r" ((x) >> 12), "r" ((y) >> 16)) +# define MAD_F_MLA(hi, lo, x, y) \ + asm ("madd16 %2,%3" \ + : "+l" (lo), "+h" (hi) \ + : "%r" ((x) >> 12), "r" ((y) >> 16)) +# define MAD_F_MLZ(hi, lo) ((mad_fixed_t) (lo)) +# endif + +# if defined(OPT_SPEED) +# define mad_f_scale64(hi, lo) \ + ((mad_fixed_t) ((hi) << (32 - MAD_F_SCALEBITS))) +# define MAD_F_SCALEBITS MAD_F_FRACBITS +# endif + +/* --- SPARC --------------------------------------------------------------- */ + +# elif defined(FPM_SPARC) + +/* + * This SPARC V8 version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("smul %2, %3, %0\n\t" \ + "rd %%y, %1" \ + : "=r" (lo), "=r" (hi) \ + : "%r" (x), "rI" (y)) + +/* --- PowerPC ------------------------------------------------------------- */ + +# elif defined(FPM_PPC) + +/* + * This PowerPC version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + do { \ + asm ("mullw %0,%1,%2" \ + : "=r" (lo) \ + : "%r" (x), "r" (y)); \ + asm ("mulhw %0,%1,%2" \ + : "=r" (hi) \ + : "%r" (x), "r" (y)); \ + } \ + while (0) + +# if defined(OPT_ACCURACY) +/* + * This gives best accuracy but is not very fast. + */ +# define MAD_F_MLA(hi, lo, x, y) \ + ({ mad_fixed64hi_t __hi; \ + mad_fixed64lo_t __lo; \ + MAD_F_MLX(__hi, __lo, (x), (y)); \ + asm ("addc %0,%2,%3\n\t" \ + "adde %1,%4,%5" \ + : "=r" (lo), "=r" (hi) \ + : "%r" (lo), "r" (__lo), \ + "%r" (hi), "r" (__hi) \ + : "xer"); \ + }) +# endif + +# if defined(OPT_ACCURACY) +/* + * This is slower than the truncating version below it. + */ +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result, __round; \ + asm ("rotrwi %0,%1,%2" \ + : "=r" (__result) \ + : "r" (lo), "i" (MAD_F_SCALEBITS)); \ + asm ("extrwi %0,%1,1,0" \ + : "=r" (__round) \ + : "r" (__result)); \ + asm ("insrwi %0,%1,%2,0" \ + : "+r" (__result) \ + : "r" (hi), "i" (MAD_F_SCALEBITS)); \ + asm ("add %0,%1,%2" \ + : "=r" (__result) \ + : "%r" (__result), "r" (__round)); \ + __result; \ + }) +# else +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("rotrwi %0,%1,%2" \ + : "=r" (__result) \ + : "r" (lo), "i" (MAD_F_SCALEBITS)); \ + asm ("insrwi %0,%1,%2,0" \ + : "+r" (__result) \ + : "r" (hi), "i" (MAD_F_SCALEBITS)); \ + __result; \ + }) +# endif + +# define MAD_F_SCALEBITS MAD_F_FRACBITS + +/* --- Default ------------------------------------------------------------- */ + +# elif defined(FPM_DEFAULT) + +/* + * This version is the most portable but it loses significant accuracy. + * Furthermore, accuracy is biased against the second argument, so care + * should be taken when ordering operands. + * + * The scale factors are constant as this is not used with SSO. + * + * Pre-rounding is required to stay within the limits of compliance. + */ +# if defined(OPT_SPEED) +# define mad_f_mul(x, y) (((x) >> 12) * ((y) >> 16)) +# else +# define mad_f_mul(x, y) ((((x) + (1L << 11)) >> 12) * \ + (((y) + (1L << 15)) >> 16)) +# endif + +/* ------------------------------------------------------------------------- */ + +# else +# error "no FPM selected" +# endif + +/* default implementations */ + +# if !defined(mad_f_mul) +# define mad_f_mul(x, y) \ + ({ register mad_fixed64hi_t __hi; \ + register mad_fixed64lo_t __lo; \ + MAD_F_MLX(__hi, __lo, (x), (y)); \ + mad_f_scale64(__hi, __lo); \ + }) +# endif + +# if !defined(MAD_F_MLA) +# define MAD_F_ML0(hi, lo, x, y) ((lo) = mad_f_mul((x), (y))) +# define MAD_F_MLA(hi, lo, x, y) ((lo) += mad_f_mul((x), (y))) +# define MAD_F_MLN(hi, lo) ((lo) = -(lo)) +# define MAD_F_MLZ(hi, lo) ((void) (hi), (mad_fixed_t) (lo)) +# endif + +# if !defined(MAD_F_ML0) +# define MAD_F_ML0(hi, lo, x, y) MAD_F_MLX((hi), (lo), (x), (y)) +# endif + +# if !defined(MAD_F_MLN) +# define MAD_F_MLN(hi, lo) ((hi) = ((lo) = -(lo)) ? ~(hi) : -(hi)) +# endif + +# if !defined(MAD_F_MLZ) +# define MAD_F_MLZ(hi, lo) mad_f_scale64((hi), (lo)) +# endif + +# if !defined(mad_f_scale64) +# if defined(OPT_ACCURACY) +# define mad_f_scale64(hi, lo) \ + ((((mad_fixed_t) \ + (((hi) << (32 - (MAD_F_SCALEBITS - 1))) | \ + ((lo) >> (MAD_F_SCALEBITS - 1)))) + 1) >> 1) +# else +# define mad_f_scale64(hi, lo) \ + ((mad_fixed_t) \ + (((hi) << (32 - MAD_F_SCALEBITS)) | \ + ((lo) >> MAD_F_SCALEBITS))) +# endif +# define MAD_F_SCALEBITS MAD_F_FRACBITS +# endif + +/* C routines */ + +mad_fixed_t mad_f_abs(mad_fixed_t); +mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t); + +# endif + +/* Id: bit.h,v 1.12 2004/01/23 09:41:32 rob Exp */ + +# ifndef LIBMAD_BIT_H +# define LIBMAD_BIT_H + +struct mad_bitptr { + unsigned char const *byte; + unsigned short cache; + unsigned short left; +}; + +void mad_bit_init(struct mad_bitptr *, unsigned char const *); + +# define mad_bit_finish(bitptr) /* nothing */ + +unsigned int mad_bit_length(struct mad_bitptr const *, + struct mad_bitptr const *); + +# define mad_bit_bitsleft(bitptr) ((bitptr)->left) +unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *); + +void mad_bit_skip(struct mad_bitptr *, unsigned int); +unsigned long mad_bit_read(struct mad_bitptr *, unsigned int); +void mad_bit_write(struct mad_bitptr *, unsigned int, unsigned long); + +unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short); + +# endif + +/* Id: timer.h,v 1.16 2004/01/23 09:41:33 rob Exp */ + +# ifndef LIBMAD_TIMER_H +# define LIBMAD_TIMER_H + +typedef struct { + signed long seconds; /* whole seconds */ + unsigned long fraction; /* 1/MAD_TIMER_RESOLUTION seconds */ +} mad_timer_t; + +extern mad_timer_t const mad_timer_zero; + +# define MAD_TIMER_RESOLUTION 352800000UL + +enum mad_units { + MAD_UNITS_HOURS = -2, + MAD_UNITS_MINUTES = -1, + MAD_UNITS_SECONDS = 0, + + /* metric units */ + + MAD_UNITS_DECISECONDS = 10, + MAD_UNITS_CENTISECONDS = 100, + MAD_UNITS_MILLISECONDS = 1000, + + /* audio sample units */ + + MAD_UNITS_8000_HZ = 8000, + MAD_UNITS_11025_HZ = 11025, + MAD_UNITS_12000_HZ = 12000, + + MAD_UNITS_16000_HZ = 16000, + MAD_UNITS_22050_HZ = 22050, + MAD_UNITS_24000_HZ = 24000, + + MAD_UNITS_32000_HZ = 32000, + MAD_UNITS_44100_HZ = 44100, + MAD_UNITS_48000_HZ = 48000, + + /* video frame/field units */ + + MAD_UNITS_24_FPS = 24, + MAD_UNITS_25_FPS = 25, + MAD_UNITS_30_FPS = 30, + MAD_UNITS_48_FPS = 48, + MAD_UNITS_50_FPS = 50, + MAD_UNITS_60_FPS = 60, + + /* CD audio frames */ + + MAD_UNITS_75_FPS = 75, + + /* video drop-frame units */ + + MAD_UNITS_23_976_FPS = -24, + MAD_UNITS_24_975_FPS = -25, + MAD_UNITS_29_97_FPS = -30, + MAD_UNITS_47_952_FPS = -48, + MAD_UNITS_49_95_FPS = -50, + MAD_UNITS_59_94_FPS = -60 +}; + +# define mad_timer_reset(timer) ((void) (*(timer) = mad_timer_zero)) + +int mad_timer_compare(mad_timer_t, mad_timer_t); + +# define mad_timer_sign(timer) mad_timer_compare((timer), mad_timer_zero) + +void mad_timer_negate(mad_timer_t *); +mad_timer_t mad_timer_abs(mad_timer_t); + +void mad_timer_set(mad_timer_t *, unsigned long, unsigned long, unsigned long); +void mad_timer_add(mad_timer_t *, mad_timer_t); +void mad_timer_multiply(mad_timer_t *, signed long); + +signed long mad_timer_count(mad_timer_t, enum mad_units); +unsigned long mad_timer_fraction(mad_timer_t, unsigned long); +void mad_timer_string(mad_timer_t, char *, char const *, + enum mad_units, enum mad_units, unsigned long); + +# endif + +/* Id: stream.h,v 1.20 2004/02/05 09:02:39 rob Exp */ + +# ifndef LIBMAD_STREAM_H +# define LIBMAD_STREAM_H + + +# define MAD_BUFFER_GUARD 8 +# define MAD_BUFFER_MDLEN (511 + 2048 + MAD_BUFFER_GUARD) + +enum mad_error { + MAD_ERROR_NONE = 0x0000, /* no error */ + + MAD_ERROR_BUFLEN = 0x0001, /* input buffer too small (or EOF) */ + MAD_ERROR_BUFPTR = 0x0002, /* invalid (null) buffer pointer */ + + MAD_ERROR_NOMEM = 0x0031, /* not enough memory */ + + MAD_ERROR_LOSTSYNC = 0x0101, /* lost synchronization */ + MAD_ERROR_BADLAYER = 0x0102, /* reserved header layer value */ + MAD_ERROR_BADBITRATE = 0x0103, /* forbidden bitrate value */ + MAD_ERROR_BADSAMPLERATE = 0x0104, /* reserved sample frequency value */ + MAD_ERROR_BADEMPHASIS = 0x0105, /* reserved emphasis value */ + + MAD_ERROR_BADCRC = 0x0201, /* CRC check failed */ + MAD_ERROR_BADBITALLOC = 0x0211, /* forbidden bit allocation value */ + MAD_ERROR_BADSCALEFACTOR = 0x0221, /* bad scalefactor index */ + MAD_ERROR_BADMODE = 0x0222, /* bad bitrate/mode combination */ + MAD_ERROR_BADFRAMELEN = 0x0231, /* bad frame length */ + MAD_ERROR_BADBIGVALUES = 0x0232, /* bad big_values count */ + MAD_ERROR_BADBLOCKTYPE = 0x0233, /* reserved block_type */ + MAD_ERROR_BADSCFSI = 0x0234, /* bad scalefactor selection info */ + MAD_ERROR_BADDATAPTR = 0x0235, /* bad main_data_begin pointer */ + MAD_ERROR_BADPART3LEN = 0x0236, /* bad audio data length */ + MAD_ERROR_BADHUFFTABLE = 0x0237, /* bad Huffman table select */ + MAD_ERROR_BADHUFFDATA = 0x0238, /* Huffman data overrun */ + MAD_ERROR_BADSTEREO = 0x0239 /* incompatible block_type for JS */ +}; + +# define MAD_RECOVERABLE(error) ((error) & 0xff00) + +struct mad_stream { + unsigned char const *buffer; /* input bitstream buffer */ + unsigned char const *bufend; /* end of buffer */ + unsigned long skiplen; /* bytes to skip before next frame */ + + int sync; /* stream sync found */ + unsigned long freerate; /* free bitrate (fixed) */ + + unsigned char const *this_frame; /* start of current frame */ + unsigned char const *next_frame; /* start of next frame */ + struct mad_bitptr ptr; /* current processing bit pointer */ + + struct mad_bitptr anc_ptr; /* ancillary bits pointer */ + unsigned int anc_bitlen; /* number of ancillary bits */ + + unsigned char (*main_data)[MAD_BUFFER_MDLEN]; + /* Layer III main_data() */ + unsigned int md_len; /* bytes in main_data */ + + int options; /* decoding options (see below) */ + enum mad_error error; /* error code (see above) */ +}; + +enum { + MAD_OPTION_IGNORECRC = 0x0001, /* ignore CRC errors */ + MAD_OPTION_HALFSAMPLERATE = 0x0002 /* generate PCM at 1/2 sample rate */ +# if 0 /* not yet implemented */ + MAD_OPTION_LEFTCHANNEL = 0x0010, /* decode left channel only */ + MAD_OPTION_RIGHTCHANNEL = 0x0020, /* decode right channel only */ + MAD_OPTION_SINGLECHANNEL = 0x0030 /* combine channels */ +# endif +}; + +void mad_stream_init(struct mad_stream *); +void mad_stream_finish(struct mad_stream *); + +# define mad_stream_options(stream, opts) \ + ((void) ((stream)->options = (opts))) + +void mad_stream_buffer(struct mad_stream *, + unsigned char const *, unsigned long); +void mad_stream_skip(struct mad_stream *, unsigned long); + +int mad_stream_sync(struct mad_stream *); + +char const *mad_stream_errorstr(struct mad_stream const *); + +# endif + +/* Id: frame.h,v 1.20 2004/01/23 09:41:32 rob Exp */ + +# ifndef LIBMAD_FRAME_H +# define LIBMAD_FRAME_H + + +enum mad_layer { + MAD_LAYER_I = 1, /* Layer I */ + MAD_LAYER_II = 2, /* Layer II */ + MAD_LAYER_III = 3 /* Layer III */ +}; + +enum mad_mode { + MAD_MODE_SINGLE_CHANNEL = 0, /* single channel */ + MAD_MODE_DUAL_CHANNEL = 1, /* dual channel */ + MAD_MODE_JOINT_STEREO = 2, /* joint (MS/intensity) stereo */ + MAD_MODE_STEREO = 3 /* normal LR stereo */ +}; + +enum mad_emphasis { + MAD_EMPHASIS_NONE = 0, /* no emphasis */ + MAD_EMPHASIS_50_15_US = 1, /* 50/15 microseconds emphasis */ + MAD_EMPHASIS_CCITT_J_17 = 3, /* CCITT J.17 emphasis */ + MAD_EMPHASIS_RESERVED = 2 /* unknown emphasis */ +}; + +struct mad_header { + enum mad_layer layer; /* audio layer (1, 2, or 3) */ + enum mad_mode mode; /* channel mode (see above) */ + int mode_extension; /* additional mode info */ + enum mad_emphasis emphasis; /* de-emphasis to use (see above) */ + + unsigned long bitrate; /* stream bitrate (bps) */ + unsigned int samplerate; /* sampling frequency (Hz) */ + + unsigned short crc_check; /* frame CRC accumulator */ + unsigned short crc_target; /* final target CRC checksum */ + + int flags; /* flags (see below) */ + int private_bits; /* private bits (see below) */ + + mad_timer_t duration; /* audio playing time of frame */ +}; + +struct mad_frame { + struct mad_header header; /* MPEG audio header */ + + int options; /* decoding options (from stream) */ + + mad_fixed_t sbsample[2][36][32]; /* synthesis subband filter samples */ + mad_fixed_t (*overlap)[2][32][18]; /* Layer III block overlap data */ +}; + +# define MAD_NCHANNELS(header) ((header)->mode ? 2 : 1) +# define MAD_NSBSAMPLES(header) \ + ((header)->layer == MAD_LAYER_I ? 12 : \ + (((header)->layer == MAD_LAYER_III && \ + ((header)->flags & MAD_FLAG_LSF_EXT)) ? 18 : 36)) + +enum { + MAD_FLAG_NPRIVATE_III = 0x0007, /* number of Layer III private bits */ + MAD_FLAG_INCOMPLETE = 0x0008, /* header but not data is decoded */ + + MAD_FLAG_PROTECTION = 0x0010, /* frame has CRC protection */ + MAD_FLAG_COPYRIGHT = 0x0020, /* frame is copyright */ + MAD_FLAG_ORIGINAL = 0x0040, /* frame is original (else copy) */ + MAD_FLAG_PADDING = 0x0080, /* frame has additional slot */ + + MAD_FLAG_I_STEREO = 0x0100, /* uses intensity joint stereo */ + MAD_FLAG_MS_STEREO = 0x0200, /* uses middle/side joint stereo */ + MAD_FLAG_FREEFORMAT = 0x0400, /* uses free format bitrate */ + + MAD_FLAG_LSF_EXT = 0x1000, /* lower sampling freq. extension */ + MAD_FLAG_MC_EXT = 0x2000, /* multichannel audio extension */ + MAD_FLAG_MPEG_2_5_EXT = 0x4000 /* MPEG 2.5 (unofficial) extension */ +}; + +enum { + MAD_PRIVATE_HEADER = 0x0100, /* header private bit */ + MAD_PRIVATE_III = 0x001f /* Layer III private bits (up to 5) */ +}; + +void mad_header_init(struct mad_header *); + +# define mad_header_finish(header) /* nothing */ + +int mad_header_decode(struct mad_header *, struct mad_stream *); + +void mad_frame_init(struct mad_frame *); +void mad_frame_finish(struct mad_frame *); + +int mad_frame_decode(struct mad_frame *, struct mad_stream *); + +void mad_frame_mute(struct mad_frame *); + +# endif + +/* Id: synth.h,v 1.15 2004/01/23 09:41:33 rob Exp */ + +# ifndef LIBMAD_SYNTH_H +# define LIBMAD_SYNTH_H + + +struct mad_pcm { + unsigned int samplerate; /* sampling frequency (Hz) */ + unsigned short channels; /* number of channels */ + unsigned short length; /* number of samples per channel */ + mad_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */ +}; + +struct mad_synth { + mad_fixed_t filter[2][2][2][16][8]; /* polyphase filterbank outputs */ + /* [ch][eo][peo][s][v] */ + + unsigned int phase; /* current processing phase */ + + struct mad_pcm pcm; /* PCM output */ +}; + +/* single channel PCM selector */ +enum { + MAD_PCM_CHANNEL_SINGLE = 0 +}; + +/* dual channel PCM selector */ +enum { + MAD_PCM_CHANNEL_DUAL_1 = 0, + MAD_PCM_CHANNEL_DUAL_2 = 1 +}; + +/* stereo PCM selector */ +enum { + MAD_PCM_CHANNEL_STEREO_LEFT = 0, + MAD_PCM_CHANNEL_STEREO_RIGHT = 1 +}; + +void mad_synth_init(struct mad_synth *); + +# define mad_synth_finish(synth) /* nothing */ + +void mad_synth_mute(struct mad_synth *); + +void mad_synth_frame(struct mad_synth *, struct mad_frame const *); + +# endif + +/* Id: decoder.h,v 1.17 2004/01/23 09:41:32 rob Exp */ + +# ifndef LIBMAD_DECODER_H +# define LIBMAD_DECODER_H + + +enum mad_decoder_mode { + MAD_DECODER_MODE_SYNC = 0, + MAD_DECODER_MODE_ASYNC +}; + +enum mad_flow { + MAD_FLOW_CONTINUE = 0x0000, /* continue normally */ + MAD_FLOW_STOP = 0x0010, /* stop decoding normally */ + MAD_FLOW_BREAK = 0x0011, /* stop decoding and signal an error */ + MAD_FLOW_IGNORE = 0x0020 /* ignore the current frame */ +}; + +struct mad_decoder { + enum mad_decoder_mode mode; + + int options; + + struct { + long pid; + int in; + int out; + } async; + + struct { + struct mad_stream stream; + struct mad_frame frame; + struct mad_synth synth; + } *sync; + + void *cb_data; + + enum mad_flow (*input_func)(void *, struct mad_stream *); + enum mad_flow (*header_func)(void *, struct mad_header const *); + enum mad_flow (*filter_func)(void *, + struct mad_stream const *, struct mad_frame *); + enum mad_flow (*output_func)(void *, + struct mad_header const *, struct mad_pcm *); + enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); + enum mad_flow (*message_func)(void *, void *, unsigned int *); +}; + +void mad_decoder_init(struct mad_decoder *, void *, + enum mad_flow (*)(void *, struct mad_stream *), + enum mad_flow (*)(void *, struct mad_header const *), + enum mad_flow (*)(void *, + struct mad_stream const *, + struct mad_frame *), + enum mad_flow (*)(void *, + struct mad_header const *, + struct mad_pcm *), + enum mad_flow (*)(void *, + struct mad_stream *, + struct mad_frame *), + enum mad_flow (*)(void *, void *, unsigned int *)); +int mad_decoder_finish(struct mad_decoder *); + +# define mad_decoder_options(decoder, opts) \ + ((void) ((decoder)->options = (opts))) + +int mad_decoder_run(struct mad_decoder *, enum mad_decoder_mode); +int mad_decoder_message(struct mad_decoder *, void *, unsigned int *); + +# endif + +# ifdef __cplusplus +} +# endif diff --git a/lorgar/lib/em/wrapper.js b/lorgar/lib/em/wrapper.js deleted file mode 100644 index 1c75774..0000000 --- a/lorgar/lib/em/wrapper.js +++ /dev/null @@ -1,4 +0,0 @@ -var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=(function(status,toThrow){throw toThrow});Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}else{return scriptDirectory+path}}if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}Module["read"]=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)};Module["setWindowTitle"]=(function(title){document.title=title})}else{}var out=Module["print"]||(typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null);var err=Module["printErr"]||(typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||out);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var asm2wasmImports={"f64-rem":(function(x,y){return x%y}),"debugger":(function(){debugger})};var functionPointers=new Array(0);var GLOBAL_BASE=1024;var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx){var endPtr=idx;while(u8Array[endPtr])++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(1){var u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|u8Array[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}}function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){++len}else if(u<=2047){len+=2}else if(u<=65535){len+=3}else if(u<=2097151){len+=4}else if(u<=67108863){len+=5}else{len+=6}}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function allocateUTF8(str){var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8Array(str,HEAP8,ret,size);return ret}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var STATIC_BASE=1024,DYNAMIC_BASE=5316240,DYNAMICTOP_PTR=73104;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}var TOTAL_STACK=5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(TOTAL_MEMORY>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="wrapper.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function mergeMemory(newBuffer){var oldBuffer=Module["buffer"];if(newBuffer.byteLength0);info.refcount--;if(info.refcount===0&&!info.rethrown){if(info.destructor){Module["dynCall_vi"](info.destructor,ptr)}delete EXCEPTIONS.infos[ptr];___cxa_free_exception(ptr)}}),clearRef:(function(ptr){if(!ptr)return;var info=EXCEPTIONS.infos[ptr];info.refcount=0})};function ___cxa_throw(ptr,type,destructor){EXCEPTIONS.infos[ptr]={ptr:ptr,adjusted:[ptr],type:type,destructor:destructor,refcount:0,caught:false,rethrown:false};EXCEPTIONS.last=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exception=1}else{__ZSt18uncaught_exceptionv.uncaught_exception++}throw ptr+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch."}function ___cxa_uncaught_exception(){return!!__ZSt18uncaught_exceptionv.uncaught_exception}function ___lock(){}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}function ___map_file(pathname,size){___setErrNo(1);return-1}var SYSCALLS={buffers:[null,[],[]],printChar:(function(stream,curr){var buffer=SYSCALLS.buffers[stream];assert(buffer);if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}}),varargs:0,get:(function(varargs){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret}),getStr:(function(){var ret=UTF8ToString(SYSCALLS.get());return ret}),get64:(function(){var low=SYSCALLS.get(),high=SYSCALLS.get();if(low>=0)assert(high===0);else assert(high===-1);return low}),getZero:(function(){assert(SYSCALLS.get()===0)})};function ___syscall140(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),offset_high=SYSCALLS.get(),offset_low=SYSCALLS.get(),result=SYSCALLS.get(),whence=SYSCALLS.get();var offset=offset_low;FS.llseek(stream,offset,whence);HEAP32[result>>2]=stream.position;if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall145(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),iov=SYSCALLS.get(),iovcnt=SYSCALLS.get();return SYSCALLS.doReadv(stream,iov,iovcnt)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall146(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.get(),iov=SYSCALLS.get(),iovcnt=SYSCALLS.get();var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];for(var j=0;j>2])}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return(new Function("body","return function "+name+"() {\n"+' "use strict";'+" return body.apply(this, arguments);\n"+"};\n"))(body)}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,(function(message){this.name=errorName;this.message=message;var stack=(new Error(message)).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}}));errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=(function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}});return errorClass}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach((function(type){typeDependencies[type]=dependentTypes}));function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i>shift])}),destructorFunction:null})}function ClassHandle_isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right}function shallowCopyInternalPointer(o){return{count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType}}function throwInstanceAlreadyDeleted(obj){function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")}function ClassHandle_clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}});clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}}function runDestructor(handle){var $$=handle.$$;if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}}function ClassHandle_delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}this.$$.count.value-=1;var toDelete=0===this.$$.count.value;if(toDelete){runDestructor(this)}if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}}function ClassHandle_isDeleted(){return!this.$$.ptr}var delayFunction=undefined;var deletionQueue=[];function flushPendingDeletes(){while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}}function ClassHandle_deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}function init_ClassHandle(){ClassHandle.prototype["isAliasOf"]=ClassHandle_isAliasOf;ClassHandle.prototype["clone"]=ClassHandle_clone;ClassHandle.prototype["delete"]=ClassHandle_delete;ClassHandle.prototype["isDeleted"]=ClassHandle_isDeleted;ClassHandle.prototype["deleteLater"]=ClassHandle_deleteLater}function ClassHandle(){}var registeredPointers={};function ensureOverloadTable(proto,methodName,humanName){if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=(function(){if(!proto[methodName].overloadTable.hasOwnProperty(arguments.length)){throwBindingError("Function '"+humanName+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+proto[methodName].overloadTable+")!")}return proto[methodName].overloadTable[arguments.length].apply(this,arguments)});proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}}function exposePublicSymbol(name,value,numArguments){if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError("Cannot register public name '"+name+"' twice")}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError("Cannot register multiple overloads of a function with the same number of arguments ("+numArguments+")!")}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}}function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}function upcastPointer(ptr,ptrClass,desiredClass){while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError("Expected null or instance of "+desiredClass.name+", got an instance of "+ptrClass.name)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr}function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,__emval_register((function(){clonedHandle["delete"]()})));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+handle.$$.ptrType.name+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function RegisteredPointer_getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr}function RegisteredPointer_destructor(ptr){if(this.rawDestructor){this.rawDestructor(ptr)}}function RegisteredPointer_deleteObject(handle){if(handle!==null){handle["delete"]()}}function downcastPointer(ptr,ptrClass,desiredClass){if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)}function getInheritedInstanceCount(){return Object.keys(registeredInstances).length}function getLiveInheritedInstances(){var rv=[];for(var k in registeredInstances){if(registeredInstances.hasOwnProperty(k)){rv.push(registeredInstances[k])}}return rv}function setDelayFunction(fn){delayFunction=fn;if(deletionQueue.length&&delayFunction){delayFunction(flushPendingDeletes)}}function init_embind(){Module["getInheritedInstanceCount"]=getInheritedInstanceCount;Module["getLiveInheritedInstances"]=getLiveInheritedInstances;Module["flushPendingDeletes"]=flushPendingDeletes;Module["setDelayFunction"]=setDelayFunction}var registeredInstances={};function getBasestPointer(class_,ptr){if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr}function getInheritedInstance(class_,ptr){ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]}function makeClassHandle(prototype,record){if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return Object.create(prototype,{$$:{value:record}})}function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr:ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}function init_RegisteredPointer(){RegisteredPointer.prototype.getPointee=RegisteredPointer_getPointee;RegisteredPointer.prototype.destructor=RegisteredPointer_destructor;RegisteredPointer.prototype["argPackAdvance"]=8;RegisteredPointer.prototype["readValueFromPointer"]=simpleReadValueFromPointer;RegisteredPointer.prototype["deleteObject"]=RegisteredPointer_deleteObject;RegisteredPointer.prototype["fromWireType"]=RegisteredPointer_fromWireType}function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var args=[];for(var i=1;i>2)+i])}return array}function __embind_register_class_constructor(rawClassType,argCount,rawArgTypesAddr,invokerSignature,invoker,rawConstructor){var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],(function(classType){classType=classType[0];var humanName="constructor "+classType.name;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError("Cannot register multiple constructors with identical number of parameters ("+(argCount-1)+") for class '"+classType.name+"'! Overload resolution is currently only performed using the parameter count, not actual type info!")}classType.registeredClass.constructor_body[argCount-1]=function unboundTypeHandler(){throwUnboundTypeError("Cannot construct "+classType.name+" due to unbound types",rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,(function(argTypes){classType.registeredClass.constructor_body[argCount-1]=function constructor_body(){if(arguments.length!==argCount-1){throwBindingError(humanName+" called with "+arguments.length+" arguments, expected "+(argCount-1))}var destructors=[];var args=new Array(argCount);args[0]=rawConstructor;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i>1])});case 2:return(function(pointer){var heap=signed?HEAP32:HEAPU32;return this["fromWireType"](heap[pointer>>2])});default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_enum(rawType,name,size,isSigned){var shift=getShiftFromSize(size);name=readLatin1String(name);function ctor(){}ctor.values={};registerType(rawType,{name:name,constructor:ctor,"fromWireType":(function(c){return this.constructor.values[c]}),"toWireType":(function(destructors,c){return c.value}),"argPackAdvance":8,"readValueFromPointer":enumReadValueFromPointer(name,shift,isSigned),destructorFunction:null});exposePublicSymbol(name,ctor)}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __embind_register_enum_value(rawEnumType,name,enumValue){var enumType=requireRegisteredType(rawEnumType,"enum");name=readLatin1String(name);var Enum=enumType.constructor;var Value=Object.create(enumType.constructor.prototype,{value:{value:enumValue},constructor:{value:createNamedFunction(enumType.name+"_"+name,(function(){}))}});Enum.values[enumValue]=Value;Enum[name]=Value}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return(function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])});case 3:return(function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])});default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":(function(value){return value}),"toWireType":(function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value}),"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn){var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,(function(){throwUnboundTypeError("Cannot call "+name+" due to unbound types",argTypes)}),argCount-1);whenDependentTypesAreResolved([],argTypes,(function(argTypes){var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn),argCount-1);return[]}))}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=(function(value){return value});if(minRange===0){var bitshift=32-8*size;fromWireType=(function(value){return value<>>bitshift})}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":(function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(valuemaxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0}),"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap["buffer"],data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":(function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var endChar=HEAPU8[value+4+length];var endCharSwap=0;if(endChar!=0){endCharSwap=endChar;HEAPU8[value+4+length]=0}var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0){var stringSegment=UTF8ToString(decodeStartPtr);if(str===undefined)str=stringSegment;else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}if(endCharSwap!=0)HEAPU8[value+4+length]=endCharSwap}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i>2];var a=new Array(length);var start=value+4>>shift;for(var i=0;i>2]=length;var start=ptr+4>>shift;for(var i=0;i>2]=rd;return returnType["toWireType"](destructors,handle)}function __emval_allocateDestructors(destructorsRef){var destructors=[];HEAP32[destructorsRef>>2]=__emval_register(destructors);return destructors}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}else{return symbol}}var emval_methodCallers=[];function __emval_call_method(caller,handle,methodName,destructorsRef,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);return caller(handle,methodName,__emval_allocateDestructors(destructorsRef),args)}function __emval_call_void_method(caller,handle,methodName,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)}function emval_get_global(){return(function(){return Function})()("return this")()}function __emval_get_global(name){if(name===0){return __emval_register(emval_get_global())}else{name=getStringOrSymbol(name);return __emval_register(emval_get_global()[name])}}function __emval_addMethodCaller(caller){var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id}function __emval_lookupTypes(argCount,argTypes,argWireTypes){var a=new Array(argCount);for(var i=0;i>2)+i],"parameter "+i)}return a}function __emval_get_method_caller(argCount,argTypes){var types=__emval_lookupTypes(argCount,argTypes);var retType=types[0];var signatureName=retType.name+"_$"+types.slice(1).map((function(t){return t.name})).join("_")+"$";var params=["retType"];var args=[retType];var argsList="";for(var i=0;i4){emval_handle_array[handle].refcount+=1}}function craftEmvalAllocator(argCount){var argsList="";for(var i=0;i> 2) + "+i+'], "parameter '+i+'");\n'+"var arg"+i+" = argType"+i+".readValueFromPointer(args);\n"+"args += argType"+i+"['argPackAdvance'];\n"}functionBody+="var obj = new constructor("+argsList+");\n"+"return __emval_register(obj);\n"+"}\n";return(new Function("requireRegisteredType","Module","__emval_register",functionBody))(requireRegisteredType,Module,__emval_register)}var emval_newers={};function __emval_new(handle,argCount,argTypes,args){handle=requireHandle(handle);var newer=emval_newers[argCount];if(!newer){newer=craftEmvalAllocator(argCount);emval_newers[argCount]=newer}return newer(handle,argTypes,args)}function __emval_new_cstring(v){return __emval_register(getStringOrSymbol(v))}function __emval_run_destructors(handle){var destructors=emval_handle_array[handle].value;runDestructors(destructors);__emval_decref(handle)}function __emval_set_property(handle,key,value){handle=requireHandle(handle);key=requireHandle(key);value=requireHandle(value);handle[key]=value}function __emval_take_value(type,argv){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](argv);return __emval_register(v)}function _abort(){Module["abort"]()}function _emscripten_get_heap_size(){return TOTAL_MEMORY}function _emscripten_resize_heap(requestedSize){abortOnCannotGrowMemory()}var ENV={};function _getenv(name){if(name===0)return 0;name=UTF8ToString(name);if(!ENV.hasOwnProperty(name))return 0;if(_getenv.ret)_free(_getenv.ret);_getenv.ret=allocateUTF8(ENV[name]);return _getenv.ret}function _llvm_stackrestore(p){var self=_llvm_stacksave;var ret=self.LLVM_SAVEDSTACKS[p];self.LLVM_SAVEDSTACKS.splice(p,1);stackRestore(ret)}function _llvm_stacksave(){var self=_llvm_stacksave;if(!self.LLVM_SAVEDSTACKS){self.LLVM_SAVEDSTACKS=[]}self.LLVM_SAVEDSTACKS.push(stackSave());return self.LLVM_SAVEDSTACKS.length-1}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}function _pthread_cond_wait(){return 0}var PTHREAD_SPECIFIC={};function _pthread_getspecific(key){return PTHREAD_SPECIFIC[key]||0}var PTHREAD_SPECIFIC_NEXT_KEY=1;var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};function _pthread_key_create(key,destructor){if(key==0){return ERRNO_CODES.EINVAL}HEAP32[key>>2]=PTHREAD_SPECIFIC_NEXT_KEY;PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY]=0;PTHREAD_SPECIFIC_NEXT_KEY++;return 0}function _pthread_once(ptr,func){if(!_pthread_once.seen)_pthread_once.seen={};if(ptr in _pthread_once.seen)return;Module["dynCall_v"](func);_pthread_once.seen[ptr]=1}function _pthread_setspecific(key,value){if(!(key in PTHREAD_SPECIFIC)){return ERRNO_CODES.EINVAL}PTHREAD_SPECIFIC[key]=value;return 0}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]);return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":(function(date){return WEEKDAYS[date.tm_wday].substring(0,3)}),"%A":(function(date){return WEEKDAYS[date.tm_wday]}),"%b":(function(date){return MONTHS[date.tm_mon].substring(0,3)}),"%B":(function(date){return MONTHS[date.tm_mon]}),"%C":(function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)}),"%d":(function(date){return leadingNulls(date.tm_mday,2)}),"%e":(function(date){return leadingSomething(date.tm_mday,2," ")}),"%g":(function(date){return getWeekBasedYear(date).toString().substring(2)}),"%G":(function(date){return getWeekBasedYear(date)}),"%H":(function(date){return leadingNulls(date.tm_hour,2)}),"%I":(function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)}),"%j":(function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)}),"%m":(function(date){return leadingNulls(date.tm_mon+1,2)}),"%M":(function(date){return leadingNulls(date.tm_min,2)}),"%n":(function(){return"\n"}),"%p":(function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}}),"%S":(function(date){return leadingNulls(date.tm_sec,2)}),"%t":(function(){return"\t"}),"%u":(function(date){var day=new Date(date.tm_year+1900,date.tm_mon+1,date.tm_mday,0,0,0,0);return day.getDay()||7}),"%U":(function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"}),"%V":(function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)}),"%Z":(function(date){return date.tm_zone}),"%%":(function(){return"%"})};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}InternalError=Module["InternalError"]=extendError(Error,"InternalError");embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");init_ClassHandle();init_RegisteredPointer();init_embind();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["wasmTableSize"]=736;Module["wasmMaxTableSize"]=736;var asmGlobalArg={};Module.asmLibraryArg={"d":abort,"ga":abortOnCannotGrowMemory,"u":___assert_fail,"D":___cxa_allocate_exception,"A":___cxa_throw,"Q":___cxa_uncaught_exception,"x":___lock,"I":___map_file,"w":___setErrNo,"H":___syscall140,"fa":___syscall145,"G":___syscall146,"ea":___syscall54,"da":___syscall6,"ca":___syscall91,"v":___unlock,"ba":__embind_finalize_value_object,"aa":__embind_register_bool,"h":__embind_register_class,"m":__embind_register_class_constructor,"f":__embind_register_class_function,"c":__embind_register_class_property,"$":__embind_register_emval,"r":__embind_register_enum,"q":__embind_register_enum_value,"F":__embind_register_float,"l":__embind_register_function,"i":__embind_register_integer,"g":__embind_register_memory_view,"E":__embind_register_std_string,"_":__embind_register_std_wstring,"Z":__embind_register_value_object,"C":__embind_register_value_object_field,"Y":__embind_register_void,"t":__emval_as,"B":__emval_call_method,"X":__emval_call_void_method,"e":__emval_decref,"W":__emval_get_global,"s":__emval_get_method_caller,"z":__emval_get_property,"y":__emval_incref,"V":__emval_new,"U":__emval_new_cstring,"o":__emval_run_destructors,"T":__emval_set_property,"n":__emval_take_value,"b":_abort,"S":_emscripten_get_heap_size,"R":_emscripten_memcpy_big,"P":_emscripten_resize_heap,"p":_getenv,"k":_llvm_stackrestore,"j":_llvm_stacksave,"O":_pthread_cond_wait,"N":_pthread_getspecific,"M":_pthread_key_create,"L":_pthread_once,"K":_pthread_setspecific,"J":_strftime_l,"a":DYNAMICTOP_PTR};var asm=Module["asm"](asmGlobalArg,Module.asmLibraryArg,buffer);Module["asm"]=asm;var __GLOBAL__sub_I_bind_cpp=Module["__GLOBAL__sub_I_bind_cpp"]=(function(){return Module["asm"]["ha"].apply(null,arguments)});var __GLOBAL__sub_I_iostream_cpp=Module["__GLOBAL__sub_I_iostream_cpp"]=(function(){return Module["asm"]["ia"].apply(null,arguments)});var __GLOBAL__sub_I_wrapper_cpp=Module["__GLOBAL__sub_I_wrapper_cpp"]=(function(){return Module["asm"]["ja"].apply(null,arguments)});var __ZSt18uncaught_exceptionv=Module["__ZSt18uncaught_exceptionv"]=(function(){return Module["asm"]["ka"].apply(null,arguments)});var ___getTypeName=Module["___getTypeName"]=(function(){return Module["asm"]["la"].apply(null,arguments)});var _free=Module["_free"]=(function(){return Module["asm"]["ma"].apply(null,arguments)});var _malloc=Module["_malloc"]=(function(){return Module["asm"]["na"].apply(null,arguments)});var stackRestore=Module["stackRestore"]=(function(){return Module["asm"]["Ia"].apply(null,arguments)});var stackSave=Module["stackSave"]=(function(){return Module["asm"]["Ja"].apply(null,arguments)});var dynCall_i=Module["dynCall_i"]=(function(){return Module["asm"]["oa"].apply(null,arguments)});var dynCall_ii=Module["dynCall_ii"]=(function(){return Module["asm"]["pa"].apply(null,arguments)});var dynCall_iii=Module["dynCall_iii"]=(function(){return Module["asm"]["qa"].apply(null,arguments)});var dynCall_iiii=Module["dynCall_iiii"]=(function(){return Module["asm"]["ra"].apply(null,arguments)});var dynCall_iiiii=Module["dynCall_iiiii"]=(function(){return Module["asm"]["sa"].apply(null,arguments)});var dynCall_iiiiid=Module["dynCall_iiiiid"]=(function(){return Module["asm"]["ta"].apply(null,arguments)});var dynCall_iiiiii=Module["dynCall_iiiiii"]=(function(){return Module["asm"]["ua"].apply(null,arguments)});var dynCall_iiiiiid=Module["dynCall_iiiiiid"]=(function(){return Module["asm"]["va"].apply(null,arguments)});var dynCall_iiiiiii=Module["dynCall_iiiiiii"]=(function(){return Module["asm"]["wa"].apply(null,arguments)});var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=(function(){return Module["asm"]["xa"].apply(null,arguments)});var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=(function(){return Module["asm"]["ya"].apply(null,arguments)});var dynCall_iiiiij=Module["dynCall_iiiiij"]=(function(){return Module["asm"]["za"].apply(null,arguments)});var dynCall_v=Module["dynCall_v"]=(function(){return Module["asm"]["Aa"].apply(null,arguments)});var dynCall_vi=Module["dynCall_vi"]=(function(){return Module["asm"]["Ba"].apply(null,arguments)});var dynCall_vii=Module["dynCall_vii"]=(function(){return Module["asm"]["Ca"].apply(null,arguments)});var dynCall_viii=Module["dynCall_viii"]=(function(){return Module["asm"]["Da"].apply(null,arguments)});var dynCall_viiii=Module["dynCall_viiii"]=(function(){return Module["asm"]["Ea"].apply(null,arguments)});var dynCall_viiiii=Module["dynCall_viiiii"]=(function(){return Module["asm"]["Fa"].apply(null,arguments)});var dynCall_viiiiii=Module["dynCall_viiiiii"]=(function(){return Module["asm"]["Ga"].apply(null,arguments)});var dynCall_viijii=Module["dynCall_viijii"]=(function(){return Module["asm"]["Ha"].apply(null,arguments)});Module["asm"]=asm;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=run;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){out(what);err(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run() - - - diff --git a/lorgar/lib/em/wrapper.wasm b/lorgar/lib/em/wrapper.wasm deleted file mode 100644 index a80529cf3ae15835b4d4f8fe2c355e668ee6e245..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256902 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
    Ht9_H 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�nCCM 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 E0Tc)@DF6Tf diff --git a/lorgar/main.js b/lorgar/main.js index 2dbe195..046eb99 100644 --- a/lorgar/main.js +++ b/lorgar/main.js @@ -40,6 +40,7 @@ window.subscribeForeignController = window.lorgar.subscribeForeignController.bind(window.lorgar); window.unsubscribeForeignController = window.lorgar.unsubscribeForeignController.bind(window.lorgar); window.play = window.lorgar.play.bind(window.lorgar); + window.scheduleToPlay = window.lorgar.scheduleToPlay.bind(window.lorgar); } } } diff --git a/lorgar/views/pane.js b/lorgar/views/pane.js index ce4dd50..e0fcf70 100644 --- a/lorgar/views/pane.js +++ b/lorgar/views/pane.js @@ -27,6 +27,7 @@ W.extend(base, options); Layout.fn.constructor.call(this, controller, options); + this._aCount = 0; this._initProxy(); this.addClass("hoverable"); this._e.addEventListener("click", this._proxy.onClick, false); @@ -65,8 +66,29 @@ Layout.fn.destructor.call(this); }, "_onAddAction": function(model) { - var view = new Button(model); - this.append(view, Layout.Aligment.LeftTop) + var alignment; + switch (this._aCount) { + case 0: + alignment = Layout.Aligment.LeftTop; + break; + case 1: + alignment = Layout.Aligment.RightTop; + break; + case 2: + alignment = Layout.Aligment.RightBottom; + break; + case 3: + alignment = Layout.Aligment.LeftBottom; + break; + default: + console.warn("Pane can't place more then 4 action, ignoring"); + break + } + if (alignment !== undefined) { + var view = new Button(model); + this.append(view, alignment); + this._aCount++; + } }, "_applyProperties": function() { this._onAddProperty("secondaryColor", "background"); diff --git a/lorgar/views/slider.js b/lorgar/views/slider.js index 328947f..a8b12b6 100644 --- a/lorgar/views/slider.js +++ b/lorgar/views/slider.js @@ -40,6 +40,8 @@ if (this._seeking) { window.removeEventListener("mouseup", this._proxy.onMouseUp); window.removeEventListener("mousemove", this._proxy.onMouseMove); + lorgar._body.removeClass("dragging"); + lorgar._body.removeClass("non-selectable"); } if (this._f.enabled) { this._e.removeEventListener("mousedown", this._proxy.onMouseDown); @@ -94,6 +96,8 @@ if (e.which === 1) { window.addEventListener("mouseup", this._proxy.onMouseUp); window.addEventListener("mousemove", this._proxy.onMouseMove); + lorgar._body.addClass("dragging"); + lorgar._body.addClass("non-selectable"); this._seeking = true; this._ap = this.getAbsolutePosition(); @@ -120,6 +124,7 @@ this._seeking = false; window.removeEventListener("mouseup", this._proxy.onMouseUp); window.removeEventListener("mousemove", this._proxy.onMouseMove); + lorgar._body.removeClass("dragging"); }, _onValue: function(pb) { this._value.style.width = pb * 100 + "%"; diff --git a/magnus/pages/album.js b/magnus/pages/album.js index cf36d4f..8aa916d 100644 --- a/magnus/pages/album.js +++ b/magnus/pages/album.js @@ -52,6 +52,10 @@ var AlbumPage = TempPage.inherit({ [{ type: 0, action: "play" + }, + { + type: 0, + action: "scheduledToPlay" }] ); var PaneClass = PaneModel.Songs; diff --git a/magnus/pages/artist.js b/magnus/pages/artist.js index b87aab6..f49a34c 100644 --- a/magnus/pages/artist.js +++ b/magnus/pages/artist.js @@ -47,6 +47,10 @@ var ArtistPage = TempPage.inherit({ [{ type: 0, action: "play" + }, + { + type: 0, + action: "scheduledToPlay" }] ); var PaneClass = PaneModel.Songs; diff --git a/magnus/pages/music.js b/magnus/pages/music.js index ef49732..ff00222 100644 --- a/magnus/pages/music.js +++ b/magnus/pages/music.js @@ -148,6 +148,10 @@ var MusicPage = Page.inherit({ [{ type: 0, action: "play" + }, + { + type: 0, + action: "scheduledToPlay" }] ); this._songsLink = new Link(this._address["+"](new Address(["songsLink"])), "Songs", this._addresses.songs.local.clone());