changeset 37:27bab3a16c9a vampy2final

new branch Vampy2final
author fazekasgy
date Mon, 05 Oct 2009 11:28:00 +0000
parents
children d2ff6e7be4a1
files Example VamPy plugins/PyMFCC.py Example VamPy plugins/PySpectralFeatures.py Example VamPy plugins/PyZeroCrossing.py Example VamPy plugins/obsolete/PySpectralCentroid.py Example VamPy plugins/test/PyMFCC_buffer.py Example VamPy plugins/test/PyMFCC_freq.py Example VamPy plugins/test/PyMFCC_oldstyle.py Example VamPy plugins/test/PyMFCC_time.py Makefile Makefile.cc-linux Makefile.cc-mingw32 Makefile.cc-osol Mutex.cpp Mutex.h PyExtensionManager.cpp PyExtensionManager.h PyExtensionModule.cpp PyExtensionModule.h PyFeature.cpp PyFeature.h PyFeatureSet.cpp PyFeatureSet.h PyOutputDescriptor.cpp PyOutputDescriptor.h PyParameterDescriptor.cpp PyParameterDescriptor.h PyPlugScanner.cpp PyPlugScanner.h PyPlugin.cpp PyPlugin.h PyRealTime.cpp PyRealTime.h PyTypeInterface.cpp PyTypeInterface.h README VamPy.vcproj vamp-plugin.map vampy-main.cpp
diffstat 38 files changed, 8349 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Example VamPy plugins/PyMFCC.py	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,397 @@
+'''PyMFCC.py - This example Vampy plugin demonstrates
+how to return sprectrogram-like features and how to return
+data using the getRemainingFeatures() function.
+
+The plugin has frequency domain input and is using the
+numpy array interface. (Flag: vf_ARRAY)
+
+Outputs: 
+1) 2-128 MFCC coefficients
+2) Mel-warped spectrum used for the MFCC computation
+3) Filter matrix used for Mel scaling
+
+Centre for Digital Music, Queen Mary University of London.
+Copyright (C) 2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+for licence information.)
+
+Constants for Mel frequency conversion and filter 
+centre calculation are taken from the GNU GPL licenced 
+Freespeech library. Copyright (C) 1999 Jean-Marc Valin
+'''
+
+import sys,numpy,vampy
+from numpy import abs,log,exp,floor,sum,sqrt,cos,hstack
+from numpy.fft import *
+from vampy import *
+
+
+class melScaling(object):
+
+	def __init__(self,sampleRate,inputSize,numBands,minHz = 0,maxHz = None):
+		'''Initialise frequency warping and DCT matrix. 
+		Parameters:
+		sampleRate: audio sample rate
+		inputSize: length of magnitude spectrum (half of FFT size assumed)
+		numBands: number of mel Bands (MFCCs)
+		minHz: lower bound of warping  (default = DC)
+		maxHz: higher bound of warping (default = Nyquist frequency)
+		'''
+		self.sampleRate = sampleRate
+		self.NqHz = sampleRate / 2.0
+		self.minHz = minHz
+		if maxHz is None : maxHz = self.NqHz
+		self.maxHz = maxHz
+		self.inputSize = inputSize
+		self.numBands = numBands
+		self.valid = False
+		self.updated = False
+		
+	def update(self): 
+		# make sure this will run only once 
+		# if called from a vamp process
+		if self.updated: return self.valid
+		self.updated = True
+		self.valid = False
+		print 'Updating parameters and recalculating filters: '
+		print 'Nyquist: ',self.NqHz
+		
+		if self.maxHz > self.NqHz : 
+			raise Exception('Maximum frequency must be smaller than the Nyquist frequency')
+		
+		self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
+		self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
+		print 'minHz:%s\nmaxHz:%s\nminMel:%s\nmaxMel:%s\n' \
+		%(self.minHz,self.maxHz,self.minMel,self.maxMel)
+		self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
+		self.DCTMatrix = self.getDCTMatrix(self.numBands)
+		self.filterIter = self.filterMatrix.__iter__()
+		self.valid = True
+		return self.valid
+				
+	def getFilterCentres(self,inputSize,numBands):
+		'''Calculate Mel filter centres around FFT bins.
+		This function calculates two extra bands at the edges for
+		finding the starting and end point of the first and last 
+		actual filters.'''
+		centresMel = numpy.array(xrange(numBands+2)) * (self.maxMel-self.minMel)/(numBands+1) + self.minMel
+		centresBin = numpy.floor(0.5 + 700.0*inputSize*(exp(centresMel*log(1+1000.0/700.0)/1000.0)-1)/self.NqHz)
+		return numpy.array(centresBin,int)
+		
+	def getFilterMatrix(self,inputSize,numBands):
+		'''Compose the Mel scaling matrix.'''
+		filterMatrix = numpy.zeros((numBands,inputSize))
+		self.filterCentres = self.getFilterCentres(inputSize,numBands)
+		for i in xrange(numBands) :
+			start,centre,end = self.filterCentres[i:i+3]
+			self.setFilter(filterMatrix[i],start,centre,end)
+		return filterMatrix.transpose()
+
+	def setFilter(self,filt,filterStart,filterCentre,filterEnd):
+		'''Calculate a single Mel filter.'''
+		k1 = numpy.float32(filterCentre-filterStart)
+		k2 = numpy.float32(filterEnd-filterCentre)
+		up = (numpy.array(xrange(filterStart,filterCentre))-filterStart)/k1
+		dn = (filterEnd-numpy.array(xrange(filterCentre,filterEnd)))/k2
+		filt[filterStart:filterCentre] = up
+		filt[filterCentre:filterEnd] = dn
+						
+	def warpSpectrum(self,magnitudeSpectrum):
+		'''Compute the Mel scaled spectrum.'''
+		return numpy.dot(magnitudeSpectrum,self.filterMatrix)
+		
+	def getDCTMatrix(self,size):
+		'''Calculate the square DCT transform matrix. Results are 
+		equivalent to Matlab dctmtx(n) with 64 bit precision.'''
+		DCTmx = numpy.array(xrange(size),numpy.float64).repeat(size).reshape(size,size)
+		DCTmxT = numpy.pi * (DCTmx.transpose()+0.5) / size
+		DCTmxT = (1.0/sqrt( size / 2.0)) * cos(DCTmx * DCTmxT)
+		DCTmxT[0] = DCTmxT[0] * (sqrt(2.0)/2.0)
+		return DCTmxT
+		
+	def dct(self,data_matrix):
+		'''Compute DCT of input matrix.'''
+		return numpy.dot(self.DCTMatrix,data_matrix)
+		
+	def getMFCCs(self,warpedSpectrum,cn=True):
+		'''Compute MFCC coefficients from Mel warped magnitude spectrum.'''
+		mfccs=self.dct(numpy.log(warpedSpectrum))
+		if cn is False : mfccs[0] = 0.0
+		return mfccs
+	
+
+class PyMFCC(melScaling): 
+	
+	def __init__(self,inputSampleRate):
+		
+		# flags for setting some Vampy options
+		self.vampy_flags = vf_DEBUG | vf_ARRAY | vf_REALTIME
+
+		self.m_inputSampleRate = int(inputSampleRate)
+		self.m_stepSize = 1024
+		self.m_blockSize = 2048
+		self.m_channels = 1
+		self.numBands = 40
+		self.cnull = 1
+		self.two_ch = False
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		
+	def initialise(self,channels,stepSize,blockSize):
+		self.m_channels = channels
+		self.m_stepSize = stepSize		
+		self.m_blockSize = blockSize
+		self.window = numpy.hamming(blockSize)
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		return True
+	
+	def getMaker(self):
+		return 'Vampy Example Plugins'
+		
+	def getCopyright(self):
+		return 'Plugin By George Fazekas'
+	
+	def getName(self):
+		return 'Vampy MFCC Plugin'
+		
+	def getIdentifier(self):
+		return 'vampy-mfcc'
+
+	def getDescription(self):
+		return 'A simple MFCC plugin'
+	
+	def getMaxChannelCount(self):
+		return 2
+		
+	def getInputDomain(self):
+		return FrequencyDomain #TimeDomain
+		
+	def getPreferredBlockSize(self):
+		return 2048
+		
+	def getPreferredStepSize(self):
+		return 1024
+			
+	def getOutputDescriptors(self):
+		
+		Generic = OutputDescriptor() 
+		Generic.hasFixedBinCount=True
+		Generic.binCount=int(self.numBands)-self.cnull
+		Generic.hasKnownExtents=False
+		Generic.isQuantized=True
+		Generic.sampleType = OneSamplePerStep 
+		
+		# note the inheritance of attributes (optional)
+		MFCC = OutputDescriptor(Generic)
+		MFCC.identifier = 'mfccs'
+		MFCC.name = 'MFCCs'
+		MFCC.description = 'MFCC Coefficients'
+		MFCC.binNames=map(lambda x: 'C '+str(x),range(self.cnull,int(self.numBands)))
+		if self.two_ch and self.m_channels == 2 :
+			MFCC.binNames *= 2 #repeat the list
+		MFCC.unit = None
+		if self.two_ch and self.m_channels == 2 :
+			MFCC.binCount = self.m_channels * (int(self.numBands)-self.cnull)
+		else :
+			MFCC.binCount = self.numBands-self.cnull
+				
+		warpedSpectrum = OutputDescriptor(Generic)
+		warpedSpectrum.identifier='warped-fft'
+		warpedSpectrum.name='Mel Scaled Spectrum'
+		warpedSpectrum.description='Mel Scaled Magnitide Spectrum'
+		warpedSpectrum.unit='Mel'
+		if self.two_ch and self.m_channels == 2 :
+			warpedSpectrum.binCount = self.m_channels * int(self.numBands) 
+		else :
+			warpedSpectrum.binCount = self.numBands
+		
+		melFilter = OutputDescriptor(Generic)
+		melFilter.identifier = 'mel-filter-matrix'
+		melFilter.sampleType='FixedSampleRate'
+		melFilter.sampleRate=self.m_inputSampleRate/self.m_stepSize
+		melFilter.name='Mel Filter Matrix'
+		melFilter.description='Returns the created filter matrix in getRemainingFeatures.'
+		melFilter.unit = None
+				
+		return OutputList(MFCC,warpedSpectrum,melFilter)
+		
+
+	def getParameterDescriptors(self):
+
+		melbands = ParameterDescriptor()
+		melbands.identifier='melbands'
+		melbands.name='Number of bands (coefficients)'
+		melbands.description='Set the number of coefficients.'
+		melbands.unit = ''
+		melbands.minValue = 2
+		melbands.maxValue = 128
+		melbands.defaultValue = 40
+		melbands.isQuantized = True
+		melbands.quantizeStep = 1
+				
+		cnull = ParameterDescriptor()
+		cnull.identifier='cnull'
+		cnull.name='Return C0'
+		cnull.description='Select if the DC coefficient is required.'
+		cnull.unit = None
+		cnull.minValue = 0
+		cnull.maxValue = 1
+		cnull.defaultValue = 0
+		cnull.isQuantized = True
+		cnull.quantizeStep = 1
+		
+		two_ch = ParameterDescriptor(cnull)
+		two_ch.identifier='two_ch'
+		two_ch.name='Process channels separately'
+		two_ch.description='Process two channel files separately.'
+		two_ch.defaultValue = False
+				
+		minHz = ParameterDescriptor()
+		minHz.identifier='minHz'
+		minHz.name='minimum frequency'
+		minHz.description='Set the lower frequency bound.'
+		minHz.unit='Hz'
+		minHz.minValue = 0
+		minHz.maxValue = 24000
+		minHz.defaultValue = 0
+		minHz.isQuantized = True
+		minHz.quantizeStep = 1.0
+		
+		maxHz = ParameterDescriptor()
+		maxHz.identifier='maxHz'
+		maxHz.description='Set the upper frequency bound.'
+		maxHz.name='maximum frequency'
+		maxHz.unit='Hz'
+		maxHz.minValue = 100
+		maxHz.maxValue = 24000
+		maxHz.defaultValue = 11025
+		maxHz.isQuantized = True
+		maxHz.quantizeStep = 100
+		
+		return ParameterList(melbands,minHz,maxHz,cnull,two_ch)
+		
+
+	def setParameter(self,paramid,newval):
+		self.valid = False
+		if paramid == 'minHz' :
+			if newval < self.maxHz and newval < self.NqHz :
+				self.minHz = float(newval)
+		if paramid == 'maxHz' :
+			if newval < self.NqHz and newval > self.minHz+1000 :
+				self.maxHz = float(newval)
+			else :
+				self.maxHz = self.NqHz
+		if paramid == 'cnull' :
+			self.cnull = int(not int(newval))
+		if paramid == 'melbands' :
+			self.numBands = int(newval)
+		if paramid == 'two_ch' :
+			self.two_ch = bool(newval)
+		return None
+
+				
+	def getParameter(self,paramid):
+		if paramid == 'minHz' :
+			return self.minHz
+		if paramid == 'maxHz' :
+			return self.maxHz
+		if paramid == 'cnull' :
+			return bool(not int(self.cnull))
+		if paramid == 'melbands' :
+			return self.numBands
+		if paramid == 'two_ch' :
+			return self.two_ch
+		else:
+			return 0.0
+
+	# set numpy array process using the 'vf_ARRAY' flag in __init__()
+	# and RealTime time stamps using the 'vf_REALTIME' flag
+	def process(self,inputbuffers,timestamp):
+		
+		# calculate the filter and DCT matrices, check 
+		# if they are computable given a set of parameters
+		# (we only do this once, when the process is called first)
+		if not self.update() : return None
+		
+		# if two channel processing is set, use process2ch
+		if self.m_channels == 2 and self.two_ch :
+			return self.process2ch(inputbuffers,timestamp)
+		
+		fftsize = self.m_blockSize
+		
+		if self.m_channels > 1 :
+			# take the average of two magnitude spectra
+			mS0 = abs(inputbuffers[0])[0:fftsize/2]
+			mS1 = abs(inputbuffers[1])[0:fftsize/2]
+			magnitudeSpectrum = (mS0 + mS1) / 2
+		else :
+			complexSpectrum = inputbuffers[0]
+			magnitudeSpectrum = abs(complexSpectrum)[0:fftsize/2]
+
+		# do the frequency warping and MFCC computation
+		melSpectrum = self.warpSpectrum(magnitudeSpectrum)
+		melCepstrum = self.getMFCCs(melSpectrum,cn=True)
+		
+		# returning the values: 
+		outputs = FeatureSet()
+		
+		# 1) full initialisation example using a FeatureList
+		f_mfccs = Feature()
+		f_mfccs.values = melCepstrum[self.cnull:]
+		outputs[0] = FeatureList(f_mfccs)
+		
+		# 2) simplified: when only one feature is required, 
+		# the FeatureList() can be omitted
+		outputs[1] = Feature(melSpectrum)
+		
+		# this is equivalint to writing :
+		# outputs[1] = Feature()
+		# outputs[1].values = melSpectrum
+		# or using keyword args: Feature(values = melSpectrum)
+			
+		return outputs
+		
+	# process channels separately (stack the returned arrays)
+	def process2ch(self,inputbuffers,timestamp):
+
+		fftsize = self.m_blockSize
+		
+		complexSpectrum0 = inputbuffers[0]
+		complexSpectrum1 = inputbuffers[1]
+		
+		magnitudeSpectrum0 = abs(complexSpectrum0)[0:fftsize/2]
+		magnitudeSpectrum1 = abs(complexSpectrum1)[0:fftsize/2]
+		
+		# do the computations
+		melSpectrum0 = self.warpSpectrum(magnitudeSpectrum0)
+		melCepstrum0 = self.getMFCCs(melSpectrum0,cn=True)
+		melSpectrum1 = self.warpSpectrum(magnitudeSpectrum1)
+		melCepstrum1 = self.getMFCCs(melSpectrum1,cn=True)
+		
+		outputs = FeatureSet()
+		outputs[0] = Feature(hstack((melCepstrum1[self.cnull:],melCepstrum0[self.cnull:])))
+		outputs[1] = Feature(hstack((melSpectrum1,melSpectrum0)))
+		
+		return outputs
+	
+
+	def getRemainingFeatures(self):
+		if not self.update() : return []
+		frameSampleStart = 0
+		
+		output_featureSet = FeatureSet()
+
+		# the filter is the third output (index starts from zero)
+		output_featureSet[2] = flist = FeatureList()
+
+		while True:
+			f = Feature()
+			f.hasTimestamp = True
+			f.timestamp = frame2RealTime(frameSampleStart,self.m_inputSampleRate)
+			try :
+				f.values = self.filterIter.next()
+			except StopIteration :
+				break
+			flist.append(f)
+			frameSampleStart += self.m_stepSize
+
+		return output_featureSet
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Example VamPy plugins/PySpectralFeatures.py	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,182 @@
+'''PySpectralFeatures.py - Example plugin demonstrates 
+how to calculate and return simple low-level spectral 
+descriptors (curves) using Numpy and the buffer interface.
+
+Outputs: 
+1) Spectral Centroid
+2) Spectral Creast Factor
+3) Spectral Band-width
+4) Spectral Difference (first order)
+
+Centre for Digital Music, Queen Mary University of London.
+Copyright (C) 2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+for licence information.)
+
+'''
+
+from numpy import *
+from vampy import *
+
+class PySpectralFeatures: 
+	
+	def __init__(self,inputSampleRate):
+
+		# flags:
+		self.vampy_flags = vf_DEBUG | vf_BUFFER | vf_REALTIME
+
+		self.m_inputSampleRate = inputSampleRate
+		self.m_stepSize = 0
+		self.m_blockSize = 0
+		self.m_channels = 0
+		self.threshold = 0.05
+		return None
+		
+	def initialise(self,channels,stepSize,blockSize):
+		self.m_channels = channels
+		self.m_stepSize = stepSize		
+		self.m_blockSize = blockSize
+		self.prevMag = zeros((blockSize/2)-1)
+		return True
+		
+	def reset(self):
+		# reset any initial conditions
+		self.prevMag = zeros((blockSize/2)-1)
+		return None
+	
+	def getMaker(self):
+		return 'Vampy Example Plugins'
+	
+	def getName(self):
+		return 'Vampy Spectral Features'
+		
+	def getIdentifier(self):
+		return 'vampy-sf3'
+
+	def getDescription(self):
+		return 'A collection of low-level spectral descriptors.'
+	
+	def getMaxChannelCount(self):
+		return 1
+		
+	def getInputDomain(self):
+		return FrequencyDomain
+			
+	def getOutputDescriptors(self):
+
+		#Generic values are the same for all
+		Generic = OutputDescriptor()
+		Generic.hasFixedBinCount=True
+		Generic.binCount=1
+		Generic.hasKnownExtents=False
+		Generic.isQuantized=False
+		Generic.sampleType = OneSamplePerStep
+		Generic.unit = 'Hz'		
+		
+		#Spectral centroid etc...
+		SC = OutputDescriptor(Generic)
+		SC.identifier = 'vampy-sc'
+		SC.name = 'Spectral Centroid'
+		SC.description ='Spectral Centroid (Brightness)'
+				
+		SCF = OutputDescriptor(Generic)
+		SCF.identifier = 'vampy-scf'
+		SCF.name = 'Spectral Crest Factor'
+		SCF.description = 'Spectral Crest (Tonality)'
+		SCF.unit = 'v'
+
+		BW = OutputDescriptor(Generic)
+		BW.identifier = 'vampy-bw'
+		BW.name = 'Band Width'
+		BW.description = 'Spectral Band Width'
+		
+		SD = OutputDescriptor(Generic)
+		SD.identifier = 'vampy-sd'
+		SD.name = 'Spectral Difference'
+		SD.description = 'Eucledian distance of successive magnitude spectra.'
+			
+		#return a tuple, list or OutputList(SC,SCF,BW)
+		return OutputList(SC,SCF,BW,SD)
+
+	def getParameterDescriptors(self):
+		
+		threshold = ParameterDescriptor()
+		threshold.identifier='threshold'
+		threshold.name='Noise threshold'
+		threshold.description='Noise threshold'
+		threshold.unit='v'
+		threshold.minValue=0
+		threshold.maxValue=1
+		threshold.defaultValue=0.05
+		threshold.isQuantized=False
+		
+		return ParameterList(threshold)
+
+	def setParameter(self,paramid,newval):
+		if paramid == 'threshold' :
+			self.threshold = newval
+		return
+		
+	def getParameter(self,paramid):
+		if paramid == 'threshold' :
+			return self.threshold
+		else:
+			return 0.0
+
+
+    # using the numpy memory buffer interface: 
+	# flag : vf_BUFFER (or implement processN)
+	# NOTE: Vampy can now pass numpy arrays directly using 
+	# the flag vf_ARRAY (see MFCC plugin for example)
+	def process(self,membuffer,timestamp):
+
+		fftsize = self.m_blockSize
+		sampleRate = self.m_inputSampleRate
+
+		#for time domain plugins use the following line:
+		#audioSamples = frombuffer(membuffer[0],float32)
+
+		#for frequency domain plugins use:
+		complexSpectrum =  frombuffer(membuffer[0],complex64,-1,8)
+
+		# meaning of the parameters above:
+		# complex64 : data type of the created numpy array
+		# -1 : convert the whole buffer 
+		#  8 : skip the DC component (2*32bit / 8bit = 8byte)
+
+		magnitudeSpectrum = abs(complexSpectrum) / (fftsize*0.5)
+		#phaseSpectrum = angle(complexSpectrum)
+		
+		freq = array(range(1,len(complexSpectrum)+1)) \
+		* sampleRate / fftsize
+		
+		# return features in a FeatureSet()
+		output_featureSet = FeatureSet()
+
+		tpower = sum(magnitudeSpectrum)
+
+		if tpower > self.threshold : 
+			centroid = sum(freq * magnitudeSpectrum) / tpower 
+			crest = max(magnitudeSpectrum)  / tpower
+			bw = sum( abs(freq - centroid) * magnitudeSpectrum ) / tpower
+			normMag = magnitudeSpectrum / tpower			
+			sd = sqrt(sum(power((normMag - self.prevMag),2)))
+			self.prevMag = normMag
+		else :
+			centroid = 0.0
+			crest = 0.0
+			bw = 0.0
+			sd = 0.0
+			
+		# Any value resulting from the process can be returned.
+		# It is no longer necessary to wrap single values into lists
+		# and convert numpy.floats to python floats,
+		# however a FeatureList() (or python list) can be returned
+		# if more than one feature is calculated per frame.
+		# The feature values can be e.g. int, float, list or array.
+		
+		output_featureSet[0] = Feature(centroid)
+		output_featureSet[1] = Feature(crest)
+		output_featureSet[2] = Feature(bw)
+		output_featureSet[3] = Feature(sd)
+
+		return output_featureSet
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Example VamPy plugins/PyZeroCrossing.py	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,162 @@
+'''PyZeroCrossing.py - Example plugin demonstrates
+how to write a Vampy plugin in pure Python without
+using Numpy or the extensions provided by the embedded 
+vampy module. 
+
+This plugin is compatible with provious versions of vampy, 
+apart from moving the inputSampleRate
+argument from initialise to __init__()
+
+Outputs: 
+1) Zero crossing counts
+2) Zero crossing locations
+
+Centre for Digital Music, Queen Mary University of London.
+Copyright (C) 2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+for licence information.)
+
+'''
+
+class PyZeroCrossing: 
+	
+	def __init__(self,inputSampleRate): 
+		self.m_inputSampleRate = inputSampleRate 
+		self.m_stepSize = 0
+		self.m_blockSize = 0
+		self.m_channels = 0
+		self.previousSample = 0.0
+		self.threshold = 0.005
+		self.counter = 0
+		
+	def initialise(self,channels,stepSize,blockSize):
+		self.m_channels = channels
+		self.m_stepSize = stepSize		
+		self.m_blockSize = blockSize
+		return True
+	
+	def getMaker(self):
+		return 'Vampy Example Plugins'
+	
+	def getName(self):
+		return 'Vampy Zero Crossings'
+		
+	def getIdentifier(self):
+		return 'vampy-zc2'
+	
+	def getMaxChannelCount(self):
+		return 1
+		
+	def getInputDomain(self):
+		return 'TimeDomain'
+			
+	def getOutputDescriptors(self):
+		
+		#descriptors can be returned as python dictionaries
+		output0={
+		'identifier':'vampy-counts',
+		'name':'Number of Zero Crossings',
+		'description':'Number of zero crossings per audio frame',
+		'unit':' ',
+		'hasFixedBinCount':True,
+		'binCount':1,
+		#'binNames':['1 Hz',1.5,'2 Hz',3,'4 Hz'],
+		'hasKnownExtents':False,
+		#'minValue':0.0,
+		#'maxValue':0.0,
+		'isQuantized':True,
+		'quantizeStep':1.0,
+		'sampleType':'OneSamplePerStep'
+		#'sampleRate':48000.0
+		}
+
+		output1={
+		'identifier':'vampy-crossings',
+		'name':'Zero Crossing Locations',
+		'description':'The locations of zero crossing points',
+		'unit':'discrete',
+		'hasFixedBinCount':True,
+		'binCount':0,
+		'sampleType':'VariableSampleRate'
+		}
+
+		return [output0,output1]
+
+
+	def getParameterDescriptors(self):
+		paramlist1={
+		'identifier':'threshold',
+		'name':'Noise threshold',
+		'description':'',
+		'unit':'v',
+		'minValue':0.0,
+		'maxValue':0.5,
+		'defaultValue':0.005,
+		'isQuantized':False
+		}
+		return [paramlist1]
+
+
+	def setParameter(self,paramid,newval):
+		if paramid == 'threshold' :
+			self.threshold = newval
+		return
+
+		
+	def getParameter(self,paramid):
+		if paramid == 'threshold' :
+			return self.threshold
+		else:
+			return 0.0
+
+
+	# legacy process type: the input is a python list of samples
+	def process(self,inbuf,timestamp):
+		crossing = False
+		prev = self.previousSample
+		count = 0.0;
+		channel = inbuf[0]
+
+		#we have two outputs defined thus we have to declare
+		#them as empty dictionaries in our output list
+		#in order to be able to return variable rate outputs
+		output0=[]
+		output1=[]
+
+		if sum([abs(s) for s in channel]) > self.threshold : 
+
+			for x in range(len(channel)-1) :
+				crossing = False
+				sample = channel[x]
+				if sample <= 0.0 : 
+					if prev > 0.0 : crossing = True
+				else :
+					if sample > 0.0 :
+						if prev <= 0.0 : crossing = True		
+			
+				if crossing == True : 
+					count = count + 1
+					feature1={
+					'hasTimestamp':True,	
+					'timeStamp':long(timestamp + x),				
+					'values':[count],			
+					'label':str(count),				
+					}				
+					output1.append(feature1)
+			
+				prev = sample	
+			self.previousSample = prev
+
+		else :
+			count = 0.0
+			self.previousSample = channel[len(channel)-1]
+
+		feature0={
+		'hasTimestamp':False,		
+		'values':[count],
+		'label':str(count)				
+		}
+		output0.append(feature0)
+		
+		#return a LIST of list of dictionaries
+		return [output0,output1]
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Example VamPy plugins/obsolete/PySpectralCentroid.py	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,132 @@
+'''PySpectralCentroid.py - Example plugin demonstrates 
+how to write a C style plugin using VamPy.
+
+Obsolete warning: this plugin will no longer be supported 
+since the legacy interface should pass a list of complex
+numbers for frequency domain plugins and a list of floats
+for time domin plugins.
+
+'''
+
+from numpy import *
+
+class PySpectralCentroid: 
+	
+	def __init__(self,inputSampleRate): 
+		self.m_imputSampleRate = 0.0 
+		self.m_stepSize = 0
+		self.m_blockSize = 0
+		self.m_channels = 0
+		self.previousSample = 0.0
+		self.m_inputSampleRate = inputSampleRate
+		self.threshold = 0.00
+		
+	def initialise(self,channels,stepSize,blockSize):
+		self.m_channels = channels
+		self.m_stepSize = stepSize		
+		self.m_blockSize = blockSize
+		return True
+	
+	def getMaker(self):
+		return 'Vampy Example Plugins'
+	
+	def getName(self):
+		return 'Spectral Centroid (legacy process interface)'
+		
+	def getIdentifier(self):
+		return 'vampy-sc2'
+	
+	def getMaxChannelCount(self):
+		return 1
+		
+	def getInputDomain(self):
+		return 'FrequencyDomain'
+			
+	def getOutputDescriptors(self):
+		
+		output0={
+		'identifier':'vampy-sf1',
+		'name':'Spectral Centroid',
+		'description':'Spectral Centroid (Brightness)',
+		'unit':' ',
+		'hasFixedBinCount':True,
+		'binCount':1,
+		'hasKnownExtents':False,
+		'isQuantized':True,
+		'quantizeStep':1.0,
+		'sampleType':'OneSamplePerStep'
+		}
+
+		return [output0]
+
+	def getParameterDescriptors(self):
+		paramlist1={
+		'identifier':'threshold',
+		'name':'Noise threshold: ',
+		'description':'Return null or delete this function if not needed.',
+		'unit':'v',
+		'minValue':0.0,
+		'maxValue':0.5,
+		'defaultValue':0.05,
+		'isQuantized':False
+		}
+		return [paramlist1]
+
+	def setParameter(self,paramid,newval):
+		if paramid == 'threshold' :
+			self.threshold = newval
+		return
+		
+	def getParameter(self,paramid):
+		if paramid == 'threshold' :
+			return self.threshold
+		else:
+			return 0.0
+			
+	def process(self,inbuf,timestamp):
+		
+		inArray = array(inbuf[0])
+		crossing = False
+		prev = self.previousSample
+		count = 0.0
+		numLin = 0.0
+		denom = 0.0
+		centroid = 0.0
+		
+		# re = array(inbuf[2:len(inArray):2])
+		# im = array(inbuf[3:len(inArray):2])
+
+		output0=[]
+		output1=[]
+
+		# pw = 0
+		# for i in xrange(1,len(inbuf[0])) : 
+		# 	pw = pw + abs(inbuf[0][i])
+		
+		if sum(abs(inArray)) > self.threshold : 
+			for i in range(1,(len(inArray)/2)) :
+			# for i in range(1,len(inbuf[0])) :
+				
+				re = inArray[i*2]
+				im = inArray[i*2+1]
+				# re = inbuf[0][i].real
+				# im = inbuf[0][i].imag
+				freq = i * self.m_inputSampleRate / self.m_blockSize
+				power = sqrt (re*re + im*im) / (self.m_blockSize/2)
+				denom = denom + power
+				numLin = numLin + freq * power
+				
+			if denom != 0 :
+				centroid = numLin / denom 
+				
+		else :
+			centroid = 0.0
+
+		feature0={
+		'hasTimestamp':False,		
+		'values':[centroid],		#strictly must be a list
+		'label':str(centroid)				
+		}
+		output0.append(feature0)
+		
+		return [output0]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Example VamPy plugins/test/PyMFCC_buffer.py	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,392 @@
+'''PyMFCC_buffer.py - This example Vampy plugin demonstrates
+how to return sprectrogram-like features.
+
+This plugin uses the numpy BUFFER interface and 
+frequency domain input. Flag: vf_BUFFER
+
+Centre for Digital Music, Queen Mary University of London.
+Copyright 2006 Gyorgy Fazekas, QMUL. 
+(See Vamp API for licence information.)
+
+Constants for Mel frequency conversion and filter 
+centre calculation are taken from the GNU GPL licenced 
+Freespeech library. Copyright (C) 1999 Jean-Marc Valin
+'''
+
+import sys,numpy
+from numpy import log,exp,floor,sum
+from numpy import *       
+from numpy.fft import *
+import vampy
+from vampy import *
+
+class melScaling(object):
+
+	def __init__(self,sampleRate,inputSize,numBands,minHz = 0,maxHz = None):
+		'''Initialise frequency warping and DCT matrix. 
+		Parameters:
+		sampleRate: audio sample rate
+		inputSize: length of magnitude spectrum (half of FFT size assumed)
+		numBands: number of mel Bands (MFCCs)
+		minHz: lower bound of warping  (default = DC)
+		maxHz: higher bound of warping (default = Nyquist frequency)
+		'''
+		self.sampleRate = sampleRate
+		self.NqHz = sampleRate / 2.0
+		self.minHz = minHz
+		if maxHz is None : maxHz = self.NqHz
+		self.maxHz = maxHz
+		self.inputSize = inputSize
+		self.numBands = numBands
+		self.valid = False
+		self.updated = False
+		
+	def update(self): 
+		# make sure this will run only once if called from a vamp process
+		
+		if self.updated: return self.valid
+		self.updated = True
+		self.valid = False
+		print 'Updating parameters and recalculating filters: '
+		print 'Nyquist: ',self.NqHz
+		
+		if self.maxHz > self.NqHz : 
+			raise Exception('Maximum frequency must be smaller than the Nyquist frequency')
+		
+		self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
+		self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
+		print 'minHz:%s\nmaxHz:%s\nminMel:%s\nmaxMel:%s\n' %(self.minHz,self.maxHz,self.minMel,self.maxMel)
+		self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
+		self.DCTMatrix = self.getDCTMatrix(self.numBands)
+		self.filterIter = self.filterMatrix.__iter__()
+		self.valid = True
+		return self.valid
+		
+		# try :
+		# 	self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
+		# 	self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
+		# 	self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
+		# 	self.DCTMatrix = self.getDCTMatrix(self.numBands)
+		# 	self.filterIter = self.filterMatrix.__iter__()
+		# 	self.valid = True
+		# 	return True
+		# except :
+		# 	print "Invalid parameter setting encountered in MelScaling class."
+		# 	return False
+		# return True
+		
+	def getFilterCentres(self,inputSize,numBands):
+		'''Calculate Mel filter centres around FFT bins.
+		This function calculates two extra bands at the edges for
+		finding the starting and end point of the first and last 
+		actual filters.'''
+		centresMel = numpy.array(xrange(numBands+2)) * (self.maxMel-self.minMel)/(numBands+1) + self.minMel
+		centresBin = numpy.floor(0.5 + 700.0*inputSize*(exp(centresMel*log(1+1000.0/700.0)/1000.0)-1)/self.NqHz)
+		return numpy.array(centresBin,int)
+		
+	def getFilterMatrix(self,inputSize,numBands):
+		'''Compose the Mel scaling matrix.'''
+		filterMatrix = numpy.zeros((numBands,inputSize))
+		self.filterCentres = self.getFilterCentres(inputSize,numBands)
+		for i in xrange(numBands) :
+			start,centre,end = self.filterCentres[i:i+3]
+			self.setFilter(filterMatrix[i],start,centre,end)
+		return filterMatrix.transpose()
+
+	def setFilter(self,filt,filterStart,filterCentre,filterEnd):
+		'''Calculate a single Mel filter.'''
+		k1 = numpy.float32(filterCentre-filterStart)
+		k2 = numpy.float32(filterEnd-filterCentre)
+		up = (numpy.array(xrange(filterStart,filterCentre))-filterStart)/k1
+		dn = (filterEnd-numpy.array(xrange(filterCentre,filterEnd)))/k2
+		filt[filterStart:filterCentre] = up
+		filt[filterCentre:filterEnd] = dn
+						
+	def warpSpectrum(self,magnitudeSpectrum):
+		'''Compute the Mel scaled spectrum.'''
+		return numpy.dot(magnitudeSpectrum,self.filterMatrix)
+		
+	def getDCTMatrix(self,size):
+		'''Calculate the square DCT transform matrix. Results are 
+		equivalent to Matlab dctmtx(n) but with 64 bit precision.'''
+		DCTmx = numpy.array(xrange(size),numpy.float64).repeat(size).reshape(size,size)
+		DCTmxT = numpy.pi * (DCTmx.transpose()+0.5) / size
+		DCTmxT = (1.0/sqrt( size / 2.0)) * cos(DCTmx * DCTmxT)
+		DCTmxT[0] = DCTmxT[0] * (sqrt(2.0)/2.0)
+		return DCTmxT
+		
+	def dct(self,data_matrix):
+		'''Compute DCT of input matrix.'''
+		return numpy.dot(self.DCTMatrix,data_matrix)
+		
+	def getMFCCs(self,warpedSpectrum,cn=True):
+		'''Compute MFCC coefficients from Mel warped magnitude spectrum.'''
+		mfccs=self.dct(numpy.log(warpedSpectrum))
+		if cn is False : mfccs[0] = 0.0
+		return mfccs
+	
+
+class PyMFCC_buffer(melScaling): 
+	
+	def __init__(self,inputSampleRate):
+		
+		# flags for setting some Vampy options
+		self.vampy_flags = vf_DEBUG | vf_BUFFER | vf_REALTIME
+
+		self.m_inputSampleRate = int(inputSampleRate)
+		self.m_stepSize = 512
+		self.m_blockSize = 2048
+		self.m_channels = 1
+		self.numBands = 40
+		self.cnull = 1
+		self.two_ch = False
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		
+	def initialise(self,channels,stepSize,blockSize):
+		self.m_channels = channels
+		self.m_stepSize = stepSize		
+		self.m_blockSize = blockSize
+		self.window = numpy.hamming(blockSize)
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		return True
+	
+	def getMaker(self):
+		return 'Vampy Test Plugins'
+		
+	def getCopyright(self):
+		return 'Plugin By George Fazekas'
+	
+	def getName(self):
+		return 'Vampy Buffer MFCC Plugin'
+		
+	def getIdentifier(self):
+		return 'vampy-mfcc-test-buffer'
+
+	def getDescription(self):
+		return 'A simple MFCC plugin. (using the Buffer interface)'
+	
+	def getMaxChannelCount(self):
+		return 2
+		
+	def getInputDomain(self):
+		return FrequencyDomain
+		
+	def getPreferredBlockSize(self):
+		return 2048
+		
+	def getPreferredStepSize(self):
+		return 512
+			
+	def getOutputDescriptors(self):
+		
+		Generic = OutputDescriptor() 
+		Generic.hasFixedBinCount=True
+		Generic.binCount=int(self.numBands)-self.cnull
+		Generic.hasKnownExtents=False
+		Generic.isQuantized=True
+		Generic.sampleType = OneSamplePerStep 
+		
+		# note the inheritance of attributes (use is optional)
+		MFCC = OutputDescriptor(Generic)
+		MFCC.identifier = 'mfccs'
+		MFCC.name = 'MFCCs'
+		MFCC.description = 'MFCC Coefficients'
+		MFCC.binNames=map(lambda x: 'C '+str(x),range(self.cnull,int(self.numBands)))
+		MFCC.unit = None
+		if self.two_ch and self.m_channels == 2 :
+			MFCC.binCount = self.m_channels * (int(self.numBands)-self.cnull)
+		else :
+			MFCC.binCount = self.numBands-self.cnull
+				
+		warpedSpectrum = OutputDescriptor(Generic)
+		warpedSpectrum.identifier='warped-fft'
+		warpedSpectrum.name='Mel Scaled Spectrum'
+		warpedSpectrum.description='Mel Scaled Magnitide Spectrum'
+		warpedSpectrum.unit='Mel'
+		if self.two_ch and self.m_channels == 2 :
+			warpedSpectrum.binCount = self.m_channels * int(self.numBands) 
+		else :
+			warpedSpectrum.binCount = self.numBands
+		
+		melFilter = OutputDescriptor(Generic)
+		melFilter.identifier = 'mel-filter-matrix'
+		melFilter.sampleType='FixedSampleRate'
+		melFilter.sampleRate=self.m_inputSampleRate/self.m_stepSize
+		melFilter.name='Mel Filter Matrix'
+		melFilter.description='Returns the created filter matrix in getRemainingFeatures.'
+		melFilter.unit = None
+				
+		return OutputList(MFCC,warpedSpectrum,melFilter)
+		
+
+	def getParameterDescriptors(self):
+
+		melbands = ParameterDescriptor()
+		melbands.identifier='melbands'
+		melbands.name='Number of bands (coefficients)'
+		melbands.description='Set the number of coefficients.'
+		melbands.unit = ''
+		melbands.minValue = 2
+		melbands.maxValue = 128
+		melbands.defaultValue = 40
+		melbands.isQuantized = True
+		melbands.quantizeStep = 1
+				
+		cnull = ParameterDescriptor()
+		cnull.identifier='cnull'
+		cnull.name='Return C0'
+		cnull.description='Select if the DC coefficient is required.'
+		cnull.unit = None
+		cnull.minValue = 0
+		cnull.maxValue = 1
+		cnull.defaultValue = 0
+		cnull.isQuantized = True
+		cnull.quantizeStep = 1
+		
+		two_ch = ParameterDescriptor(cnull)
+		two_ch.identifier='two_ch'
+		two_ch.name='Process channels separately'
+		two_ch.description='Process two channel files separately.'
+		two_ch.defaultValue = False
+				
+		minHz = ParameterDescriptor()
+		minHz.identifier='minHz'
+		minHz.name='minimum frequency'
+		minHz.description='Set the lower frequency bound.'
+		minHz.unit='Hz'
+		minHz.minValue = 0
+		minHz.maxValue = 24000
+		minHz.defaultValue = 0
+		minHz.isQuantized = True
+		minHz.quantizeStep = 1.0
+		
+		maxHz = ParameterDescriptor()
+		maxHz.identifier='maxHz'
+		maxHz.description='Set the upper frequency bound.'
+		maxHz.name='maximum frequency'
+		maxHz.unit='Hz'
+		maxHz.minValue = 100
+		maxHz.maxValue = 24000
+		maxHz.defaultValue = 11025
+		maxHz.isQuantized = True
+		maxHz.quantizeStep = 100
+		
+		return ParameterList(melbands,minHz,maxHz,cnull,two_ch)
+		
+
+	def setParameter(self,paramid,newval):
+		self.valid = False
+		if paramid == 'minHz' :
+			if newval < self.maxHz and newval < self.NqHz :
+				self.minHz = float(newval)
+			print 'minHz: ', self.minHz
+		if paramid == 'maxHz' :
+			print 'trying to set maxHz to: ',newval
+			if newval < self.NqHz and newval > self.minHz+1000 :
+				self.maxHz = float(newval)
+			else :
+				self.maxHz = self.NqHz
+			print 'set to: ',self.maxHz
+		if paramid == 'cnull' :
+			self.cnull = int(not int(newval))
+		if paramid == 'melbands' :
+			self.numBands = int(newval)
+		if paramid == 'two_ch' :
+			self.two_ch = bool(newval)
+			
+		return 
+				
+	def getParameter(self,paramid):
+		if paramid == 'minHz' :
+			return float(self.minHz)
+		if paramid == 'maxHz' :
+			return float(self.maxHz)
+		if paramid == 'cnull' :
+			return float(not int(self.cnull))
+		if paramid == 'melbands' :
+			return float(self.numBands)
+		if paramid == 'two_ch' :
+			return float(self.two_ch)
+		else:
+			return 0.0
+
+	# numpy process using the buffer interface
+	def process(self,inputbuffers,timestamp):
+
+		if not self.update() : return None
+		
+		if self.m_channels == 2 and self.two_ch :
+			return self.process2ch(inputbuffers,timestamp)
+		
+		fftsize = self.m_blockSize
+		
+		if self.m_channels > 1 :
+			# take the mean of the two magnitude spectra
+			complexSpectrum0 = frombuffer(inputbuffers[0],complex64,-1,0)
+			complexSpectrum1 = frombuffer(inputbuffers[1],complex64,-1,0)
+			magnitudeSpectrum0 = abs(complexSpectrum0)[0:fftsize/2]
+			magnitudeSpectrum1 = abs(complexSpectrum1)[0:fftsize/2]
+			magnitudeSpectrum = (magnitudeSpectrum0 + magnitudeSpectrum1) / 2
+		else :
+			complexSpectrum = frombuffer(inputbuffers[0],complex64,-1,0)
+			magnitudeSpectrum = abs(complexSpectrum)[0:fftsize/2]
+						
+		# do the computation
+		melSpectrum = self.warpSpectrum(magnitudeSpectrum)
+		melCepstrum = self.getMFCCs(melSpectrum,cn=True)
+		
+		# output feature set (the builtin dict type can also be used)
+		outputs = FeatureSet()
+		outputs[0] = Feature(melCepstrum[self.cnull:])
+		outputs[1] = Feature(melSpectrum)
+		
+		return outputs
+
+	# process two channel files (stack the returned arrays)
+	def process2ch(self,inputbuffers,timestamp):
+
+		fftsize = self.m_blockSize
+		
+		complexSpectrum0 = frombuffer(inputbuffers[0],complex64,-1,0)
+		complexSpectrum1 = frombuffer(inputbuffers[1],complex64,-1,0)
+		
+		magnitudeSpectrum0 = abs(complexSpectrum0)[0:fftsize/2]
+		magnitudeSpectrum1 = abs(complexSpectrum1)[0:fftsize/2]
+		
+		# do the computations
+		melSpectrum0 = self.warpSpectrum(magnitudeSpectrum0)
+		melCepstrum0 = self.getMFCCs(melSpectrum0,cn=True)
+		melSpectrum1 = self.warpSpectrum(magnitudeSpectrum1)
+		melCepstrum1 = self.getMFCCs(melSpectrum1,cn=True)
+		
+		outputs = FeatureSet()
+		
+		outputs[0] = Feature(hstack((melCepstrum1[self.cnull:],melCepstrum0[self.cnull:])))
+		
+		outputs[1] = Feature(hstack((melSpectrum1,melSpectrum0)))
+		
+		return outputs
+
+
+	def getRemainingFeatures(self):
+		if not self.update() : return []
+		frameSampleStart = 0
+		
+		output_featureSet = FeatureSet()
+
+		# the filter is the third output (index starts from zero)
+		output_featureSet[2] = flist = FeatureList()
+
+		while True:
+			f = Feature()
+			f.hasTimestamp = True
+			f.timestamp = frame2RealTime(frameSampleStart,self.m_inputSampleRate)
+			try :
+				f.values = self.filterIter.next()
+			except StopIteration :
+				break
+			flist.append(f)
+			frameSampleStart += self.m_stepSize
+
+		return output_featureSet
+		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Example VamPy plugins/test/PyMFCC_freq.py	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,392 @@
+'''PyMFCC_freq.py - This example Vampy plugin demonstrates
+how to return sprectrogram-like features.
+
+This plugin has frequency domain input and is using
+the numpy array interface. Flag: vf_ARRAY
+
+Centre for Digital Music, Queen Mary University of London.
+Copyright 2006 Gyorgy Fazekas, QMUL. 
+(See Vamp API for licence information.)
+
+Constants for Mel frequency conversion and filter 
+centre calculation are taken from the GNU GPL licenced 
+Freespeech library. Copyright (C) 1999 Jean-Marc Valin
+'''
+
+import sys,numpy
+from numpy import log,exp,floor,sum
+from numpy import *       
+from numpy.fft import *
+import vampy
+from vampy import *
+
+
+class melScaling(object):
+
+	def __init__(self,sampleRate,inputSize,numBands,minHz = 0,maxHz = None):
+		'''Initialise frequency warping and DCT matrix. 
+		Parameters:
+		sampleRate: audio sample rate
+		inputSize: length of magnitude spectrum (half of FFT size assumed)
+		numBands: number of mel Bands (MFCCs)
+		minHz: lower bound of warping  (default = DC)
+		maxHz: higher bound of warping (default = Nyquist frequency)
+		'''
+		self.sampleRate = sampleRate
+		self.NqHz = sampleRate / 2.0
+		self.minHz = minHz
+		if maxHz is None : maxHz = self.NqHz
+		self.maxHz = maxHz
+		self.inputSize = inputSize
+		self.numBands = numBands
+		self.valid = False
+		self.updated = False
+		
+		
+	def update(self): 
+		# make sure this will run only once if called from a vamp process
+		
+		if self.updated: return self.valid
+		self.updated = True
+		self.valid = False
+		print 'Updating parameters and recalculating filters: '
+		print 'Nyquist: ',self.NqHz
+		
+		if self.maxHz > self.NqHz : 
+			raise Exception('Maximum frequency must be smaller than the Nyquist frequency')
+		
+		self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
+		self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
+		print 'minHz:%s\nmaxHz:%s\nminMel:%s\nmaxMel:%s\n' %(self.minHz,self.maxHz,self.minMel,self.maxMel)
+		self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
+		self.DCTMatrix = self.getDCTMatrix(self.numBands)
+		self.filterIter = self.filterMatrix.__iter__()
+		self.valid = True
+		return self.valid
+		
+		# try :
+		# 	self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
+		# 	self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
+		# 	self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
+		# 	self.DCTMatrix = self.getDCTMatrix(self.numBands)
+		# 	self.filterIter = self.filterMatrix.__iter__()
+		# 	self.valid = True
+		# 	return True
+		# except :
+		# 	print "Invalid parameter setting encountered in MelScaling class."
+		# 	return False
+		# return True
+		
+	def getFilterCentres(self,inputSize,numBands):
+		'''Calculate Mel filter centres around FFT bins.
+		This function calculates two extra bands at the edges for
+		finding the starting and end point of the first and last 
+		actual filters.'''
+		centresMel = numpy.array(xrange(numBands+2)) * (self.maxMel-self.minMel)/(numBands+1) + self.minMel
+		centresBin = numpy.floor(0.5 + 700.0*inputSize*(exp(centresMel*log(1+1000.0/700.0)/1000.0)-1)/self.NqHz)
+		return numpy.array(centresBin,int)
+		
+	def getFilterMatrix(self,inputSize,numBands):
+		'''Compose the Mel scaling matrix.'''
+		filterMatrix = numpy.zeros((numBands,inputSize))
+		self.filterCentres = self.getFilterCentres(inputSize,numBands)
+		for i in xrange(numBands) :
+			start,centre,end = self.filterCentres[i:i+3]
+			self.setFilter(filterMatrix[i],start,centre,end)
+		return filterMatrix.transpose()
+
+	def setFilter(self,filt,filterStart,filterCentre,filterEnd):
+		'''Calculate a single Mel filter.'''
+		k1 = numpy.float32(filterCentre-filterStart)
+		k2 = numpy.float32(filterEnd-filterCentre)
+		up = (numpy.array(xrange(filterStart,filterCentre))-filterStart)/k1
+		dn = (filterEnd-numpy.array(xrange(filterCentre,filterEnd)))/k2
+		filt[filterStart:filterCentre] = up
+		filt[filterCentre:filterEnd] = dn
+						
+	def warpSpectrum(self,magnitudeSpectrum):
+		'''Compute the Mel scaled spectrum.'''
+		return numpy.dot(magnitudeSpectrum,self.filterMatrix)
+		
+	def getDCTMatrix(self,size):
+		'''Calculate the square DCT transform matrix. Results are 
+		equivalent to Matlab dctmtx(n) but with 64 bit precision.'''
+		DCTmx = numpy.array(xrange(size),numpy.float64).repeat(size).reshape(size,size)
+		DCTmxT = numpy.pi * (DCTmx.transpose()+0.5) / size
+		DCTmxT = (1.0/sqrt( size / 2.0)) * cos(DCTmx * DCTmxT)
+		DCTmxT[0] = DCTmxT[0] * (sqrt(2.0)/2.0)
+		return DCTmxT
+		
+	def dct(self,data_matrix):
+		'''Compute DCT of input matrix.'''
+		return numpy.dot(self.DCTMatrix,data_matrix)
+		
+	def getMFCCs(self,warpedSpectrum,cn=True):
+		'''Compute MFCC coefficients from Mel warped magnitude spectrum.'''
+		mfccs=self.dct(numpy.log(warpedSpectrum))
+		if cn is False : mfccs[0] = 0.0
+		return mfccs
+	
+
+class PyMFCC_freq(melScaling): 
+	
+	def __init__(self,inputSampleRate):
+		
+		# flags for setting some Vampy options
+		self.vampy_flags = vf_DEBUG | vf_ARRAY | vf_REALTIME
+
+		self.m_inputSampleRate = int(inputSampleRate)
+		self.m_stepSize = 512
+		self.m_blockSize = 2048
+		self.m_channels = 1
+		self.numBands = 40
+		self.cnull = 1
+		self.two_ch = False
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		
+	def initialise(self,channels,stepSize,blockSize):
+		self.m_channels = channels
+		self.m_stepSize = stepSize		
+		self.m_blockSize = blockSize
+		self.window = numpy.hamming(blockSize)
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		return True
+	
+	def getMaker(self):
+		return 'Vampy Test Plugins'
+		
+	def getCopyright(self):
+		return 'Plugin By George Fazekas'
+	
+	def getName(self):
+		return 'Vampy FrequencyDomain MFCC Plugin'
+		
+	def getIdentifier(self):
+		return 'vampy-mfcc-test-freq'
+
+	def getDescription(self):
+		return 'A simple MFCC plugin. (FrequencyDomain)'
+	
+	def getMaxChannelCount(self):
+		return 2
+		
+	def getInputDomain(self):
+		return FrequencyDomain 
+		
+	def getPreferredBlockSize(self):
+		return 2048
+		
+	def getPreferredStepSize(self):
+		return 512
+			
+	def getOutputDescriptors(self):
+		
+		Generic = OutputDescriptor() 
+		Generic.hasFixedBinCount=True
+		Generic.binCount=int(self.numBands)-self.cnull
+		Generic.hasKnownExtents=False
+		Generic.isQuantized=True
+		Generic.sampleType = OneSamplePerStep 
+		
+		# note the inheritance of attributes (use is optional)
+		MFCC = OutputDescriptor(Generic)
+		MFCC.identifier = 'mfccs'
+		MFCC.name = 'MFCCs'
+		MFCC.description = 'MFCC Coefficients'
+		MFCC.binNames=map(lambda x: 'C '+str(x),range(self.cnull,int(self.numBands)))
+		MFCC.unit = None
+		if self.two_ch and self.m_channels == 2 :
+			MFCC.binCount = self.m_channels * (int(self.numBands)-self.cnull)
+		else :
+			MFCC.binCount = self.numBands-self.cnull
+				
+		warpedSpectrum = OutputDescriptor(Generic)
+		warpedSpectrum.identifier='warped-fft'
+		warpedSpectrum.name='Mel Scaled Spectrum'
+		warpedSpectrum.description='Mel Scaled Magnitide Spectrum'
+		warpedSpectrum.unit='Mel'
+		if self.two_ch and self.m_channels == 2 :
+			warpedSpectrum.binCount = self.m_channels * int(self.numBands) 
+		else :
+			warpedSpectrum.binCount = self.numBands
+		
+		melFilter = OutputDescriptor(Generic)
+		melFilter.identifier = 'mel-filter-matrix'
+		melFilter.sampleType='FixedSampleRate'
+		melFilter.sampleRate=self.m_inputSampleRate/self.m_stepSize
+		melFilter.name='Mel Filter Matrix'
+		melFilter.description='Returns the created filter matrix in getRemainingFeatures.'
+		melFilter.unit = None
+				
+		return OutputList(MFCC,warpedSpectrum,melFilter)
+		
+
+	def getParameterDescriptors(self):
+
+		melbands = ParameterDescriptor()
+		melbands.identifier='melbands'
+		melbands.name='Number of bands (coefficients)'
+		melbands.description='Set the number of coefficients.'
+		melbands.unit = ''
+		melbands.minValue = 2
+		melbands.maxValue = 128
+		melbands.defaultValue = 40
+		melbands.isQuantized = True
+		melbands.quantizeStep = 1
+				
+		cnull = ParameterDescriptor()
+		cnull.identifier='cnull'
+		cnull.name='Return C0'
+		cnull.description='Select if the DC coefficient is required.'
+		cnull.unit = None
+		cnull.minValue = 0
+		cnull.maxValue = 1
+		cnull.defaultValue = 0
+		cnull.isQuantized = True
+		cnull.quantizeStep = 1
+		
+		two_ch = ParameterDescriptor(cnull)
+		two_ch.identifier='two_ch'
+		two_ch.name='Process channels separately'
+		two_ch.description='Process two channel files separately.'
+		two_ch.defaultValue = False
+				
+		minHz = ParameterDescriptor()
+		minHz.identifier='minHz'
+		minHz.name='minimum frequency'
+		minHz.description='Set the lower frequency bound.'
+		minHz.unit='Hz'
+		minHz.minValue = 0
+		minHz.maxValue = 24000
+		minHz.defaultValue = 0
+		minHz.isQuantized = True
+		minHz.quantizeStep = 1.0
+		
+		maxHz = ParameterDescriptor()
+		maxHz.identifier='maxHz'
+		maxHz.description='Set the upper frequency bound.'
+		maxHz.name='maximum frequency'
+		maxHz.unit='Hz'
+		maxHz.minValue = 100
+		maxHz.maxValue = 24000
+		maxHz.defaultValue = 11025
+		maxHz.isQuantized = True
+		maxHz.quantizeStep = 100
+		
+		return ParameterList(melbands,minHz,maxHz,cnull,two_ch)
+		
+
+	def setParameter(self,paramid,newval):
+		self.valid = False
+		if paramid == 'minHz' :
+			if newval < self.maxHz and newval < self.NqHz :
+				self.minHz = float(newval)
+			print 'minHz: ', self.minHz
+		if paramid == 'maxHz' :
+			print 'trying to set maxHz to: ',newval
+			if newval < self.NqHz and newval > self.minHz+1000 :
+				self.maxHz = float(newval)
+			else :
+				self.maxHz = self.NqHz
+			print 'set to: ',self.maxHz
+		if paramid == 'cnull' :
+			self.cnull = int(not int(newval))
+		if paramid == 'melbands' :
+			self.numBands = int(newval)
+		if paramid == 'two_ch' :
+			self.two_ch = bool(newval)
+			
+		return 
+				
+	def getParameter(self,paramid):
+		if paramid == 'minHz' :
+			return float(self.minHz)
+		if paramid == 'maxHz' :
+			return float(self.maxHz)
+		if paramid == 'cnull' :
+			return float(not int(self.cnull))
+		if paramid == 'melbands' :
+			return float(self.numBands)
+		if paramid == 'two_ch' :
+			return float(self.two_ch)
+		else:
+			return 0.0
+
+	# set numpy process using the 'use_numpy_interface' flag		
+	def process(self,inputbuffers,timestamp):
+		
+		if not self.update() : return None
+		
+		if self.m_channels == 2 and self.two_ch :
+			return self.process2ch(inputbuffers,timestamp)
+
+		fftsize = self.m_blockSize
+				
+		if self.m_channels > 1 :
+			# take the mean of the two magnitude spectra
+			complexSpectrum0 = inputbuffers[0]
+			complexSpectrum1 = inputbuffers[1]
+			magnitudeSpectrum0 = abs(complexSpectrum0)[0:fftsize/2]
+			magnitudeSpectrum1 = abs(complexSpectrum1)[0:fftsize/2]
+			magnitudeSpectrum = (magnitudeSpectrum0 + magnitudeSpectrum1) / 2
+		else :
+			complexSpectrum = inputbuffers[0]
+			magnitudeSpectrum = abs(complexSpectrum)[0:fftsize/2]
+		
+		# do the computation
+		melSpectrum = self.warpSpectrum(magnitudeSpectrum)
+		melCepstrum = self.getMFCCs(melSpectrum,cn=True)
+		
+		outputs = FeatureSet()
+		outputs[0] = Feature(melCepstrum[self.cnull:])
+		outputs[1] = Feature(melSpectrum)		
+		return outputs
+
+
+	# process channels separately (stack the returned arrays)
+	def process2ch(self,inputbuffers,timestamp):
+
+		fftsize = self.m_blockSize
+		
+		complexSpectrum0 = inputbuffers[0]
+		complexSpectrum1 = inputbuffers[1]
+		
+		magnitudeSpectrum0 = abs(complexSpectrum0)[0:fftsize/2]
+		magnitudeSpectrum1 = abs(complexSpectrum1)[0:fftsize/2]
+		
+		# do the computations
+		melSpectrum0 = self.warpSpectrum(magnitudeSpectrum0)
+		melCepstrum0 = self.getMFCCs(melSpectrum0,cn=True)
+		melSpectrum1 = self.warpSpectrum(magnitudeSpectrum1)
+		melCepstrum1 = self.getMFCCs(melSpectrum1,cn=True)
+		
+		outputs = FeatureSet()
+		
+		outputs[0] = Feature(hstack((melCepstrum1[self.cnull:],melCepstrum0[self.cnull:])))
+		
+		outputs[1] = Feature(hstack((melSpectrum1,melSpectrum0)))
+		
+		return outputs
+
+
+	def getRemainingFeatures(self):
+		if not self.update() : return []
+		frameSampleStart = 0
+		
+		output_featureSet = FeatureSet()
+
+		# the filter is the third output (index starts from zero)
+		output_featureSet[2] = flist = FeatureList()
+
+		while True:
+			f = Feature()
+			f.hasTimestamp = True
+			f.timestamp = frame2RealTime(frameSampleStart,self.m_inputSampleRate)
+			try :
+				f.values = self.filterIter.next()
+			except StopIteration :
+				break
+			flist.append(f)
+			frameSampleStart += self.m_stepSize
+
+		return output_featureSet
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Example VamPy plugins/test/PyMFCC_oldstyle.py	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,361 @@
+'''PyMFCC_oldstyle.py - This example Vampy plugin demonstrates
+how to return sprectrogram-like features.
+
+This plugin uses backward compatible syntax and 
+no extension module.
+
+Centre for Digital Music, Queen Mary University of London.
+Copyright 2006 Gyorgy Fazekas, QMUL. 
+(See Vamp API for licence information.)
+
+Constants for Mel frequency conversion and filter 
+centre calculation are taken from the GNU GPL licenced 
+Freespeech library. Copyright (C) 1999 Jean-Marc Valin
+'''
+
+import sys,numpy
+from numpy import log,exp,floor,sum
+from numpy import *       
+from numpy.fft import *
+
+
+class melScaling(object):
+
+	def __init__(self,sampleRate,inputSize,numBands,minHz = 0,maxHz = None):
+		'''Initialise frequency warping and DCT matrix. 
+		Parameters:
+		sampleRate: audio sample rate
+		inputSize: length of magnitude spectrum (half of FFT size assumed)
+		numBands: number of mel Bands (MFCCs)
+		minHz: lower bound of warping  (default = DC)
+		maxHz: higher bound of warping (default = Nyquist frequency)
+		'''
+		self.sampleRate = sampleRate
+		self.NqHz = sampleRate / 2.0
+		self.minHz = minHz
+		if maxHz is None : maxHz = self.NqHz
+		self.maxHz = maxHz
+		self.inputSize = inputSize
+		self.numBands = numBands
+		self.valid = False
+		self.updated = False
+		# print '\n\n>>Plugin initialised with sample rate: %s<<\n\n' %self.sampleRate
+		# print 'minHz:%s\nmaxHz:%s\n' %(self.minHz,self.maxHz)
+		
+		
+	def update(self): 
+		# make sure this will run only once if called from a vamp process
+		
+		if self.updated: return self.valid
+		self.updated = True
+		self.valid = False
+		print 'Updating parameters and recalculating filters: '
+		print 'Nyquist: ',self.NqHz
+		
+		if self.maxHz > self.NqHz : 
+			raise Exception('Maximum frequency must be smaller than the Nyquist frequency')
+		
+		self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
+		self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
+		print 'minHz:%s\nmaxHz:%s\nminMel:%s\nmaxMel:%s\n' %(self.minHz,self.maxHz,self.minMel,self.maxMel)
+		self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
+		self.DCTMatrix = self.getDCTMatrix(self.numBands)
+		self.filterIter = self.filterMatrix.__iter__()
+		self.valid = True
+		return self.valid
+		
+		# try :
+		# 	self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
+		# 	self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
+		# 	self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
+		# 	self.DCTMatrix = self.getDCTMatrix(self.numBands)
+		# 	self.filterIter = self.filterMatrix.__iter__()
+		# 	self.valid = True
+		# 	return True
+		# except :
+		# 	print "Invalid parameter setting encountered in MelScaling class."
+		# 	return False
+		# return True
+		
+	def getFilterCentres(self,inputSize,numBands):
+		'''Calculate Mel filter centres around FFT bins.
+		This function calculates two extra bands at the edges for
+		finding the starting and end point of the first and last 
+		actual filters.'''
+		centresMel = numpy.array(xrange(numBands+2)) * (self.maxMel-self.minMel)/(numBands+1) + self.minMel
+		centresBin = numpy.floor(0.5 + 700.0*inputSize*(exp(centresMel*log(1+1000.0/700.0)/1000.0)-1)/self.NqHz)
+		return numpy.array(centresBin,int)
+		
+	def getFilterMatrix(self,inputSize,numBands):
+		'''Compose the Mel scaling matrix.'''
+		filterMatrix = numpy.zeros((numBands,inputSize))
+		self.filterCentres = self.getFilterCentres(inputSize,numBands)
+		for i in xrange(numBands) :
+			start,centre,end = self.filterCentres[i:i+3]
+			self.setFilter(filterMatrix[i],start,centre,end)
+		return filterMatrix.transpose()
+
+	def setFilter(self,filt,filterStart,filterCentre,filterEnd):
+		'''Calculate a single Mel filter.'''
+		k1 = numpy.float32(filterCentre-filterStart)
+		k2 = numpy.float32(filterEnd-filterCentre)
+		up = (numpy.array(xrange(filterStart,filterCentre))-filterStart)/k1
+		dn = (filterEnd-numpy.array(xrange(filterCentre,filterEnd)))/k2
+		filt[filterStart:filterCentre] = up
+		filt[filterCentre:filterEnd] = dn
+						
+	def warpSpectrum(self,magnitudeSpectrum):
+		'''Compute the Mel scaled spectrum.'''
+		return numpy.dot(magnitudeSpectrum,self.filterMatrix)
+		
+	def getDCTMatrix(self,size):
+		'''Calculate the square DCT transform matrix. Results are 
+		equivalent to Matlab dctmtx(n) but with 64 bit precision.'''
+		DCTmx = numpy.array(xrange(size),numpy.float64).repeat(size).reshape(size,size)
+		DCTmxT = numpy.pi * (DCTmx.transpose()+0.5) / size
+		DCTmxT = (1.0/sqrt( size / 2.0)) * cos(DCTmx * DCTmxT)
+		DCTmxT[0] = DCTmxT[0] * (sqrt(2.0)/2.0)
+		return DCTmxT
+		
+	def dct(self,data_matrix):
+		'''Compute DCT of input matrix.'''
+		return numpy.dot(self.DCTMatrix,data_matrix)
+		
+	def getMFCCs(self,warpedSpectrum,cn=True):
+		'''Compute MFCC coefficients from Mel warped magnitude spectrum.'''
+		mfccs=self.dct(numpy.log(warpedSpectrum))
+		if cn is False : mfccs[0] = 0.0
+		return mfccs
+	
+
+class PyMFCC_oldstyle(melScaling): 
+	
+	def __init__(self,inputSampleRate):
+		self.vampy_flags = 1 # vf_DEBUG = 1
+		self.m_inputSampleRate = inputSampleRate 
+		self.m_stepSize = 1024
+		self.m_blockSize = 2048
+		self.m_channels = 1
+		self.numBands = 40
+		self.cnull = 1
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		
+	def initialise(self,channels,stepSize,blockSize):
+		self.m_channels = channels
+		self.m_stepSize = stepSize		
+		self.m_blockSize = blockSize
+		self.window = numpy.hamming(blockSize)
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		return True
+	
+	def getMaker(self):
+		return 'Vampy Test Plugins'
+		
+	def getCopyright(self):
+		return 'Plugin By George Fazekas'
+	
+	def getName(self):
+		return 'Vampy Old Style MFCC Plugin'
+		
+	def getIdentifier(self):
+		return 'vampy-mfcc-test-old'
+
+	def getDescription(self):
+		return 'A simple MFCC plugin. (using the old syntax)'
+	
+	def getMaxChannelCount(self):
+		return 1
+		
+	def getInputDomain(self):
+		return 'TimeDomain'
+		
+	def getPreferredBlockSize(self):
+		return 2048
+		
+	def getPreferredStepSize(self):
+		return 512
+			
+	def getOutputDescriptors(self):
+
+		Generic={
+		'hasFixedBinCount':True,
+		'binCount':int(self.numBands)-self.cnull,
+		'hasKnownExtents':False,
+		'isQuantized':True,
+		'sampleType':'OneSamplePerStep'
+		}
+		
+		MFCC=Generic.copy()
+		MFCC.update({
+		'identifier':'mfccs',
+		'name':'MFCCs',
+		'description':'MFCC Coefficients',
+		'binNames':map(lambda x: 'C '+str(x),range(self.cnull,int(self.numBands))),
+		'unit':''		
+		})
+		
+		warpedSpectrum=Generic.copy()
+		warpedSpectrum.update({
+		'identifier':'warped-fft',
+		'name':'Mel Scaled Spectrum',
+		'description':'Mel Scaled Magnitide Spectrum',
+		'unit':'Mel'
+		})
+		
+		melFilter=Generic.copy()
+		melFilter.update({
+		'identifier':'mel-filter',
+		'name':'Mel Filter Matrix',
+		'description':'Returns the created filter matrix.',
+		'sampleType':'FixedSampleRate',
+		'sampleRate':self.m_inputSampleRate/self.m_stepSize,
+		'unit':''
+		})
+				
+		return [MFCC,warpedSpectrum,melFilter]
+
+	def getParameterDescriptors(self):
+		melbands = {
+		'identifier':'melbands',
+		'name':'Number of bands (coefficients)',
+		'description':'Set the number of coefficients.',
+		'unit':'',
+		'minValue':2.0,
+		'maxValue':128.0,
+		'defaultValue':40.0,
+		'isQuantized':True,
+		'quantizeStep':1.0
+		}
+		
+		cnull = {
+		'identifier':'cnull',
+		'name':'Return C0',
+		'description':'Select if the DC coefficient is required.',
+		'unit':'',
+		'minValue':0.0,
+		'maxValue':1.0,
+		'defaultValue':0.0,
+		'isQuantized':True,
+		'quantizeStep':1.0
+		}
+		
+		minHz = {
+		'identifier':'minHz',
+		'name':'minimum frequency',
+		'description':'Set the lower frequency bound.',
+		'unit':'Hz',
+		'minValue':0.0,
+		'maxValue':24000.0,
+		'defaultValue':0.0,
+		'isQuantized':True,
+		'quantizeStep':1.0
+		}
+				
+		maxHz = {
+		'identifier':'maxHz',
+		'name':'maximum frequency',
+		'description':'Set the upper frequency bound.',
+		'unit':'Hz',
+		'minValue':100.0,
+		'maxValue':24000.0,
+		'defaultValue':11025.0,
+		'isQuantized':True,
+		'quantizeStep':100.0
+		}
+		
+		return [melbands,minHz,maxHz,cnull]
+
+	def setParameter(self,paramid,newval):
+		self.valid = False
+		if paramid == 'minHz' :
+			if newval < self.maxHz and newval < self.NqHz :
+				self.minHz = float(newval)
+			print 'minHz: ', self.minHz
+		if paramid == 'maxHz' :
+			print 'trying to set maxHz to: ',newval
+			if newval < self.NqHz and newval > self.minHz+1000 :
+				self.maxHz = float(newval)
+			else :
+				self.maxHz = self.NqHz
+			print 'set to: ',self.maxHz
+		if paramid == 'cnull' :
+			self.cnull = int(not int(newval))
+		if paramid == 'melbands' :
+			self.numBands = int(newval)
+		return 
+				
+	def getParameter(self,paramid):
+		if paramid == 'minHz' :
+			return float(self.minHz)
+		if paramid == 'maxHz' :
+			return float(self.maxHz)
+		if paramid == 'cnull' :
+			return float(not int(self.cnull))
+		if paramid == 'melbands' :
+			return float(self.numBands)
+		else:
+			return 0.0
+			
+	def processN(self,membuffer,frameSampleStart):
+		
+		# recalculate the filter and DCT matrices if needed
+		if not self.update() : return []
+
+		fftsize = self.m_blockSize
+		audioSamples = frombuffer(membuffer[0],float32)
+
+		complexSpectrum = fft(self.window*audioSamples,fftsize)
+		#complexSpectrum =  frombuffer(membuffer[0],complex64,-1,8)
+
+		magnitudeSpectrum = abs(complexSpectrum)[0:fftsize/2] / (fftsize/2)
+		melSpectrum = self.warpSpectrum(magnitudeSpectrum)
+		melCepstrum = self.getMFCCs(melSpectrum,cn=True)
+		
+		output_melCepstrum = [{
+		'hasTimestamp':False,
+		'values':melCepstrum[self.cnull:].tolist()
+		}]
+
+		output_melSpectrum = [{
+		'hasTimestamp':False,		
+		'values':melSpectrum.tolist()
+		}]
+
+		return [output_melCepstrum,output_melSpectrum,[]]
+
+
+	def getRemainingFeatures(self):
+		if not self.update() : return []
+		frameSampleStart = 0
+		output_melFilter = []
+
+		while True:
+			try :
+				melFilter = self.filterIter.next()
+				output_melFilter.append({
+				'hasTimestamp':True,
+				'timeStamp':frameSampleStart,		
+				'values':melFilter.tolist()
+				})
+				frameSampleStart += self.m_stepSize
+			except StopIteration :
+				break;
+
+		return [[],[],output_melFilter]
+
+
+# ============================================
+# Simple Unit Tests
+# ============================================
+
+def main():
+	
+	dct = melScaling(44100,2048,numBands=4)
+	dct.update()
+	print dct.DCTMatrix
+	# print dct.getMFCCs(numpy.array([0.0,0.1,0.0,-0.1],numpy.float64))
+	sys.exit(-1)
+
+if __name__ == '__main__':
+	main()
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Example VamPy plugins/test/PyMFCC_time.py	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,398 @@
+'''PyMFCC_time.py - This example Vampy plugin demonstrates
+how to return sprectrogram-like features.
+
+This plugin has time domain input and is using
+the numpy array interface. Flag: vf_ARRAY
+
+Centre for Digital Music, Queen Mary University of London.
+Copyright 2006 Gyorgy Fazekas, QMUL. 
+(See Vamp API for licence information.)
+
+Constants for Mel frequency conversion and filter 
+centre calculation are taken from the GNU GPL licenced 
+Freespeech library. Copyright (C) 1999 Jean-Marc Valin
+'''
+
+import sys,numpy
+from numpy import log,exp,floor,sum
+from numpy import *       
+from numpy.fft import *
+import vampy
+from vampy import *
+
+
+class melScaling(object):
+
+	def __init__(self,sampleRate,inputSize,numBands,minHz = 0,maxHz = None):
+		'''Initialise frequency warping and DCT matrix. 
+		Parameters:
+		sampleRate: audio sample rate
+		inputSize: length of magnitude spectrum (half of FFT size assumed)
+		numBands: number of mel Bands (MFCCs)
+		minHz: lower bound of warping  (default = DC)
+		maxHz: higher bound of warping (default = Nyquist frequency)
+		'''
+		self.sampleRate = sampleRate
+		self.NqHz = sampleRate / 2.0
+		self.minHz = minHz
+		if maxHz is None : maxHz = self.NqHz
+		self.maxHz = maxHz
+		self.inputSize = inputSize
+		self.numBands = numBands
+		self.valid = False
+		self.updated = False
+		
+		
+	def update(self): 
+		# make sure this will run only once if called from a vamp process
+		
+		if self.updated: return self.valid
+		self.updated = True
+		self.valid = False
+		print 'Updating parameters and recalculating filters: '
+		print 'Nyquist: ',self.NqHz
+		
+		if self.maxHz > self.NqHz : 
+			raise Exception('Maximum frequency must be smaller than the Nyquist frequency')
+		
+		self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
+		self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
+		print 'minHz:%s\nmaxHz:%s\nminMel:%s\nmaxMel:%s\n' %(self.minHz,self.maxHz,self.minMel,self.maxMel)
+		self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
+		self.DCTMatrix = self.getDCTMatrix(self.numBands)
+		self.filterIter = self.filterMatrix.__iter__()
+		self.valid = True
+		return self.valid
+		
+		# try :
+		# 	self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
+		# 	self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
+		# 	self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
+		# 	self.DCTMatrix = self.getDCTMatrix(self.numBands)
+		# 	self.filterIter = self.filterMatrix.__iter__()
+		# 	self.valid = True
+		# 	return True
+		# except :
+		# 	print "Invalid parameter setting encountered in MelScaling class."
+		# 	return False
+		# return True
+		
+	def getFilterCentres(self,inputSize,numBands):
+		'''Calculate Mel filter centres around FFT bins.
+		This function calculates two extra bands at the edges for
+		finding the starting and end point of the first and last 
+		actual filters.'''
+		centresMel = numpy.array(xrange(numBands+2)) * (self.maxMel-self.minMel)/(numBands+1) + self.minMel
+		centresBin = numpy.floor(0.5 + 700.0*inputSize*(exp(centresMel*log(1+1000.0/700.0)/1000.0)-1)/self.NqHz)
+		return numpy.array(centresBin,int)
+		
+	def getFilterMatrix(self,inputSize,numBands):
+		'''Compose the Mel scaling matrix.'''
+		filterMatrix = numpy.zeros((numBands,inputSize))
+		self.filterCentres = self.getFilterCentres(inputSize,numBands)
+		for i in xrange(numBands) :
+			start,centre,end = self.filterCentres[i:i+3]
+			self.setFilter(filterMatrix[i],start,centre,end)
+		return filterMatrix.transpose()
+
+	def setFilter(self,filt,filterStart,filterCentre,filterEnd):
+		'''Calculate a single Mel filter.'''
+		k1 = numpy.float32(filterCentre-filterStart)
+		k2 = numpy.float32(filterEnd-filterCentre)
+		up = (numpy.array(xrange(filterStart,filterCentre))-filterStart)/k1
+		dn = (filterEnd-numpy.array(xrange(filterCentre,filterEnd)))/k2
+		filt[filterStart:filterCentre] = up
+		filt[filterCentre:filterEnd] = dn
+						
+	def warpSpectrum(self,magnitudeSpectrum):
+		'''Compute the Mel scaled spectrum.'''
+		return numpy.dot(magnitudeSpectrum,self.filterMatrix)
+		
+	def getDCTMatrix(self,size):
+		'''Calculate the square DCT transform matrix. Results are 
+		equivalent to Matlab dctmtx(n) but with 64 bit precision.'''
+		DCTmx = numpy.array(xrange(size),numpy.float64).repeat(size).reshape(size,size)
+		DCTmxT = numpy.pi * (DCTmx.transpose()+0.5) / size
+		DCTmxT = (1.0/sqrt( size / 2.0)) * cos(DCTmx * DCTmxT)
+		DCTmxT[0] = DCTmxT[0] * (sqrt(2.0)/2.0)
+		return DCTmxT
+		
+	def dct(self,data_matrix):
+		'''Compute DCT of input matrix.'''
+		return numpy.dot(self.DCTMatrix,data_matrix)
+		
+	def getMFCCs(self,warpedSpectrum,cn=True):
+		'''Compute MFCC coefficients from Mel warped magnitude spectrum.'''
+		mfccs=self.dct(numpy.log(warpedSpectrum))
+		if cn is False : mfccs[0] = 0.0
+		return mfccs
+	
+
+class PyMFCC_time(melScaling): 
+	
+	def __init__(self,inputSampleRate):
+		
+		# flags for setting some Vampy options
+		self.vampy_flags = vf_DEBUG | vf_ARRAY | vf_REALTIME
+
+		self.m_inputSampleRate = int(inputSampleRate)
+		self.m_stepSize = 512
+		self.m_blockSize = 2048
+		self.m_channels = 1
+		self.numBands = 40
+		self.cnull = 1
+		self.two_ch = False
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		
+	def initialise(self,channels,stepSize,blockSize):
+		self.m_channels = channels
+		self.m_stepSize = stepSize		
+		self.m_blockSize = blockSize
+		self.window = numpy.hamming(blockSize)
+		melScaling.__init__(self,int(self.m_inputSampleRate),self.m_blockSize/2,self.numBands)
+		return True
+	
+	def getMaker(self):
+		return 'Vampy Test Plugins'
+		
+	def getCopyright(self):
+		return 'Plugin By George Fazekas'
+	
+	def getName(self):
+		return 'Vampy TimeDomain MFCC Plugin'
+		
+	def getIdentifier(self):
+		return 'vampy-mfcc-test-timedomain'
+
+	def getDescription(self):
+		return 'A simple MFCC plugin. (TimeDomain)'
+	
+	def getMaxChannelCount(self):
+		return 2
+		
+	def getInputDomain(self):
+		return TimeDomain
+		
+	def getPreferredBlockSize(self):
+		return 2048
+		
+	def getPreferredStepSize(self):
+		return 512
+			
+	def getOutputDescriptors(self):
+		
+		Generic = OutputDescriptor() 
+		Generic.hasFixedBinCount=True
+		Generic.binCount=int(self.numBands)-self.cnull
+		Generic.hasKnownExtents=False
+		Generic.isQuantized=True
+		Generic.sampleType = OneSamplePerStep 
+		
+		# note the inheritance of attributes (use is optional)
+		MFCC = OutputDescriptor(Generic)
+		MFCC.identifier = 'mfccs'
+		MFCC.name = 'MFCCs'
+		MFCC.description = 'MFCC Coefficients'
+		MFCC.binNames=map(lambda x: 'C '+str(x),range(self.cnull,int(self.numBands)))
+		MFCC.unit = None
+		if self.two_ch and self.m_channels == 2 :
+			MFCC.binCount = self.m_channels * (int(self.numBands)-self.cnull)
+		else :
+			MFCC.binCount = self.numBands-self.cnull
+				
+		warpedSpectrum = OutputDescriptor(Generic)
+		warpedSpectrum.identifier='warped-fft'
+		warpedSpectrum.name='Mel Scaled Spectrum'
+		warpedSpectrum.description='Mel Scaled Magnitide Spectrum'
+		warpedSpectrum.unit='Mel'
+		if self.two_ch and self.m_channels == 2 :
+			warpedSpectrum.binCount = self.m_channels * int(self.numBands) 
+		else :
+			warpedSpectrum.binCount = self.numBands
+		
+		melFilter = OutputDescriptor(Generic)
+		melFilter.identifier = 'mel-filter-matrix'
+		melFilter.sampleType='FixedSampleRate'
+		melFilter.sampleRate=self.m_inputSampleRate/self.m_stepSize
+		melFilter.name='Mel Filter Matrix'
+		melFilter.description='Returns the created filter matrix in getRemainingFeatures.'
+		melFilter.unit = None
+				
+		return OutputList(MFCC,warpedSpectrum,melFilter)
+		
+
+	def getParameterDescriptors(self):
+
+		melbands = ParameterDescriptor()
+		melbands.identifier='melbands'
+		melbands.name='Number of bands (coefficients)'
+		melbands.description='Set the number of coefficients.'
+		melbands.unit = ''
+		melbands.minValue = 2
+		melbands.maxValue = 128
+		melbands.defaultValue = 40
+		melbands.isQuantized = True
+		melbands.quantizeStep = 1
+				
+		cnull = ParameterDescriptor()
+		cnull.identifier='cnull'
+		cnull.name='Return C0'
+		cnull.description='Select if the DC coefficient is required.'
+		cnull.unit = None
+		cnull.minValue = 0
+		cnull.maxValue = 1
+		cnull.defaultValue = 0
+		cnull.isQuantized = True
+		cnull.quantizeStep = 1
+		
+		two_ch = ParameterDescriptor(cnull)
+		two_ch.identifier='two_ch'
+		two_ch.name='Process channels separately'
+		two_ch.description='Process two channel files separately.'
+		two_ch.defaultValue = False
+				
+		minHz = ParameterDescriptor()
+		minHz.identifier='minHz'
+		minHz.name='minimum frequency'
+		minHz.description='Set the lower frequency bound.'
+		minHz.unit='Hz'
+		minHz.minValue = 0
+		minHz.maxValue = 24000
+		minHz.defaultValue = 0
+		minHz.isQuantized = True
+		minHz.quantizeStep = 1.0
+		
+		maxHz = ParameterDescriptor()
+		maxHz.identifier='maxHz'
+		maxHz.description='Set the upper frequency bound.'
+		maxHz.name='maximum frequency'
+		maxHz.unit='Hz'
+		maxHz.minValue = 100
+		maxHz.maxValue = 24000
+		maxHz.defaultValue = 11025
+		maxHz.isQuantized = True
+		maxHz.quantizeStep = 100
+		
+		return ParameterList(melbands,minHz,maxHz,cnull,two_ch)
+		
+
+	def setParameter(self,paramid,newval):
+		self.valid = False
+		if paramid == 'minHz' :
+			if newval < self.maxHz and newval < self.NqHz :
+				self.minHz = float(newval)
+			print 'minHz: ', self.minHz
+		if paramid == 'maxHz' :
+			print 'trying to set maxHz to: ',newval
+			if newval < self.NqHz and newval > self.minHz+1000 :
+				self.maxHz = float(newval)
+			else :
+				self.maxHz = self.NqHz
+			print 'set to: ',self.maxHz
+		if paramid == 'cnull' :
+			self.cnull = int(not int(newval))
+		if paramid == 'melbands' :
+			self.numBands = int(newval)
+		if paramid == 'two_ch' :
+			self.two_ch = bool(newval)
+			
+		return 
+				
+	def getParameter(self,paramid):
+		if paramid == 'minHz' :
+			return float(self.minHz)
+		if paramid == 'maxHz' :
+			return float(self.maxHz)
+		if paramid == 'cnull' :
+			return float(not int(self.cnull))
+		if paramid == 'melbands' :
+			return float(self.numBands)
+		if paramid == 'two_ch' :
+			return float(self.two_ch)
+		else:
+			return 0.0
+
+	# set numpy process using the 'use_numpy_interface' flag		
+	def process(self,inputbuffers,timestamp):
+		
+		if self.m_channels == 2 and self.two_ch :
+			return self.process2ch(inputbuffers,timestamp)
+		
+		# calculate the filter and DCT matrices, check 
+		# if they are computable given a set of parameters
+		# (we only do this once, when the process is called first)
+		if not self.update() : return None
+
+		fftsize = self.m_blockSize
+				
+		if self.m_channels > 1 :
+			audioSamples = (inputbuffers[0]+inputbuffers[1])/2
+		else :
+			audioSamples = inputbuffers[0]
+
+		#complexSpectrum =  frombuffer(membuffer[0],complex64,-1,8)
+		complexSpectrum = fft(self.window*audioSamples,fftsize)
+		magnitudeSpectrum = abs(complexSpectrum)[0:fftsize/2] / (fftsize/2)
+		
+		# do the computation
+		melSpectrum = self.warpSpectrum(magnitudeSpectrum)
+		melCepstrum = self.getMFCCs(melSpectrum,cn=True)
+		
+		# output feature set (the builtin dict type can also be used)
+		outputs = FeatureSet()
+		outputs[0] = Feature(melCepstrum[self.cnull:])
+		outputs[1] = Feature(melSpectrum)
+					
+		return outputs
+
+
+	# process two channel files (stack the returned arrays)
+	def process2ch(self,inputbuffers,timestamp):
+		if not self.update() : return None
+
+		fftsize = self.m_blockSize
+		
+		audioSamples0 = inputbuffers[0]
+		audioSamples1 = inputbuffers[1]
+
+		complexSpectrum0 = fft(self.window*audioSamples0,fftsize)
+		complexSpectrum1 = fft(self.window*audioSamples1,fftsize)
+		
+		magnitudeSpectrum0 = abs(complexSpectrum0)[0:fftsize/2] / (fftsize/2)
+		magnitudeSpectrum1 = abs(complexSpectrum1)[0:fftsize/2] / (fftsize/2)
+		
+		# do the computation
+		melSpectrum0 = self.warpSpectrum(magnitudeSpectrum0)
+		melCepstrum0 = self.getMFCCs(melSpectrum0,cn=True)
+		melSpectrum1 = self.warpSpectrum(magnitudeSpectrum1)
+		melCepstrum1 = self.getMFCCs(melSpectrum1,cn=True)
+		
+		outputs = FeatureSet()
+		outputs[0] = Feature(hstack((melCepstrum1[self.cnull:],melCepstrum0[self.cnull:])))
+		outputs[1] = Feature(hstack((melSpectrum1,melSpectrum0)))
+		
+		return outputs
+
+
+	def getRemainingFeatures(self):
+		if not self.update() : return []
+		frameSampleStart = 0
+		
+		output_featureSet = FeatureSet()
+
+		# the filter is the third output (index starts from zero)
+		output_featureSet[2] = flist = FeatureList()
+
+		while True:
+			f = Feature()
+			f.hasTimestamp = True
+			f.timestamp = frame2RealTime(frameSampleStart,self.m_inputSampleRate)
+			try :
+				f.values = self.filterIter.next()
+			except StopIteration :
+				break
+			flist.append(f)
+			frameSampleStart += self.m_stepSize
+
+		return output_featureSet
+		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,44 @@
+
+#CXXFLAGS	:= -D_DEBUG_VALUES -D_DEBUG -DHAVE_NUMPY -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5 -I/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/numpy/core/include/numpy/ 
+CXXFLAGS	:= -D_DEBUG -DHAVE_NUMPY -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5 -I/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/numpy/core/include/
+#CXXFLAGS	:= -DHAVE_NUMPY -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5 -I/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/numpy/core/include/numpy/ 
+
+#without numpy headers available:
+#CXXFLAGS	:= -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5  #-I../host/pyRealTime.h 
+LDFLAGS		:= -L../vamp-plugin-sdk/vamp-sdk -lvamp-sdk -dynamiclib -lpython2.5 -lpthread
+
+default: vampy.dylib 
+all: vampy.dylib vampymod.so
+
+PyExtensionModule.a: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
+	libtool -static $^ -o $@ 
+
+# The standard python extension is .so (even on the Mac)
+vampymod.so: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
+	g++ -shared $^ -o $@ $(LDFLAGS) 
+
+vampy.dylib: PyPlugin.o PyPlugScanner.o vampy-main.o Mutex.o PyTypeInterface.o PyExtensionModule.a PyExtensionManager.o
+	g++ -shared $^ -o $@ $(LDFLAGS) 
+
+# Install plugin
+#
+LIBRARY_PREFIX		:=/Library
+INSTALL_DIR			:=$(LIBRARY_PREFIX)/Audio/Plug-Ins/Vamp
+PYEXAMPLE_DIR		:='Example VamPy Plugins'
+PLUGIN_NAME			:=vampy
+PLUGIN_EXT			:=.dylib
+	
+install:
+	mkdir -p $(INSTALL_DIR)
+	rm -f $(INSTALL_DIR)/$(PLUGIN_NAME)$(PLUGIN_EXT)
+	cp $(PLUGIN_NAME)$(PLUGIN_EXT) $(INSTALL_DIR)/$(PLUGIN_NAME)$(PLUGIN_EXT)	
+	#cp $(PYEXAMPLE_DIR)/*.py $(INSTALL_DIR)
+	
+installplug : install
+cleanplug : clean
+
+clean:	
+	rm *.o
+	rm *.a
+	rm *$(PLUGIN_EXT)
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.cc-linux	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,38 @@
+
+CXXFLAGS	:= -DHAVE_NUMPY -O2 -Wall -I/usr/include/python2.6 -I/usr/lib/python2.6/dist-packages/numpy/core/include/numpy -fPIC
+LDFLAGS		:= -shared -Wl,-Bstatic -lvamp-sdk -Wl,-Bdynamic -lpython2.6 -lpthread -Wl,--version-script=vamp-plugin.map
+
+default: vampy.so 
+all: vampy.so vampymod.so
+
+PyExtensionModule.a: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
+	ar cr $@ $^
+
+# The standard python extension is .so (even on the Mac)
+vampymod.so: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
+	g++ $^ -o $@ $(LDFLAGS) 
+
+vampy.so: PyPlugin.o PyPlugScanner.o vampy-main.o Mutex.o PyTypeInterface.o PyExtensionModule.a 
+	g++ $^ -o $@ $(LDFLAGS) 
+
+# Install plugin
+#
+LIBRARY_PREFIX		:=/Library
+INSTALL_DIR			:=$(LIBRARY_PREFIX)/Audio/Plug-Ins/Vamp
+PYEXAMPLE_DIR		:='Example VamPy Plugins'
+PLUGIN_NAME			:=vampy
+PLUGIN_EXT			:=.dylib
+
+install:
+	mkdir -p $(INSTALL_DIR)
+	rm -f $(INSTALL_DIR)/$(PLUGIN_NAME)$(PLUGIN_EXT)
+	cp $(PLUGIN_NAME)$(PLUGIN_EXT) $(INSTALL_DIR)/$(PLUGIN_NAME)$(PLUGIN_EXT)
+
+installplug : install
+cleanplug : clean
+
+clean:	
+	rm *.o
+	rm *.a
+	rm *$(PLUGIN_EXT)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.cc-mingw32	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,10 @@
+
+CXX	:= i586-mingw32msvc-g++
+CXXFLAGS	:= -I../include -O2 -Wall -I../../Python26/include
+
+vampy.dll:	PyPlugin.o PyPlugScanner.o pyvamp-main.o Mutex.o
+	i586-mingw32msvc-g++ -shared $^ -o $@ -L../lib -L../../Python26/libs -Wl,-Bstatic -lvamp-sdk -Wl,-Bdynamic -lpython26 -Wl,--version-script=vamp-plugin.map
+
+clean:	
+	rm *.o
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.cc-osol	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,39 @@
+
+CXX		:= CC
+CXXFLAGS	:= -I/usr/local/include -G -DHAVE_NUMPY -O2 +w -I/usr/include/python2.6 -I/usr/lib/python2.6/site-packages/numpy/core/include/numpy -KPIC
+LDFLAGS		:= -L/usr/local/lib -G -Bstatic -lvamp-sdk -Bdynamic -lpython2.6 -lpthread -Qoption ld -Mvamp-plugin.map
+
+default: vampy.so 
+all: vampy.so vampymod.so
+
+PyExtensionModule.a: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
+	ar cr $@ $^
+
+# The standard python extension is .so (even on the Mac)
+vampymod.so: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
+	$(CXX) $^ -o $@ $(LDFLAGS) 
+
+vampy.so: PyPlugin.o PyPlugScanner.o vampy-main.o Mutex.o PyTypeInterface.o PyExtensionModule.a 
+	$(CXX) $^ -o $@ $(LDFLAGS) 
+
+# Install plugin
+#
+LIBRARY_PREFIX		:=/Library
+INSTALL_DIR			:=$(LIBRARY_PREFIX)/Audio/Plug-Ins/Vamp
+PYEXAMPLE_DIR		:='Example VamPy Plugins'
+PLUGIN_NAME			:=vampy
+PLUGIN_EXT			:=.so
+
+install:
+	mkdir -p $(INSTALL_DIR)
+	rm -f $(INSTALL_DIR)/$(PLUGIN_NAME)$(PLUGIN_EXT)
+	cp $(PLUGIN_NAME)$(PLUGIN_EXT) $(INSTALL_DIR)/$(PLUGIN_NAME)$(PLUGIN_EXT)
+
+installplug : install
+cleanplug : clean
+
+clean:	
+	rm -f *.o
+	rm -f *.a
+	rm -f *$(PLUGIN_EXT)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mutex.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,211 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+   Basic cross-platform mutex abstraction class.
+   This file copyright 2007 Chris Cannam.
+*/
+
+#include "Mutex.h"
+#include <iostream>
+
+#ifndef _WIN32
+#include <sys/time.h>
+#include <time.h>
+#endif
+
+using std::cerr;
+using std::endl;
+using std::string;
+
+#ifdef _WIN32
+
+Mutex::Mutex()
+#ifndef NO_THREAD_CHECKS
+    :
+    m_lockedBy(-1)
+#endif
+{
+    m_mutex = CreateMutex(NULL, FALSE, NULL);
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised mutex " << &m_mutex << endl;
+#endif
+}
+
+Mutex::~Mutex()
+{
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying mutex " << &m_mutex << endl;
+#endif
+    CloseHandle(m_mutex);
+}
+
+void
+Mutex::lock()
+{
+#ifndef NO_THREAD_CHECKS
+    DWORD tid = GetCurrentThreadId();
+    if (m_lockedBy == tid) {
+        cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
+    }
+#endif
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
+#endif
+    WaitForSingleObject(m_mutex, INFINITE);
+#ifndef NO_THREAD_CHECKS
+    m_lockedBy = tid;
+#endif
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
+#endif
+}
+
+void
+Mutex::unlock()
+{
+#ifndef NO_THREAD_CHECKS
+    DWORD tid = GetCurrentThreadId();
+    if (m_lockedBy != tid) {
+        cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
+        return;
+    }
+#endif
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
+#endif
+#ifndef NO_THREAD_CHECKS
+    m_lockedBy = -1;
+#endif
+    ReleaseMutex(m_mutex);
+}
+
+bool
+Mutex::trylock()
+{
+#ifndef NO_THREAD_CHECKS
+    DWORD tid = GetCurrentThreadId();
+#endif
+    DWORD result = WaitForSingleObject(m_mutex, 0);
+    if (result == WAIT_TIMEOUT || result == WAIT_FAILED) {
+#ifdef DEBUG_MUTEX
+        cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
+#endif
+        return false;
+    } else {
+#ifndef NO_THREAD_CHECKS
+        m_lockedBy = tid;
+#endif
+#ifdef DEBUG_MUTEX
+        cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
+#endif
+        return true;
+    }
+}
+
+#else  /* !_WIN32 */
+
+Mutex::Mutex()
+#ifndef NO_THREAD_CHECKS
+    :
+    m_lockedBy(0),
+    m_locked(false)
+#endif
+{
+    pthread_mutex_init(&m_mutex, 0);
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Initialised mutex " << &m_mutex << endl;
+#endif
+}
+
+Mutex::~Mutex()
+{
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Destroying mutex " << &m_mutex << endl;
+#endif
+    pthread_mutex_destroy(&m_mutex);
+}
+
+void
+Mutex::lock()
+{
+#ifndef NO_THREAD_CHECKS
+    pthread_t tid = pthread_self();
+    if (m_locked && m_lockedBy == tid) {
+        cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
+    }
+#endif
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
+#endif
+    pthread_mutex_lock(&m_mutex);
+#ifndef NO_THREAD_CHECKS
+    m_lockedBy = tid;
+    m_locked = true;
+#endif
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
+#endif
+}
+
+void
+Mutex::unlock()
+{
+#ifndef NO_THREAD_CHECKS
+    pthread_t tid = pthread_self();
+    if (!m_locked) {
+        cerr << "ERROR: Mutex " << &m_mutex << " not locked in unlock" << endl;
+        return;
+    } else if (m_lockedBy != tid) {
+        cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
+        return;
+    }
+#endif
+#ifdef DEBUG_MUTEX
+    cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
+#endif
+#ifndef NO_THREAD_CHECKS
+    m_locked = false;
+#endif
+    pthread_mutex_unlock(&m_mutex);
+}
+
+bool
+Mutex::trylock()
+{
+#ifndef NO_THREAD_CHECKS
+    pthread_t tid = pthread_self();
+#endif
+    if (pthread_mutex_trylock(&m_mutex)) {
+#ifdef DEBUG_MUTEX
+        cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
+#endif
+        return false;
+    } else {
+#ifndef NO_THREAD_CHECKS
+        m_lockedBy = tid;
+        m_locked = true;
+#endif
+#ifdef DEBUG_MUTEX
+        cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
+#endif
+        return true;
+    }
+}
+
+#endif
+
+MutexLocker::MutexLocker(Mutex *mutex) :
+    m_mutex(mutex)
+{
+    if (m_mutex) {
+        m_mutex->lock();
+    }
+}
+
+MutexLocker::~MutexLocker()
+{
+    if (m_mutex) {
+        m_mutex->unlock();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mutex.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,53 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+   Basic cross-platform mutex abstraction class.
+   This file copyright 2007 Chris Cannam.
+*/
+
+#ifndef _MUTEX_H_
+#define _MUTEX_H_
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+class Mutex
+{
+public:
+    Mutex();
+    ~Mutex();
+
+    void lock();
+    void unlock();
+    bool trylock();
+
+private:
+#ifdef _WIN32
+    HANDLE m_mutex;
+#ifndef NO_THREAD_CHECKS
+    DWORD m_lockedBy;
+#endif
+#else
+    pthread_mutex_t m_mutex;
+#ifndef NO_THREAD_CHECKS
+    pthread_t m_lockedBy;
+    bool m_locked;
+#endif
+#endif
+};
+
+class MutexLocker
+{
+public:
+    MutexLocker(Mutex *);
+    ~MutexLocker();
+
+private:
+    Mutex *m_mutex;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyExtensionManager.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,248 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+#include "vamp/vamp.h"
+#include "PyExtensionModule.h"
+#include "PyExtensionManager.h"
+#include <algorithm>
+
+using std::cerr;
+using std::endl;
+using std::string;
+using std::vector;
+using std::find;
+
+//static
+char* PyExtensionManager::m_exposedNames[] = {
+		"ParameterDescriptor",
+		"OutputDescriptor",
+		"ParameterList",
+		"OutputList",
+	    "FeatureList",
+		"FeatureSet",
+		"Feature",
+		"RealTime",
+		"frame2RealTime",
+/* 		//using builtin objects:
+		"OneSamplePerStep",
+		"FixedSampleRate",
+		"VariableSampleRate",
+		"TimeDomain",
+		"FrequencyDomain",
+*/
+		NULL
+};
+
+PyExtensionManager::PyExtensionManager()
+{
+#ifdef _DEBUG	
+	cerr << "Creating extension manager." << endl;
+#endif
+}
+
+bool 
+PyExtensionManager::initExtension() 
+{
+	cerr << "Initialising extension module." << endl; 
+
+	/// call the module initialiser first
+	initvampy();
+
+	/// these references are all borrowed
+	m_pyGlobalNamespace = PyImport_GetModuleDict();
+	if (!m_pyGlobalNamespace) 
+		{cerr << "Vampy::PyExtensionManager::initExtension: GlobalNamespace failed." << endl; return false;}
+	PyObject *pyVampyModule = PyDict_GetItemString(m_pyGlobalNamespace,"vampy");
+	if (!pyVampyModule) 
+		{cerr << "Vampy::PyExtensionManager::initExtension: VampyModule failed." << endl; return false;}
+	m_pyVampyNamespace = PyModule_GetDict(pyVampyModule);
+	if (!m_pyVampyNamespace) 
+		{cerr << "Vampy::PyExtensionManager::initExtension: VampyNamespace failed." << endl; return false;}
+    
+	/// initialise local namespaces
+	updateAllLocals();
+#ifdef _DEBUG
+	cerr << "Vampy: Extension namespaces updated." << endl; 
+#endif	
+	return true;
+}
+
+
+PyExtensionManager::~PyExtensionManager()
+{
+#ifdef _DEBUG	
+	cerr << "Cleaning locals..." << endl;
+#endif	
+
+	cleanAllLocals(); 
+
+#ifdef _DEBUG	
+	cerr << "Cleaning module..." << endl;
+#endif	
+
+	if (!cleanModule()) 
+		cerr << "Vampy::~PyExtensionManager: failed to clean extension module." << endl;
+	cerr << "Vampy::~PyExtensionManager: Extension module cleaned." << endl;
+}
+
+
+
+void
+PyExtensionManager::setPlugModuleNames(vector<string> pyPlugs)
+{
+	for (size_t i = 0; i < pyPlugs.size(); ++i) {
+		string modName = pyPlugs[i];
+		string tmp = modName.substr(modName.rfind(':')+1,modName.size()-1);
+		m_plugModuleNames.push_back(tmp);
+
+#ifdef _DEBUG_VALUES		
+		cerr << "Inserted module name: " << tmp << endl;
+#endif		
+
+	}
+}
+
+void
+PyExtensionManager::deleteModuleName(string plugKey)
+{
+	string name = plugKey.substr(plugKey.rfind(':')+1,plugKey.size()-1);
+	vector<string>::iterator it = 
+		find (m_plugModuleNames.begin(), m_plugModuleNames.end(), name);
+	if (it != m_plugModuleNames.end()) m_plugModuleNames.erase(it);
+#ifdef _DEBUG_VALUES		
+	cerr << "PyExtensionManager::deleteModuleName: Deleted module name: " << name << endl;
+#endif	
+}
+
+
+void 
+PyExtensionManager::cleanAllLocals() const
+{
+	for (size_t i = 0; i < m_plugModuleNames.size(); ++i) {
+	    cleanLocalNamespace(m_plugModuleNames[i].c_str());
+	}
+}
+
+void 
+PyExtensionManager::updateAllLocals() const
+{
+	for (size_t i = 0; i < m_plugModuleNames.size(); ++i) {
+		updateLocalNamespace(m_plugModuleNames[i].c_str());
+	}
+}
+
+void 
+PyExtensionManager::cleanLocalNamespace(const char* plugModuleName) const
+{
+	
+	/// these references are all borrowed
+	PyObject *pyPlugModule = PyDict_GetItemString(m_pyGlobalNamespace,plugModuleName);
+	if (!pyPlugModule) return;
+	PyObject *pyPlugDict = PyModule_GetDict(pyPlugModule);
+	if (!pyPlugDict) return;
+	
+	int i = 0;
+	while (PyExtensionManager::m_exposedNames[i]) {
+		char* name = PyExtensionManager::m_exposedNames[i];
+		i++;
+		PyObject *key = PyString_FromString(name);
+		if (!key) break;
+		if (PyDict_Contains(pyPlugDict,key)) {
+			if (PyDict_SetItem(pyPlugDict,key,Py_None) != 0)
+				cerr << "Vampy::PyExtensionManager::cleanLocalNamespace: Failed: " 
+				<< name << " of "<< plugModuleName << endl;
+#ifdef _DEBUG_VALUES
+			else cerr << "Cleaned local name: " << name << endl;
+#endif			
+		}
+		Py_DECREF(key);
+	}
+}
+
+void 
+PyExtensionManager::updateLocalNamespace(const char* plugModuleName) const
+{
+	/// this allows the use of common syntax like:
+	/// from vampy import * 
+	/// even after several unload/reload cycles
+		
+	/// these references are all borrowed
+	PyObject *pyPlugModule = PyDict_GetItemString(m_pyGlobalNamespace,plugModuleName);
+	if (!pyPlugModule) return;
+	PyObject *pyPlugDict = PyModule_GetDict(pyPlugModule);
+	if (!pyPlugDict) return;
+	
+	int i = 0;
+	while (PyExtensionManager::m_exposedNames[i]) {
+		const char* name = PyExtensionManager::m_exposedNames[i];
+		i++;
+		PyObject *key = PyString_FromString(name);
+		if (!key) break;
+		if (PyDict_Contains(pyPlugDict,key)) {
+			PyObject* item = PyDict_GetItem(m_pyVampyNamespace,key);
+			if (PyDict_SetItem(pyPlugDict,key,item) != 0)
+				cerr << "Vampy::PyExtensionManager::updateLocalNamespace: Failed: " 
+				<< name << " of "<< plugModuleName << endl;
+#ifdef _DEBUG_VALUES
+			else cerr << "Updated local name: " << name << endl;
+#endif			
+		}
+		Py_DECREF(key);
+	}
+}
+
+
+bool 
+PyExtensionManager::cleanModule(void) const
+{
+		
+	PyObject *m = PyImport_AddModule("vampy");
+	if (!m) {
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		cerr << "Vampy::PyExtensionManager::cleanModule: PyImport_AddModule returned NULL!" << endl;
+		return false;
+	} else {
+		PyObject *dict = PyModule_GetDict(m);
+#ifdef _DEBUG		
+		Py_ssize_t ln = PyDict_Size(dict);
+		cerr << "Vampy::PyExtensionManager::cleanModule: Size of module dict = " << (int) ln << endl;
+#endif		
+		/// Clean the module dictionary.
+		// printDict(dict);
+		PyDict_Clear(dict);
+		if (PyErr_Occurred()) 
+			{ PyErr_Print(); PyErr_Clear(); return false; }
+		PyObject *name = PyString_FromString("vampy");
+		if (name) PyDict_SetItemString(dict,"__name__",name);
+		Py_XDECREF(name);
+#ifdef _DEBUG		
+	    ln = PyDict_Size(dict);
+		cerr << "Vampy::PyExtensionManager::cleanModule: Size of module dict (cleaned) = " << (int) ln << endl;
+#endif
+		return true;
+	}
+}
+
+void 
+PyExtensionManager::printDict(PyObject* inDict) const
+{
+	Py_ssize_t pyPos = 0;
+	PyObject *pyKey, *pyDictValue;
+	cerr << endl << endl << "Module dictionary contents: " << endl;
+	while (PyDict_Next(inDict, &pyPos, &pyKey, &pyDictValue))
+	{ 
+		char *key = PyString_AS_STRING(pyKey);
+		char *val = PyString_AS_STRING(PyObject_Str(pyDictValue));
+		cerr << "key: [ '" << key << "' ] value: " << val << endl;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyExtensionManager.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,86 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+/*
+PyExtensionManager: This class is responsible for initialisation
+and cleanup of the extension module, as well as the loaded plugin
+module namespaces. 
+
+NOTES: Why do we need to clean up the module?
+
+The module exposed by Vampy to the embedded interpreter contains 
+callback functions. These functions are accessed via function 
+pointers stored in the extension module's namespace dictionary.
+
+Unfortunately, when the shared library is unloaded and reloaded 
+during a host session, these addresses might change. 
+Therefore, we reinitialise the module dict before each use. 
+However, this will cause garbage collection errors or segmentation 
+faults, when elements of the dict of the previous session are 
+attempted to free. Therefore, we clear the dictinary describing
+the module namespace and replace all fuction pointers with Py_None
+objects in individual plugin module namespaces. The reference
+count on these can be safely decremented next time vampy is loaded
+and the namespaces are reinitialised.
+
+Why doesn't the GC clean this up correctly?
+
+In a normal Python session the GC would deallocate the module
+dict at the end. In embedded python, although the GC appears
+to be called when the shared lib is unloaded, the interpreter
+is reused. Since there is no C/API call to unload modules,
+and at the time of unloading vampy the wrapped function pointers
+are still valid, the GC doesn't collect them, nor are they freed
+by the interpreter. When vampy is reloaded however, the module
+dict will contain invalid addresses. The above procedure solves
+this problem.
+
+
+*/
+
+
+#ifndef _PYEXTENSIONMANAGER_H_
+#define _PYEXTENSIONMANAGER_H_
+
+using std::cerr;
+using std::endl;
+using std::string;
+using std::vector;
+
+class PyExtensionManager
+{
+public:
+	PyExtensionManager();
+	~PyExtensionManager();
+	bool initExtension();
+	void setPlugModuleNames(vector<string> pyPlugs);
+	void deleteModuleName(string plugKey);
+
+private:
+	static char* m_exposedNames[];
+	
+	vector<string> m_plugModuleNames;
+	PyObject* m_pyGlobalNamespace;
+	PyObject* m_pyVampyNamespace;
+
+	void cleanAllLocals() const;
+	void cleanLocalNamespace(const char* plugModuleName) const;
+	void updateAllLocals() const;
+	void updateLocalNamespace(const char* plugModuleName) const;
+
+	void printDict(PyObject* inDict) const;
+	bool cleanModule() const;
+
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyExtensionModule.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,265 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+#include "PyExtensionModule.h"
+#include "PyRealTime.h"
+#include "PyFeature.h"
+#include "PyFeatureSet.h"
+#include "PyParameterDescriptor.h"
+#include "PyOutputDescriptor.h"
+#include "vamp/vamp.h"
+#include "vamp-sdk/Plugin.h"
+
+using namespace std;
+using namespace Vamp;
+using Vamp::Plugin;
+using Vamp::RealTime;
+
+/*			 Functions Exposed by Vampy 					*/
+
+/*			 Creating PyRealTime Objects from frame count	*/
+
+/* New RealTime object from Frame (with given samplerate)   */
+static PyObject *
+RealTime_frame2RealTime(PyObject *ignored, PyObject *args)
+{
+	long frame;
+	unsigned int sampleRate;
+
+	if (!(args && PyTuple_GET_SIZE(args) == 2)) {
+		PyErr_SetString(PyExc_ValueError,"frame2RealTime requires two arguments: frame and sample rate.");
+		return NULL;
+	}
+
+	PyObject* pyFrame = PyTuple_GET_ITEM(args,0);
+	PyObject* pySampleRate = PyTuple_GET_ITEM(args,1);
+
+	/// frame 
+	if (PyInt_Check(pyFrame)) frame = PyInt_AS_LONG(pyFrame);
+	else if (PyLong_Check(pyFrame)) frame = PyLong_AsLong(pyFrame);
+	else {
+		PyErr_SetString(PyExc_ValueError,"frame2RealTime 'frame' argument must be long integer.");
+		return NULL;
+	}
+
+	/// sample rate
+	if (PyInt_Check(pySampleRate)) 
+		sampleRate = _long2uint(PyInt_AS_LONG(pySampleRate));
+	else if (PyFloat_Check(pySampleRate)) 
+		sampleRate = _dbl2uint(PyFloat_AS_DOUBLE(pySampleRate));
+	else if (PyLong_Check(pySampleRate)) 
+		sampleRate = _long2uint(PyLong_AsLong(pySampleRate));
+	else {
+		PyErr_SetString(PyExc_ValueError,"frame2RealTime 'sample rate' argument must be int, long or float.");
+		return NULL;
+	}
+	
+	if (!sampleRate) {
+		PyErr_SetString(PyExc_ValueError,"frame2RealTime 'sample rate' argument overflow error. Argument must be 0 < arg < UINT_MAX.");
+		cerr << "Value: " << sampleRate << endl;
+		return NULL;
+	}
+	
+	// simpler but slower:
+	// if (!PyArg_ParseTuple(args, "lI:realtime.frame2RealTime ", 
+	// &frame,&sampleRate))
+	// return NULL;
+
+	RealTimeObject *self;
+	self = PyObject_New(RealTimeObject, &RealTime_Type); 
+	if (self == NULL) return NULL;
+
+	self->rt = new RealTime(
+	RealTime::frame2RealTime(frame,sampleRate));
+
+	return (PyObject *) self;
+}
+
+/*
+
+Note: these functions are not very interesting on their own, but
+they can be used to make the semantics of the plugin clearer.
+They return ordinary Python list objects. All type checking 
+is performed in the type interface.
+
+*/
+
+/* New PyOutputList Objects */
+static PyObject *
+OutputList_new(PyObject *ignored, PyObject *args)
+{
+	if (args and PyTuple_Check(args)) 
+		return PySequence_List(args);
+	else return (PyObject *) PyList_New(0);
+}
+
+
+/* New PyParameterList Objects */
+static PyObject *
+ParameterList_new(PyObject *ignored, PyObject *args)
+{
+	if (args and PyTuple_Check(args)) 
+		return PySequence_List(args);
+	else return (PyObject *) PyList_New(0);
+}
+
+/* New PyFeatureList Objects */
+static PyObject *
+FeatureList_new(PyObject *ignored, PyObject *args)
+{
+	if (args and PyTuple_Check(args)) 
+		return PySequence_List(args);
+	else return (PyObject *) PyList_New(0);
+}
+
+
+/*		 	Declare the methods exposed by the vampy module 		*/
+
+
+PyMethodDef VampyMethods[] = {
+/*NOTE: This is conventionally static, but limiting the scope
+	here will cause seg fault if the declared functions are 
+	called back from a Python function wrapped in a C++ class.*/
+
+	{"frame2RealTime",	(PyCFunction)RealTime_frame2RealTime,	METH_VARARGS,
+		PyDoc_STR("frame2RealTime((int64)frame, (uint32)sampleRate ) -> returns new RealTime object from frame.")},
+
+	{"OutputList",	OutputList_new,		METH_VARARGS,
+		PyDoc_STR("OutputList() -> returns new OutputList object")},
+
+	{"ParameterList",	ParameterList_new,		METH_VARARGS,
+		PyDoc_STR("ParameterList() -> returns new ParameterList object")},
+
+	{"FeatureList",	FeatureList_new,		METH_VARARGS,
+		PyDoc_STR("FeatureList() -> returns new FeatureList object")},
+
+    {NULL, NULL, 0, NULL} 
+};
+
+/* Module Documentation */
+// PyDoc_STRVAR(vampy_doc,"This module exposes Vamp plugin data type wrappers.");
+
+static int
+setint(PyObject *d, char *name, int value)
+{
+	PyObject *v;
+	int err;
+	v = PyInt_FromLong((long)value);
+	err = PyDict_SetItemString(d, name, v);
+	Py_XDECREF(v);
+	return err;
+}
+
+static int
+setdbl(PyObject *d, char *name, double value)
+{
+	PyObject *v;
+	int err;
+	v = PyFloat_FromDouble(value);
+	err = PyDict_SetItemString(d, name, v);
+	Py_XDECREF(v);
+	return err;
+}
+
+static int
+setstr(PyObject *d, char *name, char *value)
+{
+	PyObject *v;
+	int err;
+	v = PyString_FromString(value);
+	err = PyDict_SetItemString(d, name, v);
+	Py_XDECREF(v);
+	return err;
+}
+
+
+PyMODINIT_FUNC
+initvampy(void)
+{
+	PyObject *module, *mdict;
+
+	/* if (PyType_Ready(&Feature_Type) < 0) return;
+	Note: Why do we get a segfault if this is initialised here?
+	PyType_Ready adds these object to the GC.
+	This is OK for an extension module, but it is a mistake here, 
+	because the adresses become invalid when the shared library
+	is unloaded. When the GC tries to visit a these objects, 
+	it will fail.*/
+	
+	RealTime_Type.ob_type = &PyType_Type;
+	Feature_Type.ob_type = &PyType_Type;
+	OutputDescriptor_Type.ob_type = &PyType_Type;
+	ParameterDescriptor_Type.ob_type = &PyType_Type;
+	initFeatureSetType(); // this is derived from the builtin dict
+
+	PyImport_AddModule("vampy");
+	module = Py_InitModule("vampy", VampyMethods);
+	if (!module) goto failure;
+	mdict = PyModule_GetDict(module);
+	if (!mdict) goto failure;
+
+	/// vampy plugin wrapper flags
+	if (setint(mdict, "vf_NULL", vf_NULL) < 0) goto failure;
+	if (setint(mdict, "vf_DEBUG", vf_DEBUG) < 0) goto failure;
+	if (setint(mdict, "vf_STRICT", vf_STRICT) < 0) goto failure;
+	if (setint(mdict, "vf_QUIT", vf_QUIT) < 0) goto failure;
+	if (setint(mdict, "vf_REALTIME", vf_REALTIME) < 0) goto failure;
+	if (setint(mdict, "vf_BUFFER", vf_BUFFER) < 0) goto failure;
+	if (setint(mdict, "vf_ARRAY", vf_ARRAY) < 0) goto failure;
+	if (setint(mdict, "vf_DEFAULT_V2", vf_DEFAULT_V2) < 0) goto failure;
+	
+	/// Vamp enum types simulation
+	if (setint(mdict, "OneSamplePerStep", Vamp::Plugin::OutputDescriptor::OneSamplePerStep) < 0) goto failure;
+	if (setint(mdict, "FixedSampleRate", Vamp::Plugin::OutputDescriptor::FixedSampleRate) < 0) goto failure;
+	if (setint(mdict, "VariableSampleRate", Vamp::Plugin::OutputDescriptor::VariableSampleRate) < 0) goto failure;
+	if (setint(mdict, "TimeDomain", Vamp::Plugin::TimeDomain) < 0) goto failure;
+	if (setint(mdict, "FrequencyDomain", Vamp::Plugin::FrequencyDomain) < 0) goto failure;
+
+	/// module attributes
+	if (setstr(mdict, "__name__", "vampy") < 0) goto failure;
+	if (setdbl(mdict, "__version__", 2.0) < 0) goto failure;
+	if (setdbl(mdict, "__VAMP_API_VERSION__", (double) VAMP_API_VERSION) < 0) goto failure;
+#ifdef HAVE_NUMPY
+	if (setint(mdict, "__numpy__", 1) < 0) goto failure;
+#else
+	if (setint(mdict, "__numpy__", 0) < 0) goto failure;
+#endif
+	
+	/// type objects
+	Py_INCREF(&RealTime_Type);
+	if (PyModule_AddObject(module,"RealTime",(PyObject*)&RealTime_Type) !=0) goto failure;
+
+	Py_INCREF((PyObject*)&Feature_Type);
+	if (PyModule_AddObject(module,"Feature",(PyObject*)&Feature_Type) !=0) goto failure;
+
+	Py_INCREF((PyObject*)&FeatureSet_Type);
+	if (PyModule_AddObject(module,"FeatureSet",(PyObject*)&FeatureSet_Type) !=0) goto failure;
+
+	Py_INCREF((PyObject*)&OutputDescriptor_Type);
+	if (PyModule_AddObject(module,"OutputDescriptor",(PyObject*)&OutputDescriptor_Type) !=0) goto failure;
+
+	Py_INCREF((PyObject*)&ParameterDescriptor_Type);
+	if (PyModule_AddObject(module,"ParameterDescriptor",(PyObject*)&ParameterDescriptor_Type) !=0) goto failure;
+	
+#ifdef _DEBUG	
+	cerr << "Vampy: extension module initialised." << endl;
+#endif
+
+	return;
+	
+failure :
+	if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+	cerr << "Vampy::PyExtensionModule::initvampy: Failed to initialise extension module." << endl;
+	return;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyExtensionModule.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,53 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#ifndef _PYEXTENSIONMODULE_H_
+#define _PYEXTENSIONMODULE_H_
+
+#include <Python.h>
+#include <limits.h>
+#include "PyRealTime.h"
+#include "PyFeature.h"
+#include "PyFeatureSet.h"
+#include "PyParameterDescriptor.h"
+#include "PyOutputDescriptor.h"
+
+#ifndef UINT_MAX
+#define UINT_MAX ((unsigned int) -1)
+#endif
+#define UINT_MAXD ((double) UINT_MAX)
+/* long error() { std::cerr << "type error" << std::endl; return 0; } */
+#define _dbl2uint(x) ((x) < 0 || (x) > UINT_MAXD ? 0 : (unsigned int)(x)+0.5)
+#define _long2uint(x) ((x) < 0 || (x) > UINT_MAXD ? 0 : (unsigned int)(x))
+
+using std::string;
+using std::vector;
+
+enum eVampyFlags {
+	vf_NULL = 0,
+	vf_DEBUG = 1, 
+	vf_STRICT = 2,
+	vf_QUIT = 4,
+	vf_REALTIME = 8,
+	vf_BUFFER = 16,
+	vf_ARRAY = 32,
+	vf_DEFAULT_V2 = (32 | 8)
+};
+
+#define PyDescriptor_Check(v) ((v)->ob_type == &Feature_Type) || ((v)->ob_type == &OutputDescriptor_Type) || ((v)->ob_type == &ParameterDescriptor_Type)
+
+#ifndef PyMODINIT_FUNC
+#define PyMODINIT_FUNC void
+#endif
+
+PyMODINIT_FUNC initvampy();
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyFeature.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,235 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+#include "PyExtensionModule.h"
+#include "PyFeature.h"
+#include "vamp-sdk/Plugin.h"
+#include <string>
+
+using namespace std;
+using namespace Vamp;
+using Vamp::Plugin;
+
+/* CONSTRUCTOR: New Feature object */
+static PyObject *
+Feature_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+	// FeatureObject *self = PyObject_New(FeatureObject, &Feature_Type); 
+	FeatureObject *self = (FeatureObject*)type->tp_alloc(type, 0);
+	if (self == NULL) return NULL;
+    self->dict = PyDict_New();
+	if (self->dict == NULL) return NULL;
+
+	/// 4 args max.: {values|self_copy},timestamp,duration,label 
+	if(args && PyTuple_GET_SIZE(args)>0) {
+		int s =  PyTuple_GET_SIZE(args);
+		PyObject* arg0 = PyTuple_GET_ITEM(args,0);
+		if (s == 1 && PyFeature_CheckExact(arg0))
+			PyDict_Merge(self->dict,PyFeature_AS_DICT(arg0),0);
+		else
+			PyDict_SetItemString(self->dict, "values", arg0);
+		if (s>1) {
+			PyDict_SetItemString(self->dict, "timestamp", PyTuple_GET_ITEM(args,1));
+			PyDict_SetItemString(self->dict, "hasTimestamp", Py_True);
+		}
+		if (s>2) {
+			PyDict_SetItemString(self->dict, "duration", PyTuple_GET_ITEM(args,2));
+			PyDict_SetItemString(self->dict, "hasDuration", Py_True);
+		}
+		if (s>3) {
+			PyDict_SetItemString(self->dict, "label", PyTuple_GET_ITEM(args,3));
+		}
+	}
+
+	/// accept keyword arguments: 
+	/// e.g. Feature(values = theOutputArray)
+	if (!kw || !PyDict_Size(kw)) return (PyObject *) self;
+	PyDict_Merge(self->dict,kw,0);
+
+	static char *kwlist[] = {"timestamp", "hasTimestamp", "duration", "hasDuration", 0};
+
+	int i = 0;
+	while (kwlist[i]) {
+		char* name = kwlist[i];
+		char* attr = kwlist[++i];
+		i++;
+		PyObject *key = PyString_FromString(name);
+		if (!key) break;
+		if (PyDict_Contains(kw,key)) {
+			if (PyDict_SetItem(self->dict,PyString_FromString(attr),Py_True) != 0)
+				PyErr_SetString(PyExc_TypeError, 
+					"Error: in keyword arguments of vampy.Feature().");
+		}
+		Py_DECREF(key);
+	}
+
+	return (PyObject *) self;
+}
+
+/* DESTRUCTOR: delete type object */
+static void
+FeatureObject_dealloc(FeatureObject *self)
+{
+	Py_XDECREF(self->dict);
+	self->ob_type->tp_free((PyObject*)self);
+}
+
+/*					 Feature Object's Methods 					*/ 
+//Feature objects have no callable methods
+
+/*		   PyFeature methods implementing protocols 		   	   */ 
+// these functions are called by the interpreter automatically
+
+/* Set attributes */
+static int
+Feature_setattr(FeatureObject *self, char *name, PyObject *v)
+{
+	if (v == NULL) 
+	{
+		int rv = PyDict_DelItemString(self->dict, name);
+		if (rv < 0)
+			PyErr_SetString(PyExc_AttributeError,"non-existing Feature attribute");
+		return rv;
+	}
+	else return PyDict_SetItemString(self->dict, name, v);
+}
+
+
+/* Get attributes */
+static PyObject *
+Feature_getattr(FeatureObject *self, char *name)
+{
+	if (self->dict != NULL) {
+		PyObject *v = PyDict_GetItemString(self->dict, name);
+		if (v != NULL) 
+		{
+			Py_INCREF(v);
+			return v;
+		}
+	}
+	return NULL;
+}
+
+/* The problem with this is that we'd need to implement two-way
+conversions which is really unnecesary: The case for using 
+a Vamp::Feature in Python for anything else than returning 
+values is rather obscure. It's not really worth it. */
+
+/* Set Attribute: Using wrapped Vamp::Feature 
+static int
+Feature_setattr(FeatureObject *self, char *name, PyObject *value)
+{
+	std::string key = std::string(name);
+	if (self->ti.SetValue(*(self->feature),key,value)) return 0;
+	else return -1;
+}*/
+
+/* Get Attribute: Using wrapped Vamp::Feature 
+static PyObject *
+Feature_getattr(FeatureObject *self, char *name)
+{
+	std::string key = std::string(name);
+	PyObject* pyValue;
+	if (self->ti.GetValue(*(self->feature),key,pyValue)) 
+		return pyValue;
+	else return NULL;
+}*/
+
+/*
+static int
+Feature_init(FeatureObject *self, PyObject *args, PyObject *kwds)
+{
+	cerr << "FeatureObject Init called" << endl;
+	return 0;
+}
+
+PyObject*
+Feature_test(PyObject *self, PyObject *args, PyObject *kwds)
+{
+	cerr << "FeatureObject TEST called" << endl;
+	return self;
+}
+*/
+
+/* String representation */
+static PyObject *
+Feature_repr(PyObject *self)
+{
+	FeatureObject* v = (FeatureObject*)self;
+	if (v->dict) return PyDict_Type.tp_repr((PyObject *)v->dict);
+	else return PyString_FromString("Feature()");
+}
+
+#define Feature_alloc PyType_GenericAlloc
+#define Feature_free PyObject_Del
+
+
+/*						FEATURE TYPE OBJECT						*/
+
+PyTypeObject Feature_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,						/*ob_size*/
+	"vampy.Feature",		/*tp_name*/
+	sizeof(FeatureObject),	/*tp_basicsize*/
+	0,						/*tp_itemsize*/
+	(destructor)FeatureObject_dealloc, /*tp_dealloc*/
+	0,						/*tp_print*/
+	(getattrfunc)Feature_getattr, /*tp_getattr*/
+	(setattrfunc)Feature_setattr, /*tp_setattr*/
+	0,						/*tp_compare*/
+	Feature_repr,			/*tp_repr*/
+	0,						/*tp_as_number*/
+	0,						/*tp_as_sequence*/
+	0,						/*tp_as_mapping*/
+	0,						/*tp_hash*/
+	0,//Feature_test,           /*tp_call*/ // call on an instance
+    0,                      /*tp_str*/
+    0,                      /*tp_getattro*/
+    0,                      /*tp_setattro*/
+    0,                      /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,     /*tp_flags*/
+    0,                      /*tp_doc*/
+    0,                      /*tp_traverse*/
+    0,                      /*tp_clear*/
+    0,                      /*tp_richcompare*/
+    0,                      /*tp_weaklistoffset*/
+    0,                      /*tp_iter*/
+    0,                      /*tp_iternext*/
+    0,				        /*tp_methods*/ //TypeObject Methods
+    0,                      /*tp_members*/
+    0,                      /*tp_getset*/
+    0,                      /*tp_base*/
+    0,                      /*tp_dict*/
+    0,                      /*tp_descr_get*/
+    0,                      /*tp_descr_set*/
+    0,                      /*tp_dictoffset*/
+    0,//(initproc)Feature_init, /*tp_init*/
+    Feature_alloc,          /*tp_alloc*/
+    Feature_new,            /*tp_new*/
+    Feature_free,			/*tp_free*/
+    0,                      /*tp_is_gc*/
+};
+
+/*		  		 	  PyRealTime C++ API  	  		  				*/
+
+/*Feature* from PyFeature
+const Vamp::Plugin::Feature*
+PyFeature_AsFeature (PyObject *self) { 
+
+	FeatureObject *s = (FeatureObject*) self; 
+
+	if (!PyFeature_Check(s)) {
+		PyErr_SetString(PyExc_TypeError, "Feature Object Expected.");
+		cerr << "in call PyFeature_AsPointer(): Feature Object Expected. " << endl;
+		return NULL; }
+	return s->feature; 
+};*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyFeature.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,66 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+/*
+NOTES: There are two ways to implement the Vamp::Feature wrapper.
+1) We could keep a Vamp::Feature in the object and
+convert the values on the fly as they are inserted.
+However, this requires a way to convert back to Python for
+this object to be fully usable in python code. These conversions 
+are otherwise unnecessary.
+
+2) Keep the python attribute objects in a dict as it is normally 
+done in python classes, and convert when the object is returned.
+This way the object is usable by the interpreter until it is returned
+to the C++ plugin wrapper.
+This is different form the Vampy:PyRealTime implementation where the
+two-way conversion makes more sense (in fact required). Note: For
+a host implementation option 1) will be required.
+
+*/
+
+#ifndef _PYFEATURE_H_
+#define _PYFEATURE_H_
+
+#include "vamp-sdk/Plugin.h"
+// #include "PyTypeInterface.h"
+
+
+typedef struct {
+		PyObject_HEAD
+		PyObject *dict; 
+		// Vamp::Plugin::Feature *feature;
+		/// pointer to type interface required: PyTypeInterface ti;
+} FeatureObject; 
+
+PyAPI_DATA(PyTypeObject) Feature_Type;
+
+#define PyFeature_CheckExact(v)	((v)->ob_type == &Feature_Type)
+#define PyFeature_Check(v) PyObject_TypeCheck(v, &Feature_Type)
+
+///fast macro version as per API convention
+#define PyFeature_AS_DICT(v) ((const FeatureObject* const) (v))->dict
+// #define PyFeature_AS_FEATURE(v) ((const FeatureObject* const) (v))->feature
+ 
+
+/*		  		 	  PyFeature C++ API  	  		  				*/
+
+/* Not required here: 
+ 	we will never have to pass a feature back from the wrapper */
+// PyAPI_FUNC(PyObject *) 
+// PyFeature_FromFeature(Vamp::Plugin::Feature&);
+
+// PyAPI_FUNC(const Vamp::Plugin::Feature*) 
+// PyFeature_AsFeature (PyObject *self);
+
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyFeatureSet.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,63 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+#include "PyFeatureSet.h"
+#include "vamp-sdk/Plugin.h"
+
+using namespace std;
+
+static int
+FeatureSet_init(FeatureSetObject *self, PyObject *args, PyObject *kwds)
+{
+    if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
+        return -1;
+    return 0;
+}
+
+static int
+FeatureSetObject_ass_sub(FeatureSetObject *mp, PyObject *v, PyObject *w)
+{
+	if (!PyInt_CheckExact(v)) {
+		PyErr_SetString(PyExc_ValueError,
+			"Output index must be positive integer.");
+		return 0;
+	}
+	if (w == NULL)
+		return PyDict_DelItem((PyObject *)mp, v);
+	else
+		return PyDict_SetItem((PyObject *)mp, v, w);
+}
+
+#define FeatureSet_alloc PyType_GenericAlloc
+#define FeatureSet_free PyObject_Del
+//#define FeatureSet_as_mapping PyDict_Type.tp_as_mapping
+
+static PyMappingMethods FeatureSet_as_mapping = *(PyDict_Type.tp_as_mapping);
+
+PyTypeObject FeatureSet_Type = PyDict_Type;
+
+void
+initFeatureSetType(void)
+{
+	/*This type is derived from PyDict. We just override some slots here.*/
+	/*The typical use case is index based assignment as opposed to object memeber access.*/
+	FeatureSet_Type.ob_type = &PyType_Type;
+	FeatureSet_Type.tp_base = &PyDict_Type;
+	FeatureSet_Type.tp_bases = PyTuple_Pack(1, FeatureSet_Type.tp_base);
+	FeatureSet_Type.tp_name = "vampy.FeatureSet";
+	// FeatureSet_Type.tp_new = FeatureSet_new;
+	FeatureSet_Type.tp_init = (initproc)FeatureSet_init;
+	FeatureSet_Type.tp_basicsize = sizeof(FeatureSetObject);
+	FeatureSet_as_mapping.mp_ass_subscript = (objobjargproc)FeatureSetObject_ass_sub;
+	FeatureSet_Type.tp_as_mapping = &FeatureSet_as_mapping;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyFeatureSet.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,28 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#ifndef _PYFEATURESET_H_
+#define _PYFEATURESET_H_
+
+#include <Python.h>
+
+typedef struct {
+    PyDictObject dict;
+} FeatureSetObject;
+
+PyAPI_DATA(PyTypeObject) FeatureSet_Type;
+
+#define PyFeatureSet_CheckExact(v)	((v)->ob_type == &FeatureSet_Type)
+#define PyFeatureSet_Check(v) PyObject_TypeCheck(v, &FeatureSet_Type)
+
+void initFeatureSetType(void);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyOutputDescriptor.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,156 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+#include "PyOutputDescriptor.h"
+#include "vamp-sdk/Plugin.h"
+#include <string>
+#include "PyTypeInterface.h"
+
+using namespace std;
+using namespace Vamp;
+using Vamp::Plugin;
+
+/*			 OutputDescriptor Object's Methods 					*/ 
+//these objects have no callable methods
+
+/*		   PyOutputDescriptor methods implementing protocols   	*/ 
+// these functions are called by the interpreter automatically
+
+/* New OutputDescriptor object */ 
+static PyObject *
+OutputDescriptor_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+	OutputDescriptorObject *self = 
+	(OutputDescriptorObject*)type->tp_alloc(type, 0);
+	
+	if (self == NULL) return NULL;
+    self->dict = PyDict_New();
+	if (self->dict == NULL) return NULL;
+    
+	/// allow copying objects
+    if (args and PyTuple_Size(args) == 1) {
+		PyObject* arg = PyTuple_GET_ITEM(args,0);
+		if (PyOutputDescriptor_CheckExact(arg))
+			PyDict_Merge(self->dict,PyOutputDescriptor_AS_DICT(arg),0);
+		else if (PyDict_CheckExact(arg)) 
+			PyDict_Merge(self->dict,arg,0);
+		else {
+			PyErr_SetString(PyExc_TypeError, 
+			"OutputDescriptor takes zero or one PyOutputDescriptor or dictionary arguments.");
+			return NULL; 
+		}
+	}
+	return (PyObject *) self;
+}
+
+
+/* DESTRUCTOR: delete type object */
+static void
+OutputDescriptorObject_dealloc(OutputDescriptorObject *self)
+{
+	Py_XDECREF(self->dict);
+	PyObject_Del(self);
+}
+
+
+/* Set attributes */
+static int
+OutputDescriptor_setattr(OutputDescriptorObject *self, char *name, PyObject *v)
+{
+	if (v == NULL) {
+		int rv = PyDict_DelItemString(self->dict, name);
+		if (rv < 0)
+			PyErr_SetString(PyExc_AttributeError,"non-existing OutputDescriptor attribute");
+		return rv;
+	}
+	else
+		return PyDict_SetItemString(self->dict, name, v);
+}
+
+
+/* Get attributes */
+static PyObject *
+OutputDescriptor_getattr(OutputDescriptorObject *self, char *name)
+{
+	if (self->dict != NULL) {
+		PyObject *v = PyDict_GetItemString(self->dict, name);
+		if (v != NULL) 
+		{
+			Py_INCREF(v);
+			return v;
+		}
+	}
+	return NULL;
+}
+
+
+/* String representation */
+static PyObject *
+OutputDescriptor_repr(PyObject *self)
+{
+	OutputDescriptorObject* v = (OutputDescriptorObject*)self;
+	if (v->dict) return PyDict_Type.tp_repr((PyObject *)v->dict);
+	else return PyString_FromString("OutputDescriptor()");
+}
+
+#define OutputDescriptor_alloc PyType_GenericAlloc
+#define OutputDescriptor_free PyObject_Del
+
+
+/*						REAL-TIME TYPE OBJECT						*/
+
+PyTypeObject OutputDescriptor_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,						/*ob_size*/
+	"vampy.OutputDescriptor",/*tp_name*/
+	sizeof(OutputDescriptorObject),	/*tp_basicsize*/
+	0,						/*tp_itemsize*/
+	(destructor)OutputDescriptorObject_dealloc, /*tp_dealloc*/
+	0,						/*tp_print*/
+	(getattrfunc)OutputDescriptor_getattr, /*tp_getattr*/
+	(setattrfunc)OutputDescriptor_setattr, /*tp_setattr*/
+	0,						/*tp_compare*/
+	OutputDescriptor_repr,	/*tp_repr*/
+	0,						/*tp_as_number*/
+	0,						/*tp_as_sequence*/
+	0,						/*tp_as_mapping*/
+	0,						/*tp_hash*/
+	0,                      /*tp_call*/
+    0,                      /*tp_str*/
+    0,                      /*tp_getattro*/
+    0,                      /*tp_setattro*/
+    0,                      /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT,     /*tp_flags*/
+    0,                      /*tp_doc*/
+    0,                      /*tp_traverse*/
+    0,                      /*tp_clear*/
+    0,                      /*tp_richcompare*/
+    0,                      /*tp_weaklistoffset*/
+    0,                      /*tp_iter*/
+    0,                      /*tp_iternext*/
+    0,				        /*tp_methods*/ //TypeObject Methods
+    0,                      /*tp_members*/
+    0,                      /*tp_getset*/
+    0,                      /*tp_base*/
+    0,                      /*tp_dict*/
+    0,                      /*tp_descr_get*/
+    0,                      /*tp_descr_set*/
+    0,                      /*tp_dictoffset*/
+    0,                      /*tp_init*/
+    OutputDescriptor_alloc, /*tp_alloc*/
+    OutputDescriptor_new,   /*tp_new*/
+    OutputDescriptor_free,	/*tp_free*/
+    0,                      /*tp_is_gc*/
+};
+
+/*		  		 	  PyOutputDescriptor C++ API    				*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyOutputDescriptor.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,33 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#ifndef _PYOUTPUTDESCRIPTOR_H_
+#define _PYOUTPUTDESCRIPTOR_H_
+
+#include "vamp-sdk/Plugin.h"
+
+typedef struct {
+		PyObject_HEAD
+		PyObject *dict;
+} OutputDescriptorObject; 
+
+PyAPI_DATA(PyTypeObject) OutputDescriptor_Type;
+
+#define PyOutputDescriptor_CheckExact(v)	((v)->ob_type == &OutputDescriptor_Type)
+#define PyOutputDescriptor_Check(v) PyObject_TypeCheck(v, &OutputDescriptor_Type)
+
+/*			  		 PyOutputDescriptor C++ API  	  	  	  		*/
+
+
+///fast macro version as per API convention
+#define PyOutputDescriptor_AS_DICT(v) ((const OutputDescriptorObject* const) (v))->dict
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyParameterDescriptor.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,154 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+#include "PyParameterDescriptor.h"
+#include "vamp-sdk/Plugin.h"
+#include <string>
+#include "PyTypeInterface.h"
+
+using namespace std;
+using namespace Vamp;
+using Vamp::Plugin;
+
+/*			 ParameterDescriptor Object's Methods 					*/ 
+//these objects have no callable methods
+
+/*		   PyParameterDescriptor methods implementing protocols   	*/ 
+// these functions are called by the interpreter automatically
+
+/* New ParameterDescriptor object */ 
+static PyObject *
+ParameterDescriptor_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+
+	ParameterDescriptorObject *self = 
+	(ParameterDescriptorObject*)type->tp_alloc(type, 0);
+	
+	if (self == NULL) return NULL;
+    self->dict = PyDict_New();
+	if (self->dict == NULL) return NULL;
+
+	/// allow copying objects
+    if (args and PyTuple_Size(args) == 1) {
+		PyObject* arg = PyTuple_GET_ITEM(args,0);
+		if (PyParameterDescriptor_CheckExact(arg))
+			PyDict_Merge(self->dict,PyParameterDescriptor_AS_DICT(arg),0);
+		else if (PyDict_CheckExact(arg)) 
+			PyDict_Merge(self->dict,arg,0);
+		else {
+			PyErr_SetString(PyExc_TypeError, 
+			"Object takes zero or one ParameterDescriptor or dictionary arguments.");
+			return NULL; 
+		}
+	}
+	return (PyObject *) self;
+}
+
+
+/* DESTRUCTOR: delete type object */
+static void
+ParameterDescriptorObject_dealloc(ParameterDescriptorObject *self)
+{
+	Py_XDECREF(self->dict);
+	PyObject_Del(self);
+}
+
+
+/* Set attributes */
+static int
+ParameterDescriptor_setattr(ParameterDescriptorObject *self, char *name, PyObject *v)
+{
+	if (v == NULL) {
+		int rv = PyDict_DelItemString(self->dict, name);
+		if (rv < 0)
+			PyErr_SetString(PyExc_AttributeError,"non-existing ParameterDescriptor attribute");
+		return rv;
+	}
+	else
+		return PyDict_SetItemString(self->dict, name, v);
+}
+
+
+/* Get attributes */
+static PyObject *
+ParameterDescriptor_getattr(ParameterDescriptorObject *self, char *name)
+{
+	if (self->dict != NULL) {
+		PyObject *v = PyDict_GetItemString(self->dict, name);
+		if (v != NULL) 
+		{
+			Py_INCREF(v);
+			return v;
+		}
+	}
+	return NULL;
+}
+
+
+/* String representation */
+static PyObject *
+ParameterDescriptor_repr(PyObject *self)
+{
+	ParameterDescriptorObject* v = (ParameterDescriptorObject*)self;
+	if (v->dict) return PyDict_Type.tp_repr((PyObject *)v->dict);
+	else return PyString_FromString("ParameterDescriptor()");
+}
+
+#define ParameterDescriptor_alloc PyType_GenericAlloc
+#define ParameterDescriptor_free PyObject_Del
+
+PyTypeObject ParameterDescriptor_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,						/*ob_size*/
+	"vampy.ParameterDescriptor",/*tp_name*/
+	sizeof(ParameterDescriptorObject),	/*tp_basicsize*/
+	0,						/*tp_itemsize*/
+	(destructor)ParameterDescriptorObject_dealloc, /*tp_dealloc*/
+	0,						/*tp_print*/
+	(getattrfunc)ParameterDescriptor_getattr, /*tp_getattr*/
+	(setattrfunc)ParameterDescriptor_setattr, /*tp_setattr*/
+	0,						/*tp_compare*/
+	ParameterDescriptor_repr,			/*tp_repr*/
+	0,						/*tp_as_number*/
+	0,						/*tp_as_sequence*/
+	0,						/*tp_as_mapping*/
+	0,						/*tp_hash*/
+	0,                      /*tp_call*/
+    0,                      /*tp_str*/
+    0,                      /*tp_getattro*/
+    0,                      /*tp_setattro*/
+    0,                      /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT,     /*tp_flags*/
+    0,                      /*tp_doc*/
+    0,                      /*tp_traverse*/
+    0,                      /*tp_clear*/
+    0,                      /*tp_richcompare*/
+    0,                      /*tp_weaklistoffset*/
+    0,                      /*tp_iter*/
+    0,                      /*tp_iternext*/
+    0,				        /*tp_methods*/ //TypeObject Methods
+    0,                      /*tp_members*/
+    0,                      /*tp_getset*/
+    0,                      /*tp_base*/
+    0,                      /*tp_dict*/
+    0,                      /*tp_descr_get*/
+    0,                      /*tp_descr_set*/
+    0,                      /*tp_dictoffset*/
+    0,                      /*tp_init*/
+    ParameterDescriptor_alloc,/*tp_alloc*/
+    ParameterDescriptor_new,/*tp_new*/
+    ParameterDescriptor_free,/*tp_free*/
+    0,                      /*tp_is_gc*/
+};
+
+/*		  		 	  PyParameterDescriptor C++ API    				*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyParameterDescriptor.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,33 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#ifndef _PYPARAMETERDESCRIPTOR_H_
+#define _PYPARAMETERDESCRIPTOR_H_
+
+#include "vamp-sdk/Plugin.h"
+
+typedef struct {
+		PyObject_HEAD
+		PyObject *dict;
+} ParameterDescriptorObject; 
+
+PyAPI_DATA(PyTypeObject) ParameterDescriptor_Type;
+
+#define PyParameterDescriptor_CheckExact(v)	((v)->ob_type == &ParameterDescriptor_Type)
+#define PyParameterDescriptor_Check(v) PyObject_TypeCheck(v, &ParameterDescriptor_Type)
+
+/*			  		 PyParameterDescriptor C++ API  	  		  	  */
+
+
+///fast macro version as per API convention
+#define PyParameterDescriptor_AS_DICT(v) ((const ParameterDescriptorObject* const) (v))->dict
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyPlugScanner.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,315 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+
+#include "PyPlugScanner.h"
+#include <algorithm>
+#include <cstdlib>
+//#include "vamp-hostsdk/PluginHostAdapter.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <tchar.h>
+#define pathsep ("\\")
+#else 
+#include <dirent.h>
+#include <dlfcn.h>
+#define pathsep ("/")
+#endif 
+#define joinPath(a,b) ( (a)+pathsep+(b) )
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+using std::find;
+
+PyPlugScanner::PyPlugScanner()
+{
+
+} 
+
+PyPlugScanner *PyPlugScanner::m_instance = NULL;
+bool PyPlugScanner::m_hasInstance = false;
+
+PyPlugScanner*
+PyPlugScanner::getInstance()
+{
+	if (!m_hasInstance) {
+		m_instance = new PyPlugScanner();
+		m_hasInstance = true;
+	}
+	return m_instance;
+}
+
+void
+PyPlugScanner::setPath(vector<string> path)
+{
+	m_path=path;
+}
+
+// We assume that each script on the path has one valid class
+vector<string> 
+PyPlugScanner::getPyPlugs()
+{
+	//for_each m_path listFiles then return vector<pyPlugs>
+	//key format: FullPathString/FileName.py:ClassName
+	
+	bool getCompiled = true;
+	char* getPyc = getenv("VAMPY_COMPILED");
+	if (getPyc) {
+		string value(getPyc);
+		cerr << "VAMPY_COMPILED=" << value << endl;
+		getCompiled = value.compare("1")?false:true;
+	}
+	
+	vector<string> pyPlugs;
+	string pluginKey;
+	PyObject *pyClass;
+	
+    for (size_t i = 0; i < m_path.size(); ++i) {
+        
+        vector<string> files = listFiles(m_path[i],"py");
+
+        /// recognise byte compiled plugins
+		if (getCompiled) {
+        	vector<string> compiled_files = listFiles(m_path[i],"pyc");
+			mergeFileLists(compiled_files,files);
+		}
+
+        for (vector<string>::iterator fi = files.begin();
+             fi != files.end(); ++fi) {
+				string script = *fi;
+				if (!script.empty()) {					
+					string classname=script.substr(0,script.rfind('.'));
+					pluginKey=joinPath(m_path[i],script)+":"+classname;
+					pyClass = getScriptClass(m_path[i],classname);
+					if (pyClass == NULL) 
+					cerr << "Warning: Syntax error in VamPy plugin:  " 
+					     << classname << ". Avoiding plugin." << endl;
+					else { 
+							pyPlugs.push_back(pluginKey);
+							m_pyClasses.push_back(pyClass);
+						}
+					//pyPlugs.push_back(pluginKey);
+				}
+		}		
+	}
+		
+return pyPlugs;	
+
+}
+
+/// insert python byte code names (.pyc) if a .py file can not be found
+/// The interpreter automatically generates byte code files and executes
+/// them if they exist. Therefore, we prefer .py files, but we allow
+/// (relatively) closed source distributions by recognising .pyc files.
+void
+PyPlugScanner::mergeFileLists(vector<string> &pyc, vector<string> &py)
+{
+    for (vector<string>::iterator pycit = pyc.begin();
+    	pycit != pyc.end(); ++pycit) {
+			// cerr << *pycit;
+			string pyc_name = *pycit;
+			string py_name = pyc_name.substr(0,pyc_name.rfind('.')) + ".py";
+			vector<string>::iterator pyit = find (py.begin(), py.end(), py_name);
+			if (pyit == py.end()) py.push_back(pyc_name);
+	}
+	
+}
+
+
+//For now return one class object found in each script
+vector<PyObject*> 
+PyPlugScanner::getPyClasses()
+{
+return m_pyClasses;	
+
+}
+
+//Validate
+//This should not be called more than once!
+PyObject* 
+PyPlugScanner::getScriptClass(string path, string classname)
+{
+
+	//Add plugin path to active Python Path 
+	string pyCmd = "import sys\nsys.path.append('" + path + "')\n";
+	PyRun_SimpleString(pyCmd.c_str());
+
+	//Assign an object to the source code
+	PyObject *pySource = PyString_FromString(classname.c_str());
+
+	//Import it as a module into the py interpreter
+	PyObject *pyModule = PyImport_Import(pySource);
+	PyObject* pyError = PyErr_Occurred();
+	if (! pyError == 0) { 
+		cerr << "ERROR: error importing source: " << classname << endl; 
+		PyErr_Print(); 
+		Py_DECREF(pySource); 
+		Py_CLEAR(pyModule);  // safer if pyModule==NULL
+		return NULL; 
+	}
+	Py_DECREF(pySource);
+
+	//Read the dictionary object holding the namespace of the module (borrowed reference)
+	PyObject *pyDict = PyModule_GetDict(pyModule);
+	Py_DECREF(pyModule);
+
+	//Get the PluginClass from the module (borrowed reference)
+	PyObject *pyClass = PyDict_GetItemString(pyDict, classname.c_str());
+
+	//Check if class is present and a callable method is implemented
+	if (pyClass && PyCallable_Check(pyClass)) {
+
+	    return pyClass;
+	}	
+	else {
+		cerr << "ERROR: callable plugin class could not be found in source: " << classname << endl 
+			<< "Hint: plugin source filename and plugin class name must be the same." << endl;
+		PyErr_Print(); 
+		return NULL;
+	}
+}
+
+
+
+// Return a list of files in dir with given extension
+// Code taken from hostext/PluginLoader.cpp
+vector<string>
+PyPlugScanner::listFiles(string dir, string extension)
+{
+    vector<string> files;
+
+#ifdef _WIN32
+
+    string expression = dir + "\\*." + extension;
+    WIN32_FIND_DATA data;
+    HANDLE fh = FindFirstFile(expression.c_str(), &data);
+    if (fh == INVALID_HANDLE_VALUE) return files;
+
+    bool ok = true;
+    while (ok) {
+        files.push_back(data.cFileName);
+        ok = FindNextFile(fh, &data);
+    }
+
+    FindClose(fh);
+
+#else
+
+    size_t extlen = extension.length();
+    DIR *d = opendir(dir.c_str());
+    if (!d) return files;
+            
+    struct dirent *e = 0;
+    while ((e = readdir(d))) {
+ 
+        if (!e->d_name) continue;
+       
+        size_t len = strlen(e->d_name);
+        if (len < extlen + 2 ||
+            e->d_name + len - extlen - 1 != "." + extension) {
+            continue;
+        }
+		//cerr << "pyscripts: " << e->d_name <<  endl;
+        files.push_back(e->d_name);
+    }
+
+    closedir(d);
+#endif
+
+    return files;
+}
+
+
+//!!! It would probably be better to actually call
+// PluginHostAdapter::getPluginPath.  That would mean this "plugin"
+// needs to link against vamp-hostsdk, but that's probably acceptable
+// as it is sort of a host as well.
+
+// std::vector<std::string>
+// PyPlugScanner::getAllValidPath()
+// { 
+// 	Vamp::PluginHostAdapter host_adapter( ??? );
+// 	return host_adapter.getPluginPath();
+// }
+
+// tried to implement it, but found a bit confusing how to 
+// instantiate the host adapter here...
+
+
+//Return correct plugin directories as per platform
+//Code taken from vamp-sdk/PluginHostAdapter.cpp
+std::vector<std::string>
+PyPlugScanner::getAllValidPath()
+{
+	
+    std::vector<std::string> path;
+    std::string envPath;
+
+    char *cpath = getenv("VAMP_PATH");
+    if (cpath) envPath = cpath;
+
+#ifdef _WIN32
+#define PATH_SEPARATOR ';'
+#define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins"
+#else
+#define PATH_SEPARATOR ':'
+#ifdef __APPLE__
+#define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"
+#else
+#define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"
+#endif
+#endif
+
+    if (envPath == "") {
+        envPath = DEFAULT_VAMP_PATH;
+        char *chome = getenv("HOME");
+        if (chome) {
+            std::string home(chome);
+            std::string::size_type f;
+            while ((f = envPath.find("$HOME")) != std::string::npos &&
+                    f < envPath.length()) {
+                envPath.replace(f, 5, home);
+            }
+        }
+#ifdef _WIN32
+        char *cpfiles = getenv("ProgramFiles");
+        if (!cpfiles) cpfiles = "C:\\Program Files";
+        std::string pfiles(cpfiles);
+        std::string::size_type f;
+        while ((f = envPath.find("%ProgramFiles%")) != std::string::npos &&
+               f < envPath.length()) {
+            envPath.replace(f, 14, pfiles);
+        }
+#endif
+    }
+
+    std::string::size_type index = 0, newindex = 0;
+
+    while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
+	path.push_back(envPath.substr(index, newindex - index));
+	index = newindex + 1;
+    }
+    
+    path.push_back(envPath.substr(index));
+
+	//can add an extra path for vampy plugins
+	char* extraPath = getenv("VAMPY_EXTPATH");
+	if (extraPath) {
+		string vampyPath(extraPath);
+		cerr << "VAMPY_EXTPATH=" << vampyPath << endl;
+		path.push_back(vampyPath);
+	}
+	
+    return path;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyPlugScanner.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,80 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+/*
+    Vamp
+
+    An API for audio analysis and feature extraction plugins.
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2006-2007 Chris Cannam and QMUL.
+  
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of the Centre for
+    Digital Music; Queen Mary, University of London; and Chris Cannam
+    shall not be used in advertising or otherwise to promote the sale,
+    use or other dealings in this Software without prior written
+    authorization.
+*/
+
+#ifndef _VAMP_PYPLUG_SCANNER_H_
+#define _VAMP_PYPLUG_SCANNER_H_
+
+#include <Python.h>
+#include <iostream>
+#include <vector>
+#include <string>
+#include <map>
+//#include <fstream>
+	
+class PyPlugScanner
+{
+public:
+	~PyPlugScanner() { m_hasInstance = false; }
+	static PyPlugScanner *getInstance();	
+	std::vector<std::string> getPyPlugs();
+	std::vector<PyObject*> getPyClasses();
+	void setPath(std::vector<std::string> path);
+	std::vector<std::string> getAllValidPath();
+	
+protected:
+	PyPlugScanner();
+	PyObject *getScriptClass(std::string path, std::string classname);
+	std::vector<std::string> listFiles(std::string dir, std::string ext);
+	void mergeFileLists(std::vector<std::string> &s, std::vector<std::string> &t);
+	
+	static bool m_hasInstance;
+	static PyPlugScanner *m_instance;
+	std::string m_dir;
+	std::vector<std::string> m_path; 
+	std::vector<PyObject*> m_pyClasses;
+};
+
+#endif	
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyPlugin.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,426 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+#include "PyPlugin.h"
+#include "PyTypeInterface.h"
+#include <stdlib.h>
+#include "PyExtensionModule.h"
+
+
+#ifdef _WIN32
+#define PATHSEP ('\\')
+#else 
+#define PATHSEP ('/')
+#endif
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+using std::map;
+
+Mutex PyPlugin::m_pythonInterpreterMutex;
+
+PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass, int &instcount) :
+	Plugin(inputSampleRate),
+	m_pyClass(pyClass),
+	m_instcount(instcount),
+	m_stepSize(0),
+	m_blockSize(0),
+	m_channels(0),
+	m_plugin(pluginKey),
+	m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
+	m_path((pluginKey.substr(0,pluginKey.rfind(PATHSEP)))),
+	m_processType(not_implemented),
+	m_pyProcess(NULL),
+	m_inputDomain(TimeDomain),
+	m_quitOnErrorFlag(false),
+	m_debugFlag(false)
+{	
+	m_ti.setInputSampleRate(inputSampleRate);
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	cerr << "Creating instance " << m_instcount << " of " << pluginKey << endl;
+		
+	// Create an instance
+	Py_INCREF(m_pyClass);
+	PyObject *pyInputSampleRate = PyFloat_FromDouble(inputSampleRate);
+	PyObject *args = PyTuple_Pack(1, pyInputSampleRate);
+	m_pyInstance = PyObject_Call(m_pyClass, args, NULL);
+	
+	if (!m_pyInstance || PyErr_Occurred()) { 
+		if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+		Py_DECREF(m_pyClass);
+		Py_CLEAR(args);
+		Py_CLEAR(pyInputSampleRate);
+		cerr << "PyPlugin::PyPlugin: Failed to create Python plugin instance for key \"" 
+		<< pluginKey << "\" (is the 1-arg class constructor from sample rate correctly provided?)" << endl;
+		throw std::string("Constructor failed");
+	}
+	Py_INCREF(m_pyInstance);
+	Py_DECREF(args);
+	Py_DECREF(pyInputSampleRate);
+	
+	m_instcount++;
+	
+	// query and decode vampy flags
+	m_vampyFlags = getBinaryFlags("vampy_flags",vf_NULL);
+
+	m_debugFlag = (bool) (m_vampyFlags & vf_DEBUG);
+	m_quitOnErrorFlag = (bool) (m_vampyFlags & vf_QUIT);
+	bool st_flag = (bool) (m_vampyFlags & vf_STRICT);
+	m_useRealTimeFlag = (bool) (m_vampyFlags & vf_REALTIME);
+		
+	if (m_debugFlag) cerr << "Debug messages ON for Vampy plugin: " << m_class << endl;
+	else cerr << "Debug messages OFF for Vampy plugin: " << m_class << endl;
+	
+	if (m_debugFlag && m_quitOnErrorFlag) cerr << "Quit on type error ON for: " << m_class << endl;
+   
+	if (m_debugFlag && st_flag) cerr << "Strict type conversion ON for: " << m_class << endl;
+	m_ti.setStrictTypingFlag(st_flag);
+
+}
+
+PyPlugin::~PyPlugin()
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	m_instcount--;
+	// cerr << "Deleting plugin instance. Count: " << m_instcount << endl;
+	
+	if (m_pyInstance) Py_DECREF(m_pyInstance);
+	//we increase the class refcount before creating an instance 
+	if (m_pyClass) Py_DECREF(m_pyClass); 
+	if (m_pyProcess) Py_CLEAR(m_pyProcess);
+
+#ifdef _DEBUG
+	cerr << "PyPlugin::PyPlugin:" << m_class << " instance " << m_instcount << " deleted." << endl;
+#endif
+}
+
+string
+PyPlugin::getIdentifier() const
+{	
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	string rString="vampy-xxx";
+	if (!m_debugFlag) return genericMethodCall("getIdentifier",rString);
+
+	rString = genericMethodCall("getIdentifier",rString);
+	if (rString == "vampy-xxx")
+		cerr << "Warning: Plugin must return a unique identifier." << endl;
+	return rString;
+}
+
+string
+PyPlugin::getName() const
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	string rString="VamPy Plugin (Noname)";
+    return genericMethodCall("getName",rString);
+}
+
+string
+PyPlugin::getDescription() const
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	string rString="Not given. (Hint: Implement getDescription method.)";
+	return genericMethodCall("getDescription",rString);
+}
+
+
+string
+PyPlugin::getMaker() const
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	string rString="VamPy Plugin.";
+	return genericMethodCall("getMaker",rString);
+}
+
+int
+PyPlugin::getPluginVersion() const
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	size_t rValue=2;
+	return genericMethodCall("getPluginVersion",rValue);
+}
+
+string
+PyPlugin::getCopyright() const
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	string rString="Licence information not available.";
+	return genericMethodCall("getCopyright",rString);
+}
+
+
+bool
+PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+
+	if (channels < getMinChannelCount() ||
+	    channels > getMaxChannelCount()) return false;
+
+	m_inputDomain = getInputDomain();
+
+	//Note: placing Mutex before the calls above causes deadlock !!
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
+	m_stepSize = stepSize;
+	m_blockSize = blockSize;
+	m_channels = channels;
+
+	//query the process implementation type
+	//two optional flags can be used: 'use_numpy_interface' or 'use_legacy_interface'
+	//if they are not provided, we fall back to the original method
+	setProcessType();
+	
+	return genericMethodCallArgs<bool>("initialise",channels,stepSize,blockSize);
+}
+
+void
+PyPlugin::reset()
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	genericMethodCall("reset");
+}
+
+PyPlugin::InputDomain 
+PyPlugin::getInputDomain() const  
+{ 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	return genericMethodCall("getInputDomain",m_inputDomain);
+}
+
+size_t 
+PyPlugin::getPreferredBlockSize() const 
+{ 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	size_t rValue = 0;
+	return genericMethodCall("getPreferredBlockSize",rValue); 
+}
+
+size_t 
+PyPlugin::getPreferredStepSize() const 
+{ 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	size_t rValue = 0;
+    return genericMethodCall("getPreferredStepSize",rValue); 
+}
+
+size_t 
+PyPlugin::getMinChannelCount() const 
+{ 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	size_t rValue = 1;
+    return genericMethodCall("getMinChannelCount",rValue); 
+}
+
+size_t 
+PyPlugin::getMaxChannelCount() const 
+{ 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	size_t rValue = 1;
+    return genericMethodCall("getMaxChannelCount",rValue); 
+}	
+
+PyPlugin::OutputList
+PyPlugin::getOutputDescriptors() const
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	OutputList list;
+	return genericMethodCall("getOutputDescriptors",list);
+}
+
+PyPlugin::ParameterList
+PyPlugin::getParameterDescriptors() const
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	ParameterList list;
+#ifdef _DEBUG	
+	///Note: This function is often called first by the host.
+	if (!m_pyInstance) {cerr << "Error: pyInstance is NULL" << endl; return list;}
+#endif
+
+	return genericMethodCall("getParameterDescriptors",list);
+}
+
+void PyPlugin::setParameter(std::string paramid, float newval)
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	genericMethodCallArgs<NoneType>("setParameter",paramid,newval);
+}
+
+float PyPlugin::getParameter(std::string paramid) const
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	return genericMethodCallArgs<float>("getParameter",paramid);
+}
+
+#ifdef _DEBUG_VALUES
+static int proccounter = 0;
+#endif
+
+PyPlugin::FeatureSet
+PyPlugin::process(const float *const *inputBuffers,Vamp::RealTime timestamp)
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
+#ifdef _DEBUG_VALUES
+	/// we only need this if we'd like to see what frame a set of values belong to 
+	cerr << "[Vampy::call] process, frame:" << proccounter << endl;
+	proccounter++;
+#endif
+
+    if (m_blockSize == 0 || m_channels == 0) {
+	cerr << "ERROR: PyPlugin::process: "
+	     << "Plugin has not been initialised" << endl;
+	return FeatureSet();
+    }
+
+	if (m_processType == not_implemented) {
+	cerr << "ERROR: In Python plugin [" << m_class   
+		 << "] No process implementation found. Returning empty feature set." << endl;
+	return FeatureSet();
+	}
+	
+	return processMethodCall(inputBuffers,timestamp);
+
+}
+
+PyPlugin::FeatureSet
+PyPlugin::getRemainingFeatures()
+{
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	FeatureSet rValue;
+	return genericMethodCall("getRemainingFeatures",rValue); 
+}
+
+bool
+PyPlugin::getBooleanFlag(char flagName[], bool defValue = false) const
+{
+	bool rValue = defValue;
+	if (PyObject_HasAttrString(m_pyInstance,flagName))
+	{
+		PyObject *pyValue = PyObject_GetAttrString(m_pyInstance,flagName);
+		if (!pyValue) 
+		{
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		} else {
+			rValue = m_ti.PyValue_To_Bool(pyValue);
+			if (m_ti.error) { 
+				Py_CLEAR(pyValue);
+				typeErrorHandler(flagName);
+				rValue = defValue;
+			} else Py_DECREF(pyValue);
+		}
+	}
+	if (m_debugFlag) cerr << FLAG_VALUE << endl;
+	return rValue;
+}
+
+int
+PyPlugin::getBinaryFlags(char flagName[], eVampyFlags defValue = vf_NULL) const
+{
+	int rValue = defValue;
+	if (PyObject_HasAttrString(m_pyInstance,flagName))
+	{
+		PyObject *pyValue = PyObject_GetAttrString(m_pyInstance,flagName);
+		if (!pyValue) 
+		{
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		} else {
+			rValue |= (int) m_ti.PyValue_To_Size_t(pyValue);
+			if (m_ti.error) { 
+				Py_CLEAR(pyValue);
+				typeErrorHandler(flagName);
+				rValue = defValue;
+			} else Py_DECREF(pyValue);
+		}
+	}
+	if (m_debugFlag) cerr << FLAG_VALUE << endl;
+	return rValue;
+}
+
+
+void
+PyPlugin::setProcessType()
+{
+	//quering process implementation type
+	char legacyMethod[]="process";
+	char numpyMethod[]="processN";
+
+	if (PyObject_HasAttrString(m_pyInstance,legacyMethod) &&
+	    m_processType == 0) 
+	{ 
+		m_processType = legacyProcess;
+		m_pyProcess = PyString_FromString(legacyMethod);
+		m_pyProcessCallable = PyObject_GetAttr(m_pyInstance,m_pyProcess);
+	}
+
+	if (PyObject_HasAttrString(m_pyInstance,numpyMethod) &&
+	    m_processType == 0)
+	{
+		m_processType = numpy_bufferProcess;
+		m_pyProcess = PyString_FromString(numpyMethod);
+		m_pyProcessCallable = PyObject_GetAttr(m_pyInstance,m_pyProcess);
+	}
+
+	// These flags are optional. If provided, they override the
+	// implementation type making the use of the odd processN() 
+	// function redundant.
+	// However, the code above provides backward compatibility.
+
+	if (m_vampyFlags & vf_BUFFER) {
+		m_processType = numpy_bufferProcess;
+		if (m_debugFlag) cerr << "Process using (numpy) buffer interface." << endl;
+	}
+
+    if (m_vampyFlags & vf_ARRAY) {
+#ifdef HAVE_NUMPY
+		m_processType = numpy_arrayProcess;
+		if (m_debugFlag) cerr << "Process using numpy array interface." << endl;
+#else
+		cerr << "Error: This version of vampy was compiled without numpy support, "
+			 << "however the vf_ARRAY flag is set for plugin: " << m_class << endl
+			 << "The default behaviour is: passing a python list of samples for each channel in process() "
+			 << "or a list of memory buffers in processN(). " << endl 
+			 << "This can be used create numpy arrays using the numpy.frombuffer() command." << endl;
+#endif		
+	}
+	
+	if (!m_processType)
+	{
+		m_processType = not_implemented;
+		m_pyProcess = NULL;
+		m_pyProcessCallable = NULL;
+		char method[]="initialise::setProcessType";
+		cerr << PLUGIN_ERROR << " No process implementation found. Plugin will do nothing." << endl;
+	}
+}
+
+void
+PyPlugin::typeErrorHandler(char *method) const
+{
+	bool strict = false;
+	while (m_ti.error) { 
+		PyTypeInterface::ValueError e = m_ti.getError();
+		cerr << PLUGIN_ERROR << e.str() << endl;
+		if (e.strict) strict = true;
+		// e.print();
+	}
+	/// quit on hard errors like accessing NULL pointers or strict type conversion
+	/// errors IF the user sets the quitOnErrorFlag in the plugin.
+	/// Otherwise most errors will go unnoticed apart from
+	/// a messages in the terminal.
+	/// It would be best if hosts could catch an exception instead
+	/// and display something meaningful to the user.
+	if (strict && m_quitOnErrorFlag) exit(EXIT_FAILURE);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyPlugin.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,491 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+/*
+    Vamp
+
+    An API for audio analysis and feature extraction plugins.
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2006 Chris Cannam.
+  
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of the Centre for
+    Digital Music; Queen Mary, University of London; and Chris Cannam
+    shall not be used in advertising or otherwise to promote the sale,
+    use or other dealings in this Software without prior written
+    authorization.
+*/
+
+#ifndef _PYTHON_WRAPPER_PLUGIN_H_
+#define _PYTHON_WRAPPER_PLUGIN_H_
+
+#define _CLASS_METHOD_ m_class << "::" << method
+#define PLUGIN_ERROR "ERROR: In Vampy plugin [" << _CLASS_METHOD_ << "]" << endl << "Cause: "
+#define DEBUG_NAME "[Vampy::call] " << _CLASS_METHOD_ << " "
+#define DEAFULT_RETURN "Method [" << _CLASS_METHOD_ << "] is not implemented. Returning default value."
+#define FLAG_VALUE "Flag: " << flagName << ": " << ((rValue==0)?"False":"True")
+
+#include <Python.h>
+#include "PyExtensionModule.h"
+#include "PyTypeInterface.h"
+#include "vamp-sdk/Plugin.h"
+#include "Mutex.h"
+
+using std::string;
+using std::cerr;
+using std::endl;
+
+enum eProcessType {
+	not_implemented,
+	legacyProcess,
+	numpyProcess,
+	numpy_bufferProcess,
+	numpy_arrayProcess
+	};
+
+class PyPlugin : public Vamp::Plugin
+{
+public:
+	PyPlugin(std::string plugin,float inputSampleRate, PyObject *pyClass, int &instcount);
+	virtual ~PyPlugin();
+
+	bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+	void reset();
+
+	InputDomain getInputDomain() const;
+	size_t getPreferredBlockSize() const;
+	size_t getPreferredStepSize() const; 
+	size_t getMinChannelCount() const; 
+	size_t getMaxChannelCount() const;
+
+	std::string getIdentifier() const;
+	std::string getName() const;
+	std::string getDescription() const;
+	std::string getMaker() const;
+	int getPluginVersion() const;
+	std::string getCopyright() const;
+	
+	OutputList getOutputDescriptors() const;
+	ParameterList getParameterDescriptors() const;
+	float getParameter(std::string paramid) const;
+	void setParameter(std::string paramid, float newval);
+    
+	FeatureSet process(const float *const *inputBuffers,
+			   Vamp::RealTime timestamp);
+
+	FeatureSet getRemainingFeatures();
+	
+protected:
+	static Mutex m_pythonInterpreterMutex;
+	PyObject *m_pyClass;
+	PyObject *m_pyInstance;
+	int &m_instcount;
+	size_t m_stepSize;
+	size_t m_blockSize;
+	size_t m_channels;
+	std::string m_plugin;
+	std::string m_class;
+	std::string m_path;
+	eProcessType m_processType;
+	PyObject *m_pyProcess;
+	PyObject *m_pyProcessCallable;
+	mutable InputDomain m_inputDomain;
+	PyTypeInterface m_ti;
+	int m_vampyFlags;
+	bool m_quitOnErrorFlag;
+	bool m_debugFlag;
+	bool m_useRealTimeFlag;
+
+	void setProcessType();
+	
+	FeatureSet processMethodCall(const float *const *inputBuffers,Vamp::RealTime timestamp);
+
+	bool getBooleanFlag(char flagName[],bool) const;
+	int getBinaryFlags(char flagName[], eVampyFlags) const;
+	void typeErrorHandler(char *method) const;
+
+	/// simple 'void return' call with no args
+	void genericMethodCall(char *method) const
+	{
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if ( PyObject_HasAttrString(m_pyInstance,method) ) 
+		{
+			PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL);
+			if (!pyValue) {
+				cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+				if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			}
+		}
+	}
+
+	/// 'no arg with default return value' call
+	template<typename RET> 
+	RET &genericMethodCall(char *method, RET &rValue) const
+	{
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if ( PyObject_HasAttrString(m_pyInstance,method) ) 
+		{
+			PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL);
+			if (!pyValue) {
+				cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+				if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+				return rValue;
+			}
+
+            /// convert the returned value
+			m_ti.PyValue_To_rValue(pyValue,rValue);
+			if (!m_ti.error) {
+				Py_DECREF(pyValue);
+			} else {
+				Py_CLEAR(pyValue);
+				typeErrorHandler(method);
+			}
+			return rValue;
+		}
+		if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
+		return rValue;
+	}
+
+	/// unary call
+	template<typename RET,typename A1>
+	RET genericMethodCallArgs(char *method, A1 arg1) const
+	{
+		RET rValue = RET();
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if (!PyObject_HasAttrString(m_pyInstance,method)) {
+			if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
+			return rValue;
+		}
+		
+		/// prepare arguments for fast method call
+		PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
+		PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
+		PyObject* pyArgs = PyTuple_New(1);
+		if (!(pyArgs && pyCallable && pyMethod)) {
+			cerr << PLUGIN_ERROR << "Failed to prepare argument for calling method." << endl;
+			Py_CLEAR(pyMethod);
+			Py_CLEAR(pyCallable);
+			Py_CLEAR(pyArgs);
+			return rValue;
+		}
+		
+		PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
+		if (m_ti.error) {
+			cerr << PLUGIN_ERROR << "Failed to convert argument for calling method." << endl;
+			typeErrorHandler(method);
+			Py_CLEAR(pyMethod);
+			Py_CLEAR(pyCallable);
+			Py_CLEAR(pyArg1);
+			Py_CLEAR(pyArgs);
+			return rValue;
+		}
+		
+		PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
+		Py_INCREF(pyArg1);	
+		
+        /// call the method
+		PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
+		if (!pyValue) 
+		{
+			cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			Py_CLEAR(pyMethod);
+			Py_CLEAR(pyCallable);
+			Py_CLEAR(pyArg1);
+			Py_CLEAR(pyArgs);
+			return rValue;
+		}
+			
+		Py_DECREF(pyMethod);
+		Py_DECREF(pyCallable);
+		Py_DECREF(pyArg1);
+		Py_DECREF(pyArgs);    
+		
+		/// convert the returned value
+		m_ti.PyValue_To_rValue(pyValue,rValue);
+		if (!m_ti.error) {
+			Py_DECREF(pyValue);
+		} else {
+			Py_CLEAR(pyValue);
+			typeErrorHandler(method);
+		}
+		return rValue;
+	}
+
+	/// binary call
+	template<typename RET,typename A1,typename A2>
+	RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2) const
+	{
+		RET rValue = RET();
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if (!PyObject_HasAttrString(m_pyInstance,method)) {
+			if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
+			return rValue;
+		}
+		
+		/// prepare arguments for fast method call
+		PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
+		PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
+		PyObject* pyArgs = PyTuple_New(2);
+		if (!(pyArgs && pyCallable && pyMethod)) {
+			cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl;
+			Py_CLEAR(pyMethod);
+			Py_CLEAR(pyCallable);
+			Py_CLEAR(pyArgs);
+			return rValue;
+		}
+		
+		PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
+		PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
+		if (m_ti.error) {
+			cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
+			typeErrorHandler(method);
+			Py_CLEAR(pyMethod);
+			Py_CLEAR(pyCallable);
+			Py_CLEAR(pyArg1);
+			Py_CLEAR(pyArg2);
+			Py_CLEAR(pyArgs);
+			return rValue;
+		}
+		
+		PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
+		Py_INCREF(pyArg1);	
+		PyTuple_SET_ITEM(pyArgs, 1, pyArg2);
+		Py_INCREF(pyArg2);
+
+		// calls the method
+		PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
+		if (!pyValue) 
+		{
+			cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			Py_CLEAR(pyMethod);
+			Py_CLEAR(pyCallable);
+			Py_CLEAR(pyArg1);
+			Py_CLEAR(pyArg2);
+			Py_CLEAR(pyArgs);
+			return rValue;
+		}
+			
+		Py_DECREF(pyMethod);
+		Py_DECREF(pyCallable);
+		Py_DECREF(pyArg1);
+		Py_DECREF(pyArg2);
+		Py_DECREF(pyArgs);    
+		
+		/// convert the returned value
+		m_ti.PyValue_To_rValue(pyValue,rValue);
+		if (!m_ti.error) {
+			Py_DECREF(pyValue);
+		} else {
+			Py_CLEAR(pyValue);
+			typeErrorHandler(method);
+		}
+		return rValue;
+	}
+
+	/// trenary call
+	template<typename RET,typename A1,typename A2,typename A3>
+	RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2, A3 arg3) const
+	{
+		RET rValue = RET();
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if (!PyObject_HasAttrString(m_pyInstance,method)) {
+			if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
+			return rValue;
+		}
+		
+		/// prepare arguments for fast method call
+		PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
+		PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
+		PyObject* pyArgs = PyTuple_New(3);
+		if (!(pyArgs && pyCallable && pyMethod)) {
+			cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl;
+			Py_CLEAR(pyMethod);
+			Py_CLEAR(pyCallable);
+			Py_CLEAR(pyArgs);
+			return rValue;
+		}
+		
+		PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
+		PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
+		PyObject *pyArg3 = m_ti.PyValue_From_CValue(arg3);
+		if (m_ti.error) {
+			cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
+			typeErrorHandler(method);
+			Py_CLEAR(pyMethod);
+			Py_CLEAR(pyCallable);
+			Py_CLEAR(pyArg1);
+			Py_CLEAR(pyArg2);
+			Py_CLEAR(pyArg3);
+			Py_CLEAR(pyArgs);
+			return rValue;
+		}
+		
+		/// Optimization: Pack args in a tuple to avoid va_list parsing.
+		PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
+		Py_INCREF(pyArg1);	
+		PyTuple_SET_ITEM(pyArgs, 1, pyArg2);
+		Py_INCREF(pyArg2);
+		PyTuple_SET_ITEM(pyArgs, 2, pyArg3);
+		Py_INCREF(pyArg3);
+
+		// PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,pyArg2,pyArg3,NULL);
+		/// fast method call
+		PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
+		if (!pyValue) 
+		{
+			cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			Py_CLEAR(pyMethod);
+			Py_CLEAR(pyCallable);
+			Py_CLEAR(pyArg1);
+			Py_CLEAR(pyArg2);
+			Py_CLEAR(pyArg3);
+			Py_CLEAR(pyArgs);
+			return rValue;
+		}
+			
+		Py_DECREF(pyMethod);
+		Py_DECREF(pyCallable);
+		Py_DECREF(pyArg1);
+		Py_DECREF(pyArg2);
+		Py_DECREF(pyArg3);    
+		Py_DECREF(pyArgs);    
+		
+		/// convert the returned value
+		m_ti.PyValue_To_rValue(pyValue,rValue);
+		if (!m_ti.error) {
+			Py_DECREF(pyValue);
+		} else {
+			Py_CLEAR(pyValue);
+			typeErrorHandler(method);
+		}
+		return rValue;
+	}
+
+};
+
+/// optimised process call
+inline PyPlugin::FeatureSet
+PyPlugin::processMethodCall(const float *const *inputBuffers,Vamp::RealTime timestamp)
+{
+	
+	/// Optimizations: 1) we avoid ...ObjArg functions since we know
+	/// the number of arguments, and we don't like va_list parsing 
+	/// in the process. 2) Also: we're supposed to incref args, 
+	/// but instead, we let the arguments tuple steal the references
+	/// and decref them when it is deallocated.
+	/// 3) all conversions are now using the fast sequence protocol
+	/// (indexing the underlying object array).
+	
+	FeatureSet rFeatureSet;
+	PyObject *pyChannelList = NULL;
+
+	if (m_processType == numpy_bufferProcess) {
+		pyChannelList = m_ti.InputBuffers_As_SharedMemoryList(inputBuffers,m_channels,m_blockSize);
+	} 
+
+	if (m_processType == legacyProcess) {
+		pyChannelList = m_ti.InputBuffers_As_PythonLists(inputBuffers,m_channels,m_blockSize,m_inputDomain);
+	}
+
+#ifdef HAVE_NUMPY
+	if (m_processType == numpy_arrayProcess) {
+		pyChannelList = m_ti.InputBuffers_As_NumpyArray(inputBuffers,m_channels,m_blockSize,m_inputDomain);
+	}
+#endif
+
+/// we don't expect these to fail unless out of memory (which is very unlikely on modern systems)
+#ifdef _DEBUG
+	if (!pyChannelList) {
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		std::string method = PyString_AsString(m_pyProcess);
+		cerr << PLUGIN_ERROR << "Failed to create channel list." << endl;
+		return rFeatureSet;
+	}
+#endif		
+
+	PyObject *pyTimeStamp = NULL;
+		
+	if (m_useRealTimeFlag) {
+		//(1) pass TimeStamp as PyRealTime object
+		pyTimeStamp = PyRealTime_FromRealTime(timestamp);
+
+	} else {
+		//(2) pass TimeStamp as frame count (long Sample Count)
+		pyTimeStamp = PyLong_FromLong(Vamp::RealTime::realTime2Frame 
+		(timestamp, (unsigned int) m_inputSampleRate));
+	}
+
+
+#ifdef _DEBUG
+	if (!pyTimeStamp) {
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		std::string method = PyString_AsString(m_pyProcess);
+		cerr << PLUGIN_ERROR << "Failed to create RealTime time stamp." << endl;
+		Py_DECREF(pyChannelList);
+		return rFeatureSet;
+	}
+#endif
+
+	/// Old method: Call python process (returns new reference)
+	/// PyObject *pyValue = PyObject_CallMethodObjArgs
+	/// (m_pyInstance,m_pyProcess,pyChannelList,pyTimeStamp,NULL);
+	
+	PyObject *pyArgs = PyTuple_New(2);
+	PyTuple_SET_ITEM(pyArgs, 0, pyChannelList); 
+	PyTuple_SET_ITEM(pyArgs, 1, pyTimeStamp); 
+
+	/// Call python process (returns new reference) {kwArgs = NULL}
+	PyObject *pyValue = PyObject_Call(m_pyProcessCallable,pyArgs,NULL);
+
+	if (!pyValue) {
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		std::string method = PyString_AsString(m_pyProcess);
+		cerr << PLUGIN_ERROR << "An error occurred while evaluating Python process." << endl;
+		Py_CLEAR(pyValue);
+		Py_CLEAR(pyArgs);
+		return rFeatureSet;
+	}
+        
+	rFeatureSet = m_ti.PyValue_To_FeatureSet(pyValue);
+	if (!m_ti.error) {
+		Py_DECREF(pyValue);
+		Py_DECREF(pyArgs);
+	} else {
+		typeErrorHandler(PyString_AsString(m_pyProcess));
+		Py_CLEAR(pyValue);
+		Py_CLEAR(pyArgs);
+	}
+	return rFeatureSet;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyRealTime.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,356 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+#include "PyRealTime.h"
+#include "vamp-sdk/Plugin.h"
+#include <string>
+
+using namespace std;
+using namespace Vamp;
+using Vamp::Plugin;
+using Vamp::RealTime;
+
+
+/* CONSTRUCTOR: New RealTime object from sec and nsec */
+static PyObject*
+RealTime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+	unsigned int sec = 0;
+	unsigned int nsec = 0;
+	double unary = 0;
+	const char *fmt = NULL;
+
+	if (
+	/// new RealTime from ('format',float) e.g. ('seconds',2.34123)   
+	!PyArg_ParseTuple(args, "|sd:RealTime.new ", 
+	(const char *) &fmt, 
+	(double *) &unary) 	&&
+
+	/// new RealTime from (sec{int},nsec{int}) e.g. (2,34)
+	!PyArg_ParseTuple(args, "|II:RealTime.new ", 
+	(unsigned int*) &sec, 
+	(unsigned int*) &nsec) 
+		
+	) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"RealTime initialised with wrong arguments.");
+		return NULL; 
+	  }
+
+	// PyErr_Clear();
+
+	// RealTimeObject *self = PyObject_New(RealTimeObject, &RealTime_Type); 
+	RealTimeObject *self = (RealTimeObject*)type->tp_alloc(type, 0);
+	
+	if (self == NULL) return NULL;
+
+	self->rt = NULL;
+
+	if (sec == 0 && nsec == 0 && fmt == 0) 
+		self->rt = new RealTime();
+	else if (fmt == 0)
+		self->rt = new RealTime(sec,nsec);
+	else { 
+        /// new RealTime from seconds or milliseconds: i.e. >>>RealTime('seconds',12.3)
+		if (!string(fmt).compare("float") ||
+			!string(fmt).compare("seconds"))  
+			self->rt = new RealTime( 
+			RealTime::fromSeconds((double) unary)); 
+
+		if (!string(fmt).compare("milliseconds")) {
+			self->rt = new RealTime( 
+			RealTime::fromSeconds((double) unary / 1000.0)); }
+	}
+
+	if (!self->rt) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"RealTime initialised with wrong arguments.");
+		return NULL; 
+	}
+
+	return (PyObject *) self;
+}
+
+/* DESTRUCTOR: delete type object */
+static void
+RealTimeObject_dealloc(RealTimeObject *self)
+{
+	if (self->rt) delete self->rt; 	//delete the C object
+	PyObject_Del(self); //delete the Python object (original)
+	/// this requires PyType_Ready() which fills ob_type
+	// self->ob_type->tp_free((PyObject*)self); 
+}
+
+/*					 RealTime Object's Methods 					*/ 
+//these are internals not exposed by the module but the object
+
+/* Returns a Tuple containing sec and nsec values */
+static PyObject *
+RealTime_values(RealTimeObject *self)
+{
+	return Py_BuildValue("(ii)",self->rt->sec,self->rt->nsec);
+}
+
+/* Returns a Text representation */
+static PyObject *
+RealTime_toString(RealTimeObject *self, PyObject *args)
+{
+	return Py_BuildValue("s",self->rt->toText().c_str());
+}
+
+/* Frame representation */
+static PyObject *
+RealTime_toFrame(PyObject *self, PyObject *args)
+{
+	unsigned int samplerate;
+	
+	if ( !PyArg_ParseTuple(args, "I:realtime.toFrame object ", 
+	(unsigned int *) &samplerate )) {
+		PyErr_SetString(PyExc_ValueError,"Integer Sample Rate Required.");
+		return NULL;
+	}
+	
+	return Py_BuildValue("k", 
+	RealTime::realTime2Frame( 
+	*(const RealTime*) ((RealTimeObject*)self)->rt, 
+	(unsigned int) samplerate));
+}
+
+/* Conversion of realtime to a double precision floating point value */
+/* ...in Python called by e.g. float(realtime) */
+static PyObject *
+RealTime_float(PyObject *s)
+{
+	double drt = ((double) ((RealTimeObject*)s)->rt->sec + 
+	(double)((double) ((RealTimeObject*)s)->rt->nsec)/1000000000);
+	return PyFloat_FromDouble(drt);	
+}
+
+
+/* Type object's (RealTime) methods table */
+static PyMethodDef RealTime_methods[] = 
+{
+	{"values",	(PyCFunction)RealTime_values,	METH_NOARGS,
+		PyDoc_STR("values() -> Tuple of sec,nsec representation.")},
+
+	{"toString",	(PyCFunction)RealTime_toString,	METH_NOARGS,
+		PyDoc_STR("toString() -> Return a user-readable string to the nearest millisecond in a form like HH:MM:SS.mmm")},
+
+	{"toFrame",	(PyCFunction)RealTime_toFrame,	METH_VARARGS,
+		PyDoc_STR("toFrame(samplerate) -> Sample count for given sample rate.")},
+
+	{"toFloat",	(PyCFunction)RealTime_float,	METH_NOARGS,
+		PyDoc_STR("toFloat() -> Floating point representation.")},
+	
+	{NULL,		NULL}		/* sentinel */
+};
+
+
+/*		   			 Methods implementing protocols 		   	     */ 
+// these functions are called by the interpreter 
+
+/*					 Object Protocol 					*/
+
+static int
+RealTime_setattr(RealTimeObject *self, char *name, PyObject *value)
+{
+
+	if ( !string(name).compare("sec")) { 
+		self->rt->sec= (int) PyInt_AS_LONG(value);
+		return 0;
+	}
+
+	if ( !string(name).compare("nsec")) { 
+		self->rt->nsec= (int) PyInt_AS_LONG(value);
+		return 0;
+	}
+
+	return -1;
+}
+
+static PyObject *
+RealTime_getattr(RealTimeObject *self, char *name)
+{
+
+	if ( !string(name).compare("sec") ) { 
+		return PyInt_FromSsize_t(
+		(Py_ssize_t) self->rt->sec); 
+	} 
+
+	if ( !string(name).compare("nsec") ) { 
+		return PyInt_FromSsize_t(
+		(Py_ssize_t) self->rt->nsec); 
+	} 
+
+	return Py_FindMethod(RealTime_methods, 
+	(PyObject *)self, name);
+}
+
+/* String representation called by e.g. str(realtime), print realtime*/
+static PyObject *
+RealTime_repr(PyObject *self)
+{
+	return Py_BuildValue("s",
+	((RealTimeObject*)self)->rt->toString().c_str());
+}
+
+
+/*					 Number Protocol 					*/
+/// Only add and substract make sense, or what about the
+/// square root of Monday morning?
+/// Divide by integer maybe for durations?
+
+static PyObject *
+RealTime_add(PyObject *s, PyObject *w)
+{
+	RealTimeObject *result = 
+    PyObject_New(RealTimeObject, &RealTime_Type); 
+	if (result == NULL) return NULL;
+
+	result->rt = new RealTime(
+	*((RealTimeObject*)s)->rt + *((RealTimeObject*)w)->rt);
+	return (PyObject*)result;
+}
+
+static PyObject *
+RealTime_subtract(PyObject *s, PyObject *w)
+{
+	RealTimeObject *result = 
+    PyObject_New(RealTimeObject, &RealTime_Type); 
+	if (result == NULL) return NULL;
+
+	result->rt = new RealTime(
+	*((RealTimeObject*)s)->rt - *((RealTimeObject*)w)->rt);
+	return (PyObject*)result;
+}
+
+static PyNumberMethods realtime_as_number = 
+{
+	RealTime_add,			/*nb_add*/
+	RealTime_subtract,		/*nb_subtract*/
+	0,						/*nb_multiply*/
+	0,				 		/*nb_divide*/
+    0,						/*nb_remainder*/
+    0,      	            /*nb_divmod*/
+    0,                   	/*nb_power*/
+    0,                  	/*nb_neg*/
+    0,                		/*nb_pos*/
+    0,                  	/*(unaryfunc)array_abs,*/
+    0,                    	/*nb_nonzero*/
+    0,                    	/*nb_invert*/
+    0,       				/*nb_lshift*/
+    0,      				/*nb_rshift*/
+    0,      				/*nb_and*/
+    0,      				/*nb_xor*/
+    0,       				/*nb_or*/
+    0,                      /*nb_coerce*/
+    0,						/*nb_int*/
+    0,				        /*nb_long*/
+    (unaryfunc)RealTime_float,/*nb_float*/
+    0,               		/*nb_oct*/
+    0,               		/*nb_hex*/
+};
+
+/*						REAL-TIME TYPE OBJECT						*/
+
+#define RealTime_alloc PyType_GenericAlloc
+#define RealTime_free PyObject_Del
+
+/* Doc:: 10.3 Type Objects */ /* static */ 
+PyTypeObject RealTime_Type = 
+{
+	PyObject_HEAD_INIT(NULL)
+	0,						/*ob_size*/
+	"vampy.RealTime",				/*tp_name*/
+	sizeof(RealTimeObject),	/*tp_basicsize*/
+	0,//sizeof(RealTime),		/*tp_itemsize*/
+	/*	 	methods	 	*/
+	(destructor)RealTimeObject_dealloc, /*tp_dealloc*/
+	0,						/*tp_print*/
+	(getattrfunc)RealTime_getattr, /*tp_getattr*/
+	(setattrfunc)RealTime_setattr, /*tp_setattr*/
+	0,						/*tp_compare*/
+	RealTime_repr,			/*tp_repr*/
+	&realtime_as_number,	/*tp_as_number*/
+	0,						/*tp_as_sequence*/
+	0,						/*tp_as_mapping*/
+	0,						/*tp_hash*/
+	0,//(ternaryfunc)RealTime_new,                      /*tp_call*/
+    0,                      /*tp_str*/
+    0,                      /*tp_getattro*/
+    0,                      /*tp_setattro*/
+    0,                      /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT,     /*tp_flags*/
+    "RealTime Object",      /*tp_doc*/
+    0,                      /*tp_traverse*/
+    0,                      /*tp_clear*/
+    0,                      /*tp_richcompare*/
+    0,                      /*tp_weaklistoffset*/
+    0,                      /*tp_iter*/
+    0,                      /*tp_iternext*/
+    RealTime_methods,       /*tp_methods*/ //TypeObject Methods
+    0,                      /*tp_members*/
+    0,                      /*tp_getset*/
+    0,                      /*tp_base*/
+    0,                      /*tp_dict*/
+    0,                      /*tp_descr_get*/
+    0,                      /*tp_descr_set*/
+    0,                      /*tp_dictoffset*/
+    0,                      /*tp_init*/
+    RealTime_alloc,         /*tp_alloc*/
+	RealTime_new,           /*tp_new*/
+    RealTime_free,			/*tp_free*/
+    0,                      /*tp_is_gc*/
+};
+
+
+
+/*		  		 	  PyRealTime C++ API  	  		  				*/
+
+/*PyRealTime from RealTime pointer
+PyObject* 
+PyRealTime_FromRealTime(Vamp::RealTime *rt) {
+
+	RealTimeObject *self =
+	PyObject_New(RealTimeObject, &RealTime_Type); 
+	if (self == NULL) return NULL;
+
+	self->rt = new RealTime(*rt);
+	return (PyObject*) self;
+}*/
+
+
+/*PyRealTime from RealTime*/
+PyObject* 
+PyRealTime_FromRealTime(Vamp::RealTime& rt) {
+
+	RealTimeObject *self =
+	PyObject_New(RealTimeObject, &RealTime_Type); 
+	if (self == NULL) return NULL;
+
+	self->rt = new RealTime(rt);
+	return (PyObject*) self;
+}
+
+/*RealTime* from PyRealTime*/
+const Vamp::RealTime*
+PyRealTime_AsRealTime (PyObject *self) { 
+
+	RealTimeObject *s = (RealTimeObject*) self; 
+
+	if (!PyRealTime_Check(s)) {
+		PyErr_SetString(PyExc_TypeError, "RealTime Object Expected.");
+		cerr << "in call PyRealTime_AsPointer(): RealTime Object Expected. " << endl;
+		return NULL; }
+	return s->rt; 
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyRealTime.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,39 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#ifndef _PYREALTIME_H_
+#define _PYREALTIME_H_
+
+#include "vamp-sdk/Plugin.h"
+
+typedef struct {
+		PyObject_HEAD
+		Vamp::RealTime *rt;
+} RealTimeObject; 
+
+PyAPI_DATA(PyTypeObject) RealTime_Type;
+
+#define PyRealTime_CheckExact(v)	((v)->ob_type == &RealTime_Type)
+#define PyRealTime_Check(v) PyObject_TypeCheck(v, &RealTime_Type)
+///fast macro version as per API convention
+#define PyRealTime_AS_REALTIME(v) ((const RealTimeObject* const) (v))->rt
+
+/*		  		 	  PyRealTime C++ API  	  		  				*/
+
+
+PyAPI_FUNC(PyObject *) 
+PyRealTime_FromRealTime(Vamp::RealTime&);
+
+PyAPI_FUNC(const Vamp::RealTime*) 
+PyRealTime_AsRealTime (PyObject *self);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyTypeInterface.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,1180 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+
+#ifdef HAVE_NUMPY
+#define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API
+#define NO_IMPORT_ARRAY
+#include "numpy/arrayobject.h"
+#endif
+
+#include "PyTypeInterface.h"
+#include "PyRealTime.h"
+#include "PyExtensionModule.h"
+#include <math.h>
+#include <float.h>
+#include <limits.h>
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ((size_t) -1)
+#endif
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+using std::map;
+
+static std::map<std::string, o::eOutDescriptors> outKeys;
+static std::map<std::string, p::eParmDescriptors> parmKeys;
+static std::map<std::string, eSampleTypes> sampleKeys;
+static std::map<std::string, eFeatureFields> ffKeys;
+static bool isMapInitialised = false;
+
+/*  Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS
+	(EXCEPT FOR TEMPORARY PYTHON OBJECTS)!  						 */
+
+PyTypeInterface::PyTypeInterface() : 
+	m_strict(false),
+	m_error(false),
+	error(m_error) // const public reference for easy access
+{
+}
+
+PyTypeInterface::~PyTypeInterface()
+{
+}
+
+/// floating point numbers (TODO: check numpy.float128)
+float 
+PyTypeInterface::PyValue_To_Float(PyObject* pyValue) const
+{
+	// convert float
+	if (pyValue && PyFloat_Check(pyValue)) 
+		//TODO: check for limits here (same on most systems)
+		return (float) PyFloat_AS_DOUBLE(pyValue);
+	
+	if (pyValue == NULL)
+	{
+		setValueError("Error while converting float object.",m_strict);
+		return 0.0;		
+	}
+		
+	// in strict mode we will not try harder
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not float.",m_strict);
+		return 0.0;
+	}
+
+	// convert other objects supporting the number protocol
+	if (PyNumber_Check(pyValue))
+	{
+		PyObject* pyFloat = PyNumber_Float(pyValue); // new ref
+		if (!pyFloat)
+		{
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			setValueError("Error while converting " + PyValue_Get_TypeName(pyValue) + " object to float.",m_strict);
+			return 0.0;
+		}
+		float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
+		Py_DECREF(pyFloat);
+		return rValue;
+	}
+/*	
+	// convert other objects supporting the number protocol
+	if (PyNumber_Check(pyValue)) 
+	{	
+		// PEP353: Py_ssize_t is size_t but signed !
+		// This will work up to numpy.float64
+		Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError("Error while converting integer object.",m_strict);
+			return 0.0;
+		}
+		if (rValue > (Py_ssize_t)FLT_MAX || rValue < (Py_ssize_t)FLT_MIN)
+		{
+			setValueError("Overflow error. Object can not be converted to float.",m_strict);
+			return 0.0;
+		}
+		return (float) rValue;
+	}
+*/	
+    // convert string
+	if (PyString_Check(pyValue))
+	{
+		PyObject* pyFloat = PyFloat_FromString(pyValue,NULL);
+		if (!pyFloat) 
+		{
+			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+			setValueError("String value can not be converted to float.",m_strict);
+			return 0.0;
+		}
+		float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear(); 
+			Py_CLEAR(pyFloat);
+			setValueError("Error while converting float object.",m_strict);
+			return 0.0;
+		}
+		Py_DECREF(pyFloat);
+		return rValue;
+	}
+	
+	// convert the first element of any iterable sequence (for convenience and backwards compatibility)
+	if (PySequence_Check(pyValue) and PySequence_Size(pyValue) > 0) 
+	{
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			float rValue = this->PyValue_To_Float(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				std::string msg = "Could not convert sequence element to float. ";
+				setValueError(msg,m_strict);
+				return 0.0;
+			}
+		}
+	}
+
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_Float failed. " << msg << endl;
+#endif	
+	return 0.0;
+}
+
+/// size_t (unsigned integer types)
+size_t 
+PyTypeInterface::PyValue_To_Size_t(PyObject* pyValue) const
+{
+	// convert objects supporting the number protocol 
+	if (PyNumber_Check(pyValue)) 
+	{	
+		if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue)) 
+			setValueError("Strict conversion error: object is not integer type.",m_strict);
+		// Note: this function handles Bool,Int,Long,Float
+		// speed is not critical in the use of this type by Vamp
+		// PEP353: Py_ssize_t is size_t but signed ! 
+		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError("Error while converting integer object.",m_strict);
+			return 0;
+		}
+		if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0)
+		{
+			setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
+			return 0;
+		}
+		return (size_t) rValue;
+	}
+	
+	// in strict mode we will not try harder and throw an exception
+	// then the caller should decide what to do with it
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not integer.",m_strict);
+		return 0;
+	}
+	
+	// convert string
+	if (PyString_Check(pyValue))
+	{
+		PyObject* pyLong = PyNumber_Long(pyValue);
+		if (!pyLong) 
+		{
+			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+			setValueError("String object can not be converted to size_t.",m_strict);
+			return 0;
+		}
+		size_t rValue = this->PyValue_To_Size_t(pyLong);
+		if (!m_error) {
+			Py_DECREF(pyLong);
+			return rValue;
+		} else {
+			Py_CLEAR(pyLong);
+			setValueError ("Error converting string to size_t.",m_strict);
+			return 0;
+		}
+	}
+	
+	// convert the first element of iterable sequences
+	if (PySequence_Check(pyValue) and PySequence_Size(pyValue) > 0) 
+	{
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			size_t rValue = this->PyValue_To_Size_t(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				setValueError("Could not convert sequence element to size_t. ",m_strict);
+				return 0;
+			}
+		}
+	}
+	
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_Size_t failed. " << msg << endl;
+#endif	
+	return 0;
+}
+
+/// long and int
+long 
+PyTypeInterface::PyValue_To_Long(PyObject* pyValue) const
+{
+	// most common case: convert int (faster)
+	if (pyValue && PyInt_Check(pyValue)) {
+		// if the object is not NULL and verified, this macro just extracts the value.
+		return PyInt_AS_LONG(pyValue);
+	} 
+	
+	// long
+	if (PyLong_Check(pyValue)) {
+		long rValue = PyLong_AsLong(pyValue);
+		if (PyErr_Occurred()) { 
+			PyErr_Print(); PyErr_Clear(); 
+			setValueError("Error while converting long object.",m_strict);
+			return 0;
+		}
+		return rValue;
+	}
+	
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not integer or long integer.",m_strict);
+		return 0;
+	}
+	
+	// convert all objects supporting the number protocol
+	if (PyNumber_Check(pyValue)) 
+	{	
+		// Note: this function handles Bool,Int,Long,Float
+		// PEP353: Py_ssize_t is size_t but signed ! 
+		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError("Error while converting integer object.",m_strict);
+			return 0;
+		}
+		if (rValue > LONG_MAX || rValue < LONG_MIN)
+		{
+			setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
+			return 0;
+		}
+		return (long) rValue;
+	}
+	
+	// convert string
+	if (PyString_Check(pyValue))
+	{
+		PyObject* pyLong = PyNumber_Long(pyValue);
+		if (!pyLong) 
+		{
+			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+			setValueError("String object can not be converted to long.",m_strict);
+			return 0;
+		}
+		long rValue = this->PyValue_To_Long(pyLong);
+		if (!m_error) {
+			Py_DECREF(pyLong);
+			return rValue;
+		} else {
+			Py_CLEAR(pyLong);
+			setValueError ("Error converting string to long.",m_strict);
+			return 0;
+		}
+	}
+	
+	// convert the first element of iterable sequences
+	if (PySequence_Check(pyValue) and PySequence_Size(pyValue) > 0) 
+	{
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			size_t rValue = this->PyValue_To_Long(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				setValueError("Could not convert sequence element to long. ",m_strict);
+				return 0;
+			}
+		}
+	}
+	
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to long is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_Long failed. " << msg << endl;
+#endif	
+	return 0;
+}
+
+
+bool 
+PyTypeInterface::PyValue_To_Bool(PyObject* pyValue) const
+{
+	// convert objects supporting the number protocol
+	// Note: PyBool is a subclass of PyInt
+	if (PyNumber_Check(pyValue)) 
+	{	
+		if (m_strict && !PyBool_Check(pyValue)) 
+			setValueError
+			("Strict conversion error: object is not boolean type.",m_strict);
+
+		// Note: this function handles Bool,Int,Long,Float
+		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError ("Error while converting boolean object.",m_strict);
+		}
+		if (rValue != 1 && rValue != 0)
+		{
+			setValueError ("Overflow error. Object can not be converted to boolean.",m_strict);
+		}
+		return (bool) rValue;
+	}
+	
+	if (m_strict) {
+		setValueError ("Strict conversion error: object is not numerical type.",m_strict);
+		return false;
+	}
+	
+	// convert iterables: the rule is the same as in the interpreter:
+	// empty sequence evaluates to False, anything else is True
+	if (PySequence_Check(pyValue)) 
+	{
+		return PySequence_Size(pyValue)?true:false;
+	}
+	
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_Bool failed. " << msg << endl;
+#endif	
+	return false;
+}
+
+/// string and objects that support .__str__() 
+/// TODO: check unicode objects
+std::string 
+PyTypeInterface::PyValue_To_String(PyObject* pyValue) const
+{
+	// convert string
+	if (PyString_Check(pyValue)) 
+	{	
+		char *cstr = PyString_AS_STRING(pyValue);
+		if (!cstr) 
+		{
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			setValueError("Error while converting string object.",m_strict);
+			return std::string();
+		}
+		return std::string(cstr);
+	}
+	// TODO: deal with unicode here (argh!)
+	
+	// in strict mode we will not try harder
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not string.",m_strict);
+		return std::string();
+	}
+	
+	// accept None as empty string
+	if (pyValue == Py_None) return std::string();
+			
+	// convert list or tuple: empties are turned into empty strings conventionally
+	if (PyList_Check(pyValue) || PyTuple_Check(pyValue)) 
+	{
+		if (!PySequence_Size(pyValue)) return std::string();
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			std::string rValue = this->PyValue_To_String(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				setValueError("Could not convert sequence element to string.",m_strict);
+				return std::string();
+			}
+		}
+	}
+
+	// convert any other object that has .__str__() or .__repr__()
+	PyObject* pyString = PyObject_Str(pyValue);
+	if (pyString && !PyErr_Occurred())
+	{
+		std::string rValue = this->PyValue_To_String(pyString);
+		if (!m_error) {
+			Py_DECREF(pyString);
+			return rValue;
+		} else {
+			Py_CLEAR(pyString);
+			std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. ";
+			setValueError (msg,m_strict);
+			return std::string();
+		}
+	}
+
+	// give up
+	PyErr_Print(); PyErr_Clear();
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_String failed. " << msg << endl;
+#endif	
+	return std::string();
+}
+
+/*			 			C Values to Py Values				  		*/
+
+
+PyObject*
+PyTypeInterface::PyValue_From_CValue(const char* cValue) const
+{
+	// returns new reference
+#ifdef _DEBUG
+	if (!cValue) {
+		std::string msg = "PyTypeInterface::PyValue_From_CValue: Null pointer encountered while converting from const char* .";
+		cerr << msg << endl;
+		setValueError(msg,m_strict);
+		return NULL;
+	}
+#endif
+	PyObject *pyValue = PyString_FromString(cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from char* or string.",m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from const char*" << endl;
+#endif
+		return NULL;
+	}
+	return pyValue;
+}
+
+PyObject*
+PyTypeInterface::PyValue_From_CValue(size_t cValue) const
+{
+	// returns new reference
+	PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from size_t.",m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from size_t" << endl;
+#endif
+		return NULL;
+	}
+	return pyValue;
+}
+
+PyObject*
+PyTypeInterface::PyValue_From_CValue(double cValue) const
+{
+	// returns new reference
+	PyObject *pyValue = PyFloat_FromDouble(cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from float or double.",m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from float or double" << endl;
+#endif
+		return NULL;
+	}
+	return pyValue;
+}
+
+PyObject*
+PyTypeInterface::PyValue_From_CValue(bool cValue) const
+{
+	// returns new reference
+	PyObject *pyValue = PyBool_FromLong((long)cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from bool.",m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from bool" << endl;
+#endif
+		return NULL;
+	}
+	return pyValue;
+}
+
+
+/*			 			Sequence Types to C++ Types	    		  	*/
+
+//convert Python list to C++ vector of strings
+std::vector<std::string> 
+PyTypeInterface::PyValue_To_StringVector (PyObject *pyList) const 
+{
+	
+	std::vector<std::string> Output;
+	std::string ListElement;
+	PyObject *pyString = NULL;
+	
+	if (PyList_Check(pyList)) {
+
+		for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
+			//Get next list item (Borrowed Reference)
+			pyString = PyList_GET_ITEM(pyList,i);
+			ListElement = (string) PyString_AsString(PyObject_Str(pyString));
+			Output.push_back(ListElement);
+		}
+		return Output;
+	}
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_StringVector: Warning: Value is not list of strings." << endl;
+#endif
+
+	/// Assume a single value that can be casted as string 
+	/// this allows to write e.g. Feature.label = 5.2 instead of ['5.2']
+	Output.push_back(PyValue_To_String(pyList));
+	if (m_error) {
+		std::string msg = "Value is not list of strings nor can be casted as string. ";
+		setValueError(msg,m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeInterface::PyValue_To_StringVector failed. " << msg << endl;
+#endif
+	}
+	return Output;
+}
+
+//convert PyFeature.value (typically a list or numpy array) to C++ vector of floats
+std::vector<float> 
+PyTypeInterface::PyValue_To_FloatVector (PyObject *pyValue) const 
+{
+
+#ifdef HAVE_NUMPY
+	// there are four types of values we may receive from a numpy process:
+	// * a python scalar, 
+	// * an array scalar, (e.g. numpy.float32)
+	// * an array with nd = 0  (0D array)
+	// * an array with nd > 0
+
+	/// check for scalars
+	if (PyArray_CheckScalar(pyValue) || PyFloat_Check(pyValue)) {
+
+		std::vector<float> Output;
+
+		// we rely on the behaviour the scalars are either floats
+		// or support the number protocol
+		// TODO: a potential optimisation is to handle them directly
+		Output.push_back(PyValue_To_Float(pyValue));
+		return Output;
+	}
+
+	/// numpy array
+	if (PyArray_CheckExact(pyValue)) 
+		return PyArray_To_FloatVector(pyValue);
+
+#endif
+
+	/// python list of floats (backward compatible)
+	if (PyList_Check(pyValue)) {
+		return PyList_To_FloatVector(pyValue);
+	}
+
+	std::vector<float> Output;
+	
+	/// finally assume a single value supporting the number protocol 
+	/// this allows to write e.g. Feature.values = 5 instead of [5.00]
+	Output.push_back(PyValue_To_Float(pyValue));
+	if (m_error) {
+		std::string msg = "Value is not list or array of floats nor can be casted as float. ";
+		setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_FloatVector failed." << msg << endl;
+#endif
+	}
+	return Output;
+}
+
+//convert a list of python floats
+std::vector<float> 
+PyTypeInterface::PyList_To_FloatVector (PyObject *inputList) const 
+{
+	std::vector<float> Output;
+	
+#ifdef _DEBUG
+	// This is a low level function normally called from 
+	// PyValue_To_FloatVector(). Checking for list is not required.
+	if (!PyList_Check(inputList)) {
+		std::string msg = "Value is not list.";
+		setValueError(msg,true);
+		cerr << "PyTypeInterface::PyList_To_FloatVector failed. " << msg << endl;
+		return Output; 
+	} 
+#endif
+
+	float ListElement;
+	PyObject *pyFloat = NULL;
+	PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList);
+
+	for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
+
+		// pyFloat = PyList_GET_ITEM(inputList,i);
+		pyFloat = pyObjectArray[i];
+
+#ifdef _DEBUG
+		if (!pyFloat) {
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			cerr << "PyTypeInterface::PyList_To_FloatVector: Could not obtain list element: " 
+			<< i << " PyList_GetItem returned NULL! Skipping value." << endl;
+			continue;
+		}
+#endif		
+
+		// ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
+		ListElement = PyValue_To_Float(pyFloat);
+		
+
+#ifdef _DEBUG_VALUES
+		cerr << "value: " << ListElement << endl;
+#endif
+		Output.push_back(ListElement);
+	}
+	return Output;
+}
+
+#ifdef HAVE_NUMPY
+std::vector<float> 
+PyTypeInterface::PyArray_To_FloatVector (PyObject *pyValue) const 
+{
+	std::vector<float> Output;
+	
+#ifdef _DEBUG
+	// This is a low level function, normally called from 
+	// PyValue_To_FloatVector(). Checking the array here is not required.
+	if (!PyArray_Check(pyValue)) {
+		std::string msg = "Object has no array interface.";
+		setValueError(msg,true);
+		cerr << "PyTypeInterface::PyArray_To_FloatVector failed. " << msg << endl;
+		return Output; 
+	} 
+#endif
+
+	PyArrayObject* pyArray = (PyArrayObject*) pyValue;
+	PyArray_Descr* descr = pyArray->descr;
+	
+	/// check raw data and descriptor pointers
+	if (pyArray->data == 0 || descr == 0) {
+		std::string msg = "NumPy array with NULL data or descriptor pointer encountered.";
+		setValueError(msg,m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl;
+#endif		
+		return Output;
+	}
+
+	/// check dimensions
+	if (pyArray->nd != 1) {
+		std::string msg = "NumPy array must be a one dimensional vector.";
+		setValueError(msg,m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << " Dims: " << (int) pyArray->nd << endl;
+#endif	
+		return Output;
+	}
+
+#ifdef _DEBUG_VALUES
+	cerr << "PyTypeInterface::PyArray_To_FloatVector: Numpy array verified." << endl;
+#endif
+	
+	/// check strides (useful if array is not continuous)
+	size_t strides =  *((size_t*) pyArray->strides);
+    
+	/// convert the array
+	switch (descr->type_num)
+	{
+		case NPY_FLOAT : // dtype='float32'
+			return PyArray_Convert<float,float>(pyArray->data,pyArray->dimensions[0],strides);
+		case NPY_DOUBLE : // dtype='float64'
+			return PyArray_Convert<float,double>(pyArray->data,pyArray->dimensions[0],strides);
+		case NPY_INT : // dtype='int'
+			return PyArray_Convert<float,int>(pyArray->data,pyArray->dimensions[0],strides);
+		case NPY_LONG : // dtype='long'
+			return PyArray_Convert<float,long>(pyArray->data,pyArray->dimensions[0],strides);
+		default :
+			std::string msg = "Unsupported value type in NumPy array object.";
+			setValueError(msg,m_strict);
+#ifdef _DEBUG
+			cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl;
+#endif			
+			return Output;
+	}
+}
+#endif
+
+
+/// FeatureSet (an integer map of OutputLists)
+Vamp::Plugin::FeatureSet
+PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const
+{
+	Vamp::Plugin::FeatureSet rFeatureSet;
+
+	/// Convert PyFeatureSet 
+	if (PyFeatureSet_CheckExact(pyValue)) {
+
+		Py_ssize_t pyPos = 0;
+		PyObject *pyKey, *pyDictValue; // Borrowed References
+		int key;
+		// bool it_error = false;
+
+		m_error = false;
+		while (PyDict_Next(pyValue, &pyPos, &pyKey, &pyDictValue))
+		{
+			key = (int) PyInt_AS_LONG(pyKey);
+#ifdef _DEBUG_VALUES			
+			cerr << "key: '" << key << "' value: '" << PyValue_To_String(pyDictValue) << "' " << endl;
+#endif			
+			// DictValue -> Vamp::FeatureList
+			PyValue_To_rValue(pyDictValue,rFeatureSet[key]);
+			if (m_error) {
+				// it_error = true;
+				lastError() << " in output number: " << key;
+			}
+		}
+		// if (it_error) m_error = true;
+		if (!m_errorQueue.empty()) {
+			setValueError("Error while converting FeatureSet.",m_strict);
+		} 
+		return rFeatureSet;
+	}
+
+	/// Convert Python list (backward compatibility)
+	if (PyList_Check(pyValue)) {
+		
+		PyObject *pyFeatureList; // This will be borrowed reference
+
+		//Parse Output List for each element (FeatureSet)
+		m_error = false;
+		for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) {
+			//Get i-th FeatureList (Borrowed Reference)
+			pyFeatureList = PyList_GET_ITEM(pyValue,i);
+			PyValue_To_rValue(pyFeatureList,rFeatureSet[i]);
+			if (m_error) {
+				lastError() << " in output number: " << i;
+			}
+		}
+		if (!m_errorQueue.empty()) m_error = true; 
+		return rFeatureSet;
+	}
+
+	/// accept no return values
+	if (pyValue == Py_None) return rFeatureSet;
+
+	/// give up
+	std::string msg = "Unsupported return type. Expected list or vampy.FeatureSet(). ";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_FeatureSet failed. Error: " << msg << endl;
+#endif			
+	return rFeatureSet;
+}
+
+Vamp::RealTime
+PyTypeInterface::PyValue_To_RealTime(PyObject* pyValue) const
+{
+// We accept integer sample counts (for backward compatibility)
+// or PyRealTime objects and convert them to Vamp::RealTime
+	
+	if (PyRealTime_CheckExact(pyValue))
+	{
+		/// just create a copy of the wrapped object
+		return Vamp::RealTime(*PyRealTime_AS_REALTIME(pyValue));
+	}
+
+	// assume integer sample count
+	long sampleCount = PyValue_To_Long(pyValue);
+	if (m_error) {
+		std::string msg = "Unexpected value passed as RealTime.\nMust be vampy.RealTime type or integer sample count.";
+		setValueError(msg,m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeInterface::PyValue_To_RealTime failed. " << msg << endl;
+#endif		
+		return Vamp::RealTime();
+	}
+
+#ifdef _DEBUG_VALUES
+	Vamp::RealTime rt = 
+		Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate );
+	cerr << "RealTime: " << (long)sampleCount << ", ->" << rt.toString() << endl;
+	return rt;
+#else
+	return Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate );	
+#endif
+
+}
+
+Vamp::Plugin::OutputDescriptor::SampleType 
+PyTypeInterface::PyValue_To_SampleType(PyObject* pyValue) const
+{
+	/// convert simulated enum values 
+	/// { OneSamplePerStep,FixedSampleRate,VariableSampleRate }
+	if (PyInt_CheckExact(pyValue)) {
+		long lst = PyInt_AS_LONG(pyValue);
+		if (lst<0 || lst>2) {
+			setValueError("Overflow error. SampleType has to be one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type.",m_strict);
+			return Vamp::Plugin::OutputDescriptor::SampleType();
+		}
+		return (Vamp::Plugin::OutputDescriptor::SampleType) lst; 
+	}
+	
+	/// convert string (backward compatible)
+	if (PyString_CheckExact(pyValue)) {
+		Vamp::Plugin::OutputDescriptor::SampleType st;
+		st = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[PyValue_To_String(pyValue)]; 
+		if (m_error) {
+			std::string msg = "Unexpected value passed as SampleType. Must be one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type.";
+			setValueError(msg,m_strict);
+			return Vamp::Plugin::OutputDescriptor::SampleType();
+		}
+		return st;
+	}
+
+	/// give up
+	std::string msg = "Unsupported return type. Expected one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_SampleType failed. Error: " << msg << endl;
+#endif			
+	return Vamp::Plugin::OutputDescriptor::SampleType();
+}
+
+Vamp::Plugin::InputDomain 
+PyTypeInterface::PyValue_To_InputDomain(PyObject* pyValue) const
+{
+	/// convert simulated enum values { TimeDomain,FrequencyDomain }
+	if (PyInt_CheckExact(pyValue)) {
+		long lst = PyInt_AS_LONG(pyValue);
+		if (lst!=0 && lst!=1) {
+			setValueError("Overflow error. InputDomain has to be one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type.",m_strict);
+			return Vamp::Plugin::InputDomain();
+		}
+		return (Vamp::Plugin::InputDomain) lst; 
+	}
+	
+	/// convert string (backward compatible)
+	if (PyString_CheckExact(pyValue)) {
+		Vamp::Plugin::InputDomain id;
+		id = (PyValue_To_String(pyValue) == "FrequencyDomain")?Vamp::Plugin::FrequencyDomain:Vamp::Plugin::TimeDomain;
+		if (m_error) 
+		{
+			std::string msg = "Unexpected value passed as SampleType. Must be one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type.";
+			setValueError(msg,m_strict);
+			return Vamp::Plugin::InputDomain();
+		}
+		return id;
+	}
+
+	/// give up
+	std::string msg = "Unsupported return type. Expected one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeInterface::PyValue_To_InputDomain failed. Error: " << msg << endl;
+#endif			
+	return Vamp::Plugin::InputDomain();
+}
+
+
+/// OutputDescriptor
+void
+PyTypeInterface::SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const
+{
+	switch (outKeys[key])
+	{
+		case o::not_found:
+			setValueError("Unknown key in Vamp OutputDescriptor",m_strict);
+			cerr << "Unknown key in Vamp OutputDescriptor: " << key << endl;
+			break;
+			case o::identifier: 
+			_convert(pyValue,od.identifier);
+			break;				
+		case o::name: 			
+			_convert(pyValue,od.name);
+			break;
+		case o::description:
+			_convert(pyValue,od.description);
+			break;
+		case o::unit:
+			_convert(pyValue,od.unit);
+			break;
+		case o::hasFixedBinCount:
+			_convert(pyValue,od.hasFixedBinCount);
+			break;
+		case o::binCount:
+			_convert(pyValue,od.binCount);
+			break;
+		case o::binNames:
+			_convert(pyValue,od.binNames);
+			break;
+		case o::hasKnownExtents:
+			_convert(pyValue,od.hasKnownExtents);
+			break;
+		case o::minValue:
+			_convert(pyValue,od.minValue);
+			break;
+		case o::maxValue:
+			_convert(pyValue,od.maxValue);
+			break;
+		case o::isQuantized:
+			_convert(pyValue,od.isQuantized);
+			break;					
+		case o::quantizeStep:
+			_convert(pyValue,od.quantizeStep);
+			break;
+		case o::sampleType:
+			_convert(pyValue,od.sampleType);
+			break;
+		case o::sampleRate:
+			_convert(pyValue,od.sampleRate);
+			break;
+		case o::hasDuration:
+			_convert(pyValue,od.hasDuration);
+			break;
+		default:
+			setValueError("Unknown key in Vamp OutputDescriptor",m_strict);
+			cerr << "Invalid key in Vamp OutputDescriptor: " << key << endl;
+	}
+}
+
+/// ParameterDescriptor
+void
+PyTypeInterface::SetValue(Vamp::Plugin::ParameterDescriptor& pd, std::string& key, PyObject* pyValue) const
+{
+	switch (parmKeys[key]) 
+	{
+		case p::not_found :
+			setValueError("Unknown key in Vamp ParameterDescriptor",m_strict);
+			cerr << "Unknown key in Vamp ParameterDescriptor: " << key << endl; 
+			break;
+		case p::identifier:
+			_convert(pyValue,pd.identifier);
+			break;				
+		case p::name:
+			_convert(pyValue,pd.name);
+			break;
+		case p::description: 	
+			_convert(pyValue,pd.description);
+			break; 								
+		case p::unit:
+			_convert(pyValue,pd.unit);
+			break; 																		
+		case p::minValue:	
+			_convert(pyValue,pd.minValue);
+			break;
+		case p::maxValue:
+			_convert(pyValue,pd.maxValue);
+			break;
+		case p::defaultValue:
+			_convert(pyValue,pd.defaultValue);
+			break;
+		case p::isQuantized:
+			_convert(pyValue,pd.isQuantized);
+			break;									
+		case p::quantizeStep:
+			_convert(pyValue,pd.quantizeStep);
+			break;
+		default :
+		 	setValueError("Unknown key in Vamp ParameterDescriptor",m_strict);
+			cerr << "Invalid key in Vamp ParameterDescriptor: " << key << endl; 
+	}
+}
+
+/// Feature (it's like a Descriptor)
+bool
+PyTypeInterface::SetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const
+{
+	bool found = true;
+	switch (ffKeys[key])
+	{
+		case unknown :
+			setValueError("Unknown key in Vamp Feature",m_strict);
+			cerr << "Unknown key in Vamp Feature: " << key << endl; 
+			found = false;
+			break;
+		case hasTimestamp:
+			_convert(pyValue,feature.hasTimestamp);
+			break;				
+		case timestamp:
+			_convert(pyValue,feature.timestamp);
+			break;
+		case hasDuration: 	
+			_convert(pyValue,feature.hasDuration);
+			break;
+		case duration:
+			_convert(pyValue,feature.duration);
+			break;
+		case values:
+			_convert(pyValue,feature.values);
+			break; 								
+		case label:
+			_convert(pyValue,feature.label);
+			break;
+		default:
+			setValueError("Unknown key in Vamp Feature",m_strict);
+			found = false;
+	}
+	return found;
+}
+
+
+/*			   			  	Error handling		   			  		*/
+
+void
+PyTypeInterface::setValueError (std::string message, bool strict) const
+{
+	m_error = true;
+	m_errorQueue.push(ValueError(message,strict));
+}
+
+/// return a reference to the last error or creates a new one.
+PyTypeInterface::ValueError&
+PyTypeInterface::lastError() const 
+{
+	m_error = false;
+	if (!m_errorQueue.empty()) return m_errorQueue.back();
+	else {
+		m_errorQueue.push(ValueError("Type conversion error.",m_strict));
+		return m_errorQueue.back();
+	}
+}
+
+/// helper function to iterate over the error message queue:
+/// pops the oldest item
+PyTypeInterface::ValueError 
+PyTypeInterface::getError() const
+{
+	if (!m_errorQueue.empty()) {
+		PyTypeInterface::ValueError e = m_errorQueue.front();
+		m_errorQueue.pop();
+		if (m_errorQueue.empty()) m_error = false;
+		return e;
+	}
+	else {
+		m_error = false;
+		return PyTypeInterface::ValueError();
+	}
+}
+
+/*			   			  	Utilities						  		*/
+
+/// get the type name of an object
+std::string
+PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const
+{
+	PyObject *pyType = PyObject_Type(pyValue);
+	if (!pyType) 
+	{
+		cerr << "Warning: Object type name could not be found." << endl;
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		return std::string ("< unknown type >");
+	}
+	PyObject *pyString = PyObject_Str(pyType);
+	if (!pyString)
+	{
+		cerr << "Warning: Object type name could not be found." << endl;
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		Py_CLEAR(pyType);
+		return std::string ("< unknown type >");
+	}
+	char *cstr = PyString_AS_STRING(pyString);
+	if (!cstr)
+	{
+		cerr << "Warning: Object type name could not be found." << endl;
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		Py_DECREF(pyType);
+		Py_CLEAR(pyString);
+		return std::string("< unknown type >");
+	}
+	Py_DECREF(pyType);
+	Py_DECREF(pyString);
+	return std::string(cstr);
+	
+}
+
+bool
+PyTypeInterface::initMaps() const
+{
+
+	if (isMapInitialised) return true;
+
+	outKeys["identifier"] = o::identifier;
+	outKeys["name"] = o::name;
+	outKeys["description"] = o::description;
+	outKeys["unit"] = o::unit;
+	outKeys["hasFixedBinCount"] = o::hasFixedBinCount; 
+	outKeys["binCount"] = o::binCount;
+	outKeys["binNames"] = o::binNames;
+	outKeys["hasKnownExtents"] = o::hasKnownExtents;
+	outKeys["minValue"] = o::minValue;
+	outKeys["maxValue"] = o::maxValue;
+	outKeys["isQuantized"] = o::isQuantized;
+	outKeys["quantizeStep"] = o::quantizeStep;
+	outKeys["sampleType"] = o::sampleType;
+	outKeys["sampleRate"] = o::sampleRate;
+	outKeys["hasDuration"] = o::hasDuration;
+
+	sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
+	sampleKeys["FixedSampleRate"] = FixedSampleRate;
+	sampleKeys["VariableSampleRate"] = VariableSampleRate;
+
+	ffKeys["hasTimestamp"] = hasTimestamp;
+	ffKeys["timestamp"] = timestamp; // this is the correct one
+	ffKeys["timeStamp"] = timestamp; // backward compatible
+	ffKeys["hasDuration"] = hasDuration;
+	ffKeys["duration"] = duration;
+	ffKeys["values"] = values;
+	ffKeys["label"] = label;
+
+	parmKeys["identifier"] = p::identifier;
+	parmKeys["name"] = p::name;
+	parmKeys["description"] = p::description;
+	parmKeys["unit"] = p::unit;
+	parmKeys["minValue"] = p::minValue;
+	parmKeys["maxValue"] = p::maxValue;
+	parmKeys["defaultValue"] = p::defaultValue;
+	parmKeys["isQuantized"] = p::isQuantized;
+	parmKeys["quantizeStep"] = p::quantizeStep;
+
+	isMapInitialised = true;
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyTypeInterface.h	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,661 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+/*
+PyTypeInterface: Type safe conversion utilities between Python types 
+and basic C/C++ types and Vamp API types.
+*/
+
+#ifndef _PY_TYPE_INTERFACE_H_
+#define _PY_TYPE_INTERFACE_H_
+#include <Python.h>
+#ifdef HAVE_NUMPY
+#define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API
+#define NO_IMPORT_ARRAY
+#include "numpy/arrayobject.h"
+#endif
+#include "PyExtensionModule.h"
+#include <vector>
+#include <queue>
+#include <string>
+#include <sstream>
+#include "vamp-sdk/Plugin.h"
+
+using std::cerr;
+using std::endl;
+
+#ifdef HAVE_NUMPY
+enum eArrayDataType {
+	dtype_float32 = (int) NPY_FLOAT,
+	dtype_complex64 = (int) NPY_CFLOAT 
+	};
+#endif 
+
+namespace o {
+enum eOutDescriptors {
+	not_found,
+	identifier,
+	name,
+	description,
+	unit, 
+	hasFixedBinCount,
+	binCount,
+	binNames,
+	hasKnownExtents,
+	minValue,
+	maxValue,
+	isQuantized,
+	quantizeStep,
+	sampleType,	
+	sampleRate,
+	hasDuration,
+	endNode
+	}; 
+}
+
+namespace p {
+enum eParmDescriptors {
+	not_found,
+	identifier,
+	name,
+	description,
+	unit, 
+	minValue,
+	maxValue,
+	defaultValue,
+	isQuantized,
+	quantizeStep
+	};
+}
+
+enum eSampleTypes {
+	OneSamplePerStep,
+	FixedSampleRate,
+	VariableSampleRate
+	};
+
+enum eFeatureFields {
+	unknown,
+	hasTimestamp,
+	timestamp,
+	hasDuration,
+	duration,
+	values,
+	label
+	};
+
+/* C++ mapping of PyNone Type */
+struct NoneType {};
+
+class PyTypeInterface
+{
+public:
+	PyTypeInterface();
+	~PyTypeInterface();
+	
+	// Data
+ 	class ValueError
+	{
+	public:
+		ValueError() {}
+		ValueError(std::string m, bool s) : message(m),strict(s) {}
+		std::string location;
+		std::string message;
+		bool strict;
+		std::string str() const { 
+			return (location.empty()) ? message : message + "\nLocation: " + location;}
+		void print() const { cerr << str() << endl; }
+		template<typename V> ValueError &operator<< (const V& v)
+		{
+			std::ostringstream ss;
+			ss << v;
+			location += ss.str();
+			return *this;
+		}
+	};
+	
+	// Utilities
+	void setStrictTypingFlag(bool b) {m_strict = b;}
+	ValueError getError() const;
+	std::string PyValue_Get_TypeName(PyObject*) const;
+	bool initMaps() const;
+
+	// Basic type conversion: Python to C++ 
+	float 	PyValue_To_Float(PyObject*) const;
+	size_t 	PyValue_To_Size_t(PyObject*) const;
+	bool 	PyValue_To_Bool(PyObject*) const;
+	std::string PyValue_To_String(PyObject*) const;
+	long 	PyValue_To_Long(PyObject*) const;
+	// int 	PyValue_To_Int(PyObject* pyValue) const;
+	
+	
+	// C++ to Python
+	PyObject *PyValue_From_CValue(const char*) const;
+	PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); }
+	PyObject *PyValue_From_CValue(size_t) const;
+	PyObject *PyValue_From_CValue(double) const;
+	PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); }
+	PyObject *PyValue_From_CValue(bool) const;
+	
+	// Sequence types
+	std::vector<std::string> PyValue_To_StringVector (PyObject*) const;
+	std::vector<float> PyValue_To_FloatVector (PyObject*) const;
+	std::vector<float> PyList_To_FloatVector (PyObject*) const;
+
+	// Input buffers to Python
+	PyObject* InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype);
+	PyObject* InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize);
+
+	// Numpy types
+#ifdef HAVE_NUMPY
+	std::vector<float> PyArray_To_FloatVector (PyObject *pyValue) const;
+	PyObject* InputBuffers_As_NumpyArray(const float *const *inputBuffers, const size_t&, const size_t&, const Vamp::Plugin::InputDomain& dtype);
+#endif
+
+	
+
+
+/* 						Template functions 							*/
+
+
+	/// Common wrappers to set values in Vamp API structs. (to be used in template functions)
+	void SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const;
+	void SetValue(Vamp::Plugin::ParameterDescriptor& od, std::string& key, PyObject* pyValue) const;
+	bool SetValue(Vamp::Plugin::Feature& od, std::string& key, PyObject* pyValue) const;
+    PyObject* GetDescriptor_As_Dict(PyObject* pyValue) const 
+	{
+		if PyFeature_CheckExact(pyValue) return PyFeature_AS_DICT(pyValue);
+		if PyOutputDescriptor_CheckExact(pyValue) return PyOutputDescriptor_AS_DICT(pyValue);
+		if PyParameterDescriptor_CheckExact(pyValue) return PyParameterDescriptor_AS_DICT(pyValue);
+		return NULL;
+	}
+	
+	//returns e.g. Vamp::Plugin::OutputDescriptor or Vamp::Plugin::Feature
+	template<typename RET> 
+	RET PyValue_To_VampDescriptor(PyObject* pyValue) const
+	{
+		PyObject* pyDict;
+
+		// Descriptors encoded as dicts
+		pyDict = GetDescriptor_As_Dict(pyValue);
+		if (!pyDict) pyDict = pyValue;
+	
+		// TODO: support full mapping protocol as fallback.
+		if (!PyDict_Check(pyDict)) {
+			setValueError("Error while converting descriptor or feature object.\nThe value is neither a dictionary nor a Vamp Feature or Descriptor type.",m_strict);
+#ifdef _DEBUG
+			cerr << "PyTypeInterface::PyValue_To_VampDescriptor failed. Error: Unexpected return type." << endl;
+#endif			
+			return RET();
+		}
+
+		Py_ssize_t pyPos = 0;
+		PyObject *pyKey, *pyDictValue;
+		initMaps();
+		int errors = 0;
+		m_error = false;
+		RET rd;
+
+		//Python Dictionary Iterator:
+		while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue))
+		{
+			std::string key = PyValue_To_String(pyKey);
+#ifdef _DEBUG_VALUES			
+			cerr << "key: '" << key << "' value: '" << PyValue_To_String(pyDictValue) << "' " << endl;
+#endif			
+			SetValue(rd,key,pyDictValue);
+			if (m_error) {
+				errors++;
+				lastError() << "attribute '" << key << "'";// << " of " << getDescriptorId(rd);
+			}
+		}
+		if (errors) {
+			lastError() << " of " << getDescriptorId(rd);
+			m_error = true;
+#ifdef _DEBUG
+			cerr << "PyTypeInterface::PyValue_To_VampDescriptor: Warning: Value error in descriptor." << endl;
+#endif				
+		}
+		return rd;
+	}
+
+	/// Convert a sequence (tipically list) of PySomething to 
+	/// OutputList,ParameterList or FeatureList
+	/// <OutputList> <OutputDescriptor>
+	template<typename RET,typename ELEM> 
+	RET PyValue_To_VampList(PyObject* pyValue) const
+	{
+		RET list; // e.g. Vamp::Plugin::OutputList
+		ELEM element; // e.g. Vamp::Plugin::OutputDescriptor
+
+		/// convert lists (ParameterList, OutputList, FeatureList)
+		if (PyList_Check(pyValue)) {
+			PyObject *pyDict; //This reference will be borrowed
+			m_error = false; int errors = 0;
+			for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) {
+				//Get i-th Vamp output descriptor (Borrowed Reference)
+				pyDict = PyList_GET_ITEM(pyValue,i);
+				element = PyValue_To_VampDescriptor<ELEM>(pyDict);
+				if (m_error) errors++;
+				// Check for empty Feature/Descriptor as before?
+				list.push_back(element);
+			}
+			if (errors) m_error=true;
+			return list;
+		}
+		
+		/// convert other types implementing the sequence protocol
+		if (PySequence_Check(pyValue)) {
+			PyObject *pySequence = PySequence_Fast(pyValue,"Returned value can not be converted to list or tuple.");
+			PyObject **pyElements =  PySequence_Fast_ITEMS(pySequence);
+			m_error = false; int errors = 0;
+			for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(pySequence); ++i) 
+			{
+				element = PyValue_To_VampDescriptor<ELEM>(pyElements[i]);
+				if (m_error) errors++;
+				list.push_back(element);
+			}
+			if (errors) m_error=true;
+			Py_XDECREF(pySequence);
+			return list;
+		}
+
+		// accept None as an empty list
+		if (pyValue == Py_None) return list;
+		
+		// in strict mode, returning a single value is not allowed 
+		if (m_strict) {
+			setValueError("Strict conversion error: object is not list or iterable sequence.",m_strict);
+			return list;
+		}
+		
+		/// try to insert single, non-iterable values. i.e. feature <- [feature]
+		element = PyValue_To_VampDescriptor<ELEM>(pyValue);
+		if (m_error) {
+			setValueError("Could not insert returned value to Vamp List.",m_strict);
+			return list; 
+		}
+		list.push_back(element);
+		return list;
+		
+#ifdef _DEBUG
+			cerr << "PyTypeInterface::PyValue_To_VampList failed. Expected iterable return type." << endl;
+#endif			
+
+	}
+
+	/// Convert DTYPE type 1D NumpyArray to std::vector<RET>
+	template<typename RET, typename DTYPE>
+	std::vector<RET> PyArray_Convert(char* raw_data_ptr, long length, size_t strides) const
+	{
+		std::vector<RET> rValue;
+		
+		/// check if the array is continuous, if not use strides info
+		if (sizeof(DTYPE)!=strides) {
+#ifdef _DEBUG_VALUES
+			cerr << "Warning: discontinuous numpy array. Strides: " << strides << " bytes. sizeof(dtype): " << sizeof(DTYPE) << endl;
+#endif
+			char* data = (char*) raw_data_ptr;
+			for (long i = 0; i<length; ++i){
+				rValue.push_back((RET)(*((DTYPE*)data)));
+#ifdef _DEBUG_VALUES
+				cerr << "value: " << (RET)(*((DTYPE*)data)) << endl;
+#endif				
+				data+=strides;
+			}
+			return rValue;
+		}
+
+		DTYPE* data = (DTYPE*) raw_data_ptr;
+		for (long i = 0; i<length; ++i){
+#ifdef _DEBUG_VALUES
+			cerr << "value: " << (RET)data[i] << endl;
+#endif
+			rValue.push_back((RET)data[i]);
+		}
+		return rValue;
+	}
+
+	/// this is a special case. numpy.float64 has an array interface but no array descriptor
+	inline std::vector<float> PyArray0D_Convert(PyArrayInterface *ai) const
+	{
+		std::vector<float> rValue;
+		if ((ai->typekind) == *"f") 
+			rValue.push_back((float)*(double*)(ai->data));
+		else { 
+			setValueError("Unsupported NumPy data type.",m_strict); 
+			return rValue;
+		}
+#ifdef _DEBUG_VALUES
+		cerr << "value: " << rValue[0] << endl;
+#endif
+		return rValue;
+	}
+
+	//Vamp specific types
+	Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const;
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const
+		{ r = this->PyValue_To_FeatureSet(pyValue); }
+
+	Vamp::RealTime PyValue_To_RealTime(PyObject*) const;
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::RealTime &r) const
+		{ r = this->PyValue_To_RealTime(pyValue); }
+	
+	Vamp::Plugin::OutputDescriptor::SampleType PyValue_To_SampleType(PyObject*) const;
+
+	Vamp::Plugin::InputDomain PyValue_To_InputDomain(PyObject*) const;
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::InputDomain &r) const
+		{ r = this->PyValue_To_InputDomain(pyValue); }
+	
+	
+	/* Overloaded PyValue_To_rValue() to support generic functions */
+	inline void PyValue_To_rValue(PyObject *pyValue, float &defValue) const 
+		{ float tmp = this->PyValue_To_Float(pyValue);                                              
+			if(!m_error) defValue = tmp; }
+	inline void PyValue_To_rValue(PyObject *pyValue, size_t &defValue) const
+		{ size_t tmp = this->PyValue_To_Size_t(pyValue); 
+			if(!m_error) defValue = tmp; }
+	inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const
+		{ bool tmp = this->PyValue_To_Bool(pyValue); 
+			if(!m_error) defValue = tmp; }
+	inline void PyValue_To_rValue(PyObject *pyValue, std::string &defValue) const
+		{ std::string tmp = this->PyValue_To_String(pyValue); 
+			if(!m_error) defValue = tmp; }
+	/*used by templates where we expect no return value, if there is one it will be ignored*/			
+	inline void PyValue_To_rValue(PyObject *pyValue, NoneType &defValue) const
+		{ if (m_strict && pyValue != Py_None) 
+				setValueError("Strict conversion error: Expected 'None' type.",m_strict); 
+		}
+
+	/* convert sequence types to Vamp List types */			
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::OutputList &r) const
+		{ r = this->PyValue_To_VampList<Vamp::Plugin::OutputList,Vamp::Plugin::OutputDescriptor>(pyValue); }
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::ParameterList &r) const
+		{ r = this->PyValue_To_VampList<Vamp::Plugin::ParameterList,Vamp::Plugin::ParameterDescriptor>(pyValue); }
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureList &r) const
+		{ r = this->PyValue_To_VampList<Vamp::Plugin::FeatureList,Vamp::Plugin::Feature>(pyValue); }
+	
+	/// this is only needed for RealTime->Frame conversion
+	void setInputSampleRate(float inputSampleRate)
+		{ m_inputSampleRate = (unsigned int) inputSampleRate; }
+	
+private:
+	bool m_strict;
+	mutable bool m_error;
+	mutable std::queue<ValueError> m_errorQueue;
+	unsigned int m_inputSampleRate; 
+	
+	void setValueError(std::string,bool) const;
+	ValueError& lastError() const;
+
+	/* Overloaded _convert(), bypasses error checking to avoid doing it twice in internals. */
+	inline void _convert(PyObject *pyValue,float &r) const 
+		{ r = PyValue_To_Float(pyValue); }
+	inline void _convert(PyObject *pyValue,size_t &r) const 
+		{ r = PyValue_To_Size_t(pyValue); }
+    inline void _convert(PyObject *pyValue,bool &r) const 
+		{ r = PyValue_To_Bool(pyValue); }
+	inline void _convert(PyObject *pyValue,std::string &r) const
+		{ r = PyValue_To_String(pyValue); }
+	inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const
+		{ r = PyValue_To_StringVector(pyValue); }
+	inline void _convert(PyObject *pyValue,std::vector<float> &r) const
+		{ r = PyValue_To_FloatVector(pyValue); }
+    inline void _convert(PyObject *pyValue,Vamp::RealTime &r) const 
+		{ r = PyValue_To_RealTime(pyValue); }
+	inline void _convert(PyObject *pyValue,Vamp::Plugin::OutputDescriptor::SampleType &r) const 
+		{ r = PyValue_To_SampleType(pyValue); }
+	// inline void _convert(PyObject *pyValue,Vamp::Plugin::InputDomain &r) const 
+	// 	{ r = PyValue_To_InputDomain(pyValue); }
+	    
+
+	/* Identify descriptors for error reporting */
+	inline std::string getDescriptorId(Vamp::Plugin::OutputDescriptor d) const
+		{return std::string("Output Descriptor '") + d.identifier +"' ";}
+	inline std::string getDescriptorId(Vamp::Plugin::ParameterDescriptor d) const
+		{return std::string("Parameter Descriptor '") + d.identifier +"' ";}
+	inline std::string getDescriptorId(Vamp::Plugin::Feature f) const
+		{return std::string("Feature (") + f.label + ")"; }
+	
+public:
+	const bool& error;
+
+};
+
+/* 		   		  Convert Sample Buffers to Python 	         		*/
+
+/// passing the sample buffers as buitin python lists
+/// Optimization: using fast sequence protocol
+inline PyObject*
+PyTypeInterface::InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
+{
+	//create a list of lists (new references)
+	PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
+	
+	// Pack samples into a Python List Object
+	// pyFloat/pyComplex types will always be new references, 
+	// they will be freed when the lists are deallocated.
+	
+	PyObject **pyChannelListArray =  PySequence_Fast_ITEMS(pyChannelList);
+	for (size_t i=0; i < channels; ++i) {
+
+		PyObject *pySampleList = PyList_New((Py_ssize_t) blockSize);
+		PyObject **pySampleListArray =  PySequence_Fast_ITEMS(pySampleList);
+		
+		// Note: passing a complex list crashes the C-style plugin
+		// when it tries to convert it to a numpy array directly.
+		// This plugin will be obsolete, but we have to find a way
+		// to prevent such crash.
+		
+		switch (Vamp::Plugin::TimeDomain) //(dtype)
+		{
+			case Vamp::Plugin::TimeDomain :
+
+			for (size_t j = 0; j < blockSize; ++j) {
+				PyObject *pyFloat=PyFloat_FromDouble(
+					(double) inputBuffers[i][j]);
+				pySampleListArray[j] = pyFloat;
+			}
+			break;
+
+			case Vamp::Plugin::FrequencyDomain :
+
+			size_t k = 0;
+			for (size_t j = 0; j < blockSize/2; ++j) {
+				PyObject *pyComplex=PyComplex_FromDoubles(
+					(double) inputBuffers[i][k], 
+					(double) inputBuffers[i][k+1]);
+				pySampleListArray[j] = pyComplex;
+				k += 2;
+			}
+			break;
+			
+		}
+		pyChannelListArray[i] = pySampleList;
+	}
+	return pyChannelList;
+}
+
+/// numpy buffer interface: passing the sample buffers as shared memory buffers
+/// Optimization: using sequence protocol for creating the buffer list
+inline PyObject*
+PyTypeInterface::InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize)
+{	
+	//create a list of buffers (returns new references)
+	PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
+	PyObject **pyChannelListArray =  PySequence_Fast_ITEMS(pyChannelList);
+
+	// Expose memory using the Buffer Interface.		
+	// This will pass a pointer which can be recasted in Python code 
+	// as complex or float array using Numpy's frombuffer() method
+	// (this will not copy values just keep the starting adresses 
+	// for each channel in a list)
+	Py_ssize_t bufferSize = (Py_ssize_t) sizeof(float) * blockSize;
+
+	for (size_t i=0; i < channels; ++i) {
+		PyObject *pyBuffer = PyBuffer_FromMemory
+		((void *) (float *) inputBuffers[i],bufferSize);
+		pyChannelListArray[i] = pyBuffer;
+	}
+	return pyChannelList;
+}
+
+
+/// numpy array interface: passing the sample buffers as 2D numpy array
+/// Optimization: using array API (needs numpy headers)
+#ifdef HAVE_NUMPY
+inline PyObject*
+PyTypeInterface::InputBuffers_As_NumpyArray(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
+{	
+/*
+NOTE: We create a list of 1D Numpy arrays for each channel instead
+of a matrix, because the address space of inputBuffers doesn't seem
+to be continuous. Although the array strides could be calculated for
+2 channels (i.e. inputBuffers[1] - inputBuffers[0]) i'm not sure
+if this can be trusted, especially for more than 2 channels.
+
+	cerr << "First channel: " << inputBuffers[0][0] << " address: " <<  inputBuffers[0] << endl;
+	if (channels == 2)
+		cerr << "Second channel: " << inputBuffers[1][0] << " address: " <<  inputBuffers[1] << endl;
+
+*/	
+	
+	// create a list of arrays (returns new references)
+	PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
+	PyObject **pyChannelListArray =  PySequence_Fast_ITEMS(pyChannelList);
+	
+	// Expose memory using the Numpy Array Interface.		
+	// This will wrap an array objects around the data.
+	// (will not copy values just steal the starting adresses)
+
+	int arraySize, typenum;
+	
+	switch (dtype)
+	{
+		case Vamp::Plugin::TimeDomain :
+		typenum = dtype_float32; //NPY_FLOAT; 
+		arraySize = (int) blockSize;
+		break;
+
+		case Vamp::Plugin::FrequencyDomain :
+		typenum = dtype_complex64; //NPY_CFLOAT;
+		arraySize = (int) blockSize / 2;
+		break;
+		
+		default :
+		cerr << "PyTypeInterface::InputBuffers_As_NumpyArray: Error: Unsupported numpy array data type." << endl;
+		return pyChannelList;
+	}
+
+	// size for each dimension
+	npy_intp ndims[1]={arraySize}; 
+	
+	for (size_t i=0; i < channels; ++i) {
+		PyObject *pyChannelArray = 
+			//args: (dimensions, size in each dim, type kind, pointer to continuous array)
+			PyArray_SimpleNewFromData(1, ndims, typenum, (void*) inputBuffers[i]);
+		// make it read-only: set all flags to false except NPY_C_CONTIGUOUS 
+		((PyArrayObject*)pyChannelArray)->flags = NPY_C_CONTIGUOUS;
+		pyChannelListArray[i] = pyChannelArray;
+	}
+	return pyChannelList;
+}
+#endif
+
+
+
+#ifdef NUMPY_REFERENCE
+/// This should be all we need to compile without direct dependency,
+/// but we don't do that. (it may not work on some platforms)
+typedef struct {
+    int two;              /* contains the integer 2 -- simple sanity check */
+    int nd;               /* number of dimensions */
+    char typekind;        /* kind in array --- character code of typestr */
+    int itemsize;         /* size of each element */
+    int flags;            /* flags indicating how the data should be interpreted */
+                          /*   must set ARR_HAS_DESCR bit to validate descr */
+    Py_intptr_t *shape;   /* A length-nd array of shape information */
+    Py_intptr_t *strides; /* A length-nd array of stride information */
+    void *data;           /* A pointer to the first element of the array */
+    PyObject *descr;      /* NULL or data-description (same as descr key */
+                          /*        of __array_interface__) -- must set ARR_HAS_DESCR */
+                          /*        flag or this will be ignored. */
+} PyArrayInterface;
+
+typedef struct PyArrayObject {
+        PyObject_HEAD
+        char *data;             /* pointer to raw data buffer */
+        int nd;                 /* number of dimensions, also called ndim */
+        npy_intp *dimensions;       /* size in each dimension */
+        npy_intp *strides;          /* bytes to jump to get to the
+                                   next element in each dimension */
+        PyObject *base;         /* This object should be decref'd
+                                   upon deletion of array */
+                                /* For views it points to the original array */
+                                /* For creation from buffer object it points
+                                   to an object that shold be decref'd on
+                                   deletion */
+                                /* For UPDATEIFCOPY flag this is an array
+                                   to-be-updated upon deletion of this one */
+        PyArray_Descr *descr;   /* Pointer to type structure */
+        int flags;              /* Flags describing array -- see below*/
+        PyObject *weakreflist;  /* For weakreferences */
+} PyArrayObject;
+
+typedef struct _PyArray_Descr {
+        PyObject_HEAD
+        PyTypeObject *typeobj;  /* the type object representing an
+                                   instance of this type -- should not
+                                   be two type_numbers with the same type
+                                   object. */
+        char kind;              /* kind for this type */
+        char type;              /* unique-character representing this type */
+        char byteorder;         /* '>' (big), '<' (little), '|'
+                                   (not-applicable), or '=' (native). */
+        char hasobject;         /* non-zero if it has object arrays
+                                   in fields */
+        int type_num;          /* number representing this type */
+        int elsize;             /* element size for this type */
+        int alignment;          /* alignment needed for this type */
+        struct _arr_descr                                       \
+        *subarray;              /* Non-NULL if this type is
+                                   is an array (C-contiguous)
+                                   of some other type
+                                */
+        PyObject *fields;       /* The fields dictionary for this type */
+                                /* For statically defined descr this
+                                   is always Py_None */
+
+        PyObject *names;        /* An ordered tuple of field names or NULL
+                                   if no fields are defined */
+
+        PyArray_ArrFuncs *f;     /* a table of functions specific for each
+                                    basic data descriptor */
+} PyArray_Descr;
+
+enum NPY_TYPES {    NPY_BOOL=0,
+                    NPY_BYTE, NPY_UBYTE,
+                    NPY_SHORT, NPY_USHORT,
+                    NPY_INT, NPY_UINT,
+                    NPY_LONG, NPY_ULONG,
+                    NPY_LONGLONG, NPY_ULONGLONG,
+                    NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
+                    NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
+                    NPY_OBJECT=17,
+                    NPY_STRING, NPY_UNICODE,
+                    NPY_VOID,
+                    NPY_NTYPES,
+                    NPY_NOTYPE,
+                    NPY_CHAR,      /* special flag */
+                    NPY_USERDEF=256  /* leave room for characters */
+};
+#endif /*NUMPY_REFERENCE*/
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,90 @@
+
+ * VamPy is an API wrapper for Vamp. It allows for writing Vamp 
+	plugins in Python with or without Numpy support.
+
+WHAT IS IT FOR?
+	
+	This wrapper is for writing Vamp plugins in Python which 
+	can do the same as a native C++ plugin, plus a lot more if 
+	you're using advanced Python modules.
+
+	This may be an easier way to get into Vamp development.
+	You can use it for prototyping your plugin before writing 
+	it in C++.
+
+
+WHY PYTHON?
+
+	Python is a general purpose high level scripting language.
+	It is interpreted, so you don't need to compile your plugins.
+	It has very high level libraries. e.g. you can stream audio from your VamPy plugin (it works for me...)
+	Supports functional programming. 
+
+UPDATE IN THIS VERSION:
+
+	* Two-way Numpy Support
+	* Embedded extension module exposing Vamp defined names 
+		e.g. ParameterDescriptor. This allows easier porting to C++.
+	* Support RealTime time stamps
+	* Support byte compiled Python scripts (.pyc)
+	* Environment variables: VAMPY_COMPILED, VAMPY_EXTPATH
+	* Flags to control type conversion and error reporting for development
+	* Flexible type inference to take advantage of Python's loose typing
+	* Full error checking for all Python/C API calls
+	* Various optimisations and speed-ups
+
+PREVIOUS VAMPY README:
+
+HOW DOES IT WORK:
+
+	(1) Make sure you have Python installed.
+	(2) Compile the C++ source or ask me for a binary (MacOS).
+	(3) Copy the library in your Vamp plugin directory like any other Vamp plugins: 
+		eg. /Library/Audio/Plug-Ins/Vamp
+	(4) Write some python plugins and copy them to the same place.
+	(5) Each plugin must contain a single class with the same name as your script file.
+		e.g. PyZeroCrossing.py -> calss PyZeroCrossing
+		-Scripts with syntax errors in them are ignored.
+		-Scripts not having the same class as the filename are ignored. (Python is case sensitive!)
+		-Other unknown scripts are likely to cause a crash.  (Don't put other python scripts in your Vamp directory.)
+
+	
+COMPILING AND LINKING:
+
+	(1) make sure Python.h is included wherever it is on your machine 
+	(2) the plugin needs to be linked against the Python binary: e.g.: ld -lpython2.5
+
+	example on on MacOSX:
+	g++ -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5   -c -o PyPlugin.o PyPlugin.cpp
+	g++ -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5   -c -o PyPlugScanner.o PyPlugScanner.cpp
+	g++ -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5   -c -o pyvamp-main.o pyvamp-main.cpp
+	g++ -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5   -c -o Mutex.o Mutex.cpp
+	g++ -shared PyPlugin.o PyPlugScanner.o pyvamp-main.o Mutex.o -o vampy.dylib -L../vamp-plugin-sdk/vamp-sdk -lvamp-sdk -dynamiclib -lpython2.5 -lpthread
+
+	
+	(3) There is a Makefile that compiles this plugin by default.
+
+
+LIMITATIONS:
+
+	This is mainly a proof of concept. The implementation is not the most efficient, but using NumPy it's very reasonable.	
+	Only tested on MacOSX and Linux (by Chris), but in theory should work on other platforms with small fixes.	
+
+	Error checking is not yet fully complete.
+	You better not make a mistake in your Python script, although in most cases you can see what the problem is 
+	if you start the host (e.g. Sonic Visualiser) from a command line interface.
+	The wrapper plugin is quite verbose and outputs error messages.
+
+
+TODO:	* needs more complete error checking (almost done)
+	* needs correct implementation of Python threading (done)
+	* more efficient data conversion using the buffering interface or ctypes (done)
+	* Vamp 'programs' not implemented
+	* support multiple classes per script in scanner
+	* ensure proper cleanup, (host does a good job though)
+
+HISTORY:
+	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()
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VamPy.vcproj	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="VamPy"
+	ProjectGUID="{0412DCE9-EE58-4A99-9154-14935B0BCFAA}"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="0"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;..\vamp-plugin-sdk&quot;;C:\Python26\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;VAMPY_EXPORTS;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/EXPORT:vampGetPluginDescriptor"
+				AdditionalDependencies="VampPluginSDK.lib python26.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;..\vamp-plugin-sdk\build\Debug&quot;;C:\Python26\libs"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;..\vamp-plugin-sdk&quot;;C:\Python26\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;VAMPY_EXPORTS;"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/EXPORT:vampGetPluginDescriptor"
+				AdditionalDependencies="VampPluginSDK.lib python26.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;..\vamp-plugin-sdk\build\Release&quot;;C:\Python26\libs"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\Mutex.h"
+				>
+			</File>
+			<File
+				RelativePath=".\PyPlugin.h"
+				>
+			</File>
+			<File
+				RelativePath=".\PyPlugScanner.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\Mutex.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\PyPlugin.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\PyPlugScanner.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\pyvamp-main.cpp"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-plugin.map	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,4 @@
+{
+	global: vampGetPluginDescriptor;
+	local: *;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vampy-main.cpp	Mon Oct 05 11:28:00 2009 +0000
@@ -0,0 +1,256 @@
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+
+#ifdef HAVE_NUMPY
+#define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API
+#include "numpy/arrayobject.h"
+#endif
+
+#include "vamp/vamp.h"
+#include "vamp-sdk/PluginAdapter.h"
+#include "PyPlugScanner.h"
+#include "PyPlugin.h"
+#include "PyExtensionModule.h"
+#include "PyExtensionManager.h"
+
+
+#ifdef _WIN32
+#define pathsep ('\\')
+#include <windows.h>
+#include <tchar.h>
+#else 
+#define pathsep ('/')
+#include <dirent.h>
+#include <dlfcn.h>
+#endif
+
+using std::cerr;
+using std::endl;
+using std::string;
+using std::vector;
+
+static int adinstcount;
+static int totinstcount;
+
+class PyPluginAdapter : public Vamp::PluginAdapterBase
+{
+public: 
+    PyPluginAdapter(std::string pyPlugId, PyObject* pyClass) :
+        PluginAdapterBase(),
+        m_plug(pyPlugId),		
+        m_pyClass(pyClass),
+		m_failed(false)
+    { 
+        cerr << "PyPluginAdapter:ctor:"<< adinstcount << ": " << m_plug << endl; 
+        adinstcount++;
+    }
+    
+    ~PyPluginAdapter() 
+    {
+    }
+
+	bool failed() { return m_failed; }
+	std::string getPlugKey() { return m_plug; }
+
+protected:
+    Vamp::Plugin *createPlugin(float inputSampleRate)
+    {
+        try {
+            PyPlugin *plugin = new PyPlugin(m_plug, inputSampleRate, m_pyClass, totinstcount);
+            return plugin;
+        } catch (...) {
+            cerr << "PyPluginAdapter::createPlugin: Failed to construct PyPlugin" << endl;
+			// any plugin with syntax errors will fail to construct
+			m_failed = true;
+            return 0;
+        }
+    }
+    
+    std::string m_plug;
+    PyObject *m_pyClass;
+	bool m_failed;  
+};
+
+static void array_API_initialiser()
+{
+/// numpy C-API requirement
+#ifdef HAVE_NUMPY
+	import_array();
+	if(NPY_VERSION != PyArray_GetNDArrayCVersion())
+		cerr << "Warning: Numpy ABI version mismatch. (Build version: " 
+		<< NPY_VERSION << " Runtime version: " << PyArray_GetNDArrayCVersion() << ")" << endl;
+#endif
+}
+
+
+static std::vector<PyPluginAdapter *> adapters;
+static bool haveScannedPlugins = false;
+
+static bool tryPreload(string name)
+{
+#ifdef _WIN32
+    void *lib = LoadLibrary(name.c_str());
+    if (!lib) {
+        return false;
+    }
+#else
+    void *lib = dlopen(name.c_str(), RTLD_NOW | RTLD_GLOBAL);
+    if (!lib) {
+        return false;
+    }
+#endif
+    return true;
+}
+
+static bool preloadPython()
+{
+#ifdef _WIN32
+    // this doesn't seem to be necessary at all on Windows
+    return true;
+#endif
+
+    string pyver = Py_GetVersion();
+    int dots = 2;
+    string shortver;
+    for (size_t i = 0; i < pyver.length(); ++i) {
+        if (pyver[i] == '.') {
+            if (--dots == 0) {
+                shortver = pyver.substr(0, i);
+                break;
+            }
+        }
+    }
+    cerr << "Short version: " << shortver << endl;
+	// this is useful to find out where the loaded library might be loaded from
+	cerr << "Python exec prefix: " << Py_GetExecPrefix() << endl;
+
+    vector<string> pfxs;
+    pfxs.push_back("");
+    pfxs.push_back(string(Py_GetExecPrefix()) + "/lib/");
+    pfxs.push_back(string(Py_GetExecPrefix()) + "/");
+    pfxs.push_back("/usr/lib/");
+    pfxs.push_back("/usr/local/lib/");
+    char buffer[5];
+
+    // hahaha! grossness is like a brother to us
+#ifdef __APPLE__
+    for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) {
+        for (int minor = 8; minor >= 0; --minor) {
+            sprintf(buffer, "%d", minor);
+            if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib." + buffer)) return true;
+        }
+        if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib")) return true;
+        if (tryPreload(pfxs[pfxidx] + string("libpython.dylib"))) return true;
+    }
+#else
+    for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) {
+        for (int minor = 8; minor >= 0; --minor) {
+            sprintf(buffer, "%d", minor);
+            if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so." + buffer)) return true;
+        }
+        if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so")) return true;
+        if (tryPreload(pfxs[pfxidx] + string("libpython.so"))) return true;
+    }
+#endif
+        
+    return false;
+}
+
+
+static PyExtensionManager pyExtensionManager;
+
+const VampPluginDescriptor 
+*vampGetPluginDescriptor(unsigned int version,unsigned int index)
+{	
+    if (version < 1) return 0;
+
+	int isPythonInitialized = Py_IsInitialized();
+	cerr << "# isPythonInitialized: " << isPythonInitialized << endl;
+	cerr << "# haveScannedPlugins: " << haveScannedPlugins << endl;
+
+	if (!haveScannedPlugins) {
+
+		if (!isPythonInitialized){
+
+			if (!preloadPython())
+				cerr << "Warning: Could not preload Python. Dynamic loading in scripts will fail." << endl;
+			if (PyImport_AppendInittab("vampy",initvampy) != 0)
+				cerr << "Warning: Extension module could not be added to module inittab." << endl;
+			Py_Initialize();
+			initvampy();
+#ifdef _DEBUG			
+		    cerr << "# isPythonInitialized after initialize: " << Py_IsInitialized() << endl;
+#endif		
+		}
+
+		vector<string> pyPlugs;
+		vector<string> pyPath;
+		vector<PyObject *> pyClasses;
+		static PyPlugScanner *scanner;
+		
+		//Scanning Plugins
+		cerr << "Scanning Vampy Plugins" << endl;
+		scanner = PyPlugScanner::getInstance();
+
+		// added env. varable support VAMPY_EXTPATH
+		pyPath=scanner->getAllValidPath();
+		scanner->setPath(pyPath);
+		
+		// added env. variable support: 
+		// VAMPY_COMPILED=1 to recognise .pyc files (default is 1)
+		pyPlugs = scanner->getPyPlugs();
+
+		cerr << "Found " << pyPlugs.size() << " Scripts." << endl;
+		//TODO: should this support multiple classes per script (?)
+		pyClasses = scanner->getPyClasses();
+		cerr << "Found " << pyClasses.size() << " Classes." << endl;
+
+		for (size_t i = 0; i < pyPlugs.size(); ++i) {
+			adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyClasses[i]));
+		}
+		pyExtensionManager.setPlugModuleNames(pyPlugs);
+		pyExtensionManager.initExtension();
+		array_API_initialiser();
+		haveScannedPlugins=true;
+	}
+
+#ifdef _DEBUG
+	cerr << "Accessing adapter index: " << index << " (adapters: " << adapters.size() << ")" << endl;
+#endif	
+
+	if (index<adapters.size()) {
+
+		const VampPluginDescriptor *tmp = adapters[index]->getDescriptor();
+
+		if (adapters[index]->failed()) { 
+			cerr << "\nERROR: [in vampGetPluginDescriptor] Removing adapter of: \n'" 
+			<< adapters[index]->getPlugKey() << "'\n" 
+			<< "The plugin has failed to construct. Hint: Check __init__() function." << endl;
+			pyExtensionManager.deleteModuleName(adapters[index]->getPlugKey());
+			delete adapters[index];
+			adapters.erase(adapters.begin()+index);
+			return 0;
+		}
+
+		return tmp;
+
+	} else return 0;
+}
+
+
+
+
+
+
+
+