DSPatch  v.2.42
C++ Cross-Platform, Object-Oriented, Flow-Based Programming Library
 All Classes Pages
DspCircuit.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 "DspCircuit.h"
26 #include "DspCircuitThread.h"
27 #include "DspWire.h"
28 
29 //=================================================================================================
30 
31 DspCircuit::DspCircuit( unsigned short threadCount )
32 : _currentThreadIndex( 0 ),
33  _inToInWires( true ),
34  _outToOutWires( false )
35 {
36  SetThreadCount( threadCount );
37 }
38 
39 //-------------------------------------------------------------------------------------------------
40 
41 DspCircuit::~DspCircuit()
42 {
43  StopAutoTick();
44  RemoveAllComponents();
45  SetThreadCount( 0 );
46 }
47 
48 //=================================================================================================
49 
50 void DspCircuit::PauseAutoTick()
51 {
52  // pause auto tick
53  DspComponent::PauseAutoTick();
54 
55  // manually tick until 0
56  while( _currentThreadIndex != 0 )
57  {
58  Tick();
59  Reset();
60  }
61 
62  // sync all threads
63  for( unsigned short i = 0; i < _circuitThreads.size(); i++ )
64  {
65  _circuitThreads[i].Sync();
66  }
67 }
68 
69 //-------------------------------------------------------------------------------------------------
70 
71 void DspCircuit::SetThreadCount( unsigned short threadCount )
72 {
73  if( threadCount != _circuitThreads.size() )
74  {
75  PauseAutoTick();
76 
77  // stop all threads
78  for( unsigned short i = 0; i < _circuitThreads.size(); i++ )
79  {
80  _circuitThreads[i].Stop();
81  }
82 
83  // resize thread array
84  _circuitThreads.resize( threadCount );
85 
86  // initialise and start all threads
87  for( unsigned short i = 0; i < _circuitThreads.size(); i++ )
88  {
89  _circuitThreads[i].Initialise( &_components, i );
90  _circuitThreads[i].Start();
91  }
92 
93  // set all components to the new thread count
94  for( unsigned short i = 0; i < _components.size(); i++ )
95  {
96  _components[i]->SetBufferCount( threadCount );
97  }
98 
99  ResumeAutoTick();
100  }
101 }
102 
103 //-------------------------------------------------------------------------------------------------
104 
105 unsigned short DspCircuit::GetThreadCount() const
106 {
107  return _circuitThreads.size();
108 }
109 
110 //-------------------------------------------------------------------------------------------------
111 
112 bool DspCircuit::AddComponent( DspComponent* component, std::string componentName )
113 {
114  if( component != this )
115  {
116  // if the component has a name already
117  if( component->GetComponentName() != "" && componentName == "" )
118  {
119  componentName = component->GetComponentName();
120  }
121 
122  unsigned short componentIndex;
123 
124  if( _FindComponent( component, componentIndex ) )
125  {
126  return false; // if the component is already in the array
127  }
128  if( _FindComponent( componentName, componentIndex ) )
129  {
130  return false; // if the component name is already in the array
131  }
132 
133  // components within the circuit need to have as many buffers as there are threads in the circuit
134  component->SetParentCircuit( this );
135  component->SetBufferCount( _circuitThreads.size() );
136  component->SetComponentName( componentName );
137 
138  PauseAutoTick();
139  _components.push_back( component );
140  ResumeAutoTick();
141 
142  return true;
143  }
144 
145  return false;
146 }
147 
148 //-------------------------------------------------------------------------------------------------
149 
150 bool DspCircuit::AddComponent( DspComponent& component, std::string componentName )
151 {
152  return AddComponent( &component, componentName );
153 }
154 
155 //-------------------------------------------------------------------------------------------------
156 
157 void DspCircuit::RemoveComponent( DspComponent* component )
158 {
159  unsigned short componentIndex;
160 
161  if( _FindComponent( component, componentIndex ) )
162  {
163  PauseAutoTick();
164  _RemoveComponent( componentIndex );
165  ResumeAutoTick();
166  }
167 }
168 
169 //-------------------------------------------------------------------------------------------------
170 
171 void DspCircuit::RemoveComponent( DspComponent& component )
172 {
173  RemoveComponent( &component );
174 }
175 
176 //-------------------------------------------------------------------------------------------------
177 
178 void DspCircuit::RemoveComponent( std::string componentName )
179 {
180  unsigned short componentIndex;
181 
182  if( _FindComponent( componentName, componentIndex ) )
183  {
184  PauseAutoTick();
185  _RemoveComponent( componentIndex );
186  ResumeAutoTick();
187  }
188 }
189 
190 //-------------------------------------------------------------------------------------------------
191 
192 void DspCircuit::RemoveAllComponents()
193 {
194  for( unsigned short i = 0; i < _components.size(); i++ )
195  {
196  PauseAutoTick();
197  _RemoveComponent( i-- ); // size drops as one is removed
198  ResumeAutoTick();
199  }
200 }
201 
202 //-------------------------------------------------------------------------------------------------
203 
204 unsigned short DspCircuit::GetComponentCount() const
205 {
206  return _components.size();
207 }
208 
209 //-------------------------------------------------------------------------------------------------
210 
211 void DspCircuit::DisconnectComponent( std::string component )
212 {
213  unsigned short componentIndex;
214 
215  if( !_FindComponent( component, componentIndex ) ) // verify component exists
216  {
217  return;
218  }
219 
220  PauseAutoTick();
221  _DisconnectComponent( componentIndex );
222  ResumeAutoTick();
223 }
224 
225 //-------------------------------------------------------------------------------------------------
226 
227 bool DspCircuit::AddInput( std::string inputName )
228 {
229  PauseAutoTick();
230  bool result = AddInput_( inputName );
231  ResumeAutoTick();
232 
233  return result;
234 }
235 
236 //-------------------------------------------------------------------------------------------------
237 
238 bool DspCircuit::AddOutput( std::string outputName )
239 {
240  PauseAutoTick();
241  bool result = AddOutput_( outputName );
242  ResumeAutoTick();
243 
244  return result;
245 }
246 
247 //-------------------------------------------------------------------------------------------------
248 
249 void DspCircuit::ClearInputs()
250 {
251  ClearInputs_();
252 }
253 
254 //-------------------------------------------------------------------------------------------------
255 
256 void DspCircuit::ClearOutputs()
257 {
258  ClearOutputs_();
259 }
260 
261 //=================================================================================================
262 
263 void DspCircuit::Process_( DspSignalBus& inputs, DspSignalBus& outputs )
264 {
265  DspWire* wire;
266  DspSignal* signal;
267 
268  // process in a single thread if this circuit has no threads
269  // =========================================================
270  if( _circuitThreads.size() == 0 )
271  {
272  // set all internal component inputs from connected circuit inputs
273  for( unsigned short i = 0; i < _inToInWires.GetWireCount(); i++ )
274  {
275  wire = _inToInWires.GetWire( i );
276  signal = inputs.GetSignal( wire->fromSignalIndex );
277  wire->linkedComponent->SetInputSignal( wire->toSignalIndex, signal );
278  }
279 
280  // tick all internal components
281  for( unsigned short i = 0; i < _components.size(); i++ )
282  {
283  _components[i]->Tick();
284  }
285 
286  // reset all internal components
287  for( unsigned short i = 0; i < _components.size(); i++ )
288  {
289  _components[i]->Reset();
290  }
291 
292  // set all circuit outputs from connected internal component outputs
293  for( unsigned short i = 0; i < _outToOutWires.GetWireCount(); i++ )
294  {
295  wire = _outToOutWires.GetWire( i );
296  signal = wire->linkedComponent->GetOutputSignal( wire->fromSignalIndex );
297  outputs.SetSignal( wire->toSignalIndex, signal );
298  }
299  }
300  // process in multiple thread if this circuit has threads
301  // ======================================================
302  else
303  {
304  _circuitThreads[_currentThreadIndex].Sync(); // sync with thread x
305 
306  // set all circuit outputs from connected internal component outputs
307  for( unsigned short i = 0; i < _outToOutWires.GetWireCount(); i++ )
308  {
309  wire = _outToOutWires.GetWire( i );
310  signal = wire->linkedComponent->GetOutputSignal( wire->fromSignalIndex, _currentThreadIndex );
311  outputs.SetSignal( wire->toSignalIndex, signal );
312  }
313 
314  // set all internal component inputs from connected circuit inputs
315  for( unsigned short i = 0; i < _inToInWires.GetWireCount(); i++ )
316  {
317  wire = _inToInWires.GetWire( i );
318  signal = inputs.GetSignal( wire->fromSignalIndex );
319  wire->linkedComponent->SetInputSignal( wire->toSignalIndex, _currentThreadIndex, signal );
320  }
321 
322  _circuitThreads[_currentThreadIndex].Resume(); // resume thread x
323 
324  if( ++_currentThreadIndex >= _circuitThreads.size() ) // shift to thread x+1
325  {
326  _currentThreadIndex = 0;
327  }
328  }
329 }
330 
331 //=================================================================================================
332 
333 bool DspCircuit::_FindComponent( DspComponent* component, unsigned short& returnIndex ) const
334 {
335  for( unsigned short i = 0; i < _components.size(); i++ )
336  {
337  if( _components[i] == component )
338  {
339  returnIndex = i;
340  return true;
341  }
342  }
343 
344  return false;
345 }
346 
347 //-------------------------------------------------------------------------------------------------
348 
349 bool DspCircuit::_FindComponent( DspComponent& component, unsigned short& returnIndex ) const
350 {
351  return _FindComponent( &component, returnIndex );
352 }
353 
354 //-------------------------------------------------------------------------------------------------
355 
356 bool DspCircuit::_FindComponent( std::string componentName, unsigned short& returnIndex ) const
357 {
358  for( unsigned short i = 0; i < _components.size(); i++ )
359  {
360  if( _components[i]->GetComponentName() != "" && _components[i]->GetComponentName() == componentName )
361  {
362  returnIndex = i;
363  return true;
364  }
365  }
366 
367  return false;
368 }
369 
370 //-------------------------------------------------------------------------------------------------
371 
372 bool DspCircuit::_FindComponent( unsigned short componentIndex, unsigned short& returnIndex ) const
373 {
374  if( componentIndex < _components.size() )
375  {
376  returnIndex = componentIndex;
377  return true;
378  }
379 
380  return false;
381 }
382 
383 //-------------------------------------------------------------------------------------------------
384 
385 void DspCircuit::_DisconnectComponent( unsigned short componentIndex )
386 {
387  // remove component from _inputComponents and _inputWires
388  _components[ componentIndex ]->DisconnectInputs();
389 
390  // remove component from _inToInWires
391  DspWire* wire;
392  for( unsigned short i = 0; i < _inToInWires.GetWireCount(); i++ )
393  {
394  wire = _inToInWires.GetWire( i );
395  if( wire->linkedComponent == _components[ componentIndex ] )
396  {
397  _inToInWires.RemoveWire( i );
398  }
399  }
400 
401  // remove component from _outToOutWires
402  for( unsigned short i = 0; i < _outToOutWires.GetWireCount(); i++ )
403  {
404  wire = _outToOutWires.GetWire( i );
405  if( wire->linkedComponent == _components[ componentIndex ] )
406  {
407  _outToOutWires.RemoveWire( i );
408  }
409  }
410 }
411 
412 //-------------------------------------------------------------------------------------------------
413 
414 void DspCircuit::_RemoveComponent( unsigned short componentIndex )
415 {
416  _DisconnectComponent( componentIndex );
417 
418  // set the removed component's parent circuit to NULL
419  if( _components[componentIndex]->GetParentCircuit() != NULL )
420  {
421  _components[componentIndex]->SetParentCircuit( NULL );
422  }
423  // setting a component's parent to NULL (above) calls _RemoveComponent (hence the following code will run)
424  else if( _components.size() != 0 )
425  {
426  for( unsigned short i = componentIndex; i < _components.size() - 1; i++ )
427  {
428  _components[i] = _components[i + 1]; // shift all lower elements up
429  }
430 
431  _components.pop_back(); // remove end item
432  }
433 }
434 
435 //=================================================================================================