fdBufferExperiments: More verbose, but possibly more correct version using AsyncPluginCommand

nix
Owen Green 7 years ago
parent b4bcc2f1c6
commit 72e9e02044

@ -3,10 +3,17 @@
static InterfaceTable *ft;
//Can we do buffer resizing in a BufGen. I think so.
//Goal here is to mimic the NMF case, allowing
//the dst buffer to be resized accordingly (and not need to
// precalculate the number of frames in advance lang-side
/**
/buf_gen approach: Seems to work, but having to do the 'swap' bewteen NRT mirror buffer and RT buffer
in the same thread seems smelly, given how the allocation sequeneces in SC_SequenceCommand seem to work.
**/
void BufferMatch(World *world, struct SndBuf *srcBuf, struct sc_msg_iter *msg)
{
size_t srcFrameCount = srcBuf->frames;
@ -34,11 +41,128 @@ void BufferMatch(World *world, struct SndBuf *srcBuf, struct sc_msg_iter *msg)
world->mSndBufUpdates[dstBufNum].writes ++ ;
}
/**
ASync command version. Is this an abuse of Async command? Doesn't *seem* to be, but there is almost no
documentation for its proper use :-|
**/
//Struct that holds all our state between stages
struct BufferFunTimeCmdData
{
long dstbuf;
long srcbuf;
size_t rank;
SndBuf* newdst;
};
//typedef void (*BufGenFunc)(struct World *world, struct SndBuf *buf, struct sc_msg_iter *msg);
//'Stage2()' happens in the NRT thread. Here we do our heavy stuff
bool ASyncBufferFun_NRTStage(World* world, void* inUserData)
{
BufferFunTimeCmdData* data = (BufferFunTimeCmdData*) inUserData;
SndBuf* src = World_GetNRTBuf(world, data->srcbuf);
SndBuf* dst = World_GetNRTBuf(world, data->dstbuf);
SCErr err = ft->fBufAlloc(dst, src->channels * data->rank, src->frames,src->samplerate);
data->newdst = dst;
return true;
}
//'Statge3()' happens back in the RT thread, here we swap our new buffers
//SC will send the completion message after this
bool ASyncBufferFun_RTStage(World* world, void* inUserData)
{
BufferFunTimeCmdData* data = (BufferFunTimeCmdData*) inUserData;
//Norhing will happen, unless we (a) assign the allocated data back to the main buffer pool (b?) Tell the server the buffer has changed
//Get the RT buffer
SndBuf* dstBuf = World_GetBuf(world, data->dstbuf);
//Assign value to our NRT buffer pointer's value
*dstBuf = *data->newdst;
//Ping the server
world->mSndBufUpdates[data->dstbuf].writes ++ ;
return true;
}
//'Stage 4()' is back on the NRT, we don't have anything to do here. SC will send 'done' after this
bool ASyncBufferFun_FinalBit(World* world, void* inUserData)
{
return true;
}
//Here we free any resources, including the struct we made at the start
void ASyncBufferFun_CleanUp(World* world, void* inUserData)
{
BufferFunTimeCmdData* data = (BufferFunTimeCmdData*)inUserData;
RTFree(world,data);
//scsynth will take care of the completion message
}
//This is our entry point. We need to make a struct and populate it with good things
void ASyncBufferFun_Main(World *inWorld, void* inUserData, struct sc_msg_iter *msg, void *replyAddr)
{
BufferFunTimeCmdData* data = (BufferFunTimeCmdData*)RTAlloc(inWorld, sizeof(BufferFunTimeCmdData));
// size_t srcFrameCount = srcBuf->frames;
// size_t srcChanCount = srcBuf->channels;
data->srcbuf = msg->geti();
data->dstbuf = msg->geti();
data->rank = msg->geti();
bool ok = true;
if(data->srcbuf < 0 )
{
Print("No source buffer");
ok = false;
}
if(data->dstbuf < 0 )
{
Print("No dst buffer");
ok = false;
}
if(!ok)
{
RTFree(inWorld,data);
return;
}
// how to pass a string argument: [WILL BE USEFUL FOR WINDOW FUNCTIONS?]
// const char *name = msg->gets(); // get the string argument
// if (name) {
// data->name = (char*)RTAlloc(inWorld, strlen(name)+1); // allocate space, free it in cmdCleanup.
// strcpy(data->name, name); // copy the string
// }
//Deal with completion message
size_t completionMsgSize = msg->getbsize();
char* completionMsgString = 0;
if(completionMsgSize)
{
//allocate string
completionMsgString = (char*)RTAlloc(inWorld,sizeof(completionMsgSize));
msg->getb(completionMsgString,completionMsgSize);
}
//Now, set the wheels in motion
DoAsynchronousCommand(inWorld,replyAddr,"AsyncBufMatch",
data,
(AsyncStageFn)ASyncBufferFun_NRTStage,
(AsyncStageFn)ASyncBufferFun_RTStage,
(AsyncStageFn)ASyncBufferFun_FinalBit,
ASyncBufferFun_CleanUp,
completionMsgSize, completionMsgString);
}
PluginLoad(BufferFunTime) {
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);
}

@ -9,3 +9,17 @@ f = FDBufferExperiments.allocMatch(s,a,rank:5);
//Make sure everything is kosher:
a.query
f.query
//Try full async version
s.reboot
//Quickie test of buffer allocation working
//Read a sound file
a = Buffer.read(s,"/Users/owen/Desktop/denoise_stn/sources/01-mix.wav");
//Pass buffer to this, along with a rank. It will allocate a new buffer,
//size it appropriately (in our server code) and return the new object
f = FDBufferExperiments.allocMatchAsync(s,a,rank:5);
//Make sure everything is kosher:
a.query
f.query

@ -3,7 +3,7 @@ FDBufferExperiments {
*allocMatch{|server, srcbuf, rank=1|
var dstbuf,srcbufnum;
"Rank" + rank.postln;
srcbufnum = srcbuf.bufnum;
server = server ? Server.default;
@ -14,4 +14,17 @@ FDBufferExperiments {
);
^dstbuf;
}
*allocMatchAsync{|server, srcbuf, rank=1|
var dstbuf,srcbufnum;
srcbufnum = srcbuf.bufnum;
server = server ? Server.default;
dstbuf = Buffer.new(server:server,numFrames:0,numChannels:1);
server.sendMsg(\cmd, \AsyncBufMatch, srcbufnum, dstbuf.bufnum, rank);
^dstbuf;
}
}

Loading…
Cancel
Save