@ -11,16 +11,12 @@ under the European Union’ s Horizon 2020 research and innovation programme
# pragma once
# include "SCBufferAdaptor.hpp"
# include <FluidVersion.hpp>
# include <clients/common/FluidBaseClient.hpp>
# include <clients/common/Result.hpp>
# include <data/FluidTensor.hpp>
# include <data/TensorTypes.hpp>
# include <FluidVersion.hpp>
# include <SC_PlugIn.hpp>
# include <algorithm>
# include <string>
# include <tuple>
@ -39,10 +35,7 @@ namespace impl {
// Iterate over kr/ir inputs via callbacks from params object
struct FloatControlsIter
{
FloatControlsIter ( float * * vals , index N )
: mValues ( vals )
, mSize ( N )
{ }
FloatControlsIter ( float * * vals , index N ) : mValues ( vals ) , mSize ( N ) { }
float next ( ) { return mCount > = mSize ? 0 : * mValues [ mCount + + ] ; }
@ -60,7 +53,7 @@ private:
index mCount { 0 } ;
} ;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Real Time Processor
@ -70,8 +63,6 @@ class RealTime : public SCUnit
using HostVector = FluidTensorView < float , 1 > ;
using ParamSetType = typename Client : : ParamSetType ;
// using Client = typename Wrapper::ClientType;
public :
static void setup ( InterfaceTable * ft , const char * name )
{
@ -81,7 +72,8 @@ public:
static void doLatency ( Unit * unit , sc_msg_iter * )
{
float l [ ] { static_cast < float > ( static_cast < Wrapper * > ( unit ) - > mClient . latency ( ) ) } ;
float l [ ] {
static_cast < float > ( static_cast < Wrapper * > ( unit ) - > mClient . latency ( ) ) } ;
auto ft = Wrapper : : getInterfaceTable ( ) ;
std : : stringstream ss ;
@ -91,24 +83,31 @@ public:
}
RealTime ( )
: mControlsIterator { mInBuf + mSpecialIndex + 1 , static_cast < index > ( mNumInputs ) - mSpecialIndex - 1 }
, mParams { Wrapper : : Client : : getParameterDescriptors ( ) }
, mClient { Wrapper : : setParams ( mParams , mWorld - > mVerbosity > 0 , mWorld , mControlsIterator , true ) }
: mControlsIterator { mInBuf + mSpecialIndex + 1 ,
static_cast < index > ( mNumInputs ) - mSpecialIndex - 1 } ,
mParams { Wrapper : : Client : : getParameterDescriptors ( ) } ,
mClient { Wrapper : : setParams ( mParams , mWorld - > mVerbosity > 0 , mWorld ,
mControlsIterator , true ) }
{ }
void init ( )
{
assert ( ! ( mClient . audioChannelsOut ( ) > 0 & & mClient . controlChannelsOut ( ) > 0 ) & &
assert (
! ( mClient . audioChannelsOut ( ) > 0 & & mClient . controlChannelsOut ( ) > 0 ) & &
" Client can't have both audio and control outputs " ) ;
// If we don't the number of arguments we expect, the language side code is probably the wrong version
// set plugin to no-op, squawk, and bail;
// If we don't the number of arguments we expect, the language side code is
// probably the wrong version set plugin to no-op, squawk, and bail;
if ( mControlsIterator . size ( ) ! = Client : : getParameterDescriptors ( ) . count ( ) )
{
mCalcFunc = Wrapper : : getInterfaceTable ( ) - > fClearUnitOutputs ;
std : : cout < < " ERROR: " < < Wrapper : : getName ( ) < < " wrong number of arguments. Expected "
< < Client : : getParameterDescriptors ( ) . count ( ) < < " , got " < < mControlsIterator . size ( )
< < " . Your .sc file and binary plugin might be different versions. " < < std : : endl ;
std : : cout
< < " ERROR: " < < Wrapper : : getName ( )
< < " wrong number of arguments. Expected "
< < Client : : getParameterDescriptors ( ) . count ( ) < < " , got "
< < mControlsIterator . size ( )
< < " . Your .sc file and binary plugin might be different versions. "
< < std : : endl ;
return ;
}
@ -116,7 +115,8 @@ public:
mInputConnections . reserve ( asUnsigned ( mClient . audioChannelsIn ( ) ) ) ;
mOutputConnections . reserve ( asUnsigned ( mClient . audioChannelsOut ( ) ) ) ;
mAudioInputs . reserve ( asUnsigned ( mClient . audioChannelsIn ( ) ) ) ;
mOutputs . reserve ( asUnsigned ( std : : max ( mClient . audioChannelsOut ( ) , mClient . controlChannelsOut ( ) ) ) ) ;
mOutputs . reserve ( asUnsigned (
std : : max ( mClient . audioChannelsOut ( ) , mClient . controlChannelsOut ( ) ) ) ) ;
for ( index i = 0 ; i < mClient . audioChannelsIn ( ) ; + + i )
{
@ -130,7 +130,8 @@ public:
mOutputs . emplace_back ( nullptr , 0 , 0 ) ;
}
for ( index i = 0 ; i < mClient . controlChannelsOut ( ) ; + + i ) { mOutputs . emplace_back ( nullptr , 0 , 0 ) ; }
for ( index i = 0 ; i < mClient . controlChannelsOut ( ) ; + + i )
{ mOutputs . emplace_back ( nullptr , 0 , 0 ) ; }
mCalcFunc = make_calc_function < RealTime , & RealTime : : next > ( ) ;
Wrapper : : getInterfaceTable ( ) - > fClearUnitOutputs ( this , 1 ) ;
@ -139,20 +140,22 @@ public:
void next ( int )
{
mControlsIterator . reset ( mInBuf + 1 ) ; // mClient.audioChannelsIn());
Wrapper : : setParams ( mParams , mWorld - > mVerbosity > 0 , mWorld , mControlsIterator ) ; // forward on inputs N + audio inputs as params
Wrapper : : setParams (
mParams , mWorld - > mVerbosity > 0 , mWorld ,
mControlsIterator ) ; // forward on inputs N + audio inputs as params
mParams . constrainParameterValues ( ) ;
const Unit * unit = this ;
for ( index i = 0 ; i < mClient . audioChannelsIn ( ) ; + + i )
{
if ( mInputConnections [ asUnsigned ( i ) ] )
{
mAudioInputs [ asUnsigned ( i ) ] . reset ( IN ( i ) , 0 , fullBufferSize ( ) ) ;
}
{ mAudioInputs [ asUnsigned ( i ) ] . reset ( IN ( i ) , 0 , fullBufferSize ( ) ) ; }
}
for ( index i = 0 ; i < mClient . audioChannelsOut ( ) ; + + i )
{
assert ( i < = std : : numeric_limits < int > : : max ( ) ) ;
if ( mOutputConnections [ asUnsigned ( i ) ] ) mOutputs [ asUnsigned ( i ) ] . reset ( out ( static_cast < int > ( i ) ) , 0 , fullBufferSize ( ) ) ;
if ( mOutputConnections [ asUnsigned ( i ) ] )
mOutputs [ asUnsigned ( i ) ] . reset ( out ( static_cast < int > ( i ) ) , 0 ,
fullBufferSize ( ) ) ;
}
for ( index i = 0 ; i < mClient . controlChannelsOut ( ) ; + + i )
{
@ -175,52 +178,58 @@ protected:
Client mClient ;
} ;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// Non Real Time Processor
/// This is also a UGen, but the main action is delegated off to a worker thread, via the NRT thread.
/// The RT bit is there to allow us (a) to poll our thread and (b) emit a kr progress update
/// This is also a UGen, but the main action is delegated off to a worker
/// thread, via the NRT thread. The RT bit is there to allow us (a) to poll our
/// thread and (b) emit a kr progress update
template < typename Client , typename Wrapper >
class NonRealTime : public SCUnit
{
using ParamSetType = typename Client : : ParamSetType ;
public :
static void setup ( InterfaceTable * ft , const char * name )
{
registerUnit < Wrapper > ( ft , name ) ;
ft - > fDefineUnitCmd ( name , " cancel " , doCancel ) ;
ft - > fDefineUnitCmd ( name , " queue_enabled " , [ ] ( struct Unit * unit , struct sc_msg_iter * args )
{
ft - > fDefineUnitCmd (
name , " queue_enabled " , [ ] ( struct Unit * unit , struct sc_msg_iter * args ) {
auto w = static_cast < Wrapper * > ( unit ) ;
w - > mQueueEnabled = args - > geti ( 0 ) ;
w - > mFifoMsg . Set ( w - > mWorld , [ ] ( FifoMsg * f )
{
w - > mFifoMsg . Set (
w - > mWorld ,
[ ] ( FifoMsg * f ) {
auto w = static_cast < Wrapper * > ( f - > mData ) ;
w - > mClient . setQueueEnabled ( w - > mQueueEnabled ) ;
} , nullptr , w ) ;
} ,
nullptr , w ) ;
Wrapper : : getInterfaceTable ( ) - > fSendMsgFromRT ( w - > mWorld , w - > mFifoMsg ) ;
} ) ;
ft - > fDefineUnitCmd ( name , " synchronous " , [ ] ( struct Unit * unit , struct sc_msg_iter * args )
{
ft - > fDefineUnitCmd (
name , " synchronous " , [ ] ( struct Unit * unit , struct sc_msg_iter * args ) {
auto w = static_cast < Wrapper * > ( unit ) ;
w - > mSynchronous = args - > geti ( 0 ) ;
w - > mFifoMsg . Set ( w - > mWorld , [ ] ( FifoMsg * f )
{
w - > mFifoMsg . Set (
w - > mWorld ,
[ ] ( FifoMsg * f ) {
auto w = static_cast < Wrapper * > ( f - > mData ) ;
w - > mClient . setSynchronous ( w - > mSynchronous ) ;
} , nullptr , w ) ;
} ,
nullptr , w ) ;
Wrapper : : getInterfaceTable ( ) - > fSendMsgFromRT ( w - > mWorld , w - > mFifoMsg ) ;
} ) ;
}
/// Penultimate input is the doneAction, final is blocking mode. Neither are params, so we skip them in the controlsIterator
NonRealTime ( ) :
mControlsIterator { mInBuf , index ( mNumInputs ) - mSpecialIndex - 2 }
, mParams { Wrapper : : Client : : getParameterDescriptors ( ) }
, mClient { Wrapper : : setParams ( mParams , mWorld - > mVerbosity > 0 , mWorld , mControlsIterator , true ) }
, mSynchronous { mNumInputs > 2 ? ( in0 ( int ( mNumInputs ) - 1 ) > 0 ) : false }
/// Penultimate input is the doneAction, final is blocking mode. Neither are
/// params, so we skip them in the controlsIterator
NonRealTime ( )
: mControlsIterator { mInBuf , index ( mNumInputs ) - mSpecialIndex - 2 } ,
mParams { Wrapper : : Client : : getParameterDescriptors ( ) } ,
mClient { Wrapper : : setParams ( mParams , mWorld - > mVerbosity > 0 , mWorld ,
mControlsIterator , true ) } ,
mSynchronous { mNumInputs > 2 ? ( in0 ( int ( mNumInputs ) - 1 ) > 0 ) : false }
{ }
~ NonRealTime ( )
@ -228,14 +237,16 @@ public:
if ( mClient . state ( ) = = ProcessState : : kProcessing )
{
std : : cout < < Wrapper : : getName ( ) < < " : Processing cancelled \n " ;
Wrapper : : getInterfaceTable ( ) - > fSendNodeReply ( & mParent - > mNode , 1 , " /done " , 0 , nullptr ) ;
Wrapper : : getInterfaceTable ( ) - > fSendNodeReply ( & mParent - > mNode , 1 , " /done " ,
0 , nullptr ) ;
}
// processing will be cancelled in ~NRTThreadAdaptor()
}
/// No option of not using a worker thread for now
/// init() sets up the NRT process via the SC NRT thread, and then sets our UGen calc function going
/// init() sets up the NRT process via the SC NRT thread, and then sets our
/// UGen calc function going
void init ( )
{
mFifoMsg . Set ( mWorld , initNRTJob , nullptr , this ) ;
@ -245,7 +256,8 @@ public:
set_calc_function < NonRealTime , & NonRealTime : : poll > ( ) ;
} ;
/// The calc function. Checks to see if we've cancelled, spits out progress, launches tidy up when complete
/// The calc function. Checks to see if we've cancelled, spits out progress,
/// launches tidy up when complete
void poll ( int )
{
out0 ( 0 ) = mDone ? 1.0 : static_cast < float > ( mClient . progress ( ) ) ;
@ -253,15 +265,16 @@ public:
if ( 0 = = pollCounter + + & & ! mCheckingForDone )
{
mCheckingForDone = true ;
mWorld - > ft - > fDoAsynchronousCommand ( mWorld , nullptr , Wrapper : : getName ( ) , this ,
postProcess , exchangeBuffers , tidyUp , destroy ,
0 , nullptr ) ;
mWorld - > ft - > fDoAsynchronousCommand ( mWorld , nullptr , Wrapper : : getName ( ) ,
this , postProcess , exchangeBuffers ,
tidyUp , destroy , 0 , nullptr ) ;
}
pollCounter % = checkThreadInterval ;
}
/// To be called on NRT thread. Validate parameters and commence processing in new thread
/// To be called on NRT thread. Validate parameters and commence processing in
/// new thread
static void initNRTJob ( FifoMsg * f )
{
auto w = static_cast < Wrapper * > ( f - > mData ) ;
@ -272,7 +285,8 @@ public:
if ( ! result . ok ( ) )
{
std : : cout < < " ERROR: " < < Wrapper : : getName ( ) < < " : " < < result . message ( ) . c_str ( ) < < std : : endl ;
std : : cout < < " ERROR: " < < Wrapper : : getName ( ) < < " : "
< < result . message ( ) . c_str ( ) < < std : : endl ;
return ;
}
w - > mClient . setSynchronous ( w - > mSynchronous ) ;
@ -287,11 +301,18 @@ public:
Result r ;
ProcessState s = w - > mClient . checkProgress ( r ) ;
if ( ( s = = ProcessState : : kDone | | s = = ProcessState : : kDoneStillProcessing )
| | ( w - > mSynchronous & & s = = ProcessState : : kNoProcess ) ) //I think this hinges on the fact that when mSynchrous = true, this call will always be behind process() on the command FIFO, so we can assume that if the state is kNoProcess, it has run (vs never having run)
{
//Given that cancellation from the language now always happens by freeing the
//synth, this block isn't reached normally. HOwever, if someone cancels using u_cmd, this is what will fire
if ( ( s = = ProcessState : : kDone | | s = = ProcessState : : kDoneStillProcessing ) | |
( w - > mSynchronous & &
s = = ProcessState : : kNoProcess ) ) // I think this hinges on the fact that
// when mSynchrous = true, this call
// will always be behind process() on
// the command FIFO, so we can assume
// that if the state is kNoProcess, it
// has run (vs never having run)
{
// Given that cancellation from the language now always happens by freeing
// the synth, this block isn't reached normally. HOwever, if someone
// cancels using u_cmd, this is what will fire
if ( r . status ( ) = = Result : : Status : : kCancelled )
{
std : : cout < < Wrapper : : getName ( ) < < " : Processing cancelled \n " ;
@ -301,7 +322,8 @@ public:
if ( ! r . ok ( ) )
{
std : : cout < < " ERROR: " < < Wrapper : : getName ( ) < < " : " < < r . message ( ) . c_str ( ) < < ' \n ' ;
std : : cout < < " ERROR: " < < Wrapper : : getName ( ) < < " : "
< < r . message ( ) . c_str ( ) < < ' \n ' ;
return false ;
}
@ -312,17 +334,29 @@ public:
}
/// swap NRT buffers back to RT-land
static bool exchangeBuffers ( World * world , void * data ) { return static_cast < Wrapper * > ( data ) - > exchangeBuffers ( world ) ; }
static bool exchangeBuffers ( World * world , void * data )
{
return static_cast < Wrapper * > ( data ) - > exchangeBuffers ( world ) ;
}
/// Tidy up any temporary buffers
static bool tidyUp ( World * world , void * data ) { return static_cast < Wrapper * > ( data ) - > tidyUp ( world ) ; }
static bool tidyUp ( World * world , void * data )
{
return static_cast < Wrapper * > ( data ) - > tidyUp ( world ) ;
}
/// Now we're actually properly done, call the UGen's done action (possibly destroying this instance)
/// Now we're actually properly done, call the UGen's done action (possibly
/// destroying this instance)
static void destroy ( World * world , void * data )
{
auto w = static_cast < Wrapper * > ( data ) ;
if ( w - > mDone & & w - > mNumInputs > 2 ) //don't check for doneAction if UGen has no ins (there should be 3 minimum -> sig, doneAction, blocking mode)
{
int doneAction = static_cast < int > ( w - > in0 ( int ( w - > mNumInputs ) - 2 ) ) ; //doneAction is penultimate input; THIS IS THE LAW
if ( w - > mDone & &
w - > mNumInputs >
2 ) // don't check for doneAction if UGen has no ins (there should be
// 3 minimum -> sig, doneAction, blocking mode)
{
int doneAction = static_cast < int > (
w - > in0 ( int ( w - > mNumInputs ) -
2 ) ) ; // doneAction is penultimate input; THIS IS THE LAW
world - > ft - > fDoneAction ( doneAction , w ) ;
return ;
}
@ -333,8 +367,8 @@ public:
{
static_cast < Wrapper * > ( unit ) - > mClient . cancel ( ) ;
}
private :
private :
static Result validateParameters ( NonRealTime * w )
{
auto results = w - > mParams . constrainParameterValues ( ) ;
@ -348,10 +382,13 @@ private:
bool exchangeBuffers ( World * world ) // RT thread
{
mParams . template forEachParamType < BufferT , AssignBuffer > ( world ) ;
//At this point, we can see if we're finished and let the language know (or it can wait for the doneAction, but that takes extra time)
//use replyID to convey status (0 = normal completion, 1 = cancelled)
if ( mDone ) world - > ft - > fSendNodeReply ( & mParent - > mNode , 0 , " /done " , 0 , nullptr ) ;
if ( mCancelled ) world - > ft - > fSendNodeReply ( & mParent - > mNode , 1 , " /done " , 0 , nullptr ) ;
// At this point, we can see if we're finished and let the language know (or
// it can wait for the doneAction, but that takes extra time) use replyID to
// convey status (0 = normal completion, 1 = cancelled)
if ( mDone )
world - > ft - > fSendNodeReply ( & mParent - > mNode , 0 , " /done " , 0 , nullptr ) ;
if ( mCancelled )
world - > ft - > fSendNodeReply ( & mParent - > mNode , 1 , " /done " , 0 , nullptr ) ;
return true ;
}
@ -386,6 +423,7 @@ private:
const char * mName = nullptr ;
index checkThreadInterval ;
index pollCounter { 0 } ;
protected :
ParamSetType mParams ;
Client mClient ;
@ -395,11 +433,12 @@ protected:
bool mCancelled { false } ;
} ;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// An impossible monstrosty
template < typename Client , typename Wrapper >
class NonRealTimeAndRealTime : public RealTime < Client , Wrapper > , public NonRealTime < Client , Wrapper >
class NonRealTimeAndRealTime : public RealTime < Client , Wrapper > ,
public NonRealTime < Client , Wrapper >
{
static void setup ( InterfaceTable * ft , const char * name )
{
@ -408,7 +447,7 @@ class NonRealTimeAndRealTime : public RealTime<Client, Wrapper>, public NonRealT
}
} ;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Template Specialisations for NRT/RT
@ -418,24 +457,24 @@ class FluidSCWrapperImpl;
template < typename Client , typename Wrapper >
class FluidSCWrapperImpl < Client , Wrapper , std : : true_type , std : : false_type >
: public NonRealTime < Client , Wrapper >
{
//public:
// FluidSCWrapperImpl(World* w, sc_msg_iter *args): NonRealTime<Client, Wrapper>(w,args){};
} ;
{ } ;
template < typename Client , typename Wrapper >
class FluidSCWrapperImpl < Client , Wrapper , std : : false_type , std : : true_type > : public RealTime < Client , Wrapper >
class FluidSCWrapperImpl < Client , Wrapper , std : : false_type , std : : true_type >
: public RealTime < Client , Wrapper >
{ } ;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Make base class(es), full of CRTP mixin goodness
template < typename Client >
using FluidSCWrapperBase = FluidSCWrapperImpl < Client , FluidSCWrapper < Client > , isNonRealTime < Client > , isRealTime < Client > > ;
using FluidSCWrapperBase =
FluidSCWrapperImpl < Client , FluidSCWrapper < Client > , isNonRealTime < Client > ,
isRealTime < Client > > ;
} // namespace impl
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// The main wrapper
template < typename C >
@ -448,27 +487,39 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
template < typename ArgType , size_t N , typename T >
struct Setter
{
static constexpr index argSize = C : : getParameterDescriptors ( ) . template get < N > ( ) . fixedSize ;
static constexpr index argSize =
C : : getParameterDescriptors ( ) . template get < N > ( ) . fixedSize ;
auto fromArgs ( World * , FloatControlsIter & args , LongT : : type , int ) { return args . next ( ) ; }
auto fromArgs ( World * , FloatControlsIter & args , FloatT : : type , int ) { return args . next ( ) ; }
auto fromArgs ( World * , FloatControlsIter & args , LongT : : type , int )
{
return args . next ( ) ;
}
auto fromArgs ( World * , FloatControlsIter & args , FloatT : : type , int )
{
return args . next ( ) ;
}
auto fromArgs ( World * w , ArgType args , BufferT : : type , int )
{
typename LongT : : type bufnum = static_cast < LongT : : type > ( fromArgs ( w , args , LongT : : type ( ) , - 1 ) ) ;
return BufferT : : type ( bufnum > = 0 ? new SCBufferAdaptor ( bufnum , w ) : nullptr ) ;
typename LongT : : type bufnum =
static_cast < LongT : : type > ( fromArgs ( w , args , LongT : : type ( ) , - 1 ) ) ;
return BufferT : : type ( bufnum > = 0 ? new SCBufferAdaptor ( bufnum , w )
: nullptr ) ;
}
auto fromArgs ( World * w , ArgType args , InputBufferT : : type , int )
{
typename LongT : : type bufnum = static_cast < LongT : : type > ( fromArgs ( w , args , LongT : : type ( ) , - 1 ) ) ;
return InputBufferT : : type ( bufnum > = 0 ? new SCBufferAdaptor ( bufnum , w ) : nullptr ) ;
typename LongT : : type bufnum =
static_cast < LongT : : type > ( fromArgs ( w , args , LongT : : type ( ) , - 1 ) ) ;
return InputBufferT : : type ( bufnum > = 0 ? new SCBufferAdaptor ( bufnum , w )
: nullptr ) ;
}
typename T : : type operator ( ) ( World * w , ArgType args )
{
ParamLiteralConvertor < T , argSize > a ;
using LiteralType = typename ParamLiteralConvertor < T , argSize > : : LiteralType ;
using LiteralType =
typename ParamLiteralConvertor < T , argSize > : : LiteralType ;
for ( index i = 0 ; i < argSize ; i + + )
a [ i ] = static_cast < LiteralType > ( fromArgs ( w , args , a [ 0 ] , 0 ) ) ;
@ -482,7 +533,8 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
static void doVersion ( Unit * , sc_msg_iter * )
{
std : : cout < < " Fluid Corpus Manipualtion Toolkit version " < < fluidVersion ( ) < < ' \n ' ;
std : : cout < < " Fluid Corpus Manipualtion Toolkit version " < < fluidVersion ( )
< < ' \n ' ;
}
@ -490,10 +542,7 @@ public:
using Client = C ;
using ParameterSetType = typename C : : ParamSetType ;
FluidSCWrapper ( )
{
impl : : FluidSCWrapperBase < Client > : : init ( ) ;
}
FluidSCWrapper ( ) { impl : : FluidSCWrapperBase < Client > : : init ( ) ; }
static const char * getName ( const char * setName = nullptr )
{
@ -515,15 +564,20 @@ public:
ft - > fDefineUnitCmd ( name , " version " , doVersion ) ;
}
static auto & setParams ( ParameterSetType & p , bool verbose , World * world , FloatControlsIter & inputs , bool constrain = false )
static auto & setParams ( ParameterSetType & p , bool verbose , World * world ,
FloatControlsIter & inputs , bool constrain = false )
{
// We won't even try and set params if the arguments don't match
if ( inputs . size ( ) = = C : : getParameterDescriptors ( ) . count ( ) )
{
p . template setParameterValues < ControlSetter > ( verbose , world , inputs ) ;
if ( constrain ) p . constrainParameterValues ( ) ;
} else {
std : : cout < < " ERROR: " < < getName ( ) < < " : parameter count mismatch. Perhaps your binary plugins and SC sources are different versions \n " ;
}
else
{
std : : cout < < " ERROR: " < < getName ( )
< < " : parameter count mismatch. Perhaps your binary plugins "
" and SC sources are different versions \n " ;
// TODO: work out how to bring any further work to a halt
}
return p ;