-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathREADME
523 lines (378 loc) · 19.3 KB
/
README
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
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
Vampy is a wrapper for the Vamp audio analysis plugin API.
(http://www.vamp-plugins.org/) It allows for writing Vamp
plugins in Python.
WHAT IS IT FOR?
Vamp is an audio analysis and feature extraction plugin system
with a C/C++ Application Programming Interface (API).
Typical applications of Vamp plugins include visualisation, using
a host such as Sonic Visualiser (https://www.sonicvisualiser.org/),
or batch feature extraction from audio, using Sonic Annotator
(https://vamp-plugins.org/sonic-annotator).
Vamp plugins are typically written in C++. Although currently
available plugin hosts are valuable tools in audio research,
the long and tedious development cycle of plugins does not
support quick prototyping of feature extraction algorithms.
Learning the extra skills needed for plugin development or using
scientific libraries available for C and C++ is often outside
the interest of audio researches typically using MATLAB or other
high-level development environments.
This package aims at easing Vamp plugin development, prototyping
or deployment by using the high-level Python scripting language.
WHY PYTHON?
The Python programming language is extremely popular in the
scientific community. Besides being a high-productivity
interpreted language, it has extensions for scientific
computing such as Numpy, an efficient numerical library and
SciPy, a collection of Python modules for signal processing,
linear algebra, statistics and machine learning ...
(www.SciPy.org). These packages together with matplotlib
(http://matplotlib.sourceforge.net/) provide similar
capabilities to most commercial modelling environments. As a
further advantage, Python is a general purpose language which
also supports the functional programming style.
HOW DOES IT WORK?
Vampy acts like a bridge between a Vamp plugin host application
and Python scripts. It translates host function calls to Python
interpreter calls and converts Python data types to C++ and Vamp
defined data structures.
Vampy is distributed and can be installed like any other ordinary
Vamp plugin. When it is installed, any appropriately structured
Python script in its script directory will be presented to
host programs as if they were native Vamp plugins written in C++.
Vampy embeds the Python interpreter dynamically, and also extends
it with data types defined by the Vamp C++ API, all within a
single shared library.
WHAT'S NEW IN THIS RELEASE?
See the file CHANGELOG for details of changes in this release
(and previous releases) of Vampy.
OBTAINING VAMPY:
Vampy is a free, cross platform, open source package. The
source code is available from its repository at
https://code.soundsoftware.ac.uk/projects/vampy.
* Binary distributions are available for Windows, macOS, and
Linux.
* The source code can be obtained using the Mercurial command:
hg clone https://code.soundsoftware.ac.uk/hg/vampy
DEPENDENCIES:
* Vampy requires Python 2.7.
Note that Vampy does not support Python 3 at all at this
point. Note also that on a Mac in normal circumstances Vampy
expects to use the system installation of Python, so plugins
that you write should be tested using the system Python.
* Vampy supports Numpy 1.1 or greater.
Using Numpy is optional, however writing plugins in pure
Python typically results in significantly slower processing.
BUILDING VAMPY:
It is advised to use a binary distribution if available for
your platform and Python/Numpy versions before attempting to
compile it from source. If you decide to do so, please use the
make files provided. Make sure the correct include locations
are set for Python, Numpy, and the Vamp plugin SDK.
COMPILER OPTIONS:
HAVE_NUMPY : compile with Numpy array interface support
NUMPY_SHORTVERSION : set to the minimum version of Numpy you have,
as a floating-point value; the default is 1.1, which should be
OK for using the plugin with Numpy 1.1, 1.2 and 1.3
simple debugging (for developers):
_DEBUG : print more detailed messages while Vampy is in use
_DEBUG_VALUES : print all converted values to stderr
(But note that basic debug messages are compiled in already, and
will be displayed if the environment variable VAMPY_VERBOSE is set.)
USING VAMPY:
(1) Make sure you have Python 2.7 installed and you
have a recent Vamp plugin host application.
(e.g. Sonic Visualier)
(2) Download a version of Vampy compatible with your
operating system and Python distribution.
(3) Unzip the package and copy the shared library
(Windows: vampy.dll, Linux: vampy.so, MacOS: vampy.dylib)
to your Vamp plugin path.
(4) Copy the example plugins (.py files) from the
'Example VamPy plugins' directory to the same place.
(without the example directory itself)
(5) If you are familiar with Python, it is straightforward
to start writing your own plugins by following these examples.
Note: The interpreter automatically generates a compiled version
of each plugin when their source file is first imported. This
file can be distributed alone is so desired. Compiled or compiled
and optimised versions of a plugin can also be obtained using the
'py_compile' standard library module. (Note that Python byte
compiled binaries are easier to reverse than C++ binaries.)
Some familiarity with the Vamp plugin SDK and Vamp Plugin
documentation is assumed before one would start writing a plugin
using Vampy. Only the particularities of Vampy plugins are
covered here. The Vamp plugin documentation is available at:
* http://www.vamp-plugins.org/code-doc/index.html
* http://www.vamp-plugins.org/guide.pdf
BASIC RULES:
Only the Python scripts that follow some basic rules qualify as
Vampy plugins:
(1) Each plugin must contain a single class with the
same name as the script file name.
e.g. PyZeroCrossing.py -> class PyZeroCrossing
(2) Vampy plugins have to be in a specific directory designated
to Vamp plugins. The exact location is platform specific.
Additionally, you can use the VAMPY_EXTPATH environment
variable to specify a separate path for Vampy plugins.
(3) Vampy plugins can be used and distributed as Python scripts
(.py) or byte compiled Python binaries (.pyc / .pyo).
When a script is present with the same name as a compiled
file on any of the valid paths, the script will be preferred.
(4) Vampy may decide to reject some scripts after some basic
validation is performed:
* Scripts with syntax errors in them are ignored.
* Scripts not containing a class with the exact same name
as the file name are ignored. (Python is case sensitive!)
* Scripts with the wrong number of arguments to the plugin
class's __init__() function will be avoided.
* Scripts that redefine any of Vampy's standard type names
will be avoided.
(5) Unknown scripts may cause undesired behaviour.
Don't put arbitrary Python scripts in your Vamp directory,
you may use a subdirectory for that.
PLUGIN ERRORS:
Script validation is performed by the interpreter itself
using the same rules as module compilation. This means that
while most syntax errors will be noted when Vampy is first
used by a host, runtime errors can still occur during
execution. For example, a plugin calculating the dot product
of two vectors with different sizes will produce a runtime error.
Error messages from Vampy are printed on the standard error
channel.
If you're using a graphical host (such as Sonic Visualiser)
you may start the application from a command line terminal
in order to see these messages, or they may be forwarded by
the host to its own debug log file.
Exceptions:
* Runtime errors occurring in the plugin's __init__() function
will prevent the host from loading the plugin.
* Runtime errors in the plugin's initialise() function will
prevent the host from using the plugin.
* Module level errors resulting from importing a non-existent
module or source file or an error occurring on an imported
module's source tree will prevent the plugin from loading.
Any other error, including those during the process will
only be noted on the terminal output. Processing errors will
generally result in a blank screen or no results displayed by
graphical hosts.
EXTENSION MODULE:
Vampy extends Python with some useful data types defined
by the Vamp plugin API. This extension module is embedded
into the Vampy shared library, therefore it doesn't need
to be installed separately. However, it works very similarly
to any third party Python extension within a Vampy plugin.
You may import the extension in the usual manner using
" import vampy " and " from vampy import * ". (Note that
currently the extension module is not available as a
separate package, therefore this will only work if the
plugin is executed by Vampy within a usual host context.)
You can use any standard Python statement involving
modules such as " dir(vampy) " to print the names exported
by the module. The use of the extension in entirely optional,
however its use is strongly advised for the following reasons:
* Using the module hides the mapping between Python and
C++ data types and provides improved plugin portability.
* Returning types exported by the module is often faster.
* In future releases its use may become mandatory.
PROCESS INTERFACES:
Most computationally intensive processing takes place in
the plugin's process() method. This method has two arguments,
(besides the 'self' argument mandatory in all Python class methods).
* The fist argument is used to pass audio samples (in time
domain plugins) or frequency samples (complex FFT output)
in frequency domain plugins. This argument is always a
Python list object where each element of the list corresponds
to an audio channel. (The length of this list can not be zero.)
The actual element types contained in this list depends
on the domain type of the plugin (time/frequency domain) and
the selected process interface. (explained below)
* The second argument is the time stamp of the processing
block passed to the plugin. This time stamp is either
a long integer corresponding to a sample number, or a
RealTime data type exposed by the vampy module.
The use of the time stamp is different in time and frequency
domain plugins. Please refer to the Vamp plugin documentation
for more details.
Vampy supports three interfaces to process() function.
The interface type can be selected using the flags indicated
next to the process name below. The detailed use of these
flags will be explained later.
INTERFACE TYPES:
(1) Legacy interface (default, slowest):
Vampy passes a Python List of List of values to the
plugin corresponding to each audio channel, and the
time or frequency domain samples of each channel:
* Audio samples are passed as an N element list
of floating point values in time domain plugins,
(where N equals to the block size parameter of the plugin).
* Frequency Domain plugins are passed an N element list
of complex numbers, where N = (blockSize/2) + 1. This list
includes the DC and the Nyquist frequency FFT oputputs.
Note: This is the only available interface which can be used
without Numpy or a compatible numerical library.
(2) Buffer interface (vf_BUFFER, fast):
* Both time and frequency domain plugins are passed a list
of shared memory buffer objects where each buffer corresponds
to an audio channel. The length of these buffers is blockSize
in time domain plugins and blockSize+2 in frequency domain
plugins. The easiest way to access the data in the buffers
is the use of Numpy's frombuffer() command. See the Numpy
documentation or the Vampy example plugins for more details.
Note that this interface is very similar to how the data is
passed to Vamp plugins in C++.
(3) Numpy Array interface (vf_ARRAY, fast):
Vampy passes a list of Numpy arrays to the process()
corresponding to each audio channel.
* Time Domain plugins are passed an array of numpy.float32
values where the array size is N = blockSize.
* Frequency Domain plugins are passed an array of
numpy.complex64 values where the size N = (blockSize/2) + 1.
RETURNING VALUES:
Python is a dynamically typed language, which means
that the programmer is not forced to declare variable
types strictly and specifically, they can be decided
or changed at runtime. This leads to different programming
styles compared to using statically typed languages such
as C++. The Vamp API is declared using C++ and expects
statically declared types returned by the plugin.
This leads to difficulties to the Python programmer, and
requires a detailed knowledge of the API which otherwise
would be unnecessary. Vampy relaxes this requirement by
using a runtime type inference mechanism.
Vampy can convert just about any suitable Python data
object to the appropriate C++ data type expected by a
Vamp plugin host. This includes Numpy data types such as
numpy.float32 or a Numpy array. The type conversion is
dynamic and it is decided based on the plugin context and
the expected data type defined by the Vamp plugin API
in that context. This mechanism also takes advantage of the
higher level Python number, sequence and mapping protocols.
For example if the Vamp API expects a floating point value,
any returned Python object will be attempted to cast
to a floating point value first and returned to the host.
If the value can not be converted, an error message is
displayed.
Similarly, any returned value will be converted to a vector of
the appropriate element type when the expected return type is
a sequence of values. This allows the programmer to omit
unnecessary conversions, when, for example, a one element
list (vector) would be returned.
The type conversion can be controlled specifically for
each plugin. Vampy supports the use case of prototyping
C++ Vamp plugins in Python by using a more strict type
conversion mechanism which would issue an error message
if the Python object does not correspond to a C++ type
according to a strict one-to-one mapping. This mapping
can be briefly outlined as follows:
* numerical types require direct correspondence
between Python and C++ types when available
e.g. C++ float -> Python float
* Data structures defined in the Vamp Plugin API require
a type exported be the vampy extension module.
Vamp::FeatureSet() -> vampy.FeatureSet()
Vamp::RealTime() -> vampy.RealTime()
The strict type conversion method can be selected using
the Vampy flag: vf_STRICT (explained in the FLAGS section).
TIME STAMPS :
Vamp uses RealTime time stamps to indicate the position of
a processing block passed to the plugin, or the position of
any returned features relative to the start of the audio.
RealTime uses two integer values to represent time values
to nanosecond precision. Vampy provides a Python compatible
representation of this this type which can be imported and
used in any Vampy plugin.
* Vampy RealTime objects can be initialised using integers
corresponding to second and nanosecond values, or seconds (floats).
e.g.:
timestamp1 = RealTime(2,0)
timestamp2 = RealTime('seconds',2.123)
Please note that only the following methods are available:
* values() : returns a tuple of integers (sec,nsec)
* toFloat() : return a floating point representation (in seconds)
* toFrame(samplerate) : convert to frame
(sample number) given the audio sample rate
* toString() : human readable string representation
* a limited set of arithmetic operators (+,-)
Additionally Vampy provides a function to convert frame
counts (in audio samples) to RealTime:
timestamp = frame2RealTime(frameCount,inputSampleRate)
For the detailed use of time stamps, refer to the Vamp plugin
documentation. i.e. Section 5, "Sample Types and Timestamps"
in the Vamp plugin guide, and the Vamp SDK documentation:
http://vamp-plugins.org/code-doc/classVamp_1_1Plugin.html
on how time stamps are used in process calls.
Note: The support for RealTime time stamps is new in this
version of Vampy. Vampy 1 used long integer sample counts
instead. This is still accepted for backward compatibility,
but the use of RealTime is encouraged whenever possible.
By default sample counts are used, please set the falg:
vf_REALTIME to obtain RealTime time stamps in process calls.
VAMPY FLAGS :
The execution of Vampy plugins can be controlled using a set
of flags. (Each control flag is prefixed by vf_)
vf_NULL : zero value, default for Vampy version 1 behaviour
vf_DEBUG : print debug messages to standard error
vf_STRICT : strict type conversion (follows the C++ API more closely)
vf_QUIT : quit the host process on hard errors
vf_REALTIME : use RealTime time stamps
vf_BUFFER : use the Numpy Buffer interface
vf_ARRAY : use the numpy Array interface
vf_DEFAULT_V2 : default Vampy version 2 behaviour
(equals to setting: vf_ARRAY | vf_REALTIME)
The use of flags is optional. The default behaviour is that
of Vampy version 1.
To set the flags, place a variable called 'vampy_flags' in
your plugin class's __init__() function.
Example:
class PyMFCC(melScaling):
def __init__(self,inputSampleRate):
self.vampy_flags = vf_DEBUG | vf_ARRAY | vf_REALTIME
ENVIRONMENT VARIABLES:
Vampy recognises these optional environment variables:
VAMPY_VERBOSE if set at all, print out debug info to stderr
VAMPY_COMPILED=1 recognise byte compiled python plugins (default)
VAMPY_COMPILED=0 ignore them
VAMPY_EXTPATH: if given, searches this path for vampy plugins.
This is useful if you want to keep your python plugins
separate. Only a single absolute path name is recognised.
Example:
export VAMPY_EXTPATH="/Users/Shared/Development/vampy-path"
VAMPY_PYLIB: path to the Python shared library to be preloaded
before scripts are run. The preload is necessary on some
systems to support plugins that load additional Python modules.
Vampy will attempt to preload the right library by default, but
it sometimes fails; if so, set this variable to override it.
HISTORY:
v1:
* added support for Numpy arrays in processN()
* framecount is now passed also to legacy process()
and fixed resulting bugs in the PyZeroCrossing plugin
* added two examples which use Frequency Domain input in processN()
v2.0:
* complete rewrite using generic functions for
implementing full error checking on Python/C API calls
* added extension module;
supports RealTime and other Vamp type wrappers
enables a much more readable syntax
* added Numpy Array interface
* added flags
* added environment variables
* recognise byte compiled python scripts
* new example plugin PyMFCC
* modified all examples for the new syntax
* bug fix: Nyquist frequency FFT output is now passed correctly
TODO:
* Vamp 'programs' not implemented
* support multiple classes per script in scanner
* implement missing methods of vampy.RealTime type
LICENCE:
VamPy is distributed under a "new-style BSD" license; see the
file COPYING for details. You may modify and redistribute it
within any commercial or non-commercial, proprietary or
open-source context. VamPy imposes no limitation on how you
may choose to license your own plugin scripts. Note that
these happen to be the same terms as the Vamp SDK itself.
VamPy was written by Gyorgy Fazekas at the Centre for Digital
Music, Queen Mary University of London.
Copyright 2008-2009 Gyorgy Fazekas.
Copyright 2008-2019 Queen Mary University of London.