diff --git a/CMakeLists.txt b/CMakeLists.txt index 07f08b4..a6c4b9d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ message("${FLUID_ABS_PATH}") # endif() if (NOT (EXISTS "${FLUID_ABS_PATH}/build/fluid_decomposition-exports.cmake")) - message(FATAL_ERROR "Can't find the fluid_decomposition CMake targets file at ${FLUID_ABS_PATH}/build/fluid_decomposition-expors.cmake. Please go to ${FLUID_ABS_PATH}/build and run CMake") + message(FATAL_ERROR "Can't find the fluid_decomposition CMake targets file at ${FLUID_ABS_PATH}/build/fluid_decomposition-exports.cmake. Please go to ${FLUID_ABS_PATH}/build and run CMake") endif() if (NOT (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/")) @@ -61,6 +61,17 @@ if(APPLE OR WIN32) set(CMAKE_SHARED_MODULE_SUFFIX ".scx") endif() +get_property(FFT_SOURCES TARGET HISSTools_FFT PROPERTY INTERFACE_SOURCES) +get_property(FFT_LINK TARGET HISSTools_FFT PROPERTY INTERFACE_LINK_LIBRARIES) + +add_library(FFTLIB STATIC ${FFT_SOURCES}) +target_link_libraries( + FFTLIB PRIVATE ${FFT_LINK} +) + target_compile_options( + FFTLIB PRIVATE $<$>:-mavx -msse -msse2 -msse3 -msse4> + ) + add_library(FLUID_SC_WRAPPER INTERFACE) target_sources(FLUID_SC_WRAPPER INTERFACE diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 16201eb..f93aa09 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -1,4 +1,4 @@ - #pragma once +#pragma once #include "SCBufferAdaptor.hpp" #include @@ -16,299 +16,209 @@ namespace fluid { namespace client { -template class FluidSCWrapper; +template +class FluidSCWrapper; namespace impl { -template struct Setter; -template struct ArgumentGetter; -template struct ControlGetter; -template using msg_iter_method = T (sc_msg_iter::*)(T); - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//Iterate over kr/ir inputs via callbacks from params object +// Iterate over kr/ir inputs via callbacks from params object struct FloatControlsIter { - FloatControlsIter(float** vals, size_t N):mValues(vals), mSize(N) {} - - float next() - { - return mCount >= mSize ? 0 : *mValues[mCount++]; - } - - void reset(float** vals) + FloatControlsIter(float **vals, size_t N) + : mValues(vals) + , mSize(N) + {} + + float next() { return mCount >= mSize ? 0 : *mValues[mCount++]; } + + void reset(float **vals) { mValues = vals; - mCount = 0; + mCount = 0; } - + size_t size() const noexcept { return mSize; } - - 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 ControlGetter : public GetControl -{}; - -//Specializations -template struct ControlGetter -{ - auto operator() (World* w, FloatControlsIter& iter) - { - typename LongT::type bufnum = iter.next(); - return std::unique_ptr(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w): nullptr); - } -}; - -template -struct ControlGetter -{ - typename FloatPairsArrayT::type operator()(World*, FloatControlsIter& iter) - { - return {{iter.next(),iter.next()},{iter.next(),iter.next()}}; - } -}; - -template -struct ControlGetter -{ - typename FFTParamsT::type operator()(World*, FloatControlsIter& iter) - { - return {static_cast(iter.next()),static_cast(iter.next()),static_cast(iter.next())}; - } -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/// Iterate over arguments in sc_msg_iter, via callbacks from params object - -template Method> struct GetArgument -{ - T operator()(World* w, sc_msg_iter *args) - { - T r = (args->*Method)(T{0}); - return r; - } -}; - -//General cases -template struct ArgumentGetter : public GetArgument -{}; - -template struct ArgumentGetter : public GetArgument -{}; - -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 ArgumentGetter -{ - typename FloatPairsArrayT::type operator()(World* w, sc_msg_iter *args) - { - return {{args->getf(),args->getf()},{args->getf(),args->getf()}}; - } -}; - -template struct ArgumentGetter -{ - typename FFTParamsT::type operator()(World* w, sc_msg_iter *args) - { - return {args->geti(),args->geti(),args->geti()}; - } + +private: + float **mValues; + size_t mSize; + size_t mCount{0}; }; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//Real Time Processor + +// Real Time Processor -template class RealTime : public SCUnit +template +class RealTime : public SCUnit { using HostVector = FluidTensorView; + using ParamSetType = typename Client::ParamSetType; + // using Client = typename Wrapper::ClientType; public: static void setup(InterfaceTable *ft, const char *name) { registerUnit(ft, name); - ft->fDefineUnitCmd(name,"latency",doLatency); + ft->fDefineUnitCmd(name, "latency", doLatency); } - - static void doLatency(Unit *unit, sc_msg_iter *args) + + static void doLatency(Unit *unit, sc_msg_iter*) { - float l[] {static_cast(static_cast(unit)->mClient.latency())}; - auto ft = Wrapper::getInterfaceTable(); - + float l[]{static_cast(static_cast(unit)->mClient.latency())}; + auto ft = Wrapper::getInterfaceTable(); + std::stringstream ss; ss << '/' << Wrapper::getName() << "_latency"; std::cout << ss.str() << '\n'; - ft->fSendNodeReply(&unit->mParent->mNode,-1,ss.str().c_str() , 1, l); + ft->fSendNodeReply(&unit->mParent->mNode, -1, ss.str().c_str(), 1, l); } - - RealTime(): - mControlsIterator{mInBuf + mSpecialIndex + 1,mNumInputs - mSpecialIndex - 1}, - mParams{*Wrapper::getParamDescriptors()}, - mClient{Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld, mControlsIterator)} + + RealTime() + : mControlsIterator{mInBuf + mSpecialIndex + 1,static_cast(static_cast(mNumInputs) - mSpecialIndex - 1)} + , mParams{Wrapper::Client::getParameterDescriptors()} + , mClient{Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld, mControlsIterator,true)} {} void init() { - assert(!(mClient.audioChannelsOut() > 0 && mClient.controlChannelsOut() > 0) && "Client can't have both audio and control outputs"); + assert(!(mClient.audioChannelsOut() > 0 && mClient.controlChannelsOut() > 0) && + "Client can't have both audio and control outputs"); //If we don't the number of arguments we expect, the language side code is probably the wrong version //set plugin to no-op, squawk, and bail; - if(mControlsIterator.size() != Wrapper::getParamDescriptors()->count()) + if(mControlsIterator.size() != Client::getParameterDescriptors().count()) { mCalcFunc = Wrapper::getInterfaceTable()->fClearUnitOutputs; - std::cout << "ERROR: " << Wrapper::getName() << - " wrong number of arguments. Expected " << Wrapper::getParamDescriptors()->count() << - ", got " << mControlsIterator.size() << ". Your .sc file and binary plugin might be different versions." << std::endl; + std::cout << "ERROR: " << Wrapper::getName() << " wrong number of arguments. Expected " + << Client::getParameterDescriptors().count() << ", got " << mControlsIterator.size() + << ". Your .sc file and binary plugin might be different versions." << std::endl; return; } - + + mClient.sampleRate(fullSampleRate()); mInputConnections.reserve(mClient.audioChannelsIn()); mOutputConnections.reserve(mClient.audioChannelsOut()); mAudioInputs.reserve(mClient.audioChannelsIn()); - mOutputs.reserve(std::max(mClient.audioChannelsOut(),mClient.controlChannelsOut())); - - for (int i = 0; i < mClient.audioChannelsIn(); ++i) + mOutputs.reserve(std::max(mClient.audioChannelsOut(), mClient.controlChannelsOut())); + + for (int i = 0; i < static_cast(mClient.audioChannelsIn()); ++i) { mInputConnections.emplace_back(isAudioRateIn(i)); mAudioInputs.emplace_back(nullptr, 0, 0); } - for (int i = 0; i < mClient.audioChannelsOut(); ++i) + for (int i = 0; i < static_cast(mClient.audioChannelsOut()); ++i) { mOutputConnections.emplace_back(true); mOutputs.emplace_back(nullptr, 0, 0); } - for (int i = 0; i < mClient.controlChannelsOut(); ++i) - { - mOutputs.emplace_back(nullptr, 0, 0); - } - + for (int i = 0; i < static_cast(mClient.controlChannelsOut()); ++i) { mOutputs.emplace_back(nullptr, 0, 0); } + + set_calc_function(); Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1); + + + } - void next(int n) + void next(int) { mControlsIterator.reset(mInBuf + 1); //mClient.audioChannelsIn()); - Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld,mControlsIterator); // forward on inputs N + audio inputs as params + Wrapper::setParams(mParams, mWorld->mVerbosity > 0, mWorld, mControlsIterator); // forward on inputs N + audio inputs as params + mParams.template constrainParameterValues(); const Unit *unit = this; - for (int i = 0; i < mClient.audioChannelsIn(); ++i) + for (size_t i = 0; i < mClient.audioChannelsIn(); ++i) { if (mInputConnections[i]) mAudioInputs[i].reset(IN(i), 0, fullBufferSize()); } - for (int i = 0; i < mClient.audioChannelsOut(); ++i) + for (size_t i = 0; i < mClient.audioChannelsOut(); ++i) { - if (mOutputConnections[i]) mOutputs[i].reset(out(i), 0, fullBufferSize()); - } - for(int i = 0; i < mClient.controlChannelsOut();++i) - { - mOutputs[i].reset(out(i),0,1); + if (mOutputConnections[i]) mOutputs[i].reset(out(static_cast(i)), 0, fullBufferSize()); } + for (size_t i = 0; i < mClient.controlChannelsOut(); ++i) { mOutputs[i].reset(out(static_cast(i)), 0, 1); } mClient.process(mAudioInputs, mOutputs); } + private: std::vector mInputConnections; std::vector mOutputConnections; std::vector mAudioInputs; std::vector mOutputs; FloatControlsIter mControlsIterator; + protected: - ParameterSet mParams; - Client mClient; + ParamSetType mParams; + Client mClient; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Non Real Time Processor -template class NonRealTime + +template +class NonRealTime { + using ParamSetType = typename Client::ParamSetType; + public: static void setup(InterfaceTable *ft, const char *name) { DefinePlugInCmd(name, launch, nullptr); } - NonRealTime(World *world,sc_msg_iter *args): - mParams{*Wrapper::getParamDescriptors()}, - mClient{mParams} + NonRealTime(World* w, sc_msg_iter* args) + : mParams{Client::getParameterDescriptors()} + , mClient{Wrapper::setParams(mParams, false, w, args)} {} void init(){}; - static void launch(World *world, void *inUserData, struct sc_msg_iter *args, void *replyAddr) + static void launch(World *world, void */*inUserData*/, struct sc_msg_iter *args, void *replyAddr) { - - if(args->tags && ((std::string{args->tags}.size() - 1) != Wrapper::getParamDescriptors()->count())) + if (args->tags && ((std::string{args->tags}.size() - 1) != Client::getParameterDescriptors().count())) { - std::cout << "ERROR: " << Wrapper::getName() << - " wrong number of arguments. Expected " << Wrapper::getParamDescriptors()->count() << - ", got " << (std::string{args->tags}.size() - 1) << ". Your .sc file and binary plugin might be different versions." << std::endl; + std::cout << "ERROR: " << Wrapper::getName() << " wrong number of arguments. Expected " + << Client::getParameterDescriptors().count() << ", got " << (std::string{args->tags}.size() - 1) + << ". Your .sc file and binary plugin might be different versions." << std::endl; return; } - - 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); + + Wrapper *w = new Wrapper( + world, args); // this has to be on the heap, because it doesn't get destroyed until the async command is done + + Result result = validateParameters(w); if (!result.ok()) { - std::cout << "ERROR: " << Wrapper::getName() << ": " << result.message().c_str() << std::endl; - delete w; - return; + std::cout << "ERROR: " << Wrapper::getName() << ": " << result.message().c_str() << std::endl; + delete w; + return; } - args->count = argsPosition; - args->rdpos = argsRdPos; - Wrapper::setParams(w->mParams,false, world, args); - size_t msgSize = args->getbsize(); + size_t msgSize = args->getbsize(); std::vector completionMessage(msgSize); -// char * completionMsgData = 0; - if (msgSize) - { - args->getb(completionMessage.data(), msgSize); - } + // char * completionMsgData = 0; + if (msgSize) { args->getb(completionMessage.data(), msgSize); } - world->ft->fDoAsynchronousCommand(world, replyAddr, Wrapper::getName(), w, process, exchangeBuffers, tidyUp, destroy,msgSize, completionMessage.data()); + world->ft->fDoAsynchronousCommand(world, replyAddr, Wrapper::getName(), w, process, exchangeBuffers, tidyUp, destroy, + static_cast(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) - { - -// void* c = static_cast(data)->mCompletionMessage; -// if(c) world->ft->fRTFree(world,c); - delete static_cast(data); - } + static void destroy(World *, void *data) { delete static_cast(data); } protected: - ParameterSet mParams; - Client mClient; + ParamSetType mParams; + Client mClient; + private: - static Result validateParameters(NonRealTime *w, World* world, sc_msg_iter *args) + + static Result validateParameters(NonRealTime *w) { - auto results = w->mParams.template checkParameterValues(world, args); + auto results = w->mParams.template constrainParameterValues(); for (auto &r : results) { if (!r.ok()) return r; @@ -316,122 +226,157 @@ private: return {}; } - bool process(World *world) + bool process(World *) { - Result r = mClient.process();///mInputs, mOutputs); - - if(!r.ok()) + Result r = mClient.process(); + + if (!r.ok()) { std::cout << "ERROR: " << Wrapper::getName() << ": " << r.message().c_str(); - return false; + return false; } - + return true; } bool exchangeBuffers(World *world) { - mParams.template forEachParamType(world); -// for (auto &b : mBuffersOut) b.assignToRT(world); + mParams.template forEachParamType(world); return true; } - bool tidyUp(World *world) + bool tidyUp(World *) { -// for (auto &b : mBuffersIn) b.cleanUp(); -// for (auto &b : mBuffersOut) b.cleanUp() - mParams.template forEachParamType(); + mParams.template forEachParamType(); return true; } - template + template struct AssignBuffer { - void operator()(typename BufferT::type& p, World* w) + void operator()(const typename BufferT::type &p, World *w) { - if(auto b = static_cast(p.get())) - b->assignToRT(w); + if (auto b = static_cast(p.get())) b->assignToRT(w); } }; - - template + + template struct CleanUpBuffer { - void operator()(typename BufferT::type& p) + void operator()(const typename BufferT::type &p) { - if(auto b = static_cast(p.get())) - b->cleanUp(); + 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; + char * mCompletionMessage = nullptr; + void * mReplyAddr = nullptr; + const char *mName = nullptr; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// An impossible monstrosty -template class NonRealTimeAndRealTime : public RealTime, public NonRealTime +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){}; + 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,Params, isNonRealTime, isRealTime>; +template +using FluidSCWrapperBase = FluidSCWrapperImpl, isNonRealTime, isRealTime>; } // namespace impl //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///The main wrapper -template class FluidSCWrapper : public impl::FluidSCWrapperBase +template +class FluidSCWrapper : public impl::FluidSCWrapperBase { + using FloatControlsIter = impl::FloatControlsIter; + + // Iterate over arguments in sc_msg_iter, via callbacks from params object + + template + struct Setter + { + static constexpr size_t argSize = C::getParameterDescriptors().template get().fixedSize; + + auto fromArgs(World *, FloatControlsIter& args, LongT::type, int) { return args.next(); } + auto fromArgs(World *, FloatControlsIter& args, FloatT::type, int) { return args.next(); } + auto fromArgs(World *, sc_msg_iter* args, LongT::type, int defVal) { return args->geti(defVal); } + auto fromArgs(World *, sc_msg_iter* args, FloatT::type, int) { return args->getf(); } + auto fromArgs(World *w, ArgType args, BufferT::type, int) + { + typename LongT::type bufnum = static_cast(fromArgs(w, args, LongT::type(), -1)); + return BufferT::type(bufnum >= 0 ? new SCBufferAdaptor(bufnum, w) : nullptr); + } + + typename T::type operator()(World *w, ArgType args) + { + ParamLiteralConvertor a; + using LiteralType = typename ParamLiteralConvertor::LiteralType; + + for (size_t i = 0; i < argSize; i++) + a[i] = static_cast(fromArgs(w, args, a[0], 0)); + + return a.value(); + } + }; + + template + using ArgumentSetter = Setter; + + template + using ControlSetter = Setter; + public: using Client = C; - using Params = P; - - FluidSCWrapper() //mParams{*getParamDescriptors()}, //impl::FluidSCWrapperBase() - { impl::FluidSCWrapperBase::init(); } + using ParameterSetType = typename C::ParamSetType; - FluidSCWrapper(World* w, sc_msg_iter *args): impl::FluidSCWrapperBase(w,args) - { impl::FluidSCWrapperBase::init(); } + FluidSCWrapper() // mParams{*getParamDescriptors()}, //impl::FluidSCWrapperBase() + { + impl::FluidSCWrapperBase::init(); + } + FluidSCWrapper(World* w, sc_msg_iter *args): impl::FluidSCWrapperBase(w,args) + { + 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) { @@ -439,42 +384,35 @@ public: return (ft = setTable ? setTable : ft); } - static void setup(Params& p, InterfaceTable *ft, const char *name) + static void setup(InterfaceTable *ft, const char *name) { getName(name); getInterfaceTable(ft); - getParamDescriptors(&p); - impl::FluidSCWrapperBase::setup(ft, name); + impl::FluidSCWrapperBase::setup(ft, name); } - template - static auto& setParams(ParameterSet& p, bool verbose, World* world, impl::FloatControlsIter& inputs) + static auto& setParams(ParameterSetType& p, bool verbose, World* world, FloatControlsIter& inputs, bool constrain = false) { //We won't even try and set params if the arguments don't match - if(inputs.size() == getParamDescriptors()->count()) - p.template setParameterValues(verbose, world, inputs); + if(inputs.size() == C::getParameterDescriptors().count()) + { + p.template setParameterValues(verbose, world, inputs); + if (constrain)p.template constrainParameterValues(); + } return p; } - template - static auto& setParams(ParameterSet& p, bool verbose, World* world, sc_msg_iter *args) + static auto& setParams(ParameterSetType& p, bool verbose, World* world, sc_msg_iter *args) { - p.template setParameterValues(verbose,world, args); + p.template setParameterValues(verbose,world, args); return p; } - -// impl::ParameterSet mParams; - -// Client &client() { return mClient; } -// -//private: -// Client mClient; }; -template