diff options
Diffstat (limited to 'site/app/twist/_unlive/apid.js')
-rw-r--r-- | site/app/twist/_unlive/apid.js | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/site/app/twist/_unlive/apid.js b/site/app/twist/_unlive/apid.js new file mode 100644 index 0000000..28a00f2 --- /dev/null +++ b/site/app/twist/_unlive/apid.js @@ -0,0 +1,978 @@ +var twst = {};
+
+
+
+
+twst.Parameter = function(instr, definition, parent, transform, twist) {
+ var self = this;
+ var refreshable = false;
+ var changeFunc;
+ var value;
+ var initval = true;
+ var type;
+ var applicable;
+ var channel = (parent) ? parent.channel : instr + "_";
+ if (definition.hasOwnProperty("channel")) {
+ channel += definition.channel;
+ } else {
+ channel += definition.name.toLowerCase();
+ }
+
+ Object.defineProperty(this, "channel", {
+ get: function() { return channel; },
+ set: function(x) {}
+ });
+
+
+ if (definition.hasOwnProperty("options")) {
+ if (!definition.hasOwnProperty("automatable")) {
+ definition.automatable = false;
+ }
+ }
+
+ if (definition.hasOwnProperty("preset")) {
+ var save = {};
+ if (definition.hasOwnProperty("dfault")) {
+ save.dfault = definition.dfault;
+ }
+
+ if (definition.hasOwnProperty("name")) {
+ save.name = definition.name;
+ }
+
+ if (definition.preset == "fftsize") {
+ Object.assign(definition, {name: "FFT size", channel: "fftsize", description: "FFT size", options: [256, 512, 1024, 2048, 4096], dfault: 1, asvalue: true, automatable: false});
+ } else if (definition.preset == "wave") {
+ Object.assign(definition, {name: "Wave", description: "Wave shape to use", options: ["Sine", "Square", "Saw", "Pulse", "Triangle"], dfault: 0});
+ } else if (definition.preset == "instance") {
+ initval = false;
+ transform.refreshable = true;
+ refreshable = true;
+ Object.assign(definition, {
+ name: "Instance", description: "Other wave to use", channel: "instanceindex",
+ options: twist.otherInstanceNames,
+ automatable: false
+ });
+ changeFunc = function(index) {
+ var s = twist.waveforms[index].selected;
+ app.setControlChannel(instr + "_" + "otinststart", s[0]);
+ app.setControlChannel(instr + "_" + "otinstend", s[1]);
+ app.setControlChannel(instr + "_" + "otiinstchan", s[2]);
+ }
+ }
+ if (save) {
+ Object.assign(definition, save);
+ }
+ } // if preset
+
+
+
+ if (definition.hasOwnProperty("options") || (definition.hostrange && parent.definition.hasOwnProperty("options"))) {
+ type = "select";
+ } else {
+ type = "range";
+ }
+
+
+ if (definition.hasOwnProperty("conditions") && !parent) {
+ transform.refreshable = refreshable = true;
+ }
+
+ Object.defineProperty(this, "applicable", {
+ get: function() { return applicable; },
+ set: function(v) { }
+ });
+
+ Object.defineProperty(this, "value", {
+ get: function() { return value; },
+ set: function(v) {
+ if (type == "select") {
+ if (v < 0) {
+ v = 0;
+ } else if (v >= definition.options.length) {
+ v = defintion.options.length - 1;
+ }
+ if (definition.asvalue) {
+ value = definition.options[v];
+ } else {
+ value = v;
+ }
+ } else if (type == "range") {
+ if (v > definition.max) {
+ v = definition.max;
+ } else if (v < definition.min) {
+ v = definition.min;
+ } else if (v % definition.step != 0) {
+ if (definition.step == 1) {
+ v = Math.round(v);
+ } else {
+ v = Math.ceil((v - definition.min) / definition.step) * definition.step + definition.min;
+ }
+ }
+ value = v;
+ }
+ twist.csapp.setControlChannel(channel, value);
+ }
+ });
+
+
+
+
+ var automation = [];
+
+ this.definition = definition;
+ this.modulation = null;
+ this.channel = channel;
+ var modulationParameters = null;
+
+
+ if (!definition.hasOwnProperty("step")) {
+ definition.step = 0.0000001;
+ }
+
+ if (!definition.hasOwnProperty("min")) {
+ definition.min = 0;
+ }
+
+ if (!definition.hasOwnProperty("max")) {
+ definition.max = 1;
+ }
+
+ if (!definition.hasOwnProperty("automatable")) {
+ definition.automatable = true;
+ }
+
+ if (!definition.hasOwnProperty("dfault")) {
+ definition.dfault = 1;
+ }
+
+
+ if (parent && definition.hostrange) {
+ for (var o of ["step", "min", "max", "dfault", "options", "condition", "hostrange"]) {
+ if (parent.definition.hasOwnProperty(o)) {
+ definition[o] = parent.definition[o];
+ }
+ }
+ }
+
+ this.refresh = function() {
+ if (!refreshable) {
+ return;
+ }
+ for (var k in definition.conditions) {
+ var c = definition.conditions[k];
+ var val = transform.parameters[transform.instr + "_" + c.channel].getValue();
+ if (
+ (c.operator == "eq" && val != c.value) ||
+ (c.operator == "lt" && val >= c.value) ||
+ (c.operator == "gt" && val <= c.value) ||
+ (c.operator == "le" && val > c.value) ||
+ (c.operator == "ge" && val < c.value)
+ ) {
+ applicable = false;
+ }
+ }
+ applicable = true;
+ };
+
+ this.setDefault = function() {
+ value = definition.dfault;
+ };
+
+ if (initval) {
+ self.setDefault();
+ }
+
+ this.getAutomationData = function() {
+ if (!self.modulation) return;
+ var m = twist.appdata.modulations[self.modulation];
+ return [m.instr, self.channel];
+ };
+
+ function showModulations() {
+ modulationShown = true;
+ elValueLabel.hide();
+ elInput.hide();
+ elModulations.show();
+ elModButton.text("Close");
+ if (elModulations.children().length != 0) {
+ elModSelect.val(0).trigger("change");
+ return;
+ }
+ var tb = $("<tbody />");
+ function buildModulation(i) {
+ tb.empty();
+ modulationParameters = [];
+ self.modulation = i;
+ let m = twist.appdata.modulations[i];
+ for (let x of m.parameters) {
+ var tp = new twst.Parameter(m.instr, x, self, transform, twist);
+ modulationParameters.push(tp);
+ tb.append(tp.getElementRow(true)); // hmm modulate the modulation with false
+ }
+ }
+ var selecttb = $("<tbody />").appendTo($("<table />)").appendTo(elModulations));
+ var row = $("<tr />").append($("<td />").text("Modulation type")).appendTo(selecttb);
+
+ elModSelect = $("<select />").change(function() {
+ self.modulation = $(this).val();
+ buildModulation(self.modulation);
+ automation.push(self);
+ }).appendTo($("<td />").appendTo(row));
+ $("<table />").append(tb).appendTo(elModulations);
+
+ for (let i in twist.appdata.modulations) {
+ var m = twist.appdata.modulations[i];
+ $("<option />").text(m.name).val(i).appendTo(elModSelect);
+ }
+ elModSelect.val(0).trigger("change");
+ }
+
+};
+
+function getTransformContainer(name) {
+ return $("<div />").addClass("tfv_container").append(
+ $("<div />").addClass("tfv_header").text(name)
+ );
+}
+
+twst.ParameterGroup = function(def, instance, twist) {
+ var self = this;
+ this.instr = def.instr;
+ this.refreshable = false;
+ var presetParameters;
+ this.parameters = {};
+
+ if (def.hasOwnProperty("preset") && def.preset == "pvsynth") {
+ var conditions = [
+ {channel: "pvresmode", operator: "eq", value: 1}
+ ];
+ presetParameters = [
+ {name: "Resynth mode", channel: "pvresmode", description: "Type of FFT resynthesis used", dfault: 0, options: ["Overlap-add", "Additive"], automatable: false},
+ {name: "Oscillator spread", channel: "pvaoscnum", description: "Number of oscillators used", automatable: false, conditions: conditions},
+ {name: "Frequency modulation", channel: "pvafreqmod", description: "Frequency modulation", dfault: 1, min: 0.01, max: 2, conditions: conditions},
+ {name: "Oscillator offset", channel: "pvabinoffset", description: "Oscillator bin offset", automatable: false, conditions: conditions},
+ {name: "Oscillator increment", channel: "pvabinoffset", description: "Oscillator bin increment", min: 1, max: 32, dfault: 1, step: 1, automatable: false, conditions: conditions}
+ ];
+ }
+
+ this.refresh = function() {
+ if (!self.refreshable) {
+ return;
+ }
+ for (var k in self.parameters) {
+ self.parameters[k].refresh();
+ }
+ };
+
+ this.getAutomationData = function() {
+ var automations = [];
+ for (var k in self.parameters) {
+ var data = self.parameters[k].getAutomationData();
+ if (data) {
+ automations.push(data);
+ }
+ }
+ return automations;
+ };
+
+ this.removeParameter = function(channel) {
+ if (self.parameters.hasOwnProperty(channel)) {
+ self.parameters[channel].remove();
+ delete self.parameters[channel]
+ }
+ };
+
+ this.addParameter = function(pdef) {
+ var tp = new twst.Parameter(def.instr, pdef, null, self, twist);
+ self.parameters[tp.channel] = tp;
+ return tp;
+ };
+
+ function build() {
+ getTransformContainer(def.name).appendTo(elContainer);
+
+ var tbl = $("<table />").appendTo(elContainer);
+ elTb = $("<tbody />").appendTo(tbl);
+
+ for (let p of def.parameters) {
+ self.addParameter(p);
+ }
+
+ if (presetParameters) {
+ for (let p of presetParameters) {
+ self.addParameter(p);
+ }
+ }
+ self.refresh();
+ }
+ build();
+};
+
+
+var Transform = function(definition, instance, twist) {
+ var parameterGroup = new ParameterGroup(definition, instance, twist);
+
+ Object.defineProperty(this, "parameterGroup", {
+ get: function() { return parameterGroup; },
+ set: function(x) {}
+ });
+
+ Object.defineProperty(this, "parameters", {
+ get: function() { return parameterGroup.parameters; },
+ set: function(x) {}
+ });
+
+
+ function handleAutomation(onready) {
+ if (transform) {
+ var automations = transform.getAutomationData();
+ if (automations && automations.length > 0) {
+ var cbid = app.createCallback(function(ndata){
+ if (ndata.status == 1) {
+ onready(1);
+ } else {
+ return twist.errorHandler("Cannot parse automation data");
+ }
+ });
+ var call = [0, 1, cbid];
+ for (let i in automations) {
+ call.push(automations[i][0] + " \\\"" + automations[i][1] + "\\\"");
+ }
+ twist.csapp.insertScore("twst_automationprepare", call);
+ } else {
+ onready(0);
+ }
+ }
+ }
+
+ this.audition = function(start, end, timeUnit) {
+ if (twist.isProcessing || twist.inUse) return twist.errorHandler("Already in use");
+ errorState = "Playback error";
+
+ if (!start) {
+ start = instance.selection.ratio[0];
+ end = instance.selection.ratio[1];
+ } else {
+ if (!timeUnit) timeUnit = "seconds");
+ start = timeConvert(start, timeUnit);
+ end = timeConvert(end, timeUnit);
+ }
+
+ handleAutomation(function(automating){
+var cbid = playPositionHandler();
+ operation({
+ instr: "twst_audition",
+ score: [start, end, instance.selectedChannel, definition.instr, automating]
+ });
+
+
+
+ });
+
+ };
+
+ this.commit = function(start, end, timeUnitPos, crossfadeIn, crossfadeOut, timeUnitCrossfade) {
+ if (twist.isProcessing || twist.inUse) return twist.errorHandler("Already in use");
+ handleAutomation(function(automating){
+ if (!start) {
+ start = instance.selection.start.ratio;
+ end = instance.selection.end.ratio;
+ } else {
+ if (!timeUnitPos) timeUnitPos = "seconds");
+ start = timeConvert(start, timeUnitPos);
+ end = timeConvert(end, timeUnitPos);
+ }
+
+ if (!crossfadeIn) {
+ crossfadeIn = instance.selection.ratio[0];
+ crossfadeOut = instance.selection.ratio[1];
+ } else {
+ if (!timeUnitPos) timeUnitPos = "seconds");
+ crossfadeIn = timeConvert(start, timeUnitPos);
+ crossfadeOut = timeConvert(end, timeUnitPos);
+ }
+
+ errorState = "Transform commit error";
+ operation({
+ instr: "twst_commit",
+ refresh: true,
+ score: [start, end, instance.selectedChannel, definition.instr, automating, instance.crossFade.start.ratio, instance.crossFade.end.ratio]
+ });
+
+ });
+ };
+};
+
+
+
+
+
+var TwistInstance = function(instanceIndex, twist, options) {
+ var self = this;
+ if (!options) options = {};
+ var transform;
+ var channels;
+ var durationSamples;
+ var selectedChannel = -1;
+ var filename;
+ var sr;
+ var csTables = [];
+
+ var Time = function(dfault, onValidate, onChange) {
+ var tself = this;
+ var value = dfault;
+
+ Object.defineProperty(this, "samples", {
+ get: function() { return value; },
+ set: function(v) {
+ if (value == v) return;
+ value = v;
+ if (onValidate) {
+ var res = onValidate(value);
+ if (res) {
+ value = res;
+ }
+ }
+ if (onChange) onChange(tself);
+ }
+ });
+
+ Object.defineProperty(this, "seconds", {
+ get: function() { return value / sr; },
+ set: function(v) {
+ tself.samples = Math.round(v * sr);
+ }
+ });
+
+ Object.defineProperty(this, "ratio", {
+ get: function() { return value / durationSamples; },
+ set: function(v) {
+ tself.samples = Math.round(v * durationSamples);
+ }
+ });
+ };
+
+ var playPosition = new Time(0);
+ var selection = new Time({start: 0, end: 0}, function(v) {
+ if (typeof(v) != "object") {
+ v = {start: v, end: v};
+ return v;
+ }
+ if (v.start > v.end) {
+ v.start = v.end
+ }
+ if (v.end > durationSamples) {
+ v.end = durationSamples);
+ }
+ }, options.onSelectionChange);
+
+ var crossFade = new Time({start: 0, end: 0}, function(v) {
+ iif (typeof(v) != "object") {
+ v = {start: v, end: v};
+ return v;
+ }
+ var half = Math.round(durationSamples * 0.5);
+ if (v.start > half) {
+ v.start = half;
+ }
+ if (v.end > half) {
+ v.end = half;
+ }
+ }, options.onCrossFadeChange);
+
+
+ Object.defineProperty(this, "selectedChannel", {
+ get: function() { return selectedChannel; },
+ set: function(v) {
+ if (channels == 1) return;
+ if (v >= channels) {
+ selectedChannel = channels - 1;
+ } else if (v < 0) {
+ selectedChannel = 0;
+ } else {
+ selectedChannel = v;
+ }
+ }
+ });
+
+ Object.defineProperty(this, "playPosition", {
+ get: function() { return playPosition; },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "selection", {
+ get: function() { return selection; },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "crossFade", {
+ get: function() { return crossFade; },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "instanceIndex", {
+ get: function() { return instanceIndex; },
+ set: function(v) {}
+ });
+
+ var durationObj;
+ Object.defineProperty(durationObj, "samples", {
+ get: function() { return durationSamples; },
+ set: function(v) {}
+ });
+ Object.defineProperty(durationObj, "seconds", {
+ get: function() { return durationSamples / sr; },
+ set: function(v) {}
+ });
+ Object.defineProperty(this, "duration", {
+ get: function() { return durationObj; },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "filename", {
+ get: function() { return filename; },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "sr", {
+ get: function() { return sr; },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "csTables", {
+ get: function() { return csTables; },
+ set: function(v) {}
+ });
+
+
+ function refresh(data) {
+ twist.errorState = "Overview refresh error";
+ csTables = [data.waveL];
+ if (data.hasOwnProperty("waveR")) {
+ csTables.push(data.waveR);
+ }
+ sr = data.sr;
+ durationSamples = Math.round(data.sr * data.duration);
+ if (options.onRefresh) options.onRefresh(self);
+ }
+
+
+
+ function getTransform(path) {
+ if (!twist.transforms.hasOwnProperty(path)) {
+ return;
+ }
+ return new ParameterGroup(transforms[path], self, twist);
+ }
+
+
+ function operation(data) {
+ if (!data.setUsage) data.setUsage = true;
+ if (!data.setProcessing) data.setProcessing = true;
+ if (twist.inUse || twist.isProcessing) {
+ return twist.errorHandler("Already processing");
+ }
+
+ var score = [0, -1];
+ if (!data.noCallback) {
+ cbid = twist.csapp.createCallback(function(ndata){
+ if (data.refresh) refresh();
+ if (data.onComplete) data.onComplete(ndata);
+ if (data.setUsage) twist.inUse = false;
+ if (data.setProcessing) twist.isProcessing = false;
+ });
+ score.push(cbid);
+ if (data.setUsage) twist.inUse = true;
+ if (data.setProcessing) twist.isProcessing = true;
+ }
+ if (data.onRun) options.onRun();
+ if (data.score) {
+ for (s of data.score) {
+ score.push(s);
+ }
+ }
+
+ twist.csapp.insertScore(data.instr, score);
+ } // operation
+
+ function loadFile(name) {
+ var cbid = twist.csapp.createCallback(async function(ndata){
+ await app.getCsound().fs.unlink(name);
+ if (ndata.status == 0) {
+ return twist.errorHandler("File not valid");
+ } else {
+ refresh(ndata);
+ }
+ twist.inUse = false;
+ twist.isProcessing = false;
+ });
+ twist.inUse = true;
+ twist.isProcessing = true;
+ app.insertScore("twst_loadfile", [0, -1, cbid, item.name]);
+ }
+
+ this.loadUrl = function(url, onLoad) {
+ twist.csapp.loadFile(url, loadFile);
+ };
+
+ this.loadBuffer = function(arrayBuffer, onLoad) {
+ twist.csapp.loadBuffer(url, loadFile);
+ };
+
+ this.saveFile = function(name, onSave) {
+ if (!onSave) {
+ onSave = options.onSave;
+ }
+
+ if (!onSave) {
+ return twist.errorHandler("Instance or saveFile onSave option has not been provided");
+ }
+
+ twist.inUse = true;
+ twist.isProcessing = true;
+
+ if (!name) {
+ name = filename;
+ }
+ if (!name) {
+ name = "export.wav";
+ }
+
+ if (!name.toLowerCase().endsWith(".wav")) {
+ name += ".wav";
+ }
+ var cbid = twist.csapp.createCallback(async function(ndata){
+ var content = await twist.csapp.getCsound().fs.readFile(name);
+ var blob = new Blob(content, {type: "audio/wav"});
+ var url = window.URL.createObjectURL(blob);
+ onSave(url);
+ twist.inUse = false;
+ twist.isProcessing = false;
+ });
+ twist.csapp.insertScore("twst_savefile", [0, -1, cbid, name]);
+ };
+
+ function timeConvert(val, mode) { // returns ratio right now
+ if (mode == "ratio") {
+ return val;
+ } else if (mode == "samples") {
+ return val / durationSamples;
+ } else if (mode == "seconds") {
+ return val / (durationSamples / sr);
+ }
+ }
+
+ this.cut = function(start, end, timeUnit) {
+ if (!start) {
+ start = self.selection.ratio[0];
+ end = self.selection.ratio[1];
+ } else {
+ if (!timeUnit) timeUnit = "seconds");
+ start = timeConvert(start, timeUnit);
+ end = timeConvert(end, timeUnit);
+ }
+ operation({
+ instr: "twst_cut",
+ score: [start, end, selectedChannel],
+ refresh: true,
+ });
+ };
+
+ this.copy = function(start, end, timeUnit) {
+ if (!start) {
+ start = self.selection.ratio[0];
+ end = self.selection.ratio[1];
+ } else {
+ if (!timeUnit) timeUnit = "seconds");
+ start = timeConvert(start, timeUnit);
+ end = timeConvert(end, timeUnit);
+ }
+ operation({
+ instr: "twst_copy",
+ score: [start, end, selectedChannel],
+ });
+ };
+
+ this.paste = function(start, end, timeUnit) {
+ if (!start) {
+ start = self.selection.ratio[0];
+ end = self.selection.ratio[1];
+ } else {
+ if (!timeUnit) timeUnit = "seconds");
+ start = timeConvert(start, timeUnit);
+ end = timeConvert(end, timeUnit);
+ }
+ operation({
+ instr: "twst_paste",
+ score: [start, end, selectedChannel],
+ });
+ };
+
+ this.pasteSpecial = function(start, end, timeUnit) {
+ pasteSpecial: {instr: "twst_pastespecial", refresh: true, parameters: [
+ {name: "Repetitions", channel: "repetitions", min: 1, max: 40, step: 1, dfault: 1, automatable: false},
+ {name: "Repetition random time variance ratio", channel: "timevar", min: 0, max: 1, step: 0.000001, dfault: 0, automatable: false},
+ {name: "Mix paste", channel: "mixpaste", step: 1, dfault: 0, automatable: false},
+ {name: "Mix crossfade", channel: "mixfade", automatable: false, conditions: [{channel: "mixpaste", operator: "eq", value: 1}]}
+ ]},
+ };
+
+ this.play = function(start, end, timeUnit) {
+ errorState = "Playback error";
+ if (!start) {
+ start = self.selection.ratio[0];
+ end = self.selection.ratio[1];
+ } else {
+ if (!timeUnit) timeUnit = "seconds");
+ start = timeConvert(start, timeUnit);
+ end = timeConvert(end, timeUnit);
+ }
+ operation({
+ instr: "twst_play",
+ score: [start, end, selectedChannel],
+ });
+ };
+
+ this.stop = function() {
+ operation({
+ instr: "twst_stop"
+ });
+ };
+
+
+
+
+
+
+
+
+
+};
+
+
+var Twist = function(options) {
+ var twist = this;
+ var inUse = false;
+ var isProcessing = false;
+ var instanceIndex = 0;
+ var instances = [];
+ var transforms;
+ var modulations;
+ var onRunFunc;
+ this.errorState = null;
+
+ if (!options) options = {};
+
+ if (!options.appdata) {
+ const xhr = new XMLHttpRequest();
+ xhr.open("GET", "appdata.json", false);
+ xhr.send();
+ if (xhr.status == 200) {
+ options.appdata = JSON.parse(xhr.responseText);
+ } else {
+ throw "No appdata available";
+ }
+ }
+
+ function errorHandlerInner(error, func) {
+ if (!error && twist.errorState) {
+ error = twist.errorState;
+ twist.errorState = null;
+ } elseif (!error && !twist.errorState) {
+ error = "Unhandled error";
+ }
+ func(error);
+ }
+
+ this.errorHandler = function(error) {
+ if (!error && twist.errorState) {
+ error = twist.errorState;
+ twist.errorState = null;
+ } elseif (!error && !twist.errorState) {
+ error = "Unhandled error";
+ }
+ if (options.errorHandler) {
+ options.errorHandler(error);
+ } else {
+ throw error;
+ }
+ };
+
+ this.setPercent = function(percent) {
+ if (options.onPercentChange) {
+ options.onPercentChange(percent);
+ }
+ };
+
+ if (!csapp) {
+ csapp = new CSApplication({
+ csdUrl: "twist.csd",
+ csOptions: ["--omacro:TWST_FAILONLAG=1"],
+ onPlay: function () {
+ if (onRunFunc) onRunFunc();
+ },
+ errorHandler: options.errorHandler,
+ ioReceivers: {percent: twist.setPercent}
+ });
+ }
+
+
+ Object.defineProperty(this, "csapp", {
+ get: function() {
+ return csapp;
+ },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "instances", {
+ get: function() {
+ return instances;
+ },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "transforms", {
+ get: function() {
+ return transforms;
+ },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "modulations", {
+ get: function() {
+ return modulations;
+ },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "appdata", {
+ get: function() {
+ return options.appdata;
+ },
+ set: function(v) {}
+ });
+
+ Object.defineProperty(this, "inUse", {
+ get: function() {
+ return inUse;
+ },
+ set: function(v) {
+ if (inUse != v) {
+ inUse = v;
+ if (options.onUsage) options.onUsage(v);
+ }
+ }
+ });
+
+ Object.defineProperty(this, "isProcessing", {
+ get: function() {
+ return isProcessing;
+ },
+ set: function(v) {
+ if (isProcessing != v) {
+ isProcessing = v;
+ if (options.onUsage) options.onUsage(v);
+ }
+ }
+ });
+
+ this.run = function(onRunFunc) {
+ onRunFunc = onRun;
+ csapp.play();
+ };
+
+ this.createInstance = function() {
+ var instance = new TwistInstance(instanceIndex, twist, options.instance);
+ instances[instanceIndex] = instance;
+ instanceIndex ++;
+ return instance;
+ };
+
+ this.removeInstanceByIndex = function(index) {
+ if (i < 0 || i > instances.length - 2) return;
+ delete instances[index];
+ };
+
+ function getProcesses(appdata, type) {
+ var processes = {};
+
+ function recurse(items, prefix) {
+ if (!prefix) {
+ prefix = "/";
+ }
+ for (let item of items) {
+ if (item.hasOwnProperty("contents")) {
+ var subitems = recurse(item.contents, prefix + item.name + "/");
+ } else {
+ processes[prefix + item.name] = item;
+ }
+ }
+ }
+ recurse(appdata[type]);
+ return processes;
+ }
+
+ transforms = getProcesses(options.appdata, "transforms");
+ modulations = getProcesses(options.appdata, "modulations");
+
+};
+
+
+
+
+
+
+
+
+
+
+
+window.t = new Twist({
+ csapp: null,
+ appdata: null,
+ latencyCorrection: 170,
+ onPercentChange,
+ onProcessing: state => {
+
+ },
+ onUsage: state => {
+
+ },
+ instance: {
+
+ onPlayPositionChange: position => {
+
+ },
+ onSelectionChange: selection => {
+
+ },
+ onCrossFadeChange: crossfades => {
+
+ },
+ onRefresh: () => {
+
+ },
+ onPlay: () => {
+
+ },
+ onSave: () => {
+
+ }
+ }
+});
+
+
+
+
+
+
+$("#start_invoke").click(function(){
+ $("#loading").show();
+ t.run(function(){
+ $("#start").hide();
+ $("#loading").hide();
+ });
+});
+
+
|