70 using SPtr = std::shared_ptr<Component>;
72 enum class ProcessOrder
78 Component( ProcessOrder processOrder = ProcessOrder::InOrder );
81 bool ConnectInput(
const Component::SPtr& fromComponent,
int fromOutput,
int toInput );
83 void DisconnectInput(
int inputNo );
84 void DisconnectInput(
const Component::SPtr& fromComponent );
85 void DisconnectAllInputs();
87 int GetInputCount()
const;
88 int GetOutputCount()
const;
90 std::string GetInputName(
int inputNo )
const;
91 std::string GetOutputName(
int outputNo )
const;
93 void SetBufferCount(
int bufferCount,
int startBuffer );
94 int GetBufferCount()
const;
96 void Tick(
int bufferNo );
97 void TickParallel(
int bufferNo );
99 void Scan( std::vector<Component*>& components );
100 void ScanParallel( std::vector<std::vector<DSPatch::Component*>>& componentsMap,
int& scanPosition );
106 void SetInputCount_(
int inputCount,
const std::vector<std::string>& inputNames = {} );
107 void SetOutputCount_(
int outputCount,
const std::vector<std::string>& outputNames = {} );
110 class AtomicFlag final
113 AtomicFlag(
const AtomicFlag& ) =
delete;
114 AtomicFlag& operator=(
const AtomicFlag& ) =
delete;
116 inline AtomicFlag() =
default;
118 inline AtomicFlag( AtomicFlag&& )
122 inline void WaitAndClear()
124 while ( flag.test_and_set( std::memory_order_acquire ) )
126 std::this_thread::yield();
132 flag.clear( std::memory_order_release );
137 flag.test_and_set( std::memory_order_acquire );
141 std::atomic_flag flag = {
true };
144 struct RefCounter final
148 AtomicFlag readyFlag;
158 void _WaitForRelease(
int bufferNo );
159 void _ReleaseNextBuffer(
int bufferNo );
161 void _GetOutput(
int bufferNo,
int fromOutput,
int toInput,
DSPatch::SignalBus& toBus );
162 void _GetOutputParallel(
int bufferNo,
int fromOutput,
int toInput,
DSPatch::SignalBus& toBus );
164 void _IncRefs(
int output );
165 void _DecRefs(
int output );
167 const DSPatch::Component::ProcessOrder _processOrder;
169 int _bufferCount = 0;
171 std::vector<DSPatch::SignalBus> _inputBuses;
172 std::vector<DSPatch::SignalBus> _outputBuses;
174 std::vector<std::vector<RefCounter>> _refs;
176 std::vector<Wire> _inputWires;
178 std::vector<AtomicFlag> _releaseFlags;
180 std::vector<std::string> _inputNames;
181 std::vector<std::string> _outputNames;
183 int _scanPosition = -1;
186inline Component::Component( ProcessOrder processOrder )
187 : _processOrder( processOrder )
189 SetBufferCount( 1, 0 );
192inline Component::~Component() =
default;
194inline bool Component::ConnectInput(
const Component::SPtr& fromComponent,
int fromOutput,
int toInput )
196 if ( fromOutput >= fromComponent->GetOutputCount() || toInput >= GetInputCount() )
202 auto findFn = [&toInput](
const auto& wire ) {
return wire.toInput == toInput; };
204 if (
auto it = std::find_if( _inputWires.begin(), _inputWires.end(), findFn ); it != _inputWires.end() )
206 if ( it->fromComponent == fromComponent.get() && it->fromOutput == fromOutput )
213 it->fromComponent->_DecRefs( it->fromOutput );
216 for (
auto& inputBus : _inputBuses )
218 inputBus.ClearValue( toInput );
222 it->fromComponent = fromComponent.get();
223 it->fromOutput = fromOutput;
228 _inputWires.emplace_back( Wire{ fromComponent.get(), fromOutput, toInput } );
232 fromComponent->_IncRefs( fromOutput );
237inline void Component::DisconnectInput(
int inputNo )
240 auto findFn = [&inputNo](
const auto& wire ) {
return wire.toInput == inputNo; };
242 if (
auto it = std::find_if( _inputWires.begin(), _inputWires.end(), findFn ); it != _inputWires.end() )
245 it->fromComponent->_DecRefs( it->fromOutput );
248 for (
auto& inputBus : _inputBuses )
250 inputBus.ClearValue( inputNo );
254 _inputWires.erase( it );
258inline void Component::DisconnectInput(
const Component::SPtr& fromComponent )
261 auto findFn = [&fromComponent](
const auto& wire ) {
return wire.fromComponent == fromComponent.get(); };
263 for (
auto it = std::find_if( _inputWires.begin(), _inputWires.end(), findFn ); it != _inputWires.end();
264 it = std::find_if( it, _inputWires.end(), findFn ) )
267 fromComponent->_DecRefs( it->fromOutput );
270 for (
auto& inputBus : _inputBuses )
272 inputBus.ClearValue( it->toInput );
276 it = _inputWires.erase( it );
280inline void Component::DisconnectAllInputs()
283 for (
const auto& wire : _inputWires )
285 wire.fromComponent->_DecRefs( wire.fromOutput );
289 for (
auto& inputBus : _inputBuses )
291 inputBus.ClearAllValues();
298inline int Component::GetInputCount()
const
300 return _inputBuses[0].GetSignalCount();
303inline int Component::GetOutputCount()
const
305 return _outputBuses[0].GetSignalCount();
309inline std::string Component::GetInputName(
int inputNo )
const
311 if ( inputNo < (
int)_inputNames.size() )
313 return _inputNames[inputNo];
319inline std::string Component::GetOutputName(
int outputNo )
const
321 if ( outputNo < (
int)_outputNames.size() )
323 return _outputNames[outputNo];
328inline void Component::SetBufferCount(
int bufferCount,
int startBuffer )
332 if ( bufferCount <= 0 )
337 if ( startBuffer >= bufferCount )
343 _inputBuses.resize( bufferCount );
344 _outputBuses.resize( bufferCount );
346 _releaseFlags.resize( bufferCount );
348 _refs.resize( bufferCount );
350 const auto inputCount = GetInputCount();
351 const auto outputCount = GetOutputCount();
352 const auto refCount = _refs[0].size();
355 for (
int i = 0; i < bufferCount; ++i )
357 _inputBuses[i].SetSignalCount( inputCount );
358 _outputBuses[i].SetSignalCount( outputCount );
360 if ( i == startBuffer )
362 _releaseFlags[i].Set();
366 _releaseFlags[i].Clear();
369 _refs[i].resize( refCount );
370 for (
size_t j = 0; j < refCount; ++j )
373 _refs[i][j].total = _refs[0][j].total;
377 _bufferCount = bufferCount;
380inline int Component::GetBufferCount()
const
385inline void Component::Tick(
int bufferNo )
387 auto& inputBus = _inputBuses[bufferNo];
389 for (
const auto& wire : _inputWires )
392 wire.fromComponent->_GetOutput( bufferNo, wire.fromOutput, wire.toInput, inputBus );
395 if ( _bufferCount != 1 && _processOrder == ProcessOrder::InOrder )
398 _WaitForRelease( bufferNo );
401 Process_( inputBus, _outputBuses[bufferNo] );
404 _ReleaseNextBuffer( bufferNo );
409 Process_( inputBus, _outputBuses[bufferNo] );
413inline void Component::TickParallel(
int bufferNo )
415 auto& inputBus = _inputBuses[bufferNo];
417 for (
const auto& wire : _inputWires )
420 wire.fromComponent->_GetOutputParallel( bufferNo, wire.fromOutput, wire.toInput, inputBus );
423 if ( _bufferCount != 1 && _processOrder == ProcessOrder::InOrder )
426 _WaitForRelease( bufferNo );
429 Process_( inputBus, _outputBuses[bufferNo] );
432 _ReleaseNextBuffer( bufferNo );
437 Process_( inputBus, _outputBuses[bufferNo] );
441 for (
auto& ref : _refs[bufferNo] )
444 if ( ref.total != 0 )
451inline void Component::Scan( std::vector<Component*>& components )
454 if ( _scanPosition != -1 )
462 for (
const auto& wire : _inputWires )
465 wire.fromComponent->Scan( components );
468 components.emplace_back(
this );
471inline void Component::ScanParallel( std::vector<std::vector<DSPatch::Component*>>& componentsMap,
int& scanPosition )
474 if ( _scanPosition != -1 )
476 scanPosition = _scanPosition;
484 for (
const auto& wire : _inputWires )
487 wire.fromComponent->ScanParallel( componentsMap, scanPosition );
490 _scanPosition = std::max( _scanPosition, ++scanPosition );
494 while ( (
int)componentsMap.size() <= _scanPosition )
496 componentsMap.emplace_back( std::vector<DSPatch::Component*>{} );
497 componentsMap.back().reserve( componentsMap.capacity() );
499 componentsMap[_scanPosition].emplace_back(
this );
502inline void Component::EndScan()
508inline void Component::SetInputCount_(
int inputCount,
const std::vector<std::string>& inputNames )
510 _inputNames = inputNames;
512 for (
auto& inputBus : _inputBuses )
514 inputBus.SetSignalCount( inputCount );
517 _inputWires.reserve( inputCount );
520inline void Component::SetOutputCount_(
int outputCount,
const std::vector<std::string>& outputNames )
522 _outputNames = outputNames;
524 for (
auto& outputBus : _outputBuses )
526 outputBus.SetSignalCount( outputCount );
530 for (
auto& ref : _refs )
532 ref.resize( outputCount );
536inline void Component::_WaitForRelease(
int bufferNo )
538 _releaseFlags[bufferNo].WaitAndClear();
541inline void Component::_ReleaseNextBuffer(
int bufferNo )
543 if ( ++bufferNo == _bufferCount )
545 _releaseFlags[0].Set();
549 _releaseFlags[bufferNo].Set();
553inline void Component::_GetOutput(
int bufferNo,
int fromOutput,
int toInput,
DSPatch::SignalBus& toBus )
555 auto& signal = *_outputBuses[bufferNo].GetSignal( fromOutput );
557 if ( !signal.has_value() )
559 toBus.ClearValue( toInput );
563 auto& ref = _refs[bufferNo][fromOutput];
565 if ( ref.total == 1 )
568 toBus.MoveSignal( toInput, signal );
570 else if ( ++ref.count != ref.total )
573 toBus.SetSignal( toInput, signal );
579 toBus.MoveSignal( toInput, signal );
583inline void Component::_GetOutputParallel(
int bufferNo,
int fromOutput,
int toInput,
DSPatch::SignalBus& toBus )
585 auto& signal = *_outputBuses[bufferNo].GetSignal( fromOutput );
586 auto& ref = _refs[bufferNo][fromOutput];
589 ref.readyFlag.WaitAndClear();
591 if ( !signal.has_value() )
593 toBus.ClearValue( toInput );
595 if ( ref.total != 1 )
597 if ( ++ref.count != ref.total )
609 else if ( ref.total == 1 )
612 toBus.MoveSignal( toInput, signal );
614 else if ( ++ref.count != ref.total )
617 toBus.SetSignal( toInput, signal );
624 toBus.MoveSignal( toInput, signal );
628inline void Component::_IncRefs(
int output )
630 for (
auto& ref : _refs )
636inline void Component::_DecRefs(
int output )
638 for (
auto& ref : _refs )
Abstract base class for DSPatch components.