Mercurial > hg > may
view yetilab/vamp/vamp.yeti @ 218:a7f4eb1cdd72 matrix_opaque_immutable
More block -> vector
author | Chris Cannam |
---|---|
date | Sat, 11 May 2013 12:04:05 +0100 |
parents | 26111c11d8e4 |
children | 937f908cae52 |
line wrap: on
line source
module yetilab.vamp.vamp; import org.vamp_plugins: Plugin, Plugin$InputDomain, PluginLoader, PluginLoader$AdapterFlags, PluginLoader$LoadFailedException, ParameterDescriptor, OutputDescriptor, OutputDescriptor$SampleType, RealTime, Feature; import java.lang: UnsatisfiedLinkError; import java.util: Map, List; vec = load yetilab.block.vector; fr = load yetilab.stream.framer; af = load yetilab.stream.audiofile; mat = load yetilab.matrix.matrix; vamprdf = load yetilab.vamp.vamprdf; vamppost = load yetilab.vamp.vamppost; store = load yertle.store; realTime r is ~RealTime -> number = r#sec() + (r#nsec() / 1000000000); feature f is ~Feature -> 'a = { timestamp = if f#hasTimestamp then Time (realTime f#timestamp) else Untimed () fi, duration = if f#hasDuration then Time (realTime f#duration) else Untimed () fi, values = vec.fromFloats f#values, label = f#label, }; featureList fl is ~Object -> 'a = if nullptr? fl then [] else a = fl unsafely_as ~List; result = array []; itr = a#iterator(); itr#hasNext() loop (push result (feature (itr#next() unsafely_as ~Feature))); list result fi; featureSet fs is ~Map -> 'a = (numberOf n is ~Object -> number = (n unsafely_as ~Integer)#intValue(); s = [:]; kk = list fs#keySet()#toArray(); for kk do k: s[numberOf k] := featureList fs#get(k) done; s); stores = [:]; getSingletonStoreFor loader = synchronized stores do: if loader in stores then stores[loader] else s = store.newRdfStore (); loader s; stores[loader] := s; s; fi done; getSystemStore () = getSingletonStoreFor vamprdf.loadSystemVampRdf; getGlobalStore () = getSingletonStoreFor vamprdf.loadGlobalVampRdf; getPluginPath () = (try map string PluginLoader#getInstance()#getPluginPath(); catch UnsatisfiedLinkError e: eprintln "Warning: Unable to obtain plugin path:\n\(e)"; []; yrt); listPlugins () = (try map string PluginLoader#getInstance()#listPlugins(); catch UnsatisfiedLinkError e: eprintln "Warning: Unable to obtain plugin list:\n\(e)"; []; yrt); getKnownPluginKeys () = (store = getGlobalStore (); nodes = vamprdf.allPluginNodes store; // ordering is random out of the store; might as well sort sort (map do n: (vamprdf.pluginDataByNode store n).pluginKey done nodes)); getDataForKnownPlugin key = vamprdf.pluginDataByKey (getGlobalStore ()) key; categoryOf key = list PluginLoader#getInstance()#getPluginCategory(key); inputDomain d is ~Plugin$InputDomain -> 'a = if d == Plugin$InputDomain#FREQUENCY_DOMAIN then FrequencyDomain () else TimeDomain () fi; parameterDescriptor pd is ~ParameterDescriptor -> 'a = { identifier = pd#identifier, name = pd#name, description = pd#description, unit = pd#unit, minValue = pd#minValue, maxValue = pd#maxValue, defaultValue = pd#defaultValue, get quantize () = if pd#isQuantized then QuantizeStep pd#quantizeStep else Unquantized () fi, valueNames = map string pd#valueNames }; sampleType t rate is ~OutputDescriptor$SampleType -> number -> 'a = if t == OutputDescriptor$SampleType#OneSamplePerStep then OneSamplePerStep () elif t == OutputDescriptor$SampleType#FixedSampleRate then FixedSampleRate rate else VariableSampleRate rate fi; structureOf rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = (computes = case rdfOutputData of Some d: d.computes; None (): Unknown () esac; s = getSystemStore (); noteIRI = case s.expand "af:Note" of IRI iri: iri; _: "" esac; if od#hasFixedBinCount and od#binCount == 0 then Instants (); elif od#hasDuration then if computes != Unknown () then if computes == Event noteIRI then Notes (); else Regions (); fi elif od#hasFixedBinCount then if od#binCount > 1 then Notes (); elif od#unit == "Hz" or strIndexOf (strLower od#unit) "midi" 0 >= 0 then Notes (); else Regions (); fi else Unknown (); fi elif od#hasFixedBinCount and od#binCount == 1 then case computes of Event e: if strEnds? e "Segment" then Segmentation () else Curve () fi; _: if od#sampleType == OutputDescriptor$SampleType#OneSamplePerStep then Series () else Curve () fi; esac; elif od#hasFixedBinCount and od#sampleType != OutputDescriptor$SampleType#VariableSampleRate then Grid (); else Unknown (); fi); outputDescriptor rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = { identifier = od#identifier, name = od#name, description = od#description, get binCount () = if od#hasFixedBinCount then Fixed od#binCount else Variable () fi, get valueExtents () = if od#hasKnownExtents then Known { min = od#minValue, max = od#maxValue } else Unknown () fi, get valueQuantize () = if od#isQuantized then QuantizeStep od#quantizeStep else Unquantized () fi, valueUnit = od#unit, binNames = array (map string od#binNames), sampleType = sampleType od#sampleType od#sampleRate, hasDuration = od#hasDuration, get computes () = case rdfOutputData of Some data: data.computes; None (): Unknown () esac, get inferredStructure () = structureOf rdfOutputData od, }; plugin key p is string -> ~Plugin -> 'a = (rdfData = vamprdf.pluginDataByKey (getSystemStore ()) key; { plugin = p, key, get apiVersion () = p#getVampApiVersion(), get identifier () = p#getIdentifier(), get name () = p#getName(), get description () = p#getDescription(), get maker () = p#getMaker(), get copyright () = p#getCopyright(), get version () = p#getPluginVersion(), get category () = PluginLoader#getInstance()#getPluginCategory(key), get hasRdfDescription () = (rdfData != None ()), get infoURL () = case rdfData of Some data: data.infoURL; None (): "" esac, get parameters () = array (map parameterDescriptor p#getParameterDescriptors()), parameterValue identifier = p#getParameter(identifier), setParameterValue identifier value = p#setParameter(identifier, value), get programs () = array (map string p#getPrograms()), get currentProgram () = p#getCurrentProgram(), selectProgram pr = p#selectProgram(pr), get inputDomain () = inputDomain p#getInputDomain(), get preferredBlockSize () = p#getPreferredBlockSize(), get preferredStepSize () = p#getPreferredStepSize(), get minChannelCount () = p#getMinChannelCount(), get maxChannelCount () = p#getMaxChannelCount(), initialise { channels, hop, blockSize } = p#initialise(channels, hop, blockSize), reset () = p#reset(), get outputs () = array case rdfData of Some data: map2 outputDescriptor (map Some data.outputs) p#getOutputDescriptors(); None (): map (outputDescriptor (None ())) p#getOutputDescriptors(); esac, process frame time is 'a -> ~RealTime -> 'b = featureSet p#process((map vec.floats (mat.asRows frame)) as ~float[][], 0, time), getRemainingFeatures () = featureSet p#getRemainingFeatures(), dispose () = p#dispose(), }); featuresFromSet outputNo f = if outputNo in f then f[outputNo] else [] fi; outputNumberByName p name = (outputs = p.outputs; case find ((== name) . (.identifier)) outputs of first::rest: index first outputs; _: -1; esac); loadPlugin rate key = try OK (plugin key PluginLoader#getInstance()#loadPlugin(key, rate, PluginLoader$AdapterFlags#ADAPT_INPUT_DOMAIN + PluginLoader$AdapterFlags#ADAPT_CHANNEL_COUNT)) catch PluginLoader$LoadFailedException _: Error "Failed to load Vamp plugin with key \(key)" yrt; //!!! bring block typedef into scope -- this shouldn't be necessary, //but see comment in processed below load yetilab.block.blocktype; processed { p, sampleRate, hop } frames count // I don't know why this type declaration is necessary. Without // it, yeti records the return type as 'a and can't do anything // useful with it (giving IncompatibleClassChangeError when // e.g. accessing the values array) is 'a -> 'b -> 'c -> list<hash<number, list<{ timestamp is Time number | Untimed (), duration is Time number | Untimed (), label is string, values is block }>>> = case frames of frame::rest: p.process frame RealTime#frame2RealTime(count, sampleRate) :. \(processed { p, sampleRate, hop } rest (count + hop)); _: (rf = p.getRemainingFeatures (); p.dispose (); [rf]); esac; converted { p, sampleRate, hop } outputNo fl = map (featuresFromSet outputNo) fl; returnErrorFrom p stream text = (p.dispose (); stream.close (); failWith text); processWith key p outputNo stream = (blockSize = if p.preferredBlockSize == 0 then 2048 else p.preferredBlockSize fi; stepSize = if p.preferredStepSize == 0 then if p.inputDomain == FrequencyDomain () then blockSize / 2 else blockSize fi; else p.preferredStepSize fi; channels = 1; params = { p, sampleRate = stream.sampleRate, channels = 1, framesize = blockSize, blockSize, hop = stepSize }; if p.initialise params then { key = key, output = p.outputs[outputNo], parameters = mapIntoHash id p.parameterValue (map (.identifier) p.parameters), config = { channels, blockSize, stepSize, sampleRate = stream.sampleRate }, features = converted params outputNo (processed params (fr.frames params stream) 0) }; // If processing completed successfully, then p is // disposed by processed and stream is closed by the // framer else returnErrorFrom p stream "Failed to initialise plugin \(key) with channels = \(channels), blockSize = \(blockSize), stepSize = \(stepSize)"; fi); processStream key output stream = case loadPlugin stream.sampleRate key of OK p: outputNo = outputNumberByName p output; if outputNo >= 0 then processWith key p outputNo stream else outputs = strJoin ", " (map (.identifier) p.outputs); returnErrorFrom p stream "Plugin \(key) has no output named \(output) (outputs are: \(outputs))" fi; Error e: failWith e; esac; processFile key output filename = processStream key output (af.open filename); processStreamStructured key output filename = vamppost.postprocess (processStream key output filename); processFileStructured key output filename = vamppost.postprocess (processFile key output filename); { get pluginPath = getPluginPath, get pluginKeys = listPlugins, loadPlugin, categoryOf, processStream, processFile, processStreamStructured, processFileStructured, getKnownPluginKeys, getDataForKnownPlugin, }