Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / HelpSource / Guides / WritingUGens.schelp
blobb810418f855faf00627050943f2d8c32a543e7df
1 title:: Writing Unit Generators
2 summary:: Get started with writing unit generators
3 categories:: Internals
5 section:: How Unit Generator plug-ins work.
7 The server loads unit generator plug-ins when it starts up. Unit Generator plug-ins are dynamically loaded libraries
8 written in C++. Each library may contain one or multiple unit generator definitions. A plug-in can also define things
9 other than unit generators such as buffer fill ("/b_gen") commands. Plug-ins are loaded during the startup of the
10 synthesis server. Therefore the server will have to be restarted after (re-)compiling the plugin.
13 section:: The Entry Point
15 When the library is loaded the server calls a function in the library, which is defined by the code::PluginLoad()::
16 macro.  This entry point has two responsibilities:
18 list::
19 ## It needs to store the passed in pointer to the InterfaceTable in a global variable.
20 ## It registers the unit generators.
23 Unit Generators are defined by calling a function in the InterfaceTable and passing it the name of the unit generator,
24 the size of its C data struct, and pointers to functions for constructing and destructing it. There are 4 macros, which
25 can be used to simplify the process.
27 definitionList::
28 ## DefineSimpleUnit || Define a `simple' unit generator
29 ## DefineDtorUnit || Define a unit generator with a descructor
30 ## DefineSimpleCantAliasUnit || Define a `simple' unit generator, whose input and output buffers cannot alias
31 ## DefineDtorCantAliasUnit || Define a unit generator with a destructor, whose input and output buffers cannot alias
34 These macros depend on a specific naming convention:
35 list::
36 ## The unit generator struct is named like the plug-in.
37 ## The unit generator constructor is named code::PluginName_Ctor::
38 ## The unit generator destructor is named code::PluginName_Dtor::
42 section:: A Simple Unit Generator Plugin
44 Unit generator plugins require two parts: A C++ part, which implements the server-side code that is loaded as a
45 dynamically loaded library, and an SCLang class, that is required to build the link::Classes/SynthDef::. The following
46 example implements a simple Sawtooth oscillator
48 subsection:: C++-side Definition of Unit Generators
50 The following code shows the C++ source of a simple unit generator.
52 code::
53 #include "SC_Plugin.h"
55 // InterfaceTable contains pointers to functions in the host (server).
56 static InterfaceTable *ft;
58 // declare struct to hold unit generator state
59 struct MySaw : public Unit
61         double mPhase; // phase of the oscillator, from -1 to 1.
62         float mFreqMul; // a constant for multiplying frequency
65 // declare unit generator functions
66 static void MySaw_next_a(MySaw *unit, int inNumSamples);
67 static void MySaw_next_k(MySaw *unit, int inNumSamples);
68 static void MySaw_Ctor(MySaw* unit);
71 //////////////////////////////////////////////////////////////////
73 // Ctor is called to initialize the unit generator.
74 // It only executes once.
76 // A Ctor usually does 3 things.
77 // 1. set the calculation function.
78 // 2. initialize the unit generator state variables.
79 // 3. calculate one sample of output.
80 void MySaw_Ctor(MySaw* unit)
82         // 1. set the calculation function.
83         if (INRATE(0) == calc_FullRate) {
84                 // if the frequency argument is audio rate
85                 SETCALC(MySaw_next_a);
86         } else {
87                 // if the frequency argument is control rate (or a scalar).
88                 SETCALC(MySaw_next_k);
89         }
91         // 2. initialize the unit generator state variables.
92         // initialize a constant for multiplying the frequency
93         unit->mFreqMul = 2.0 * SAMPLEDUR;
94         // get initial phase of oscillator
95         unit->mPhase = IN0(1);
97         // 3. calculate one sample of output.
98         MySaw_next_k(unit, 1);
102 //////////////////////////////////////////////////////////////////
104 // The calculation function executes once per control period
105 // which is typically 64 samples.
107 // calculation function for an audio rate frequency argument
108 void MySaw_next_a(MySaw *unit, int inNumSamples)
110         // get the pointer to the output buffer
111         float *out = OUT(0);
113         // get the pointer to the input buffer
114         float *freq = IN(0);
116         // get phase and freqmul constant from struct and store it in a
117         // local variable.
118         // The optimizer will cause them to be loaded it into a register.
119         float freqmul = unit->mFreqMul;
120         double phase = unit->mPhase;
122         // perform a loop for the number of samples in the control period.
123         // If this unit is audio rate then inNumSamples will be 64 or whatever
124         // the block size is. If this unit is control rate then inNumSamples will
125         // be 1.
126         for (int i=0; i < inNumSamples; ++i)
127         {
128                 // out must be written last for in place operation
129                 float z = phase;
130                 phase += freq[i] * freqmul;
132                 // these if statements wrap the phase a +1 or -1.
133                 if (phase >= 1.f) phase -= 2.f;
134                 else if (phase <= -1.f) phase += 2.f;
136                 // write the output
137                 out[i] = z;
138         }
140         // store the phase back to the struct
141         unit->mPhase = phase;
144 //////////////////////////////////////////////////////////////////
146 // calculation function for a control rate frequency argument
147 void MySaw_next_k(MySaw *unit, int inNumSamples)
149         // get the pointer to the output buffer
150         float *out = OUT(0);
152         // freq is control rate, so calculate it once.
153         float freq = IN0(0) * unit->mFreqMul;
155         // get phase from struct and store it in a local variable.
156         // The optimizer will cause it to be loaded it into a register.
157         double phase = unit->mPhase;
159         // since the frequency is not changing then we can simplify the loops
160         // by separating the cases of positive or negative frequencies.
161         // This will make them run faster because there is less code inside the loop.
162         if (freq >= 0.f) {
163                 // positive frequencies
164                 for (int i=0; i < inNumSamples; ++i)
165                 {
166                         out[i] = phase;
167                         phase += freq;
168                         if (phase >= 1.f) phase -= 2.f;
169                 }
170         } else {
171                 // negative frequencies
172                 for (int i=0; i < inNumSamples; ++i)
173                 {
174                         out[i] = phase;
175                         phase += freq;
176                         if (phase <= -1.f) phase += 2.f;
177                 }
178         }
180         // store the phase back to the struct
181         unit->mPhase = phase;
185 // the entry point is called by the host when the plug-in is loaded
186 PluginLoad(MySaw)
188     // InterfaceTable *inTable implicitly given as argument to the load function
189         ft = inTable; // store pointer to InterfaceTable
191         DefineSimpleUnit(MySaw);
195 subsection:: SCLang-side Definition of Unit Generators
197 SuperCollider requires an SCLang class in order to build SynthDefs.
199 The arguments to the MySaw UGen are code::freq:: and code::iphase::.  The code::multiNew:: method handles multi channel
200 expansion.  The code::madd:: method provides support for the mul and add arguments. It will create a MulAdd UGen if
201 necessary. You could write the class without mul and add arguments, but providing them makes it more convenient for the
202 user. See link::Guides/WritingClasses:: for details on writing sclang classes.
204 code::
205 // without mul and add.
206 MySaw : UGen {
207         *ar { arg freq = 440.0, iphase = 0.0;
208                 ^this.multiNew('audio', freq, iphase)
209         }
210         *kr { arg freq = 440.0, iphase = 0.0;
211                 ^this.multiNew('control', freq, iphase)
212         }
216 subsection:: Building Unit Generator Plugins
218 The most portable way to build plugins is using cmake footnote::http://www.cmake.org::, a cross-platform build
219 system. In order build the example with cmake, the following code should go into a code::CMakeLists.txt:: file.
221 code::
222 cmake_minimum_required (VERSION 2.8)
223 project (MySaw)
225 include_directories(${SC_PATH}/include/plugin_interface)
226 include_directories(${SC_PATH}/include/common)
227 include_directories(${SC_PATH}/external_libraries/libsndfile/)
229 set(CMAKE_SHARED_MODULE_PREFIX "")
230 if(APPLE OR WIN32)
231 set(CMAKE_SHARED_MODULE_SUFFIX ".scx")
232 endif()
234 add_library(MySaw MODULE MySaw.cpp)
238 section:: Coding Guidelines
240 Unit generator plugins are called from the real-time context, which means that special care needs to be taken in order
241 to avoid audio dropouts.
243 definitionList::
244 ## Memory Allocation || Do not allocate memory from the OS via code::malloc:: / code::free:: or code::new::/ code::delete::.
245                         Instead you should use the real-time memory allocator via code::RTAlloc:: / code::RTFree::.
246 ## STL Containers || It is generally not recommended to use STL containers, since they internally allocate memory. The only
247                      way the STL containers can be used is by providing an Allocator, which maps to the allocating functions of
248                      the server.
249 ## Blocking API Calls || Unit generators should not call any code, which could block the execution of the current thread. In
250                          particular, system calls should be avoided. If synchronization with other threads is required, this has to be
251                          done in a lock-free manner.
255 section:: Thread Safety
257 There are two different implementations of the SuperCollider server. strong::scsynth:: is the traditional server and
258 strong::supernova:: is a new implementation with support for multi-processor audio synthesis. Since the plugins in
259 strong::supernova:: can be called at the same time from multiple threads, write access to global data structures needs
260 to be synchronized.
262 definitionList::
263 ## Shared Global Data Structures || Unit generators should not share data structures, which are written to. While it it safe to use
264     global data structures for read-only purposes (e.g. different unit generators could use the same constant wavetable),
265     the data structures that are modified by the unit generators should not be shared among different instances.
267 ## Resource Locking || SuperCollider's buffers and busses are global data structures, and access needs to be synchronized.
268     This is done internally by using reader-writer spinlocks. This is done by using the code::ACQUIRE_::, code::RELEASE_::, and
269     code::LOCK_:: macros, which are defined in SC_Unit.h.
272 subsection:: Deadlock Prevention
274 In order to prevent deadlocks, a simple deadlock prevention scheme is implemented, based on the following constraints.
276 list::
277 ## Lock resources only when required: few unit generators actually require the access to more than one resource at the same time.
278    The main exception of this rule are the FFT Chain ugens, which access multiple buffers at the same time. There is no known unit
279    generator, which accesses both buffers and busses at the same time.
280 ## Acquire reader locks if possible. Since multiple ugens can acquire a reader lock to the same resource at the same time, their
281    use reduces contention.
282 ## Resources have to be acquired in a well-defined order: busses should be acquired before buffers and resources with a high index
283    should be acquired before resources with a low index.