#pragma once #include #include #include #include namespace dsp { template class ChainLinkAny { public: virtual ~ChainLinkAny() {} virtual void setInput(stream* stream) = 0; virtual stream* getOutput() = 0; virtual void start() = 0; virtual void stop() = 0; bool enabled = false; }; template class ChainLink : public ChainLinkAny { public: ~ChainLink() {} void setInput(stream* stream) { block.setInput(stream); } stream* getOutput() { return &block.out; } void start() { block.start(); } void stop() { block.stop(); } BLOCK block; }; template class Chain { public: Chain() {} Chain(stream* input, EventHandler*>* outputChangedHandler) { init(input, outputChangedHandler); } void init(stream* input, EventHandler*>* outputChangedHandler) { _input = input; onOutputChanged.bindHandler(outputChangedHandler); } void add(ChainLinkAny* link) { // Check that link exists if (std::find(links.begin(), links.end(), link) != links.end()) { spdlog::error("Could not add new link to the chain, link already in the chain"); return; } // Assert that the link is stopped and disabled link->stop(); link->enabled = false; // Add new link to the list links.push_back(link); } void enable(ChainLinkAny* link) { // Check that link exists and locate it auto lnit = std::find(links.begin(), links.end(), link); if (lnit == links.end()) { spdlog::error("Could not enable link"); return; } // Enable the link link->enabled = true; // Find input stream* input = _input; for (auto i = links.begin(); i < lnit; i++) { if (!(*i)->enabled) { continue; } input = (*i)->getOutput(); } // Find next block ChainLinkAny* nextLink = NULL; for (auto i = ++lnit; i < links.end(); i++) { if (!(*i)->enabled) { continue; } nextLink = *i; } if (nextLink) { // If a next block exists, change its input nextLink->setInput(link->getOutput()); } else { // If there are no next blocks, change output of outside reader onOutputChanged.emit(link->getOutput()); } // Set input of newly enabled link link->setInput(input); // If running, start everything if (running) { start(); } } void disable(ChainLinkAny* link) { // Check that link exists and locate it auto lnit = std::find(links.begin(), links.end(), link); if (lnit == links.end()) { spdlog::error("Could not disable link"); return; } // Stop and disable link link->stop(); link->enabled = false; // Find its input stream* input = _input; for (auto i = links.begin(); i < lnit; i++) { if (!(*i)->enabled) { continue; } input = (*i)->getOutput(); } // Find next block ChainLinkAny* nextLink = NULL; for (auto i = ++lnit; i < links.end(); i++) { if (!(*i)->enabled) { continue; } nextLink = *i; } if (nextLink) { // If a next block exists, change its input nextLink->setInput(input); } else { // If there are no next blocks, change output of outside reader onOutputChanged.emit(input); } } void disableAll() { for (auto& ln : links) { disable(ln); } } void setState(ChainLinkAny* link, bool enabled) { enabled ? enable(link) : disable(link); } void setInput(stream* input) { _input = input; // Set input of first enabled link for (auto& ln : links) { if (!ln->enabled) { continue; } ln->setInput(_input); return; } // No block found, this means nothing is enabled onOutputChanged.emit(_input); } stream* getOutput() { stream* lastOutput = _input; for (auto& ln : links) { if (!ln->enabled) { continue; } lastOutput = ln->getOutput(); } return lastOutput; } void start() { running = true; for (auto& ln : links) { if (ln->enabled) { ln->start(); } else { ln->stop(); } } } void stop() { running = false; for (auto& ln : links) { ln->stop(); } } Event*> onOutputChanged; private: stream* _input; std::vector*> links; bool running = false; }; }