To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / src / may / vamp.yeti @ 594:495cc8973458
History | View | Annotate | Download (10.9 KB)
| 1 |
module may.vamp; |
|---|---|
| 2 |
|
| 3 |
import org.vamp_plugins: |
| 4 |
Plugin, Plugin$InputDomain, |
| 5 |
PluginLoader, PluginLoader$AdapterFlags, PluginLoader$LoadFailedException, |
| 6 |
ParameterDescriptor, OutputDescriptor, OutputDescriptor$SampleType, |
| 7 |
RealTime, Feature; |
| 8 |
|
| 9 |
import java.lang: UnsatisfiedLinkError; |
| 10 |
|
| 11 |
import java.util: Map, List; |
| 12 |
|
| 13 |
vec = load may.vector; |
| 14 |
fr = load may.stream.framer; |
| 15 |
af = load may.stream.audiofile; |
| 16 |
mat = load may.matrix; |
| 17 |
vamprdf = load may.vamp.vamprdf; |
| 18 |
vamppost = load may.vamp.vamppost; |
| 19 |
|
| 20 |
store = load yertle.store; |
| 21 |
|
| 22 |
realTime r is ~RealTime -> number = r#sec() + (r#nsec() / 1000000000); |
| 23 |
|
| 24 |
feature f is ~Feature -> 'a = {
|
| 25 |
timestamp = if f#hasTimestamp then Time (realTime f#timestamp) else Untimed () fi, |
| 26 |
duration = if f#hasDuration then Time (realTime f#duration) else Untimed () fi, |
| 27 |
values = vec.fromFloats f#values, |
| 28 |
label = f#label, |
| 29 |
}; |
| 30 |
|
| 31 |
featureList fl is ~Object -> 'a = |
| 32 |
if nullptr? fl then [] |
| 33 |
else |
| 34 |
a = fl unsafely_as ~List; |
| 35 |
result = array []; |
| 36 |
itr = a#iterator(); |
| 37 |
itr#hasNext() loop (push result (feature (itr#next() unsafely_as ~Feature))); |
| 38 |
list result |
| 39 |
fi; |
| 40 |
|
| 41 |
featureSet fs is ~Map -> 'a = |
| 42 |
(numberOf n is ~Object -> number = (n unsafely_as ~Integer)#intValue(); |
| 43 |
s = [:]; |
| 44 |
kk = list fs#keySet()#toArray(); |
| 45 |
for kk do k: s[numberOf k] := featureList fs#get(k) done; |
| 46 |
s); |
| 47 |
|
| 48 |
stores = [:]; |
| 49 |
|
| 50 |
getSingletonStoreFor loader = |
| 51 |
synchronized stores do: |
| 52 |
if loader in stores then |
| 53 |
stores[loader] |
| 54 |
else |
| 55 |
s = store.newRdfStore (); |
| 56 |
loader s; |
| 57 |
stores[loader] := s; |
| 58 |
s; |
| 59 |
fi |
| 60 |
done; |
| 61 |
|
| 62 |
getSystemStore () = |
| 63 |
getSingletonStoreFor vamprdf.loadSystemVampRdf; |
| 64 |
|
| 65 |
getGlobalStore () = |
| 66 |
getSingletonStoreFor vamprdf.loadGlobalVampRdf; |
| 67 |
|
| 68 |
getPluginPath () = |
| 69 |
(try |
| 70 |
map string PluginLoader#getInstance()#getPluginPath(); |
| 71 |
catch UnsatisfiedLinkError e: |
| 72 |
eprintln "Warning: Unable to obtain plugin path:\n\(e)"; |
| 73 |
[]; |
| 74 |
yrt); |
| 75 |
|
| 76 |
listPlugins () = |
| 77 |
(try |
| 78 |
map string PluginLoader#getInstance()#listPlugins(); |
| 79 |
catch UnsatisfiedLinkError e: |
| 80 |
eprintln "Warning: Unable to obtain plugin list:\n\(e)"; |
| 81 |
[]; |
| 82 |
yrt); |
| 83 |
|
| 84 |
getPluginKeysFrom store = |
| 85 |
(nodes = vamprdf.allPluginNodes store; |
| 86 |
// ordering is random out of the store; might as well sort |
| 87 |
sort (concatMap do n: |
| 88 |
case vamprdf.pluginKeyByNode store n of Some k: [k]; None (): [] esac |
| 89 |
done nodes)); |
| 90 |
|
| 91 |
getKnownPluginKeys () = |
| 92 |
(global = getPluginKeysFrom (getGlobalStore ()); |
| 93 |
system = getPluginKeysFrom (getSystemStore ()); |
| 94 |
sort (nub (concat [global, system]))); |
| 95 |
|
| 96 |
getDataForKnownPlugin key = |
| 97 |
case vamprdf.pluginDataByKey (getSystemStore ()) key of |
| 98 |
Some d: Some d; |
| 99 |
None _: vamprdf.pluginDataByKey (getGlobalStore ()) key; |
| 100 |
esac; |
| 101 |
|
| 102 |
categoryOf key = |
| 103 |
map string PluginLoader#getInstance()#getPluginCategory(key); |
| 104 |
|
| 105 |
inputDomain d is ~Plugin$InputDomain -> 'a = |
| 106 |
if d == Plugin$InputDomain#FREQUENCY_DOMAIN then |
| 107 |
FrequencyDomain () |
| 108 |
else |
| 109 |
TimeDomain () |
| 110 |
fi; |
| 111 |
|
| 112 |
parameterDescriptor pd is ~ParameterDescriptor -> 'a = {
|
| 113 |
identifier = pd#identifier, |
| 114 |
name = pd#name, |
| 115 |
description = pd#description, |
| 116 |
unit = pd#unit, |
| 117 |
minValue = pd#minValue, |
| 118 |
maxValue = pd#maxValue, |
| 119 |
defaultValue = pd#defaultValue, |
| 120 |
get quantize () = if pd#isQuantized then QuantizeStep pd#quantizeStep else Unquantized () fi, |
| 121 |
valueNames = map string pd#valueNames |
| 122 |
}; |
| 123 |
|
| 124 |
sampleType t rate is ~OutputDescriptor$SampleType -> number -> 'a = |
| 125 |
if t == OutputDescriptor$SampleType#OneSamplePerStep then |
| 126 |
OneSamplePerStep () |
| 127 |
elif t == OutputDescriptor$SampleType#FixedSampleRate then |
| 128 |
FixedSampleRate rate |
| 129 |
else |
| 130 |
VariableSampleRate rate |
| 131 |
fi; |
| 132 |
|
| 133 |
structureOf rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = |
| 134 |
(computes = case rdfOutputData of Some d: d.computes; None (): Unknown () esac; |
| 135 |
s = getSystemStore (); |
| 136 |
noteIRI = case s.expand "af:Note" of IRI iri: iri; _: "" esac; |
| 137 |
if od#hasFixedBinCount and od#binCount == 0 then |
| 138 |
Instants (); |
| 139 |
elif od#hasDuration then |
| 140 |
if computes != Unknown () then |
| 141 |
if computes == Event noteIRI then Notes (); |
| 142 |
else Regions (); |
| 143 |
fi |
| 144 |
elif od#hasFixedBinCount then |
| 145 |
if od#binCount > 1 then Notes (); |
| 146 |
elif od#unit == "Hz" or strIndexOf (strLower od#unit) "midi" 0 >= 0 then Notes (); |
| 147 |
else Regions (); |
| 148 |
fi |
| 149 |
else |
| 150 |
Unknown (); |
| 151 |
fi |
| 152 |
elif od#hasFixedBinCount and od#binCount == 1 then |
| 153 |
case computes of |
| 154 |
Event e: |
| 155 |
if strEnds? e "Segment" |
| 156 |
then Segmentation () |
| 157 |
else Curve () |
| 158 |
fi; |
| 159 |
_: |
| 160 |
if od#sampleType == OutputDescriptor$SampleType#OneSamplePerStep |
| 161 |
then Series () |
| 162 |
else Curve () |
| 163 |
fi; |
| 164 |
esac; |
| 165 |
elif od#hasFixedBinCount and |
| 166 |
od#sampleType != OutputDescriptor$SampleType#VariableSampleRate then |
| 167 |
Grid (); |
| 168 |
else |
| 169 |
Unknown (); |
| 170 |
fi); |
| 171 |
|
| 172 |
outputDescriptor rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = {
|
| 173 |
identifier = od#identifier, |
| 174 |
name = od#name, |
| 175 |
description = od#description, |
| 176 |
get binCount () = if od#hasFixedBinCount then Fixed od#binCount else Variable () fi, |
| 177 |
get valueExtents () = if od#hasKnownExtents then Known { min = od#minValue, max = od#maxValue } else Unknown () fi,
|
| 178 |
get valueQuantize () = if od#isQuantized then QuantizeStep od#quantizeStep else Unquantized () fi, |
| 179 |
valueUnit = od#unit, |
| 180 |
binNames = array (map string od#binNames), |
| 181 |
sampleType = sampleType od#sampleType od#sampleRate, |
| 182 |
hasDuration = od#hasDuration, |
| 183 |
computes is Event string | Feature string | Signal string | Unknown () = case rdfOutputData of Some data: data.computes; None (): Unknown () esac, |
| 184 |
get inferredStructure () = structureOf rdfOutputData od, |
| 185 |
}; |
| 186 |
|
| 187 |
plugin key p is string -> ~Plugin -> 'a = |
| 188 |
(rdfData = vamprdf.pluginDataByKey (getSystemStore ()) key; |
| 189 |
{
|
| 190 |
plugin = p, |
| 191 |
key, |
| 192 |
get apiVersion () = p#getVampApiVersion(), |
| 193 |
get identifier () = p#getIdentifier(), |
| 194 |
get name () = p#getName(), |
| 195 |
get description () = p#getDescription(), |
| 196 |
get maker () = p#getMaker(), |
| 197 |
get copyright () = p#getCopyright(), |
| 198 |
get version () = p#getPluginVersion(), |
| 199 |
get category () = PluginLoader#getInstance()#getPluginCategory(key), |
| 200 |
get hasRdfDescription () = (rdfData != None ()), |
| 201 |
get infoURL () = case rdfData of Some data: data.infoURL; None (): "" esac, |
| 202 |
get parameters () = array (map parameterDescriptor p#getParameterDescriptors()), |
| 203 |
parameterValue identifier = p#getParameter(identifier), |
| 204 |
setParameterValue identifier value = p#setParameter(identifier, value), |
| 205 |
get programs () = array (map string p#getPrograms()), |
| 206 |
get currentProgram () = p#getCurrentProgram(), |
| 207 |
selectProgram pr = p#selectProgram(pr), |
| 208 |
get inputDomain () = inputDomain p#getInputDomain(), |
| 209 |
get preferredBlockSize () = p#getPreferredBlockSize(), |
| 210 |
get preferredStepSize () = p#getPreferredStepSize(), |
| 211 |
get minChannelCount () = p#getMinChannelCount(), |
| 212 |
get maxChannelCount () = p#getMaxChannelCount(), |
| 213 |
initialise { channels, hop, blockSize } = p#initialise(channels, hop, blockSize),
|
| 214 |
reset () = p#reset(), |
| 215 |
get outputs () = |
| 216 |
array case rdfData of |
| 217 |
Some data: map2 outputDescriptor (map Some data.outputs) p#getOutputDescriptors(); |
| 218 |
None (): map (outputDescriptor (None ())) p#getOutputDescriptors(); |
| 219 |
esac, |
| 220 |
process frame time is 'a -> ~RealTime -> 'b = |
| 221 |
featureSet p#process((map vec.floats (mat.asRows frame)) as ~float[][], 0, time), |
| 222 |
getRemainingFeatures () = featureSet p#getRemainingFeatures(), |
| 223 |
dispose () = p#dispose(), |
| 224 |
}); |
| 225 |
|
| 226 |
featuresFromSet outputNo f = if outputNo in f then f[outputNo] else [] fi; |
| 227 |
|
| 228 |
outputNumberByName p name = |
| 229 |
(outputs = p.outputs; |
| 230 |
case find ((== name) . (.identifier)) outputs of |
| 231 |
first::rest: index first outputs; |
| 232 |
_: -1; |
| 233 |
esac); |
| 234 |
|
| 235 |
loadPlugin rate key = |
| 236 |
try |
| 237 |
OK (plugin key |
| 238 |
PluginLoader#getInstance()#loadPlugin(key, rate, |
| 239 |
PluginLoader$AdapterFlags#ADAPT_INPUT_DOMAIN + |
| 240 |
PluginLoader$AdapterFlags#ADAPT_CHANNEL_COUNT)) |
| 241 |
catch PluginLoader$LoadFailedException _: |
| 242 |
Error "Failed to load Vamp plugin with key \(key)" |
| 243 |
yrt; |
| 244 |
|
| 245 |
processed params frames count = |
| 246 |
(p = params.p; |
| 247 |
case frames of |
| 248 |
frame::rest: |
| 249 |
p.process frame RealTime#frame2RealTime(count, params.sampleRate) |
| 250 |
:. |
| 251 |
\(processed params rest (count + params.hop)); |
| 252 |
_: |
| 253 |
(rf = p.getRemainingFeatures (); |
| 254 |
p.dispose (); |
| 255 |
[rf]); |
| 256 |
esac); |
| 257 |
|
| 258 |
converted { p, sampleRate, hop } outputNo fl =
|
| 259 |
map (featuresFromSet outputNo) fl; |
| 260 |
|
| 261 |
returnErrorFrom p stream text = (p.dispose (); stream.close (); failWith text); |
| 262 |
|
| 263 |
processWith key p outputNo stream = |
| 264 |
(blockSize = |
| 265 |
if p.preferredBlockSize == 0 then 2048 |
| 266 |
else p.preferredBlockSize fi; |
| 267 |
stepSize = |
| 268 |
if p.preferredStepSize == 0 then |
| 269 |
if p.inputDomain == FrequencyDomain () then blockSize / 2 |
| 270 |
else blockSize fi; |
| 271 |
else p.preferredStepSize fi; |
| 272 |
channels = 1; |
| 273 |
params = {
|
| 274 |
p, |
| 275 |
sampleRate = stream.sampleRate, |
| 276 |
channels = 1, |
| 277 |
blockSize, |
| 278 |
hop = stepSize |
| 279 |
}; |
| 280 |
if p.initialise params then |
| 281 |
{
|
| 282 |
key, |
| 283 |
output = p.outputs[outputNo], |
| 284 |
parameters = mapIntoHash id p.parameterValue |
| 285 |
(map (.identifier) p.parameters), |
| 286 |
config = {
|
| 287 |
channels, blockSize, stepSize, |
| 288 |
sampleRate = stream.sampleRate |
| 289 |
}, |
| 290 |
features = converted params outputNo |
| 291 |
(processed params (fr.frames blockSize [ Hop stepSize ] stream) 0) |
| 292 |
}; |
| 293 |
// If processing completed successfully, then p is |
| 294 |
// disposed by processed and stream is closed by the |
| 295 |
// framer |
| 296 |
else |
| 297 |
returnErrorFrom p stream "Failed to initialise plugin \(key) with channels = \(channels), blockSize = \(blockSize), stepSize = \(stepSize)"; |
| 298 |
fi); |
| 299 |
|
| 300 |
processStream key output stream = |
| 301 |
case loadPlugin stream.sampleRate key of |
| 302 |
OK p: |
| 303 |
outputNo = outputNumberByName p output; |
| 304 |
if outputNo >= 0 then |
| 305 |
processWith key p outputNo stream |
| 306 |
else |
| 307 |
outputs = strJoin ", " (map (.identifier) p.outputs); |
| 308 |
returnErrorFrom p stream "Plugin \(key) has no output named \(output) (outputs are: \(outputs))" |
| 309 |
fi; |
| 310 |
Error e: failWith e; |
| 311 |
esac; |
| 312 |
|
| 313 |
processFile key output filename = |
| 314 |
processStream key output (af.open filename); |
| 315 |
|
| 316 |
processStreamStructured key output stream = |
| 317 |
vamppost.postprocess (processStream key output stream); |
| 318 |
|
| 319 |
processFileStructured key output filename = |
| 320 |
vamppost.postprocess (processFile key output filename); |
| 321 |
|
| 322 |
{
|
| 323 |
get pluginPath = getPluginPath, |
| 324 |
get pluginKeys = listPlugins, |
| 325 |
loadPlugin, |
| 326 |
categoryOf, |
| 327 |
processStream, |
| 328 |
processFile, |
| 329 |
processStreamStructured, |
| 330 |
processFileStructured, |
| 331 |
getKnownPluginKeys, |
| 332 |
getDataForKnownPlugin, |
| 333 |
} |
| 334 |
|