diff options
author | Richard <q@1bpm.net> | 2025-04-13 18:48:02 +0100 |
---|---|---|
committer | Richard <q@1bpm.net> | 2025-04-13 18:48:02 +0100 |
commit | 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 (patch) | |
tree | 291bd79ce340e67affa755a8a6b4f6a83cce93ea /site/app/twist/_unlive/index.api.html | |
download | apps.csound.1bpm.net-9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22.tar.gz apps.csound.1bpm.net-9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22.tar.bz2 apps.csound.1bpm.net-9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22.zip |
initial
Diffstat (limited to 'site/app/twist/_unlive/index.api.html')
-rw-r--r-- | site/app/twist/_unlive/index.api.html | 1144 |
1 files changed, 1144 insertions, 0 deletions
diff --git a/site/app/twist/_unlive/index.api.html b/site/app/twist/_unlive/index.api.html new file mode 100644 index 0000000..80c5eb9 --- /dev/null +++ b/site/app/twist/_unlive/index.api.html @@ -0,0 +1,1144 @@ +<html>
+ <head>
+ <title>twist</title>
+ <script type="text/javascript" src="/code/jquery.js"></script>
+ <script type="text/javascript" src="../base/base.js"></script>
+ <script type="text/javascript" src="../base/waveform.js"></script>
+ <script type="text/javascript">
+
+
+ var TransformParameterUI = function(instr, definition, parent, transform, twist) {
+ var self = this;
+ var parameter = twist.Parameter(instr, definition, transform, twist);
+ var initval = true;
+ var elContainer = $("<div />");
+ var elValueLabel = $("<div />");
+ var elValueInput;
+ var elModulations;
+ var elInput;
+ var elRow;
+ var elModSelect;
+
+ this.refresh = function() {
+ if (!refreshable) {
+ return;
+ }
+ parameter.refresh();
+
+ if (definition.preset == "instance") {
+ createSelectOptions(elInput, twist.otherInstanceNames);
+ }
+ if (parameter.applicable) {
+ elRow.show();
+ } else {
+ elRow.hide();
+ }
+ };
+
+ function createSelectOptions(elSelect, options) {
+ elSelect.empty();
+ var selected = elInput.val();
+ for (var x in options) {
+ var opt = $("<option />").text(options[x]).val(x).appendTo(elSelect);
+ if (x == selected) {
+ opt.attr("selected", "1");
+ }
+ }
+ }
+
+ function updateLabel() {
+ if (elValueInput) {
+ var val = self.getValue();
+ updateinput = false;
+ elValueInput.val(val);
+ updateinput = true;
+ //elValueLabel.text(val);
+ }
+ }
+
+ if (type == "select") {
+ elInput = $("<select />").change(function(){
+ transform.refresh();
+ parameter.value = $(this).val();
+ if (changeFunc) changeFunc(parameter.value);
+ });
+ var options = (definition.hostrange) ? parent.definitions.options : definition.options;
+ createSelectOptions(elInput, options);
+ } else {
+ var updateinput = true;
+ var max = definition.max;
+ var min = definition.min;
+ var step = definition.step;
+ var dfault = definition.dfault;
+
+
+
+ elInput = $("<input />").attr("type", "range").on("input", function() {
+ updateLabel();
+ }).change(function() {
+ transform.refresh();
+ parameter.value = $(this).val();
+ }).attr("min", min).attr("max", max).attr("step", step).val(dfault);
+
+ elValueInput = $("<input />").attr("type", "number").attr("min", min).attr("max", max).attr("step", step).addClass("transparentinput").appendTo(elValueLabel).change(function() {
+ if (updateinput) {
+ elInput.val($(this).val()).trigger("change").trigger("input");
+ }
+ });
+ }
+
+ elContainer.append(elInput);
+ if (initval) {
+ elInput.val(definition.dfault).trigger("change");
+ updateLabel();
+ }
+
+
+ this.setDefault = function() {
+ elInput.val(definition.dfault).trigger("change");
+ //app.setControlChannel(channel, definition.dfault);
+ };
+
+ this.remove = function() {
+ elContainer.remove();
+ };
+
+ this.getAutomationData = function() {
+ if (!self.modulation) return;
+ var m = twist.appdata.modulations[self.modulation];
+ return [m.instr, self.channel];
+ };
+
+ var elAutomation = $("<button />").text("Automate").click(function() {
+
+ });
+
+ var modulationShown = false;
+ var elModButton = $("<button />").text("Modulate").click(function() {
+ if (elModulations && modulationShown) {
+ hideModulations();
+ } else {
+ showModulations();
+ }
+ });
+
+ function hideModulations() {
+ app.setControlChannel(channel, self.getValue());
+ modulationShown = false;
+ elValueLabel.show();
+ elInput.show();
+ self.modulation = null;
+ elModButton.text("Modulate");
+ if (elModulations) {
+ elModulations.hide();
+ if (automation.includes(self)) {
+ delete automation[automation.indexOf(self)];
+ }
+ }
+ }
+
+
+ elModulations = $("<div />").addClass("tfv_container").hide().appendTo(elContainer);
+
+ 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 TransformParameter(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");
+ }
+
+ this.getElementRow = function(nocontrols) {
+ if (elRow) {
+ return elRow;
+ }
+ elRow = $("<tr />");
+ $("<td />").addClass("tfv_cell").text(definition.name).appendTo(elRow);
+ $("<td />").addClass("tfv_cell").append(elContainer).appendTo(elRow);
+ $("<td />").addClass("tfv_cellfixed").append(elValueLabel).appendTo(elRow);
+ if (!nocontrols) {
+ if (definition.automatable) {
+ $("<td />").addClass("tfv_cell").append(elAutomation).appendTo(elRow);
+ $("<td />").addClass("tfv_cell").append(elModButton).appendTo(elRow);
+ }
+ }
+ return elRow;
+ };
+
+
+ this.automate = function(start, end) {
+ app.insertScore("twst_createautomation", []);
+ };
+ };
+
+ function getTransformContainer(name) {
+ return $("<div />").addClass("tfv_container").append(
+ $("<div />").addClass("tfv_header").text(name)
+ );
+ }
+
+ var TransformUI = function(target, def, twist) {
+ var self = this;
+ var transform = new Transform(target, def, twist);
+ var elContainer = $("<div />").addClass("tfv_container").appendTo(target);
+ var elTb;
+ var pAddOdd = true;
+ this.uiparameters = [];
+ this.instr = def.instr;
+ this.refreshable = false;
+
+
+ this.refresh = function() {
+ if (!self.refreshable) {
+ return;
+ }
+ for (var k in self.uiparameters) {
+ self.uiparameters[k].refresh();
+ }
+ };
+
+ this.getAutomationData = function() {
+ return transform.getAutomationData();;
+ };
+
+ this.removeParameter = function(channel) {
+ if (self.uiparameters.hasOwnProperty(channel)) {
+ self.uiparameters[channel].remove();
+ delete self.uiparameters[channel]
+ }
+ transform.parameterGroup.removeParameter(channel);
+ };
+
+ this.addParameter = function(definition) {
+ self.addParameterUI(transform.parameterGroup.addParameter(definition));
+ };
+
+ this.addParameterUI = function(parameter) {
+ var tp = new TransformParameterUI(def.instr, parameter, null, self, twist);
+ self.uiparameters[tp.channel] = tp;
+ elTb.append(tp.getElementRow().addClass("tfv_row_" + ((pAddOdd) ? "odd" : "even")));
+ pAddOdd = !pAddOdd;
+ };
+
+ function build() {
+ getTransformContainer(def.name).appendTo(elContainer);
+
+ var tbl = $("<table />").appendTo(elContainer);
+ elTb = $("<tbody />").appendTo(tbl);
+
+ for (let p of transform.parameters) {
+ self.addParameter(p);
+ }
+ self.refresh();
+ }
+ build();
+ };
+
+ var TransformsTreeView = function(options, twist) {
+ var self = this;
+ var elTarget = $("#" + options.target);
+
+
+ function recurse(items, descended) {
+ items = (items) ? items : options.items;
+ var ul = $("<ul />").css({"border-bottom": "1px solid #878787", "padding-inline-start": 10}).addClass((descended) ? "nested" : "treelist");
+
+ for (let k in items) {
+ var li = $("<li />");
+ if (items[k].hasOwnProperty("contents")) {
+ $("<span />").addClass("caret").text(items[k].name).click(function() {
+ $(this).parent().children(".nested").toggleClass("active");
+ $(this).toggleClass("caret-down");
+ }).appendTo(li);
+ var subitems = recurse(items[k].contents, true);
+ li.append(subitems);
+
+ } else {
+ li.text(items[k].name).css("cursor", "pointer").click(function(){
+ var el = $("#controls").empty();
+ if (items[k].hasOwnProperty("display")) {
+ var container = getTransformContainer(items[k].name).appendTo(el);
+ twist.currentTransform = items[k].display(container);
+ } else {
+ twist.currentTransform = new Transform(el, items[k], twist);
+ }
+ });
+ }
+ ul.append(li);
+ }
+ elTarget.append(ul);
+ return ul;
+ }
+
+ elTarget.append(recurse());
+ };
+
+
+
+
+ var TwistUI = function(options) {
+ var self = this;
+ var toptions = {
+ errorHandler: function(text) {
+ self.showPrompt(text);
+ },
+ onProcessing: function(state) {
+
+ },
+ onUsage: function(state) {
+ self.waveform.cover(state);
+ }
+ };
+ var twist = new Twist(options);
+ var audioTypes = ["audio/mpeg", "audio/mp4", "audio/ogg", "audio/vorbis", "audio/x-flac","audio/aiff","audio/x-aiff", "audio/vnd.wav", "audio/wave", "audio/x-wav", "audio/wav"];
+ var maxsize = 1e+8; // 100 MB
+
+ var instanceIndex = 0;
+ this.stoptoggle = null;
+ this.waveforms = [];
+ var waveformTabs = [];
+ var keyModifier = {shift: false, alt: false, ctrl: false};
+ var playheadInterval;
+ var playing = false;
+ var elCrossfades = [];
+ var elPasteSpecial;
+
+ if (!options) options = {};
+ if (!options.latencyCorrection) options.latencyCorrection = 0;
+
+ function newInstance() {
+ var instance = twist.createInstance();
+ var element = $("<div />").addClass("waveform").appendTo("#waveforms");
+ let index = self.waveforms.length;
+ if (index < 0) index = 0;
+ waveformTabs.push(
+ $("<td />").text("New file").click(function() {
+ self.waveform = index;
+ }).addClass("wtab_selected").appendTo("#waveform_tabs")
+ );
+
+ self.waveforms.push(
+ new Waveform({target: element, latencyCorrection: options.latencyCorrection, showcrossfades: true})
+ );
+
+ self.waveform = index;
+ }
+
+ function removeInstance(i) {
+ if (i < 0 || i > this.waveforms.length - 2) {
+ return;
+ }
+ self.waveform.destroy();
+ twist.removeInstanceByIndex(i);
+ if (instanceIndex == i) {
+ instanceIndex = i + ((i == 0) ? 1 : -1);
+ self.waveform.show();
+ }
+ }
+
+ this.setPercent = function(percent) {
+ $("#loading_percent_inner").width(percent + "%");
+ };
+
+
+ function setLoadingStatus(state, showpercent) {
+ var el = $("#loading");
+ if (state) {
+ el.show();
+ if (showpercent) {
+ $("#loading_percent").show();
+ } else {
+ $("#loading_percent").hide();
+ }
+ } else {
+ el.hide();
+ }
+ }
+
+ this.setLoadingStatus = setLoadingStatus;
+
+ this.showPrompt = function(text, oncomplete) {
+ setLoadingStatus(false);
+ $("#prompt").show();
+ $("#prompt_text").text(text);
+ $("#prompt_button").unbind().click(function(){
+ if (oncomplete) {
+ oncomplete();
+ }
+ $("#prompt").hide();
+ });
+ };
+
+
+ function playPositionHandler(noPlayhead) {
+ function callback(ndata) {
+ if (ndata.status == 1) {
+ playing = true;
+ if (!noPlayhead) {
+ if (playheadInterval) {
+ clearInterval(playheadInterval);
+ }
+ playheadInterval = setInterval(async function(){
+ var val = await app.getControlChannel("playposratio");
+ if (val < 0 || val >= 1) {
+ clearInterval(playheadInterval);
+ }
+ self.waveform.movePlayhead(val);
+ }, 50);
+ }
+ } else {
+ playing = false;
+ if (ndata.status == -1) {
+ self.errorHandler("Not enough processing power to transform in realtime");
+ }
+ if (self.stoptoggle) {
+ setTimeout(self.stoptoggle, latencyCorrection);
+ }
+ app.removeCallback(ndata.cbid);
+ if (!noPlayhead) {
+ self.waveform.movePlayhead(0);
+ if (playheadInterval) {
+ clearInterval(playheadInterval);
+ }
+ }
+ self.waveform.cover(false);
+ }
+ }
+ return app.createCallback(callback, true);
+ }
+
+
+
+ async function refreshOverviews(ndata) {
+ errorState = "Overview refresh error";
+ var wavedata = [];
+ var duration = ndata.duration;
+
+ wavedata.push(async function(v) {
+ if (v < 0) {
+ return await app.getCsound().tableLength(ndata.waveL);
+ } else {
+ return await app.getCsound().tableGet(ndata.waveL, v);
+ }
+ });
+
+ if (ndata.hasOwnProperty("waveR")) {
+ wavedata.push(async function(v) {
+ return await app.getCsound().tableGet(ndata.waveR, v);
+ });
+ }
+ self.waveform.setData(wavedata, ndata.duration);
+
+ self.waveform.cover(false);
+ }
+
+ this.cut = function() {
+ self.instance.cut();
+ };
+
+ this.copy = function() {
+ self.instance.copy();
+ };
+
+ this.paste = function() {
+ self.instance.paste();
+ };
+
+ this.moveToStart = function() {
+ self.waveform.setSelection(0);
+ };
+
+ this.moveToEnd = function() {
+ self.waveform.setSelection(1);
+ };
+
+
+ this.pasteSpecial = function() {
+ if (!elPasteSpecial) {
+ elPasteSpecial = $("<div />").addClass("waveform_overlay").appendTo($("#waveforms"));
+ elPasteSpecial.append($("<h2 />").text("Paste special"));
+ var def = {
+ instr: "twst_pastespecial",
+ 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}]}
+ ]
+ };
+ var tf = new Transform(elPasteSpecial, def, self);
+
+ $("<button />").text("Paste").click(function(){
+ elPasteSpecial.hide();
+ self.waveform.cover(true);
+ operation("twst_pastespecial", refreshOverviews, true);
+ }).appendTo(elPasteSpecial);
+
+ } else {
+ elPasteSpecial.show();
+ }
+ };
+
+
+ this.play = function() {
+ self.instance.play();
+ };
+
+ this.stop = function() {
+ self.instance.stop();
+ };
+
+ this.saveFile = function(name) {
+ self.instance.saveFile(name, function(url) {
+ var a = $("<a />").attr("href", url).attr("download", name).appendTo($("body")).css("display", "none");
+ a.click();
+ setTimeout(function(){
+ a.remove();
+ window.URL.revokeObjectURL(url);
+ app.getCsound().fs.unlink(name);
+ }, 2000);
+ });
+ };
+
+ this.audition = function() {
+ self.instance.audition();
+
+ };
+
+ this.commit = function() {
+ self.instance.commit();
+ }
+
+ function buildWavecontrols() {
+ var el = $("#wavecontrols_inner");
+ var items = [
+ {label: "Zoom sel", click: function() {self.waveform.zoomSelection();}},
+ {label: "Zoom in", click: function() {self.waveform.zoomIn();}},
+ {label: "Zoom out", click: function() {self.waveform.zoomOut();}},
+ {label: "Show all", click: function() {self.waveform.zoomLevel = 1;}},
+
+ {label: "Cut", click: self.cut, css: {"background-color": "#a5ab30"}},
+ {label: "Copy", click: self.copy, css: {"background-color": "#d5db60"}},
+ {label: "Paste", click: self.paste, css: {"background-color": "#e5df90"}},
+ {label: "Paste special", click: self.pasteSpecial, css: {"background-color": "#e9dfa5"}},
+
+ {label: "Play", click: function(b) {
+ self.stoptoggle = function() {
+ b.text("Play");
+ };
+ if (b.text() == "Play") {
+ b.text("Stop");
+ self.play();
+ } else {
+ b.text("Play");
+ self.stop();
+ }
+ }, css: {"background-color": "#cc9999"}},
+ {label: "Audition", click: function(b) {
+ self.stoptoggle = function() {
+ b.text("Audition");
+ };
+ if (b.text() == "Audition") {
+ b.text("Stop");
+ self.audition();
+ } else {
+ b.text("Audition");
+ self.stop();
+ }
+ }, css: {"background-color": "#aa6666"}},
+ {label: "Commit", click: self.commit, css: {"background-color": "#ff4444"}},
+ ];
+
+ for (let i of items) {
+ let button = $("<button />").text(i.label)
+ button.click(function() {
+ i.click(button);
+ });
+ if (i.hasOwnProperty("css")) {
+ button.css(i.css);
+ }
+ $("<td />").append(
+ button
+ ).appendTo(el);
+ }
+
+ for (let e of ["in", "out"]) {
+ var elRange = $("<input />").attr("type", "range").attr("min", 0).attr("max", 0.45).attr("step", 0.00001).val(0).on("input", function() {
+ if (e == "in") {
+ self.waveform.crossFadeInRatio = $(this).val();
+ } else {
+ self.waveform.crossFadeOutRatio = $(this).val();
+ }
+ });
+ elCrossfades.push(elRange);
+ $("<td />").append($("<div />").text("Commit crossfade " + e)).append(elRange).appendTo(el);
+ }
+ }
+
+ function createLeftPane() {
+ var el = $("<div />").addClass("treetop").appendTo($("#panetree"));
+ $("<div />").addClass("treetop_header").text("twist").appendTo(el);
+
+ var ttv = new TransformsTreeView({
+ target: "panetree",
+ items: appdata.transforms
+ }, self);
+ }
+
+ async function handleFileDrop(e, obj) {
+ e.preventDefault();
+ if (!e.originalEvent.dataTransfer.files) {
+ return;
+ }
+ twist.isProcessing = true;
+ for (const item of e.originalEvent.dataTransfer.files) {
+ //item.size;
+ //item.type "audio/mpeg";
+ if (!audioTypes.includes(item.type)) {
+ return self.errorHandler("Unsupported file type");
+ }
+ if (item.size > maxsize) {
+ return self.errorHandler("File too big");
+ }
+ twist.errorState = "File loading error";
+ var content = await item.arrayBuffer();
+ self.instance.loadBuffer(content, function(ndata){
+ self.waveformTab.text(item.name);
+ if (self.currentTransform) {
+ self.currentTransform.refresh();
+ }
+ });
+ }
+ }
+
+ this.run = function() {
+ twist.run();
+
+ Object.defineProperty(this, "waveformTab", {
+ get: function() { return waveformTabs[instanceIndex]; },
+ set: function(x) {}
+ });
+
+ Object.defineProperty(this, "otherInstanceNames", {
+ get: function() {
+ var data = {};
+ for (var i in waveformTabs) {
+ if (i != instanceIndex) {
+ data[i] = waveformTabs[i].text();
+ }
+ }
+ return data
+ },
+ set: function(x) {}
+ });
+
+ Object.defineProperty(this, "waveform", {
+ get: function() { return self.waveforms[instanceIndex]; },
+ set: function(x) {
+ if (instanceIndex != x) {
+ self.waveformTab.removeClass("wtab_selected").addClass("wtab_unselected");
+ self.waveform.hide();
+ var cbid = app.createCallback(function(ndata){
+ if (ndata.status == 1) {
+ instanceIndex = x;
+ self.waveformTab.removeClass("wtab_unselected").addClass("wtab_selected");
+ self.waveform.show();
+ if (self.currentTransform) {
+ self.currentTransform.refresh();
+ }
+ } else {
+ self.showPrompt("Error changing instance");
+ }
+ });
+ app.insertScore("twst_setinstance", [0, 1, cbid, x]);
+
+ }
+ }
+ });
+
+ $("<td />").text("+").click(function() {
+ newInstance();
+ }).appendTo("#waveform_tabs").addClass("wtab_selected");
+
+ $("body").on("dragover", function(e) {
+ e.preventDefault();
+ e.originalEvent.dataTransfer.effectAllowed = "all";
+ e.originalEvent.dataTransfer.dropEffect = "copy";
+ return false;
+ }).on("dragleave", function(e) {
+ e.preventDefault();
+ }).on("drop", function(e) {
+ handleFileDrop(e, self);
+ }).on("keydown", function(e){
+ switch (e.which) {
+ case 32: // space
+ if (playing) {
+ self.stop();
+ } else {
+ self.play;
+ }
+ break;
+ case 13: // enter
+ if (keyModifier.alt) self.commit();
+ break;
+ case 67: // c
+ if (keyModifier.ctrl) self.copy();
+ break;
+ case 88: // x
+ if (keyModifier.ctrl) self.cut();
+ break;
+ case 86: // v
+ if (keyModifier.ctrl) {
+ if (keyModifier.shift) {
+ self.pasteSpecial();
+ } else {
+ self.paste();
+ }
+ }
+ break;
+ case 17:
+ keyModifier.ctrl = true;
+ break;
+ case 18:
+ keyModifier.alt = true;
+ break;
+ case 16:
+ keyModifier.shift = true;
+ break;
+ default:
+ return;
+ }
+ e.preventDefault();
+ }).on("keyup", function(e){
+ switch (e.which) {
+ case 17:
+ keyModifier.ctrl = false;
+ break;
+ case 18:
+ keyModifier.alt = false;
+ break;
+ case 16:
+ keyModifier.shift = false;
+ break;
+ default:
+ return;
+ }
+ e.preventDefault();
+ });
+
+ newInstance();
+ buildWavecontrols();
+ createLeftPane();
+ };
+
+ }; // end twist
+
+ $(function() {
+ window.twist = new Twist(appdata);
+ window.app = new CSApplication({
+ csdUrl: "twist.csd",
+ csOptions: ["--omacro:TWST_FAILONLAG=1"],
+ onPlay: function () {
+ twist.setLoadingStatus(false);
+ },
+ errorHandler: twist.errorHandler,
+ ioReceivers: {percent: twist.setPercent}
+ });
+
+ $("#start_invoke").click(function() {
+ $("#start").hide();
+ twist.run();
+ twist.setLoadingStatus(true);
+ app.play();
+ });
+
+ });
+
+
+ </script>
+ <style type="text/css">
+ /* Remove default bullets */
+ ul, .treelist {
+ list-style-type: none;
+ }
+
+ /* Remove margins and padding from the parent ul */
+ .treelist {
+ margin: 0;
+ padding: 0;
+ }
+
+ /* Style the caret/arrow */
+ .caret {
+ cursor: pointer;
+ font-weight: bold;
+ user-select: none; /* Prevent text selection */
+ }
+
+ /* Create the caret/arrow with a unicode, and style it */
+ .caret::before {
+ content: "\25B6";
+ color: black;
+ display: inline-block;
+ margin-right: 6px;
+ }
+
+ /* Rotate the caret/arrow icon when clicked on (using JavaScript) */
+ .caret-down::before {
+ transform: rotate(90deg);
+ }
+
+ /* Hide the nested list */
+ .nested {
+ display: none;
+ }
+
+ /* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */
+ .active {
+ display: block;
+ }
+
+
+ .treetop_header {
+ font-size: 16pt;
+ font-weight: bold;
+ padding-top: 10px;
+ width: 100%;
+ text-align: center;
+ top: 0px;
+ }
+
+ .treetop {
+ width: 100%;
+ height: 50px;
+ border-bottom: 1px solid black;
+ }
+ </style>
+ <style type="text/css">
+ #loading {
+ position: fixed;
+ display: none;
+ z-index: 161;
+ background-color: #7e80f2;
+ text-align: center;
+ font-size: 64pt;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 100%;
+ }
+
+ #loading_percent {
+ position: absolute;
+ top: 20%;
+ left: 30%;
+ width: 40%;
+ height: 10%;
+ background-color: #9a88f7;
+ }
+
+ #loading_percent_inner {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 1%;
+ background-color: #5e50a2;
+ }
+
+ #main {
+ position: absolute;
+ z-index: 5;
+ background-color: "#c5c5f0;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 100%;
+ }
+
+ .waveform {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ }
+
+ #waveforms {
+ position: absolute;
+ left: 15%;
+ top: 0px;
+ height: 60%;
+ width: 85%;
+ }
+
+ .waveform_overlay {
+ position: absolute;
+ padding: 20px;
+ width: 100%;
+ height: 100%;
+ background-color: #fcf6de;
+ opacity: 0.9;
+ left: 0px;
+ top: 0px;
+ z-index: 20;
+ }
+
+ #sidepane {
+ position: absolute;
+ background-color: #a5a5d9;
+ left: 0px;
+ top: 0px;
+ height: 100%;
+ width: 15%;
+ border-right: 1px solid black;
+ }
+
+ #controls {
+ position: absolute;
+ background-color: #9d9ded;
+ left: 15%;
+ top: 65%;
+ height: 40%;
+ width: 85%;
+ border-top: 1px solid black;
+ }
+
+ #wavecontrols {
+ position: absolute;
+ overflow: hidden;
+ background-color: #323265;
+ left: 15%;
+ top: 60%;
+ height: 5%;
+ width: 85%;
+ border-top: 1px solid black;
+ }
+
+ #waveform_tabs {
+ cursor: pointer;
+ }
+
+ #panetree {
+ font-size: 8pt;
+ font-family: Arial, sans-serif;
+ }
+
+ button {
+ border: none;
+ background-color: #8787bd;
+ font-size: 8pt;
+ padding: 1px;
+ font-family: Arial, sans-serif;
+ }
+
+ .tfv_script {
+ background-color: #323265;
+ color: #ffc67a;
+ font-size: 10pt;
+ font-family: monospace, Courier;
+ width: 100%;
+ height: 100%;
+ }
+
+ .tfv_container {
+ background-color: #8181fa;
+ font-size: 10pt;
+ font-family: Arial, sans-serif;
+ }
+
+ .tfv_row_odd {
+ background-color: #8181c9;
+ font-size: 10pt;
+ font-family: Arial, sans-serif;
+ }
+
+ .tfv_row_even {
+ background-color: #7171ba;
+ font-size: 10pt;
+ font-family: Arial, sans-serif;
+ }
+
+ .tfv_cell {
+ font-size: 10pt;
+ font-family: Arial, sans-serif;
+ }
+
+ .tfv_cellfixed {
+ font-size: 8pt;
+ font-family: Arial, sans-serif;
+ overflow: hidden;
+ width: 40px;
+ }
+
+ .tfv_header {
+ background-color: #565698;
+ font-size: 11pt;
+ font-weight: bold;
+ }
+
+ .automate_container {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ z-index: 125;
+ display: none;
+ }
+
+ #prompt {
+ z-index: 201;
+ position: fixed;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 100%;
+ background-color: #3434d9;
+ display: none;
+ }
+
+ #prompt_centre {
+ z-index: 202;
+ position: relative;
+ height: 200px;
+ }
+
+ #prompt_inner {
+ z-index: 203;
+ margin: 0;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-size: 24pt;
+ cursor: pointer;
+ text-align: centre;
+ }
+
+ #prompt_button {
+ font-size: 24pt;
+ padding: 20px;
+ }
+
+ #start {
+ z-index: 200;
+ position: fixed;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 100%;
+ background-color: #5656d1;
+ }
+
+ #start_centre {
+ z-index: 201;
+ position: relative;
+ height: 200px;
+ }
+
+ .transparentinput {
+ font-size: 8pt;
+ background-color: 9898ff;
+ color: #000000";
+ border: none;
+ }
+
+ .wtab_selected {
+ font-size: 8pt;
+ font-weight: bold;
+ background-color: 9898ff;
+ color: #000000";
+ padding: 3px;
+ border: 1px solid black;
+ border-top: 0;
+ }
+
+ .wtab_unselected {
+ font-size: 8pt;
+ background-color: #8888df;
+ font-weight: normal;
+ color: #000000";
+ padding: 3px;
+ border: 1px solid black;
+ }
+
+ #start_invoke {
+ z-index: 202;
+ text-align: centre;
+ margin: 0;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-size: 72pt;
+ cursor: pointer;
+ }
+
+ body {
+ font-family: Arial, sans-serif;
+ }
+
+ </style>
+ </head>
+ <body>
+ <div id="prompt">
+ <div id="prompt_centre">
+ <div id="prompt_inner">
+ <p id="prompt_text"></p>
+ <button id="prompt_button">OK</button>
+ </div>
+ </div>
+ </div>
+ <div id="start">
+ <div id="start_centre">
+ <h1>twist</h1>
+ <p>Web based audio transformer</p>
+ <p id="start_invoke">Press to begin</p>
+ </div>
+ </div>
+ <div id="loading">
+ Processing
+ <div id="loading_percent"><div id="loading_percent_inner"></div></div>
+ </div>
+ <div id="main">
+ <div id="waveforms"></div>
+ <div id= "automate_container"></div>
+ <div id="wavecontrols">
+ <table><tbody><tr id="waveform_tabs"></tr><tbody></table>
+ <table><tbody><tr id="wavecontrols_inner"></tr><tbody></table>
+ </div>
+ <div id="sidepane">
+ <div id="panetree"></div>
+ </div>
+ <div id="controls"></div>
+ </div>
+ </body>
+</html>
\ No newline at end of file |