diff --git a/include/wrapper/RealTimeBase.hpp b/include/wrapper/RealTimeBase.hpp index 0249e61..554d8ab 100644 --- a/include/wrapper/RealTimeBase.hpp +++ b/include/wrapper/RealTimeBase.hpp @@ -1,169 +1,229 @@ -#pragma once +#pragma once #include -namespace fluid{ -namespace client{ -namespace impl{ - template - struct RealTimeBase - { - using HostVector = FluidTensorView; - using Params = typename Client::ParamSetType; - template - struct doExpectedCount; - - template - struct doExpectedCount - { - static void count(const T& d,FloatControlsIter& c,Result& status) - { - if(!status.ok()) return; - - if(c.remain()) - { - index statedSize = d.fixedSize; - - if(c.remain() < statedSize) - status = {Result::Status::kError,"Ran out of arguments at ", d.name}; - - //fastforward - for(index i=0; i < statedSize; ++i) c.next(); - - } - } - }; - - template - struct doExpectedCount - { - static void count(const T& d,FloatControlsIter& c,Result& status) - { - if(!status.ok()) return; - - if(c.remain()) - { - index statedSize = 1; - - if(c.remain() < statedSize) - status = {Result::Status::kError,"Ran out of arguments at ", d.name}; - - //fastforward - for(index i=0; i < statedSize; ++i) c.next(); - - } - } - }; - template - struct ExpectedCount{ - void operator ()(const T& descriptor,FloatControlsIter& c, Result& status) +namespace fluid { +namespace client { +namespace impl { + + +template +struct RealTimeBase +{ + using IOMapFn = void (RealTimeBase::*)(SCUnit&, Client&); + using HostVector = FluidTensorView; + using Params = typename Client::ParamSetType; + template + struct doExpectedCount; + + template + struct doExpectedCount + { + static void count(const T& d, FloatControlsIter& c, Result& status) + { + if (!status.ok()) return; + + if (c.remain()) { - doExpectedCount::value>::count(descriptor,c,status); + index statedSize = d.fixedSize; + + if (c.remain() < statedSize) + status = {Result::Status::kError, "Ran out of arguments at ", d.name}; + + // fastforward + for (index i = 0; i < statedSize; ++i) c.next(); } - }; + } + }; - Result expectedSize(FloatControlsIter& controls) + template + struct doExpectedCount + { + static void count(const T& d, FloatControlsIter& c, Result& status) { - if(controls.size() < Client::getParameterDescriptors().count()) + if (!status.ok()) return; + + if (c.remain()) { - return {Result::Status::kError,"Fewer parameters than exepected. Got ", controls.size(), "expect at least", Client::getParameterDescriptors().count()}; + index statedSize = 1; + + if (c.remain() < statedSize) + status = {Result::Status::kError, "Ran out of arguments at ", d.name}; + + // fastforward + for (index i = 0; i < statedSize; ++i) c.next(); } - - Result countScan; - Client::getParameterDescriptors().template iterate( - std::forward(controls), - std::forward(countScan)); - return countScan; } + }; + template + struct ExpectedCount + { + void operator()(const T& descriptor, FloatControlsIter& c, Result& status) + { + doExpectedCount::value>::count( + descriptor, c, status); + } + }; - // static index ControlOffset(Unit* unit) { return unit->mSpecialIndex + 1; } - // static index ControlSize(Unit* unit) { return static_cast(unit->mNumInputs) - unit->mSpecialIndex - 1 -(IsModel_t::value ? 1 : 0); } - - void init(SCUnit& unit, Client& client, FloatControlsIter& controls) + Result expectedSize(FloatControlsIter& controls) + { + if (controls.size() < Client::getParameterDescriptors().count()) { - assert(!(client.audioChannelsOut() > 0 && client.controlChannelsOut() > 0) &&"Client can't have both audio and control outputs"); - // consoltr.reset(unit.mInBuf + unit.mSpecialIndex + 1); - client.sampleRate(unit.fullSampleRate()); - mInputConnections.reserve(asUnsigned(client.audioChannelsIn())); - mOutputConnections.reserve(asUnsigned(client.audioChannelsOut())); - mAudioInputs.reserve(asUnsigned(client.audioChannelsIn())); - mOutputs.reserve(asUnsigned( - std::max(client.audioChannelsOut(), client.controlChannelsOut()))); + return {Result::Status::kError, "Fewer parameters than exepected. Got ", + controls.size(), "expect at least", + Client::getParameterDescriptors().count()}; + } + Result countScan; + Client::getParameterDescriptors().template iterate( + std::forward(controls), + std::forward(countScan)); + return countScan; + } - Result r; - if(!(r = expectedSize(controls)).ok()) - { -// mCalcFunc = Wrapper::getInterfaceTable()->fClearUnitOutputs; - std::cout - << "ERROR: " << Wrapper::getName() - << " wrong number of arguments." - << r.message() - << std::endl; - return; - } + void init(SCUnit& unit, Client& client, FloatControlsIter& controls) + { + assert(!(client.audioChannelsOut() > 0 && + client.controlChannelsOut().count > 0) && + "Client can't have both audio and control outputs"); + client.sampleRate(unit.fullSampleRate()); + mInputConnections.reserve(asUnsigned(client.audioChannelsIn())); + mOutputConnections.reserve(asUnsigned(client.audioChannelsOut())); + Result r; + if (!(r = expectedSize(controls)).ok()) + { + std::cout << "ERROR: " << Wrapper::getName() + << " wrong number of arguments." << r.message() << std::endl; + return; + } + if (client.audioChannelsIn()) + { + mAudioInputs.reserve(asUnsigned(client.audioChannelsIn())); for (index i = 0; i < client.audioChannelsIn(); ++i) { mInputConnections.emplace_back(unit.isAudioRateIn(static_cast(i))); mAudioInputs.emplace_back(nullptr, 0, 0); } + mInputMapper = &RealTimeBase::mapAudioInputs; + } + else if (client.controlChannelsIn()) + { + mControlInputBuffer.resize(unit.mSpecialIndex + 1); + mAudioInputs.emplace_back(mControlInputBuffer); + mInputMapper = &RealTimeBase::mapControlInputs; + } + + index outputSize = client.controlChannelsOut().size > 0 + ? std::max(client.audioChannelsOut(), + client.controlChannelsOut().size) + : unit.mSpecialIndex + 1; + mOutputs.reserve(asUnsigned(outputSize)); + if (client.audioChannelsOut()) + { for (index i = 0; i < client.audioChannelsOut(); ++i) { mOutputConnections.emplace_back(true); mOutputs.emplace_back(nullptr, 0, 0); } - - for (index i = 0; i < client.controlChannelsOut(); ++i) - { - mOutputs.emplace_back(nullptr, 0, 0); + + mOutMapperPre = &RealTimeBase::mapAudioOutputs; + mOutMapperPost = &RealTimeBase::mapNoOp; + } + else + { + index totalControlOutputs = + client.controlChannelsOut().count * outputSize; + mControlOutputBuffer.resize(totalControlOutputs); + for (index i = 0; i < client.controlChannelsOut().count; ++i) + { + mOutputs.emplace_back( + mControlOutputBuffer(fluid::Slice(i * outputSize, outputSize))); } - } - - void next(SCUnit& unit, Client& client,Params& params,FloatControlsIter& controls,bool updateParams = true) - { - bool trig = IsModel_t::value ? !mPrevTrig && unit.in0(0) > 0 : false; - - mPrevTrig = trig; - - if(updateParams) - { + + mOutMapperPre = &RealTimeBase::mapNoOp; + mOutMapperPost = &RealTimeBase::mapControlOutputs; + } + } + + void mapNoOp(SCUnit&, Client&) {} + + void mapAudioInputs(SCUnit& unit, Client& client) + { + for (index i = 0; i < client.audioChannelsIn(); ++i) + { + assert(i <= std::numeric_limits::max()); + if (mInputConnections[asUnsigned(i)]) + mAudioInputs[asUnsigned(i)].reset( + const_cast(unit.in(static_cast(i))), 0, + unit.fullBufferSize()); + } + } + + void mapAudioOutputs(SCUnit& unit, Client& client) + { + for (index i = 0; i < client.audioChannelsOut(); ++i) + { + assert(i <= std::numeric_limits::max()); + if (mOutputConnections[asUnsigned(i)]) + mOutputs[asUnsigned(i)].reset(unit.out(static_cast(i)), 0, + unit.fullBufferSize()); + } + } + + void mapControlInputs(SCUnit& unit, Client& client) + { + for (index i = 0; i < unit.mSpecialIndex + 1; ++i) + { + assert(i <= std::numeric_limits::max()); + mControlInputBuffer[asUnsigned(i)] = unit.in0(static_cast(i)); + } + } + + void mapControlOutputs(SCUnit& unit, Client& client) + { + for (index i = 0; i < mControlOutputBuffer.size(); ++i) + { + assert(i <= std::numeric_limits::max()); + unit.out0(static_cast(i)) = mControlOutputBuffer(i); + } + } + + void next(SCUnit& unit, Client& client, Params& params, + FloatControlsIter& controls, bool updateParams = true) + { + bool trig = + IsModel_t::value ? !mPrevTrig && unit.in0(0) > 0 : false; + + mPrevTrig = trig; + + if (updateParams) + { Wrapper::setParams(&unit, params, controls); params.constrainParameterValuesRT(nullptr); - } - - for (index i = 0; i < client.audioChannelsIn(); ++i) - { - assert(i <= std::numeric_limits::max()); - if (mInputConnections[asUnsigned(i)]) - mAudioInputs[asUnsigned(i)].reset(const_cast(unit.in(static_cast(i))), 0,unit.fullBufferSize()); - } - - for (index i = 0; i < client.audioChannelsOut(); ++i) - { - assert(i <= std::numeric_limits::max()); - if (mOutputConnections[asUnsigned(i)]) - mOutputs[asUnsigned(i)].reset(unit.out(static_cast(i)), 0, - unit.fullBufferSize()); - } - - for (index i = 0; i < client.controlChannelsOut(); ++i) - { - assert(i <= std::numeric_limits::max()); - mOutputs[asUnsigned(i)].reset(unit.out(static_cast(i)), 0, 1); - } - client.process(mAudioInputs, mOutputs, mContext); - } - private: - std::vector mInputConnections; - std::vector mOutputConnections; - std::vector mAudioInputs; - std::vector mOutputs; - FluidContext mContext; - bool mPrevTrig; - }; -} -} -} + } + + (this->*mInputMapper)(unit, client); + (this->*mOutMapperPre)(unit, client); + client.process(mAudioInputs, mOutputs, mContext); + (this->*mOutMapperPost)(unit, client); + } + +private: + std::vector mInputConnections; + std::vector mOutputConnections; + std::vector mAudioInputs; + std::vector mOutputs; + FluidTensor mControlInputBuffer; + FluidTensor mControlOutputBuffer; + FluidContext mContext; + bool mPrevTrig; + IOMapFn mInputMapper; + IOMapFn mOutMapperPre; + IOMapFn mOutMapperPost; +}; +} // namespace impl +} // namespace client +} // namespace fluid