Mercurial > hg > piper-vamp-js
changeset 58:f6220d293bff
Simple test that can be run with any library name and plugin key
author | Chris Cannam |
---|---|
date | Thu, 10 Nov 2016 15:07:24 +0000 |
parents | 10d4f117a9a8 |
children | a1eb63b9ba6f c5c280791042 |
files | test/node-load-test.js |
diffstat | 1 files changed, 219 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/node-load-test.js Thu Nov 10 15:07:24 2016 +0000 @@ -0,0 +1,219 @@ +"use strict"; + +function note(blah) { + console.log(blah); +} + +if (process.argv.length < 4) { + note("\nUsage: " + process.argv[0] + " <LibraryPath> <pluginKey>"); + note("e.g. " + process.argv[0] + " ./VampExamplePlugins.js vamp-example-plugins:zerocrossing"); + throw "Wrong number of command-line args (2 expected)" +} + +var libraryPath = process.argv[2]; +var pluginKey = process.argv[3]; + +var base64 = require("./base64"); + +note("Loading library \"" + libraryPath + "\"..."); +var extractor = require(libraryPath); +var extractorModule = extractor(); + +var piperRequestJson = extractorModule.cwrap( + 'piperRequestJson', 'number', ['number'] +); + +var piperProcessRaw = extractorModule.cwrap( + "piperProcessRaw", "number", ["number", "number", "number", "number"] +); + +var piperFreeJson = extractorModule.cwrap( + 'piperFreeJson', 'void', ['number'] +); + +function processRaw(request) { + + const nChannels = request.processInput.inputBuffers.length; + const nFrames = request.processInput.inputBuffers[0].length; + + const buffersPtr = extractorModule._malloc(nChannels * 4); + const buffers = new Uint32Array( + extractorModule.HEAPU8.buffer, buffersPtr, nChannels); + + for (let i = 0; i < nChannels; ++i) { + const framesPtr = extractorModule._malloc(nFrames * 4); + const frames = new Float32Array( + extractorModule.HEAPU8.buffer, framesPtr, nFrames); + frames.set(request.processInput.inputBuffers[i]); + buffers[i] = framesPtr; + } + + const responseJson = piperProcessRaw( + request.handle, + buffersPtr, + request.processInput.timestamp.s, + request.processInput.timestamp.n); + + for (let i = 0; i < nChannels; ++i) { + extractorModule._free(buffers[i]); + } + extractorModule._free(buffersPtr); + + const responseJstr = extractorModule.Pointer_stringify(responseJson); + const response = JSON.parse(responseJstr); + + piperFreeJson(responseJson); + + return response; +} + +function makeTimestamp(seconds) { + if (seconds >= 0.0) { + return { + s: Math.floor(seconds), + n: Math.floor((seconds - Math.floor(seconds)) * 1e9 + 0.5) + }; + } else { + const { s, n } = makeTimestamp(-seconds); + return { s: -s, n: -n }; + } +} + +function frame2timestamp(frame, rate) { + return makeTimestamp(frame / rate); +} + +function request(req) { + var jsonStr = JSON.stringify(req); + var m = extractorModule; + // Inspection reveals that intArrayFromString converts the string + // from utf16 to utf8, which is what we want (though the docs + // don't mention this). Note the *Cstr values are Emscripten heap + // pointers + let inCstr = m.allocate(m.intArrayFromString(jsonStr), 'i8', m.ALLOC_NORMAL); + let outCstr = piperRequestJson(inCstr); + m._free(inCstr); + const responseJstr = m.Pointer_stringify(outCstr); + const response = JSON.parse(responseJstr); + piperFreeJson(outCstr); + return response; +} + +function myFromBase64(b64) { + while (b64.length % 4 > 0) { b64 += "="; } + let conv = new Float32Array(base64.toByteArray(b64).buffer); + return conv; +} + +function convertWireFeature(wfeature) { + let out = {}; + if (wfeature.timestamp != null) { + out.timestamp = wfeature.timestamp; + } + if (wfeature.duration != null) { + out.duration = wfeature.duration; + } + if (wfeature.label != null) { + out.label = wfeature.label; + } + const vv = wfeature.featureValues; + if (vv != null) { + if (typeof vv === "string") { + out.featureValues = myFromBase64(vv); + } else { + out.featureValues = new Float32Array(vv); + } + } + return out; +} + +function convertWireFeatureList(wfeatures) { + return wfeatures.map(convertWireFeature); +} + +function responseToFeatureSet(response) { + const features = new Map(); + const processResponse = response.result; + const wireFeatures = processResponse.features; + Object.keys(wireFeatures).forEach(key => { + return features.set(key, convertWireFeatureList(wireFeatures[key])); + }); + return features; +} + +function test() { + + const rate = 44100; + + note("Loading plugin \"" + pluginKey + "\"..."); + let response = request({ + method: "load", + params: { + key: pluginKey, + inputSampleRate: rate, + adapterFlags: ["AdaptAllSafe"] + } + }); + + const blockSize = 1024; + + response = request({ + method: "configure", + params: { + handle: 1, + configuration: { + blockSize: blockSize, + channelCount: 1, + stepSize: blockSize + } + } + }); + + const nblocks = 1000; + + const makeBlock = (n => { + return { + timestamp : frame2timestamp(n * blockSize, rate), + inputBuffers : [ + new Float32Array(Array.from(Array(blockSize).keys(), + n => n / blockSize)) + ], + } + }); + + const blocks = Array.from(Array(nblocks).keys(), makeBlock); + + note("Now processing " + nblocks + " blocks of 1024 samples each..."); + + let featureCount = 0; + + for (let i = 0; i < nblocks; ++i) { + response = processRaw({ + "handle": 1, + "processInput": blocks[i] + }); + let features = responseToFeatureSet(response); + for (let featureList of features.values()) { + featureCount += featureList.length; + } + console.log(i); + } + + note("Cleaning up the plugin and getting any remaining features..."); + response = request({ + method: "finish", + params: { + handle: 1 + } + }); + + let features = responseToFeatureSet(response); + for (let featureList of features.values()) { + featureCount += featureList.length; + } + + note("Done, total number of features across all outputs = " + featureCount); +} + +test(); +