UNPKG

flocking

Version:

Creative audio synthesis for the Web

148 lines (122 loc) 4.6 kB
/* * Flocking Synth * https://github.com/continuing-creativity/flocking * * Copyright 2013-2018, Colin Clark * Dual licensed under the MIT and GPL Version 2 licenses. */ /*global require, flock*/ var fluid = fluid || require("infusion"), flock = fluid.registerNamespace("flock"); /** * A synth is a collection of signal-generating units, * wired together to form an instrument. * They are created with a synthDef object, * which is a declarative structure that describes the instrument's * unit generator graph. */ fluid.defaults("flock.synth", { gradeNames: ["flock.node", "flock.noteTarget"], rate: flock.rates.AUDIO, addToEnvironment: true, mergePolicy: { ugens: "nomerge" }, ugens: { expander: { funcName: "flock.makeUGens", args: [ "{that}.options.synthDef", "{that}.rate", "{that}.nodeList", "{that}.enviro", "{that}.audioSettings" ] } }, members: { rate: "{that}.options.rate", audioSettings: "{that}.enviro.audioSystem.model", // TODO: Move this. nodeList: "@expand:flock.nodeList()", out: "{that}.options.ugens" }, model: { blockSize: "@expand:flock.synth.calcBlockSize({that}.rate, {that}.enviro.audioSystem.model)" }, invokers: { /** * Sets the value of the ugen at the specified path. * * @param {String||Object} a keypath or change specification object * @param {Number || UGenDef} val a value to set * @param {Boolean} swap whether or not to reattach the current unit generator's inputs to the new one * @return {UGen} the newly created UGen that was set at the specified path */ set: { funcName: "flock.synth.set", args: ["{that}", "{that}.nodeList.namedNodes", "{arguments}.0", "{arguments}.1", "{arguments}.2"] }, /** * Gets the value of a ugen at the specified path. * * @param {String} path the ugen's path within the synth graph * @return {Number|UGen} a scalar value in the case of a value ugen, otherwise the ugen itself */ get: { funcName: "flock.input.get", args: ["{that}.nodeList.namedNodes", "{arguments}.0"] }, generate: { funcName: "flock.evaluate.synth", args: ["{that}"] } } }); flock.synth.createUGenTree = function (synthDef, rate, enviro) { return new flock.UGenTree(synthDef, rate, enviro); }; flock.synth.calcBlockSize = function (rate, audioSettings) { return rate === flock.rates.AUDIO ? audioSettings.blockSize : 1; }; flock.synth.set = function (that, namedNodes, path, val, swap) { return flock.input.set(namedNodes, path, val, undefined, function (ugenDef, path, target, prev) { return flock.synth.ugenValueParser(that, ugenDef, prev, swap); }); }; flock.synth.input = function (args, getFn, setFn) { //path, val, swap var path = args[0]; return !path ? undefined : typeof path === "string" ? args.length < 2 ? getFn(path) : setFn.apply(null, args) : flock.isIterable(path) ? getFn(path) : setFn.apply(null, args); }; // TODO: Reduce all these dependencies on "that" (i.e. a synth instance). flock.synth.ugenValueParser = function (that, ugenDef, prev, swap) { if (ugenDef === null || ugenDef === undefined) { return prev; } var parsed = flock.parse.ugenDef(ugenDef, that.enviro, { audioSettings: that.audioSettings, buses: that.enviro.busManager.buses, buffers: that.enviro.buffers }); var newUGens = flock.isIterable(parsed) ? parsed : (parsed !== undefined ? [parsed] : []), oldUGens = flock.isIterable(prev) ? prev : (prev !== undefined ? [prev] : []); var replaceLen = Math.min(newUGens.length, oldUGens.length), replaceFnName = swap ? "swapTree" : "replaceTree", i, atIdx, j; // TODO: Improve performance by handling arrays inline instead of repeated function calls. for (i = 0; i < replaceLen; i++) { atIdx = flock.ugenNodeList[replaceFnName](that.nodeList, newUGens[i], oldUGens[i]); } for (j = i; j < newUGens.length; j++) { atIdx++; flock.ugenNodeList.insertTree(that.nodeList, newUGens[j], atIdx); } for (j = i; j < oldUGens.length; j++) { flock.ugenNodeList.removeTree(that.nodeList, oldUGens[j]); } return parsed; };