annotate vamp/process.py @ 98:f0c18ba7b54e

Fixes to process_frames, and tests; doc strings
author Chris Cannam
date Tue, 03 Feb 2015 14:43:50 +0000
parents 3e5791890b65
children 7764eb74a3c6
rev   line source
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@98 55 """
Chris@89 56
Chris@89 57 plugin, step_size, block_size = load.load_and_configure(data, sample_rate, key, parameters)
Chris@89 58
Chris@89 59 if output == "":
Chris@89 60 output = plugin.get_output(0)["identifier"]
Chris@89 61
Chris@89 62 ff = frames.frames_from_array(data, step_size, block_size)
Chris@89 63
Chris@89 64 for r in process_frames_with_plugin(ff, sample_rate, step_size, plugin, [output]):
Chris@89 65 yield r[output]
Chris@76 66
Chris@89 67 plugin.unload()
Chris@89 68
Chris@76 69
Chris@98 70 def process_frames(ff, sample_rate, step_size, key, output = "", parameters = {}):
Chris@98 71 """Process audio data with a Vamp plugin, and make the results from a
Chris@98 72 single plugin output available as a generator.
Chris@95 73
Chris@98 74 The provided data should be an enumerable sequence of time-domain
Chris@98 75 audio frames, of which each frame is 2-dimensional list or NumPy
Chris@98 76 array of floats. The first dimension is taken to be the channel
Chris@98 77 count, and the second dimension the frame or block size. The
Chris@98 78 step_size argument gives the increment in audio samples from one
Chris@98 79 frame to the next. Each frame must have the same size.
Chris@95 80
Chris@98 81 The returned results will be those calculated by the plugin with
Chris@98 82 the given key and returned through its output with the given
Chris@98 83 output identifier. If the requested output is the empty string,
Chris@98 84 the first output provided by the plugin will be used.
Chris@95 85
Chris@98 86 If the parameters dict is non-empty, the plugin will be configured
Chris@98 87 by setting its parameters according to the (string) key and
Chris@98 88 (float) value data found in the dict.
Chris@98 89
Chris@98 90 This function acts as a generator, yielding a sequence of result
Chris@98 91 features as it obtains them. Each feature is represented as a
Chris@98 92 dictionary containing, optionally, timestamp and duration
Chris@98 93 (RealTime objects), label (string), and a 1-dimensional array of
Chris@98 94 float values.
Chris@98 95 """
Chris@98 96
Chris@98 97 plugin = vampyhost.load_plugin(key, sample_rate,
Chris@98 98 vampyhost.ADAPT_INPUT_DOMAIN +
Chris@98 99 vampyhost.ADAPT_BUFFER_SIZE +
Chris@98 100 vampyhost.ADAPT_CHANNEL_COUNT)
Chris@98 101
Chris@98 102 fi = 0
Chris@98 103 channels = 0
Chris@98 104 block_size = 0
Chris@98 105
Chris@98 106 if output == "":
Chris@98 107 out_index = 0
Chris@98 108 else:
Chris@98 109 out_index = plugin.get_output(output)["output_index"]
Chris@95 110
Chris@98 111 for f in ff:
Chris@95 112
Chris@98 113 if fi == 0:
Chris@98 114 channels = f.shape[0]
Chris@98 115 block_size = f.shape[1]
Chris@98 116 plugin.set_parameter_values(parameters)
Chris@98 117 if not plugin.initialise(channels, step_size, block_size):
Chris@98 118 raise "Failed to initialise plugin"
Chris@98 119
Chris@98 120 timestamp = vampyhost.frame_to_realtime(fi, sample_rate)
Chris@98 121 results = plugin.process_block(f, timestamp)
Chris@98 122 # results is a dict mapping output number -> list of feature dicts
Chris@98 123 if out_index in results:
Chris@98 124 for r in results[out_index]:
Chris@98 125 yield r
Chris@98 126
Chris@98 127 fi = fi + step_size
Chris@98 128
Chris@98 129 if fi > 0:
Chris@98 130 results = plugin.get_remaining_features()
Chris@98 131 if out_index in results:
Chris@98 132 for r in results[out_index]:
Chris@98 133 yield r
Chris@98 134
Chris@95 135 plugin.unload()
Chris@95 136
Chris@95 137
Chris@84 138 def process_multiple_outputs(data, sample_rate, key, outputs, parameters = {}):
Chris@68 139 #!!! docstring
Chris@68 140
Chris@89 141 plugin, step_size, block_size = load.load_and_configure(data, sample_rate, key, parameters)
Chris@64 142
Chris@84 143 ff = frames.frames_from_array(data, step_size, block_size)
Chris@64 144
Chris@89 145 for r in process_frames_with_plugin(ff, sample_rate, step_size, plugin, outputs):
Chris@89 146 yield r
Chris@61 147
Chris@89 148 plugin.unload()