-
Notifications
You must be signed in to change notification settings - Fork 0
/
PluginParameters.html
435 lines (365 loc) · 18.8 KB
/
PluginParameters.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>PluginParameters</title>
<link rel="stylesheet" href="/css/reset.css" type="text/css" />
<link rel="stylesheet" href="/css/default.css" type="text/css" />
<link rel="stylesheet" href="/css/button.css" type="text/css" />
<script language="javascript" src="/js/email.js"></script>
<!-- google analytics -->
<script type='text/javascript'>
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type='text/javascript'>
var pageTracker = _gat._getTracker("UA-4400684-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</head>
<body>
<div id="smallheader">
<div class="wrapper">
<div id="logo">
<a href="/"><img src="/images/ta_logo_inverted.png" alt="Teragon Audio"/></a>
</div>
<!--
<div id="right">
<form method="get" id="searchform" action="#">
<fieldset class="search">
<input type="text" class="box" />
<button class="btn" title="Search">Search</button>
</fieldset>
</form>
</div>
-->
</div>
</div>
<div id="contentpart">
<div class="wrapper">
<ul class="menu">
<li class="menuitem"><a href="index.html">Home</a></li>
<li class="menuitem"><a href="/software.html">Software</a></li>
<li class="menuitem"><a href="/developers.html">Developer Portal</a></li>
<li class="menuitem"><a href="/performers.html">Performer Portal</a></li>
<li class="menuitem"><a href="/contact.html">Contact</a></li>
</ul>
<div id="content">
<div id="main" class="news">
<!-- Start content -->
<h1 id="pluginparameters">PluginParameters</h1>
<p>PluginParameters is a simple library used to keep parameter information for an
audio plugin, such as a VST or AudioUnit. The need for this arises from the
fact that most plugins have a number of parameters they need to maintain, and
this information needs to be sent to various parts of the plugin’s processing
code. The VST or AudioUnit side of things also needs to query this information
in a more structured manner, and this can lead to plugin code getting very
messy with huge <code>switch</code> blocks to get/set the correct value.</p>
<h2 id="features">Features</h2>
<ul>
<li>Provides a parameter database which supports the following data types:
<ul>
<li>BlobParameter</li>
<li>BooleanParameter</li>
<li>DecibelParameter</li>
<li>FloatParameter</li>
<li>FrequencyParameter</li>
<li>IntegerParameter</li>
<li>StringParameter</li>
</ul>
</li>
<li>For all parameter types, you can get the raw value (ie, the thing you
probably need in your code to do useful stuff), or a scaled value between
0.0 - 1.0. This makes PluginParameters ideal for use in VST plugins, which
need a 0.0 - 1.0 representation of all data.</li>
<li>The decibel parameter is represented internally as a linear value, which is
more convenient for most audio processing work. Additionally, it is
logarithmic, which is useful when fitting it to a knob or fader control.</li>
<li>The frequency parameter uses logarithmic scaling for its value, so it is
easier to select higher frequencies. This is particularly convenient for
filters where one MIDI step would otherwise mean a difference of several
hundred hertz.</li>
<li>All parameters provide a minimum, maximum, and default value.</li>
<li>All parameter types also have a function to get the displayable value as a
string.</li>
<li>Parameters have string unit suffixes for pretty-printing the value. For
example, DecibelParameter automatically adds “dB” to the printed value, and
FrequencyParameter adds “Hz” or “kHz”, depending on the frequency.</li>
<li>Parameters can have an unlimited number of observers, which will receive a
callback when the parameter value is changed. Observers can be added or
removed to a parameter at any time.</li>
<li>Lookup of parameters can be done either by index or by name, with either the
<code>get()</code> method or the square brackets (ie, <code>parameters["frequency"]</code>).</li>
<li>Small! Just a few hundred lines of code, and only one CPP file to add to your
project (tinythread.cpp, which is from a third-party library). Simply include
<code>PluginParameters.h</code> and you’ve got the whole library at your fingertips.</li>
<li>Threadsafe! PluginParameters can be built to run in a multi-threaded
environment ideal for audio plugins, with one high-priority audio thread and
multiple low-priority threads for background tasks or GUI.</li>
<li>The multi-threaded implementation is based on lock-free queues, and is
completely mutex-free for high performance in realtime audio applications.</li>
</ul>
<h2 id="usage-single-threaded">Usage (Single-Threaded)</h2>
<p><em>Note</em>: As of PluginParameters version 3.0, the multi-threaded implementation is
the default. To use the single-threaded implementation, you will need to define
the following preprocessor definition in your project:</p>
<figure class="highlight"><pre><code class="language-cpp" data-lang="cpp">#define PLUGINPARAMETERS_MULTITHREADED 0
#include "PluginParameters.h"</code></pre></figure>
<p>Assuming that you’ve pointed your source to include <code>PluginParameters.h</code> and
everything compiles fine, your next step is to make a <code>ParameterSet</code> and add
some parameters to it. This should probably be done in your plugin’s
constructor:</p>
<figure class="highlight"><pre><code class="language-cpp" data-lang="cpp">MyPlugin::MyPlugin() {
// Assumes that there is a ParameterSet member named "parameters" in
// the header file.
this->parameters.add(new BooleanParameter("Awesomeness", true));
this->parameters.add(new FrequencyParameter("Frequency", 20.0, 20000.0, 10000.0);
this->parameters.add(new DecibelParameter("Gain", -60.0, 3.0, 0.0));
}</code></pre></figure>
<p>For a VST plugin, a ton of boilerplate code regarding parameter values can be
eliminated and replaced with the following:</p>
<figure class="highlight"><pre><code class="language-cpp" data-lang="cpp">float MyPlugin::getParameter(VstInt32 index) {
return this->parameters[index]->getScaledValue();
}
void MyPlugin::setParameter(VstInt32 index, float value) {
this->parameters[index]->setScaledValue(value);
}
void MyPlugin::getParameterName (VstInt32 index, char* label) {
vst_strncpy(label, this->parameters[index]->getName().c_str(), kVstMaxParamStrLen);
}
void MyPlugin::getParameterDisplay(VstInt32 index, char* text) {
vst_strncpy(text, this->parameters[index]->getDisplayText().c_str(), kVstMaxParamStrLen);
}</code></pre></figure>
<p>When you actually want to use the parameter data in your code, it might look
something like this:</p>
<figure class="highlight"><pre><code class="language-cpp" data-lang="cpp">void MyPlugin::processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames) {
if(this->parameters["Awesomeness"]->getValue()) {
for(int i = 0; i < sampleFrames; i++) {
*outputs[0][i] = *inputs[0][i] * this->parameters["Gain"]->getValue();
*outputs[1][i] = *inputs[1][i] * this->parameters["Gain"]->getValue();
}
}
}</code></pre></figure>
<p>Note: The above example code may look a bit different than your actual
implementation. It’s just to give you a general idea as to how the library
should be used. For real-world examples of PluginParameters, check out the
source code for any of the <a href="https://github.com/teragonaudio">Teragon Audio plugins</a>.</p>
<h2 id="usage-multi-threaded">Usage (Multi-threaded)</h2>
<p>If you intend on using PluginParameters in combination with a plugin GUI, then
you will need to use the multi-threaded features of PluginParameters. Attempting
to use the single-threaded version in a multi-threaded environment may result in
priority inversion (and thus, occaisional stuttering on the audio thread), or
race conditions caused by multiple objects attempting to get/set parameter
values.</p>
<p>The multi-threaded mode must be enabled at compile-time like so:</p>
<figure class="highlight"><pre><code class="language-cpp" data-lang="cpp">#define PLUGINPARAMETERS_MULTITHREADED 1
#include "PluginParameters.h"</code></pre></figure>
<p><em>Note</em>: As of PluginParameters version 3.0, the multi-threaded implementation is
the default; it is not necessary to force this definition anymore. Simply
including <code>PluginParameters.h</code> is enough.</p>
<p>Some dependencies of the multi-threaded implementation require C++11 support,
so you may need to enable this for your compiler as necessary. Likewise, you
will need to add <code>tinythread.cpp</code> to the list of files compiled by your
project.</p>
<p>When a <code>ConcurrentParameterSet</code> (which should be used instead of the standard
<code>PluginParameterSet</code>) is created by your plugin, it will create a new
low-priority background thread for asynchronous parameter events. This thread
will be automatically shut down and destroyed when the <code>ConcurrentParameterSet</code>
is destroyed.</p>
<p>In multi-threaded mode, you may not directly modify parameter values. Instead,
you must schedule changes via an event dispatcher. Therefore a full
implementation would look something like this:</p>
<p>In VST plugin’s audio processing code:</p>
<figure class="highlight"><pre><code class="language-cpp" data-lang="cpp">MyPlugin::MyPlugin() {
// Assumes that there is a ConcurrentParameterSet member named
// "parameters" in the header file.
this->parameters.add(new BooleanParameter("Awesomeness", true));
this->parameters.add(new FrequencyParameter("Frequency", 20.0, 20000.0, 10000.0);
this->parameters.add(new DecibelParameter("Gain", -60.0, 3.0, 0.0));
}
void MyPlugin::process(float** inputs, float** outputs, long blocksize) {
this->parameters.processRealtimeEvents();
// Other processing code follows...
}
float MyPlugin::getParameter(VstInt32 index) {
return this->parameters[index]->getScaledValue();
}
void MyPlugin::setParameter(VstInt32 index, float value) {
this->parameters.setScaled(index, value);
}
void MyPlugin::getParameterName (VstInt32 index, char* label) {
vst_strncpy(label, this->parameters[index]->getName().c_str(), kVstMaxParamStrLen);
}
void MyPlugin::getParameterDisplay(VstInt32 index, char* text) {
vst_strncpy(text, this->parameters[index]->getDisplayText().c_str(), kVstMaxParamStrLen);
}
void MyPlugin::suspend() {
this->parameters.pause();
}
void MyPlugin::resume() {
this->parameters.resume();
}</code></pre></figure>
<p>In plugin’s GUI code:</p>
<figure class="highlight"><pre><code class="language-cpp" data-lang="cpp">// This code will be highly implementation-specific, but basically let's
// assume that some GUI code is ready to set a parameter value after user
// interaction. However in this example we'll assume that the GUI also wants
// to be notified about updates to the parameter, so it therefore would
// implement PluginParameterObserver.
MyGui::onValueUpdated(int index, float newValue) {
// We must pass "this" as the last argument so we don't notify ourselves
// when sending parameter changes to the audio thread.
this->parameters.set(index, newValue, this);
}
bool MyGui::isRealtimePriority() const {
return false;
}
void MyGui::onParameterUpdated(const PluginParameter* parameter) {
// Update widget to reflect parameter's new value
}</code></pre></figure>
<p>You can also have parameter observers on the realtime thread. This can be
useful to recalculate cached values based on parameter data (like filter
coefficients, for example).</p>
<p>Note that <code>ConcurrentParameterSet</code> <em>cannot</em> fully guarantee that the
asynchronous event thread will be ready to process events after the parameter
set itself is finished being constructed. In other words, never do this:</p>
<figure class="highlight"><pre><code class="language-cpp" data-lang="cpp">// Assumes a member of type ThreadsafePluginParameterSet*, and a
// PluginParameterObserver* named observer.
void MyPlugin::initialize() {
parameters = new ThreadsafePluginParameterSet();
Parameter *p = new BooleanParameter("test");
p->addObserver(observer);
parameters.add(p);
parameters.set("test", true); // BAD! Here we cannot guarantee that the
// observer will be called. The easy fix is to simply call set() elsewhere
// after this constructor exits.
// Also never do this:
parameters = new ConcurrentParameterSet();
delete parameters;
}</code></pre></figure>
<p>The reason that this code is bad is because the low-priority event thread may
not be fully started when the call to <code>set()</code> has been made, and therefore the
parameter change would not be correctly scheduled on that thread. The only way
to guarantee this behavior would be to have a mutex within both <code>set()</code> and
<code>processRealtimeEvents()</code>, which has performance consequences for the audio
thread.</p>
<p>That said, as long as you don’t attempt to schedule parameter changes or destroy
the parameter set immediately after construction, <code>ConcurrentParameterSet</code>
should be safe and reliable to use. Also it should be noted that all <code>Parameter</code>
subclasses provide a constructor which allows you to set a default value, so it
shouldn’t be necessary to schedule parameter changes immediately after
constructing the parameter set.</p>
<h2 id="testing">Testing</h2>
<p>PluginParameters comes with a small test suite which is used to develop the
library as well as fix bugs. If you think you’ve found a bug in
PluginParameters, then please build the test suites and run it before reporting
a bug for your platform. The test suites are built using CMake, and generate two
executables, <code>pluginparametertest</code> and <code>multithreadedtest</code>.</p>
<p>PluginParameters is built with <a href="http://www.cmake.org">CMake</a> and should compile cleanly out of
the box. Building on unix platforms (including Mac OSX) is simply a matter of
running <code>cmake . ; make</code>. On Windows, one can run <code>cmake.exe -G "Visual Studio
12"</code> to generate a Visual Studio project file which can build the project.</p>
<h2 id="license">License</h2>
<p>PluginParameters is licensed under the BSD licnese. See the file <code>LICENSE.txt</code>
provided with the source code for more details. If built in multi-threaded mode,
then code from <a href="http://tinythreadpp.bitsnbites.eu">TinyThread++</a> and <a href="https://github.com/cameron314/readerwriterqueue">readerwriterqueue</a> is used. Please see
the respective license files for each of these libraries, which can be found in
the <code>include</code> directory.</p>
<p>Finally, a big thanks to the authors of TinyThread++ and readerwriterqueue for
making this library possible. Writing multi-threaded code is hard!</p>
<hr />
<p>Changelog:</p>
<p>Version 3.2:</p>
<ul>
<li>Add pause/resume methods to ConcurrentParameterSet for processing
events when playback is paused.</li>
<li>Parameters now may have string descriptions for help</li>
<li>The “type” field has been removed from Parameter</li>
<li>Parameter class now has public getters for unit & precision</li>
</ul>
<p>Version 3.1:</p>
<ul><li> Compilation fixes for 64-bit Windows</li></ul>
<p>Version 3.0:</p>
<ul>
<li>Renaming several classes to be less verbose, including:
<ul>
<li>ENABLE_MULTITHREADED -> PLUGINPARAMETERS_MULTITHREADED</li>
<li>ThreadsafePluginParameterSet -> ConcurrentParameterSet</li>
<li>PluginParameterSet -> ParameterSet</li>
<li>PluginParameter -> Parameter</li>
<li>PluginParameterObserver -> ParameterObserver</li>
</ul>
</li>
<li>Several bufixes in thread handling, much safer startup and
shutdown procedures.</li>
<li>Introduce BlobParameter class</li>
<li>Small API cleanups and improvements</li>
<li>Separate test suites for single/multithreaded code</li>
<li>Both test suites now build on Windows</li>
<li>Other windows bugfixes</li>
</ul>
<p>Version 2.4:</p>
<ul>
<li>Compilation fixes on Mac OS X</li>
<li>DecibelParameter is now logarithmic</li>
<li>Fix documentation</li>
</ul>
<p>Version 2.3:</p>
<ul>
<li>Now threadsafe! See the README for how to use PluginParameters
in a multithreaded environment.</li>
</ul>
<p>Version 2.2:</p>
<ul>
<li>Adding parameter to set returns pointer to the parameter</li>
<li>Fix some bugs in triggering observer callbacks</li>
<li>Add VoidParameter type</li>
<li>BooleanParameter sets internal value before calling super</li>
<li>Add documentation for building test suite</li>
<li>Fix heap corruption in removeObserver</li>
</ul>
<p>Version 2.1:</p>
<ul>
<li>Add StringParameter type</li>
<li>Display precision can be set for parameters</li>
<li>Display frequency in kHz when >1000Hz</li>
<li>Add ability to observe parameter changes</li>
<li>Expose min/max value of parameters</li>
<li>Improve test suite</li>
</ul>
<p>Version 2.0:</p>
<ul>
<li>Rename DecibelParameter to FrequencyParameter</li>
<li>Introduce real DecibelParameter type</li>
<li>Much more efficient lookup of parameters</li>
<li>Ability to lookup with [] operator</li>
<li>Move all code to header files to make it easier to include in a project</li>
<li>Add test suite</li>
<li>Add documentation!</li>
</ul>
<p>Version 1.0:</p>
<ul>
<li>Bugfixes</li>
</ul>
<!-- End content -->
</div>
<div id="sidebar">
<ul class="sidemenu">
<li><a href="http://static.teragonaudio.com/downloads/PluginParametersPluginParameters.zip" class="downloadbutton"><b>Download</b></a><p></p></li>
<li><a href="https://github.com/teragonaudio/PluginParameters/zipball/master">Source code</a></li>
<li><a href="https://github.com/teragonaudio/PluginParameters">Project page</a></li>
</ul>
</div>
</div>
<div style="clear:both;"></div>
<div id="bottom">
<p class="footer">
<b>Having problems with this software?</b> Send an email to
<script>mail2("support", "teragonaudio", 0, "subject=PluginParameters", "support at teragonaudio dot com")</script>.
Copyright (c) 2012 Teragon Audio. All Rights Reserved.
</p>
</div>
</div>
</div>
</body>
</html>