Merge remote-tracking branch 'origin/pr/25' into feature/named+rolling
commit
f63ae2cab3
@ -1,169 +1,229 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SC_PlugIn.hpp>
|
#include <SC_PlugIn.hpp>
|
||||||
|
|
||||||
namespace fluid{
|
namespace fluid {
|
||||||
namespace client{
|
namespace client {
|
||||||
namespace impl{
|
namespace impl {
|
||||||
template <typename Client, class Wrapper>
|
|
||||||
struct RealTimeBase
|
|
||||||
{
|
template <typename Client, class Wrapper>
|
||||||
using HostVector = FluidTensorView<float, 1>;
|
struct RealTimeBase
|
||||||
using Params = typename Client::ParamSetType;
|
{
|
||||||
template<typename T, bool>
|
using IOMapFn = void (RealTimeBase::*)(SCUnit&, Client&);
|
||||||
struct doExpectedCount;
|
using HostVector = FluidTensorView<float, 1>;
|
||||||
|
using Params = typename Client::ParamSetType;
|
||||||
template<typename T>
|
template <typename T, bool>
|
||||||
struct doExpectedCount<T, false>
|
struct doExpectedCount;
|
||||||
{
|
|
||||||
static void count(const T& d,FloatControlsIter& c,Result& status)
|
template <typename T>
|
||||||
{
|
struct doExpectedCount<T, false>
|
||||||
if(!status.ok()) return;
|
{
|
||||||
|
static void count(const T& d, FloatControlsIter& c, Result& status)
|
||||||
if(c.remain())
|
{
|
||||||
{
|
if (!status.ok()) return;
|
||||||
index statedSize = d.fixedSize;
|
|
||||||
|
if (c.remain())
|
||||||
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 = 1;
|
|
||||||
|
|
||||||
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);
|
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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Result expectedSize(FloatControlsIter& controls)
|
template <typename T>
|
||||||
|
struct doExpectedCount<T, true>
|
||||||
|
{
|
||||||
|
static void count(const T& d, FloatControlsIter& c, Result& status)
|
||||||
{
|
{
|
||||||
if(controls.size() < Client::getParameterDescriptors().count())
|
if (!status.ok()) return;
|
||||||
|
|
||||||
|
if (c.remain())
|
||||||
{
|
{
|
||||||
return {Result::Status::kError,"Fewer parameters than exepected. Got ", controls.size(), "expect at least", Client::getParameterDescriptors().count()};
|
index statedSize = 1;
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result countScan;
|
|
||||||
Client::getParameterDescriptors().template iterate<ExpectedCount>(
|
|
||||||
std::forward<FloatControlsIter&>(controls),
|
|
||||||
std::forward<Result&>(countScan));
|
|
||||||
return countScan;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// static index ControlOffset(Unit* unit) { return unit->mSpecialIndex + 1; }
|
Result expectedSize(FloatControlsIter& controls)
|
||||||
// static index ControlSize(Unit* unit) { return static_cast<index>(unit->mNumInputs) - unit->mSpecialIndex - 1 -(IsModel_t<Client>::value ? 1 : 0); }
|
{
|
||||||
|
if (controls.size() < Client::getParameterDescriptors().count())
|
||||||
void init(SCUnit& unit, Client& client, FloatControlsIter& controls)
|
|
||||||
{
|
{
|
||||||
assert(!(client.audioChannelsOut() > 0 && client.controlChannelsOut() > 0) &&"Client can't have both audio and control outputs");
|
return {Result::Status::kError, "Fewer parameters than exepected. Got ",
|
||||||
// consoltr.reset(unit.mInBuf + unit.mSpecialIndex + 1);
|
controls.size(), "expect at least",
|
||||||
client.sampleRate(unit.fullSampleRate());
|
Client::getParameterDescriptors().count()};
|
||||||
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 countScan;
|
||||||
|
Client::getParameterDescriptors().template iterate<ExpectedCount>(
|
||||||
|
std::forward<FloatControlsIter&>(controls),
|
||||||
|
std::forward<Result&>(countScan));
|
||||||
|
return countScan;
|
||||||
|
}
|
||||||
|
|
||||||
Result r;
|
void init(SCUnit& unit, Client& client, FloatControlsIter& controls)
|
||||||
if(!(r = expectedSize(controls)).ok())
|
{
|
||||||
{
|
assert(!(client.audioChannelsOut() > 0 &&
|
||||||
// mCalcFunc = Wrapper::getInterfaceTable()->fClearUnitOutputs;
|
client.controlChannelsOut().count > 0) &&
|
||||||
std::cout
|
"Client can't have both audio and control outputs");
|
||||||
<< "ERROR: " << Wrapper::getName()
|
client.sampleRate(unit.fullSampleRate());
|
||||||
<< " wrong number of arguments."
|
mInputConnections.reserve(asUnsigned(client.audioChannelsIn()));
|
||||||
<< r.message()
|
mOutputConnections.reserve(asUnsigned(client.audioChannelsOut()));
|
||||||
<< std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Result r;
|
||||||
|
if (!(r = expectedSize(controls)).ok())
|
||||||
|
{
|
||||||
|
std::cout << "ERROR: " << Wrapper::getName()
|
||||||
|
<< " wrong number of arguments." << r.message() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client.audioChannelsIn())
|
||||||
|
{
|
||||||
|
mAudioInputs.reserve(asUnsigned(client.audioChannelsIn()));
|
||||||
for (index i = 0; i < client.audioChannelsIn(); ++i)
|
for (index i = 0; i < client.audioChannelsIn(); ++i)
|
||||||
{
|
{
|
||||||
mInputConnections.emplace_back(unit.isAudioRateIn(static_cast<int>(i)));
|
mInputConnections.emplace_back(unit.isAudioRateIn(static_cast<int>(i)));
|
||||||
mAudioInputs.emplace_back(nullptr, 0, 0);
|
mAudioInputs.emplace_back(nullptr, 0, 0);
|
||||||
}
|
}
|
||||||
|
mInputMapper = &RealTimeBase::mapAudioInputs;
|
||||||
|
}
|
||||||
|
else if (client.controlChannelsIn())
|
||||||
|
{
|
||||||
|
mControlInputBuffer.resize(unit.mSpecialIndex + 1);
|
||||||
|
mAudioInputs.emplace_back(mControlInputBuffer);
|
||||||
|
mInputMapper = &RealTimeBase::mapControlInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
index outputSize = client.controlChannelsOut().size > 0
|
||||||
|
? std::max(client.audioChannelsOut(),
|
||||||
|
client.controlChannelsOut().size)
|
||||||
|
: unit.mSpecialIndex + 1;
|
||||||
|
mOutputs.reserve(asUnsigned(outputSize));
|
||||||
|
|
||||||
|
if (client.audioChannelsOut())
|
||||||
|
{
|
||||||
for (index i = 0; i < client.audioChannelsOut(); ++i)
|
for (index i = 0; i < client.audioChannelsOut(); ++i)
|
||||||
{
|
{
|
||||||
mOutputConnections.emplace_back(true);
|
mOutputConnections.emplace_back(true);
|
||||||
mOutputs.emplace_back(nullptr, 0, 0);
|
mOutputs.emplace_back(nullptr, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index i = 0; i < client.controlChannelsOut(); ++i)
|
mOutMapperPre = &RealTimeBase::mapAudioOutputs;
|
||||||
{
|
mOutMapperPost = &RealTimeBase::mapNoOp;
|
||||||
mOutputs.emplace_back(nullptr, 0, 0);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index totalControlOutputs =
|
||||||
|
client.controlChannelsOut().count * outputSize;
|
||||||
|
mControlOutputBuffer.resize(totalControlOutputs);
|
||||||
|
for (index i = 0; i < client.controlChannelsOut().count; ++i)
|
||||||
|
{
|
||||||
|
mOutputs.emplace_back(
|
||||||
|
mControlOutputBuffer(fluid::Slice(i * outputSize, outputSize)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
mOutMapperPre = &RealTimeBase::mapNoOp;
|
||||||
void next(SCUnit& unit, Client& client,Params& params,FloatControlsIter& controls,bool updateParams = true)
|
mOutMapperPost = &RealTimeBase::mapControlOutputs;
|
||||||
{
|
}
|
||||||
bool trig = IsModel_t<Client>::value ? !mPrevTrig && unit.in0(0) > 0 : false;
|
}
|
||||||
|
|
||||||
mPrevTrig = trig;
|
void mapNoOp(SCUnit&, Client&) {}
|
||||||
|
|
||||||
if(updateParams)
|
void mapAudioInputs(SCUnit& unit, Client& client)
|
||||||
{
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapAudioOutputs(SCUnit& unit, Client& client)
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapControlInputs(SCUnit& unit, Client& client)
|
||||||
|
{
|
||||||
|
for (index i = 0; i < unit.mSpecialIndex + 1; ++i)
|
||||||
|
{
|
||||||
|
assert(i <= std::numeric_limits<int>::max());
|
||||||
|
mControlInputBuffer[asUnsigned(i)] = unit.in0(static_cast<int>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapControlOutputs(SCUnit& unit, Client& client)
|
||||||
|
{
|
||||||
|
for (index i = 0; i < mControlOutputBuffer.size(); ++i)
|
||||||
|
{
|
||||||
|
assert(i <= std::numeric_limits<int>::max());
|
||||||
|
unit.out0(static_cast<int>(i)) = mControlOutputBuffer(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void next(SCUnit& unit, Client& client, Params& params,
|
||||||
|
FloatControlsIter& controls, bool updateParams = true)
|
||||||
|
{
|
||||||
|
bool trig =
|
||||||
|
IsModel_t<Client>::value ? !mPrevTrig && unit.in0(0) > 0 : false;
|
||||||
|
|
||||||
|
mPrevTrig = trig;
|
||||||
|
|
||||||
|
if (updateParams)
|
||||||
|
{
|
||||||
Wrapper::setParams(&unit, params, controls);
|
Wrapper::setParams(&unit, params, controls);
|
||||||
params.constrainParameterValuesRT(nullptr);
|
params.constrainParameterValuesRT(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index i = 0; i < client.audioChannelsIn(); ++i)
|
(this->*mInputMapper)(unit, client);
|
||||||
{
|
(this->*mOutMapperPre)(unit, client);
|
||||||
assert(i <= std::numeric_limits<int>::max());
|
client.process(mAudioInputs, mOutputs, mContext);
|
||||||
if (mInputConnections[asUnsigned(i)])
|
(this->*mOutMapperPost)(unit, client);
|
||||||
mAudioInputs[asUnsigned(i)].reset(const_cast<float*>(unit.in(static_cast<int>(i))), 0,unit.fullBufferSize());
|
}
|
||||||
}
|
|
||||||
|
private:
|
||||||
for (index i = 0; i < client.audioChannelsOut(); ++i)
|
std::vector<bool> mInputConnections;
|
||||||
{
|
std::vector<bool> mOutputConnections;
|
||||||
assert(i <= std::numeric_limits<int>::max());
|
std::vector<HostVector> mAudioInputs;
|
||||||
if (mOutputConnections[asUnsigned(i)])
|
std::vector<HostVector> mOutputs;
|
||||||
mOutputs[asUnsigned(i)].reset(unit.out(static_cast<int>(i)), 0,
|
FluidTensor<float, 1> mControlInputBuffer;
|
||||||
unit.fullBufferSize());
|
FluidTensor<float, 1> mControlOutputBuffer;
|
||||||
}
|
FluidContext mContext;
|
||||||
|
bool mPrevTrig;
|
||||||
for (index i = 0; i < client.controlChannelsOut(); ++i)
|
IOMapFn mInputMapper;
|
||||||
{
|
IOMapFn mOutMapperPre;
|
||||||
assert(i <= std::numeric_limits<int>::max());
|
IOMapFn mOutMapperPost;
|
||||||
mOutputs[asUnsigned(i)].reset(unit.out(static_cast<int>(i)), 0, 1);
|
};
|
||||||
}
|
} // namespace impl
|
||||||
client.process(mAudioInputs, mOutputs, mContext);
|
} // namespace client
|
||||||
}
|
} // namespace fluid
|
||||||
private:
|
|
||||||
std::vector<bool> mInputConnections;
|
|
||||||
std::vector<bool> mOutputConnections;
|
|
||||||
std::vector<HostVector> mAudioInputs;
|
|
||||||
std::vector<HostVector> mOutputs;
|
|
||||||
FluidContext mContext;
|
|
||||||
bool mPrevTrig;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
FluidStats : MultiOutUGen {
|
||||||
|
|
||||||
|
var <channels;
|
||||||
|
|
||||||
|
*kr { arg inputs;
|
||||||
|
// ^super.new.rate_('control').inputs_(inputs.asArray++0).initOutputs(inputs.asArray.size);
|
||||||
|
^this.new1('control',inputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
init {arg ...theInputs;
|
||||||
|
inputs = theInputs ++ 0;
|
||||||
|
^this.initOutputs(inputs.asArray.size - 1,rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkInputs {
|
||||||
|
/* if(inputs.any.rate != 'control') {
|
||||||
|
^"input array input is not control rate";
|
||||||
|
};*/
|
||||||
|
this.specialIndex = (inputs.size - 2).min(0);
|
||||||
|
this.specialIndex.postln;
|
||||||
|
^this.checkValidInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
initOutputs{|numChans,rate|
|
||||||
|
if(numChans.isNil or: {numChans < 1})
|
||||||
|
{
|
||||||
|
Error("No input channels").throw
|
||||||
|
};
|
||||||
|
|
||||||
|
channels = Array.fill(numChans * 2, { |i|
|
||||||
|
// Array.fill(numChans,{ |j|
|
||||||
|
OutputProxy('control',this,i);
|
||||||
|
});
|
||||||
|
// });
|
||||||
|
^channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// synthIndex_ { arg index;
|
||||||
|
// synthIndex = index;
|
||||||
|
// channels.do{
|
||||||
|
// arg outputGroup;
|
||||||
|
// outputGroup.do{
|
||||||
|
// arg output;
|
||||||
|
// output.synthIndex_(index);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
numOutputs { ^(channels.size); }
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue