DSPatch  v.2.42
C++ Cross-Platform, Object-Oriented, Flow-Based Programming Library
 All Classes Pages
DspComponent.cpp
1 /************************************************************************
2 DSPatch - Cross-Platform, Object-Oriented, Flow-Based Programming Library
3 Copyright (c) 2012-2013 Marcus Tomlinson
4 
5 This file is part of DSPatch.
6 
7 GNU Lesser General Public License Usage
8 This file may be used under the terms of the GNU Lesser General Public
9 License version 3.0 as published by the Free Software Foundation and
10 appearing in the file LGPLv3.txt included in the packaging of this
11 file. Please review the following information to ensure the GNU Lesser
12 General Public License version 3.0 requirements will be met:
13 http://www.gnu.org/copyleft/lgpl.html.
14 
15 Other Usage
16 Alternatively, this file may be used in accordance with the terms and
17 conditions contained in a signed written agreement between you and
18 Marcus Tomlinson.
19 
20 DSPatch is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 ************************************************************************/
24 
25 #include "../include/DSPatch.h"
26 
27 #include "DspCircuit.h"
28 #include "DspComponent.h"
29 #include "DspComponentThread.h"
30 #include "DspWire.h"
31 
32 //=================================================================================================
33 
34 DspComponent::DspComponent()
35 : _parentCircuit( NULL ),
36  _bufferCount( 0 ),
37  _componentName( "" ),
38  _isAutoTickRunning( false ),
39  _isAutoTickPaused( false ),
40  _hasTicked( false )
41 {
42  _componentThread.Initialise( this );
43 }
44 
45 //-------------------------------------------------------------------------------------------------
46 
47 DspComponent::~DspComponent()
48 {
49  if( _parentCircuit != NULL )
50  {
51  _parentCircuit->RemoveComponent( this );
52  }
53 
54  StopAutoTick();
55  SetBufferCount( 0 );
56  DisconnectInputs();
57 }
58 
59 //=================================================================================================
60 
61 void DspComponent::SetComponentName( std::string componentName )
62 {
63  _componentName = componentName;
64 }
65 
66 //-------------------------------------------------------------------------------------------------
67 
68 std::string DspComponent::GetComponentName() const
69 {
70  return _componentName;
71 }
72 
73 //-------------------------------------------------------------------------------------------------
74 
75 void DspComponent::SetParentCircuit( DspCircuit* parentCircuit )
76 {
77  if( _parentCircuit != parentCircuit && parentCircuit != this )
78  {
79  DspCircuit* currentParent = _parentCircuit;
80  _parentCircuit = NULL;
81 
82  // if this component is part of another circuit, remove it from that circuit first
83  if( currentParent != NULL )
84  {
85  currentParent->RemoveComponent( this );
86  }
87 
88  _parentCircuit = parentCircuit;
89 
90  // this method is called from within AddComponent() so don't call AddComponent() here
91  }
92 }
93 
94 //-------------------------------------------------------------------------------------------------
95 
96 DspCircuit* DspComponent::GetParentCircuit()
97 {
98  return _parentCircuit;
99 }
100 
101 //-------------------------------------------------------------------------------------------------
102 
103 void DspComponent::DisconnectInput( unsigned short inputIndex )
104 {
105  PauseAutoTick();
106 
107  // remove inputComponent from _inputWires
108  for( unsigned short i = 0; i < _inputWires.GetWireCount(); i++ )
109  {
110  DspWire* wire = _inputWires.GetWire( i );
111  if( wire->toSignalIndex == inputIndex )
112  {
113  _inputWires.RemoveWire( i );
114  break;
115  }
116  }
117 
118  ResumeAutoTick();
119 }
120 
121 //-------------------------------------------------------------------------------------------------
122 
123 void DspComponent::DisconnectInput( std::string inputName )
124 {
125  unsigned short inputIndex;
126 
127  if( FindInput( inputName, inputIndex ) )
128  {
129  DisconnectInput( inputIndex );
130  }
131 }
132 
133 //-------------------------------------------------------------------------------------------------
134 
135 void DspComponent::DisconnectInput( DspComponent* inputComponent )
136 {
137  PauseAutoTick();
138 
139  // remove inputComponent from _inputWires
140  for( unsigned short i = 0; i < _inputWires.GetWireCount(); i++ )
141  {
142  DspWire* wire = _inputWires.GetWire( i );
143  if( wire->linkedComponent == inputComponent )
144  {
145  _inputWires.RemoveWire( i );
146  }
147  }
148 
149  ResumeAutoTick();
150 }
151 
152 //-------------------------------------------------------------------------------------------------
153 
154 void DspComponent::DisconnectInputs()
155 {
156  PauseAutoTick();
157  _inputWires.RemoveAllWires();
158  ResumeAutoTick();
159 }
160 
161 //-------------------------------------------------------------------------------------------------
162 
163 unsigned short DspComponent::GetInputCount() const
164 {
165  return _inputBus.GetSignalCount();
166 }
167 
168 //-------------------------------------------------------------------------------------------------
169 
170 unsigned short DspComponent::GetOutputCount() const
171 {
172  return _outputBus.GetSignalCount();
173 }
174 
175 //-------------------------------------------------------------------------------------------------
176 
177 bool DspComponent::FindInput( std::string signalName, unsigned short& returnIndex ) const
178 {
179  return _inputBus.FindSignal( signalName, returnIndex );
180 }
181 
182 //-------------------------------------------------------------------------------------------------
183 
184 bool DspComponent::FindInput( unsigned short signalIndex, unsigned short& returnIndex ) const
185 {
186  if( signalIndex < _inputBus.GetSignalCount() )
187  {
188  returnIndex = signalIndex;
189  return true;
190  }
191 
192  return false;
193 }
194 
195 //-------------------------------------------------------------------------------------------------
196 
197 bool DspComponent::FindOutput( std::string signalName, unsigned short& returnIndex ) const
198 {
199  return _outputBus.FindSignal( signalName, returnIndex );
200 }
201 
202 //-------------------------------------------------------------------------------------------------
203 
204 bool DspComponent::FindOutput( unsigned short signalIndex, unsigned short& returnIndex ) const
205 {
206  if( signalIndex < _outputBus.GetSignalCount() )
207  {
208  returnIndex = signalIndex;
209  return true;
210  }
211 
212  return false;
213 }
214 
215 //-------------------------------------------------------------------------------------------------
216 
217 void DspComponent::Tick()
218 {
219  // continue only if this component has not already been ticked
220  if( !_hasTicked )
221  {
222  // 1. set _hasTicked flag
223  _hasTicked = true;
224 
225  // 2. get outputs required from input components
226  for( unsigned short i = 0; i < _inputWires.GetWireCount(); i++ )
227  {
228  DspWire* wire = _inputWires.GetWire( i );
229  wire->linkedComponent->Tick();
230 
231  DspSignal* signal = wire->linkedComponent->_outputBus.GetSignal( wire->fromSignalIndex );
232  _inputBus.SetSignal( wire->toSignalIndex, signal );
233  }
234 
235  // 3. clear all outputs
236  _outputBus.ClearAllValues();
237 
238  // 4. call Process_() with newly aquired inputs
239  Process_( _inputBus, _outputBus );
240  }
241 }
242 
243 //-------------------------------------------------------------------------------------------------
244 
245 void DspComponent::Reset()
246 {
247  // clear all inputs
248  _inputBus.ClearAllValues();
249 
250  // reset _hasTicked flag
251  _hasTicked = false;
252 }
253 
254 //-------------------------------------------------------------------------------------------------
255 
256 void DspComponent::StartAutoTick()
257 {
258  // Global scoped components (components not within a circuit) are added to the "global circuit" in
259  // order to be auto-ticked. Technically it is only the global circuit that auto-ticks -This in turn
260  // auto-ticks all components contained.
261 
262  // if this is the global circuit
263  if( DSPatch::IsThisGlobalCircuit( this ) )
264  {
265  if( _componentThread.IsStopped() )
266  {
267  _componentThread.Start();
268 
269  _isAutoTickRunning = true;
270  _isAutoTickPaused = false;
271  }
272  else
273  {
274  ResumeAutoTick();
275  }
276  }
277  // else if this component has no parent or it's parent is the global circuit
278  else if( _parentCircuit == NULL || DSPatch::IsThisGlobalCircuit( _parentCircuit ) )
279  {
280  DSPatch::AddGlobalComponent( this );
281  DSPatch::StartGlobalAutoTick();
282  }
283 }
284 
285 //-------------------------------------------------------------------------------------------------
286 
287 void DspComponent::StopAutoTick()
288 {
289  // If a component is part of the global circuit, a call to StopAutoTick() removes it from the
290  // global circuit as to stop it from being auto-ticked. When all components are removed, the
291  // global circuit auto-ticking is stopped.
292 
293  // if this is the global circuit
294  if( DSPatch::IsThisGlobalCircuit( this ) && !_componentThread.IsStopped() )
295  {
296  _componentThread.Stop();
297 
298  _isAutoTickRunning = false;
299  _isAutoTickPaused = false;
300  }
301  // else if this component's parent is the global circuit
302  else if( DSPatch::IsThisGlobalCircuit( _parentCircuit ) )
303  {
304  DSPatch::RemoveGlobalComponent( this );
305 
306  if( DSPatch::GetGlobalComponentCount() == 0 )
307  {
308  DSPatch::StopGlobalAutoTick();
309  }
310  }
311 }
312 
313 //-------------------------------------------------------------------------------------------------
314 
315 void DspComponent::PauseAutoTick()
316 {
317  // A call to PauseAutoTick() recursively traverses it's parent circuits until it reaches the
318  // global circuit. When the global circuit is reached, it's auto-tick is paused.
319 
320  // if this is the global circuit
321  if( DSPatch::IsThisGlobalCircuit( this ) && !_componentThread.IsStopped() )
322  {
323  if( _isAutoTickRunning )
324  {
325  _componentThread.Pause();
326  _isAutoTickPaused = true;
327  _isAutoTickRunning = false;
328  }
329  }
330  else if( _parentCircuit != NULL )
331  {
332  _parentCircuit->PauseAutoTick(); // recursive call to find the global circuit
333  }
334 }
335 
336 //-------------------------------------------------------------------------------------------------
337 
338 void DspComponent::ResumeAutoTick()
339 {
340  // A call to ResumeAutoTick() recursively traverses it's parent circuits until it reaches the
341  // global circuit. When the global circuit is reached, it's auto-tick is resumed.
342 
343  // if this is the global circuit
344  if( DSPatch::IsThisGlobalCircuit( this ) && _isAutoTickPaused )
345  {
346  _componentThread.Resume();
347  _isAutoTickPaused = false;
348  _isAutoTickRunning = true;
349  }
350  else if( _parentCircuit != NULL )
351  {
352  _parentCircuit->ResumeAutoTick(); // recursive call to find the global circuit
353  }
354 }
355 
356 //-------------------------------------------------------------------------------------------------
357 
358 void DspComponent::SetBufferCount( unsigned short bufferCount )
359 {
360  // _bufferCount is the current thread count / bufferCount is new thread count
361 
362  // delete excess _hasTickeds (if new buffer count is less than current)
363  for( long i = _bufferCount - 1; i >= ( long ) bufferCount; i-- )
364  {
365  delete _hasTickeds[i];
366  }
367 
368  // resize local buffer array
369  _hasTickeds.resize( bufferCount );
370 
371  // create excess _hasTickeds (if new buffer count is more than current)
372  for( unsigned short i = _bufferCount; i < bufferCount; i++ )
373  {
374  _hasTickeds[i] = new bool();
375  }
376 
377  _inputBuses.resize( bufferCount );
378  _outputBuses.resize( bufferCount );
379 
380  _gotReleases.resize( bufferCount );
381  _releaseMutexes.resize( bufferCount );
382  _releaseCondts.resize( bufferCount );
383 
384  for( unsigned short i = _bufferCount; i < bufferCount; i++ )
385  {
386  *_hasTickeds[i] = false;
387  _gotReleases[i] = false;
388 
389  for( unsigned short j = 0; j < _inputBus.GetSignalCount(); j++ )
390  {
391  _inputBuses[i].AddSignal( _inputBus.GetSignal( j )->GetSignalName() );
392  }
393 
394  for( unsigned short j = 0; j < _outputBus.GetSignalCount(); j++ )
395  {
396  _outputBuses[i].AddSignal( _outputBus.GetSignal( j )->GetSignalName() );
397  }
398  }
399 
400  if( bufferCount > 0 )
401  {
402  _gotReleases[0] = true;
403  }
404 
405  _bufferCount = bufferCount;
406 }
407 
408 //-------------------------------------------------------------------------------------------------
409 
410 unsigned short DspComponent::GetBufferCount() const
411 {
412  return _bufferCount;
413 }
414 
415 //-------------------------------------------------------------------------------------------------
416 
417 void DspComponent::ThreadTick( unsigned short threadNo )
418 {
419  // continue only if this component has not already been ticked
420  if( *_hasTickeds[threadNo] == false )
421  {
422  // 1. set _hasTicked flag
423  *_hasTickeds[threadNo] = true;
424 
425  // 2. get outputs required from input components
426  for( unsigned short i = 0; i < _inputWires.GetWireCount(); i++ )
427  {
428  DspWire* wire = _inputWires.GetWire( i );
429  wire->linkedComponent->ThreadTick( threadNo );
430 
431  DspSignal* signal = wire->linkedComponent->_outputBuses[threadNo].GetSignal( wire->fromSignalIndex );
432  _inputBuses[threadNo].SetSignal( wire->toSignalIndex, signal );
433  }
434 
435  // 3. clear all outputs
436  _outputBuses[threadNo].ClearAllValues();
437 
438  // 4. wait for your turn to process.
439  _WaitForRelease( threadNo );
440 
441  // 5. call Process_() with newly aquired inputs
442  Process_( _inputBuses[threadNo], _outputBuses[threadNo] );
443 
444  // 6. signal that you're done processing.
445  _ReleaseThread( threadNo );
446  }
447 }
448 
449 //-------------------------------------------------------------------------------------------------
450 
451 void DspComponent::ThreadReset( unsigned short threadNo )
452 {
453  // clear all inputs
454  _inputBuses[threadNo].ClearAllValues();
455 
456  // reset _hasTicked flag
457  *_hasTickeds[threadNo] = false;
458 }
459 
460 //-------------------------------------------------------------------------------------------------
461 
462 bool DspComponent::SetInputSignal( unsigned short inputIndex, const DspSignal* newSignal )
463 {
464  return _inputBus.SetSignal( inputIndex, newSignal );
465 }
466 
467 //-------------------------------------------------------------------------------------------------
468 
469 bool DspComponent::SetInputSignal( unsigned short inputIndex, unsigned short threadIndex, const DspSignal* newSignal )
470 {
471  return _inputBuses[threadIndex].SetSignal( inputIndex, newSignal );
472 }
473 
474 //-------------------------------------------------------------------------------------------------
475 
476 DspSignal* DspComponent::GetOutputSignal( unsigned short outputIndex )
477 {
478  return _outputBus.GetSignal( outputIndex );
479 }
480 
481 //-------------------------------------------------------------------------------------------------
482 
483 DspSignal* DspComponent::GetOutputSignal( unsigned short outputIndex, unsigned short threadIndex )
484 {
485  return _outputBuses[threadIndex].GetSignal( outputIndex );
486 }
487 
488 //=================================================================================================
489 
490 bool DspComponent::AddInput_( std::string inputName )
491 {
492  for( unsigned short i = 0; i < _inputBuses.size(); i++ )
493  {
494  _inputBuses[i].AddSignal( inputName );
495  }
496  return _inputBus.AddSignal( inputName );
497 }
498 
499 //-------------------------------------------------------------------------------------------------
500 
501 bool DspComponent::AddOutput_( std::string outputName )
502 {
503  for( unsigned short i = 0; i < _outputBuses.size(); i++ )
504  {
505  _outputBuses[i].AddSignal( outputName );
506  }
507  return _outputBus.AddSignal( outputName );
508 }
509 
510 //-------------------------------------------------------------------------------------------------
511 
512 void DspComponent::ClearInputs_()
513 {
514  for( unsigned short i = 0; i < _inputBuses.size(); i++ )
515  {
516  _inputBuses[i].RemoveAllSignals();
517  }
518  return _inputBus.RemoveAllSignals();
519 }
520 
521 //-------------------------------------------------------------------------------------------------
522 
523 void DspComponent::ClearOutputs_()
524 {
525  for( unsigned short i = 0; i < _outputBuses.size(); i++ )
526  {
527  _outputBuses[i].RemoveAllSignals();
528  }
529  return _outputBus.RemoveAllSignals();
530 }
531 
532 //=================================================================================================
533 
534 void DspComponent::_WaitForRelease( unsigned short threadNo )
535 {
536  _releaseMutexes[threadNo].Lock();
537  if( !_gotReleases[threadNo] )
538  {
539  _releaseCondts[threadNo].Wait( _releaseMutexes[threadNo] ); // wait for resume
540  }
541  _gotReleases[threadNo] = false; // reset the release flag
542  _releaseMutexes[threadNo].Unlock();
543 }
544 
545 //-------------------------------------------------------------------------------------------------
546 
547 void DspComponent::_ReleaseThread( unsigned short threadNo )
548 {
549  unsigned short nextThread = threadNo + 1;
550 
551  if( nextThread >= _bufferCount )
552  nextThread = 0;
553 
554  _releaseMutexes[nextThread].Lock();
555  _gotReleases[nextThread] = true;
556  _releaseCondts[nextThread].WakeAll();
557  _releaseMutexes[nextThread].Unlock();
558 }
559 
560 //=================================================================================================