diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index cf5cc42..9f9d4f6 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -1,131 +1,300 @@ #pragma once -#include +#include "SCBufferAdaptor.hpp" +#include +#include #include #include #include #include +#include #include #include + namespace fluid { namespace client { +template class FluidSCWrapper; + namespace impl { -template struct SetterDispatchImpl; -template struct GetterDispatchImpl; -} // namespace impl +template struct Setter; +template struct ArgumentGetter; +template struct ControlGetter; +template using msg_iter_method = T (sc_msg_iter::*)(T); + +template Method> struct GetArgument +{ + T operator()(sc_msg_iter *args) + { + T r = (args->*Method)(0); + std::cout << r << '\n'; + return r; + } +}; + +template struct GetControl +{ + T operator()(float **controls) { return *controls[N]; } +}; + +template struct ArgumentGetter : public GetArgument +{}; + +template struct ArgumentGetter : public GetArgument +{}; + +template struct ControlGetter : public GetControl +{}; + +template class RealTime : public SCUnit +{ + using HostVector = FluidTensorView; + // using Client = typename Wrapper::ClientType; -template -class FluidSCWrapper : public SCUnit { public: - FluidSCWrapper() { + static void setup(InterfaceTable *ft, const char *name) { registerUnit(ft, name); } + + RealTime() {} + + void init() + { + Wrapper *w = static_cast(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(); + set_calc_function(); + Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1); + } -// mCalcFunc = [](Unit *u, int n) { -// FluidSCWrapper *f = static_cast(u); -// f->next(n); -// }; + void next(int n) + { + Wrapper *w = static_cast(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 mInputConnections; + std::vector mOutputConnections; + std::vector mAudioInputs; + std::vector mAudioOutputs; +}; + +template class NonRealTime +{ +public: + static void setup(InterfaceTable *ft, const char *name) { DefinePlugInCmd(name, launch, nullptr); } + + NonRealTime() {} - setParams(mInBuf + 1); // forward on inputs N + 1 as params + void init(){}; - const Unit *unit = this; - for (int i = 0; i < mClient.audioChannelsIn(); ++i) { - if (mInputConnections[i]) - mAudioInputs[i].reset(IN(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(data)->process(world); } + static bool exchangeBuffers(World *world, void *data) { return static_cast(data)->exchangeBuffers(world); } + static bool tidyUp(World *world, void *data) { return static_cast(data)->tidyUp(world); } + static void destroy(World *world, void *data) { delete static_cast(data); } + +private: + static Result validateParameters(Wrapper *w, sc_msg_iter *args) + { + auto &c = w->client(); + auto results = c.template checkParameterValues(args); + for (auto &r : results) + { + std::cout << r.message() << r.status() << '\n'; + if (!r.ok()) return r; } + return {}; + } + + 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 < mClient.audioChannelsOut(); ++i) { - if (mOutputConnections[i]) - mAudioOutputs[i].reset(out(i), 0, fullBufferSize()); + 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); } - mClient.process(mAudioInputs, mAudioOutputs); + for (int i = 0; i < c.audioBuffersOut(); i++) + { + mBuffersOut.emplace_back(args->geti(0), world); + mOutputs.emplace_back(); + mOutputs[i].buffer = &mBuffersOut[i]; + } } - void setParams(float **inputs) { - setParams(inputs, ParamIndexList()); + bool process(World *world) + { + Wrapper *wrapper = static_cast(this); + Result r = wrapper->client().process(mInputs, mOutputs); + + if(!r.ok()) + { + std::cout << "FluCoMa Error " << Wrapper::getName() << ": " << r.message().c_str(); + return false; + } + + return true; } -private: - template - void setParams(float **inputs, std::index_sequence) { - (void)std::initializer_list{ - (impl::SetterDispatchImpl::f(mClient, 1, inputs[Is], - mInputConnections[Is+1]), - 0)...}; + bool exchangeBuffers(World *world) + { + for (auto &b : mBuffersOut) b.assignToRT(world); + return true; } - std::vector mInputConnections; - std::vector mOutputConnections; - std::vector> mAudioInputs; - std::vector> mAudioOutputs; + bool tidyUp(World *world) + { + for (auto &b : mBuffersIn) b.cleanUp(); + for (auto &b : mBuffersOut) b.cleanUp(); + return true; + } - Client mClient; + std::vector mBuffersIn; + std::vector mBuffersOut; + std::vector mInputs; + std::vector mOutputs; + void * mReplyAddr; + const char * mName; }; -namespace impl { -template -struct SetterDispatchImpl { - static void f(Client &x, long ac, float *av, bool isAudio) { - if (!isAudio) - x.template setter()(*av); +template class NonRealTimeAndRealTime : public RealTime, public NonRealTime +{ + static void setup(InterfaceTable *ft, const char *name) + { + RealTime::setup(ft, name); + NonRealTime::setup(ft, name); } }; -template -struct SetterDispatchImpl { - static void f(Client &x, long ac, float *av, bool isAudio) { - if (!isAudio) - x.template setter()(*av); +// Template Specialisations for NRT/RT + +template class FluidSCWrapperImpl; + +template class FluidSCWrapperImpl : public NonRealTime +{}; + +template class FluidSCWrapperImpl : public RealTime +{}; + +// Make base class(es), full of CRTP mixin goodness +template +using FluidSCWrapperBase = FluidSCWrapperImpl, isNonRealTime, isRealTime>; + +} // namespace impl + +template class FluidSCWrapper : public impl::FluidSCWrapperBase +{ + +public: + using ClientType = Client; + + FluidSCWrapper() { impl::FluidSCWrapperBase::init(); } + + static const char *getName(const char *setName = nullptr) + { + static const char *name = nullptr; + return (name = setName ? setName : name); } -}; -template -struct SetterDispatchImpl { - static void f(Client *x, long ac, float *av, bool isAudio) { - if (!isAudio) - x->template setter()(*av); + static InterfaceTable *getInterfaceTable(InterfaceTable *setTable = nullptr) + { + static InterfaceTable *ft = nullptr; + return (ft = setTable ? setTable : ft); } -}; -template -struct SetterDispatchImpl { - static void f(Client *x, long ac, float *av, bool isAudio) { - if (!isAudio) - x->template setter()(*av); + static void setup(InterfaceTable *ft, const char *name) + { + getName(name); + getInterfaceTable(ft); + impl::FluidSCWrapperBase::setup(ft, name); } -}; -} // namespace impl + auto setParams(float **inputs, bool verbose) + { + return mClient.template setParameterValues(inputs, verbose); + } -template -void makeSCWrapper(InterfaceTable *ft, const char *className, Client::ParamType ¶ms) + auto setParams(sc_msg_iter *args, bool verbose) + { + return mClient.template setParameterValues(args, verbose); + } + + Client &client() { return mClient; } + +private: + Client mClient; +}; + +template void makeSCWrapper(InterfaceTable *ft, const char *name) { - registerUnit(ft, className); + FluidSCWrapper::setup(ft, name); } } // namespace client } // namespace fluid - diff --git a/include/SCBufferAdaptor.hpp b/include/SCBufferAdaptor.hpp new file mode 100644 index 0000000..2819c11 --- /dev/null +++ b/include/SCBufferAdaptor.hpp @@ -0,0 +1,244 @@ +#pragma once + +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include + +// 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), 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 samps(size_t channel, size_t rankIdx = 0) override + { + FluidTensorView v{mBuffer->data, 0, + static_cast(mBuffer->frames), + static_cast(mBuffer->channels)}; + + return v.col(rankIdx + channel * mRank); + } + + // Return a 2D chunk + FluidTensorView samps(size_t offset, size_t nframes, + size_t chanoffset) override + { + FluidTensorView v{mBuffer->data, 0, + static_cast(mBuffer->frames), + static_cast(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(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 samps(size_t channel, size_t rankIdx = 0) override + { + FluidTensorView v{mBuffer->data, 0, + static_cast(mBuffer->frames), + static_cast(mBuffer->channels)}; + + return v.col(rankIdx + channel * mRank); + } + + FluidTensorView samps(size_t offset, size_t nframes, + size_t chanoffset) override + { + FluidTensorView v{mBuffer->data, 0, + static_cast(mBuffer->frames), + static_cast(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(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 + diff --git a/include/fdNRTBase.hpp b/include/fdNRTBase.hpp deleted file mode 100644 index f67589c..0000000 --- a/include/fdNRTBase.hpp +++ /dev/null @@ -1,402 +0,0 @@ -#pragma once - - -#include "data/FluidTensor.hpp" -#include "clients/common/FluidParams.hpp" - -#include "SC_PlugIn.h" - -#include -#include -#include -#include -#include -#include -#include - - -//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), 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 samps(size_t channel, size_t rankIdx = 0) override - { - FluidTensorView v{mBuffer->data,0, static_cast(mBuffer->frames),static_cast(mBuffer->channels)}; - - return v.col(rankIdx + channel * mRank ); - } -// //Return a view of all the data -// FluidTensorView samps() override -// { -// return {mBuffer->data,0, static_cast(mBuffer->frames), static_cast(mBuffer->channels)}; -// } - - //Return a 2D chunk - FluidTensorView samps(size_t offset, size_t nframes, size_t chanoffset) override - { - FluidTensorView v{mBuffer->data,0, static_cast(mBuffer->frames), static_cast(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(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 samps(size_t channel, size_t rankIdx = 0) override - { - FluidTensorView v{mBuffer->data,0, static_cast(mBuffer->frames),static_cast(mBuffer->channels)}; - - return v.col(rankIdx + channel * mRank ); - } - - FluidTensorView samps(size_t offset, size_t nframes, size_t chanoffset) override - { - FluidTensorView v{mBuffer->data,0, static_cast(mBuffer->frames), static_cast(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(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 using AsyncFn = bool (T::*)(World* w); - template using AsyncCleanup = void (T::*)(); - - template F> - static bool call(World* w,void* x){return (static_cast(x)->*F)(w);} - - template - static void call(World*, void* x){delete static_cast(x);} - - template Stage2, AsyncFn Stage3, AsyncFn 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, call, call,call, - completionMsgSize,completionMsgData); - } - - protected: -// World * mWorld; -// InterfaceTable *ft; - long bufNUm; - void* mReplyAddr; - const char* cmdName; - void *cmdData; - char* mCompletionMsgData; - size_t mCompletionMsgSize; -// std::vector mParams; - }; - - template - 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("< - 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 params = NRT_Plug::client_type::newParameterSet(); - for (auto&& p: cmd->parameters()) - { - switch(p.getDescriptor().getType()) - { - case client::Type::kBuffer: { - long bufnum = static_cast(args->geti()); - if (bufnum >= 0) { - SCBufferView *buf = new SCBufferView(bufnum, inWorld); - p.setBuffer(buf); - } - break; - } - case client::Type::kLong: { - p.setLong(static_cast(args->geti())); - break; - } - case client::Type::kFloat: { - p.setFloat(args->getf()); - break; - } - default: - { - p.setLong(static_cast(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 -void registerCommand(InterfaceTable* ft, const char* name) -{ - PlugInCmdFunc cmd = fluid::wrapper::command; - (*ft->fDefinePlugInCmd)(name,cmd,nullptr); - -} - diff --git a/release-packaging/Classes/FluidSTFTPass.sc b/release-packaging/Classes/FluidSTFTPass.sc index d9cd1f2..5171e63 100644 --- a/release-packaging/Classes/FluidSTFTPass.sc +++ b/release-packaging/Classes/FluidSTFTPass.sc @@ -3,3 +3,4 @@ FluidSTFTPass : UGen { ^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize, maxWinSize) } } +// \ No newline at end of file diff --git a/src/FluidBufTransients/FluidBufTransients.cpp b/src/FluidBufTransients/FluidBufTransients.cpp index a1cf3c5..a83e861 100644 --- a/src/FluidBufTransients/FluidBufTransients.cpp +++ b/src/FluidBufTransients/FluidBufTransients.cpp @@ -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 Union’s 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 -#include +//#include "clients/nrt/TransientNRTClient.hpp" +//#include "fdNRTBase.hpp" +//#include "data/FluidTensor.hpp" +//#include "clients/common/FluidParams.hpp" +//#include "SC_PlugIn.h" +//#include +//#include -static InterfaceTable *ft; +#include +#include + +#include -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(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(mModel.trans)->assignToRT(world); - if(mModel.returnResidual) - static_cast(mModel.res)->assignToRT(world); - return true; - } - - bool postComplete(World*) - { - if(mModel.returnTransients) - static_cast(mModel.trans)->cleanUp(); - if(mModel.returnResidual) - static_cast(mModel.res)->cleanUp(); - return true; - - } - std::vector& parameters() - { - return trans.getParams(); - } - private: - client_type trans; - client_type::ProcessModel mModel; - };//class - } //namespace wrapper -}//namespace fluid +static InterfaceTable *ft; + +//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(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(mModel.trans)->assignToRT(world); +// if(mModel.returnResidual) +// static_cast(mModel.res)->assignToRT(world); +// return true; +// } +// +// bool postComplete(World*) +// { +// if(mModel.returnTransients) +// static_cast(mModel.trans)->cleanUp(); +// if(mModel.returnResidual) +// static_cast(mModel.res)->cleanUp(); +// return true; +// +// } +// std::vector& parameters() +// { +// return trans.getParams(); +// } +// private: +// client_type trans; +// client_type::ProcessModel mModel; +// };//class +// } //namespace wrapper +//}//namespace fluid PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; - registerCommand(ft, "BufTransients"); - fluid::wrapper::printCmd(ft,"BufTransients","FDTransients"); + using namespace fluid::client; + makeSCWrapper, decltype(TransientParams), TransientParams>>(ft,"BufTransients"); + +// registerCommand(ft, "BufTransients"); +// fluid::wrapper::printCmd(ft,"BufTransients","FDTransients"); } diff --git a/src/FluidGain/FluidGain.cpp b/src/FluidGain/FluidGain.cpp index aba78d6..64a04a1 100644 --- a/src/FluidGain/FluidGain.cpp +++ b/src/FluidGain/FluidGain.cpp @@ -9,5 +9,5 @@ static InterfaceTable *ft; PluginLoad(FluidGainUgen) { ft = inTable; using namespace fluid::client; - makeSCWrapper>(ft, "FluidGain",GainParams); + makeSCWrapper>(ft, "FluidGain"); } diff --git a/src/FluidTransients/FluidTransients.cpp b/src/FluidTransients/FluidTransients.cpp index a9627d7..32a59b0 100644 --- a/src/FluidTransients/FluidTransients.cpp +++ b/src/FluidTransients/FluidTransients.cpp @@ -1,129 +1,17 @@ // A tool from the FluCoMa project, funded by the European Research Council (ERC) under the European Union’s 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::AudioSignal; - using SignalWrapper = client::TransientsClient::Signal; - - // using SignalPointer = std::unique_ptr; - 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(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(); +#include +#include - //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(); +#include - mCalcFunc = make_calc_function(); - 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; - } - } - } - - - void next(int numsamples) - { - setParams(false); - const float* input = in(0); - const float inscalar = in0(0); - inputSignals[0]->set(const_cast(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 *mClient; - SignalWrapper *inputSignals[1]; - SignalWrapper *outputSignals[2]; - }; -} -} +static InterfaceTable *ft; PluginLoad(FluidSTFTUGen) { ft = inTable; - registerUnit(ft, "FluidTransients"); +// registerUnit(ft, "FluidTransients"); + using namespace fluid::client; + makeSCWrapper>(ft, "FluidTransients",TransientParams); }