changeset 98:f0c18ba7b54e

Fixes to process_frames, and tests; doc strings
author Chris Cannam
date Tue, 03 Feb 2015 14:43:50 +0000
parents 06c4afba4fc5
children 7764eb74a3c6
files test/test_process.py vamp/__init__.py vamp/load.py vamp/process.py
diffstat 4 files changed, 137 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/test/test_process.py	Tue Feb 03 10:29:21 2015 +0000
+++ b/test/test_process.py	Tue Feb 03 14:43:50 2015 +0000
@@ -1,6 +1,7 @@
 
 import vamp
 import numpy as np
+import vamp.frames as fr
 
 plugin_key = "vamp-test-plugin:vamp-test-plugin"
 plugin_key_freq = "vamp-test-plugin:vamp-test-plugin-freq"
@@ -73,6 +74,21 @@
         actual = results[i]["values"][0]
         assert actual == expected
 
+def test_process_summary_frames():
+    buf = input_data(blocksize * 10)
+    ff = fr.frames_from_array(buf, blocksize, blocksize)
+    results = list(vamp.process_frames(ff, rate, blocksize, plugin_key, "input-summary", {}))
+    assert len(results) == 10
+    for i in range(len(results)):
+        #
+        # each feature has a single value, equal to the number of non-zero elts
+        # in the input block (which is all of them, i.e. the blocksize) plus
+        # the first elt (which is i * blockSize + 1)
+        #
+        expected = blocksize + i * blocksize + 1
+        actual = results[i]["values"][0]
+        assert actual == expected
+
 def test_process_multi_summary():
     buf = input_data(blocksize * 10)
     results = list(vamp.process_multiple_outputs(buf, rate, plugin_key, [ "input-summary" ], {}))
--- a/vamp/__init__.py	Tue Feb 03 10:29:21 2015 +0000
+++ b/vamp/__init__.py	Tue Feb 03 14:43:50 2015 +0000
@@ -2,7 +2,7 @@
 
 import vampyhost
 
-from load import list_plugins
+from load import list_plugins, get_outputs_of, get_category_of
 from process import process, process_frames, process_multiple_outputs
 from collect import collect
 
--- a/vamp/load.py	Tue Feb 03 10:29:21 2015 +0000
+++ b/vamp/load.py	Tue Feb 03 14:43:50 2015 +0000
@@ -3,9 +3,45 @@
 import vampyhost
 
 def list_plugins():
+    """Obtain a list of plugin keys for all currently installed Vamp plugins.
+
+    The returned value is a list of strings, each of which is the key
+    for one plugin. (Note that a plugin may have multiple outputs, if
+    it computes more than one type of feature.)
+
+    To query the available outputs and category of a plugin, you may
+    use vamp.get_outputs_of() and vamp.get_category_of(). Further
+    information may be retrieved by loading the plugin and querying
+    its info dictionary using the low-level functions in the
+    vamp.vampyhost extension module.
+
+    To make use of a plugin to extract features from audio data, pass
+    the plugin key and optionally an output identifier to
+    vamp.process() or vamp.collect().
+    """
     return vampyhost.list_plugins()
 
+def get_outputs_of(key):
+    """Obtain a list of the output identifiers for the given plugin key.
+    """
+    return vampyhost.get_outputs_of(key)
+
+def get_category_of(key):
+    """Obtain the category descriptor, if any, for the given plugin key.
+
+    The returned value is a list of descriptor terms, from least
+    specific to most specific. The list may be empty if no category
+    information is found for the plugin.
+    """
+    return vampyhost.get_category_of(key)
+
 def load_and_configure(data, sample_rate, key, parameters):
+    """Load the plugin with the given key at a given sample rate,
+    configure it with the parameter keys and values in the given
+    parameter dictionary, and initialise it with its preferred step
+    and block size. The channel count is taken from the shape of the
+    data array provided.
+    """
 
     plug = vampyhost.load_plugin(key, sample_rate,
                                  vampyhost.ADAPT_INPUT_DOMAIN +
@@ -29,4 +65,3 @@
         return (plug, step_size, block_size)
     else:
         raise "Failed to initialise plugin"
-
--- a/vamp/process.py	Tue Feb 03 10:29:21 2015 +0000
+++ b/vamp/process.py	Tue Feb 03 14:43:50 2015 +0000
@@ -4,10 +4,10 @@
 import frames
 import load
 
-
 def process_frames_with_plugin(ff, sample_rate, step_size, plugin, outputs):
 
-    out_indices = dict([(id, plugin.get_output(id)["output_index"]) for id in outputs])
+    out_indices = dict([(id, plugin.get_output(id)["output_index"])
+                        for id in outputs])
     plugin.reset()
     fi = 0
 
@@ -31,7 +31,28 @@
 
 
 def process(data, sample_rate, key, output = "", parameters = {}):
-#!!! docstring
+    """Process audio data with a Vamp plugin, and make the results from a
+    single plugin output available as a generator.
+
+    The provided data should be a 1- or 2-dimensional list or NumPy
+    array of floats. If it is 2-dimensional, the first dimension is
+    taken to be the channel count.
+
+    The returned results will be those calculated by the plugin with
+    the given key and returned through its output with the given
+    output identifier. If the requested output is the empty string,
+    the first output provided by the plugin will be used.
+
+    If the parameters dict is non-empty, the plugin will be configured
+    by setting its parameters according to the (string) key and
+    (float) value data found in the dict.
+
+    This function acts as a generator, yielding a sequence of result
+    features as it obtains them. Each feature is represented as a
+    dictionary containing, optionally, timestamp and duration
+    (RealTime objects), label (string), and a 1-dimensional array of
+    float values.
+    """
 
     plugin, step_size, block_size = load.load_and_configure(data, sample_rate, key, parameters)
 
@@ -46,24 +67,71 @@
     plugin.unload()
 
 
-def process_frames(ff, channels, sample_rate, step_size, key, output = "", parameters = {}):
+def process_frames(ff, sample_rate, step_size, key, output = "", parameters = {}):
+    """Process audio data with a Vamp plugin, and make the results from a
+    single plugin output available as a generator.
 
-    plug = vampyhost.load_plugin(key, sample_rate,
-                                 vampyhost.ADAPT_INPUT_DOMAIN +
-                                 vampyhost.ADAPT_BUFFER_SIZE +
-                                 vampyhost.ADAPT_CHANNEL_COUNT)
+    The provided data should be an enumerable sequence of time-domain
+    audio frames, of which each frame is 2-dimensional list or NumPy
+    array of floats. The first dimension is taken to be the channel
+    count, and the second dimension the frame or block size. The
+    step_size argument gives the increment in audio samples from one
+    frame to the next. Each frame must have the same size.
 
-    plug.set_parameter_values(parameters)
+    The returned results will be those calculated by the plugin with
+    the given key and returned through its output with the given
+    output identifier. If the requested output is the empty string,
+    the first output provided by the plugin will be used.
 
-    if not plug.initialise(channels, step_size, block_size):
-        raise "Failed to initialise plugin"
+    If the parameters dict is non-empty, the plugin will be configured
+    by setting its parameters according to the (string) key and
+    (float) value data found in the dict.
+
+    This function acts as a generator, yielding a sequence of result
+    features as it obtains them. Each feature is represented as a
+    dictionary containing, optionally, timestamp and duration
+    (RealTime objects), label (string), and a 1-dimensional array of
+    float values.
+    """
+
+    plugin = vampyhost.load_plugin(key, sample_rate,
+                                   vampyhost.ADAPT_INPUT_DOMAIN +
+                                   vampyhost.ADAPT_BUFFER_SIZE +
+                                   vampyhost.ADAPT_CHANNEL_COUNT)
+
+    fi = 0
+    channels = 0
+    block_size = 0
+
+    if output == "":
+        out_index = 0
+    else:
+        out_index = plugin.get_output(output)["output_index"]
     
-    if output == "":
-        output = plugin.get_output(0)["identifier"]
+    for f in ff:
 
-    for r in process_frames_with_plugin(ff, sample_rate, step_size, plugin, [output]):
-        yield r[output]
-    
+        if fi == 0:
+            channels = f.shape[0]
+            block_size = f.shape[1]
+            plugin.set_parameter_values(parameters)
+            if not plugin.initialise(channels, step_size, block_size):
+                raise "Failed to initialise plugin"
+
+        timestamp = vampyhost.frame_to_realtime(fi, sample_rate)
+        results = plugin.process_block(f, timestamp)
+        # results is a dict mapping output number -> list of feature dicts
+        if out_index in results:
+            for r in results[out_index]:
+                yield r
+
+        fi = fi + step_size
+
+    if fi > 0:
+        results = plugin.get_remaining_features()
+        if out_index in results:
+            for r in results[out_index]:
+                yield r
+        
     plugin.unload()
     
 
@@ -78,4 +146,3 @@
         yield r
 
     plugin.unload()
-