#pragma once #include #include #include "processor.h" namespace dsp { template class chain { public: chain() {} chain(stream* in) { init(in); } void init(stream* in) { _in = in; out = _in; } template void setInput(stream* in, Func onOutputChange) { _in = in; for (auto& ln : links) { if (states[ln]) { ln->setInput(_in); return; } } out = _in; onOutputChange(out); } void addBlock(Processor* block, bool enabled) { // Check if block is already part of the chain if (blockExists(block)) { throw std::runtime_error("[chain] Tried to add a block that is already part of the chain"); } // Add to the list links.push_back(block); states[block] = false; // Enable if needed if (enabled) { enableBlock(block, [](stream* out){}); } } template void removeBlock(Processor* block, Func onOutputChange) { // Check if block is part of the chain if (!blockExists(block)) { throw std::runtime_error("[chain] Tried to remove a block that is not part of the chain"); } // Disable the block disableBlock(block, onOutputChange); // Remove block from the list states.erase(block); links.erase(std::find(links.begin(), links.end(), block)); } template void enableBlock(Processor* block, Func onOutputChange) { // Check that the block is part of the chain if (!blockExists(block)) { throw std::runtime_error("[chain] Tried to enable a block that isn't part of the chain"); } // If already enable, don't do anything if (states[block]) { return; } // Gather blocks before and after the block to enable Processor* before = blockBefore(block); Processor* after = blockAfter(block); // Update input of next block or output if (after) { after->setInput(&block->out); } else { out = &block->out; onOutputChange(out); } // Set input of the new block block->setInput(before ? &before->out : _in); // Start new block if (running) { block->start(); } states[block] = true; } template void disableBlock(Processor* block, Func onOutputChange) { // Check that the block is part of the chain if (!blockExists(block)) { throw std::runtime_error("[chain] Tried to disable a block that isn't part of the chain"); } // If already disabled, don't do anything if (!states[block]) { return; } // Stop disabled block block->stop(); states[block] = false; // Gather blocks before and after the block to disable Processor* before = blockBefore(block); Processor* after = blockAfter(block); // Update input of next block or output if (after) { after->setInput(before ? &before->out : _in); } else { out = before ? &before->out : _in; onOutputChange(out); } } template void setBlockEnabled(Processor* block, bool enabled, Func onOutputChange) { if (enabled) { enableBlock(block, onOutputChange); } else { disableBlock(block, onOutputChange); } } template void enableAllBlocks(Func onOutputChange) { for (auto& ln : links) { enableBlock(ln, onOutputChange); } } template void disableAllBlocks(Func onOutputChange) { for (auto& ln : links) { disableBlock(ln, onOutputChange); } } void start() { if (running) { return; } for (auto& ln : links) { if (!states[ln]) { continue; } ln->start(); } running = true; } void stop() { if (!running) { return; } for (auto& ln : links) { if (!states[ln]) { continue; } ln->stop(); } running = false; } stream* out; private: Processor* blockBefore(Processor* block) { // TODO: This is wrong and must be fixed when I get more time for (auto& ln : links) { if (ln == block) { return NULL; } if (states[ln]) { return ln; } } return NULL; } Processor* blockAfter(Processor* block) { bool blockFound = false; for (auto& ln : links) { if (ln == block) { blockFound = true; continue; } if (states[ln] && blockFound) { return ln; } } return NULL; } bool blockExists(Processor* block) { return states.find(block) != states.end(); } stream* _in; std::vector*> links; std::map*, bool> states; bool running = false; }; }