Add NRT to wrapper, remove old NRT header. Seperate out buffer adaptor to own header. Small changes to existing clients

include/fdNRTBase.hpp
include/FluidSCWrapper.hpp
include/SCBufferAdaptor.hpp
release-packaging/Classes/FluidSTFTPass.sc
src/FluidBufTransients/FluidBufTransients.cpp
src/FluidGain/FluidGain.cpp
src/FluidTransients/FluidTransients.cpp
nix
Owen Green 7 years ago
parent a5121a8f71
commit c61190993f

@ -1,131 +1,300 @@
#pragma once
#include <clients/rt/GainClient.hpp>
#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> class FluidSCWrapper;
namespace impl {
template <typename Client, typename T, size_t N> struct SetterDispatchImpl;
template <typename Client, typename T, size_t N> struct GetterDispatchImpl;
} // 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);
template <size_t N, typename T, msg_iter_method<T> Method> struct GetArgument
{
T operator()(sc_msg_iter *args)
{
T r = (args->*Method)(0);
std::cout << r << '\n';
return r;
}
};
template <size_t N, typename T> struct GetControl
{
T operator()(float **controls) { return *controls[N]; }
};
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, typename T> struct ControlGetter : public GetControl<N, typename T::type>
{};
template <class Wrapper> class RealTime : public SCUnit
{
using HostVector = FluidTensorView<float, 1>;
// using Client = typename Wrapper::ClientType;
template <typename Client>
class FluidSCWrapper : public SCUnit {
public:
FluidSCWrapper() {
static void setup(InterfaceTable *ft, const char *name) { registerUnit<Wrapper>(ft, name); }
RealTime() {}
void init()
{
Wrapper *w = static_cast<Wrapper *>(this);
auto &mClient = w->client();
mInputConnections.reserve(mClient.audioChannelsIn());
mOutputConnections.reserve(mClient.audioChannelsOut());
mAudioInputs.reserve(mClient.audioChannelsIn());
mAudioOutputs.reserve(mClient.audioChannelsOut());
for (int i = 0; i < mClient.audioChannelsIn(); ++i) {
for (int i = 0; i < mClient.audioChannelsIn(); ++i)
{
mInputConnections.emplace_back(isAudioRateIn(i));
mAudioInputs.emplace_back(nullptr, 0, 0);
}
// const Unit *unit = this;
//
for (int i = 0; i < mClient.audioChannelsOut(); ++i) {
for (int i = 0; i < mClient.audioChannelsOut(); ++i)
{
mOutputConnections.emplace_back(true);
mAudioOutputs.emplace_back(nullptr, 0, 0);
}
set_calc_function<FluidSCWrapper, &FluidSCWrapper::next>();
set_calc_function<RealTime, &RealTime::next>();
Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1);
}
// mCalcFunc = [](Unit *u, int n) {
// FluidSCWrapper *f = static_cast<FluidSCWrapper *>(u);
// f->next(n);
// };
void next(int n)
{
Wrapper *w = static_cast<Wrapper *>(this);
auto &client = w->client();
w->setParams(mInBuf + client.audioChannelsIn(), mWorld->mVerbosity > 0); // forward on inputs N + audio inputs as params
const Unit *unit = this;
for (int i = 0; i < client.audioChannelsIn(); ++i)
{
if (mInputConnections[i]) mAudioInputs[i].reset(IN(i), 0, fullBufferSize());
}
for (int i = 0; i < client.audioChannelsOut(); ++i)
{
if (mOutputConnections[i]) mAudioOutputs[i].reset(out(i), 0, fullBufferSize());
}
client.process(mAudioInputs, mAudioOutputs);
}
void next(int n) {
private:
std::vector<bool> mInputConnections;
std::vector<bool> mOutputConnections;
std::vector<HostVector> mAudioInputs;
std::vector<HostVector> mAudioOutputs;
};
template <class Wrapper> class NonRealTime
{
public:
static void setup(InterfaceTable *ft, const char *name) { DefinePlugInCmd(name, launch, nullptr); }
setParams(mInBuf + 1); // forward on inputs N + 1 as params
NonRealTime() {}
const Unit *unit = this;
for (int i = 0; i < mClient.audioChannelsIn(); ++i) {
if (mInputConnections[i])
mAudioInputs[i].reset(IN(i), 0, fullBufferSize());
}
void init(){};
for (int i = 0; i < mClient.audioChannelsOut(); ++i) {
if (mOutputConnections[i])
mAudioOutputs[i].reset(out(i), 0, fullBufferSize());
static void launch(World *world, void *inUserData, struct sc_msg_iter *args, void *replyAddr)
{
Wrapper *w = new Wrapper(); //this has to be on the heap, because it doesn't get destoryed until the async command is done
w->parseBuffers(w, world, args);
int argsPosition = args->count;
Result result = validateParameters(w, args);
if (!result.ok())
{
std::cout << "FluCoMa Error " << Wrapper::getName() << ": " << result.message().c_str();
return;
}
args->count = argsPosition;
w->setParams(args,false);
size_t msgSize = args->getbsize();
char * completionMsgData = 0;
if (msgSize)
{
completionMsgData = (char *) world->ft->fRTAlloc(world, msgSize);
args->getb(completionMsgData, msgSize);
}
world->ft->fDoAsynchronousCommand(world, replyAddr, Wrapper::getName(), w, process, exchangeBuffers, tidyUp, destroy,
msgSize, completionMsgData);
}
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) { delete static_cast<Wrapper *>(data); }
mClient.process(mAudioInputs, mAudioOutputs);
private:
static Result validateParameters(Wrapper *w, sc_msg_iter *args)
{
auto &c = w->client();
auto results = c.template checkParameterValues<ArgumentGetter, sc_msg_iter>(args);
for (auto &r : results)
{
std::cout << r.message() << r.status() << '\n';
if (!r.ok()) return r;
}
return {};
}
void setParams(float **inputs) {
setParams(inputs, ParamIndexList());
void parseBuffers(Wrapper *w, World *world, sc_msg_iter *args)
{
auto &c = w->client();
mBuffersIn.reserve(c.audioBuffersIn());
mInputs.reserve(c.audioBuffersIn());
mBuffersOut.reserve(c.audioBuffersOut());
mOutputs.reserve(c.audioBuffersOut());
for (int i = 0; i < c.audioBuffersIn(); i++)
{
mBuffersIn.emplace_back(args->geti(0), world);
mInputs.emplace_back();
mInputs[i].buffer = &mBuffersIn[i];
mInputs[i].startFrame = args->geti(0);
mInputs[i].nFrames = args->geti(0);
mInputs[i].startChan = args->geti(0);
mInputs[i].nChans = args->geti(0);
}
private:
template <size_t... Is>
void setParams(float **inputs, std::index_sequence<Is...>) {
(void)std::initializer_list<int>{
(impl::SetterDispatchImpl<Client, Ts, Is>::f(mClient, 1, inputs[Is],
mInputConnections[Is+1]),
0)...};
for (int i = 0; i < c.audioBuffersOut(); i++)
{
mBuffersOut.emplace_back(args->geti(0), world);
mOutputs.emplace_back();
mOutputs[i].buffer = &mBuffersOut[i];
}
}
std::vector<bool> mInputConnections;
std::vector<bool> mOutputConnections;
std::vector<HostVector<float>> mAudioInputs;
std::vector<HostVector<float>> mAudioOutputs;
bool process(World *world)
{
Wrapper *wrapper = static_cast<Wrapper *>(this);
Result r = wrapper->client().process(mInputs, mOutputs);
Client mClient;
};
if(!r.ok())
{
std::cout << "FluCoMa Error " << Wrapper::getName() << ": " << r.message().c_str();
return false;
}
namespace impl {
template <typename Client, size_t N>
struct SetterDispatchImpl<Client, FloatT, N> {
static void f(Client &x, long ac, float *av, bool isAudio) {
if (!isAudio)
x.template setter<N>()(*av);
return true;
}
};
template <typename Client, size_t N>
struct SetterDispatchImpl<Client, LongT, N> {
static void f(Client &x, long ac, float *av, bool isAudio) {
if (!isAudio)
x.template setter<N>()(*av);
bool exchangeBuffers(World *world)
{
for (auto &b : mBuffersOut) b.assignToRT(world);
return true;
}
};
template <typename Client, size_t N>
struct SetterDispatchImpl<Client, BufferT, N> {
static void f(Client *x, long ac, float *av, bool isAudio) {
if (!isAudio)
x->template setter<N>()(*av);
bool tidyUp(World *world)
{
for (auto &b : mBuffersIn) b.cleanUp();
for (auto &b : mBuffersOut) b.cleanUp();
return true;
}
std::vector<SCBufferAdaptor> mBuffersIn;
std::vector<SCBufferAdaptor> mBuffersOut;
std::vector<BufferProcessSpec> mInputs;
std::vector<BufferProcessSpec> mOutputs;
void * mReplyAddr;
const char * mName;
};
template <typename Client, size_t N>
struct SetterDispatchImpl<Client, EnumT, N> {
static void f(Client *x, long ac, float *av, bool isAudio) {
if (!isAudio)
x->template setter<N>()(*av);
template <typename Wrapper> class NonRealTimeAndRealTime : public RealTime<Wrapper>, public NonRealTime<Wrapper>
{
static void setup(InterfaceTable *ft, const char *name)
{
RealTime<Wrapper>::setup(ft, name);
NonRealTime<Wrapper>::setup(ft, name);
}
};
} // namespace impl
// Template Specialisations for NRT/RT
template <typename Wrapper, typename NRT, typename RT> class FluidSCWrapperImpl;
template <typename Wrapper> class FluidSCWrapperImpl<Wrapper, std::true_type, std::false_type> : public NonRealTime<Wrapper>
{};
template <typename Wrapper> class FluidSCWrapperImpl<Wrapper, std::false_type, std::true_type> : public RealTime<Wrapper>
{};
// Make base class(es), full of CRTP mixin goodness
template <typename Client>
void makeSCWrapper(InterfaceTable *ft, const char *className, Client::ParamType &params)
using FluidSCWrapperBase = FluidSCWrapperImpl<FluidSCWrapper<Client>, isNonRealTime<Client>, isRealTime<Client>>;
} // namespace impl
template <typename Client> class FluidSCWrapper : public impl::FluidSCWrapperBase<Client>
{
registerUnit<FluidSCWrapper<Client>(ft, className);
public:
using ClientType = Client;
FluidSCWrapper() { impl::FluidSCWrapperBase<Client>::init(); }
static const char *getName(const char *setName = nullptr)
{
static const char *name = nullptr;
return (name = setName ? setName : name);
}
static InterfaceTable *getInterfaceTable(InterfaceTable *setTable = nullptr)
{
static InterfaceTable *ft = nullptr;
return (ft = setTable ? setTable : ft);
}
static void setup(InterfaceTable *ft, const char *name)
{
getName(name);
getInterfaceTable(ft);
impl::FluidSCWrapperBase<Client>::setup(ft, name);
}
auto setParams(float **inputs, bool verbose)
{
return mClient.template setParameterValues<impl::ControlGetter, float*>(inputs, verbose);
}
auto setParams(sc_msg_iter *args, bool verbose)
{
return mClient.template setParameterValues<impl::ArgumentGetter, sc_msg_iter>(args, verbose);
}
Client &client() { return mClient; }
private:
Client mClient;
};
template <typename Client> void makeSCWrapper(InterfaceTable *ft, const char *name)
{
FluidSCWrapper<Client>::setup(ft, name);
}
} // namespace client
} // namespace fluid

@ -0,0 +1,244 @@
#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;
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 {}
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;
}
protected:
bool equal(BufferAdaptor *rhs) const override
{
SCBufferAdaptor *x = dynamic_cast<SCBufferAdaptor *>(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 {}
// 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);
}

@ -3,3 +3,4 @@ FluidSTFTPass : UGen {
^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize, maxWinSize)
}
}
//

@ -1,81 +1,90 @@
// FD_BufNMF, an NRT buffer NMF Processor
// A tool from the FluCoMa project, funded by the European Research Council (ERC) under the European Unions Horizon 2020 research and innovation programme (grant agreement No 725899)
#include "clients/nrt/TransientNRTClient.hpp"
#include "fdNRTBase.hpp"
#include "data/FluidTensor.hpp"
#include "clients/common/FluidParams.hpp"
#include "SC_PlugIn.h"
#include <unordered_set>
#include <vector>
//#include "clients/nrt/TransientNRTClient.hpp"
//#include "fdNRTBase.hpp"
//#include "data/FluidTensor.hpp"
//#include "clients/common/FluidParams.hpp"
//#include "SC_PlugIn.h"
//#include <unordered_set>
//#include <vector>
static InterfaceTable *ft;
namespace fluid {
namespace wrapper{
#include <clients/nrt/FluidNRTClientWrapper.hpp>
#include <clients/rt/TransientClient.hpp>
class BufTransients: public NRTCommandBase
{
public:
using client_type = client::TransientNRTClient;
using NRTCommandBase::NRTCommandBase;
#include <FluidSCWrapper.hpp>
~BufTransients() {}
void runCommand(World* world, void* replyAddr, char* completionMsgData, size_t completionMsgSize)
{
cmd<BufTransients, &BufTransients::process, &BufTransients::postProcess, &BufTransients::postComplete>(world, "/BufTransients", replyAddr, completionMsgData, completionMsgSize);
}
bool process(World* world)
{
//sanity check the parameters
bool parametersOk;
client_type::ProcessModel processModel;
std::string whatHappened;//this will give us a message to pass back if param check fails
std::tie(parametersOk,whatHappened,processModel) = trans.sanityCheck();
if(!parametersOk)
{
Print("fdTransients: %s \n", whatHappened.c_str());
return false;
}
trans.process(processModel);
mModel = processModel;
return true;
}
bool postProcess(World* world)
{
if(mModel.returnTransients)
static_cast<SCBufferView*>(mModel.trans)->assignToRT(world);
if(mModel.returnResidual)
static_cast<SCBufferView*>(mModel.res)->assignToRT(world);
return true;
}
bool postComplete(World*)
{
if(mModel.returnTransients)
static_cast<SCBufferView*>(mModel.trans)->cleanUp();
if(mModel.returnResidual)
static_cast<SCBufferView*>(mModel.res)->cleanUp();
return true;
static InterfaceTable *ft;
}
std::vector<client::Instance>& parameters()
{
return trans.getParams();
}
private:
client_type trans;
client_type::ProcessModel mModel;
};//class
} //namespace wrapper
}//namespace fluid
//namespace fluid {
// namespace wrapper{
//
// class BufTransients: public NRTCommandBase
// {
// public:
// using client_type = client::TransientNRTClient;
// using NRTCommandBase::NRTCommandBase;
//
// ~BufTransients() {}
//
// void runCommand(World* world, void* replyAddr, char* completionMsgData, size_t completionMsgSize)
// {
// cmd<BufTransients, &BufTransients::process, &BufTransients::postProcess, &BufTransients::postComplete>(world, "/BufTransients", replyAddr, completionMsgData, completionMsgSize);
// }
//
// bool process(World* world)
// {
// //sanity check the parameters
// bool parametersOk;
// client_type::ProcessModel processModel;
// std::string whatHappened;//this will give us a message to pass back if param check fails
// std::tie(parametersOk,whatHappened,processModel) = trans.sanityCheck();
// if(!parametersOk)
// {
// Print("fdTransients: %s \n", whatHappened.c_str());
// return false;
// }
// trans.process(processModel);
// mModel = processModel;
// return true;
// }
//
// bool postProcess(World* world)
// {
// if(mModel.returnTransients)
// static_cast<SCBufferView*>(mModel.trans)->assignToRT(world);
// if(mModel.returnResidual)
// static_cast<SCBufferView*>(mModel.res)->assignToRT(world);
// return true;
// }
//
// bool postComplete(World*)
// {
// if(mModel.returnTransients)
// static_cast<SCBufferView*>(mModel.trans)->cleanUp();
// if(mModel.returnResidual)
// static_cast<SCBufferView*>(mModel.res)->cleanUp();
// return true;
//
// }
// std::vector<client::Instance>& parameters()
// {
// return trans.getParams();
// }
// private:
// client_type trans;
// client_type::ProcessModel mModel;
// };//class
// } //namespace wrapper
//}//namespace fluid
PluginLoad(OfflineFluidDecompositionUGens) {
ft = inTable;
registerCommand<fluid::wrapper::BufTransients,fluid::client::TransientNRTClient>(ft, "BufTransients");
fluid::wrapper::printCmd<fluid::client::TransientNRTClient>(ft,"BufTransients","FDTransients");
using namespace fluid::client;
makeSCWrapper<NRTClientWrapper<TransientClient<double,float>, decltype(TransientParams), TransientParams>>(ft,"BufTransients");
// registerCommand<fluid::wrapper::BufTransients,fluid::client::TransientNRTClient>(ft, "BufTransients");
// fluid::wrapper::printCmd<fluid::client::TransientNRTClient>(ft,"BufTransients","FDTransients");
}

@ -9,5 +9,5 @@ static InterfaceTable *ft;
PluginLoad(FluidGainUgen) {
ft = inTable;
using namespace fluid::client;
makeSCWrapper<GainClient<double,float>>(ft, "FluidGain",GainParams);
makeSCWrapper<GainClient<double,float>>(ft, "FluidGain");
}

@ -1,129 +1,17 @@
// A tool from the FluCoMa project, funded by the European Research Council (ERC) under the European Unions Horizon 2020 research and innovation programme (grant agreement No 725899)
#include "SC_PlugIn.hpp"
#include "data/FluidTensor.hpp"
#include "clients/rt/TransientClient.hpp"
static InterfaceTable *ft;
namespace fluid {
namespace wrapper{
class FluidTransients: public SCUnit
{
using AudioSignalWrapper = client::TransientsClient<double, float>::AudioSignal;
using SignalWrapper = client::TransientsClient<double, float>::Signal<float>;
// using SignalPointer = std::unique_ptr<signal_wrapper>;
public:
FluidTransients()
{
//Order of args
//Window size, Hop size, FFT Size
//Get the window size
// const float hfilter_size = in0(1);
// const float pfilter_size = in0(2);
// const float window_size = in0(3);
// const float hop_size = in0(4);
// const float fft_size = in0(5);
//
//Oh NO! Heap allocation! Make client object
mClient = new client::TransientsClient<double,float>(65536);
setParams(true);
// mClient->geParams()[0].setLong(pfilter_size);
// mClient->geParams()[1].setLong(hfilter_size);
// mClient->geParams()[2].setLong(window_size);
// mClient->geParams()[3].setLong(hop_size);
// mClient->geParams()[4].setLong(fft_size);
bool isOK;
std::string feedback;
std::tie(isOK, feedback) = mClient->sanityCheck();
if(!isOK)
{
Print("fdRTHPSS Error: %s",feedback.c_str());
return;
}
mClient->setHostBufferSize(bufferSize());
mClient->reset();
//Work out what signals we need. For now keep it simple:
//in 0 => only audio
//out 0 => only audio
inputSignals[0] = new AudioSignalWrapper();
outputSignals[0] = new AudioSignalWrapper();
outputSignals[1] = new AudioSignalWrapper();
mCalcFunc = make_calc_function<FluidTransients,&FluidTransients::next>();
Unit* unit = this;
ClearUnitOutputs(unit,1);
}
~FluidTransients()
{
delete inputSignals[0];
delete outputSignals[0];
delete outputSignals[1];
delete mClient;
}
private:
void setParams(bool instantiation)
{
assert(mClient);
for(size_t i = 0; i < mClient->getParams().size(); ++i)
{
client::Instance& p = mClient->getParams()[i];
if(!instantiation && p.getDescriptor().instantiation())
continue;
switch(p.getDescriptor().getType())
{
case client::Type::kLong:
p.setLong(in0(i + 1));
p.checkRange();
break;
case client::Type::kFloat:
p.setFloat(in0(i + 1));
p.checkRange();
break;
case client::Type::kBuffer:
// p.setBuffer( in0(i+1));
break;
default:
break;
}
}
}
#include <clients/rt/TransientClient.hpp>
#include <SC_PlugIn.hpp>
#include <FluidSCWrapper.hpp>
void next(int numsamples)
{
setParams(false);
const float* input = in(0);
const float inscalar = in0(0);
inputSignals[0]->set(const_cast<float*>(input), inscalar);
outputSignals[0]->set(out(0), out0(0));
outputSignals[1]->set(out(1), out0(1));
mClient->doProcess(std::begin(inputSignals),std::end(inputSignals),std::begin(outputSignals), std::end(outputSignals),numsamples,1,2);
}
client::TransientsClient<double, float> *mClient;
SignalWrapper *inputSignals[1];
SignalWrapper *outputSignals[2];
};
}
}
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen) {
ft = inTable;
registerUnit<fluid::wrapper::FluidTransients>(ft, "FluidTransients");
// registerUnit<fluid::wrapper::FluidTransients>(ft, "FluidTransients");
using namespace fluid::client;
makeSCWrapper<TransientClient<double,float>>(ft, "FluidTransients",TransientParams);
}

Loading…
Cancel
Save