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 it->fromComponent = fromComponent.get();
217 it->fromOutput = fromOutput;
222 _inputWires.emplace_back( Wire{ fromComponent.get(), fromOutput, toInput } );
226 fromComponent->_IncRefs( fromOutput );
231inline void Component::DisconnectInput(
int inputNo )
234 auto findFn = [&inputNo](
const auto& wire ) {
return wire.toInput == inputNo; };
236 if (
auto it = std::find_if( _inputWires.begin(), _inputWires.end(), findFn ); it != _inputWires.end() )
239 it->fromComponent->_DecRefs( it->fromOutput );
241 _inputWires.erase( it );
245inline void Component::DisconnectInput(
const Component::SPtr& fromComponent )
248 auto findFn = [&fromComponent](
const auto& wire ) {
return wire.fromComponent == fromComponent.get(); };
250 for (
auto it = std::find_if( _inputWires.begin(), _inputWires.end(), findFn ); it != _inputWires.end();
251 it = std::find_if( it, _inputWires.end(), findFn ) )
254 fromComponent->_DecRefs( it->fromOutput );
256 it = _inputWires.erase( it );
260inline void Component::DisconnectAllInputs()
263 for (
const auto& wire : _inputWires )
266 wire.fromComponent->_DecRefs( wire.fromOutput );
272inline int Component::GetInputCount()
const
274 return _inputBuses[0].GetSignalCount();
277inline int Component::GetOutputCount()
const
279 return _outputBuses[0].GetSignalCount();
283inline std::string Component::GetInputName(
int inputNo )
const
285 if ( inputNo < (
int)_inputNames.size() )
287 return _inputNames[inputNo];
293inline std::string Component::GetOutputName(
int outputNo )
const
295 if ( outputNo < (
int)_outputNames.size() )
297 return _outputNames[outputNo];
302inline void Component::SetBufferCount(
int bufferCount,
int startBuffer )
306 if ( bufferCount <= 0 )
311 if ( startBuffer >= bufferCount )
317 _inputBuses.resize( bufferCount );
318 _outputBuses.resize( bufferCount );
320 _releaseFlags.resize( bufferCount );
322 _refs.resize( bufferCount );
324 const auto inputCount = GetInputCount();
325 const auto outputCount = GetOutputCount();
326 const auto refCount = _refs[0].size();
329 for (
int i = 0; i < bufferCount; ++i )
331 _inputBuses[i].SetSignalCount( inputCount );
332 _outputBuses[i].SetSignalCount( outputCount );
334 if ( i == startBuffer )
336 _releaseFlags[i].Set();
340 _releaseFlags[i].Clear();
343 _refs[i].resize( refCount );
344 for (
size_t j = 0; j < refCount; ++j )
347 _refs[i][j].total = _refs[0][j].total;
351 _bufferCount = bufferCount;
354inline int Component::GetBufferCount()
const
356 return (
int)_inputBuses.size();
359inline void Component::Tick(
int bufferNo )
361 auto& inputBus = _inputBuses[bufferNo];
362 auto& outputBus = _outputBuses[bufferNo];
365 inputBus.ClearAllValues();
367 for (
const auto& wire : _inputWires )
370 wire.fromComponent->_GetOutput( bufferNo, wire.fromOutput, wire.toInput, inputBus );
374 outputBus.ClearAllValues();
376 if ( _bufferCount != 1 && _processOrder == ProcessOrder::InOrder )
379 _WaitForRelease( bufferNo );
382 Process_( inputBus, outputBus );
385 _ReleaseNextBuffer( bufferNo );
390 Process_( inputBus, outputBus );
394inline void Component::TickParallel(
int bufferNo )
396 auto& inputBus = _inputBuses[bufferNo];
397 auto& outputBus = _outputBuses[bufferNo];
400 inputBus.ClearAllValues();
401 outputBus.ClearAllValues();
403 for (
const auto& wire : _inputWires )
406 wire.fromComponent->_GetOutputParallel( bufferNo, wire.fromOutput, wire.toInput, inputBus );
409 if ( _bufferCount != 1 && _processOrder == ProcessOrder::InOrder )
412 _WaitForRelease( bufferNo );
415 Process_( inputBus, outputBus );
418 _ReleaseNextBuffer( bufferNo );
423 Process_( inputBus, outputBus );
427 for (
auto& ref : _refs[bufferNo] )
430 if ( ref.total != 0 )
437inline void Component::Scan( std::vector<Component*>& components )
440 if ( _scanPosition != -1 )
448 for (
const auto& wire : _inputWires )
451 wire.fromComponent->Scan( components );
454 components.emplace_back(
this );
457inline void Component::ScanParallel( std::vector<std::vector<DSPatch::Component*>>& componentsMap,
int& scanPosition )
460 if ( _scanPosition != -1 )
462 scanPosition = _scanPosition;
470 for (
const auto& wire : _inputWires )
473 wire.fromComponent->ScanParallel( componentsMap, scanPosition );
476 _scanPosition = std::max( _scanPosition, ++scanPosition );
480 if ( _scanPosition == (
int)componentsMap.size() )
482 componentsMap.emplace_back( std::vector<DSPatch::Component*>{} );
483 componentsMap[_scanPosition].reserve( componentsMap.capacity() );
485 componentsMap[_scanPosition].emplace_back(
this );
488inline void Component::EndScan()
494inline void Component::SetInputCount_(
int inputCount,
const std::vector<std::string>& inputNames )
496 _inputNames = inputNames;
498 for (
auto& inputBus : _inputBuses )
500 inputBus.SetSignalCount( inputCount );
503 _inputWires.reserve( inputCount );
506inline void Component::SetOutputCount_(
int outputCount,
const std::vector<std::string>& outputNames )
508 _outputNames = outputNames;
510 for (
auto& outputBus : _outputBuses )
512 outputBus.SetSignalCount( outputCount );
516 for (
auto& ref : _refs )
518 ref.resize( outputCount );
522inline void Component::_WaitForRelease(
int bufferNo )
524 _releaseFlags[bufferNo].WaitAndClear();
527inline void Component::_ReleaseNextBuffer(
int bufferNo )
529 if ( ++bufferNo == _bufferCount )
531 _releaseFlags[0].Set();
535 _releaseFlags[bufferNo].Set();
539inline void Component::_GetOutput(
int bufferNo,
int fromOutput,
int toInput,
DSPatch::SignalBus& toBus )
541 auto& signal = *_outputBuses[bufferNo].GetSignal( fromOutput );
543 if ( !signal.has_value() )
548 auto& ref = _refs[bufferNo][fromOutput];
550 if ( ref.total == 1 )
553 toBus.MoveSignal( toInput, signal );
555 else if ( ++ref.count != ref.total )
558 toBus.SetSignal( toInput, signal );
564 toBus.MoveSignal( toInput, signal );
568inline void Component::_GetOutputParallel(
int bufferNo,
int fromOutput,
int toInput,
DSPatch::SignalBus& toBus )
570 auto& signal = *_outputBuses[bufferNo].GetSignal( fromOutput );
571 auto& ref = _refs[bufferNo][fromOutput];
574 ref.readyFlag.WaitAndClear();
576 if ( !signal.has_value() )
581 if ( ref.total == 1 )
584 toBus.MoveSignal( toInput, signal );
586 else if ( ++ref.count != ref.total )
589 toBus.SetSignal( toInput, signal );
598 toBus.MoveSignal( toInput, signal );
602inline void Component::_IncRefs(
int output )
604 for (
auto& ref : _refs )
610inline void Component::_DecRefs(
int output )
612 for (
auto& ref : _refs )
Abstract base class for DSPatch components.