Merge branch 'ParametersWithTuples' into refactor
commit
2fef8a0a07
@ -0,0 +1,462 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SCBufferAdaptor.hpp"
|
||||||
|
#include <clients/common/FluidBaseClient.hpp>
|
||||||
|
#include <clients/common/Result.hpp>
|
||||||
|
#include <data/FluidTensor.hpp>
|
||||||
|
#include <data/TensorTypes.hpp>
|
||||||
|
|
||||||
|
#include <SC_PlugIn.hpp>
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace fluid {
|
||||||
|
namespace client {
|
||||||
|
|
||||||
|
template <typename Client, typename Params> class FluidSCWrapper;
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
template <typename Client, typename T, size_t N> struct Setter;
|
||||||
|
template <size_t N, typename T> struct ArgumentGetter;
|
||||||
|
template <size_t N, typename T> struct ControlGetter;
|
||||||
|
template <typename T> using msg_iter_method = T (sc_msg_iter::*)(T);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//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 && "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 <size_t N, typename T> struct GetControl
|
||||||
|
{
|
||||||
|
T operator()(World*, FloatControlsIter& controls) { return controls.next(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <size_t N, typename T> struct ControlGetter : public GetControl<N, typename T::type>
|
||||||
|
{};
|
||||||
|
|
||||||
|
//Specializations
|
||||||
|
template <size_t N> struct ControlGetter<N, BufferT>
|
||||||
|
{
|
||||||
|
auto operator() (World* w, FloatControlsIter& iter)
|
||||||
|
{
|
||||||
|
typename LongT::type bufnum = iter.next();
|
||||||
|
return std::unique_ptr<BufferAdaptor>(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w): nullptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
struct ControlGetter<N,FloatPairsArrayT>
|
||||||
|
{
|
||||||
|
typename FloatPairsArrayT::type operator()(World*, FloatControlsIter& iter)
|
||||||
|
{
|
||||||
|
return {{iter.next(),iter.next()},{iter.next(),iter.next()}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
struct ControlGetter<N,FFTParamsT>
|
||||||
|
{
|
||||||
|
typename FFTParamsT::type operator()(World*, FloatControlsIter& iter)
|
||||||
|
{
|
||||||
|
return {static_cast<long>(iter.next()),static_cast<long>(iter.next()),static_cast<long>(iter.next())};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Iterate over arguments in sc_msg_iter, via callbacks from params object
|
||||||
|
|
||||||
|
template <size_t N, typename T, msg_iter_method<T> Method> struct GetArgument
|
||||||
|
{
|
||||||
|
T operator()(World* w, sc_msg_iter *args)
|
||||||
|
{
|
||||||
|
T r = (args->*Method)(T{0});
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//General cases
|
||||||
|
template <size_t N> struct ArgumentGetter<N, FloatT> : public GetArgument<N, float, &sc_msg_iter::getf>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <size_t N> struct ArgumentGetter<N, LongT> : public GetArgument<N, int32, &sc_msg_iter::geti>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <size_t N> struct ArgumentGetter<N, EnumT> : public GetArgument<N, int32, &sc_msg_iter::geti>
|
||||||
|
{};
|
||||||
|
|
||||||
|
//Specializations
|
||||||
|
template <size_t N> struct ArgumentGetter<N, BufferT>
|
||||||
|
{
|
||||||
|
auto operator() (World* w, sc_msg_iter *args)
|
||||||
|
{
|
||||||
|
typename LongT::type bufnum = args->geti(-1);
|
||||||
|
return std::unique_ptr<BufferAdaptor>(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w) : nullptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <size_t N> struct ArgumentGetter<N, FloatPairsArrayT>
|
||||||
|
{
|
||||||
|
typename FloatPairsArrayT::type operator()(World* w, sc_msg_iter *args)
|
||||||
|
{
|
||||||
|
return {{args->getf(),args->getf()},{args->getf(),args->getf()}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <size_t N> struct ArgumentGetter<N, FFTParamsT>
|
||||||
|
{
|
||||||
|
typename FFTParamsT::type operator()(World* w, sc_msg_iter *args)
|
||||||
|
{
|
||||||
|
return {args->geti(),args->geti(),args->geti()};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//Real Time Processor
|
||||||
|
|
||||||
|
template <typename Client,class Wrapper, class Params> class RealTime : public SCUnit
|
||||||
|
{
|
||||||
|
using HostVector = FluidTensorView<float, 1>;
|
||||||
|
// using Client = typename Wrapper::ClientType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
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 *args)
|
||||||
|
{
|
||||||
|
float l[] {static_cast<float>(static_cast<Wrapper*>(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)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
mOutputs.reserve(std::max(mClient.audioChannelsOut(),mClient.controlChannelsOut()));
|
||||||
|
|
||||||
|
for (int i = 0; i < mClient.audioChannelsIn(); ++i)
|
||||||
|
{
|
||||||
|
mInputConnections.emplace_back(isAudioRateIn(i));
|
||||||
|
mAudioInputs.emplace_back(nullptr, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_calc_function<RealTime, &RealTime::next>();
|
||||||
|
Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void next(int n)
|
||||||
|
{
|
||||||
|
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 < mClient.audioChannelsIn(); ++i)
|
||||||
|
{
|
||||||
|
if (mInputConnections[i]) mAudioInputs[i].reset(IN(i), 0, fullBufferSize());
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
mOutputs[i].reset(out(i),0,1);
|
||||||
|
}
|
||||||
|
mClient.process(mAudioInputs, mOutputs);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::vector<bool> mInputConnections;
|
||||||
|
std::vector<bool> mOutputConnections;
|
||||||
|
std::vector<HostVector> mAudioInputs;
|
||||||
|
std::vector<HostVector> mOutputs;
|
||||||
|
FloatControlsIter mControlsIterator;
|
||||||
|
protected:
|
||||||
|
ParameterSet<Params> mParams;
|
||||||
|
Client mClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Non Real Time Processor
|
||||||
|
template <typename Client, typename Wrapper, typename Params> class NonRealTime
|
||||||
|
{
|
||||||
|
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}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void init(){};
|
||||||
|
|
||||||
|
static void launch(World *world, void *inUserData, struct sc_msg_iter *args, void *replyAddr)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
args->rdpos = argsRdPos;
|
||||||
|
Wrapper::setParams(w->mParams,false, world, args);
|
||||||
|
|
||||||
|
size_t msgSize = args->getbsize();
|
||||||
|
std::vector<char> completionMessage(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());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool process(World *world, void *data) { return static_cast<Wrapper *>(data)->process(world); }
|
||||||
|
static bool exchangeBuffers(World *world, void *data) { return static_cast<Wrapper *>(data)->exchangeBuffers(world); }
|
||||||
|
static bool tidyUp(World *world, void *data) { return static_cast<Wrapper *>(data)->tidyUp(world); }
|
||||||
|
static void destroy(World *world, void *data)
|
||||||
|
{
|
||||||
|
|
||||||
|
// void* c = static_cast<Wrapper *>(data)->mCompletionMessage;
|
||||||
|
// if(c) world->ft->fRTFree(world,c);
|
||||||
|
delete static_cast<Wrapper *>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ParameterSet<Params> mParams;
|
||||||
|
Client mClient;
|
||||||
|
private:
|
||||||
|
static Result validateParameters(NonRealTime *w, World* world, sc_msg_iter *args)
|
||||||
|
{
|
||||||
|
auto results = w->mParams.template checkParameterValues<ArgumentGetter>(world, args);
|
||||||
|
for (auto &r : results)
|
||||||
|
{
|
||||||
|
std::cout << r.message() << '\n';
|
||||||
|
if (!r.ok()) return r;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process(World *world)
|
||||||
|
{
|
||||||
|
Result r = mClient.process();///mInputs, mOutputs);
|
||||||
|
|
||||||
|
if(!r.ok())
|
||||||
|
{
|
||||||
|
std::cout << "FluCoMa Error " << Wrapper::getName() << ": " << r.message().c_str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exchangeBuffers(World *world)
|
||||||
|
{
|
||||||
|
mParams.template forEachParamType<BufferT,AssignBuffer>(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()
|
||||||
|
mParams.template forEachParamType<BufferT,CleanUpBuffer>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N,typename T>
|
||||||
|
struct AssignBuffer
|
||||||
|
{
|
||||||
|
void operator()(typename BufferT::type& p, World* w)
|
||||||
|
{
|
||||||
|
if(auto b = static_cast<SCBufferAdaptor*>(p.get()))
|
||||||
|
b->assignToRT(w);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t N,typename T>
|
||||||
|
struct CleanUpBuffer
|
||||||
|
{
|
||||||
|
void operator()(typename BufferT::type& p)
|
||||||
|
{
|
||||||
|
if(auto b = static_cast<SCBufferAdaptor*>(p.get()))
|
||||||
|
b->cleanUp();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// std::vector<SCBufferAdaptor> mBuffersIn;
|
||||||
|
// std::vector<SCBufferAdaptor> mBuffersOut;
|
||||||
|
// std::vector<BufferProcessSpec> mInputs;
|
||||||
|
// std::vector<BufferProcessSpec> mOutputs;
|
||||||
|
char * mCompletionMessage = nullptr;
|
||||||
|
void * mReplyAddr = nullptr;
|
||||||
|
const char * mName = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// An impossible monstrosty
|
||||||
|
template <typename Client, typename Wrapper, typename Params> class NonRealTimeAndRealTime : public RealTime<Client,Wrapper, Params>, public NonRealTime<Client,Wrapper, Params>
|
||||||
|
{
|
||||||
|
static void setup(InterfaceTable *ft, const char *name)
|
||||||
|
{
|
||||||
|
RealTime<Client,Wrapper,Params >::setup(ft, name);
|
||||||
|
NonRealTime<Client,Wrapper, Params>::setup(ft, name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Template Specialisations for NRT/RT
|
||||||
|
|
||||||
|
template <typename Client, typename Wrapper, typename Params, typename NRT, typename RT> class FluidSCWrapperImpl;
|
||||||
|
|
||||||
|
template <typename Client, typename Wrapper, typename Params> class FluidSCWrapperImpl<Client, Wrapper, Params, std::true_type, std::false_type> : public NonRealTime<Client, Wrapper, Params>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FluidSCWrapperImpl(World* w, sc_msg_iter *args): NonRealTime<Client, Wrapper, Params>(w,args){};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Client, typename Wrapper, typename Params> class FluidSCWrapperImpl<Client, Wrapper,Params, std::false_type, std::true_type> : public RealTime<Client, Wrapper, Params>
|
||||||
|
{};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Make base class(es), full of CRTP mixin goodness
|
||||||
|
template <typename Client,typename Params>
|
||||||
|
using FluidSCWrapperBase = FluidSCWrapperImpl<Client, FluidSCWrapper<Client, Params>,Params, isNonRealTime<Client>, isRealTime<Client>>;
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///The main wrapper
|
||||||
|
template <typename C, typename P> class FluidSCWrapper : public impl::FluidSCWrapperBase<C,P>
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Client = C;
|
||||||
|
using Params = P;
|
||||||
|
|
||||||
|
FluidSCWrapper() //mParams{*getParamDescriptors()}, //impl::FluidSCWrapperBase<Client,Params>()
|
||||||
|
{ impl::FluidSCWrapperBase<Client,Params>::init(); }
|
||||||
|
|
||||||
|
FluidSCWrapper(World* w, sc_msg_iter *args): impl::FluidSCWrapperBase<Client, Params>(w,args)
|
||||||
|
{ impl::FluidSCWrapperBase<Client, Params>::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)
|
||||||
|
{
|
||||||
|
static InterfaceTable *ft = nullptr;
|
||||||
|
return (ft = setTable ? setTable : ft);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup(Params& p, InterfaceTable *ft, const char *name)
|
||||||
|
{
|
||||||
|
getName(name);
|
||||||
|
getInterfaceTable(ft);
|
||||||
|
getParamDescriptors(&p);
|
||||||
|
impl::FluidSCWrapperBase<Client, Params>::setup(ft, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ParameterSet>
|
||||||
|
static auto& setParams(ParameterSet& p, bool verbose, World* world, impl::FloatControlsIter& inputs)
|
||||||
|
{
|
||||||
|
p.template setParameterValues<impl::ControlGetter>(verbose, world, inputs);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ParameterSet>
|
||||||
|
static auto& setParams(ParameterSet& p, bool verbose, World* world, sc_msg_iter *args)
|
||||||
|
{
|
||||||
|
p.template setParameterValues<impl::ArgumentGetter>(verbose,world, args);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl::ParameterSet<Params> mParams;
|
||||||
|
|
||||||
|
// Client &client() { return mClient; }
|
||||||
|
//
|
||||||
|
//private:
|
||||||
|
// Client mClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class Client,typename...Rest,typename Params>
|
||||||
|
void makeSCWrapper(const char *name, Params& params, InterfaceTable *ft)
|
||||||
|
{
|
||||||
|
FluidSCWrapper<Client<ParameterSet<Params>,Rest...>, Params>::setup(params, ft, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace client
|
||||||
|
} // namespace fluid
|
||||||
@ -0,0 +1,250 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SC_PlugIn.h>
|
||||||
|
#include <boost/align/aligned_alloc.hpp>
|
||||||
|
#include <cctype>
|
||||||
|
//#include <clients/common/FluidParams.hpp>
|
||||||
|
#include <data/FluidTensor.hpp>
|
||||||
|
#include <clients/common/BufferAdaptor.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// static InterfaceTable *ft;
|
||||||
|
|
||||||
|
namespace fluid
|
||||||
|
{
|
||||||
|
namespace client
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
A descendent of SndBuf that will populate itself
|
||||||
|
from the NRT mirror buffers given a world and a bufnum
|
||||||
|
**/
|
||||||
|
struct NRTBuf {
|
||||||
|
NRTBuf(SndBuf *b)
|
||||||
|
: mBuffer(b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
NRTBuf(World *world, long bufnum, bool rt = false)
|
||||||
|
: NRTBuf(rt ? World_GetBuf(world, bufnum)
|
||||||
|
: World_GetNRTBuf(world, bufnum))
|
||||||
|
{
|
||||||
|
if (mBuffer && !mBuffer->samplerate)
|
||||||
|
mBuffer->samplerate = world->mFullRate.mSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SndBuf *mBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
A combination of SndBuf and client::BufferAdaptor (which, in turn, exposes
|
||||||
|
FluidTensorView<float,2>), for simple transfer of data
|
||||||
|
|
||||||
|
Given a World* and a buffer number, this will populate its SndBuf stuff
|
||||||
|
from the NRT mirror buffers, and create a FluidTensorView wrapper of
|
||||||
|
appropriate dimensions.
|
||||||
|
|
||||||
|
The SndBuf can then be 'transferred' back to the RT buffers once we're done
|
||||||
|
with it, and SC notified of the update. (In the context of SequencedCommands,
|
||||||
|
in which this is meant to be used, this would happen at Stage3() on the
|
||||||
|
real-time thread)
|
||||||
|
|
||||||
|
nSamps = rows
|
||||||
|
nChans = columns
|
||||||
|
**/
|
||||||
|
class SCBufferAdaptor : public NRTBuf, public client::BufferAdaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// SCBufferAdaptor() = delete;
|
||||||
|
SCBufferAdaptor(SCBufferAdaptor &) = delete;
|
||||||
|
SCBufferAdaptor operator=(SCBufferAdaptor &) = delete;
|
||||||
|
|
||||||
|
SCBufferAdaptor(SCBufferAdaptor&&) = default;
|
||||||
|
SCBufferAdaptor& operator=(SCBufferAdaptor&&) = default;
|
||||||
|
|
||||||
|
|
||||||
|
SCBufferAdaptor(long bufnum,World *world, bool rt = false)
|
||||||
|
: NRTBuf(world, bufnum, rt)
|
||||||
|
, mBufnum(bufnum)
|
||||||
|
, mWorld(world)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SCBufferAdaptor() = default;
|
||||||
|
|
||||||
|
~SCBufferAdaptor(){ cleanUp(); }
|
||||||
|
|
||||||
|
void assignToRT(World *rtWorld)
|
||||||
|
{
|
||||||
|
SndBuf *rtBuf = World_GetBuf(rtWorld, mBufnum);
|
||||||
|
*rtBuf = *mBuffer;
|
||||||
|
rtWorld->mSndBufUpdates[mBufnum].writes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanUp()
|
||||||
|
{
|
||||||
|
if (mOldData)
|
||||||
|
{
|
||||||
|
boost::alignment::aligned_free(mOldData);
|
||||||
|
mOldData = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No locks in (vanilla) SC, so no-ops for these
|
||||||
|
void acquire() override {}
|
||||||
|
void release() override {}
|
||||||
|
|
||||||
|
// Validity is based on whether this buffer is within the range the server
|
||||||
|
// knows about
|
||||||
|
bool valid() const override
|
||||||
|
{
|
||||||
|
return (mBuffer && mBufnum >= 0 && mBufnum < mWorld->mNumSndBufs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exists() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FluidTensorView<float, 1> samps(size_t channel, size_t rankIdx = 0) override
|
||||||
|
{
|
||||||
|
FluidTensorView<float, 2> v{mBuffer->data, 0,
|
||||||
|
static_cast<size_t>(mBuffer->frames),
|
||||||
|
static_cast<size_t>(mBuffer->channels)};
|
||||||
|
|
||||||
|
return v.col(rankIdx + channel * mRank);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a 2D chunk
|
||||||
|
FluidTensorView<float, 1> samps(size_t offset, size_t nframes,
|
||||||
|
size_t chanoffset) override
|
||||||
|
{
|
||||||
|
FluidTensorView<float, 2> v{mBuffer->data, 0,
|
||||||
|
static_cast<size_t>(mBuffer->frames),
|
||||||
|
static_cast<size_t>(mBuffer->channels)};
|
||||||
|
|
||||||
|
return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1)).col(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numFrames() const override
|
||||||
|
{
|
||||||
|
return valid() ? this->mBuffer->frames : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numChans() const override
|
||||||
|
{
|
||||||
|
return valid() ? this->mBuffer->channels / mRank : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t rank() const override { return valid() ? mRank : 0; }
|
||||||
|
|
||||||
|
void resize(size_t frames, size_t channels, size_t rank) override
|
||||||
|
{
|
||||||
|
SndBuf *thisThing = mBuffer;
|
||||||
|
mOldData = thisThing->data;
|
||||||
|
mRank = rank;
|
||||||
|
mWorld->ft->fBufAlloc(mBuffer, channels * rank, frames,
|
||||||
|
thisThing->samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bufnum() { return mBufnum; }
|
||||||
|
void realTime(bool rt) { mRealTime = rt; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool equal(BufferAdaptor *rhs) const override
|
||||||
|
{
|
||||||
|
SCBufferAdaptor *x = dynamic_cast<SCBufferAdaptor *>(rhs);
|
||||||
|
if (x) { return mBufnum == x->mBufnum; }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mRealTime{false};
|
||||||
|
float *mOldData{0};
|
||||||
|
long mBufnum;
|
||||||
|
World *mWorld;
|
||||||
|
size_t mRank{1};
|
||||||
|
};
|
||||||
|
|
||||||
|
class RTBufferView : public client::BufferAdaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RTBufferView(World *world, int bufnum)
|
||||||
|
: mWorld(world)
|
||||||
|
, mBufnum(bufnum)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void acquire() override { mBuffer = World_GetBuf(mWorld, mBufnum); }
|
||||||
|
void release() override {}
|
||||||
|
|
||||||
|
// Validity is based on whether this buffer is within the range the server
|
||||||
|
// knows about
|
||||||
|
bool valid() const override
|
||||||
|
{
|
||||||
|
return (mBuffer && mBufnum >= 0 && mBufnum < mWorld->mNumSndBufs);
|
||||||
|
}
|
||||||
|
|
||||||
|
FluidTensorView<float, 1> samps(size_t channel, size_t rankIdx = 0) override
|
||||||
|
{
|
||||||
|
FluidTensorView<float, 2> v{mBuffer->data, 0,
|
||||||
|
static_cast<size_t>(mBuffer->frames),
|
||||||
|
static_cast<size_t>(mBuffer->channels)};
|
||||||
|
|
||||||
|
return v.col(rankIdx + channel * mRank);
|
||||||
|
}
|
||||||
|
|
||||||
|
FluidTensorView<float, 1> samps(size_t offset, size_t nframes,
|
||||||
|
size_t chanoffset) override
|
||||||
|
{
|
||||||
|
FluidTensorView<float, 2> v{mBuffer->data, 0,
|
||||||
|
static_cast<size_t>(mBuffer->frames),
|
||||||
|
static_cast<size_t>(mBuffer->channels)};
|
||||||
|
|
||||||
|
return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1)).col(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numFrames() const override
|
||||||
|
{
|
||||||
|
return valid() ? this->mBuffer->frames : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numChans() const override
|
||||||
|
{
|
||||||
|
return valid() ? this->mBuffer->channels / mRank : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t rank() const override { return valid() ? mRank : 0; }
|
||||||
|
|
||||||
|
void resize(size_t frames, size_t channels, size_t rank) override
|
||||||
|
{
|
||||||
|
assert(false && "Don't try and resize real-time buffers");
|
||||||
|
}
|
||||||
|
|
||||||
|
int bufnum() { return mBufnum; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool equal(BufferAdaptor *rhs) const override
|
||||||
|
{
|
||||||
|
RTBufferView *x = dynamic_cast<RTBufferView *>(rhs);
|
||||||
|
if (x) { return mBufnum == x->mBufnum; }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mRank = 1;
|
||||||
|
World * mWorld;
|
||||||
|
int mBufnum = -1;
|
||||||
|
SndBuf *mBuffer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator <<(std::ostream& os, SCBufferAdaptor& b)
|
||||||
|
{
|
||||||
|
return os << b.bufnum();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace client
|
||||||
|
} // namespace fluid
|
||||||
|
|
||||||
@ -1,402 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include "data/FluidTensor.hpp"
|
|
||||||
#include "clients/common/FluidParams.hpp"
|
|
||||||
|
|
||||||
#include "SC_PlugIn.h"
|
|
||||||
|
|
||||||
#include <boost/align/aligned_alloc.hpp>
|
|
||||||
#include <cctype>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
//static InterfaceTable *ft;
|
|
||||||
|
|
||||||
namespace fluid {
|
|
||||||
namespace wrapper{
|
|
||||||
/**
|
|
||||||
A descendent of SndBuf that will populate itself
|
|
||||||
from the NRT mirror buffers given a world and a bufnum
|
|
||||||
**/
|
|
||||||
struct NRTBuf//: public SndBuf
|
|
||||||
{
|
|
||||||
NRTBuf(SndBuf* b):mBuffer(b){}
|
|
||||||
NRTBuf(World* world,long bufnum, bool rt=false):
|
|
||||||
NRTBuf(rt?World_GetBuf(world, bufnum):World_GetNRTBuf(world,bufnum))
|
|
||||||
{
|
|
||||||
if(mBuffer && !mBuffer->samplerate)
|
|
||||||
mBuffer->samplerate = world->mFullRate.mSampleRate;
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
SndBuf* mBuffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
A combination of SndBuf and client::BufferAdaptor (which, in turn, exposes FluidTensorView<float,2>), for simple transfer of data
|
|
||||||
|
|
||||||
Given a World* and a buffer number, this will populate its SndBuf stuff
|
|
||||||
from the NRT mirror buffers, and create a FluidTensorView wrapper of
|
|
||||||
appropriate dimensions.
|
|
||||||
|
|
||||||
The SndBuf can then be 'transferred' back to the RT buffers once we're done with it,
|
|
||||||
and SC notified of the update. (In the context of SequencedCommands, in which this is meant
|
|
||||||
to be used, this would happen at Stage3() on the real-time thread)
|
|
||||||
|
|
||||||
nSamps = rows
|
|
||||||
nChans = columns
|
|
||||||
**/
|
|
||||||
class SCBufferView: public NRTBuf, public client::BufferAdaptor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SCBufferView() = delete;
|
|
||||||
SCBufferView(SCBufferView&) = delete;
|
|
||||||
SCBufferView operator=(SCBufferView&) = delete;
|
|
||||||
|
|
||||||
|
|
||||||
SCBufferView(long bufnum,World* world,bool rt=false):
|
|
||||||
NRTBuf(world,bufnum,rt), mBufnum(bufnum), mWorld(world)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
~SCBufferView() = default;
|
|
||||||
|
|
||||||
void assignToRT(World* rtWorld)
|
|
||||||
{
|
|
||||||
SndBuf* rtBuf = World_GetBuf(rtWorld,mBufnum);
|
|
||||||
*rtBuf = *mBuffer;
|
|
||||||
rtWorld->mSndBufUpdates[mBufnum].writes++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cleanUp()
|
|
||||||
{
|
|
||||||
if(mOldData)
|
|
||||||
boost::alignment::aligned_free(mOldData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//No locks in (vanilla) SC, so no-ops for these
|
|
||||||
void acquire() override {
|
|
||||||
// NRTLock(mWorld);
|
|
||||||
}
|
|
||||||
void release() override {
|
|
||||||
// NRTUnlock(mWorld);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Validity is based on whether this buffer is within the range the server knows about
|
|
||||||
bool valid() const override {
|
|
||||||
return (mBuffer && mBufnum >=0 && mBufnum < mWorld->mNumSndBufs);
|
|
||||||
}
|
|
||||||
|
|
||||||
FluidTensorView<float,1> samps(size_t channel, size_t rankIdx = 0) override
|
|
||||||
{
|
|
||||||
FluidTensorView<float,2> v{mBuffer->data,0, static_cast<size_t>(mBuffer->frames),static_cast<size_t>(mBuffer->channels)};
|
|
||||||
|
|
||||||
return v.col(rankIdx + channel * mRank );
|
|
||||||
}
|
|
||||||
// //Return a view of all the data
|
|
||||||
// FluidTensorView<float,2> samps() override
|
|
||||||
// {
|
|
||||||
// return {mBuffer->data,0, static_cast<size_t>(mBuffer->frames), static_cast<size_t>(mBuffer->channels)};
|
|
||||||
// }
|
|
||||||
|
|
||||||
//Return a 2D chunk
|
|
||||||
FluidTensorView<float,1> samps(size_t offset, size_t nframes, size_t chanoffset) override
|
|
||||||
{
|
|
||||||
FluidTensorView<float,2> v{mBuffer->data,0, static_cast<size_t>(mBuffer->frames), static_cast<size_t>(mBuffer->channels)};
|
|
||||||
|
|
||||||
return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1))
|
|
||||||
.col(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t numFrames() const override
|
|
||||||
{
|
|
||||||
return valid() ? this->mBuffer->frames : 0 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t numChans() const override
|
|
||||||
{
|
|
||||||
return valid() ? this->mBuffer->channels / mRank : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t rank() const override
|
|
||||||
{
|
|
||||||
return valid() ? mRank :0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(size_t frames, size_t channels, size_t rank) override {
|
|
||||||
SndBuf* thisThing = mBuffer;
|
|
||||||
mOldData = thisThing->data;
|
|
||||||
mRank = rank;
|
|
||||||
mWorld->ft->fBufAlloc(mBuffer, channels * rank, frames, thisThing->samplerate);
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
bool equal(BufferAdaptor* rhs) const override
|
|
||||||
{
|
|
||||||
SCBufferView* x = dynamic_cast<SCBufferView*>(rhs);
|
|
||||||
if(x)
|
|
||||||
{
|
|
||||||
return mBufnum == x->mBufnum;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float* mOldData = 0;
|
|
||||||
long mBufnum;
|
|
||||||
World* mWorld;
|
|
||||||
size_t mRank = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RTBufferView: public client::BufferAdaptor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RTBufferView(World* world, int bufnum): mWorld(world), mBufnum(bufnum) {}
|
|
||||||
|
|
||||||
void acquire() override {
|
|
||||||
mBuffer = World_GetBuf(mWorld, mBufnum);
|
|
||||||
}
|
|
||||||
void release() override {
|
|
||||||
// NRTUnlock(mWorld);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Validity is based on whether this buffer is within the range the server knows about
|
|
||||||
bool valid() const override {
|
|
||||||
return (mBuffer && mBufnum >=0 && mBufnum < mWorld->mNumSndBufs);
|
|
||||||
}
|
|
||||||
|
|
||||||
FluidTensorView<float,1> samps(size_t channel, size_t rankIdx = 0) override
|
|
||||||
{
|
|
||||||
FluidTensorView<float,2> v{mBuffer->data,0, static_cast<size_t>(mBuffer->frames),static_cast<size_t>(mBuffer->channels)};
|
|
||||||
|
|
||||||
return v.col(rankIdx + channel * mRank );
|
|
||||||
}
|
|
||||||
|
|
||||||
FluidTensorView<float,1> samps(size_t offset, size_t nframes, size_t chanoffset) override
|
|
||||||
{
|
|
||||||
FluidTensorView<float,2> v{mBuffer->data,0, static_cast<size_t>(mBuffer->frames), static_cast<size_t>(mBuffer->channels)};
|
|
||||||
|
|
||||||
return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1))
|
|
||||||
.col(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t numFrames() const override
|
|
||||||
{
|
|
||||||
return valid() ? this->mBuffer->frames : 0 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t numChans() const override
|
|
||||||
{
|
|
||||||
return valid() ? this->mBuffer->channels / mRank : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t rank() const override
|
|
||||||
{
|
|
||||||
return valid() ? mRank :0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(size_t frames, size_t channels, size_t rank) override {
|
|
||||||
assert(false && "Don't try and resize real-time buffers");
|
|
||||||
// SndBuf* thisThing = mBuffer;
|
|
||||||
// mOldData = thisThing->data;
|
|
||||||
// mRank = rank;
|
|
||||||
// mWorld->ft->fBufAlloc(mBuffer, channels * rank, frames, thisThing->samplerate);
|
|
||||||
}
|
|
||||||
|
|
||||||
int bufnum() {
|
|
||||||
return mBufnum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
bool equal(BufferAdaptor* rhs) const override
|
|
||||||
{
|
|
||||||
RTBufferView* x = dynamic_cast<RTBufferView*>(rhs);
|
|
||||||
if(x)
|
|
||||||
{
|
|
||||||
return mBufnum == x->mBufnum;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mRank = 1;
|
|
||||||
World* mWorld;
|
|
||||||
int mBufnum = -1;
|
|
||||||
SndBuf* mBuffer = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class NRTCommandBase{
|
|
||||||
using param_type = fluid::client::Instance;
|
|
||||||
public:
|
|
||||||
NRTCommandBase() = delete;
|
|
||||||
NRTCommandBase(NRTCommandBase&) = delete;
|
|
||||||
NRTCommandBase& operator=(NRTCommandBase&) = delete;
|
|
||||||
|
|
||||||
NRTCommandBase(void* inUserData)
|
|
||||||
// mWorld(inWorld),mReplyAddr(replyAddr), mCompletionMsgData(completionMsgData), mCompletionMsgSize(completionMsgSize),
|
|
||||||
|
|
||||||
{}
|
|
||||||
|
|
||||||
~NRTCommandBase() = default;
|
|
||||||
|
|
||||||
template <typename T> using AsyncFn = bool (T::*)(World* w);
|
|
||||||
template <typename T> using AsyncCleanup = void (T::*)();
|
|
||||||
|
|
||||||
template <typename T, AsyncFn<T> F>
|
|
||||||
static bool call(World* w,void* x){return (static_cast<T*>(x)->*F)(w);}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static void call(World*, void* x){delete static_cast<T*>(x);}
|
|
||||||
|
|
||||||
template<typename T, AsyncFn<T> Stage2, AsyncFn<T> Stage3, AsyncFn<T> Stage4>
|
|
||||||
void cmd(World* world, std::string name, void* replyAddr, char* completionMsgData, size_t completionMsgSize)
|
|
||||||
{
|
|
||||||
(world->ft->fDoAsynchronousCommand)(world, replyAddr,name.c_str(),this,
|
|
||||||
call<T,Stage2>, call<T,Stage3>, call<T,Stage4>,call<T>,
|
|
||||||
completionMsgSize,completionMsgData);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// World * mWorld;
|
|
||||||
// InterfaceTable *ft;
|
|
||||||
long bufNUm;
|
|
||||||
void* mReplyAddr;
|
|
||||||
const char* cmdName;
|
|
||||||
void *cmdData;
|
|
||||||
char* mCompletionMsgData;
|
|
||||||
size_t mCompletionMsgSize;
|
|
||||||
// std::vector<param_type> mParams;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Client>
|
|
||||||
static void printCmd(InterfaceTable* ft, const char* name, const char* classname)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// std::string filepath(__FILE__);
|
|
||||||
// size_t path_sep = filepath.rfind('/');
|
|
||||||
// size_t extdot = filepath.rfind('.');
|
|
||||||
// filepath.erase(filepath.begin() + extdot,filepath.end());
|
|
||||||
// filepath.erase(filepath.begin(),filepath.begin() + path_sep + 1);
|
|
||||||
// std::for_each(filepath.begin(), filepath.begin() + 2, [](char& c){
|
|
||||||
// c = std::toupper(c);
|
|
||||||
// });
|
|
||||||
|
|
||||||
std::string filepath("/tmp/");
|
|
||||||
filepath.append(classname);
|
|
||||||
filepath.append(".sc");
|
|
||||||
|
|
||||||
std::ofstream ss(filepath);
|
|
||||||
ss << classname << "{\n";
|
|
||||||
|
|
||||||
ss << "\t\t*process { arg server";
|
|
||||||
|
|
||||||
std::ostringstream cmd;
|
|
||||||
cmd << "\t\t\tserver.sendMsg(\\cmd, \\" << name;
|
|
||||||
|
|
||||||
size_t count = 0;
|
|
||||||
for(auto&& d: Client::getParamDescriptors())
|
|
||||||
{
|
|
||||||
ss << ", " << d.getName();
|
|
||||||
if(d.hasDefault())
|
|
||||||
{
|
|
||||||
ss << " = " << d.getDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd << ", ";
|
|
||||||
if (d.getType() == client::Type::kBuffer) {
|
|
||||||
if (count == 0)
|
|
||||||
cmd << d.getName() << ".bufnum";
|
|
||||||
else
|
|
||||||
cmd << "\nif( " << d.getName() << ".isNil, -1, {" << d.getName() << ".bufnum})";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cmd << d.getName();
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd << ");\n\n";
|
|
||||||
|
|
||||||
ss << ";\n\n\t\tserver = server ? Server.default\n;" ;
|
|
||||||
|
|
||||||
if (Client::getParamDescriptors()[0].getType() ==
|
|
||||||
client::Type::kBuffer) {
|
|
||||||
ss << "if("<<Client::getParamDescriptors()[0].getName()
|
|
||||||
<< ".bufnum.isNil) {Error(\"Invalid Buffer\").format(thisMethod.name, this.class.name).throw};\n\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
ss << cmd.str() << "\n\n}\n}";
|
|
||||||
|
|
||||||
// Print(ss.str().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//This wraps a class instance in a function call to pass to SC
|
|
||||||
template<typename NRT_Plug>
|
|
||||||
void command(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr)
|
|
||||||
{
|
|
||||||
|
|
||||||
NRT_Plug* cmd = new NRT_Plug(inUserData);
|
|
||||||
|
|
||||||
//Iterate over parameter descriptions associated with this client object, fill with data from language side
|
|
||||||
// std::vector<client::Instance> params = NRT_Plug::client_type::newParameterSet();
|
|
||||||
for (auto&& p: cmd->parameters())
|
|
||||||
{
|
|
||||||
switch(p.getDescriptor().getType())
|
|
||||||
{
|
|
||||||
case client::Type::kBuffer: {
|
|
||||||
long bufnum = static_cast<long>(args->geti());
|
|
||||||
if (bufnum >= 0) {
|
|
||||||
SCBufferView *buf = new SCBufferView(bufnum, inWorld);
|
|
||||||
p.setBuffer(buf);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case client::Type::kLong: {
|
|
||||||
p.setLong(static_cast<long>(args->geti()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case client::Type::kFloat: {
|
|
||||||
p.setFloat(args->getf());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
p.setLong(static_cast<long>(args->geti()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Deal with the completion message at the end, if any
|
|
||||||
size_t completionMsgSize = args->getbsize();
|
|
||||||
char* completionMsgData = 0;
|
|
||||||
if(completionMsgSize)
|
|
||||||
{
|
|
||||||
//allocate string
|
|
||||||
completionMsgData = (char*)inWorld->ft->fRTAlloc(inWorld,completionMsgSize);
|
|
||||||
args->getb(completionMsgData,completionMsgSize);
|
|
||||||
}
|
|
||||||
//Make a new pointer for our plugin, and set it going
|
|
||||||
|
|
||||||
cmd->runCommand(inWorld, replyAddr, completionMsgData, completionMsgSize);
|
|
||||||
}
|
|
||||||
} //namespace wrapper
|
|
||||||
}//namespace fluid
|
|
||||||
|
|
||||||
|
|
||||||
template <typename NRT_Plug,typename NRT_Client>
|
|
||||||
void registerCommand(InterfaceTable* ft, const char* name)
|
|
||||||
{
|
|
||||||
PlugInCmdFunc cmd = fluid::wrapper::command<NRT_Plug>;
|
|
||||||
(*ft->fDefinePlugInCmd)(name,cmd,nullptr);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,14 +1,11 @@
|
|||||||
FluidBufCompose{
|
FluidBufCompose{
|
||||||
*process { arg server, srcBufNumA, startAtA = 0, nFramesA = -1, startChanA = 0, nChansA = -1, srcGainA = 1, dstStartAtA = 0, dstStartChanA = 0, srcBufNumB, startAtB = 0, nFramesB = -1, startChanB = 0, nChansB = -1, srcGainB = 1, dstStartAtB = 0, dstStartChanB = 0, dstBufNum;
|
*process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, srcGain = 1, dstBufNum, dstStartAt = 0, dstStartChan = 0;
|
||||||
|
|
||||||
if(srcBufNumA.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw};
|
if(srcBufNum.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw};
|
||||||
if(srcBufNumB.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw};
|
if(srcBufNum.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw};
|
||||||
if(dstBufNum.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw};
|
if(dstBufNum.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw};
|
||||||
|
|
||||||
server = server ? Server.default;
|
server = server ? Server.default;
|
||||||
|
server.sendMsg(\cmd, \BufCompose, srcBufNum, startAt, nFrames, startChan, nChans, srcGain, dstBufNum,dstStartAt, dstStartChan);
|
||||||
server.sendMsg(\cmd, \BufCompose, srcBufNumA, startAtA, nFramesA, startChanA, nChansA, srcGainA, dstStartAtA, dstStartChanA,
|
|
||||||
srcBufNumB, startAtB, nFramesB, startChanB, nChansB, srcGainB, dstStartAtB, dstStartChanB,
|
|
||||||
dstBufNum);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,11 +1,11 @@
|
|||||||
FluidBufTransientSlice{
|
FluidBufTransientSlice{
|
||||||
*process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, transBufNum, order = 200, blockSize = 2048, padSize = 1024, skew = 0, threshFwd = 3, threshBack = 1.1, winSize = 14, debounce = 25;
|
*process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, transBufNum, order = 200, blockSize = 2048, padSize = 1024, skew = 0, threshFwd = 3, threshBack = 1.1, winSize = 14, debounce = 25, minSlice = 1000;
|
||||||
|
|
||||||
if(srcBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw};
|
if(srcBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw};
|
||||||
if(transBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw};
|
if(transBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw};
|
||||||
|
|
||||||
server = server ? Server.default;
|
server = server ? Server.default;
|
||||||
|
|
||||||
server.sendMsg(\cmd, \BufTransientSlice, srcBufNum, startAt, nFrames, startChan, nChans, transBufNum, order, blockSize, padSize, skew, threshFwd, threshBack, winSize, debounce);
|
server.sendMsg(\cmd, \BufTransientSlice, srcBufNum, startAt, nFrames, startChan, nChans, transBufNum, order, blockSize, padSize, skew, threshFwd, threshBack, winSize, debounce, minSlice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
FluidGain : UGen {
|
FluidGain : UGen {
|
||||||
*ar { arg in = 0, frameSize=64, gain=1.0;
|
*ar { arg in = 0, gain=1.0;
|
||||||
^this.multiNew('audio', in.asAudioRateInput(this),frameSize, gain)
|
^this.multiNew('audio', in.asAudioRateInput(this), gain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
FluidOnsetSlice : UGen {
|
||||||
|
*ar { arg in = 0, function = 0, threshold = 0.1, debounce = 2, filterSize = 5, winSize = 1024, hopSize = 256, frameDelta = 0, fftSize = 1024, maFFTSize = 16384;
|
||||||
|
^this.multiNew('audio', in.asAudioRateInput(this), function, threshold, debounce, filterSize, winSize, hopSize, frameDelta, fftSize, maFFTSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
FluidSTFTPass : UGen {
|
FluidSTFTPass : UGen {
|
||||||
*ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1;
|
*ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1, maxFFTSize = 16384;
|
||||||
^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize)
|
^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize, maxFFTSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
FluidTransientSlice : UGen {
|
FluidTransientSlice : UGen {
|
||||||
*ar { arg in = 0, order = 20, blockSize = 256, padSize = 128, skew = 0.0, threshFwd = 3.0, threshBack = 1.1, winSize=14, debounce=25;
|
*ar { arg in = 0, order = 20, blockSize = 256, padSize = 128, skew = 0.0, threshFwd = 3.0, threshBack = 1.1, winSize=14, debounce=25, minSlice = 1000;
|
||||||
^this.multiNew('audio', in.asAudioRateInput(this), order, blockSize, padSize, skew, threshFwd ,threshBack, winSize, debounce)
|
^this.multiNew('audio', in.asAudioRateInput(this), order, blockSize, padSize, skew, threshFwd ,threshBack, winSize, debounce, minSlice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.3)
|
||||||
|
get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE)
|
||||||
|
message("Configuring ${PLUGIN}")
|
||||||
|
set(FILENAME ${PLUGIN}.cpp)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
${PLUGIN}
|
||||||
|
MODULE
|
||||||
|
${FILENAME}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
${PLUGIN} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../../include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${PLUGIN} PRIVATE FLUID_DECOMPOSITION
|
||||||
|
)
|
||||||
|
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/../../scripts/target_post.cmake)
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
s.reboot;
|
||||||
|
|
||||||
|
b = Buffer.read(s,"../../release-packaging/AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav".resolveRelative);
|
||||||
|
|
||||||
|
// basic param (the process add a latency of (blockSize + padding - order) samples
|
||||||
|
{var sig = PlayBuf.ar(1,b.bufnum,loop:1); [FluidTransientSlice.ar(sig)*0.5, DelayN.ar(sig, 1, ((256 + 128 - 20)/ s.sampleRate))]}.play
|
||||||
|
|
||||||
|
// sexier params
|
||||||
|
{var sig = PlayBuf.ar(1,b.bufnum,loop:1); [FluidTransientSlice.ar(sig,order:80,debounce:2205)*0.5, DelayN.ar(sig, 1, ((256 + 128 - 80)/ s.sampleRate))]}.play
|
||||||
|
|
||||||
|
// more musical trans-trigged autopan
|
||||||
|
(
|
||||||
|
{
|
||||||
|
var sig, trig, syncd, pan;
|
||||||
|
sig = PlayBuf.ar(1,b.bufnum,loop:1);
|
||||||
|
trig = FluidTransientSlice.ar(sig,order:10,debounce:2205);
|
||||||
|
syncd = DelayN.ar(sig, 1, ((256 + 128 - 10)/ s.sampleRate));
|
||||||
|
pan = TRand.ar(-1,1,trig);
|
||||||
|
Pan2.ar(syncd,pan);
|
||||||
|
}.play
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue