annotate test/node-load-test.js @ 169:9c746a913d7f

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