Skip to content
/ vampy Public
forked from vamp-plugins/vampy

A wrapper allowing Vamp audio analysis plugins to be written in Python

License

Notifications You must be signed in to change notification settings

c4dm/vampy

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

77 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

	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.
	

About

A wrapper allowing Vamp audio analysis plugins to be written in Python

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 62.9%
  • Python 34.7%
  • C 2.1%
  • Shell 0.3%