Chris@37: /* Chris@37: jVamp Chris@37: Chris@37: A Java host interface for Vamp audio analysis plugins Chris@37: Chris@37: Centre for Digital Music, Queen Mary, University of London. Chris@37: Copyright 2012 Chris Cannam and QMUL. Chris@37: Chris@37: Permission is hereby granted, free of charge, to any person Chris@37: obtaining a copy of this software and associated documentation Chris@37: files (the "Software"), to deal in the Software without Chris@37: restriction, including without limitation the rights to use, copy, Chris@37: modify, merge, publish, distribute, sublicense, and/or sell copies Chris@37: of the Software, and to permit persons to whom the Software is Chris@37: furnished to do so, subject to the following conditions: Chris@37: Chris@37: The above copyright notice and this permission notice shall be Chris@37: included in all copies or substantial portions of the Software. Chris@37: Chris@37: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Chris@37: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF Chris@37: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND Chris@37: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR Chris@37: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF Chris@37: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION Chris@37: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Chris@37: Chris@37: Except as contained in this notice, the names of the Centre for Chris@37: Digital Music; Queen Mary, University of London; and Chris Cannam Chris@37: shall not be used in advertising or otherwise to promote the sale, Chris@37: use or other dealings in this Software without prior written Chris@37: authorization. Chris@37: */ Chris@0: Chris@0: package org.vamp_plugins; Chris@0: Chris@40: import java.util.Map; Chris@40: import java.util.List; Chris@2: Chris@28: /** Chris@28: * A Java wrapper for a native-code Vamp plugin. Plugins are obtained Chris@28: * using PluginLoader and must be freed by calling dispose() after use Chris@28: * (being native code they cannot be garbage collected). Chris@28: * Chris@28: * The plugin lifecycle looks roughly like this, from the host's Chris@28: * perspective: Chris@28: * Chris@28: * - Plugin is loaded using PluginLoader Chris@28: * Chris@28: * - Host may query the plugin's available outputs with Chris@28: * getOutputDescriptors(). This will report what outputs exist, Chris@28: * but their properties (e.g. resolution, value count, extents) Chris@28: * are not yet fixed Chris@28: * Chris@28: * - Host may query and set the plugin's programs and parameters with Chris@28: * getPrograms(), getParameterDescriptors(), setParameter() etc Chris@28: * Chris@28: * - After all parameters are set, host queries the plugin's preferred Chris@28: * step size, block size, and channel count (which may depend on Chris@28: * the parameter settings) Chris@28: * Chris@28: * - Host initialises plugin by calling initialise(). If it returns Chris@28: * false, initialise failed -- most likely because the step size, Chris@28: * block size, or channel count was rejected Chris@28: * Chris@28: * - Host may now get final values for the output properties using Chris@28: * getOutputDescriptors() Chris@28: * Chris@28: * - Host calls process() repeatedly to process data. This may return Chris@28: * some results as it goes along (if the plugin is causal) Chris@28: * Chris@28: * - Host calls getRemainingFeatures() exactly once when all input has Chris@28: * been processed, to obtain any non-causal or leftover features. Chris@28: * Chris@28: * - At any point after initialise() has been called, host may call Chris@28: * reset() to restart processing. Parameter values remain fixed Chris@28: * across reset() calls. Chris@28: * Chris@28: * - When host is finished with plugin, it calls dispose(). Chris@28: * Chris@28: * The host may not change any parameter or program settings after Chris@28: * calling initialise(), and may not call initialise() more than once Chris@28: * on any given plugin. Chris@28: * Chris@28: * See the PluginBase and Plugin classes in the C++ Vamp plugin SDK Chris@28: * for further documentation. Chris@28: */ Chris@0: public class Plugin Chris@0: { Chris@0: private long nativeHandle; Chris@0: protected Plugin(long handle) { nativeHandle = handle; } Chris@0: Chris@28: /** Chris@28: * Dispose of this Plugin. Call this when you have finished using Chris@28: * it to ensure the native code object is released. Chris@28: */ Chris@20: public native void dispose(); Chris@20: Chris@28: /** Chris@28: * Get the Vamp API compatibility level of the plugin. Chris@28: */ Chris@28: public native int getVampApiVersion(); Chris@3: Chris@28: /** Chris@28: * Get the computer-usable name of the plugin. This will contain Chris@28: * only the characters [a-zA-Z0-9_-]. This is the authoritative Chris@28: * way for a host to identify a plugin within a given library, but Chris@28: * it is not the primary label shown to the user (that will be the Chris@28: * name, below). Chris@28: */ Chris@0: public native String getIdentifier(); Chris@28: Chris@28: /** Chris@28: * Get a human-readable name or title of the plugin. This is the Chris@28: * main identifying label shown to the user. Chris@28: */ Chris@0: public native String getName(); Chris@28: Chris@28: /** Chris@28: * Get a human-readable description for the plugin, typically Chris@28: * a line of text that may optionally be displayed in addition Chris@28: * to the plugin's "name". May be empty if the name has said Chris@28: * it all already. Chris@28: */ Chris@0: public native String getDescription(); Chris@28: Chris@28: /** Chris@28: * Get the name of the author or vendor of the plugin in Chris@28: * human-readable form. This should be short enough to be used to Chris@28: * label plugins from the same source in a tree or menu if Chris@28: * appropriate. Chris@28: */ Chris@3: public native String getMaker(); Chris@28: Chris@28: /** Chris@28: * Get the copyright statement or licensing summary for the Chris@28: * plugin. Chris@28: */ Chris@3: public native String getCopyright(); Chris@28: Chris@28: /** Chris@28: * Get the version number of the plugin. Chris@28: */ Chris@0: public native int getPluginVersion(); Chris@2: Chris@28: /** Chris@28: * Get the controllable parameters of this plugin. Chris@28: */ Chris@3: public native ParameterDescriptor[] getParameterDescriptors(); Chris@28: Chris@28: /** Chris@28: * Get the value of a named parameter. The argument is the identifier Chris@28: * field from that parameter's descriptor. Chris@28: */ Chris@3: public native float getParameter(String identifier); Chris@28: Chris@28: /** Chris@28: * Set a named parameter. The first argument is the identifier field Chris@28: * from that parameter's descriptor. Chris@28: */ Chris@3: public native void setParameter(String identifier, float value); Chris@3: Chris@28: /** Chris@28: * Get the program settings available in this plugin. A program Chris@28: * is a named shorthand for a set of parameter values; changing Chris@28: * the program may cause the plugin to alter the values of its Chris@28: * published parameters (and/or non-public internal processing Chris@28: * parameters). The host should re-read the plugin's parameter Chris@28: * values after setting a new program. Chris@28: * Chris@28: * The programs must have unique names. Chris@28: */ Chris@3: public native String[] getPrograms(); Chris@28: Chris@28: /** Chris@28: * Get the current program (if any). Chris@28: */ Chris@3: public native String getCurrentProgram(); Chris@28: Chris@28: /** Chris@28: * Select a program. (If the given program name is not one of the Chris@28: * available programs, do nothing.) Chris@28: */ Chris@3: public native void selectProgram(String program); Chris@3: Chris@28: /** Chris@28: * Initialise a plugin to prepare it for use with the given number Chris@28: * of input channels, step size (window increment, in sample Chris@28: * frames) and block size (window size, in sample frames). Chris@28: * Chris@28: * The input sample rate should have been already specified when Chris@28: * loading the plugin. Chris@28: * Chris@28: * Return true for successful initialisation, false if the number Chris@28: * of input channels, step size and/or block size cannot be Chris@28: * supported. Chris@28: */ Chris@2: public native boolean initialise(int inputChannels, Chris@2: int stepSize, Chris@2: int blockSize); Chris@2: Chris@28: /** Chris@28: * Reset the plugin after use, to prepare it for another clean Chris@28: * run. Chris@28: */ Chris@2: public native void reset(); Chris@2: Chris@25: public static enum InputDomain { TIME_DOMAIN, FREQUENCY_DOMAIN }; Chris@28: Chris@28: /** Chris@28: * Get the plugin's required input domain. Chris@28: * Chris@28: * If this is TimeDomain, the samples provided to the process() Chris@28: * function (below) must be in the time domain, as for a Chris@28: * traditional audio processing plugin. Chris@28: * Chris@28: * If this is FrequencyDomain, the host must carry out a windowed Chris@28: * FFT of size equal to the negotiated block size on the data Chris@28: * before passing the frequency bin data in to process(). The Chris@28: * input data for the FFT will be rotated so as to place the Chris@28: * origin in the centre of the block. The plugin does not get to Chris@28: * choose the window type -- the host will either let the user do Chris@28: * so, or will use a Hanning window. Chris@28: */ Chris@2: public native InputDomain getInputDomain(); Chris@2: Chris@28: /** Chris@28: * Get the preferred block size (window size -- the number of Chris@28: * sample frames passed in each block to the process() function). Chris@28: * This should be called before initialise(). Chris@28: * Chris@28: * A plugin that can handle any block size may return 0. The Chris@28: * final block size will be set in the initialise() call. Chris@28: */ Chris@2: public native int getPreferredBlockSize(); Chris@28: Chris@28: /** Chris@28: * Get the preferred step size (window increment -- the distance Chris@28: * in sample frames between the start frames of consecutive blocks Chris@28: * passed to the process() function) for the plugin. This should Chris@28: * be called before initialise(). Chris@28: * Chris@28: * A plugin may return 0 if it has no particular interest in the Chris@28: * step size. In this case, the host should make the step size Chris@28: * equal to the block size if the plugin is accepting input in the Chris@28: * time domain. If the plugin is accepting input in the frequency Chris@28: * domain, the host may use any step size. The final step size Chris@28: * will be set in the initialise() call. Chris@28: */ Chris@2: public native int getPreferredStepSize(); Chris@28: Chris@28: /** Chris@28: * Get the minimum supported number of input channels. Chris@28: */ Chris@2: public native int getMinChannelCount(); Chris@28: Chris@28: /** Chris@28: * Get the maximum supported number of input channels. Chris@28: */ Chris@2: public native int getMaxChannelCount(); Chris@2: Chris@28: /** Chris@28: * Get the outputs of this plugin. An output's index in this list Chris@28: * is used as its numeric index when looking it up in the Chris@28: * FeatureSet returned from the process() call. Chris@28: */ Chris@2: public native OutputDescriptor[] getOutputDescriptors(); Chris@2: Chris@28: /** Chris@28: * Process a single block of input data. Chris@28: * Chris@28: * If the plugin's inputDomain is TimeDomain, inputBuffers must Chris@28: * contain one array of floats per input channel, and each of Chris@28: * these arrays will contain blockSize consecutive audio samples Chris@28: * (the host will zero-pad as necessary). The timestamp in this Chris@28: * case will be the real time in seconds of the start of the Chris@28: * supplied block of samples. Chris@28: * Chris@28: * If the plugin's inputDomain is FrequencyDomain, inputBuffers Chris@28: * must contain one array of floats per input channel, and each of Chris@28: * these arrays will contain blockSize/2+1 consecutive pairs of Chris@28: * real and imaginary component floats corresponding to bins Chris@28: * 0..(blockSize/2) of the FFT output. That is, bin 0 (the first Chris@28: * pair of floats) contains the DC output, up to bin blockSize/2 Chris@28: * which contains the Nyquist-frequency output. There will Chris@28: * therefore be blockSize+2 floats per channel in total. The Chris@28: * timestamp will be the real time in seconds of the centre of the Chris@28: * FFT input window (i.e. the very first block passed to process Chris@28: * might contain the FFT of half a block of zero samples and the Chris@28: * first half-block of the actual data, with a timestamp of zero). Chris@28: * Chris@28: * Return any features that have become available after this Chris@28: * process call. (These do not necessarily have to fall within Chris@28: * the process block, except for OneSamplePerStep outputs.) Chris@28: */ Chris@40: public Map> Chris@22: process(float[][] inputBuffers, Chris@22: RealTime timestamp) { Chris@24: return process(inputBuffers, 0, timestamp); Chris@22: } Chris@22: Chris@28: /** Chris@28: * As process() above, but taking input data starting at the given Chris@28: * offset from within each of the channel arrays. Provided to Chris@28: * avoid potentially having to extract a set of sub-arrays from Chris@28: * longer arrays (fiddly in Java). Chris@28: */ Chris@40: public native Map> Chris@2: process(float[][] inputBuffers, Chris@24: int offset, Chris@2: RealTime timestamp); Chris@2: Chris@28: /** Chris@28: * After all blocks have been processed, calculate and return any Chris@28: * remaining features derived from the complete input. Chris@28: */ Chris@40: public native Map> Chris@2: getRemainingFeatures(); Chris@0: } Chris@0: