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 )
228 _components = components;
229 _bufferNo = bufferNo;
234 _thread = std::thread( &CircuitThread::_Run,
this );
243 if ( _thread.joinable() )
251 std::unique_lock<std::mutex> lock( _syncMutex );
255 _syncCondt.wait( lock );
262 _resumeCondt.notify_all();
263 std::this_thread::yield();
266 inline void SyncAndResume()
276 SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST );
278 sched_param sch_params;
279 sch_params.sched_priority = sched_get_priority_max( SCHED_RR );
280 pthread_setschedparam( pthread_self(), SCHED_RR, &sch_params );
288 std::unique_lock<std::mutex> lock( _syncMutex );
291 _syncCondt.notify_all();
292 _resumeCondt.wait( lock );
309 for (
auto component : *_components )
311 component->Tick( _bufferNo );
318 std::vector<DSPatch::Component*>* _components =
nullptr;
321 bool _gotSync =
false;
322 std::mutex _syncMutex;
323 std::condition_variable _resumeCondt, _syncCondt;
326 class CircuitThreadParallel final
329 CircuitThreadParallel(
const CircuitThreadParallel& ) =
delete;
330 CircuitThreadParallel& operator=(
const CircuitThreadParallel& ) =
delete;
332 inline CircuitThreadParallel() =
default;
335 inline CircuitThreadParallel( CircuitThreadParallel&& )
339 inline ~CircuitThreadParallel()
344 inline void Start( std::vector<DSPatch::Component*>* components,
int bufferNo,
int threadNo,
int threadCount )
346 _components = components;
347 _bufferNo = bufferNo;
348 _threadNo = threadNo;
349 _threadCount = threadCount;
354 _thread = std::thread( &CircuitThreadParallel::_Run,
this );
363 if ( _thread.joinable() )
371 std::unique_lock<std::mutex> lock( _syncMutex );
375 _syncCondt.wait( lock );
382 _resumeCondt.notify_all();
383 std::this_thread::yield();
390 SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST );
392 sched_param sch_params;
393 sch_params.sched_priority = sched_get_priority_max( SCHED_RR );
394 pthread_setschedparam( pthread_self(), SCHED_RR, &sch_params );
402 std::unique_lock<std::mutex> lock( _syncMutex );
405 _syncCondt.notify_all();
406 _resumeCondt.wait( lock );
414 for (
auto it = _components->begin() + _threadNo; it < _components->end(); it += _threadCount )
416 ( *it )->TickParallel( _bufferNo );
423 std::vector<DSPatch::Component*>* _components =
nullptr;
426 int _threadCount = 0;
428 bool _gotSync =
false;
429 std::mutex _syncMutex;
430 std::condition_variable _resumeCondt, _syncCondt;
435 int _bufferCount = 0;
436 int _threadCount = 0;
437 int _currentBuffer = 0;
439 AutoTickThread _autoTickThread;
441 std::unordered_set<DSPatch::Component::SPtr> _componentsSet;
443 std::vector<DSPatch::Component*> _components;
444 std::vector<DSPatch::Component*> _componentsParallel;
446 std::vector<CircuitThread> _circuitThreads;
447 std::vector<std::vector<CircuitThreadParallel>> _circuitThreadsParallel;
449 bool _circuitDirty =
false;
452inline Circuit::Circuit() =
default;
454inline Circuit::~Circuit()
457 DisconnectAllComponents();
460inline bool Circuit::AddComponent(
const Component::SPtr& component )
462 if ( !component || _componentsSet.find( component ) != _componentsSet.end() )
468 component->SetBufferCount( _bufferCount, _currentBuffer );
471 _components.emplace_back( component.get() );
472 _componentsParallel.emplace_back( component.get() );
475 _componentsSet.emplace( component );
480inline bool Circuit::RemoveComponent(
const Component::SPtr& component )
482 if ( _componentsSet.find( component ) == _componentsSet.end() )
487 auto findFn = [&component](
auto comp ) {
return comp == component.get(); };
489 if (
auto it = std::find_if( _components.begin(), _components.end(), findFn ); it != _components.end() )
493 DisconnectComponent( component );
495 _components.erase( it );
499 _componentsSet.erase( component );
508inline void Circuit::RemoveAllComponents()
512 DisconnectAllComponents();
515 _componentsParallel.clear();
519 _componentsSet.clear();
522inline int Circuit::GetComponentCount()
const
524 return (
int)_components.size();
527inline bool Circuit::ConnectOutToIn(
const Component::SPtr& fromComponent,
529 const Component::SPtr& toComponent,
532 if ( _componentsSet.find( fromComponent ) == _componentsSet.end() ||
533 _componentsSet.find( toComponent ) == _componentsSet.end() )
540 bool result = toComponent->ConnectInput( fromComponent, fromOutput, toInput );
542 _circuitDirty = result;
549inline bool Circuit::DisconnectComponent(
const Component::SPtr& component )
551 if ( _componentsSet.find( component ) == _componentsSet.end() )
558 component->DisconnectAllInputs();
561 for (
auto comp : _components )
563 comp->DisconnectInput( component );
566 _circuitDirty =
true;
573inline void Circuit::DisconnectAllComponents()
577 for (
auto component : _components )
579 component->DisconnectAllInputs();
585inline void Circuit::SetBufferCount(
int bufferCount )
589 _bufferCount = bufferCount;
592 for (
auto& circuitThread : _circuitThreads )
594 circuitThread.Stop();
598 if ( _threadCount != 0 )
600 _circuitThreads.resize( 0 );
601 SetThreadCount( _threadCount );
605 _circuitThreads.resize( _bufferCount );
608 for (
int i = 0; i < _bufferCount; ++i )
610 _circuitThreads[i].Start( &_components, i );
614 if ( _currentBuffer >= _bufferCount )
620 for (
auto component : _components )
622 component->SetBufferCount( _bufferCount, _currentBuffer );
628inline int Circuit::GetBufferCount()
const
633inline void Circuit::SetThreadCount(
int threadCount )
637 if ( _threadCount == 0 && threadCount != 0 )
639 _circuitDirty =
true;
642 _threadCount = threadCount;
645 for (
auto& circuitThreads : _circuitThreadsParallel )
647 for (
auto& circuitThread : circuitThreads )
649 circuitThread.Stop();
654 if ( _threadCount == 0 )
656 _circuitThreadsParallel.resize( 0 );
657 SetBufferCount( _bufferCount );
661 _circuitThreadsParallel.resize( _bufferCount == 0 ? 1 : _bufferCount );
662 for (
auto& circuitThread : _circuitThreadsParallel )
664 circuitThread.resize( _threadCount );
669 for (
auto& circuitThreads : _circuitThreadsParallel )
672 for (
auto& circuitThread : circuitThreads )
674 circuitThread.Start( &_componentsParallel, i, j++, _threadCount );
684inline int Circuit::GetThreadCount()
const
689inline void Circuit::Tick()
698 if ( _threadCount != 0 )
700 auto& circuitThreads = _circuitThreadsParallel[_currentBuffer];
702 for (
auto& circuitThread : circuitThreads )
704 circuitThread.Sync();
706 for (
auto& circuitThread : circuitThreads )
708 circuitThread.Resume();
713 else if ( _bufferCount == 0 )
716 for (
auto component : _components )
718 component->Tick( 0 );
725 _circuitThreads[_currentBuffer].SyncAndResume();
728 if ( _bufferCount != 0 && ++_currentBuffer == _bufferCount )
734inline void Circuit::Sync()
737 for (
auto& circuitThread : _circuitThreads )
739 circuitThread.Sync();
741 for (
auto& circuitThreads : _circuitThreadsParallel )
743 for (
auto& circuitThread : circuitThreads )
745 circuitThread.Sync();
750inline void Circuit::StartAutoTick()
752 _autoTickThread.Start(
this );
755inline void Circuit::StopAutoTick()
757 _autoTickThread.Stop();
761inline void Circuit::PauseAutoTick()
763 _autoTickThread.Pause();
767inline void Circuit::ResumeAutoTick()
769 _autoTickThread.Resume();
772inline void Circuit::Optimize()
782inline void Circuit::_Optimize()
785 std::vector<DSPatch::Component*> orderedComponents;
786 orderedComponents.reserve( _components.size() );
788 for (
auto component : _components )
790 component->Scan( orderedComponents );
792 for (
auto component : _components )
794 component->EndScan();
797 _components = std::move( orderedComponents );
800 if ( _threadCount != 0 )
802 std::vector<std::vector<DSPatch::Component*>> componentsMap;
803 componentsMap.reserve( _components.size() );
806 for (
auto component : _components )
808 component->ScanParallel( componentsMap, scanPosition );
810 for (
auto component : _components )
812 component->EndScan();
815 _componentsParallel.clear();
816 _componentsParallel.reserve( _components.size() );
817 for (
auto& componentsMapEntry : componentsMap )
819 _componentsParallel.insert( _componentsParallel.end(), componentsMapEntry.begin(), componentsMapEntry.end() );
824 _circuitDirty =
false;
Workspace for adding and routing components.