Merge lp:dspatch/2.70 into lp:dspatch

Proposed by Marcus Tomlinson
Status: Merged
Merged at revision: 24
Proposed branch: lp:dspatch/2.70
Merge into: lp:dspatch
Diff against target: 1273 lines (+707/-321)
20 files modified
.bzrignore (+3/-1)
CMakeLists.txt (+3/-7)
build.sh (+2/-2)
doc/Doxyfile (+1/-1)
example/CMakeLists.txt (+13/-3)
example/DspOscillator.cpp (+0/-223)
example/DspOscillator.h (+0/-71)
example/main.cpp (+15/-7)
example/oscillator-plugin/CMakeLists.txt (+20/-0)
example/oscillator-plugin/DspOscillator.cpp (+223/-0)
example/oscillator-plugin/DspOscillator.h (+105/-0)
include/DSPatch.h (+6/-0)
include/dspatch/DspPlugin.h (+95/-0)
include/dspatch/DspPluginLoader.h (+68/-0)
include/dspatch/DspThreadNull.h (+1/-1)
include/dspatch/DspThreadWin.h (+1/-1)
install.sh (+3/-3)
src/DspCircuit.cpp (+1/-1)
src/DspPlugin.cpp (+34/-0)
src/DspPluginLoader.cpp (+113/-0)
To merge this branch: bzr merge lp:dspatch/2.70
Reviewer Review Type Date Requested Status
Marcus Tomlinson Pending
Review via email: mp+245293@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2014-01-19 08:28:22 +0000
3+++ .bzrignore 2014-12-21 12:19:18 +0000
4@@ -1,2 +1,4 @@
5-*.user
6+./CMakeLists.txt.user
7 ./doc/html
8+./doc/doxygen_sqlite3.db
9+./build
10
11=== modified file 'CMakeLists.txt'
12--- CMakeLists.txt 2014-08-17 10:44:10 +0000
13+++ CMakeLists.txt 2014-12-21 12:19:18 +0000
14@@ -1,11 +1,6 @@
15 cmake_minimum_required(VERSION 2.8)
16
17-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -pthread")
18-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy")
19-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdisabled-optimization -Wformat=2 -Wlogical-op -Wmissing-declarations")
20-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-include-dirs -Woverloaded-virtual -Wredundant-decls -Winit-self")
21-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wreorder -Wno-vla")
22-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wswitch-default -Wno-unused -Wnon-virtual-dtor -Wshadow -Wnoexcept -Wabi")
23+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -pthread -pedantic -Wall -Wextra -Wnon-virtual-dtor")
24
25 project(DSPatch)
26
27@@ -25,11 +20,12 @@
28 ${in_hdrs}
29 )
30
31-# Link pthread on Unix
32+# Link pthread and dl on Unix
33 if(UNIX)
34 target_link_libraries(
35 ${PROJECT_NAME}
36 pthread
37+ dl
38 )
39 endif(UNIX)
40
41
42=== renamed file 'build' => 'build.sh'
43--- build 2014-02-02 16:21:18 +0000
44+++ build.sh 2014-12-21 12:19:18 +0000
45@@ -1,6 +1,6 @@
46 #!/bin/bash
47-src_dir=$(dirname ${BASH_SOURCE[0]})
48-build_dir=${src_dir}-build
49+src_dir=$(dirname $(readlink -f "$0"))
50+build_dir=${src_dir}/build
51
52 if [ -f "/usr/bin/ninja" ] ; then
53 GENERATOR="Ninja"
54
55=== modified file 'doc/Doxyfile'
56--- doc/Doxyfile 2014-08-17 10:44:10 +0000
57+++ doc/Doxyfile 2014-12-21 12:19:18 +0000
58@@ -32,7 +32,7 @@
59 # This could be handy for archiving the generated documentation or
60 # if some version control system is used.
61
62-PROJECT_NUMBER = v.2.62
63+PROJECT_NUMBER = v.2.70
64
65 # Using the PROJECT_BRIEF tag one can provide an optional one line description
66 # for a project that appears at the top of each page and should give viewer
67
68=== modified file 'example/CMakeLists.txt'
69--- example/CMakeLists.txt 2014-06-08 09:18:18 +0000
70+++ example/CMakeLists.txt 2014-12-21 12:19:18 +0000
71@@ -1,5 +1,7 @@
72 project(DSPatchExample)
73
74+add_subdirectory(oscillator-plugin)
75+
76 file(GLOB srcs *.cpp rtaudio/*.cpp)
77 file(GLOB hdrs *.h rtaudio/*.h)
78
79@@ -9,7 +11,7 @@
80 ${CMAKE_CURRENT_SOURCE_DIR}/rtaudio
81 )
82
83-# Add definition of example audio file
84+# Add definition for example audio file
85 add_definitions(-DEXAMPLE_WAV_FILE="${CMAKE_CURRENT_SOURCE_DIR}/Sample.wav")
86
87 add_executable(
88@@ -25,8 +27,9 @@
89
90 # Definition for RtAudio Windows, using direct sound
91 if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
92+ add_definitions(-DEXAMPLE_PLUGIN_FILE="${CMAKE_CURRENT_BINARY_DIR}/oscillator-plugin/$<CONFIGURATION>/DspOscillator.dll")
93 add_definitions(-D__WINDOWS_WASAPI__)
94-
95+
96 add_custom_command(
97 TARGET ${PROJECT_NAME} POST_BUILD
98 COMMAND ${CMAKE_COMMAND} -E copy_if_different
99@@ -37,16 +40,23 @@
100
101 # Definition for RtAudio Linux, using ALSA
102 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
103+ add_definitions(-DEXAMPLE_PLUGIN_FILE="${CMAKE_CURRENT_BINARY_DIR}/oscillator-plugin/libDspOscillator.so")
104 add_definitions(-D__LINUX_ALSA__)
105
106+ find_library(ASOUND asound)
107+ if(NOT ASOUND)
108+ message(FATAL_ERROR "ALSA not found (Ensure that libasound2-dev is installed)")
109+ endif()
110+
111 target_link_libraries(
112 ${PROJECT_NAME}
113- asound
114+ ${ASOUND}
115 )
116 endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
117
118 # Definition for RtAudio Mac OSX, using Core Audio
119 if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
120+ add_definitions(-DEXAMPLE_PLUGIN_FILE="${CMAKE_CURRENT_BINARY_DIR}/oscillator-plugin/$<CONFIGURATION>/libDspOscillator.dylib")
121 add_definitions(-D__MACOSX_CORE__)
122
123 target_link_libraries(
124
125=== removed file 'example/DspOscillator.cpp'
126--- example/DspOscillator.cpp 2014-08-17 08:07:56 +0000
127+++ example/DspOscillator.cpp 1970-01-01 00:00:00 +0000
128@@ -1,223 +0,0 @@
129-/************************************************************************
130-DSPatch - Cross-Platform, Object-Oriented, Flow-Based Programming Library
131-Copyright (c) 2012-2014 Marcus Tomlinson
132-
133-This file is part of DSPatch.
134-
135-GNU Lesser General Public License Usage
136-This file may be used under the terms of the GNU Lesser General Public
137-License version 3.0 as published by the Free Software Foundation and
138-appearing in the file LGPLv3.txt included in the packaging of this
139-file. Please review the following information to ensure the GNU Lesser
140-General Public License version 3.0 requirements will be met:
141-http://www.gnu.org/copyleft/lgpl.html.
142-
143-Other Usage
144-Alternatively, this file may be used in accordance with the terms and
145-conditions contained in a signed written agreement between you and
146-Marcus Tomlinson.
147-
148-DSPatch is distributed in the hope that it will be useful,
149-but WITHOUT ANY WARRANTY; without even the implied warranty of
150-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
151-************************************************************************/
152-
153-#include <DspOscillator.h>
154-
155-#include <math.h>
156-
157-//=================================================================================================
158-
159-static const float TWOPI = 6.283185307179586476925286766559f;
160-
161-std::string const DspOscillator::pBufferSize = "bufferSize";
162-std::string const DspOscillator::pSampleRate = "sampleRate";
163-std::string const DspOscillator::pAmplitude = "amplitude";
164-std::string const DspOscillator::pFrequency = "frequency";
165-
166-//=================================================================================================
167-
168-DspOscillator::DspOscillator( float startFreq, float startAmpl )
169-: _lastPos( 0 ),
170- _lookupLength( 0 )
171-{
172- AddInput_( "Sample Rate" );
173- AddInput_( "Buffer Size" );
174-
175- AddOutput_();
176-
177- AddParameter_( pBufferSize, DspParameter( DspParameter::Int, 256 ) );
178- AddParameter_( pSampleRate, DspParameter( DspParameter::Int, 44100 ) );
179- AddParameter_( pAmplitude, DspParameter( DspParameter::Float, startAmpl ) );
180- AddParameter_( pFrequency, DspParameter( DspParameter::Float, startFreq ) );
181-
182- _BuildLookup();
183-}
184-
185-//-------------------------------------------------------------------------------------------------
186-
187-DspOscillator::~DspOscillator() {}
188-
189-//=================================================================================================
190-
191-void DspOscillator::SetBufferSize( int bufferSize )
192-{
193- SetParameter_( pBufferSize, DspParameter( DspParameter::Int, bufferSize ) );
194-
195- _processMutex.Lock();
196- _BuildLookup();
197- _processMutex.Unlock();
198-}
199-
200-//-------------------------------------------------------------------------------------------------
201-
202-void DspOscillator::SetSampleRate( int sampleRate )
203-{
204- SetParameter_( pSampleRate, DspParameter( DspParameter::Int, sampleRate ) );
205-
206- _processMutex.Lock();
207- _BuildLookup();
208- _processMutex.Unlock();
209-}
210-
211-//-------------------------------------------------------------------------------------------------
212-
213-void DspOscillator::SetAmpl( float ampl )
214-{
215- SetParameter_( pAmplitude, DspParameter( DspParameter::Float, ampl ) );
216-
217- _processMutex.Lock();
218- _BuildLookup();
219- _processMutex.Unlock();
220-}
221-
222-//-------------------------------------------------------------------------------------------------
223-
224-void DspOscillator::SetFreq( float freq )
225-{
226- SetParameter_( pFrequency, DspParameter( DspParameter::Float, freq ) );
227-
228- _processMutex.Lock();
229- _BuildLookup();
230- _processMutex.Unlock();
231-}
232-
233-//-------------------------------------------------------------------------------------------------
234-
235-int DspOscillator::GetBufferSize() const
236-{
237- return *GetParameter_( pBufferSize )->GetInt();
238-}
239-
240-//-------------------------------------------------------------------------------------------------
241-
242-int DspOscillator::GetSampleRate() const
243-{
244- return *GetParameter_( pSampleRate )->GetInt();
245-}
246-
247-//-------------------------------------------------------------------------------------------------
248-
249-float DspOscillator::GetAmpl() const
250-{
251- return *GetParameter_( pAmplitude )->GetFloat();
252-}
253-
254-//-------------------------------------------------------------------------------------------------
255-
256-float DspOscillator::GetFreq() const
257-{
258- return *GetParameter_( pFrequency )->GetFloat();
259-}
260-
261-//=================================================================================================
262-
263-void DspOscillator::Process_( DspSignalBus& inputs, DspSignalBus& outputs )
264-{
265- // Synchronise sample rate with the "Sample Rate" input feed
266- // =========================================================
267- int sampleRate;
268- if( inputs.GetValue( "Sample Rate", sampleRate ) )
269- {
270- if( sampleRate != GetSampleRate() )
271- {
272- SetSampleRate( sampleRate );
273- }
274- }
275-
276- // Synchronise buffer size with the size of incoming buffers
277- // =========================================================
278- if( inputs.GetValue( "Buffer Size", _signal ) )
279- {
280- if( GetBufferSize() != (int) _signal.size() )
281- {
282- SetBufferSize( _signal.size() );
283- }
284- }
285-
286- _processMutex.Lock();
287-
288- if( _signalLookup.size() != 0 )
289- {
290- for( unsigned long i = 0; i < _signal.size(); i ++ )
291- {
292- if( _lastPos >= _lookupLength )
293- _lastPos = 0;
294- _signal[i] = _signalLookup[_lastPos++];
295- }
296-
297- outputs.SetValue( 0, _signal );
298- }
299-
300- _processMutex.Unlock();
301-}
302-
303-//-------------------------------------------------------------------------------------------------
304-
305-bool DspOscillator::ParameterUpdating_( std::string const& name, DspParameter const& param )
306-{
307- if( name == pBufferSize )
308- {
309- SetBufferSize( *param.GetInt() );
310- return true;
311- }
312- else if( name == pSampleRate )
313- {
314- SetSampleRate( *param.GetInt() );
315- return true;
316- }
317- else if( name == pAmplitude )
318- {
319- SetAmpl( *param.GetFloat() );
320- return true;
321- }
322- else if( name == pFrequency )
323- {
324- SetFreq( *param.GetFloat() );
325- return true;
326- }
327-
328- return false;
329-}
330-
331-//=================================================================================================
332-
333-void DspOscillator::_BuildLookup()
334-{
335- float posFrac = ( float ) _lastPos / ( float ) _lookupLength;
336- float angleInc = TWOPI * GetFreq() / GetSampleRate();
337-
338- _lookupLength = ( unsigned long ) ( ( float ) GetSampleRate() / GetFreq() );
339-
340- _signal.resize( GetBufferSize() );
341- _signalLookup.resize( _lookupLength );
342-
343- for( unsigned long i = 0; i < _lookupLength; i++ )
344- {
345- _signalLookup[i] = sin( angleInc * i ) * GetAmpl();
346- }
347-
348- _lastPos = ( unsigned long ) ( posFrac * ( float ) _lookupLength + 0.5f ); //calculate new position (round up)
349-}
350-
351-//=================================================================================================
352
353=== removed file 'example/DspOscillator.h'
354--- example/DspOscillator.h 2014-06-16 10:02:03 +0000
355+++ example/DspOscillator.h 1970-01-01 00:00:00 +0000
356@@ -1,71 +0,0 @@
357-/************************************************************************
358-DSPatch - Cross-Platform, Object-Oriented, Flow-Based Programming Library
359-Copyright (c) 2012-2014 Marcus Tomlinson
360-
361-This file is part of DSPatch.
362-
363-GNU Lesser General Public License Usage
364-This file may be used under the terms of the GNU Lesser General Public
365-License version 3.0 as published by the Free Software Foundation and
366-appearing in the file LGPLv3.txt included in the packaging of this
367-file. Please review the following information to ensure the GNU Lesser
368-General Public License version 3.0 requirements will be met:
369-http://www.gnu.org/copyleft/lgpl.html.
370-
371-Other Usage
372-Alternatively, this file may be used in accordance with the terms and
373-conditions contained in a signed written agreement between you and
374-Marcus Tomlinson.
375-
376-DSPatch is distributed in the hope that it will be useful,
377-but WITHOUT ANY WARRANTY; without even the implied warranty of
378-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
379-************************************************************************/
380-
381-#ifndef DSPOSCILLATOR_H
382-#define DSPOSCILLATOR_H
383-
384-#include <DSPatch.h>
385-
386-//=================================================================================================
387-
388-class DspOscillator : public DspComponent
389-{
390-public:
391- static std::string const pBufferSize; // Int
392- static std::string const pSampleRate; // Int
393- static std::string const pAmplitude; // Float
394- static std::string const pFrequency; // Float
395-
396- DspOscillator( float startFreq = 1000.0, float startAmpl = 1.0 );
397- ~DspOscillator();
398-
399- void SetBufferSize( int bufferSize );
400- void SetSampleRate( int sampleRate );
401- void SetAmpl( float ampl );
402- void SetFreq( float freq );
403-
404- int GetBufferSize() const;
405- int GetSampleRate() const;
406- float GetAmpl() const;
407- float GetFreq() const;
408-
409-protected:
410- virtual void Process_( DspSignalBus& inputs, DspSignalBus& outputs );
411- virtual bool ParameterUpdating_( std::string const& name, DspParameter const& param );
412-
413-private:
414- std::vector< float > _signalLookup;
415- std::vector< float > _signal;
416-
417- unsigned long _lastPos;
418- unsigned long _lookupLength;
419-
420- DspMutex _processMutex;
421-
422- void _BuildLookup();
423-};
424-
425-//=================================================================================================
426-
427-#endif /* DSPOSCILLATOR_H */
428
429=== modified file 'example/main.cpp'
430--- example/main.cpp 2014-06-16 15:31:48 +0000
431+++ example/main.cpp 2014-12-21 12:19:18 +0000
432@@ -27,7 +27,6 @@
433 #include <DspWaveStreamer.h>
434 #include <DspGain.h>
435 #include <DspAudioDevice.h>
436-#include <DspOscillator.h>
437 #include <DspAdder.h>
438
439 #include <stdio.h>
440@@ -73,7 +72,7 @@
441 circuit.ConnectOutToIn( gainRight, 0, audioDevice, 1 ); // gain right into audio device right channel
442
443 // set the gain of components gainLeft and gainRight (wave left and right channels)
444- gainLeft.SetGain( 0.75 );
445+ gainLeft.SetParameter( DspGain::pGain, DspParameter( DspParameter::Float, 0.75f ) ); // OR: gainLeft.SetGain( 0.75 );
446 gainRight.SetParameter( DspGain::pGain, DspParameter( DspParameter::Float, 0.75f ) ); // OR: gainRight.SetGain( 0.75 );
447
448 // load a wave into the wave streamer and start playing the track
449@@ -89,10 +88,16 @@
450 // pause the track
451 waveStreamer.Pause();
452
453- // A component input pin can only receive one signal at a time so an adders are required to combine the signals
454-
455- // declare components to be added to the circuit
456- DspOscillator oscillator( 1000.0f, 0.1f );
457+ // a component input pin can only receive one signal at a time so an adders are required to combine the signals
458+
459+ // load the oscillator plugin and create an instance of it
460+ DspPluginLoader oscillPlugin( EXAMPLE_PLUGIN_FILE );
461+ std::map< std::string, DspParameter > oscillParams = oscillPlugin.GetCreateParams();
462+ oscillParams[ "startFreq" ] = DspParameter( DspParameter::Float, 1000.0f );
463+ oscillParams[ "startAmpl" ] = DspParameter( DspParameter::Float, 0.1f );
464+ DspComponent* oscillator = oscillPlugin.Create( oscillParams );
465+
466+ // declare the rest of the components to be added to the circuit
467 DspAdder adder1;
468 DspAdder adder2;
469
470@@ -120,7 +125,7 @@
471 // 3. Overlay both streams
472 // =======================
473
474- // resume the track (via parameter)
475+ // resume the track
476 waveStreamer.Play();
477
478 // wait for key press
479@@ -129,6 +134,9 @@
480 // clean up DSPatch
481 DSPatch::Finalize();
482
483+ // clean up the oscillator pointer
484+ delete oscillator;
485+
486 return 0;
487 }
488
489
490=== added directory 'example/oscillator-plugin'
491=== added file 'example/oscillator-plugin/CMakeLists.txt'
492--- example/oscillator-plugin/CMakeLists.txt 1970-01-01 00:00:00 +0000
493+++ example/oscillator-plugin/CMakeLists.txt 2014-12-21 12:19:18 +0000
494@@ -0,0 +1,20 @@
495+project(DspOscillator)
496+
497+file(GLOB srcs *.cpp)
498+file(GLOB hdrs *.h)
499+
500+include_directories(
501+ ${CMAKE_SOURCE_DIR}/include
502+ ${CMAKE_CURRENT_SOURCE_DIR}
503+)
504+
505+add_library(
506+ ${PROJECT_NAME} SHARED
507+ ${srcs}
508+ ${hdrs}
509+)
510+
511+target_link_libraries(
512+ ${PROJECT_NAME}
513+ DSPatch
514+)
515
516=== added file 'example/oscillator-plugin/DspOscillator.cpp'
517--- example/oscillator-plugin/DspOscillator.cpp 1970-01-01 00:00:00 +0000
518+++ example/oscillator-plugin/DspOscillator.cpp 2014-12-21 12:19:18 +0000
519@@ -0,0 +1,223 @@
520+/************************************************************************
521+DSPatch - Cross-Platform, Object-Oriented, Flow-Based Programming Library
522+Copyright (c) 2012-2014 Marcus Tomlinson
523+
524+This file is part of DSPatch.
525+
526+GNU Lesser General Public License Usage
527+This file may be used under the terms of the GNU Lesser General Public
528+License version 3.0 as published by the Free Software Foundation and
529+appearing in the file LGPLv3.txt included in the packaging of this
530+file. Please review the following information to ensure the GNU Lesser
531+General Public License version 3.0 requirements will be met:
532+http://www.gnu.org/copyleft/lgpl.html.
533+
534+Other Usage
535+Alternatively, this file may be used in accordance with the terms and
536+conditions contained in a signed written agreement between you and
537+Marcus Tomlinson.
538+
539+DSPatch is distributed in the hope that it will be useful,
540+but WITHOUT ANY WARRANTY; without even the implied warranty of
541+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
542+************************************************************************/
543+
544+#include <DspOscillator.h>
545+
546+#include <math.h>
547+
548+//=================================================================================================
549+
550+static const float TWOPI = 6.283185307179586476925286766559f;
551+
552+std::string const DspOscillator::pBufferSize = "bufferSize";
553+std::string const DspOscillator::pSampleRate = "sampleRate";
554+std::string const DspOscillator::pAmplitude = "amplitude";
555+std::string const DspOscillator::pFrequency = "frequency";
556+
557+//=================================================================================================
558+
559+DspOscillator::DspOscillator( float startFreq, float startAmpl )
560+: _lastPos( 0 ),
561+ _lookupLength( 0 )
562+{
563+ AddInput_( "Sample Rate" );
564+ AddInput_( "Buffer Size" );
565+
566+ AddOutput_();
567+
568+ AddParameter_( pBufferSize, DspParameter( DspParameter::Int, 256 ) );
569+ AddParameter_( pSampleRate, DspParameter( DspParameter::Int, 44100 ) );
570+ AddParameter_( pAmplitude, DspParameter( DspParameter::Float, startAmpl ) );
571+ AddParameter_( pFrequency, DspParameter( DspParameter::Float, startFreq ) );
572+
573+ _BuildLookup();
574+}
575+
576+//-------------------------------------------------------------------------------------------------
577+
578+DspOscillator::~DspOscillator() {}
579+
580+//=================================================================================================
581+
582+void DspOscillator::SetBufferSize( int bufferSize )
583+{
584+ SetParameter_( pBufferSize, DspParameter( DspParameter::Int, bufferSize ) );
585+
586+ _processMutex.Lock();
587+ _BuildLookup();
588+ _processMutex.Unlock();
589+}
590+
591+//-------------------------------------------------------------------------------------------------
592+
593+void DspOscillator::SetSampleRate( int sampleRate )
594+{
595+ SetParameter_( pSampleRate, DspParameter( DspParameter::Int, sampleRate ) );
596+
597+ _processMutex.Lock();
598+ _BuildLookup();
599+ _processMutex.Unlock();
600+}
601+
602+//-------------------------------------------------------------------------------------------------
603+
604+void DspOscillator::SetAmpl( float ampl )
605+{
606+ SetParameter_( pAmplitude, DspParameter( DspParameter::Float, ampl ) );
607+
608+ _processMutex.Lock();
609+ _BuildLookup();
610+ _processMutex.Unlock();
611+}
612+
613+//-------------------------------------------------------------------------------------------------
614+
615+void DspOscillator::SetFreq( float freq )
616+{
617+ SetParameter_( pFrequency, DspParameter( DspParameter::Float, freq ) );
618+
619+ _processMutex.Lock();
620+ _BuildLookup();
621+ _processMutex.Unlock();
622+}
623+
624+//-------------------------------------------------------------------------------------------------
625+
626+int DspOscillator::GetBufferSize() const
627+{
628+ return *GetParameter_( pBufferSize )->GetInt();
629+}
630+
631+//-------------------------------------------------------------------------------------------------
632+
633+int DspOscillator::GetSampleRate() const
634+{
635+ return *GetParameter_( pSampleRate )->GetInt();
636+}
637+
638+//-------------------------------------------------------------------------------------------------
639+
640+float DspOscillator::GetAmpl() const
641+{
642+ return *GetParameter_( pAmplitude )->GetFloat();
643+}
644+
645+//-------------------------------------------------------------------------------------------------
646+
647+float DspOscillator::GetFreq() const
648+{
649+ return *GetParameter_( pFrequency )->GetFloat();
650+}
651+
652+//=================================================================================================
653+
654+void DspOscillator::Process_( DspSignalBus& inputs, DspSignalBus& outputs )
655+{
656+ // Synchronise sample rate with the "Sample Rate" input feed
657+ // =========================================================
658+ int sampleRate;
659+ if( inputs.GetValue( "Sample Rate", sampleRate ) )
660+ {
661+ if( sampleRate != GetSampleRate() )
662+ {
663+ SetSampleRate( sampleRate );
664+ }
665+ }
666+
667+ // Synchronise buffer size with the size of incoming buffers
668+ // =========================================================
669+ if( inputs.GetValue( "Buffer Size", _signal ) )
670+ {
671+ if( GetBufferSize() != ( int ) _signal.size() )
672+ {
673+ SetBufferSize( _signal.size() );
674+ }
675+ }
676+
677+ _processMutex.Lock();
678+
679+ if( _signalLookup.size() != 0 )
680+ {
681+ for( unsigned long i = 0; i < _signal.size(); i ++ )
682+ {
683+ if( _lastPos >= _lookupLength )
684+ _lastPos = 0;
685+ _signal[i] = _signalLookup[_lastPos++];
686+ }
687+
688+ outputs.SetValue( 0, _signal );
689+ }
690+
691+ _processMutex.Unlock();
692+}
693+
694+//-------------------------------------------------------------------------------------------------
695+
696+bool DspOscillator::ParameterUpdating_( std::string const& name, DspParameter const& param )
697+{
698+ if( name == pBufferSize )
699+ {
700+ SetBufferSize( *param.GetInt() );
701+ return true;
702+ }
703+ else if( name == pSampleRate )
704+ {
705+ SetSampleRate( *param.GetInt() );
706+ return true;
707+ }
708+ else if( name == pAmplitude )
709+ {
710+ SetAmpl( *param.GetFloat() );
711+ return true;
712+ }
713+ else if( name == pFrequency )
714+ {
715+ SetFreq( *param.GetFloat() );
716+ return true;
717+ }
718+
719+ return false;
720+}
721+
722+//=================================================================================================
723+
724+void DspOscillator::_BuildLookup()
725+{
726+ float posFrac = ( float ) _lastPos / ( float ) _lookupLength;
727+ float angleInc = TWOPI * GetFreq() / GetSampleRate();
728+
729+ _lookupLength = ( unsigned long ) ( ( float ) GetSampleRate() / GetFreq() );
730+
731+ _signal.resize( GetBufferSize() );
732+ _signalLookup.resize( _lookupLength );
733+
734+ for( unsigned long i = 0; i < _lookupLength; i++ )
735+ {
736+ _signalLookup[i] = sin( angleInc * i ) * GetAmpl();
737+ }
738+
739+ _lastPos = ( unsigned long ) ( posFrac * ( float ) _lookupLength + 0.5f ); //calculate new position (round up)
740+}
741+
742+//=================================================================================================
743
744=== added file 'example/oscillator-plugin/DspOscillator.h'
745--- example/oscillator-plugin/DspOscillator.h 1970-01-01 00:00:00 +0000
746+++ example/oscillator-plugin/DspOscillator.h 2014-12-21 12:19:18 +0000
747@@ -0,0 +1,105 @@
748+/************************************************************************
749+DSPatch - Cross-Platform, Object-Oriented, Flow-Based Programming Library
750+Copyright (c) 2012-2014 Marcus Tomlinson
751+
752+This file is part of DSPatch.
753+
754+GNU Lesser General Public License Usage
755+This file may be used under the terms of the GNU Lesser General Public
756+License version 3.0 as published by the Free Software Foundation and
757+appearing in the file LGPLv3.txt included in the packaging of this
758+file. Please review the following information to ensure the GNU Lesser
759+General Public License version 3.0 requirements will be met:
760+http://www.gnu.org/copyleft/lgpl.html.
761+
762+Other Usage
763+Alternatively, this file may be used in accordance with the terms and
764+conditions contained in a signed written agreement between you and
765+Marcus Tomlinson.
766+
767+DSPatch is distributed in the hope that it will be useful,
768+but WITHOUT ANY WARRANTY; without even the implied warranty of
769+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
770+************************************************************************/
771+
772+#ifndef DSPOSCILLATOR_H
773+#define DSPOSCILLATOR_H
774+
775+#include <DSPatch.h>
776+
777+//=================================================================================================
778+
779+class DspOscillator : public DspComponent
780+{
781+public:
782+ static std::string const pBufferSize; // Int
783+ static std::string const pSampleRate; // Int
784+ static std::string const pAmplitude; // Float
785+ static std::string const pFrequency; // Float
786+
787+ DspOscillator( float startFreq = 1000.0, float startAmpl = 1.0 );
788+ ~DspOscillator();
789+
790+ void SetBufferSize( int bufferSize );
791+ void SetSampleRate( int sampleRate );
792+ void SetAmpl( float ampl );
793+ void SetFreq( float freq );
794+
795+ int GetBufferSize() const;
796+ int GetSampleRate() const;
797+ float GetAmpl() const;
798+ float GetFreq() const;
799+
800+protected:
801+ virtual void Process_( DspSignalBus& inputs, DspSignalBus& outputs );
802+ virtual bool ParameterUpdating_( std::string const& name, DspParameter const& param );
803+
804+private:
805+ std::vector< float > _signalLookup;
806+ std::vector< float > _signal;
807+
808+ unsigned long _lastPos;
809+ unsigned long _lookupLength;
810+
811+ DspMutex _processMutex;
812+
813+ void _BuildLookup();
814+};
815+
816+//=================================================================================================
817+
818+class DspOscillatorPlugin : public DspPlugin
819+{
820+ std::map< std::string, DspParameter > GetCreateParams() const
821+ {
822+ std::map< std::string, DspParameter > params;
823+ params[ "startFreq" ] = DspParameter( DspParameter::Float );
824+ params[ "startAmpl" ] = DspParameter( DspParameter::Float, 1.0f, std::make_pair( 0.0f, 1.0f ) );
825+ return params;
826+ }
827+
828+ DspComponent* Create( std::map< std::string, DspParameter >& params ) const
829+ {
830+ float const* startFreq = params[ "startFreq" ].GetFloat();
831+ float const* startAmpl = params[ "startAmpl" ].GetFloat();
832+
833+ if( startFreq && startAmpl )
834+ {
835+ return new DspOscillator( *startFreq, *startAmpl );
836+ }
837+ else if( startFreq && !startAmpl )
838+ {
839+ return new DspOscillator( *startFreq );
840+ }
841+ else
842+ {
843+ return new DspOscillator();
844+ }
845+ }
846+};
847+
848+EXPORT_DSPPLUGIN( DspOscillatorPlugin )
849+
850+//=================================================================================================
851+
852+#endif /* DSPOSCILLATOR_H */
853
854=== modified file 'include/DSPatch.h'
855--- include/DSPatch.h 2014-08-18 16:44:09 +0000
856+++ include/DSPatch.h 2014-12-21 12:19:18 +0000
857@@ -28,6 +28,7 @@
858 //-------------------------------------------------------------------------------------------------
859
860 #include <dspatch/DspCircuit.h>
861+#include <dspatch/DspPluginLoader.h>
862
863 //=================================================================================================
864 /// System-wide DSPatch functionality
865@@ -106,6 +107,7 @@
866
867 \section features_sec Features
868 - <b>Automatic branch synchronization</b> - The result of data diverging across parallel branches is guaranteed to arrive synchronized at a converging point.
869+ - <b>Component plugins</b> - Package components into plugins to be dynamically loaded into DSPatch host applications.
870 - <b>Dynamic thread count adjustment</b> - Specify at run-time, the number of threads in which you require a circuit to process.
871 - <b>Easy-to-use object-oriented API</b> - DSPatch is modeled around real-world circuit entities and concepts, making code more readable and easy to understand.
872 - <b>Feedback loops</b> - Create true closed-circuit systems by feeding resultant signals back into previous component inputs.
873@@ -372,6 +374,10 @@
874
875 \section changelog Changelog
876
877+\subsection v270 v.2.70 (21 December 2014)
878+ - Added support for DspComponent plugins (DspPlugin + DspPluginLoader).
879+ - Fixed build and install scripts.
880+
881 \subsection v262 v.2.62 (18 August 2014)
882 - Added alternative Get* methods returning const pointers.
883 - Increased build warning level and fixed all issues.
884
885=== added file 'include/dspatch/DspPlugin.h'
886--- include/dspatch/DspPlugin.h 1970-01-01 00:00:00 +0000
887+++ include/dspatch/DspPlugin.h 2014-12-21 12:19:18 +0000
888@@ -0,0 +1,95 @@
889+/************************************************************************
890+DSPatch - Cross-Platform, Object-Oriented, Flow-Based Programming Library
891+Copyright (c) 2012-2014 Marcus Tomlinson
892+
893+This file is part of DSPatch.
894+
895+GNU Lesser General Public License Usage
896+This file may be used under the terms of the GNU Lesser General Public
897+License version 3.0 as published by the Free Software Foundation and
898+appearing in the file LGPLv3.txt included in the packaging of this
899+file. Please review the following information to ensure the GNU Lesser
900+General Public License version 3.0 requirements will be met:
901+http://www.gnu.org/copyleft/lgpl.html.
902+
903+Other Usage
904+Alternatively, this file may be used in accordance with the terms and
905+conditions contained in a signed written agreement between you and
906+Marcus Tomlinson.
907+
908+DSPatch is distributed in the hope that it will be useful,
909+but WITHOUT ANY WARRANTY; without even the implied warranty of
910+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
911+************************************************************************/
912+
913+#ifndef DSPPLUGIN_H
914+#define DSPPLUGIN_H
915+
916+//-------------------------------------------------------------------------------------------------
917+
918+#include <dspatch/DspComponent.h>
919+
920+#include <map>
921+#include <string>
922+
923+//=================================================================================================
924+/// Abstract base class for DspComponent plugins
925+
926+/**
927+A DspComponent can be packaged into a shared library (.so / .dylib / .dll) and dynamically loaded
928+from a DSPatch application at runtime. This allows DSPatch applications and components to be built
929+and released independently of each other, resulting in a highly flexible developer (and end-user)
930+experience. Now, in order for a DspComponent to be packaged into a plugin (shared library), the
931+plugin needs to expose some details about itself to the outside world. This is achieved via the
932+DspPlugin abstract base class.
933+
934+A DspComponent plugin project must contain 2 classes: 1. A class derived from DspComponent that
935+implements the component logic, and 2. A class derived from DspPlugin that implements the component
936+construction logic.
937+
938+Classes derived from DspPlugin must (at least) implement the pure virtual method: Create(). If the
939+DspComponent does not require any construction parameters, Create() should simply return a pointer
940+to a new instantiation of that DspComponent. If a DspComponent does require construction parameters
941+to be instantiated, the derived class must also implement the virtual GetCreateParams() method.
942+This method should return a map of parameter name-to-DspParameter pairs. The plugin host can then
943+assign values to this parameter map and return them via the Create() call.
944+
945+Once both DspComponent and DspPlugin classes have been implemented, add the line
946+"EXPORT_DSPPLUGIN( MyPlugin )" anywhere after the declaration of your DspPlugin class, where
947+"MyPlugin" is the name of your DspPlugin class. Then compile the project into a shared library.
948+
949+The plugin is now ready to be loaded into a DSPatch host application (see DspPluginLoader).
950+*/
951+
952+class DLLEXPORT DspPlugin
953+{
954+public:
955+ virtual ~DspPlugin() {}
956+ virtual std::map< std::string, DspParameter > GetCreateParams() const;
957+ virtual DspComponent* Create( std::map< std::string, DspParameter >& params ) const = 0;
958+};
959+
960+//=================================================================================================
961+
962+#define EXPORT_DSPPLUGIN( Plugin )\
963+extern "C"\
964+{\
965+ DLLEXPORT std::map< std::string, DspParameter > GetCreateParams()\
966+ {\
967+ DspPlugin* plugin = new Plugin();\
968+ std::map< std::string, DspParameter > params = plugin->GetCreateParams();\
969+ delete plugin;\
970+ return params;\
971+ }\
972+ DLLEXPORT DspComponent* Create( std::map< std::string, DspParameter >& params )\
973+ {\
974+ DspPlugin* plugin = new Plugin();\
975+ DspComponent* component = plugin->Create( params );\
976+ delete plugin;\
977+ return component;\
978+ }\
979+}
980+
981+//=================================================================================================
982+
983+#endif // DSPPLUGIN_H
984
985=== added file 'include/dspatch/DspPluginLoader.h'
986--- include/dspatch/DspPluginLoader.h 1970-01-01 00:00:00 +0000
987+++ include/dspatch/DspPluginLoader.h 2014-12-21 12:19:18 +0000
988@@ -0,0 +1,68 @@
989+/************************************************************************
990+DSPatch - Cross-Platform, Object-Oriented, Flow-Based Programming Library
991+Copyright (c) 2012-2014 Marcus Tomlinson
992+
993+This file is part of DSPatch.
994+
995+GNU Lesser General Public License Usage
996+This file may be used under the terms of the GNU Lesser General Public
997+License version 3.0 as published by the Free Software Foundation and
998+appearing in the file LGPLv3.txt included in the packaging of this
999+file. Please review the following information to ensure the GNU Lesser
1000+General Public License version 3.0 requirements will be met:
1001+http://www.gnu.org/copyleft/lgpl.html.
1002+
1003+Other Usage
1004+Alternatively, this file may be used in accordance with the terms and
1005+conditions contained in a signed written agreement between you and
1006+Marcus Tomlinson.
1007+
1008+DSPatch is distributed in the hope that it will be useful,
1009+but WITHOUT ANY WARRANTY; without even the implied warranty of
1010+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1011+************************************************************************/
1012+
1013+#ifndef DSPPLUGINLOADER_H
1014+#define DSPPLUGINLOADER_H
1015+
1016+//-------------------------------------------------------------------------------------------------
1017+
1018+#include <dspatch/DspPlugin.h>
1019+
1020+//=================================================================================================
1021+/// Plugin loader for DspPlugin host applications
1022+
1023+/**
1024+A DspComponent packaged into a shared library (.so / .dylib / .dll) and exported via the DspPlugin
1025+class can be dynamically loaded from a DSPatch application at runtime using a DspPluginLoader. A
1026+DspPluginLoader represents exactly one DspPlugin in a host application.
1027+
1028+A DspPluginLoader should be constructed with the absolute path of the plugin (shared library) to be
1029+loaded. Once instantiated you should check that the plugin was successfully loaded by calling
1030+IsLoaded(). Thereafter, the contained DspComponent can be instantiated via the GetCreateParams()
1031+and Create() methods accordingly (For more detail on the structure of a plugin, see DspPlugin).
1032+*/
1033+
1034+class DLLEXPORT DspPluginLoader : public DspPlugin
1035+{
1036+public:
1037+ DspPluginLoader( std::string const& pluginPath );
1038+ ~DspPluginLoader();
1039+
1040+ bool IsLoaded() const;
1041+
1042+ std::map< std::string, DspParameter > GetCreateParams() const;
1043+ DspComponent* Create( std::map< std::string, DspParameter >& params ) const;
1044+
1045+private:
1046+ typedef std::map< std::string, DspParameter >( *GetCreateParams_t )();
1047+ typedef DspComponent*( *Create_t )( std::map< std::string, DspParameter >& );
1048+
1049+ void* _handle;
1050+ GetCreateParams_t _getCreateParams;
1051+ Create_t _create;
1052+};
1053+
1054+//=================================================================================================
1055+
1056+#endif // DSPPLUGINLOADER_H
1057
1058=== modified file 'include/dspatch/DspThreadNull.h'
1059--- include/dspatch/DspThreadNull.h 2014-04-07 16:39:53 +0000
1060+++ include/dspatch/DspThreadNull.h 2014-12-21 12:19:18 +0000
1061@@ -55,7 +55,7 @@
1062 HighPriority,
1063 HighestPriority,
1064
1065- TimeCriticalPriority,
1066+ TimeCriticalPriority
1067 };
1068
1069 virtual void Start( Priority priority ) {}
1070
1071=== modified file 'include/dspatch/DspThreadWin.h'
1072--- include/dspatch/DspThreadWin.h 2014-04-08 13:23:50 +0000
1073+++ include/dspatch/DspThreadWin.h 2014-12-21 12:19:18 +0000
1074@@ -55,7 +55,7 @@
1075 HighPriority = 1,
1076 HighestPriority = 2,
1077
1078- TimeCriticalPriority = 15,
1079+ TimeCriticalPriority = 15
1080 };
1081
1082 virtual void Start( Priority priority = NormalPriority )
1083
1084=== renamed file 'install' => 'install.sh'
1085--- install 2014-02-02 16:21:18 +0000
1086+++ install.sh 2014-12-21 12:19:18 +0000
1087@@ -1,6 +1,6 @@
1088 #!/bin/bash
1089-src_dir=$(dirname ${BASH_SOURCE[0]})
1090-build_dir=${src_dir}-build
1091+src_dir=$(dirname $(readlink -f "$0"))
1092+build_dir=${src_dir}/build
1093
1094 if [ -f "/usr/bin/ninja" ] ; then
1095 BUILD_COMMAND="ninja"
1096@@ -8,6 +8,6 @@
1097 BUILD_COMMAND="make"
1098 fi
1099
1100-${src_dir}/build
1101+${src_dir}/build.sh
1102 cd ${build_dir}
1103 sudo ${BUILD_COMMAND} install
1104
1105=== modified file 'src/DspCircuit.cpp'
1106--- src/DspCircuit.cpp 2014-06-14 15:35:42 +0000
1107+++ src/DspCircuit.cpp 2014-12-21 12:19:18 +0000
1108@@ -111,7 +111,7 @@
1109
1110 bool DspCircuit::AddComponent( DspComponent* component, std::string const& componentName )
1111 {
1112- if( component != this )
1113+ if( component != this && component != NULL )
1114 {
1115 std::string compName = componentName;
1116
1117
1118=== added file 'src/DspPlugin.cpp'
1119--- src/DspPlugin.cpp 1970-01-01 00:00:00 +0000
1120+++ src/DspPlugin.cpp 2014-12-21 12:19:18 +0000
1121@@ -0,0 +1,34 @@
1122+/************************************************************************
1123+DSPatch - Cross-Platform, Object-Oriented, Flow-Based Programming Library
1124+Copyright (c) 2012-2014 Marcus Tomlinson
1125+
1126+This file is part of DSPatch.
1127+
1128+GNU Lesser General Public License Usage
1129+This file may be used under the terms of the GNU Lesser General Public
1130+License version 3.0 as published by the Free Software Foundation and
1131+appearing in the file LGPLv3.txt included in the packaging of this
1132+file. Please review the following information to ensure the GNU Lesser
1133+General Public License version 3.0 requirements will be met:
1134+http://www.gnu.org/copyleft/lgpl.html.
1135+
1136+Other Usage
1137+Alternatively, this file may be used in accordance with the terms and
1138+conditions contained in a signed written agreement between you and
1139+Marcus Tomlinson.
1140+
1141+DSPatch is distributed in the hope that it will be useful,
1142+but WITHOUT ANY WARRANTY; without even the implied warranty of
1143+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1144+************************************************************************/
1145+
1146+#include <dspatch/DspPlugin.h>
1147+
1148+//=================================================================================================
1149+
1150+std::map< std::string, DspParameter > DspPlugin::GetCreateParams() const
1151+{
1152+ return std::map< std::string, DspParameter >();
1153+}
1154+
1155+//=================================================================================================
1156
1157=== added file 'src/DspPluginLoader.cpp'
1158--- src/DspPluginLoader.cpp 1970-01-01 00:00:00 +0000
1159+++ src/DspPluginLoader.cpp 2014-12-21 12:19:18 +0000
1160@@ -0,0 +1,113 @@
1161+/************************************************************************
1162+DSPatch - Cross-Platform, Object-Oriented, Flow-Based Programming Library
1163+Copyright (c) 2012-2014 Marcus Tomlinson
1164+
1165+This file is part of DSPatch.
1166+
1167+GNU Lesser General Public License Usage
1168+This file may be used under the terms of the GNU Lesser General Public
1169+License version 3.0 as published by the Free Software Foundation and
1170+appearing in the file LGPLv3.txt included in the packaging of this
1171+file. Please review the following information to ensure the GNU Lesser
1172+General Public License version 3.0 requirements will be met:
1173+http://www.gnu.org/copyleft/lgpl.html.
1174+
1175+Other Usage
1176+Alternatively, this file may be used in accordance with the terms and
1177+conditions contained in a signed written agreement between you and
1178+Marcus Tomlinson.
1179+
1180+DSPatch is distributed in the hope that it will be useful,
1181+but WITHOUT ANY WARRANTY; without even the implied warranty of
1182+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1183+************************************************************************/
1184+
1185+#include <dspatch/DspPluginLoader.h>
1186+
1187+#ifdef _WIN32
1188+ #include <windows.h>
1189+#else
1190+ #include <dlfcn.h>
1191+#endif
1192+
1193+//=================================================================================================
1194+
1195+DspPluginLoader::DspPluginLoader( std::string const& pluginPath )
1196+ : _handle( NULL )
1197+{
1198+ // open library
1199+ #ifdef _WIN32
1200+ _handle = LoadLibrary( pluginPath.c_str() );
1201+ #else
1202+ _handle = dlopen( pluginPath.c_str(), RTLD_NOW );
1203+ #endif
1204+
1205+ if( _handle )
1206+ {
1207+ // load symbols
1208+ #ifdef _WIN32
1209+ _getCreateParams = ( GetCreateParams_t ) GetProcAddress( ( HMODULE ) _handle, "GetCreateParams" );
1210+ _create = ( Create_t ) GetProcAddress( ( HMODULE ) _handle, "Create" );
1211+ #else
1212+ _getCreateParams = ( GetCreateParams_t ) dlsym( _handle, "GetCreateParams" );
1213+ _create = ( Create_t ) dlsym( _handle, "Create" );
1214+ #endif
1215+
1216+ if( !_getCreateParams || !_create )
1217+ {
1218+ #ifdef _WIN32
1219+ FreeLibrary( ( HMODULE ) _handle );
1220+ #else
1221+ dlclose( _handle );
1222+ #endif
1223+
1224+ _handle = NULL;
1225+ }
1226+ }
1227+}
1228+
1229+//-------------------------------------------------------------------------------------------------
1230+
1231+DspPluginLoader::~DspPluginLoader()
1232+{
1233+ // close library
1234+ if( _handle )
1235+ {
1236+ #ifdef _WIN32
1237+ FreeLibrary( ( HMODULE ) _handle );
1238+ #else
1239+ dlclose( _handle );
1240+ #endif
1241+ }
1242+}
1243+
1244+//=================================================================================================
1245+
1246+bool DspPluginLoader::IsLoaded() const
1247+{
1248+ return _handle ? true : false;
1249+}
1250+
1251+//-------------------------------------------------------------------------------------------------
1252+
1253+std::map< std::string, DspParameter > DspPluginLoader::GetCreateParams() const
1254+{
1255+ if( _handle )
1256+ {
1257+ return _getCreateParams();
1258+ }
1259+ return std::map< std::string, DspParameter >();
1260+}
1261+
1262+//-------------------------------------------------------------------------------------------------
1263+
1264+DspComponent* DspPluginLoader::Create( std::map< std::string, DspParameter >& params ) const
1265+{
1266+ if( _handle )
1267+ {
1268+ return _create( params );
1269+ }
1270+ return NULL;
1271+}
1272+
1273+//=================================================================================================

Subscribers

People subscribed via source and target branches

to all changes: