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 _threadCount = threadCount;
640 for (
auto& circuitThreads : _circuitThreadsParallel )
642 for (
auto& circuitThread : circuitThreads )
644 circuitThread.Stop();
649 if ( _threadCount == 0 )
651 _circuitThreadsParallel.resize( 0 );
652 SetBufferCount( _bufferCount );
656 _circuitThreadsParallel.resize( _bufferCount == 0 ? 1 : _bufferCount );
657 for (
auto& circuitThread : _circuitThreadsParallel )
659 circuitThread.resize( _threadCount );
664 for (
auto& circuitThreads : _circuitThreadsParallel )
667 for (
auto& circuitThread : circuitThreads )
669 circuitThread.Start( &_componentsParallel, i, j++, _threadCount );
679inline int Circuit::GetThreadCount()
const
684inline void Circuit::Tick()
693 if ( _threadCount != 0 )
695 auto& circuitThreads = _circuitThreadsParallel[_currentBuffer];
697 for (
auto& circuitThread : circuitThreads )
699 circuitThread.Sync();
701 for (
auto& circuitThread : circuitThreads )
703 circuitThread.Resume();
708 else if ( _bufferCount == 0 )
711 for (
auto component : _components )
713 component->Tick( 0 );
720 _circuitThreads[_currentBuffer].SyncAndResume();
723 if ( _bufferCount != 0 && ++_currentBuffer == _bufferCount )
729inline void Circuit::Sync()
732 for (
auto& circuitThread : _circuitThreads )
734 circuitThread.Sync();
736 for (
auto& circuitThreads : _circuitThreadsParallel )
738 for (
auto& circuitThread : circuitThreads )
740 circuitThread.Sync();
745inline void Circuit::StartAutoTick()
747 _autoTickThread.Start(
this );
750inline void Circuit::StopAutoTick()
752 _autoTickThread.Stop();
756inline void Circuit::PauseAutoTick()
758 _autoTickThread.Pause();
762inline void Circuit::ResumeAutoTick()
764 _autoTickThread.Resume();
767inline void Circuit::Optimize()
777inline void Circuit::_Optimize()
781 std::vector<DSPatch::Component*> orderedComponents;
782 orderedComponents.reserve( _components.size() );
784 for (
auto component : _components )
786 component->Scan( orderedComponents );
788 for (
auto component : _components )
790 component->EndScan();
793 _components = std::move( orderedComponents );
797 std::vector<std::vector<DSPatch::Component*>> componentsMap;
798 componentsMap.reserve( _components.size() );
801 for (
auto component : _components )
803 component->ScanParallel( componentsMap, scanPosition );
805 for (
auto component : _components )
807 component->EndScan();
810 _componentsParallel.clear();
811 _componentsParallel.reserve( _components.size() );
812 for (
auto& componentsMapEntry : componentsMap )
814 _componentsParallel.insert( _componentsParallel.end(), componentsMapEntry.begin(), componentsMapEntry.end() );
818 _circuitDirty =
false;
Workspace for adding and routing components.