c@103: "use strict"; c@103: c@103: var VampExamplePlugins = require("./VampExamplePlugins"); c@103: var exampleModule = VampExamplePlugins(); c@103: c@103: // It is possible to declare both parameters and return values as c@103: // "string", in which case Emscripten will take care of c@103: // conversions. But it's not clear how one would manage memory for c@103: // newly-constructed returned C strings -- the returned pointer from c@103: // vampipeRequestJson would appear (?) to be thrown away by the c@103: // Emscripten string converter if we declare it as returning a string, c@103: // so we have no opportunity to pass it to vampipeFreeJson, which c@103: // suggests this would leak memory if the string isn't static. Not c@103: // wholly sure though. Anyway, passing and returning pointers (as c@103: // numbers) means we can manage the Emscripten heap memory however we c@103: // want in our request wrapper function below. c@103: c@103: var vampipeRequestJson = exampleModule.cwrap( c@103: 'vampipeRequestJson', 'number', ['number'] c@103: ); c@103: c@103: var vampipeProcessRaw = exampleModule.cwrap( c@103: "vampipeProcessRaw", "number", ["number", "number", "number", "number"] c@103: ); c@103: c@103: var vampipeFreeJson = exampleModule.cwrap( c@103: 'vampipeFreeJson', 'void', ['number'] c@103: ); c@103: c@103: function note(blah) { c@103: console.log(blah); c@103: } c@103: c@103: function comment(blah) { c@103: console.log(blah); c@103: } c@103: c@103: function processRaw(request) { c@103: c@103: const nChannels = request.processInput.inputBuffers.length; c@103: const nFrames = request.processInput.inputBuffers[0].values.length; c@103: c@103: const buffersPtr = exampleModule._malloc(nChannels * 4); c@103: const buffers = new Uint32Array( c@103: exampleModule.HEAPU8.buffer, buffersPtr, nChannels); c@103: c@103: for (let i = 0; i < nChannels; ++i) { c@103: const framesPtr = exampleModule._malloc(nFrames * 4); c@103: const frames = new Float32Array( c@103: exampleModule.HEAPU8.buffer, framesPtr, nFrames); c@103: frames.set(request.processInput.inputBuffers[i].values); c@103: buffers[i] = framesPtr; c@103: } c@103: c@103: const responseJson = vampipeProcessRaw( c@103: request.pluginHandle, c@103: buffersPtr, c@103: request.processInput.timestamp.s, c@103: request.processInput.timestamp.n); c@103: c@103: for (let i = 0; i < nChannels; ++i) { c@103: exampleModule._free(buffers[i]); c@103: } c@103: exampleModule._free(buffersPtr); c@103: c@103: const response = JSON.parse( c@103: exampleModule.Pointer_stringify(responseJson)); c@103: c@103: vampipeFreeJson(responseJson); c@103: c@103: return response; c@103: } c@103: c@103: function request(jsonStr) { c@103: note("Request JSON = " + jsonStr); c@103: var m = exampleModule; c@103: // Inspection reveals that intArrayFromString converts the string c@103: // from utf16 to utf8, which is what we want (though the docs c@103: // don't mention this). Note the *Cstr values are Emscripten heap c@103: // pointers c@103: var inCstr = m.allocate(m.intArrayFromString(jsonStr), 'i8', m.ALLOC_NORMAL); c@103: var outCstr = vampipeRequestJson(inCstr); c@103: m._free(inCstr); c@103: var result = m.Pointer_stringify(outCstr); c@103: vampipeFreeJson(outCstr); c@103: note("Returned JSON = " + result); c@103: return result; c@103: } c@103: c@103: function test() { c@103: c@103: comment("Loading zero crossings plugin..."); c@103: let result = request('{"type":"load","content": {"pluginKey":"vamp-example-plugins:zerocrossing","inputSampleRate":44100,"adapterFlags":["AdaptAllSafe"]}}'); c@103: c@103: const blockSize = 1024; c@103: c@103: result = request('{"type":"configure","content":{"pluginHandle":1,"configuration":{"blockSize": ' + blockSize + ', "channelCount": 1, "stepSize": ' + blockSize + '}}}'); c@103: c@103: const nblocks = 1000; c@103: c@103: let processInputBuffers = [new Float32Array( c@103: Array.from(Array(blockSize).keys(), n => n / blockSize)) c@103: ]; c@103: c@103: comment("Now processing " + nblocks + " blocks of 1024 samples each..."); c@103: c@103: let start = (new Date()).getTime(); c@103: comment("Start at " + start); c@103: c@103: for (let i = 0; i < nblocks; ++i) { c@103: let ts = { "s": i, "n": 0 }; // wholly bogus, but ZC plugin doesn't use it c@103: result = processRaw({ c@103: "pluginHandle": 1, c@103: "processInput": { c@103: "timestamp": ts, c@103: "inputBuffers": processInputBuffers c@103: } c@103: }); c@103: } c@103: c@103: let finish = (new Date()).getTime(); c@103: comment("Finish at " + finish + " for a time of " + (finish - start) + " ms"); c@103: c@103: comment("Again..."); c@103: c@103: start = (new Date()).getTime(); c@103: comment("Start at " + start); c@103: c@103: for (let i = 0; i < nblocks; ++i) { c@103: let ts = { "s": i, "n": 0 }; // wholly bogus, but ZC plugin doesn't use it c@103: result = processRaw({ c@103: "pluginHandle": 1, c@103: "processInput": { c@103: "timestamp": ts, c@103: "inputBuffers": processInputBuffers c@103: } c@103: }); c@103: } c@103: c@103: finish = (new Date()).getTime(); c@103: comment("Finish at " + finish + " for a time of " + (finish - start) + " ms"); c@103: c@103: comment("Cleaning up the plugin and getting any remaining features..."); c@103: result = request('{"type":"finish","content":{"pluginHandle":1}}'); c@103: } c@103: c@103: test(); c@103: