annotate vamp/process.py @ 122:26f75b221828

Make sure M_PI is defined when using VC++
author Chris Cannam
date Tue, 23 Jun 2015 10:48:52 +0100
parents 2370b942cd32
children b8fe675f9c3f
rev   line source
Chris@117 1 #!/usr/bin/env python
Chris@117 2
Chris@117 3 # Python Vamp Host
Chris@117 4 # Copyright (c) 2008-2015 Queen Mary, University of London
Chris@117 5 #
Chris@117 6 # Permission is hereby granted, free of charge, to any person
Chris@117 7 # obtaining a copy of this software and associated documentation
Chris@117 8 # files (the "Software"), to deal in the Software without
Chris@117 9 # restriction, including without limitation the rights to use, copy,
Chris@117 10 # modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@117 11 # of the Software, and to permit persons to whom the Software is
Chris@117 12 # furnished to do so, subject to the following conditions:
Chris@117 13 #
Chris@117 14 # The above copyright notice and this permission notice shall be
Chris@117 15 # included in all copies or substantial portions of the Software.
Chris@117 16 #
Chris@117 17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@117 18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@117 19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@117 20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
Chris@117 21 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@117 22 # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@117 23 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@117 24 #
Chris@117 25 # Except as contained in this notice, the names of the Centre for
Chris@117 26 # Digital Music and Queen Mary, University of London shall not be
Chris@117 27 # used in advertising or otherwise to promote the sale, use or other
Chris@117 28 # dealings in this Software without prior written authorization.
Chris@117 29
Chris@56 30 '''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 31
Chris@56 32 import vampyhost
Chris@112 33 import vamp.frames
Chris@112 34 import vamp.load
Chris@68 35
Chris@100 36 def process_with_initialised_plugin(ff, sample_rate, step_size, plugin, outputs):
Chris@89 37
Chris@98 38 out_indices = dict([(id, plugin.get_output(id)["output_index"])
Chris@98 39 for id in outputs])
Chris@89 40 plugin.reset()
Chris@89 41 fi = 0
Chris@89 42
Chris@89 43 for f in ff:
Chris@89 44 timestamp = vampyhost.frame_to_realtime(fi, sample_rate)
Chris@89 45 results = plugin.process_block(f, timestamp)
Chris@89 46 # results is a dict mapping output number -> list of feature dicts
Chris@89 47 for o in outputs:
Chris@89 48 ix = out_indices[o]
Chris@89 49 if ix in results:
Chris@89 50 for r in results[ix]:
Chris@89 51 yield { o: r }
Chris@89 52 fi = fi + step_size
Chris@89 53
Chris@89 54 results = plugin.get_remaining_features()
Chris@89 55 for o in outputs:
Chris@89 56 ix = out_indices[o]
Chris@89 57 if ix in results:
Chris@89 58 for r in results[ix]:
Chris@89 59 yield { o: r }
Chris@89 60
Chris@89 61
Chris@112 62 def process_audio(data, sample_rate, key, output = "", parameters = {}):
Chris@98 63 """Process audio data with a Vamp plugin, and make the results from a
Chris@98 64 single plugin output available as a generator.
Chris@98 65
Chris@98 66 The provided data should be a 1- or 2-dimensional list or NumPy
Chris@98 67 array of floats. If it is 2-dimensional, the first dimension is
Chris@98 68 taken to be the channel count.
Chris@98 69
Chris@98 70 The returned results will be those calculated by the plugin with
Chris@98 71 the given key and returned through its output with the given
Chris@98 72 output identifier. If the requested output is the empty string,
Chris@98 73 the first output provided by the plugin will be used.
Chris@98 74
Chris@98 75 If the parameters dict is non-empty, the plugin will be configured
Chris@98 76 by setting its parameters according to the (string) key and
Chris@98 77 (float) value data found in the dict.
Chris@98 78
Chris@98 79 This function acts as a generator, yielding a sequence of result
Chris@98 80 features as it obtains them. Each feature is represented as a
Chris@98 81 dictionary containing, optionally, timestamp and duration
Chris@98 82 (RealTime objects), label (string), and a 1-dimensional array of
Chris@98 83 float values.
Chris@99 84
Chris@99 85 If you would prefer to obtain all features in a single output
Chris@99 86 structure, consider using vamp.collect() instead.
Chris@98 87 """
Chris@89 88
Chris@112 89 plugin, step_size, block_size = vamp.load.load_and_configure(data, sample_rate, key, parameters)
Chris@89 90
Chris@89 91 if output == "":
Chris@89 92 output = plugin.get_output(0)["identifier"]
Chris@89 93
Chris@112 94 ff = vamp.frames.frames_from_array(data, step_size, block_size)
Chris@89 95
Chris@100 96 for r in process_with_initialised_plugin(ff, sample_rate, step_size, plugin, [output]):
Chris@89 97 yield r[output]
Chris@76 98
Chris@89 99 plugin.unload()
Chris@89 100
Chris@76 101
Chris@98 102 def process_frames(ff, sample_rate, step_size, key, output = "", parameters = {}):
Chris@98 103 """Process audio data with a Vamp plugin, and make the results from a
Chris@98 104 single plugin output available as a generator.
Chris@95 105
Chris@98 106 The provided data should be an enumerable sequence of time-domain
Chris@98 107 audio frames, of which each frame is 2-dimensional list or NumPy
Chris@98 108 array of floats. The first dimension is taken to be the channel
Chris@98 109 count, and the second dimension the frame or block size. The
Chris@98 110 step_size argument gives the increment in audio samples from one
Chris@98 111 frame to the next. Each frame must have the same size.
Chris@95 112
Chris@98 113 The returned results will be those calculated by the plugin with
Chris@98 114 the given key and returned through its output with the given
Chris@98 115 output identifier. If the requested output is the empty string,
Chris@98 116 the first output provided by the plugin will be used.
Chris@95 117
Chris@98 118 If the parameters dict is non-empty, the plugin will be configured
Chris@98 119 by setting its parameters according to the (string) key and
Chris@98 120 (float) value data found in the dict.
Chris@98 121
Chris@98 122 This function acts as a generator, yielding a sequence of result
Chris@98 123 features as it obtains them. Each feature is represented as a
Chris@98 124 dictionary containing, optionally, timestamp and duration
Chris@98 125 (RealTime objects), label (string), and a 1-dimensional array of
Chris@98 126 float values.
Chris@99 127
Chris@99 128 If you would prefer to obtain all features in a single output
Chris@99 129 structure, consider using vamp.collect() instead.
Chris@98 130 """
Chris@98 131 plugin = vampyhost.load_plugin(key, sample_rate,
Chris@98 132 vampyhost.ADAPT_INPUT_DOMAIN +
Chris@98 133 vampyhost.ADAPT_BUFFER_SIZE +
Chris@98 134 vampyhost.ADAPT_CHANNEL_COUNT)
Chris@98 135
Chris@98 136 fi = 0
Chris@98 137 channels = 0
Chris@98 138 block_size = 0
Chris@98 139
Chris@98 140 if output == "":
Chris@98 141 out_index = 0
Chris@98 142 else:
Chris@98 143 out_index = plugin.get_output(output)["output_index"]
Chris@95 144
Chris@98 145 for f in ff:
Chris@95 146
Chris@98 147 if fi == 0:
Chris@98 148 channels = f.shape[0]
Chris@98 149 block_size = f.shape[1]
Chris@98 150 plugin.set_parameter_values(parameters)
Chris@98 151 if not plugin.initialise(channels, step_size, block_size):
Chris@98 152 raise "Failed to initialise plugin"
Chris@98 153
Chris@98 154 timestamp = vampyhost.frame_to_realtime(fi, sample_rate)
Chris@98 155 results = plugin.process_block(f, timestamp)
Chris@98 156 # results is a dict mapping output number -> list of feature dicts
Chris@98 157 if out_index in results:
Chris@98 158 for r in results[out_index]:
Chris@98 159 yield r
Chris@98 160
Chris@98 161 fi = fi + step_size
Chris@98 162
Chris@98 163 if fi > 0:
Chris@98 164 results = plugin.get_remaining_features()
Chris@98 165 if out_index in results:
Chris@98 166 for r in results[out_index]:
Chris@98 167 yield r
Chris@98 168
Chris@95 169 plugin.unload()
Chris@95 170
Chris@95 171
Chris@117 172 def process_audio_multiple_outputs(data, sample_rate, key, outputs, parameters = {}):
Chris@99 173 """Process audio data with a Vamp plugin, and make the results from a
Chris@99 174 set of plugin outputs available as a generator.
Chris@99 175
Chris@99 176 The provided data should be a 1- or 2-dimensional list or NumPy
Chris@99 177 array of floats. If it is 2-dimensional, the first dimension is
Chris@99 178 taken to be the channel count.
Chris@99 179
Chris@99 180 The returned results will be those calculated by the plugin with
Chris@99 181 the given key and returned through its outputs whose identifiers
Chris@99 182 are given in the outputs argument.
Chris@99 183
Chris@99 184 If the parameters dict is non-empty, the plugin will be configured
Chris@99 185 by setting its parameters according to the (string) key and
Chris@99 186 (float) value data found in the dict.
Chris@99 187
Chris@99 188 This function acts as a generator, yielding a sequence of result
Chris@99 189 feature sets as it obtains them. Each feature set is a dictionary
Chris@99 190 mapping from output identifier to a list of features, each
Chris@99 191 represented as a dictionary containing, optionally, timestamp and
Chris@99 192 duration (RealTime objects), label (string), and a 1-dimensional
Chris@99 193 array of float values.
Chris@99 194 """
Chris@68 195
Chris@112 196 plugin, step_size, block_size = vamp.load.load_and_configure(data, sample_rate, key, parameters)
Chris@64 197
Chris@112 198 ff = vamp.frames.frames_from_array(data, step_size, block_size)
Chris@64 199
Chris@100 200 for r in process_with_initialised_plugin(ff, sample_rate, step_size, plugin, outputs):
Chris@89 201 yield r
Chris@61 202
Chris@89 203 plugin.unload()
Chris@99 204
Chris@100 205
Chris@100 206 def process_frames_multiple_outputs(ff, sample_rate, step_size, key, outputs, parameters = {}):
Chris@100 207 """Process audio data with a Vamp plugin, and make the results from a
Chris@100 208 set of plugin outputs available as a generator.
Chris@100 209
Chris@100 210 The provided data should be an enumerable sequence of time-domain
Chris@100 211 audio frames, of which each frame is 2-dimensional list or NumPy
Chris@100 212 array of floats. The first dimension is taken to be the channel
Chris@100 213 count, and the second dimension the frame or block size. The
Chris@100 214 step_size argument gives the increment in audio samples from one
Chris@100 215 frame to the next. Each frame must have the same size.
Chris@100 216
Chris@100 217 The returned results will be those calculated by the plugin with
Chris@100 218 the given key and returned through its outputs whose identifiers
Chris@100 219 are given in the outputs argument.
Chris@100 220
Chris@100 221 If the parameters dict is non-empty, the plugin will be configured
Chris@100 222 by setting its parameters according to the (string) key and
Chris@100 223 (float) value data found in the dict.
Chris@100 224
Chris@100 225 This function acts as a generator, yielding a sequence of result
Chris@100 226 feature sets as it obtains them. Each feature set is a dictionary
Chris@100 227 mapping from output identifier to a list of features, each
Chris@100 228 represented as a dictionary containing, optionally, timestamp and
Chris@100 229 duration (RealTime objects), label (string), and a 1-dimensional
Chris@100 230 array of float values.
Chris@100 231 """
Chris@100 232 plugin = vampyhost.load_plugin(key, sample_rate,
Chris@100 233 vampyhost.ADAPT_INPUT_DOMAIN +
Chris@100 234 vampyhost.ADAPT_BUFFER_SIZE +
Chris@100 235 vampyhost.ADAPT_CHANNEL_COUNT)
Chris@100 236
Chris@100 237 out_indices = dict([(id, plugin.get_output(id)["output_index"])
Chris@100 238 for id in outputs])
Chris@100 239
Chris@100 240 fi = 0
Chris@100 241 channels = 0
Chris@100 242 block_size = 0
Chris@100 243
Chris@100 244 for f in ff:
Chris@100 245
Chris@100 246 if fi == 0:
Chris@100 247 channels = f.shape[0]
Chris@100 248 block_size = f.shape[1]
Chris@100 249 plugin.set_parameter_values(parameters)
Chris@100 250 if not plugin.initialise(channels, step_size, block_size):
Chris@100 251 raise "Failed to initialise plugin"
Chris@100 252
Chris@100 253 timestamp = vampyhost.frame_to_realtime(fi, sample_rate)
Chris@100 254 results = plugin.process_block(f, timestamp)
Chris@100 255 # results is a dict mapping output number -> list of feature dicts
Chris@100 256 for o in outputs:
Chris@100 257 ix = out_indices[o]
Chris@100 258 if ix in results:
Chris@100 259 for r in results[ix]:
Chris@100 260 yield { o: r }
Chris@100 261 fi = fi + step_size
Chris@100 262
Chris@100 263 if fi > 0:
Chris@100 264 results = plugin.get_remaining_features()
Chris@100 265 for o in outputs:
Chris@100 266 ix = out_indices[o]
Chris@100 267 if ix in results:
Chris@100 268 for r in results[ix]:
Chris@100 269 yield { o: r }
Chris@100 270
Chris@100 271 plugin.unload()
Chris@100 272
Chris@100 273