Hyperion.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. // STL includes
  2. #include <exception>
  3. #include <sstream>
  4. // QT includes
  5. #include <QString>
  6. #include <QStringList>
  7. #include <QThread>
  8. // hyperion include
  9. #include <hyperion/Hyperion.h>
  10. #if defined(ENABLE_FORWARDER)
  11. #include <forwarder/MessageForwarder.h>
  12. #endif
  13. #include <hyperion/ImageProcessor.h>
  14. #include <hyperion/ColorAdjustment.h>
  15. // utils
  16. #include <utils/hyperion.h>
  17. #include <utils/GlobalSignals.h>
  18. #include <utils/Logger.h>
  19. // LedDevice includes
  20. #include <leddevice/LedDeviceWrapper.h>
  21. #include <hyperion/MultiColorAdjustment.h>
  22. #include <hyperion/LinearColorSmoothing.h>
  23. #if defined(ENABLE_EFFECTENGINE)
  24. // effect engine includes
  25. #include <effectengine/EffectEngine.h>
  26. #endif
  27. // settingsManagaer
  28. #include <hyperion/SettingsManager.h>
  29. // BGEffectHandler
  30. #include <hyperion/BGEffectHandler.h>
  31. // CaptureControl (Daemon capture)
  32. #include <hyperion/CaptureCont.h>
  33. // Boblight
  34. #if defined(ENABLE_BOBLIGHT_SERVER)
  35. #include <boblightserver/BoblightServer.h>
  36. #endif
  37. Hyperion::Hyperion(quint8 instance, bool readonlyMode)
  38. : QObject()
  39. , _instIndex(instance)
  40. , _settingsManager(new SettingsManager(instance, this, readonlyMode))
  41. , _componentRegister(nullptr)
  42. , _ledString(LedString::createLedString(getSetting(settings::LEDS).array(), hyperion::createColorOrder(getSetting(settings::DEVICE).object())))
  43. , _imageProcessor(nullptr)
  44. , _muxer(nullptr)
  45. , _raw2ledAdjustment(hyperion::createLedColorsAdjustment(static_cast<int>(_ledString.leds().size()), getSetting(settings::COLOR).object()))
  46. , _ledDeviceWrapper(nullptr)
  47. , _deviceSmooth(nullptr)
  48. #if defined(ENABLE_EFFECTENGINE)
  49. , _effectEngine(nullptr)
  50. #endif
  51. #if defined(ENABLE_FORWARDER)
  52. , _messageForwarder(nullptr)
  53. #endif
  54. , _log(nullptr)
  55. , _hwLedCount()
  56. , _ledGridSize(hyperion::getLedLayoutGridSize(getSetting(settings::LEDS).array()))
  57. , _BGEffectHandler(nullptr)
  58. , _captureCont(nullptr)
  59. , _ledBuffer(_ledString.leds().size(), ColorRgb::BLACK)
  60. #if defined(ENABLE_BOBLIGHT_SERVER)
  61. , _boblightServer(nullptr)
  62. #endif
  63. , _readOnlyMode(readonlyMode)
  64. {
  65. qRegisterMetaType<ComponentList>("ComponentList");
  66. QString subComponent = "I"+QString::number(instance);
  67. this->setProperty("instance", (QString) subComponent);
  68. _log= Logger::getInstance("HYPERION", subComponent);
  69. _componentRegister = new ComponentRegister(this);
  70. _imageProcessor = new ImageProcessor(_ledString, this);
  71. _muxer = new PriorityMuxer(static_cast<int>(_ledString.leds().size()), this);
  72. }
  73. Hyperion::~Hyperion()
  74. {
  75. freeObjects();
  76. }
  77. void Hyperion::start()
  78. {
  79. // forward settings changed to Hyperion
  80. connect(_settingsManager, &SettingsManager::settingsChanged, this, &Hyperion::settingsChanged);
  81. // get newVideoMode from HyperionIManager
  82. connect(this, &Hyperion::newVideoMode, this, &Hyperion::handleNewVideoMode);
  83. if (!_raw2ledAdjustment->verifyAdjustments())
  84. {
  85. Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!");
  86. }
  87. // handle hwLedCount
  88. _hwLedCount = getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount());
  89. // Initialize colororder vector
  90. for (const Led& led : _ledString.leds())
  91. {
  92. _ledStringColorOrder.push_back(led.colorOrder);
  93. }
  94. // connect Hyperion::update with Muxer visible priority changes as muxer updates independent
  95. connect(_muxer, &PriorityMuxer::visiblePriorityChanged, this, &Hyperion::update);
  96. connect(_muxer, &PriorityMuxer::visiblePriorityChanged, this, &Hyperion::handleSourceAvailability);
  97. connect(_muxer, &PriorityMuxer::visibleComponentChanged, this, &Hyperion::handleVisibleComponentChanged);
  98. // listen for suspend/resume, idle requests to perform core activation/deactivation actions
  99. connect(this, &Hyperion::suspendRequest, this, &Hyperion::setSuspend);
  100. connect(this, &Hyperion::idleRequest, this, &Hyperion::setIdle);
  101. // listen for settings updates of this instance (LEDS & COLOR)
  102. connect(_settingsManager, &SettingsManager::settingsChanged, this, &Hyperion::handleSettingsUpdate);
  103. #if 0
  104. // set color correction activity state
  105. const QJsonObject color = getSetting(settings::COLOR).object();
  106. #endif
  107. // initialize LED-devices
  108. QJsonObject ledDevice = getSetting(settings::DEVICE).object();
  109. ledDevice["currentLedCount"] = _hwLedCount; // Inject led count info
  110. _ledDeviceWrapper = new LedDeviceWrapper(this);
  111. connect(this, &Hyperion::compStateChangeRequest, _ledDeviceWrapper, &LedDeviceWrapper::handleComponentState);
  112. connect(this, &Hyperion::ledDeviceData, _ledDeviceWrapper, &LedDeviceWrapper::updateLeds);
  113. _ledDeviceWrapper->createLedDevice(ledDevice);
  114. // smoothing
  115. _deviceSmooth = new LinearColorSmoothing(getSetting(settings::SMOOTHING), this);
  116. connect(this, &Hyperion::settingsChanged, _deviceSmooth, &LinearColorSmoothing::handleSettingsUpdate);
  117. //Start in pause mode, a new priority will activate smoothing (either start-effect or grabber)
  118. _deviceSmooth->setPause(true);
  119. #if defined(ENABLE_FORWARDER)
  120. // create the message forwarder only on main instance
  121. if (_instIndex == 0)
  122. {
  123. _messageForwarder = new MessageForwarder(this);
  124. _messageForwarder->handleSettingsUpdate(settings::NETFORWARD, getSetting(settings::NETFORWARD));
  125. #if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
  126. connect(GlobalSignals::getInstance(), &GlobalSignals::setBufferImage, this, &Hyperion::forwardBufferMessage);
  127. #endif
  128. }
  129. #endif
  130. #if defined(ENABLE_EFFECTENGINE)
  131. // create the effect engine; needs to be initialized after smoothing!
  132. _effectEngine = new EffectEngine(this);
  133. connect(_effectEngine, &EffectEngine::effectListUpdated, this, &Hyperion::effectListUpdated);
  134. #endif
  135. // initial startup effect
  136. hyperion::handleInitialEffect(this, getSetting(settings::FGEFFECT).object());
  137. // handle background effect
  138. _BGEffectHandler = new BGEffectHandler(this);
  139. // create the Daemon capture interface
  140. _captureCont = new CaptureCont(this);
  141. // forwards global signals to the corresponding slots
  142. connect(GlobalSignals::getInstance(), &GlobalSignals::registerGlobalInput, this, &Hyperion::registerInput);
  143. connect(GlobalSignals::getInstance(), &GlobalSignals::clearGlobalInput, this, &Hyperion::clear);
  144. connect(GlobalSignals::getInstance(), &GlobalSignals::setGlobalColor, this, &Hyperion::setColor);
  145. connect(GlobalSignals::getInstance(), &GlobalSignals::setGlobalImage, this, &Hyperion::setInputImage);
  146. // if there is no startup / background effect and no sending capture interface we probably want to push once BLACK (as PrioMuxer won't emit a priority change)
  147. update();
  148. #if defined(ENABLE_BOBLIGHT_SERVER)
  149. // boblight, can't live in global scope as it depends on layout
  150. _boblightServer = new BoblightServer(this, getSetting(settings::BOBLSERVER));
  151. connect(this, &Hyperion::settingsChanged, _boblightServer, &BoblightServer::handleSettingsUpdate);
  152. #endif
  153. // instance initiated, enter thread event loop
  154. emit started();
  155. }
  156. void Hyperion::stop()
  157. {
  158. emit finished();
  159. thread()->wait();
  160. }
  161. void Hyperion::freeObjects()
  162. {
  163. //delete Background effect first that it does not kick in when other priorities are stopped
  164. delete _BGEffectHandler;
  165. //Remove all priorities to switch off all leds
  166. clear(-1,true);
  167. // delete components on exit of hyperion core
  168. #if defined(ENABLE_BOBLIGHT_SERVER)
  169. delete _boblightServer;
  170. #endif
  171. delete _captureCont;
  172. #if defined(ENABLE_EFFECTENGINE)
  173. delete _effectEngine;
  174. #endif
  175. delete _raw2ledAdjustment;
  176. #if defined(ENABLE_FORWARDER)
  177. delete _messageForwarder;
  178. #endif
  179. delete _settingsManager;
  180. delete _ledDeviceWrapper;
  181. delete _imageProcessor;
  182. delete _muxer;
  183. delete _componentRegister;
  184. }
  185. void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
  186. {
  187. if(type == settings::COLOR)
  188. {
  189. const QJsonObject obj = config.object();
  190. // change in color recreate ledAdjustments
  191. delete _raw2ledAdjustment;
  192. _raw2ledAdjustment = hyperion::createLedColorsAdjustment(static_cast<int>(_ledString.leds().size()), obj);
  193. if (!_raw2ledAdjustment->verifyAdjustments())
  194. {
  195. Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!");
  196. }
  197. }
  198. else if(type == settings::LEDS)
  199. {
  200. const QJsonArray leds = config.array();
  201. #if defined(ENABLE_EFFECTENGINE)
  202. // stop and cache all running effects, as effects depend heavily on LED-layout
  203. _effectEngine->cacheRunningEffects();
  204. #endif
  205. // ledstring, img processor, muxer, ledGridSize (effect-engine image based effects), _ledBuffer and ByteOrder of ledstring
  206. _ledString = LedString::createLedString(leds, hyperion::createColorOrder(getSetting(settings::DEVICE).object()));
  207. _imageProcessor->setLedString(_ledString);
  208. _muxer->updateLedColorsLength(static_cast<int>(_ledString.leds().size()));
  209. _ledGridSize = hyperion::getLedLayoutGridSize(leds);
  210. std::vector<ColorRgb> color(_ledString.leds().size(), ColorRgb{0,0,0});
  211. _ledBuffer = color;
  212. _ledStringColorOrder.clear();
  213. for (const Led& led : _ledString.leds())
  214. {
  215. _ledStringColorOrder.push_back(led.colorOrder);
  216. }
  217. // handle hwLedCount update
  218. _hwLedCount = getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount());
  219. // change in leds are also reflected in adjustment
  220. delete _raw2ledAdjustment;
  221. _raw2ledAdjustment = hyperion::createLedColorsAdjustment(static_cast<int>(_ledString.leds().size()), getSetting(settings::COLOR).object());
  222. #if defined(ENABLE_EFFECTENGINE)
  223. // start cached effects
  224. _effectEngine->startCachedEffects();
  225. #endif
  226. }
  227. else if(type == settings::DEVICE)
  228. {
  229. QJsonObject dev = config.object();
  230. // handle hwLedCount update
  231. _hwLedCount = dev["hardwareLedCount"].toInt(getLedCount());
  232. // force ledString update, if device ByteOrder changed
  233. if(_ledDeviceWrapper->getColorOrder() != dev["colorOrder"].toString("rgb"))
  234. {
  235. _ledString = LedString::createLedString(getSetting(settings::LEDS).array(), hyperion::createColorOrder(dev));
  236. _imageProcessor->setLedString(_ledString);
  237. _ledStringColorOrder.clear();
  238. for (const Led& led : _ledString.leds())
  239. {
  240. _ledStringColorOrder.push_back(led.colorOrder);
  241. }
  242. }
  243. // do always reinit until the led devices can handle dynamic changes
  244. dev["currentLedCount"] = _hwLedCount; // Inject led count info
  245. _ledDeviceWrapper->createLedDevice(dev);
  246. // TODO: Check, if framegrabber frequency is lower than latchtime..., if yes, stop
  247. }
  248. // update once to push single color sets / adjustments/ ledlayout resizes and update ledBuffer color
  249. update();
  250. }
  251. QJsonDocument Hyperion::getSetting(settings::type type) const
  252. {
  253. return _settingsManager->getSetting(type);
  254. }
  255. bool Hyperion::saveSettings(const QJsonObject& config, bool correct)
  256. {
  257. return _settingsManager->saveSettings(config, correct);
  258. }
  259. bool Hyperion::restoreSettings(const QJsonObject& config, bool correct)
  260. {
  261. return _settingsManager->restoreSettings(config, correct);
  262. }
  263. int Hyperion::getLatchTime() const
  264. {
  265. return _ledDeviceWrapper->getLatchTime();
  266. }
  267. unsigned Hyperion::addSmoothingConfig(int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
  268. {
  269. return _deviceSmooth->addConfig(settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
  270. }
  271. unsigned Hyperion::updateSmoothingConfig(unsigned id, int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
  272. {
  273. return _deviceSmooth->updateConfig(id, settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
  274. }
  275. int Hyperion::getLedCount() const
  276. {
  277. return static_cast<int>(_ledString.leds().size());
  278. }
  279. void Hyperion::setSourceAutoSelect(bool state)
  280. {
  281. _muxer->setSourceAutoSelectEnabled(state);
  282. }
  283. bool Hyperion::setVisiblePriority(int priority)
  284. {
  285. return _muxer->setPriority(priority);
  286. }
  287. bool Hyperion::sourceAutoSelectEnabled() const
  288. {
  289. return _muxer->isSourceAutoSelectEnabled();
  290. }
  291. void Hyperion::setNewComponentState(hyperion::Components component, bool state)
  292. {
  293. _componentRegister->setNewComponentState(component, state);
  294. }
  295. std::map<hyperion::Components, bool> Hyperion::getAllComponents() const
  296. {
  297. return _componentRegister->getRegister();
  298. }
  299. int Hyperion::isComponentEnabled(hyperion::Components comp) const
  300. {
  301. return _componentRegister->isComponentEnabled(comp);
  302. }
  303. void Hyperion::setSuspend(bool isSuspend)
  304. {
  305. bool enable = !isSuspend;
  306. emit compStateChangeRequestAll(enable);
  307. }
  308. void Hyperion::setIdle(bool isIdle)
  309. {
  310. clear(-1);
  311. bool enable = !isIdle;
  312. emit compStateChangeRequestAll(enable, {hyperion::COMP_LEDDEVICE, hyperion::COMP_SMOOTHING} );
  313. }
  314. void Hyperion::registerInput(int priority, hyperion::Components component, const QString& origin, const QString& owner, unsigned smooth_cfg)
  315. {
  316. _muxer->registerInput(priority, component, origin, owner, smooth_cfg);
  317. }
  318. bool Hyperion::setInput(int priority, const std::vector<ColorRgb>& ledColors, int timeout_ms, bool clearEffect)
  319. {
  320. if(_muxer->setInput(priority, ledColors, timeout_ms))
  321. {
  322. #if defined(ENABLE_EFFECTENGINE)
  323. // clear effect if this call does not come from an effect
  324. if(clearEffect)
  325. {
  326. _effectEngine->channelCleared(priority);
  327. }
  328. #endif
  329. // if this priority is visible, update immediately
  330. if(priority == _muxer->getCurrentPriority())
  331. {
  332. update();
  333. }
  334. return true;
  335. }
  336. return false;
  337. }
  338. bool Hyperion::setInputImage(int priority, const Image<ColorRgb>& image, int64_t timeout_ms, bool clearEffect)
  339. {
  340. if (!_muxer->hasPriority(priority))
  341. {
  342. emit GlobalSignals::getInstance()->globalRegRequired(priority);
  343. return false;
  344. }
  345. if(_muxer->setInputImage(priority, image, timeout_ms))
  346. {
  347. #if defined(ENABLE_EFFECTENGINE)
  348. // clear effect if this call does not come from an effect
  349. if(clearEffect)
  350. {
  351. _effectEngine->channelCleared(priority);
  352. }
  353. #endif
  354. // if this priority is visible, update immediately
  355. if(priority == _muxer->getCurrentPriority())
  356. {
  357. update();
  358. }
  359. return true;
  360. }
  361. return false;
  362. }
  363. bool Hyperion::setInputInactive(quint8 priority)
  364. {
  365. return _muxer->setInputInactive(priority);
  366. }
  367. void Hyperion::setColor(int priority, const std::vector<ColorRgb> &ledColors, int timeout_ms, const QString &origin, bool clearEffects)
  368. {
  369. #if defined(ENABLE_EFFECTENGINE)
  370. // clear effect if this call does not come from an effect
  371. if (clearEffects)
  372. {
  373. _effectEngine->channelCleared(priority);
  374. }
  375. #endif
  376. // create full led vector from single/multiple colors
  377. size_t size = _ledString.leds().size();
  378. std::vector<ColorRgb> newLedColors;
  379. while (true)
  380. {
  381. for (const auto &entry : ledColors)
  382. {
  383. newLedColors.emplace_back(entry);
  384. if (newLedColors.size() == size)
  385. {
  386. goto end;
  387. }
  388. }
  389. }
  390. end:
  391. // register color
  392. registerInput(priority, hyperion::COMP_COLOR, origin);
  393. // write color to muxer
  394. setInput(priority, newLedColors, timeout_ms);
  395. }
  396. QStringList Hyperion::getAdjustmentIds() const
  397. {
  398. return _raw2ledAdjustment->getAdjustmentIds();
  399. }
  400. ColorAdjustment * Hyperion::getAdjustment(const QString& id) const
  401. {
  402. return _raw2ledAdjustment->getAdjustment(id);
  403. }
  404. void Hyperion::adjustmentsUpdated()
  405. {
  406. emit adjustmentChanged();
  407. update();
  408. }
  409. bool Hyperion::clear(int priority, bool forceClearAll)
  410. {
  411. bool isCleared = false;
  412. if (priority < 0)
  413. {
  414. _muxer->clearAll(forceClearAll);
  415. #if defined(ENABLE_EFFECTENGINE)
  416. // send clearall signal to the effect engine
  417. _effectEngine->allChannelsCleared();
  418. #endif
  419. isCleared = true;
  420. }
  421. else
  422. {
  423. #if defined(ENABLE_EFFECTENGINE)
  424. // send clear signal to the effect engine
  425. // (outside the check so the effect gets cleared even when the effect is not sending colors)
  426. _effectEngine->channelCleared(priority);
  427. #endif
  428. if (_muxer->clearInput(priority))
  429. {
  430. isCleared = true;
  431. }
  432. }
  433. return isCleared;
  434. }
  435. int Hyperion::getCurrentPriority() const
  436. {
  437. return _muxer->getCurrentPriority();
  438. }
  439. bool Hyperion::isCurrentPriority(int priority) const
  440. {
  441. return getCurrentPriority() == priority;
  442. }
  443. QList<int> Hyperion::getActivePriorities() const
  444. {
  445. return _muxer->getPriorities();
  446. }
  447. Hyperion::InputInfo Hyperion::getPriorityInfo(int priority) const
  448. {
  449. return _muxer->getInputInfo(priority);
  450. }
  451. #if defined(ENABLE_EFFECTENGINE)
  452. QString Hyperion::saveEffect(const QJsonObject& obj)
  453. {
  454. return _effectEngine->saveEffect(obj);
  455. }
  456. QString Hyperion::deleteEffect(const QString& effectName)
  457. {
  458. return _effectEngine->deleteEffect(effectName);
  459. }
  460. std::list<EffectDefinition> Hyperion::getEffects() const
  461. {
  462. return _effectEngine->getEffects();
  463. }
  464. std::list<ActiveEffectDefinition> Hyperion::getActiveEffects() const
  465. {
  466. return _effectEngine->getActiveEffects();
  467. }
  468. std::list<EffectSchema> Hyperion::getEffectSchemas() const
  469. {
  470. return _effectEngine->getEffectSchemas();
  471. }
  472. int Hyperion::setEffect(const QString &effectName, int priority, int timeout, const QString & origin)
  473. {
  474. return _effectEngine->runEffect(effectName, priority, timeout, origin);
  475. }
  476. int Hyperion::setEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, const QString &imageData)
  477. {
  478. return _effectEngine->runEffect(effectName, args, priority, timeout, pythonScript, origin, 0, imageData);
  479. }
  480. #endif
  481. QJsonObject Hyperion::getQJsonConfig() const
  482. {
  483. return _settingsManager->getSettings();
  484. }
  485. void Hyperion::setLedMappingType(int mappingType)
  486. {
  487. if(mappingType != _imageProcessor->getUserLedMappingType())
  488. {
  489. _imageProcessor->setLedMappingType(mappingType);
  490. emit imageToLedsMappingChanged(mappingType);
  491. }
  492. }
  493. int Hyperion::getLedMappingType() const
  494. {
  495. return _imageProcessor->getUserLedMappingType();
  496. }
  497. void Hyperion::setVideoMode(VideoMode mode)
  498. {
  499. emit videoMode(mode);
  500. }
  501. VideoMode Hyperion::getCurrentVideoMode() const
  502. {
  503. return _currVideoMode;
  504. }
  505. QString Hyperion::getActiveDeviceType() const
  506. {
  507. return _ledDeviceWrapper->getActiveDeviceType();
  508. }
  509. void Hyperion::handleVisibleComponentChanged(hyperion::Components comp)
  510. {
  511. _imageProcessor->setBlackbarDetectDisable((comp == hyperion::COMP_EFFECT));
  512. _imageProcessor->setHardLedMappingType((comp == hyperion::COMP_EFFECT) ? 0 : -1);
  513. _raw2ledAdjustment->setBacklightEnabled((comp != hyperion::COMP_COLOR && comp != hyperion::COMP_EFFECT));
  514. }
  515. void Hyperion::handleSourceAvailability(int priority)
  516. {
  517. int previousPriority = _muxer->getPreviousPriority();
  518. if ( priority == PriorityMuxer::LOWEST_PRIORITY)
  519. {
  520. // Keep LED-device on, as background effect will kick-in shortly
  521. if (!_BGEffectHandler->_isEnabled())
  522. {
  523. Debug(_log,"No source left -> Pause output processing and switch LED-Device off");
  524. emit _ledDeviceWrapper->switchOff();
  525. emit _deviceSmooth->setPause(true);
  526. }
  527. }
  528. else
  529. {
  530. if ( previousPriority == PriorityMuxer::LOWEST_PRIORITY )
  531. {
  532. Debug(_log,"new source available -> Resume output processing and switch LED-Device on");
  533. emit _ledDeviceWrapper->switchOn();
  534. emit _deviceSmooth->setPause(false);
  535. }
  536. }
  537. }
  538. void Hyperion::update()
  539. {
  540. // Obtain the current priority channel
  541. int priority = _muxer->getCurrentPriority();
  542. const PriorityMuxer::InputInfo priorityInfo = _muxer->getInputInfo(priority);
  543. // copy image & process OR copy ledColors from muxer
  544. Image<ColorRgb> image = priorityInfo.image;
  545. if (image.width() > 1 || image.height() > 1)
  546. {
  547. emit currentImage(image);
  548. _ledBuffer = _imageProcessor->process(image);
  549. }
  550. else
  551. {
  552. _ledBuffer = priorityInfo.ledColors;
  553. if (_ledString.hasBlackListedLeds())
  554. {
  555. for (int id : _ledString.blacklistedLedIds())
  556. {
  557. if (id > _ledBuffer.size()-1)
  558. {
  559. break;
  560. }
  561. _ledBuffer.at(id) = ColorRgb::BLACK;
  562. }
  563. }
  564. }
  565. // emit rawLedColors before transform
  566. emit rawLedColors(_ledBuffer);
  567. _raw2ledAdjustment->applyAdjustment(_ledBuffer);
  568. int i = 0;
  569. for (ColorRgb& color : _ledBuffer)
  570. {
  571. // correct the color byte order
  572. switch (_ledStringColorOrder.at(i))
  573. {
  574. case ColorOrder::ORDER_RGB:
  575. // leave as it is
  576. break;
  577. case ColorOrder::ORDER_BGR:
  578. std::swap(color.red, color.blue);
  579. break;
  580. case ColorOrder::ORDER_RBG:
  581. std::swap(color.green, color.blue);
  582. break;
  583. case ColorOrder::ORDER_GRB:
  584. std::swap(color.red, color.green);
  585. break;
  586. case ColorOrder::ORDER_GBR:
  587. std::swap(color.red, color.green);
  588. std::swap(color.green, color.blue);
  589. break;
  590. case ColorOrder::ORDER_BRG:
  591. std::swap(color.red, color.blue);
  592. std::swap(color.green, color.blue);
  593. break;
  594. }
  595. i++;
  596. }
  597. // fill additional hardware LEDs with black
  598. if ( _hwLedCount > static_cast<int>(_ledBuffer.size()) )
  599. {
  600. _ledBuffer.resize(_hwLedCount, ColorRgb::BLACK);
  601. }
  602. // Write the data to the device
  603. if (_ledDeviceWrapper->enabled())
  604. {
  605. // Smoothing is disabled
  606. if (! _deviceSmooth->enabled())
  607. {
  608. emit ledDeviceData(_ledBuffer);
  609. }
  610. else
  611. {
  612. // feed smoothing in pause mode to maintain a smooth transition back to smooth mode
  613. if (_deviceSmooth->enabled() || _deviceSmooth->pause())
  614. {
  615. _deviceSmooth->updateLedValues(_ledBuffer);
  616. }
  617. }
  618. }
  619. }