annotate test/node-load-test.js @ 66:08d80862b69c

-ffast-math is not a great idea as a default flag, because some plugins won't work correctly with it. Also allow people to override these
author Chris Cannam
date Sat, 12 Nov 2016 09:58:24 +0000
parents 1cde1f236634
children 4b593b643918
rev   line source
Chris@58 1 "use strict";
Chris@58 2
Chris@58 3 function note(blah) {
Chris@58 4 console.log(blah);
Chris@58 5 }
Chris@58 6
Chris@59 7 if (process.argv.length < 3 || process.argv.length > 4) {
Chris@59 8 note("\nUsage: " + process.argv[0] + " <librarypath> [<pluginkey>]");
Chris@59 9 note("e.g. " + process.argv[0] + " ./VampExamplePlugins.js");
Chris@58 10 note("e.g. " + process.argv[0] + " ./VampExamplePlugins.js vamp-example-plugins:zerocrossing");
Chris@59 11 throw "Wrong number of command-line args (1 or 2 expected)"
Chris@58 12 }
Chris@58 13
Chris@58 14 var libraryPath = process.argv[2];
Chris@59 15
Chris@59 16 var pluginKey = "";
Chris@59 17 if (process.argv.length > 3) {
Chris@59 18 pluginKey = process.argv[3];
Chris@59 19 }
Chris@58 20
Chris@58 21 var base64 = require("./base64");
Chris@58 22
Chris@58 23 note("Loading library \"" + libraryPath + "\"...");
Chris@58 24 var extractor = require(libraryPath);
Chris@58 25 var extractorModule = extractor();
Chris@58 26
Chris@58 27 var piperRequestJson = extractorModule.cwrap(
Chris@58 28 'piperRequestJson', 'number', ['number']
Chris@58 29 );
Chris@58 30
Chris@58 31 var piperProcessRaw = extractorModule.cwrap(
Chris@58 32 "piperProcessRaw", "number", ["number", "number", "number", "number"]
Chris@58 33 );
Chris@58 34
Chris@58 35 var piperFreeJson = extractorModule.cwrap(
Chris@58 36 'piperFreeJson', 'void', ['number']
Chris@58 37 );
Chris@58 38
Chris@58 39 function processRaw(request) {
Chris@58 40
Chris@58 41 const nChannels = request.processInput.inputBuffers.length;
Chris@58 42 const nFrames = request.processInput.inputBuffers[0].length;
Chris@58 43
Chris@58 44 const buffersPtr = extractorModule._malloc(nChannels * 4);
Chris@58 45 const buffers = new Uint32Array(
Chris@58 46 extractorModule.HEAPU8.buffer, buffersPtr, nChannels);
Chris@58 47
Chris@58 48 for (let i = 0; i < nChannels; ++i) {
Chris@58 49 const framesPtr = extractorModule._malloc(nFrames * 4);
Chris@58 50 const frames = new Float32Array(
Chris@58 51 extractorModule.HEAPU8.buffer, framesPtr, nFrames);
Chris@58 52 frames.set(request.processInput.inputBuffers[i]);
Chris@58 53 buffers[i] = framesPtr;
Chris@58 54 }
Chris@58 55
Chris@58 56 const responseJson = piperProcessRaw(
Chris@58 57 request.handle,
Chris@58 58 buffersPtr,
Chris@58 59 request.processInput.timestamp.s,
Chris@58 60 request.processInput.timestamp.n);
Chris@58 61
Chris@58 62 for (let i = 0; i < nChannels; ++i) {
Chris@58 63 extractorModule._free(buffers[i]);
Chris@58 64 }
Chris@58 65 extractorModule._free(buffersPtr);
Chris@58 66
Chris@58 67 const responseJstr = extractorModule.Pointer_stringify(responseJson);
Chris@58 68 const response = JSON.parse(responseJstr);
Chris@58 69
Chris@58 70 piperFreeJson(responseJson);
Chris@58 71
Chris@58 72 return response;
Chris@58 73 }
Chris@58 74
Chris@58 75 function makeTimestamp(seconds) {
Chris@58 76 if (seconds >= 0.0) {
Chris@58 77 return {
Chris@58 78 s: Math.floor(seconds),
Chris@58 79 n: Math.floor((seconds - Math.floor(seconds)) * 1e9 + 0.5)
Chris@58 80 };
Chris@58 81 } else {
Chris@58 82 const { s, n } = makeTimestamp(-seconds);
Chris@58 83 return { s: -s, n: -n };
Chris@58 84 }
Chris@58 85 }
Chris@58 86
Chris@58 87 function frame2timestamp(frame, rate) {
Chris@58 88 return makeTimestamp(frame / rate);
Chris@58 89 }
Chris@58 90
Chris@58 91 function request(req) {
Chris@58 92 var jsonStr = JSON.stringify(req);
Chris@58 93 var m = extractorModule;
Chris@58 94 // Inspection reveals that intArrayFromString converts the string
Chris@58 95 // from utf16 to utf8, which is what we want (though the docs
Chris@58 96 // don't mention this). Note the *Cstr values are Emscripten heap
Chris@58 97 // pointers
Chris@58 98 let inCstr = m.allocate(m.intArrayFromString(jsonStr), 'i8', m.ALLOC_NORMAL);
Chris@58 99 let outCstr = piperRequestJson(inCstr);
Chris@58 100 m._free(inCstr);
Chris@58 101 const responseJstr = m.Pointer_stringify(outCstr);
Chris@58 102 const response = JSON.parse(responseJstr);
Chris@58 103 piperFreeJson(outCstr);
Chris@58 104 return response;
Chris@58 105 }
Chris@58 106
Chris@58 107 function myFromBase64(b64) {
Chris@58 108 while (b64.length % 4 > 0) { b64 += "="; }
Chris@58 109 let conv = new Float32Array(base64.toByteArray(b64).buffer);
Chris@58 110 return conv;
Chris@58 111 }
Chris@58 112
Chris@58 113 function convertWireFeature(wfeature) {
Chris@58 114 let out = {};
Chris@58 115 if (wfeature.timestamp != null) {
Chris@58 116 out.timestamp = wfeature.timestamp;
Chris@58 117 }
Chris@58 118 if (wfeature.duration != null) {
Chris@58 119 out.duration = wfeature.duration;
Chris@58 120 }
Chris@58 121 if (wfeature.label != null) {
Chris@58 122 out.label = wfeature.label;
Chris@58 123 }
Chris@58 124 const vv = wfeature.featureValues;
Chris@58 125 if (vv != null) {
Chris@58 126 if (typeof vv === "string") {
Chris@58 127 out.featureValues = myFromBase64(vv);
Chris@58 128 } else {
Chris@58 129 out.featureValues = new Float32Array(vv);
Chris@58 130 }
Chris@58 131 }
Chris@58 132 return out;
Chris@58 133 }
Chris@58 134
Chris@58 135 function convertWireFeatureList(wfeatures) {
Chris@58 136 return wfeatures.map(convertWireFeature);
Chris@58 137 }
Chris@58 138
Chris@58 139 function responseToFeatureSet(response) {
Chris@58 140 const features = new Map();
Chris@58 141 const processResponse = response.result;
Chris@58 142 const wireFeatures = processResponse.features;
Chris@58 143 Object.keys(wireFeatures).forEach(key => {
Chris@58 144 return features.set(key, convertWireFeatureList(wireFeatures[key]));
Chris@58 145 });
Chris@58 146 return features;
Chris@58 147 }
Chris@58 148
Chris@59 149 function checkSuccess(response) {
Chris@59 150 if (response.error) {
Chris@59 151 console.log("Request type " + response.method + " failed: " +
Chris@59 152 response.error.message);
Chris@59 153 throw response.error.message;
Chris@59 154 }
Chris@59 155 }
Chris@59 156
Chris@58 157 function test() {
Chris@58 158
Chris@62 159 let start = (new Date()).getTime();
Chris@62 160
Chris@58 161 const rate = 44100;
Chris@59 162
Chris@59 163 note("Listing plugins...");
Chris@59 164 let response = request({
Chris@59 165 method: "list"
Chris@59 166 });
Chris@59 167 checkSuccess(response);
Chris@59 168
Chris@59 169 if (pluginKey === "") {
Chris@59 170 pluginKey = response.result.available[0].key;
Chris@59 171 note("Loading first plugin \"" + pluginKey + "\"...");
Chris@59 172 } else {
Chris@59 173 note("Loading requested plugin \"" + pluginKey + "\"...");
Chris@59 174 }
Chris@58 175
Chris@59 176 response = request({
Chris@58 177 method: "load",
Chris@58 178 params: {
Chris@58 179 key: pluginKey,
Chris@58 180 inputSampleRate: rate,
Chris@58 181 adapterFlags: ["AdaptAllSafe"]
Chris@58 182 }
Chris@58 183 });
Chris@59 184 checkSuccess(response);
Chris@58 185
Chris@59 186 const blockSize = response.result.defaultConfiguration.blockSize;
Chris@59 187 const stepSize = response.result.defaultConfiguration.stepSize;
Chris@58 188
Chris@58 189 response = request({
Chris@58 190 method: "configure",
Chris@58 191 params: {
Chris@58 192 handle: 1,
Chris@58 193 configuration: {
Chris@58 194 blockSize: blockSize,
Chris@59 195 stepSize: stepSize,
Chris@59 196 channelCount: 1
Chris@58 197 }
Chris@58 198 }
Chris@58 199 });
Chris@59 200 checkSuccess(response);
Chris@58 201
Chris@58 202 const nblocks = 1000;
Chris@58 203
Chris@58 204 const makeBlock = (n => {
Chris@58 205 return {
Chris@58 206 timestamp : frame2timestamp(n * blockSize, rate),
Chris@58 207 inputBuffers : [
Chris@58 208 new Float32Array(Array.from(Array(blockSize).keys(),
Chris@58 209 n => n / blockSize))
Chris@58 210 ],
Chris@58 211 }
Chris@58 212 });
Chris@58 213
Chris@58 214 const blocks = Array.from(Array(nblocks).keys(), makeBlock);
Chris@58 215
Chris@58 216 note("Now processing " + nblocks + " blocks of 1024 samples each...");
Chris@58 217
Chris@58 218 let featureCount = 0;
Chris@58 219
Chris@58 220 for (let i = 0; i < nblocks; ++i) {
Chris@58 221 response = processRaw({
Chris@58 222 "handle": 1,
Chris@58 223 "processInput": blocks[i]
Chris@58 224 });
Chris@58 225 let features = responseToFeatureSet(response);
Chris@58 226 for (let featureList of features.values()) {
Chris@58 227 featureCount += featureList.length;
Chris@58 228 }
Chris@58 229 }
Chris@58 230
Chris@58 231 note("Cleaning up the plugin and getting any remaining features...");
Chris@58 232 response = request({
Chris@58 233 method: "finish",
Chris@58 234 params: {
Chris@58 235 handle: 1
Chris@58 236 }
Chris@58 237 });
Chris@59 238 checkSuccess(response);
Chris@58 239
Chris@58 240 let features = responseToFeatureSet(response);
Chris@58 241 for (let featureList of features.values()) {
Chris@58 242 featureCount += featureList.length;
Chris@58 243 }
Chris@58 244
Chris@58 245 note("Done, total number of features across all outputs = " + featureCount);
Chris@62 246
Chris@62 247 let finish = (new Date()).getTime();
Chris@62 248 note("Total time taken " + (finish - start) + " ms");
Chris@58 249 }
Chris@58 250
Chris@58 251 test();
Chris@58 252