From 5100d91a72ebf921dac579e882507e4a7be33350 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(); } -- 2.50.0 From 46444c5fad9736f850ce8152420ae19418466f2b 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(); -- 2.50.0 From bc4ed4a7cd8d93a9a5a901e70d4fd68af70dadfa 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, -- 2.50.0 From 9abb5ee1164b2ae46796869801cc84099fa65673 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; -- 2.50.0 From cacbc5d89143058b67e1f6da089f77c8cfc14119 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(); -- 2.50.0 From b2ddc804c70d57e7a7868ffdaa6a27cbf93d351c 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"); -- 2.50.0 From 43d0a1dfe92e9415066e11cdad5ac73a69034d14 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)); -- 2.50.0 From 98a443e2987c1e7a67030f24b47b581021efcd4a 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) { -- 2.50.0 From 9b5198a6ce5120604f20d872499ec55cdf6de2db 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(); -- 2.50.0 From 22323b504fdbf46aa59a19c6f1cdf34412af0a9f 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() -- 2.50.0 From 0e31c5fdf2d91fd083a5ca57602321f5ec42eb17 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 bdc76d3..2a9a7fa 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]; -- 2.50.0 From e690d67b8069615295a6d117bf7792f4c1658289 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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 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"); -- 2.50.0 From 6e933257b1cb078b22aa7ed0ce3765deef45a64a 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) { -- 2.50.0 From 35a9abc7d71007aab28908d26ac7563d1b36e982 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; + } } } } -- 2.50.0 From d2e3aa088017da83f7c28c219e2e3f71397c3889 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" } }); -- 2.50.0 From 7f03a0bd75567cc30dc9af335d692edbc92eb3fa 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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

ez~^)%upi+HH#y=e1X0aky`a!w znWNq$28ITZ%{LgAGKcXNPh??WU;$gLq0*PVpj(B3K>;LP=AcoS;vB2O2(!AXGgPbjz?%;#hc8-b^)P%i}W!`o`neQ8a6#95-!Sc$6u(F zNH^$lLxjvXgME!Ah>$tkK9P4Rl6LzZQwbj=?ez+|26K?K3p-v)aOgz@oqo}tgA=3> zfs?ajV)H}OHYQle_j0Ty22cwu%E%{+5+vx z)(Vp>%Mx!)ML1l0@}7eSv=I)^IQFV_VK^dSR`xRUHSa^D$3xPsGHo*@xnK@gu{v$Z zlWGii_=?h=JcHQ?cWrK7aX8@G353J%2Hr?C$WB4{?5D~*gE^*?;HmON?YazyY!!Ia z1#lXEFj!-11h+z?O`uHTh7`;V4KrEzWSygx7u%>-Opv}KCAn1hAoJZ1*G_13bIMq; z?QnCm^!=bn8@z61Ta*Tix5UY2O3K zya(ASQ(D;g%beqt7tb-tcp>peN>X)2WAmL4*H37~^2$76yWr+l?oea)_He*04g+YU z)tEUj$lQ~be7cpf=|RJz6EFB)TwgXxB1)E#3z7^PKCyAMGp|v0zGCj+AyXtPx%2_! zp+^nxPH2eo3y8IsySr&tHe9e+U}NNUmbvBl!Z#BGyW|vH_+It*1bt;lEYdibGG!Ax z$JAySwZ&I#J$A?x8A(3<;OO*h!R(V7Gx>$g+Qog{B5NmHu-s8;(?)feJTcpDlrA0%a#GqN}^Lrh{gAn?+z zS>2R@p#TvwGcz2vvI#KogGyl#c2<$)U37&3Tvk9sX3H|hk5Ufc%nfzSJ(G?kW(Ed! zxMPG?u$|9=*aD5Fs;duH@-i^UKuls_X!F=7<+B}9zC)u)Gp^a)9O7kY$Ta3W_`n7Z zTxc|@Oy`xk2eAd}m?N7Rk4Qsof;#4gSw{_uV}kCp_2w%a02u)`*T5y{E(0^a0)rCB zgCN}I@kl!55hF_jSRPa#31rqYbK5j9bbzEmSVHM&0mDRg1_nNOG%YdUllg(-m@mf~ zndQOm1=oQLJQIIeR6Id(jF2`vS1rQ<14c+HVK8vn^weP?KZArC%-lAQ2Qnf*8X1^b zAz{IAKw#w@W)D{g59~q-rK`mX8#%x>fxN}Q;JjoqU)LrErUgt8Wef=&M=l+FsN}#9 z!T`w}3_KIltQrznI2yPhZf0muycEIS-^0N00Fh=Uy;evRWRL&{F38($9@Vl6I!p}B z;KR5eA+v?K*{y+L2O`ZZExXXd!N4N{HJ8CzLCsnc^?PFjJV1#NiaEW@~@Ip|5K?{*)-pdNuGqE_ZLL!{ufI#NH zW+k5n2G9mrXvjP)H|XUACp1{di1LdCGcYV*2Kk2p!gDT8>aEFEpA+uR}`t|ciHjECyBRpo9{m_ zsXWJ|dN)~I^n&?{T_;m_TKKXDo=)EK`)u9(%TF!2rZ)dOe{bESHxpotG`i^j<^I z3ELaVP7+F=Si3g#sW5PVbU)By!MouCOYE74hJSV0K`KITs4KB~Dg5J@A+VfLY}bOg zTefxEA0}2sozZJP^5%QR-=)tVrcU^&%dWY6ilb)A-JHDky9z}!0~Otgn2DaQn#xWfpJ$ zO*;JLLwJnc^1BK@tluu1{-5%O#aF;_9~Ee`1vJC$IbRI|JLlWe^8u*zs*X{p`bxf76;T?qQpGIJ0b~kNTHM z)1RmA-0Q#r?#k_gVZxYM)`e=Tc3>7|mIM-q~kJ0JVAFFQKo`cA$e=$N>vCGCs zA0jMY0@JkcbYf8?UsC($RLc``Y1dCran$@)?ZxgoQKNkBS--|3rJHx^uphjiX}(uyxyY}jcRyIks;rxR zHr2A@UtROFw+6F$o%TLm@aXc4MdDpM?l0IB^KV*k&qg^07khzk%mVLO1>Ud=JmnO) z$1QN3SKtc2z*#|oW5NRaMFsYV3v87XST`H2c0xJxg>B3N-MqW|AqgW?_dA_U;fUuiko-;|3By+tT^xFf!tmLomch|b8o#k#?%ZlS^m)f z|NrYR^#1w#|G#{K{fzX#|NlR{!X0z&?|=CR#-bl$cxvu1$bQ7yI-`;IEl5NAhyVZo z%aY#?urjsf_DPe;&+EbSj|TnG96PV>g| z|NqM;O&4&y{r~^LCxMBk_VeuP>MfiP`gkn<1+s$#^-@r8>;QQq(dN^a|NrYhd`y_~ z`Tu|R3v$;cfBRqWks88qyU%xGjohh#1^oMGfW1wEdRT0vfjq9z|Lf2H|MFqh9_Ro3 z|Nrn_>*uL||I5D+5_PI_&V1t5E-T{oSZ@)?6Y?ae-+15wNJ~2?faFgw>w)60jIT%z zoUR=9C;tE6e%X$-^87Qoht-O#t#cZ$){{OEx zxar{j@&AAJ;2GDi{r|66>#LZiTjN_2((#u;^w1)(4F|t~eEWgp@c;k+52i579{vAc z-X}3G`v3p-FQ%Hq)#9lu6>|M$QCLE*pu{}1*B{{P=@uF^WW zH_kfo`hly>AUov4l)#6ak*rISn+KG;>N`NbVl@4A8&tR$-rWOA&XxcF*Gn9}{QrNW zn0w-J`R{&yh9^Eg0EILABnR?z9b;k!^iFK&VKF8#M1lqN#||F0K#dg=fF zg}knfW^+IL-FdUUc^jz2`}I(Qn+L2<1Efz;@5asl|LZ46+JN-M82tZVzr*tqDEJ*4 z*Gca4JLIv3c{WJjtB2rhx9|-p(sm@IgTg=U!<~Qs>kAHoa<`i2|Nrd!*;#j`{jlOx z-pH2&^2&<#WF3PWpzQbXIY{3|gXI7J|10Xp-TL>xUg7oc|Nk4$xc>joF8aTDf6N_A zM&Uv}Cy>4hc96RN?ejr4A3N0Z_y7O)Jr$WC^=m*0%Sin1fBBF<{QrsypR@QJvE%@q zVE9nBXXAkckY((1K>AXYYC!sKg4j+s{{64_2>kv3|H4}5|Nq-1zcv5%`)8inEYEl6 z@Bjbx4(&z z7DoX_M-djmA|o-41_h3$fXM%=&%Q91>gM8TQs_AID}J5Z{!1AVASsty|BEbtEcH6f z#L=Xnapm9a(+BmZX-R>k8h_o-VLP7W*{Hzb^mYF&p1xy?n3@zi-qi1u(&=quyc#siUR9p|oJ9l!=s>0*BCp7(TFi zt^z&wrCn?a9BdY|dsSJR1hS1cu4qt5TIVJurr>ersl#C=4z8UtD>4|G9A{4z;kbEb z1;ddAIV)VN*xA|Hpnw?(K)SCCEUc|X2V@l3jyeYfIIy2#ObQUVqO`Y(i4hE-iqNR0 zrY5Tmd;-mf7KptR72$vbG-aTktcb`h#`1=!CGHLm4hj$;fC(Hxc0XY3YC38;fo}uz zdj}f_&aMQOhGh#3_%AR|S-_LQ#r3(twxP*3fj^*0Xo0524d$N=sv0b_nhx0+@GscF ze}h@$4fAgXRSi~<&&~UP2V1$onfL!{MfrW!dKmD zz)uDa0TBrq1r-e)0}~4yhY6x4EKQ9K3K|?dP0bAqB958@%|UC!){1F3I5-?&IMmc? zJ3&B$g`3gYf#K8wnGVN`vy9XE1jKayF}6QYY~YY!@(SQ%NnmM^5LuaGw9{~r;a>cQzQ(77BDa} zI&yG}$sBZP5G-MlV^r0UPYRgOvao}Rm4k!BF=7J)ry5hMf{FmAhT~7ch9m_xR<2GD zjev%R296e1?nwzs8k{~&lN*Gl)H4`rI668yHZrlWs3_<}EMXBo=)6E^4a<}Tf7m%3 z90i)0SlM_)K%Qef)a2@IAh?4?pV7yG^VI(ahAAwD8crSw4j|1u3OW%dScDJyI0#<> zX_oJBWE5&*;u29%5J)`uNNom(5z`z6^#v?X|2s0AYLXC1P*7Rmz{u1jAf{8+)Y+i^ zg0qInE8w3!%L0QA$3`Y4uvV7DgG?GTIGUIiCTM`Px-)n+ONb~bD1x*q35e-*HFX}) zu;7{i()yo~Wr0P9BPSCVSTAGZK_|@_9MhPVEzkt%wRd1R)hr>Rke~q4%q1YEGq0(W zL92sn36oajIeTx~a>5Neh zW^Gnh`XV#p601^IILkeAgfb7yy-Nf$TlYO!Ahw1zhY{?^Adqt)j)XC*cd!S8L_v;> z{vdV$7%~_B0$(Nel=GnBd~%vTP!p6QgLH_}_hmQ~& zD?78Nii&}RO5%hA2@c5xAGrT99cVbBvT*?e!-SR=76u0)ejx@16E^mP2?h#09zA^R zhaK73nin=dJh;HnLV~TGG07oml7WGNgh!L2;z0#Y<~9~)spjUS4H5=yDsJp7ixwPi zo_OJ)g69PZ8JXte3`Pn@8DCf%9TO)=n6OP`oGHnuz@X}o7BGWDgIPqasfD4n^MInm zLB$yy0SkCEm_;<2TNqeR9Z+;oR9wIl;K3opBqGGr&cNEsG>}MJC9>@qZtm4x!^J-=(Ss=59?II)N zik>2#6-r*sM@k%IL)b4eGHU#4_{6i~PD9aR6OS178;)fQWCa?6_%v+1npw&xNM*3! zWn^5jLyB*KiN^u9`-~MAWCa>7EjIC3!nVrMO+ikeVb_XXN&E{;JSMO|ZL9 zz_ORI3d9lO(|FvF#H(TF)!b6GL2d*4TSi8WT~&)sJOtR^GuB*?6KIgqu=i?qsaBBh zVE@d>xZ+5|E8Z1n7`&QYY7^w|fQ7y`BxxRD@M>;xnjrsz{Wqh~+Q#e;Qg7H<7OY^- zvRtr_S%X*T-@$qY1(1-KR?j5`MTG)(=0kN33|@u}mlO;IeON*r8yy(DOcqRF<}zux zq)@1!z`^MR5?Xo+q@A0onL$B>gJppjGnd_hZ5q5ne21DD6hR_pr`j(mC@T7J{Bq1| zfW+ZWM#dG789+(lfJ_9(PDVzJGYzj6ns_8|Y;kOxAT7`!v~o+)A`_1s4jHF*2U&rJ zF3q0)eT4>_&hQo%btwCAg zp!65EeT;n$467^~E-5^e`oLz-)aSsUWx3#=2CtBS(*y;T2OKO5JYKb4QgBpBVQ~e? zuCiYs$J_-ny--DgGt_aC0|S@Qf+%LLzDo)lRSY6S zm|xj8TvAX}P2dQ2n$+M@pdiD;?#aZs;(kNcLKBY&&TyvQ2`UPLvM<;r7|R?Oy6hV+ zDNK~l;M@=5Wi5#TnHF=X^MYyuJIewk5HH@zNk9g~3j^`q9?TL@1M!-?Y!q9dg7`O~TNk%4vGaJOq>bazFQO$z= z%|Vcqb;Bivi*h?y@(;~yXlZtkV_{EcVqDQQ3zR)9Sc(qKDNs{rlu=0Xc<<0zcT!F;+V;oB{>SL`@Y=3#RIZBl#QD3fSK; zGHU!~0F^KsR0_C2yyp$OK*6zxZQh~f2jm1AtiVZ~-O*_Uh_`F8iN^sBtwSpg$SD}g z2C!dctZrz@pCEOE^9>{83Wvr;psX;5YXwut1yzBDSqn@&R&d!kwSzdXKvEmHz8#ze z;#u))yaVN_)gQDju*EV7aWIt~kS^i$n8U{ERChsDp-?t~{ifq|2ZmQ5M;A)(;o9Of zy}_j|LDhskmPshgY2pFZ5>A!{1)y;K&{*3b_<)OL!L2T{hD!1DMYwk`33)VCZcqZ5J&6mHgd25KxcQmZIWT0|FL(#C`?OR30UeP1E)efQWA+1` z2V9WCwn1BAqJR&(GDx}CDk+fsk;W|sx**lhG{6DXSiueA%nn*);_-v+fzyrx zb%6$@#U>sq?B5Q8Ib3`ihF;AsI}`NQaF#O(X))C_DBs~^S&##=)3vF7f*y#s1jKVZ zl(|9g4kx58C{R}jRAFJCaA0~_uwdJ5}ML9#X(Yp zn`MC+$ll*f6%3*vo)(C=&T;<+DG_du8qQRvo&X(zhEtlBUd=2A6l7RY17vSQZ7yw{UYX3GqAb`XH^q;nBi%sIjm?L4i>|g7Yq8Q^S#U4O(y5IhcgX zo8~%bC~!a;NDT@C4NagxIl*S(ybHv$T4>_&g2(${6-cja4f{XFriPZ<13DkrIGBVS z9rFrg6*xQ`IE)WYY*0`zl;z6^ssA9)z`?=9xZ*h|8y0WS2mouI0~ z;o-yW-I&v$pzu-4fv1M4so}_M1(h034kn@NOce&o3LG95><15)Hz+__4IuMs8kA+Y zIGBXqIvy}kQ{eFU!YzBK9pt=83r#%Mu=_cm0&%()n0UNl_h!7(prCM3eF}>(V|l}o zkX2}up22;PvAn_MK!A=9=N(2N za8sv%-NT37xaqGVe)a z{sZ|Nyetbmm{&DlQV6t=;M>!9x4~u81L->)Wz0e;O{+HO+~DN!zV3P!yU9F%V19JU|rfdbp8@wKS zcsQF163i7I%II)OG%jyAGSxsyf^{B~P|Kks3*;-fJT9;;KiKj>Q(>cG0f%hUatDT0 zc3|6E`1G5XHyml6pvl5BkBL#^5U8@*@jze#-#jLv?FUyhXjO1|RB-(`l>I_vIKDS7Z)lmTpn8D|dtl&sv;RiK^ zKotc}-$Sz-T8bw~cd+L(33)KJe6ZTX3F(M^P*d2bC&9Pk(Ch}5n;UczKnjEoH5I7s z;q>s~+{Ae9gPOuesV(f~hh{e%X*AGS0a9@KP*;Na9!`%H9DE16KBy@yRE^-MIXv5e zfeX~Yb(A&XynYzuWCINwkc<8?&OD&GhttD=C*a`34{8dHiZR>^56^CBah{;?1Z1AP zQ}+X;{&F0{T-xCKxvrIVkVpWLeOr!7F6J-1Nb252wc*wg*fHK&lld@W_LLsB(h* z3y^W4&UpzIpfKc|(zxn_n!-VY3tUW~K<+J2_F++A5{hv;ut1=JgJpr72CvX}$A1RG z4ICaFJeLmzF(?T%7%epM_``9M=|6*#f}!pi_E6@IhL%+i1lF)AFfnQ81d z0+W#Mp_vSF4ICa9I4(MtF(@fqlnxQt#Msfm(xxEa041YW*w3pD{sx(# z8^X)L+|j@?ae|--NI_Y1!2;t34v#b3F-;Fa3Zxl$R)HM3Il+s&{aCHcj}TrEpPZ4ad`i zs~cLjH|Vo)t!EPQY|1eJ*{8z&!ExpXErmqY7)}$AgPH|IdO!}^b?9gVC{VU=u0J^S zgOG$3W`||9U1Ng{E@~>U+36T-bjxx*afANVGV^ zZp?VU!DZ(Ic^%doW})@WB?s(3@On6Ke0I8ez+9oxcnQyHkb>+F>Lz?O%tFT;CoPcr z!0YjZJ?c>Y0doaMqZsbTO!pg(_)JjDV6R~o(m&j!AO}*wX2$dqq(CEs^9sm>>H_%$ zjv8j6lZ^cZ3Lkhq3OLoBrXMg@FjQK?y@Tm~gUj>}nkzsiOmUi>VE%#E;{%(`!Py7Q z6(%YMu&00&R3Ffp0a9>=>2QJa2VRdFPEN;y1Lg`BWhU?~WWL|vQo2Fs2}l9w;S~z1 zA9y`9*!37o4wx$x+9q)PXT0CQlEa`dg}a7XXp2+v1CTGau&;KUall;Rp@srS4b%OG zmIec*BOphfYn*GK`+?VE1AF$N9*`pqpRg|mxnWX+%nPm>W}yv?IR+qK^l+v)%{*YP zuuhY3i5TYzW}XAQFuKhu;3P&mBcI(%>{C>$gcSTvdMHyp{jpgIBM$X=%z0{S0# zLA|kqE(NvI0z|evb_HQ;u#0whD%7Z@An*3if;u z2w}a>EVR(M$3Z2AA38!|tKg`a!x4J;YlF)I1LY8b>&!x-%{Mkk#qfJf;S_c%DzH^} zD8R#^e&}n1%gzF=7H*IUO*d>qLTZKX?3HF(XzBaH_ z1*nK{TxS;A;J9-G$dM{MZx|PXys0U{>UrpE!;xGAEftUgZKmZPKyKK=d5*EVz*d1# zE`ZD8@Ye>GMGv%>fE>BDxhg;hz|PcE39>>{fwL3ji{b=p6_6Dv z&LsxYG5j7D98Vkz3Tzc7svO~%0P;m!fiw?D!QZCh2K^X*j|bdkPWc743Lj-%`1C*u z@+W9mfE1i@68)$NG66iuW2KmNpO!EqC6&%${IIbT0+HfTMg3&!x8P0a@sWB5H1 z*cUp30&1h442KFRsQWKyOaTQ{^P%%7eVQ$w21=$eUtJ)efL=IKZ~mu^Z$Dl^dKwAQSEe$lU;$ zz;I;F1bdJPdP(z1X z@?dU*%dQKm60F-9g_bb)1c=^Y^DyA}#5l1)T4AFa4;S~L+y<6v1?dpp?TkX4&C?k4 z?y!0Au%{oIUm&gEDEEeg;Ye2z(h3hX=5WqDl-tlUr@-(D$cl-~{t3z;H*je&Ed-e$^?=h8q@XZCRfc0bqflql zv;ws|Y#u7?JDjG2e4)IDeK*J#B>|>)IJYwjaWt(mFa&v%{VZc%fwaO!#V_1<4(2wn z>|l^>0C_V7G;VZ<&BKE`_R#7AX@!ZJCY&jUavNN-9+<@NZ)X&;Z)!-8yTj%I9{U4% z)A|g@$wRpfN17Xq&VU>_&G|)v${jY3KkWY)H-k)&QsG>CIJbf2rGm~AkT+$Wt{zah z!v+~J1UXW%gCpf|ZbQp<26+dNf;oq_Dwy11^GM;k;5eZ`TH&F50oMaiK%Ht(xB*gd zma*-D)Ezbt6RvZOiwmR`4E5KrC4wBeH9$xMq`<)G)B*K7Y#vK^rXAi_AgyrF{sHG- zkRz8bkWm1I!?xxN0rGd)JZd;6ICX-;LA8VTGbo^{8?<}4wlfO-J~ZirEXa{u=NuP+ ztWcf9aT}x{H9%Aa6r1gb7BMK^Ve`;oo#X_H%|z7;9MeGFyvZQ1z`dPONb=D14|brC zYN9du2Q zQ&3de!FIB-vcaV;LD7Wo8KaQiq2&S6GuS-}IM+38Nsv=GsM5l>tFf}7WrBfp49_!0 zp<|AV4D@EOd#JGNYb;KXQ(#nX;P7p#Y+#xHKr=+}8KY1TQ{Dx+8SEY`T;+#egA}M< zVEf%z*>I%sf_eb^Ge#lDLyZkuGuS;+xICHq666#%$_sFDf=sB`pt6VU8KY3GQ{DlP z2?gxG8FLfl6buz6@a<@-Y&f#~gOv}+4c`yWY5+O%4_h`zV9DDce*@&r8=yfRa5#7~El-eB5R?_*S`M<}=mZrV zP(U3#*eGB%gWcl=TkWAK333XFdKcLCftkT=g9Y!+~v!S12Kvbk|;f}FxdH3ROOprG!)ApL{u8KaOkQ}F?n8SEY% zpiyg3K$)em*MQtG)j;VD$PE=vJs0$6uzTF#T*){oK~AAitA_n6C@!iTjHZCxV9&J4 z0Hgps)D4O(dkMb#AS)hj&|m>s;o9VVL2U-RhXVU@#*-j7XfOz*f~=VSL0Sf+z~@l) z2ap?l*snO2f>YENPPOLBhL+VEEDJafh_xQoKvT-iR1lb(!pCASKAM7|l;jqu~l!81cB)O(EIwx2wBwByqS8aUT zaHLc~?+nW}W+9d4G69hrd>-KO_ylVOM$J2%E=_M6TuK$pbU3y#3$0^X5@33R&x3(O ziFrqYwZcK=9*+8^w+%=76;v1mwlNDOx)d`=-{6A`;wM-uJhTX4GiZ9-(30~&SAcyR zv(OaA!UVk=d>$I?zZ(ldCa5prz6ElF^8@KUAO&lf_9@8S;PU_v{3lo|1PWPj%mi7n zl|k_d+cst)<)$SG$~X8tPH=KD_9a*=G#dGEaDuF86)@NXQebl^`vAy<9bD^~auci- zHtP6r?r3`3z|uZJ)`w>sv(UeTJq;j7F5y1GR1UI2&w)3g`E7&CS-N6q2CXi3Do}L-_)B9#BYT9nfI_nV{G7_<#)9n^zCbNw8K>)D_{h z2Px>DAlM?fjakU?V19z?4L-;uZGyGJN4XDd`#`>E`=Dt6a%9b+=>l3e_&h4OPB6^} zg`~L;%lF2&4K3>!q+R&7F$+Cw>^0E6!RG<$3#|pYL2Cl9F({yxH>enZ!eRHJ-vOY2 zYGCJTT$f-CntNkg3yO>RAEbCdj*LB2%Ak0I&m)B+%&9oRT4AEp0rqLlZyQ>cTu@Q~ zdGntmtD)KrK94=@Gn+a<;h?>TQ=l0X)E_iOK#t^b>QvCY!RHad>B=-66p{jS*n~i_ zx#fb~4UhukL%Sx}-{A9j!9KsK02CMUXE;8Af;u-rE`aSMlh7QefCmC9+#UzmzcIQ^ z&{0s7W8qPC+|1E@f@}Aowh1~43soifT%0z6#;En@fUGD#)VV+&Y{KQH?Gtnq8g)eY{G2y6 zxJ*Bw93pU%N$BIDO&2s&xIG?l_8yu)K}X@D{t*sgkO>VFR2V=Cqz|9r-PcjMh zIXx*bRN?kW;Am~$IYCF^q3#Qw$4;9XT-+{LNq`h=aC|HvtHSM3z`nAv3}k}T1vW_w-Dfq+OZ~>%X3&$?U>IpguiRv}%pFwWuJRrM=?`Fwnkw9oX)KTx zN_*IMg4|HuAQJ#Gf%VYW1Z5R&571=T!U;MGjItW+5+FDHbI?%XJjo<<+G%0~$O;bb z!-pEd-fZDs4~h%#0|s+I3idZv9gtJu_ORjj4WMDkQ=r*P2T`Ap@e-EQxnJvMF;jW=S>YQ zMFO%7yeFB2o;nq8&{N^|P~d!aunQEMS})iYKqjmMb;M6H3CTN6S1?oI_Tb5A z;o>_8ip`5wJJ^{uojk&=(ZPQ8P!HIVA9z250;=A~4 zS}NQge>mnjZ3Q_}B!u+?C`CQ~p!x!2!t2JW1B#$D$u4xUMA6c|0=ISVpj$^-!!kO_MZb|hGWyvg%6OIKx39**rnO z17yX+rlJMLD%>7DoLd+{$v#j?gGCpl;IM&=1Sma(ADU|biVGKZ$;P>$*tGbBY3T-q0xpjfcCn`I2Q(EDjS@Kgn3sdP z4>BPFbC`s#I?cGC0WyL2<)QfpG(lAo%Sp!N4M+MOC@_E&JUZBQ!2;w+(8TfqO@)h6 zEL>YbZdf%zX9dWL@TR;C$^~2=8tffRJqI)u7-bDO_A@STXqjptAHy?;NhsIp)CZ#i zF34;&$O_FpY{x)Wwu<$qYMMjdgkQ~M}9NNrf|(+68hfQ8vycV3+ExnJWxQ%#c+EwEpKRX z-XOOCq~LX9U4vo)m&Xc@4~%^WG!-6d6>!}E`Jy^OPljU-lh6|8ssNBTWjLG;&pe>1 zuuFbSDE zm3+`D;PN=aF^TCu$PJ1Mcv3*VnBpM)0~FMcok9yhZUC>-I-sf0s8hhj4~p&s2{JJt zD*_sq6oBI54yOk5@&lR*2NmCNZDw5F;Ih#{g$1O*rDBA5tWR*J zfKt>c0m~XtQ0q3`Fi-~tHM@1wg#(%jii#Z^_8?y@PEce4c{9psx`0~&m&XitX{Vha z1*$AuVIW_$AJAC<3To>^vmQtlfJSIPHa!MKx5g2UKBnajM}id03_vCb9qKbs0tFQJ z3&$0pG-(mRc^zazM}syG$eYuew{Ord08OC@9I6H7EcqQAe?e~OYS5|ynPB4NX`oxc z)};PiOI{eUrKfvSR`;sZA6rfCgFIvAus@JBHT zZE5T(kjminDBxQ2<$x4O`EYJ+oYrvUbc6B=wkRecjzeu5lruOX z>rFsbNdMv34|3#$0G$|~C?=t2j*k;SRtRv(AKI}%RpFym3)iv6X`uF`vJofrpl~?apd!E(#UvzuD5nAB$TJ)}8OuN> zs7kQ1gA_CvXo&DdF$ozvPAE{z;DjuT0R^??8xD)+X$>qh6D%%(ya}q(LB0rJb3Zf} zDct}fJ_FbM+5Il#u9L%eZZ{*a^%JXa(_6Yn1t3I?i2vUCV0sZD5&Ku zI39r0gMm&2Cn(V#p4niO!RZmh!_blqGC?YUs}E$t)dva|AV=PHe0>09!Wp*OLmi-S zFq*@03Y0JMCK$zVM==TUIc6Dv+;E2b=fQm-1*#X=3_*^RxTxp?icLPI$`7ibfa2si zyai;1f(7?iP?B4~pt=MUo39TZH2|fD2JWJ!2@6yeE-Dpp@PHz#>w|m`$PG+Q^#QsW zoRD?83se;ZWzMiPfgZvZLS!^3~5VS%cGqIv+k3Mf5HeW1$>}*M zR{$tBeK_KoiWaCUFq&=Qn+Edc>;_{SP&m{!ZE4WR;Pg1c{nHr~n-is8a3zC$vGap` z3doAEL$etSGB`cXa6Do>0=7bjRUV{Zmw}oH$b_>83l4yM(ZPGV=^RLb?ibD&P;9zf zP}~AC;R)lF1W@J$ufYO&Q#OL54CIT|2h1HnvDtm-wSayGr^gfa<&B^Ovru*gM>og{ zCj;FRp!8tllQxOJUf)r&{E7`+QYq>Q7He=wgj0oY#tn(Hyuk1q!ko(?r`{m zte97zu!ns!qtKqltP8Sd*gUqde`>4%Ss`V@{uvYwrvbw-JdhidYB)I#n3& z0oA}@+5mFHO2(51%+IiSyx>x10=Yp^v4w9R$QRWMonA_HlK zK&2%-*AM12xNH*8PyvPHo5sfrRL`(^Jm5HZaHWB?LZkEpE_aY4ixYa`S4?qF6f~~x%+W<5*z{0}-Qm|};!UT{n<~Vg9 z07VuL*IGtUWPui0D;>^hXn87N^#|mOwTG(&R6uExE!#=LP+H-l>>9SGAUC`e(2oFx zK$&?JG!4z}-&*#^=I69p`|_kk2FKVW_WKh5HQSNl>cRkKu0yS#h91%>)#Z`pv}!8sId^&D0BW zq|6OYe~^O17i1JbadFz|$p^bLY#u&5O3fe>8jV%Blt5Oj-k`kzWWrM?(S=H9*gOh2 zdz~hNtk6Ee84e1Ewhwk5AQKKZO>h7udmT;<=To5cAZ@_ib~vZOrRagC56FaDjlBt= z%=?4gfawazo4OLLA3-MMPB7vCg~N5GlN&&eoWp6@R0Hy+Z~=!fh9hkkWKFmxFbRnsIl4j0fy-kLkNTncAaAPca0r7;c>O>~g?$2((EY}S z2{H~`9u?d%Obj3sq*FN5K?+I()J*s$FbTb3tYMG_d-JQ~4hBsHN3{=}TR|b2IYG9B zV*-;<#i2P1Kvw8*|7_d>a-{4THfyFO4J}(9NFM+xkZxMO0Azv<%gaOg44MiDg%jA1 zfK14mpc%t6fl265W7!8I2QH5_90pB088j6hTKI502D#zX0ecSa2~0v)8od)hjs&lO zWzbZZD6@s*94I8GHpsbvd?C)<3n~aa3OH^%O$G(EwE+(!^OA-mM?a|U0V#NLup_|L zfy?6ndze!>gQkL@ngjbIkQ?eJ$Zr8DP&&NQK;D7NV*$_hgR>Yk6$0gdu&-xc($Laj zU^oF34x!HTCuo9#nrp=&P+SPAondDMdDHuW%o9*#T|eCCAnO2H!7hAg5`(5fp|lQ% z8ORrI2ZR@Z;zIe5i-U#(m&YB>GNy$LnhK119$XS26S@+N9)JSMn5k%jiUXI21=m`} zGLR!x40t%1mNc+bG^ogc6kI>FHNe7w3$oA`6b|-(*waDLz2kw-7tRSxLY+>p56C%i zdE{_MIZX$pNuxV#7N8WhbA!?akR$7v@-}EYfVy%P&bvUdX_dgf1LVkw0Sb3OCWtwe z2k1C}678WwM?eZ>-f#qf+~CjPumTiNPa3y3fMOH8q8OBD6*X8mKqh!@&`cCW2ZwK^c+B|lI}OwGiWLp3ZLQ72AS|$z;X}B z4cv#eGAKE4d3@mPJG>f{qKsPvYe2CX#30)NGJ&&swS$@im&XnEGfbcqRj5_KwGR}V zvkRnS_$M$4-C^t~06B6E$DPJXkQLH*IJbdfbLs_k8;~QJnffMx;(~>B=fP4?nv~nZ zZVrlzA^}+yP?B>wbo2lyx*fP=o2G%>AgIE=8B{(r1eneN#iqfbHUUtY1TUNh%2*K;aPR7{kp2vSRrIjU6CgST#>oP<7z)_`&|4 zu>llWat7?@K)zUgKw$zXpbj~`J^*s$0``LkmxFSa)E$lspp27WAbkcD)D}$l6+l_f zg8g;V1qMxpjmm4-?Lj8w6{!CKx#6zkbOBJByuilZ)Cy9dBfyo&vZUe2mH>qYkbY6AO0P(baNV59+Z z!wRPU0$ork$0fiFD&+$8X7C&arH9`QIvYS%7#v!-K_8UlxC9Q>f~-)@;Wh*%xs407 zzkuT6>cJHPmLL;2oeqIAPN2{QE)P&R6n#+j0V#NWu=W9{C_cbe;{-B6QL%+{3&@1o z544wna#lRksQ^%-jp2T9um_Z)wEnO=fgHKVK>ZBJg!jxh4;X+d6qX>Sd7!*$^@VLQ z$eWulSWN->;w@%4* zfl`#k8qN-o2@DtILO>>Lauoe&2P&i384u3@Wj!?)b~TV2x)WqlKqj;t+Mxgns1N-5 z%m+Z;RQbd90_4pF49X55M_z8)vH+w2yh8w_K&ge>6%>*SE?C5X(!(kyhJ(ruTpm~0 zPBtz9Kvswfa6SRKp))}A2FMC?rjP|%pwb?+7Xjo=6A9LzAYT+55IzD5Y8xjv1yFie z!C~B30E%wa9W33T1mpBT=mf|F*+b3>pbF&+r|LnM13C(f3K}d^7&kYxJZ%tEVL8Jj zbcE6Efq((G#|{oYMz;ex3X19~EL@D68(bDm5SRi|AnfS$0i>XYYf7W{0UZTF*#I_U zkO>_If+-*ciAP)x2pfQ=tArf`Kne_eSlmDgE*l8yu%2NOQa$LxAZox3S}*4qdO$}Z zP{@ZxnrU-G%Vh&W0nRf_LX3x94%kCXIG71C!Oe$-8>FDaK=1|o8784~jHwTF4Y)lF z*rzyN1vyeafX$D2b3@D92?8MkXPATzIXW@ufqcQm=eYQQj>1Oe1eVo|n;VWSXb}7Z zvf^i>lYycEH*}wdj)I}04GROy=7yGr4+3*I&M*lvG<#pLFyQvMz+udoa{x3mn8Naq zX>-GosRx9wuz`Hh7!XGy8#w?HmX$RIzOq&~6P6dd*0hyqAxQ#*CfZJmM*PrIR z13C%^)#tG72ZiM01@ZzQUwmuaUSMbdnnUqBd>RxEav=iGKvr~J(CFbl!z9#uXug6D z*bTx>g$HyLCdx7hoCEoy_kx8B$b_R#I~K?qaC@k5$~sL3xk1Z=n~`~QgUdq(kS}Z>^{_cLDhiU zV+v;!(>YK`>d0_z0VTPI2Xx+m+;HyDlnJ2paE5&y(>jnN?L9clLB7a3AR___>Y%0* z2B5fr?7GoWXf&R}{fcpO154Qi*#{tRvNtW>AZNhs;lQcP1ajm=oe!LMKnhM3$lu^S z!z6U#;PeNefP(DQ(NWka$HDm;WJRrk)(?;)Pd2XGpk%=9!N76*&}>jRh&XU4fV_F4 zL1qugk^31p9WXcG_Sgd6-J_#$P;&u$3P?d&f$9g48@id6K9Dxx_Tb?VI`s8`j>1A2 z2j1-Mugo>DY3ba7!f$f=70Z4(73%ffgvdS*V>VN{O{m^R$kT>^m zUSZq}iY$=_91EE@gKAz29*}~4jOQ*`8E|{B@Ekof1r*eR3LHN`zUbPZ_XOlfPUia; zK)#s5zP)kv0Ud>pvUfOmKmj#VKxPNXkuirhD1c&9hl7Wy0ptc*1NL(uH!S&}JOLEc zx1Dw#kTKx)IKZ~=5XcvTRxMl?K>4C%gZ>#%iduhYi-Hj-*@HJe=_m+Vg>c)0tk|(Z z_YcSoxrY`AsDKI(ZvUoMuoWpBi7cBNjx+_RG=LPuFij5tC73CkWld8-DN0v|>l?_5 z6%B$ZAO*Qh{trNDasj(b(_@e?1VRM%fxKDF;9voY&6?&c1&}w7aELR5^5#c@4E98j zFUl{-^?;laybem$*$vtsK)$d#Tx9_ArUkb)6DXi2YW`sR z4N~AzpnM19h7SiP3V=$O7Qr7*`$73a+Jbu`C@yAyP_6-)aHp}h0pv}{{w^JbLfH*m zd>}WJ80cOBnXvNU9tUj$ZVw5*T~44v%uvsPLlxwUX&+S1fE;|*`VJ04mJSu%$bJ^2J0Q(58mX4J?}z%vE^KFbUZ+-FE=R zrUeH-Qwu2BE3vRQgTkR@g8USa8(uROUjPNv8*VWsP)IV0{@`i{Sy6dFJpxpKxH3(0 z00k6e8=HK!XEkn1l=t%?JP&L0qnfejm_Lc&OvSkqk;O(>G|$0J&k+ zL1zU}=G9=4W;y_JgK>z!3sBZO$sp|jQlQ3MxB#T!1&{Bcc2GD7rf|7}OlWUVjsZFH zjpOtKAUAk$zG_?oDvD*+a9DxrtgHmN08oNCb7Ap zAE)DshL+0{R4iB)G7AYa=Qe;8fOq%_SSc`ycJQi#6ud1^wgD-affrbO?LS~_7Oa}r) zTlhRASTzr~30NsO%5iYGIK60anfO6q4%ypHLhoHXyNm?!TI}8C&(AFXE=JDUo^11ydZS| zm6u3bd6b|g7EIk5N3WBmF9J@f_ zP>~?>2V?^0q1O&Fpr8hAeiX1$P&8S>t?&Gz;m9@yvl$>00vam~Kvpc_KHaoIz)Inu zmIvoC#}^GpngrY|K#n}^G($kPh0jBWE54~rz)GP|WeU45$PNDuG(hvULf4y4evoV7 z^Vq;1<0L8w3Md_}yN)j!T((XS+yXLz!Re}jJjk28TMy0>uu_;PEy2DX1 z6%^E!0n&RwR)jSb7pS%Hd0b%o?FfpjiyC{_-hjek>H@hEkO>t{HyVsv_&h+PnYrMQ zG~n0`vSN9H;u26uIv(n1&~5>(Jmfnx7Zev7FSw3^6qF=b`tU4d7Fy*vkwLWuw4g4a zxeAn`WNcVogRF3VpsT>KkXb0fIrjj_kvv@I8t;OlTTz5#9>|1k1!@hTB)5a9X#*&- zCa~{otOuuR9d2zaSNP?^BT4~p*T0TwEtpw>TJ zRRD6N3irN)y&zv`=y0C|MOMiHnF5f4n~r4*K;B%#W_Tz^z)B%ezK3f$$dNlQ$gqIY zLnG6X0+kj%j|rTs4s8O(h0+d|GawU6158`^7BUO1YusX>14=M_?;T$YSSego7vKs8 znNZQ7{Qwly&zL$UfKn8A!!0PN4R&y>1DP->K+gaalIsr@JOG6Q2k+;mDIgQn95@(2 zA=%a-X8|$+v~Aq1h0o&%2mit40#*tSbuD-=fXau>8@XmBYIuxtP+SkG7!0E(;_9{;AP z0#*tO2W;QJ`0A+t3 zjv^*ddSEom;rI^9n{Eu!M?faTJC$6}2gik((-Tl+$vohS2U+2Kz+3@j!U?AW1Kk!r z4-U>Vjm@C)LH!5US5QDrHqgBQa%7ED_5_eG&Tu3`%^)(YHfLB1%OV3Y&0qPfZ00900kcT5XdDFo^q;7|dj>Kz914j^y3 z9LhETnV`c}<~$Q*f<+AbSx`CIazH@=o?q5#TzcR2eFyBO#wJQTRXKIPzsh9k8T3{+SSGYQo+cRdi`;r6g#?`Co{ z0QI{+@T(r&(BRUxK*|QB;DclJ10f!641Vnha zJz_YOn*u>5h#K&CAKcKu@-o5Ff%PzxP!!Yj08t)pj~*^A#)%*|=$df-IlQ5vCEq}A z4%=ZSA(KOsHYo6LdkAm|H`f_}8~<$g4sB>)DZ3yY!h4uWD7mTjfe8<{M*)|I6RV+) z0;4n!$Ad!~8eEDQ3{AKWGYOqLv}l7A4>x4fyn&7aqw)cclOS(8J6JIY9A*-l!gQ`c z3FHRO8t2Cbpq_gR--d%58d^FM6kE6tGYMTjSQ{YC!wosJ3FJ+c4vtkI6Ltycdw>+I zJJ`mc%){;B!L_O}&j7UWcn#-%kO>zqs0y$jW)c!+ykB6*!|gGFbK&9B20980jUzao z9Rhh%K)DBGf`ntXf({S2#}sac=0XDsG`Ds1>}a>12Q_C zhna*_9akiPym^OhG1DrL6`BfMEugr_Pf$iI*=6_YdFe5zL>6QUgk~CoX7ofYRhM#}WsS0ugRb zrhEe(g+hfN?E64*F^NGlhW{{=P_2_hAt*&vaK$%O8t5o&)S1Au?eK;MmdOg5HXtkf zojeObv01^*aHJPxf_jMHNl>a@aY4NR1hEdF4k~gKDY^#q68dR&wzqDTS2#l?=X|l`h#@_pd|N!McDZ@$PKzGT*07_ z>^~s$02GpY4sM+w&jT9C+2sWCg`xZc_H`f=iVXyJfE;;|afbrP4SV=5GB$vMT26-J z97sXs2ek>HaCmxX!vPr{ZVw)=ZwHry6xc6ey8w#KbqSVdK+%2uP>F&O54Q&kYv{p# zkT-1)aQp{FR@Ve+7LbD1jCl!)-~wchlZ2s;LZLDT?*ov6IsxS=AV+>Z*pL8r1Lvfs zT2OjW+`)1aWJUi4iyffozI>?W0Vv5$;C&LE$j*fq(`mBsC7V6zKARhFL;c=7WM-@BzHxbT$co7ga$i7>T) z1@#TiAf~mTe4*XKwG!mbss-9pKnk`tb{T-O-UN2OgL^>UR8wK+0VSB#3UUuX0rm9I zIs+|`8+f)kgHqH-WdruBptx9XAX5YK#g;?c7(iBpu-i0&GLE6}85S8(imDEf-U14T zIZn$qfV>&P9pE$@R8Hz;a594wEczg?!gH8ONbT@+2T)|~VLQv%0(OH3M>EKq)f*H| zKvoDa7dC*R8+@n-DDz7HV4rq)Lxamq1Dy*XU+6Vue*guw2p4J_a)nP-HE1ezCxqhuh-=$4$niAQSWqcw#^b z79Mxj+ra~&kVfHt}=bauKRt-z@Kf}Ibfp#6cA1I)V- zKnh+S+V=pYAckk=A)gD<3J--GIE+CiR5eJafE3(sd^iDQ#RpDzCjSf43W6#EoQ@y` z%?a`>ta}-SCLG$4Ao7LHV-DBnra+Ja84*5j$NUDD7ZVh9KnfU`@)<zo~G6{1-Nl89WtDbszjw_5iK;fV% z!}S1U#Q_F06Ry3CLS@eXE@*sV^LW7%d?*WKf<}lyJ;(|-0kuDzdl`iuIEosAe6fdJ z=1|K8(4w6OTqhm#8;;~GFjip)#b)C)28S!i^Iy zSb(CNhn*=0tRRJB11PAgA4s==e6fnrEkGI+o1AAHb3xv;Y~hv#Idakk{Sr_(B(jt) zkov;rv4yX_3FOE`xi#FEKp|NVYNG6A6ngDgw?X*}n}-8uFH_G2X@!k)EnEg*1sCLA zfRfxc=h+KDR&3!5IFt{H3%4yC`$2A)RG=aN^2Idf{{@C%H{3jU^n$d)LMaz^edqiJ zm+1kzdwBLT3jJg}m!Jpsg=^DJP&i25;dl)8rho_s$QM7FS`~D_;c%p}5NyI3j$@Ab z4K33O6fD42IJZ5J`NHPG!gJlZ1ndS4mRq2ZbT&}W04aFZm~}zr3uqabhtp(`3338l zjL!KDM}9Zxuz=j~>fq`Ra$ndyYB)X}tiB+vP-x4*5$clP(BgE#q6B1u{h`_mvR~Ld zEZBE8R$P!)Fw{_Be*{XCi#F(O0Vz;#YPbM0frn%7!5UCN>HOi$2Khqtp!yn6bgw$} z`hyk77n}lzUW2UADqvsYoZrB*aDmnYP;5RpG-ZP37tp?D(IcQVxlp@@<2T5gITz$a zK#{fXP(y&i7tpG|9gcY*E989GcY@q7U%)B=l$|dY(py)2! zpnC&k!WPCU4O*a7&E3Yl3Y5Dw9k^OR3Q88pCx8@uZ(Q5}N|Org?-~0pNGmAH7jRgB z6!aJvs(^e^?$kX2WW@yD(@bR`H|Xkca608T90_`$p#m~t{lV%2kRw?*WezohtWXx= zZUsem^#vsnkT)+J-1GsILFyJ<>7W$V{6X#u$O>7f>KDnVeOVrwZsl0J$OADSrb< z!2?cVrY2B=QQE-80Sc)80EGfjWbHk;@Bk=9>2PZ|-32L-KEYWAN|QMZ3Kbwno?*&i zF#E#hv4dkG^9^vSUcmJl6c?)-G}eF|xvS~M15hCbJ|zm|3&As-+8}T4+@QP%Ht}x-@%~(Qc#c}w+CcJsEgYH^Dk^38JuEF_b*5*1nTbLNdmbcvq8Os z7hH%oy z)d~tKAV)ejb{BvGDu!GAP%kK`RljhXgM8uKprrx|hwqGwCV(RA2YU+Ba*!3$8Z1$u zfI6UHlmQBdzNS0_kQ*j&8Xp3clNaUYa4rW~(e^=c4#*1mL%jl^0>l7xfEFkuWf$m6mw?=$?!hquWJRBWjseIGE0}f&fO2;N$91O{AYWLd za2*DjFc;Lc*~=)TaH#77NP!IJCr42B|0q9!HyC8Xqzj4+)vO=YCV--Q?O~S#pl|@6 z69!Ts?ZG`CWWrJh?HW)()i^(70L8@wb^&HkNoy#5hoczehM)k^4p2cF=2WI&^o7l1 z4?AP?1yGeFvxUtGl%kp&r2l~2Al$U-1E@lI!S(ZCJ*XIzRbh7oSy3pU%mRumt)|`t zP!Y6)?P_ByxMKammgth-aOCI%p$1UK`RFu(0hF^?xSlzI>We_VDeO-{ZYZ6g7XdP1 zi{q&T)h}!wCG2OKYC!=d9U`CsN^+qEx(h&#oN};k0>~FDxZ0gSg;=6R1IId00n$A| zzyef8Jvlh%0jOdHABP4C2jMf^`#@G?T~M_Eg~OqyB@aNAy9(#QMo^0SsP%%~2jq*J z0%`^zH+(%fO8}H{VmMQsW`Gim#u^S~kO|oaf-N8u^bRc-fW)SCQxT|)QaHnL3gm{3 z7t~`w>0#lasRg>AQjTRg(|nK#syZBpL0PZ%fC>*N9Jmk7Ish^uhCP)DoE{8*u>Xcy zaR;Q}>Y?QYpz`4iyMYs^?hcec!(j-@I28xvzJRRYVeY>GN^&Zk2OXb)B1_{1dpyV& zGYyn#K)#S{kg(BIw2idw*R#1RzKis}YDUqQZj z;vjtiWdoAp9fcf0!p7j z;3+8MOcJo10tyFXroI4BNEUD?Ic)`dQ-$k3sA7G{AbJ3#z_IZ$11O;0aNKPK)fbJ* z6L@xkLh>tv84Ji4Pn+flfTJ69xE&~W3mxEC3yO+oZ+@QybV;+ z3OjJ+f^ydU07o8>H~X098-N0egJY-TA&?{06}UJ-`J(oL^aN0vyyxV`07~{}*q$!TB>C|;=T!Fd+s&AtnY3LsykGOcX@W!@F+ z>4z4ABFiF%vmNA%4FWO|pj6G^a@7G8)Mq$OF@g%xjdCI!{vb!XHR#xYLUJN=egmkK ztKc$bTm(v!Qd77)KyD}!kPQJ@G2baW0F-ea@NgXZ4Js#PI5^&e;$jJdLJ!Dv= zpzLqKt=e=FWP;KLc1e&4s}>lifWl!v;}Qi>83jK04-`;>8@L!id9!jITiy0GSSAa~=auWRr3MdZ_mBa0z*cAN1?h5k7RR_r!kQ*L1 zohSfhe-#dK=6+D-m7cl6j?JJj3$7*`QqTN1W=;A!#Sl9)Dm-4?%-Jk3aE7- zj2u8kv82;h22clN52vv6Kad*~ZgBnt1$FlUg(IMRA?uW@07_8?JX@L?K;fY9h4T<7 z>$xp3<^WmoopH$qP@;Xn*4s1(6c-A2*o!~`mF=K$0;C|gsY3yj>~C9F$yEd@pC8Qgk}s~cJtGsy1% zDNt^zG7#Ru<#C7o=V2d^0u=@hNstvM6?8v<6v#JCH~>Kkt9 zrqvBCH4YjAoa>l`RxllKP}#u+IWY2pmV%?^9Jb{kHjkOI>*Kh3Ol$wrm$Q+ z*aWgdX$Jc*kb#PqM%X&GQs@Nx&=}@Kr7XSnm~>;H2lJL31r1N z0lhaM1+`9D8I+avZaduhL3#(5#{+J@L-`N16cXj< za2{z~4LU>ISODaUtBx-U40mvOSg@QtcpB_Y1y23u)eSDY0xV{L9J!9EKLO;(2b>cQ z?EpDaehu3pP)Jq_SaN_AxH~l^$n40ofg( zHUBpn%Rp|BtKql>N-$3aWK2Looz1jEz+eZLM+@h7#{;0~)>Gkp4^q&*Kxq%i1U<)s z0M{K{9tPZ^F6AIc3fy783sSJULAe8@;9gUgf*i;fpff`sXekI9ga~{F1$Dy)ebCY{ zp?s#k4Qe~MJXlz@4$T537@0X->zh|M99b9OIDu~+lMw&GS_i8gTpkLX7Ea3^Xek^t zU%@dG6y1FSGH*auxH_>0g3@FU$9Km@P*B^daP9O-%3aAMUvNu4H73DNB0TfvZ9H*I9fphm7wib|rY5_|Du60a8j}J9ADDD7l zudrbPWt>2118xhDf?NYd6;MDKFin~O$~Y42>lw>H8OQ1c&kc|pW*X?IfUMAFVkiVT z5_~l311*J#vR^n`LEbDspeh3Lrsm-(A3!O}glogWnIJbPE@4XtSy9kn`~_si<)()h zK*=6dCRT%jTCRj678DLE6;w(<3L2euH5l*U@(2+qV>$i6@f|^~}c^625;S>Ispfp)_K;{8R!4{^%0+1B~>>m!!1tl1%HS9-0R-k?gJoieqh_%2+F*Snk5|9L5}P<(2wC?$0YRq;M@X`0tb$O!=M5r zQGEjMGmtm43Jh<6qT8%#U4k{ZLb-FW8RSSUAC^u~TvUCKR{_O^dQ({eDABHAS2QgvI#n%oW=c_5fo5?Di=8BfFi3dK`sN79yAWO8Gzg{g=OI( zP$~COONVng$ckPCr8yugRvgL^0F@6@I7E+31Q&x}xZOeC>?u&t0aQgsQ> z1CR+@FGx=T1r&GFmIRPDE4UUnO$Eh;)C%@*AO%+y)Ng>S*mk(T!Dt5;Xbb&PoepvX$#_~f_( z)2gBqycAdKjc&wSXEA$QSH~CLI8o09xw@ z%A1UaEbPBQRy_Hjeg~vrZ)0--D8by|wQ%kM`9gC7yCFycXzLTm3Y&vR1uS=PL5_3= zrAeg*-guCL;spW@*YN~K-0h!?Bpm_llP@*n%6F_Bk2Ky?Bi!E$gPT8PvurT1h4f4gN0;MgWfO>tX z=K`o|=HMtl)BsA=3LG5FAO$@NCMrDZn1nt!mN!_nddDo8KN)NrJN6f_7}nSf%GohhdQl=XBtJ~I`8LQ=_L!}C!3MGU)lo`|tnyC1Nn*n4(>IL-$AYW`~Y-s>BauPTgn2vyIJ?j`AEs!tP zUyxb>GQs3f*9TDhL4Z@z5meGnRI%W41%*TN1nC%%8w8jR6o7Jf1NUhrZ~uqP!1fgnLtUdQF;eU z8Aw6p1B)9VD}FjQE&!#;D{KtSpk|VxmJDYAs2JSE;P3=g>xCZdnP3m9k~oe!?EzV# zq{HuL@YoGejn<1 zAYj1ZF@?K@$?brG0;56$+D072?0fz?*>-U3A2NV<(&GxYU0(o;`g2fAV9wwogO`9L+8gO{L;eO_H^?-uH zMMV{!Q0C?amI_cujE70+fm3LJBgh2MsqzOE6eh|fus>jGZfIHTpxMC9!z6T!vH60A z0f$Eq*ZzZ92NV<>rMIxH2KnOQ2em((JWN7*P5}mr1{@wSJj#baYsU;V1h`Iu0&4jI zWfhPctexr@91J)-Y&fkCb%GqJ`hrUxWJT`-c@sV!(0Uj*25AEhj}Y!nj5!As6dr2b z;CRT?+`v*Dpwa?zL+{}!0U!kv*jG8WgW^KFhFumEP-P5eD?s6Ju+duqu_2#H8&jD0lH6$he_z9<7)<%Zb7456A@JMsEih z0}jaH`CtV)oZ`&Q4J;EsD8}$WO!!~~3J300jXS|s)UZDTSy9Dc)&p`R$PGFM93BgJ z`kFR?9jU{43=|h79~31(;m~_{$^(!UUpOy0m4M{;Rf!_D zdq8pV$2ru&%76oMN5BCEg^f}&95X?YwfKTk3KtKP(5=SJ8$c$!;Ck%T2=b_c-BKyl&2ev5GxC{?S; zaIFBDaCd@+0LY4mPOOcf6eYrWnW+sF4(dy|EkHrtt040LlrLJES|@-4>JR5z#xhWv zlnY_M0rF;pfwT%pL5)*U0VrQg;B`6#a%7?G1GZLBNZx%Qum|MGTBouPQlQMs$$Dre z$eU^oJn5hmC2FYi1?0&0jadgkAql<;;edidpu!LKSdfCI1HunLaUp!TqrupK!{Y~= z1ye4l2+|MW+5*ZK*$+intUCaT3l<&$=5mlP^mw?-K&jeaLAL_r z$j+v94>S!pJUqCxnQnl>K~948HOQN#3uM-SQgyjg(*sa+?*ZNT07~}e6L_^j3c3?y z_JDk`*|GS88aQY1Gj)J+x3mTCdXR!;4;1!*tdL|{cfcH!qPU8f?t`pQp2D5P+}z+Y z^Mlm{kO`-oIvhYISb(-~gG|u8!nO|-l8-;g{s4KCqp7~Y)_}v~3Y+6WP*5vsws36+ zg~R>^*%_czJ;A9v0Tfvq*i)L{g3_e41v@{;4W11$HlT1|INUq|RESMs7d-+>lZHxH z*sp^U%<=%8J0Jz854lVLW!^h%-yAoA@`d~x_Bo(L+r(g40P@8v$JYx$aRI*A0u)(h z1st0}rQFO9T5~`OqMSknK)HJd#~P;sP-!nahtnNo!rBCN8IU(knoev0S;4{ao^c6C zfs6vz1W;u48b}*}g8CUFgCHpDS@7{Vzc`?v@KL3J{V*s!WIhnu0?M15Op`Bw6nJn- z90H|>K(zp_V32|=289P86J9rMm;j0_1gsUkQ1mS3rbM} z!pzN}oTU@MrU!Dvxdx*hpm4Bo&Qkz+vxZ&131r1Z*(dA_AS?ELkhTC>apYjb1CTGk z_jiEOgPsn@8Bj=07qBz{#l_4+>pp-|)C8VG2bY7akZoYU0CGda2dgunaJayDzyOr& zE!Yn?od9JV84qqJP~Mz&K#_wNRJk+W{{SikyJlRQ*E0hDoaxZgHrgEEfN44!o$H`Fp{ zT7cq0*{S`3wgHF73D7kqphPR(z|jY?Vnu-H2~eUnJhV>%ls7pz-!Os-^N9ve_ zp-Mod1>}Z92Wt$JK(!vP(jidBSt#4Ww-98)E(Ki;P)NEnwJ!jrs1~l8!&^ZCr6a&u z12Q4xg8m1P2|F2c4L}OO7uSLv*}%RAWP;NK%{QRP@@6`+K_Aq9;0`_n@}{BM3pPVg zZ0;~nI0B09waxh#KnhYgemOn?1+}~n_e4-!Of68a0a>BSnA!je>JHwUjFUia&VG%kSh#TKW<6F?=c2#2u~sQoa} zU=6z}D9KfQ5I6&J!xP5I2B7E$U*Q4@NnHs(Cy*n{KWLr-S&{E_;DCVvhsOv04yMDP zj3YINs{#}b9SqVvAS+HDEH}_H0Np2~?NkZMn+guBS3wHOHt2_dOmK0U{s9!5GF%@I zfr`OI`4+(spfq{I!RiIbg!Rlv7Jy>2g8PTl0+1C(f7oO|ZrC=#paA5^>xXhLfP7)V z?ss?_C{=4-;JOV`uxo+b7EnO#ZgMgJg@X#`rh^TjDoOSM2PY^+ExVwk0!mRc4=r~9 zwI2f58JR)Nq=_mDTmm2y)(Ob)fZXufX-5F47zE!`12Vy^f#WR5kwqI66+r1>tz%CE zD7u&MY&p0PRLaSp;A{t(Fe^bm0+c3eobwz&Aql?N6;vI_7;yN5A}druM*$QL7EDDA zpv=32!<=amD7rO#IIe0rk?UjsX-|FSx{+K~<8X91qtEkQKEb6dXV% zh#$^c07~{6>`qNxpv-G@gI6Bp$R`s7ML;3B{_xfSP?7^*$OCeNssnF0$PIG^R6c;L z&^z>60aU{LVH0Qu6{H(=A8=cN5^a8gVE`y39~@fX08&uH&d)R*WQD>SHcgO%JOlkD zAU7~H-@O2G!xV0t#)n`lK5({yBJ1%5bq|mgHctN(KrN6j+=)j(O|^qMDO^uLse1Yc z#R;H*I?}j00aS?XV0qjGYQr!Zny{||#YK66vID3PJLOn3!5-8K;#}~3f|C!nDMQV_s6^MSw)4#-_a z50n%bRV_Fq8oL`0iruNJVf|}54M36$nId1 zZt8Aec?p`0(qj@*bvossvV+5858nmG{|}TD0_8#kmxD|wOE8+lrpF}Y@AP7W0!RVp zuEx3tN(zR86L@}s!r?@Mbp^K`lhCn)SplXyK$lv6cDnjNNg>g?f!D9OyWz(c5rw+;L$vs^*~AC zp@{=~eN%UXOKE_s4~HI;P+!wY1H~O29x?ofor*w?RQSWj(9+$|a+yJq0c3^lq2>am z9ULB8*y^1gKTuK-)Ox_#+uYsIGUb8%0gx}YIfn}9fvjNr>jZK`p~3^Mt)RH5n;=jE zvf_Q?;tL=vB-lNhKyFCX^I=~F^5%vQ${rwZ`W~9KK^YVdd;*929w;eHRQbYY0CMC; z1HBg@EA|~+xIlUb2ju1{kT0|kupI$KR^brd#{lHW2|U*ifgC9)vVr|jQ+Gp4uYwE*NWss>+60*$93DIz-c7|I z6HE&@&w(PV{DY@?SW!L9yAVAhU*3k4flnQ|$*UP&j}t*a9iAEZ|(y+}*%3 z6LelNC}%ZRYyg>Hz^QZyl%g7yA8@mRyxH=>=m{t!#h8jFfI<>2@{(aPXHx*296typny7PeuMJ{$eWD`iYlP=aO+@Q0Vvt4u-hDJ1o=Y5 zg1Z%zsux{Q*#mN9+u`3IK#4YnbK&8cpzLq>hpiTrv#Jaa}SRyQ!Xejv~KY31}RvcAhHA$-D?lmP5`Bc9*&nx z>p;=1rovJVvLf|>${mmu`iC1q$FF-Ra0EDS1m$k|26o}*?gp3Q3DOQA1&y!2Ou138cU>f{z0fP&))<3P91#)0CB9 zzJtRffGfA@E~p4nxWP9M!tVrRw!UziLLahSM6i{?OHc zlEShXl>KLdP8rl=5?Xv{T>;3OHK1GJKq0AXz9xet@K;>18PP$}1DAm0Fr&4UNq89>SY02_nTPEexNX5k3~1@+eniV+|;s5{jq zfXXNbjzdhRKxxuSfm;KVU|t{4NdcMAeJK9{DEnXFI@_2H_U0M3K9D0z7fAg8MV5=x zp$FPKI6P+XbT%ypIZ}TP$0krvzZTFq0Sf9J2frQwMK}14KTwKNoWh<6%Kpv=%zHrj z!lr4v04Od@*o~c5fC5Tx4fiQf&YJF^5(5hA>rKrCx}dDb#lbWmTvki49tH*V`V0Cz zAV(@6I&uJH!VwO=gZn_Sslvnl8|2M~4cd1=3K*K51wbLm!J+Kb19GIo2KK)oH*8Rl z{{ph2wrR0|N_|*e0Y8y1O=3#f&}|h zP*67p$W8&dVauTn0U$@R@H{(I4k~F?E^yojDJW;qJOEO_b2xtiD6&*IPc(u`+D4r@ zT#X=auHK+r0E!E~g9{FTQWOj494An83mTMg+y;5`sewWcD4^yXD!rh#gTvzh+lGS; zpai3~g^d}cU|NE;3aGT#XJ&8&rRoLjyO>Ub@}^u2zW^xXtoxwO14=Nxhsq5!c5ry~ zfNpFA#im9B_gPSE<{N04fE>Am`F;ba_SfO?JG>ASP|9bx+d(GG`=Ay9D#X4u);WM; zQ-|A_2~CV;}>09(8hxMG!gz@`MUqEtYH0i@ul z(|!g}1H*wAP3lYH=P6JZWRrdDIiB~EYJ-A zDLBQLdjMoY0Gos(DDyTNYp`pA63o5^<1L`rlx}iPu-L)j@quk&(?d|^)hOW<0!8<% z2?9Q#a9DV#!vNF@TEiC01gb9-RRh?{Knk1CRNW0F<+QSf(&u0hyrE!WjUv z!uf#Q6Mj7=p`b%90-!`|!jW54s$XQ8*~~g;SWZxS^%!fQk>x8Ac(!gDwt|2J9Yd z*lU?m56CDesu*xiVJvQNDKZdL0Vz1>IDdkG0lP;BhmVuf0U3pjDn2ZHU=uE=TYwb& za-8u1q+kx0FrypD3gs`H5{$(SEV%+|2_Oac54tP>DKO!D(+Dy_P_2cNi?O)jNQ;By z6p(@ojMV``2J9X>tjbQF2V@isbpqJ&3J(QrSOP%4$Z61a04ZQ+TFoG8 z!0vH`o8K`Mq`=}1XDG;#*&FmjKnkWD^x2?j!0xeu>*%4j12PJY3U}D0nTi`+u1)|Q z{>CVD`_K^w6$5sU7Cu9!iJ*Xz|G@Hxxwye)4}xFTRVhwTib(AUPm4GISAklR!b$S5Q#D{yi%6*sUqaR9 zc8?I=q{CSt1%gx9SA#-w5rf_z&NGZcZOk)2s2i|*h;Uv#G#}(mqcv>8AS*UKkoMs? z!zk3wRAT@N>M5MUPDP;fpmvAtBq%nE1vFGZ;V_MvfzbhE1^YH;hJ!K+jdEMq7+8uM zTFzatm;*9lmD8dEB?ER33l`=>ouGW7c!jMO6c0$!f_oPzMKyd-d;zjTz^VEJ$dNDD=O4-knV|iFV?Rj2sSj2Hppcw&XpV!7 z0lS9_`xK@^kO?Yp*u_Bsb?Ad~49^)xp_7i?1%?Lf9v|4Q96Sw5)mjl8`XB|YhO&D= z3R0L>C4d6z0Q=LXod;wTE?TVMdIoZ2PJ?m}D8Y0voiYF^=wSbN2o#cnZYmsyKmnEd zK$`=k;LgEC3OWYt9t9lh8$oVJlri8u2FjbQ27(qKM;bd$e*khM_zGZ8S38$+UKyKK>S>s#|a)U+>*Ike!8!l*cfK1rhn6Cgb;R^eQ#tKkC zsjINR1u2-GAh!ji;HP8u1&{&{?hOZPK)G8shW#_h7rQ1HoB=6tY|PrAX21@)=@?{! z>J-jwP@1e^P~HPd)te4Z{9t9k?(v0l+TqurtS7LCX9*~G7YJBQ04aFIxX1ydU=G_c z$7NtE9&pbDnJ_KECSFze6Jigg3^Ol4d+pi0=EEBACMzio0c1ZiXa~D zl?RW2!a+laBLHMYD1(v%$b?v?c?=+LP61ud4GKx+4{WbMX|imA_6krqoMB>U1o>hL zCqEOYoD7ua;n)EV>I;f%KniX*P1^vKi z2j?LsQ0_jc`hfcmD5#qzC>DTBSmSgc!Q6n|;{`iI(_K)a)v4hqV=iuJ=`fJ50EL6a zp*asUK?Mlkl&0mNnpgS>TLMVI<^;tCP}R)ISjk{!!0rL+^MXQhp%N(Z6*sV~Q&3m~ zDklY;9zFo&O#v>Srh0Hd1+Zy@GR|uU=`|onsxr;r0IK!Cw~&LXBqbl7e6Rx0N#JJ~ zg%%$QVgM-+;3{M80J%Z&0+#~Fo9i|x>;XAa>(J~Epqv%MUvX$P$QJ@8Ts2@vK9K$Z za^wcb1qVRhtl?B|x&ew!pN#M{RX%EC4Cs;c`3#s(BeTK^GtwH@K8ED9!-IML5%`1W;^(FIxx2rX1*! z)#8RDK>}(wKw0m;Bj~tMb`J-x-G`b%soH7-7e6Q*QYQ$ifWqN(Q`H0w1CRm_r$wMt zt(?Pg9puQ64SF#kE6yJ5DFBrZQ@BG9gUYClN*%oBpqy3qLG}(fE*y&{fKs&y`!?rI zpmI`U3+G8tT=ZU0EC5--c_`-qC_R*LoL~f{2Ss@S_9&1EPeGUeoM99)bShl{O4Sp1 zFCGLnQ4UHQaBK!8+H3~HGoXMv=U80;iYyD>3kO$%GOzp#p5-7Dx&jnfK#pW?Y83$0 zo8UX;L2l4~z~K&Z!}14GGN6oe=Fp-7P*Hq?ul5kwk@78Er$GviED&%2Ir7cHxeOpj zs&E=IEdj-aiUjK!kOI)M2vC|_&%E{k$eU|8xt(5s6sR?DECfZ?G6Ss^P*7hvm}LM` zkifD1;091xtp+;eqqyP7Tmii;AO-W7mR|r>NiqDXpwrbA3RV8F1%u+E;ed`0$dMY% ziwr>F@P+#v=M)??S9*`UE ze-PLKip~EAk30ZnoEr9t&E24kW9q;f1aiX`1~U(kBVQisQ2;s8gEN%50hIORI(QjC z0k!CZECa}dTZ{}3LE-R$t+Qz}$QLpyJm)|roKw)90LnPK4o-9cW&b@~CQLU$xmyO* zdMa*cncJXm0E*2=jU5L-v1z~^dIXeUE~-u7oey&44h78`P-G<>u44eDNf$mxrV>ze z3r%3Z07@|H8kEm~9C@lS+W=HwSg;fwngfa~?G5ZopekwK0+|j_N$Y*kSpn2L_`xpR zd;wIc$-3}4fnu{gK=cpD7r{(7K7i`Y4;;pa`a$J`f(7q?P%*gQLG2I7k@ZdMK7ita zhg;og0x08H#IQSp!r=&mA`8e3x0!kpKvnY=_6bd`p!A@tz%2$UA09uDX#usPl$uuy zxPkkd0?rZ#LH*4w><>V(nQEZk0J7pF({u(J=|SlU`#w-)O<^$j0g5cX#)=1^62^jSeiNu0)hHXl)dxxs zt0qXF09g^nRG|P$vMDVT1=p>oTKs? z_QRmanyg^N12VzfsoMaQXjM2@Fo7zRLZt;fYrv7Eps)et2F}AXH|T@Av6ew7L-0+im@&i!w;0QOL zV=c%HG7q@Ef=T&%wC`x0sVD#xn>yV3he6?>XyU_Z3^HN<1jRET1-qO?6+wkL z1J9X8P}Xyl4B&DCg+q&j>={rw`Pp%&0VtpxIDa1A1Iqq7B78ic%6+kbngJ-;-)3@a z0LA7F&T^)CprDp<;i~{yu`oci2NYTShjtl&63h>-&xclkYJZsq?x&!JmUn^l6p%OX z9^4iH%9|57Wt~6?=Arf+uB#w7{7$e80lC4idBX=#&icZ+_aLYp^-yO4`+ZQ(I&?wq z0LTRCrV|XH=-$Jo%LM8K8LBVf+68jMrUs)IAUE_LUbFxdl505LI4%IS29;yD8$k+E z4TK9o;o!-XcK}qvL~!siwS%Hta}L{DP+ZLVptS`Q)Mp&GUH}EP2IcoxsyHhbJ zvJ@1!&w{+!@IXcZ6q4*s-3=fGJY4cjpxoVPJb|wr;Soe^`T4%$dO+en*(GG z*gbrB_kbFEt<04l>ty@>*{3qX!cY?{&lO4WO~!kIw514W%T>;fPK{}L1( zKyGkqTEzhBp*&${Z|VZYrd$iB7RZ~A7YNjVtY~xI_yOdGGu-iqz-iJQWg13P}OZlLtX{R-vj2S2!p=%wtfD0V#NJF#iB3E>yS=Gl6Sfy%{_2O+s9JwGt{sqX9zncmcfckn79B&wxf<_OlK5$L} zg=Fpo!2*yK9866IK*iu3&XtUy-r_{*5ME7?2?q{HF9Dfwgt2`BD5wvxZFK~-f;LLc z;nD^9qRv5i3&@);O@#@dTF-%%rwP>OO%$o&XanVoKnE)ikb(fm2@0Ta5a29p0ww#0 zx+)x(L5X($0TmxmP;X^)a{vc5&rzmIP^IQt!}$cHV3LE%4Ui+>9Gsm1E~9v#HiEj7 z9~D&CSAoKzu0VDLC>)+1TCf0AM!E1EVY~wJrrH+10FW;xPEd3JHMAreD<*)3VHpI9 zo&JIHru-I;pP*!a#6jZ-DA68l%oYHZlPT<<96{wIqx=OnCQw{V-=GgV$VBMgp&$iN z&f3G5&|Cm&CaIm_J_ITTFI>>j0lDF7Q{@IwvR}c)d_z~ z1=Rqy`AkAdhYK7eYq&h#aN9UKeb7{3G%aA~Jh;5UrP@GQg=IdI&_ZX{hXOTR9$PrC zH#>jOR0wq3!pV1Vc|*%`1>FRY0>eX_8bDTPuv}$y16d(w!pQ|vkn=!C1Eiq4X~_bR z33E8FIC_52R1j2);8X>0-Z z<}(T1bX>GSp@z!?bY@Z02Tg@W4FUFFAO)KYR9~>qXA(9sI6PK&|5c*DN>;PQqeM;YYSfYM}))4vTMZ}PCGADaI`Q=!l{hP(dI z@&=d569j!g-u%SaWB>}uDeS6;T0pU>8X|BK;xrR`z;*mAV*Gh&@kbf&m_dt{P==J4VOoY z;1tFjkQ-zlaBTp^<~ae&10YAOAxQc%IPJU|*` z0%yBZF31WQ4sO{)%Ntsz9Z)C%`Qo4B#0wx_lyLrT%=)0IFj2aJeHAEGmkH>v0GV*f zX}*FkC^p$@nzn!fO63EKHOLB|1oJl_6Q(py*q~g)<-x)6fT`z$rouw48SDli1tk*< z4uBN2HRmk=xj};Oa8n*AE@V?Uc7d!|r6BhQWW}Mz6CXedELbid%m+CVbO|6RE;0|O z2!KLTxXG!&u!hUy1zW(OqaQ#Q-&=5qA70+TvTA|+9-jG3LNA$SelV)x^4P;AbLjL3 zO@)m*B^=K{-n>wtG6R&NYM2%!fCB0Tm+v7^KrtFj;C&2A_NfO{dq4{6nN}(2fJzwl zb&VT9jx_XPIR=W&f(d#OAUCXY+@Ao7O%^WcreaX`x7fpZ4ipzVKFC^t6tFry7LWx+ zH)oVn2`FdDMetn&`C?mwOa@3nQB(HJ2v|$eYVIi0lEGaQV=#4{|kJ9#8ly4poB+F#{F$P*Ae(El>^-oX;e* z(y=(ewFY!R#ABy&kRz3MaNPwtvf+bb3CIK!r)3Ht6I!?*G**CuTKWk0BakC|E~sw- zDF`@NZ~>%X1-s+H8c;~;S8#m>MV9vggEJrnM-R>4pjHDqtfTYLERX_`DV*7$ki7B1 zXb&jSRyfstu&Uwmn8TrU=rzcZG86cgfHH4eg5m^_g5Qq+96$;{C)+IpIa1^U=S)z7 z`FcS34aka)rn?(JMzA76gDwm=m1h&Y%>fX!eAC zC&-Z<42DlYDawNRr2{CabGXHrO2Mi63I7$aHw)BsKtUbKGJgXos9pGM8hbxzDm;{_ z;4%Z{?j8gE8z3t#9-QBxRRcO=qLXPAD0jL9y@^w(n2)@4o*;lX$eqK0a=ma+*kk#2MPAD zLye&FL4$*x9psBm4aOp%pzb|f8vrUmUT_5*%myj2UBj^+WJODW?jBG;H6H3L0L7*X zSJa`IAaCkk;7A8~v-g3_7my?OGB#XL2W5XwD`!wKn5eG9`396PR!orH0CHs6VV4W4 zppuq-htqUWs@8Ggiv>CI!U6jSpuB0pe80gMlqPu_na+VSugVp+Eg%yl3RNzE-0<45 z)B%+J-*CJ?xDJ#aENZxRgG^|?p!5b5)Q6e+CV(>U9=1)6yFk8B(qP#E@@6-K>I0Ah z9_QKy?HbUnk)em@f?`uXhQAyX)Uyl}?tpx8uPHA8l)IPk9Cq3WN|PEL97jP`tT&MN z0Xg!_p?U*Q38TQV>d+BTs+Qlw767uMy+GFiWP&84{{m3HSi)1*Tm|x`%o*-iAYXKX zwqMO>654dIv;pJ`1NO6wpfo8c)5HB5lqPQ+P*?*BsDMLLH-Jo#;n>Ltip`DkH`qBq zRvb`JR{+JP_~CU2K+#>o@s|mdc_+#UaF&5G4(ms)8=zY6Ueme+b5PD=+uFDs6b@1{ zoby25YzmOA0ENT7L)8psHC!GI+!q*cfReq81YZKkg!Tz4Ye1!(KJ(-a;E-fjZL9|+ zIfVyo|3JQYI6>+M$dRucSvP{JqzRnQ4t9aUL1zMwHYh!mILPb)g+n6Kz7L=T!@((V zcs3}qEGO_OfI{-2fLjB|7jBIW3?LIcxML5k1{GqmZ@AZk6x?MH{Q&aC;X_>qK)x{G zyvlU{gQmhoDHFb=!^<05S`4H+Kng@zHYtF7k;3K61WJ>PN(SsHAQMhZFq!~z!(yhk z1E8SxVeexC)fbG?8Z7$`E^lC|ULf}al%j%});<6!Si> zzX8fwWzL}=Kv}PaEB{b4$eVIC?EIj(s1eXp0ma2n$ASr<@dPGzvgg>~)-ZKoiui=6KdL4dh5g1CA(AKou3JW`F|9g{jm4Vgyt$dU67^%a21s0hA=he55u zM#T;ecaS%G4CHk{j=bnNVFSpK8tegwL5{qr_=R%<$PH5sWE?D;XVU0q5gtJ3n(O4A6zK_stzJJPdL2*DUfF2ISf+J@j;UZWW~A0hXx=Mmaus` zfhv?lOV`J|HP(WF5t#bsWsEN`lEbBl)eIP(*2gny^nwlSg z0;+@~lo=G=3$2i%7=y88@T3!!XckQ)B&V` z{m^U%P?D?Q{=f)oq6Esea2JCjYkh&r8IU9Q9QA+s zI8z#Q{(#(Y$MJvwC`F}kU2vQL@`Z&5ha)H)+$JbQfJ_iL+>rpPH(9uh9VI?$DjZb5 z!J7zb&;n}YEO#nm0Oide>~okvZJ3Md7dRe(!r|ot*(spte#TTB04n7e1azHt zf-;VZ3TGI|n@$315g>1VJmj1JYG5qk;b^J_HCdH7IKP3C{mBpN3qaoVKh)a*YELS# zw=;$4)`1lK4iK^crRo<4s~&)B zULND7#~>@T)`0HGYjANYQ2qf*QQij^J^5V(iYr(ppYy-plSh9aD%Z; z0hA`!uy1MvW!{epQ&@aJzUbZ{X8`g=-=UrZppZPnz1ndGDEn)~uqT2{*wY}>0#Xp# zTx68sMWBGvT*H0}6b{=JR5U=| zTz`0e0jTlcz+rx9E2!?4m*Kh&GNA@EW`F22kEy!ZYpgK2VA>%wYcx zGU5IKnL8jita0it07cdWc26fz|Kg)u4~HShn*|2KUqB{&XuNv?WWopj3a9;`$kJgD zmfT_d>{q;17s~giT0Occ>u_fH~5^K zK`F{n`3C1#P=!)mpmqTi)He?nfKG|^_`nk22F^#D0ge5a8-a}voAsQ0muZ- z<~a?Z*xbOrX-JsS=cXHd1cP+$+wRgi+4541u+ z0j18=9{>udH{9NbKy8>n1q;6WpcM7=fxrQf3G17x7(fA~!J^6p>R%)(nsDs``JxPT zk@0*cArB|j95S+Y2h^K0H}Oe!js6<4l3N8~8>mgIGl%OoC>%-~G;%XwP6BP zZgA#;tmrRL;{gS=1=DH+P~{%L7V3Bi6i}889GswHaJ7Jj3MeFHo3=QB%7+;|3z<)X z9I42_qXJT}&cVt7WJ0L(P6m)8Ww^STK!XDxm6vcggRGd_puz+41w+gB0FWD2a9no= zHF64dC-9_#6f}P@G64nD66WR$p#G)~>m(;ofAgct4UQ9_d@=cfwgO1O^+u-xPy-`@ zoELdgg92vD-$<+LdQlqe2Ns2grnt2XqubzS!B= z(ExHo49|LJP(Lfsv4Q<6C@wrVXoP?qDRgMv2fG?Bj}(shL%%_tV#OEi$sj9M6xjBF zl3YB~Ndr(gv~cM+gFiJBoCV)cHgR{>GG+=d6dJ2mYD9P<> zQ0M^pBKXiA1yII$zpdABJu#joT0Z>r0aCI{EgA}ML zu-kxq;V&TT0Sd|ejK!dtZx0!cw&o?E6eXv^VFmI<>jIe=AgEK z6%1vza7+Oy=$oLR0#cySTr@$zf!*T|r(2^l$OQQ{9DIx=4K0@!Xj_03C^cs_2s*HP zSnwWZa$}HH5L8*fE&(#3WrMs1NWr?s+65pJ4sc9y^kk4#D3tf%Q3aV$F+pkyNWp!_ z#UDTlzHpi!0$HJ`6v4;OSkl0fe?esjNCDr$IS+&!*ga~vo-}$h$SNr6&fzp>ENO7b zI-qq1q@eat+XRpsUhvd7gWX`2!z~Fif#IX{2atl5j&%ow9oRh{aD_AZgG^A+;dBI< zFyVnV3+n|&p|_5n2_g>c9y542ngT)Lpku(}2J%IIfszhLLF%EE8$b%qu)RMV1TsN) z3wr>_gkk{|2atl(O%0&Ns|N@7Zl_R?0;L+xP>>1BAL!ys$-By1m^!d~sBqkEyv!i0 zz$pEP-H*AXf#u2sdkc_)+f3&I96`~|H_@4uQC7iF8njZqq=6;3KpNDW7dm%v0fU|c zyT=FqLr#ksWECzdF>v%Ul{B!NoM2?ab%9anH&fXLkS`qAPaVtxg@dvLYdup*Lrc{M zwLhS6@OE18K^+tq+}4L$KyJ|U;S>gW)A@s<56GLB9rGs0IIw$kaIAAI0x3{TU}0b> zX<(VRL5@M-0;ABx!+RJU9N0ZtI2n#~GRP_gfspgRK;4pSUi4MEW@!QOcY98h{PT#rEkRk1*p1Ek;tV~K(esDxoHYudmd ztI(+Rh4UCFpk5TnOMu+K!~FjNC^l7C_B9rRylFLo=Nu^WE=kaH0V%lJG(|ub30EdFpWKeWl7jXE3+%S(pnFZtv7pFP_15oy7 z3wJsIGC}?Z$9s?)JQbw(fK1rkD+9La}jK;fW&hCLe;n=JxvYe32VXw#exYM>;?RetC-DC4MH;93ugi}e>Y zCh%Qg6bg0T(ns8ID?}QU+Ot zK(#yUS3us}RUoAUa->pI{svG`ui+3lGzsKQ^&W0BP@7}BAS+Z2I5|N_9VKxhsq96Xwq7l0z`1Mk&CGeM4&F5##JIr6uF)fbQgC*~s; zK!w;B&Yg^)^x&vs!S@Cf7Yz#pNB+uch4cZRu9y>UA4zB~5pl-tV66A*b z4LVCeS+B^cZ2~B7@^CC+1}SJXy1~8!6c>vo2;2d=;Ra(~0mzXh9G?%(1=V_jb2yHI zOqeVnBLXsEV)MxWQ0A@ST7UQm$O_vCPGL|$&2*4-0GV*Hv5EoY3kzN+rYYbwslxsW z4aN>jM+fULM|Ab0~*B}p?)NiYXxUKZn~yP&ub zQemG5if-outqM>;2_KyC0F*C$ShAUJfW0||I{_5b&IW>OK;BekoU#EFP#;)~5A6c^ zLQ#eNAJ~cltsfvqsvny10F-(Euw@_W0u_S>Q@FLkjx-S50}6*)rYRpl>7jt#7&LUH zkSM3Zt^f+jDFs>$AYUXNnZcms!0z#eJNwXTkO>-7xYvUm*DtME{UK_Cef)Y$?u9Uuk!8c!;iIk0;eu&-wZCAo|G5u7QY?BDAk`2m!9KQ&ez z0A=1QY@eC(!KM8ij(s3sye&}q0aEbIvF!m!K@Rtl!(Ty76qy_B*Flwg&jW!wAO$ZE zRTY2~?BL=#3`%l_$|iizK#^6lL1zXi9ITlRB!D980o(7!x1btFK81Z7b4i2C%mzUl zkT*ja%Rhi3>jB5&L(QPrly2ef1O?QB13D_8xNu}VG69tR6WDhi1eGw3W)^(cK~^jb z5V`|0LAYso0jL0};JSLK7Zh1CB^)O~0aak2qXLR7??deqKxxu}-J5ASs34WI;F<$c zP;4Na0g8*mhjuLhrO68%9~!5D60PAIj?JLVySYLC49J@uho%~Uyy?Q;a%d$e98_C4 zmxDsG|9~(H$eU(|W($C-q#s-|P6Z%u3jASn2PwGmKuZQ>MPt*s0#FeY!{d2q6R04S z(O^Ffazn!g5eJYrUo+lk042FCY`IKJK;fXWhvy6^9Lf|_4M4tdaq2z*@&yY!yVDC$ zL2ALnz7P}_O%5tNAO$BF^9?`>5;z17f$B{|eGcxmprAf*KxPZ5j9PQ3GR23fIVf&2rI2{#)n8}uDO3&~C}?gOPLsSNg?pu)Ue!RQIdo61aACV*1) z4DKzCpak<#Re^IaC@yA!4qm&!D75QP=>siLoyFI(X+$+*M;lF9iY#Rn4tr2^ zI~&OS0r^7pP}>JkNZ#StbFdy{f}8`#e^5~WQ_x`nS#g;O)K6gdDBybHI02-}LRFy))cQOckI8 zr@{lSryw^}IcQG-Mfc-F^AkWpt--RnaVn^ZqP&Mc4CKxE8`N%q!r^e!)C7f`~cK+ z|H5h92x>Nel>5Qn2MVYn0SyaKn$&B|djP7Ews7oiTo3Z5$_t)-Aa8D+pke{a7vB$V zeE`b-3wS~sb3l$Xo4~mVlsA_+7@YuFv8{Q-0Z`5YZLI;dN{8+dOr&Ie^2X$_XcpnS11 z!JG$V0*}*H1CR+Vf~y!o`JzzQhjR@mE+!PHZUA{Rm1*GyP}Ym#R6YdCdWM2JtlvTD z;pzeNJ0KID9cm~5#YF0J{7P8w;$dg1hpR~YW!i32f1OYf=mr4pc)U&Z2*Pj4bGK}pk~rV z3l;XuAa6Da$oPP~x!kGE0Mr5bz&W!CR8~(^Okw8(1yoaj&=rs)S2QgT06B6F*L}xY zP=c}a;NAi<;Z%eE1&}wbo0d3$qWcD~g%hZc(`cl@z7mvRPBMs20r}!2RM|vLWH2{Uf zAC41;_JC59Vh1}9D9M#D$QghV?ZU$@4WP)9;d;e550oC14R|U*zQ|#a?g2TnnQ5~D zC_NnD&^iQ44;yuKIG=)&+#&_(DIjn9GWiF9!oh$&-wBi+5-ql{T?LuYSYTKKQgFC& z$_G%s_`u(G7}Nqul-tAh0c1jNf&2lGg6yU`&}sV~7F^q!K@F`y(Fnd>AQMVI$gzOj z@Zw;-04Uju@O3*a099(rBHS_{1*Z*^3qaxUl!@UYC}(}(KkWo+a0*&6@T>)eWJ7>L z4k#Q_n$~XsIZ}jE&v7;=(Mtbd&jkh4CIO8tpy;+ZoNoXsil=b$9BKdsl++R)W{`rG z0tFRNK&2nrHv!ZMQea=scoGy)+B4WyK-qsrgUkewf->g=44{U00GB-zsNbDv&A~1J zif*R>9UhP`c$_*7K)x{HVsHVqKn|+NaHfKMQO#g51>^=9r^XAQeBr~h&k59(Q&il+ zasrg>Uq6sn00opVQ+oqQK@I2rgW$%$!VZphP2R2U6x>a)z5og+{>G;cpaf&U`TpQ!P&ml4aQcJ1S-C;O2IL0ELq{4Q6^auRsA_i9 zoWs!pa%4Y)rUJ-{os35sK)&!{zv2jLflQP=!FCmtyJsE{-ot-^QAm}s(%@d~Kj`m{_1H0V)Q~nc5UU-n_$hsu7fE70p6e zFN0!p_5o=hP)PnexWE9EdDn1XWUK@wd%X^xCm;n~0{WnxT0-lY)+K-nkRNO-8$q3* zi5j4_%_R*-Ru-tN0Qn-A>A(U|0WyJiC*u`RG3aK&6#(+)El-Zz69oCg*5@O6U%Y6j?7#S4r=9~zw$K#r{8nAbE1lrMx|a20`)ea`~v6Ce|A zFg7cI%IY6%n$4i$g^$XhqY39Uv`i?F_hBh!5(;msbC5j4=`n|`lPT3eU16h|4d;}D za~h7!R*+KxDfrJ=F+t!Ar^gGfDUHqs>I#YqYuNcf3i1QwEIJxK zQozpCHUZ>@KkTO*L2g*66vAo)Qc(Cn`U6P8X{VV7gwJq#OyIfY7+|2TaM9uqha*Tq zrGg9#YcZ41E~kwNB4;=~d^nt%0u9s^3Z+f>yg_crKA@umQn2-4`v#DLIb184LJZUu z8g+U&0ze85Fo=eL6euyz3=jo{1FwKnsDZkIqqGaV^r1NoEzJr>IUL1ILc&cA8x%nb zxXPI(f&xl;3Wv*~ISog$3zR+aZUVVM)`5c?WW|IBGB4PRnS{(A%hSS4<^J7z;fw}^t z!yV3hAO#l!lq$H3nS@*pbq1K8;q=(SHNojBC?thfaD*P7)8O(VLD_=0m`OI#9T92^f0&1qn% zC{Q=yDrOS8bg1Wo#u-kJH{9xnvOreI8*r}%rHA$fN^3yAc*(TtgZddxj}IKmhvplo zD@@dJU=;?1L(lCqy1mN5rpg**$-Lr_31`5@l{3aI%_a|A%%T*LXwF&C8VH4S*Sg4}Q+K)M8E z#g&6oE`S`lg3HFK9TZs_Dx9l8>0y_F%nFbd0S7Y`bkA^lJm7rRxCNA=WFz=4fxNln zg6tcR2{uj=8gz+nJVFh4-|07yYc)0PDwM@De$ZOj7&wN3%& zE|3*P0TzEiRxli{{Qy#Mg6$qtA;_ENG3-Y`jx1}?5C8>~@WELHhTzQm?ch;RdXUv% z(LX$=;YbyO*&d!^CZWep3qBZ~;q(Y#JJPrllxU4SIG=&SAzMLl1}Gf(nW_yy;qZXN z;}9siFIt#z9Rew6SfI)QQqbIVQbFeor-ugn??#Xt8ufp09Rs;x`2;}=kQ-Q;Iv&V? zf|{GTsTkx7Ar9_~paP^Fbc$v%lTahm6#-dLdf%nP1J zphP=)g2EP%g1$rhE`StRaQ!-11Bq^~&tL@&I%hx%79OhEpmv7SV*}T>gR>0O6+WtJ zu&f6qxlRVNJ$%JXLiZgPfDR4!n80&{@g*qpYA|pt0V$YhAUgr1V3pJK37Tg(J*Kem zIV}TOq5FsPHz*vofNq5=W)ix~cwhr4cdKw*acneDS4cEB;A90Q`{fBDPeAEme$$N! zp!5*KE#L%7FblO^*sp+0=u$8V069|P;35Z5P@C`t9GV19_69uOAQQ?1q;G(d+}gua z5v;ubvC_PLykWT=a zklR$-0Lm99IJp@6Kqknn;kE#!>LUjfAAl5`J9KmcC^o0CpK}7aK~Z4>yC+D&4hQK3 zkR$&&);53~xqwI52~^4j%F1wZg51E$Xs7}*A-1Wv08|V*uqz(|g~LS|2i8_ldf5Iz zS_Bl5TO5l6EY5IxL~t-3&IXk*iY%P#LE*5)KyVHyMWr07DgZ^65BJl9GeL17_=ckv zWJS{htuG)2Vos+nK+34~jGz=1=<34v29#j(0~||03a&CPzo2@C(_;p=n)7r6bp=7I zH|!RN=QOY^dZ7IPlqQcc`hyNw^w`0*o(WWdEL2kA*#b&1FCWOf0hN;v8c%G{KEvsu z!^L!H9VjH#eRy7i;$p3V{t{5m5_ZaM04v}QW&$Z#sN})51EipDg2Ek;8w?NaD*!oi z4ck4Zji8cNCx-nfC@vm0Xo!GKIQ-fGl>G}hZXP@W%6hIlSOP#n-LXN*0c1kG(`*Ki zFBmu;H&ua>y?_JzD^SMionXHL6c=sG>l#2Q>Ib_q6DUO~Dw*)T28F{$1D!P>1^%E_ z!Jtx($CC*ZS&cG0>>QwwoW4P!0HmP(Q1by$Y%bwG!Bh^)7j|dZ%Rm9u)L?W2RO8q< zc|HIo`yXuo8kd7|x6Br{c_2q_NYHBlDfn}EIfEG}UvLL7-vFnm2VAc~R%8VztpR!S zhU4Q0pnQ?Sv9P%w6q3?0oc}D)$nOC~miwV?AGFSJdK_ST%yb{*3)vd38c;zx zdxHH3kRx3V%~b$7(udo)3FOE|=>u#jAQJ*ESWN&~F_F370hHtvIBqcJgRD?_!@UQT zCMPVA{{hOpDThiQfP&hD?`k7R!9|%peAht%weNvc45)dKeaNQ(q+kVC{vl9`D%9oS z*bYijHxguKfP%WW`9uP!jM~G`)Km#79~6Cfwt-AocfjBVC|~qCwSNF*90jf)hnhj< zq+9?OKPVik0xVQO-n`_re*!3X7jXI=E(N7(%L11qute+(8OT7s$wff_fL@#0?-f2yi|-xCs>9_7QxiLHXjOf}8`$4ZE7A zGJulY5e_cK&7gpiU&DO{q@eqPlmW;WQB6Aqtj=(H?BSa4^a7N#44?2X1eMhf3)Fc) z3U)S5FaTK*BKXkhHAsP;59eA?dgxnVyagQ8hZ_w*-dw|GcxVc!FgLN_{Q$yZ{OZAC6QfP~|PJvFWIBfSm`F>8X~Ol3@g}Hzkd0wa z0eLe!Kz0Hs*(Wi-JOGM|9UOhkpvt{aH-%+B$b^OuS~Va?wt?1{fm$G-xmj=#^oRWd zDADGD`X$9oLcxcs3_yk02Cl1z=73^T;{b;es4(|dQ0)K}q~{KnD1e$MYuGKCFMvW) z=L)+MC{-VxAoB<0%_odYK7i7s2e<2?eo%^1f57n{WW`MbnLnTev+Gck0I0^XV7cx% z0o3@H4Pkc##l>3(s|b(@-y0t%fa0wnC<|j z2Y#nb52Vg;dhl>0H-Rd(g;F9MeW19Qs32_tN^%`dfe%3S#UA!Ojq5=LsgVi$K9Dz8 zeUP&N#YHSr#RE|8R^a4o1T}guYBca}0$H*0fZ_>|6)z5+J^%_R(EcA#L#t5!3BM00 zHs=TEw19lE_V6Ci;JAkm`__Y?a&n>E6Lw{gf`$XCJ)n^Md~l`!sGR)38Sk_L6x0@L z*iM1sqC`MO0~8lFj7JuL5)2FbibGq$c~gV^Iw(!%AF%%bvSL!x+XJBVP{DPAX+9`T z8m!?w49XW(52ScNCa4|uIRLU^1^arY)gW&wP2gDr^5)$IvTs0f5q_wC11M*G;1xay z3hG341&;3^6Q(i9-vODR$5Yo`elK$F|Q$SYy zI(XCoe8Rr<;2uzGQ0)o(XOIvNo_w90Eo6Mg<=B#ULw+ zHz-U2`J(txX#gnWyy1H9462eos=r~s3Nqoq1C0=n6+TUYA3)864{Uo5f|>^xWfj=( zgX(V23$h15Ca5^?WB_HH26nDSP%DU0=?D8RkRvNDsJ#HCYVXEE0Z^*$;Z$;70LuRI zI$Vt)H@t3;E&zqYQKzj3K)Kt6eU~FB<7^aR;8+U^>UIaYEufI(IlOKIsHZlCTlLU3 zQ0CPf&=OkKnn5?H8FtPP{Mhgu>};=@_YCNK#{d$gFFw&7wSzp1|VO2 z;P-X}wMZ8V{9sE3S#hO7W(vp+lbp&gfHF=BN0<|+q)oJ(!g2zXvrcYMQUC>1K3$-?|cYqw}79g(x zvO=1PArKUs3<3+CLG6b`y$>8$L9w}Pg2En98|IB;&j-6RoE|^eMUTt?MV8hXwq%eA zB@6~VAa9;(>`ed_gEj1@8c%|$+n?qQ$V1S*0Yr7gIW zK)xtV5MclXwIfqL11K)eaGYQ~07|q5CG0OiZg5MGUjPcI$A_F5K&|38T=`6(RxzWd z3XcG&Al)h;y8>i||DpN?N@qAd&ag~521^o`FXfj844@WDC*P;72s-*m79)Ed;%VSNHBNSz97CxAjy zxcR9AD0lmCzipfgY97d^u$O@x`PD#p1t>iT99q2qR916vH#e;Uc~gdkCjjKgRRV4f zp!UOVCbtQoA+IwWubuvZ(xmhj&Yz%gXikth0!ngaO&0_}MX>|tCr3~jbx=`(g9+rw z$qTeOK#uG?d{hCH>|e0YZvwRj1+9*79|GlzD+Y!-AU9|qTCo9?v-a>?H-Q=$g=!w0 zMIaLvILMs7R#^@%XqVQ333MWVb zOWp$^4UhtTXVHZq6Hag{G=bc3QECb|7s!eU42oa{`A(hzLM)sf9qf$Go**}f?BP@e zSusPvZ3@VQ-%f|X3R?Ii4uT!2ox#rUIH7^1@PWJyNC97C>j#h(5q!CaKneu zR=jv1vje2yDASDxAS+zh|2KMr!a+2L8>HY!yMf>tkb=)m8w`Y5Kt1=e!#*HiC~)u^ zgWNFlfFfAIv!)ub0v*=JP9Se8YASF@f~;6zpq>IU!KZ261W-8maCUKx2bv90Ne%pcBIF z2y(+N0e!H78wc|fKngP01DXOsj#Qt(>jqNb93UqFGC`C13RuAf4ueBM0xAlP>LT3U zAO%|)6m&oe{xiYy$a0)rXVYX+i@_Zh*WF z$dNCZrh^sS;Z$#`17$tAFPy(XvDtLN>IJ(alhEs?<^}RBpq|@1gkuDhh^b3GDTtfLc_b@&^>%qAvSC zsIzc-m~gs+67gUez8Wd=|{ z%{=0*7l0lvqFm`|@A~7iAl`dqHure1eJz zpCgk{igUpQ3l>g~GaTO?9}B1`IBKro04Z=;%%FDw6b>t#CNW5}aC)e49c0WAP*G5n zzQeu&&?4gXS#k4?*EjTOi*8imbDZU0?+%EDxM=K_Mxx z!nqZcyT1y^Tmf0(bEq}|WW@{~EwF+>(*|x?P;@scVVy$z*1yD$y;r{N}4swIS z3J$P>5(d2$AQMuYCM^KPW)H`~Mo?^iRJ_B!3Y2knd{6`{c+I#&0hFpEI6a%TfD()y z3;QKdY_iCa3+v~Lisgp;-KhuDo}{wabyyD!?>itkcHF3f@|X8 zqXH@lg8DI>AO$RaAJq4N6o3wvFk<2Kn7}^a&}mSj)vDpt2j%XH1Il0pPY%vc07Z8K zM{Dy=kOCtE?q{IrZup=&0~C_!O-sNETDXJ{fzm^u&>ptOAO%$dRy`mEUl}JEfJ~_1 zwmJ+_P-v^deh3tj4IiX9Knji=+yGkda?=I@6@^087d#*ZEUOqCBtYKuIW#i? zPF69DxCZO`6kLlb6P<1eeZLi~GkS|oGaQK2!^{E64u!5sbxdH~D z?9a9Zv`1P&QEmqpBPgx@Hcj{- z$HM7xhx5rnkOD`e6>Om{6B<}b8?-|N9hro-G<65KvT%BEaPv5e3aTg^RJp+kQgEbm zgK`PT1p7mCFMxdUfuF&t98?TyJ>a|xvcj3c6s*9VsYd~1g$~!zrV5Z7G%UCufzsq$ z1Fa5_3Hu!Xffa1w*yRXvgQA%O=UY%fO?NQc0#dNvY3l`$2?d-Voj?i>nhUUh1_$*5 zxicUI`wlKQ098phIPV{<0b9WVR&Zodf#DiZNV*@Y+Mvb)nyxB7Gz;v=7hKt(QtrQk zI#_{y)6Nf8ESw&5IPM&L4JrmzI(XKDLUO|a#XX=>?rUQWSiuvvLrgD0Rv6siT>?tg z>pmz?04b1n%60&m5W_#kaT%x>l(b-<2}-ox3}z{y3T3t9gbA7~oE|+KxlSMj7iBG2 zeuKQ(E+G2`h0m$39@2sg6b1c_OErC304rmrN>wbN^&|S z>{mbv7!=I{KyKh;I^_V0%?<1)zzPyAQdqn}0o8m#P6rf{22A-IKxy&-`?`aZKq09a z!3R>%;*=nA1LVkc2WKUK3NaCm>&?BOd?ELP%M6rgUwlvjD_F%C(x3%yCM{uJ1!^8B z&0t>v@3RwC#C_DfuC~oR)068*+YYr2r ztUjpvfztvMS*;8PUrvVg_I^3>IAO#C$*RXMdOz5AWpaOEkQ>G;oK(V=jJ>Ch_ z5=#{E-~ua{XP_tpQeb{4y8xtsgZuCyP;@J5`f#&@9GUH)305F{xHAA$^M(k#aeN4B zCaL*wwt~`RgM+pRC{0>8b%Pb8usl4J4Jz$rAMmUPWt7j5ig``z8$ed<;qzw#DPYudU@Zs5<|+rPJ0NeW zG*=dYLNbQi=g?eG%Un8y9i-sME(aA6kQG-P^8$2OI6bbgU3c6Fif$nd_M;#xjwBd? z6+AuIWB{s~e{h){Is(ewss&uapn#ffAmalHs2hw`UD|Kv2ts>lG*@izg_o07ceGrX>qNv8lij-&6$(2W1bif|jxg zG7msO&2VI911P9jSl2RxilBvB792Z3rG3W%Rj>kPr^g#WCS2f(Jp?jAQ0)o(YmkBq z0ZMB?R;+Dq0V}ZKkYxhp3r4dg+#Dcpg07GR<%<3Fy$qfvv7K(a9n7-3#!~LUvQN< zPiSyCq@WH~uAS+t9wU|H(4D}kg*MqE>)gZeE6b_z;HhlmU<`1|g9$pQy zLhSvHP(V#MpbA#d?DSXx6p}R@u}z?m zRFrwbo&-v?Z3fC6AQQG8ECDMhVPC}vDuMzn9&n|A+^|bQbpps22N~x%fV|1U8^8=w za8T<7+a6Fzwlk=H0HsL*=HdgOH0i_gff3XyX4KQ+0x4)IOVIlPQjpG6{s5$40;f|m zNWnpcEo}QhWz-4>$rw<-yRoUbz?KEHfa>+3ub}7_ZV|i=@!7?@Bw!T-a%A$MEd`*QCBPX2RxnZ8gwGt5sux{Qy#sQ?LZ`X{ zaK*}@dI(he2b%h@gB46#Af*CI_7j-aO#l^Q792rNn?RMj;sef;AUEVqum>x+b1?q^ zDC@NdzG4Jry+Vx|t~sDY`+tFU0mzY_O>@8s9&kTyng%Kcb#L%SffTrXkk0_6hb7Ll z7k~<}Ib3`PLH*4@r407XAYasMP&xyO3(!g6pvXGI)_e%0Kv87}%W{w}oD}5dfUIC; znppr!)m!-19b5^DZp8>bu!7JHA}pYAsAYO70O}q5;dtg)04izK3^)%uPH1px|6m7J zu%79E0jT}(h5O1u&`6G=`W+5;kRwYEsLOyH$-r~~tiXmd^e`wK0;L~toCYbFDIlW* z3aBkkJsUs)mBJE!2&CYm>L1PtAV-!3SU7+jDdhBm0TfUZ`1qKXfZ9y29kKuy*h?sBIWpuDMM!MzZaJ4nHi zOaYMxAS?DAoYkPu!s+3_ah-V|D8cBQVEX|w;bwydSizHnZ4*G{ zPf%PeF3^1fimc6z9bg3=9QT|+xqG8Z0>@sEf)xc?UqI>Mk8{rjPJ)H-6`Z?ZVE{_@7R=`kfU=$e&t67Q)+;pR z;N$@XRK0^7Sb^Tbz6YR!bO!s;rfyJV8CY=ZffQte?(KAB68hZK09Me$t=|j^hejg> zjv$bNOa&7UP(Uqo&Q?$bg#+&t#s*O1U&)1?0Ti3159Ap@ZfIq$U;w!xgj;|Kq~N0L z4wiGEfLeV))&dlgs~BfK07X^<`?^L@dU&XNfdizVrF(ks{lOtn z<^>IT%?J772!mz~C?wy5j#C1S4f0qWhA3bVxBx1v^A5;4fJ|Uu-p2qcVJf&(nLyp@ zLRAkAkb)zt7f77}g+m+jIs;HM=>{Lep*f&%(CFbR23fI5Kp(6?^59Vg(D;J|_v^+J zpk(jZ!J`E7MePB_4jxA)pGrz%31K590DnLsG-C99~2H{6Ey#Td~v_=?FUer ze88i82vm0$s`hY#6u4{xjjcK|33)TF5&)GC5u8y@6F_CP%o}b;kQM6|D6xRNdDLk! z=&oN6A9l{BR#0iLZ@?`EicJPX-3X8y;+d9$6{v9ZI!g$uD11~b;Y=j&)ZUOb& zA2dx6a03lsay)SaDVV76hT{P!sQUwS8bFRb%yg3hRO1|AyUz&fm@BGqu!9u1Y)sIb z0!lF5OyvQfCdwandneF9O`z)*&ZnTDp8P-{0^~?@r^yMRG`WUNp=m0(LW$rE1Noxr zf(%%J1fzcfC>(xpeQvA;wWBm*_`iX&-l+!~H$ZNf&$I}vAVkoG=@iHW#V2eUpxS>* zf${=SWa%@{Zve%n3>O14NP(b?1@BFeFM1}Zq<~CFJv4CwD8Zazo9GPcXKhsW-~uUd zDV`v+1C+bno#sCP^>Jc&el&slIE@-h*w%sEP^X{>R>0Vt^#Ih3s^Qqt1RB6pG-BZB z1G!;RfSd)W5c}!82dtolQ@nXSsGL++;MfPsdZ7v?KR~IP$2t1}sBM3PkFyapR?MiJ z!QKZ7s2LlSEIY8O}tI8&(Qfwt!6d+_(g+-~{K%gP^wDM5!;F${+~iVI=p@&%ys;R>65 z6L>hr)u{tWkTkQ-PRYJnAKGWQgKQgsM-z#&ko7IdrO`VMkKyYy091f5aPT|s2Ze)D3Hx7=BUd@7eF3>aw(0Q& zkQ+2u{GC7w6qOuUCxX)Co(=M#3yy@soE8aKvT%B^u%B{#0xBP*J2*fJT$Tlx)_?+P z17qI@P~Nm*aX$p=H5aOW;f@FSBKv?cSixb(q6Scka$v7z0u6B#DnH=%0L4XBfRX~p zgewP2zzPJ|FC7AncrTO};l2z~Fz11e56F=M&RY#YvB|@6=paZzqsk0!K9Ch<3Fa0c zZ|WVYe*mhIV%V9RK-FTRxdzKuP%oWf3^364bTIh?AXpzbhGodR+shf`JnDA_OJ76K~>v{=Dr3{tSL zK>Z9z!OW)32B665V840@6q^fWIoLr8T6QMraexA9f8$*RP)M#|``-vE%mwv$IGjKx zFf0@}0}3eNL)8YL*j&R_b9fIZy7f}nKZ6wPNU#Je5Iquf05p)>z&(@cFsSdZVZ*@# zita1{Edx+7DD2b*RxpR-9@9KfXHYMJqXHBcTLfetfZgD@zX6nSdbn-C3NEUsurCJ1 zMfC;s9#BaBX5420O7;mHs)sGs2xVYoEF#uE@?BPmr26aF_D%7w) z1x41T4H{qtJco7!fTA1J6$WMAhuSQhS3z-6JHa3XvaS<%hZ3sxY(8p;S7r~Rld!tnuQ#pwds10V%U4sT@urH3z^49p+}jAj0vwL z6|jO9uKkRl3Z+r*0ow^sg2_@aQUED<|Uz8kB1}nJ8$nX)A{Z+W$90XO(f$~q-{Xq&`6jW?L z;qbe0?gx;92iyis;I5pS1Lp~lBkLGs6+j7Qhtq-vP|G}pU6>KnF;~>IVDA7aDBPf= z0P@8gr=1NTUxaX{GJzCqRQ$kl71Rn^w?Qog6b}0i z28BKRj!Z)SOshWFv2c2La4$df8#GX(aD?MMD8XzkPz5Wv=Tu|>imVE*+C!lB!$;Kz z+{vIM=VqYX1MKviB0PgKq<V8q( zf?X064jm8VQ$Qif>9}(ODC@o9N_7G$IH;Avq6D^LgIWhj!Rv#$3ZSC+0+&w{sEP7W zw}%s?fF*x}0t3j3wT!D6K*`>NdpXkqP|IBB2nPem7i|TqU0Z^hf z;NWZo4Gt*EXRuEKnJ|+<$pe(4l$vT4K%)m=INO^*3O>q8uv&pavV4N(3s5-J9BN(w z8dPuLKGg^sRR5^l!2wnf`oJUrWWr&mNe&)PS_&FOl~drH0CaZeawqKsIXc;D`Zvb7q5j0mv7ePJ6%#Sh&QUL2Y|S*#dS=P>P!OL3s(t4eJj# zOaP^*DI8pmpkDJuxe!5JkQHkc%(j5MdAITL1xSMNcLFI;l*{301NowJg0uuEcV|0o zN&vO(4R{VWf~H6&O0NJbV5zyF;Q=zi!s(#`D6%H-9Bu-Yau-!Ea0!8|Sd?G^R>0Ae zWdO=qF`VUxKpoP9(i3KX0;P)JT> zFa;~o+Q5AX zl=X@W6gWWP@a)hA1yEU?!~L}p)O7!-Ccy_*;J-jh2joqkLvuHPO1TAGDThI&T%l?W zdpF36It6vGf?bV;3ZQ_>;eOo&>iavYHLw?f0xB~=?F1+! zgwKrS69ghSJUqDUot(f{@NjT~te6xaWC2pJ%1QJgNWl-TlqTl{MTLv1Ke+fn3Y;4> zzzRH=CN_ZF@Ppl($t^)qVWU(Ar$l3GgUjp<`UxNtPCG#qWUvc2fvh;FJcpADq+n-* zz6MCan}at5gZ;@*x3*HfUMBr;Wh>-D0k3412Unz=^##3e*!Bws9?cv15)sCgVG0(g3#uv2S8SYu%Bi02U#J@!s-a} zMVEsW3#%BD(4j-k0wNI{9-w||K!Tz|qk0DiNI}c$2PP7%VoWO!io5tQUuiJy;LT~i z%V43w*Vp{?f#n3gHO+4iSaa|nYyPZYTfqN_`4@xz1O8vl42=#30wOJJicSjzv|6|w zoj(XTu?QV>aS#k*5qs!5K`^UD#?k$SU=52xqKARd6c%+wuLVM@SacMv%T z5Wdi2;^>ta{~N-8SR5P!G(>n^ z#Twukq9E$U8mt%^AsWRRp%^wnG_5u2VAu}PBG$Nt;XgzhS`!*048;0aQx`^7h%IQ% zXpGt*wxKo0G5UenuGW0V7zOcjtR;@I3F5a{%OA!zh(BSiS{S!M{9S8}WBdd0KdtqS z2@(<S@O3m7Raq)f6Z8ZLT*d@+s5h_a(mj}GuCj(A8G&CSfe3-ru{Qxt%v-T_OFe# z8S;17e<;>XkblPhYhm36`FHGp9P4k$|6>3Du%1JKrGv4lK|_J3gPEz(LqVj2wW%>f zL8gP9si{LjrGvAnX@i0u2ai(o1qCw>zD3O+6zn(zlv)H7-8h66wHPS+afm3j1}KJc zh%IU@P>kb{P->f?n8qQssBME{9*2xl`vt`^4!K3`9~A326qGsyl-f9y7IhdX^>L^u zbp|L+<4{}FS)eqJLqn-+g3>Y$twUWqls0teICbAp+R>qRsQZV~0S?2Y9tGu79LA4& z9F#9{m?rfmDBt2Rf7IKc{D{Lcsc(VuD-P>NeFv03ao8sHKT!U~VgIO~L4}FaF=>K= z3KysIqX`ZwLY%Hi6BAUVINcvjY*10+^h}zxKt+qw`_ZHWDn^{XNs}L_SaJG4n#`c; z#2J`0MM2ezGx*UI2h||X(4?ses!^QbkES-LCUHh4O_@W>sBPlR zO`82cZ5L<$quC7Vhd2w9<|wG2;w*kN$3guPXKB*h1oc~-<&Wkzs6XPYOq#bq{S{~R zqj?9^KXKM3&3~Z&i?jaGdDRx@ZH;@X(BMnU@&*XBoS z9JDWSZB1I6pnZ#L`=hlD+K;$)Caqhb{fcY%qjd+gKXL6%TK_=%7uWtr>lt*IxDO_6 zP|)GxKKy8dgN_jQ(WH$DI#S%nA8l;VQQ|(Cv}u8k7We5#n-1t0ai2}v{6NQw`~0KL z47yI-7n8Oq=z4Kqeze6wH;DUc($)msDDLZzwl?S{ao(F`}U)42Xu?L?R0#l!sgfP;Y$4{P$l1Oq7^_QwYs z43u~{lMgL0(Bk2KeCU9I5f5+j;Rgm*Jp7LjGZ;GY2qqsY9mg3&A<^~Wb0j27`|CZAehw2DXj@u>qwn|O4SPd_l)#iRfDG=uRW9>e4_3dW~+ zj31wIFuufNntV3F_!f`(W+yUcHJhsW_9~l4Qv44D?!Gwv| zG5Lam2^X*P;|mTZLcFfY7ZXgRc-Kl zzRY0i#2c7=MZwgIH~8@t2h$+l(B!KLrcu1%kFPeEChY%p8Io0)uTf!QkF?8mnb zm~G^&5s{ASP1d8CO=HDkm759{IJ17 ziLW#H(E4VFoKGn1b!u*~9{{rK4d%ObwH$ZvWH~Ieq`(OP3AOB}?U=m~SB5P!nj=$IrRnZmZvF-t)D3EM%(A_3VH_J@vD0`gDT8J(I06jL}9ow@{+pKv%j zO%hN|;Y@UzC7}L)2x9Gx!-n5OV1I^Pm7f5O}7{7Aqug>RwrD*@{#djVE=@l(S=FS zF-1Vpg-g)+iGZVvkf3XdV4{nZp!*ZSMi(VP&lI7BE?R=#PlOJ-7zz5O2tRbO67+u} z%;@SQ7?>iW=;|dH{6xgjHApZtMKsYhN-+G1XrpVAU}TEeLf0(8=qF+aU5f-`Q^X&- zRtd&G5odI35==~yP;~1OOnxHa=r&0(HAOPfZI)pA6Uj!mMS__rQVZQy31&Z$I_S1Z zFgHc|q1!IO{3p_k?uP^mQ)Cp~PYD)3k#TgtBv_gvo9KQ^u>6T^qx&Pl$`rYU?ym%^ zpU53_|0GzOBLC3+mtg%9c}5Q=p~e&iMGr2a<|hh{9zsH`DT;|6QbO%d6dOI1ggR4{ z7J6t2bw5!$=wT$(o1*;C!%C?Ci87<7lhDKz6-7@kp~+8F96f`CrlzPSdPWINf1=vx znItqbMQx#HmeA}cY6m@wgyyEGKlH2;n*T(d(W^;lVTy*LSC`P@CmN1klZ2M0XeN5i z5?cO5v(amj(8?68g14&XNulJ?^i;*pXeR*{v@- zAAVxs=p!V2G{rE{M@snk6T?OyCE=4PMhktkgik*)I_P60d^W}Sp^ugD`6tGVzD~jy zQ%n?ny@W46F>&+_626*Zn&=xPeEo@Oqi>S%%@nhRzFESzpO_u=EfT()V*b##O8EX0 zb4I@=;fE;}ihfY(2y;kPN) z5B+utzkg!Q=zmD~V~UNU|0&_mPi!3hFA0B5u}$>9CH(z~ZKMAq;h!mX3;kaS|9)b3 z(EpS0-xT|Y{=bC(Ke1;FU=m?Wbx;i85@CMo;20nz!kX%s7$7CW{?xHCKuLr%)oEdX zmI(J#r-K1TBD|^24+E@3_@6p620Dodrn)EwdWi@>b#V*~5)n;xO$>|@5r6917?>m? znd-JMFiS-GsoTN8A`#hC_lJR1BJxk&8H1Wc6jMDEgSteNpL#e3O%hQ}^-K(!C8GY+ zvoUCqh-RwS!k|?m+E2X>25l12P4#{lv`a+)sW)TrArZq=AI0EPBF0aB9D^^3n5OzB z2Hz4ff9l&9{7A$y)o)?&D-r9beg}g;iP)z4KMejQV*k{iF@#CfF*QIjgiF-{FU}A`rsQc5v#tW9(20sk367_!?%oyq<8kicQ80sY& z{4~TdG)OcwH8e3aN;LdwXk%!SXk=>G!q6u5O@12T7&b{XH8nCZY?f&H)5ylKMWUIhQ47OXiDo~IIvBP|G&eQ+Vc0Iw{HM{3 z;fF*EQ)3jvPl*;kjd2XWBwCspn;3pewESsoWB4P{%G9`p;jcuipT->w|0G(Q8vii- zmuUUdc*Y1OvBuN{#Rx93=BEjc5kg|EsfmdZQey2-6B{Fx#5z-x7Di}^bw5oy7-1yV zo0|ME!b+_FX)V#O9`^Ka8vroBuSOF{(*yVQPkARF~M|rx}h>lf;&$W+q0>5?lT>voUIs*vizb zg;A@-RzJ-;7_~`kZEE(zs9j>~pJp>g9}?S`nxhzfN^JAf9LMNOVp~&l6Qgg5ZGW2E z82w0WXKLQU=vQL9pXMEm{v@_HHUDAsFR}ek^BH59#1EzxD8_J!AAVZk7$YQpG_^1> zMoRqn)569WCGnG~MGIrJ#7{phIv8Ulem1rEVT_gd`KQHSniv};e*I}_V{DT6&D64mv037`pOzhrEfT+*TK+J$O8oxQa>lqO@rS7uig8`y zkDpdJ#!V7`np&9{H%t8a)5^xUMdB}0s}{zs5`X=)>R{X^@wchf594-;zkgcI7=K9o zV``0J{3-FzPiq|GFNuFmtxb%-CI0)63*%pj|9)C`F#ePH-_-ht@xR3X zKdom>V3J@=Yfwz!l3;$;;FusJ!J5{Xm>?y={;aVvK}mu$t!ZI`mIU{+rh^Ga61-{6 z4->2;_@6a1COSz7rnM+0dPxXBYjI2rk`PU6O-ziE5P#O%n3yCXnbx*2F-t=FS=+(H zA_>{F_J@g867tX58IzhM6w^8sle#37pLIAUO_ESe>r70VC87STvoUFrgl1aT!lYFa z+RwTUCT)_?P3wM`v`a$&SvOwHS62{MZ9Fs3en5Ok6Cf|}Uf7aWW{7Aww zt#4uSD+%joeFu|2N!X_KKTQ55VgIb3F@;IeF>Qik3YVnwvk8tVLXxg&6BARUB;B7) zY)ny-^h}$yFhxt!``M&}DMpgMX_FtOSV{Uno6MN%BpH}CMKRS&GWgjP$J8Ln(6p(E zsZo;Q&!#q}CP_x7O}RtMrfrhUO`H8NZI@*Jv)PR4ha?Nr<|wA0 zk}Q5U$1(kqWNF&m#PnN|<LS{cPF6%p$3| zY0DpGR!Pl&wwy7mNorx*3dO80sm0G$IA%?fTAH>pF>998@@Fd>vldCMOk1@uYn9aM zXR8ioZIW7>w)$b#E~)j;Rx@TFlG>QIMlt)8)aGYv9J4P;ZB1L7n0-rX`?Ix;*^i`l zrmb6;{Yq;0vvmivKS}LPTmLZom(>1e>lt&Hqz|TTP|V?yKKyKhV~&vY(X@?;Ia1Qc zpKWZ+QIbBHwrOFGmh|aon-1m}NuN#I{4mE#`uwxajJZzI7t^*V=6XqAezwIiH%R(w z+SbI}DCz6Zwl?M_N#9J{wlFtK`u4MJ2Xl+0@1|{km|G=%|JioNye8>~X*(42x}+aJ z+u@iuN&0Ep&cwV~($AmmY|L9E{W5LW!n{?|ub=HYn72v#ZQAaKdAp?FKikcie@Oac z+8)LHQ_`QG?QzV%B>gpQZ({x}>F>|>Hs(K){+YIKVg4)W-_Q0P%>N|)H*NpJ{9n@l zpY3NXV3J`>KcHB^CByvufMbD>3~Tzq!~!W9_U8v13zTFy(+@2y(30VPe&}F85ip8g7jGv!zEWRXTntnF1_?C?M^Rtb` zk7O*<&n+x|C1d^k+`-~cGPddG9~S?Tv44J^v4lz1G5vyK374$%^9zn8Lb9&u7ZXdQ zWZj=%Y%Ecd^-RCCutZDN`}w7VB}THo>6agtSjqZ7zsy+bBpaB1MX}UNHu(7!$I>9# z(DbW`rBSls&#yL?Cdo#oUt3t3B^&+x+QHHy+1T{!4@;|Lf(ZUKXx$ftW4ptb+^`<|5 zSYajC|NJpyrIXym^e2jyUUHM4KXI%KlAD_TG_f*DZu;}5jg?7qGt-|ftjv;|{ruU% z$|AYB>CYclR>{qO{+zL@Np4~K3&pA~xy8?4I95%PTblkdv1*pw^5-ubs}{+vOn2e{8H#l0TXLX8C2 zNd9X2*TmW=`RmWWHr6J|-%S6uur^En_VaHCYm4OXrhk7}TP1)0`FF;;Ci#cyKNRb_ zfS8pZ_{ow@LnO`tOHzyX4)<2T}nf`BK{VVz3&;K2)|0Mr6{r|)I zU-JK-|7UDqQeezrP-@^(V1B{i)F7n5n!%XVAf>?mg0ZPVNr5v1v=vN&`vudX1|tRD z4CY4-Rto$tn3)=#6a+I^lp4JhgkP{YH3lh&X0RqTMk$EDU~OtlQjpAGThy4PApL^v zP-BsTYzF(I#wrE*7wk+;O$v$`97;`H3d%1yoSG&nsAg~`HO*2`f5F+*v`9fSgKJUK zDh2HqT!)%ADd=W!KWf^gp#OrKsritCVFr&<^C<=67d%eQmlRAhc$1oMDVV?DZEAj` zV41pZ(4rPCMei3vhgysjeKUj~wOA?ozYu0>by5t>5K(INQVf0};?x?X7@8rP z)EcE2{z9~=HAyitLu^rNmSXe^u|uszim@5uk6Nn~<6np~wKXXwW=JTtbtxvlkZ@|7 zq?no^nbbB*G5v*PQ`;iN%nYeTZL1WsUq~Hl+oYJAA^oUrmty`4X{Po=iiH_6O6{i< zi(kk%wO>*!&5%uMzol6ILbj>>kz!?r+@khZiq$XV4z+($tj&;r)c#Ac{)IeK2a{4` zhJsQDms0Z!1*Z-nrPd6^qz);i_7{px9ZE`_8A^*fw3NDEC>`oBQtHi6e$-*5)c-=6 zsnbbmVup%RrZR$)?nwg=ts547x_6xN`okdD>Gt?h- zRw>PYq0ZFRq_i+YL#eAvY4HmUr>;p#OEWZ+x@IXYf1%mbwMc1YhSs94RZ6R0XdUX> zq_j3e`%%{}rS&hgnYs@tZOqV7>OQ5k`Gt;C_a&vR8M;Z`x0JTO&~55|q_i_bZ&CLv zrQI*|4t0N0+MA*OsQZ`F{ula8Jxt06GYph^xRejSFmUP-Qa+ktnA9VseEfxBQ;(AJ z$qb`KJzC1AUl<+gF;YI8Vf?7aO8NW?W2Rmw<%=06O1)mnmtUAT^#&sjZ(h; z!nCP3N%>}m*`nSo<=ZdJ4)qo(-_0<8)LW%||AjeIUz75~3=5^cF6GBBES&l#DL>7y zOzNAZ{QQMwQ{N)xml;-z`c^5weqnW}ZAb_1{wd{=&AY|B>>~47)}BuatkkushWMN%?Pv{iFV0%Ku;3GfiMpVa#+; zn!u&P{L;Z`f{+Spreo3sDHZmYj!hGkR5&x87ERDn;eP3KXo8UnZ>IC3305lnFP)ht zI;jX|x+qQbQW1XX;xsWxMKsejX=0R$_)FKOiAgGwnQn_FW~oTObUQS$NJTc&{n5lK z75SI$Op}^a6f-@PCUvPOzw~gLG)YA@(=%z(EEV;ao=uY$sc2?;Et<4SMf;`Kp-G!m zbThplP1>cR|I(Xj@*x$&OdqAmr&Nqz`Z!I#q+*)sn>6{Biup_5rpb>~EHnKUO@5_f z{nGEyCZHUN!2kkKxqn>s`JYLrzt|Ju9<;JQ>0YgUj{Z!QBw8H z3|cfrOV#^j(4i?ts=k@QkEU3u`o9cjn(Cw)m>Hrp)k`(_Wr)+%Al1;!(4?tRs^Kp~ zo2DkIMrMXBnwq5={W9#()FRc`% z&3~EBG^sG zZTHK(L$g1r?aj=8H2as@{+IbobC}c*W)>*T;Zi^RvcPGMkowWg!lXG;>c?LeHqB8| zKbcvyXpWZp>6b-^<`}7;%`AR2$4dSD%VMUvPU;skOO)n%sb79s;xso%{c2`u(%dNZ z>n}^2<|e7%%q&|pH%tBY%d$gri`4ICmOq+XrGEcqIn%r*^@o`iO7ptZAHS?{nm0-P zX=Y{8yjkkcUsg8FTcrLnvue@2RqC%_RvntRN&RhR^`m*a)Zf3XW}1IU{bOd0()?5E zpI_EE&A+7nHM2Hp{w?+IFKe6TKT`jhS+{8ZEA`(m>kiHTr2aRv{?Ytj>i=KXGc91! zV9aVzTEL~j{Hnoefsh7kR%6lvDGl~ljZF)bG&r-G7A?@y;C|I~Xn~OiZ&vf81y&mT zubP<_I%x=IwJ0t0(hz>t;t21fQEDiNnolT1tX=rA3En2inL;F?N zp+%cCbhEl2E!w4_|Eim5@gWVvtRAJsr!9w`ut!&C0BKiPq}7_WFlmL9R{N`kO)HeNIrRhzWdX03j-YM0jfSF4#;AJW>GwMJ?6DXq<~);O)cq_s6`ZPMynTH9Z( zZCd?EYiHKFMXO(F?S8fH(CSZGd$ZO*TK!9F|Eu*(YnZeTW^GVf!=-)r)dr_ELfS{O zHYTl+(mwubW78TX?UPxX7Om0JKK*Lbp*2R@XR|gxT4SYs{?%rtwNBa>v$iO$_0qol zYKzm_AnmJJTa(sCXGt*z3&|7ttax+d+1 zSv!>0b!k6-wZm!MB<-hJJCoMU(tiGGXVbbx+Ap(qEn2rq`}M0`ht_SgBkiAA`xdQ#rTzQWzC-Ij zY5&dI|7iU$?f9`Sk&(4MIAs*$0z0Na?V@KG?KDNryB0(4q}m zI^3@h9ok@|!<&8h(FQ9W{?~_@Hah7DW*<@7=%pk4`iRrUARW={qe&a1bi`jDZQ7Wm zBbj|{(Z(zt>DR{&Z7kA}%|8BUW0j8l>*GwDnsgMiPbh8b(oueW!fDea9o6iUNt`RNbXz6;tzI14dk*;s{kc z8<>4XX{(oR@arp1TZ42%v#%y?jnWN&eYI(8l5S-7wMARAbfaHiJG8Y(H#YnFqpelC z@vpBlZEMm^%)X(ttxGrg^$n+OlXO$FZzgS3OV zbF*(h+O|tK|MhLA?T2&=v+pQvKc!pz`i|4~OS+}mcayf?(k*{|w`uz$-OB8Hi?+Yg zt$uy)(DqNdwb}O{ZU3cP|N1`D4ko?E><3Caxb&J|KXBS1q}Q7LFlmRBUi<5ZO*@qI zI0f{SwP|mX{>|)fi}q&e-+uk= z(B2~byV>6#?XA+k|N1-Az9#*L**}!_b?HBT{ljVBB>kt^Ka=*&(trN?XVbn#`Y*G8 zE!wwA|Mlx%hxTpKf1CaL(Y{^!?_d9B+J8v@WA-1V{ipOlzy9O2|C0XK?7vC-Z|Q%3 z{kLiVBmJM*{}%0krT_c&zeD>!>Hp3C|7ia&{r|83GaX3^;R`79Y?u;C{n&_<)fCZw~Y016Bt7ZH2X;X|7YbaS{LAKGQ0|Aw3S z@F4@k93JJvrwokW@Hij7WMG=Zn|%0|f%zNW=EIK+EOYo4AAV(E{f6)G;ZFv(IsA_g z|1z+D!_Rz#$}r6r4{88MWpp zCZCWpYJa2Hd_u{nGe>Fh2`!`UH%f<37#a2EC_g@7Wz_#hnfauX(Zn1T<&$1Uli#Q~ zpA0gZnxmS0GRkQB8`b8MNk%hs)E1x2GMfEH?eNJWqq#Zik55(^&3~iLe5%Q4VUC9K zsV<|%Z#0}wO)^@VqnUhameKMzn$4#c8LiCGT6}7i(dsu^hfi%XTAQQ&_|z_=^>4J9 zPaiVcn4_b7`jpY;H#*LzFBxsk(M>*m%V_%>-R9GejCSVeEk6CqX!jev!>2zP?ak4D zeEOHs{x|x}XPAr+<`^iS;W9q_#=!ZEknzzR!{jqk#>d|nHlI;4KAB^*_>7kE={H7) z&lnk>%`tv_#>)8o8)N3PPR18=Oq9=h8DD;5;(Rv9_-c-6^4Tck>u*e(&n6k)%rRSh zHp}?-8?(b_i;VB)m_I&SWqkjQIrF(D<*v*Wc)YB{_*)=#{b{gGhbjbVa#<3sxrlZ=IPhI++OOx+q`t zG7*03;(Rg4L^Rhm`C^ob_*>WJi%BMuxo(RuW|>I8bvt~q$V4{R{qe;r6ZyC9%$J%> z6mvb4FLjwHzx8mwG|5CY*E9LjEEDy&p3RpQnP}#EExxqMMEkAR;Y*uLbaTBQU)p7& z|JIxN@*xw$Tp#7jr%a6B`Z!;{WMZ1@n|%3}iTPXK=F5*vEOY%9Uw&m`{nqdB(6|J$<#47K=}%nsq@{uDOB9SENkc-v%~cQ8M++4O)Cf%hdaA z(BUgaroOqskFQvn`o9fkzUpKem>Z&e)yp*aZHV*LAk)y?(B!L8rr~cxo3AFBM&^bs zzM5qk{Wk3I)gsf_-0;U&t4!nHhBIGlGEK~lP`=h>n*27x`PwAY)ZEDAYqLz#-$piH zTV$G<8@2e_D%0$@QHQT>GR@76etd10Y5v=2=Ie({3v*+Xub(n4ejDR_{gP>EZfx@P zTc+i2W1Fu(GOf&wTYUYMY4zKTnfa!Z*~Huw<(pn+ zli#K|-wZOFnwy$@Gs4G8Zyz$-n46<~`;^({w>i$YFPUx4%}u_2%WV7G+~(Vl%y#DHEx!HAZ1>x|!?!<~ z?aj@9eEXN#{PwO z>9<9P?--e%%`JX>$IATt+hXRsPUaVLOO)?=nO}Ze;(RyA{AzA#^4%!&>u*b&?Mimy;ki-lWd1j|{_*`^=KtT;Ge2OmV9aY!e!ykH z{I0?Ifsh4jUSskDDGT;@jm-~~EI9L;7C+Fk;C|P1_<@lHZ(j4`2UZsR@0yt(I#~$j zwJ1OIvJigP;`}hkLNu>6`C*iW_`BBThe;Nad2NdyW?4wTYdid~$U-)+{qe&p3;B2L z%#WHZ6!SWiA9YzMzw2;*G|56WuQU14EDQB_oz0IHS!m{UEq=7hLi=6U;YXV+bo06& zKiXxX|E`<)@gWPtydLGpr!0)$^*BGiWMP`uoBa5eh55VQ=EsjLEc5ynKYnFl{jTru z<4+d0dHs(c|FW=u*U$Wf$zxej;V*{%&IP6D3Q}yh)3n zXjyu{n{@bzk)?0m@VhC_PlGH&^QI<0jj{}XH?{d` zl4WGxw8c-eETi8|JN&fBGB$7e3nr_^yamcH zxU8DrEpUDzWYwCtF!_a)Rr|Yz%`cR!I`bASexYU6{ch3W7e-dSd5a&vu(IlZx0v~* zlhwq$CCV?otR}x(;`}nmYHHrnjLZGQd8YG>ZM z#jjsk?S8lJ@as=jd-K*me*Md8|GV|fZyvq#7QfN5KK*Xf;WtLsXY)2ceq&{Q{@rHgw@%g<^R_6z^|HSFZj1BVAnU7n zTa({LSzmv*wfSw5_07C(i{EBh-+s64@Y^EmyLsCmzpb*q|86_;yC&<0c{`Nfby+`t zx5N3}B|oew(-Z@w;8t@89iaet*dN zW8NO+_ou8szuV*d{*v|AyuHcqZ&`nTx3~HIBkP}e`xd`{W&QizzQgZ7S^v%3|M>kc z>;LceGk;*RVaz|E{DI4c`TYUs4?;Gq`3I9fNZGKzKiK?1$%Zrk(BcnTHr($I9sXcs z!<&Ej@dqm#{`ZHOKRVe6<{wf1=w&1P{)qF(ARE#AqsbqmY{cImZT^^KBbk3}@y9G1 z>G#JDe=M?*%|HJ5W0j5k`{T@?nrsyFPbh!tvQd72!uiuA8`b=i$)9G~sJ}ni{ArPm zX8x(gpH|suzdv>O(S&*%-e+AZ`Ky<0 z@cS#yUxREz^RFg_JN&iCHa7qI?Xf|;`}qnZfgG1n_ph0MAF|t+|3>-uDZ9<@-#Gui zWVbc{ZSwD1cH7^-ZT|hpZfE|x#lK(K?SB96@b6D{d-LBv{{72t|NHmMf0*nK=6_KB z!)1T?{RihiLiR`VKPLZ?vOoU*WAh&+`;+;f7XQ(*KmGpG;Xg+9XY)Tl{$pi-{{3g> zzfSfS^S>zn^|HVG{)_Y9Ap5KNUz7hv*SiNKa>B>vVZ>mXY;>B_Am2)E&jL4{`LD` zhyQJ|f1CgN@xNX6@8ADs{(s2+WBwoI|EKIfzyIU>|C0UJ{J+WnZ`pr;|F`-7Bm1BE z{}%s$W&ivAzr+7O+5gS||M>qe`~UC%GczzdFcvVVFmO9Ce_(K75O!cKU`%0yjFa|q_7Ou2xGB>YytZd#%c%o59};V%?^qM94buR4$2=mT$m<1 zs1|UhFwJ&Q|G?S8wAewjfNKfUY6tBPTt}ETJLnd0KVjPKp#OoJh54|9VF8Z{^Jxd; z4?Hf+mmN$CcvF~fJD7jqZDD@wU|GPog!#3D^#{Hq%%2@>3;3Tf|8}tdz|X?M>z&YAmYLr>=;@gn!+0G82&-Dg*DkRvOsJJYqn$b2eBip#g4HB;!jws9pgWU zv#>QgCKgDjuys2oe~@rto9vicAeq88+cEuvWDDD3$IJq$C2Xr5vp+~3VcYDOTOj>} zZMS3o2Wb}e!;XaoGAit+9g9E6xUgS#EG>{tVZZHI{z0~d{jp*^*Vu6YZr?=DO4=OI4!A?^PR8u&kou+?KZQ)FInpvQ> zgfrV|_6M~ioW)La3)G)*Ry)oApw7b8?6j~zLxro`Y4HaQ7p}=pOA9npxMn*o|Df5z zwb*H8fz}eP)lREFXdU6&?6kH(`w7=>r}ZDSS-1~7Z7k4H;XduO`GbxN_hqN81-dER zx1F|s&~4#4Z?p5;0_!JyyPe;E zux8;u?EJC7Muq>h^XCsXF8r6BzZTf0@ZWa+{=v3||FQGW0=p&rubqE?usg#4+4*mQ z{S*G*&i_Byvj{M|Fcvzf2ynYFe{^sW5O!fLbW9PDc47bM*dn0p!dd9FL_phx`=iql z0b>{5Lgyy})-L=Xomm8(T?7kVR0O?Ugg?5t2nM@|7P_VgM!SfAbZrq#c9AS}TOye4 zBK^_rh+wgcY@z!T!D<)zkM1l&%`S?C9x6iJF3KN0T!bdOs1|yr2+ej;|LEBwwAe+n z&})g%Y8UN~UPpvByXY2rKM~sPqW{sGMfk9bVWE$T@M#z0k3KHKmt9N?eN%*QyO@9U zZ4rL#Vp-_7MEJFf^+&%W!k=Ai3;mx6|8}we=+7d;?CMw;pd!NU>ijXlMMT)uwJX+rsd< zafJ9<`^DQCn-n;dwEk=_NII9kLeH}PSe|p932)RRliGi&)6bR&tY^<+>x@slnxW&h z|9Dn_7t2Zq=ahh7qG~He5@iEL{x@rNH44mWTp*Eb3o;IDF319qxkAt8UwXaZv*sFZ z<^O$a7@8C~xIX*8D!uSa)gi3(WD?TW4%YT0!Pz@nzmO=O$r?^j3dMqIGSAMAKJyxq@eLbIz3@8wJIDx+4JLECT;IH^$!bvGXyPdK=xzXk0|yQ;I5sjm9cprB zIePRM+l(hqBn6Ow1Q=*&Xc!n6SXfv%I5-3Z1Y~4naBy-8&NX3X0t03c%?t*ttgLKo zZ0zjp92^{6TwJ`oyo!p7uO^5wfM8x=`#AcF{q4Un+*@bG}R zal?iU1_lNJ?OS-jKtM!7MnS{C!oepdqoSiE$HQ+PC~(2J5eyian3|fJnwp!NTUuJ$ z+SoWaI=Z^LT3T3cdKwuZ0Z3p&Li)mm3k-~mfq{V&CrnVVtONxzIJj9bgIYpDLQYOj zLqkJINGL`9g3d9wd5#R8G~cvLB=MgX67SHR6#NCQ1l5D zxR4YF4`O%#K%BtB!eU}#@`*=6LV|;X1350RDm<|)cY)d^<12ycWlXm?E^GU&7x267 z=(i+&#bdt@E?Webh0lmvXsf}}eOT$MBct*Ho)i3RN0q)hCfb9U$CbW1KJ)-HPbz(N zJZJ}Io>pRvG1q_<8~`y5 zctF}1VpWVa_CVBvm>gi|G{mYnoRI83v1ro?9lP#}kG4eU#&utRw6y|8rFGv<+Wteg zt^0A(&IrAE-7g>Qx}i5oQsh&6+QfeeA3#i@RuEG_f0CrggccCf0K{Z!12F?YOdYV= z0uVE!86-LZ#B2d8*Z^X7fwf%#F|UCQ`v795fYk~ZOp+9N0A?D1m}yNQ69Nn-DYQIr zt(+LQMf{^{?Zo&sVt-v50u$zlaUM%Ij53k%T&}C6amo0~MD?nsN010slo4{PYLHWy zx2E;SxObFmVa{ z8^%MKr!%^~@RZ)+oOi_H&=;=D+AbXIofG9Yu)8swSiV+S>yq)6i|Tbjk6~8nxK$mH zQ<%MN!YYsR0q%2eaQ4BhIwA40v9_V%me(ebRrO3-)-bCYlb5i6V-(8rehIRwrEA3x zm{sll6XkBOcdS^es&mQsilNpLp=TW6M5`#{;#QR)udsOAj7=bmR?gs>3A0E;5@gYY zTUnPt7A;hS|dI#4Wm_;36ix%AK`UJ9QJ(G4Z%%aA$Gwk0OWipOcCdeOXOxptC)F#L; zU^(j0Qm{a>_*iX&kO+(5p~kd3lHVD<0z_Om*k^4_zr(KKm?@wrlW}Z*p}fM%ZAD6Tcknj^LI*y@j2d!*L8tryG@ zkv{6SX=09v^jWu8&4-#CBqzx8TyT5U+~fpiUI8-=1SiPz+;EF(nQ-ld>9XF;$G3Kv zZR^cle4WFr3$#|v!)#V>n(|l2g{3n%PVlqkD}QxVOz;3P3zfe*I$DFvy<+9Bjt4Uf zK%%9}UmX+Gz|3;6TClcCklHA)wrY^tXfU%DWUe#VgnBR&thN!PHUexyGf1=$%xqOQ zb>hwIky`Gy4(!2Ws{wU14XP-T;dBDPSfz zUCaS7dk%n-$Py59IXGRc>AS+-`WGy^1;kW72vV>Iq~JGL^azN#+z}*t2E@DtHunlh zZ6#Rk9k6HuC~ZCgiSmF&-+)9j8I=|6CBA@|(%=O72gJ+=i?Z}zVP|~>HjD?%1e+kz ze}%nuCId*D3`jH+Y?um&nGa^_fS7N=YE3|DkAZz*0}^cod(#CZY6o_&4~WSGW`=;6 zc3_KRz)Y}VDIjf$UjS}=a-(2Xi`-K8%@eD($Zd3gJF)tU+(Gw`6KhQ5FS;L^ z_-g^^q?jk{%wH$|TEL)b!SaNi`P;-_3nmC8fSBJW{#x+B1kC&~@z;U`Wgn2}&xyYl z2p9ygJz;151!C%{fJA>!{I%eMss@Pp2h0R(`#bU1f)7$)bN_)1lL0IE53*PRtbkz> zNCDVf#z|@mHD>g!c>L&w#WF}b_3I5*zJ9`VTW@ai?Hgw6`rj(Q^RT|vx99P1&{EWo z${#&!l=?p}{-j}ktM{w&y%py7`oBN^TVe0je`)a-4cl40X^U@Wm_6(Nz4&W}?YI8F z$^UQI|LbQ|`N3h=)&FGi&kj4j2`!+EuL3S4SXI6{G6sQ}>>#E;n8~T~)lpFqTrzO0 ze06;20%r1pL=yr)|-PZTUY_%AiHC^~xF6|59d^gMC$VugvKuZM_G>mC{7)HZ_EJ^-r)i#`E~J_f6O0n(N~0TfVgzzV=td;p0$ffalKG4sKm z{{b?$3as`INYoi@E`#T*=B5o`CX45*W~awsCI^VQ1MD&$5OY3Qn}Fx5W~TpOQ4!Bq z&4;qV0VM%4p%`qj3`lJw*pUh#=3}s^3W&K3Y=Q9%ZQc8c^*w|x@}Q)Fh^ zzw0l4A`|I;Z(`*Wxts3aCe}ZZ&$Rv5-CrURx%qI1xsCe4( zO_-db>S+--2~<^rE4maAvjbeJ=YW_j;2NL=#QY5|_G>`Q%!i;Fpk>k(_Er~gmDU3i zy$!B~rhrAkZLB#UX2U`i1$&7lAZ97JidX|u>krnp1;oq*E7${4FmnM&?Gcb@K3Mb& zi0KbD_XhV_=u@ zfS9)*fP5h``3gJhJ1|oQEDAPP1hnWjVtq<6}J|N~- zaLpY8QqT@IH)iq_&WoT*(e$KrQQ;ZI#m81a>&A__InuX}Z7XblqGIbAVALt1>UmP* z(i9WbW{;4dsVS=SPiSuHS|S_k87?$!ifX23)TL=#RCC>9g37O`*1A71tlOhB@%Yb) z)1Ro;dd3UQU{P!IObD7GqSoq}xT&Z_?)~xKpn7wm`-{R76}4W^l%Sa@YI8l)H}&W! zpFd&zsr!ulzg5Vl1chau~6Qse+ zyh*#q|Ba0^eTHs&>W)@HSwV*%+%q#(kN>2gR zvZa$i)vyhSSvCn&IfF&ZC;eKmK@V(h1;|`|u(nFD0x+`*Yywz8HP{Vc(V9uW7F2~%i=KW*~!6v3H(>n6Wd(a`joH0gbc zjid|T#Lr8#PI_IN{Cx@QO#gS2e=pH~>2+(;wkJYAT|hfZ*j74zoBUUW{iI{n1UVHB zPN!FWCl+&PI!&6OvgCt?&A-VSPoB=Ol=&u>`P^(}n-!ox>u@`)4& z$pF47tWO705J`iR)E|KVlHC=d2<4Y>A?;X-2h@1FoT#EK+HZC5c30w zxd|*P5E3LWVgwd705OG{R)O3LV*0g!m<1rFM>~i)0mMAe24Zf2FnJsQBwPS9*_0ap zBzyod-?05_{F5LM8YC~m0A?D1m2q5|PT@*-U=Eg*A2Oe3(`01$Id8z|HZK+G;k_=1>1O!*-9 zf|!0RAm#-S(}Nwv`~YGWFoT!^5kc}IeP9I!Am$seXaI=$pc$0p3P4OIHc%p%0AfC4 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�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 z z16a%9daxFU7_j#rfwc&VgJOTi4v;MmkASsk=z-$JqY&hnpz*^WOz*>%g zwIm(`YcT_B*#XwV+y~ZD1lF?QF~}A+d9ap0U@eSiz*-W)S|o}=wlvQKYdHtj((nwV zrOgDaWz9~I!w#MWYsm*|X#i_+o&(nM46G&LIarG|Sjz*j7RB>mE!AKxAHZ4;&j)L9 zhy{7y;FVJYS9DttSj&uEAX^l#g0-vyYl$cYIgEKVSW668i@gNtmObiOFURh%WjY@j(5OX9)q_=3B9L9VatR)7lMc^}7%S^DAGhi)^&%j#Dz*W6d{ z9azhP|6nbD!CF3mwJiJ(*76^$Mc^RFmctx;paRyT0Ob9ECg%xU(QU#qpuE500mxyA ztnHwtf{q0!_A?+_xWQUdz*-ENL0Z_Pz*??=wLD}4Yq0`rxdGO~%n#O51=jKbqQwxb zrRO2YmPQ`1mQ=77i^Cv?HA{iDTmx%4&<3)l%?zw%4_J#MA6QEV%Sc}7Hki(jz zz*=sBwLAc8Y1 z9jxU5Sc{__Sj$(i7LJQxEgfJjZY3bUI4lC&A}kBa$a7wRY*BOtYtga-#eM=tI`U@-^D$NZu*s2uM5~upXqPts1Q5$!m};iSb}9f5BRQfVDWE0NdhL269-y zCa{*tU@c4DfVHH8wdh)dLagE@$QI`_U@d77Et|nwW`ni-c_Xmk(6q!Hu$EM?7K7U$ zEzGyTTCRY#Y}f|YvJI?d&s&f!jCo)!MPMxpz*?N|g0;K@YniYeq=juSSjz{nmV^0V zE%jh69Ctys9DV`T;!zIrOTsR&mMdT_OWuKONh}3xSqs)u0M^3%2CO9oti@nANK4x- zu$DVuEsW)0ExW*49)PttzXxln18Wi32hzg!5v*mxdyp*$YrtBbgSB|v2RrN+Sj!Et zmIn|mKfqd!fVCvnfwg=EYuNzS!u$`c+ zH;8QGDY0SMu_5)sW5o~6y3F$Yjv6_VPL&)l5>FePa!%lnW($)84W;h+B=FkoE`WX7!(Z|7#4CeFmUrUNVGV#&t`RIxKXe< zfrCLRPfW(ak*9IPp|eej4F9%A8n8J0H{)(&$he($P=G=GwvGXVqC`i0u9$!m!-Fi4 zmcU#w9!7yxAoUJgBMn#%%m=Cea2ce&_LhzWQ-eRq{5P2(#kL^DAC`d>U)lmvJOiZo z#YK=}bC6;MH<02r8JiP08ic@#=Yte~+6+=$15%uE9;EpBO&tj)1sjm!H)$Znw{paI z7z<{B6gz88r1-=^kYZ!7 zVpfpiISC-e0$|1e&on7A+?o$k{L`4bje(;cq0%q2_1-Y)e`(VH!(`FYY|+DPIi=Zh4ztygW~&*8G#5B&tvIB$!AX0^A?*WB zIwub4TyWC8aY*-plirm^**lDKPa5UkFv@>vl>fu1(bA;R!=yQdNq~bnP=bAu2KQwP zei2XM&`9xVnbOxQCdWTEgJRC>rD_dL>czhT|1bz&2QIULeqr@S_+M z;I-#;B$yn|gT(h(f&$zO6tD}PfdaN<4k&hdL9r822vYp81jz6YiD`_2 z91Pqbc0zobqah2^f_-P0R0P? zE@p*DkU5PfjJVqvc7%fU2CP2Aq{Pq?3eq@X)fpyb0k#H

?dl6-L}Vi406m?jW~4 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 OwCUz#=4FGbbp` + */ + +# 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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 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()); -- 2.50.0