diff --git a/CMakeLists.txt b/CMakeLists.txt index 609e103..caab9fd 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ MACRO(SUBDIRLIST result curdir) ENDMACRO() set(FLUID_PATH ~/fluid_decomposition CACHE PATH "The top level of the fluid_decomposition repo") +set(LOCAL_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include) + get_filename_component(FLUID_ABS_PATH ${FLUID_PATH} ABSOLUTE) message(${FLUID_ABS_PATH}) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 18166e6..4850a3d 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -1,4 +1,4 @@ -#pragma once + #pragma once #include "SCBufferAdaptor.hpp" #include @@ -16,7 +16,7 @@ namespace fluid { namespace client { -template class FluidSCWrapper; +template class FluidSCWrapper; namespace impl { @@ -25,120 +25,160 @@ template struct ArgumentGetter; template struct ControlGetter; template using msg_iter_method = T (sc_msg_iter::*)(T); -template Method> struct GetArgument -{ - T operator()(World* w, sc_msg_iter *args) - { - T r = (args->*Method)(0); - return r; - } -}; - - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Iterate over kr/ir inputs via callbacks from params object struct FloatControlsIter { FloatControlsIter(float** vals, size_t N):mValues(vals), mSize(N) {} - + float next() { - assert(mCount < mSize); - return *mValues[mCount++]; + assert(mCount < mSize && "Boundary error fail horror"); + float f = *mValues[mCount++]; + return f; } - + +// float operator[](size_t i) +// { +// assert(i < mSize); +// return *mValues[i]; +// } + void reset(float** vals) { mValues = vals; mCount = 0; } - + private: float** mValues; size_t mSize; size_t mCount{0}; }; +//General case template struct GetControl { T operator()(World*, FloatControlsIter& controls) { return controls.next(); } }; -template struct ArgumentGetter : public GetArgument -{}; - -template struct ArgumentGetter : public GetArgument -{}; - -template struct ArgumentGetter : public GetArgument +template struct ControlGetter : public GetControl {}; -template struct ArgumentGetter +//Specializations +template struct ControlGetter { - auto operator()(World* w, sc_msg_iter *args) + auto operator() (World* w, FloatControlsIter& iter) { + typename LongT::type bufnum = iter.next(); + return std::unique_ptr(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w): nullptr); + } +}; - long bufnum = args->geti(-1); +template +struct ControlGetter +{ + typename FloatPairsArrayT::type operator()(World*, FloatControlsIter& iter) + { + return {{iter.next(),iter.next()},{iter.next(),iter.next()}}; + } +}; - return std::unique_ptr(new SCBufferAdaptor(bufnum,w)); +template +struct ControlGetter +{ + typename FFTParamsT::type operator()(World*, FloatControlsIter& iter) + { + return {static_cast(iter.next()),static_cast(iter.next()),static_cast(iter.next())}; } }; -template struct ArgumentGetter +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Iterate over arguments in sc_msg_iter, via callbacks from params object + +template Method> struct GetArgument { - typename FloatPairsArrayT::type operator()(World* w, sc_msg_iter *args) + T operator()(World* w, sc_msg_iter *args) { - return {{args->getf(),args->getf()},{args->getf(),args->getf()}}; + T r = (args->*Method)(T{0}); + return r; } }; +//General cases +template struct ArgumentGetter : public GetArgument +{}; +template struct ArgumentGetter : public GetArgument +{}; -template struct ControlGetter : public GetControl +template struct ArgumentGetter : public GetArgument {}; +//Specializations +template struct ArgumentGetter +{ + auto operator() (World* w, sc_msg_iter *args) + { + typename LongT::type bufnum = args->geti(-1); + return std::unique_ptr(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w) : nullptr); + } +}; -template struct ControlGetter +template struct ArgumentGetter { - auto operator()(World* w, FloatControlsIter& iter) + typename FloatPairsArrayT::type operator()(World* w, sc_msg_iter *args) { - long bufnum = iter.next(); - return std::unique_ptr(new SCBufferAdaptor(bufnum,w)); + return {{args->getf(),args->getf()},{args->getf(),args->getf()}}; } }; -template -struct ControlGetter +template struct ArgumentGetter { - typename FloatPairsArrayT::type operator()(World*, FloatControlsIter& iter) + typename FFTParamsT::type operator()(World* w, sc_msg_iter *args) { - return {{iter.next(),iter.next()},{iter.next(),iter.next()}}; + return {args->geti(),args->geti(),args->geti()}; } }; -//template class RealTime : public SCUnit +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Real Time Processor + +template class RealTime : public SCUnit { using HostVector = FluidTensorView; // using Client = typename Wrapper::ClientType; public: - static void setup(InterfaceTable *ft, const char *name) { registerUnit(ft, name); } - - RealTime(): mControlsIterator{mInBuf + mSpecialIndex + 1,mNumInputs - mSpecialIndex - 1} + static void setup(InterfaceTable *ft, const char *name) + { + registerUnit(ft, name); + ft->fDefineUnitCmd(name,"latency",doLatency); + } + + static void doLatency(Unit *unit, sc_msg_iter *args) + { + float l[] {static_cast(static_cast(unit)->mClient.latency())}; + auto ft = Wrapper::getInterfaceTable(); + ft->fSendNodeReply(&unit->mParent->mNode,-1,Wrapper::getName(), 1, l); + } + + RealTime(): + mControlsIterator{mInBuf + mSpecialIndex + 1,mNumInputs - mSpecialIndex - 1}, + mParams{*Wrapper::getParamDescriptors()}, + mClient{Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld, mControlsIterator)} {} - //mControlsIterator{nullptr,0} {} void init() { - Wrapper *w = static_cast(this); - - auto &mClient = w->client(); + assert(!(mClient.audioChannelsOut() > 0 && mClient.controlChannelsOut() > 0) && "Client can't have both audio and control outputs"); mInputConnections.reserve(mClient.audioChannelsIn()); mOutputConnections.reserve(mClient.audioChannelsOut()); mAudioInputs.reserve(mClient.audioChannelsIn()); - mAudioOutputs.reserve(mClient.audioChannelsOut()); - + mOutputs.reserve(std::max(mClient.audioChannelsOut(),mClient.controlChannelsOut())); + for (int i = 0; i < mClient.audioChannelsIn(); ++i) { mInputConnections.emplace_back(isAudioRateIn(i)); @@ -148,7 +188,12 @@ public: for (int i = 0; i < mClient.audioChannelsOut(); ++i) { mOutputConnections.emplace_back(true); - mAudioOutputs.emplace_back(nullptr, 0, 0); + mOutputs.emplace_back(nullptr, 0, 0); + } + + for (int i = 0; i < mClient.controlChannelsOut(); ++i) + { + mOutputs.emplace_back(nullptr, 0, 0); } set_calc_function(); @@ -157,74 +202,95 @@ public: void next(int n) { - Wrapper *w = static_cast(this); - auto &client = w->client(); - mControlsIterator.reset(mInBuf + client.audioChannelsIn()); - w->setParams( mWorld->mVerbosity > 0, mWorld,mControlsIterator); // forward on inputs N + audio inputs as params + mControlsIterator.reset(mInBuf + 1); //mClient.audioChannelsIn()); + Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld,mControlsIterator); // forward on inputs N + audio inputs as params const Unit *unit = this; - for (int i = 0; i < client.audioChannelsIn(); ++i) + for (int i = 0; i < mClient.audioChannelsIn(); ++i) { if (mInputConnections[i]) mAudioInputs[i].reset(IN(i), 0, fullBufferSize()); } - for (int i = 0; i < client.audioChannelsOut(); ++i) + for (int i = 0; i < mClient.audioChannelsOut(); ++i) + { + if (mOutputConnections[i]) mOutputs[i].reset(out(i), 0, fullBufferSize()); + } + for(int i = 0; i < mClient.controlChannelsOut();++i) { - if (mOutputConnections[i]) mAudioOutputs[i].reset(out(i), 0, fullBufferSize()); + mOutputs[i].reset(out(i),0,1); } - client.process(mAudioInputs, mAudioOutputs); + mClient.process(mAudioInputs, mOutputs); } - private: std::vector mInputConnections; std::vector mOutputConnections; std::vector mAudioInputs; - std::vector mAudioOutputs; + std::vector mOutputs; FloatControlsIter mControlsIterator; +protected: + ParameterSet mParams; + Client mClient; }; -template class NonRealTime +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Non Real Time Processor +template class NonRealTime { public: static void setup(InterfaceTable *ft, const char *name) { DefinePlugInCmd(name, launch, nullptr); } - NonRealTime() {} + NonRealTime(World *world,sc_msg_iter *args): + mParams{*Wrapper::getParamDescriptors()}, + mClient{mParams} + {} void init(){}; static void launch(World *world, void *inUserData, struct sc_msg_iter *args, void *replyAddr) { - Wrapper *w = new Wrapper(); //this has to be on the heap, because it doesn't get destoryed until the async command is done - w->parseBuffers(w, world, args); + + + Wrapper *w = new Wrapper(world,args); //this has to be on the heap, because it doesn't get destoryed until the async command is done int argsPosition = args->count; + auto argsRdPos = args->rdpos; Result result = validateParameters(w, world, args); if (!result.ok()) { std::cout << "FluCoMa Error " << Wrapper::getName() << ": " << result.message().c_str(); + delete w; return; } args->count = argsPosition; - w->setParams(false, world, args); - + args->rdpos = argsRdPos; + Wrapper::setParams(w->mParams,false, world, args); + size_t msgSize = args->getbsize(); - char * completionMsgData = 0; + std::vector completionMessage(msgSize); +// char * completionMsgData = 0; if (msgSize) { - completionMsgData = (char *) world->ft->fRTAlloc(world, msgSize); - args->getb(completionMsgData, msgSize); + args->getb(completionMessage.data(), msgSize); } - world->ft->fDoAsynchronousCommand(world, replyAddr, Wrapper::getName(), w, process, exchangeBuffers, tidyUp, destroy, - msgSize, completionMsgData); + + world->ft->fDoAsynchronousCommand(world, replyAddr, Wrapper::getName(), w, process, exchangeBuffers, tidyUp, destroy,msgSize, completionMessage.data()); } static bool process(World *world, void *data) { return static_cast(data)->process(world); } static bool exchangeBuffers(World *world, void *data) { return static_cast(data)->exchangeBuffers(world); } static bool tidyUp(World *world, void *data) { return static_cast(data)->tidyUp(world); } - static void destroy(World *world, void *data) { delete static_cast(data); } + static void destroy(World *world, void *data) + { + +// void* c = static_cast(data)->mCompletionMessage; +// if(c) world->ft->fRTFree(world,c); + delete static_cast(data); + } +protected: + ParameterSet mParams; + Client mClient; private: - static Result validateParameters(Wrapper *w, World* world, sc_msg_iter *args) + static Result validateParameters(NonRealTime *w, World* world, sc_msg_iter *args) { - auto &c = w->client(); - auto results = c.template checkParameterValues(world, args); + auto results = w->mParams.template checkParameterValues(world, args); for (auto &r : results) { std::cout << r.message() << '\n'; @@ -233,107 +299,122 @@ private: return {}; } - void parseBuffers(Wrapper *w, World *world, sc_msg_iter *args) - { - auto &c = w->client(); - - mBuffersIn.reserve(c.audioBuffersIn()); - mInputs.reserve(c.audioBuffersIn()); - mBuffersOut.reserve(c.audioBuffersOut()); - mOutputs.reserve(c.audioBuffersOut()); - - for (int i = 0; i < c.audioBuffersIn(); i++) - { - mBuffersIn.emplace_back(args->geti(0), world); - mInputs.emplace_back(); - mInputs[i].buffer = &mBuffersIn[i]; - mInputs[i].startFrame = args->geti(0); - mInputs[i].nFrames = args->geti(0); - mInputs[i].startChan = args->geti(0); - mInputs[i].nChans = args->geti(0); - } - - for (int i = 0; i < c.audioBuffersOut(); i++) - { - mBuffersOut.emplace_back(args->geti(0), world); - mOutputs.emplace_back(); - mOutputs[i].buffer = &mBuffersOut[i]; - } - } - bool process(World *world) { - Wrapper *wrapper = static_cast(this); - Result r = wrapper->client().process(mInputs, mOutputs); - + Result r = mClient.process();///mInputs, mOutputs); + if(!r.ok()) { std::cout << "FluCoMa Error " << Wrapper::getName() << ": " << r.message().c_str(); - return false; + return false; } - + return true; } bool exchangeBuffers(World *world) { - for (auto &b : mBuffersOut) b.assignToRT(world); + mParams.template forEachParamType(world); +// for (auto &b : mBuffersOut) b.assignToRT(world); return true; } bool tidyUp(World *world) { - for (auto &b : mBuffersIn) b.cleanUp(); - for (auto &b : mBuffersOut) b.cleanUp(); +// for (auto &b : mBuffersIn) b.cleanUp(); +// for (auto &b : mBuffersOut) b.cleanUp() + mParams.template forEachParamType(); return true; } - std::vector mBuffersIn; - std::vector mBuffersOut; - std::vector mInputs; - std::vector mOutputs; - void * mReplyAddr; - const char * mName; + template + struct AssignBuffer + { + void operator()(typename BufferT::type& p, World* w) + { + if(auto b = static_cast(p.get())) + b->assignToRT(w); + } + }; + + template + struct CleanUpBuffer + { + void operator()(typename BufferT::type& p) + { + if(auto b = static_cast(p.get())) + b->cleanUp(); + } + }; + +// std::vector mBuffersIn; +// std::vector mBuffersOut; +// std::vector mInputs; +// std::vector mOutputs; + char * mCompletionMessage = nullptr; + void * mReplyAddr = nullptr; + const char * mName = nullptr; }; -template class NonRealTimeAndRealTime : public RealTime, public NonRealTime +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// An impossible monstrosty +template class NonRealTimeAndRealTime : public RealTime, public NonRealTime { static void setup(InterfaceTable *ft, const char *name) { - RealTime::setup(ft, name); - NonRealTime::setup(ft, name); + RealTime::setup(ft, name); + NonRealTime::setup(ft, name); } }; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Template Specialisations for NRT/RT -template class FluidSCWrapperImpl; +template class FluidSCWrapperImpl; -template class FluidSCWrapperImpl : public NonRealTime -{}; +template class FluidSCWrapperImpl : public NonRealTime +{ +public: + FluidSCWrapperImpl(World* w, sc_msg_iter *args): NonRealTime(w,args){}; +}; -template class FluidSCWrapperImpl : public RealTime +template class FluidSCWrapperImpl : public RealTime {}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Make base class(es), full of CRTP mixin goodness -template -using FluidSCWrapperBase = FluidSCWrapperImpl, isNonRealTime, isRealTime>; +template +using FluidSCWrapperBase = FluidSCWrapperImpl,Params, isNonRealTime, isRealTime>; } // namespace impl -template class FluidSCWrapper : public impl::FluidSCWrapperBase +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///The main wrapper +template class FluidSCWrapper : public impl::FluidSCWrapperBase { public: - using ClientType = Client; + using Client = C; + using Params = P; + + FluidSCWrapper() //mParams{*getParamDescriptors()}, //impl::FluidSCWrapperBase() + { impl::FluidSCWrapperBase::init(); } + + FluidSCWrapper(World* w, sc_msg_iter *args): impl::FluidSCWrapperBase(w,args) + { impl::FluidSCWrapperBase::init(); } - FluidSCWrapper() { impl::FluidSCWrapperBase::init(); } static const char *getName(const char *setName = nullptr) { static const char *name = nullptr; return (name = setName ? setName : name); } + + static Params *getParamDescriptors(Params *setParams = nullptr) + { + static Params* descriptors = nullptr; + return (descriptors = setParams ? setParams : descriptors); + } static InterfaceTable *getInterfaceTable(InterfaceTable *setTable = nullptr) { @@ -341,32 +422,40 @@ public: return (ft = setTable ? setTable : ft); } - static void setup(InterfaceTable *ft, const char *name) + static void setup(Params& p, InterfaceTable *ft, const char *name) { getName(name); getInterfaceTable(ft); - impl::FluidSCWrapperBase::setup(ft, name); + getParamDescriptors(&p); + impl::FluidSCWrapperBase::setup(ft, name); } - auto setParams(bool verbose, World* world, impl::FloatControlsIter& inputs) + template + static auto& setParams(ParameterSet& p, bool verbose, World* world, impl::FloatControlsIter& inputs) { - return mClient.template setParameterValues(verbose, world, inputs); + p.template setParameterValues(verbose, world, inputs); + return p; } - auto setParams(bool verbose, World* world, sc_msg_iter *args) + template + static auto& setParams(ParameterSet& p, bool verbose, World* world, sc_msg_iter *args) { - return mClient.template setParameterValues(verbose,world, args); + p.template setParameterValues(verbose,world, args); + return p; } - Client &client() { return mClient; } +// impl::ParameterSet mParams; -private: - Client mClient; +// Client &client() { return mClient; } +// +//private: +// Client mClient; }; -template void makeSCWrapper(InterfaceTable *ft, const char *name) +template