Mtp2 » History » Version 9

Chris Cannam, 2012-07-12 04:29 PM

1 1 Chris Cannam
h1. From Method to Plugin: Building a new plugin on Windows using Visual C++
2 1 Chris Cannam
3 7 Chris Cannam
{{>toc}}
4 7 Chris Cannam
5 8 Chris Cannam
**Note:** This tutorial is specific to **Windows with Visual C++**.
6 8 Chris Cannam
Go [[mtp1|here]] for a version that uses Mac OS/X.
7 1 Chris Cannam
8 1 Chris Cannam
We're going to walk through the process of making, and compiling, a new Vamp plugin based on the skeleton files included with the Vamp plugin SDK.
9 1 Chris Cannam
10 1 Chris Cannam
After downloading the various bits and pieces of code we'll need, we will start by setting up a new Visual C++ project in which we just get the skeleton plugin to compile without it doing any actual work, and then we'll add some substance to it afterwards.
11 1 Chris Cannam
12 1 Chris Cannam
This tutorial assumes the use of Microsoft Visual C++ 2008 Express Edition (free with registration from http://www.microsoft.com/Express/VC/), though it should generally apply to other versions as well.
13 1 Chris Cannam
14 1 Chris Cannam
The focus here is on the practical details of what you need to put in a plugin and how to get it to build and run -- not on the real mathematical or signal-processing aspect.  We will pick a very simple method (time-domain signal power, block by block) for this example.  Please refer to the [[http://vamp-plugins.org/guide.pdf|Vamp plugin API programmer's guide]] for further reading, with information about returning more sophisticated features.
15 1 Chris Cannam
16 1 Chris Cannam
h2.  1. Download and unpack the SDK headers and pre-built libraries 
17 1 Chris Cannam
18 9 Chris Cannam
Download the Vamp plugin SDK version from the "development headers and source code" link on the developer page at http://vamp-plugins.org/develop.html -- the file you want is called @vamp-plugin-sdk-N.zip@ where N is the current SDK version number, for example 2.3.  Unpack this into your Visual Studio projects folder, which by default is found in your @Documents@ folder, at @Documents\Visual Studio 2008\Projects@.  You should now have a new folder in this location called @vamp-plugin-sdk-N@.  This picture shows version 2.1, which is no longer the latest, but the principle is the same.
19 1 Chris Cannam
20 5 Chris Cannam
!mtp2-sdk-folder.png!
21 1 Chris Cannam
22 9 Chris Cannam
We're not going to compile the SDK, only draw the header files from it.  To go with them, download the file @vamp-plugin-sdk-N-staticlibs-win32-msvc.zip@ from the same location, which contains some pre-compiled SDK libraries, and unpack it in the @Projects@ folder as well.
23 1 Chris Cannam
24 1 Chris Cannam
h2.  2. Make a new project based on the skeleton files 
25 1 Chris Cannam
26 1 Chris Cannam
We're going to build our plugin in a new project called @tutorial@, which initially will contain the skeleton plugin code from the SDK.
27 1 Chris Cannam
28 1 Chris Cannam
There are various ways to accomplish this; here's one.
29 1 Chris Cannam
30 9 Chris Cannam
Drag-copy the @skeleton@ folder from within @vamp-plugin-sdk-N@ directly into the @Projects@ folder...
31 1 Chris Cannam
32 5 Chris Cannam
!mtp2-skeleton-copy.png!
33 1 Chris Cannam
34 1 Chris Cannam
... and then rename @skeleton@ to @tutorial@ ...
35 1 Chris Cannam
36 5 Chris Cannam
!mtp2-skeleton-rename.png!
37 1 Chris Cannam
38 1 Chris Cannam
Now open Visual Studio, select @File@ -> @New@ -> @Project From Existing Code...@...
39 1 Chris Cannam
40 5 Chris Cannam
!mtp2-new-project-from.png!
41 1 Chris Cannam
42 1 Chris Cannam
... and in the new-project wizard do the following:
43 2 Chris Cannam
44 3 Chris Cannam
  * On the first page, choose the _Visual C++ Project_ type
45 3 Chris Cannam
  * On the next page, under _Specify Project Location and Source Files_, navigate to the new @tutorial@ folder in your @Projects@ directory and _Select Folder_
46 2 Chris Cannam
47 5 Chris Cannam
            !mtp2-project-location.png!
48 2 Chris Cannam
49 3 Chris Cannam
  * Under _Project Name_ enter @Tutorial@
50 3 Chris Cannam
  * **Important:** In the _Project Settings_ page under _How do you want to build the project?_, select @Use Visual Studio@ and @Dynamically linked library (DLL) project@
51 2 Chris Cannam
52 5 Chris Cannam
            !mtp2-project-type.png!
53 2 Chris Cannam
54 9 Chris Cannam
  * **Important:** In the _Configuration Settings_ page under _Include search paths (/I)_, type @..\vamp-plugin-sdk-N@
55 1 Chris Cannam
  * Finish
56 1 Chris Cannam
57 1 Chris Cannam
Now save the project (Ctrl+S or equivalent).  Once the project has been created, we still have a couple more properties to set.  These are found in the @Project@ -> @Properties@ window:
58 1 Chris Cannam
59 9 Chris Cannam
  * Under @Configuration Properties@ -> @Linker@ -> @General@ -> @Additional Library Directories@, navigate to the directory containing the **Debug** versions of the pre-compiled libraries you downloaded earlier (e.g. in my case this would be @C:\Users\cannam\Documents\Visual Studio 2008\Projects\vamp-plugin-sdk-N-staticlibs-win32-msvc\debug@) and add it to the list
60 1 Chris Cannam
  * Under @Configuration Properties@ -> @Linker@ -> @Input@ -> @Additional Dependencies@, add @VampPluginSDK.lib@
61 1 Chris Cannam
  * Under @Configuration Properties@ -> @Linker@ -> @Command Line@ -> @Additional options@, add @/EXPORT:vampGetPluginDescriptor@
62 1 Chris Cannam
63 1 Chris Cannam
You should now be able to build the project (press F7).
64 1 Chris Cannam
65 1 Chris Cannam
In the above, it's critically important that the Debug configuration of your project uses the Debug version of the pre-compiled library folder, and the Release configuration (when you come to that) uses the Release version.  If you get this wrong, your plugin will build but will crash when you try to use it!
66 1 Chris Cannam
67 1 Chris Cannam
The bulk of the skeleton plugin code is contained in the files @MyPlugin.cpp@ and @MyPlugin.h@.  These two files implement a single C++ class, called @MyPlugin@.  For the sake of brevity in the tutorial we'll leave these names unchanged, but you might prefer to change them!  To do so, rename the two files as you wish, and replace every occurrence of the text @MyPlugin@ in both of them, and in @plugins.cpp@, with your preferred plugin class name.
68 1 Chris Cannam
69 1 Chris Cannam
The file @plugins.cpp@ contains the entry point for the plugin library.  A library can hold more than one plugin, and the job of @plugins.cpp@ is to provide a single known public function (@vampGetPluginDescriptor@) which the host can use to find out what plugins are available in the library.  The skeleton version of @plugins.cpp@ just returns the single MyPlugin plugin class.
70 1 Chris Cannam
71 1 Chris Cannam
Note that it makes absolutely no difference to the operation of the plugin what its class is called, or what any of these files is called; MyPlugin is (in purely technical terms) as good a name as any.  It also shouldn't matter if two different libraries happen to use the same class name.  But if you have more than one plugin in the same library, they'll need to have different class names then!
72 1 Chris Cannam
73 1 Chris Cannam
h2.  3. Check that the plugin works with some test programs 
74 1 Chris Cannam
75 1 Chris Cannam
The next thing to do is gather some programs we can use to test our plugin, so that we can check it built correctly, and so that we'll be well placed to test it properly when it actually does something.
76 1 Chris Cannam
77 1 Chris Cannam
h3. vamp-plugin-tester 
78 1 Chris Cannam
79 1 Chris Cannam
One host worth setting up at the start is @vamp-plugin-tester@, a program that tests your plugin for a number of possible problems and pitfalls.  You can download this from http://vamp-plugins.org/develop.html as well; you're looking for the file @vamp-plugin-tester-1.0-win32.zip@.  Unpack it somewhere convenient, and (for now) copy the @vamp-plugin-tester.exe@ program into the @tutorial@ project folder for easy reference.
80 1 Chris Cannam
81 1 Chris Cannam
We can then run the tester from the command prompt (go to the Start menu and type @cmd@ to get the command prompt up).
82 1 Chris Cannam
83 1 Chris Cannam
First go to the @tutorial\Debug@ folder which is where our newly built plugin lives:
84 1 Chris Cannam
85 1 Chris Cannam
<pre>
86 1 Chris Cannam
C:\Users\cannam>cd "Documents\Visual Studio 2008\Projects\tutorial\Debug"
87 1 Chris Cannam
C:\Users\cannam\Documents\Visual Studio 2008\Projects\tutorial\Debug>
88 1 Chris Cannam
</pre>
89 1 Chris Cannam
90 1 Chris Cannam
If you type @dir *.dll@, you should see @Tutorial.dll@, the plugin library we just built.
91 1 Chris Cannam
92 1 Chris Cannam
Like all Vamp hosts, @vamp-plugin-tester@ understands the @VAMP_PATH@ environment variable to tell it where to look for Vamp plugins.  We need to set that, at least temporarily, to point to our new plugin in the current directory:
93 1 Chris Cannam
94 1 Chris Cannam
<pre>
95 1 Chris Cannam
C:\Users\cannam\Documents\Visual Studio 2008\Projects\tutorial\Debug>set VAMP_PATH=.
96 1 Chris Cannam
</pre>
97 1 Chris Cannam
98 1 Chris Cannam
And run the tester:
99 1 Chris Cannam
100 1 Chris Cannam
<pre>
101 1 Chris Cannam
C:\Users\cannam\Documents\Visual Studio 2008\Projects\tutorial\Debug>..\vamp-plugin-tester.exe -a
102 1 Chris Cannam
</pre>
103 1 Chris Cannam
104 6 Chris Cannam
!mtp2-tester.png!
105 1 Chris Cannam
106 1 Chris Cannam
As you see, @vamp-plugin-tester@ runs quite a number of tests -- see its @README@ file for more details about the error and warning messages it might give.  It's a good idea to use the tester right from the start of plugin development.
107 1 Chris Cannam
108 1 Chris Cannam
h3. vamp-simple-host 
109 1 Chris Cannam
110 9 Chris Cannam
The tester gives some instant feedback, but the simplest way to run a plugin and see what happens is to use @vamp-simple-host@.  This is also part of the Vamp SDK, and is available as a binary executable in the @vamp-plugin-sdk-N-binaries-win32-mingw.zip@ package (the "Pre-compiled library and host binaries" link on the [[http://vamp-plugins.org/develop.html|developer page]]).  Extract only the @vamp-simple-host.exe@ program from this package, and drop it into the @tutorial@ folder as before.
111 1 Chris Cannam
112 1 Chris Cannam
We set the @VAMP_PATH@ environment variable already when using @vamp-plugin-tester.exe@ above, but if you skipped that part:
113 1 Chris Cannam
114 1 Chris Cannam
<pre>
115 1 Chris Cannam
C:\Users\cannam>cd "Documents\Visual Studio 2008\Projects\tutorial\Debug"
116 1 Chris Cannam
C:\Users\cannam\Documents\Visual Studio 2008\Projects\tutorial\Debug>set VAMP_PATH=.
117 1 Chris Cannam
</pre>
118 1 Chris Cannam
119 1 Chris Cannam
Now, with the @-l@ option, we can ask the host to list the plugins it finds there.
120 1 Chris Cannam
121 1 Chris Cannam
<pre>
122 1 Chris Cannam
C:\Users\cannam\Documents\Visual Studio 2008\Projects\tutorial\Debug>..\vamp-simple-host.exe -l
123 1 Chris Cannam
Vamp plugin search path: [.]
124 1 Chris Cannam
125 1 Chris Cannam
Vamp plugin libraries found in search path:
126 1 Chris Cannam
127 1 Chris Cannam
  ./tutorial.dll:
128 1 Chris Cannam
    [A] [v2] My Plugin, "myplugin" []
129 1 Chris Cannam
130 1 Chris Cannam
C:\Users\cannam\Documents\Visual Studio 2008\Projects\tutorial\Debug>
131 1 Chris Cannam
</pre>
132 1 Chris Cannam
133 1 Chris Cannam
Huzzah.  We can use this host to run the plugin on some test audio files, not just list it -- but there isn't much point yet.
134 1 Chris Cannam
135 1 Chris Cannam
h2.  4. Now, the code! 
136 1 Chris Cannam
137 1 Chris Cannam
Right, let's make the plugin do something.  We're going to calculate the mean power for each processing block.  The work we do in this section will involve making a few edits to the @MyPlugin.cpp@ file (and at one point also @MyPlugins.h@) and rebuilding the project.
138 1 Chris Cannam
139 1 Chris Cannam
The calculation we want is @sum(x[i]^2) / N@, where @x[i]@ is audio sample number @i@, for @i@ in the range 0 to @N-1@, with @N@ the number of samples in the processing block.
140 1 Chris Cannam
141 1 Chris Cannam
h3. Describing the input and output formats 
142 1 Chris Cannam
143 1 Chris Cannam
Our calculation is a time-domain one (working directly from the PCM audio data), which means we don't need to change this function (found at line 63 of MyPlugin.cpp):
144 1 Chris Cannam
145 1 Chris Cannam
<pre>
146 1 Chris Cannam
MyPlugin::InputDomain
147 1 Chris Cannam
MyPlugin::getInputDomain() const
148 1 Chris Cannam
{
149 1 Chris Cannam
    return TimeDomain;
150 1 Chris Cannam
}
151 1 Chris Cannam
</pre>
152 1 Chris Cannam
153 1 Chris Cannam
We are going to write code to handle a single audio channel only, and leave it to the host to decide what to do if more than one channel is provided (most hosts will mix-down the input for us).  So that means we don't need to change these functions either:
154 1 Chris Cannam
155 1 Chris Cannam
<pre>
156 1 Chris Cannam
size_t
157 1 Chris Cannam
MyPlugin::getMinChannelCount() const
158 1 Chris Cannam
{
159 1 Chris Cannam
    return 1;
160 1 Chris Cannam
}
161 1 Chris Cannam
162 1 Chris Cannam
size_t
163 1 Chris Cannam
MyPlugin::getMaxChannelCount() const
164 1 Chris Cannam
{
165 1 Chris Cannam
    return 1;
166 1 Chris Cannam
}
167 1 Chris Cannam
</pre>
168 1 Chris Cannam
169 1 Chris Cannam
Nothing about our calculation requires us to constrain the processing block size -- we can handle any block size.  So we can leave this function unchanged as well:
170 1 Chris Cannam
171 1 Chris Cannam
<pre>
172 1 Chris Cannam
size_t
173 1 Chris Cannam
MyPlugin::getPreferredBlockSize() const
174 1 Chris Cannam
{
175 1 Chris Cannam
    return 0; // 0 means "I can handle any block size"
176 1 Chris Cannam
}
177 1 Chris Cannam
</pre>
178 1 Chris Cannam
179 1 Chris Cannam
The function @getOutputDescriptors@ describes what sort of features we intend to return.  As it happens, the skeleton already contains pretty much the description we are going to need: a single feature, with a single value, returned for each processing block.  We should probably change the name of the output, at least:
180 1 Chris Cannam
181 1 Chris Cannam
<pre>
182 1 Chris Cannam
MyPlugin::OutputList
183 1 Chris Cannam
MyPlugin::getOutputDescriptors() const
184 1 Chris Cannam
{
185 1 Chris Cannam
    OutputList list;
186 1 Chris Cannam
187 1 Chris Cannam
    OutputDescriptor d;
188 1 Chris Cannam
    d.identifier = "power";
189 1 Chris Cannam
    d.name = "Power";
190 1 Chris Cannam
    d.description = "";
191 1 Chris Cannam
    d.unit = "";
192 1 Chris Cannam
    d.hasFixedBinCount = true;
193 1 Chris Cannam
    d.binCount = 1;
194 1 Chris Cannam
    d.hasKnownExtents = false;
195 1 Chris Cannam
    d.isQuantized = false;
196 1 Chris Cannam
    d.sampleType = OutputDescriptor::OneSamplePerStep;
197 1 Chris Cannam
    d.hasDuration = false;
198 1 Chris Cannam
    list.push_back(d);
199 1 Chris Cannam
200 1 Chris Cannam
    return list;
201 1 Chris Cannam
}
202 1 Chris Cannam
</pre>
203 1 Chris Cannam
204 1 Chris Cannam
h3. Initialisation 
205 1 Chris Cannam
206 1 Chris Cannam
We said that we can **accept** any block size -- but we do need to know what the block size is.
207 1 Chris Cannam
208 1 Chris Cannam
This is told to us in the @initialise@ function.  Looking at that function, we can see the argument is @size_t blockSize@.  It's our job to remember the value of this.
209 1 Chris Cannam
210 1 Chris Cannam
We need to add a class data member for this.  In @MyPlugin.h@, look for this line at line 54 (near the bottom of the file):
211 1 Chris Cannam
212 1 Chris Cannam
<pre>
213 1 Chris Cannam
    // plugin-specific data and methods go here
214 1 Chris Cannam
</pre>
215 1 Chris Cannam
216 1 Chris Cannam
and add a line after it:
217 1 Chris Cannam
218 1 Chris Cannam
<pre>
219 1 Chris Cannam
    // plugin-specific data and methods go here
220 1 Chris Cannam
    size_t m_blockSize;
221 1 Chris Cannam
</pre>
222 1 Chris Cannam
223 1 Chris Cannam
Then, back in @MyPlugin.cpp@, find this line at line 187 in the @initialise@ function:
224 1 Chris Cannam
225 1 Chris Cannam
<pre>
226 1 Chris Cannam
    // Real initialisation work goes here!
227 1 Chris Cannam
</pre>
228 1 Chris Cannam
229 1 Chris Cannam
and add a line to set the data member:
230 1 Chris Cannam
231 1 Chris Cannam
<pre>
232 1 Chris Cannam
    // Real initialisation work goes here!
233 1 Chris Cannam
    m_blockSize = blockSize;
234 1 Chris Cannam
</pre>
235 1 Chris Cannam
236 1 Chris Cannam
Also it's very good practice to make sure the data member is initialised to zero in the class constructor.  That, at line 10 of @MyPlugin.cpp@, initially reads:
237 1 Chris Cannam
238 1 Chris Cannam
<pre>
239 1 Chris Cannam
MyPlugin::MyPlugin(float inputSampleRate) :
240 1 Chris Cannam
    Plugin(inputSampleRate)
241 1 Chris Cannam
{
242 1 Chris Cannam
}
243 1 Chris Cannam
</pre>
244 1 Chris Cannam
245 1 Chris Cannam
and we want it to read:
246 1 Chris Cannam
247 1 Chris Cannam
<pre>
248 1 Chris Cannam
MyPlugin::MyPlugin(float inputSampleRate) :
249 1 Chris Cannam
    Plugin(inputSampleRate),
250 1 Chris Cannam
    m_blockSize(0)
251 1 Chris Cannam
{
252 1 Chris Cannam
}
253 1 Chris Cannam
</pre>
254 1 Chris Cannam
255 1 Chris Cannam
At this point it's a good idea to try rebuilding the project and make sure it still compiles.
256 1 Chris Cannam
257 1 Chris Cannam
h3. Processing 
258 1 Chris Cannam
259 1 Chris Cannam
The core of our calculation happens in the @process@ method:
260 1 Chris Cannam
261 1 Chris Cannam
<pre>
262 1 Chris Cannam
MyPlugin::FeatureSet
263 1 Chris Cannam
MyPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
264 1 Chris Cannam
{
265 1 Chris Cannam
    // Do actual work!
266 1 Chris Cannam
    return FeatureSet();
267 1 Chris Cannam
}
268 1 Chris Cannam
</pre>
269 1 Chris Cannam
270 1 Chris Cannam
Here @inputBuffers@ is effectively an array of arrays -- to retrieve a single audio sample, we index it first by audio channel number (we know that we only have one channel, so the only valid index is 0) and then by audio sample number (from 0 to the processing block size less 1).
271 1 Chris Cannam
272 1 Chris Cannam
What we want to do is add up the squares of the audio sample values, and divide by the number of samples.
273 1 Chris Cannam
274 1 Chris Cannam
<pre>
275 1 Chris Cannam
MyPlugin::FeatureSet
276 1 Chris Cannam
MyPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
277 1 Chris Cannam
{
278 1 Chris Cannam
    float sumOfSquares = 0.0f;
279 1 Chris Cannam
280 1 Chris Cannam
    size_t i = 0; // note: same type as m_blockSize
281 1 Chris Cannam
282 1 Chris Cannam
    while (i < m_blockSize) {
283 1 Chris Cannam
        float sample = inputBuffers[0][i];
284 1 Chris Cannam
        sumOfSquares += sample * sample;
285 1 Chris Cannam
        ++i;
286 1 Chris Cannam
    }
287 1 Chris Cannam
288 1 Chris Cannam
    float meanPower = sumOfSquares / m_blockSize;
289 1 Chris Cannam
290 1 Chris Cannam
    // now what?
291 1 Chris Cannam
292 1 Chris Cannam
    return FeatureSet();
293 1 Chris Cannam
}
294 1 Chris Cannam
</pre>
295 1 Chris Cannam
296 1 Chris Cannam
So we've calculated the mean power value -- now how to return it?
297 1 Chris Cannam
298 1 Chris Cannam
In Vamp plugin terms, what we have is a plugin that has a single output, on which is returned a single audio feature for each process block, with one value.  We need to construct a @Feature@ object, give it a single value, and then push it as the only feature in output 0 (the first) of a new @FeatureSet@ object.  See the [[http://vamp-plugins.org/guide.pdf|Vamp plugin API programmer's guide]] for more information about feature representation.
299 1 Chris Cannam
300 1 Chris Cannam
Here's the code:
301 1 Chris Cannam
302 1 Chris Cannam
<pre>
303 1 Chris Cannam
MyPlugin::FeatureSet
304 1 Chris Cannam
MyPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
305 1 Chris Cannam
{
306 1 Chris Cannam
    float sumOfSquares = 0.0f;
307 1 Chris Cannam
308 1 Chris Cannam
    size_t i = 0;
309 1 Chris Cannam
310 1 Chris Cannam
    while (i < m_blockSize) {
311 1 Chris Cannam
        float sample = inputBuffers[0][i];
312 1 Chris Cannam
        sumOfSquares += sample * sample;
313 1 Chris Cannam
        ++i;
314 1 Chris Cannam
    }
315 1 Chris Cannam
316 1 Chris Cannam
    float meanPower = sumOfSquares / m_blockSize;
317 1 Chris Cannam
318 1 Chris Cannam
    Feature f;
319 1 Chris Cannam
    f.hasTimestamp = false;
320 1 Chris Cannam
    f.values.push_back(meanPower);
321 1 Chris Cannam
322 1 Chris Cannam
    FeatureSet fs;
323 1 Chris Cannam
    fs[0].push_back(f);
324 1 Chris Cannam
    return fs;
325 1 Chris Cannam
}
326 1 Chris Cannam
</pre>
327 1 Chris Cannam
328 1 Chris Cannam
After making this change and rebuilding the project, we now have a plugin that actually does something.
329 1 Chris Cannam
330 1 Chris Cannam
Returning to our command prompt, and with the aid of a suitable input file (@.wav@ or a similar uncompressed format that @vamp-simple-host@ understands) in the @tutorial@ folder, we can now run it.  For example:
331 1 Chris Cannam
332 1 Chris Cannam
<pre>
333 1 Chris Cannam
C:\Users\cannam\Documents\Visual Studio 2008\Projects\tutorial\Debug>..\vamp-simple-host.exe Tutorial:myplugin ..\my-song.wav
334 1 Chris Cannam
vamp-simple-host: Running...
335 1 Chris Cannam
Reading file: "C:/Users/cannam/Documents/Visual Studio 2008/Projects/tutorial/my-song.wav", writing to standard output
336 1 Chris Cannam
Running plugin: "myplugin"...                                        
337 1 Chris Cannam
Using block size = 1024, step size = 1024                            
338 1 Chris Cannam
Plugin accepts 1 -> 1 channel(s)                                     
339 1 Chris Cannam
Sound file has 2 (will mix/augment if necessary)                     
340 1 Chris Cannam
Output is: "output"                                                  
341 1 Chris Cannam
 0.000000000: 0
342 1 Chris Cannam
 0.023219954: 0
343 1 Chris Cannam
 0.046439909: 0
344 1 Chris Cannam
 0.069659863: 0
345 1 Chris Cannam
 0.092879818: 0
346 1 Chris Cannam
 0.116099773: 0
347 1 Chris Cannam
 0.139319727: 0
348 1 Chris Cannam
 0.162539682: 1.56888e-11
349 1 Chris Cannam
 0.185759637: 4.90218e-09
350 1 Chris Cannam
 0.208979591: 2.135e-07
351 1 Chris Cannam
 0.232199546: 0.00666197
352 1 Chris Cannam
 ... and lots and lots and lots and lots more output ...
353 1 Chris Cannam
C:\Users\cannam\Documents\Visual Studio 2008\Projects\tutorial\Debug>
354 1 Chris Cannam
</pre>
355 1 Chris Cannam
356 1 Chris Cannam
Try using the @vamp-plugin-tester@ again as well.
357 1 Chris Cannam
358 1 Chris Cannam
359 1 Chris Cannam
h2.  5. Fill in descriptions and other metadata 
360 1 Chris Cannam
361 1 Chris Cannam
Now we have a working plugin, but it still has the rather awkward name of @MyPlugin@.  There are several functions at the top of @MyPlugin.cpp@ which we can use to give it a more sensible name and description.
362 1 Chris Cannam
363 1 Chris Cannam
For example:
364 1 Chris Cannam
365 1 Chris Cannam
<pre>
366 1 Chris Cannam
string
367 1 Chris Cannam
MyPlugin::getIdentifier() const
368 1 Chris Cannam
{
369 1 Chris Cannam
    return "myplugin";
370 1 Chris Cannam
}
371 1 Chris Cannam
</pre>
372 1 Chris Cannam
373 1 Chris Cannam
The identifier is a string that is not normally used by people (for example, it never appears when plugins are listed in a menu of a graphical application), but that uniquely identifies the plugin within its library.  Something like @"power"@ is perfectly appropriate here.
374 1 Chris Cannam
375 1 Chris Cannam
You should fill in all of @getIdentifier@, @getName@, @getDescription@, @getMaker@, @getPluginVersion@, and @getCopyright@ for every plugin you write.
376 1 Chris Cannam
377 1 Chris Cannam
In my case, I would need something like:
378 1 Chris Cannam
379 1 Chris Cannam
<pre>
380 1 Chris Cannam
string
381 1 Chris Cannam
MyPlugin::getIdentifier() const
382 1 Chris Cannam
{
383 1 Chris Cannam
    return "power";
384 1 Chris Cannam
}
385 1 Chris Cannam
386 1 Chris Cannam
string
387 1 Chris Cannam
MyPlugin::getName() const
388 1 Chris Cannam
{
389 1 Chris Cannam
    return "Signal power level";
390 1 Chris Cannam
}
391 1 Chris Cannam
392 1 Chris Cannam
string
393 1 Chris Cannam
MyPlugin::getDescription() const
394 1 Chris Cannam
{
395 1 Chris Cannam
    return "Calculate the mean signal power for each processing block";
396 1 Chris Cannam
}
397 1 Chris Cannam
398 1 Chris Cannam
string
399 1 Chris Cannam
MyPlugin::getMaker() const
400 1 Chris Cannam
{
401 1 Chris Cannam
    return "Chris Cannam";
402 1 Chris Cannam
}
403 1 Chris Cannam
404 1 Chris Cannam
int
405 1 Chris Cannam
MyPlugin::getPluginVersion() const
406 1 Chris Cannam
{
407 1 Chris Cannam
    return 1;
408 1 Chris Cannam
}
409 1 Chris Cannam
410 1 Chris Cannam
string
411 1 Chris Cannam
MyPlugin::getCopyright() const
412 1 Chris Cannam
{
413 1 Chris Cannam
    return "Freely redistributable (tutorial example code)";
414 1 Chris Cannam
}
415 1 Chris Cannam
</pre>