Formatting

nix
Owen Green 6 years ago
parent 83a18adb62
commit ac7fc5b29c

@ -11,16 +11,12 @@ under the European Unions Horizon 2020 research and innovation programme
#pragma once #pragma once
#include "SCBufferAdaptor.hpp" #include "SCBufferAdaptor.hpp"
#include <FluidVersion.hpp>
#include <clients/common/FluidBaseClient.hpp> #include <clients/common/FluidBaseClient.hpp>
#include <clients/common/Result.hpp> #include <clients/common/Result.hpp>
#include <data/FluidTensor.hpp> #include <data/FluidTensor.hpp>
#include <data/TensorTypes.hpp> #include <data/TensorTypes.hpp>
#include <FluidVersion.hpp>
#include <SC_PlugIn.hpp> #include <SC_PlugIn.hpp>
#include <algorithm> #include <algorithm>
#include <string> #include <string>
#include <tuple> #include <tuple>
@ -39,14 +35,11 @@ namespace impl {
// Iterate over kr/ir inputs via callbacks from params object // Iterate over kr/ir inputs via callbacks from params object
struct FloatControlsIter struct FloatControlsIter
{ {
FloatControlsIter(float **vals, index N) FloatControlsIter(float** vals, index N) : mValues(vals), mSize(N) {}
: mValues(vals)
, mSize(N)
{}
float next() { return mCount >= mSize ? 0 : *mValues[mCount++]; } float next() { return mCount >= mSize ? 0 : *mValues[mCount++]; }
void reset(float **vals) void reset(float** vals)
{ {
mValues = vals; mValues = vals;
mCount = 0; mCount = 0;
@ -55,12 +48,12 @@ struct FloatControlsIter
index size() const noexcept { return mSize; } index size() const noexcept { return mSize; }
private: private:
float **mValues; float** mValues;
index mSize; index mSize;
index mCount{0}; index mCount{0};
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Real Time Processor // Real Time Processor
@ -70,18 +63,17 @@ class RealTime : public SCUnit
using HostVector = FluidTensorView<float, 1>; using HostVector = FluidTensorView<float, 1>;
using ParamSetType = typename Client::ParamSetType; using ParamSetType = typename Client::ParamSetType;
// using Client = typename Wrapper::ClientType;
public: public:
static void setup(InterfaceTable *ft, const char *name) static void setup(InterfaceTable* ft, const char* name)
{ {
registerUnit<Wrapper>(ft, name); registerUnit<Wrapper>(ft, name);
ft->fDefineUnitCmd(name, "latency", doLatency); ft->fDefineUnitCmd(name, "latency", doLatency);
} }
static void doLatency(Unit *unit, sc_msg_iter*) static void doLatency(Unit* unit, sc_msg_iter*)
{ {
float l[]{static_cast<float>(static_cast<Wrapper *>(unit)->mClient.latency())}; float l[]{
static_cast<float>(static_cast<Wrapper*>(unit)->mClient.latency())};
auto ft = Wrapper::getInterfaceTable(); auto ft = Wrapper::getInterfaceTable();
std::stringstream ss; std::stringstream ss;
@ -91,24 +83,31 @@ public:
} }
RealTime() RealTime()
: mControlsIterator{mInBuf + mSpecialIndex + 1,static_cast<index>(mNumInputs) - mSpecialIndex - 1} : mControlsIterator{mInBuf + mSpecialIndex + 1,
, mParams{Wrapper::Client::getParameterDescriptors()} static_cast<index>(mNumInputs) - mSpecialIndex - 1},
, mClient{Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld, mControlsIterator,true)} mParams{Wrapper::Client::getParameterDescriptors()},
mClient{Wrapper::setParams(mParams, mWorld->mVerbosity > 0, mWorld,
mControlsIterator, true)}
{} {}
void init() void init()
{ {
assert(!(mClient.audioChannelsOut() > 0 && mClient.controlChannelsOut() > 0) && assert(
!(mClient.audioChannelsOut() > 0 && mClient.controlChannelsOut() > 0) &&
"Client can't have both audio and control outputs"); "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 // If we don't the number of arguments we expect, the language side code is
//set plugin to no-op, squawk, and bail; // probably the wrong version set plugin to no-op, squawk, and bail;
if(mControlsIterator.size() != Client::getParameterDescriptors().count()) if (mControlsIterator.size() != Client::getParameterDescriptors().count())
{ {
mCalcFunc = Wrapper::getInterfaceTable()->fClearUnitOutputs; mCalcFunc = Wrapper::getInterfaceTable()->fClearUnitOutputs;
std::cout << "ERROR: " << Wrapper::getName() << " wrong number of arguments. Expected " std::cout
<< Client::getParameterDescriptors().count() << ", got " << mControlsIterator.size() << "ERROR: " << Wrapper::getName()
<< ". Your .sc file and binary plugin might be different versions." << std::endl; << " wrong number of arguments. Expected "
<< Client::getParameterDescriptors().count() << ", got "
<< mControlsIterator.size()
<< ". Your .sc file and binary plugin might be different versions."
<< std::endl;
return; return;
} }
@ -116,7 +115,8 @@ public:
mInputConnections.reserve(asUnsigned(mClient.audioChannelsIn())); mInputConnections.reserve(asUnsigned(mClient.audioChannelsIn()));
mOutputConnections.reserve(asUnsigned(mClient.audioChannelsOut())); mOutputConnections.reserve(asUnsigned(mClient.audioChannelsOut()));
mAudioInputs.reserve(asUnsigned(mClient.audioChannelsIn())); mAudioInputs.reserve(asUnsigned(mClient.audioChannelsIn()));
mOutputs.reserve(asUnsigned(std::max(mClient.audioChannelsOut(), mClient.controlChannelsOut()))); mOutputs.reserve(asUnsigned(
std::max(mClient.audioChannelsOut(), mClient.controlChannelsOut())));
for (index i = 0; i < mClient.audioChannelsIn(); ++i) for (index i = 0; i < mClient.audioChannelsIn(); ++i)
{ {
@ -130,7 +130,8 @@ public:
mOutputs.emplace_back(nullptr, 0, 0); mOutputs.emplace_back(nullptr, 0, 0);
} }
for (index i = 0; i < mClient.controlChannelsOut(); ++i) { mOutputs.emplace_back(nullptr, 0, 0); } for (index i = 0; i < mClient.controlChannelsOut(); ++i)
{ mOutputs.emplace_back(nullptr, 0, 0); }
mCalcFunc = make_calc_function<RealTime, &RealTime::next>(); mCalcFunc = make_calc_function<RealTime, &RealTime::next>();
Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1); Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1);
@ -138,28 +139,30 @@ public:
void next(int) void next(int)
{ {
mControlsIterator.reset(mInBuf + 1); //mClient.audioChannelsIn()); 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.constrainParameterValues(); mParams.constrainParameterValues();
const Unit *unit = this; const Unit* unit = this;
for (index i = 0; i < mClient.audioChannelsIn(); ++i) for (index i = 0; i < mClient.audioChannelsIn(); ++i)
{ {
if (mInputConnections[asUnsigned(i)]) if (mInputConnections[asUnsigned(i)])
{ { mAudioInputs[asUnsigned(i)].reset(IN(i), 0, fullBufferSize()); }
mAudioInputs[asUnsigned(i)].reset(IN(i), 0, fullBufferSize());
}
} }
for (index i = 0; i < mClient.audioChannelsOut(); ++i) for (index i = 0; i < mClient.audioChannelsOut(); ++i)
{ {
assert(i <= std::numeric_limits<int>::max()); assert(i <= std::numeric_limits<int>::max());
if (mOutputConnections[asUnsigned(i)]) mOutputs[asUnsigned(i)].reset(out(static_cast<int>(i)), 0, fullBufferSize()); 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 < mClient.controlChannelsOut(); ++i)
{ {
assert(i <= std::numeric_limits<int>::max()); assert(i <= std::numeric_limits<int>::max());
mOutputs[asUnsigned(i)].reset(out(static_cast<int>(i)), 0, 1); mOutputs[asUnsigned(i)].reset(out(static_cast<int>(i)), 0, 1);
} }
mClient.process(mAudioInputs, mOutputs,mContext); mClient.process(mAudioInputs, mOutputs, mContext);
} }
private: private:
@ -175,93 +178,103 @@ protected:
Client mClient; Client mClient;
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// Non Real Time Processor /// Non Real Time Processor
/// This is also a UGen, but the main action is delegated off to a worker thread, via the NRT thread. /// This is also a UGen, but the main action is delegated off to a worker
/// The RT bit is there to allow us (a) to poll our thread and (b) emit a kr progress update /// thread, via the NRT thread. The RT bit is there to allow us (a) to poll our
/// thread and (b) emit a kr progress update
template <typename Client, typename Wrapper> template <typename Client, typename Wrapper>
class NonRealTime: public SCUnit class NonRealTime : public SCUnit
{ {
using ParamSetType = typename Client::ParamSetType; using ParamSetType = typename Client::ParamSetType;
public: public:
static void setup(InterfaceTable* ft, const char* name)
static void setup(InterfaceTable *ft, const char *name)
{ {
registerUnit<Wrapper>(ft, name); registerUnit<Wrapper>(ft, name);
ft->fDefineUnitCmd(name, "cancel", doCancel); ft->fDefineUnitCmd(name, "cancel", doCancel);
ft->fDefineUnitCmd(name, "queue_enabled", [](struct Unit* unit, struct sc_msg_iter* args) ft->fDefineUnitCmd(
{ name, "queue_enabled", [](struct Unit* unit, struct sc_msg_iter* args) {
auto w = static_cast<Wrapper *>(unit); auto w = static_cast<Wrapper*>(unit);
w->mQueueEnabled = args->geti(0); w->mQueueEnabled = args->geti(0);
w->mFifoMsg.Set(w->mWorld,[](FifoMsg* f) w->mFifoMsg.Set(
{ w->mWorld,
[](FifoMsg* f) {
auto w = static_cast<Wrapper*>(f->mData); auto w = static_cast<Wrapper*>(f->mData);
w->mClient.setQueueEnabled(w->mQueueEnabled); w->mClient.setQueueEnabled(w->mQueueEnabled);
},nullptr,w); },
nullptr, w);
Wrapper::getInterfaceTable()->fSendMsgFromRT(w->mWorld, w->mFifoMsg); Wrapper::getInterfaceTable()->fSendMsgFromRT(w->mWorld, w->mFifoMsg);
}); });
ft->fDefineUnitCmd(name, "synchronous", [](struct Unit* unit, struct sc_msg_iter* args) ft->fDefineUnitCmd(
{ name, "synchronous", [](struct Unit* unit, struct sc_msg_iter* args) {
auto w = static_cast<Wrapper *>(unit); auto w = static_cast<Wrapper*>(unit);
w->mSynchronous = args->geti(0); w->mSynchronous = args->geti(0);
w->mFifoMsg.Set(w->mWorld,[](FifoMsg* f) w->mFifoMsg.Set(
{ w->mWorld,
[](FifoMsg* f) {
auto w = static_cast<Wrapper*>(f->mData); auto w = static_cast<Wrapper*>(f->mData);
w->mClient.setSynchronous(w->mSynchronous); w->mClient.setSynchronous(w->mSynchronous);
},nullptr,w); },
nullptr, w);
Wrapper::getInterfaceTable()->fSendMsgFromRT(w->mWorld, w->mFifoMsg); Wrapper::getInterfaceTable()->fSendMsgFromRT(w->mWorld, w->mFifoMsg);
}); });
} }
/// Penultimate input is the doneAction, final is blocking mode. Neither are params, so we skip them in the controlsIterator /// Penultimate input is the doneAction, final is blocking mode. Neither are
NonRealTime() : /// params, so we skip them in the controlsIterator
mControlsIterator{mInBuf,index(mNumInputs) - mSpecialIndex - 2} NonRealTime()
, mParams{Wrapper::Client::getParameterDescriptors()} : mControlsIterator{mInBuf, index(mNumInputs) - mSpecialIndex - 2},
, mClient{Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld, mControlsIterator,true)} mParams{Wrapper::Client::getParameterDescriptors()},
, mSynchronous{mNumInputs > 2 ? (in0(int(mNumInputs) - 1) > 0) : false} mClient{Wrapper::setParams(mParams, mWorld->mVerbosity > 0, mWorld,
mControlsIterator, true)},
mSynchronous{mNumInputs > 2 ? (in0(int(mNumInputs) - 1) > 0) : false}
{} {}
~NonRealTime() ~NonRealTime()
{ {
if(mClient.state() == ProcessState::kProcessing) if (mClient.state() == ProcessState::kProcessing)
{ {
std::cout << Wrapper::getName() << ": Processing cancelled \n"; std::cout << Wrapper::getName() << ": Processing cancelled \n";
Wrapper::getInterfaceTable()->fSendNodeReply(&mParent->mNode,1,"/done",0,nullptr); Wrapper::getInterfaceTable()->fSendNodeReply(&mParent->mNode, 1, "/done",
0, nullptr);
} }
//processing will be cancelled in ~NRTThreadAdaptor() // processing will be cancelled in ~NRTThreadAdaptor()
} }
/// No option of not using a worker thread for now /// No option of not using a worker thread for now
/// init() sets up the NRT process via the SC NRT thread, and then sets our UGen calc function going /// init() sets up the NRT process via the SC NRT thread, and then sets our
/// UGen calc function going
void init() void init()
{ {
mFifoMsg.Set(mWorld, initNRTJob, nullptr, this); mFifoMsg.Set(mWorld, initNRTJob, nullptr, this);
mWorld->ft->fSendMsgFromRT(mWorld,mFifoMsg); mWorld->ft->fSendMsgFromRT(mWorld, mFifoMsg);
//we want to poll thread roughly every 20ms // we want to poll thread roughly every 20ms
checkThreadInterval = static_cast<index>(0.02 / controlDur()); checkThreadInterval = static_cast<index>(0.02 / controlDur());
set_calc_function<NonRealTime, &NonRealTime::poll>(); set_calc_function<NonRealTime, &NonRealTime::poll>();
}; };
/// The calc function. Checks to see if we've cancelled, spits out progress, launches tidy up when complete /// The calc function. Checks to see if we've cancelled, spits out progress,
/// launches tidy up when complete
void poll(int) void poll(int)
{ {
out0(0) = mDone ? 1.0 : static_cast<float>(mClient.progress()); out0(0) = mDone ? 1.0 : static_cast<float>(mClient.progress());
if(0 == pollCounter++ && !mCheckingForDone) if (0 == pollCounter++ && !mCheckingForDone)
{ {
mCheckingForDone = true; mCheckingForDone = true;
mWorld->ft->fDoAsynchronousCommand(mWorld, nullptr, Wrapper::getName(), this, mWorld->ft->fDoAsynchronousCommand(mWorld, nullptr, Wrapper::getName(),
postProcess, exchangeBuffers, tidyUp, destroy, this, postProcess, exchangeBuffers,
0, nullptr); tidyUp, destroy, 0, nullptr);
} }
pollCounter %= checkThreadInterval; pollCounter %= checkThreadInterval;
} }
/// To be called on NRT thread. Validate parameters and commence processing in new thread /// To be called on NRT thread. Validate parameters and commence processing in
/// new thread
static void initNRTJob(FifoMsg* f) static void initNRTJob(FifoMsg* f)
{ {
auto w = static_cast<Wrapper*>(f->mData); auto w = static_cast<Wrapper*>(f->mData);
@ -272,7 +285,8 @@ public:
if (!result.ok()) if (!result.ok())
{ {
std::cout << "ERROR: " << Wrapper::getName() << ": " << result.message().c_str() << std::endl; std::cout << "ERROR: " << Wrapper::getName() << ": "
<< result.message().c_str() << std::endl;
return; return;
} }
w->mClient.setSynchronous(w->mSynchronous); w->mClient.setSynchronous(w->mSynchronous);
@ -281,27 +295,35 @@ public:
} }
/// Check result and report if bad /// Check result and report if bad
static bool postProcess(World*, void *data) static bool postProcess(World*, void* data)
{ {
auto w = static_cast<Wrapper*>(data); auto w = static_cast<Wrapper*>(data);
Result r; Result r;
ProcessState s = w->mClient.checkProgress(r); ProcessState s = w->mClient.checkProgress(r);
if((s==ProcessState::kDone || s==ProcessState::kDoneStillProcessing) if ((s == ProcessState::kDone || s == ProcessState::kDoneStillProcessing) ||
|| (w->mSynchronous && s==ProcessState::kNoProcess) ) //I think this hinges on the fact that when mSynchrous = true, this call will always be behind process() on the command FIFO, so we can assume that if the state is kNoProcess, it has run (vs never having run) (w->mSynchronous &&
s == ProcessState::kNoProcess)) // I think this hinges on the fact that
// when mSynchrous = true, this call
// will always be behind process() on
// the command FIFO, so we can assume
// that if the state is kNoProcess, it
// has run (vs never having run)
{ {
//Given that cancellation from the language now always happens by freeing the // Given that cancellation from the language now always happens by freeing
//synth, this block isn't reached normally. HOwever, if someone cancels using u_cmd, this is what will fire // the synth, this block isn't reached normally. HOwever, if someone
if(r.status() == Result::Status::kCancelled) // cancels using u_cmd, this is what will fire
if (r.status() == Result::Status::kCancelled)
{ {
std::cout << Wrapper::getName() << ": Processing cancelled \n"; std::cout << Wrapper::getName() << ": Processing cancelled \n";
w->mCancelled = true; w->mCancelled = true;
return false; return false;
} }
if(!r.ok()) if (!r.ok())
{ {
std::cout << "ERROR: " << Wrapper::getName() << ": " << r.message().c_str() << '\n'; std::cout << "ERROR: " << Wrapper::getName() << ": "
<< r.message().c_str() << '\n';
return false; return false;
} }
@ -312,50 +334,65 @@ public:
} }
/// swap NRT buffers back to RT-land /// swap NRT buffers back to RT-land
static bool exchangeBuffers(World *world, void *data) { return static_cast<Wrapper *>(data)->exchangeBuffers(world); } static bool exchangeBuffers(World* world, void* data)
{
return static_cast<Wrapper*>(data)->exchangeBuffers(world);
}
/// Tidy up any temporary buffers /// Tidy up any temporary buffers
static bool tidyUp(World *world, void *data) { return static_cast<Wrapper *>(data)->tidyUp(world); } static bool tidyUp(World* world, void* data)
{
return static_cast<Wrapper*>(data)->tidyUp(world);
}
/// Now we're actually properly done, call the UGen's done action (possibly destroying this instance) /// Now we're actually properly done, call the UGen's done action (possibly
/// destroying this instance)
static void destroy(World* world, void* data) static void destroy(World* world, void* data)
{ {
auto w = static_cast<Wrapper*>(data); auto w = static_cast<Wrapper*>(data);
if(w->mDone && w->mNumInputs > 2) //don't check for doneAction if UGen has no ins (there should be 3 minimum -> sig, doneAction, blocking mode) if (w->mDone &&
{ w->mNumInputs >
int doneAction = static_cast<int>(w->in0(int(w->mNumInputs) - 2)); //doneAction is penultimate input; THIS IS THE LAW 2) // don't check for doneAction if UGen has no ins (there should be
world->ft->fDoneAction(doneAction,w); // 3 minimum -> sig, doneAction, blocking mode)
{
int doneAction = static_cast<int>(
w->in0(int(w->mNumInputs) -
2)); // doneAction is penultimate input; THIS IS THE LAW
world->ft->fDoneAction(doneAction, w);
return; return;
} }
w->mCheckingForDone = false; w->mCheckingForDone = false;
} }
static void doCancel(Unit *unit, sc_msg_iter*) static void doCancel(Unit* unit, sc_msg_iter*)
{ {
static_cast<Wrapper *>(unit)->mClient.cancel(); static_cast<Wrapper*>(unit)->mClient.cancel();
} }
private:
static Result validateParameters(NonRealTime *w) private:
static Result validateParameters(NonRealTime* w)
{ {
auto results = w->mParams.constrainParameterValues(); auto results = w->mParams.constrainParameterValues();
for (auto &r : results) for (auto& r : results)
{ {
if (!r.ok()) return r; if (!r.ok()) return r;
} }
return {}; return {};
} }
bool exchangeBuffers(World *world) //RT thread bool exchangeBuffers(World* world) // RT thread
{ {
mParams.template forEachParamType<BufferT, AssignBuffer>(world); mParams.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) // At this point, we can see if we're finished and let the language know (or
//use replyID to convey status (0 = normal completion, 1 = cancelled) // it can wait for the doneAction, but that takes extra time) use replyID to
if(mDone) world->ft->fSendNodeReply(&mParent->mNode,0,"/done",0,nullptr); // convey status (0 = normal completion, 1 = cancelled)
if(mCancelled) world->ft->fSendNodeReply(&mParent->mNode,1,"/done",0,nullptr); if (mDone)
world->ft->fSendNodeReply(&mParent->mNode, 0, "/done", 0, nullptr);
if (mCancelled)
world->ft->fSendNodeReply(&mParent->mNode, 1, "/done", 0, nullptr);
return true; return true;
} }
bool tidyUp(World *) //NRT thread bool tidyUp(World*) // NRT thread
{ {
mParams.template forEachParamType<BufferT, CleanUpBuffer>(); mParams.template forEachParamType<BufferT, CleanUpBuffer>();
return true; return true;
@ -364,18 +401,18 @@ private:
template <size_t N, typename T> template <size_t N, typename T>
struct AssignBuffer struct AssignBuffer
{ {
void operator()(const typename BufferT::type &p, World *w) void operator()(const typename BufferT::type& p, World* w)
{ {
if (auto b = static_cast<SCBufferAdaptor *>(p.get())) b->assignToRT(w); if (auto b = static_cast<SCBufferAdaptor*>(p.get())) b->assignToRT(w);
} }
}; };
template <size_t N, typename T> template <size_t N, typename T>
struct CleanUpBuffer struct CleanUpBuffer
{ {
void operator()(const typename BufferT::type &p) void operator()(const typename BufferT::type& p)
{ {
if (auto b = static_cast<SCBufferAdaptor *>(p.get())) b->cleanUp(); if (auto b = static_cast<SCBufferAdaptor*>(p.get())) b->cleanUp();
} }
}; };
@ -383,32 +420,34 @@ private:
FifoMsg mFifoMsg; FifoMsg mFifoMsg;
char* mCompletionMessage = nullptr; char* mCompletionMessage = nullptr;
void* mReplyAddr = nullptr; void* mReplyAddr = nullptr;
const char *mName = nullptr; const char* mName = nullptr;
index checkThreadInterval; index checkThreadInterval;
index pollCounter{0}; index pollCounter{0};
protected: protected:
ParamSetType mParams; ParamSetType mParams;
Client mClient; Client mClient;
bool mSynchronous{true}; bool mSynchronous{true};
bool mQueueEnabled{false}; bool mQueueEnabled{false};
bool mCheckingForDone{false}; //only write to this from RT thread kthx bool mCheckingForDone{false}; // only write to this from RT thread kthx
bool mCancelled{false}; bool mCancelled{false};
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// An impossible monstrosty /// An impossible monstrosty
template <typename Client, typename Wrapper> template <typename Client, typename Wrapper>
class NonRealTimeAndRealTime : public RealTime<Client, Wrapper>, public NonRealTime<Client, Wrapper> class NonRealTimeAndRealTime : public RealTime<Client, Wrapper>,
public NonRealTime<Client, Wrapper>
{ {
static void setup(InterfaceTable *ft, const char *name) static void setup(InterfaceTable* ft, const char* name)
{ {
RealTime<Client,Wrapper>::setup(ft, name); RealTime<Client, Wrapper>::setup(ft, name);
NonRealTime<Client,Wrapper>::setup(ft, name); NonRealTime<Client, Wrapper>::setup(ft, name);
} }
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Template Specialisations for NRT/RT // Template Specialisations for NRT/RT
@ -418,26 +457,26 @@ class FluidSCWrapperImpl;
template <typename Client, typename Wrapper> template <typename Client, typename Wrapper>
class FluidSCWrapperImpl<Client, Wrapper, std::true_type, std::false_type> class FluidSCWrapperImpl<Client, Wrapper, std::true_type, std::false_type>
: public NonRealTime<Client, Wrapper> : public NonRealTime<Client, Wrapper>
{ {};
//public:
// FluidSCWrapperImpl(World* w, sc_msg_iter *args): NonRealTime<Client, Wrapper>(w,args){};
};
template <typename Client, typename Wrapper> template <typename Client, typename Wrapper>
class FluidSCWrapperImpl<Client, Wrapper, std::false_type, std::true_type> : public RealTime<Client, Wrapper> class FluidSCWrapperImpl<Client, Wrapper, std::false_type, std::true_type>
: public RealTime<Client, Wrapper>
{}; {};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Make base class(es), full of CRTP mixin goodness // Make base class(es), full of CRTP mixin goodness
template <typename Client> template <typename Client>
using FluidSCWrapperBase = FluidSCWrapperImpl<Client, FluidSCWrapper<Client>, isNonRealTime<Client>, isRealTime<Client>>; using FluidSCWrapperBase =
FluidSCWrapperImpl<Client, FluidSCWrapper<Client>, isNonRealTime<Client>,
isRealTime<Client>>;
} // namespace impl } // namespace impl
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
///The main wrapper /// The main wrapper
template <typename C> template <typename C>
class FluidSCWrapper : public impl::FluidSCWrapperBase<C> class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
{ {
@ -448,27 +487,39 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
template <typename ArgType, size_t N, typename T> template <typename ArgType, size_t N, typename T>
struct Setter struct Setter
{ {
static constexpr index argSize = C::getParameterDescriptors().template get<N>().fixedSize; static constexpr index argSize =
C::getParameterDescriptors().template get<N>().fixedSize;
auto fromArgs(World *, FloatControlsIter& args, LongT::type, int) { return args.next(); } auto fromArgs(World*, FloatControlsIter& args, LongT::type, int)
auto fromArgs(World *, FloatControlsIter& args, FloatT::type, int) { return args.next(); } {
return args.next();
}
auto fromArgs(World*, FloatControlsIter& args, FloatT::type, int)
{
return args.next();
}
auto fromArgs(World *w, ArgType args, BufferT::type, int) auto fromArgs(World* w, ArgType args, BufferT::type, int)
{ {
typename LongT::type bufnum = static_cast<LongT::type>(fromArgs(w, args, LongT::type(), -1)); typename LongT::type bufnum =
return BufferT::type(bufnum >= 0 ? new SCBufferAdaptor(bufnum, w) : nullptr); static_cast<LongT::type>(fromArgs(w, args, LongT::type(), -1));
return BufferT::type(bufnum >= 0 ? new SCBufferAdaptor(bufnum, w)
: nullptr);
} }
auto fromArgs(World *w, ArgType args, InputBufferT::type, int) auto fromArgs(World* w, ArgType args, InputBufferT::type, int)
{ {
typename LongT::type bufnum = static_cast<LongT::type>(fromArgs(w, args, LongT::type(), -1)); typename LongT::type bufnum =
return InputBufferT::type(bufnum >= 0 ? new SCBufferAdaptor(bufnum, w) : nullptr); static_cast<LongT::type>(fromArgs(w, args, LongT::type(), -1));
return InputBufferT::type(bufnum >= 0 ? new SCBufferAdaptor(bufnum, w)
: nullptr);
} }
typename T::type operator()(World *w, ArgType args) typename T::type operator()(World* w, ArgType args)
{ {
ParamLiteralConvertor<T, argSize> a; ParamLiteralConvertor<T, argSize> a;
using LiteralType = typename ParamLiteralConvertor<T, argSize>::LiteralType; using LiteralType =
typename ParamLiteralConvertor<T, argSize>::LiteralType;
for (index i = 0; i < argSize; i++) for (index i = 0; i < argSize; i++)
a[i] = static_cast<LiteralType>(fromArgs(w, args, a[0], 0)); a[i] = static_cast<LiteralType>(fromArgs(w, args, a[0], 0));
@ -480,9 +531,10 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
template <size_t N, typename T> template <size_t N, typename T>
using ControlSetter = Setter<FloatControlsIter&, N, T>; using ControlSetter = Setter<FloatControlsIter&, N, T>;
static void doVersion(Unit *, sc_msg_iter *) static void doVersion(Unit*, sc_msg_iter*)
{ {
std::cout << "Fluid Corpus Manipualtion Toolkit version " << fluidVersion() << '\n'; std::cout << "Fluid Corpus Manipualtion Toolkit version " << fluidVersion()
<< '\n';
} }
@ -490,24 +542,21 @@ public:
using Client = C; using Client = C;
using ParameterSetType = typename C::ParamSetType; using ParameterSetType = typename C::ParamSetType;
FluidSCWrapper() FluidSCWrapper() { impl::FluidSCWrapperBase<Client>::init(); }
{
impl::FluidSCWrapperBase<Client>::init();
}
static const char *getName(const char *setName = nullptr) static const char* getName(const char* setName = nullptr)
{ {
static const char *name = nullptr; static const char* name = nullptr;
return (name = setName ? setName : name); return (name = setName ? setName : name);
} }
static InterfaceTable *getInterfaceTable(InterfaceTable *setTable = nullptr) static InterfaceTable* getInterfaceTable(InterfaceTable* setTable = nullptr)
{ {
static InterfaceTable *ft = nullptr; static InterfaceTable* ft = nullptr;
return (ft = setTable ? setTable : ft); return (ft = setTable ? setTable : ft);
} }
static void setup(InterfaceTable *ft, const char *name) static void setup(InterfaceTable* ft, const char* name)
{ {
getName(name); getName(name);
getInterfaceTable(ft); getInterfaceTable(ft);
@ -515,23 +564,28 @@ public:
ft->fDefineUnitCmd(name, "version", doVersion); ft->fDefineUnitCmd(name, "version", doVersion);
} }
static auto& setParams(ParameterSetType& p, bool verbose, World* world, FloatControlsIter& inputs, bool constrain = false) 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 // We won't even try and set params if the arguments don't match
if(inputs.size() == C::getParameterDescriptors().count()) if (inputs.size() == C::getParameterDescriptors().count())
{ {
p.template setParameterValues<ControlSetter>(verbose, world, inputs); p.template setParameterValues<ControlSetter>(verbose, world, inputs);
if (constrain)p.constrainParameterValues(); if (constrain) p.constrainParameterValues();
} else { }
std::cout << "ERROR: " << getName() << ": parameter count mismatch. Perhaps your binary plugins and SC sources are different versions\n"; else
//TODO: work out how to bring any further work to a halt {
std::cout << "ERROR: " << getName()
<< ": parameter count mismatch. Perhaps your binary plugins "
"and SC sources are different versions\n";
// TODO: work out how to bring any further work to a halt
} }
return p; return p;
} }
}; };
template <template<typename T> class Client> template <template <typename T> class Client>
void makeSCWrapper(const char *name, InterfaceTable *ft) void makeSCWrapper(const char* name, InterfaceTable* ft)
{ {
FluidSCWrapper<Client<float>>::setup(ft, name); FluidSCWrapper<Client<float>>::setup(ft, name);
} }

@ -10,12 +10,12 @@ under the European Unions Horizon 2020 research and innovation programme
#pragma once #pragma once
#include <SC_PlugIn.h>
#include <SC_Errors.h>
#include <boost/align/aligned_alloc.hpp> #include <boost/align/aligned_alloc.hpp>
#include <cctype>
#include <data/FluidTensor.hpp>
#include <clients/common/BufferAdaptor.hpp> #include <clients/common/BufferAdaptor.hpp>
#include <data/FluidTensor.hpp>
#include <SC_Errors.h>
#include <SC_PlugIn.h>
#include <cctype>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -23,20 +23,16 @@ under the European Unions Horizon 2020 research and innovation programme
#include <vector> #include <vector>
namespace fluid namespace fluid {
{ namespace client {
namespace client
{
/** /**
A descendent of SndBuf that will populate itself A descendent of SndBuf that will populate itself
from the NRT mirror buffers given a world and a bufnum from the NRT mirror buffers given a world and a bufnum
**/ **/
struct NRTBuf { struct NRTBuf
NRTBuf(SndBuf *b) {
: mBuffer(b) NRTBuf(SndBuf* b) : mBuffer(b) {}
{ NRTBuf(World* world, index bufnum, bool rt = false)
}
NRTBuf(World *world, index bufnum, bool rt = false)
: NRTBuf(rt ? World_GetBuf(world, static_cast<uint32>(bufnum)) : NRTBuf(rt ? World_GetBuf(world, static_cast<uint32>(bufnum))
: World_GetNRTBuf(world, static_cast<uint32>(bufnum))) : World_GetNRTBuf(world, static_cast<uint32>(bufnum)))
{ {
@ -45,7 +41,7 @@ struct NRTBuf {
} }
protected: protected:
SndBuf *mBuffer; SndBuf* mBuffer;
}; };
/** /**
@ -67,26 +63,23 @@ protected:
class SCBufferAdaptor : public NRTBuf, public client::BufferAdaptor class SCBufferAdaptor : public NRTBuf, public client::BufferAdaptor
{ {
public: public:
// SCBufferAdaptor() = delete; // SCBufferAdaptor() = delete;
SCBufferAdaptor(const SCBufferAdaptor &) = delete; SCBufferAdaptor(const SCBufferAdaptor&) = delete;
SCBufferAdaptor& operator=(const SCBufferAdaptor &) = delete; SCBufferAdaptor& operator=(const SCBufferAdaptor&) = delete;
SCBufferAdaptor(SCBufferAdaptor&&) = default; SCBufferAdaptor(SCBufferAdaptor&&) = default;
SCBufferAdaptor& operator=(SCBufferAdaptor&&) = default; SCBufferAdaptor& operator=(SCBufferAdaptor&&) = default;
SCBufferAdaptor(index bufnum,World *world, bool rt = false) SCBufferAdaptor(index bufnum, World* world, bool rt = false)
: NRTBuf(world, bufnum, rt) : NRTBuf(world, bufnum, rt), mBufnum(bufnum), mWorld(world)
, mBufnum(bufnum) {}
, mWorld(world)
{
}
~SCBufferAdaptor(){ cleanUp(); } ~SCBufferAdaptor() { cleanUp(); }
void assignToRT(World *rtWorld) void assignToRT(World* rtWorld)
{ {
SndBuf *rtBuf = World_GetBuf(rtWorld, static_cast<uint32>(mBufnum)); SndBuf* rtBuf = World_GetBuf(rtWorld, static_cast<uint32>(mBufnum));
*rtBuf = *mBuffer; *rtBuf = *mBuffer;
rtWorld->mSndBufUpdates[mBufnum].writes++; rtWorld->mSndBufUpdates[mBufnum].writes++;
} }
@ -111,15 +104,11 @@ public:
return (mBuffer && mBufnum >= 0 && mBufnum < asSigned(mWorld->mNumSndBufs)); return (mBuffer && mBufnum >= 0 && mBufnum < asSigned(mWorld->mNumSndBufs));
} }
bool exists() const override bool exists() const override { return true; }
{
return true;
}
FluidTensorView<float, 1> samps(index channel) override FluidTensorView<float, 1> samps(index channel) override
{ {
FluidTensorView<float, 2> v{mBuffer->data, 0, FluidTensorView<float, 2> v{mBuffer->data, 0, mBuffer->frames,
mBuffer->frames,
mBuffer->channels}; mBuffer->channels};
return v.col(channel); return v.col(channel);
@ -128,8 +117,7 @@ public:
FluidTensorView<float, 1> samps(index offset, index nframes, FluidTensorView<float, 1> samps(index offset, index nframes,
index chanoffset) override index chanoffset) override
{ {
FluidTensorView<float, 2> v{mBuffer->data, 0, FluidTensorView<float, 2> v{mBuffer->data, 0, mBuffer->frames,
mBuffer->frames,
mBuffer->channels}; mBuffer->channels};
return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1)).col(0); return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1)).col(0);
@ -137,8 +125,7 @@ public:
FluidTensorView<const float, 1> samps(index channel) const override FluidTensorView<const float, 1> samps(index channel) const override
{ {
FluidTensorView<const float, 2> v{mBuffer->data, 0, FluidTensorView<const float, 2> v{mBuffer->data, 0, mBuffer->frames,
mBuffer->frames,
mBuffer->channels}; mBuffer->channels};
return v.col(channel); return v.col(channel);
@ -147,8 +134,7 @@ public:
FluidTensorView<const float, 1> samps(index offset, index nframes, FluidTensorView<const float, 1> samps(index offset, index nframes,
index chanoffset) const override index chanoffset) const override
{ {
FluidTensorView<const float, 2> v{mBuffer->data, 0, FluidTensorView<const float, 2> v{mBuffer->data, 0, mBuffer->frames,
mBuffer->frames,
mBuffer->channels}; mBuffer->channels};
return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1)).col(0); return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1)).col(0);
@ -165,19 +151,24 @@ public:
return valid() ? this->mBuffer->channels : 0; return valid() ? this->mBuffer->channels : 0;
} }
double sampleRate() const override { return valid() ? mBuffer->samplerate : 0; } double sampleRate() const override
{
return valid() ? mBuffer->samplerate : 0;
}
std::string asString() const override { return std::to_string(bufnum()); } std::string asString() const override { return std::to_string(bufnum()); }
const Result resize(index frames, index channels, double sampleRate) override const Result resize(index frames, index channels, double sampleRate) override
{ {
SndBuf *thisThing = mBuffer; SndBuf* thisThing = mBuffer;
mOldData = thisThing->data; mOldData = thisThing->data;
int allocResult = mWorld->ft->fBufAlloc(mBuffer, static_cast<int>(channels), static_cast<int>(frames), sampleRate); int allocResult =
mWorld->ft->fBufAlloc(mBuffer, static_cast<int>(channels),
static_cast<int>(frames), sampleRate);
Result r; Result r;
if(allocResult != kSCErr_None) if (allocResult != kSCErr_None)
{ {
r.set(Result::Status::kError); r.set(Result::Status::kError);
r.addMessage("Resize on buffer ", bufnum(), " failed."); r.addMessage("Resize on buffer ", bufnum(), " failed.");
@ -189,14 +180,13 @@ public:
void realTime(bool rt) { mRealTime = rt; } void realTime(bool rt) { mRealTime = rt; }
protected: protected:
bool mRealTime{false}; bool mRealTime{false};
float *mOldData{0}; float* mOldData{0};
index mBufnum; index mBufnum;
World *mWorld; World* mWorld;
}; };
std::ostream& operator <<(std::ostream& os, SCBufferAdaptor& b) std::ostream& operator<<(std::ostream& os, SCBufferAdaptor& b)
{ {
return os << b.bufnum(); return os << b.bufnum();
} }

Loading…
Cancel
Save