Amend wrapper creation to fetch client and params from different places

This is to enable persistent storage for certain client typee
nix
Owen Green 6 years ago
parent 40691d4217
commit 1eabc42b24

@ -13,6 +13,7 @@ under the European Unions Horizon 2020 research and innovation programme
#include "SCBufferAdaptor.hpp"
#include <clients/common/FluidBaseClient.hpp>
#include <clients/nrt/FluidSharedInstanceAdaptor.hpp>
#include <clients/common/FluidNRTClientWrapper.hpp>
#include <clients/common/Result.hpp>
#include <data/FluidTensor.hpp>
#include <data/TensorTypes.hpp>
@ -87,16 +88,20 @@ class RealTime : public SCUnit
using ParamSetType = typename Client::ParamSetType;
public:
static index ControlOffset(Unit* unit) { return unit->mSpecialIndex + 1; }
static index ControlSize(Unit* unit) { return static_cast<index>(unit->mNumInputs) - unit->mSpecialIndex - 1; }
static void setup(InterfaceTable* ft, const char* name)
{
registerUnit<Wrapper>(ft, name);
ft->fDefineUnitCmd(name, "latency", doLatency);
}
static void doLatency(Unit* unit, sc_msg_iter*)
{
float l[]{
static_cast<float>(static_cast<Wrapper*>(unit)->mClient.latency())};
static_cast<float>(static_cast<Wrapper*>(unit)->mClient.latency())
};
auto ft = Wrapper::getInterfaceTable();
std::stringstream ss;
@ -106,55 +111,51 @@ public:
}
RealTime()
: mControlsIterator{mInBuf + mSpecialIndex + 1,
static_cast<index>(mNumInputs) - mSpecialIndex - 1},
mParams{Wrapper::Client::getParameterDescriptors()},
mClient{Wrapper::setParams(static_cast<Wrapper*>(this),
mParams, mWorld->mVerbosity > 0, mWorld,
mControlsIterator, true)}
{}
void init()
{
auto& client =static_cast<Wrapper*>(this)->mClient;
assert(
!(mClient.audioChannelsOut() > 0 && mClient.controlChannelsOut() > 0) &&
!(client.audioChannelsOut() > 0 && client.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() != Client::getParameterDescriptors().count())
if (static_cast<Wrapper*>(this)->mControlsIterator.size() != Client::getParameterDescriptors().count())
{
mCalcFunc = Wrapper::getInterfaceTable()->fClearUnitOutputs;
std::cout
<< "ERROR: " << Wrapper::getName()
<< " wrong number of arguments. Expected "
<< Client::getParameterDescriptors().count() << ", got "
<< mControlsIterator.size()
<< static_cast<Wrapper*>(this)->mControlsIterator.size()
<< ". Your .sc file and binary plugin might be different versions."
<< std::endl;
return;
}
mClient.sampleRate(fullSampleRate());
mInputConnections.reserve(asUnsigned(mClient.audioChannelsIn()));
mOutputConnections.reserve(asUnsigned(mClient.audioChannelsOut()));
mAudioInputs.reserve(asUnsigned(mClient.audioChannelsIn()));
client.sampleRate(fullSampleRate());
mInputConnections.reserve(asUnsigned(client.audioChannelsIn()));
mOutputConnections.reserve(asUnsigned(client.audioChannelsOut()));
mAudioInputs.reserve(asUnsigned(client.audioChannelsIn()));
mOutputs.reserve(asUnsigned(
std::max(mClient.audioChannelsOut(), mClient.controlChannelsOut())));
std::max(client.audioChannelsOut(), client.controlChannelsOut())));
for (index i = 0; i < mClient.audioChannelsIn(); ++i)
for (index i = 0; i < client.audioChannelsIn(); ++i)
{
mInputConnections.emplace_back(isAudioRateIn(static_cast<int>(i)));
mAudioInputs.emplace_back(nullptr, 0, 0);
}
for (index i = 0; i < mClient.audioChannelsOut(); ++i)
for (index i = 0; i < client.audioChannelsOut(); ++i)
{
mOutputConnections.emplace_back(true);
mOutputs.emplace_back(nullptr, 0, 0);
}
for (index i = 0; i < mClient.controlChannelsOut(); ++i)
for (index i = 0; i < client.controlChannelsOut(); ++i)
{ mOutputs.emplace_back(nullptr, 0, 0); }
mCalcFunc = make_calc_function<RealTime, &RealTime::next>();
@ -163,49 +164,41 @@ public:
void next(int)
{
mControlsIterator.reset(mInBuf + mSpecialIndex +
auto& client = static_cast<Wrapper*>(this)->mClient;
auto& params = static_cast<Wrapper*>(this)->mParams;
static_cast<Wrapper*>(this)->mControlsIterator.reset(mInBuf + mSpecialIndex +
1); // mClient.audioChannelsIn());
Wrapper::setParams(static_cast<Wrapper*>(this),
mParams, mWorld->mVerbosity > 0, mWorld,
mControlsIterator); // forward on inputs N + audio inputs as params
mParams.constrainParameterValues();
params, static_cast<Wrapper*>(this)->mControlsIterator); // forward on inputs N + audio inputs as params
params.constrainParameterValues();
const Unit* unit = this;
for (index i = 0; i < mClient.audioChannelsIn(); ++i)
for (index i = 0; i < client.audioChannelsIn(); ++i)
{
if (mInputConnections[asUnsigned(i)])
{ mAudioInputs[asUnsigned(i)].reset(IN(i), 0, fullBufferSize()); }
}
for (index i = 0; i < mClient.audioChannelsOut(); ++i)
for (index i = 0; i < client.audioChannelsOut(); ++i)
{
assert(i <= std::numeric_limits<int>::max());
if (mOutputConnections[asUnsigned(i)])
mOutputs[asUnsigned(i)].reset(out(static_cast<int>(i)), 0,
fullBufferSize());
}
for (index i = 0; i < mClient.controlChannelsOut(); ++i)
for (index i = 0; i < client.controlChannelsOut(); ++i)
{
assert(i <= std::numeric_limits<int>::max());
mOutputs[asUnsigned(i)].reset(out(static_cast<int>(i)), 0, 1);
}
mClient.process(mAudioInputs, mOutputs, mContext);
client.process(mAudioInputs, mOutputs, mContext);
}
ParamSetType& params()
{
return mParams;
}
private:
std::vector<bool> mInputConnections;
std::vector<bool> mOutputConnections;
std::vector<HostVector> mAudioInputs;
std::vector<HostVector> mOutputs;
FloatControlsIter mControlsIterator;
FluidContext mContext;
protected:
ParamSetType mParams;
Client mClient;
};
////////////////////////////////////////////////////////////////////////////////
@ -220,9 +213,12 @@ class NonRealTime : public SCUnit
using ParamSetType = typename Client::ParamSetType;
public:
static index ControlOffset(Unit*) { return 0; }
static index ControlSize(Unit* unit) { return index(unit->mNumInputs) - unit->mSpecialIndex - 2; }
static void setup(InterfaceTable* ft, const char* name)
{
registerUnit<Wrapper>(ft, name);
ft->fDefineUnitCmd(name, "cancel", doCancel);
ft->fDefineUnitCmd(
name, "queue_enabled", [](struct Unit* unit, struct sc_msg_iter* args) {
@ -253,18 +249,14 @@ public:
}
/// Penultimate input is the doneAction, final is blocking mode. Neither are
/// params, so we skip them in the controlsIterator
/// params, so we skip them in the controlsIterator. We may also have an ID for Model objects
NonRealTime()
: mControlsIterator{mInBuf, index(mNumInputs) - mSpecialIndex - 2},
mParams{Wrapper::Client::getParameterDescriptors()},
mClient{Wrapper::setParams(static_cast<Wrapper*>(this), mParams, mWorld->mVerbosity > 0, mWorld,
mControlsIterator, true)},
mSynchronous{mNumInputs > 2 ? (in0(int(mNumInputs) - 1) > 0) : false}
: mSynchronous{mNumInputs > 2 ? (in0(int(mNumInputs) - 1) > 0) : false}
{}
~NonRealTime()
{
if (mClient.state() == ProcessState::kProcessing)
if (client().state() == ProcessState::kProcessing)
{
std::cout << Wrapper::getName() << ": Processing cancelled" << std::endl;
Wrapper::getInterfaceTable()->fSendNodeReply(&mParent->mNode, 1, "/done",
@ -290,7 +282,7 @@ public:
/// launches tidy up when complete
void poll(int)
{
out0(0) = mDone ? 1.0f : static_cast<float>(mClient.progress());
out0(0) = mDone ? 1.0f : static_cast<float>(client().progress());
if (0 == pollCounter++ && !mCheckingForDone)
{
@ -399,15 +391,13 @@ public:
static_cast<Wrapper*>(unit)->mClient.cancel();
}
ParamSetType& params()
{
return mParams;
}
ParamSetType& params() { return mWrapper->mParams; }
Client& client() { return mWrapper->mClient; }
private:
static Result validateParameters(NonRealTime* w)
static Result validateParameters(NonRealTime* nrt)
{
auto results = w->mParams.constrainParameterValues();
auto results = nrt->params().constrainParameterValues();
for (auto& r : results)
{
if (!r.ok()) return r;
@ -417,7 +407,7 @@ private:
bool exchangeBuffers(World* world) // RT thread
{
mParams.template forEachParamType<BufferT, AssignBuffer>(world);
params().template forEachParamType<BufferT, AssignBuffer>(world);
// At this point, we can see if we're finished and let the language know (or
// it can wait for the doneAction, but that takes extra time) use replyID to
// convey status (0 = normal completion, 1 = cancelled)
@ -430,7 +420,7 @@ private:
bool tidyUp(World*) // NRT thread
{
mParams.template forEachParamType<BufferT, impl::CleanUpBuffer>();
params().template forEachParamType<BufferT, impl::CleanUpBuffer>();
return true;
}
@ -452,7 +442,6 @@ private:
}
};
FloatControlsIter mControlsIterator;
FifoMsg mFifoMsg;
char* mCompletionMessage = nullptr;
void* mReplyAddr = nullptr;
@ -461,12 +450,12 @@ private:
index pollCounter{0};
protected:
ParamSetType mParams;
Client mClient;
bool mSynchronous{true};
bool mQueueEnabled{false};
bool mSynchronous{true};
bool mQueueEnabled{false};
bool mCheckingForDone{false}; // only write to this from RT thread kthx
bool mCancelled{false};
private:
Wrapper* mWrapper{static_cast<Wrapper*>(this)};
};
////////////////////////////////////////////////////////////////////////////////
@ -487,28 +476,137 @@ class NonRealTimeAndRealTime : public RealTime<Client, Wrapper>,
//Discovery for clients that need persistent storage (Dataset and friends)
/// Named, shared clients already have a lookup table in their adaptor class
template <typename T>
struct IsPersistent : std::false_type
{};
struct IsPersistent
{
using type = std::false_type;
};
//TODO: make less tied to current implementation
template <typename T>
struct IsPersistent<NRTThreadingAdaptor<NRTSharedInstanceAdaptor<T>>>
: std::true_type
{};
{
using type = std::true_type;
};
template<typename T>
using IsPersistent_t = typename IsPersistent<T>::type;
/// Models don't, but still need to survive CMD-.
template<typename T>
struct IsModel
{
using type = std::false_type;
};
template<typename T>
struct IsModel<NRTThreadingAdaptor<ClientWrapper<T>>>
{
using type = typename ClientWrapper<T>::isModelObject;
};
template<typename T>
using IsModel_t = typename IsModel<T>::type;
template<typename,typename,typename, typename>
struct LifetimePolicy;
template<typename,typename, bool>
struct ObjectPersistance;
//template<typename Client, typename Wrapper>
//struct LifetimePolicy<Client, Wrapper,std::true_type, std::true_type>
//{
//// static_assert(false,"Shared Objecthood and Model Objecthood are not compatible");
//};
/// Default policy
template<typename Client, typename Wrapper>
struct ObjectPersistance<Client, Wrapper, false>{
void init(){}
struct LifetimePolicy<Client, Wrapper,std::false_type, std::false_type>
{
static void constructClass(Unit* unit)
{
FloatControlsIter controlsReader{unit->mInBuf + Wrapper::ControlOffset(unit),Wrapper::ControlSize(unit)};
auto params = typename Wrapper::ParamSetType{Client::getParameterDescriptors()};
Wrapper::setParams(unit, params, controlsReader);
Client client{params};
new (static_cast<Wrapper*>(unit)) Wrapper(std::move(controlsReader), std::move(client), std::move(params));
}
static void destroyClass(Unit* unit) { static_cast<Wrapper*>(unit)->~Wrapper(); }
static void setup(InterfaceTable*, const char*){}
};
/// Model objects
template<typename Client, typename Wrapper>
struct ObjectPersistance<Client,Wrapper, true>
struct LifetimePolicy<Client, Wrapper,std::true_type, std::false_type>
{
index uid;
struct CacheRecord
{
typename Client::ParamSetType params{Client::getParameterDescriptors()};
Client client{params};
bool leased{false};
};
using Cache = std::unordered_map<index,CacheRecord>;
static void constructClass(Unit* unit)
{
index uid = static_cast<index>(unit->mInBuf[Wrapper::ControlOffset(unit)][0]);
FloatControlsIter controlsReader{unit->mInBuf + 1 + Wrapper::ControlOffset(unit),Wrapper::ControlSize(unit)};
auto& entry = mRegistry[uid];
auto& client = entry.client;
auto& params = entry.params;
if(entry.leased) //if this happens, then the client has probably messed up
{
std::cout << "ERROR: ID " << uid << "is already being used by the cache" << std::endl;
return;
}
Wrapper::setParams(unit, entry.params,controlsReader);
new (static_cast<Wrapper*>(unit)) Wrapper{std::move(controlsReader),std::move(client),std::move(params)};
static_cast<Wrapper*>(unit)->uid = uid;
entry.leased = true;
}
static void destroyClass(Unit* unit)
{
auto wrapper = static_cast<Wrapper*>(unit);
index uid = wrapper->uid;
auto pos = mRegistry.find(uid);
if( pos != mRegistry.end() )
{
//on cmd-. live to fight another day
auto& entry = *pos;
entry.second.client = std::move(wrapper->client());
entry.second.params = std::move(wrapper->params());
entry.second.leased = false;
}
wrapper->~Wrapper();
}
static void setup(InterfaceTable* ft, const char* name)
{
ft->fDefineUnitCmd(name, "free", [](Unit* unit, sc_msg_iter*)
{
//This ABSOLUTELY ASSUMES the client is going to also delete
//the Unit by calling Synth.free.
auto wrapper = static_cast<Wrapper*>(unit);
mRegistry.erase(wrapper->uid);
});
}
private:
static std::unordered_map<index,CacheRecord> mRegistry;
};
template<typename Client, typename Wrapper>
typename LifetimePolicy<Client, Wrapper, std::true_type, std::false_type>::Cache
LifetimePolicy<Client, Wrapper, std::true_type, std::false_type>::mRegistry{};
/// Shared objects
template<typename Client, typename Wrapper>
struct LifetimePolicy<Client, Wrapper,std::false_type, std::true_type>
{
template<typename> struct GetSharedType;
@ -522,12 +620,24 @@ struct ObjectPersistance<Client,Wrapper, true>
using SharedType = typename GetSharedType<Client>::type;
using ClientPointer = typename SharedType::ClientPointer;
void init()
static void constructClass(Unit* unit)
{
auto clientRef = getClientPointer(static_cast<Wrapper*>(this));
FloatControlsIter controlsReader{unit->mInBuf + Wrapper::ControlOffset(unit),Wrapper::ControlSize(unit)};
auto params = typename Client::ParamSetType{Client::getParameterDescriptors()};
Wrapper::setParams(unit, params,controlsReader);
auto& name = params.template get<0>();
auto client = Client{params};
auto clientRef = SharedType::lookup(name);
auto pos = mRegistry.find(clientRef);
if(pos == mRegistry.end()) mRegistry.emplace(clientRef);
new (static_cast<Wrapper*>(unit)) Wrapper(std::move(controlsReader),std::move(client),std::move(params));
}
static void destroyClass(Unit* unit) { static_cast<Wrapper*>(unit)->~Wrapper(); }
static void setup(InterfaceTable* ft, const char* name)
{
@ -538,9 +648,7 @@ struct ObjectPersistance<Client,Wrapper, true>
if(pos != mRegistry.end()) mRegistry.erase(clientRef);
});
}
private:
static ClientPointer getClientPointer(Wrapper* wrapper)
{
auto& params = wrapper->params();
@ -552,40 +660,44 @@ private:
};
template<typename Client, typename Wrapper>
std::unordered_set<typename ObjectPersistance<Client,Wrapper, true>::ClientPointer>
ObjectPersistance<Client,Wrapper, true>::mRegistry;
// Template Specialisations for NRT/RT
std::unordered_set<typename LifetimePolicy<Client, Wrapper, std::false_type, std::true_type>::ClientPointer>
LifetimePolicy<Client, Wrapper, std::false_type, std::true_type>::mRegistry{};
//// Template Specialisations for NRT/RT
template <typename Client, typename Wrapper, typename NRT, typename RT>
class FluidSCWrapperImpl;
template <typename Client, typename Wrapper>
class FluidSCWrapperImpl<Client, Wrapper, std::true_type, std::false_type>
: public NonRealTime<Client, Wrapper>, public ObjectPersistance<Client,Wrapper,IsPersistent<Client>::value>
: public NonRealTime<Client, Wrapper>,
public LifetimePolicy<Client,Wrapper,IsModel_t<Client>, IsPersistent_t<Client>>
{
public:
void init(){
NonRealTime<Client,Wrapper>::init();
ObjectPersistance<Client,Wrapper,IsPersistent<Client>::value>::init();
}
static void setup(InterfaceTable* ft, const char* name){
static void setup(InterfaceTable* ft, const char* name)
{
NonRealTime<Client,Wrapper>::setup(ft,name);
ObjectPersistance<Client,Wrapper,IsPersistent<Client>::value>::setup(ft,name);
LifetimePolicy<Client,Wrapper,IsModel_t<Client>, IsPersistent_t<Client>>::setup(ft,name);
}
};
template <typename Client, typename Wrapper>
class FluidSCWrapperImpl<Client, Wrapper, std::false_type, std::true_type>
: public RealTime<Client, Wrapper>, public ObjectPersistance<Client,Wrapper,IsPersistent<Client>::value>
: public RealTime<Client, Wrapper>,
public LifetimePolicy<Client,Wrapper,IsModel_t<Client>, IsPersistent_t<Client>>
{
public:
void init(){
RealTime<Client,Wrapper>::init();
ObjectPersistance<Client,Wrapper,IsPersistent<Client>::value>::init();
}
static void setup(InterfaceTable* ft, const char* name){
static void setup(InterfaceTable* ft, const char* name)
{
RealTime<Client,Wrapper>::setup(ft,name);
ObjectPersistance<Client,Wrapper,IsPersistent<Client>::value>::setup(ft,name);
LifetimePolicy<Client,Wrapper,IsModel_t<Client>, IsPersistent_t<Client>>::setup(ft,name);
}
};
@ -608,6 +720,10 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
using FloatControlsIter = impl::FloatControlsIter;
//I would like to template these to something more scaleable, but baby steps
friend class impl::RealTime<C,FluidSCWrapper>;
friend class impl::NonRealTime<C,FluidSCWrapper>;
template <typename ArgType>
struct ParamReader
{
@ -692,20 +808,20 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
return tag == 's';
}
static auto fromArgs(FluidSCWrapper*, World*, sc_msg_iter* args, std::string, int)
static auto fromArgs(Unit*, sc_msg_iter* args, std::string, int)
{
const char* recv = args->gets("");
return std::string(recv ? recv : "");
}
static auto fromArgs(FluidSCWrapper*,World* w, FloatControlsIter& args, std::string, int)
static auto fromArgs(Unit* x, FloatControlsIter& args, std::string, int)
{
// first is string size, then chars
index size = static_cast<index>(args.next());
char* chunk =
static_cast<char*>(FluidSCWrapper::getInterfaceTable()->fRTAlloc(
w, asUnsigned(size + 1)));
x->mWorld, asUnsigned(size + 1)));
if (!chunk)
{
@ -718,74 +834,74 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
chunk[i] = static_cast<char>(args.next());
chunk[size] = 0; // terminate string
//todo: Did I check that this is getting cleaned up somewhere? It doesn't
//look like it is
return std::string{chunk};
}
template <typename T>
static std::enable_if_t<std::is_integral<T>::value, T>
fromArgs(FluidSCWrapper*,World*, FloatControlsIter& args, T, int)
fromArgs(Unit*, FloatControlsIter& args, T, int)
{
return static_cast<index>(args.next());
}
template <typename T>
static std::enable_if_t<std::is_floating_point<T>::value, T>
fromArgs(FluidSCWrapper*,World*, FloatControlsIter& args, T, int)
fromArgs(Unit*, FloatControlsIter& args, T, int)
{
return args.next();
}
template <typename T>
static std::enable_if_t<std::is_integral<T>::value, T>
fromArgs(FluidSCWrapper*,World*, sc_msg_iter* args, T, int defVal)
fromArgs(Unit*, sc_msg_iter* args, T, int defVal)
{
return args->geti(defVal);
}
template <typename T>
static std::enable_if_t<std::is_floating_point<T>::value, T>
fromArgs(World*, sc_msg_iter* args, T, int)
fromArgs(Unit*, sc_msg_iter* args, T, int)
{
return args->getf();
}
static SCBufferAdaptor* fetchBuffer(FluidSCWrapper* x, World* w, index bufnum)
static SCBufferAdaptor* fetchBuffer(Unit* x, index bufnum)
{
if(bufnum >= w->mNumSndBufs)
if(bufnum >= x->mWorld->mNumSndBufs)
{
index localBufNum = bufnum - w->mNumSndBufs;
index localBufNum = bufnum - x->mWorld->mNumSndBufs;
Graph* parent = static_cast<Unit*>(x)->mParent;
Graph* parent = x->mParent;
return localBufNum <= parent -> localMaxBufNum ?
new SCBufferAdaptor(parent->mLocalSndBufs + localBufNum,w,true)
return localBufNum <= parent->localMaxBufNum ?
new SCBufferAdaptor(parent->mLocalSndBufs + localBufNum,x->mWorld,true)
: nullptr;
}
else
return bufnum >= 0 ? new SCBufferAdaptor(bufnum, w) : nullptr;
return bufnum >= 0 ? new SCBufferAdaptor(bufnum, x->mWorld) : nullptr;
}
static auto fromArgs(FluidSCWrapper* x,World* w, ArgType args, BufferT::type&, int)
static auto fromArgs(Unit* x, ArgType args, BufferT::type&, int)
{
typename LongT::type bufnum = static_cast<typename LongT::type>(
ParamReader::fromArgs(x, w, args, typename LongT::type(), -1));
return BufferT::type(fetchBuffer(x,w,bufnum));
ParamReader::fromArgs(x, args, typename LongT::type(), -1));
return BufferT::type(fetchBuffer(x, bufnum));
}
static auto fromArgs(FluidSCWrapper* x,World* w, ArgType args, InputBufferT::type&, int)
static auto fromArgs(Unit* x, ArgType args, InputBufferT::type&, int)
{
typename LongT::type bufnum =
static_cast<LongT::type>(fromArgs(x, w, args, LongT::type(), -1));
return InputBufferT::type(fetchBuffer(x,w,bufnum));
static_cast<LongT::type>(fromArgs(x, args, LongT::type(), -1));
return InputBufferT::type(fetchBuffer(x, bufnum));
}
template <typename P>
static std::enable_if_t<IsSharedClient<P>::value, P>
fromArgs(FluidSCWrapper* x,World* w, ArgType args, P&, int)
fromArgs(Unit* x, ArgType args, P&, int)
{
return {fromArgs(x, w, args, std::string{}, 0).c_str()};
return {fromArgs(x, args, std::string{}, 0).c_str()};
}
};
@ -797,7 +913,7 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
static constexpr index argSize =
C::getParameterDescriptors().template get<N>().fixedSize;
typename T::type operator()(FluidSCWrapper* x, World* w, ArgType args)
typename T::type operator()(Unit* x, ArgType args)
{
// Just return default if there's nothing left to grab
if (args.remain() == 0)
@ -813,7 +929,7 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
for (index i = 0; i < argSize; i++)
a[i] = static_cast<LiteralType>(
ParamReader<ArgType>::fromArgs(x, w, args, a[0], 0));
ParamReader<ArgType>::fromArgs(x, args, a[0], 0));
return a.value();
}
@ -977,14 +1093,12 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
using ReturnType = typename MessageDescriptor::ReturnType;
using IndexList = typename MessageDescriptor::IndexList;
using MessageData = MessageDispatch<N, ReturnType, ArgTuple>;
auto ft = getInterfaceTable();
void* msgptr = ft->fRTAlloc(x->mWorld, sizeof(MessageData));
MessageData* msg = new (msgptr) MessageData;
msg->name = '/' + Client::getMessageDescriptors().template name<N>();
msg->wrapper = x;
ArgTuple& args = msg->args;
// type check OSC message
std::string tags(inArgs->tags + inArgs->count);
@ -1008,14 +1122,14 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
auto tagsIter = tags.begin();
auto tagsEnd = tags.end();
ForEach(args,[&typesMatch,&tagsIter,&tagsEnd](auto& x){
ForEach(args,[&typesMatch,&tagsIter,&tagsEnd](auto& arg){
if(tagsIter == tagsEnd)
{
typesMatch = false;
return;
}
char t = *(tagsIter++);
typesMatch = typesMatch && ParamReader<sc_msg_iter*>::argTypeOK(x,t);
typesMatch = typesMatch && ParamReader<sc_msg_iter*>::argTypeOK(arg,t);
});
willContinue = willContinue && typesMatch;
@ -1056,7 +1170,7 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
///
ForEach(args,[x,&inArgs](auto& arg){
arg = ParamReader<sc_msg_iter*>::fromArgs(x,x->mWorld,inArgs,arg,0);
arg = ParamReader<sc_msg_iter*>::fromArgs(x, inArgs,arg,0);
});
@ -1108,8 +1222,6 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
return x->mClient.template invoke<N>(x->mClient, std::get<Is>(args)...);
}
template <typename T> // call from RT
static void messageOutput(FluidSCWrapper* x, const std::string& s,
MessageResult<T>& result)
@ -1165,9 +1277,17 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
public:
using Client = C;
using ParameterSetType = typename C::ParamSetType;
using ParamSetType = typename C::ParamSetType;
FluidSCWrapper() { impl::FluidSCWrapperBase<Client>::init(); }
FluidSCWrapper(FloatControlsIter&& i, Client&& c, ParamSetType&& p):
mControlsIterator{std::move(i)},
mParams{std::move(p)}, mClient{std::move(c)}
{
mClient.setParams(mParams); //<-IMPORTANT: client's ref to params is by address, and this has just changed
impl::FluidSCWrapperBase<Client>::init();
}
static const char* getName(const char* setName = nullptr)
{
@ -1185,20 +1305,20 @@ public:
{
getName(name);
getInterfaceTable(ft);
registerUnit(ft, name);
impl::FluidSCWrapperBase<Client>::setup(ft, name);
Client::getMessageDescriptors().template iterate<SetupMessage>();
ft->fDefineUnitCmd(name, "version", doVersion);
}
static auto& setParams(FluidSCWrapper* x, ParameterSetType& p, bool verbose, World* world,
static auto& setParams(Unit* x, ParamSetType& p,
FloatControlsIter& inputs, bool constrain = false)
{
//TODO: Regain this robustness if possible?
// We won't even try and set params if the arguments don't match
// if (inputs.size() == C::getParameterDescriptors().count())
// {
p.template setParameterValues<ControlSetter>(verbose, x, world, inputs);
p.template setParameterValues<ControlSetter>(x->mWorld->mVerbosity > 0, x, inputs);
if (constrain) p.constrainParameterValues();
// }
// else
@ -1235,6 +1355,21 @@ public:
}
}
}
auto& client() { return mClient; }
auto& params() { return mParams; }
private:
static void registerUnit(InterfaceTable* ft, const char* name) {
UnitCtorFunc ctor =impl::FluidSCWrapperBase<Client>::constructClass;
UnitDtorFunc dtor = impl::FluidSCWrapperBase<Client>::destroyClass;
(*ft->fDefineUnit)(name, sizeof(FluidSCWrapper), ctor, dtor, 0);
}
FloatControlsIter mControlsIterator;
ParamSetType mParams;
Client mClient;
};
template <typename Client>

Loading…
Cancel
Save