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'
|
fazekasgy@37
|
42
|
fazekasgy@37
|
43 def getIdentifier(self):
|
fazekasgy@37
|
44 return 'vampy-zc2'
|
fazekasgy@37
|
45
|
fazekasgy@37
|
46 def getMaxChannelCount(self):
|
fazekasgy@37
|
47 return 1
|
fazekasgy@37
|
48
|
fazekasgy@37
|
49 def getInputDomain(self):
|
fazekasgy@37
|
50 return 'TimeDomain'
|
fazekasgy@37
|
51
|
fazekasgy@37
|
52 def getOutputDescriptors(self):
|
fazekasgy@37
|
53
|
fazekasgy@37
|
54 #descriptors can be returned as python dictionaries
|
fazekasgy@37
|
55 output0={
|
fazekasgy@37
|
56 'identifier':'vampy-counts',
|
fazekasgy@37
|
57 'name':'Number of Zero Crossings',
|
fazekasgy@37
|
58 'description':'Number of zero crossings per audio frame',
|
fazekasgy@37
|
59 'unit':' ',
|
fazekasgy@37
|
60 'hasFixedBinCount':True,
|
fazekasgy@37
|
61 'binCount':1,
|
fazekasgy@37
|
62 #'binNames':['1 Hz',1.5,'2 Hz',3,'4 Hz'],
|
fazekasgy@37
|
63 'hasKnownExtents':False,
|
fazekasgy@37
|
64 #'minValue':0.0,
|
fazekasgy@37
|
65 #'maxValue':0.0,
|
fazekasgy@37
|
66 'isQuantized':True,
|
fazekasgy@37
|
67 'quantizeStep':1.0,
|
fazekasgy@37
|
68 'sampleType':'OneSamplePerStep'
|
fazekasgy@37
|
69 #'sampleRate':48000.0
|
fazekasgy@37
|
70 }
|
fazekasgy@37
|
71
|
fazekasgy@37
|
72 output1={
|
fazekasgy@37
|
73 'identifier':'vampy-crossings',
|
fazekasgy@37
|
74 'name':'Zero Crossing Locations',
|
fazekasgy@37
|
75 'description':'The locations of zero crossing points',
|
fazekasgy@37
|
76 'unit':'discrete',
|
fazekasgy@37
|
77 'hasFixedBinCount':True,
|
fazekasgy@37
|
78 'binCount':0,
|
fazekasgy@37
|
79 'sampleType':'VariableSampleRate'
|
fazekasgy@37
|
80 }
|
fazekasgy@37
|
81
|
fazekasgy@37
|
82 return [output0,output1]
|
fazekasgy@37
|
83
|
fazekasgy@37
|
84
|
fazekasgy@37
|
85 def getParameterDescriptors(self):
|
fazekasgy@37
|
86 paramlist1={
|
fazekasgy@37
|
87 'identifier':'threshold',
|
fazekasgy@37
|
88 'name':'Noise threshold',
|
Chris@68
|
89 'description':'Magnitude below which a process block will be considered to be all zero',
|
fazekasgy@37
|
90 'unit':'v',
|
fazekasgy@37
|
91 'minValue':0.0,
|
fazekasgy@37
|
92 'maxValue':0.5,
|
fazekasgy@37
|
93 'defaultValue':0.005,
|
fazekasgy@37
|
94 'isQuantized':False
|
fazekasgy@37
|
95 }
|
fazekasgy@37
|
96 return [paramlist1]
|
fazekasgy@37
|
97
|
fazekasgy@37
|
98
|
fazekasgy@37
|
99 def setParameter(self,paramid,newval):
|
fazekasgy@37
|
100 if paramid == 'threshold' :
|
fazekasgy@37
|
101 self.threshold = newval
|
fazekasgy@37
|
102 return
|
fazekasgy@37
|
103
|
fazekasgy@37
|
104
|
fazekasgy@37
|
105 def getParameter(self,paramid):
|
fazekasgy@37
|
106 if paramid == 'threshold' :
|
fazekasgy@37
|
107 return self.threshold
|
fazekasgy@37
|
108 else:
|
fazekasgy@37
|
109 return 0.0
|
fazekasgy@37
|
110
|
fazekasgy@37
|
111
|
fazekasgy@37
|
112 # legacy process type: the input is a python list of samples
|
fazekasgy@37
|
113 def process(self,inbuf,timestamp):
|
fazekasgy@37
|
114 crossing = False
|
fazekasgy@37
|
115 prev = self.previousSample
|
fazekasgy@37
|
116 count = 0.0;
|
fazekasgy@37
|
117 channel = inbuf[0]
|
fazekasgy@37
|
118
|
fazekasgy@37
|
119 #we have two outputs defined thus we have to declare
|
fazekasgy@37
|
120 #them as empty dictionaries in our output list
|
fazekasgy@37
|
121 #in order to be able to return variable rate outputs
|
fazekasgy@37
|
122 output0=[]
|
fazekasgy@37
|
123 output1=[]
|
fazekasgy@37
|
124
|
fazekasgy@37
|
125 if sum([abs(s) for s in channel]) > self.threshold :
|
fazekasgy@37
|
126
|
fazekasgy@37
|
127 for x in range(len(channel)-1) :
|
fazekasgy@37
|
128 crossing = False
|
fazekasgy@37
|
129 sample = channel[x]
|
fazekasgy@37
|
130 if sample <= 0.0 :
|
fazekasgy@37
|
131 if prev > 0.0 : crossing = True
|
fazekasgy@37
|
132 else :
|
fazekasgy@37
|
133 if sample > 0.0 :
|
fazekasgy@37
|
134 if prev <= 0.0 : crossing = True
|
fazekasgy@37
|
135
|
fazekasgy@37
|
136 if crossing == True :
|
fazekasgy@37
|
137 count = count + 1
|
fazekasgy@37
|
138 feature1={
|
fazekasgy@37
|
139 'hasTimestamp':True,
|
fazekasgy@37
|
140 'timeStamp':long(timestamp + x),
|
fazekasgy@37
|
141 'values':[count],
|
fazekasgy@37
|
142 'label':str(count),
|
fazekasgy@37
|
143 }
|
fazekasgy@37
|
144 output1.append(feature1)
|
fazekasgy@37
|
145
|
fazekasgy@37
|
146 prev = sample
|
fazekasgy@37
|
147 self.previousSample = prev
|
fazekasgy@37
|
148
|
fazekasgy@37
|
149 else :
|
fazekasgy@37
|
150 count = 0.0
|
fazekasgy@37
|
151 self.previousSample = channel[len(channel)-1]
|
fazekasgy@37
|
152
|
fazekasgy@37
|
153 feature0={
|
fazekasgy@37
|
154 'hasTimestamp':False,
|
fazekasgy@37
|
155 'values':[count],
|
fazekasgy@37
|
156 'label':str(count)
|
fazekasgy@37
|
157 }
|
fazekasgy@37
|
158 output0.append(feature0)
|
fazekasgy@37
|
159
|
fazekasgy@37
|
160 #return a LIST of list of dictionaries
|
fazekasgy@37
|
161 return [output0,output1]
|
fazekasgy@37
|
162
|