Chris@37
|
1 /*
|
Chris@37
|
2 jVamp
|
Chris@37
|
3
|
Chris@37
|
4 A Java host interface for Vamp audio analysis plugins
|
Chris@37
|
5
|
Chris@37
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@37
|
7 Copyright 2012 Chris Cannam and QMUL.
|
Chris@37
|
8
|
Chris@37
|
9 Permission is hereby granted, free of charge, to any person
|
Chris@37
|
10 obtaining a copy of this software and associated documentation
|
Chris@37
|
11 files (the "Software"), to deal in the Software without
|
Chris@37
|
12 restriction, including without limitation the rights to use, copy,
|
Chris@37
|
13 modify, merge, publish, distribute, sublicense, and/or sell copies
|
Chris@37
|
14 of the Software, and to permit persons to whom the Software is
|
Chris@37
|
15 furnished to do so, subject to the following conditions:
|
Chris@37
|
16
|
Chris@37
|
17 The above copyright notice and this permission notice shall be
|
Chris@37
|
18 included in all copies or substantial portions of the Software.
|
Chris@37
|
19
|
Chris@37
|
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Chris@37
|
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
Chris@37
|
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
Chris@37
|
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
Chris@37
|
24 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
Chris@37
|
25 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
Chris@37
|
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
Chris@37
|
27
|
Chris@37
|
28 Except as contained in this notice, the names of the Centre for
|
Chris@37
|
29 Digital Music; Queen Mary, University of London; and Chris Cannam
|
Chris@37
|
30 shall not be used in advertising or otherwise to promote the sale,
|
Chris@37
|
31 use or other dealings in this Software without prior written
|
Chris@37
|
32 authorization.
|
Chris@37
|
33 */
|
Chris@0
|
34
|
Chris@0
|
35 package org.vamp_plugins;
|
Chris@0
|
36
|
Chris@40
|
37 import java.util.Map;
|
Chris@40
|
38 import java.util.List;
|
Chris@2
|
39
|
Chris@28
|
40 /**
|
Chris@28
|
41 * A Java wrapper for a native-code Vamp plugin. Plugins are obtained
|
Chris@28
|
42 * using PluginLoader and must be freed by calling dispose() after use
|
Chris@28
|
43 * (being native code they cannot be garbage collected).
|
Chris@28
|
44 *
|
Chris@28
|
45 * The plugin lifecycle looks roughly like this, from the host's
|
Chris@28
|
46 * perspective:
|
Chris@28
|
47 *
|
Chris@28
|
48 * - Plugin is loaded using PluginLoader
|
Chris@28
|
49 *
|
Chris@28
|
50 * - Host may query the plugin's available outputs with
|
Chris@28
|
51 * getOutputDescriptors(). This will report what outputs exist,
|
Chris@28
|
52 * but their properties (e.g. resolution, value count, extents)
|
Chris@28
|
53 * are not yet fixed
|
Chris@28
|
54 *
|
Chris@28
|
55 * - Host may query and set the plugin's programs and parameters with
|
Chris@28
|
56 * getPrograms(), getParameterDescriptors(), setParameter() etc
|
Chris@28
|
57 *
|
Chris@28
|
58 * - After all parameters are set, host queries the plugin's preferred
|
Chris@28
|
59 * step size, block size, and channel count (which may depend on
|
Chris@28
|
60 * the parameter settings)
|
Chris@28
|
61 *
|
Chris@28
|
62 * - Host initialises plugin by calling initialise(). If it returns
|
Chris@28
|
63 * false, initialise failed -- most likely because the step size,
|
Chris@28
|
64 * block size, or channel count was rejected
|
Chris@28
|
65 *
|
Chris@28
|
66 * - Host may now get final values for the output properties using
|
Chris@28
|
67 * getOutputDescriptors()
|
Chris@28
|
68 *
|
Chris@28
|
69 * - Host calls process() repeatedly to process data. This may return
|
Chris@28
|
70 * some results as it goes along (if the plugin is causal)
|
Chris@28
|
71 *
|
Chris@28
|
72 * - Host calls getRemainingFeatures() exactly once when all input has
|
Chris@28
|
73 * been processed, to obtain any non-causal or leftover features.
|
Chris@28
|
74 *
|
Chris@28
|
75 * - At any point after initialise() has been called, host may call
|
Chris@28
|
76 * reset() to restart processing. Parameter values remain fixed
|
Chris@28
|
77 * across reset() calls.
|
Chris@28
|
78 *
|
Chris@28
|
79 * - When host is finished with plugin, it calls dispose().
|
Chris@28
|
80 *
|
Chris@28
|
81 * The host may not change any parameter or program settings after
|
Chris@28
|
82 * calling initialise(), and may not call initialise() more than once
|
Chris@28
|
83 * on any given plugin.
|
Chris@28
|
84 *
|
Chris@28
|
85 * See the PluginBase and Plugin classes in the C++ Vamp plugin SDK
|
Chris@28
|
86 * for further documentation.
|
Chris@28
|
87 */
|
Chris@0
|
88 public class Plugin
|
Chris@0
|
89 {
|
Chris@0
|
90 private long nativeHandle;
|
Chris@0
|
91 protected Plugin(long handle) { nativeHandle = handle; }
|
Chris@0
|
92
|
Chris@28
|
93 /**
|
Chris@28
|
94 * Dispose of this Plugin. Call this when you have finished using
|
Chris@28
|
95 * it to ensure the native code object is released.
|
Chris@28
|
96 */
|
Chris@20
|
97 public native void dispose();
|
Chris@20
|
98
|
Chris@28
|
99 /**
|
Chris@28
|
100 * Get the Vamp API compatibility level of the plugin.
|
Chris@28
|
101 */
|
Chris@28
|
102 public native int getVampApiVersion();
|
Chris@3
|
103
|
Chris@28
|
104 /**
|
Chris@28
|
105 * Get the computer-usable name of the plugin. This will contain
|
Chris@28
|
106 * only the characters [a-zA-Z0-9_-]. This is the authoritative
|
Chris@28
|
107 * way for a host to identify a plugin within a given library, but
|
Chris@28
|
108 * it is not the primary label shown to the user (that will be the
|
Chris@28
|
109 * name, below).
|
Chris@28
|
110 */
|
Chris@0
|
111 public native String getIdentifier();
|
Chris@28
|
112
|
Chris@28
|
113 /**
|
Chris@28
|
114 * Get a human-readable name or title of the plugin. This is the
|
Chris@28
|
115 * main identifying label shown to the user.
|
Chris@28
|
116 */
|
Chris@0
|
117 public native String getName();
|
Chris@28
|
118
|
Chris@28
|
119 /**
|
Chris@28
|
120 * Get a human-readable description for the plugin, typically
|
Chris@28
|
121 * a line of text that may optionally be displayed in addition
|
Chris@28
|
122 * to the plugin's "name". May be empty if the name has said
|
Chris@28
|
123 * it all already.
|
Chris@28
|
124 */
|
Chris@0
|
125 public native String getDescription();
|
Chris@28
|
126
|
Chris@28
|
127 /**
|
Chris@28
|
128 * Get the name of the author or vendor of the plugin in
|
Chris@28
|
129 * human-readable form. This should be short enough to be used to
|
Chris@28
|
130 * label plugins from the same source in a tree or menu if
|
Chris@28
|
131 * appropriate.
|
Chris@28
|
132 */
|
Chris@3
|
133 public native String getMaker();
|
Chris@28
|
134
|
Chris@28
|
135 /**
|
Chris@28
|
136 * Get the copyright statement or licensing summary for the
|
Chris@28
|
137 * plugin.
|
Chris@28
|
138 */
|
Chris@3
|
139 public native String getCopyright();
|
Chris@28
|
140
|
Chris@28
|
141 /**
|
Chris@28
|
142 * Get the version number of the plugin.
|
Chris@28
|
143 */
|
Chris@0
|
144 public native int getPluginVersion();
|
Chris@2
|
145
|
Chris@28
|
146 /**
|
Chris@28
|
147 * Get the controllable parameters of this plugin.
|
Chris@28
|
148 */
|
Chris@3
|
149 public native ParameterDescriptor[] getParameterDescriptors();
|
Chris@28
|
150
|
Chris@28
|
151 /**
|
Chris@28
|
152 * Get the value of a named parameter. The argument is the identifier
|
Chris@28
|
153 * field from that parameter's descriptor.
|
Chris@28
|
154 */
|
Chris@3
|
155 public native float getParameter(String identifier);
|
Chris@28
|
156
|
Chris@28
|
157 /**
|
Chris@28
|
158 * Set a named parameter. The first argument is the identifier field
|
Chris@28
|
159 * from that parameter's descriptor.
|
Chris@28
|
160 */
|
Chris@3
|
161 public native void setParameter(String identifier, float value);
|
Chris@3
|
162
|
Chris@28
|
163 /**
|
Chris@28
|
164 * Get the program settings available in this plugin. A program
|
Chris@28
|
165 * is a named shorthand for a set of parameter values; changing
|
Chris@28
|
166 * the program may cause the plugin to alter the values of its
|
Chris@28
|
167 * published parameters (and/or non-public internal processing
|
Chris@28
|
168 * parameters). The host should re-read the plugin's parameter
|
Chris@28
|
169 * values after setting a new program.
|
Chris@28
|
170 *
|
Chris@28
|
171 * The programs must have unique names.
|
Chris@28
|
172 */
|
Chris@3
|
173 public native String[] getPrograms();
|
Chris@28
|
174
|
Chris@28
|
175 /**
|
Chris@28
|
176 * Get the current program (if any).
|
Chris@28
|
177 */
|
Chris@3
|
178 public native String getCurrentProgram();
|
Chris@28
|
179
|
Chris@28
|
180 /**
|
Chris@28
|
181 * Select a program. (If the given program name is not one of the
|
Chris@28
|
182 * available programs, do nothing.)
|
Chris@28
|
183 */
|
Chris@3
|
184 public native void selectProgram(String program);
|
Chris@3
|
185
|
Chris@28
|
186 /**
|
Chris@28
|
187 * Initialise a plugin to prepare it for use with the given number
|
Chris@28
|
188 * of input channels, step size (window increment, in sample
|
Chris@28
|
189 * frames) and block size (window size, in sample frames).
|
Chris@28
|
190 *
|
Chris@28
|
191 * The input sample rate should have been already specified when
|
Chris@28
|
192 * loading the plugin.
|
Chris@28
|
193 *
|
Chris@28
|
194 * Return true for successful initialisation, false if the number
|
Chris@28
|
195 * of input channels, step size and/or block size cannot be
|
Chris@28
|
196 * supported.
|
Chris@28
|
197 */
|
Chris@2
|
198 public native boolean initialise(int inputChannels,
|
Chris@2
|
199 int stepSize,
|
Chris@2
|
200 int blockSize);
|
Chris@2
|
201
|
Chris@28
|
202 /**
|
Chris@28
|
203 * Reset the plugin after use, to prepare it for another clean
|
Chris@28
|
204 * run.
|
Chris@28
|
205 */
|
Chris@2
|
206 public native void reset();
|
Chris@2
|
207
|
Chris@25
|
208 public static enum InputDomain { TIME_DOMAIN, FREQUENCY_DOMAIN };
|
Chris@28
|
209
|
Chris@28
|
210 /**
|
Chris@28
|
211 * Get the plugin's required input domain.
|
Chris@28
|
212 *
|
Chris@28
|
213 * If this is TimeDomain, the samples provided to the process()
|
Chris@28
|
214 * function (below) must be in the time domain, as for a
|
Chris@28
|
215 * traditional audio processing plugin.
|
Chris@28
|
216 *
|
Chris@28
|
217 * If this is FrequencyDomain, the host must carry out a windowed
|
Chris@28
|
218 * FFT of size equal to the negotiated block size on the data
|
Chris@28
|
219 * before passing the frequency bin data in to process(). The
|
Chris@28
|
220 * input data for the FFT will be rotated so as to place the
|
Chris@28
|
221 * origin in the centre of the block. The plugin does not get to
|
Chris@28
|
222 * choose the window type -- the host will either let the user do
|
Chris@28
|
223 * so, or will use a Hanning window.
|
Chris@28
|
224 */
|
Chris@2
|
225 public native InputDomain getInputDomain();
|
Chris@2
|
226
|
Chris@28
|
227 /**
|
Chris@28
|
228 * Get the preferred block size (window size -- the number of
|
Chris@28
|
229 * sample frames passed in each block to the process() function).
|
Chris@28
|
230 * This should be called before initialise().
|
Chris@28
|
231 *
|
Chris@28
|
232 * A plugin that can handle any block size may return 0. The
|
Chris@28
|
233 * final block size will be set in the initialise() call.
|
Chris@28
|
234 */
|
Chris@2
|
235 public native int getPreferredBlockSize();
|
Chris@28
|
236
|
Chris@28
|
237 /**
|
Chris@28
|
238 * Get the preferred step size (window increment -- the distance
|
Chris@28
|
239 * in sample frames between the start frames of consecutive blocks
|
Chris@28
|
240 * passed to the process() function) for the plugin. This should
|
Chris@28
|
241 * be called before initialise().
|
Chris@28
|
242 *
|
Chris@28
|
243 * A plugin may return 0 if it has no particular interest in the
|
Chris@28
|
244 * step size. In this case, the host should make the step size
|
Chris@28
|
245 * equal to the block size if the plugin is accepting input in the
|
Chris@28
|
246 * time domain. If the plugin is accepting input in the frequency
|
Chris@28
|
247 * domain, the host may use any step size. The final step size
|
Chris@28
|
248 * will be set in the initialise() call.
|
Chris@28
|
249 */
|
Chris@2
|
250 public native int getPreferredStepSize();
|
Chris@28
|
251
|
Chris@28
|
252 /**
|
Chris@28
|
253 * Get the minimum supported number of input channels.
|
Chris@28
|
254 */
|
Chris@2
|
255 public native int getMinChannelCount();
|
Chris@28
|
256
|
Chris@28
|
257 /**
|
Chris@28
|
258 * Get the maximum supported number of input channels.
|
Chris@28
|
259 */
|
Chris@2
|
260 public native int getMaxChannelCount();
|
Chris@2
|
261
|
Chris@28
|
262 /**
|
Chris@28
|
263 * Get the outputs of this plugin. An output's index in this list
|
Chris@28
|
264 * is used as its numeric index when looking it up in the
|
Chris@28
|
265 * FeatureSet returned from the process() call.
|
Chris@28
|
266 */
|
Chris@2
|
267 public native OutputDescriptor[] getOutputDescriptors();
|
Chris@2
|
268
|
Chris@28
|
269 /**
|
Chris@28
|
270 * Process a single block of input data.
|
Chris@28
|
271 *
|
Chris@28
|
272 * If the plugin's inputDomain is TimeDomain, inputBuffers must
|
Chris@28
|
273 * contain one array of floats per input channel, and each of
|
Chris@28
|
274 * these arrays will contain blockSize consecutive audio samples
|
Chris@28
|
275 * (the host will zero-pad as necessary). The timestamp in this
|
Chris@28
|
276 * case will be the real time in seconds of the start of the
|
Chris@28
|
277 * supplied block of samples.
|
Chris@28
|
278 *
|
Chris@28
|
279 * If the plugin's inputDomain is FrequencyDomain, inputBuffers
|
Chris@28
|
280 * must contain one array of floats per input channel, and each of
|
Chris@28
|
281 * these arrays will contain blockSize/2+1 consecutive pairs of
|
Chris@28
|
282 * real and imaginary component floats corresponding to bins
|
Chris@28
|
283 * 0..(blockSize/2) of the FFT output. That is, bin 0 (the first
|
Chris@28
|
284 * pair of floats) contains the DC output, up to bin blockSize/2
|
Chris@28
|
285 * which contains the Nyquist-frequency output. There will
|
Chris@28
|
286 * therefore be blockSize+2 floats per channel in total. The
|
Chris@28
|
287 * timestamp will be the real time in seconds of the centre of the
|
Chris@28
|
288 * FFT input window (i.e. the very first block passed to process
|
Chris@28
|
289 * might contain the FFT of half a block of zero samples and the
|
Chris@28
|
290 * first half-block of the actual data, with a timestamp of zero).
|
Chris@28
|
291 *
|
Chris@28
|
292 * Return any features that have become available after this
|
Chris@28
|
293 * process call. (These do not necessarily have to fall within
|
Chris@28
|
294 * the process block, except for OneSamplePerStep outputs.)
|
Chris@28
|
295 */
|
Chris@40
|
296 public Map<Integer, List<Feature>>
|
Chris@22
|
297 process(float[][] inputBuffers,
|
Chris@22
|
298 RealTime timestamp) {
|
Chris@24
|
299 return process(inputBuffers, 0, timestamp);
|
Chris@22
|
300 }
|
Chris@22
|
301
|
Chris@28
|
302 /**
|
Chris@28
|
303 * As process() above, but taking input data starting at the given
|
Chris@28
|
304 * offset from within each of the channel arrays. Provided to
|
Chris@28
|
305 * avoid potentially having to extract a set of sub-arrays from
|
Chris@28
|
306 * longer arrays (fiddly in Java).
|
Chris@28
|
307 */
|
Chris@40
|
308 public native Map<Integer, List<Feature>>
|
Chris@2
|
309 process(float[][] inputBuffers,
|
Chris@24
|
310 int offset,
|
Chris@2
|
311 RealTime timestamp);
|
Chris@2
|
312
|
Chris@28
|
313 /**
|
Chris@28
|
314 * After all blocks have been processed, calculate and return any
|
Chris@28
|
315 * remaining features derived from the complete input.
|
Chris@28
|
316 */
|
Chris@40
|
317 public native Map<Integer, List<Feature>>
|
Chris@2
|
318 getRemainingFeatures();
|
Chris@0
|
319 }
|
Chris@0
|
320
|