diff --git a/include/fdNRTBase.hpp b/include/fdNRTBase.hpp index c312f9f..e2cc2e5 100644 --- a/include/fdNRTBase.hpp +++ b/include/fdNRTBase.hpp @@ -1,168 +1,213 @@ -//Can I reallocate buffers on the server? Yes I can. +#pragma once + + +#include "data/FluidTensor.hpp" +#include "clients/common/FluidParams.hpp" + #include "SC_PlugIn.h" + +#include #include -#include "data/FluidTensor.hpp" -static InterfaceTable *ft; + +//static InterfaceTable *ft; namespace fluid { namespace sc{ - using ViewType = fluid::FluidTensorView; + /** + 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):SndBuf(b){} + NRTBuf(World* world,long bufnum): + NRTBuf(*World_GetNRTBuf(world,bufnum)) + { + + this->samplerate = world->mFullRate.mSampleRate; + + } + }; + + /** + A combination of SndBuf and parameter::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 parameter::BufferAdaptor + { + public: + SCBufferView() = delete; + SCBufferView(SCBufferView&) = delete; + SCBufferView operator=(SCBufferView&) = delete; + + SCBufferView(long bufnum,World* world): + NRTBuf(world,bufnum), + BufferAdaptor({0,{static_cast(frames),static_cast(channels)}},NRTBuf::data), + mBufnum(bufnum), mWorld(world) + {} - /** - A descendent of SndBuf that will populate itself - from the NRT mirror buffers given a world and a bufnum - **/ - struct NRTBuf: public SndBuf + ~SCBufferView() = default; + + void assignToRT(World* rtWorld) { - NRTBuf(SndBuf& b):SndBuf(b){} - - NRTBuf(World* world,size_t bufnum): - NRTBuf(*World_GetNRTBuf(world,bufnum)) - {} - }; + SndBuf* rtBuf = World_GetBuf(rtWorld,mBufnum); + *rtBuf = static_cast(*this); + rtWorld->mSndBufUpdates[mBufnum].writes++; + } + //No locks in (vanilla) SC, so no-ops for these + void acquire() override {} + void release() override {} - /** - A combination of SndBuf and 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) - - **/ - class SCBufferView: public NRTBuf,ViewType + //Validity is based on whether this buffer is within the range the server knows about + bool valid() const override { + return (mBufnum >=0 && mBufnum < mWorld->mNumSndBufs); + } + + void resize(size_t frames, size_t channels, size_t rank) override { + + SndBuf* thisThing = static_cast(this); + + float* oldData = thisThing->data; + + mWorld->ft->fBufAlloc(this, channels * rank, frames, this->samplerate); + + FluidTensorView v= FluidTensorView(NRTBuf::data,0,static_cast(frames),static_cast(channels * rank)); + + static_cast&>(*this) = std::move(v); + + if(oldData) + boost::alignment::aligned_free(oldData); + + + } + protected: + bool equal(BufferAdaptor* rhs) const override { - public: - SCBufferView() = delete; - SCBufferView(SCBufferView&) = delete; - SCBufferView operator=(SCBufferView&) = delete; - - SCBufferView(size_t bufnum,World* world): - NRTBuf(world,bufnum), - ViewType({0,{static_cast(frames), - static_cast(channels)}},NRTBuf::data), - mBufnum(bufnum), mWorld(world) - {} - - void assignToRT() - { - SndBuf* rtBuf = World_GetBuf(mWorld,mBufnum); - *rtBuf = static_cast(*this); - mWorld->mSndBufUpdates[mBufnum].writes++; - } - - private: - size_t mBufnum; - World * mWorld; - }; + SCBufferView* x = dynamic_cast(rhs); + if(x) + { + return mBufnum == x->mBufnum; + } + return false; + } - class NRTCommandBase{ - - - template - using AsyncFn = bool (T::*)(); - - template - using AsyncCleanup = void (T::*) (); - - template F> - static bool call(World*,void* x) - { - return (static_cast(x)->*F)(); - } - - template F> - static void call(World*, void* x) + long mBufnum; + World* mWorld; + }; + + + class NRTCommandBase{ + using param_type = fluid::parameter::Instance; + public: + NRTCommandBase() = delete; + NRTCommandBase(NRTCommandBase&) = delete; + NRTCommandBase& operator=(NRTCommandBase&) = delete; + + NRTCommandBase(std::vector params, + void* inUserData): +// mWorld(inWorld),mReplyAddr(replyAddr), mCompletionMsgData(completionMsgData), mCompletionMsgSize(completionMsgSize), + mParams(params) + {} + + ~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; + }; + + //This wraps a class instance in a function call to pass to SC + template + void command(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr) + { + //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: params) + { + switch(p.getDescriptor().getType()) + { + case parameter::Type::Buffer: { - (static_cast(x)->*F)(); + long bufNum = static_cast(args->geti()); + if(bufNum >= 0){ + SCBufferView* buf = new SCBufferView(bufNum,inWorld); + p.setBuffer(buf); + } + break; } - - template Stage2, AsyncFn Stage3, AsyncFn Stage4, AsyncCleanup Cleanup> - void cmd(std::string name) + case parameter::Type::Long: { - (*ft->fDoAsynchronousCommand)( mWorld, mReplyAddr,name.c_str(),this, - call, call, call,call, - mCompletionMsgSize,mCompletionMsgData); + p.setLong(static_cast(args->geti())); + break; } - - public: - NRTCommandBase() = delete; - NRTCommandBase(NRTCommandBase&) = delete; - NRTCommandBase& operator=(NRTCommandBase&) = delete; - - NRTCommandBase(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr): - mWorld(inWorld),mReplyAddr(replyAddr){} - - virtual ~NRTCommandBase() = default; - - /**Override these**/ - virtual bool process() { return true; } //NRT - virtual bool post_processing() { return true; } //RT - virtual bool post_complete() { return true; } //NRT - void cleanup() {} - - /**Probably not this though**/ - void runCommand(std::string name) + case parameter::Type::Float: { - cmd (name); + p.setFloat(args->getf()); + break; } - private: - protected: - World * mWorld; - void* mReplyAddr; - const char* cmdName; - void *cmdData; - size_t mCompletionMsgSize; - char* mCompletionMsgData; - - void handleCompletionMessage(struct sc_msg_iter *args) + default: { - mCompletionMsgSize = args->getbsize(); - mCompletionMsgData = 0; - if(mCompletionMsgSize) - { - //allocate string - mCompletionMsgData = (char*)RTAlloc(mWorld,mCompletionMsgSize); - args->getb(mCompletionMsgData,mCompletionMsgSize); - } + p.setLong(static_cast(args->geti())); } - }; -} //namespace supercollider + } + } + + //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 + NRT_Plug* cmd = new NRT_Plug(params, inUserData); + cmd->runCommand(inWorld, replyAddr, completionMsgData, completionMsgSize); + } +} //namespace sc }//namespace fluid -template -void command(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr) -{ - NRT_Plug cmd(inWorld, inUserData, args, replyAddr); - cmd.runCommand("AysncCommand"); -} - - -template +template void registerCommand(InterfaceTable* ft, const char* name) { - //(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr); - PlugInCmdFunc cmd = command; - (*ft->fDefinePlugInCmd)(name,cmd,nullptr); + PlugInCmdFunc cmd = fluid::sc::command; + (*ft->fDefinePlugInCmd)(name,cmd,nullptr); } - -//PluginLoad(BufferFunTime) { -// -// using fluid::sc::NRTCommandBase; -// -// registerCommand(inTable, "ASyncBufMatch"); -// -//// ft = inTable; -//// //BufGen version: all in the NRT thread -////// DefineBufGen("BufMatch", BufferMatch); -//// //ASync version: swaps between NRT and RT threads -//// DefinePlugInCmd("AsyncBufMatch", ASyncBufferFun_Main, nullptr); -//// -//} -