Chris@58: "use strict"; Chris@58: Chris@58: function note(blah) { Chris@58: console.log(blah); Chris@58: } Chris@58: Chris@59: if (process.argv.length < 3 || process.argv.length > 4) { Chris@59: note("\nUsage: " + process.argv[0] + " []"); Chris@59: note("e.g. " + process.argv[0] + " ./VampExamplePlugins.js"); Chris@58: note("e.g. " + process.argv[0] + " ./VampExamplePlugins.js vamp-example-plugins:zerocrossing"); Chris@59: throw "Wrong number of command-line args (1 or 2 expected)" Chris@58: } Chris@58: Chris@58: var libraryPath = process.argv[2]; Chris@59: Chris@59: var pluginKey = ""; Chris@59: if (process.argv.length > 3) { Chris@59: pluginKey = process.argv[3]; Chris@59: } Chris@58: Chris@58: var base64 = require("./base64"); Chris@58: Chris@58: note("Loading library \"" + libraryPath + "\"..."); Chris@58: var extractor = require(libraryPath); Chris@58: var extractorModule = extractor(); Chris@58: Chris@58: var piperRequestJson = extractorModule.cwrap( Chris@58: 'piperRequestJson', 'number', ['number'] Chris@58: ); Chris@58: Chris@58: var piperProcessRaw = extractorModule.cwrap( Chris@58: "piperProcessRaw", "number", ["number", "number", "number", "number"] Chris@58: ); Chris@58: Chris@58: var piperFreeJson = extractorModule.cwrap( Chris@58: 'piperFreeJson', 'void', ['number'] Chris@58: ); Chris@58: Chris@58: function processRaw(request) { Chris@58: Chris@58: const nChannels = request.processInput.inputBuffers.length; Chris@58: const nFrames = request.processInput.inputBuffers[0].length; Chris@58: Chris@58: const buffersPtr = extractorModule._malloc(nChannels * 4); Chris@58: const buffers = new Uint32Array( Chris@58: extractorModule.HEAPU8.buffer, buffersPtr, nChannels); Chris@58: Chris@58: for (let i = 0; i < nChannels; ++i) { Chris@58: const framesPtr = extractorModule._malloc(nFrames * 4); Chris@58: const frames = new Float32Array( Chris@58: extractorModule.HEAPU8.buffer, framesPtr, nFrames); Chris@58: frames.set(request.processInput.inputBuffers[i]); Chris@58: buffers[i] = framesPtr; Chris@58: } Chris@58: Chris@58: const responseJson = piperProcessRaw( Chris@58: request.handle, Chris@58: buffersPtr, Chris@58: request.processInput.timestamp.s, Chris@58: request.processInput.timestamp.n); Chris@58: Chris@58: for (let i = 0; i < nChannels; ++i) { Chris@58: extractorModule._free(buffers[i]); Chris@58: } Chris@58: extractorModule._free(buffersPtr); Chris@58: Chris@58: const responseJstr = extractorModule.Pointer_stringify(responseJson); Chris@58: const response = JSON.parse(responseJstr); Chris@58: Chris@58: piperFreeJson(responseJson); Chris@58: Chris@58: return response; Chris@58: } Chris@58: Chris@58: function makeTimestamp(seconds) { Chris@58: if (seconds >= 0.0) { Chris@58: return { Chris@58: s: Math.floor(seconds), Chris@58: n: Math.floor((seconds - Math.floor(seconds)) * 1e9 + 0.5) Chris@58: }; Chris@58: } else { Chris@58: const { s, n } = makeTimestamp(-seconds); Chris@58: return { s: -s, n: -n }; Chris@58: } Chris@58: } Chris@58: Chris@58: function frame2timestamp(frame, rate) { Chris@58: return makeTimestamp(frame / rate); Chris@58: } Chris@58: Chris@58: function request(req) { Chris@58: var jsonStr = JSON.stringify(req); Chris@58: var m = extractorModule; Chris@58: // Inspection reveals that intArrayFromString converts the string Chris@58: // from utf16 to utf8, which is what we want (though the docs Chris@58: // don't mention this). Note the *Cstr values are Emscripten heap Chris@58: // pointers Chris@58: let inCstr = m.allocate(m.intArrayFromString(jsonStr), 'i8', m.ALLOC_NORMAL); Chris@58: let outCstr = piperRequestJson(inCstr); Chris@58: m._free(inCstr); Chris@58: const responseJstr = m.Pointer_stringify(outCstr); Chris@58: const response = JSON.parse(responseJstr); Chris@58: piperFreeJson(outCstr); Chris@58: return response; Chris@58: } Chris@58: Chris@58: function myFromBase64(b64) { Chris@58: while (b64.length % 4 > 0) { b64 += "="; } Chris@58: let conv = new Float32Array(base64.toByteArray(b64).buffer); Chris@58: return conv; Chris@58: } Chris@58: Chris@58: function convertWireFeature(wfeature) { Chris@58: let out = {}; Chris@58: if (wfeature.timestamp != null) { Chris@58: out.timestamp = wfeature.timestamp; Chris@58: } Chris@58: if (wfeature.duration != null) { Chris@58: out.duration = wfeature.duration; Chris@58: } Chris@58: if (wfeature.label != null) { Chris@58: out.label = wfeature.label; Chris@58: } Chris@58: const vv = wfeature.featureValues; Chris@58: if (vv != null) { Chris@58: if (typeof vv === "string") { Chris@58: out.featureValues = myFromBase64(vv); Chris@58: } else { Chris@58: out.featureValues = new Float32Array(vv); Chris@58: } Chris@58: } Chris@58: return out; Chris@58: } Chris@58: Chris@58: function convertWireFeatureList(wfeatures) { Chris@58: return wfeatures.map(convertWireFeature); Chris@58: } Chris@58: Chris@58: function responseToFeatureSet(response) { Chris@58: const features = new Map(); Chris@58: const processResponse = response.result; Chris@58: const wireFeatures = processResponse.features; Chris@58: Object.keys(wireFeatures).forEach(key => { Chris@58: return features.set(key, convertWireFeatureList(wireFeatures[key])); Chris@58: }); Chris@58: return features; Chris@58: } Chris@58: Chris@59: function checkSuccess(response) { Chris@59: if (response.error) { Chris@59: console.log("Request type " + response.method + " failed: " + Chris@59: response.error.message); Chris@59: throw response.error.message; Chris@59: } Chris@59: } Chris@59: Chris@58: function test() { Chris@58: Chris@62: let start = (new Date()).getTime(); Chris@62: Chris@58: const rate = 44100; Chris@59: Chris@59: note("Listing plugins..."); Chris@59: let response = request({ Chris@59: method: "list" Chris@59: }); Chris@59: checkSuccess(response); Chris@59: Chris@59: if (pluginKey === "") { Chris@59: pluginKey = response.result.available[0].key; Chris@59: note("Loading first plugin \"" + pluginKey + "\"..."); Chris@59: } else { Chris@59: note("Loading requested plugin \"" + pluginKey + "\"..."); Chris@59: } Chris@58: Chris@59: response = request({ Chris@58: method: "load", Chris@58: params: { Chris@58: key: pluginKey, Chris@58: inputSampleRate: rate, Chris@58: adapterFlags: ["AdaptAllSafe"] Chris@58: } Chris@58: }); Chris@59: checkSuccess(response); Chris@58: Chris@59: const blockSize = response.result.defaultConfiguration.blockSize; Chris@59: const stepSize = response.result.defaultConfiguration.stepSize; Chris@58: Chris@58: response = request({ Chris@58: method: "configure", Chris@58: params: { Chris@58: handle: 1, Chris@58: configuration: { Chris@58: blockSize: blockSize, Chris@59: stepSize: stepSize, Chris@59: channelCount: 1 Chris@58: } Chris@58: } Chris@58: }); Chris@59: checkSuccess(response); Chris@58: Chris@58: const nblocks = 1000; Chris@58: Chris@58: const makeBlock = (n => { Chris@58: return { Chris@58: timestamp : frame2timestamp(n * blockSize, rate), Chris@58: inputBuffers : [ Chris@58: new Float32Array(Array.from(Array(blockSize).keys(), Chris@58: n => n / blockSize)) Chris@58: ], Chris@58: } Chris@58: }); Chris@58: Chris@58: const blocks = Array.from(Array(nblocks).keys(), makeBlock); Chris@58: Chris@58: note("Now processing " + nblocks + " blocks of 1024 samples each..."); Chris@58: Chris@58: let featureCount = 0; Chris@58: Chris@58: for (let i = 0; i < nblocks; ++i) { Chris@58: response = processRaw({ Chris@58: "handle": 1, Chris@58: "processInput": blocks[i] Chris@58: }); Chris@58: let features = responseToFeatureSet(response); Chris@58: for (let featureList of features.values()) { Chris@58: featureCount += featureList.length; Chris@58: } Chris@58: } Chris@58: Chris@58: note("Cleaning up the plugin and getting any remaining features..."); Chris@58: response = request({ Chris@58: method: "finish", Chris@58: params: { Chris@58: handle: 1 Chris@58: } Chris@58: }); Chris@59: checkSuccess(response); Chris@58: Chris@58: let features = responseToFeatureSet(response); Chris@58: for (let featureList of features.values()) { Chris@58: featureCount += featureList.length; Chris@58: } Chris@58: Chris@58: note("Done, total number of features across all outputs = " + featureCount); Chris@62: Chris@62: let finish = (new Date()).getTime(); Chris@62: note("Total time taken " + (finish - start) + " ms"); Chris@58: } Chris@58: Chris@58: test(); Chris@58: