fazekasgy@37
|
1 '''PyZeroCrossing.py - Example plugin demonstrates
|
fazekasgy@37
|
2 how to write a Vampy plugin in pure Python without
|
fazekasgy@37
|
3 using Numpy or the extensions provided by the embedded
|
fazekasgy@37
|
4 vampy module.
|
fazekasgy@37
|
5
|
fazekasgy@37
|
6 This plugin is compatible with provious versions of vampy,
|
fazekasgy@37
|
7 apart from moving the inputSampleRate
|
fazekasgy@37
|
8 argument from initialise to __init__()
|
fazekasgy@37
|
9
|
fazekasgy@37
|
10 Outputs:
|
fazekasgy@37
|
11 1) Zero crossing counts
|
fazekasgy@37
|
12 2) Zero crossing locations
|
fazekasgy@37
|
13
|
fazekasgy@37
|
14 Centre for Digital Music, Queen Mary University of London.
|
fazekasgy@37
|
15 Copyright (C) 2009 Gyorgy Fazekas, QMUL. (See Vamp sources
|
fazekasgy@37
|
16 for licence information.)
|
fazekasgy@37
|
17
|
fazekasgy@37
|
18 '''
|
fazekasgy@37
|
19
|
fazekasgy@37
|
20 class PyZeroCrossing:
|
fazekasgy@37
|
21
|
fazekasgy@37
|
22 def __init__(self,inputSampleRate):
|
fazekasgy@37
|
23 self.m_inputSampleRate = inputSampleRate
|
fazekasgy@37
|
24 self.m_stepSize = 0
|
fazekasgy@37
|
25 self.m_blockSize = 0
|
fazekasgy@37
|
26 self.m_channels = 0
|
fazekasgy@37
|
27 self.previousSample = 0.0
|
fazekasgy@37
|
28 self.threshold = 0.005
|
fazekasgy@37
|
29 self.counter = 0
|
fazekasgy@37
|
30
|
fazekasgy@37
|
31 def initialise(self,channels,stepSize,blockSize):
|
fazekasgy@37
|
32 self.m_channels = channels
|
fazekasgy@37
|
33 self.m_stepSize = stepSize
|
fazekasgy@37
|
34 self.m_blockSize = blockSize
|
fazekasgy@37
|
35 return True
|
fazekasgy@37
|
36
|
fazekasgy@37
|
37 def getMaker(self):
|
fazekasgy@37
|
38 return 'Vampy Example Plugins'
|
fazekasgy@37
|
39
|
fazekasgy@37
|
40 def getName(self):
|
fazekasgy@37
|
41 return 'Vampy Zero Crossings'
|
Chris@69
|
42
|
Chris@69
|
43 def getDescription(self):
|
Chris@69
|
44 return 'Count the number of simple zero-crossings for the signal within each processing block'
|
Chris@69
|
45
|
Chris@69
|
46 def getCopyright(self):
|
Chris@69
|
47 return 'Plugin By George Fazekas. Freely redistributable example plugin (BSD license)'
|
fazekasgy@37
|
48
|
fazekasgy@37
|
49 def getIdentifier(self):
|
fazekasgy@37
|
50 return 'vampy-zc2'
|
fazekasgy@37
|
51
|
fazekasgy@37
|
52 def getMaxChannelCount(self):
|
fazekasgy@37
|
53 return 1
|
fazekasgy@37
|
54
|
fazekasgy@37
|
55 def getInputDomain(self):
|
fazekasgy@37
|
56 return 'TimeDomain'
|
fazekasgy@37
|
57
|
fazekasgy@37
|
58 def getOutputDescriptors(self):
|
fazekasgy@37
|
59
|
fazekasgy@37
|
60 #descriptors can be returned as python dictionaries
|
fazekasgy@37
|
61 output0={
|
fazekasgy@37
|
62 'identifier':'vampy-counts',
|
fazekasgy@37
|
63 'name':'Number of Zero Crossings',
|
fazekasgy@37
|
64 'description':'Number of zero crossings per audio frame',
|
fazekasgy@37
|
65 'unit':' ',
|
fazekasgy@37
|
66 'hasFixedBinCount':True,
|
fazekasgy@37
|
67 'binCount':1,
|
fazekasgy@37
|
68 #'binNames':['1 Hz',1.5,'2 Hz',3,'4 Hz'],
|
fazekasgy@37
|
69 'hasKnownExtents':False,
|
fazekasgy@37
|
70 #'minValue':0.0,
|
fazekasgy@37
|
71 #'maxValue':0.0,
|
fazekasgy@37
|
72 'isQuantized':True,
|
fazekasgy@37
|
73 'quantizeStep':1.0,
|
fazekasgy@37
|
74 'sampleType':'OneSamplePerStep'
|
fazekasgy@37
|
75 #'sampleRate':48000.0
|
fazekasgy@37
|
76 }
|
fazekasgy@37
|
77
|
fazekasgy@37
|
78 output1={
|
fazekasgy@37
|
79 'identifier':'vampy-crossings',
|
fazekasgy@37
|
80 'name':'Zero Crossing Locations',
|
fazekasgy@37
|
81 'description':'The locations of zero crossing points',
|
fazekasgy@37
|
82 'unit':'discrete',
|
fazekasgy@37
|
83 'hasFixedBinCount':True,
|
fazekasgy@37
|
84 'binCount':0,
|
fazekasgy@37
|
85 'sampleType':'VariableSampleRate'
|
fazekasgy@37
|
86 }
|
fazekasgy@37
|
87
|
fazekasgy@37
|
88 return [output0,output1]
|
fazekasgy@37
|
89
|
fazekasgy@37
|
90
|
fazekasgy@37
|
91 def getParameterDescriptors(self):
|
fazekasgy@37
|
92 paramlist1={
|
fazekasgy@37
|
93 'identifier':'threshold',
|
fazekasgy@37
|
94 'name':'Noise threshold',
|
Chris@68
|
95 'description':'Magnitude below which a process block will be considered to be all zero',
|
fazekasgy@37
|
96 'unit':'v',
|
fazekasgy@37
|
97 'minValue':0.0,
|
fazekasgy@37
|
98 'maxValue':0.5,
|
fazekasgy@37
|
99 'defaultValue':0.005,
|
fazekasgy@37
|
100 'isQuantized':False
|
fazekasgy@37
|
101 }
|
fazekasgy@37
|
102 return [paramlist1]
|
fazekasgy@37
|
103
|
fazekasgy@37
|
104
|
fazekasgy@37
|
105 def setParameter(self,paramid,newval):
|
fazekasgy@37
|
106 if paramid == 'threshold' :
|
fazekasgy@37
|
107 self.threshold = newval
|
fazekasgy@37
|
108 return
|
fazekasgy@37
|
109
|
fazekasgy@37
|
110
|
fazekasgy@37
|
111 def getParameter(self,paramid):
|
fazekasgy@37
|
112 if paramid == 'threshold' :
|
fazekasgy@37
|
113 return self.threshold
|
fazekasgy@37
|
114 else:
|
fazekasgy@37
|
115 return 0.0
|
fazekasgy@37
|
116
|
fazekasgy@37
|
117
|
fazekasgy@37
|
118 # legacy process type: the input is a python list of samples
|
fazekasgy@37
|
119 def process(self,inbuf,timestamp):
|
fazekasgy@37
|
120 crossing = False
|
fazekasgy@37
|
121 prev = self.previousSample
|
fazekasgy@37
|
122 count = 0.0;
|
fazekasgy@37
|
123 channel = inbuf[0]
|
fazekasgy@37
|
124
|
fazekasgy@37
|
125 #we have two outputs defined thus we have to declare
|
fazekasgy@37
|
126 #them as empty dictionaries in our output list
|
fazekasgy@37
|
127 #in order to be able to return variable rate outputs
|
fazekasgy@37
|
128 output0=[]
|
fazekasgy@37
|
129 output1=[]
|
fazekasgy@37
|
130
|
fazekasgy@37
|
131 if sum([abs(s) for s in channel]) > self.threshold :
|
fazekasgy@37
|
132
|
fazekasgy@37
|
133 for x in range(len(channel)-1) :
|
fazekasgy@37
|
134 crossing = False
|
fazekasgy@37
|
135 sample = channel[x]
|
fazekasgy@37
|
136 if sample <= 0.0 :
|
fazekasgy@37
|
137 if prev > 0.0 : crossing = True
|
fazekasgy@37
|
138 else :
|
fazekasgy@37
|
139 if sample > 0.0 :
|
fazekasgy@37
|
140 if prev <= 0.0 : crossing = True
|
fazekasgy@37
|
141
|
fazekasgy@37
|
142 if crossing == True :
|
fazekasgy@37
|
143 count = count + 1
|
fazekasgy@37
|
144 feature1={
|
fazekasgy@37
|
145 'hasTimestamp':True,
|
fazekasgy@37
|
146 'timeStamp':long(timestamp + x),
|
fazekasgy@37
|
147 'values':[count],
|
fazekasgy@37
|
148 'label':str(count),
|
fazekasgy@37
|
149 }
|
fazekasgy@37
|
150 output1.append(feature1)
|
fazekasgy@37
|
151
|
fazekasgy@37
|
152 prev = sample
|
fazekasgy@37
|
153 self.previousSample = prev
|
fazekasgy@37
|
154
|
fazekasgy@37
|
155 else :
|
fazekasgy@37
|
156 count = 0.0
|
fazekasgy@37
|
157 self.previousSample = channel[len(channel)-1]
|
fazekasgy@37
|
158
|
fazekasgy@37
|
159 feature0={
|
fazekasgy@37
|
160 'hasTimestamp':False,
|
fazekasgy@37
|
161 'values':[count],
|
fazekasgy@37
|
162 'label':str(count)
|
fazekasgy@37
|
163 }
|
fazekasgy@37
|
164 output0.append(feature0)
|
fazekasgy@37
|
165
|
fazekasgy@37
|
166 #return a LIST of list of dictionaries
|
fazekasgy@37
|
167 return [output0,output1]
|
fazekasgy@37
|
168
|