34#define WIN32_LEAN_AND_MEAN
36#undef WIN32_LEAN_AND_MEAN
40#include <condition_variable>
42#include <unordered_set>
81 bool AddComponent(
const Component::SPtr& component );
83 bool RemoveComponent(
const Component::SPtr& component );
84 void RemoveAllComponents();
86 int GetComponentCount()
const;
88 bool ConnectOutToIn(
const Component::SPtr& fromComponent,
int fromOutput,
const Component::SPtr& toComponent,
int toInput );
90 bool DisconnectComponent(
const Component::SPtr& component );
91 void DisconnectAllComponents();
93 void SetBufferCount(
int bufferCount );
94 int GetBufferCount()
const;
96 void SetThreadCount(
int threadCount );
97 int GetThreadCount()
const;
102 void StartAutoTick();
104 void PauseAutoTick();
105 void ResumeAutoTick();
110 class AutoTickThread final
113 AutoTickThread(
const AutoTickThread& ) =
delete;
114 AutoTickThread& operator=(
const AutoTickThread& ) =
delete;
116 inline AutoTickThread() =
default;
118 inline ~AutoTickThread()
137 _thread = std::thread( &AutoTickThread::_Run,
this );
145 if ( _thread.joinable() )
153 if ( !_stopped && ++pauseCount == 1 )
155 std::unique_lock<std::mutex> lock( _resumeMutex );
157 _pauseCondt.wait( lock );
163 if ( _pause && --pauseCount == 0 )
166 _resumeCondt.notify_all();
167 std::this_thread::yield();
187 std::unique_lock<std::mutex> lock( _resumeMutex );
189 _pauseCondt.notify_all();
190 _resumeCondt.wait( lock );
203 bool _stopped =
true;
204 std::mutex _resumeMutex;
205 std::condition_variable _resumeCondt, _pauseCondt;
208 class CircuitThread final
211 CircuitThread(
const CircuitThread& ) =
delete;
212 CircuitThread& operator=(
const CircuitThread& ) =
delete;
214 inline CircuitThread() =
default;
217 inline CircuitThread( CircuitThread&& )
221 inline ~CircuitThread()
226 inline void Start( std::vector<DSPatch::Component*>* components,
int bufferNo,
int bufferCount )
228 _components = components;
229 _bufferNo = bufferNo;
230 _loneBuffer = bufferCount <= 1;
235 _thread = std::thread( &CircuitThread::_Run,
this );
244 if ( _thread.joinable() )
252 std::unique_lock<std::mutex> lock( _syncMutex );
256 _syncCondt.wait( lock );
263 _resumeCondt.notify_all();
264 std::this_thread::yield();
267 inline void SyncAndResume()
277 SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST );
279 sched_param sch_params;
280 sch_params.sched_priority = sched_get_priority_max( SCHED_RR );
281 pthread_setschedparam( pthread_self(), SCHED_RR, &sch_params );
289 std::unique_lock<std::mutex> lock( _syncMutex );
292 _syncCondt.notify_all();
293 _resumeCondt.wait( lock );
312 for (
auto component : *_components )
319 for (
auto component : *_components )
321 component->Tick( _bufferNo );
329 std::vector<DSPatch::Component*>* _components =
nullptr;
331 bool _loneBuffer =
false;
333 bool _gotSync =
false;
334 std::mutex _syncMutex;
335 std::condition_variable _resumeCondt, _syncCondt;
338 class CircuitThreadParallel final
341 CircuitThreadParallel(
const CircuitThreadParallel& ) =
delete;
342 CircuitThreadParallel& operator=(
const CircuitThreadParallel& ) =
delete;
344 inline CircuitThreadParallel() =
default;
347 inline CircuitThreadParallel( CircuitThreadParallel&& )
351 inline ~CircuitThreadParallel()
357 std::vector<DSPatch::Component*>* components,
int bufferNo,
int bufferCount,
int threadNo,
int threadCount )
359 _components = components;
360 _bufferNo = bufferNo;
361 _loneBuffer = bufferCount <= 1;
362 _threadNo = threadNo;
363 _threadCount = threadCount;
368 _thread = std::thread( &CircuitThreadParallel::_Run,
this );
377 if ( _thread.joinable() )
385 std::unique_lock<std::mutex> lock( _syncMutex );
389 _syncCondt.wait( lock );
396 _resumeCondt.notify_all();
397 std::this_thread::yield();
404 SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST );
406 sched_param sch_params;
407 sch_params.sched_priority = sched_get_priority_max( SCHED_RR );
408 pthread_setschedparam( pthread_self(), SCHED_RR, &sch_params );
416 std::unique_lock<std::mutex> lock( _syncMutex );
419 _syncCondt.notify_all();
420 _resumeCondt.wait( lock );
430 for (
auto it = _components->begin() + _threadNo; it < _components->end(); it += _threadCount )
432 ( *it )->TickParallel();
437 for (
auto it = _components->begin() + _threadNo; it < _components->end(); it += _threadCount )
439 ( *it )->TickParallel( _bufferNo );
447 std::vector<DSPatch::Component*>* _components =
nullptr;
449 bool _loneBuffer =
false;
451 int _threadCount = 0;
453 bool _gotSync =
false;
454 std::mutex _syncMutex;
455 std::condition_variable _resumeCondt, _syncCondt;
460 int _bufferCount = 0;
461 int _threadCount = 0;
462 int _currentBuffer = 0;
464 AutoTickThread _autoTickThread;
466 std::unordered_set<DSPatch::Component::SPtr> _componentsSet;
468 std::vector<DSPatch::Component*> _components;
469 std::vector<DSPatch::Component*> _componentsParallel;
471 std::vector<CircuitThread> _circuitThreads;
472 std::vector<std::vector<CircuitThreadParallel>> _circuitThreadsParallel;
474 bool _circuitDirty =
false;
477inline Circuit::Circuit() =
default;
479inline Circuit::~Circuit()
482 DisconnectAllComponents();
485inline bool Circuit::AddComponent(
const Component::SPtr& component )
487 if ( !component || _componentsSet.find( component ) != _componentsSet.end() )
493 component->SetBufferCount( _bufferCount, _currentBuffer );
496 _components.emplace_back( component.get() );
497 _componentsParallel.emplace_back( component.get() );
500 _componentsSet.emplace( component );
505inline bool Circuit::RemoveComponent(
const Component::SPtr& component )
507 if ( _componentsSet.find( component ) == _componentsSet.end() )
512 auto findFn = [&component](
auto comp ) {
return comp == component.get(); };
514 if (
auto it = std::find_if( _components.begin(), _components.end(), findFn ); it != _components.end() )
518 DisconnectComponent( component );
520 _components.erase( it );
524 _componentsSet.erase( component );
533inline void Circuit::RemoveAllComponents()
537 DisconnectAllComponents();
540 _componentsParallel.clear();
544 _componentsSet.clear();
547inline int Circuit::GetComponentCount()
const
549 return (
int)_components.size();
552inline bool Circuit::ConnectOutToIn(
const Component::SPtr& fromComponent,
554 const Component::SPtr& toComponent,
557 if ( _componentsSet.find( fromComponent ) == _componentsSet.end() ||
558 _componentsSet.find( toComponent ) == _componentsSet.end() )
565 bool result = toComponent->ConnectInput( fromComponent, fromOutput, toInput );
567 _circuitDirty = result;
574inline bool Circuit::DisconnectComponent(
const Component::SPtr& component )
576 if ( _componentsSet.find( component ) == _componentsSet.end() )
583 component->DisconnectAllInputs();
586 for (
auto comp : _components )
588 comp->DisconnectInput( component );
591 _circuitDirty =
true;
598inline void Circuit::DisconnectAllComponents()
602 for (
auto component : _components )
604 component->DisconnectAllInputs();
610inline void Circuit::SetBufferCount(
int bufferCount )
614 _bufferCount = bufferCount;
617 for (
auto& circuitThread : _circuitThreads )
619 circuitThread.Stop();
623 if ( _threadCount != 0 )
625 _circuitThreads.resize( 0 );
626 SetThreadCount( _threadCount );
630 _circuitThreads.resize( _bufferCount );
633 for (
int i = 0; i < _bufferCount; ++i )
635 _circuitThreads[i].Start( &_components, i, _bufferCount );
639 if ( _currentBuffer >= _bufferCount )
645 for (
auto component : _components )
647 component->SetBufferCount( _bufferCount, _currentBuffer );
653inline int Circuit::GetBufferCount()
const
658inline void Circuit::SetThreadCount(
int threadCount )
662 if ( _threadCount == 0 && threadCount != 0 )
664 _circuitDirty =
true;
667 _threadCount = threadCount;
670 for (
auto& circuitThreads : _circuitThreadsParallel )
672 for (
auto& circuitThread : circuitThreads )
674 circuitThread.Stop();
679 if ( _threadCount == 0 )
681 _circuitThreadsParallel.resize( 0 );
682 SetBufferCount( _bufferCount );
686 _circuitThreadsParallel.resize( _bufferCount == 0 ? 1 : _bufferCount );
687 for (
auto& circuitThread : _circuitThreadsParallel )
689 circuitThread.resize( _threadCount );
694 for (
auto& circuitThreads : _circuitThreadsParallel )
697 for (
auto& circuitThread : circuitThreads )
699 circuitThread.Start( &_componentsParallel, i, _bufferCount, j++, _threadCount );
709inline int Circuit::GetThreadCount()
const
714inline void Circuit::Tick()
723 if ( _threadCount != 0 )
725 auto& circuitThreads = _circuitThreadsParallel[_currentBuffer];
727 for (
auto& circuitThread : circuitThreads )
729 circuitThread.Sync();
731 for (
auto& circuitThread : circuitThreads )
733 circuitThread.Resume();
738 else if ( _bufferCount == 0 )
741 for (
auto component : _components )
750 _circuitThreads[_currentBuffer].SyncAndResume();
753 if ( _bufferCount != 0 && ++_currentBuffer == _bufferCount )
759inline void Circuit::Sync()
762 for (
auto& circuitThread : _circuitThreads )
764 circuitThread.Sync();
766 for (
auto& circuitThreads : _circuitThreadsParallel )
768 for (
auto& circuitThread : circuitThreads )
770 circuitThread.Sync();
775inline void Circuit::StartAutoTick()
777 _autoTickThread.Start(
this );
780inline void Circuit::StopAutoTick()
782 _autoTickThread.Stop();
786inline void Circuit::PauseAutoTick()
788 _autoTickThread.Pause();
792inline void Circuit::ResumeAutoTick()
794 _autoTickThread.Resume();
797inline void Circuit::Optimize()
807inline void Circuit::_Optimize()
810 std::vector<DSPatch::Component*> orderedComponents;
811 orderedComponents.reserve( _components.size() );
813 for (
auto component : _components )
815 component->Scan( orderedComponents );
817 for (
auto component : _components )
819 component->EndScan();
822 _components = std::move( orderedComponents );
825 if ( _threadCount != 0 )
827 std::vector<std::vector<DSPatch::Component*>> componentsMap;
828 componentsMap.reserve( _components.size() );
831 for (
auto component : _components )
833 component->ScanParallel( componentsMap, scanPosition );
835 for (
auto component : _components )
837 component->EndScan();
840 _componentsParallel.clear();
841 _componentsParallel.reserve( _components.size() );
842 for (
auto& componentsMapEntry : componentsMap )
844 _componentsParallel.insert( _componentsParallel.end(), componentsMapEntry.begin(), componentsMapEntry.end() );
849 _circuitDirty =
false;
Workspace for adding and routing components.