Merge branch 'refactor/NRTSynths' into clients/inter_client_comms
commit
d96bec54b1
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,337 @@
|
||||
#pragma once
|
||||
|
||||
#include "Meta.hpp"
|
||||
|
||||
namespace fluid {
|
||||
namespace client {
|
||||
|
||||
namespace impl {
|
||||
// Iterate over kr/ir inputs via callbacks from params object
|
||||
struct FloatControlsIter
|
||||
{
|
||||
FloatControlsIter(float** vals, index N) : mValues(vals), mSize(N) {}
|
||||
|
||||
float next() { return mCount >= mSize ? 0 : *mValues[mCount++]; }
|
||||
|
||||
void reset(float** vals)
|
||||
{
|
||||
mValues = vals;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
index size() const noexcept { return mSize; }
|
||||
index remain() { return mSize - mCount; }
|
||||
|
||||
private:
|
||||
float** mValues;
|
||||
index mSize;
|
||||
index mCount{0};
|
||||
};
|
||||
} //impl
|
||||
|
||||
//Specializations of param reader for RT and NRT cases (data encoded differently, buffer semantics differ cause of local bufs)
|
||||
template <typename ArgType> struct ParamReader;
|
||||
|
||||
// RT case: we're decoding data from float**, there will be a Unit, we can have LocalBufs
|
||||
// TODO: All the allocations should be using SC RT allocator, but this won't work reliably until it propagates down through the param set
|
||||
template<>
|
||||
struct ParamReader<impl::FloatControlsIter>
|
||||
{
|
||||
|
||||
using Controls = impl::FloatControlsIter;
|
||||
|
||||
static auto fromArgs(Unit* /*x*/, Controls& args, std::string, int)
|
||||
{
|
||||
// first is string size, then chars
|
||||
index size = static_cast<index>(args.next());
|
||||
std::string res;
|
||||
res.resize(asUnsigned(size));
|
||||
for (index i = 0; i < size; ++i)
|
||||
res[asUnsigned(i)] = static_cast<char>(args.next());
|
||||
return res;
|
||||
}
|
||||
|
||||
static auto fromArgs(Unit*, Controls& args,typename LongArrayT::type&, int)
|
||||
{
|
||||
//first is array size, then items
|
||||
using Container = typename LongArrayT::type;
|
||||
using Value = typename Container::type;
|
||||
index size = static_cast<index>(args.next());
|
||||
Container res(size);
|
||||
for (index i = 0; i < size; ++i)
|
||||
res[i] = static_cast<Value>(args.next());
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_integral<T>::value, T>
|
||||
fromArgs(Unit*, Controls& args, T, int)
|
||||
{
|
||||
return static_cast<index>(args.next());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_floating_point<T>::value, T>
|
||||
fromArgs(Unit*, Controls& args, T, int)
|
||||
{
|
||||
return args.next();
|
||||
}
|
||||
|
||||
static SCBufferAdaptor* fetchBuffer(Unit* x, index bufnum)
|
||||
{
|
||||
if(bufnum >= x->mWorld->mNumSndBufs)
|
||||
{
|
||||
index localBufNum = bufnum - x->mWorld->mNumSndBufs;
|
||||
|
||||
Graph* parent = x->mParent;
|
||||
|
||||
return localBufNum <= parent->localMaxBufNum ?
|
||||
new SCBufferAdaptor(parent->mLocalSndBufs + localBufNum,x->mWorld,true)
|
||||
: nullptr;
|
||||
}
|
||||
else
|
||||
return bufnum >= 0 ? new SCBufferAdaptor(bufnum, x->mWorld) : nullptr;
|
||||
}
|
||||
|
||||
static auto fromArgs(Unit* x, Controls& args, BufferT::type&, int)
|
||||
{
|
||||
typename LongT::type bufnum = static_cast<typename LongT::type>(
|
||||
ParamReader::fromArgs(x, args, typename LongT::type(), -1));
|
||||
return BufferT::type(fetchBuffer(x, bufnum));
|
||||
}
|
||||
|
||||
static auto fromArgs(Unit* x, Controls& args, InputBufferT::type&, int)
|
||||
{
|
||||
typename LongT::type bufnum =
|
||||
static_cast<LongT::type>(fromArgs(x, args, LongT::type(), -1));
|
||||
return InputBufferT::type(fetchBuffer(x, bufnum));
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
static std::enable_if_t<IsSharedClient<P>::value, P>
|
||||
fromArgs(Unit* x, Controls& args, P&, int)
|
||||
{
|
||||
auto id = fromArgs(x, args, index{}, 0);
|
||||
return {id >= 0 ? std::to_string(id).c_str() : "" };
|
||||
}
|
||||
};
|
||||
|
||||
// NRT case: we're decoding data from sc_msg_iter*, there will be a World*, we can't have LocalBufs
|
||||
// TODO: All the allocations should be using SC RT allocator (I guess: this will probably always run on the RT thread), but this won't work reliably until it propagates down through the param set
|
||||
template<>
|
||||
struct ParamReader<sc_msg_iter>
|
||||
{
|
||||
static const char* oscTagToString(char tag)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case 'i': return "integer"; break;
|
||||
case 'f': return "float"; break;
|
||||
case 'd': return "double"; break;
|
||||
case 's': return "string"; break;
|
||||
case 'b': return "blob"; break;
|
||||
case 't': return "time tag"; break;
|
||||
default: return "unknown type";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* argTypeToString(std::string&)
|
||||
{
|
||||
return "string";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_integral<T>::value, const char*>
|
||||
argTypeToString(T&)
|
||||
{
|
||||
return "integer";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_floating_point<T>::value, const char*>
|
||||
argTypeToString(T&)
|
||||
{
|
||||
return "float";
|
||||
}
|
||||
|
||||
static const char* argTypeToString(BufferT::type&)
|
||||
{
|
||||
return "buffer";
|
||||
}
|
||||
|
||||
static const char* argTypeToString(InputBufferT::type&)
|
||||
{
|
||||
return "buffer";
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
static std::enable_if_t<IsSharedClient<P>::value,const char*>
|
||||
argTypeToString(P&)
|
||||
{
|
||||
return "shared_object"; //not ideal
|
||||
}
|
||||
|
||||
static bool argTypeOK(std::string&, char tag)
|
||||
{
|
||||
return tag == 's';
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_integral<T>::value
|
||||
|| std::is_floating_point<T>::value, bool>
|
||||
argTypeOK(T&, char tag)
|
||||
{
|
||||
return tag == 'i' || tag == 'f' || tag == 'd';
|
||||
}
|
||||
|
||||
static bool argTypeOK(BufferT::type&, char tag)
|
||||
{
|
||||
return tag == 'i';
|
||||
}
|
||||
|
||||
static bool argTypeOK(InputBufferT::type&, char tag)
|
||||
{
|
||||
return tag == 'i';
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
static std::enable_if_t<IsSharedClient<P>::value,bool>
|
||||
argTypeOK(P&, char tag)
|
||||
{
|
||||
return tag == 'i';
|
||||
}
|
||||
|
||||
static auto fromArgs(World*, sc_msg_iter& args, std::string, int)
|
||||
{
|
||||
const char* recv = args.gets("");
|
||||
|
||||
return std::string(recv ? recv : "");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_integral<T>::value, T>
|
||||
fromArgs(World*, sc_msg_iter& args, T, int defVal)
|
||||
{
|
||||
return args.geti(defVal);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_floating_point<T>::value, T>
|
||||
fromArgs(World*, sc_msg_iter& args, T, int)
|
||||
{
|
||||
return args.getf();
|
||||
}
|
||||
|
||||
static SCBufferAdaptor* fetchBuffer(World* x, index bufnum)
|
||||
{
|
||||
if(bufnum >= x->mNumSndBufs)
|
||||
{
|
||||
std::cout << "ERROR: bufnum " << bufnum << " is invalid for global buffers\n";
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
return bufnum >= 0 ? new SCBufferAdaptor(bufnum, x) : nullptr;
|
||||
}
|
||||
|
||||
static auto fromArgs(World* x, sc_msg_iter& args, BufferT::type&, int)
|
||||
{
|
||||
typename LongT::type bufnum = static_cast<typename LongT::type>(
|
||||
ParamReader::fromArgs(x, args, typename LongT::type(), -1));
|
||||
return BufferT::type(fetchBuffer(x, bufnum));
|
||||
}
|
||||
|
||||
static auto fromArgs(World* x, sc_msg_iter& args, InputBufferT::type&, int)
|
||||
{
|
||||
typename LongT::type bufnum =
|
||||
static_cast<LongT::type>(fromArgs(x, args, LongT::type(), -1));
|
||||
return InputBufferT::type(fetchBuffer(x, bufnum));
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
static std::enable_if_t<IsSharedClient<P>::value, P>
|
||||
fromArgs(World* x, sc_msg_iter& args, P&, int)
|
||||
{
|
||||
auto id = fromArgs(x, args, index{}, 0);
|
||||
return {id >= 0 ? std::to_string(id).c_str() : ""};
|
||||
}
|
||||
|
||||
static auto fromArgs(World*, sc_msg_iter& args,typename LongArrayT::type&, int)
|
||||
{
|
||||
//first is array size, then items
|
||||
using Container = typename LongArrayT::type;
|
||||
using Value = typename Container::type;
|
||||
index size = static_cast<index>(args.geti());
|
||||
Container res(size);
|
||||
for (index i = 0; i < size; ++i)
|
||||
res[i] = static_cast<Value>(args.geti());
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Wrapper>
|
||||
struct ClientParams{
|
||||
// Iterate over arguments via callbacks from params object
|
||||
template <typename ArgType, size_t N, typename T>
|
||||
struct Setter
|
||||
{
|
||||
static constexpr index argSize =
|
||||
Wrapper::Client::getParameterDescriptors().template get<N>().fixedSize;
|
||||
|
||||
|
||||
/// Grizzly enable_if hackage coming up. Need to brute force an int from incoming data into a string param for FluidDataSet / FluidLabelSet.
|
||||
/// This will go away one day
|
||||
|
||||
template<typename Context, typename Client = typename Wrapper::Client, size_t Number = N>
|
||||
std::enable_if_t<!impl::IsNamedShared_v<Client> || Number!=0, typename T::type>
|
||||
operator()(Context* x, ArgType& args)
|
||||
{
|
||||
// Just return default if there's nothing left to grab
|
||||
if (args.remain() == 0)
|
||||
{
|
||||
std::cout << "WARNING: " << Wrapper::getName()
|
||||
<< " received fewer parameters than expected\n";
|
||||
return Wrapper::Client::getParameterDescriptors().template makeValue<N>();
|
||||
}
|
||||
|
||||
ParamLiteralConvertor<T, argSize> a;
|
||||
using LiteralType =
|
||||
typename ParamLiteralConvertor<T, argSize>::LiteralType;
|
||||
|
||||
for (index i = 0; i < argSize; i++)
|
||||
a[i] = static_cast<LiteralType>(
|
||||
ParamReader<ArgType>::fromArgs(x, args, a[0], 0));
|
||||
|
||||
return a.value();
|
||||
}
|
||||
|
||||
template<typename Context, typename Client = typename Wrapper::Client, size_t Number = N>
|
||||
std::enable_if_t<impl::IsNamedShared_v<Client> && Number==0, typename T::type>
|
||||
operator()(Context* x, ArgType& args)
|
||||
{
|
||||
// Just return default if there's nothing left to grab
|
||||
if (args.remain() == 0)
|
||||
{
|
||||
std::cout << "WARNING: " << Wrapper::getName()
|
||||
<< " received fewer parameters than expected\n";
|
||||
return Wrapper::Client::getParameterDescriptors().template makeValue<N>();
|
||||
}
|
||||
|
||||
index id = ParamReader<ArgType>::fromArgs(x,args,index{},0);
|
||||
return std::to_string(id);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ArgType, size_t N, typename T>
|
||||
struct Getter
|
||||
{
|
||||
static constexpr index argSize =
|
||||
Wrapper::Client::getParameterDescriptors().template get<N>().fixedSize;
|
||||
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,201 @@
|
||||
#pragma once
|
||||
|
||||
namespace fluid {
|
||||
namespace client {
|
||||
|
||||
struct ToFloatArray
|
||||
{
|
||||
static index allocSize(typename BufferT::type) { return 1; }
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<
|
||||
std::is_integral<T>::value || std::is_floating_point<T>::value, index>
|
||||
allocSize(T)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static index allocSize(std::string s)
|
||||
{
|
||||
return asSigned(s.size()) + 1;
|
||||
} // put null char at end when we send
|
||||
|
||||
static index allocSize(FluidTensor<std::string, 1> s)
|
||||
{
|
||||
index count = 0;
|
||||
for (auto& str : s) count += (str.size() + 1);
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static index allocSize(FluidTensor<T, 1> s)
|
||||
{
|
||||
return s.size();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static std::tuple<std::array<index, sizeof...(Ts)>, index>
|
||||
allocSize(std::tuple<Ts...>&& t)
|
||||
{
|
||||
return allocSizeImpl(std::forward<decltype(t)>(t),
|
||||
std::index_sequence_for<Ts...>());
|
||||
};
|
||||
|
||||
template <typename... Ts, size_t... Is>
|
||||
static std::tuple<std::array<index, sizeof...(Ts)>, index>
|
||||
allocSizeImpl(std::tuple<Ts...>&& t, std::index_sequence<Is...>)
|
||||
{
|
||||
index size{0};
|
||||
std::array<index, sizeof...(Ts)> res;
|
||||
(void) std::initializer_list<int>{
|
||||
(res[Is] = size, size += ToFloatArray::allocSize(std::get<Is>(t)),
|
||||
0)...};
|
||||
return std::make_tuple(res,
|
||||
size); // array of offsets into allocated buffer &
|
||||
// total number of floats to alloc
|
||||
};
|
||||
|
||||
static void convert(float* f, typename BufferT::type buf)
|
||||
{
|
||||
f[0] = static_cast<SCBufferAdaptor*>(buf.get())->bufnum();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_integral<T>::value ||
|
||||
std::is_floating_point<T>::value>
|
||||
convert(float* f, T x)
|
||||
{
|
||||
f[0] = static_cast<float>(x);
|
||||
}
|
||||
|
||||
static void convert(float* f, std::string s)
|
||||
{
|
||||
std::copy(s.begin(), s.end(), f);
|
||||
f[s.size()] = 0; // terminate
|
||||
}
|
||||
static void convert(float* f, FluidTensor<std::string, 1> s)
|
||||
{
|
||||
for (auto& str : s)
|
||||
{
|
||||
std::copy(str.begin(), str.end(), f);
|
||||
f += str.size();
|
||||
*f++ = 0;
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
static void convert(float* f, FluidTensor<T, 1> s)
|
||||
{
|
||||
static_assert(std::is_convertible<T, float>::value,
|
||||
"Can't convert this to float output");
|
||||
std::copy(s.begin(), s.end(), f);
|
||||
}
|
||||
|
||||
template <typename... Ts, size_t... Is>
|
||||
static void convert(float* f, std::tuple<Ts...>&& t,
|
||||
std::array<index, sizeof...(Ts)> offsets,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
(void) std::initializer_list<int>{
|
||||
(convert(f + offsets[Is], std::get<Is>(t)), 0)...};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Packet>
|
||||
struct ToOSCTypes
|
||||
{
|
||||
|
||||
static index numTags(typename BufferT::type) { return 1; }
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<
|
||||
std::is_integral<T>::value || std::is_floating_point<T>::value, index>
|
||||
numTags(T)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static index numTags(std::string)
|
||||
{
|
||||
return 1;;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static index numTags(FluidTensor<T, 1> s)
|
||||
{
|
||||
return s.size();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static index numTags(std::tuple<Ts...>&&)
|
||||
{
|
||||
return std::tuple_size<std::tuple<Ts...>>::value;
|
||||
};
|
||||
|
||||
|
||||
static void getTag(Packet& p, typename BufferT::type) { p.addtag('i'); }
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_integral<std::decay_t<T>>::value>
|
||||
getTag(Packet& p, T&&) { p.addtag('i'); }
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_floating_point<std::decay_t<T>>::value>
|
||||
getTag(Packet& p, T&&) { p.addtag('f'); }
|
||||
|
||||
static void getTag (Packet& p, std::string) { p.addtag('s'); }
|
||||
|
||||
template <typename T>
|
||||
static void getTag(Packet& p, FluidTensor<T, 1> x)
|
||||
{
|
||||
T dummy{};
|
||||
for (int i = 0; i < x.rows(); i++)
|
||||
getTag(p, dummy);
|
||||
}
|
||||
|
||||
template <typename... Ts, size_t... Is>
|
||||
static void getTag(Packet& p, std::tuple<Ts...>&& t)
|
||||
{
|
||||
ForEach(t,[&p](auto& x){getTag(p,x);});
|
||||
}
|
||||
|
||||
|
||||
static void convert(Packet& p, typename BufferT::type buf)
|
||||
{
|
||||
p.addi(static_cast<SCBufferAdaptor*>(buf.get())->bufnum());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_integral<T>::value>
|
||||
convert(Packet& p, T x)
|
||||
{
|
||||
p.addi(x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::enable_if_t<std::is_floating_point<T>::value>
|
||||
convert(Packet& p, T x)
|
||||
{
|
||||
p.addf(x);
|
||||
}
|
||||
|
||||
static void convert(Packet& p, std::string s)
|
||||
{
|
||||
p.adds(s.c_str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void convert(Packet& p, FluidTensor<T, 1> s)
|
||||
{
|
||||
for(auto& x: s) convert(p,x);
|
||||
}
|
||||
|
||||
template <typename... Ts, size_t... Is>
|
||||
static void convert(Packet& p, std::tuple<Ts...>&& t)
|
||||
{
|
||||
ForEach(t,[&p](auto& x){ convert(p,x);});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "SCBufferAdaptor.hpp"
|
||||
|
||||
namespace fluid {
|
||||
namespace client {
|
||||
namespace impl {
|
||||
|
||||
template <size_t N, typename T>
|
||||
struct AssignBuffer
|
||||
{
|
||||
void operator()(const typename BufferT::type& p, World* w)
|
||||
{
|
||||
if (auto b = static_cast<SCBufferAdaptor*>(p.get())) b->assignToRT(w);
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N, typename T>
|
||||
struct CleanUpBuffer
|
||||
{
|
||||
void operator()(const typename BufferT::type& p)
|
||||
{
|
||||
if (auto b = static_cast<SCBufferAdaptor*>(p.get())) b->cleanUp();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <SC_ReplyImpl.hpp>
|
||||
|
||||
namespace fluid{
|
||||
namespace client{
|
||||
|
||||
void* copyReplyAddress(InterfaceTable* ft, World* inWorld, void* inreply)
|
||||
{
|
||||
|
||||
if(! inreply) return nullptr;
|
||||
|
||||
ReplyAddress* reply = (ReplyAddress*)ft->fRTAlloc(inWorld, sizeof(ReplyAddress));
|
||||
|
||||
*reply = *(static_cast<ReplyAddress*>(inreply));
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void deleteReplyAddress(InterfaceTable* ft, World* inWorld, void* inreply)
|
||||
{
|
||||
if(! inreply) return;
|
||||
ft->fRTFree(inWorld,(ReplyAddress*)inreply);
|
||||
}
|
||||
|
||||
void* copyReplyAddress(void* inreply)
|
||||
{
|
||||
|
||||
if(! inreply) return nullptr;
|
||||
|
||||
ReplyAddress* reply = new ReplyAddress();
|
||||
|
||||
*reply = *(static_cast<ReplyAddress*>(inreply));
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void deleteReplyAddress(void* inreply)
|
||||
{
|
||||
if(! inreply) return;
|
||||
delete (ReplyAddress*)inreply;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "NonRealtime.hpp"
|
||||
#include "Realtime.hpp"
|
||||
|
||||
namespace fluid {
|
||||
namespace client {
|
||||
|
||||
template <typename Client> class FluidSCWrapper;
|
||||
|
||||
namespace impl {
|
||||
|
||||
template <typename Client,typename Wrapper>
|
||||
struct BaseChooser
|
||||
{
|
||||
template<bool>struct Choose
|
||||
{
|
||||
using type = NonRealTime<Client,Wrapper>;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Choose<true>
|
||||
{
|
||||
using type = RealTime<Client,Wrapper>;
|
||||
};
|
||||
|
||||
using RT = typename Client::isRealTime;
|
||||
|
||||
static constexpr bool UseRealTime = RT::value && !IsModel_t<Client>::value;
|
||||
|
||||
using type = typename Choose<UseRealTime>::type;
|
||||
};
|
||||
|
||||
template <typename Client,typename Wrapper>
|
||||
using BaseChooser_t = typename BaseChooser<Client,Wrapper>::type;
|
||||
|
||||
|
||||
template <typename Client>
|
||||
using FluidSCWrapperBase = BaseChooser_t<Client,FluidSCWrapper<Client>>;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,268 @@
|
||||
#pragma once
|
||||
|
||||
#include "ArgsFromClient.hpp"
|
||||
#include "ArgsToClient.hpp"
|
||||
#include <scsynthsend.h>
|
||||
|
||||
namespace fluid {
|
||||
namespace client {
|
||||
|
||||
template<typename FluidSCWrapper, typename Client>
|
||||
struct FluidSCMessaging{
|
||||
|
||||
static auto getInterfaceTable(){ return FluidSCWrapper::getInterfaceTable(); }
|
||||
static auto getName(){ return FluidSCWrapper::getName(); }
|
||||
|
||||
|
||||
template <size_t N>
|
||||
struct MessageDispatchCmd
|
||||
{
|
||||
using Descriptor = typename Client::MessageSetType::template MessageDescriptorAt<N>;
|
||||
using ArgTuple = typename Descriptor::ArgumentTypes;
|
||||
using ReturnType = typename Descriptor::ReturnType;
|
||||
using IndexList = typename Descriptor::IndexList;
|
||||
|
||||
static constexpr size_t Message = N;
|
||||
index id;
|
||||
ArgTuple args;
|
||||
ReturnType result;
|
||||
std::string name;
|
||||
IndexList argIndices;
|
||||
void* replyAddr{nullptr};
|
||||
};
|
||||
|
||||
|
||||
template <size_t N, typename T>
|
||||
struct SetupMessageCmd
|
||||
{
|
||||
|
||||
void operator()(const T& message)
|
||||
{
|
||||
static std::string messageName = std::string{getName()} + '/' + message.name;
|
||||
auto ft = getInterfaceTable();
|
||||
ft->fDefinePlugInCmd(messageName.c_str(), doMessage<N>,(void*)messageName.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Message>
|
||||
static bool validateMessageArgs(Message* msg, sc_msg_iter* inArgs)
|
||||
{
|
||||
using ArgTuple = decltype(msg->args);
|
||||
|
||||
std::string tags(inArgs->tags + inArgs->count);//evidently this needs commenting: construct string at pointer offset by tag count, to pick up args
|
||||
bool willContinue = true;
|
||||
bool typesMatch = true;
|
||||
|
||||
auto& args = msg->args;
|
||||
|
||||
constexpr size_t expectedArgCount = std::tuple_size<ArgTuple>::value;
|
||||
|
||||
/// TODO this squawks if we have a completion message, so maybe we can check if extra arg is a 'b' and squawk if not?
|
||||
// if(tags.size() > expectedArgCount)
|
||||
// {
|
||||
// std::cout << "WARNING: " << msg->name << " received more arguments than expected (got "
|
||||
// << tags.size() << ", expect " << expectedArgCount << ")\n";
|
||||
// }
|
||||
|
||||
if(tags.size() < expectedArgCount)
|
||||
{
|
||||
std::cout << "ERROR: " << msg->name << " received fewer arguments than expected (got "
|
||||
<< tags.size() << ", expect " << expectedArgCount << ")\n";
|
||||
willContinue = false;
|
||||
}
|
||||
|
||||
auto tagsIter = tags.begin();
|
||||
auto tagsEnd = tags.end();
|
||||
ForEach(args,[&typesMatch,&tagsIter,&tagsEnd](auto& arg){
|
||||
if(tagsIter == tagsEnd)
|
||||
{
|
||||
typesMatch = false;
|
||||
return;
|
||||
}
|
||||
char t = *(tagsIter++);
|
||||
typesMatch = typesMatch && ParamReader<sc_msg_iter>::argTypeOK(arg,t);
|
||||
});
|
||||
|
||||
willContinue = willContinue && typesMatch;
|
||||
|
||||
if(!typesMatch)
|
||||
{
|
||||
auto& report = std::cout;
|
||||
report << "ERROR: " << msg->name << " type signature incorrect.\nExpect: (";
|
||||
size_t i{0};
|
||||
ForEach(args, [&i](auto& x){
|
||||
std::cout << ParamReader<sc_msg_iter>::argTypeToString(x);
|
||||
if(i < (std::tuple_size<ArgTuple>::value - 1 ) )
|
||||
{
|
||||
std::cout << " ,";
|
||||
}
|
||||
i++;
|
||||
});
|
||||
report << ")\nReceived: (";
|
||||
i = 0;
|
||||
for(auto t: tags)
|
||||
{
|
||||
report << ParamReader<sc_msg_iter>::oscTagToString(t);
|
||||
if( i < ( tags.size() - 1 ) )
|
||||
{
|
||||
report << ", ";
|
||||
}
|
||||
i++;
|
||||
}
|
||||
report << ")\n";
|
||||
}
|
||||
|
||||
return willContinue;
|
||||
}
|
||||
|
||||
|
||||
template<size_t N>
|
||||
static void doMessage(World* inWorld, void* inUserData, struct sc_msg_iter* args, void* replyAddr)
|
||||
{
|
||||
using MessageData = MessageDispatchCmd<N>;
|
||||
|
||||
auto msg = new MessageData();
|
||||
|
||||
msg->id = args->geti();
|
||||
msg->replyAddr = copyReplyAddress(replyAddr);
|
||||
///TODO make this step contingent on verbosity or something, in the name of effieciency
|
||||
bool willContinue = validateMessageArgs(msg, args);
|
||||
|
||||
if(!willContinue)
|
||||
{
|
||||
delete msg;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
msg->name = std::string{'/'} + (const char*)(inUserData);
|
||||
|
||||
ForEach(msg-> args,[inWorld,&args](auto& thisarg)
|
||||
{
|
||||
thisarg = ParamReader<sc_msg_iter>::fromArgs(inWorld, *args,thisarg,0);
|
||||
});
|
||||
|
||||
size_t completionMsgSize{args ? args->getbsize() : 0};
|
||||
assert(completionMsgSize <= std::numeric_limits<int>::max());
|
||||
char* completionMsgData = nullptr;
|
||||
|
||||
if (completionMsgSize) {
|
||||
completionMsgData = (char*)getInterfaceTable()->fRTAlloc(inWorld, completionMsgSize);
|
||||
args->getb(completionMsgData, completionMsgSize);
|
||||
}
|
||||
|
||||
|
||||
getInterfaceTable()->fDoAsynchronousCommand(inWorld, replyAddr, getName(), msg,
|
||||
[](World* world, void* data) // NRT thread: invocation
|
||||
{
|
||||
MessageData* m = static_cast<MessageData*>(data);
|
||||
using ReturnType = typename MessageData::ReturnType;
|
||||
|
||||
if(auto ptr = FluidSCWrapper::get(m->id).lock())
|
||||
{
|
||||
m->result =
|
||||
ReturnType{invokeImpl<N>(ptr->mClient, m->args,m->argIndices)};
|
||||
|
||||
if (!m->result.ok())
|
||||
FluidSCWrapper::printResult(world, m->result);
|
||||
} else FluidSCWrapper::printNotFound(m->id);
|
||||
|
||||
return true;
|
||||
},
|
||||
[](World* world, void* data) // RT thread: buffer swap (and possible completion messages)
|
||||
{
|
||||
MessageData* m = static_cast<MessageData*>(data);
|
||||
MessageData::Descriptor::template forEachArg<typename BufferT::type,
|
||||
impl::AssignBuffer>(m->args,
|
||||
world);
|
||||
return true;
|
||||
},
|
||||
[](World*, void* data) // NRT Thread: Send reply
|
||||
{
|
||||
MessageData* m = static_cast<MessageData*>(data);
|
||||
if(m->result.status() != Result::Status::kError)
|
||||
messageOutput(m->name, m->id, m->result, m->replyAddr);
|
||||
return false;
|
||||
},
|
||||
[](World*, void* data) // RT thread: clean up
|
||||
{
|
||||
MessageData* m = static_cast<MessageData*>(data);
|
||||
delete m;
|
||||
},
|
||||
static_cast<int>(completionMsgSize), completionMsgData);
|
||||
}
|
||||
|
||||
template <size_t N, typename ArgsTuple, size_t... Is> // Call from NRT
|
||||
static decltype(auto) invokeImpl(Client& x, ArgsTuple& args,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
return x.template invoke<N>(x, std::get<Is>(args)...);
|
||||
}
|
||||
|
||||
template <typename T> // call from RT
|
||||
static void messageOutput(const std::string& s, index id, MessageResult<T>& result, void* replyAddr)
|
||||
{
|
||||
index numTags = ToOSCTypes<small_scpacket>::numTags(static_cast<T>(result));
|
||||
if(numTags > 2048)
|
||||
{
|
||||
std::cout << "ERROR: Message response too big to send (" << asUnsigned(numTags) * sizeof(float) << " bytes)." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
small_scpacket packet;
|
||||
packet.adds(s.c_str());
|
||||
packet.maketags(static_cast<int>(numTags) + 2);
|
||||
packet.addtag(',');
|
||||
packet.addtag('i');
|
||||
ToOSCTypes<small_scpacket>::getTag(packet, static_cast<T>(result));
|
||||
|
||||
packet.addi(static_cast<int>(id));
|
||||
ToOSCTypes<small_scpacket>::convert(packet, static_cast<T>(result));
|
||||
|
||||
if(replyAddr)
|
||||
::SendReply(static_cast<ReplyAddress*>(replyAddr),packet.data(),static_cast<int>(packet.size()));
|
||||
}
|
||||
|
||||
static void messageOutput(const std::string& s,index id, MessageResult<void>&, void* replyAddr)
|
||||
{
|
||||
small_scpacket packet;
|
||||
packet.adds(s.c_str());
|
||||
packet.maketags(2);
|
||||
packet.addtag(',');
|
||||
packet.addtag('i');
|
||||
packet.addi(static_cast<int>(id));
|
||||
|
||||
if(replyAddr)
|
||||
::SendReply(static_cast<ReplyAddress*>(replyAddr),packet.data(),static_cast<int>(packet.size()));
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static void messageOutput(const std::string& s, index id, MessageResult<std::tuple<Ts...>>& result, void* replyAddr)
|
||||
{
|
||||
using T = std::tuple<Ts...>;
|
||||
|
||||
index numTags = ToOSCTypes<small_scpacket>::numTags(static_cast<T>(result));
|
||||
if(numTags > 2048)
|
||||
{
|
||||
std::cout << "ERROR: Message response too big to send (" << asUnsigned(numTags) * sizeof(float) << " bytes)." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
small_scpacket packet;
|
||||
packet.adds(s.c_str());
|
||||
packet.maketags(static_cast<int>(numTags + 3));
|
||||
packet.addtag(',');
|
||||
packet.addtag('i');
|
||||
ToOSCTypes<small_scpacket>::getTag(packet,static_cast<T>(result));
|
||||
|
||||
packet.addi(static_cast<int>(id));
|
||||
ToOSCTypes<small_scpacket>::convert(packet, static_cast<T>(result));
|
||||
|
||||
if(replyAddr)
|
||||
::SendReply(static_cast<ReplyAddress*>(replyAddr),packet.data(),static_cast<int>(packet.size()));
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <clients/nrt/FluidSharedInstanceAdaptor.hpp>
|
||||
#include <clients/common/FluidNRTClientWrapper.hpp>
|
||||
#include <clients/common/SharedClientUtils.hpp>
|
||||
|
||||
namespace fluid {
|
||||
namespace client {
|
||||
namespace impl {
|
||||
/// Named, shared clients already have a lookup table in their adaptor class
|
||||
template <typename T>
|
||||
struct IsNamedShared
|
||||
{
|
||||
using type = std::false_type;
|
||||
};
|
||||
|
||||
//TODO: make less tied to current implementation
|
||||
template <typename T>
|
||||
struct IsNamedShared<NRTThreadingAdaptor<NRTSharedInstanceAdaptor<T>>>
|
||||
{
|
||||
using type = std::true_type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using IsNamedShared_t = typename IsNamedShared<T>::type;
|
||||
|
||||
template<typename T>
|
||||
constexpr bool IsNamedShared_v = IsNamedShared_t<T>::value;
|
||||
|
||||
/// Models don't, but still need to survive CMD-.
|
||||
template<typename T>
|
||||
struct IsModel
|
||||
{
|
||||
using type = std::false_type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IsModel<NRTThreadingAdaptor<ClientWrapper<T>>>
|
||||
{
|
||||
using type = typename ClientWrapper<T>::isModelObject;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IsModel<ClientWrapper<T>>
|
||||
{
|
||||
using type = typename ClientWrapper<T>::isModelObject;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using IsModel_t = typename IsModel<T>::type;
|
||||
|
||||
template<typename T>
|
||||
constexpr bool IsModel_v = IsModel_t<T>::value;
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,957 @@
|
||||
#pragma once
|
||||
|
||||
#include "BufferFuncs.hpp"
|
||||
#include "Meta.hpp"
|
||||
#include "SCBufferAdaptor.hpp"
|
||||
#include "CopyReplyAddress.hpp"
|
||||
#include "Messaging.hpp"
|
||||
#include "RealTimeBase.hpp"
|
||||
|
||||
#include <clients/common/FluidBaseClient.hpp>
|
||||
#include <SC_PlugIn.hpp>
|
||||
#include <SC_ReplyImpl.hpp>
|
||||
#include <scsynthsend.h>
|
||||
#include <map>
|
||||
|
||||
namespace fluid {
|
||||
namespace client {
|
||||
namespace impl {
|
||||
|
||||
/// Non Real Time Processor
|
||||
|
||||
template <typename Client, typename Wrapper>
|
||||
class NonRealTime : public SCUnit
|
||||
{
|
||||
using Params = typename Client::ParamSetType;
|
||||
|
||||
template<typename T,typename...Args>
|
||||
static T* rtalloc(World* world,Args&&...args)
|
||||
{
|
||||
void* space = getInterfaceTable()->fRTAlloc(world, sizeof(T));
|
||||
return new (space) T{std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
/// Instance cache
|
||||
struct CacheEntry
|
||||
{
|
||||
|
||||
CacheEntry(const Params& p):mParams{p},mClient{mParams}
|
||||
{}
|
||||
|
||||
Params mParams;
|
||||
Client mClient;
|
||||
bool mDone{false};
|
||||
};
|
||||
|
||||
using CacheEntryPointer = std::shared_ptr<CacheEntry>;
|
||||
using WeakCacheEntryPointer = std::weak_ptr<CacheEntry>; //could use weak_type in 17
|
||||
using Cache = std::map<index,CacheEntryPointer>;
|
||||
|
||||
static bool isNull(WeakCacheEntryPointer const& weak) {
|
||||
return !weak.owner_before(WeakCacheEntryPointer{}) && !WeakCacheEntryPointer{}.owner_before(weak);
|
||||
}
|
||||
|
||||
static Cache mCache;
|
||||
|
||||
public:
|
||||
static WeakCacheEntryPointer get(index id)
|
||||
{
|
||||
auto lookup = mCache.find(id);
|
||||
return lookup == mCache.end() ? WeakCacheEntryPointer() : lookup->second;
|
||||
}
|
||||
|
||||
static WeakCacheEntryPointer add(index id, const Params& params)
|
||||
{
|
||||
if(isNull(get(id)))
|
||||
{
|
||||
auto result = mCache.emplace(id,
|
||||
std::make_shared<CacheEntry>(params));
|
||||
|
||||
return result.second ? (result.first)->second : WeakCacheEntryPointer(); //sob
|
||||
}
|
||||
else //client has screwed up
|
||||
{
|
||||
std::cout << "ERROR: " << Wrapper::getName() << " ID " << id << " already in use\n";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
static void remove(index id)
|
||||
{
|
||||
mCache.erase(id);
|
||||
}
|
||||
|
||||
static void printNotFound(index id)
|
||||
{
|
||||
std::cout << "ERROR: " << Wrapper::getName() << " no instance with ID " << id << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
static InterfaceTable* getInterfaceTable() { return Wrapper::getInterfaceTable() ;}
|
||||
|
||||
template <size_t N, typename T>
|
||||
using ParamsFromOSC = typename ClientParams<Wrapper>::template Setter<sc_msg_iter, N, T>;
|
||||
|
||||
template <size_t N, typename T>
|
||||
using ParamsFromSynth = typename ClientParams<Wrapper>::template Setter<impl::FloatControlsIter, N, T>;
|
||||
|
||||
|
||||
struct NRTCommand
|
||||
{
|
||||
NRTCommand(World*, sc_msg_iter* args, void* replyAddr, bool consumeID = true)
|
||||
{
|
||||
auto count = args->count;
|
||||
auto pos = args->rdpos;
|
||||
|
||||
mID = args->geti();
|
||||
|
||||
if(!consumeID)
|
||||
{
|
||||
args->count = count;
|
||||
args->rdpos = pos;
|
||||
}
|
||||
|
||||
if(replyAddr)
|
||||
mReplyAddress = copyReplyAddress(replyAddr);
|
||||
}
|
||||
|
||||
~NRTCommand()
|
||||
{
|
||||
if(mReplyAddress) deleteReplyAddress(mReplyAddress);
|
||||
}
|
||||
|
||||
NRTCommand(){}
|
||||
|
||||
explicit NRTCommand(index id):mID{id}{}
|
||||
|
||||
bool stage2(World*) { return true; } //nrt
|
||||
bool stage3(World*) { return true; } //rt
|
||||
bool stage4(World*) { return false; } //nrt
|
||||
void cleanup(World*) {} //rt
|
||||
|
||||
void sendReply(const char* name,bool success)
|
||||
{
|
||||
if(mReplyAddress)
|
||||
{
|
||||
std::string slash{"/"};
|
||||
small_scpacket packet;
|
||||
packet.adds((slash+name).c_str());
|
||||
packet.maketags(3);
|
||||
packet.addtag(',');
|
||||
packet.addtag('i');
|
||||
packet.addtag('i');
|
||||
packet.addi(success);
|
||||
packet.addi(static_cast<int>(mID));
|
||||
|
||||
::SendReply(static_cast<ReplyAddress*>(mReplyAddress),packet.data(), static_cast<int>(packet.size()));
|
||||
}
|
||||
}
|
||||
// protected:
|
||||
index mID;
|
||||
void* mReplyAddress{nullptr};
|
||||
};
|
||||
|
||||
struct CommandNew : public NRTCommand
|
||||
{
|
||||
CommandNew(World* world, sc_msg_iter* args,void* replyAddr)
|
||||
: NRTCommand{world,args, replyAddr, !IsNamedShared_v<Client>},
|
||||
mParams{Client::getParameterDescriptors()}
|
||||
{
|
||||
mParams.template setParameterValuesRT<ParamsFromOSC>(nullptr, world, *args);
|
||||
}
|
||||
|
||||
CommandNew(index id, World*, FloatControlsIter& args, Unit* x)
|
||||
:NRTCommand{id},
|
||||
mParams{Client::getParameterDescriptors()}
|
||||
{
|
||||
mParams.template setParameterValuesRT<ParamsFromSynth>(nullptr, x, args);
|
||||
}
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
static std::string cmd = std::string(Wrapper::getName()) + "/new";
|
||||
return cmd.c_str();
|
||||
}
|
||||
|
||||
bool stage2(World*)
|
||||
{
|
||||
// auto entry = ;
|
||||
mResult = (!isNull(add(NRTCommand::mID, mParams)));
|
||||
|
||||
//Sigh. The cache entry above has both the client instance and main params instance.
|
||||
// The client is linked to the params by reference; I've not got the in-place constrction
|
||||
// working properly so that params are in their final resting place by the time we make the client
|
||||
// so (for) now we need to manually repoint the client to the correct place. Or badness.
|
||||
if(mResult)
|
||||
{
|
||||
auto ptr = get(NRTCommand::mID).lock();
|
||||
ptr->mClient.setParams(ptr->mParams);
|
||||
}
|
||||
|
||||
NRTCommand::sendReply(name(),mResult);
|
||||
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mResult;
|
||||
Params mParams;
|
||||
};
|
||||
|
||||
struct CommandFree: public NRTCommand
|
||||
{
|
||||
using NRTCommand::NRTCommand;
|
||||
|
||||
|
||||
template<bool b>
|
||||
struct CancelCheck{
|
||||
void operator()(index id)
|
||||
{
|
||||
if(auto ptr = get(id).lock())
|
||||
{
|
||||
auto& client = ptr->mClient;
|
||||
if(!client.synchronous() && client.state() == ProcessState::kProcessing)
|
||||
std::cout << Wrapper::getName()
|
||||
<< ": Processing cancelled"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CancelCheck<true>{
|
||||
void operator()(index)
|
||||
{}
|
||||
};
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
static std::string cmd = std::string(Wrapper::getName()) + "/free";
|
||||
return cmd.c_str();
|
||||
}
|
||||
|
||||
bool stage2(World*)
|
||||
{
|
||||
CancelCheck<IsRTQueryModel>()(NRTCommand::mID);
|
||||
remove(NRTCommand::mID);
|
||||
NRTCommand::sendReply(name(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// Not registered as a PlugInCmd. Triggered by worker thread callback
|
||||
struct CommandAsyncComplete: public NRTCommand
|
||||
{
|
||||
CommandAsyncComplete(World*, index id, void* replyAddress)
|
||||
{
|
||||
NRTCommand::mID = id;
|
||||
NRTCommand::mReplyAddress = replyAddress;
|
||||
}
|
||||
|
||||
static const char* name() { return CommandProcess::name(); }
|
||||
|
||||
bool stage2(World* world)
|
||||
{
|
||||
|
||||
// std::cout << "In Async completion\n";
|
||||
if(auto ptr = get(NRTCommand::mID).lock())
|
||||
{
|
||||
Result r;
|
||||
auto& client = ptr->mClient;
|
||||
ProcessState s = client.checkProgress(r);
|
||||
if (s == ProcessState::kDone || s == ProcessState::kDoneStillProcessing)
|
||||
{
|
||||
if (r.status() == Result::Status::kCancelled)
|
||||
{
|
||||
std::cout << Wrapper::getName()
|
||||
<< ": Processing cancelled"
|
||||
<< std::endl;
|
||||
ptr->mDone = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
client.checkProgress(r);
|
||||
mSuccess = !(r.status() == Result::Status::kError);
|
||||
if (!r.ok())
|
||||
{
|
||||
Wrapper::printResult(world,r);
|
||||
if(r.status() == Result::Status::kError)
|
||||
{
|
||||
ptr->mDone = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool stage3(World* world)
|
||||
{
|
||||
if(auto ptr = get(NRTCommand::mID).lock())
|
||||
{
|
||||
auto& params = ptr->mParams;
|
||||
params.template forEachParamType<BufferT, AssignBuffer>(world);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool stage4(World*) //nrt
|
||||
{
|
||||
if(auto ptr = get(NRTCommand::mID).lock())
|
||||
{
|
||||
ptr->mParams.template forEachParamType<BufferT, impl::CleanUpBuffer>();
|
||||
|
||||
if(NRTCommand::mID >= 0 && NRTCommand::mReplyAddress)
|
||||
{
|
||||
NRTCommand::sendReply(name(),mSuccess);
|
||||
}
|
||||
ptr->mDone = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mSuccess;
|
||||
};
|
||||
|
||||
|
||||
static void doProcessCallback(World* world, index id,size_t completionMsgSize,char* completionMessage,void* replyAddress)
|
||||
{
|
||||
auto ft = getInterfaceTable();
|
||||
struct Context{
|
||||
World* mWorld;
|
||||
index mID;
|
||||
size_t mCompletionMsgSize;
|
||||
char* mCompletionMessage;
|
||||
void* mReplyAddress;
|
||||
};
|
||||
|
||||
Context* c = new Context{world,id,completionMsgSize,completionMessage,replyAddress};
|
||||
|
||||
auto launchCompletionFromNRT = [](FifoMsg* inmsg)
|
||||
{
|
||||
auto runCompletion = [](FifoMsg* msg){
|
||||
// std::cout << "In FIFOMsg\n";
|
||||
Context* c = static_cast<Context*>(msg->mData);
|
||||
World* world = c->mWorld;
|
||||
index id = c->mID;
|
||||
auto ft = getInterfaceTable();
|
||||
void* space = ft->fRTAlloc(world,sizeof(CommandAsyncComplete));
|
||||
CommandAsyncComplete* cmd = new (space) CommandAsyncComplete(world, id,c->mReplyAddress);
|
||||
runAsyncCommand(world, cmd, c->mReplyAddress, c->mCompletionMsgSize, c->mCompletionMessage);
|
||||
};
|
||||
|
||||
auto tidyup = [](FifoMsg* msg)
|
||||
{
|
||||
Context* c = static_cast<Context*>(msg->mData);
|
||||
delete c;
|
||||
};
|
||||
|
||||
auto ft = getInterfaceTable();
|
||||
FifoMsg fwd = *inmsg;
|
||||
fwd.Set(inmsg->mWorld, runCompletion, tidyup, inmsg->mData);
|
||||
if(inmsg->mWorld->mRunning)
|
||||
ft->fSendMsgToRT(inmsg->mWorld,fwd);
|
||||
};
|
||||
|
||||
FifoMsg msg;
|
||||
msg.Set(world, launchCompletionFromNRT, nullptr, c);
|
||||
|
||||
if(world->mRunning) ft->fSendMsgFromRT(world,msg);
|
||||
}
|
||||
|
||||
struct CommandProcess: public NRTCommand
|
||||
{
|
||||
CommandProcess(World* world, sc_msg_iter* args, void* replyAddr): NRTCommand{world, args, replyAddr}
|
||||
{
|
||||
auto& ar = *args;
|
||||
|
||||
if(auto ptr = get(NRTCommand::mID).lock())
|
||||
{
|
||||
ptr->mDone = false;
|
||||
ptr->mParams.template setParameterValuesRT<ParamsFromOSC>(nullptr, world, ar);
|
||||
mSynchronous = static_cast<bool>(ar.geti());
|
||||
} //if this fails, we'll hear about it in stage2 anyway
|
||||
}
|
||||
|
||||
explicit CommandProcess(index id,bool synchronous):NRTCommand{id},mSynchronous(synchronous)
|
||||
{}
|
||||
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
static std::string cmd = std::string(Wrapper::getName()) + "/process";
|
||||
return cmd.c_str();
|
||||
}
|
||||
|
||||
bool stage2(World* world)
|
||||
{
|
||||
if(auto ptr = get(NRTCommand::mID).lock())
|
||||
{
|
||||
auto& params = ptr->mParams;
|
||||
auto& client = ptr->mClient;
|
||||
|
||||
// if(mOSCData)
|
||||
// {
|
||||
// params.template setParameterValuesRT<ParamsFromOSC>(nullptr, world, *mOSCData);
|
||||
// mSynchronous = static_cast<bool>(mOSCData->geti());
|
||||
// }
|
||||
|
||||
Result result = validateParameters(params);
|
||||
Wrapper::printResult(world, result);
|
||||
if (result.status() != Result::Status::kError)
|
||||
{
|
||||
// client.done()
|
||||
client.setSynchronous(mSynchronous);
|
||||
index id = NRTCommand::mID;
|
||||
size_t completionMsgSize = mCompletionMsgSize;
|
||||
char* completionMessage = mCompletionMessage;
|
||||
void* replyAddress = copyReplyAddress(NRTCommand::mReplyAddress);
|
||||
|
||||
auto callback = [world,id,completionMsgSize,completionMessage,replyAddress](){
|
||||
doProcessCallback(world,id,completionMsgSize,completionMessage,replyAddress);
|
||||
};
|
||||
|
||||
result = mSynchronous ? client.enqueue(params) : client.enqueue(params,callback);
|
||||
Wrapper::printResult(world, result);
|
||||
|
||||
if(result.ok())
|
||||
{
|
||||
ptr->mDone = false;
|
||||
mResult = client.process();
|
||||
Wrapper::printResult(world,mResult);
|
||||
|
||||
bool error =mResult.status() == Result::Status::kError;
|
||||
|
||||
if(error) ptr->mDone = true;
|
||||
return mSynchronous && !error;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mResult = Result{Result::Status::kError, "No ", Wrapper::getName(), " with ID ", NRTCommand::mID};
|
||||
Wrapper::printResult(world,mResult);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//Only for blocking execution
|
||||
bool stage3(World* world) //rt
|
||||
{
|
||||
if(auto ptr = get(NRTCommand::mID).lock())
|
||||
{
|
||||
ptr->mParams.template forEachParamType<BufferT, AssignBuffer>(world);
|
||||
// NRTCommand::sendReply(world, name(), mResult.ok());
|
||||
return true;
|
||||
}
|
||||
// std::cout << "Ohno\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
//Only for blocking execution
|
||||
bool stage4(World*) //nrt
|
||||
{
|
||||
if(auto ptr = get(NRTCommand::mID).lock())
|
||||
{
|
||||
ptr->mParams.template forEachParamType<BufferT, impl::CleanUpBuffer>();
|
||||
|
||||
if(NRTCommand::mID >= 0 && mSynchronous)
|
||||
NRTCommand::sendReply(name(), mResult.ok());
|
||||
ptr->mDone = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool synchronous()
|
||||
{
|
||||
return mSynchronous;
|
||||
}
|
||||
|
||||
void addCompletionMessage(size_t size, char* message)//, void* addr)
|
||||
{
|
||||
mCompletionMsgSize = size;
|
||||
mCompletionMessage = message;
|
||||
}
|
||||
|
||||
// private:
|
||||
Result mResult;
|
||||
bool mSynchronous;
|
||||
size_t mCompletionMsgSize{0};
|
||||
char* mCompletionMessage{nullptr};
|
||||
};
|
||||
|
||||
struct CommandProcessNew: public NRTCommand
|
||||
{
|
||||
CommandProcessNew(World* world, sc_msg_iter* args,void* replyAddr)
|
||||
: mNew{world, args, replyAddr},
|
||||
mProcess{mNew.mID,false}
|
||||
{
|
||||
mProcess.mSynchronous = args->geti();
|
||||
mProcess.mReplyAddress = mNew.mReplyAddress;
|
||||
}
|
||||
|
||||
CommandProcessNew(index id, World* world, FloatControlsIter& args, Unit* x)
|
||||
: mNew{id, world, args, x},
|
||||
mProcess{id}
|
||||
{}
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
static std::string cmd = std::string(Wrapper::getName()) + "/processNew";
|
||||
return cmd.c_str();
|
||||
}
|
||||
|
||||
bool stage2(World* world)
|
||||
{
|
||||
return mNew.stage2(world) ? mProcess.stage2(world) : false;
|
||||
}
|
||||
|
||||
bool stage3(World* world) //rt
|
||||
{
|
||||
return mProcess.stage3(world);
|
||||
}
|
||||
|
||||
bool stage4(World* world) //nrt
|
||||
{
|
||||
return mProcess.stage4(world);
|
||||
}
|
||||
|
||||
void cleanup(World* world)
|
||||
{
|
||||
mProcess.mReplyAddress = nullptr;
|
||||
mProcess.cleanup(world);
|
||||
}
|
||||
|
||||
bool synchronous()
|
||||
{
|
||||
return mProcess.synchronous();
|
||||
}
|
||||
|
||||
void addCompletionMessage(size_t size, char* message)
|
||||
{
|
||||
mProcess.addCompletionMessage(size, message);
|
||||
}
|
||||
|
||||
private:
|
||||
CommandNew mNew;
|
||||
CommandProcess mProcess;
|
||||
};
|
||||
|
||||
|
||||
struct CommandCancel: public NRTCommand
|
||||
{
|
||||
CommandCancel(World* world, sc_msg_iter* args, void* replyAddr)
|
||||
: NRTCommand{world, args, replyAddr}
|
||||
{}
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
static std::string cmd = std::string(Wrapper::getName()) + "/cancel";
|
||||
return cmd.c_str();
|
||||
}
|
||||
|
||||
bool stage2(World*)
|
||||
{
|
||||
if(auto ptr = get(NRTCommand::mID).lock())
|
||||
{
|
||||
auto& client = ptr->mClient;
|
||||
if(!client.synchronous())
|
||||
{
|
||||
client.cancel();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct CommandSetParams: public NRTCommand
|
||||
{
|
||||
CommandSetParams(World* world, sc_msg_iter* args, void* replyAddr)
|
||||
: NRTCommand{world, args, replyAddr}
|
||||
{
|
||||
auto& ar = *args;
|
||||
if(auto ptr = get(NRTCommand::mID).lock())
|
||||
{
|
||||
ptr->mParams.template setParameterValuesRT<ParamsFromOSC>(nullptr, world, ar);
|
||||
Result result = validateParameters(ptr->mParams);
|
||||
ptr->mClient.setParams(ptr->mParams);
|
||||
} else printNotFound(NRTCommand::mID);
|
||||
}
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
static std::string cmd = std::string(Wrapper::getName()) + "/setParams";
|
||||
return cmd.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Command>
|
||||
static auto runAsyncCommand(World* world, Command* cmd, void* replyAddr,
|
||||
size_t completionMsgSize, char* completionMsgData)
|
||||
{
|
||||
auto ft = getInterfaceTable();
|
||||
|
||||
return ft->fDoAsynchronousCommand(world, replyAddr,Command::name(),cmd,
|
||||
[](World* w, void* d) { return static_cast<Command*>(d)->stage2(w); },
|
||||
[](World* w, void* d) { return static_cast<Command*>(d)->stage3(w); },
|
||||
[](World* w, void* d) { return static_cast<Command*>(d)->stage4(w); },
|
||||
[](World* w, void* d)
|
||||
{
|
||||
auto cmd = static_cast<Command*>(d);
|
||||
cmd->cleanup(w);
|
||||
cmd->~Command();
|
||||
getInterfaceTable()->fRTFree(w,d);
|
||||
},
|
||||
static_cast<int>(completionMsgSize), completionMsgData);
|
||||
}
|
||||
|
||||
|
||||
static auto runAsyncCommand(World* world, CommandProcess* cmd, void* replyAddr,
|
||||
size_t completionMsgSize, char* completionMsgData)
|
||||
{
|
||||
if(!cmd->synchronous())
|
||||
{
|
||||
cmd->addCompletionMessage(completionMsgSize,completionMsgData);
|
||||
return runAsyncCommand<CommandProcess>(world, cmd, replyAddr, 0, nullptr);
|
||||
}
|
||||
else return runAsyncCommand<CommandProcess>(world, cmd, replyAddr, completionMsgSize, completionMsgData);
|
||||
}
|
||||
|
||||
static auto runAsyncCommand(World* world, CommandProcessNew* cmd, void* replyAddr,
|
||||
size_t completionMsgSize, char* completionMsgData)
|
||||
{
|
||||
if(!cmd->synchronous())
|
||||
{
|
||||
cmd->addCompletionMessage(completionMsgSize,completionMsgData);
|
||||
return runAsyncCommand<CommandProcessNew>(world, cmd, replyAddr, 0, nullptr);
|
||||
}
|
||||
else return runAsyncCommand<CommandProcessNew>(world, cmd, replyAddr, completionMsgSize, completionMsgData);
|
||||
}
|
||||
|
||||
|
||||
template<typename Command>
|
||||
static void defineNRTCommand()
|
||||
{
|
||||
auto ft = getInterfaceTable();
|
||||
auto commandRunner = [](World* world, void*, struct sc_msg_iter* args, void* replyAddr)
|
||||
{
|
||||
|
||||
auto ft = getInterfaceTable();
|
||||
void* space = ft->fRTAlloc(world,sizeof(Command));
|
||||
Command* cmd = new (space) Command(world, args, replyAddr);
|
||||
//This is brittle, but can't think of something better offhand
|
||||
//This is the only place we can check for a completion message at the end of the OSC packet
|
||||
//beause it has to be passed on to DoAsynhronousCommand at this point. However, detecting correctly
|
||||
//relies on the Command type having fully consumed arguments from the args iterator in the constructor for cmd
|
||||
size_t completionMsgSize{args ? args->getbsize() : 0};
|
||||
assert(completionMsgSize <= std::numeric_limits<int>::max());
|
||||
char* completionMsgData = nullptr;
|
||||
|
||||
if (completionMsgSize) {
|
||||
completionMsgData = (char*)ft->fRTAlloc(world, completionMsgSize);
|
||||
args->getb(completionMsgData, completionMsgSize);
|
||||
}
|
||||
runAsyncCommand(world, cmd, replyAddr, completionMsgSize, completionMsgData);
|
||||
};
|
||||
ft->fDefinePlugInCmd(Command::name(),commandRunner,nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct NRTProgressUnit: SCUnit
|
||||
{
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
static std::string n = std::string(Wrapper::getName()) + "Monitor";
|
||||
return n.c_str();
|
||||
}
|
||||
|
||||
NRTProgressUnit()
|
||||
{
|
||||
mInterval = static_cast<index>(0.02 / controlDur());
|
||||
set_calc_function<NRTProgressUnit, &NRTProgressUnit::next>();
|
||||
Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1);
|
||||
}
|
||||
|
||||
void next(int)
|
||||
{
|
||||
if (0 == mCounter++)
|
||||
{
|
||||
index id = static_cast<index>(mInBuf[0][0]);
|
||||
if(auto ptr = get(id).lock())
|
||||
{
|
||||
if(ptr->mClient.done()) mDone = 1;
|
||||
out0(0) = static_cast<float>(ptr->mClient.progress());
|
||||
}
|
||||
else
|
||||
std::cout << "WARNING: No " << Wrapper::getName() << " with ID " << id << std::endl;
|
||||
}
|
||||
mCounter %= mInterval;
|
||||
}
|
||||
|
||||
private:
|
||||
index mInterval;
|
||||
index mCounter{0};
|
||||
};
|
||||
|
||||
|
||||
struct NRTTriggerUnit: SCUnit
|
||||
{
|
||||
|
||||
static index count(){
|
||||
static index counter = -1;
|
||||
return counter--;
|
||||
}
|
||||
|
||||
index ControlOffset() { return mSpecialIndex + 1; }
|
||||
|
||||
index ControlSize()
|
||||
{
|
||||
return index(mNumInputs)
|
||||
- mSpecialIndex //used for oddball cases
|
||||
- 3; //id + trig + blocking;
|
||||
}
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
static std::string n = std::string(Wrapper::getName()) + "Trigger";
|
||||
return n.c_str();
|
||||
}
|
||||
|
||||
NRTTriggerUnit()
|
||||
: mControlsIterator{mInBuf + ControlOffset(),ControlSize()}
|
||||
{
|
||||
mID = static_cast<index>(mInBuf[0][0]);
|
||||
if(mID == -1) mID = count();
|
||||
auto cmd = NonRealTime::rtalloc<CommandNew>(mWorld,mID,mWorld, mControlsIterator, this);
|
||||
runAsyncCommand(mWorld, cmd, nullptr, 0, nullptr);
|
||||
set_calc_function<NRTTriggerUnit, &NRTTriggerUnit::next>();
|
||||
Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1);
|
||||
}
|
||||
|
||||
~NRTTriggerUnit()
|
||||
{
|
||||
if(auto ptr = get(mID).lock())
|
||||
{
|
||||
auto cmd = NonRealTime::rtalloc<CommandFree>(mWorld,mID);
|
||||
runAsyncCommand(mWorld, cmd, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void next(int)
|
||||
{
|
||||
index triggerInput = static_cast<index>(mInBuf[static_cast<index>(mNumInputs) - 2][0]);
|
||||
mTrigger = mTrigger || triggerInput;
|
||||
|
||||
if(auto ptr = get(mID).lock())
|
||||
{
|
||||
bool trigger = (mPreviousTrigger <= 0) && mTrigger > 0;
|
||||
mPreviousTrigger = mTrigger;
|
||||
mTrigger = 0;
|
||||
auto& client = ptr->mClient;
|
||||
|
||||
if(trigger)
|
||||
{
|
||||
mControlsIterator.reset(1 + mInBuf); //add one for ID
|
||||
auto& params = ptr->mParams;
|
||||
Wrapper::setParams(this,params,mControlsIterator,true,false);
|
||||
bool blocking = mInBuf[mNumInputs - 1][0] > 0;
|
||||
CommandProcess* cmd = rtalloc<CommandProcess>(mWorld,mID,blocking);
|
||||
runAsyncCommand(mWorld,cmd, nullptr,0, nullptr);
|
||||
mRunCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDone = ptr->mDone;
|
||||
out0(0) = mDone ? 1 : static_cast<float>(client.progress());
|
||||
}
|
||||
}
|
||||
// else printNotFound(id);
|
||||
}
|
||||
|
||||
private:
|
||||
bool mPreviousTrigger{0};
|
||||
bool mTrigger{0};
|
||||
Result mResult;
|
||||
impl::FloatControlsIter mControlsIterator;
|
||||
index mID;
|
||||
index mRunCount{0};
|
||||
};
|
||||
|
||||
struct NRTModelQueryUnit: SCUnit
|
||||
{
|
||||
using Delegate = impl::RealTimeBase<Client,Wrapper>;
|
||||
|
||||
index ControlOffset() { return mSpecialIndex + 2; }
|
||||
index ControlSize()
|
||||
{
|
||||
return index(mNumInputs)
|
||||
- mSpecialIndex //used for oddball cases
|
||||
- 2; // trig + id
|
||||
}
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
static std::string n = std::string(Wrapper::getName()) + "/query";
|
||||
return n.c_str();
|
||||
}
|
||||
|
||||
NRTModelQueryUnit()
|
||||
//Offset controls by 1 to account for ID
|
||||
: mControls{mInBuf + ControlOffset(),ControlSize()}
|
||||
{
|
||||
index id = static_cast<index>(in0(1));
|
||||
if(auto ptr = get(id).lock())
|
||||
{
|
||||
auto& client = ptr->mClient;
|
||||
mDelegate.init(*this,client,mControls);
|
||||
set_calc_function<NRTModelQueryUnit, &NRTModelQueryUnit::next>();
|
||||
Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1);
|
||||
}else printNotFound(id);
|
||||
}
|
||||
|
||||
void next(int)
|
||||
{
|
||||
index id = static_cast<index>(in0(1));
|
||||
if(auto ptr = get(id).lock())
|
||||
{
|
||||
auto& client = ptr->mClient;
|
||||
auto& params = ptr->mParams;
|
||||
mControls.reset(mInBuf + ControlOffset());
|
||||
mDelegate.next(*this,client,params,mControls);
|
||||
}else printNotFound(id);
|
||||
}
|
||||
|
||||
private:
|
||||
Delegate mDelegate;
|
||||
FloatControlsIter mControls;
|
||||
index mID;
|
||||
};
|
||||
|
||||
|
||||
using ParamSetType = typename Client::ParamSetType;
|
||||
|
||||
template <size_t N, typename T>
|
||||
using SetupMessageCmd = typename FluidSCMessaging<Wrapper,Client>::template SetupMessageCmd<N,T>;
|
||||
|
||||
|
||||
template<bool, typename CommandType>
|
||||
struct DefineCommandIf
|
||||
{
|
||||
void operator()() { }
|
||||
};
|
||||
|
||||
|
||||
template<typename CommandType>
|
||||
struct DefineCommandIf<true, CommandType>
|
||||
{
|
||||
void operator()() {
|
||||
// std::cout << CommandType::name() << std::endl;
|
||||
defineNRTCommand<CommandType>();
|
||||
}
|
||||
};
|
||||
|
||||
template<bool, typename UnitType>
|
||||
struct RegisterUnitIf
|
||||
{
|
||||
void operator()(InterfaceTable*) {}
|
||||
};
|
||||
|
||||
template<typename UnitType>
|
||||
struct RegisterUnitIf<true, UnitType>
|
||||
{
|
||||
void operator()(InterfaceTable* ft) { registerUnit<UnitType>(ft,UnitType::name()); }
|
||||
};
|
||||
|
||||
|
||||
using IsRTQueryModel_t = typename Client::isRealTime;
|
||||
static constexpr bool IsRTQueryModel = IsRTQueryModel_t::value;
|
||||
|
||||
static constexpr bool IsModel = Client::isModelObject::value;
|
||||
|
||||
|
||||
public:
|
||||
static void setup(InterfaceTable* ft, const char*)
|
||||
{
|
||||
defineNRTCommand<CommandNew>();
|
||||
DefineCommandIf<!IsRTQueryModel, CommandProcess>()();
|
||||
DefineCommandIf<!IsRTQueryModel, CommandProcessNew>()();
|
||||
DefineCommandIf<!IsRTQueryModel, CommandCancel>()();
|
||||
|
||||
DefineCommandIf<IsModel,CommandSetParams>()();
|
||||
|
||||
defineNRTCommand<CommandFree>();
|
||||
RegisterUnitIf<!IsRTQueryModel,NRTProgressUnit>()(ft);
|
||||
RegisterUnitIf<!IsRTQueryModel,NRTTriggerUnit>()(ft);
|
||||
|
||||
RegisterUnitIf<IsRTQueryModel,NRTModelQueryUnit>()(ft);
|
||||
Client::getMessageDescriptors().template iterate<SetupMessageCmd>();
|
||||
}
|
||||
|
||||
|
||||
void init(){};
|
||||
|
||||
private:
|
||||
static Result validateParameters(ParamSetType& p)
|
||||
{
|
||||
auto results = p.constrainParameterValues();
|
||||
for (auto& r : results)
|
||||
{
|
||||
if (!r.ok()) return r;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template <size_t N, typename T>
|
||||
struct AssignBuffer
|
||||
{
|
||||
void operator()(const typename BufferT::type& p, World* w)
|
||||
{
|
||||
if (auto b = static_cast<SCBufferAdaptor*>(p.get())) b->assignToRT(w);
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N, typename T>
|
||||
struct CleanUpBuffer
|
||||
{
|
||||
void operator()(const typename BufferT::type& p)
|
||||
{
|
||||
if (auto b = static_cast<SCBufferAdaptor*>(p.get())) b->cleanUp();
|
||||
}
|
||||
};
|
||||
|
||||
FifoMsg mFifoMsg;
|
||||
char* mCompletionMessage = nullptr;
|
||||
void* mReplyAddr = nullptr;
|
||||
const char* mName = nullptr;
|
||||
index checkThreadInterval;
|
||||
index pollCounter{0};
|
||||
index mPreviousTrigger{0};
|
||||
|
||||
bool mSynchronous{true};
|
||||
Wrapper* mWrapper{static_cast<Wrapper*>(this)};
|
||||
Result mResult;
|
||||
};
|
||||
|
||||
//initialize static cache
|
||||
template<typename Client, typename Wrapper>
|
||||
using Cache = typename NonRealTime<Client,Wrapper>::Cache;
|
||||
|
||||
template<typename Client, typename Wrapper>
|
||||
Cache<Client,Wrapper> NonRealTime<Client,Wrapper>::mCache{};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,171 @@
|
||||
#pragma once
|
||||
|
||||
#include <SC_PlugIn.hpp>
|
||||
|
||||
namespace fluid{
|
||||
namespace client{
|
||||
namespace impl{
|
||||
template <typename Client, class Wrapper>
|
||||
struct RealTimeBase
|
||||
{
|
||||
using HostVector = FluidTensorView<float, 1>;
|
||||
using Params = typename Client::ParamSetType;
|
||||
template<typename T, bool>
|
||||
struct doExpectedCount;
|
||||
|
||||
template<typename T>
|
||||
struct doExpectedCount<T, false>
|
||||
{
|
||||
static void count(const T& d,FloatControlsIter& c,Result& status)
|
||||
{
|
||||
if(!status.ok()) return;
|
||||
|
||||
if(c.remain())
|
||||
{
|
||||
index statedSize = d.fixedSize;
|
||||
|
||||
if(c.remain() < statedSize)
|
||||
status = {Result::Status::kError,"Ran out of arguments at ", d.name};
|
||||
|
||||
//fastforward
|
||||
for(index i=0; i < statedSize; ++i) c.next();
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct doExpectedCount<T, true>
|
||||
{
|
||||
static void count(const T& d,FloatControlsIter& c,Result& status)
|
||||
{
|
||||
if(!status.ok()) return;
|
||||
|
||||
if(c.remain())
|
||||
{
|
||||
index statedSize = static_cast<index>(c.next());
|
||||
|
||||
if(c.remain() < statedSize)
|
||||
status = {Result::Status::kError,"Ran out of arguments at ", d.name};
|
||||
|
||||
//fastforward
|
||||
for(index i=0; i < statedSize; ++i) c.next();
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
template<size_t N, typename T>
|
||||
struct ExpectedCount{
|
||||
void operator ()(const T& descriptor,FloatControlsIter& c, Result& status)
|
||||
{
|
||||
doExpectedCount<T,IsSharedClientRef<typename T::type>::value>::count(descriptor,c,status);
|
||||
}
|
||||
};
|
||||
|
||||
Result expectedSize(FloatControlsIter& controls)
|
||||
{
|
||||
if(controls.size() < Client::getParameterDescriptors().count())
|
||||
{
|
||||
return {Result::Status::kError,"Fewer parameters than exepected. Got ", controls.size(), "expect at least", Client::getParameterDescriptors().count()};
|
||||
}
|
||||
|
||||
Result countScan;
|
||||
Client::getParameterDescriptors().template iterate<ExpectedCount>(
|
||||
std::forward<FloatControlsIter&>(controls),
|
||||
std::forward<Result&>(countScan));
|
||||
return countScan;
|
||||
}
|
||||
|
||||
// static index ControlOffset(Unit* unit) { return unit->mSpecialIndex + 1; }
|
||||
// static index ControlSize(Unit* unit) { return static_cast<index>(unit->mNumInputs) - unit->mSpecialIndex - 1 -(IsModel_t<Client>::value ? 1 : 0); }
|
||||
|
||||
void init(SCUnit& unit, Client& client, FloatControlsIter& controls)
|
||||
{
|
||||
assert(!(client.audioChannelsOut() > 0 && client.controlChannelsOut() > 0) &&"Client can't have both audio and control outputs");
|
||||
// consoltr.reset(unit.mInBuf + unit.mSpecialIndex + 1);
|
||||
client.sampleRate(unit.fullSampleRate());
|
||||
mInputConnections.reserve(asUnsigned(client.audioChannelsIn()));
|
||||
mOutputConnections.reserve(asUnsigned(client.audioChannelsOut()));
|
||||
mAudioInputs.reserve(asUnsigned(client.audioChannelsIn()));
|
||||
mOutputs.reserve(asUnsigned(
|
||||
std::max(client.audioChannelsOut(), client.controlChannelsOut())));
|
||||
|
||||
|
||||
Result r;
|
||||
if(!(r = expectedSize(controls)).ok())
|
||||
{
|
||||
// mCalcFunc = Wrapper::getInterfaceTable()->fClearUnitOutputs;
|
||||
std::cout
|
||||
<< "ERROR: " << Wrapper::getName()
|
||||
<< " wrong number of arguments."
|
||||
<< r.message()
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (index i = 0; i < client.audioChannelsIn(); ++i)
|
||||
{
|
||||
mInputConnections.emplace_back(unit.isAudioRateIn(static_cast<int>(i)));
|
||||
mAudioInputs.emplace_back(nullptr, 0, 0);
|
||||
}
|
||||
|
||||
for (index i = 0; i < client.audioChannelsOut(); ++i)
|
||||
{
|
||||
mOutputConnections.emplace_back(true);
|
||||
mOutputs.emplace_back(nullptr, 0, 0);
|
||||
}
|
||||
|
||||
for (index i = 0; i < client.controlChannelsOut(); ++i)
|
||||
{
|
||||
mOutputs.emplace_back(nullptr, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void next(SCUnit& unit, Client& client,Params& params,FloatControlsIter& controls)
|
||||
{
|
||||
bool trig = IsModel_t<Client>::value ? !mPrevTrig && unit.in0(0) > 0 : false;
|
||||
bool shouldProcess = IsModel_t<Client>::value ? trig : true;
|
||||
mPrevTrig = trig;
|
||||
|
||||
// if(shouldProcess)
|
||||
// {
|
||||
// controls.reset(unit.mInBuf + unit.mSpecialIndex + 1);
|
||||
Wrapper::setParams(&unit, params, controls);
|
||||
params.constrainParameterValues();
|
||||
// }
|
||||
|
||||
for (index i = 0; i < client.audioChannelsIn(); ++i)
|
||||
{
|
||||
assert(i <= std::numeric_limits<int>::max());
|
||||
if (mInputConnections[asUnsigned(i)])
|
||||
mAudioInputs[asUnsigned(i)].reset(const_cast<float*>(unit.in(static_cast<int>(i))), 0,
|
||||
unit.fullBufferSize());
|
||||
}
|
||||
|
||||
for (index i = 0; i < client.audioChannelsOut(); ++i)
|
||||
{
|
||||
assert(i <= std::numeric_limits<int>::max());
|
||||
if (mOutputConnections[asUnsigned(i)])
|
||||
mOutputs[asUnsigned(i)].reset(unit.out(static_cast<int>(i)), 0,
|
||||
unit.fullBufferSize());
|
||||
}
|
||||
|
||||
for (index i = 0; i < client.controlChannelsOut(); ++i)
|
||||
{
|
||||
assert(i <= std::numeric_limits<int>::max());
|
||||
mOutputs[asUnsigned(i)].reset(unit.out(static_cast<int>(i)), 0, 1);
|
||||
}
|
||||
client.process(mAudioInputs, mOutputs, mContext);
|
||||
}
|
||||
private:
|
||||
std::vector<bool> mInputConnections;
|
||||
std::vector<bool> mOutputConnections;
|
||||
std::vector<HostVector> mAudioInputs;
|
||||
std::vector<HostVector> mOutputs;
|
||||
FluidContext mContext;
|
||||
bool mPrevTrig;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
|
||||
#include "ArgsFromClient.hpp"
|
||||
#include "Meta.hpp"
|
||||
#include "RealTimeBase.hpp"
|
||||
#include <clients/common/FluidBaseClient.hpp>
|
||||
#include <SC_PlugIn.hpp>
|
||||
|
||||
// Real Time Processor
|
||||
namespace fluid {
|
||||
namespace client {
|
||||
namespace impl {
|
||||
|
||||
template <typename Client, class Wrapper>
|
||||
class RealTime : public SCUnit
|
||||
{
|
||||
|
||||
using Delegate = impl::RealTimeBase<Client,Wrapper>;
|
||||
using Params = typename Client::ParamSetType;
|
||||
|
||||
public:
|
||||
|
||||
// static index ControlOffset(Unit* unit) { return Delegate::ControlOffset(unit); }
|
||||
// static index ControlSize(Unit* unit) { return Delegate::ControlSize(unit); }
|
||||
|
||||
static index ControlOffset(Unit* unit) { return unit->mSpecialIndex + 1; }
|
||||
static index ControlSize(Unit* unit)
|
||||
{
|
||||
return static_cast<index>(unit->mNumInputs)
|
||||
- unit->mSpecialIndex
|
||||
- 1
|
||||
- (IsModel_t<Client>::value ? 1 : 0);
|
||||
}
|
||||
|
||||
static void setup(InterfaceTable* ft, const char* name)
|
||||
{
|
||||
ft->fDefineUnitCmd(name, "latency", doLatency);
|
||||
registerUnit<RealTime>(ft,name);
|
||||
}
|
||||
|
||||
static void doLatency(Unit* unit, sc_msg_iter*)
|
||||
{
|
||||
float l[]{
|
||||
static_cast<float>(static_cast<RealTime*>(unit)->mClient.latency())
|
||||
};
|
||||
auto ft = Wrapper::getInterfaceTable();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << '/' << Wrapper::getName() << "_latency";
|
||||
std::cout << ss.str() << std::endl;
|
||||
ft->fSendNodeReply(&unit->mParent->mNode, -1, ss.str().c_str(), 1, l);
|
||||
}
|
||||
|
||||
RealTime()
|
||||
: mControls{mInBuf + ControlOffset(this),ControlSize(this)},
|
||||
mClient{Wrapper::setParams(this, mParams, mControls,true)}
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
// auto& client = mClient;
|
||||
|
||||
mDelegate.init(*this,mClient,mControls);
|
||||
mCalcFunc = make_calc_function<RealTime, &RealTime::next>();
|
||||
Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1);
|
||||
|
||||
// assert(
|
||||
// !(client.audioChannelsOut() > 0 && client.controlChannelsOut() > 0) &&
|
||||
// "Client can't have both audio and control outputs");
|
||||
//
|
||||
// Result r;
|
||||
// if(!(r = expectedSize(mWrapper->mControlsIterator)).ok())
|
||||
// {
|
||||
// mCalcFunc = Wrapper::getInterfaceTable()->fClearUnitOutputs;
|
||||
// std::cout
|
||||
// << "ERROR: " << Wrapper::getName()
|
||||
// << " wrong number of arguments."
|
||||
// << r.message()
|
||||
// << std::endl;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// mWrapper->mControlsIterator.reset(mInBuf + mSpecialIndex + 1);
|
||||
//
|
||||
// client.sampleRate(fullSampleRate());
|
||||
// mInputConnections.reserve(asUnsigned(client.audioChannelsIn()));
|
||||
// mOutputConnections.reserve(asUnsigned(client.audioChannelsOut()));
|
||||
// mAudioInputs.reserve(asUnsigned(client.audioChannelsIn()));
|
||||
// mOutputs.reserve(asUnsigned(
|
||||
// std::max(client.audioChannelsOut(), client.controlChannelsOut())));
|
||||
//
|
||||
// for (index i = 0; i < client.audioChannelsIn(); ++i)
|
||||
// {
|
||||
// mInputConnections.emplace_back(isAudioRateIn(static_cast<int>(i)));
|
||||
// mAudioInputs.emplace_back(nullptr, 0, 0);
|
||||
// }
|
||||
//
|
||||
// for (index i = 0; i < client.audioChannelsOut(); ++i)
|
||||
// {
|
||||
// mOutputConnections.emplace_back(true);
|
||||
// mOutputs.emplace_back(nullptr, 0, 0);
|
||||
// }
|
||||
//
|
||||
// for (index i = 0; i < client.controlChannelsOut(); ++i)
|
||||
// { mOutputs.emplace_back(nullptr, 0, 0); }
|
||||
//
|
||||
// mCalcFunc = make_calc_function<RealTime, &RealTime::next>();
|
||||
// Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1);
|
||||
}
|
||||
|
||||
void next(int)
|
||||
{
|
||||
mControls.reset(mInBuf + ControlOffset(this));
|
||||
mDelegate.next(*this,mClient,mParams,mControls);
|
||||
}
|
||||
private:
|
||||
Delegate mDelegate;
|
||||
FloatControlsIter mControls;
|
||||
Params mParams{Client::getParameterDescriptors()};
|
||||
Client mClient;
|
||||
Wrapper* mWrapper{static_cast<Wrapper*>(this)};
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,36 +1,43 @@
|
||||
FluidBufAmpGate : UGen {
|
||||
FluidBufAmpGate : FluidBufProcessor {
|
||||
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, trig = 1, blocking|
|
||||
var maxSize = max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead));
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, trig = 1, blocking = 0|
|
||||
|
||||
var maxSize = max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead));
|
||||
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufAmpGateTrigger,-1, source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq,maxSize, trig, blocking);
|
||||
}
|
||||
|
||||
source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufAmpSlice: Invalid features buffer".throw};
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, freeWhenDone = true, action |
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq, maxSize, trig, blocking);
|
||||
}
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq, trig, blocking);
|
||||
}
|
||||
var maxSize = max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead));
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, action |
|
||||
source = source ? -1;
|
||||
indices = indices ? -1;
|
||||
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [indices]
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq
|
||||
^this.new(
|
||||
server, nil, [indices]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq, maxSize, 0],freeWhenDone,action
|
||||
);
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, action|
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, freeWhenDone = true, action |
|
||||
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [indices], blocking: 1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq
|
||||
);
|
||||
}
|
||||
|
||||
var maxSize = max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead));
|
||||
|
||||
source = source ? -1;
|
||||
indices = indices ? -1;
|
||||
|
||||
^this.new(
|
||||
server, nil, [indices]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq, maxSize, 1],freeWhenDone,action
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,35 +1,39 @@
|
||||
FluidBufAmpSlice : UGen {
|
||||
FluidBufAmpSlice : FluidBufProcessor {
|
||||
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, trig = 1, blocking|
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, trig = 1, blocking = 0|
|
||||
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufAmpSlice: Invalid features buffer".throw};
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufAmpSliceTrigger, -1, source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq, trig, blocking);
|
||||
}
|
||||
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
*process { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, freeWhenDone = true, action |
|
||||
|
||||
source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufAmpSlice: Invalid features buffer".throw};
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq, trig, blocking);
|
||||
}
|
||||
source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufAmpSlice: Invalid features buffer".throw};
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq, trig, blocking);
|
||||
^this.new(server, nil, [indices]).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq,0],freeWhenDone, action
|
||||
);
|
||||
}
|
||||
|
||||
*process { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, action |
|
||||
*processBlocking { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, freeWhenDone = true, action |
|
||||
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [indices]
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq
|
||||
);
|
||||
}
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
*processBlocking { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, action|
|
||||
source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufAmpSlice: Invalid features buffer".throw};
|
||||
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [indices], blocking: 1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq
|
||||
^this.new(server, nil, [indices]).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq,1],freeWhenDone, action
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,33 +1,38 @@
|
||||
FluidBufCompose : UGen {
|
||||
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, gain = 1, destination, destStartFrame = 0, destStartChan = 0, destGain = 0, trig = 1, blocking|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufCompose: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufCompose: Invalid destination buffer".throw};
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, gain, destination, destStartFrame, destStartChan, destGain, trig, blocking);
|
||||
}
|
||||
FluidBufCompose : FluidBufProcessor {
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, gain = 1, destination, destStartFrame = 0, destStartChan = 0, destGain = 0, trig = 1, blocking = 1|
|
||||
^this.new1('control', source, startFrame, numFrames, startChan, numChans, gain, destination, destStartFrame, destStartChan, destGain, trig, blocking);
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufCompose: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufCompose: Invalid destination buffer".throw};
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufNMFTrigger,-1, source, startFrame, numFrames, startChan, numChans, gain, destination, destStartFrame, destStartChan, destGain, trig, blocking);
|
||||
}
|
||||
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, gain = 1, destination, destStartFrame = 0, destStartChan = 0, destGain = 0, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [destination], blocking:1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, gain, destination, destStartFrame, destStartChan, destGain
|
||||
);
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, gain = 1, destination, destStartFrame = 0, destStartChan = 0, destGain = 0, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufCompose: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufCompose: Invalid destination buffer".throw};
|
||||
|
||||
^this.new( server, nil, [destination]).processList([source, startFrame, numFrames, startChan, numChans, gain, destination, destStartFrame, destStartChan, destGain, 1], freeWhenDone, action);//NB always blocking
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, gain = 1, destination, destStartFrame = 0, destStartChan = 0, destGain = 0, action|
|
||||
^process(
|
||||
source, startFrame, numFrames, startChan, numChans, gain, destination, destStartFrame, destStartChan, destGain
|
||||
);
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, gain = 1, destination, destStartFrame = 0, destStartChan = 0, destGain = 0, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufCompose: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufCompose: Invalid destination buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [destination]
|
||||
).processList([source, startFrame, numFrames, startChan, numChans, gain, destination, destStartFrame, destStartChan, destGain, 1], freeWhenDone, action);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,31 +1,46 @@
|
||||
FluidBufFlatten : UGen {
|
||||
FluidBufFlatten : FluidBufProcessor {
|
||||
|
||||
*new1 { |rate, source, destination, axis = 1, trig = 1, blocking|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
*kr { |source, destination, axis = 1, trig = 1, blocking = 1|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufFlatten: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufFlatten: Invalid destination buffer".throw};
|
||||
^super.new1(rate, source, destination, axis, trig, blocking);
|
||||
source.isNil.if {"FluidBufFlatten: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufFlatten: Invalid destination buffer".throw};
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufFlattenTrigger,-1, source, destination, axis, trig, blocking);
|
||||
}
|
||||
|
||||
*kr { |source, destination, axis = 1, trig = 1, blocking = 1|
|
||||
^this.new1('control', source, destination, axis, trig, blocking);
|
||||
}
|
||||
*process { |server, source, destination, axis = 1, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
*process { |server, source, destination, axis = 1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [destination], blocking:1
|
||||
).process(
|
||||
source, destination, axis
|
||||
source.isNil.if {"FluidBufFlatten: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufFlatten: Invalid destination buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [destination],
|
||||
).processList(
|
||||
[source, destination, axis,0],freeWhenDone,action
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, destination, axis = 1, action|
|
||||
^process(
|
||||
source, destination, axis
|
||||
);
|
||||
}
|
||||
*processBlocking { |server, source, destination, axis = 1, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufFlatten: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufFlatten: Invalid destination buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [destination],
|
||||
).processList(
|
||||
[source, destination, axis,1],freeWhenDone,action
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,45 +1,51 @@
|
||||
FluidBufHPSS : UGen {
|
||||
FluidBufHPSS : FluidBufProcessor {
|
||||
|
||||
*new1 {|rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, harmonic = -1, percussive = -1, residual = -1, harmFilterSize = 17, percFilterSize = 31, maskingMode = 0, harmThreshFreq1 = 0.1, harmThreshAmp1 = 0, harmThreshFreq2 = 0.5, harmThreshAmp2 = 0, percThreshFreq1 = 0.1, percThreshAmp1 = 0, percThreshFreq2 = 0.5, percThreshAmp2 = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking|
|
||||
*kr {|source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, harmonic = -1, percussive = -1, residual = -1, harmFilterSize = 17, percFilterSize = 31, maskingMode = 0, harmThreshFreq1 = 0.1, harmThreshAmp1 = 0, harmThreshFreq2 = 0.5, harmThreshAmp2 = 0, percThreshFreq1 = 0.1, percThreshAmp1 = 0, percThreshFreq2 = 0.5, percThreshAmp2 = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
source = source.asUGenInput;
|
||||
harmonic = harmonic.asUGenInput;
|
||||
percussive = percussive.asUGenInput;
|
||||
residual = residual.asUGenInput;
|
||||
source.isNil.if {"FluidBufHPSS: Invalid source buffer".throw};
|
||||
harmonic = harmonic ? -1;
|
||||
percussive = percussive ? -1;
|
||||
residual = residual ? -1;
|
||||
source.isNil.if {"FluidBufHPSS: Invalid source buffer".throw};
|
||||
|
||||
//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)
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize, harmFilterSize, percFilterSize, trig, blocking);
|
||||
^FluidProxyUgen.kr(\FluidBufHPSSTrigger, -1, source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize, harmFilterSize, percFilterSize, trig, blocking
|
||||
);
|
||||
}
|
||||
|
||||
*kr {|source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, harmonic = -1, percussive = -1, residual = -1, harmFilterSize = 17, percFilterSize = 31, maskingMode = 0, harmThreshFreq1 = 0.1, harmThreshAmp1 = 0, harmThreshFreq2 = 0.5, harmThreshAmp2 = 0, percThreshFreq1 = 0.1, percThreshAmp1 = 0, percThreshFreq2 = 0.5, percThreshAmp2 = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
*process {|server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, harmonic = -1, percussive = -1, residual = -1, harmFilterSize = 17, percFilterSize = 31, maskingMode = 0, harmThreshFreq1 = 0.1, harmThreshAmp1 = 0, harmThreshFreq2 = 0.5, harmThreshAmp2 = 0, percThreshFreq1 = 0.1, percThreshAmp1 = 0, percThreshFreq2 = 0.5, percThreshAmp2 = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone=true, action|
|
||||
|
||||
^this.multiNew(
|
||||
'control', source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, trig, blocking
|
||||
);
|
||||
}
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
harmonic = harmonic ? -1;
|
||||
percussive = percussive ? -1;
|
||||
residual = residual ? -1;
|
||||
source.isNil.if {"FluidBufHPSS: Invalid source buffer".throw};
|
||||
|
||||
*process {|server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, harmonic = -1, percussive = -1, residual = -1, harmFilterSize = 17, percFilterSize = 31, maskingMode = 0, harmThreshFreq1 = 0.1, harmThreshAmp1 = 0, harmThreshFreq2 = 0.5, harmThreshAmp2 = 0, percThreshFreq1 = 0.1, percThreshAmp1 = 0, percThreshFreq2 = 0.5, percThreshAmp2 = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [harmonic, percussive, residual].select{|x| x!= -1}
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize
|
||||
^this.new(
|
||||
server, nil, [harmonic, percussive, residual].select{|x| x!= -1}
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize, harmFilterSize, percFilterSize,0], freeWhenDone,action
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
*processBlocking {|server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, harmonic = -1, percussive = -1, residual = -1, harmFilterSize = 17, percFilterSize = 31, maskingMode = 0, harmThreshFreq1 = 0.1, harmThreshAmp1 = 0, harmThreshFreq2 = 0.5, harmThreshAmp2 = 0, percThreshFreq1 = 0.1, percThreshAmp1 = 0, percThreshFreq2 = 0.5, percThreshAmp2 = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
*processBlocking {|server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, harmonic = -1, percussive = -1, residual = -1, harmFilterSize = 17, percFilterSize = 31, maskingMode = 0, harmThreshFreq1 = 0.1, harmThreshAmp1 = 0, harmThreshFreq2 = 0.5, harmThreshAmp2 = 0, percThreshFreq1 = 0.1, percThreshAmp1 = 0, percThreshFreq2 = 0.5, percThreshAmp2 = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone=true, action|
|
||||
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [harmonic, percussive, residual].select{|x| x!= -1}, blocking:1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize
|
||||
);
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
}
|
||||
harmonic = harmonic ? -1;
|
||||
percussive = percussive ? -1;
|
||||
residual = residual ? -1;
|
||||
source.isNil.if {"FluidBufHPSS: Invalid source buffer".throw};
|
||||
|
||||
|
||||
^this.new(
|
||||
server, nil, [harmonic, percussive, residual].select{|x| x!= -1}
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize,harmFilterSize, percFilterSize,1], freeWhenDone,action
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,37 +1,45 @@
|
||||
FluidBufMFCC : UGen{
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
|
||||
FluidBufMFCC : FluidBufProcessor{
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufMFCC: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufMFCC: Invalid features buffer".throw};
|
||||
|
||||
//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)
|
||||
// same goes to maxNumCoeffs, which is passed numCoeffs in this case
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq, numCoeffs, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufMFCCTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq,numCoeffs, windowSize, hopSize, fftSize, maxFFTSize,trig, blocking);
|
||||
}
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq, windowSize, hopSize, fftSize, trig, blocking);
|
||||
}
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone=true, action |
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, action |
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [features]
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq, windowSize, hopSize, fftSize
|
||||
source.isNil.if {"FluidBufMFCC: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufMFCC: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil,[features]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq, numCoeffs,windowSize, hopSize, fftSize,maxFFTSize,0],freeWhenDone,action
|
||||
);
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, action |
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [features],blocking: 1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq, windowSize, hopSize, fftSize
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone=true, action |
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufMFCC: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufMFCC: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil,[features]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq,numCoeffs, windowSize, hopSize, fftSize,maxFFTSize,1],freeWhenDone,action
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,38 +1,50 @@
|
||||
FluidBufMelBands : UGen {
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
FluidBufMelBands : FluidBufProcessor {
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
source.isNil.if {"FluidBufMelBands: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufMelBands: Invalid features buffer".throw};
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
//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)
|
||||
// same for maxNumBands which is passed numBands
|
||||
source.isNil.if {"FluidBufMelBands: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufMelBands: Invalid features buffer".throw};
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
|
||||
}
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize, trig, blocking);
|
||||
^FluidProxyUgen.kr(\FluidBufMelBandsTrigger,-1, source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize,maxFFTSize, trig, blocking);
|
||||
}
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [features]
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, normalize, windowSize, hopSize, fftSize
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufMelBands: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufMelBands: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [features]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize,maxFFTSize,0],freeWhenDone,action
|
||||
);
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [features], blocking:1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, normalize, windowSize, hopSize, fftSize
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufMelBands: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufMelBands: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [features]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize,maxFFTSize,1],freeWhenDone,action
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,47 +1,36 @@
|
||||
FluidBufNMF : UGen {
|
||||
|
||||
*new1 {|rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth, bases, basesMode = 0, activations, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, trig = 1, blocking = 0|
|
||||
|
||||
source = source.asUGenInput;
|
||||
resynth = resynth.asUGenInput;
|
||||
bases = bases.asUGenInput;
|
||||
activations = activations.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufNMF: Invalid source buffer".throw};
|
||||
FluidBufNMF : FluidBufProcessor //: UGen {
|
||||
{
|
||||
*kr {|source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth, bases, basesMode = 0, activations, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, trig = 1, blocking = 0|
|
||||
|
||||
source.isNil.if {"FluidBufNMF: Invalid source buffer".throw};
|
||||
resynth = resynth ? -1;
|
||||
bases = bases ? -1;
|
||||
activations = activations ? -1;
|
||||
|
||||
^super.new1(rate,source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components, iterations, windowSize, hopSize, fftSize, trig, blocking);
|
||||
|
||||
}
|
||||
|
||||
*kr {|source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth, bases, basesMode = 0, activations, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, trig = 1, blocking = 0|
|
||||
^this.new1(\control,source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components, iterations, windowSize, hopSize, fftSize, trig, blocking);
|
||||
|
||||
activations = activations ? -1;
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufNMFTrigger,-1,source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components, iterations, windowSize, hopSize, fftSize, trig, blocking);
|
||||
}
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth = -1, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1,freeWhenDone = true, action|
|
||||
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth = -1, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, action|
|
||||
|
||||
source.isNil.if {"FluidBufNMF: Invalid source buffer".throw};
|
||||
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [resynth, bases, activations].select{|x| x!= -1}
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, windowType, randomSeed
|
||||
);
|
||||
source.isNil.if {"FluidBufNMF: Invalid source buffer".throw};
|
||||
resynth = resynth ? -1;
|
||||
bases = bases ? -1;
|
||||
activations = activations ? -1;
|
||||
|
||||
^this.new(
|
||||
server,nil,[resynth, bases, activations].select{|x| x!= -1}
|
||||
).processList([source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize,0],freeWhenDone,action);
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth = -1, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1,freeWhenDone = true, action|
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth = -1, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, action|
|
||||
|
||||
source.isNil.if {"FluidBufNMF: Invalid source buffer".throw};
|
||||
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [resynth, bases, activations].select{|x| x!= -1},blocking: 1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, windowType, randomSeed
|
||||
);
|
||||
source.isNil.if {"FluidBufNMF: Invalid source buffer".throw};
|
||||
resynth = resynth ? -1;
|
||||
bases = bases ? -1;
|
||||
activations = activations ? -1;
|
||||
|
||||
^this.new(
|
||||
server,nil,[resynth, bases, activations].select{|x| x!= -1}
|
||||
).processList([source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, 1],freeWhenDone,action);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,34 +1,48 @@
|
||||
FluidBufNMFCross : UGen{
|
||||
|
||||
*new1 { |rate, source, target, output , timeSparsity = 10, polyphony = 7, iterations = 50, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
|
||||
FluidBufNMFCross : FluidBufProcessor {
|
||||
|
||||
*kr { |source, target, output , timeSparsity = 10, polyphony = 7, iterations = 50, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
|
||||
source = source.asUGenInput;
|
||||
target = target.asUGenInput;
|
||||
output = output.asUGenInput;
|
||||
source.isNil.if {"FluidBufNMFCross: Invalid source buffer".throw};
|
||||
target.isNil.if {"FluidBufNMFCross: Invalid target buffer".throw};
|
||||
target = target.asUGenInput;
|
||||
output = output.asUGenInput;
|
||||
source.isNil.if {"FluidBufNMFCross: Invalid source buffer".throw};
|
||||
target.isNil.if {"FluidBufNMFCross: Invalid target buffer".throw};
|
||||
output.isNil.if {"FluidBufNMFCross: Invalid output buffer".throw};
|
||||
|
||||
^super.new1(rate, source, target, output, timeSparsity, polyphony, iterations, windowSize, hopSize, fftSize, trig, blocking);
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufNMFCrossTrigger, -1, source, target, output, timeSparsity, polyphony, iterations, windowSize, hopSize, fftSize, trig, blocking);
|
||||
}
|
||||
|
||||
*kr { |source, target, output , timeSparsity = 10, polyphony = 7, iterations = 50, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, target, output, timeSparsity, polyphony, iterations, windowSize, hopSize, fftSize, trig, blocking);
|
||||
}
|
||||
*process { |server, source, target, output , timeSparsity = 10, polyphony = 7, iterations = 50, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
target = target.asUGenInput;
|
||||
output = output.asUGenInput;
|
||||
source.isNil.if {"FluidBufNMFCross: Invalid source buffer".throw};
|
||||
target.isNil.if {"FluidBufNMFCross: Invalid target buffer".throw};
|
||||
output.isNil.if {"FluidBufNMFCross: Invalid output buffer".throw};
|
||||
|
||||
*process { |server, source, target, output , timeSparsity = 10, polyphony = 7, iterations = 50, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [output].select{|x| x!= -1}
|
||||
).process(
|
||||
source, target, output, timeSparsity, polyphony, iterations, windowSize, hopSize, fftSize
|
||||
|
||||
^this.new(
|
||||
server, nil, [output]
|
||||
).processList(
|
||||
[source, target, output, timeSparsity, polyphony, iterations, windowSize, hopSize, fftSize,0],freeWhenDone, action
|
||||
);
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, target, output , timeSparsity = 10, polyphony = 7, iterations = 50, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [output].select{|x| x!= -1}, blocking: 1
|
||||
).process(
|
||||
source, target, output, timeSparsity, polyphony, iterations, windowSize, hopSize, fftSize
|
||||
*processBlocking { |server, source, target, output , timeSparsity = 10, polyphony = 7, iterations = 50, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
target = target.asUGenInput;
|
||||
output = output.asUGenInput;
|
||||
source.isNil.if {"FluidBufNMFCross: Invalid source buffer".throw};
|
||||
target.isNil.if {"FluidBufNMFCross: Invalid target buffer".throw};
|
||||
output.isNil.if {"FluidBufNMFCross: Invalid output buffer".throw};
|
||||
|
||||
|
||||
^this.new(
|
||||
server, nil, [output]
|
||||
).processList(
|
||||
[source, target, output, timeSparsity, polyphony, iterations, windowSize, hopSize, fftSize,1],freeWhenDone, action
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,35 +1,47 @@
|
||||
FluidBufNNDSVD : UGen{
|
||||
*new1 { |rate, source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking=0|
|
||||
|
||||
source.isNil.if {"FluidBufNNDSVD: Invalid source buffer".throw};
|
||||
bases.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
|
||||
activations.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
|
||||
source = source.asUGenInput;
|
||||
bases = bases.asUGenInput;
|
||||
activations = activations.asUGenInput;
|
||||
|
||||
^super.new1(rate, source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize, trig, blocking)
|
||||
|
||||
}
|
||||
FluidBufNNDSVD : FluidBufProcessor{
|
||||
|
||||
*kr { |source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
^this.new1(\control, source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize, trig, blocking);
|
||||
|
||||
source.isNil.if {"FluidBufNNDSVD: Invalid source buffer".throw};
|
||||
bases.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
|
||||
activations.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
|
||||
source = source.asUGenInput;
|
||||
bases = bases.asUGenInput;
|
||||
activations = activations.asUGenInput;
|
||||
|
||||
^FluidProxyUgen.kr1(\FluidBufNNDSVDTrigger, -1, source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize, trig, blocking);
|
||||
}
|
||||
|
||||
|
||||
*process { |server, source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [bases]
|
||||
).process(
|
||||
source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize
|
||||
*process { |server, source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
source.isNil.if {"FluidBufNNDSVD: Invalid source buffer".throw};
|
||||
bases.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
|
||||
activations.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
|
||||
source = source.asUGenInput;
|
||||
bases = bases.asUGenInput;
|
||||
activations = activations.asUGenInput;
|
||||
|
||||
^this.new(
|
||||
server, nil, [bases]
|
||||
).processList(
|
||||
[source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize,0],freeWhenDone, action
|
||||
)
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [bases],blocking:1
|
||||
).process(
|
||||
source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize
|
||||
*processBlocking { |server, source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
source.isNil.if {"FluidBufNNDSVD: Invalid source buffer".throw};
|
||||
bases.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
|
||||
activations.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
|
||||
source = source.asUGenInput;
|
||||
bases = bases.asUGenInput;
|
||||
activations = activations.asUGenInput;
|
||||
|
||||
^this.new(
|
||||
server, nil, [bases]
|
||||
).processList(
|
||||
[source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize,1],freeWhenDone, action
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,37 +1,48 @@
|
||||
FluidBufOnsetSlice : UGen {
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
FluidBufOnsetSlice : FluidBufProcessor {
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
source.isNil.if {"FluidBufOnsetSlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufOnsetSlice: Invalid features buffer".throw};
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufOnsetSliceTrigger, -1, source, startFrame, numFrames, startChan, numChans, indices, metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
|
||||
}
|
||||
|
||||
source.isNil.if {"FluidBufOnsetSlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufOnsetSlice: Invalid features buffer".throw};
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {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)
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
|
||||
source.isNil.if {"FluidBufOnsetSlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufOnsetSlice: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [indices]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, indices, metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize,maxFFTSize,0],freeWhenDone,action
|
||||
);
|
||||
}
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, trig, blocking);
|
||||
}
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [indices]
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, indices, metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize
|
||||
);
|
||||
}
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [indices], blocking: 1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, indices, metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize
|
||||
source.isNil.if {"FluidBufOnsetSlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufOnsetSlice: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [indices]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, indices, metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize,maxFFTSize,1],freeWhenDone,action
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,39 +1,50 @@
|
||||
FluidBufPitch : UGen{
|
||||
FluidBufPitch : FluidBufProcessor{
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
*new1 {|rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufPitch: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufPitch: Invalid features buffer".throw};
|
||||
|
||||
//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)
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
|
||||
source.isNil.if {"FluidBufPitch: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufPitch: Invalid features buffer".throw};
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufPitchTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
|
||||
|
||||
}
|
||||
|
||||
*kr {|source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, trig, blocking);
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
}
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [features]
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize
|
||||
source.isNil.if {"FluidBufPitch: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufPitch: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [features]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone, action
|
||||
);
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [features], blocking: 1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
|
||||
|
||||
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
|
||||
|
||||
source = source.asUGenInput;
|
||||
features = features.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufPitch: Invalid source buffer".throw};
|
||||
features.isNil.if {"FluidBufPitch: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [features]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone, action
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,31 +1,43 @@
|
||||
FluidBufScale : UGen {
|
||||
FluidBufScale : FluidBufProcessor {
|
||||
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, inputLow = 0, inputHigh = 1, outputLow = 0, outputHigh = 1, trig = 1, blocking|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, inputLow = 0, inputHigh = 1, outputLow = 0, outputHigh = 1, trig = 1, blocking = 1|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufScale: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufScale: Invalid destination buffer".throw};
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, destination, inputLow, inputHigh, outputLow, outputHigh, trig, blocking);
|
||||
source.isNil.if {"FluidBufScale: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufScale: Invalid destination buffer".throw};
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufScaleTrigger, -1, source, startFrame, numFrames, startChan, numChans, destination, inputLow, inputHigh, outputLow, outputHigh, trig, blocking);
|
||||
}
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, inputLow = 0, inputHigh = 1, outputLow = 0, outputHigh = 1, trig = 1, blocking = 1|
|
||||
^this.new1('control', source, startFrame, numFrames, startChan, numChans, destination, inputLow, inputHigh, outputLow, outputHigh, trig, blocking);
|
||||
}
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, inputLow = 0, inputHigh = 1, outputLow = 0, outputHigh = 1, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, inputLow = 0, inputHigh = 1, outputLow = 0, outputHigh = 1, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [destination], blocking:1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, destination, inputLow, inputHigh, outputLow, outputHigh
|
||||
source.isNil.if {"FluidBufScale: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufScale: Invalid destination buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [destination]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, destination, inputLow, inputHigh, outputLow, outputHigh, 0], freeWhenDone, action
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, inputLow = 0, inputHigh = 1, outputLow = 0, outputHigh = 1, action|
|
||||
^process(
|
||||
source, startFrame, numFrames, startChan, numChans, destination, inputLow, inputHigh, outputLow, outputHigh
|
||||
);
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, inputLow = 0, inputHigh = 1, outputLow = 0, outputHigh = 1, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufScale: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufScale: Invalid destination buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [destination]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, destination, inputLow, inputHigh, outputLow, outputHigh, 1], freeWhenDone, action
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,36 +1,51 @@
|
||||
FluidBufStats : UGen{
|
||||
FluidBufStats : FluidBufProcessor {
|
||||
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, trig = 1, blocking = 0|
|
||||
|
||||
source = source.asUGenInput;
|
||||
stats = stats.asUGenInput;
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, trig = 1, blocking = 0|
|
||||
|
||||
source = source.asUGenInput;
|
||||
stats = stats.asUGenInput;
|
||||
weights = weights.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufStats: Invalid source buffer".throw};
|
||||
stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw};
|
||||
weights = weights ? -1;
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, stats, numDerivs, low, middle, high, outliersCutoff, weights, trig, blocking);
|
||||
source.isNil.if {"FluidBufStats: Invalid source buffer".throw};
|
||||
stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw};
|
||||
weights = weights ? -1;
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufStatsTrigger, -1, source, startFrame, numFrames, startChan, numChans, stats, numDerivs, low, middle, high, outliersCutoff, weights, trig, blocking);
|
||||
}
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, stats, numDerivs, low, middle, high, outliersCutoff, weights, trig, blocking);
|
||||
}
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
stats = stats.asUGenInput;
|
||||
weights = weights.asUGenInput;
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [stats]
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, stats,numDerivs, low, middle, high, outliersCutoff, weights
|
||||
source.isNil.if {"FluidBufStats: Invalid source buffer".throw};
|
||||
stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw};
|
||||
weights = weights ? -1;
|
||||
|
||||
^this.new(
|
||||
server, nil, [stats]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, stats,numDerivs, low, middle, high, outliersCutoff, weights, 0], freeWhenDone, action
|
||||
);
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [stats], blocking: 1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, stats,numDerivs, low, middle, high, outliersCutoff, weights
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
stats = stats.asUGenInput;
|
||||
weights = weights.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufStats: Invalid source buffer".throw};
|
||||
stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw};
|
||||
weights = weights ? -1;
|
||||
|
||||
^this.new(
|
||||
server, nil, [stats]
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, stats,numDerivs, low, middle, high, outliersCutoff, weights, 1], freeWhenDone, action
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,29 +1,33 @@
|
||||
FluidBufThreadDemo : UGen{
|
||||
FluidBufThreadDemo : FluidBufProcessor{
|
||||
|
||||
*new1 {|rate, result, time, trig = 1, blocking = 0 |
|
||||
result = result.asUGenInput;
|
||||
result.isNil.if {this.class.name+": Invalid output buffer".throw};
|
||||
^super.new1(rate, result, time, trig, blocking);
|
||||
}
|
||||
*kr {|result, time, trig = 1, blocking = 0|
|
||||
|
||||
result = result.asUGenInput;
|
||||
result.isNil.if {this.class.name+": Invalid output buffer".throw};
|
||||
|
||||
*kr {|result, time, trig = 1, blocking = 0|
|
||||
^this.new1(\control, result, time, trig, blocking);
|
||||
^FluidProxyUgen.kr(\FluidBufThreadDemoTrigger, -1, result, time, trig, blocking);
|
||||
}
|
||||
|
||||
*process { |server, result, time = 1000, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [result]
|
||||
).process(
|
||||
result, time
|
||||
*process { |server, result, time = 1000, freeWhenDone = true, action|
|
||||
|
||||
|
||||
result ?? {this.class.name+": Invalid output buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [result]
|
||||
).processList(
|
||||
[result.asUGenInput, time, 0], freeWhenDone, action
|
||||
);
|
||||
}
|
||||
|
||||
*processBlocking { |server, result, time = 1000, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [result], blocking: 1
|
||||
).process(
|
||||
result, time
|
||||
*processBlocking { |server, result, time = 1000, freeWhenDone = true, action|
|
||||
|
||||
result ?? {this.class.name+": Invalid output buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [result]
|
||||
).processList(
|
||||
[result.asUGenInput, time, 1], freeWhenDone, action
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,31 +1,45 @@
|
||||
FluidBufThresh : UGen {
|
||||
FluidBufThresh : FluidBufProcessor {
|
||||
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, threshold = 0, trig = 1, blocking|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, threshold = 0, trig = 1, blocking = 1|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufThresh: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufThresh: Invalid destination buffer".throw};
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, destination, threshold, trig, blocking);
|
||||
source.isNil.if {"FluidBufThresh: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufThresh: Invalid destination buffer".throw};
|
||||
|
||||
^FluidProxyUgen.kr(\FluidBufThreshTrigger, -1, source, startFrame, numFrames, startChan, numChans, destination, threshold, trig, blocking);
|
||||
}
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, threshold = 0, trig = 1, blocking = 1|
|
||||
^this.new1('control', source, startFrame, numFrames, startChan, numChans, destination, threshold, trig, blocking);
|
||||
}
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, threshold = 0, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, threshold = 0, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action, [destination], blocking:1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, destination, threshold
|
||||
source.isNil.if {"FluidBufThresh: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufThresh: Invalid destination buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [destination],
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, destination, threshold, 0], freeWhenDone, action
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, threshold = 0, action|
|
||||
^process(
|
||||
source, startFrame, numFrames, startChan, numChans, destination, threshold
|
||||
);
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, threshold = 0, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
destination = destination.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufThresh: Invalid source buffer".throw};
|
||||
destination.isNil.if {"FluidBufThresh: Invalid destination buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil, [destination],
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, destination, threshold, 1], freeWhenDone, action
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,30 +1,43 @@
|
||||
FluidBufTransientSlice : UGen{
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, minSliceLength = 1000, trig = 1, blocking = 0|
|
||||
FluidBufTransientSlice : FluidBufProcessor {
|
||||
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
*objectClassName{^\FluidBufTrSlice}
|
||||
|
||||
source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw};
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, minSliceLength = 1000, trig = 1, blocking = 0|
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, minSliceLength, trig, blocking);
|
||||
}
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw};
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, minSliceLength = 1000, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, minSliceLength, trig, blocking);
|
||||
^FluidProxyUgen.kr(this.objectClassName++\Trigger, -1, source, startFrame, numFrames, startChan, numChans, indices, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, minSliceLength, trig, blocking);
|
||||
}
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, minSliceLength = 1000, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action,[indices]
|
||||
).process(source, startFrame, numFrames, startChan, numChans, indices, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, minSliceLength
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, minSliceLength = 1000, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil,[indices]
|
||||
).processList([source, startFrame, numFrames, startChan, numChans, indices, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, minSliceLength,0], freeWhenDone, action
|
||||
);
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, minSliceLength = 1000, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action,[indices], blocking: 1
|
||||
).process(source, startFrame, numFrames, startChan, numChans, indices, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, minSliceLength
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, minSliceLength = 1000, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
indices = indices.asUGenInput;
|
||||
|
||||
source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw};
|
||||
indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil,[indices]
|
||||
).processList([source, startFrame, numFrames, startChan, numChans, indices, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, minSliceLength,1], freeWhenDone, action
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,36 +1,43 @@
|
||||
FluidBufTransients : UGen {
|
||||
FluidBufTransients : FluidBufProcessor {
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, transients = -1, residual = -1, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, trig = 1, blocking = 0|
|
||||
|
||||
*new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, transients = -1, residual = -1, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, trig = 1, blocking = 0 |
|
||||
source = source.asUGenInput;
|
||||
transients = transients ? -1;
|
||||
residual = residual ? -1;
|
||||
|
||||
source = source.asUGenInput;
|
||||
transients = transients.asUGenInput;
|
||||
residual = residual.asUGenInput;
|
||||
source.isNil.if {"FluidBufTransients: Invalid source buffer".throw};
|
||||
|
||||
source.isNil.if {"FluidBufTransients: Invalid source buffer".throw};
|
||||
|
||||
^super.new1(rate, source, startFrame, numFrames, startChan, numChans, transients, residual, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, trig, blocking);
|
||||
^FluidProxyUgen.kr(\FluidBufTransientsTrigger, -1, source, startFrame, numFrames, startChan, numChans, transients, residual, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, trig, blocking);
|
||||
}
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, transients = -1, residual = -1, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, freeWhenDone = true, action|
|
||||
|
||||
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, transients = -1, residual = -1, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, trig = 1, blocking = 0|
|
||||
^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, transients, residual, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength, trig, blocking);
|
||||
source = source.asUGenInput;
|
||||
transients = transients ? -1;
|
||||
residual = residual ? -1;
|
||||
|
||||
}
|
||||
source.isNil.if {"FluidBufTransients: Invalid source buffer".throw};
|
||||
|
||||
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, transients = -1, residual = -1, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action,[transients, residual].select{|x| x!= -1}
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, transients, residual, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength
|
||||
^this.new(
|
||||
server, nil,[transients, residual].select{|x| x!= -1}
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, transients, residual, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength,0],freeWhenDone,action
|
||||
);
|
||||
}
|
||||
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, transients = -1, residual = -1, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, action|
|
||||
^FluidNRTProcess.new(
|
||||
server, this, action,[transients, residual].select{|x| x!= -1}, blocking: 1
|
||||
).process(
|
||||
source, startFrame, numFrames, startChan, numChans, transients, residual, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength
|
||||
);
|
||||
}
|
||||
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, transients = -1, residual = -1, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, freeWhenDone = true, action|
|
||||
|
||||
source = source.asUGenInput;
|
||||
transients = transients ? -1;
|
||||
residual = residual ? -1;
|
||||
|
||||
source.isNil.if {"FluidBufTransients: Invalid source buffer".throw};
|
||||
|
||||
^this.new(
|
||||
server, nil,[transients, residual].select{|x| x!= -1}
|
||||
).processList(
|
||||
[source, startFrame, numFrames, startChan, numChans, transients, residual, order, blockSize, padSize, skew, threshFwd, threshBack, windowSize, clumpLength,1],freeWhenDone = true,action
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,91 +1,65 @@
|
||||
|
||||
FluidDataSetExistsError : Exception{
|
||||
}
|
||||
|
||||
FluidDataSet : FluidManipulationClient {
|
||||
FluidDataSet : FluidDataObject
|
||||
{
|
||||
*new{|server| ^super.new(server) }
|
||||
|
||||
var <id;
|
||||
classvar serverCaches;
|
||||
addPointMsg{|label,buffer|
|
||||
buffer = this.prEncodeBuffer(buffer);
|
||||
^this.prMakeMsg(\addPoint,id,label.asSymbol,buffer);
|
||||
}
|
||||
|
||||
*initClass {
|
||||
serverCaches = FluidServerCache.new;
|
||||
addPoint{|label, buffer, action|
|
||||
actions[\addPoint] = [nil,action];
|
||||
this.prSendMsg(this.addPointMsg(label,buffer));
|
||||
}
|
||||
|
||||
*at{ |server, name|
|
||||
^serverCaches.tryPerform(\at, server, name)
|
||||
}
|
||||
getPointMsg{|label,buffer|
|
||||
buffer = this.prEncodeBuffer(buffer);
|
||||
^this.prMakeMsg(\getPoint,id,label.asSymbol,buffer,["/b_query",buffer.asUGenInput]);
|
||||
}
|
||||
|
||||
*new { |server, name|
|
||||
if(this.at(server,name).notNil){
|
||||
FluidDataSetExistsError("A FluidDataset called % already exists.".format(name)).throw;
|
||||
^nil
|
||||
}
|
||||
^super.new(server,FluidManipulationClient.prServerString(name))!?{|inst|inst.init(name);inst}
|
||||
}
|
||||
getPoint{|label, buffer, action|
|
||||
actions[\getPoint] = [nil,action];
|
||||
this.prSendMsg(this.getPointMsg(label,buffer));
|
||||
}
|
||||
|
||||
init {|name|
|
||||
this.baseinit(FluidManipulationClient.prServerString(name));
|
||||
id = name;
|
||||
this.cache;
|
||||
}
|
||||
updatePointMsg{|label,buffer|
|
||||
buffer = this.prEncodeBuffer(buffer);
|
||||
^this.prMakeMsg(\updatePoint,id,label.asSymbol,buffer,["/b_query",buffer.asUGenInput]);
|
||||
}
|
||||
|
||||
cache {
|
||||
serverCaches.initCache(server);
|
||||
serverCaches.put(server,id,this);
|
||||
}
|
||||
updatePoint{|label, buffer, action|
|
||||
actions[\updatePoint] = [nil,action];
|
||||
this.prSendMsg(this.updatePointMsg(label,buffer));
|
||||
}
|
||||
|
||||
*asUGenInput { |input|
|
||||
var ascii = input.asString.ascii;
|
||||
^[ascii.size].addAll(ascii)
|
||||
}
|
||||
deletePointMsg{|label| ^this.prMakeMsg(\deletePoint,id,label.asSymbol);}
|
||||
|
||||
asString {
|
||||
^"FluidDataSet(%)".format(id).asString;
|
||||
}
|
||||
deletePoint{|label, buffer, action|
|
||||
actions[\deletePoint] = [nil,action];
|
||||
this.prSendMsg(this.deletePointMsg(label));
|
||||
}
|
||||
|
||||
asSymbol {
|
||||
^id.asSymbol
|
||||
}
|
||||
clearMsg { ^this.prMakeMsg(\clear,id); }
|
||||
|
||||
addPoint{|label, buffer, action|
|
||||
buffer = this.prEncodeBuffer(buffer);
|
||||
this.prSendMsg(\addPoint,[label.asSymbol,buffer],action);
|
||||
clear { |action|
|
||||
actions[\clear] = [nil,action];
|
||||
this.prSendMsg(this.clearMsg);
|
||||
}
|
||||
|
||||
getPoint{|label, buffer, action|
|
||||
buffer = this.prEncodeBuffer(buffer);
|
||||
this.prSendMsg(\getPoint,[label.asSymbol,buffer],action,outputBuffers:[buffer]);
|
||||
}
|
||||
|
||||
updatePoint{|label, buffer, action|
|
||||
buffer = this.prEncodeBuffer(buffer);
|
||||
this.prSendMsg(\updatePoint,[label.asSymbol,buffer],action,outputBuffers:[buffer]);
|
||||
}
|
||||
|
||||
deletePoint{|label, action|
|
||||
this.prSendMsg(\deletePoint,[label.asSymbol],action);
|
||||
}
|
||||
|
||||
clear { |action|
|
||||
this.prSendMsg(\clear,[],action);
|
||||
}
|
||||
mergeMsg{|sourceDataSet, overwrite = 0|
|
||||
^this.prMakeMsg(\merge,id,sourceDataSet.asUGenInput,overwrite);
|
||||
}
|
||||
|
||||
merge{|sourceDataSet, overwrite = 0, action|
|
||||
this.prSendMsg(\merge,
|
||||
[sourceDataSet.asSymbol, overwrite], action);
|
||||
actions[\merge] = [nil,action];
|
||||
this.prSendMsg(this.mergeMsg(sourceDataSet,overwrite));
|
||||
}
|
||||
|
||||
print { |action|
|
||||
action ?? {action = postit};
|
||||
this.prSendMsg(\print,[],action,[string(FluidMessageResponse,_,_)]);
|
||||
}
|
||||
|
||||
free {
|
||||
serverCaches.remove(server,id);
|
||||
super.free;
|
||||
}
|
||||
printMsg { ^this.prMakeMsg(\print,id); }
|
||||
|
||||
*freeAll { |server|
|
||||
serverCaches.do(server,{|x|x.free;});
|
||||
print { |action=(postResponse)|
|
||||
actions[\print] = [string(FluidMessageResponse,_,_),action];
|
||||
this.prSendMsg(this.printMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,52 +1,84 @@
|
||||
|
||||
FluidDataSetQuery : FluidManipulationClient {
|
||||
FluidDataSetQuery : FluidDataObject {
|
||||
|
||||
*new {|server|
|
||||
var uid = UniqueID.next;
|
||||
^super.new(server,uid)!?{|inst|inst.init(uid);inst}
|
||||
}
|
||||
|
||||
init {|uid|
|
||||
id = uid;
|
||||
this.baseinit(uid);
|
||||
}
|
||||
addColumnMsg { |column|
|
||||
^this.prMakeMsg(\addColumn,id,column);
|
||||
}
|
||||
|
||||
addColumn{|column, action|
|
||||
this.prSendMsg(\addColumn, [column], action);
|
||||
actions[\addColumn] = [nil,action];
|
||||
this.prSendMsg(this.addColumnMsg(column));
|
||||
}
|
||||
|
||||
addRangeMsg{|start,count|
|
||||
^this.prMakeMsg(\addRange,id,start,count);
|
||||
}
|
||||
|
||||
addRange{|start, count, action|
|
||||
this.prSendMsg(\addRange, [start, count], action);
|
||||
actions[\addRange] = [nil, action];
|
||||
this.prSendMsg(this.addRangeMsg(start, count));
|
||||
}
|
||||
|
||||
filterMsg{|column, condition, value, action|
|
||||
^this.prMakeMsg(\filter,id,column,condition.asSymbol,value);
|
||||
}
|
||||
|
||||
filter{|column, condition, value, action|
|
||||
this.prSendMsg(\filter, [column, condition.asSymbol, value], action);
|
||||
actions[\filter] = [nil, action];
|
||||
this.prSendMsg(this.filterMsg(column, condition, value));
|
||||
}
|
||||
|
||||
andMsg{ |column, condition, value|
|
||||
^this.prMakeMsg(\and,id,column, condition.asSymbol, value);
|
||||
}
|
||||
|
||||
and{|column, condition, value, action|
|
||||
this.prSendMsg(\and, [column, condition, value], action);
|
||||
actions[\and] = [nil, action];
|
||||
this.prSendMsg(this.andMsg(column,condition,value));
|
||||
}
|
||||
|
||||
orMsg{|column, condition, value|
|
||||
^this.prMakeMsg(\or,id,column, condition.asSymbol, value)
|
||||
}
|
||||
|
||||
or{|column, condition, value, action|
|
||||
this.prSendMsg(\or, [column, condition, value], action);
|
||||
actions[\or] = [nil,action];
|
||||
this.prSendMsg(this.orMsg(column, condition, value));
|
||||
}
|
||||
|
||||
clearMsg{
|
||||
^this.prMakeMsg(\clear,id);
|
||||
}
|
||||
|
||||
clear{|action|
|
||||
this.prSendMsg(\clear, [], action);
|
||||
actions[\clear] = [nil, action];
|
||||
this.prSendMsg(this.clearMsg);
|
||||
}
|
||||
|
||||
limitMsg{|rows|
|
||||
^this.prMakeMsg(\limit,id,rows);
|
||||
}
|
||||
|
||||
limit{|rows, action|
|
||||
this.prSendMsg(\limit, [rows], action);
|
||||
actions[\limit] = [nil,action];
|
||||
this.prSendMsg(this.limitMsg(rows));
|
||||
}
|
||||
|
||||
transformMsg{|sourceDataSet, destDataSet|
|
||||
^this.prMakeMsg(\transform,id,sourceDataSet.id,destDataSet.id);
|
||||
}
|
||||
|
||||
transform{|sourceDataSet, destDataSet, action|
|
||||
this.prSendMsg(\transform,[sourceDataSet.asSymbol, destDataSet.asSymbol],action);
|
||||
actions[\transform] = [nil,action];
|
||||
this.prSendMsg(this.transformMsg(sourceDataSet,destDataSet));
|
||||
}
|
||||
|
||||
transformJoinMsg{|source1DataSet, source2DataSet, destDataSet|
|
||||
^this.prMakeMsg(\transformJoin,id,source1DataSet.id, source2DataSet.id, destDataSet.id);
|
||||
}
|
||||
|
||||
transformJoin{|source1DataSet, source2DataSet, destDataSet, action|
|
||||
this.prSendMsg(\transformJoin,[source1DataSet.asSymbol, source2DataSet.asSymbol, destDataSet.asSymbol],action);
|
||||
actions[\transformJoin] = [nil,action];
|
||||
this.prSendMsg(this.transformJoinMsg(source1DataSet, source2DataSet, destDataSet));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
FluidDataSetWr : UGen {
|
||||
FluidDataSetWr : FluidBufProcessor {
|
||||
*kr { |dataset,labelPrefix = "", labelOffset = 0,buf, trig=1, blocking = 1|
|
||||
var args;
|
||||
buf ?? {"No input buffer provided".error};
|
||||
labelPrefix = labelPrefix !? {[labelPrefix.asString.size] ++ labelPrefix.asString.ascii} ?? {0};
|
||||
|
||||
*new1 { |rate, dataset, labelPrefix = "", labelOffset = 0, buf, trig, blocking|
|
||||
buf ?? {"No input buffer provided".error};
|
||||
^super.new1(rate,*(FluidManipulationClient.prServerString(dataset.asSymbol)
|
||||
++ FluidDataSet.asUGenInput(labelPrefix.asSymbol) ++ labelOffset.asInteger.asUGenInput ++buf.asUGenInput ++ trig ++ blocking));
|
||||
}
|
||||
args = [-1] ++ dataset.asUGenInput ++labelPrefix ++ labelOffset.asInteger.asUGenInput ++buf.asUGenInput ++ trig ++ blocking;
|
||||
|
||||
*kr { |dataset,labelPrefix = "", labelOffset = 0,buf, trig=1, blocking = 0|
|
||||
^this.new1(\control,dataset,labelPrefix,labelOffset, buf, trig, blocking)
|
||||
^FluidProxyUgen.kr(\FluidDataSetWrTrigger,*args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,41 +1,60 @@
|
||||
FluidKDTree : FluidRTDataClient {
|
||||
FluidKDTree : FluidRealTimeModel
|
||||
{
|
||||
|
||||
*new {|server,numNeighbours = 1, radius = 0, lookupDataSet = ""|
|
||||
var env;
|
||||
var names = [\numNeighbours, \radius]
|
||||
++ this.prServerString(lookupDataSet.asSymbol).collect{|x,i|
|
||||
("lookupDataSet"++i).asSymbol;
|
||||
};
|
||||
var neighbours,radius,lookup;
|
||||
|
||||
var values = [numNeighbours, radius] ++ this.prServerString(lookupDataSet.asSymbol);
|
||||
var params = [names,values].lace;
|
||||
*new{ |server, numNeighbours = 1, radius = 0, lookupDataSet|
|
||||
^super.new(server,[numNeighbours,radius,lookupDataSet ? -1])
|
||||
.numNeighbours_(numNeighbours)
|
||||
.radius_(radius)
|
||||
.lookupDataSet_(lookupDataSet);
|
||||
}
|
||||
|
||||
numNeighbours_{|k|neighbours = k.asInteger; }
|
||||
numNeighbours{ ^neighbours; }
|
||||
|
||||
/* env = Environment();
|
||||
synthControls[1..].do{|x|
|
||||
env.put(x,0);
|
||||
};
|
||||
env.put(\numNeighbours,1); */
|
||||
radius_{|r| radius = r.asUGenInput;}
|
||||
radius{ ^radius; }
|
||||
|
||||
^super.new1(server,params);
|
||||
/* env,
|
||||
[\numNeighbours]++lookupDataSet); */
|
||||
}
|
||||
lookupDataSet_{|ds| lookup = ds ? -1; }
|
||||
lookupDataSet{|ds| ^ (lookup ? -1) }
|
||||
|
||||
prGetParams{^[this.numNeighbours,this.radius,this.lookupDataSet,-1,-1];}
|
||||
|
||||
fitMsg{ |dataSet| ^this.prMakeMsg(\fit,this.id,dataSet.id);}
|
||||
|
||||
fit{|dataSet,action|
|
||||
this.prSendMsg(\fit, [dataSet.asSymbol], action);
|
||||
actions[\fit] = [nil,action];
|
||||
this.prSendMsg(this.fitMsg(dataSet));
|
||||
}
|
||||
|
||||
kNearestMsg{|buffer|
|
||||
^this.prMakeMsg(\kNearest,id,this.prEncodeBuffer(buffer));
|
||||
}
|
||||
|
||||
kNearest{ |buffer, action|
|
||||
this.prSendMsg(\kNearest,
|
||||
[buffer.asUGenInput], action,
|
||||
[strings(FluidMessageResponse,_,_)]
|
||||
);
|
||||
actions[\kNearest] = [strings(FluidMessageResponse,_,_),action];
|
||||
this.prSendMsg(this.kNearestMsg(buffer));
|
||||
}
|
||||
|
||||
kNearestDistMsg {|buffer|
|
||||
^this.prMakeMsg(\kNearestDist,id,this.prEncodeBuffer(buffer));
|
||||
}
|
||||
|
||||
kNearestDist { |buffer, action|
|
||||
this.prSendMsg(\kNearestDist, [buffer.asUGenInput], action,
|
||||
[numbers(FluidMessageResponse,_,nil,_)]
|
||||
);
|
||||
actions[\kNearestDist] = [numbers(FluidMessageResponse,_,nil,_),action];
|
||||
this.prSendMsg(this.kNearestDistMsg(buffer));
|
||||
}
|
||||
|
||||
kr{|trig, inputBuffer,outputBuffer, numNeighbours = 1, lookupDataSet|
|
||||
this.numNeighbours_(numNeighbours);
|
||||
lookupDataSet = lookupDataSet ? -1;
|
||||
this.lookupDataSet_(lookupDataSet);
|
||||
this.lookupDataSet.asUGenInput.postln;
|
||||
^FluidProxyUgen.kr('FluidKDTree/query', K2A.ar(trig),
|
||||
id, this.numNeighbours, this.radius, this.lookupDataSet.asUGenInput,
|
||||
this.prEncodeBuffer(inputBuffer),
|
||||
this.prEncodeBuffer(outputBuffer));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,35 +1,68 @@
|
||||
FluidKMeans : FluidRTDataClient {
|
||||
FluidKMeans : FluidRealTimeModel {
|
||||
|
||||
var clusters, maxiter;
|
||||
|
||||
*new {|server, numClusters = 4, maxIter = 100|
|
||||
^super.new1(server,[\numClusters,numClusters,\maxIter,maxIter]);
|
||||
^super.new(server,[numClusters,maxIter])
|
||||
.numClusters_(numClusters)
|
||||
.maxIter_(maxIter);
|
||||
}
|
||||
|
||||
fit{|dataSet,action|
|
||||
this.prSendMsg(\fit,
|
||||
[dataSet.asSymbol], action,
|
||||
[numbers(FluidMessageResponse,_,this.numClusters,_)]
|
||||
);
|
||||
}
|
||||
numClusters_{|n| clusters = n.asInteger}
|
||||
numClusters{ ^clusters }
|
||||
|
||||
maxIter_{|i| maxiter = i.asInteger}
|
||||
maxIter{ ^maxiter }
|
||||
|
||||
prGetParams{^[this.numClusters,this.maxIter,-1,-1];}
|
||||
|
||||
fitMsg{ |dataSet| ^this.prMakeMsg(\fit,id,dataSet.id);}
|
||||
|
||||
fit{|dataSet, action|
|
||||
actions[\fit] = [
|
||||
numbers( FluidMessageResponse, _, this.numClusters ,_),
|
||||
action
|
||||
];
|
||||
this.prSendMsg(this.fitMsg(dataSet));
|
||||
}
|
||||
|
||||
fitPredictMsg{|dataSet, labelSet|
|
||||
^this.prMakeMsg(\fitPredict, id, dataSet.id, labelSet.id)
|
||||
}
|
||||
|
||||
fitPredict{|dataSet, labelSet,action|
|
||||
this.prSendMsg(\fitPredict,
|
||||
[dataSet.asSymbol,labelSet.asSymbol],
|
||||
action,[numbers(FluidMessageResponse,_,this.numClusters,_)]
|
||||
);
|
||||
actions[\fitPredict] = [
|
||||
numbers(FluidMessageResponse, _, this.numClusters, _),
|
||||
action
|
||||
];
|
||||
this.prSendMsg(this.fitPredictMsg(dataSet,labelSet));
|
||||
}
|
||||
|
||||
predict{ |dataSet, labelSet,action|
|
||||
this.prSendMsg(\predict,
|
||||
[dataSet.asSymbol, labelSet.asSymbol], action,
|
||||
[numbers(FluidMessageResponse,_,this.numClusters,_)]
|
||||
);
|
||||
predictMsg{|dataSet, labelSet|
|
||||
^this.prMakeMsg(\predict, id, dataSet.id, labelSet.id)
|
||||
}
|
||||
|
||||
predict{ |dataSet, labelSet, action|
|
||||
actions[\predict] = [
|
||||
numbers(FluidMessageResponse, _, this.numClusters, _),
|
||||
action
|
||||
];
|
||||
this.prSendMsg(this.predictMsg(dataSet,labelSet));
|
||||
}
|
||||
|
||||
predictPointMsg{|buffer|
|
||||
^this.prMakeMsg(\predictPoint, id, this.prEncodeBuffer(buffer))
|
||||
}
|
||||
|
||||
predictPoint { |buffer, action|
|
||||
buffer = this.prEncodeBuffer(buffer);
|
||||
this.prSendMsg(\predictPoint,
|
||||
[buffer], action,
|
||||
[number(FluidMessageResponse,_,_)]
|
||||
);
|
||||
actions[\predictPoint] = [number(FluidMessageResponse,_,_),action];
|
||||
this.prSendMsg(this.predictPointMsg(buffer))
|
||||
}
|
||||
|
||||
kr{|trig, inputBuffer,outputBuffer|
|
||||
^FluidProxyUgen.kr('FluidKMeans/query', K2A.ar(trig),
|
||||
id, clusters, maxiter,
|
||||
this.prEncodeBuffer(inputBuffer),
|
||||
this.prEncodeBuffer(outputBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,47 @@
|
||||
FluidKNNClassifier : FluidRTDataClient {
|
||||
FluidKNNClassifier : FluidRealTimeModel {
|
||||
|
||||
var <>numNeighbours, <>weight;
|
||||
|
||||
*new {|server, numNeighbours = 3, weight = 1|
|
||||
^super.new1(server,[\numNeighbours,numNeighbours,\weight,weight]);
|
||||
^super.new(server,[numNeighbours,weight])
|
||||
.numNeighbours_(numNeighbours)
|
||||
.weight_(weight);
|
||||
}
|
||||
|
||||
prGetParams{^[this.numNeighbours,this.weight,-1,-1];}
|
||||
|
||||
fitMsg{|dataSet, labelSet|
|
||||
^this.prMakeMsg(\fit, id, dataSet.id, labelSet.id)
|
||||
}
|
||||
|
||||
fit{|dataSet, labelSet, action|
|
||||
this.prSendMsg(\fit,[dataSet.asSymbol, labelSet.asSymbol], action);
|
||||
actions[\fit] = [nil,action];
|
||||
this.prSendMsg(this.fitMsg(dataSet, labelSet));
|
||||
}
|
||||
|
||||
predict{|dataSet, labelSet, action|
|
||||
this.prSendMsg(\predict,
|
||||
[dataSet.asSymbol, labelSet.asSymbol],
|
||||
action);
|
||||
predictMsg{|dataSet, labelSet|
|
||||
^this.prMakeMsg(\predict, id, dataSet.id, labelSet.id)
|
||||
}
|
||||
|
||||
predict{|dataSet, labelSet, action|
|
||||
actions[\predict] = [nil, action];
|
||||
this.prSendMsg(this.predictMsg(dataSet, labelSet));
|
||||
}
|
||||
|
||||
predictPointMsg{|buffer|
|
||||
^this.prMakeMsg(\predictPoint, id, this.prEncodeBuffer(buffer))
|
||||
}
|
||||
|
||||
predictPoint {|buffer, action|
|
||||
buffer = this.prEncodeBuffer(buffer);
|
||||
this.prSendMsg(\predictPoint,
|
||||
[buffer.asUGenInput], action,
|
||||
[string(FluidMessageResponse,_,_)]
|
||||
);
|
||||
actions[\predictPoint] = [string(FluidMessageResponse,_,_),action];
|
||||
this.prSendMsg(this.predictPointMsg(buffer));
|
||||
}
|
||||
|
||||
kr{|trig, inputBuffer,outputBuffer|
|
||||
^FluidProxyUgen.kr(this.class.name.asString++'/query', K2A.ar(trig),
|
||||
id, this.numNeighbours, this.weight,
|
||||
this.prEncodeBuffer(inputBuffer),
|
||||
this.prEncodeBuffer(outputBuffer));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,25 +1,46 @@
|
||||
FluidKNNRegressor : FluidRTDataClient {
|
||||
FluidKNNRegressor : FluidRealTimeModel {
|
||||
|
||||
var <>numNeighbours, <>weight;
|
||||
|
||||
*new {|server, numNeighbours = 3, weight = 1|
|
||||
^super.new1(server,[\numNeighbours,numNeighbours,\weight,weight]);
|
||||
^super.new(server,[numNeighbours,weight])
|
||||
.numNeighbours_(numNeighbours)
|
||||
.weight_(weight);
|
||||
}
|
||||
|
||||
prGetParams{^[this.numNeighbours,this.weight,-1,-1];}
|
||||
|
||||
fitMsg{|sourceDataSet, targetDataSet|
|
||||
^this.prMakeMsg(\fit,this.id,sourceDataSet.id,targetDataSet.id)
|
||||
}
|
||||
|
||||
fit{|sourceDataSet, targetDataSet, action|
|
||||
this.prSendMsg(\fit,
|
||||
[sourceDataSet.asSymbol, targetDataSet.asSymbol],
|
||||
action
|
||||
);
|
||||
actions[\fit] = [nil,action];
|
||||
this.prSendMsg(this.fitMsg(sourceDataSet, targetDataSet));
|
||||
}
|
||||
|
||||
predictMsg{ |sourceDataSet, targetDataSet|
|
||||
^this.prMakeMsg(\predict,this.id,sourceDataSet.id,targetDataSet.id)
|
||||
}
|
||||
|
||||
predict{ |sourceDataSet, targetDataSet,action|
|
||||
this.prSendMsg(\predict,
|
||||
[sourceDataSet.asSymbol, targetDataSet.asSymbol],
|
||||
action);
|
||||
actions[\predict] = [nil, action];
|
||||
this.prSendMsg(this.predictMsg(sourceDataSet, targetDataSet));
|
||||
}
|
||||
|
||||
predictPointMsg { |buffer|
|
||||
^this.prMakeMsg(\predictPoint,id, this.prEncodeBuffer(buffer));
|
||||
}
|
||||
|
||||
predictPoint { |buffer, action|
|
||||
buffer = this.prEncodeBuffer(buffer);
|
||||
this.prSendMsg(\predictPoint, [buffer], action,
|
||||
[number(FluidMessageResponse,_,_)]);
|
||||
actions[\predictPoint] = [number(FluidMessageResponse,_,_),action];
|
||||
this.prSendMsg(this.predictPointMsg(buffer));
|
||||
}
|
||||
|
||||
kr{|trig, inputBuffer,outputBuffer|
|
||||
^FluidProxyUgen.kr(this.class.name.asString++'/query', K2A.ar(trig),
|
||||
id, this.numNeighbours, this.weight,
|
||||
this.prEncodeBuffer(inputBuffer),
|
||||
this.prEncodeBuffer(outputBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,81 +1,54 @@
|
||||
FluidLabelSetExistsError : Exception{
|
||||
}
|
||||
FluidLabelSet : FluidDataObject {
|
||||
|
||||
FluidLabelSet : FluidManipulationClient {
|
||||
*new{|server| ^super.new(server) }
|
||||
|
||||
var <id;
|
||||
classvar serverCaches;
|
||||
addLabelMsg{|identifier,label|
|
||||
^this.prMakeMsg(\addLabel,id,identifier.asSymbol,label.asSymbol);
|
||||
}
|
||||
|
||||
*initClass {
|
||||
serverCaches = FluidServerCache.new;
|
||||
addLabel{|identifier, label, action|
|
||||
actions[\addLabel] = [nil, action];
|
||||
this.prSendMsg(this.addLabelMsg(identifier,label));
|
||||
}
|
||||
|
||||
*at{ |server, name|
|
||||
^serverCaches.tryPerform(\at, server, name)
|
||||
}
|
||||
updateLabelMsg{|identifier, label|
|
||||
^this.prMakeMsg(\updateLabel, id, identifier.asSymbol, label.asSymbol);
|
||||
}
|
||||
|
||||
*new { |server,name|
|
||||
serverCaches.at(server,name) !? {
|
||||
FluidLabelSetExistsError("A FluidLabelSet called % already exists.".format(name)).throw;
|
||||
};
|
||||
^super.new(server,FluidManipulationClient.prServerString(name))!?{|inst|inst.init(name);inst}
|
||||
updateLabel{|identifier, label, action|
|
||||
actions[\updateLabel] = [nil,action];
|
||||
this.prSendMsg(this.updateLabelMsg(identifier,label));
|
||||
}
|
||||
|
||||
init { |name|
|
||||
this.baseinit(FluidManipulationClient.prServerString(name));
|
||||
id = name;
|
||||
this.cache;
|
||||
}
|
||||
getLabelMsg{|identifier|
|
||||
^this.prMakeMsg(\getLabel, id, identifier.asSymbol);
|
||||
}
|
||||
|
||||
cache {
|
||||
serverCaches.initCache(server);
|
||||
serverCaches.put(server,id,this);
|
||||
getLabel{|identifier, action|
|
||||
actions[\getLabel] = [string(FluidMessageResponse,_,_),action];
|
||||
this.prSendMsg(this.getLabelMsg(identifier));
|
||||
}
|
||||
|
||||
asString {
|
||||
^"FluidLabelSet(%)".format(id).asString;
|
||||
}
|
||||
deleteLabelMsg{|identifier, action|
|
||||
^this.prMakeMsg(\deleteLabel, id, identifier.asSymbol);
|
||||
}
|
||||
|
||||
asSymbol {
|
||||
^id
|
||||
deleteLabel{|identifier, action|
|
||||
actions[\deleteLabel] = [nil, action];
|
||||
this.prSendMsg(this.deleteLabelMsg(identifier));
|
||||
}
|
||||
|
||||
*asUGenInput { |input|
|
||||
var ascii = input.asString.ascii;
|
||||
^[ascii.size].addAll(ascii)
|
||||
}
|
||||
clearMsg { ^this.prMakeMsg(\clear,id); }
|
||||
|
||||
addLabel{|id, label, action|
|
||||
this.prSendMsg(\addLabel, [id.asString, label.asString],action);
|
||||
}
|
||||
|
||||
updateLabel{|id, label, action|
|
||||
this.prSendMsg(\updateLabel, [id.asString, label.asString],action);
|
||||
}
|
||||
clear { |action|
|
||||
actions[\clear] = [nil,action];
|
||||
this.prSendMsg(this.clearMsg);
|
||||
}
|
||||
|
||||
getLabel{|id, action|
|
||||
this.prSendMsg(\getLabel, [id.asString], action,[string(FluidMessageResponse,_,_)]);
|
||||
}
|
||||
|
||||
deleteLabel{|id, action|
|
||||
this.prSendMsg(\deleteLabel, [id.asString],action);
|
||||
}
|
||||
|
||||
clear {|action|
|
||||
this.prSendMsg(\clear,[], action);
|
||||
}
|
||||
|
||||
free {|action|
|
||||
serverCaches.remove(server, id);
|
||||
super.free;
|
||||
}
|
||||
|
||||
*freeAll {|server|
|
||||
serverCaches.do(server,{|x| x.free;});
|
||||
}
|
||||
printMsg { ^this.prMakeMsg(\print,id); }
|
||||
|
||||
print { |action|
|
||||
action ?? {action = postit};
|
||||
this.prSendMsg(\print,[], action, [string(FluidMessageResponse,_,_)]);
|
||||
print { |action=(postResponse)|
|
||||
actions[\print] = [string(FluidMessageResponse,_,_),action];
|
||||
this.prSendMsg(this.printMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,103 +1,151 @@
|
||||
FluidMLPRegressor : FluidRTDataClient {
|
||||
FluidMLPRegressor : FluidRealTimeModel {
|
||||
|
||||
const <identity = 0;
|
||||
const <sigmoid = 1;
|
||||
const <relu = 2;
|
||||
const <tanh = 3;
|
||||
|
||||
var <>hidden, <>activation, <>outputActivation, <>tapIn, <>tapOut, <>maxIter, <>learnRate, <>momentum, <>batchSize, <>validation;
|
||||
|
||||
*new {|server, hidden = #[3,3] , activation = 2, outputActivation = 0, tapIn = 0, tapOut = -1,maxIter = 1000, learnRate = 0.0001, momentum = 0.9, batchSize = 50, validation = 0.2|
|
||||
var hiddenCtrlLabels;
|
||||
hidden = [hidden.size]++hidden;
|
||||
|
||||
hiddenCtrlLabels = hidden.collect{|x,i| \hidden++i};
|
||||
|
||||
^super.new1(server,
|
||||
[hiddenCtrlLabels,hidden].lace ++
|
||||
[
|
||||
\activation,activation,
|
||||
\outputActivation, outputActivation,
|
||||
\tapIn, tapIn,
|
||||
\tapOut, tapOut,
|
||||
\maxIter, maxIter,
|
||||
\learnRate,learnRate,
|
||||
\momentum, momentum,
|
||||
\batchSize,batchSize,
|
||||
\validation,validation,
|
||||
])
|
||||
|
||||
^super.new(server, [hidden.size] ++ hidden ++ [activation, outputActivation, tapIn, tapOut, maxIter, learnRate, momentum, batchSize, validation])
|
||||
.hidden_(hidden)
|
||||
.activation_(activation)
|
||||
.outputActivation_(outputActivation)
|
||||
.tapIn_(tapIn)
|
||||
.tapOut_(tapOut)
|
||||
.maxIter_(maxIter)
|
||||
.learnRate_(learnRate)
|
||||
.momentum_(momentum)
|
||||
.batchSize_(batchSize)
|
||||
.validation_(validation);
|
||||
}
|
||||
|
||||
clear{ |action|
|
||||
this.prSendMsg(\clear,action:action);
|
||||
prGetParams{
|
||||
^[this.hidden.size] ++ this.hidden ++ [this.activation, this.outputActivation, this.tapIn, this.tapOut, this.maxIter, this.learnRate, this.momentum, this.batchSize, this.validation, -1, -1]
|
||||
}
|
||||
|
||||
clearMsg{ ^this.prMakeMsg(\clear, id) }
|
||||
|
||||
clear{ |action|
|
||||
actions[\clear] = [nil, action];
|
||||
this.prSendMsg(this.clearMsg);
|
||||
}
|
||||
|
||||
fitMsg{|sourceDataSet, targetDataSet|
|
||||
^this.prMakeMsg(\fit,id,sourceDataSet.id, targetDataSet.id);
|
||||
}
|
||||
|
||||
fit{|sourceDataSet, targetDataSet, action|
|
||||
this.prSendMsg(\fit,
|
||||
[sourceDataSet.asSymbol, targetDataSet.asSymbol],
|
||||
action,numbers(FluidMessageResponse,_,1,_)
|
||||
);
|
||||
actions[\fit] = [numbers(FluidMessageResponse,_,1,_),action];
|
||||
this.prSendMsg(this.fitMsg(sourceDataSet,targetDataSet));
|
||||
}
|
||||
|
||||
predict{ |sourceDataSet, targetDataSet, action|
|
||||
this.prSendMsg(\predict,
|
||||
[sourceDataSet.asSymbol, targetDataSet.asSymbol],
|
||||
action);
|
||||
predictMsg{|sourceDataSet, targetDataSet|
|
||||
^this.prMakeMsg(\predict,id,sourceDataSet.id, targetDataSet.id);
|
||||
}
|
||||
|
||||
predict{|sourceDataSet, targetDataSet, action|
|
||||
actions[\predict] = [nil,action];
|
||||
this.prSendMsg(this.predictMsg(sourceDataSet,targetDataSet));
|
||||
}
|
||||
|
||||
|
||||
predictPointMsg { |sourceBuffer, targetBuffer|
|
||||
^this.prMakeMsg(\predictPoint,id,
|
||||
this.prEncodeBuffer(sourceBuffer),
|
||||
this.prEncodeBuffer(targetBuffer),
|
||||
["/b_query", targetBuffer.asUGenInput]);
|
||||
}
|
||||
|
||||
predictPoint { |sourceBuffer, targetBuffer, action|
|
||||
sourceBuffer = this.prEncodeBuffer(sourceBuffer);
|
||||
targetBuffer = this.prEncodeBuffer(targetBuffer);
|
||||
this.prSendMsg(\predictPoint,
|
||||
[sourceBuffer.asUGenInput, targetBuffer.asUGenInput], action,outputBuffers:[targetBuffer]);
|
||||
actions[\predictPoint] = [nil,{action.value(targetBuffer)}];
|
||||
this.predictPointMsg(sourceBuffer, targetBuffer);
|
||||
this.prSendMsg(this.predictPointMsg(sourceBuffer, targetBuffer));
|
||||
}
|
||||
|
||||
kr{|trig, inputBuffer,outputBuffer, tapIn = 0, tapOut = -1|
|
||||
var params;
|
||||
tapIn = tapIn ? this.tapIn;
|
||||
tapOut = tapOut ? this.tapOut;
|
||||
|
||||
this.tapIn_(tapIn).tapOut_(tapOut);
|
||||
|
||||
params = this.prGetParams.drop(-2) ++ [this.prEncodeBuffer(inputBuffer),
|
||||
this.prEncodeBuffer(outputBuffer)];
|
||||
|
||||
^FluidProxyUgen.kr(this.class.name.asString++'/query', K2A.ar(trig),
|
||||
id, *params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
FluidMLPClassifier : FluidRTDataClient {
|
||||
FluidMLPClassifier : FluidRealTimeModel {
|
||||
|
||||
const <identity = 0;
|
||||
const <sigmoid = 1;
|
||||
const <relu = 2;
|
||||
const <tanh = 3;
|
||||
|
||||
var <>hidden, <>activation, <> maxIter, <>learnRate, <> momentum, <>batchSize, <>validation;
|
||||
|
||||
*new {|server, hidden = #[3,3] , activation = 2, maxIter = 1000, learnRate = 0.0001, momentum = 0.9, batchSize = 50, validation = 0.2|
|
||||
var hiddenCtrlLabels;
|
||||
hidden = [hidden.size]++hidden;
|
||||
|
||||
hiddenCtrlLabels = hidden.collect{|x,i| \hidden++i};
|
||||
|
||||
^super.new1(server,
|
||||
[hiddenCtrlLabels,hidden].lace ++
|
||||
[
|
||||
\activation,activation,
|
||||
\maxIter, maxIter,
|
||||
\learnRate,learnRate,
|
||||
\momentum, momentum,
|
||||
\batchSize,batchSize,
|
||||
\validation,validation,
|
||||
])
|
||||
^super.new(server,[hidden.size] ++ hidden ++ [activation, maxIter, learnRate, momentum, batchSize, validation])
|
||||
.hidden_(hidden)
|
||||
.activation_(activation)
|
||||
.maxIter_(maxIter)
|
||||
.learnRate_(learnRate)
|
||||
.momentum_(momentum)
|
||||
.batchSize_(batchSize)
|
||||
.validation_(validation);
|
||||
}
|
||||
|
||||
prGetParams{
|
||||
^[ this.hidden.size] ++ this.hidden ++ [this.activation, this.maxIter, this.learnRate, this.momentum, this.batchSize, this.validation, -1, -1];
|
||||
}
|
||||
|
||||
clearMsg{ ^this.prMakeMsg(\clear,id) }
|
||||
|
||||
clear{ |action|
|
||||
this.prSendMsg(\clear,action:action);
|
||||
actions[\clear] = [nil,action];
|
||||
this.prSendMsg(this.clearMsg);
|
||||
}
|
||||
|
||||
fitMsg{|sourceDataSet, targetLabelSet|
|
||||
^this.prMakeMsg(\fit,id,sourceDataSet.id, targetLabelSet.id);
|
||||
}
|
||||
|
||||
fit{|sourceDataSet, targetLabelSet, action|
|
||||
this.prSendMsg(\fit,
|
||||
[sourceDataSet.asSymbol, targetLabelSet.asSymbol],
|
||||
action,numbers(FluidMessageResponse,_,1,_)
|
||||
);
|
||||
actions[\fit] = [numbers(FluidMessageResponse,_,1,_),action];
|
||||
this.prSendMsg(this.fitMsg(sourceDataSet,targetLabelSet));
|
||||
}
|
||||
|
||||
predictMsg{|sourceDataSet, targetLabelSet|
|
||||
^this.prMakeMsg(\predict,id,sourceDataSet.id, targetLabelSet.id);
|
||||
}
|
||||
|
||||
predict{ |sourceDataSet, targetLabelSet, action|
|
||||
this.prSendMsg(\predict,
|
||||
[sourceDataSet.asSymbol, targetLabelSet.asSymbol],
|
||||
action);
|
||||
actions[\predict]=[nil,action];
|
||||
this.prSendMsg(this.predictMsg(sourceDataSet,targetLabelSet));
|
||||
}
|
||||
|
||||
predictPointMsg { |sourceBuffer|
|
||||
^this.prMakeMsg(\predictPoint,id,this.prEncodeBuffer(sourceBuffer))
|
||||
}
|
||||
|
||||
predictPoint { |sourceBuffer, action|
|
||||
sourceBuffer = this.prEncodeBuffer(sourceBuffer);
|
||||
this.prSendMsg(\predictPoint,
|
||||
[sourceBuffer], action, string(FluidMessageResponse,_,_));
|
||||
actions[\predictPoint] = [string(FluidMessageResponse,_,_),action];
|
||||
this.prSendMsg(this.predictPointMsg(sourceBuffer));
|
||||
}
|
||||
|
||||
kr{|trig, inputBuffer,outputBuffer|
|
||||
|
||||
var params = this.prGetParams.drop(-2) ++ [this.prEncodeBuffer(inputBuffer),
|
||||
this.prEncodeBuffer(outputBuffer)];
|
||||
|
||||
^FluidProxyUgen.kr(this.class.name.asString++'/query', K2A.ar(trig),
|
||||
id, *params);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,31 +1,68 @@
|
||||
FluidNormalize : FluidRTDataClient {
|
||||
FluidNormalize : FluidRealTimeModel {
|
||||
|
||||
var <>min, <>max, <>invert;
|
||||
|
||||
*new {|server, min = 0, max = 1, invert = 0|
|
||||
^super.new1(server,[\min,min,\max,max, \invert, invert]);
|
||||
^super.new(server,[min,max,invert])
|
||||
.min_(min).max_(max).invert_(invert);
|
||||
}
|
||||
|
||||
prGetParams{
|
||||
^[this.min,this.max,this.invert,-1,-1];
|
||||
}
|
||||
|
||||
|
||||
fitMsg{|dataSet|
|
||||
^this.prMakeMsg(\fit,id,dataSet.id)
|
||||
}
|
||||
|
||||
fit{|dataSet, action|
|
||||
this.prSendMsg(\fit,[dataSet.asSymbol], action);
|
||||
actions[\fit] = [nil,action];
|
||||
this.prSendMsg(this.fitMsg(dataSet));
|
||||
}
|
||||
|
||||
transformMsg{|sourceDataSet, destDataSet|
|
||||
^this.prMakeMsg(\transform,id,sourceDataSet.id,destDataSet.id);
|
||||
}
|
||||
|
||||
transform{|sourceDataSet, destDataSet, action|
|
||||
this.prSendMsg(\transform,
|
||||
[sourceDataSet.asSymbol, destDataSet.asSymbol], action
|
||||
);
|
||||
actions[\transform] = [nil,action];
|
||||
this.prSendMsg(this.transformMsg(sourceDataSet, destDataSet));
|
||||
}
|
||||
|
||||
fitTransformMsg{|sourceDataSet, destDataSet|
|
||||
^this.prMakeMsg(\fitTransform,id,sourceDataSet.id,destDataSet.id)
|
||||
}
|
||||
|
||||
fitTransform{|sourceDataSet, destDataSet, action|
|
||||
this.prSendMsg(\fitTransform,
|
||||
[sourceDataSet.asSymbol, destDataSet.asSymbol], action
|
||||
);
|
||||
actions[\fitTransform] = [nil,action];
|
||||
this.prSendMsg(this.fitTransformMsg(sourceDataSet, destDataSet));
|
||||
}
|
||||
|
||||
transformPointMsg{|sourceBuffer, destBuffer|
|
||||
^this.prMakeMsg(\transformPoint,id,
|
||||
this.prEncodeBuffer(sourceBuffer),
|
||||
this.prEncodeBuffer(destBuffer),
|
||||
["/b_query",destBuffer.asUGenInput]
|
||||
);
|
||||
}
|
||||
|
||||
transformPoint{|sourceBuffer, destBuffer, action|
|
||||
sourceBuffer = this.prEncodeBuffer(sourceBuffer);
|
||||
destBuffer = this.prEncodeBuffer(destBuffer);
|
||||
this.prSendMsg(\transformPoint,
|
||||
[sourceBuffer, destBuffer], action,
|
||||
outputBuffers:[destBuffer]
|
||||
);
|
||||
actions[\transformPoint] = [nil,{action.value(destBuffer)}];
|
||||
this.prSendMsg(this.transformPointMsg(sourceBuffer, destBuffer));
|
||||
}
|
||||
|
||||
kr{|trig, inputBuffer,outputBuffer,min,max,invert|
|
||||
|
||||
min = min ? this.min;
|
||||
max = max ? this.max;
|
||||
invert = invert ? this.invert;
|
||||
|
||||
this.min_(min).max_(max).invert_(invert);
|
||||
|
||||
^FluidProxyUgen.kr(this.class.name.asString++'/query', K2A.ar(trig),
|
||||
id, this.min, this.max, this.invert, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,24 +1,62 @@
|
||||
FluidPCA : FluidRTDataClient {
|
||||
FluidPCA : FluidRealTimeModel{
|
||||
|
||||
*new {|server, numDimensions = 2|
|
||||
^super.new1(server,[\numDimensions,numDimensions]);
|
||||
}
|
||||
var <>numDimensions;
|
||||
|
||||
*new {|server, numDimensions = 2|
|
||||
^super.new(server,[numDimensions]).numDimensions_(numDimensions);
|
||||
}
|
||||
|
||||
prGetParams{
|
||||
^[numDimensions,-1,-1];
|
||||
}
|
||||
|
||||
fitMsg{|dataSet|
|
||||
^this.prMakeMsg(\fit,id, dataSet.id);
|
||||
}
|
||||
|
||||
fit{|dataSet, action|
|
||||
this.prSendMsg(\fit,[dataSet.asSymbol], action);
|
||||
actions[\fit] = [nil, action];
|
||||
this.prSendMsg(this.fitMsg(dataSet));
|
||||
}
|
||||
|
||||
transformMsg{|sourceDataSet, destDataSet|
|
||||
^this.prMakeMsg(\transform, id, sourceDataSet.id, destDataSet.id);
|
||||
}
|
||||
|
||||
transform{|sourceDataSet, destDataSet, action|
|
||||
this.prSendMsg(\transform,[sourceDataSet.asSymbol, destDataSet.asSymbol], action, [numbers(FluidMessageResponse,_,1,_)]);
|
||||
actions[\transform] = [numbers(FluidMessageResponse,_,1,_),action];
|
||||
this.prSendMsg(this.transformMsg(sourceDataSet,destDataSet));
|
||||
}
|
||||
|
||||
fitTransformMsg{|sourceDataSet, destDataSet|
|
||||
^this.prMakeMsg(\fitTransform,id, sourceDataSet.id, destDataSet.id);
|
||||
}
|
||||
|
||||
fitTransform{|sourceDataSet, destDataSet, action|
|
||||
this.prSendMsg(\fitTransform,[sourceDataSet.asSymbol, destDataSet.asSymbol], action, [numbers(FluidMessageResponse,_,1,_)]);
|
||||
actions[\fitTransform] = [numbers(FluidMessageResponse,_,1,_),action];
|
||||
this.prSendMsg(this.fitTransformMsg(sourceDataSet,destDataSet));
|
||||
}
|
||||
|
||||
transformPointMsg{|sourceBuffer, destBuffer|
|
||||
^this.prMakeMsg(\transformPoint,id,
|
||||
this.prEncodeBuffer(sourceBuffer),
|
||||
this.prEncodeBuffer(destBuffer),
|
||||
["/b_query",destBuffer.asUGenInput]
|
||||
);
|
||||
}
|
||||
|
||||
transformPoint{|sourceBuffer, destBuffer, action|
|
||||
sourceBuffer = this.prEncodeBuffer(sourceBuffer);
|
||||
destBuffer = this.prEncodeBuffer(destBuffer);
|
||||
this.prSendMsg(\transformPoint,[sourceBuffer, destBuffer], action, outputBuffers:[destBuffer]);
|
||||
actions[\transformPoint] = [nil,{action.value(destBuffer)}];
|
||||
this.prSendMsg(this.transformPointMsg(sourceBuffer,destBuffer));
|
||||
}
|
||||
|
||||
kr{|trig, inputBuffer,outputBuffer,numDimensions|
|
||||
|
||||
numDimensions = numDimensions ? this.numDimensions;
|
||||
this.numDimensions_(numDimensions);
|
||||
|
||||
^FluidProxyUgen.kr(this.class.name.asString++'/query', K2A.ar(trig),
|
||||
id, this.numDimensions, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,92 @@
|
||||
FluidProxyUgen : UGen {
|
||||
|
||||
var <>pluginname;
|
||||
|
||||
*kr { |pluginname...args|
|
||||
^this.new1('control', pluginname,*args)
|
||||
}
|
||||
|
||||
init { |pluginname...args|
|
||||
this.pluginname = pluginname;
|
||||
inputs = args;
|
||||
rate = 'control';
|
||||
}
|
||||
|
||||
name{
|
||||
^pluginname.asString;
|
||||
}
|
||||
|
||||
poll{ |trig = 10, label, trigid = -1|
|
||||
^super.poll(trig, label ? this.name, trigid)
|
||||
}
|
||||
}
|
||||
|
||||
FluidServerCache {
|
||||
|
||||
var <cache;
|
||||
|
||||
*new{ ^super.new.init }
|
||||
|
||||
init{
|
||||
cache = IdentityDictionary.new;
|
||||
}
|
||||
|
||||
do { |server, func|
|
||||
cache[server]!?{cache[server].do{|x|func.value(x)}}
|
||||
}
|
||||
|
||||
doAll {|func|
|
||||
cache.do{|subCache|
|
||||
subCache.do{|item|
|
||||
func.value(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
postln{
|
||||
cache.postln;
|
||||
}
|
||||
|
||||
at { |server,id|
|
||||
^cache[server].tryPerform(\at,id)
|
||||
}
|
||||
|
||||
includesKey{|server,key|
|
||||
^cache[server].tryPerform(\includesKey,key)
|
||||
}
|
||||
|
||||
put {|server,id,x|
|
||||
cache[server][id] = x;
|
||||
}
|
||||
|
||||
remove { |server,id|
|
||||
cache[server]!? {cache[server].removeAt(id)};
|
||||
}
|
||||
|
||||
initCache {|server|
|
||||
cache[server] ?? {
|
||||
cache[server] = IdentityDictionary.new;
|
||||
NotificationCenter.register(server,\newAllocators,this,
|
||||
{
|
||||
this.clearCache(server);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
clearCache { |server|
|
||||
cache[server] !?
|
||||
{
|
||||
var bundle = [];
|
||||
cache[server].values.do{|i|
|
||||
if(i.respondsTo(\freeMsg)){
|
||||
bundle = bundle.add(i.freeMsg); //server objects
|
||||
}{
|
||||
i.free; //OSCFunc
|
||||
}
|
||||
};
|
||||
server.listSendBundle(nil,bundle);
|
||||
cache.removeAt(server);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,305 @@
|
||||
FluidServerObject
|
||||
{
|
||||
classvar serverCaches;
|
||||
classvar count;
|
||||
classvar persistent = true;
|
||||
var <server,<id;
|
||||
|
||||
*initClass {
|
||||
// serverCaches = FluidServerCache.new;
|
||||
serverCaches = IdentityDictionary.new;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
*initCache {|server|
|
||||
serverCaches[this] ?? {serverCaches[this] = FluidServerCache.new};
|
||||
serverCaches[this].initCache(server);
|
||||
NotificationCenter.register(server,\newAllocators,this,{ count = 0; });
|
||||
}
|
||||
|
||||
*newMsg{|id, params|
|
||||
params = params !? {params.collect(_.asUGenInput)};
|
||||
// ("Newms"++params).postln;
|
||||
^['/cmd',this.objectClassName ++ '/new',id] ++ params
|
||||
}
|
||||
|
||||
*new{ |server, id, params, action, callNew = true|
|
||||
var newObj;
|
||||
server ?? {server = Server.default};
|
||||
if(server.serverRunning.not){"Server not running".warn};
|
||||
id !? { id = id.asInteger }
|
||||
?? { id = count; count = count + 1; };
|
||||
newObj = super.newCopyArgs(server,id,action);
|
||||
// params.postln;
|
||||
if(callNew) {server.listSendMsg(this.newMsg(id,params))};
|
||||
^newObj.cache
|
||||
}
|
||||
|
||||
cache {
|
||||
this.class.initCache(server);
|
||||
serverCaches[this.class].put(server,this.id,this);
|
||||
}
|
||||
|
||||
uncache{
|
||||
serverCaches[this.class].remove(server,id);
|
||||
}
|
||||
|
||||
prMakeMsg{|msg,id...args|
|
||||
^['/cmd',"%/%".format(this.class.objectClassName,msg),id].addAll(args);
|
||||
}
|
||||
|
||||
freeMsg {
|
||||
var msg;
|
||||
id ?? {" % already freed".format(this.class.name).warn; ^nil};
|
||||
this.uncache;
|
||||
msg = this.prMakeMsg(\free,id);
|
||||
id = nil;
|
||||
^msg;
|
||||
}
|
||||
|
||||
free{
|
||||
var msg = this.freeMsg;
|
||||
msg !? {server.listSendMsg(msg)} ?? {^nil};
|
||||
}
|
||||
|
||||
*freeAll{|server|
|
||||
serverCaches[this] !? {|cache|
|
||||
cache.clearCache(server ? Server.default);
|
||||
};
|
||||
count = 0;
|
||||
}
|
||||
|
||||
asUGenInput{ ^id }
|
||||
|
||||
asString {
|
||||
^"%(%)".format(this.class.name,id).asString;
|
||||
}
|
||||
|
||||
asSymbol {
|
||||
^id.asSymbol
|
||||
}
|
||||
|
||||
*objectClassName { ^this.name.asSymbol }
|
||||
|
||||
}
|
||||
|
||||
FluidBufProcessor : FluidServerObject
|
||||
{
|
||||
var <processAction;
|
||||
var <outputBuffers;
|
||||
var <freeWhenDone;
|
||||
classvar responder;
|
||||
classvar count;
|
||||
|
||||
*cmdPeriod {
|
||||
serverCaches[this] !? {|cache|
|
||||
cache.doAll{|processor| processor !? { processor.free;} };
|
||||
serverCaches[this] = nil;
|
||||
};
|
||||
count = 0;
|
||||
}
|
||||
|
||||
*initCache {|server|
|
||||
// "initcache".postln;
|
||||
// this.done.postln;
|
||||
super.initCache(server);
|
||||
CmdPeriod.add(this);
|
||||
if(serverCaches[this].includesKey(server,\processResponder).not)
|
||||
{
|
||||
serverCaches[this].put(server,\processResponder,OSCFunc({|m|
|
||||
var id = m.last.asInteger;
|
||||
// "I'm in the pizza hut".postln;
|
||||
serverCaches[this].at(server,id) !? {|p|
|
||||
// "I'm in the taco bell".postln ;
|
||||
p!?{
|
||||
p.processAction!?{|a|
|
||||
var bufs = p.outputBuffers;
|
||||
|
||||
bufs = bufs.collect{|b|
|
||||
if(b.isKindOf(Buffer))
|
||||
{b}
|
||||
{Buffer.cachedBufferAt(server,b)};
|
||||
};
|
||||
a.valueArray(valueArray(bufs));
|
||||
};
|
||||
if(p.freeWhenDone){p.free};
|
||||
}
|
||||
}
|
||||
},this.done ,server.addr).fix)
|
||||
}
|
||||
}
|
||||
|
||||
*new {|server,id,outputBuffers|
|
||||
^super.new(server,id, nil, nil,false).init(outputBuffers);
|
||||
}
|
||||
|
||||
init{ |ob|
|
||||
outputBuffers = ob;
|
||||
}
|
||||
|
||||
*done {
|
||||
^"/%/process".format(this.objectClassName);
|
||||
}
|
||||
|
||||
wait {
|
||||
var condition = Condition.new;
|
||||
OSCFunc({
|
||||
condition.unhang;
|
||||
},this.class.done,server.addr).oneShot;
|
||||
condition.hang;
|
||||
}
|
||||
|
||||
processMsg {|params|
|
||||
var msg;
|
||||
var completionMsg = outputBuffers !? {
|
||||
[["/sync"]] ++ outputBuffers.collect{|b| ["/b_query", b.asUGenInput]}
|
||||
} ?? {[]};
|
||||
|
||||
// completionMsg.postln;
|
||||
id ?? {Error("% already freed".format(this.class.name)).throw};
|
||||
msg = this.prMakeMsg(\processNew,id).addAll(params).add(completionMsg);
|
||||
// msg.postln;
|
||||
^msg;
|
||||
}
|
||||
|
||||
processList { |params,shouldFree,action|
|
||||
freeWhenDone = shouldFree;
|
||||
processAction = action;
|
||||
params = params.collect(_.asUGenInput);
|
||||
server.listSendMsg(this.processMsg(params));
|
||||
}
|
||||
|
||||
cancelMsg{
|
||||
id ?? {Error("% already freed".format(this.class.name)).throw};
|
||||
^this.prMakeMsg(\cancel, id);
|
||||
}
|
||||
|
||||
cancel{
|
||||
server.listSendMsg(this.cancelMsg);
|
||||
}
|
||||
|
||||
kr{ ^FluidProxyUgen.kr(this.objectClassName ++ "Monitor",id) }
|
||||
}
|
||||
|
||||
FluidOSCPatternInversion : OSCMessageDispatcher
|
||||
{
|
||||
value {|msg, time, addr, recvPort|
|
||||
var msgpath = msg[0];
|
||||
active.keysValuesDo({|key, func|
|
||||
if(msgpath.matchOSCAddressPattern(key), {func.value(msg, time, addr, recvPort);});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FluidDataObject : FluidServerObject
|
||||
{
|
||||
classvar postResponse;
|
||||
|
||||
var <actions;
|
||||
|
||||
*initClass{
|
||||
postResponse = _.postln;
|
||||
}
|
||||
|
||||
*initCache{ |server|
|
||||
super.initCache(server);
|
||||
if(serverCaches[this].includesKey(server,\messageResponder).not)
|
||||
{
|
||||
serverCaches[this].put(server,\messageResponder,OSCFunc.new({|m|
|
||||
var id = m[1].asInteger;
|
||||
var method;
|
||||
serverCaches[this].at(server,id) !? { |p|
|
||||
method = m[0].asString.findRegexp("/"++this.name++"/(.*)")[1][1].asSymbol;
|
||||
p.actions[method] !? {|a|
|
||||
//two items: parser and action
|
||||
var parser = a[0];
|
||||
var action = a[1];
|
||||
var result = FluidMessageResponse.collectArgs(parser,m[2..]);
|
||||
action.value(result);
|
||||
}
|
||||
}
|
||||
},'/' ++ this.objectClassName ++ '/*',server.addr, dispatcher:FluidOSCPatternInversion.new).fix)
|
||||
}
|
||||
}
|
||||
|
||||
*new{|server...args|
|
||||
// args.flatten.postln;
|
||||
^super.new(server,params:args.flatten).init;
|
||||
}
|
||||
|
||||
*cachedInstanceAt{|server,id|
|
||||
this.initCache;
|
||||
^serverCaches[this].at(server,id);
|
||||
}
|
||||
|
||||
init {
|
||||
actions = IdentityDictionary.new;
|
||||
}
|
||||
|
||||
prEncodeBuffer { |buf| buf !? {^buf.asUGenInput} ?? {^-1} }
|
||||
|
||||
prSendMsg {|msg| server !? {server.listSendMsg(msg)};}
|
||||
|
||||
colsMsg { ^this.prMakeMsg(\cols,id);}
|
||||
|
||||
cols{ |action=(postResponse)|
|
||||
actions[\cols] = [numbers(FluidMessageResponse,_,1,_),action];
|
||||
this.prSendMsg(this.colsMsg)
|
||||
}
|
||||
|
||||
readMsg { |filename| ^this.prMakeMsg(\read,id,filename.asString);}
|
||||
|
||||
read{|filename, action|
|
||||
actions[\read] = [nil,action];
|
||||
this.prSendMsg(this.readMsg(filename));
|
||||
}
|
||||
|
||||
writeMsg {|filename|
|
||||
// ^['/cmd',this.class.name ++ '/write',id,filename.asString]
|
||||
^this.prMakeMsg(\write,id,filename.asString);
|
||||
}
|
||||
|
||||
write{|filename, action|
|
||||
actions[\write] = [nil,action];
|
||||
this.prSendMsg(this.writeMsg(filename));
|
||||
}
|
||||
|
||||
sizeMsg{
|
||||
// ^['/cmd',this.class.name ++ '/size',id]
|
||||
^this.prMakeMsg(\size,id);
|
||||
}
|
||||
|
||||
size {|action=(postResponse)|
|
||||
actions[\size] = [numbers(FluidMessageResponse,_,1,_),action];
|
||||
this.prSendMsg(this.sizeMsg);
|
||||
}
|
||||
}
|
||||
|
||||
FluidModelObject : FluidDataObject
|
||||
{
|
||||
prGetParams{
|
||||
"Subclass should provide this".throw;
|
||||
}
|
||||
|
||||
prUpdateStateMsg{
|
||||
var params = this.prGetParams.value.collect(_.asUGenInput);
|
||||
^this.prMakeMsg(\setParams,id) ++ params;
|
||||
}
|
||||
|
||||
prSendMsg {|msg|
|
||||
//These need to happen sequentially, but not simultaneously
|
||||
//sending as a bundle makes reasoning about timing w/r/t other
|
||||
//commands more awkward, unless we set the offet to 0 (in which case,
|
||||
//noisy 'late' messages)
|
||||
super.prSendMsg(this.prUpdateStateMsg);
|
||||
super.prSendMsg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
FluidRealTimeModel : FluidModelObject
|
||||
{
|
||||
*new{ |server, params|
|
||||
^super.new(server,params++[-1,-1]);
|
||||
}
|
||||
}
|
||||
@ -1,29 +1,58 @@
|
||||
FluidStandardize : FluidRTDataClient {
|
||||
*new {|server, invert = 0|
|
||||
^super.new1(server,[\invert, invert]);
|
||||
FluidStandardize : FluidRealTimeModel {
|
||||
|
||||
var <>invert;
|
||||
|
||||
*new {|server, invert = 0|
|
||||
^super.new(server,[invert]).invert_(invert);
|
||||
}
|
||||
|
||||
fit{|dataSet, action|
|
||||
this.prSendMsg(\fit, [dataSet.asSymbol], action);
|
||||
prGetParams{
|
||||
^[this.invert, -1, 1];
|
||||
}
|
||||
|
||||
fitMsg{|dataSet|
|
||||
^this.prMakeMsg(\fit,id,dataSet.id);
|
||||
}
|
||||
|
||||
fit{|dataSet, action|
|
||||
actions[\fit] = [nil, action];
|
||||
this.prSendMsg(this.fitMsg(dataSet));
|
||||
}
|
||||
|
||||
transformMsg{|sourceDataSet, destDataSet|
|
||||
^this.prMakeMsg(\transform,id,sourceDataSet.id,destDataSet.id);
|
||||
}
|
||||
|
||||
transform{|sourceDataSet, destDataSet, action|
|
||||
this.prSendMsg(\transform,
|
||||
[sourceDataSet.asSymbol, destDataSet.asSymbol], action
|
||||
);
|
||||
actions[\transform] = [nil,action];
|
||||
this.prSendMsg(this.transformMsg(sourceDataSet,destDataSet));
|
||||
}
|
||||
|
||||
fitTransformMsg{|sourceDataSet, destDataSet|
|
||||
^this.prMakeMsg(\fitTransform,id,sourceDataSet.id,destDataSet.id)
|
||||
}
|
||||
|
||||
fitTransform{|sourceDataSet, destDataSet, action|
|
||||
this.prSendMsg(\fitTransform,
|
||||
[sourceDataSet.asSymbol, destDataSet.asSymbol], action
|
||||
);
|
||||
actions[\fitTransform] = [nil,action];
|
||||
this.prSendMsg(this.fitTransformMsg(sourceDataSet, destDataSet));
|
||||
}
|
||||
|
||||
|
||||
transformPointMsg{|sourceBuffer, destBuffer|
|
||||
^this.prMakeMsg(\transformPoint, id, this.prEncodeBuffer(sourceBuffer), this.prEncodeBuffer(destBuffer),["/b_query",destBuffer.asUGenInput]);
|
||||
}
|
||||
|
||||
transformPoint{|sourceBuffer, destBuffer, action|
|
||||
sourceBuffer = this.prEncodeBuffer(sourceBuffer);
|
||||
destBuffer = this.prEncodeBuffer(destBuffer);
|
||||
this.prSendMsg(\transformPoint,
|
||||
[sourceBuffer, destBuffer], action, outputBuffers:[destBuffer]
|
||||
);
|
||||
actions[\transformPoint] = [nil, {action.value(destBuffer)}];
|
||||
this.prSendMsg(this.transformPointMsg(sourceBuffer,destBuffer));
|
||||
}
|
||||
|
||||
kr{|trig, inputBuffer,outputBuffer,invert|
|
||||
|
||||
invert = invert ? this.invert;
|
||||
this.invert_(invert);
|
||||
|
||||
^FluidProxyUgen.kr(this.class.name.asString++'/query', K2A.ar(trig),
|
||||
id, this.invert, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,122 +1,228 @@
|
||||
// load a source
|
||||
b = Buffer.read(s,"/Volumes/machins/projets/newsfeed/sons/textes/Audio/synth/fromtexttospeech-AmE-George.wav")
|
||||
b.play
|
||||
// load a source folder
|
||||
~loader = FluidLoadFolder(File.realpath(FluidBufPitch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/");
|
||||
~loader.play;
|
||||
|
||||
//slightly oversegment with novelty
|
||||
//segments should still make sense but might cut a few elements in 2 or 3
|
||||
~originalslices = Buffer(s);
|
||||
FluidBufNoveltySlice.process(s, b, indices: ~originalslices, feature: 1, kernelSize: 29, threshold: 0.05, filterSize: 5, hopSize: 128, action: {~originalslices.numFrames.postln;})
|
||||
~slicer = FluidSliceCorpus({ |src,start,num,dest| FluidBufNoveltySlice.kr(src,start,num,indices:dest, feature: 1, kernelSize: 29, threshold: 0.1, filterSize: 5, hopSize: 128, blocking: 1)});
|
||||
~slicer.play(s, ~loader.buffer,~loader.index);
|
||||
|
||||
//test the segmentation by looping them
|
||||
(
|
||||
{
|
||||
BufRd.ar(1, b,
|
||||
Phasor.ar(0,1,
|
||||
BufRd.kr(1, ~originalslices,
|
||||
MouseX.kr(0, BufFrames.kr(~originalslices) - 1), 0, 1),
|
||||
BufRd.kr(1, ~originalslices,
|
||||
MouseX.kr(1, BufFrames.kr(~originalslices)), 0, 1),
|
||||
BufRd.kr(1,~originalslices,
|
||||
MouseX.kr(0, BufFrames.kr(~originalslices) - 1), 0, 1)), 0, 1);
|
||||
~originalindices = Array.newFrom(~slicer.index.keys).sort{|a,b| ~slicer.index[a][\bounds][0]< ~slicer.index[b][\bounds][0]}.collect{|x|~slicer.index[x][\bounds]};
|
||||
d = {arg start=0, end = 44100;
|
||||
BufRd.ar(1, ~loader.buffer, Phasor.ar(0,1,start,end,start),0,1);
|
||||
}.play;
|
||||
|
||||
w = Window.new(bounds:Rect(100,100,400,60)).front;
|
||||
b = ControlSpec(0, ~originalindices.size - 1, \linear, 1); // min, max, mapping, step
|
||||
c = StaticText(w, Rect(340, 20, 50, 20)).align_(\center);
|
||||
a = Slider(w, Rect(10, 20, 330, 20))
|
||||
.action_({var val = b.map(a.value).asInteger;
|
||||
c.string_(val.asString);
|
||||
d.set(\start,~originalindices[val][0], \end, ~originalindices[val][1]);
|
||||
});
|
||||
)
|
||||
|
||||
//analyse each segment with MFCCs in a dataset
|
||||
~originalslices.getn(0,~originalslices.numFrames, {|x|~originalslicesarray = x; if ((x.last != b.numFrames), {~originalslicesarray = ~originalslicesarray ++ (b.numFrames)}); });//retrieve the indices and add the file boundary at the end if not there already
|
||||
//analyse each segment with 20 MFCCs in a dataset and spectralshapes in another one
|
||||
(
|
||||
~featuresbuf = 4.collect{Buffer.new};
|
||||
~statsbuf = 4.collect{Buffer.new};
|
||||
~flatbuf = 4.collect{Buffer.new};
|
||||
~slicesMFCC = FluidDataSet(s);
|
||||
~slicesShapes = FluidDataSet(s);
|
||||
~extractor = FluidProcessSlices({|src,start,num,data|
|
||||
var features, stats, writer, flatten,mfccBuf, statsBuf, flatBuf, label, voice;
|
||||
label = data.key;
|
||||
voice = data.value[\voice];
|
||||
features = FluidBufMFCC.kr(src,startFrame:start,numFrames:num,numChans:1, numCoeffs: 20, features:~featuresbuf[voice],trig:1,blocking: 1);
|
||||
stats = FluidBufStats.kr(~featuresbuf[voice],stats:~statsbuf[voice],trig:Done.kr(features),blocking: 1);
|
||||
flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1);
|
||||
writer = FluidDataSetWr.kr(~slicesMFCC,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1);
|
||||
features = FluidBufSpectralShape.kr(src,startFrame:start,numFrames:num,numChans:1, features:~featuresbuf[voice],trig:Done.kr(writer),blocking: 1);
|
||||
stats = FluidBufStats.kr(~featuresbuf[voice],stats:~statsbuf[voice],trig:Done.kr(features),blocking: 1);
|
||||
flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1);
|
||||
writer = FluidDataSetWr.kr(~slicesShapes,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1);
|
||||
});
|
||||
)
|
||||
|
||||
//iterates through the
|
||||
//a few buffers and our dataset - with back and forth from the language
|
||||
(
|
||||
~mfccs = Buffer(s);
|
||||
~stats = Buffer(s);
|
||||
~flat = Buffer(s);
|
||||
~slices = FluidDataSet(s,\slices);
|
||||
|
||||
Routine{
|
||||
s.sync;
|
||||
(~originalslicesarray.size - 1).do{|i|
|
||||
FluidBufMFCC.process(s, b, startFrame: ~originalslicesarray[i], numFrames: (~originalslicesarray[i+1] - ~originalslicesarray[i]), numChans: 1,features: ~mfccs, numCoeffs: 20, action: {
|
||||
FluidBufStats.process(s, ~mfccs, startChan: 1, stats: ~stats, action: {
|
||||
FluidBufFlatten.process(s, ~stats, ~flat, action: {
|
||||
~slices.addPoint(i.asSymbol, ~flat);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}.play;
|
||||
t = Main.elapsedTime;
|
||||
~extractor.play(s,~loader.buffer, ~slicer.index, action:{(Main.elapsedTime - t).postln;"Analysis done".postln});
|
||||
)
|
||||
|
||||
~slices.print
|
||||
~slicesMFCC.print
|
||||
~slicesShapes.print
|
||||
|
||||
//run a window over consecutive segments, forcing them in 2 classes, and merging the consecutive segments of similar class
|
||||
//we overlap the analysis with the last (original) slice to check for continuity
|
||||
(
|
||||
~winSize = 4;//the number of consecutive items to split in 2 classes;
|
||||
~curated = FluidDataSet(s);
|
||||
~query = FluidDataSetQuery(s);
|
||||
~kmeans = FluidKMeans(s,2,100);
|
||||
~windowDS = FluidDataSet(s,\windowDS);
|
||||
~windowLS = FluidLabelSet(s,\windowLS);
|
||||
~stan = FluidStandardize(s);
|
||||
~kmeans = FluidKMeans(s,2,1000);
|
||||
~windowDS = FluidDataSet(s);
|
||||
~windowLS = FluidLabelSet(s);
|
||||
)
|
||||
|
||||
(
|
||||
Routine{
|
||||
~indices = [0];
|
||||
~head = 0;
|
||||
|
||||
~sliceDict = Dictionary.new(4);
|
||||
~tempDict = Dictionary.new(4);
|
||||
|
||||
~slices.dump{|x|~sliceDict = x;};
|
||||
s.sync;
|
||||
|
||||
while ( {~head <= (~originalslicesarray.size - ~winSize)},
|
||||
{
|
||||
var step = ~winSize - 1;
|
||||
var nbass = [];
|
||||
//run a process on ~winSize items from ~head (with an overlap of 1)
|
||||
//copy the items to a subdataset
|
||||
~winSize.do{|i|
|
||||
~tempDict.put((i.asString), ~sliceDict["data"][(i+~head).asString]);//here one could curate which stats to take
|
||||
"whichslices:%\n".postf(i+~head);
|
||||
};
|
||||
~windowDS.load(Dictionary.newFrom([\cols, 133, \data, ~tempDict]));
|
||||
s.sync;
|
||||
"% - loaded\n".postf(~head);
|
||||
//curate stats (MFCCs)
|
||||
~query.clear
|
||||
~query.addRange((0*20)+1,10);
|
||||
~query.transform(~slicesMFCC,~curated);
|
||||
|
||||
//kmeans 2 and retrieve ordered array of class assignations
|
||||
~kmeans.fitPredict(~windowDS, ~windowLS, {|x| nbass = x;});
|
||||
s.sync;
|
||||
"% - fitted1: ".postf(~head); nbass.postln;
|
||||
//OR
|
||||
//curate stats (moments)
|
||||
~query.clear
|
||||
~query.addRange(0,3);
|
||||
~query.transform(~slicesShapes,~curated);
|
||||
|
||||
// if (nbass.includes(0.0), { Routine{~kmeans.fitPredict(~windowDS, ~windowLS, {|x| nbass = x; "% - fitted2: ".postf(~head); nbass.postln; s.sync;});}.play; });
|
||||
//OR
|
||||
//curate both
|
||||
~query.clear
|
||||
~query.addColumn(0);//add col 0 (mean of mfcc0 as 'loudness')
|
||||
~query.transform(~slicesMFCC,~curated);//mfcc0 as loudness
|
||||
~query.clear;
|
||||
~query.addRange(0,3);//add some spectral moments
|
||||
~query.transformJoin(~slicesShapes, ~curated, ~curated);//join in centroids
|
||||
|
||||
~windowLS.dump{|x|~assignments = x.at("data").asSortedArray.flop[1].flatten;};
|
||||
s.sync;
|
||||
"% - assigned ".postf(~head);
|
||||
//optionally standardize in place
|
||||
~stan.fitTransform(~curated, ~curated);
|
||||
|
||||
~assignments.postln;
|
||||
~curated.print
|
||||
|
||||
step.do{|i|
|
||||
if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[~head+i+1])});
|
||||
};
|
||||
//retrieve the dataset as dictionary
|
||||
~curated.dump{|x|~sliceDict = x;};
|
||||
|
||||
~head = ~head + step;
|
||||
"-----------------".postln;
|
||||
});
|
||||
~originalslicesarray = (~originalindices.flatten ++ ~loader.buffer.numFrames).asSet.asArray.sort
|
||||
~orginalkeys = Array.newFrom(~slicer.index.keys).sort{|a,b| ~slicer.index[a][\bounds][0]< ~slicer.index[b][\bounds][0]}
|
||||
|
||||
//the windowed function, recursive to deal with sync dependencies
|
||||
(
|
||||
~windowedFunct = {arg head, winSize, overlap;
|
||||
var nbass = [], assignments = [], tempDict = ();
|
||||
//check the size of everything to not overrun
|
||||
winSize = (~originalslicesarray.size - head).min(winSize);
|
||||
//copy the items to a subdataset from hear
|
||||
winSize.do{|i|
|
||||
tempDict.put((i.asString), ~sliceDict["data"][(~orginalkeys[(i+head)]).asString]);//here one could curate which stats to take
|
||||
// "whichslices:%\n".postf(i+head);
|
||||
};
|
||||
~windowDS.load(Dictionary.newFrom([\cols, ~sliceDict["cols"].asInteger, \data, tempDict]), action: {
|
||||
// "% - loaded\n".postf(head);
|
||||
|
||||
//kmeans 2 and retrieve ordered array of class assignations
|
||||
~kmeans.fitPredict(~windowDS, ~windowLS, action: {|x|
|
||||
nbass = x;
|
||||
// "% - fitted1: ".postf(head); nbass.postln;
|
||||
|
||||
if (nbass.includes(winSize.asFloat), {
|
||||
~kmeans.fitPredict(~windowDS, ~windowLS, {|x|
|
||||
nbass = x;
|
||||
// "% - fitted2: ".postf(head); nbass.postln;
|
||||
if (nbass.includes(winSize.asFloat), {
|
||||
~kmeans.fitPredict(~windowDS, ~windowLS, {|x|
|
||||
nbass = x;
|
||||
// "% - fitted3: ".postf(head); nbass.postln;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
~windowLS.dump{|x|
|
||||
var assignments = x.at("data").asSortedArray.flop[1].flatten;
|
||||
"% - assigned ".postf(head);
|
||||
|
||||
//leftovers
|
||||
if ( (~originalslicesarray.size - ~head) > 1, {
|
||||
//run a process on (a.size - ~head) items from ~head
|
||||
(~originalslicesarray.size - ~head - 1).do{|i|
|
||||
if (~assignments[i+1] != ~assignments[i], {~indices= ~indices ++ (~originalslicesarray[~head+i+1])});
|
||||
// (~head+i).postln;
|
||||
};
|
||||
assignments.postln;
|
||||
|
||||
(winSize-1).do{|i|
|
||||
if (assignments[i+1] != assignments[i], {
|
||||
~newindices= ~newindices ++ (~originalslicesarray[head+i+1]).asInteger;
|
||||
~newkeys = ~newkeys ++ (~orginalkeys[head+i+1]);
|
||||
});
|
||||
|
||||
};
|
||||
//if we still have some frames to do, do them
|
||||
if (((winSize + head) < ~originalslicesarray.size), {
|
||||
"-----------------".postln;
|
||||
~windowedFunct.value(head + winSize - overlap, winSize, overlap);
|
||||
}, {~newindices = (~newindices ++ ~loader.buffer.numFrames); "done".postln;});//if we're done close the books
|
||||
};
|
||||
});
|
||||
});
|
||||
~indices.postln;
|
||||
}.play;
|
||||
}
|
||||
)
|
||||
|
||||
{var i = 8;BufRd.ar(1,b,Line.ar(~originalslicesarray[i],~originalslicesarray[i+1],(~originalslicesarray[i+1] - ~originalslicesarray[i])/b.sampleRate, doneAction: 2))}.play;
|
||||
{var i = 4;BufRd.ar(1,b,Line.ar(~indices[i],~indices[i+1],(~indices[i+1] - ~indices[i])/b.sampleRate, doneAction: 2))}.play;
|
||||
//the job
|
||||
|
||||
//test 1 - start at the begining, consider 4 items at a time, make 2 clusters, overlap 1
|
||||
~newindices = [~originalslicesarray[0]]; ~newkeys = [~orginalkeys[0]];
|
||||
~windowedFunct.value(0, 4, 1);
|
||||
|
||||
//OPTIONAL: try again with more clusters (3) and a wider window (6) and more overlap (2)
|
||||
~newindices = [~originalslicesarray[0]]; ~newkeys = [~orginalkeys[0]];
|
||||
~kmeans.numClusters = 3;
|
||||
~windowedFunct.value(0,6,2);
|
||||
|
||||
//compare sizes
|
||||
~orginalkeys.size
|
||||
~newkeys.size;
|
||||
|
||||
//export to reaper
|
||||
(
|
||||
//first create a new file that ends with rpp - it will overwrite if the file exists
|
||||
f = File.new("/tmp/clusteredslices-" ++ Date.getDate.stamp ++".rpp","w+");
|
||||
|
||||
if (f.isOpen , {
|
||||
var path, prevpath ="", sr, count, dur;
|
||||
//write the header
|
||||
f.write("<REAPER_PROJECT 0.1 \"5.99/OSX64\" 1603037150\n\n");
|
||||
|
||||
//a first track with the originalslicearray
|
||||
//write the track header
|
||||
f.write("<TRACK\nNAME \"novelty output\"\n");
|
||||
// iterate through the items in the track
|
||||
~orginalkeys.do{|v, i|
|
||||
path = ~slicer.index[v][\path];
|
||||
if (path != prevpath, {
|
||||
sr = ~slicer.index[v][\sr];
|
||||
prevpath = path;
|
||||
count = 0;
|
||||
});
|
||||
dur = ~originalslicesarray[i+1] - ~originalslicesarray[i];
|
||||
if ( dur > 0, {
|
||||
f.write("<ITEM\nPOSITION " ++ (~originalslicesarray[i] / sr) ++ "\nLENGTH " ++ (dur / sr) ++ "\nNAME \"" ++ v ++ "\"\nSOFFS " ++ (count / sr) ++ "\n<SOURCE WAVE\nFILE \"" ++ path ++ "\"\n>\n>\n");
|
||||
});
|
||||
count = count + dur;
|
||||
};
|
||||
//write the track footer
|
||||
f.write(">\n");
|
||||
|
||||
// a second track with the new ~indices
|
||||
prevpath = "";
|
||||
//write the track header
|
||||
f.write("<TRACK\nNAME \"clustered output\"\n");
|
||||
// iterate through the items in the track
|
||||
~newkeys.do{|v, i|
|
||||
path = ~slicer.index[v][\path];
|
||||
if (path != prevpath, {
|
||||
sr = ~slicer.index[v][\sr];
|
||||
prevpath = path;
|
||||
count = 0;
|
||||
});
|
||||
dur = ~newindices[i+1] - ~newindices[i];
|
||||
if (dur > 0, {
|
||||
f.write("<ITEM\nPOSITION " ++ (~newindices[i] / sr) ++ "\nLENGTH " ++ (dur / sr) ++ "\nNAME \"" ++ v ++ "\"\nSOFFS " ++ (count / sr) ++ "\n<SOURCE WAVE\nFILE \"" ++ path ++ "\"\n>\n>\n");
|
||||
});
|
||||
count = count + dur;
|
||||
};
|
||||
//write the track footer
|
||||
f.write(">\n");
|
||||
|
||||
//write the footer
|
||||
f.write(">\n");
|
||||
f.close;
|
||||
});
|
||||
)
|
||||
|
||||
(then open the time-stamped reaper file clusterdslice in the folder tmp)
|
||||
@ -0,0 +1,330 @@
|
||||
// Lookup in a KDTree using melbands
|
||||
// Demonstration of a massive parallel approach to batch process swiftly in SC
|
||||
|
||||
s.options.numBuffers = 16384 //The method below for doing the analysus quickly needs lots of buffers
|
||||
s.reboot
|
||||
|
||||
//Step 0: Make a corpus
|
||||
|
||||
//We'll jam together some random flucoma sounds for illustrative purposes
|
||||
//Get some files
|
||||
(
|
||||
~audioexamples_path = File.realpath(FluidBufMelBands.class.filenameSymbol).dirname.withTrailingSlash +/+ "../AudioFiles/*.wav";
|
||||
~allTheSounds = SoundFile.collect(~audioexamples_path);
|
||||
~testSounds = ~allTheSounds;
|
||||
~testSounds.do{|f| f.path.postln}; // print out the files that are loaded
|
||||
)
|
||||
|
||||
//Load the files into individual buffers:
|
||||
(
|
||||
~audio_buffers = ~testSounds.collect{|f|
|
||||
Buffer.readChannel(
|
||||
server: s,
|
||||
path:f.path,
|
||||
channels:[0],
|
||||
action:{("Loaded" + f.path).postln;}
|
||||
)
|
||||
};
|
||||
)
|
||||
|
||||
//Do a segmentation of each buffer, in parallel
|
||||
(
|
||||
fork{
|
||||
~index_buffers = ~audio_buffers.collect{Buffer.new};
|
||||
s.sync;
|
||||
~count = ~audio_buffers.size;
|
||||
~audio_buffers.do{|src,i|
|
||||
FluidBufOnsetSlice.process(
|
||||
server:s,
|
||||
source:src,
|
||||
indices:~index_buffers[i],
|
||||
metric: 9,
|
||||
threshold:0.2,
|
||||
minSliceLength: 17,
|
||||
action:{
|
||||
(~testSounds[i].path ++ ":" + ~index_buffers[i].numFrames + "slices").postln;
|
||||
~count = ~count - 1;
|
||||
if(~count == 0){"Done slicing".postln};
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// we now have an array of index buffers, one per source buffer, each containing the segmentation points as a frame positions
|
||||
// this allows us to make an array of sizes
|
||||
~index_buffers.collect{|b| b.numFrames}.sum
|
||||
|
||||
//For each of these segments, let's make a datapoint using the mean melbands.
|
||||
// There's a number of ways of skinning this cat w/r/t telling the server what to do, but here we want to minimize traffic between language and server, and also produce undertsandable code
|
||||
|
||||
//First, we'll grab the onset points as language-side arrays, then scroll through each slice getting the mean melbands
|
||||
(
|
||||
// - a dataset to keep the mean melbands in
|
||||
~mels = FluidDataSet(s);
|
||||
// - a dictionary to keep the slice points in for later playback
|
||||
~slices = Dictionary();
|
||||
//The code below (as well as needing lots of buffers), creates lots of threads and we need a big ass scheduling queue
|
||||
~clock = TempoClock(queueSize:8192);
|
||||
)
|
||||
|
||||
|
||||
// Do the Mel analysis in a cunning parallel fashion
|
||||
(
|
||||
{
|
||||
var counter, remaining;
|
||||
var condition = Condition.new; // used to create a test condition to pause the routine ...
|
||||
var index_arrays = Dictionary();
|
||||
|
||||
"Process started. Please wait.".postln;
|
||||
|
||||
~total_slice_count = ~index_buffers.collect{|b| b.numFrames}.sum + ~index_buffers.size; //we get an extra slice in buffer
|
||||
~featurebuffers = ~total_slice_count.collect{Buffer.new}; // create a buffer per slice
|
||||
|
||||
//Make our dictionary FluidDataSet-shaped
|
||||
~slices.put("cols",3);//[bufnum,start,end] for each slice
|
||||
~slices.put("data",Dictionary());
|
||||
|
||||
//Collect each set of onsets into a language side array and store them in a dict
|
||||
~index_buffers.do{|b,i| // iterate over the 4 buffers
|
||||
{
|
||||
b.loadToFloatArray( // load to language side array
|
||||
action:{|indices|
|
||||
//Glue the first and last samples of the buffer on to the index list, and place in dictionary wiht the
|
||||
//Buffer object as a key
|
||||
|
||||
index_arrays.put(~audio_buffers[i], Array.newFrom([0] ++ indices ++ (~audio_buffers[i].numFrames - 1)));
|
||||
|
||||
if(i==(~index_buffers.size-1)) {condition.unhang};
|
||||
}
|
||||
)
|
||||
}.fork(stackSize:~total_slice_count);
|
||||
};
|
||||
condition.hang; //Pause until all the callbacks above have completed
|
||||
"Arrays loaded. Starting on the analysis, please wait.".postln;
|
||||
|
||||
//For each of these lists of points, we want to scroll over the indices in pairs and get some mel bands
|
||||
counter = 0;
|
||||
remaining = ~total_slice_count;
|
||||
|
||||
s.sync;
|
||||
|
||||
// now iterate over Dict and calc melbands
|
||||
|
||||
index_arrays.keysValuesDo{|buffer, indices|
|
||||
indices.doAdjacentPairs{|start,end,num|
|
||||
var analysis = Routine({|counter|
|
||||
|
||||
FluidBufMelBands.processBlocking(
|
||||
server:s,
|
||||
source:buffer,
|
||||
startFrame:start,
|
||||
numFrames:(end-1) - start,
|
||||
features:~featurebuffers[counter],
|
||||
action:{
|
||||
remaining = remaining - 1;
|
||||
if(remaining == 0) { ~numMelBands = ~featurebuffers[0].numChannels;condition.unhang };
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
~slices["data"].put(counter,[buffer.bufnum,start,end]);
|
||||
|
||||
//I'm spawning new threads to wait for the analysis callback from the server. The final callback will un-hang this thread
|
||||
analysis.value(counter); //Done differently to other blocks because I need to pass in the value of counter
|
||||
counter = counter + 1;
|
||||
}
|
||||
};
|
||||
condition.hang;
|
||||
"Analysis of % slices done.\n".postf(~total_slice_count);
|
||||
}.fork(clock:~clock);
|
||||
)
|
||||
|
||||
|
||||
// Run stats on each mel buffer
|
||||
|
||||
// create a stats buffer for each of the slices
|
||||
~statsbuffers = ~total_slice_count.collect{Buffer.new}; // create n Slices buffers - to be filled with (40 mel bands * 7 stats)
|
||||
|
||||
// run stats on all the buffers
|
||||
(
|
||||
{
|
||||
var remaining = ~total_slice_count;
|
||||
~featurebuffers.do{|buffer,i|
|
||||
FluidBufStats.processBlocking(
|
||||
server:s,
|
||||
source:buffer,
|
||||
stats:~statsbuffers[i],
|
||||
action:{
|
||||
remaining = remaining - 1;
|
||||
if(remaining == 0) { "done".postln};
|
||||
}
|
||||
);
|
||||
};
|
||||
}.fork(clock:~clock);
|
||||
)
|
||||
|
||||
~featurebuffers.size
|
||||
|
||||
//Flatten each stats buffer into a data point
|
||||
~flatbuffers = ~total_slice_count.collect{Buffer.new};// create an array of flatten stats
|
||||
|
||||
(
|
||||
{
|
||||
var remaining = ~total_slice_count;
|
||||
~statsbuffers.do{|buffer,i|
|
||||
FluidBufFlatten.processBlocking(
|
||||
server:s,
|
||||
source:buffer,
|
||||
destination:~flatbuffers[i],
|
||||
action:{
|
||||
remaining = remaining - 1;
|
||||
if(remaining == 0) { "Got flat points".postln; };
|
||||
}
|
||||
);
|
||||
};
|
||||
}.fork(clock:~clock);
|
||||
)
|
||||
|
||||
|
||||
//Ram each flat point into a data set. At this point we have more data than we need, but we'll prune in moment
|
||||
(
|
||||
"Filling dataset".postln;
|
||||
~mels.clear;
|
||||
|
||||
// ~flatbuffers = flatbuffers;
|
||||
~flatbuffers.do{|buf,i|
|
||||
~mels.addPoint(i,buf);
|
||||
};
|
||||
|
||||
~mels.print;
|
||||
)
|
||||
|
||||
|
||||
// Prune & standardise
|
||||
|
||||
// Tidy up the temp arrays of buffers we do not need anymore
|
||||
|
||||
(
|
||||
"Cleaning".postln;
|
||||
(~featurebuffers ++ ~statsbuffers ++ ~flatbuffers).do{|buf| buf.free};
|
||||
)
|
||||
|
||||
//Above we sneakily made a dictionary of slice data for playback (bufnum,start,end). Let's throw it in a dataset
|
||||
~slicedata = FluidDataSet(s); // will hold slice data (bufnum,start,end) for playback
|
||||
|
||||
//dict -> dataset
|
||||
(
|
||||
~slicedata.load(~slices);
|
||||
~slicedata.print;
|
||||
)
|
||||
|
||||
// Step 1. Let's prune and standardize before fitting to a tree
|
||||
(
|
||||
~meanmels = FluidDataSet(s);//will hold pruned mel data
|
||||
~stdmels = FluidDataSet(s);//will standardised, pruned mel data
|
||||
~standardizer = FluidStandardize(s);
|
||||
~pruner = FluidDataSetQuery(s);
|
||||
~tree = FluidKDTree(s,numNeighbours:10,lookupDataSet:~slicedata);//we have to supply the lookup data set when we make the tree (boo!)
|
||||
)
|
||||
|
||||
//Prune, standardize and fit KDTree
|
||||
(
|
||||
{
|
||||
~meanmels.clear;
|
||||
~stdmels.clear;
|
||||
~pruner.addRange(0,~numMelBands).transform(~mels,~meanmels); //prune with a 'query' -- so this is dropping all but ~meanmels
|
||||
~standardizer.fitTransform(~meanmels,~stdmels);
|
||||
~tree.fit(~stdmels,{"KDTree ready".postln});
|
||||
}.fork(clock:~clock);
|
||||
)
|
||||
|
||||
~meanmels.print
|
||||
|
||||
//Step 2: Set the FluidStandardizer and FluidKDTree up for listening
|
||||
//set the buffers and busses needed
|
||||
(
|
||||
~stdInputPoint = Buffer.alloc(s,40);
|
||||
~stdOutputPoint = Buffer.alloc(s,40);
|
||||
~treeOutputPoint = Buffer.alloc(s,3 * 10);//numNeighbours x triples of bufnum,start,end
|
||||
)
|
||||
|
||||
|
||||
// let's play a random sound (to make sure we understand our data structure!
|
||||
(
|
||||
{
|
||||
var randPoint, buf, start, stop, dur;
|
||||
|
||||
randPoint = ~slices["data"].keys.asArray.scramble[0]; // this good way of getting - but recast as strong
|
||||
|
||||
buf= ~slices["data"][randPoint][0];
|
||||
start = ~slices["data"][randPoint][1];
|
||||
stop = ~slices["data"][randPoint][2];
|
||||
|
||||
dur = stop - start;
|
||||
|
||||
BufRd.ar(1,buf, Line.ar(start,stop,dur/s.sampleRate, doneAction: 2), 0, 2);
|
||||
}.play
|
||||
)
|
||||
|
||||
|
||||
// Query KD tree
|
||||
|
||||
// a target sound from outside our dataset
|
||||
~inBuf = Buffer.readChannel(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav", numFrames:15000, channels:[0]);
|
||||
~inBuf.play
|
||||
|
||||
//OR one from within
|
||||
~inBuf = Buffer.alloc(s,15000);
|
||||
~randomSlice = ~slices["data"].keys.asArray.scramble[0];
|
||||
~audio_buffers[~slices["data"][~randomSlice][0]].copyData(~inBuf,srcStartAt: ~slices["data"][~randomSlice][1], numSamples: 15000.min(~slices["data"][~randomSlice][2] - (~slices["data"][~randomSlice][1])));
|
||||
~inBuf.play
|
||||
|
||||
// now try getting a point, playing it, grabbing nearest neighbour and playing it ...
|
||||
|
||||
(
|
||||
~inBufMels = Buffer(s);
|
||||
~inBufStats = Buffer(s);
|
||||
~inBufFlat = Buffer(s);
|
||||
~inBufComp = Buffer(s);
|
||||
~inBufStand = Buffer(s);
|
||||
)
|
||||
|
||||
// FluidBuf Compose is buf version of dataSetQuery
|
||||
|
||||
(
|
||||
FluidBufMelBands.process(s, ~inBuf, features: ~inBufMels, action: {
|
||||
FluidBufStats.process(s, ~inBufMels, stats:~inBufStats, action: {
|
||||
FluidBufFlatten.process(s, ~inBufStats, ~inBufFlat, action: {
|
||||
FluidBufCompose.process(s, ~inBufFlat, numFrames: ~numMelBands, destination: ~inBufComp, action: {
|
||||
~standardizer.transformPoint(~inBufComp, ~inBufStand, {
|
||||
~tree.kNearest(~inBufStand,{ |a|a.postln;~nearest = a;})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
// playback nearest in order
|
||||
(
|
||||
fork{
|
||||
~nearest.do{|i|
|
||||
var buf, start, stop, dur;
|
||||
|
||||
buf= ~slices["data"][i.asInteger][0];
|
||||
start = ~slices["data"][i.asInteger][1];
|
||||
stop = ~slices["data"][i.asInteger][2];
|
||||
dur = (stop - start)/ s.sampleRate;
|
||||
{BufRd.ar(1,buf, Line.ar(start,stop,dur, doneAction: 2), 0, 2);}.play;
|
||||
|
||||
i.postln;
|
||||
dur.wait;
|
||||
};
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,161 @@
|
||||
// Make:
|
||||
// - A kmeans
|
||||
// - a datasetquery
|
||||
// - a normalizer
|
||||
// - a standardizer
|
||||
// - 3 DataSets of example points R-G-B descriptions
|
||||
// - 3 DataSets for the scaled versions
|
||||
// - 1 summative dataset and a LabelSet for predicted labels
|
||||
|
||||
(
|
||||
~classifier = FluidKMeans(s,5, 1000);
|
||||
~query = FluidDataSetQuery(s);
|
||||
~stan = FluidStandardize(s);
|
||||
~norm = FluidNormalize(s);
|
||||
~sourceR = FluidDataSet(s);
|
||||
~sourceG = FluidDataSet(s);
|
||||
~sourceB = FluidDataSet(s);
|
||||
~scaledR = FluidDataSet(s);
|
||||
~scaledG = FluidDataSet(s);
|
||||
~scaledB = FluidDataSet(s);
|
||||
~composited = FluidDataSet(s);
|
||||
~labels = FluidLabelSet(s);
|
||||
)
|
||||
|
||||
//Make some random, but clustered test points, each descriptor category in a separate dataset
|
||||
(
|
||||
~sourceR.load(Dictionary.newFrom([\cols, 1, \data, (Dictionary.newFrom(40.collect{|x| [x, 1.0.sum3rand]}.flatten))]));
|
||||
~sourceG.load(Dictionary.newFrom([\cols, 1, \data, (Dictionary.newFrom(40.collect{|x| [x, 1.0.rand2]}.flatten))]));
|
||||
~sourceB.load(Dictionary.newFrom([\cols, 1, \data, (Dictionary.newFrom(40.collect{|x| [x, (0.5.sum3rand).squared + [0.75,-0.1].choose]}.flatten))]));
|
||||
)
|
||||
|
||||
//here we manipulate
|
||||
|
||||
//assemble the scaled dataset
|
||||
(
|
||||
~query.addColumn(0, {
|
||||
~query.transformJoin(~sourceB, ~sourceG, ~composited, {
|
||||
~query.transformJoin(~sourceR, ~composited, ~composited);
|
||||
});
|
||||
});
|
||||
)
|
||||
|
||||
~composited.print
|
||||
|
||||
//Fit the classifier to the example DataSet and labels, and then run prediction on the test data into our mapping label set
|
||||
~classifier.fitPredict(~composited,~labels,{~labels.dump{|x|~labeldict = x;};~composited.dump{|x|~compodict=x;};});
|
||||
|
||||
//Visualise:
|
||||
(
|
||||
w = Window("sourceClasses", Rect(128, 64, 820, 120));
|
||||
w.drawFunc = {
|
||||
Pen.use{
|
||||
~compodict["data"].keysValuesDo{|key, colour|
|
||||
Pen.fillColor = Color.fromArray((colour * 0.5 + 0.5 ).clip(0,1) ++ 1);
|
||||
Pen.fillRect( Rect( (key.asFloat * 20 + 10), (~labeldict["data"].at(key).asInteger[0] * 20 + 10),15,15));
|
||||
};
|
||||
};
|
||||
};
|
||||
w.refresh;
|
||||
w.front;
|
||||
)
|
||||
|
||||
// standardize our colours and rerun
|
||||
(
|
||||
~stan.fitTransform(~sourceR, ~scaledR, {
|
||||
~stan.fitTransform(~sourceG, ~scaledG, {
|
||||
~stan.fitTransform(~sourceB, ~scaledB, {
|
||||
//assemble
|
||||
~query.addColumn(0, {
|
||||
~query.transformJoin(~scaledB, ~scaledG, ~composited, {
|
||||
~query.transformJoin(~scaledR, ~composited, ~composited, {
|
||||
//fit
|
||||
~classifier.fitPredict(~composited,~labels,{~labels.dump{|x|~labeldict2 = x;};~composited.dump{|x|~compodict2=x;};});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
)
|
||||
|
||||
//Visualise:
|
||||
(
|
||||
w = Window("stanClasses", Rect(128, 204, 820, 120));
|
||||
w.drawFunc = {
|
||||
Pen.use{
|
||||
~compodict2["data"].keysValuesDo{|key, colour|
|
||||
Pen.fillColor = Color.fromArray((colour * 0.25 + 0.5 ).clip(0,1) ++ 1);
|
||||
Pen.fillRect( Rect( (key.asFloat * 20 + 10), (~labeldict2["data"].at(key).asInteger[0] * 20 + 10),15,15));
|
||||
};
|
||||
};
|
||||
};
|
||||
w.refresh;
|
||||
w.front;
|
||||
)
|
||||
|
||||
//now let's normalise instead
|
||||
(
|
||||
~norm.fitTransform(~sourceR, ~scaledR, {
|
||||
~norm.fitTransform(~sourceG, ~scaledG, {
|
||||
~norm.fitTransform(~sourceB, ~scaledB, {
|
||||
//assemble
|
||||
~query.addColumn(0, {
|
||||
~query.transformJoin(~scaledB, ~scaledG, ~composited, {
|
||||
~query.transformJoin(~scaledR, ~composited, ~composited, {
|
||||
//fit
|
||||
~classifier.fitPredict(~composited,~labels,{~labels.dump{|x|~labeldict2 = x;};~composited.dump{|x|~compodict2=x;};});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
)
|
||||
|
||||
//Visualise:
|
||||
(
|
||||
w = Window("normClasses", Rect(128, 344, 820, 120));
|
||||
w.drawFunc = {
|
||||
Pen.use{
|
||||
~compodict2["data"].keysValuesDo{|key, colour|
|
||||
Pen.fillColor = Color.fromArray((colour * 0.25 + 0.5 ).clip(0,1) ++ 1);
|
||||
Pen.fillRect( Rect( (key.asFloat * 20 + 10), (~labeldict2["data"].at(key).asInteger[0] * 20 + 10),15,15));
|
||||
};
|
||||
};
|
||||
};
|
||||
w.refresh;
|
||||
w.front;
|
||||
)
|
||||
|
||||
// let's mess up with the scaling of one dimension: let's multiply the range of Red by 10
|
||||
~norm.min = -10;
|
||||
~norm.max = 10;
|
||||
(
|
||||
~norm.fitTransform(~sourceR, ~scaledR, {
|
||||
//assemble
|
||||
~query.addColumn(0, {
|
||||
~query.transformJoin(~scaledB, ~scaledG, ~composited, {
|
||||
~query.transformJoin(~scaledR, ~composited, ~composited, {
|
||||
//fit
|
||||
~classifier.fitPredict(~composited,~labels,{~labels.dump{|x|~labeldict2 = x;};~composited.dump{|x|~compodict2=x;};});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
)
|
||||
|
||||
//Visualise:
|
||||
(
|
||||
w = Window("norm10rClasses", Rect(128, 484, 820, 120));
|
||||
w.drawFunc = {
|
||||
Pen.use{
|
||||
~compodict2["data"].keysValuesDo{|key, colour|
|
||||
Pen.fillColor = Color.fromArray((colour * 0.25 + 0.5 ).clip(0,1) ++ 1);
|
||||
Pen.fillRect( Rect( (key.asFloat * 20 + 10), (~labeldict2["data"].at(key).asInteger[0] * 20 + 10),15,15));
|
||||
};
|
||||
};
|
||||
};
|
||||
w.refresh;
|
||||
w.front;
|
||||
)
|
||||
@ -1,59 +0,0 @@
|
||||
(
|
||||
b = Buffer.read(s,File.realpath(FluidBufNoveltySlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav");
|
||||
c = Buffer.new(s);
|
||||
)
|
||||
|
||||
(
|
||||
// with basic params
|
||||
Routine{
|
||||
var startTime, target, tolerance, startThresh, prevThresh, curThresh, curVal, prevVal, iters, maxIters, dVal, dThresh;
|
||||
startTime = Main.elapsedTime;
|
||||
prevThresh = 0.1; //initial threshold (between 0.00001 and 0.99999
|
||||
target = 10; //number of slices desired
|
||||
tolerance = 0; // the acceptable error in the number of slices yield
|
||||
maxIters = 100; //max number of iterations acceptable
|
||||
|
||||
//makes a first iteration
|
||||
FluidBufNoveltySlice.process(s,b, indices: c, threshold:prevThresh,action:{|x|prevVal = x.numFrames});
|
||||
//makes a second iteration
|
||||
if ( (prevVal < target), {
|
||||
curThresh = (prevThresh * 0.5).max(0.000001);
|
||||
}, {
|
||||
curThresh = (prevThresh * 2).min(0.999999);
|
||||
});
|
||||
FluidBufNoveltySlice.process(s,b, indices: c, threshold:curThresh,action:{|x|curVal = x.numFrames});
|
||||
|
||||
//makes further iterations until the result is achieved, or the maximum of acceptable iterations is reached
|
||||
iters = 2;
|
||||
while ( {
|
||||
(iters < maxIters) && ((curVal - target).abs > tolerance)
|
||||
}, {
|
||||
iters = iters + 1;
|
||||
dVal = curVal - prevVal;
|
||||
dThresh = curThresh - prevThresh;
|
||||
|
||||
prevThresh = curThresh;
|
||||
prevVal = curVal;
|
||||
|
||||
if ( (dVal == 0), {
|
||||
//if we have not change results between the last 2 passes, make the variation of threshold bigger
|
||||
curThresh = (dThresh + curThresh).min(0.999999).max(0.000001);
|
||||
},{
|
||||
//if we have
|
||||
curThresh = (((dThresh / dVal) * (target - curVal)) + curThresh).min(0.999999).max(0.000001);
|
||||
});
|
||||
FluidBufNoveltySlice.process(s,b, indices: c, threshold:curThresh,action:{|x|curVal = x.numFrames});
|
||||
}
|
||||
);
|
||||
//depending on the outcome, gives the right info back
|
||||
|
||||
if ( iters >= maxIters, {
|
||||
// failed
|
||||
"Failed to find a suitable threshold in % seconds.\n".postf((Main.elapsedTime - startTime).round(0.01));
|
||||
}, {
|
||||
// succeeded
|
||||
"Found % as a suitable threshold for % slices in % seconds and % iterations.\n".postf(curThresh, curVal, (Main.elapsedTime - startTime).round(0.01), iters);
|
||||
}
|
||||
);
|
||||
}.play
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue