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{
|
||||
*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(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(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};
|
||||
|
||||
server = server ? Server.default;
|
||||
|
||||
server.sendMsg(\cmd, \BufCompose, srcBufNumA, startAtA, nFramesA, startChanA, nChansA, srcGainA, dstStartAtA, dstStartChanA,
|
||||
srcBufNumB, startAtB, nFramesB, startChanB, nChansB, srcGainB, dstStartAtB, dstStartChanB,
|
||||
dstBufNum);
|
||||
server.sendMsg(\cmd, \BufCompose, srcBufNum, startAt, nFrames, startChan, nChans, srcGain, dstBufNum,dstStartAt, dstStartChan);
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
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(transBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw};
|
||||
|
||||
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 {
|
||||
*ar { arg in = 0, frameSize=64, gain=1.0;
|
||||
^this.multiNew('audio', in.asAudioRateInput(this),frameSize, gain)
|
||||
*ar { arg in = 0, gain=1.0;
|
||||
^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 {
|
||||
*ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1;
|
||||
^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize)
|
||||
*ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1, maxFFTSize = 16384;
|
||||
^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize, maxFFTSize)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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;
|
||||
^this.multiNew('audio', in.asAudioRateInput(this), order, blockSize, padSize, skew, threshFwd ,threshBack, winSize, debounce)
|
||||
*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, 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