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.cppnix
parent
a5121a8f71
commit
c61190993f
@ -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);
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue