Chris@56
|
1 '''A high-level interface to the vampyhost extension module, for quickly and easily running Vamp audio analysis plugins on audio files and buffers.'''
|
Chris@56
|
2
|
Chris@56
|
3 import vampyhost
|
Chris@75
|
4 import frames
|
Chris@75
|
5 import load
|
Chris@68
|
6
|
Chris@89
|
7 def process_frames_with_plugin(ff, sample_rate, step_size, plugin, outputs):
|
Chris@89
|
8
|
Chris@98
|
9 out_indices = dict([(id, plugin.get_output(id)["output_index"])
|
Chris@98
|
10 for id in outputs])
|
Chris@89
|
11 plugin.reset()
|
Chris@89
|
12 fi = 0
|
Chris@89
|
13
|
Chris@89
|
14 for f in ff:
|
Chris@89
|
15 timestamp = vampyhost.frame_to_realtime(fi, sample_rate)
|
Chris@89
|
16 results = plugin.process_block(f, timestamp)
|
Chris@89
|
17 # results is a dict mapping output number -> list of feature dicts
|
Chris@89
|
18 for o in outputs:
|
Chris@89
|
19 ix = out_indices[o]
|
Chris@89
|
20 if ix in results:
|
Chris@89
|
21 for r in results[ix]:
|
Chris@89
|
22 yield { o: r }
|
Chris@89
|
23 fi = fi + step_size
|
Chris@89
|
24
|
Chris@89
|
25 results = plugin.get_remaining_features()
|
Chris@89
|
26 for o in outputs:
|
Chris@89
|
27 ix = out_indices[o]
|
Chris@89
|
28 if ix in results:
|
Chris@89
|
29 for r in results[ix]:
|
Chris@89
|
30 yield { o: r }
|
Chris@89
|
31
|
Chris@89
|
32
|
Chris@89
|
33 def process(data, sample_rate, key, output = "", parameters = {}):
|
Chris@98
|
34 """Process audio data with a Vamp plugin, and make the results from a
|
Chris@98
|
35 single plugin output available as a generator.
|
Chris@98
|
36
|
Chris@98
|
37 The provided data should be a 1- or 2-dimensional list or NumPy
|
Chris@98
|
38 array of floats. If it is 2-dimensional, the first dimension is
|
Chris@98
|
39 taken to be the channel count.
|
Chris@98
|
40
|
Chris@98
|
41 The returned results will be those calculated by the plugin with
|
Chris@98
|
42 the given key and returned through its output with the given
|
Chris@98
|
43 output identifier. If the requested output is the empty string,
|
Chris@98
|
44 the first output provided by the plugin will be used.
|
Chris@98
|
45
|
Chris@98
|
46 If the parameters dict is non-empty, the plugin will be configured
|
Chris@98
|
47 by setting its parameters according to the (string) key and
|
Chris@98
|
48 (float) value data found in the dict.
|
Chris@98
|
49
|
Chris@98
|
50 This function acts as a generator, yielding a sequence of result
|
Chris@98
|
51 features as it obtains them. Each feature is represented as a
|
Chris@98
|
52 dictionary containing, optionally, timestamp and duration
|
Chris@98
|
53 (RealTime objects), label (string), and a 1-dimensional array of
|
Chris@98
|
54 float values.
|
Chris@99
|
55
|
Chris@99
|
56 If you would prefer to obtain all features in a single output
|
Chris@99
|
57 structure, consider using vamp.collect() instead.
|
Chris@98
|
58 """
|
Chris@89
|
59
|
Chris@89
|
60 plugin, step_size, block_size = load.load_and_configure(data, sample_rate, key, parameters)
|
Chris@89
|
61
|
Chris@89
|
62 if output == "":
|
Chris@89
|
63 output = plugin.get_output(0)["identifier"]
|
Chris@89
|
64
|
Chris@89
|
65 ff = frames.frames_from_array(data, step_size, block_size)
|
Chris@89
|
66
|
Chris@89
|
67 for r in process_frames_with_plugin(ff, sample_rate, step_size, plugin, [output]):
|
Chris@89
|
68 yield r[output]
|
Chris@76
|
69
|
Chris@89
|
70 plugin.unload()
|
Chris@89
|
71
|
Chris@76
|
72
|
Chris@98
|
73 def process_frames(ff, sample_rate, step_size, key, output = "", parameters = {}):
|
Chris@98
|
74 """Process audio data with a Vamp plugin, and make the results from a
|
Chris@98
|
75 single plugin output available as a generator.
|
Chris@95
|
76
|
Chris@98
|
77 The provided data should be an enumerable sequence of time-domain
|
Chris@98
|
78 audio frames, of which each frame is 2-dimensional list or NumPy
|
Chris@98
|
79 array of floats. The first dimension is taken to be the channel
|
Chris@98
|
80 count, and the second dimension the frame or block size. The
|
Chris@98
|
81 step_size argument gives the increment in audio samples from one
|
Chris@98
|
82 frame to the next. Each frame must have the same size.
|
Chris@95
|
83
|
Chris@98
|
84 The returned results will be those calculated by the plugin with
|
Chris@98
|
85 the given key and returned through its output with the given
|
Chris@98
|
86 output identifier. If the requested output is the empty string,
|
Chris@98
|
87 the first output provided by the plugin will be used.
|
Chris@95
|
88
|
Chris@98
|
89 If the parameters dict is non-empty, the plugin will be configured
|
Chris@98
|
90 by setting its parameters according to the (string) key and
|
Chris@98
|
91 (float) value data found in the dict.
|
Chris@98
|
92
|
Chris@98
|
93 This function acts as a generator, yielding a sequence of result
|
Chris@98
|
94 features as it obtains them. Each feature is represented as a
|
Chris@98
|
95 dictionary containing, optionally, timestamp and duration
|
Chris@98
|
96 (RealTime objects), label (string), and a 1-dimensional array of
|
Chris@98
|
97 float values.
|
Chris@99
|
98
|
Chris@99
|
99 If you would prefer to obtain all features in a single output
|
Chris@99
|
100 structure, consider using vamp.collect() instead.
|
Chris@98
|
101 """
|
Chris@98
|
102 plugin = vampyhost.load_plugin(key, sample_rate,
|
Chris@98
|
103 vampyhost.ADAPT_INPUT_DOMAIN +
|
Chris@98
|
104 vampyhost.ADAPT_BUFFER_SIZE +
|
Chris@98
|
105 vampyhost.ADAPT_CHANNEL_COUNT)
|
Chris@98
|
106
|
Chris@98
|
107 fi = 0
|
Chris@98
|
108 channels = 0
|
Chris@98
|
109 block_size = 0
|
Chris@98
|
110
|
Chris@98
|
111 if output == "":
|
Chris@98
|
112 out_index = 0
|
Chris@98
|
113 else:
|
Chris@98
|
114 out_index = plugin.get_output(output)["output_index"]
|
Chris@95
|
115
|
Chris@98
|
116 for f in ff:
|
Chris@95
|
117
|
Chris@98
|
118 if fi == 0:
|
Chris@98
|
119 channels = f.shape[0]
|
Chris@98
|
120 block_size = f.shape[1]
|
Chris@98
|
121 plugin.set_parameter_values(parameters)
|
Chris@98
|
122 if not plugin.initialise(channels, step_size, block_size):
|
Chris@98
|
123 raise "Failed to initialise plugin"
|
Chris@98
|
124
|
Chris@98
|
125 timestamp = vampyhost.frame_to_realtime(fi, sample_rate)
|
Chris@98
|
126 results = plugin.process_block(f, timestamp)
|
Chris@98
|
127 # results is a dict mapping output number -> list of feature dicts
|
Chris@98
|
128 if out_index in results:
|
Chris@98
|
129 for r in results[out_index]:
|
Chris@98
|
130 yield r
|
Chris@98
|
131
|
Chris@98
|
132 fi = fi + step_size
|
Chris@98
|
133
|
Chris@98
|
134 if fi > 0:
|
Chris@98
|
135 results = plugin.get_remaining_features()
|
Chris@98
|
136 if out_index in results:
|
Chris@98
|
137 for r in results[out_index]:
|
Chris@98
|
138 yield r
|
Chris@98
|
139
|
Chris@95
|
140 plugin.unload()
|
Chris@95
|
141
|
Chris@95
|
142
|
Chris@84
|
143 def process_multiple_outputs(data, sample_rate, key, outputs, parameters = {}):
|
Chris@99
|
144 """Process audio data with a Vamp plugin, and make the results from a
|
Chris@99
|
145 set of plugin outputs available as a generator.
|
Chris@99
|
146
|
Chris@99
|
147 The provided data should be a 1- or 2-dimensional list or NumPy
|
Chris@99
|
148 array of floats. If it is 2-dimensional, the first dimension is
|
Chris@99
|
149 taken to be the channel count.
|
Chris@99
|
150
|
Chris@99
|
151 The returned results will be those calculated by the plugin with
|
Chris@99
|
152 the given key and returned through its outputs whose identifiers
|
Chris@99
|
153 are given in the outputs argument.
|
Chris@99
|
154
|
Chris@99
|
155 If the parameters dict is non-empty, the plugin will be configured
|
Chris@99
|
156 by setting its parameters according to the (string) key and
|
Chris@99
|
157 (float) value data found in the dict.
|
Chris@99
|
158
|
Chris@99
|
159 This function acts as a generator, yielding a sequence of result
|
Chris@99
|
160 feature sets as it obtains them. Each feature set is a dictionary
|
Chris@99
|
161 mapping from output identifier to a list of features, each
|
Chris@99
|
162 represented as a dictionary containing, optionally, timestamp and
|
Chris@99
|
163 duration (RealTime objects), label (string), and a 1-dimensional
|
Chris@99
|
164 array of float values.
|
Chris@99
|
165 """
|
Chris@68
|
166
|
Chris@89
|
167 plugin, step_size, block_size = load.load_and_configure(data, sample_rate, key, parameters)
|
Chris@64
|
168
|
Chris@84
|
169 ff = frames.frames_from_array(data, step_size, block_size)
|
Chris@64
|
170
|
Chris@89
|
171 for r in process_frames_with_plugin(ff, sample_rate, step_size, plugin, outputs):
|
Chris@89
|
172 yield r
|
Chris@61
|
173
|
Chris@89
|
174 plugin.unload()
|
Chris@99
|
175
|
Chris@99
|
176 #!!!
|
Chris@99
|
177 # + process_frames_multiple_outputs
|
Chris@99
|
178 # + refactor common material
|