fdNMF.cpp / .sc + fdNMF/tests.scd: Refactor for new client / parmater archiecture (see fluid_decomposition commit ec1fe1332c522a64b04e5210d1e48266f6b6512b)

nix
Owen Green 7 years ago
parent f4a9560e9c
commit 524d95aec0

@ -1,174 +1,123 @@
// FD_BufNMF, an NRT buffer NMF Processor // 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) // 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.h" #include "fdNRTBase.hpp"
#include "algorithms/STFT.hpp" #include "algorithms/STFT.hpp"
#include "data/FluidTensor.hpp" #include "data/FluidTensor.hpp"
#include "clients/nrt/NMFClient.hpp" #include "clients/nrt/NMFClient.hpp"
#include "clients/common/FluidParams.hpp"
#include "util/TupleUtils.hpp"
#include "SC_PlugIn.h"
#include <unordered_set>
#include <vector>
static InterfaceTable *ft;
//Using statements for fluidtensor //Using statements for fluidtensor
using fluid::FluidTensor; using fluid::FluidTensor;
using fluid::FluidTensorView; using fluid::FluidTensorView;
using fluid::nmf::NMFClient; using fluid::nmf::NMFClient;
static InterfaceTable *ft; namespace fluid {
namespace sc{
void BufNMF(World *world, struct SndBuf *srcBuf, struct sc_msg_iter *msg)
{ class BufNMF: public NRTCommandBase
size_t srcFrameCount = srcBuf->frames; {
size_t srcChanCount = srcBuf->channels; /*
- srcbuf num
long dstBufNum = msg->geti();  src start frame
long dictBufNum = msg->geti(); - src numframes
long actBufNum = msg->geti(); src start chan
size_t rank = msg->geti();  src num chans
size_t iterations = msg->geti();  resynths dst
size_t fftSize = msg->geti();  dicts dst
size_t windowSize = msg->geti();  acts dst
size_t hopSize = msg->geti(); - 'overwrite' flag [-1:1]
if (dstBufNum == -1 && dictBufNum == -1 && actBufNum == -1) { - rank
Print("fdNMF is not happy because there are no output buffer specified.\n"); - iterations
return;  window size
}  hop size
 fft size
SndBuf *dstBuf, *dictBuf, *actBuf; - boundary flag
size_t dstFrameCount, dictFrameCount, actFrameCount; - rand seed
size_t dstChanCount, dictChanCount, actChanCount; */
// check sanity of audio destination buffer public:
if (dstBufNum != -1){ using client_type = NMFClient;
if (dstBufNum >= world->mNumSndBufs){ using NRTCommandBase::NRTCommandBase;
Print("fdNMF is not happy because the destination buffer does not exist.\n");
return;
} ~BufNMF()
{
dstBuf = world->mSndBufs + dstBufNum; // if(src) delete src;
// if(resynth) delete resynth;
if (srcBuf->data == dstBuf->data){ // if(dict) delete dict;
Print("fdNMF is not happy because the destination buffer is the same as the source buffer.\n"); // if(act) delete act;
return; }
}
void runCommand(World* world, void* replyAddr, char* completionMsgData, size_t completionMsgSize)
dstFrameCount = dstBuf->frames; {
dstChanCount = dstBuf->channels; cmd<BufNMF, &BufNMF::process, &BufNMF::postProcess, &BufNMF::postComplete>(world, "AsyncNMF", replyAddr, completionMsgData, completionMsgSize);
}
if (dstChanCount < (rank * srcChanCount)) {
Print("fdNMF is not happy because the destination buffer has a lower channel count than the number of ranks.\n"); bool process(World* world)
return; {
} //sanity check the parameters
bool parametersOk;
if (dstFrameCount < srcFrameCount) { NMFClient::ProcessModel processModel;
Print("fdNMF is not happy because the destination buffer shorter than the source buffer.\n"); std::string whatHappened;//this will give us a message to pass back if param check fails
return; std::tie(parametersOk,whatHappened,processModel) = NMFClient::sanityCheck(mParams);
} if(!parametersOk)
} {
Print("fdNMF: %s \n", whatHappened.c_str());
// check sanity of dictionary destination buffer return false;
if (dictBufNum != -1){ }
if (dictBufNum >= world->mNumSndBufs){ //Now, we can proceed
Print("fdNMF is not happy because the destination buffer does not exist.\n"); NMFClient nmf(processModel);
return; nmf.process();
} mModel = processModel;
src = static_cast<SCBufferView*>(parameter::lookupParam("Source Buffer", mParams).getBuffer());
resynth = static_cast<SCBufferView*>(parameter::lookupParam("Resynthesis Buffer", mParams).getBuffer());
dict = static_cast<SCBufferView*>(parameter::lookupParam("Dictionary Buffer", mParams).getBuffer());
act = static_cast<SCBufferView*>(parameter::lookupParam("Activation Buffer", mParams).getBuffer());
return true;
}
bool postProcess(World* world)
{
if(mModel.resynthesise)
resynth->assignToRT(world);
if(mModel.returnDictionaries)
dict->assignToRT(world);
if(mModel.returnActivations)
act->assignToRT(world);
return true;
}
bool postComplete(World* w) { return true; }
private:
NMFClient::ProcessModel mModel;
SCBufferView* src;
SCBufferView* resynth;
SCBufferView* dict;
SCBufferView* act;
};//class
} //namespace sc
}//namespace fluid
dictBuf = world->mSndBufs + dictBufNum;
if (srcBuf->data == dictBuf->data){
Print("fdNMF is not happy because the destination buffer is the same as the source buffer.\n");
return;
}
dictFrameCount = dictBuf->frames;
dictChanCount = dictBuf->channels;
if (dictChanCount < (rank * srcChanCount)) {
Print("fdNMF is not happy because the destination buffer has a lower channel count than the number of ranks.\n");
return;
}
if (dictFrameCount < (fftSize / 2 + 1)) {
Print("fdNMF is not happy because the destination buffer shorter than the source buffer.\n");
return;
}
}
// check sanity of activations destination buffer
if (actBufNum != -1){
if (actBufNum >= world->mNumSndBufs){
Print("fdNMF is not happy because the destination buffer does not exist.\n");
return;
}
actBuf = world->mSndBufs + actBufNum;
if (srcBuf->data == actBuf->data){
Print("fdNMF is not happy because the destination buffer is the same as the source buffer.\n");
return;
}
actFrameCount = actBuf->frames;
actChanCount = actBuf->channels;
if (actChanCount < (rank * srcChanCount)) {
Print("fdNMF is not happy because the destination buffer has a lower channel count than the number of ranks.\n");
return;
}
if (actFrameCount < (srcFrameCount / hopSize + 1)) {
Print("fdNMF is not happy because the destination buffer shorter than the source buffer.\n");
return;
}
}
// make fuildtensorviewers of the SC interleaved input buffer
FluidTensorView<float,2> in_view ({0,{srcFrameCount, srcChanCount}},srcBuf->data);
//setup the nmf
NMFClient nmf(rank ,iterations, fftSize, windowSize, hopSize);
//for each channels
for (int j=0;j<srcChanCount;j++){
//copies and casts to double the source samples
FluidTensor<double,1> audio_in(in_view.col(j));
//Process, with resynthesis if needs be
if (dstBufNum != -1){
nmf.process(audio_in,true);
} else {
nmf.process(audio_in,false);
}
//Copy audio outputs if they are requested
if (dstBufNum != -1){
FluidTensorView<float,2> out_view ({0,{dstFrameCount, dstChanCount}},dstBuf->data);
for (int i = 0; i < rank; ++i)
{
out_view.col(i + (j*rank)) = nmf.source(i);
}
}
//Copy dictionaries if they are requested
if (dictBufNum != -1){
FluidTensorView<float,2> out_view ({0,{dictFrameCount, dictChanCount}},dictBuf->data);
for (int i = 0; i < rank; ++i)
{
out_view.col(i + (j*rank)) = nmf.dictionary(i);
}
}
//Copy activations if they are requested
if (actBufNum != -1){
FluidTensorView<float,2> out_view ({0,{actFrameCount, actChanCount}},actBuf->data);
for (int i = 0; i < rank; ++i)
{
out_view.col(i + (j*rank)) = nmf.activation(i);
}
}
}
}
PluginLoad(OfflineFluidDecompositionUGens) { PluginLoad(OfflineFluidDecompositionUGens) {
ft = inTable; ft = inTable;
DefineBufGen("BufNMF", BufNMF); registerCommand<fluid::sc::BufNMF,fluid::nmf::NMFClient>(ft, "BufNMF");
} }

@ -1,30 +1,61 @@
s.reboot s.reboot
//////////////////////////// ////////////////////////////
// test for efficiency // test for efficiency
( (
b = Buffer.read(s,"/Users/pa/Documents/documents@hudd/research/projects/fluid corpus navigation/research/denoise_stn/sources/01-mix.wav"); b = Buffer.read(s,"/Users/owen/Desktop/denoise_stn/sources/01-mix.wav", numFrames:88200);
// s.sync;
~fft_size = 2048; ~fft_size = 2048;
~frame_size = 1024; ~frame_size = 1024;
~hop_size = 256; ~hop_size = 256;
~which_rank = 0; ~which_rank = 0;
) )
// (
// c = Buffer.alloc(s,b.numFrames,5);
// x = Buffer.alloc(s,(~fft_size / 2 +1),5);
// y = Buffer.alloc(s,(b.numFrames / ~hop_size + 1) ,5);
// )
( (
c = Buffer.alloc(s,b.numFrames,5); c = Buffer.new(s, numFrames:0, numChannels:1);
x = Buffer.alloc(s,(~fft_size / 2 +1),5); x = Buffer.new(s,numFrames:0,numChannels:1);
y = Buffer.alloc(s,(b.numFrames / ~hop_size + 1) ,5); y = Buffer.new(s,numFrames:0,numChannels:1);
) )
(
// without sources // without sources
d = Main.elapsedTime; b.fdNMF(nil, x, y, 5, 100, ~fft_size,~frame_size,~hop_size,{e = Main.elapsedTime; (e-d).postln}) r = Routine{
t = Main.elapsedTime;
FDNMF.nmf(s,b,0,-1,0,-1,c,x,0,y,0,5,100,~frame_size,~hop_size,~fft_size);
s.sync;
u = Main.elapsedTime;
(u-t).postln;
}.play
);
c.query
x.query
// with sources // with sources
d = Main.elapsedTime; b.fdNMF(c, x, y, 5, 100, ~fft_size,~frame_size,~hop_size,{e = Main.elapsedTime; (e-d).postln}) (
r = Routine{
t = Main.elapsedTime;
FDNMF.nmf(s,b, 0,-1,0,-1,c,x,0,y,0,5,100,~frame_size,~hop_size,~fft_size);
s.sync;
u = Main.elapsedTime;
(u-t).postln;
}.play
)
//look at the dictionaries and activations //look at the dictionaries and activations
x.plot; y.plot; x.plot; y.plot;
d.plot;
c.plot;
//null test of the sum of sources //null test of the sum of sources
{(PlayBuf.ar(5,c.bufnum,doneAction:2).sum)+(-1*PlayBuf.ar(1,b.bufnum,doneAction:2))}.play {(PlayBuf.ar(5,c.bufnum,doneAction:2).sum)+(-1*PlayBuf.ar(1,b.bufnum,doneAction:2))}.play
@ -56,10 +87,10 @@ x.plot; y.plot;
( (
{ {
var chain; var chain;
chain = FFT(LocalBuf(~fft_size), WhiteNoise.ar(BufRd.kr(5,y.bufnum,Phasor.ar(1,1/~hop_size,0,(b.numFrames / ~hop_size + 1)),0,1)[~which_rank]*0.15),0.25,1); chain = FFT(LocalBuf(~fft_size), WhiteNoise.ar(BufRd.kr(5,d.bufnum,Phasor.ar(1,1/~hop_size,0,(b.numFrames / ~hop_size + 1)),0,1)[~which_rank]*0.15),0.25,1);
chain = chain.pvcollect(~fft_size, {|mag, phase, index| chain = chain.pvcollect(~fft_size, {|mag, phase, index|
[mag * BufRd.kr(5,x.bufnum,DC.kr(index),0,1)[~which_rank]]; [mag * BufRd.kr(5,c.bufnum,DC.kr(index),0,1)[~which_rank]];
}); });
[0,IFFT(chain)]; [0,IFFT(chain)];

@ -1,18 +1,43 @@
// adds an instance method to the Buffer class // adds an instance method to the Buffer class
+ Buffer { FDNMF {
fdNMF { arg dstBuf, dictBuf, actBuf, rank = 1, iterations = 100, fftSize = 2048, windowSize = 2048, hopSize = 512, action; /*fdNMF { arg dstBuf, dictBuf, actBuf, rank = 1, iterations = 100, fftSize = 2048, windowSize = 2048, hopSize = 512, action;
var resp; var resp;
if(bufnum.isNil) { Error("Cannot call % on a % that has been freed".format(thisMethod.name, this.class.name)).throw }; if(bufnum.isNil) { Error("Cannot call % on a % that has been freed".format(thisMethod.name, this.class.name)).throw };
// responder idea stolen from getToFloatArray /* // responder idea stolen from getToFloatArray
resp = OSCFunc({ arg msg; resp = OSCFunc({ arg msg;
if(msg[1]== '/b_gen' && msg[2]== bufnum, { if(msg[1]== '/b_gen' && msg[2]== bufnum, {
resp.clear; resp.clear;
action.value(bufnum); action.value(bufnum);
}); });
}, '/done', server.addr); }, '/done', server.addr);*/
server.listSendMsg([\b_gen, bufnum, "BufNMF", if(dstBuf.isNil, -1, {dstBuf.bufnum}), if(dictBuf.isNil, -1, {dictBuf.bufnum}), if(actBuf.isNil, -1, {actBuf.bufnum}), rank, iterations, fftSize, windowSize, hopSize]) // server.listSendMsg([\b_gen, bufnum, "BufNMF", if(dstBuf.isNil, -1, {dstBuf.bufnum}), if(dictBuf.isNil, -1, {dictBuf.bufnum}), if(actBuf.isNil, -1, {actBuf.bufnum}), rank, iterations, fftSize, windowSize, hopSize])
server.sendMsg(\cmd, \BufNMF, bufnum, if(dstBuf.isNil, -1, {dstBuf.bufnum}), if(dictBuf.isNil, -1, {dictBuf.bufnum}), if(actBuf.isNil, -1, {actBuf.bufnum}), rank, iterations, fftSize, windowSize, hopSize);
}*/
*nmf { arg server, srcBuf, startAt = 0, nFrames = -1,startChan = 0,nChans = -1, dstBuf, dictBuf, dictFlag = 0, actBuf, actFlag = 0, rank = 1, iterations = 100, windowSize = 2048, hopSize = 512, fftSize = 2048, action;
var resp;
server = server ? Server.default;
if(srcBuf.bufnum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw};
dstBuf.bufnum.postln;
server.sendMsg(\cmd, \BufNMF,
if(srcBuf.isNil, -1, {srcBuf.bufnum}),
startAt, nFrames, startChan, nChans,
if(dstBuf.isNil, -1, {dstBuf.bufnum}),
if(dictBuf.isNil, -1, {dictBuf.bufnum}),
dictFlag,
if(actBuf.isNil, -1, {actBuf.bufnum}),
actFlag,
rank, iterations, windowSize, hopSize,fftSize);
} }
} }

Loading…
Cancel
Save