From eb0e1c02afccb8704f672fac8580c56709a31375 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Mon, 3 Dec 2018 11:50:21 +0000 Subject: [PATCH 01/31] CMakeLists.txt: Change to C++14 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79bd49f..9186370 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.3) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -mavx -msse -msse2 -msse3 -msse4") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libc++") From b091e482443e865d4d481d3e99f1b4190f3572c3 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Mon, 3 Dec 2018 14:54:24 +0000 Subject: [PATCH 02/31] Add generic SC wrapper include/FluidSCWrapper.hpp CMakeLists.txt --- CMakeLists.txt | 3 + include/FluidSCWrapper.hpp | 115 +++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 include/FluidSCWrapper.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9186370..bcd92ac 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,9 @@ if(APPLE OR WIN32) set(CMAKE_SHARED_MODULE_SUFFIX ".scx") endif() +add_library(FLUID_SC_WRAPPER INTERFACE) +target_sources(FLUID_SC_WRAPPER INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include/FluidSCWrapper.hpp") + SUBDIRLIST(PROJECT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src) foreach (project_dir ${PROJECT_DIRS}) if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/${project_dir}/CMakeLists.txt") diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp new file mode 100644 index 0000000..b74602b --- /dev/null +++ b/include/FluidSCWrapper.hpp @@ -0,0 +1,115 @@ +#pragma once + +#include +#include + +#include + +#include +#include +#include +namespace fluid { +namespace client { + +namespace impl { +template struct SetterDispatchImpl; +template struct GetterDispatchImpl; +} // namespace impl + +template +class FluidSCWrapper : public SCUnit { +public: + FluidSCWrapper() { + mInputConnections.reserve(mClient.audioChannelsIn()); + mOutputConnections.reserve(mClient.audioChannelsOut()); + mAudioInputs.reserve(mClient.audioChannelsIn()); + mAudioOutputs.reserve(mClient.audioChannelsOut()); + + 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) { + mOutputConnections.emplace_back(BUFLENGTH != 1); + mAudioOutputs.emplace_back(nullptr, 0, 0); + } + + mCalcFunc = [](Unit *u, int n) { + FluidSCWrapper *f = static_cast(u); + f->next(n); + }; + } + + void next(int n) { + + setParams(mInBuf + 1); //forward on inputs N + 1 as params + + const Unit *unit = this; + for (int i = 0; i < mClient.audioChannelsIn(); ++i) { + if (mInputConnections[i]) + mAudioInputs[i].reset(IN(i), 0, fullBufferSize()); + } + + for (int i = 0; i < mClient.audioChannelsOut(); ++i) { + if (mOutputConnections[i]) + mAudioOutputs[i].reset(out(i), 0, fullBufferSize()); + } + + mClient.process(mAudioInputs, mAudioOutputs); + } + + void setParams(float **inputs) { + setParams(inputs, std::index_sequence_for()); + } + +private: + template + void setParams(float **inputs, std::index_sequence) { + (void)std::initializer_list{( + impl::SetterDispatchImpl::f(mClient, 1, inputs[Is]), 0)...}; + } + + std::vector mInputConnections; + std::vector mOutputConnections; + std::vector> mAudioInputs; + std::vector> mAudioOutputs; + + Client mClient; +}; + +namespace impl { +template +struct SetterDispatchImpl { + static void f(Client &x, long ac, float *av) { x.template setter()(*av); } +}; + +template +struct SetterDispatchImpl { + static void f(Client &x, long ac, float *av) { x.template setter()(*av); } +}; + +template +struct SetterDispatchImpl { + static void f(Client *x, long ac, float *av) { x->template setter()(*av); } +}; + +template +struct SetterDispatchImpl { + static void f(Client *x, long ac, float *av) { x->template setter()(*av); } +}; + +} // namespace impl + +template +void makeSCWrapper(InterfaceTable *ft, const char *className, + const std::tuple ¶ms) { + registerUnit>(ft, + className); +} + +} // namespace client +} // namespace fluid + From b06fdf03621e161234695bbacd6be83e66d416f8 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Mon, 3 Dec 2018 14:55:51 +0000 Subject: [PATCH 03/31] Non-bufferig FluidGain (ar / kr aware) release-packaging/Classes/FluidGain.sc src/FluidGain/CMakeLists.txt src/FluidGain/FluidGain.cpp --- release-packaging/Classes/FluidGain.sc | 4 +- src/FluidGain/CMakeLists.txt | 2 +- src/FluidGain/FluidGain.cpp | 67 +++----------------------- 3 files changed, 10 insertions(+), 63 deletions(-) diff --git a/release-packaging/Classes/FluidGain.sc b/release-packaging/Classes/FluidGain.sc index 2d654f6..da1178d 100644 --- a/release-packaging/Classes/FluidGain.sc +++ b/release-packaging/Classes/FluidGain.sc @@ -1,6 +1,6 @@ FluidGain : UGen { - *ar { arg in = 0, frameSize=64, gain=1.0; - ^this.multiNew('audio', in.asAudioRateInput(this),frameSize, gain) + *ar { arg in = 0, gain=1.0; + ^this.multiNew('audio', in.asAudioRateInput(this), gain) } } diff --git a/src/FluidGain/CMakeLists.txt b/src/FluidGain/CMakeLists.txt index 3693881..4f27137 100755 --- a/src/FluidGain/CMakeLists.txt +++ b/src/FluidGain/CMakeLists.txt @@ -14,7 +14,7 @@ target_include_directories( ) target_link_libraries( - ${PLUGIN} PRIVATE FLUID_DECOMPOSITION + ${PLUGIN} PRIVATE FLUID_DECOMPOSITION FLUID_SC_WRAPPER ) include(${CMAKE_CURRENT_LIST_DIR}/../../scripts/target_post.cmake) diff --git a/src/FluidGain/FluidGain.cpp b/src/FluidGain/FluidGain.cpp index 7454cf2..aba78d6 100644 --- a/src/FluidGain/FluidGain.cpp +++ b/src/FluidGain/FluidGain.cpp @@ -1,66 +1,13 @@ // 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/GainClient.hpp" -#include "clients/common/FluidParams.hpp" - +#include +#include +#include static InterfaceTable *ft; -namespace fluid { -class FDGain: public SCUnit -{ - using AudioClient = fluid::client::GainAudioClient; - using ClientPointer = std::unique_ptr; - using SignalWrapper = AudioClient::Signal; - using AudioSignal= AudioClient::AudioSignal; - using ControlSignal = AudioClient::ScalarSignal; - using SignalPointer = std::unique_ptr; - template - using SignalArray = std::array; -public: - FDGain() - { - mClient = ClientPointer(new AudioClient(65536)); - - std::vector& params = mClient->getParams(); - - client::lookupParam("winsize", params).setLong(in0(1)); - client::lookupParam("hopsize", params).setLong(in0(1)); - - mClient->setHostBufferSize(bufferSize()); - mClient->reset(); - - inputSignals[0] = SignalPointer(new AudioSignal()); - outputSignals[0] = SignalPointer(new AudioSignal()); - - if(isAudioRateIn(2)) - inputSignals[1] = SignalPointer(new AudioSignal()); - else - inputSignals[1] = SignalPointer(new ControlSignal()); - - mCalcFunc = make_calc_function(); - Unit* unit = this; - ClearUnitOutputs(unit,1); - } - - ~FDGain() {} -private: - void next(int numsamples) - { - //TODO: Remove const_cast code smell by making input_signal type for const - inputSignals[0]->set(const_cast(in(0)), in0(0)); - inputSignals[1]->set(const_cast(in(2)), in0(2)); - outputSignals[0]->set(out(0), out0(0)); - mClient->doProcess(inputSignals.begin(),inputSignals.end(),outputSignals.begin(),outputSignals.end(),numsamples,2,1); - } - - ClientPointer mClient; - SignalArray<2> inputSignals; - SignalArray<1> outputSignals; -}; -} -PluginLoad(BoringMixer2UGens) { + +PluginLoad(FluidGainUgen) { ft = inTable; - registerUnit(ft, "FluidGain"); + using namespace fluid::client; + makeSCWrapper>(ft, "FluidGain",GainParams); } From 03e9ff1dc14a3257439d45281d1f937334c23281 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Mon, 3 Dec 2018 15:02:48 +0000 Subject: [PATCH 04/31] include/FluidSCWrapper.hpp: Don't update params with audio rate inputs --- include/FluidSCWrapper.hpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index b74602b..33aeaca 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -45,7 +45,7 @@ public: void next(int n) { - setParams(mInBuf + 1); //forward on inputs N + 1 as params + setParams(mInBuf + 1); // forward on inputs N + 1 as params const Unit *unit = this; for (int i = 0; i < mClient.audioChannelsIn(); ++i) { @@ -68,8 +68,10 @@ public: private: template void setParams(float **inputs, std::index_sequence) { - (void)std::initializer_list{( - impl::SetterDispatchImpl::f(mClient, 1, inputs[Is]), 0)...}; + (void)std::initializer_list{ + (impl::SetterDispatchImpl::f(mClient, 1, inputs[Is], + mInputConnections[Is+1]), + 0)...}; } std::vector mInputConnections; @@ -83,22 +85,34 @@ private: namespace impl { template struct SetterDispatchImpl { - static void f(Client &x, long ac, float *av) { x.template setter()(*av); } + static void f(Client &x, long ac, float *av, bool isAudio) { + if (!isAudio) + x.template setter()(*av); + } }; template struct SetterDispatchImpl { - static void f(Client &x, long ac, float *av) { x.template setter()(*av); } + static void f(Client &x, long ac, float *av, bool isAudio) { + if (!isAudio) + x.template setter()(*av); + } }; template struct SetterDispatchImpl { - static void f(Client *x, long ac, float *av) { x->template setter()(*av); } + static void f(Client *x, long ac, float *av, bool isAudio) { + if (!isAudio) + x->template setter()(*av); + } }; template struct SetterDispatchImpl { - static void f(Client *x, long ac, float *av) { x->template setter()(*av); } + static void f(Client *x, long ac, float *av, bool isAudio) { + if (!isAudio) + x->template setter()(*av); + } }; } // namespace impl From 86e65376d3e4154281d36f9ec49229676ee791c7 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Fri, 7 Dec 2018 18:57:44 +0000 Subject: [PATCH 05/31] src/FluidSTFTPass/FluidSTFTPass.cpp: Update to new regime -> remove most of the code! release-packaging/Classes/FluidSTFTPass.sc: Add maxWinSize parameter --- release-packaging/Classes/FluidSTFTPass.sc | 4 +- src/FluidSTFTPass/FluidSTFTPass.cpp | 83 ++-------------------- 2 files changed, 6 insertions(+), 81 deletions(-) diff --git a/release-packaging/Classes/FluidSTFTPass.sc b/release-packaging/Classes/FluidSTFTPass.sc index 6b86f5e..d9cd1f2 100644 --- a/release-packaging/Classes/FluidSTFTPass.sc +++ b/release-packaging/Classes/FluidSTFTPass.sc @@ -1,5 +1,5 @@ FluidSTFTPass : UGen { - *ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1; - ^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize) + *ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1, maxWinSize= 16384; + ^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize, maxWinSize) } } diff --git a/src/FluidSTFTPass/FluidSTFTPass.cpp b/src/FluidSTFTPass/FluidSTFTPass.cpp index 3ef3cef..b39840e 100644 --- a/src/FluidSTFTPass/FluidSTFTPass.cpp +++ b/src/FluidSTFTPass/FluidSTFTPass.cpp @@ -1,88 +1,13 @@ // 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/BaseSTFTClient.hpp" +#include +#include static InterfaceTable *ft; -namespace fluid { - namespace stft{ - - -class FDSTFTPass: public SCUnit -{ - using AudioSignalWrapper = client::BaseSTFTClient::AudioSignal; - using SignalWrapper = client::BaseSTFTClient::Signal; - -// using SignalPointer = std::unique_ptr; -public: - FDSTFTPass() - { - //Order of args - //Window size, Hop size, FFT Size - - //Get the window size - const float windowSize = in0(1); - const float hopSize = in0(2); - const float fftSize = in0(3); - - //Oh NO! Heap allocation! Make client object - mClient = new client::BaseSTFTClient(65536); - mClient->getParams()[0].setLong(windowSize); - mClient->getParams()[1].setLong(hopSize); - mClient->getParams()[2].setLong(fftSize); - - bool isOK; - std::string feedback; - - std::tie(isOK, feedback) = mClient->sanityCheck(); - if(!isOK) - { - Print("fdSTFTPass Error: %s",feedback.c_str()); - return; - } - - - mClient->setHostBufferSize(bufferSize()); - mClient->reset(); - - //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(); - - mCalcFunc = make_calc_function(); - Unit* unit = this; - ClearUnitOutputs(unit,1); - } - - ~FDSTFTPass() - { - delete inputSignals[0]; - delete outputSignals[0]; - delete mClient; - } - -private: - void next(int numsamples) - { - const float* input = in(0); - const float inscalar = in0(0); - inputSignals[0]->set(const_cast(input), inscalar); - outputSignals[0]->set(out(0), out0(0)); - mClient->doProcess(std::begin(inputSignals),std::end(inputSignals),std::begin(outputSignals), std::end(outputSignals),numsamples,1,1); - } - - client::BaseSTFTClient *mClient; - SignalWrapper *inputSignals[1]; - SignalWrapper *outputSignals[1]; -}; -} -} PluginLoad(FluidSTFTUGen) { ft = inTable; - registerUnit(ft, "FluidSTFTPass"); + using namespace fluid::client; + makeSCWrapper>(ft, "FluidSTFTPass",STFTParams); } From 4e95063af7a3d036f2e702c7f2ca592cb746c673 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 18 Dec 2018 12:04:19 +0000 Subject: [PATCH 06/31] include/FluidSCWrapper.hpp: Tidy types --- include/FluidSCWrapper.hpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 33aeaca..5dc96d9 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -30,17 +31,19 @@ public: mAudioInputs.emplace_back(nullptr, 0, 0); } - const Unit *unit = this; - +// const Unit *unit = this; +// for (int i = 0; i < mClient.audioChannelsOut(); ++i) { - mOutputConnections.emplace_back(BUFLENGTH != 1); + mOutputConnections.emplace_back(true); mAudioOutputs.emplace_back(nullptr, 0, 0); } - mCalcFunc = [](Unit *u, int n) { - FluidSCWrapper *f = static_cast(u); - f->next(n); - }; + set_calc_function(); + +// mCalcFunc = [](Unit *u, int n) { +// FluidSCWrapper *f = static_cast(u); +// f->next(n); +// }; } void next(int n) { @@ -76,8 +79,8 @@ private: std::vector mInputConnections; std::vector mOutputConnections; - std::vector> mAudioInputs; - std::vector> mAudioOutputs; + std::vector> mAudioInputs; + std::vector> mAudioOutputs; Client mClient; }; From a5121a8f71d576b92b673af4d475b3fa3b1a732a Mon Sep 17 00:00:00 2001 From: Alex Harker Date: Tue, 18 Dec 2018 12:29:18 +0000 Subject: [PATCH 07/31] Template only on the client (untested/uncompiled) --- include/FluidSCWrapper.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 5dc96d9..cf5cc42 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -17,7 +17,7 @@ template struct SetterDispatchImpl; template struct GetterDispatchImpl; } // namespace impl -template +template class FluidSCWrapper : public SCUnit { public: FluidSCWrapper() { @@ -65,7 +65,7 @@ public: } void setParams(float **inputs) { - setParams(inputs, std::index_sequence_for()); + setParams(inputs, ParamIndexList()); } private: @@ -120,11 +120,10 @@ struct SetterDispatchImpl { } // namespace impl -template -void makeSCWrapper(InterfaceTable *ft, const char *className, - const std::tuple ¶ms) { - registerUnit>(ft, - className); +template +void makeSCWrapper(InterfaceTable *ft, const char *className, Client::ParamType ¶ms) +{ + registerUnit(ft, className); } } // namespace client From c61190993f4a41113aa65d1d2356ee94d541e8d5 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Wed, 16 Jan 2019 10:59:41 +0000 Subject: [PATCH 08/31] 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.cpp --- include/FluidSCWrapper.hpp | 307 ++++++++++--- include/SCBufferAdaptor.hpp | 244 +++++++++++ include/fdNRTBase.hpp | 402 ------------------ release-packaging/Classes/FluidSTFTPass.sc | 1 + src/FluidBufTransients/FluidBufTransients.cpp | 149 ++++--- src/FluidGain/FluidGain.cpp | 2 +- src/FluidTransients/FluidTransients.cpp | 126 +----- 7 files changed, 570 insertions(+), 661 deletions(-) create mode 100644 include/SCBufferAdaptor.hpp delete mode 100644 include/fdNRTBase.hpp 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); } From 4157c949298962722660694ef186007e3f97a3b9 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Wed, 16 Jan 2019 11:00:17 +0000 Subject: [PATCH 09/31] Start of CMake changes scripts/target_post.cmake src/FluidTransients/CMakeLists.txt CMakeLists.txt --- CMakeLists.txt | 9 ++++++++- scripts/target_post.cmake | 15 ++++++++++++++- src/FluidTransients/CMakeLists.txt | 8 -------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bcd92ac..a919b34 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,14 @@ set(CMAKE_SHARED_MODULE_SUFFIX ".scx") endif() add_library(FLUID_SC_WRAPPER INTERFACE) -target_sources(FLUID_SC_WRAPPER INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include/FluidSCWrapper.hpp") +target_sources(FLUID_SC_WRAPPER +INTERFACE +${CMAKE_CURRENT_SOURCE_DIR}/include/FluidSCWrapper.hpp +${CMAKE_CURRENT_SOURCE_DIR}/include/NRTCommand.hpp +${CMAKE_CURRENT_SOURCE_DIR}/include/SCBufferAdaptor.hpp +${CMAKE_CURRENT_SOURCE_DIR}/include/GenerateSCCode.hpp +${CMAKE_CURRENT_SOURCE_DIR}/include/fdNRTBase.hpp +) SUBDIRLIST(PROJECT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src) foreach (project_dir ${PROJECT_DIRS}) diff --git a/scripts/target_post.cmake b/scripts/target_post.cmake index 3d49245..0acffe9 100644 --- a/scripts/target_post.cmake +++ b/scripts/target_post.cmake @@ -1,5 +1,15 @@ + +target_link_libraries( + ${PLUGIN} + PRIVATE + FLUID_DECOMPOSITION + FLUID_SC_WRAPPER +) + target_include_directories( ${PLUGIN} + PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/../../include SYSTEM PRIVATE ${SC_PATH}/include/plugin_interface ${SC_PATH}/include/common @@ -7,12 +17,15 @@ target_include_directories( ${SC_PATH}/external_libraries/boost #we need boost::align for deallocating buffer memory :-( ) +get_property(HEADERS TARGET FLUID_DECOMPOSITION PROPERTY INTERFACE_SOURCES) +source_group(TREE ${FLUID_PATH}/include FILES ${HEADERS}) + + if (SUPERNOVA) target_include_directories( ${PLUGIN} SYSTEM PRIVATE ${SC_PATH}/external_libraries/nova-tt - ${SC_PATH}/external_libraries/boost_lockfree ${SC_PATH}/external_libraries/boost-lockfree ) diff --git a/src/FluidTransients/CMakeLists.txt b/src/FluidTransients/CMakeLists.txt index 3693881..d1e5005 100755 --- a/src/FluidTransients/CMakeLists.txt +++ b/src/FluidTransients/CMakeLists.txt @@ -9,12 +9,4 @@ add_library( ${FILENAME} ) -target_include_directories( - ${PLUGIN} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../../include -) - -target_link_libraries( - ${PLUGIN} PRIVATE FLUID_DECOMPOSITION -) - include(${CMAKE_CURRENT_LIST_DIR}/../../scripts/target_post.cmake) From 57fea4a584d297d82e5647304fc917c7b6c4d975 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Mon, 21 Jan 2019 16:55:55 +0000 Subject: [PATCH 10/31] Ignore compiled plugins --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bc57530..960a6f8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build **/.DS_Store release-packaging/Plugins release-packaging/AudioFiles +*.scx From 5c7641a734cb02af7df5b6366769c85856fd981a Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 29 Jan 2019 10:46:03 +0000 Subject: [PATCH 11/31] Handle buffer parameters in wrapper include/FluidSCWrapper.hpp --- include/FluidSCWrapper.hpp | 45 ++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 9f9d4f6..7065455 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -26,28 +26,44 @@ template using msg_iter_method = T (sc_msg_iter::*)(T); template Method> struct GetArgument { - T operator()(sc_msg_iter *args) + T operator()(World* w, 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]; } + T operator()(World*, float **controls) { return *controls[N]; } }; + template struct ArgumentGetter : public GetArgument {}; template struct ArgumentGetter : public GetArgument {}; +template struct ArgumentGetter : public GetArgument +{}; + +template struct ArgumentGetter +{ + auto operator()(World* w, sc_msg_iter *args) + { + + long bufnum = args->geti(-1); + + return std::unique_ptr(new SCBufferAdaptor(bufnum,w)); + } +}; + template struct ControlGetter : public GetControl {}; +//template class RealTime : public SCUnit { using HostVector = FluidTensorView; @@ -89,7 +105,7 @@ public: { 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 + w->setParams( mWorld->mVerbosity > 0, mWorld,mInBuf + client.audioChannelsIn()); // forward on inputs N + audio inputs as params const Unit *unit = this; for (int i = 0; i < client.audioChannelsIn(); ++i) { @@ -123,15 +139,16 @@ public: 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); + Result result = validateParameters(w, world, 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(); + w->setParams(false, world, args); + + size_t msgSize = args->getbsize(); char * completionMsgData = 0; if (msgSize) { @@ -148,13 +165,13 @@ public: static void destroy(World *world, void *data) { delete static_cast(data); } private: - static Result validateParameters(Wrapper *w, sc_msg_iter *args) + static Result validateParameters(Wrapper *w, World* world, sc_msg_iter *args) { auto &c = w->client(); - auto results = c.template checkParameterValues(args); + auto results = c.template checkParameterValues(world, args); for (auto &r : results) { - std::cout << r.message() << r.status() << '\n'; + std::cout << r.message() << '\n'; if (!r.ok()) return r; } return {}; @@ -275,14 +292,14 @@ public: impl::FluidSCWrapperBase::setup(ft, name); } - auto setParams(float **inputs, bool verbose) + auto setParams(bool verbose, World* world, float **inputs) { - return mClient.template setParameterValues(inputs, verbose); + return mClient.template setParameterValues(verbose, world, inputs); } - auto setParams(sc_msg_iter *args, bool verbose) + auto setParams(bool verbose, World* world, sc_msg_iter *args) { - return mClient.template setParameterValues(args, verbose); + return mClient.template setParameterValues(verbose,world, args); } Client &client() { return mClient; } From 75089d60833e929881f2e6cdd248148859463c7b Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 29 Jan 2019 10:46:56 +0000 Subject: [PATCH 12/31] New dinky clients src/FluidBufNMF/FluidBufNMF.cpp src/FluidBufSines/FluidBufSines.cpp src/FluidBufTransients/FluidBufTransients.cpp src/FluidBufTransientSlice/FluidBufTransientSlice.cpp src/FluidSines/FluidSines.cpp src/FluidTransientSlice/FluidTransientSlice.cpp --- src/FluidBufNMF/FluidBufNMF.cpp | 133 +----------------- src/FluidBufSines/FluidBufSines.cpp | 96 +------------ .../FluidBufTransientSlice.cpp | 76 +--------- src/FluidBufTransients/FluidBufTransients.cpp | 81 +---------- src/FluidSines/FluidSines.cpp | 125 +--------------- .../FluidTransientSlice.cpp | 102 +------------- 6 files changed, 26 insertions(+), 587 deletions(-) diff --git a/src/FluidBufNMF/FluidBufNMF.cpp b/src/FluidBufNMF/FluidBufNMF.cpp index bc14bec..2e75538 100644 --- a/src/FluidBufNMF/FluidBufNMF.cpp +++ b/src/FluidBufNMF/FluidBufNMF.cpp @@ -1,135 +1,10 @@ - // 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 "fdNRTBase.hpp" - -#include "algorithms/STFT.hpp" -#include "data/FluidTensor.hpp" -#include "clients/nrt/NMFClient.hpp" -#include "clients/common/FluidParams.hpp" - - -#include "SC_PlugIn.h" - -#include -#include +#include +#include static InterfaceTable *ft; -//Using statements for fluidtensor -using fluid::FluidTensor; -using fluid::FluidTensorView; -using fluid::client::NMFClient; - -namespace fluid { - namespace wrapper{ - - class BufNMF: public NRTCommandBase - { - /* - - srcbuf num - – src start frame - - src numframes - – src start chan - – src num chans - – resynths dst - – dicts dst - – acts dst - - 'overwrite' flag [-1:1] - - - rank - - iterations - – window size - – hop size - – fft size - -– boundary flag - -– rand seed - */ - - public: - using client_type = NMFClient; - using NRTCommandBase::NRTCommandBase; - - - ~BufNMF() - { -// if(src) delete src; -// if(resynth) delete resynth; -// if(dict) delete dict; -// if(act) delete act; - } - - void runCommand(World* world, void* replyAddr, char* completionMsgData, size_t completionMsgSize) - { - cmd(world, "/BufNMF", replyAddr, completionMsgData, completionMsgSize); - } - - bool process(World* world) - { - //sanity check the parameters - bool parametersOk; - NMFClient::ProcessModel processModel; - std::string whatHappened;//this will give us a message to pass back if param check fails - std::tie(parametersOk,whatHappened,processModel) = nmf.sanityCheck(); - if(!parametersOk) - { - Print("fdNMF: %s \n", whatHappened.c_str()); - return false; - } - //Now, we can proceed - - nmf.process(processModel); - mModel = processModel; - - src = static_cast(client::lookupParam("src", nmf.getParams()).getBuffer()); - resynth = static_cast(client::lookupParam("resynthbuf", nmf.getParams()).getBuffer()); - dict = static_cast(client::lookupParam("filterbuf", nmf.getParams()).getBuffer()); - act = static_cast(client::lookupParam("envbuf", nmf.getParams()).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*) { - if(mModel.resynthesise) - resynth->cleanUp(); - if(mModel.returnDictionaries) - dict->cleanUp(); - if(mModel.returnActivations) - act->cleanUp(); - return true; - } - - std::vector& parameters() - { - return nmf.getParams(); - } - private: - NMFClient nmf; - NMFClient::ProcessModel mModel; - SCBufferView* src; - SCBufferView* resynth; - SCBufferView* dict; - SCBufferView* act; - };//class - } //namespace wrapper -}//namespace fluid - - PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; - registerCommand(ft, "BufNMF"); + using namespace fluid::client; + makeSCWrapper(ft, "BufNMF"); } diff --git a/src/FluidBufSines/FluidBufSines.cpp b/src/FluidBufSines/FluidBufSines.cpp index 6cf22d4..abd82fd 100644 --- a/src/FluidBufSines/FluidBufSines.cpp +++ b/src/FluidBufSines/FluidBufSines.cpp @@ -1,99 +1,15 @@ // FD_BufSines, an NRT buffer Sinusoidal Modelling 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 "fdNRTBase.hpp" -#include "algorithms/STFT.hpp" -#include "data/FluidTensor.hpp" -#include "clients/nrt/Sines.hpp" -#include "clients/common/FluidParams.hpp" -#include "SC_PlugIn.h" -#include -#include +#include +#include +#include static InterfaceTable *ft; -//Using statements for fluidtensor -using fluid::FluidTensor; -using fluid::FluidTensorView; - -namespace fluid { - namespace wrapper{ - - class BufSines: public NRTCommandBase - { - /* - - srcbuf num - – src start frame - - src numframes - – src start chan - – src num chans - – sines dst - – residual dst - – bandwidth (bins) - – threshold (0-1) - – minTrackLen (frames, 0 for no tracking) - - magnitude weight(0-1) - - freq weight (0-1) - – window size - – hop size - – fft size - */ - public: - using client_type = client::SinesClient; - using NRTCommandBase::NRTCommandBase; - - ~BufSines() {} - - void runCommand(World* world, void* replyAddr, char* completionMsgData, size_t completionMsgSize) - { - cmd(world, "/BufSines", replyAddr, completionMsgData, completionMsgSize); - } - - bool process(World* world) - { - //sanity check the parameters - bool parametersOk; - client::SinesClient::ProcessModel processModel; - std::string whatHappened;//this will give us a message to pass back if param check fails - std::tie(parametersOk,whatHappened,processModel) = processor.sanityCheck(); - if(!parametersOk) - { - Print("fdNMF: %s \n", whatHappened.c_str()); - return false; - } - //Now, we can proceed - processor.process(processModel); - mModel = processModel; - return true; - } - - bool postProcess(World* world) - { - static_cast(mModel.sine)->assignToRT(world); - static_cast(mModel.res)->assignToRT(world); - return true; - } - - bool postComplete(World* w) { - static_cast(mModel.sine)->cleanUp(); - static_cast(mModel.res)->cleanUp(); - return true; - } - - std::vector& parameters() - { - return processor.getParams(); - } - private: - client::SinesClient processor; - client::SinesClient::ProcessModel mModel; - };//class - } //namespace wrapper -}//namespace fluid - - PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; - registerCommand(ft, "BufSines"); - fluid::wrapper::printCmd(ft,"BufSines","FDSines"); + using namespace fluid::client; + makeSCWrapper>>(ft, "BufSines"); + } diff --git a/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp b/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp index 2780a33..3e0db18 100644 --- a/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp +++ b/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp @@ -1,77 +1,15 @@ // 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) -#define EIGEN_USE_BLAS - -#include "clients/nrt/TransientSliceNRT.hpp" -#include "fdNRTBase.hpp" -#include "data/FluidTensor.hpp" -#include "clients/common/FluidParams.hpp" -#include "SC_PlugIn.h" -#include -#include - -static InterfaceTable *ft; - -namespace fluid { - namespace wrapper{ - - class BufTransientsSlice: public NRTCommandBase - { - public: - using client_type = client::TransientSliceNRT; - using NRTCommandBase::NRTCommandBase; - - ~BufTransientsSlice() {} - - void runCommand(World* world, void* replyAddr, char* completionMsgData, size_t completionMsgSize) - { - cmd(world, "/BufTransientSlice", 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("FluidBufTransientSlice: %s \n", whatHappened.c_str()); - return false; - } - trans.process(processModel); - mModel = processModel; - return true; - } - - bool postProcess(World* world) - { - static_cast(mModel.trans)->assignToRT(world); - return true; - } - - bool postComplete(World*) - { - static_cast(mModel.trans)->cleanUp(); - return true; - } - - std::vector& parameters() - { - return trans.getParams(); - } - private: - client_type trans; - client_type::ProcessModel mModel; - };//class - } //namespace wrapper -}//namespace fluid +#include +#include +#include +static InterfaceTable* ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; - registerCommand(ft, "BufTransientSlice"); - fluid::wrapper::printCmd(ft,"BufTransientsSlice","FluidBufTransientSlice"); + using namespace fluid::client; + makeSCWrapper>>(ft, "BufTransientSlice"); + } diff --git a/src/FluidBufTransients/FluidBufTransients.cpp b/src/FluidBufTransients/FluidBufTransients.cpp index a83e861..1b2ae80 100644 --- a/src/FluidBufTransients/FluidBufTransients.cpp +++ b/src/FluidBufTransients/FluidBufTransients.cpp @@ -1,90 +1,11 @@ - // 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 #include - #include - 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; using namespace fluid::client; - makeSCWrapper, decltype(TransientParams), TransientParams>>(ft,"BufTransients"); - -// registerCommand(ft, "BufTransients"); -// fluid::wrapper::printCmd(ft,"BufTransients","FDTransients"); + makeSCWrapper>>(ft,"BufTransients"); } diff --git a/src/FluidSines/FluidSines.cpp b/src/FluidSines/FluidSines.cpp index 9f2f93a..bc268f5 100644 --- a/src/FluidSines/FluidSines.cpp +++ b/src/FluidSines/FluidSines.cpp @@ -1,131 +1,14 @@ // 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/SinesClient.hpp" +#include +#include static InterfaceTable *ft; -namespace fluid { -namespace wrapper{ - class FDRTSines: public SCUnit - { - using AudioSignalWrapper = client::SinesClient::AudioSignal; - using SignalWrapper = client::SinesClient::Signal; - - // using SignalPointer = std::unique_ptr; - public: - FDRTSines() - { - //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::SinesClient(65536); - setParams(true); - -// m_client->getParams()[0].setLong(pfilter_size); -// m_client->getParams()[1].setLong(hfilter_size); -// m_client->getParams()[2].setLong(window_size); -// m_client->getParams()[3].setLong(hop_size); -// m_client->getParams()[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(); - - //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(); - - mCalcFunc = make_calc_function(); - Unit* unit = this; - ClearUnitOutputs(unit,1); - } - - ~FDRTSines() - { - 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::SinesClient *mClient; - SignalWrapper *inputSignals[1]; - SignalWrapper *outputSignals[2]; - }; -} -} PluginLoad(FluidSTFTUGen) { ft = inTable; - registerUnit(ft, "FluidSines"); + using namespace fluid::client; + makeSCWrapper>(ft, "FluidSines"); } diff --git a/src/FluidTransientSlice/FluidTransientSlice.cpp b/src/FluidTransientSlice/FluidTransientSlice.cpp index 25e96fa..8058b57 100644 --- a/src/FluidTransientSlice/FluidTransientSlice.cpp +++ b/src/FluidTransientSlice/FluidTransientSlice.cpp @@ -1,107 +1,13 @@ // 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/TransientSlice.hpp" +#include +#include static InterfaceTable *ft; -namespace fluid { -namespace segmentation{ - class FluidSliceTransients: public SCUnit - { - using audio_client = client::TransientsSlice; - using AudioSignalWrapper = audio_client::AudioSignal; - using SignalWrapper = audio_client::Signal; - - // using SignalPointer = std::unique_ptr; - public: - FluidSliceTransients() - { - mClient = new audio_client(65536); - setParams(true); - bool isOK; - std::string feedback; - - std::tie(isOK, feedback) = mClient->sanityCheck(); - if(!isOK) - { - Print("FluidSliceTransients Error: %s",feedback.c_str()); - return; - } - - - mClient->setHostBufferSize(bufferSize()); - mClient->reset(); - - //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(); - - mCalcFunc = make_calc_function(); - Unit* unit = this; - ClearUnitOutputs(unit,1); - } - - ~FluidSliceTransients() - { - delete inputSignals[0]; - delete outputSignals[0]; - 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)); - mClient->doProcess(std::begin(inputSignals),std::end(inputSignals),std::begin(outputSignals), std::end(outputSignals),numsamples,1,1); - } - - audio_client *mClient; - SignalWrapper *inputSignals[1]; - SignalWrapper *outputSignals[1]; - }; -} -} PluginLoad(FluidSTFTUGen) { ft = inTable; - registerUnit(ft, "FluidTransientSlice"); + using namespace fluid::client; + makeSCWrapper>(ft, "FluidTransientSlice"); } From 4ee4d8edfaa924c840f679270873a1fdea0f6a80 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Fri, 1 Feb 2019 17:19:22 +0000 Subject: [PATCH 13/31] Remove spurious entries from CMakelists, sorry --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a919b34..609e103 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,10 +63,7 @@ add_library(FLUID_SC_WRAPPER INTERFACE) target_sources(FLUID_SC_WRAPPER INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/FluidSCWrapper.hpp -${CMAKE_CURRENT_SOURCE_DIR}/include/NRTCommand.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/SCBufferAdaptor.hpp -${CMAKE_CURRENT_SOURCE_DIR}/include/GenerateSCCode.hpp -${CMAKE_CURRENT_SOURCE_DIR}/include/fdNRTBase.hpp ) SUBDIRLIST(PROJECT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src) From 5496a72a188304029abc305a04e772225a47b176 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Mon, 4 Feb 2019 10:58:37 +0000 Subject: [PATCH 14/31] Updates to wrapper for HPSS freq-amp pairs parameter, improved kontrol input handling. Updated object stubs include/FluidSCWrapper.hpp src/FluidBufHPSS/FluidBufHPSS.cpp src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp src/FluidHPSS/FluidHPSS.cpp --- include/FluidSCWrapper.hpp | 64 ++++++++- src/FluidBufHPSS/FluidBufHPSS.cpp | 97 +------------ .../FluidBufNoveltySlice.cpp | 71 +--------- src/FluidHPSS/FluidHPSS.cpp | 134 +----------------- 4 files changed, 73 insertions(+), 293 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 7065455..b7ef1f5 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -19,6 +19,7 @@ namespace client { template class FluidSCWrapper; namespace impl { + template struct Setter; template struct ArgumentGetter; template struct ControlGetter; @@ -33,11 +34,33 @@ template Method> struct GetArgument } }; -template struct GetControl + +struct FloatControlsIter { - T operator()(World*, float **controls) { return *controls[N]; } + FloatControlsIter(float** vals, size_t N):mValues(vals), mSize(N) {} + + float next() + { + assert(mCount + 1 < mSize); + return *mValues[mCount++]; + } + + void reset(float** vals) + { + mValues = vals; + mCount = 0; + } + + private: + float** mValues; + size_t mSize; + size_t mCount{0}; }; +template struct GetControl +{ + T operator()(World*, FloatControlsIter& controls) { return controls.next(); } +}; template struct ArgumentGetter : public GetArgument {}; @@ -59,9 +82,38 @@ template struct ArgumentGetter } }; +template struct ArgumentGetter +{ + typename FloatPairsArrayT::type operator()(World* w, sc_msg_iter *args) + { + return {{args->getf(),args->getf()},{args->getf(),args->getf()}}; + } +}; + + + template struct ControlGetter : public GetControl {}; + +template struct ControlGetter +{ + auto operator()(World* w, FloatControlsIter& iter) + { + long bufnum = iter.next(); + return std::unique_ptr(new SCBufferAdaptor(bufnum,w)); + } +}; + +template +struct ControlGetter +{ + typename FloatPairsArrayT::type operator()(World*, FloatControlsIter& iter) + { + return {{iter.next(),iter.next()},{iter.next(),iter.next()}}; + } +}; + //template class RealTime : public SCUnit @@ -72,7 +124,7 @@ template class RealTime : public SCUnit public: static void setup(InterfaceTable *ft, const char *name) { registerUnit(ft, name); } - RealTime() {} + RealTime():mControlsIterator{nullptr,0} {} void init() { @@ -105,7 +157,8 @@ public: { Wrapper *w = static_cast(this); auto &client = w->client(); - w->setParams( mWorld->mVerbosity > 0, mWorld,mInBuf + client.audioChannelsIn()); // forward on inputs N + audio inputs as params + mControlsIterator.reset(mInBuf + client.audioChannelsIn()); + w->setParams( mWorld->mVerbosity > 0, mWorld,mControlsIterator); // forward on inputs N + audio inputs as params const Unit *unit = this; for (int i = 0; i < client.audioChannelsIn(); ++i) { @@ -123,6 +176,7 @@ private: std::vector mOutputConnections; std::vector mAudioInputs; std::vector mAudioOutputs; + FloatControlsIter mControlsIterator; }; template class NonRealTime @@ -292,7 +346,7 @@ public: impl::FluidSCWrapperBase::setup(ft, name); } - auto setParams(bool verbose, World* world, float **inputs) + auto setParams(bool verbose, World* world, impl::FloatControlsIter& inputs) { return mClient.template setParameterValues(verbose, world, inputs); } diff --git a/src/FluidBufHPSS/FluidBufHPSS.cpp b/src/FluidBufHPSS/FluidBufHPSS.cpp index 7e5c774..bc979c0 100644 --- a/src/FluidBufHPSS/FluidBufHPSS.cpp +++ b/src/FluidBufHPSS/FluidBufHPSS.cpp @@ -1,101 +1,14 @@ // FD_BufHPSS, an NRT buffer HPSS 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 "fdNRTBase.hpp" -#include "algorithms/STFT.hpp" -#include "data/FluidTensor.hpp" -#include "clients/nrt/HPSS.hpp" -#include "clients/common/FluidParams.hpp" -#include "SC_PlugIn.h" -#include -#include +#include +#include +#include static InterfaceTable *ft; -//Using statements for fluidtensor -using fluid::FluidTensor; -using fluid::FluidTensorView; - -namespace fluid { - namespace wrapper{ - - class BufHPSS: public NRTCommandBase - { - /* - - srcbuf num - – src start frame - - src numframes - – src start chan - – src num chans - – harms dst - – perc dst - – window size - – hop size - – fft size - */ - public: - using client_type = client::HPSSClient; - using NRTCommandBase::NRTCommandBase; - - ~BufHPSS() {} - - void runCommand(World* world, void* replyAddr, char* completionMsgData, size_t completionMsgSize) - { - cmd(world, "/BufHPSS", replyAddr, completionMsgData, completionMsgSize); - } - - bool process(World* world) - { - //sanity check the parameters - bool parametersOk; - client::HPSSClient::ProcessModel processModel; - std::string whatHappened;//this will give us a message to pass back if param check fails - std::tie(parametersOk,whatHappened,processModel) = processor.sanityCheck(); - if(!parametersOk) - { - Print("fdHPSS: %s \n", whatHappened.c_str()); - return false; - } - //Now, we can proceed - processor.process(processModel); - mModel = processModel; - return true; - } - - bool postProcess(World* world) - { - static_cast(mModel.harm)->assignToRT(world); - static_cast(mModel.perc)->assignToRT(world); - - if(mModel.res) - static_cast(mModel.res)->assignToRT(world); - - return true; - } - - bool postComplete(World*) { - static_cast(mModel.harm)->cleanUp(); - static_cast(mModel.perc)->cleanUp(); - if(mModel.res) - static_cast(mModel.res)->cleanUp(); - return true; - } - - - std::vector& parameters() - { - return processor.getParams(); - } - private: - client::HPSSClient processor; - client::HPSSClient::ProcessModel mModel; - };//class - } //namespace wrapper -}//namespace fluid - - PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; - registerCommand(ft, "BufHPSS"); - fluid::wrapper::printCmd(ft,"BufHPSS","FDHPSS"); + using namespace fluid::client; + makeSCWrapper>>(ft, "BufHPSS"); } diff --git a/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp b/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp index 7950753..206b5e2 100644 --- a/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp +++ b/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp @@ -2,74 +2,13 @@ // 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/NoveltyClient.hpp" -#include "fdNRTBase.hpp" -#include "data/FluidTensor.hpp" -#include "clients/common/FluidParams.hpp" -//#include "SC_PlugIn.h" -//#include -//#include - -static InterfaceTable *ft; - -namespace fluid { - namespace wrapper{ - - class BufNoveltySlice: public NRTCommandBase - { - public: - using client_type = client::NoveltyClient; - using NRTCommandBase::NRTCommandBase; - - ~BufNoveltySlice() {} - - void runCommand(World* world, void* replyAddr, char* completionMsgData, size_t completionMsgSize) - { - cmd(world, "/BufNoveltySlice", 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("FluidBufNovletySlice: %s \n", whatHappened.c_str()); - return false; - } - trans.process(processModel); - mModel = processModel; - return true; - } - - bool postProcess(World* world) - { - static_cast(mModel.indices)->assignToRT(world); - return true; - } - - bool postComplete(World*) { - static_cast(mModel.indices)->cleanUp(); - return true; - } - - std::vector& parameters() - { - return trans.getParams(); - } - private: - client_type trans; - client_type::ProcessModel mModel; - };//class - } //namespace wrapper -}//namespace fluid +#include +#include +static InterfaceTable* ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; - registerCommand(ft, "BufNoveltySlice"); - fluid::wrapper::printCmd(ft,"BufNoveltySlice","FluidBufNoveltySlice"); + using namespace fluid::client; + makeSCWrapper(ft, "BufNoveltySlice"); } diff --git a/src/FluidHPSS/FluidHPSS.cpp b/src/FluidHPSS/FluidHPSS.cpp index 015e5ba..1b779e5 100644 --- a/src/FluidHPSS/FluidHPSS.cpp +++ b/src/FluidHPSS/FluidHPSS.cpp @@ -1,140 +1,14 @@ // 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/HPSSClient.hpp" +#include +#include static InterfaceTable *ft; -namespace fluid { -namespace wrapper{ - class FDRTHPSS: public SCUnit - { - using AudioSignalWrapper = client::HPSSClient::AudioSignal; - using SignalWrapper = client::HPSSClient::Signal; - using SignalPointer = std::unique_ptr; - using ClientPointer = std::unique_ptr>; - template - using SignalArray = std::array; - public: - FDRTHPSS() - { - //Order of args - //psize hszie pthresh hthresh Window size, Hop size, FFT Size - - //Oh NO! Heap allocation! Make client object - mClient = ClientPointer(new client::HPSSClient(65536)); - - setParams(true); - - 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(); - - //Work out what signals we need. For now keep it simple: - inputSignals[0] = SignalPointer(new AudioSignalWrapper()); - outputSignals[0] = SignalPointer(new AudioSignalWrapper()); - outputSignals[1] = SignalPointer(new AudioSignalWrapper()); - outputSignals[2] = SignalPointer(new AudioSignalWrapper()); - - mCalcFunc = make_calc_function(); - Unit* unit = this; - ClearUnitOutputs(unit,1); - } - - ~FDRTHPSS() {} - - 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: { - - // We need to constrain threshold (normalised) frequency pairs at - // runtime. - std::string attrname = p.getDescriptor().getName(); - auto constraint = paramConstraints.find(attrname); - - if (constraint != paramConstraints.end()) { - double limit = client::lookupParam(constraint->second.param, - mClient->getParams()) - .getFloat(); - - if (!constraint->second.condition(in0(i + 1), limit)) { - return; - } - } - - 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)); - outputSignals[2]->set(out(2), out0(2)); - mClient->doProcess(std::begin(inputSignals),std::end(inputSignals),std::begin(outputSignals), std::end(outputSignals),numsamples,1,3); - } - - struct Constraint{ - std::string param; - std::function condition; - }; - - std::map paramConstraints{ - {"ptf1",{"ptf2", std::less()}}, - {"htf1",{"htf2", std::less()}}, - {"ptf2",{"ptf1", std::greater()}}, - {"htf2",{"htf1", std::greater()}} - }; - - - ClientPointer mClient; - SignalArray<1> inputSignals; - SignalArray<3> outputSignals; - }; -} -} PluginLoad(FluidSTFTUGen) { ft = inTable; - registerUnit(ft, "FluidHPSS"); + using namespace fluid::client; + makeSCWrapper>(ft, "FluidHPSS"); } From 9ab5dc3d5665c1dcc031eee0e0c22b85f519faeb Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 5 Feb 2019 20:20:54 +0000 Subject: [PATCH 15/31] Make client factory, attempts to initialise client with constructor args from istantiation params.Add NMF wrapper include/FluidSCWrapper.hpp include/SCBufferAdaptor.hpp src/FluidNMFMatch/FluidNMFMatch.cpp --- include/FluidSCWrapper.hpp | 163 ++++++++++++++++++++-------- include/SCBufferAdaptor.hpp | 5 +- src/FluidNMFMatch/FluidNMFMatch.cpp | 127 +--------------------- 3 files changed, 124 insertions(+), 171 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index b7ef1f5..4551eba 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -29,7 +29,7 @@ template Method> struct GetArgument { T operator()(World* w, sc_msg_iter *args) { - T r = (args->*Method)(0); + T r = (args->*Method)(T{0}); return r; } }; @@ -63,22 +63,29 @@ template struct GetControl }; template struct ArgumentGetter : public GetArgument -{}; +{ +// ArgumentGetter() { std::cout << "FloatT @ " << N << '\n'; } +}; template struct ArgumentGetter : public GetArgument -{}; +{ +// ArgumentGetter() { std::cout << "LongT @ " << N << '\n'; } + +}; template struct ArgumentGetter : public GetArgument -{}; +{ +// ArgumentGetter() { std::cout << "Enum @ " << N << '\n'; } + +}; template struct ArgumentGetter { - auto operator()(World* w, sc_msg_iter *args) +// ArgumentGetter() { std::cout << "Buffer @ " << N << '\n'; } + auto operator() (World* w, sc_msg_iter *args) { - - long bufnum = args->geti(-1); - - return std::unique_ptr(new SCBufferAdaptor(bufnum,w)); + typename LongT::type bufnum = args->geti(-1); + return std::unique_ptr(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w) : nullptr); } }; @@ -98,10 +105,10 @@ template struct ControlGetter : public GetControl struct ControlGetter { - auto operator()(World* w, FloatControlsIter& iter) + auto operator() (World* w, FloatControlsIter& iter) { - long bufnum = iter.next(); - return std::unique_ptr(new SCBufferAdaptor(bufnum,w)); + typename LongT::type bufnum = iter.next(); + return std::unique_ptr(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w): nullptr); } }; @@ -114,29 +121,54 @@ struct ControlGetter } }; + +template class Fetcher> +struct ClientFactory +{ + static Client create(World* world, Args* args) + { + return createImpl(world, args, FixedParamIndices{}); + } + +private: + using FixedParamIndices = typename Client::FixedParams; + template + using ThisParamType = typename Client::template ParamDescriptorTypeAt; + + template + static Client createImpl(World* world, Args* args, std::index_sequence) + { + return Client{Fetcher>{}(world,*args)...}; + } +}; + //template class RealTime : public SCUnit +template class RealTime : public SCUnit { using HostVector = FluidTensorView; // using Client = typename Wrapper::ClientType; public: static void setup(InterfaceTable *ft, const char *name) { registerUnit(ft, name); } - - RealTime():mControlsIterator{nullptr,0} {} + + RealTime(): + SCUnit{}, + mControlsIterator{mInBuf + mSpecialIndex + 1,mNumInputs - mSpecialIndex - 1}, + mClient{ClientFactory::create(mWorld,&mControlsIterator)} + {} void init() { - Wrapper *w = static_cast(this); - - auto &mClient = w->client(); + assert(!(mClient.audioChannelsOut() > 0 && mClient.controlChannelsOut() > 0) && "Client can't have both audio and control outputs"); mInputConnections.reserve(mClient.audioChannelsIn()); mOutputConnections.reserve(mClient.audioChannelsOut()); mAudioInputs.reserve(mClient.audioChannelsIn()); mAudioOutputs.reserve(mClient.audioChannelsOut()); - + mControlOutputs.reserve(mClient.controlChannelsOut()); +// mControlOutputData.resize(mClient.controlChannelsOut(),) + for (int i = 0; i < mClient.audioChannelsIn(); ++i) { mInputConnections.emplace_back(isAudioRateIn(i)); @@ -149,6 +181,11 @@ public: mAudioOutputs.emplace_back(nullptr, 0, 0); } +// for (int i = 0; i < mClient.controlChannelsOut(); ++i) +// { +// mControlOutputs.emplace_back() +// } + set_calc_function(); Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1); } @@ -156,50 +193,61 @@ public: void next(int n) { Wrapper *w = static_cast(this); - auto &client = w->client(); - mControlsIterator.reset(mInBuf + client.audioChannelsIn()); +// auto &client = w->client(); + mControlsIterator.reset(mInBuf + mClient.audioChannelsIn()); w->setParams( mWorld->mVerbosity > 0, mWorld,mControlsIterator); // forward on inputs N + audio inputs as params const Unit *unit = this; - for (int i = 0; i < client.audioChannelsIn(); ++i) + for (int i = 0; i < mClient.audioChannelsIn(); ++i) { if (mInputConnections[i]) mAudioInputs[i].reset(IN(i), 0, fullBufferSize()); } - for (int i = 0; i < client.audioChannelsOut(); ++i) + for (int i = 0; i < mClient.audioChannelsOut(); ++i) { if (mOutputConnections[i]) mAudioOutputs[i].reset(out(i), 0, fullBufferSize()); } - client.process(mAudioInputs, mAudioOutputs); + for(int i = 0; i < mClient.controlChannelsOut();++i) + { + if(mOutputConnections[i]) mControlOutputs[i].reset(out(i),0,1); + } + mClient.process(mAudioInputs, mAudioOutputs); } - private: std::vector mInputConnections; std::vector mOutputConnections; std::vector mAudioInputs; std::vector mAudioOutputs; + std::vector mControlOutputs; FloatControlsIter mControlsIterator; +protected: + Client mClient; + }; -template class NonRealTime +template class NonRealTime { public: static void setup(InterfaceTable *ft, const char *name) { DefinePlugInCmd(name, launch, nullptr); } - NonRealTime() {} + NonRealTime(World *world,sc_msg_iter *args): + mClient{ClientFactory::create(world,args)} + {} void init(){}; 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 + Wrapper *w = new Wrapper(world,args); //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; + auto argsRdPos = args->rdpos; Result result = validateParameters(w, world, args); if (!result.ok()) { std::cout << "FluCoMa Error " << Wrapper::getName() << ": " << result.message().c_str(); return; } - args->count = argsPosition; + args->count = argsPosition; + args->rdpos = argsRdPos; w->setParams(false, world, args); size_t msgSize = args->getbsize(); @@ -218,10 +266,13 @@ public: static bool tidyUp(World *world, void *data) { return static_cast(data)->tidyUp(world); } static void destroy(World *world, void *data) { delete static_cast(data); } +protected: + Client mClient; + private: - static Result validateParameters(Wrapper *w, World* world, sc_msg_iter *args) + static Result validateParameters(NonRealTime *w, World* world, sc_msg_iter *args) { - auto &c = w->client(); + auto &c = w->mClient; auto results = c.template checkParameterValues(world, args); for (auto &r : results) { @@ -233,7 +284,7 @@ private: void parseBuffers(Wrapper *w, World *world, sc_msg_iter *args) { - auto &c = w->client(); + auto &c = mClient; mBuffersIn.reserve(c.audioBuffersIn()); mInputs.reserve(c.audioBuffersIn()); @@ -261,8 +312,7 @@ private: bool process(World *world) { - Wrapper *wrapper = static_cast(this); - Result r = wrapper->client().process(mInputs, mOutputs); + Result r = mClient.process(mInputs, mOutputs); if(!r.ok()) { @@ -275,6 +325,8 @@ private: bool exchangeBuffers(World *world) { + + mClient.template forEachParamType(world); for (auto &b : mBuffersOut) b.assignToRT(world); return true; } @@ -286,6 +338,16 @@ private: return true; } + template + struct AssignBuffer + { + void operator()(typename BufferT::type& p, World* w) + { + if(auto b = static_cast(p.get())) + b->assignToRT(w); + } + }; + std::vector mBuffersIn; std::vector mBuffersOut; std::vector mInputs; @@ -294,28 +356,31 @@ private: const char * mName; }; -template class NonRealTimeAndRealTime : public RealTime, public NonRealTime +template class NonRealTimeAndRealTime : public RealTime, public NonRealTime { static void setup(InterfaceTable *ft, const char *name) { - RealTime::setup(ft, name); - NonRealTime::setup(ft, name); + RealTime::setup(ft, name); + NonRealTime::setup(ft, name); } }; // Template Specialisations for NRT/RT -template class FluidSCWrapperImpl; +template class FluidSCWrapperImpl; -template class FluidSCWrapperImpl : public NonRealTime -{}; +template class FluidSCWrapperImpl : public NonRealTime +{ +public: + FluidSCWrapperImpl(World* w, sc_msg_iter *args): NonRealTime(w,args){}; +}; -template class FluidSCWrapperImpl : public RealTime +template class FluidSCWrapperImpl : public RealTime {}; // Make base class(es), full of CRTP mixin goodness template -using FluidSCWrapperBase = FluidSCWrapperImpl, isNonRealTime, isRealTime>; +using FluidSCWrapperBase = FluidSCWrapperImpl, isNonRealTime, isRealTime>; } // namespace impl @@ -327,6 +392,10 @@ public: FluidSCWrapper() { impl::FluidSCWrapperBase::init(); } + FluidSCWrapper(World* w, sc_msg_iter *args): impl::FluidSCWrapperBase(w,args) + { impl::FluidSCWrapperBase::init(); } + + static const char *getName(const char *setName = nullptr) { static const char *name = nullptr; @@ -348,18 +417,18 @@ public: auto setParams(bool verbose, World* world, impl::FloatControlsIter& inputs) { - return mClient.template setParameterValues(verbose, world, inputs); + return impl::FluidSCWrapperBase::mClient.template setParameterValues(verbose, world, inputs); } auto setParams(bool verbose, World* world, sc_msg_iter *args) { - return mClient.template setParameterValues(verbose,world, args); + return impl::FluidSCWrapperBase::mClient.template setParameterValues(verbose,world, args); } - Client &client() { return mClient; } +// Client &client() { return mClient; } -private: - Client mClient; +//private: +// Client mClient; }; template void makeSCWrapper(InterfaceTable *ft, const char *name) diff --git a/include/SCBufferAdaptor.hpp b/include/SCBufferAdaptor.hpp index 2819c11..b753a15 100644 --- a/include/SCBufferAdaptor.hpp +++ b/include/SCBufferAdaptor.hpp @@ -66,15 +66,18 @@ public: SCBufferAdaptor& operator=(SCBufferAdaptor&&) = default; - SCBufferAdaptor(long bufnum, World *world, bool rt = false) + SCBufferAdaptor(long bufnum,World *world, bool rt = false) : NRTBuf(world, bufnum, rt) , mBufnum(bufnum) , mWorld(world) { } + SCBufferAdaptor() = default; + ~SCBufferAdaptor(){ cleanUp(); } + void assignToRT(World *rtWorld) { SndBuf *rtBuf = World_GetBuf(rtWorld, mBufnum); diff --git a/src/FluidNMFMatch/FluidNMFMatch.cpp b/src/FluidNMFMatch/FluidNMFMatch.cpp index 60f0a13..6eec74e 100644 --- a/src/FluidNMFMatch/FluidNMFMatch.cpp +++ b/src/FluidNMFMatch/FluidNMFMatch.cpp @@ -1,134 +1,15 @@ // 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 "fdNRTBase.hpp" -#include "clients/rt/NMFMatch.hpp" - - +#include +#include static InterfaceTable *ft; -namespace fluid { -namespace nmf{ - class FDNMFMatch: public SCUnit - { - using Client = client::NMFMatch; - using AudioSignalWrapper = Client::AudioSignal; - using SignalWrapper = Client::Signal; - using SignalPointer = std::unique_ptr; - using ClientPointer = std::unique_ptr; - template - using SignalArray = std::array; - using SignalVector = std::vector; - - public: - FDNMFMatch() - { - //Order of args - //psize hszie pthresh hthresh Window size, Hop size, FFT Size - - mClient = ClientPointer(new Client(65536)); - - setParams(true); - - bool isOK; - std::string feedback; - - std::tie(isOK, feedback) = mClient->sanityCheck(); - if(!isOK) - { - std::cout << "FluidNMFMatch Error: " << feedback << '\n'; - - mCalcFunc = ClearUnitOutputs; - - return; - } - - mRank = client::lookupParam("rank", mClient->getParams()).getLong(); - - - mClient->setHostBufferSize(bufferSize()); - mClient->reset(); - - inputSignals[0] = SignalPointer(new AudioSignalWrapper()); - - outputSignals.resize(mRank); - for(size_t i = 0; i < mRank; ++i) - outputSignals[i].reset(new Client::ScalarSignal()); - - mCalcFunc = make_calc_function(); - Unit* unit = this; - ClearUnitOutputs(unit,1); - } - - ~FDNMFMatch() {} - - 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: { - long bufnum = static_cast(in0(i+1)); - wrapper::RTBufferView* currentBuf = static_cast(p.getBuffer()); - - - if(bufnum >= 0 && (currentBuf? (currentBuf->bufnum() != bufnum) : true)){ - wrapper::RTBufferView* buf = new wrapper::RTBufferView(mWorld,bufnum); - p.setBuffer(buf); - } - break; - } - default: - break; - } - } - } - - void next(int numsamples) - { - setParams(false); - const float* input = zin(0); - const float inscalar = in0(0); - inputSignals[0]->set(const_cast(input), inscalar); - for(size_t i = 0; i < mRank; ++i) - outputSignals[i]->set(out(i),out0(i)); - - mClient->doProcessNoOla(inputSignals.begin(),inputSignals.end(), outputSignals.begin(), outputSignals.end(), mWorld->mFullRate.mBufLength ,1,mRank); - for(size_t i = 0; i < mRank; ++i) - out0(i) = outputSignals[i]->next(); - } - - - - size_t mRank; - ClientPointer mClient; - SignalArray<1> inputSignals; - SignalVector outputSignals; - }; -} -} PluginLoad(FluidSTFTUGen) { ft = inTable; - registerUnit(ft, "FluidNMFMatch"); + using namespace fluid::client; + makeSCWrapper>(ft, "FluidNMFMatch"); } From c23dfbe35975b672ff71f3d1184fa340eb0aecc9 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 5 Feb 2019 22:58:04 +0000 Subject: [PATCH 16/31] Yeah, maybe don't overwrite the Unit that SC loving prepared for you. That would be stupid include/FluidSCWrapper.hpp --- include/FluidSCWrapper.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 4551eba..aaeeee6 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -153,7 +153,6 @@ public: static void setup(InterfaceTable *ft, const char *name) { registerUnit(ft, name); } RealTime(): - SCUnit{}, mControlsIterator{mInBuf + mSpecialIndex + 1,mNumInputs - mSpecialIndex - 1}, mClient{ClientFactory::create(mWorld,&mControlsIterator)} {} From 326030278226c6178536739c2cf042c73927fd47 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 5 Feb 2019 22:58:43 +0000 Subject: [PATCH 17/31] Counting and arthmetic are valuble skills, I hear include/FluidSCWrapper.hpp --- include/FluidSCWrapper.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index aaeeee6..cd1c8fc 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -41,8 +41,9 @@ struct FloatControlsIter float next() { - assert(mCount + 1 < mSize); - return *mValues[mCount++]; + assert(mCount < mSize && "Boundary error fail horror"); + float f = *mValues[mCount++]; + return f; } void reset(float** vals) From aaba970d0f4f9d5f36ba0892d9a0014b4992da0d Mon Sep 17 00:00:00 2001 From: Owen Green Date: Wed, 6 Feb 2019 01:40:01 +0000 Subject: [PATCH 18/31] NMFMatch working in SC Having gone to the trouble of making the right numbers, I should use them, rather than other numbers. I should also use the outputs I've made, rather than nothing. include/FluidSCWrapper.hpp --- include/FluidSCWrapper.hpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index cd1c8fc..47fd62c 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -46,6 +46,12 @@ struct FloatControlsIter return f; } + float operator[](size_t i) + { + assert(i < mSize); + return *mValues[i]; + } + void reset(float** vals) { mValues = vals; @@ -60,7 +66,7 @@ struct FloatControlsIter template struct GetControl { - T operator()(World*, FloatControlsIter& controls) { return controls.next(); } + T operator()(World*, FloatControlsIter& controls) { return controls[N]; } }; template struct ArgumentGetter : public GetArgument @@ -165,9 +171,7 @@ public: mInputConnections.reserve(mClient.audioChannelsIn()); mOutputConnections.reserve(mClient.audioChannelsOut()); mAudioInputs.reserve(mClient.audioChannelsIn()); - mAudioOutputs.reserve(mClient.audioChannelsOut()); - mControlOutputs.reserve(mClient.controlChannelsOut()); -// mControlOutputData.resize(mClient.controlChannelsOut(),) + mOutputs.reserve(std::max(mClient.audioChannelsOut(),mClient.controlChannelsOut())); for (int i = 0; i < mClient.audioChannelsIn(); ++i) { @@ -178,13 +182,13 @@ public: for (int i = 0; i < mClient.audioChannelsOut(); ++i) { mOutputConnections.emplace_back(true); - mAudioOutputs.emplace_back(nullptr, 0, 0); + mOutputs.emplace_back(nullptr, 0, 0); } -// for (int i = 0; i < mClient.controlChannelsOut(); ++i) -// { -// mControlOutputs.emplace_back() -// } + for (int i = 0; i < mClient.controlChannelsOut(); ++i) + { + mOutputs.emplace_back(nullptr, 0, 0); + } set_calc_function(); Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1); @@ -203,20 +207,19 @@ public: } for (int i = 0; i < mClient.audioChannelsOut(); ++i) { - if (mOutputConnections[i]) mAudioOutputs[i].reset(out(i), 0, fullBufferSize()); + if (mOutputConnections[i]) mOutputs[i].reset(out(i), 0, fullBufferSize()); } for(int i = 0; i < mClient.controlChannelsOut();++i) { - if(mOutputConnections[i]) mControlOutputs[i].reset(out(i),0,1); + mOutputs[i].reset(out(i),0,1); } - mClient.process(mAudioInputs, mAudioOutputs); + mClient.process(mAudioInputs, mOutputs); } private: std::vector mInputConnections; std::vector mOutputConnections; std::vector mAudioInputs; - std::vector mAudioOutputs; - std::vector mControlOutputs; + std::vector mOutputs; FloatControlsIter mControlsIterator; protected: Client mClient; From 266fa5f746497336f4617717b2530bc4b4b90c19 Mon Sep 17 00:00:00 2001 From: Gerard Date: Tue, 19 Feb 2019 14:53:32 +0000 Subject: [PATCH 19/31] add FluidOnsetSlice --- release-packaging/Classes/FluidOnsetSlice.sc | 5 +++++ src/FluidOnsetSlice/CMakeLists.txt | 20 +++++++++++++++++++ src/FluidOnsetSlice/FluidOnsetSlice.cpp | 13 ++++++++++++ src/FluidOnsetSlice/test.scd | 21 ++++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 release-packaging/Classes/FluidOnsetSlice.sc create mode 100755 src/FluidOnsetSlice/CMakeLists.txt create mode 100644 src/FluidOnsetSlice/FluidOnsetSlice.cpp create mode 100644 src/FluidOnsetSlice/test.scd diff --git a/release-packaging/Classes/FluidOnsetSlice.sc b/release-packaging/Classes/FluidOnsetSlice.sc new file mode 100644 index 0000000..8dcfc0d --- /dev/null +++ b/release-packaging/Classes/FluidOnsetSlice.sc @@ -0,0 +1,5 @@ +FluidOnsetSlice : UGen { + *ar { arg in = 0, function = 0, threshold = 0.1, debounce = 2, filterSize = 5, winSize = 1024, hopSize = 256, frameDelta = 0, fftSize = 1024, maFFTSize = 16384; + ^this.multiNew('audio', in.asAudioRateInput(this), function, threshold, debounce, filterSize, winSize, hopSize, frameDelta, fftSize, maFFTSize) + } +} diff --git a/src/FluidOnsetSlice/CMakeLists.txt b/src/FluidOnsetSlice/CMakeLists.txt new file mode 100755 index 0000000..3693881 --- /dev/null +++ b/src/FluidOnsetSlice/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.3) +get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) +message("Configuring ${PLUGIN}") +set(FILENAME ${PLUGIN}.cpp) + +add_library( + ${PLUGIN} + MODULE + ${FILENAME} +) + +target_include_directories( + ${PLUGIN} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../../include +) + +target_link_libraries( + ${PLUGIN} PRIVATE FLUID_DECOMPOSITION +) + +include(${CMAKE_CURRENT_LIST_DIR}/../../scripts/target_post.cmake) diff --git a/src/FluidOnsetSlice/FluidOnsetSlice.cpp b/src/FluidOnsetSlice/FluidOnsetSlice.cpp new file mode 100644 index 0000000..27a2746 --- /dev/null +++ b/src/FluidOnsetSlice/FluidOnsetSlice.cpp @@ -0,0 +1,13 @@ + +// 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 +#include + +static InterfaceTable *ft; + +PluginLoad(FluidSTFTUGen) { + ft = inTable; + using namespace fluid::client; + makeSCWrapper>(ft, "FluidOnsetSlice"); +} diff --git a/src/FluidOnsetSlice/test.scd b/src/FluidOnsetSlice/test.scd new file mode 100644 index 0000000..b82344e --- /dev/null +++ b/src/FluidOnsetSlice/test.scd @@ -0,0 +1,21 @@ +s.reboot; + +b = Buffer.read(s,"../../release-packaging/AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav".resolveRelative); + +// basic param (the process add a latency of (blockSize + padding - order) samples +{var sig = PlayBuf.ar(1,b.bufnum,loop:1); [FluidTransientSlice.ar(sig)*0.5, DelayN.ar(sig, 1, ((256 + 128 - 20)/ s.sampleRate))]}.play + +// sexier params +{var sig = PlayBuf.ar(1,b.bufnum,loop:1); [FluidTransientSlice.ar(sig,order:80,debounce:2205)*0.5, DelayN.ar(sig, 1, ((256 + 128 - 80)/ s.sampleRate))]}.play + +// more musical trans-trigged autopan +( +{ + var sig, trig, syncd, pan; + sig = PlayBuf.ar(1,b.bufnum,loop:1); + trig = FluidTransientSlice.ar(sig,order:10,debounce:2205); + syncd = DelayN.ar(sig, 1, ((256 + 128 - 10)/ s.sampleRate)); + pan = TRand.ar(-1,1,trig); + Pan2.ar(syncd,pan); +}.play +) \ No newline at end of file From ebaab35bc9e6b2576c3c5a2646beccd3b76b06f4 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 19 Feb 2019 15:01:29 +0000 Subject: [PATCH 20/31] Make sure objects can find local include files --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 609e103..caab9fd 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ MACRO(SUBDIRLIST result curdir) ENDMACRO() set(FLUID_PATH ~/fluid_decomposition CACHE PATH "The top level of the fluid_decomposition repo") +set(LOCAL_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include) + get_filename_component(FLUID_ABS_PATH ${FLUID_PATH} ABSOLUTE) message(${FLUID_ABS_PATH}) From 33fb34cbfebb27fb384c86581d1dd51e88e55797 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 19 Feb 2019 15:01:59 +0000 Subject: [PATCH 21/31] Local include variable --- scripts/target_post.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/target_post.cmake b/scripts/target_post.cmake index 0acffe9..247c069 100644 --- a/scripts/target_post.cmake +++ b/scripts/target_post.cmake @@ -9,7 +9,7 @@ target_link_libraries( target_include_directories( ${PLUGIN} PRIVATE - ${CMAKE_CURRENT_LIST_DIR}/../../include + ${LOCAL_INCLUDES} SYSTEM PRIVATE ${SC_PATH}/include/plugin_interface ${SC_PATH}/include/common From 9738c8a0572d77311da867ac3cb487b1ad22ac43 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 19 Feb 2019 15:02:42 +0000 Subject: [PATCH 22/31] Gaffa tape max size into SC class stubs --- release-packaging/Classes/FluidBufNoveltySlice.sc | 2 +- release-packaging/Classes/FluidNMFMatch.sc | 2 +- release-packaging/Classes/FluidSines.sc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/release-packaging/Classes/FluidBufNoveltySlice.sc b/release-packaging/Classes/FluidBufNoveltySlice.sc index 9a0bb4d..09fbb1f 100644 --- a/release-packaging/Classes/FluidBufNoveltySlice.sc +++ b/release-packaging/Classes/FluidBufNoveltySlice.sc @@ -1,5 +1,5 @@ FluidBufNoveltySlice{ - *process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, transBufNum, kernelSize = 3, thresh = 0.8, filterSize = 0, winSize = 1024, hopSize = 512, fftSize = 2048; + *process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, transBufNum, kernelSize = 3, thresh = 0.8, filterSize = 11, winSize = 1024, hopSize = 512, fftSize = 2048, maxWindowSize=16384; if(srcBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw}; if(transBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw}; diff --git a/release-packaging/Classes/FluidNMFMatch.sc b/release-packaging/Classes/FluidNMFMatch.sc index c34b730..8c257e3 100644 --- a/release-packaging/Classes/FluidNMFMatch.sc +++ b/release-packaging/Classes/FluidNMFMatch.sc @@ -1,7 +1,7 @@ FluidNMFMatch : MultiOutUGen { *kr { arg in = 0, dictBufNum, rank = 1, nIter = 10, winSize = 1024, hopSize = 256, fftSize = -1; - ^this.multiNew('control', in, dictBufNum, rank, nIter, winSize, hopSize, fftSize); + ^this.multiNew('control', in, dictBufNum, rank, nIter, winSize, hopSize, fftSize,16384); } init {arg ...theInputs; diff --git a/release-packaging/Classes/FluidSines.sc b/release-packaging/Classes/FluidSines.sc index f2c377b..d44a7fa 100644 --- a/release-packaging/Classes/FluidSines.sc +++ b/release-packaging/Classes/FluidSines.sc @@ -1,13 +1,13 @@ FluidSines : MultiOutUGen { *ar { arg in = 0, bandwidth = 76, thresh = 0.7, minTrackLen = 15, magWeight = 0.1, freqWeight = 1.0, winSize= 2048, hopSize= 512, fftSize= 8192; - ^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, thresh, minTrackLen, magWeight,freqWeight ,winSize, hopSize, fftSize) + ^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, thresh, minTrackLen, magWeight,freqWeight ,winSize, hopSize, fftSize,16384) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate, this, 0), OutputProxy(rate, this, 1) - ]; + ] ^channels } checkInputs { ^this.checkNInputs(1) } From e2d7e302488f8cad54d7136ae7c09d17449744f0 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 19 Feb 2019 15:03:09 +0000 Subject: [PATCH 23/31] Don't pass Params tuple to SC object factory --- src/FluidSTFTPass/FluidSTFTPass.cpp | 2 +- src/FluidTransients/FluidTransients.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/FluidSTFTPass/FluidSTFTPass.cpp b/src/FluidSTFTPass/FluidSTFTPass.cpp index b39840e..681e7c5 100644 --- a/src/FluidSTFTPass/FluidSTFTPass.cpp +++ b/src/FluidSTFTPass/FluidSTFTPass.cpp @@ -9,5 +9,5 @@ static InterfaceTable *ft; PluginLoad(FluidSTFTUGen) { ft = inTable; using namespace fluid::client; - makeSCWrapper>(ft, "FluidSTFTPass",STFTParams); + makeSCWrapper>(ft, "FluidSTFTPass"); } diff --git a/src/FluidTransients/FluidTransients.cpp b/src/FluidTransients/FluidTransients.cpp index 32a59b0..708fe64 100644 --- a/src/FluidTransients/FluidTransients.cpp +++ b/src/FluidTransients/FluidTransients.cpp @@ -3,7 +3,6 @@ #include -#include #include @@ -13,5 +12,5 @@ PluginLoad(FluidSTFTUGen) { ft = inTable; // registerUnit(ft, "FluidTransients"); using namespace fluid::client; - makeSCWrapper>(ft, "FluidTransients",TransientParams); + makeSCWrapper>(ft, "FluidTransients"); } From 5f14c163479b1830d7a4984862db43682cb7cf58 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 19 Feb 2019 17:36:46 +0000 Subject: [PATCH 24/31] Initialise a thing that needs a size to have a size, rather than no size (ControlsIterator, that is) include/FluidSCWrapper.hpp --- include/FluidSCWrapper.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index b7ef1f5..83e9a20 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -124,7 +124,9 @@ template class RealTime : public SCUnit public: static void setup(InterfaceTable *ft, const char *name) { registerUnit(ft, name); } - RealTime():mControlsIterator{nullptr,0} {} + RealTime(): mControlsIterator{mInBuf + mSpecialIndex + 1,mNumInputs - mSpecialIndex - 1} + {} + //mControlsIterator{nullptr,0} {} void init() { From 374f7fcc870b0d032127dcbd13220ff99552572c Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 19 Feb 2019 18:37:20 +0000 Subject: [PATCH 25/31] Overenthusiastic assert include/FluidSCWrapper.hpp --- include/FluidSCWrapper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 83e9a20..1e430ab 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -41,7 +41,7 @@ struct FloatControlsIter float next() { - assert(mCount + 1 < mSize); + assert(mCount < mSize); return *mValues[mCount++]; } From 657d03152338d9a62a447312a681fc16cfc70192 Mon Sep 17 00:00:00 2001 From: Gerard Date: Thu, 21 Feb 2019 14:49:01 +0000 Subject: [PATCH 26/31] update assertion --- include/FluidSCWrapper.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 83e9a20..18166e6 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -38,19 +38,19 @@ template Method> struct GetArgument struct FloatControlsIter { FloatControlsIter(float** vals, size_t N):mValues(vals), mSize(N) {} - + float next() { - assert(mCount + 1 < mSize); + assert(mCount < mSize); return *mValues[mCount++]; } - + void reset(float** vals) { mValues = vals; mCount = 0; } - + private: float** mValues; size_t mSize; @@ -75,9 +75,9 @@ template struct ArgumentGetter { auto operator()(World* w, sc_msg_iter *args) { - + long bufnum = args->geti(-1); - + return std::unique_ptr(new SCBufferAdaptor(bufnum,w)); } }; @@ -114,7 +114,7 @@ struct ControlGetter } }; -//template class RealTime : public SCUnit { @@ -201,9 +201,9 @@ public: std::cout << "FluCoMa Error " << Wrapper::getName() << ": " << result.message().c_str(); return; } - args->count = argsPosition; + args->count = argsPosition; w->setParams(false, world, args); - + size_t msgSize = args->getbsize(); char * completionMsgData = 0; if (msgSize) @@ -265,13 +265,13 @@ private: { 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 false; } - + return true; } From eb0c997b5b46702ef059c379a29a653307109950 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Sun, 3 Mar 2019 23:18:15 +0000 Subject: [PATCH 27/31] Pull in updated class stubs and help files from master --- release-packaging/Classes/FluidBufNMF.sc | 2 +- .../Classes/FluidBufNoveltySlice.sc | 2 +- .../Classes/FluidBufTransientSlice.sc | 4 +- release-packaging/Classes/FluidNMFMatch.sc | 4 +- release-packaging/Classes/FluidSTFTPass.sc | 5 +- release-packaging/Classes/FluidSines.sc | 4 +- .../Classes/FluidTransientSlice.sc | 4 +- .../HelpSource/Classes/FluidBufCompose.schelp | 2 +- .../HelpSource/Classes/FluidBufHPSS.schelp | 101 +++--- .../HelpSource/Classes/FluidBufNMF.schelp | 168 ++++++++-- .../Classes/FluidBufNoveltySlice.schelp | 41 ++- .../Classes/FluidBufTransientSlice.schelp | 9 +- .../Classes/FluidBufTransients.schelp | 5 +- .../HelpSource/Classes/FluidGain.schelp | 22 +- .../HelpSource/Classes/FluidHPSS.schelp | 31 +- .../HelpSource/Classes/FluidNMFMatch.schelp | 296 ++++++++++++++++-- .../HelpSource/Classes/FluidSTFTPass.schelp | 32 +- .../Classes/FluidTransientSlice.schelp | 10 +- 18 files changed, 585 insertions(+), 157 deletions(-) diff --git a/release-packaging/Classes/FluidBufNMF.sc b/release-packaging/Classes/FluidBufNMF.sc index d0e8b80..5f42b73 100644 --- a/release-packaging/Classes/FluidBufNMF.sc +++ b/release-packaging/Classes/FluidBufNMF.sc @@ -1,5 +1,5 @@ FluidBufNMF { - *process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, dstBufNum, dictBufNum, dictFlag = 0, actBufNum, actFlag = 0, rank = 1, nIter = 100, sortFlag = 0, winSize = 1024, hopSize = 256, fftSize = -1, winType = 0, randSeed = -1; + *process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, dstBufNum, dictBufNum, dictFlag = 0, actBufNum, actFlag = 0, rank = 1, nIter = 100, sortFlag = 0, winSize = 1024, hopSize = 512, fftSize = -1, winType = 0, randSeed = -1; if(srcBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw}; diff --git a/release-packaging/Classes/FluidBufNoveltySlice.sc b/release-packaging/Classes/FluidBufNoveltySlice.sc index 09fbb1f..9a0bb4d 100644 --- a/release-packaging/Classes/FluidBufNoveltySlice.sc +++ b/release-packaging/Classes/FluidBufNoveltySlice.sc @@ -1,5 +1,5 @@ FluidBufNoveltySlice{ - *process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, transBufNum, kernelSize = 3, thresh = 0.8, filterSize = 11, winSize = 1024, hopSize = 512, fftSize = 2048, maxWindowSize=16384; + *process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, transBufNum, kernelSize = 3, thresh = 0.8, filterSize = 0, winSize = 1024, hopSize = 512, fftSize = 2048; if(srcBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw}; if(transBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw}; diff --git a/release-packaging/Classes/FluidBufTransientSlice.sc b/release-packaging/Classes/FluidBufTransientSlice.sc index bdda702..fd8c4bb 100644 --- a/release-packaging/Classes/FluidBufTransientSlice.sc +++ b/release-packaging/Classes/FluidBufTransientSlice.sc @@ -1,11 +1,11 @@ FluidBufTransientSlice{ - *process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, transBufNum, order = 200, blockSize = 2048, padSize = 1024, skew = 0, threshFwd = 3, threshBack = 1.1, winSize = 14, debounce = 25; + *process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, transBufNum, order = 200, blockSize = 2048, padSize = 1024, skew = 0, threshFwd = 3, threshBack = 1.1, winSize = 14, debounce = 25, minSlice = 1000; if(srcBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw}; if(transBufNum.isNil) { Error("Invalid buffer").format(thisMethod.name, this.class.name).throw}; server = server ? Server.default; - server.sendMsg(\cmd, \BufTransientSlice, srcBufNum, startAt, nFrames, startChan, nChans, transBufNum, order, blockSize, padSize, skew, threshFwd, threshBack, winSize, debounce); + server.sendMsg(\cmd, \BufTransientSlice, srcBufNum, startAt, nFrames, startChan, nChans, transBufNum, order, blockSize, padSize, skew, threshFwd, threshBack, winSize, debounce, minSlice); } } diff --git a/release-packaging/Classes/FluidNMFMatch.sc b/release-packaging/Classes/FluidNMFMatch.sc index 8c257e3..6fffd9e 100644 --- a/release-packaging/Classes/FluidNMFMatch.sc +++ b/release-packaging/Classes/FluidNMFMatch.sc @@ -1,7 +1,7 @@ FluidNMFMatch : MultiOutUGen { - *kr { arg in = 0, dictBufNum, rank = 1, nIter = 10, winSize = 1024, hopSize = 256, fftSize = -1; - ^this.multiNew('control', in, dictBufNum, rank, nIter, winSize, hopSize, fftSize,16384); + *kr { arg in = 0, dictBufNum, maxRank = 1, nIter = 10, winSize = 1024, hopSize = 512, fftSize = -1; + ^this.multiNew('control', in, dictBufNum, maxRank, nIter, winSize, hopSize, fftSize); } init {arg ...theInputs; diff --git a/release-packaging/Classes/FluidSTFTPass.sc b/release-packaging/Classes/FluidSTFTPass.sc index 5171e63..6b86f5e 100644 --- a/release-packaging/Classes/FluidSTFTPass.sc +++ b/release-packaging/Classes/FluidSTFTPass.sc @@ -1,6 +1,5 @@ FluidSTFTPass : UGen { - *ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1, maxWinSize= 16384; - ^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize, maxWinSize) + *ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1; + ^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize) } } -// \ No newline at end of file diff --git a/release-packaging/Classes/FluidSines.sc b/release-packaging/Classes/FluidSines.sc index d44a7fa..f2c377b 100644 --- a/release-packaging/Classes/FluidSines.sc +++ b/release-packaging/Classes/FluidSines.sc @@ -1,13 +1,13 @@ FluidSines : MultiOutUGen { *ar { arg in = 0, bandwidth = 76, thresh = 0.7, minTrackLen = 15, magWeight = 0.1, freqWeight = 1.0, winSize= 2048, hopSize= 512, fftSize= 8192; - ^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, thresh, minTrackLen, magWeight,freqWeight ,winSize, hopSize, fftSize,16384) + ^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, thresh, minTrackLen, magWeight,freqWeight ,winSize, hopSize, fftSize) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate, this, 0), OutputProxy(rate, this, 1) - ] + ]; ^channels } checkInputs { ^this.checkNInputs(1) } diff --git a/release-packaging/Classes/FluidTransientSlice.sc b/release-packaging/Classes/FluidTransientSlice.sc index 5ef269a..00ae369 100644 --- a/release-packaging/Classes/FluidTransientSlice.sc +++ b/release-packaging/Classes/FluidTransientSlice.sc @@ -1,5 +1,5 @@ FluidTransientSlice : UGen { - *ar { arg in = 0, order = 20, blockSize = 256, padSize = 128, skew = 0.0, threshFwd = 3.0, threshBack = 1.1, winSize=14, debounce=25; - ^this.multiNew('audio', in.asAudioRateInput(this), order, blockSize, padSize, skew, threshFwd ,threshBack, winSize, debounce) + *ar { arg in = 0, order = 20, blockSize = 256, padSize = 128, skew = 0.0, threshFwd = 3.0, threshBack = 1.1, winSize=14, debounce=25, minSlice = 1000; + ^this.multiNew('audio', in.asAudioRateInput(this), order, blockSize, padSize, skew, threshFwd ,threshBack, winSize, debounce, minSlice) } } \ No newline at end of file diff --git a/release-packaging/HelpSource/Classes/FluidBufCompose.schelp b/release-packaging/HelpSource/Classes/FluidBufCompose.schelp index 43e9b31..01c6493 100644 --- a/release-packaging/HelpSource/Classes/FluidBufCompose.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufCompose.schelp @@ -183,4 +183,4 @@ f.play; // compare with the original b.play; - :: \ No newline at end of file +:: diff --git a/release-packaging/HelpSource/Classes/FluidBufHPSS.schelp b/release-packaging/HelpSource/Classes/FluidBufHPSS.schelp index dae40e5..57e9398 100644 --- a/release-packaging/HelpSource/Classes/FluidBufHPSS.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufHPSS.schelp @@ -115,55 +115,54 @@ Discussion:: EXAMPLES:: code:: - //load buffers - ( - b = Buffer.read(s,File.realpath(FluidBufHPSS.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav"); - c = Buffer.new(s); - d = Buffer.new(s); - e = Buffer.new(s); - ) - - // run with basic parameters - ( - Routine{ - t = Main.elapsedTime; - FluidBufHPSS.process(s, b.bufnum, harmBufNum: c.bufnum, percBufNum: d.bufnum); +//load buffers +( + b = Buffer.read(s,File.realpath(FluidBufHPSS.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav"); + c = Buffer.new(s); + d = Buffer.new(s); + e = Buffer.new(s); +) + +// run with basic parameters +( + Routine{ + t = Main.elapsedTime; + FluidBufHPSS.process(s, b.bufnum, harmBufNum: c.bufnum, percBufNum: d.bufnum); + s.sync; + (Main.elapsedTime - t).postln; + }.play +) + +//query and play the harmonic +c.query; +c.play; +//querry and play the percussive +d.query; +d.play; + +//nullsumming tests +{(PlayBuf.ar(1,c.bufnum))+(PlayBuf.ar(1,d.bufnum))+(-1*PlayBuf.ar(1,b.bufnum,doneAction:2))}.play + +//more daring parameters, in mode 2 +( + Routine{ + t = Main.elapsedTime; + FluidBufHPSS.process(s, b.bufnum, harmBufNum: c.bufnum, percBufNum: d.bufnum, resBufNum:e.bufnum, harmFiltSize:31, modeFlag:2, htf1: 0.005, hta1: 7.5, htf2: 0.168, hta2: 7.5, ptf1: 0.004, pta1: 26.5, ptf2: 0.152, pta2: 26.5); s.sync; - (Main.elapsedTime - t).postln; - }.play - ) - - //query and play the harmonic - c.query; - c.play; - //querry and play the percussive - d.query; - d.play; - - //nullsumming tests - {(PlayBuf.ar(1,c.bufnum))+(PlayBuf.ar(1,d.bufnum))+(-1*PlayBuf.ar(1,b.bufnum,doneAction:2))}.play - - //more daring parameters, in mode 2 - ( - Routine{ - t = Main.elapsedTime; - FluidBufHPSS.process(s, b.bufnum, harmBufNum: c.bufnum, percBufNum: d.bufnum, resBufNum:e.bufnum, harmFiltSize:31, modeFlag:2, htf1: 0.005, hta1: 7.5, htf2: 0.168, hta2: 7.5, ptf1: 0.004, pta1: 26.5, ptf2: 0.152, pta2: 26.5); - s.sync; - (Main.elapsedTime - t).postln; - }.play - ) - - //query and play the harmonic - c.query; - c.play; - //query and play the percussive - d.query; - d.play; - //query and play the residual - e.query; - e.play; - - //still nullsumming - {PlayBuf.ar(1,c.bufnum) + PlayBuf.ar(1,d.bufnum) + PlayBuf.ar(1,e.bufnum) - PlayBuf.ar(1,b.bufnum,doneAction:2)}.play; - :: - \ No newline at end of file + (Main.elapsedTime - t).postln; + }.play +) + +//query and play the harmonic +c.query; +c.play; +//query and play the percussive +d.query; +d.play; +//query and play the residual +e.query; +e.play; + +//still nullsumming +{PlayBuf.ar(1,c.bufnum) + PlayBuf.ar(1,d.bufnum) + PlayBuf.ar(1,e.bufnum) - PlayBuf.ar(1,b.bufnum,doneAction:2)}.play; +:: diff --git a/release-packaging/HelpSource/Classes/FluidBufNMF.schelp b/release-packaging/HelpSource/Classes/FluidBufNMF.schelp index 36d3dc0..5c61110 100644 --- a/release-packaging/HelpSource/Classes/FluidBufNMF.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufNMF.schelp @@ -31,10 +31,7 @@ The whole process can be related to a channel vocoder where, instead of fixed ba More information on possible musicianly uses of NMF are availabe in LINK::Guides/FluCoMa:: overview file. FluidBufNMF is part of the Fluid Decomposition Toolkit of the FluCoMa project. footnote:: -This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899). -:: - - +This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899). :: CLASSMETHODS:: @@ -113,6 +110,58 @@ RETURNS:: EXAMPLES:: +STRONG::A didactic example:: +CODE:: +( +// create buffers +b = Buffer.alloc(s,44100); +c = Buffer.alloc(s, 44100); +d = Buffer.new(s); +e = Buffer.new(s); +f = Buffer.new(s); +g = Buffer.new(s); +) + +( +// fill them with 2 clearly segregated sine waves and composite a buffer where they are consecutive +Routine { + b.sine2([500],[1], false, false); + c.sine2([5000],[1],false, false); + s.sync; + FluidBufCompose.process(s,srcBufNumA:b.bufnum, srcBufNumB:c.bufnum,dstStartAtB:44100,dstBufNum:d.bufnum); + s.sync; + d.query; +}.play; +) + +// check +d.plot +d.play //////(beware !!!! loud!!!) + +( +// separate them in 2 ranks +Routine { + FluidBufNMF.process(s, d.bufnum, dstBufNum:e.bufnum, dictBufNum: f.bufnum, actBufNum:g.bufnum, rank:2); + s.sync; + e.query; + f.query; + g.query; +}.play +) + +// look at the resynthesised separated signal +e.plot; + +// look at the dictionaries signal for 2 spikes +f.plot; + +// look at the activations +g.plot; + +//trying running the same process on superimposed sinewaves instead of consecutive in the source and see how it fails. +:: + +STRONG::Basic musical examples:: code:: // set some buffers and parameters @@ -186,11 +235,11 @@ c.plot;x.plot; y.plot; ) :: - STRONG::Fixed Dictionnaries:: The process can be trained, and the learnt dictionaries or activations can be used as templates. +STRONG::Fixed Dictionnaries:: The process can be trained, and the learnt dictionaries or activations can be used as templates. - CODE:: +CODE:: - //set some buffers +//set some buffers ( b = Buffer.read(s,File.realpath(FluidBufNMF.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav"); c = Buffer.new(s); @@ -199,7 +248,7 @@ e = Buffer.alloc(s,1,1); y = Buffer.alloc(s,1,1); ) - // train only 2 seconds +// train only 2 seconds ( Routine { FluidBufNMF.process(s,b.bufnum,0,88200,0,1, c.bufnum, x.bufnum, rank:10); @@ -210,27 +259,28 @@ Routine { // find the rank that has the picking sound by changing which channel to listen to ( - ~element = 0; + ~element = 9; {PlayBuf.ar(10,c.bufnum)[~element]}.play ) // copy all the other ranks on itself and the picking dictionnary as the sole component of the 1st channel ( Routine{ - (0..9).remove(~element).do({|chan|FluidBufCompose.process(s,srcBufNumA: x.bufnum, startChanA:chan, nChansA: 1, srcBufNumB: e.bufnum, dstBufNum: e.bufnum)}); - s.sync; - e.query; - s.sync; - FluidBufCompose.process(s,srcBufNumA: x.bufnum, startChanA: ~element, nChansA: 1, srcBufNumB: e.bufnum, dstStartChanB: 1, dstBufNum: e.bufnum); - s.sync; - e.query; + z = (0..9); + FluidBufCompose.process(s,srcBufNumA: x.bufnum, startChanA: z.removeAt(~element), nChansA: 1, srcBufNumB: e.bufnum, dstBufNum: e.bufnum); + s.sync; + e.query; + s.sync; + z.do({|chan|FluidBufCompose.process(s,srcBufNumA: x.bufnum, startChanA:chan, nChansA: 1, dstStartChanA: 1, srcBufNumB: e.bufnum, dstBufNum: e.bufnum)}); + s.sync; + e.query; }.play; ) //process the whole file, splitting it with the 2 trained dictionnaries ( Routine{ - FluidBufNMF.process(s, b.bufnum, dstBufNum: c.bufnum, dictBufNum: e.bufnum, dictFlag: 2, actBufNum:y.bufnum, rank:2); + FluidBufNMF.process(s, b.bufnum, dstBufNum: c.bufnum, dictBufNum: e.bufnum, dictFlag: 2, actBufNum: y.bufnum, rank:2); s.sync; c.query; }.play; @@ -242,4 +292,86 @@ c.play // it even null-sums {(PlayBuf.ar(2,c.bufnum,doneAction:2).sum)-(PlayBuf.ar(1,b.bufnum,doneAction:2))}.play :: - \ No newline at end of file + +STRONG::Updating Dictionnaries:: The process can update dictionaries provided as seed. + +CODE:: +( +// create buffers +b = Buffer.alloc(s,44100); +c = Buffer.alloc(s, 44100); +d = Buffer.new(s); +e = Buffer.alloc(s,513,3); +f = Buffer.new(s); +g = Buffer.new(s); +) + +( +// fill them with 2 clearly segregated sine waves and composite a buffer where they are consecutive +Routine { + b.sine2([500],[1], false, false); + c.sine2([5000],[1],false, false); + s.sync; + FluidBufCompose.process(s,srcBufNumA:b.bufnum, srcBufNumB:c.bufnum,dstStartAtB:44100,dstBufNum:d.bufnum); + s.sync; + d.query; +}.play; +) + +// check +d.plot +d.play //////(beware !!!! loud!!!) + +( +//make a seeding dictionary of 3 ranks: +var highpass, lowpass, direct; +highpass = Array.fill(513,{|i| (i < 50).asInteger}); +lowpass = 1 - highpass; +direct = Array.fill(513,0.1); +e.setn(0,[highpass, lowpass, direct].flop.flat); +) + +//check the dictionary: a steep lowpass, a steep highpass, and a small DC +e.plot +e.query + +( +// use the seeding dictionary, without updating +Routine { + FluidBufNMF.process(s, d.bufnum, dstBufNum:f.bufnum, dictBufNum: e.bufnum, dictFlag: 2, actBufNum:g.bufnum, rank:3); + s.sync; + e.query; + f.query; + g.query; +}.play +) + +// look at the resynthesised separated signal +f.plot; + +// look at the dictionaries that have not changed +e.plot; + +// look at the activations +g.plot; + +( +// use the seeding dictionary, with updating this time +Routine { + FluidBufNMF.process(s, d.bufnum, dstBufNum:f.bufnum, dictBufNum: e.bufnum, dictFlag: 1, actBufNum:g.bufnum, rank:3); + s.sync; + e.query; + f.query; + g.query; +}.play +) + +// look at the resynthesised separated signal +f.plot; + +// look at the dictionaries that have now updated in place (with the 3rd channel being more focused +e.plot; + +// look at the activations (sharper 3rd rank at transitions) +g.plot; +:: \ No newline at end of file diff --git a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp index 777b609..c7a4dde 100644 --- a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp @@ -40,7 +40,10 @@ ARGUMENT:: kernelSize The granularity of the window in which the algorithm looks for change, in samples. A small number will be sensitive to short term changes, and a large number should look for long term changes. ARGUMENT:: thresh - The normalised threshold, between 0 an 1, to consider a peak as a sinusoidal component from the in the novelty curve. + The normalised threshold, between 0 an 1, on the novelty curve to consider it a segmentation point. + +ARGUMENT:: filterSize + The size of a smoothing filter that is applied on the novelty curve. A larger filter filter size allows for cleaner cuts on very sharp changes. ARGUMENT:: winSize The window size. As novelty estimation relies on spectral frames, we need to decide what precision we give it spectrally and temporally, in line with Gabor Uncertainty principles. http://www.subsurfwiki.org/wiki/Gabor_uncertainty @@ -91,3 +94,39 @@ c.query; }.play; ) :: + +STRONG::Examples of the impact of the filterSize:: + + CODE:: +// load some buffers +( +b = Buffer.read(s,File.realpath(FluidBufNoveltySlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav"); +c = Buffer.new(s); +) + +// process with a given filterSize +FluidBufNoveltySlice.process(s,b.bufnum, transBufNum: c.bufnum, kernelSize:31, thresh:0.35, filterSize:0) + +//check the number of slices: it is the number of frames in the transBuf minus the boundary index. +c.query; + +//play slice number 2 +( +{ + BufRd.ar(1, b.bufnum, + Line.ar( + BufRd.kr(1, c.bufnum, DC.kr(2), 0, 1), + BufRd.kr(1, c.bufnum, DC.kr(3), 0, 1), + (BufRd.kr(1, c.bufnum, DC.kr(3)) - BufRd.kr(1, c.bufnum, DC.kr(2), 0, 1) + 1) / s.sampleRate), + 0,1); +}.play; +) + +// change the filterSize in the code above to 4. Then to 8. Listen in between to the differences. + +// What's happening? In the first instance (filterSize = 0), the novelty line is jittery and therefore overtriggers on the arpegiated guitar. We also can hear attacks at the end of the segment. Setting the threshold higher (like in the 'Basic Example' pane) misses some more subtle variations. + +// So in the second settings (filterSize = 4), we smooth the novelty line a little, which allows us to catch small differences that are not jittery. It also corrects the ending cutting by the same trick: the averaging of the sharp pick is sliding up, crossing the threshold slightly earlier. + +// If we smooth too much, like the third settings (filterSize = 8), we start to loose precision. Have fun with different values of theshold then will allow you to find the perfect segment for your signal. +:: \ No newline at end of file diff --git a/release-packaging/HelpSource/Classes/FluidBufTransientSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufTransientSlice.schelp index d693f36..16af951 100644 --- a/release-packaging/HelpSource/Classes/FluidBufTransientSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufTransientSlice.schelp @@ -58,7 +58,10 @@ ARGUMENT:: winSize The averaging window of the error detection function. It needs smoothing as it is very jittery. The longer the window, the less precise, but the less false positives. ARGUMENT:: debounce - The window size in sample within which positive detections will be clumped together to avoid overdetecting in time. No slice will be shorter than this duration. + The window size in sample within which positive detections will be clumped together to avoid overdetecting in time. + +ARGUMENT:: minSlice + The minimum duration of a slice in samples. RETURNS:: Nothing, as the destination buffer is declared in the function call. @@ -77,7 +80,7 @@ c = Buffer.new(s); ( Routine{ t = Main.elapsedTime; - FluidBufTransientSlice.process(s,b.bufnum, transBufNum:c.bufnum, order:80, debounce:4410); + FluidBufTransientSlice.process(s,b.bufnum, transBufNum:c.bufnum, order:80, minSlice:4410); s.sync; (Main.elapsedTime - t).postln; }.play @@ -105,7 +108,7 @@ c.query; ( Routine{ t = Main.elapsedTime; - FluidBufTransients.process(s,b.bufnum, 44100, 44100, 0, 0, c.bufnum, d.bufnum, 100, 512,256,1,2,1,12,20); + FluidBufTransients.process(s,b.bufnum, 44100, 44100, 0, 0, c.bufnum, d.bufnum, 100, 512,256,1,2,1,12,20,441); s.sync; (Main.elapsedTime - t).postln; }.play diff --git a/release-packaging/HelpSource/Classes/FluidBufTransients.schelp b/release-packaging/HelpSource/Classes/FluidBufTransients.schelp index 812e9a6..1e5b3dd 100644 --- a/release-packaging/HelpSource/Classes/FluidBufTransients.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufTransients.schelp @@ -109,7 +109,4 @@ Routine{ (Main.elapsedTime - t).postln; }.play ) - :: - - - \ No newline at end of file +:: diff --git a/release-packaging/HelpSource/Classes/FluidGain.schelp b/release-packaging/HelpSource/Classes/FluidGain.schelp index eb54159..b039a81 100644 --- a/release-packaging/HelpSource/Classes/FluidGain.schelp +++ b/release-packaging/HelpSource/Classes/FluidGain.schelp @@ -28,14 +28,14 @@ RETURNS:: EXAMPLES:: Summing with the inverse (gain of -1) with a delay of the latency gives us CPU-expensive silence. - CODE:: - { var source = PinkNoise.ar(0.1); DelayN.ar(source,delaytime:1000/s.sampleRate) + FluidGain.ar(source,1000,-1); }.play - :: - Varying the gain at audio rate. - CODE:: - { FluidGain.ar(PinkNoise.ar(0.1), gain:LFTri.ar(1)) }.play - :: - Varying the gain at comtrol rate, in beautiful stereo. - CODE:: - { FluidGain.ar(SinOsc.ar([222,333],mul:0.1), gain:LFTri.kr([0.5,0.7])) }.play - :: +CODE:: +{ var source = PinkNoise.ar(0.1); DelayN.ar(source,delaytime:1000/s.sampleRate) + FluidGain.ar(source,1000,-1); }.play +:: +Varying the gain at audio rate. +CODE:: +{ FluidGain.ar(PinkNoise.ar(0.1), gain:LFTri.ar(1)) }.play +:: +Varying the gain at comtrol rate, in beautiful stereo. +CODE:: +{ FluidGain.ar(SinOsc.ar([222,333],mul:0.1), gain:LFTri.kr([0.5,0.7])) }.play +:: diff --git a/release-packaging/HelpSource/Classes/FluidHPSS.schelp b/release-packaging/HelpSource/Classes/FluidHPSS.schelp index deff4aa..418cbd4 100644 --- a/release-packaging/HelpSource/Classes/FluidHPSS.schelp +++ b/release-packaging/HelpSource/Classes/FluidHPSS.schelp @@ -89,24 +89,23 @@ Discussion:: EXAMPLES:: CODE:: - //load a soundfile to play - b = Buffer.read(s,File.realpath(FluidHPSS.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav"); +//load a soundfile to play +b = Buffer.read(s,File.realpath(FluidHPSS.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav"); - // run with basic parameters (left is harmonic, right is percussive) - {FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1))}.play +// run with basic parameters (left is harmonic, right is percussive) +{FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1))}.play - // run in mode 1 - {FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1),17,31,1,0.05,40,0.1,-40)}.play +// run in mode 1 +{FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1),17,31,1,0.05,40,0.1,-40)}.play - // run in mode 2m listening to - //the harmonic stream - {FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1),17,31,2,0.05,40,0.1,-40, 0.1, -10, 0.2, 10)[0].dup}.play - // the percussive stream - {FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1),17,31,2,0.05,40,0.1,-40, 0.1, -10, 0.2, 10)[1].dup}.play - // the residual stream - {FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1),17,31,2,0.05,40,0.1,-40, 0.1, -10, 0.2, 10)[2].dup}.play +// run in mode 2m listening to +//the harmonic stream +{FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1),17,31,2,0.05,40,0.1,-40, 0.1, -10, 0.2, 10)[0].dup}.play +// the percussive stream +{FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1),17,31,2,0.05,40,0.1,-40, 0.1, -10, 0.2, 10)[1].dup}.play +// the residual stream +{FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1),17,31,2,0.05,40,0.1,-40, 0.1, -10, 0.2, 10)[2].dup}.play - // null test (the process add a latency of ((harmFiltSize + (winSize / hopSize) - 1) * hopSize) samples - {var sig = PlayBuf.ar(1,b.bufnum,loop:1); [FluidHPSS.ar(sig,17,31, winSize:1024,hopSize:512,fftSize:2048).sum - DelayN.ar(sig, 1, ((31 + 1) * 512 / s.sampleRate))]}.play +// null test (the process add a latency of ((harmFiltSize + (winSize / hopSize) - 1) * hopSize) samples +{var sig = PlayBuf.ar(1,b.bufnum,loop:1); [FluidHPSS.ar(sig,17,31, winSize:1024,hopSize:512,fftSize:2048).sum - DelayN.ar(sig, 1, ((31 + 1) * 512 / s.sampleRate))]}.play :: - \ No newline at end of file diff --git a/release-packaging/HelpSource/Classes/FluidNMFMatch.schelp b/release-packaging/HelpSource/Classes/FluidNMFMatch.schelp index a08e9cc..df68113 100644 --- a/release-packaging/HelpSource/Classes/FluidNMFMatch.schelp +++ b/release-packaging/HelpSource/Classes/FluidNMFMatch.schelp @@ -1,55 +1,313 @@ TITLE:: FluidNMFMatch -SUMMARY:: Real-Time Non-Negative Matrix Factorisation on Buffered Dictionaries +SUMMARY:: Real-Time Non-Negative Matrix Factorisation with Fixed Dictionaries CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Classes/FluidBufNMF DESCRIPTION:: -The FluidBufNMF object provides the activation (linked to amplitude) for each pre-defined dictionaries (similar to spectra) predefined in a buffer. These dictionaries would have usually be computed through an offline Non-Negative Matrix Factorisation (NMF) footnote:: Lee, Daniel D., and H. Sebastian Seung. 1999. ‘Learning the Parts of Objects by Non-Negative Matrix Factorization’. Nature 401 (6755): 788–91. https://doi.org/10.1038/44565 :: with the link::Classes/FluidBufNMF:: UGen. NMF has been a popular technique in signal processing research for things like source separation and transcription footnote:: Smaragdis and Brown, Non-Negative Matrix Factorization for Polyphonic Music Transcription.::, although its creative potential is so far relatively unexplored. +The FluidNMFMatch object matches an incoming audio signal against a set of spectral templates using an slimmed-down version of Nonnegative Matrix Factorisation (NMF) footnote:: Lee, Daniel D., and H. Sebastian Seung. 1999. ‘Learning the Parts of Objects by Non-Negative Matrix Factorization’. Nature 401 (6755): 788–91. https://doi.org/10.1038/44565. :: -The algorithm takes a buffer in which provides a spectral definition of a number of components, determined by the rank argument and the dictionary buffer channel count. It works iteratively, by trying to find a combination of amplitudes ('activations') that yield the original magnitude spectrogram of the audio input when added together. By and large, there is no unique answer to this question (i.e. there are different ways of accounting for an evolving spectrum in terms of some set of templates and envelopes). In its basic form, NMF is a form of unsupervised learning: it starts with some random data and then converges towards something that minimizes the distance between its generated data and the original:it tends to converge very quickly at first and then level out. Fewer iterations mean less processing, but also less predictable results. +It outputs at kr the degree of detected match for each template (the activation amount, in NMF-terms). The spectral templates are presumed to have been produced by the offline NMF process (link::Classes/FluidBufNMF::), and must be the correct size with respect to the FFT settings being used (FFT size / 2 + 1 frames long). The rank of the decomposition is determined by the number of channels in the supplied buffer of templates, up to a maximum set by the STRONG::maxRank:: parameter. + +NMF has been a popular technique in signal processing research for things like source separation and transcription footnote:: Smaragdis and Brown, Non-Negative Matrix Factorization for Polyphonic Music Transcription.::, although its creative potential is so far relatively unexplored. It works iteratively, by trying to find a combination of amplitudes ('activations') that yield the original magnitude spectrogram of the audio input when added together. By and large, there is no unique answer to this question (i.e. there are different ways of accounting for an evolving spectrum in terms of some set of templates and envelopes). In its basic form, NMF is a form of unsupervised learning: it starts with some random data and then converges towards something that minimizes the distance between its generated data and the original:it tends to converge very quickly at first and then level out. Fewer iterations mean less processing, but also less predictable results. The whole process can be related to a channel vocoder where, instead of fixed bandpass filters, we get more complex filter shapes and the activations correspond to channel envelopes. More information on possible musicianly uses of NMF are availabe in LINK::Guides/FluCoMa:: overview file. -FluidBufNMF is part of the Fluid Decomposition Toolkit of the FluCoMa project. footnote:: -This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899). -:: +FluidBufNMF is part of the Fluid Decomposition Toolkit of the FluCoMa project. footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899). :: CLASSMETHODS:: METHOD:: kr -The real-time processing method. It takes an audio or control input, and will yield a control stream in the form of a multichannel array of size STRONG::rank::. +The real-time processing method. It takes an audio or control input, and will yield a control stream in the form of a multichannel array of size STRONG::maxRank:: . If the dictionary buffer has fewer than maxRank channels, the remaining outputs will be zeroed. ARGUMENT:: in -The input to the factorisation process. +The signal input to the factorisation process. ARGUMENT:: dictBufNum - The index of the buffer where the different dictionaries will be matched against. Dictionaries must be STRONG::(fft size / 2) + 1:: frames and STRONG::rank:: channels + The server index of the buffer containing the different dictionaries that the input signal will be matched against. Dictionaries must be STRONG::(fft size / 2) + 1:: frames. If the buffer has more than STRONG::maxRank:: channels, the excess will be ignored. -ARGUMENT:: rank - The number of elements the NMF algorithm will try to divide the spectrogram of the source in. This should match the number of channels of the dictBuf defined above. +ARGUMENT::maxRank + The maximum number of elements the NMF algorithm will try to divide the spectrogram of the source in. This dictates the number of output channelsfor the ugen. ARGUMENT:: nIter - The NMF process is iterative, trying to converge to the smallest error in its factorisation. The number of iterations will decide how many times it tries to adjust its estimates. Higher numbers here will be more CPU expensive, lower numbers will be more unpredictable in quality. + The NMF process is iterative, trying to converge to the smallest error in its factorisation. The number of iterations will decide how many times it tries to adjust its estimates. Higher numbers here will be more CPU intensive, lower numbers will be more unpredictable in quality. ARGUMENT:: winSize - The window size. As NMF relies on spectral frames, we need to decide what precision we give it spectrally and temporally, in line with Gabor Uncertainty principles. http://www.subsurfwiki.org/wiki/Gabor_uncertainty + The number of samples that are analysed at a time. A lower number yields greater temporal resolution, at the expense of spectral resoultion, and vice-versa. ARGUMENT:: hopSize - The window hope size. As NMF relies on spectral frames, we need to move the window forward. It can be any size but low overlap will create audible artefacts. + The window hope size. As NMF relies on spectral frames, we need to move the window forward. It can be any size but low overlap will create audible artefacts. Default = winSize / 2 ARGUMENT:: fftSize - The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. + The FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. Default = winSize -returns:: - A multichannel array, giving for each dictionary the activation value. +RETURNS:: + A multichannel kr output, giving for each dictionary component the activation amount. EXAMPLES:: -yes +STRONG::A didactic example:: + CODE:: +( +// create buffers +b= Buffer.alloc(s,44100); +c = Buffer.alloc(s, 44100); +d = Buffer.new(s); +e= Buffer.new(s); +) + +( +// fill them with 2 clearly segregated sine waves and composite a buffer where they are consecutive +Routine { + b.sine2([500],[1], false, false); + c.sine2([5000],[1],false, false); + s.sync; + FluidBufCompose.process(s,srcBufNumA:b.bufnum, srcBufNumB:c.bufnum,dstStartAtB:44100,dstBufNum:d.bufnum); + s.sync; + d.query; +}.play; +) + +// check +d.plot +d.play //////(beware !!!! loud!!!) + +( +// separate them in 2 ranks +Routine { + FluidBufNMF.process(s, d.bufnum, dictBufNum: e.bufnum, rank:2); + s.sync; + e.query; +}.play +) + +// check for 2 spikes in the spectra +e.query +e.plot + +// test the activations values with test one, another, or both ideal material +{FluidNMFMatch.kr(SinOsc.ar(500),e.bufnum,2, hopSize:512)}.plot(1) + +{FluidNMFMatch.kr(SinOsc.ar(5000),e.bufnum,2, hopSize:512)}.plot(1) + +{FluidNMFMatch.kr(SinOsc.ar([500,5000]).sum,e.bufnum,2, hopSize:512)}.plot(1) +:: + +STRONG::A pick compressor:: + CODE:: +//set some buffers +( +b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav"); +c = Buffer.new(s); +x = Buffer.new(s); +e = Buffer.alloc(s,1,1); +) + +// train only 2 seconds +( +Routine { + FluidBufNMF.process(s,b.bufnum,0,88200,0,1, c.bufnum, x.bufnum, rank:10,fftSize:2048); + s.sync; + c.query; +}.play; +) + +// wait for the query to print +// then find the rank that has the picking sound by changing which channel to listen to +( + ~element = 8; + {PlayBuf.ar(10,c.bufnum)[~element]}.play +) + +// copy all the other ranks on itself and the picking dictionnary as the sole component of the 1st channel +( +Routine{ + z = (0..9); + FluidBufCompose.process(s,srcBufNumA: x.bufnum, startChanA: z.removeAt(~element), nChansA: 1, srcBufNumB: e.bufnum, dstBufNum: e.bufnum); + s.sync; + e.query; + s.sync; + z.do({|chan|FluidBufCompose.process(s,srcBufNumA: x.bufnum, startChanA:chan, nChansA: 1, dstStartChanA: 1, srcBufNumB: e.bufnum, dstBufNum: e.bufnum)}); + s.sync; + e.query; +}.play; +) +e.plot; + +//using this trained dictionary we can see the envelop (activations) of each rank +{FluidNMFMatch.kr(PlayBuf.ar(1,b.bufnum),e.bufnum,2,fftSize:2048)}.plot(1); +// the left/top activations are before, the pick before the sustain. + +//we can then use the activation value to sidechain a compression patch that is sent in a delay +( +{ + var source, todelay, delay1, delay2, delay3, feedback, mod1, mod2, mod3, mod4; + //read the source + source = PlayBuf.ar(1, b.bufnum); + + // generate modulators that are coprime in frequency + mod1 = SinOsc.ar(1, 0, 0.001); + mod2 = SinOsc.ar(((617 * 181) / (461 * 991)), 0, 0.001); + mod3 = SinOsc.ar(((607 * 193) / (491 * 701)), 0, 0.001); + mod4 = SinOsc.ar(((613 * 191) / (463 * 601)), 0, 0.001); + + // compress the signal to send to the delays + todelay = DelayN.ar(source,0.1, 800/44100, //delaying it to compensate for FluidNMFMatch's latency + LagUD.ar(K2A.ar(FluidNMFMatch.kr(source,e.bufnum,2,fftSize:2048)[0]), //reading the channel of the activations on the pick dictionary + 80/44100, // lag uptime (compressor's attack) + 1000/44100, // lag downtime (compressor's decay) + (1/(2.dbamp) // compressor's threshold inverted + )).clip(1,1000).pow((8.reciprocal)-1)); //clipping it so we only affect above threshold, then ratio(8) becomes the exponent of that base + + // delay network + feedback = LocalIn.ar(3);// take the feedback in for the delays + delay1 = DelayC.ar(BPF.ar(todelay+feedback[1]+(feedback[2] * 0.3), 987, 6.7,0.8),0.123,0.122+(mod1*mod2)); + delay2 = DelayC.ar(BPF.ar(todelay+feedback[0]+(feedback[2] * 0.3), 1987, 6.7,0.8),0.345,0.344+(mod3*mod4)); + delay3 = DelayC.ar(BPF.ar(todelay+feedback[1], 1456, 6.7,0.8),0.567,0.566+(mod1*mod3),0.6); + LocalOut.ar([delay1,delay2, delay3]); // write the feedback for the delays + + //listen to the delays only by uncommenting the following line + // [delay1+delay3,delay2+delay3] + source.dup + ([delay1+delay3,delay2+delay3]*(-3.dbamp)) +}.play; +) + +:: +STRONG::Object finder:: + CODE:: +/set some buffers +( +b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-BaB-SoundscapeGolcarWithDog.wav"); +c = Buffer.new(s); +x = Buffer.new(s); +e = Buffer.alloc(s,1,1); +) + +// train where all objects are present +( +Routine { + FluidBufNMF.process(s,b.bufnum,130000,150000,0,1, c.bufnum, x.bufnum, rank:10); + s.sync; + c.query; +}.play; +) + +// wait for the query to print +// then find a rank for each item you want to find. You could also sum them. Try to find a rank with a good object-to-rest ratio +( + ~dog =0; + {PlayBuf.ar(10,c.bufnum)[~dog]}.play +) + +( + ~bird = 5; + {PlayBuf.ar(10,c.bufnum)[~bird]}.play +) + + +// copy at least one other rank to a third rank, a sort of left-over channel +( +Routine{ + FluidBufCompose.process(s,srcBufNumA: x.bufnum, startChanA:~dog, nChansA: 1, srcBufNumB: e.bufnum, dstBufNum: e.bufnum); + FluidBufCompose.process(s,srcBufNumA: x.bufnum, startChanA:~bird, nChansA: 1, dstStartChanA: 1, srcBufNumB: e.bufnum, dstBufNum: e.bufnum); + s.sync; + (0..9).removeAll([~dog,~bird]).do({|chan|FluidBufCompose.process(s,srcBufNumA: x.bufnum, startChanA:chan, nChansA: 1, dstStartChanA: 2, srcBufNumB: e.bufnum, dstBufNum: e.bufnum)}); + s.sync; + e.query; +}.play; +) +e.plot; + +//using this trained dictionary we can then see the activation... +( +{ + var source, blips; + //read the source + source = PlayBuf.ar(2, b.bufnum); + blips = FluidNMFMatch.kr(source.sum,e.bufnum,3); + }.plot(10); +) + +// ...and use some threshold to 'find' objects... +( +{ + var source, blips; + //read the source + source = PlayBuf.ar(2, b.bufnum); + blips = Schmidt.kr(FluidNMFMatch.kr(source.sum,e.bufnum,3),0.5,[10,1,1000]); + }.plot(10); +) + +// ...and use these to sonify them +( +{ + var source, blips, dogs, birds; + //read the source + source = PlayBuf.ar(2, b.bufnum); + blips = Schmidt.kr(FluidNMFMatch.kr(source.sum,e.bufnum,3),0.5,[10,1,1000]); + dogs = SinOsc.ar(100,0,Lag.kr(blips[0],0.05,0.15)); + birds = SinOsc.ar(1000,0,Lag.kr(blips[1],0.05,0.05)); + [dogs, birds] + source; + }.play; +) +:: + STRONG::Pretrained piano:: + CODE:: +//load in the sound in and a pretrained dictionary +( + b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav"); + c = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/filters/piano-dicts.wav"); +) +b.play +c.query + +//use the pretrained dictionary to compute activations of each notes to drive the amplitude of a resynth +( +{ + var source, resynth; + source = PlayBuf.ar(2, b.bufnum,loop:1).sum; + resynth = SinOsc.ar((21..108).midicps, 0, FluidNMFMatch.kr(source,c.bufnum,88,10,4096).madd(0.002)).sum; + [source, resynth] +}.play +) + + +//now sample and hold the same stream to get notes identified, played and sent back via osc +( +{ + var source, resynth, chain, trig, acts; + source = PlayBuf.ar(2,b.bufnum,loop:1).sum; + + // built in attack detection, delayed until the stable part of the sound + chain = FFT(LocalBuf(256), source); + trig = TDelay.kr(Onsets.kr(chain, 0.5),0.1); + + // samples and holds activation values that are scaled and capped, in effect thresholding them + acts = Latch.kr(FluidNMFMatch.kr(source,c.bufnum,88,10,4096).linlin(15,20,0,0.1),trig); + + // resynths as in the previous example, with the values sent back to the language + resynth = SinOsc.ar((21..108).midicps, 0, acts).sum; + SendReply.kr(trig, '/activations', acts); + [source, resynth] + // [source, T2A.ar(trig)] + // resynth +}.play +) + +// define a receiver for the activations +( + OSCdef(\listener, {|msg| + var data = msg[3..]; + // removes the silent and spits out the indicies as midinote number + data.collect({arg item, i; if (item > 0.01, {i + 21})}).reject({arg item; item.isNil}).postln; + }, '/activations'); +) + +:: + STRONG::Strange Resonators:: CODE:: - //indeed + //to be completed :: \ No newline at end of file diff --git a/release-packaging/HelpSource/Classes/FluidSTFTPass.schelp b/release-packaging/HelpSource/Classes/FluidSTFTPass.schelp index 67c6806..1bc8260 100644 --- a/release-packaging/HelpSource/Classes/FluidSTFTPass.schelp +++ b/release-packaging/HelpSource/Classes/FluidSTFTPass.schelp @@ -31,19 +31,19 @@ RETURNS:: EXAMPLES:: - Summing with the inverse (gain of -1) with a delay of the latency gives us CPU-expensive silence. - CODE:: - { var source = PinkNoise.ar(0.1); DelayN.ar(source, delaytime:1024/s.sampleRate, mul: -1) + FluidSTFTPass.ar(source, 1024, 256, 1024); }.play - :: - Larger, oversampled, FFT - CODE:: - { FluidSTFTPass.ar(PinkNoise.ar(0.1), 2048, 128, 8192) }.play - :: - Stereo Input Tests. - CODE:: - { FluidSTFTPass.ar([SinOsc.ar(222,mul: 0.1), PinkNoise.ar(Decay.ar(Impulse.ar(0.666,mul: 0.2), 0.5))], fftSize:1024)}.play - :: - Stereo Parameter Tests. - CODE:: - { FluidSTFTPass.ar(SinOsc.ar(222,mul: 0.1), [1024,8192],256,8192)}.play - :: +Summing with the inverse (gain of -1) with a delay of the latency gives us CPU-expensive silence. +CODE:: +{ var source = PinkNoise.ar(0.1); DelayN.ar(source, delaytime:1024/s.sampleRate, mul: -1) + FluidSTFTPass.ar(source, 1024, 256, 1024); }.play +:: +Larger, oversampled, FFT +CODE:: +{ FluidSTFTPass.ar(PinkNoise.ar(0.1), 2048, 128, 8192) }.play +:: +Stereo Input Tests. +CODE:: +{ FluidSTFTPass.ar([SinOsc.ar(222,mul: 0.1), PinkNoise.ar(Decay.ar(Impulse.ar(0.666,mul: 0.2), 0.5))], fftSize:1024)}.play +:: +Stereo Parameter Tests. +CODE:: +{ FluidSTFTPass.ar(SinOsc.ar(222,mul: 0.1), [1024,8192],256,8192)}.play +:: diff --git a/release-packaging/HelpSource/Classes/FluidTransientSlice.schelp b/release-packaging/HelpSource/Classes/FluidTransientSlice.schelp index fd1ea88..326f75b 100644 --- a/release-packaging/HelpSource/Classes/FluidTransientSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidTransientSlice.schelp @@ -38,7 +38,10 @@ ARGUMENT:: winSize The averaging window of the error detection function. It needs smoothing as it is very jittery. The longer the window, the less precise, but the less false positives. ARGUMENT:: debounce - The window size in sample within with positive detections will be clumped together to avoid overdetecting in time. No slice will be shorter than this duration. + The window size in sample within with positive detections will be clumped together to avoid overdetecting in time. + +ARGUMENT:: minSlice + The minimum duration of a slice in samples. RETURNS:: An audio stream with impulses at detected transients. The latency between the input and the output is (blockSize + padSize - order) samples. @@ -54,18 +57,17 @@ b = Buffer.read(s,File.realpath(FluidTransientSlice.class.filenameSymbol).dirnam {var sig = PlayBuf.ar(1,b.bufnum,loop:1); [FluidTransientSlice.ar(sig)*0.5, DelayN.ar(sig, 1, ((256 + 128 - 20)/ s.sampleRate))]}.play // other parameters -{var sig = PlayBuf.ar(1,b.bufnum,loop:1); [FluidTransientSlice.ar(sig,order:80,debounce:2205)*0.5, DelayN.ar(sig, 1, ((256 + 128 - 80)/ s.sampleRate))]}.play +{var sig = PlayBuf.ar(1,b.bufnum,loop:1); [FluidTransientSlice.ar(sig,order:80,minSlice:2205)*0.5, DelayN.ar(sig, 1, ((256 + 128 - 80)/ s.sampleRate))]}.play // more musical trans-trigged autopan ( { var sig, trig, syncd, pan; sig = PlayBuf.ar(1,b.bufnum,loop:1); - trig = FluidTransientSlice.ar(sig,order:10,debounce:2205); + trig = FluidTransientSlice.ar(sig,order:10,minSlice:4410); syncd = DelayN.ar(sig, 1, ((256 + 128 - 10)/ s.sampleRate)); pan = TRand.ar(-1,1,trig); Pan2.ar(syncd,pan); }.play ) :: - From d42034c91124551ded54b0b58e3c3de0d39ce584 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Sun, 3 Mar 2019 23:19:10 +0000 Subject: [PATCH 28/31] Class stubs updtaed for client interface changes release-packaging/Classes/FluidBufCompose.sc release-packaging/Classes/FluidBufHPSS.sc release-packaging/Classes/FluidBufSines.sc release-packaging/Classes/FluidBufTransients.sc release-packaging/Classes/FluidHPSS.sc release-packaging/Classes/FluidNMFMatch.sc release-packaging/Classes/FluidSines.sc release-packaging/Classes/FluidSTFTPass.sc --- release-packaging/Classes/FluidBufCompose.sc | 11 ++++------- release-packaging/Classes/FluidBufHPSS.sc | 5 ++++- release-packaging/Classes/FluidBufSines.sc | 5 ++++- release-packaging/Classes/FluidBufTransients.sc | 3 +++ release-packaging/Classes/FluidHPSS.sc | 4 ++-- release-packaging/Classes/FluidNMFMatch.sc | 4 ++-- release-packaging/Classes/FluidSTFTPass.sc | 4 ++-- release-packaging/Classes/FluidSines.sc | 4 ++-- 8 files changed, 23 insertions(+), 17 deletions(-) diff --git a/release-packaging/Classes/FluidBufCompose.sc b/release-packaging/Classes/FluidBufCompose.sc index 9e71b0a..7294b4c 100644 --- a/release-packaging/Classes/FluidBufCompose.sc +++ b/release-packaging/Classes/FluidBufCompose.sc @@ -1,14 +1,11 @@ FluidBufCompose{ - *process { arg server, srcBufNumA, startAtA = 0, nFramesA = -1, startChanA = 0, nChansA = -1, srcGainA = 1, dstStartAtA = 0, dstStartChanA = 0, srcBufNumB, startAtB = 0, nFramesB = -1, startChanB = 0, nChansB = -1, srcGainB = 1, dstStartAtB = 0, dstStartChanB = 0, dstBufNum; + *process { arg server, srcBufNum, startAt = 0, nFrames = -1, startChan = 0, nChans = -1, srcGain = 1, dstBufNum, dstStartAt = 0, dstStartChan = 0; - if(srcBufNumA.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw}; - if(srcBufNumB.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw}; + if(srcBufNum.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw}; + if(srcBufNum.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw}; if(dstBufNum.isNil) {Error("Invalid Buffer").format(thisMethod.name, this.class.name).throw}; server = server ? Server.default; - - server.sendMsg(\cmd, \BufCompose, srcBufNumA, startAtA, nFramesA, startChanA, nChansA, srcGainA, dstStartAtA, dstStartChanA, - srcBufNumB, startAtB, nFramesB, startChanB, nChansB, srcGainB, dstStartAtB, dstStartChanB, - dstBufNum); + server.sendMsg(\cmd, \BufCompose, srcBufNum, startAt, nFrames, startChan, nChans, srcGain, dstBufNum,dstStartAt, dstStartChan); } } \ No newline at end of file diff --git a/release-packaging/Classes/FluidBufHPSS.sc b/release-packaging/Classes/FluidBufHPSS.sc index d3ca2dd..132c578 100644 --- a/release-packaging/Classes/FluidBufHPSS.sc +++ b/release-packaging/Classes/FluidBufHPSS.sc @@ -7,6 +7,9 @@ FluidBufHPSS{ harmBufNum = harmBufNum ? -1; percBufNum = percBufNum ? -1; - server.sendMsg(\cmd, \BufHPSS, srcBufNum, startAt, nFrames, startChan, nChans, harmBufNum, percBufNum, resBufNum, percFiltSize, harmFiltSize, modeFlag, htf1, hta1, htf2, hta2, ptf1, pta1, ptf2, pta2, winSize, hopSize, fftSize); + //For wrapped RT clients, send maximal param values as aliases of the ones that are passed + harmFiltSize.postln; + + server.sendMsg(\cmd, \BufHPSS, srcBufNum, startAt, nFrames, startChan, nChans, harmBufNum, percBufNum, resBufNum, harmFiltSize,percFiltSize, modeFlag, htf1, hta1, htf2, hta2, ptf1, pta1, ptf2, pta2, winSize, hopSize, fftSize, fftSize,harmFiltSize, percFiltSize); } } diff --git a/release-packaging/Classes/FluidBufSines.sc b/release-packaging/Classes/FluidBufSines.sc index 71e4cb9..142989b 100644 --- a/release-packaging/Classes/FluidBufSines.sc +++ b/release-packaging/Classes/FluidBufSines.sc @@ -7,6 +7,9 @@ FluidBufSines{ sineBufNum = sineBufNum ? -1; resBufNum = resBufNum ? -1; - server.sendMsg(\cmd, \BufSines, srcBufNum, startAt, nFrames, startChan, nChans, sineBufNum, resBufNum, bandwidth, thresh, minTrackLen, magWeight, freqWeight, winSize, hopSize, fftSize); + //NB For wrapped versions of NRT classes, we set the params for maxima to + //whatever has been passed in language-side (e.g maxFFTSize still exists as a parameter for the server plugin, but makes less sense here: it just needs to be set to a legal value) + + server.sendMsg(\cmd, \BufSines, srcBufNum, startAt, nFrames, startChan, nChans, sineBufNum, resBufNum, bandwidth, thresh, minTrackLen, magWeight, freqWeight, winSize, hopSize, fftSize, fftSize); } } diff --git a/release-packaging/Classes/FluidBufTransients.sc b/release-packaging/Classes/FluidBufTransients.sc index beb01b6..3485761 100644 --- a/release-packaging/Classes/FluidBufTransients.sc +++ b/release-packaging/Classes/FluidBufTransients.sc @@ -7,6 +7,9 @@ FluidBufTransients { transBufNum = transBufNum ? -1; resBufNum = resBufNum ? -1; + ("Source" + srcBufNum).postln; + ("Trans" + transBufNum).postln; + ("Res" + resBufNum).postln; server.sendMsg(\cmd, \BufTransients, srcBufNum, startAt, nFrames, startChan, nChans, transBufNum, resBufNum, order, blockSize, padSize, skew, threshFwd, threshBack, winSize, debounce); } } \ No newline at end of file diff --git a/release-packaging/Classes/FluidHPSS.sc b/release-packaging/Classes/FluidHPSS.sc index 7a090ec..6b13386 100644 --- a/release-packaging/Classes/FluidHPSS.sc +++ b/release-packaging/Classes/FluidHPSS.sc @@ -1,6 +1,6 @@ FluidHPSS : MultiOutUGen { - *ar { arg in = 0, harmFiltSize=17, percFiltSize = 17, modeFlag=0, htf1 = 0.1, hta1 = 0, htf2 = 0.5, hta2 = 0, ptf1 = 0.1, pta1 = 0, ptf2 = 0.5, pta2 = 0, winSize= 1024, hopSize= 256, fftSize= -1; - ^this.multiNew('audio', in.asAudioRateInput(this), percFiltSize, harmFiltSize, modeFlag, htf1, hta1, htf2, hta2, ptf1, pta1, ptf2, pta2, winSize, hopSize, fftSize) + *ar { arg in = 0, harmFiltSize=17, percFiltSize = 17, modeFlag=0, htf1 = 0.1, hta1 = 0, htf2 = 0.5, hta2 = 0, ptf1 = 0.1, pta1 = 0, ptf2 = 0.5, pta2 = 0, winSize= 1024, hopSize= 256, fftSize= -1, maxFFTSize = 16384, maxHSize = 101, maxPSize = 101; + ^this.multiNew('audio', in.asAudioRateInput(this), percFiltSize, harmFiltSize, modeFlag, htf1, hta1, htf2, hta2, ptf1, pta1, ptf2, pta2, winSize, hopSize, fftSize, maxFFTSize, maxHSize, maxPSize) } init { arg ... theInputs; inputs = theInputs; diff --git a/release-packaging/Classes/FluidNMFMatch.sc b/release-packaging/Classes/FluidNMFMatch.sc index 6fffd9e..a5bd325 100644 --- a/release-packaging/Classes/FluidNMFMatch.sc +++ b/release-packaging/Classes/FluidNMFMatch.sc @@ -1,7 +1,7 @@ FluidNMFMatch : MultiOutUGen { - *kr { arg in = 0, dictBufNum, maxRank = 1, nIter = 10, winSize = 1024, hopSize = 512, fftSize = -1; - ^this.multiNew('control', in, dictBufNum, maxRank, nIter, winSize, hopSize, fftSize); + *kr { arg in = 0, dictBufNum, maxRank = 1, nIter = 10, winSize = 1024, hopSize = 512, fftSize = -1, maxFFTSize = 16384; + ^this.multiNew('control', in, dictBufNum, maxRank, nIter, winSize, hopSize, fftSize, maxFFTSize); } init {arg ...theInputs; diff --git a/release-packaging/Classes/FluidSTFTPass.sc b/release-packaging/Classes/FluidSTFTPass.sc index 6b86f5e..e36fb44 100644 --- a/release-packaging/Classes/FluidSTFTPass.sc +++ b/release-packaging/Classes/FluidSTFTPass.sc @@ -1,5 +1,5 @@ FluidSTFTPass : UGen { - *ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1; - ^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize) + *ar { arg in = 0, windowSize= 1024, hopSize= 256, fftSize= -1, maxFFTSize = 16384; + ^this.multiNew('audio', in.asAudioRateInput(this),windowSize, hopSize, fftSize, maxFFTSize) } } diff --git a/release-packaging/Classes/FluidSines.sc b/release-packaging/Classes/FluidSines.sc index f2c377b..9df0f7a 100644 --- a/release-packaging/Classes/FluidSines.sc +++ b/release-packaging/Classes/FluidSines.sc @@ -1,6 +1,6 @@ FluidSines : MultiOutUGen { - *ar { arg in = 0, bandwidth = 76, thresh = 0.7, minTrackLen = 15, magWeight = 0.1, freqWeight = 1.0, winSize= 2048, hopSize= 512, fftSize= 8192; - ^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, thresh, minTrackLen, magWeight,freqWeight ,winSize, hopSize, fftSize) + *ar { arg in = 0, bandwidth = 76, thresh = 0.7, minTrackLen = 15, magWeight = 0.1, freqWeight = 1.0, winSize= 2048, hopSize= 512, fftSize= 8192, maxFFTSize=16384; + ^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, thresh, minTrackLen, magWeight,freqWeight ,winSize, hopSize, fftSize, maxFFTSize) } init { arg ... theInputs; inputs = theInputs; From 1d204f97b5879a6e70fc1be6f274381561c524cd Mon Sep 17 00:00:00 2001 From: Owen Green Date: Sun, 3 Mar 2019 23:20:01 +0000 Subject: [PATCH 29/31] Object stubs updated to new client / parameter relationship src/FluidBufCompose/FluidBufCompose.cpp src/FluidBufHPSS/FluidBufHPSS.cpp src/FluidBufNMF/FluidBufNMF.cpp src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp src/FluidBufSines/FluidBufSines.cpp src/FluidBufTransients/FluidBufTransients.cpp src/FluidBufTransientSlice/FluidBufTransientSlice.cpp src/FluidGain/FluidGain.cpp src/FluidHPSS/FluidHPSS.cpp src/FluidNMFMatch/FluidNMFMatch.cpp src/FluidSines/FluidSines.cpp src/FluidSTFTPass/FluidSTFTPass.cpp src/FluidTransients/FluidTransients.cpp src/FluidTransientSlice/FluidTransientSlice.cpp --- src/FluidBufCompose/FluidBufCompose.cpp | 72 ++----------------- src/FluidBufHPSS/FluidBufHPSS.cpp | 3 +- src/FluidBufNMF/FluidBufNMF.cpp | 2 +- .../FluidBufNoveltySlice.cpp | 2 +- src/FluidBufSines/FluidBufSines.cpp | 2 +- .../FluidBufTransientSlice.cpp | 3 +- src/FluidBufTransients/FluidBufTransients.cpp | 2 +- src/FluidGain/FluidGain.cpp | 2 +- src/FluidHPSS/FluidHPSS.cpp | 2 +- src/FluidNMFMatch/FluidNMFMatch.cpp | 2 +- src/FluidSTFTPass/FluidSTFTPass.cpp | 2 +- src/FluidSines/FluidSines.cpp | 2 +- .../FluidTransientSlice.cpp | 2 +- src/FluidTransients/FluidTransients.cpp | 5 +- 14 files changed, 19 insertions(+), 84 deletions(-) diff --git a/src/FluidBufCompose/FluidBufCompose.cpp b/src/FluidBufCompose/FluidBufCompose.cpp index 8016fc3..316ecff 100644 --- a/src/FluidBufCompose/FluidBufCompose.cpp +++ b/src/FluidBufCompose/FluidBufCompose.cpp @@ -1,74 +1,14 @@ - // 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/BufferComposeNRT.hpp" -#include "fdNRTBase.hpp" -#include "data/FluidTensor.hpp" -#include "clients/common/FluidParams.hpp" -#include "SC_PlugIn.h" -#include -#include +#include +#include static InterfaceTable *ft; -namespace fluid { - namespace wrapper{ - - class BufCompose: public NRTCommandBase - { - public: - using client_type = client::BufferComposeClient; - using NRTCommandBase::NRTCommandBase; - - ~BufCompose() {} - - void runCommand(World* world, void* replyAddr, char* completionMsgData, size_t completionMsgSize) - { - cmd(world, "/BufCompose", 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) = bufferCompose.sanityCheck(); - if(!parametersOk) - { - Print("fdCompose: %s \n", whatHappened.c_str()); - return false; - } - bufferCompose.process(processModel); - mModel = processModel; - return true; - } - - bool postProcess(World* world) - { - static_cast(mModel.dst)->assignToRT(world); - return true; - } - - bool postComplete(World* w) { - static_cast(mModel.dst)->cleanUp(); - return true; - } - - std::vector& parameters() - { - return bufferCompose.getParams(); - } - private: - client_type bufferCompose; - client_type::ProcessModel mModel; - };//class - } //namespace wrapper -}//namespace fluid - - PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; - registerCommand(ft, "BufCompose"); - fluid::wrapper::printCmd(ft,"BufCompose","FDCompose"); + using namespace fluid::client; + makeSCWrapper("BufCompose", BufComposeParams, ft); +// registerCommand(ft, "BufCompose"); +// fluid::wrapper::printCmd(ft,"BufCompose","FDCompose"); } diff --git a/src/FluidBufHPSS/FluidBufHPSS.cpp b/src/FluidBufHPSS/FluidBufHPSS.cpp index bc979c0..8737d38 100644 --- a/src/FluidBufHPSS/FluidBufHPSS.cpp +++ b/src/FluidBufHPSS/FluidBufHPSS.cpp @@ -2,7 +2,6 @@ // 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 -#include #include static InterfaceTable *ft; @@ -10,5 +9,5 @@ static InterfaceTable *ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper>>(ft, "BufHPSS"); + makeSCWrapper("BufHPSS",NRTHPSSParams,ft); } diff --git a/src/FluidBufNMF/FluidBufNMF.cpp b/src/FluidBufNMF/FluidBufNMF.cpp index 2e75538..abd323d 100644 --- a/src/FluidBufNMF/FluidBufNMF.cpp +++ b/src/FluidBufNMF/FluidBufNMF.cpp @@ -6,5 +6,5 @@ static InterfaceTable *ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper(ft, "BufNMF"); + makeSCWrapper("BufNMF",NMFParams, ft); } diff --git a/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp b/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp index 206b5e2..8f0d64e 100644 --- a/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp +++ b/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp @@ -10,5 +10,5 @@ static InterfaceTable* ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper(ft, "BufNoveltySlice"); + makeSCWrapper("BufNoveltySlice",NoveltyParams,ft); } diff --git a/src/FluidBufSines/FluidBufSines.cpp b/src/FluidBufSines/FluidBufSines.cpp index abd82fd..2368551 100644 --- a/src/FluidBufSines/FluidBufSines.cpp +++ b/src/FluidBufSines/FluidBufSines.cpp @@ -10,6 +10,6 @@ static InterfaceTable *ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper>>(ft, "BufSines"); + makeSCWrapper("BufSines",NRTSineParams,ft); } diff --git a/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp b/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp index 3e0db18..68fade3 100644 --- a/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp +++ b/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp @@ -10,6 +10,5 @@ static InterfaceTable* ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper>>(ft, "BufTransientSlice"); - + makeSCWrapper("BufTransientSlice",NRTTransientSliceParams, ft); } diff --git a/src/FluidBufTransients/FluidBufTransients.cpp b/src/FluidBufTransients/FluidBufTransients.cpp index 1b2ae80..3102005 100644 --- a/src/FluidBufTransients/FluidBufTransients.cpp +++ b/src/FluidBufTransients/FluidBufTransients.cpp @@ -7,5 +7,5 @@ static InterfaceTable *ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper>>(ft,"BufTransients"); + makeSCWrapper("BufTransients",NRTTransientParams,ft); } diff --git a/src/FluidGain/FluidGain.cpp b/src/FluidGain/FluidGain.cpp index 64a04a1..fa40308 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"); + makeSCWrapper("FluidGain", GainParams,ft); } diff --git a/src/FluidHPSS/FluidHPSS.cpp b/src/FluidHPSS/FluidHPSS.cpp index 1b779e5..72ab11b 100644 --- a/src/FluidHPSS/FluidHPSS.cpp +++ b/src/FluidHPSS/FluidHPSS.cpp @@ -8,7 +8,7 @@ static InterfaceTable *ft; PluginLoad(FluidSTFTUGen) { ft = inTable; using namespace fluid::client; - makeSCWrapper>(ft, "FluidHPSS"); + makeSCWrapper("FluidHPSS",HPSSParams,ft); } diff --git a/src/FluidNMFMatch/FluidNMFMatch.cpp b/src/FluidNMFMatch/FluidNMFMatch.cpp index 6eec74e..ae854a4 100644 --- a/src/FluidNMFMatch/FluidNMFMatch.cpp +++ b/src/FluidNMFMatch/FluidNMFMatch.cpp @@ -9,7 +9,7 @@ static InterfaceTable *ft; PluginLoad(FluidSTFTUGen) { ft = inTable; using namespace fluid::client; - makeSCWrapper>(ft, "FluidNMFMatch"); + makeSCWrapper("FluidNMFMatch",NMFMatchParams,ft); } diff --git a/src/FluidSTFTPass/FluidSTFTPass.cpp b/src/FluidSTFTPass/FluidSTFTPass.cpp index 681e7c5..b1c15dd 100644 --- a/src/FluidSTFTPass/FluidSTFTPass.cpp +++ b/src/FluidSTFTPass/FluidSTFTPass.cpp @@ -9,5 +9,5 @@ static InterfaceTable *ft; PluginLoad(FluidSTFTUGen) { ft = inTable; using namespace fluid::client; - makeSCWrapper>(ft, "FluidSTFTPass"); + makeSCWrapper("FluidSTFTPass",STFTParams,ft); } diff --git a/src/FluidSines/FluidSines.cpp b/src/FluidSines/FluidSines.cpp index bc268f5..eab70a4 100644 --- a/src/FluidSines/FluidSines.cpp +++ b/src/FluidSines/FluidSines.cpp @@ -9,6 +9,6 @@ static InterfaceTable *ft; PluginLoad(FluidSTFTUGen) { ft = inTable; using namespace fluid::client; - makeSCWrapper>(ft, "FluidSines"); + makeSCWrapper("FluidSines",SinesParams,ft); } diff --git a/src/FluidTransientSlice/FluidTransientSlice.cpp b/src/FluidTransientSlice/FluidTransientSlice.cpp index 8058b57..fd138c9 100644 --- a/src/FluidTransientSlice/FluidTransientSlice.cpp +++ b/src/FluidTransientSlice/FluidTransientSlice.cpp @@ -9,5 +9,5 @@ static InterfaceTable *ft; PluginLoad(FluidSTFTUGen) { ft = inTable; using namespace fluid::client; - makeSCWrapper>(ft, "FluidTransientSlice"); + makeSCWrapper("FluidTransientSlice",TransientParams,ft); } diff --git a/src/FluidTransients/FluidTransients.cpp b/src/FluidTransients/FluidTransients.cpp index 708fe64..55de31d 100644 --- a/src/FluidTransients/FluidTransients.cpp +++ b/src/FluidTransients/FluidTransients.cpp @@ -1,16 +1,13 @@ // 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 - #include static InterfaceTable *ft; PluginLoad(FluidSTFTUGen) { ft = inTable; -// registerUnit(ft, "FluidTransients"); using namespace fluid::client; - makeSCWrapper>(ft, "FluidTransients"); + makeSCWrapper("FluidTransients", TransientParams, ft); } From 6529d6c813e14a65730dc988033c6055bd425b7c Mon Sep 17 00:00:00 2001 From: Owen Green Date: Sun, 3 Mar 2019 23:20:37 +0000 Subject: [PATCH 30/31] Cosmetic changes to include/SCBufferAdaptor.hpp --- include/SCBufferAdaptor.hpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/include/SCBufferAdaptor.hpp b/include/SCBufferAdaptor.hpp index b753a15..98195a7 100644 --- a/include/SCBufferAdaptor.hpp +++ b/include/SCBufferAdaptor.hpp @@ -87,7 +87,11 @@ public: void cleanUp() { - if (mOldData) boost::alignment::aligned_free(mOldData); + if (mOldData) + { + boost::alignment::aligned_free(mOldData); + mOldData = nullptr; + } } // No locks in (vanilla) SC, so no-ops for these @@ -147,10 +151,8 @@ public: thisThing->samplerate); } - int bufnum() - { - return mBufnum; - } + int bufnum() { return mBufnum; } + void realTime(bool rt) { mRealTime = rt; } protected: bool equal(BufferAdaptor *rhs) const override @@ -160,10 +162,11 @@ protected: return false; } - float *mOldData = 0; + bool mRealTime{false}; + float *mOldData{0}; long mBufnum; World *mWorld; - size_t mRank = 1; + size_t mRank{1}; }; class RTBufferView : public client::BufferAdaptor From 82c2c798c10777692eeeddb61b4f773b9360ca83 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Sun, 3 Mar 2019 23:21:48 +0000 Subject: [PATCH 31/31] Deals with separation of clients and params; new FFT param type; include/FluidSCWrapper.hpp --- include/FluidSCWrapper.hpp | 313 ++++++++++++++++++++----------------- 1 file changed, 166 insertions(+), 147 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 47fd62c..4850a3d 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -1,4 +1,4 @@ -#pragma once + #pragma once #include "SCBufferAdaptor.hpp" #include @@ -16,7 +16,7 @@ namespace fluid { namespace client { -template class FluidSCWrapper; +template class FluidSCWrapper; namespace impl { @@ -25,16 +25,8 @@ template struct ArgumentGetter; template struct ControlGetter; template using msg_iter_method = T (sc_msg_iter::*)(T); -template Method> struct GetArgument -{ - T operator()(World* w, sc_msg_iter *args) - { - T r = (args->*Method)(T{0}); - return r; - } -}; - - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Iterate over kr/ir inputs via callbacks from params object struct FloatControlsIter { FloatControlsIter(float** vals, size_t N):mValues(vals), mSize(N) {} @@ -46,11 +38,11 @@ struct FloatControlsIter return f; } - float operator[](size_t i) - { - assert(i < mSize); - return *mValues[i]; - } +// float operator[](size_t i) +// { +// assert(i < mSize); +// return *mValues[i]; +// } void reset(float** vals) { @@ -64,104 +56,118 @@ struct FloatControlsIter size_t mCount{0}; }; +//General case template struct GetControl { - T operator()(World*, FloatControlsIter& controls) { return controls[N]; } + T operator()(World*, FloatControlsIter& controls) { return controls.next(); } }; -template struct ArgumentGetter : public GetArgument -{ -// ArgumentGetter() { std::cout << "FloatT @ " << N << '\n'; } -}; +template struct ControlGetter : public GetControl +{}; -template struct ArgumentGetter : public GetArgument +//Specializations +template struct ControlGetter { -// ArgumentGetter() { std::cout << "LongT @ " << N << '\n'; } - + auto operator() (World* w, FloatControlsIter& iter) + { + typename LongT::type bufnum = iter.next(); + return std::unique_ptr(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w): nullptr); + } }; -template struct ArgumentGetter : public GetArgument +template +struct ControlGetter { -// ArgumentGetter() { std::cout << "Enum @ " << N << '\n'; } - + typename FloatPairsArrayT::type operator()(World*, FloatControlsIter& iter) + { + return {{iter.next(),iter.next()},{iter.next(),iter.next()}}; + } }; -template struct ArgumentGetter +template +struct ControlGetter { -// ArgumentGetter() { std::cout << "Buffer @ " << N << '\n'; } - auto operator() (World* w, sc_msg_iter *args) + typename FFTParamsT::type operator()(World*, FloatControlsIter& iter) { - typename LongT::type bufnum = args->geti(-1); - return std::unique_ptr(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w) : nullptr); + return {static_cast(iter.next()),static_cast(iter.next()),static_cast(iter.next())}; } }; -template struct ArgumentGetter +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Iterate over arguments in sc_msg_iter, via callbacks from params object + +template Method> struct GetArgument { - typename FloatPairsArrayT::type operator()(World* w, sc_msg_iter *args) + T operator()(World* w, sc_msg_iter *args) { - return {{args->getf(),args->getf()},{args->getf(),args->getf()}}; + T r = (args->*Method)(T{0}); + return r; } }; +//General cases +template struct ArgumentGetter : public GetArgument +{}; - -template struct ControlGetter : public GetControl +template struct ArgumentGetter : public GetArgument {}; +template struct ArgumentGetter : public GetArgument +{}; -template struct ControlGetter +//Specializations +template struct ArgumentGetter { - auto operator() (World* w, FloatControlsIter& iter) + auto operator() (World* w, sc_msg_iter *args) { - typename LongT::type bufnum = iter.next(); - return std::unique_ptr(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w): nullptr); + typename LongT::type bufnum = args->geti(-1); + return std::unique_ptr(bufnum >= 0 ? new SCBufferAdaptor(bufnum,w) : nullptr); } }; -template -struct ControlGetter +template struct ArgumentGetter { - typename FloatPairsArrayT::type operator()(World*, FloatControlsIter& iter) + typename FloatPairsArrayT::type operator()(World* w, sc_msg_iter *args) { - return {{iter.next(),iter.next()},{iter.next(),iter.next()}}; + return {{args->getf(),args->getf()},{args->getf(),args->getf()}}; } }; - -template class Fetcher> -struct ClientFactory +template struct ArgumentGetter { - static Client create(World* world, Args* args) - { - return createImpl(world, args, FixedParamIndices{}); - } - -private: - using FixedParamIndices = typename Client::FixedParams; - template - using ThisParamType = typename Client::template ParamDescriptorTypeAt; - - template - static Client createImpl(World* world, Args* args, std::index_sequence) + typename FFTParamsT::type operator()(World* w, sc_msg_iter *args) { - return Client{Fetcher>{}(world,*args)...}; + return {args->geti(),args->geti(),args->geti()}; } }; -//template class RealTime : public SCUnit +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Real Time Processor + +template class RealTime : public SCUnit { using HostVector = FluidTensorView; // using Client = typename Wrapper::ClientType; public: - static void setup(InterfaceTable *ft, const char *name) { registerUnit(ft, name); } + static void setup(InterfaceTable *ft, const char *name) + { + registerUnit(ft, name); + ft->fDefineUnitCmd(name,"latency",doLatency); + } + + static void doLatency(Unit *unit, sc_msg_iter *args) + { + float l[] {static_cast(static_cast(unit)->mClient.latency())}; + auto ft = Wrapper::getInterfaceTable(); + ft->fSendNodeReply(&unit->mParent->mNode,-1,Wrapper::getName(), 1, l); + } RealTime(): mControlsIterator{mInBuf + mSpecialIndex + 1,mNumInputs - mSpecialIndex - 1}, - mClient{ClientFactory::create(mWorld,&mControlsIterator)} + mParams{*Wrapper::getParamDescriptors()}, + mClient{Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld, mControlsIterator)} {} void init() @@ -196,10 +202,8 @@ public: void next(int n) { - Wrapper *w = static_cast(this); -// auto &client = w->client(); - mControlsIterator.reset(mInBuf + mClient.audioChannelsIn()); - w->setParams( mWorld->mVerbosity > 0, mWorld,mControlsIterator); // forward on inputs N + audio inputs as params + mControlsIterator.reset(mInBuf + 1); //mClient.audioChannelsIn()); + Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld,mControlsIterator); // forward on inputs N + audio inputs as params const Unit *unit = this; for (int i = 0; i < mClient.audioChannelsIn(); ++i) { @@ -222,61 +226,71 @@ private: std::vector mOutputs; FloatControlsIter mControlsIterator; protected: + ParameterSet mParams; Client mClient; - }; -template class NonRealTime +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Non Real Time Processor +template class NonRealTime { public: static void setup(InterfaceTable *ft, const char *name) { DefinePlugInCmd(name, launch, nullptr); } NonRealTime(World *world,sc_msg_iter *args): - mClient{ClientFactory::create(world,args)} + mParams{*Wrapper::getParamDescriptors()}, + mClient{mParams} {} void init(){}; static void launch(World *world, void *inUserData, struct sc_msg_iter *args, void *replyAddr) { + + Wrapper *w = new Wrapper(world,args); //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; auto argsRdPos = args->rdpos; Result result = validateParameters(w, world, args); if (!result.ok()) { std::cout << "FluCoMa Error " << Wrapper::getName() << ": " << result.message().c_str(); + delete w; return; } args->count = argsPosition; args->rdpos = argsRdPos; - w->setParams(false, world, args); + Wrapper::setParams(w->mParams,false, world, args); size_t msgSize = args->getbsize(); - char * completionMsgData = 0; + std::vector completionMessage(msgSize); +// char * completionMsgData = 0; if (msgSize) { - completionMsgData = (char *) world->ft->fRTAlloc(world, msgSize); - args->getb(completionMsgData, msgSize); + args->getb(completionMessage.data(), msgSize); } - world->ft->fDoAsynchronousCommand(world, replyAddr, Wrapper::getName(), w, process, exchangeBuffers, tidyUp, destroy, - msgSize, completionMsgData); + + world->ft->fDoAsynchronousCommand(world, replyAddr, Wrapper::getName(), w, process, exchangeBuffers, tidyUp, destroy,msgSize, completionMessage.data()); } 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); } + static void destroy(World *world, void *data) + { + +// void* c = static_cast(data)->mCompletionMessage; +// if(c) world->ft->fRTFree(world,c); + delete static_cast(data); + } protected: + ParameterSet mParams; Client mClient; - private: static Result validateParameters(NonRealTime *w, World* world, sc_msg_iter *args) { - auto &c = w->mClient; - auto results = c.template checkParameterValues(world, args); + auto results = w->mParams.template checkParameterValues(world, args); for (auto &r : results) { std::cout << r.message() << '\n'; @@ -285,37 +299,9 @@ private: return {}; } - void parseBuffers(Wrapper *w, World *world, sc_msg_iter *args) - { - auto &c = mClient; - - mBuffersIn.reserve(c.audioBuffersIn()); - mInputs.reserve(c.audioBuffersIn()); - mBuffersOut.reserve(c.audioBuffersOut()); - mOutputs.reserve(c.audioBuffersOut()); - - 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); - } - - for (int i = 0; i < c.audioBuffersOut(); i++) - { - mBuffersOut.emplace_back(args->geti(0), world); - mOutputs.emplace_back(); - mOutputs[i].buffer = &mBuffersOut[i]; - } - } - bool process(World *world) { - Result r = mClient.process(mInputs, mOutputs); + Result r = mClient.process();///mInputs, mOutputs); if(!r.ok()) { @@ -328,16 +314,16 @@ private: bool exchangeBuffers(World *world) { - - mClient.template forEachParamType(world); - for (auto &b : mBuffersOut) b.assignToRT(world); + mParams.template forEachParamType(world); +// for (auto &b : mBuffersOut) b.assignToRT(world); return true; } bool tidyUp(World *world) { - for (auto &b : mBuffersIn) b.cleanUp(); - for (auto &b : mBuffersOut) b.cleanUp(); +// for (auto &b : mBuffersIn) b.cleanUp(); +// for (auto &b : mBuffersOut) b.cleanUp() + mParams.template forEachParamType(); return true; } @@ -350,53 +336,72 @@ private: b->assignToRT(w); } }; + + template + struct CleanUpBuffer + { + void operator()(typename BufferT::type& p) + { + if(auto b = static_cast(p.get())) + b->cleanUp(); + } + }; - std::vector mBuffersIn; - std::vector mBuffersOut; - std::vector mInputs; - std::vector mOutputs; - void * mReplyAddr; - const char * mName; +// std::vector mBuffersIn; +// std::vector mBuffersOut; +// std::vector mInputs; +// std::vector mOutputs; + char * mCompletionMessage = nullptr; + void * mReplyAddr = nullptr; + const char * mName = nullptr; }; -template class NonRealTimeAndRealTime : public RealTime, public NonRealTime +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// An impossible monstrosty +template class NonRealTimeAndRealTime : public RealTime, public NonRealTime { static void setup(InterfaceTable *ft, const char *name) { - RealTime::setup(ft, name); - NonRealTime::setup(ft, name); + RealTime::setup(ft, name); + NonRealTime::setup(ft, name); } }; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Template Specialisations for NRT/RT -template class FluidSCWrapperImpl; +template class FluidSCWrapperImpl; -template class FluidSCWrapperImpl : public NonRealTime +template class FluidSCWrapperImpl : public NonRealTime { public: - FluidSCWrapperImpl(World* w, sc_msg_iter *args): NonRealTime(w,args){}; + FluidSCWrapperImpl(World* w, sc_msg_iter *args): NonRealTime(w,args){}; }; -template class FluidSCWrapperImpl : public RealTime +template class FluidSCWrapperImpl : public RealTime {}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Make base class(es), full of CRTP mixin goodness -template -using FluidSCWrapperBase = FluidSCWrapperImpl, isNonRealTime, isRealTime>; +template +using FluidSCWrapperBase = FluidSCWrapperImpl,Params, isNonRealTime, isRealTime>; } // namespace impl -template class FluidSCWrapper : public impl::FluidSCWrapperBase +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///The main wrapper +template class FluidSCWrapper : public impl::FluidSCWrapperBase { public: - using ClientType = Client; + using Client = C; + using Params = P; - FluidSCWrapper() { impl::FluidSCWrapperBase::init(); } + FluidSCWrapper() //mParams{*getParamDescriptors()}, //impl::FluidSCWrapperBase() + { impl::FluidSCWrapperBase::init(); } - FluidSCWrapper(World* w, sc_msg_iter *args): impl::FluidSCWrapperBase(w,args) - { impl::FluidSCWrapperBase::init(); } + FluidSCWrapper(World* w, sc_msg_iter *args): impl::FluidSCWrapperBase(w,args) + { impl::FluidSCWrapperBase::init(); } static const char *getName(const char *setName = nullptr) @@ -404,6 +409,12 @@ public: static const char *name = nullptr; return (name = setName ? setName : name); } + + static Params *getParamDescriptors(Params *setParams = nullptr) + { + static Params* descriptors = nullptr; + return (descriptors = setParams ? setParams : descriptors); + } static InterfaceTable *getInterfaceTable(InterfaceTable *setTable = nullptr) { @@ -411,32 +422,40 @@ public: return (ft = setTable ? setTable : ft); } - static void setup(InterfaceTable *ft, const char *name) + static void setup(Params& p, InterfaceTable *ft, const char *name) { getName(name); getInterfaceTable(ft); - impl::FluidSCWrapperBase::setup(ft, name); + getParamDescriptors(&p); + impl::FluidSCWrapperBase::setup(ft, name); } - auto setParams(bool verbose, World* world, impl::FloatControlsIter& inputs) + template + static auto& setParams(ParameterSet& p, bool verbose, World* world, impl::FloatControlsIter& inputs) { - return impl::FluidSCWrapperBase::mClient.template setParameterValues(verbose, world, inputs); + p.template setParameterValues(verbose, world, inputs); + return p; } - auto setParams(bool verbose, World* world, sc_msg_iter *args) + template + static auto& setParams(ParameterSet& p, bool verbose, World* world, sc_msg_iter *args) { - return impl::FluidSCWrapperBase::mClient.template setParameterValues(verbose,world, args); + p.template setParameterValues(verbose,world, args); + return p; } -// Client &client() { return mClient; } +// impl::ParameterSet mParams; +// Client &client() { return mClient; } +// //private: // Client mClient; }; -template void makeSCWrapper(InterfaceTable *ft, const char *name) +template