From 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Apr 2025 18:48:02 +0100 Subject: initial --- site/app/twine/_hOLD/clip.js | 499 +++++++++++ site/app/twine/_hOLD/index.html | 863 +++++++++++++++++++ site/app/twine/_hOLD/index_old.html | 102 +++ site/app/twine/_hOLD/index_workingold.html | 1251 ++++++++++++++++++++++++++++ site/app/twine/_hOLD/timeline.csd | 154 ++++ site/app/twine/_hOLD/timeline_base.html | 633 ++++++++++++++ 6 files changed, 3502 insertions(+) create mode 100644 site/app/twine/_hOLD/clip.js create mode 100644 site/app/twine/_hOLD/index.html create mode 100644 site/app/twine/_hOLD/index_old.html create mode 100644 site/app/twine/_hOLD/index_workingold.html create mode 100644 site/app/twine/_hOLD/timeline.csd create mode 100644 site/app/twine/_hOLD/timeline_base.html (limited to 'site/app/twine/_hOLD') diff --git a/site/app/twine/_hOLD/clip.js b/site/app/twine/_hOLD/clip.js new file mode 100644 index 0000000..1c4cc48 --- /dev/null +++ b/site/app/twine/_hOLD/clip.js @@ -0,0 +1,499 @@ +var Clip = function(twine, data, parent) { + var clip = this; + var loaded = false; + var waveformClip; + var waveformEdit; + var datatable; + this.channel = null; + var minWidth = 10; + + if (!data) { + var id = twine.getNewID(); + var data = { + name: "Clip " + id, + channel: -1, + id: id, + clipindex: null, + playLength: 1, + colour: "#" + (Math.random() * 0xFFFFFF << 0).toString(16), + position: 0, + // debugs: + duration: 1, + warp: false, + loop: false + }; + } else { + loaded = true; + } + this.data = data; + Object.defineProperty(this, "colour", { + get: function() { return data.colour; }, + set: function(x) { + data.colour = x; + clip.element.css("background-color", data.colour); + } + }); + + this.exportData = function() { + return data; + }; + + this.destroy = function(onComplete) { + var cbid = app.createCallback(function(ndata){ + clip.element.remove(); + clip.channel.removeClip(clip); + if (onComplete) { + onComplete(ndata); + } + }); + app.insertScore("twine_removeclip", [0, 1, cbid, clip.data.clipindex]); + }; + + var dataMode = { + fnL: 0, fnR: 1, divisionsPerBeat: 2, duration: 3, beatsLength: 4, utilisedLength: 5, + warpMode: 6, pitch: 7, amp: 8, fftSize: 9, txtWinSize: 10, txtRandom: 11, txtOverlap: 12, + loop: 13, warp: 14, txtWinType: 15, // warp points are 16 + in table + position: -1, name: -2, channel: -3, clipindex: -4, playLength: -5 + }; + + + this.element = $("
").addClass("twine_clip").css({ + "background-color": data.colour + }).click(function(e){ + if (e.ctrlKey) { + twine.timeline.selectedClips.push(clip); + } else { + $(".twine_clip").css("outline", "none"); + twine.timeline.selectedClips = [clip]; + } +console.log("ch", clip.data); + clip.element.css("outline", "1px dashed white"); + + var cui = twine.ui.clip; + cui.name.setValue(data.name); + cui.colour.setValue(data.colour); + cui.amp.setValue(data.amp); + cui.warp.setValue(data.warp); + cui.loop.setValue(data.loop); + cui.readType.setValue(data.warpMode); + cui.pitch.setValue(Math.round((Math.log(data.pitch) / Math.log(2)) * 12)); + cui.fftSize.setValue(data.fftSize); + cui.winSize.setValue(data.txtWinSize); + cui.winRandom.setValue(data.txtRandom); + cui.winOverlap.setValue(data.txtOverlap); + cui.winType.setValue(data.txtWinType); + + showEditWaveform($("#twine_clipdetailsright")); + twine.ui.showPane(twine.ui.pane.CLIP); + }); + var elWaveClip = $("
").css({position: "absolute", width: "100%", height: "100%", top: "0px", left: "0px"}).appendTo(clip.element); + var elWaveText = $("
").css({position: "absolute", width: "100%", height: "100%", top: "0px", left: "0px", "font-size": "var(--fontSizeSmall)", color: "var(--fgColor1)"}).text(data.name).appendTo(clip.element); + + var elResizeLeft = $("
").addClass("twine_clip_edge_left").appendTo(clip.element); + var elResizeRight = $("
").addClass("twine_clip_edge_right").appendTo(clip.element); + var elMove = $("
").addClass("twine_clip_centre").appendTo(clip.element); + var elWaveEdit = $("
").css({width: "100%", height: "100%", top: "0px", left: "0px"}); + + async function getDataFromTable(key) { + async function setFromKey(key) { + if (dataMode[key] < 0) return; + var value = await app.getCsound().tableGet(datatable, dataMode[key]) + data[key] = value; + } + + for (var k in dataMode) { + setFromKey(k); + } + } + + function setClipAudioUnique(onComplete) { + var cbid = app.createCallback(async function(ndata){ + await getDataFromTable(); + if (onComplete) onComplete(); + }); + app.insertScore("twine_setclipaudiounique", [0, 1, cbid]); + } + + function reloadAfterEdit(tables) { + twirl.loading.show("Loading"); + var cbid = app.createCallback(async function(ndata){ + datatable = ndata.datatable; + await getDataFromTable(); + clip.redraw(); + twine.setVisible(true); + twigs.setVisible(false); + twist.setVisible(false); + twirl.loading.hide(); + }); + var call = [0, 1, cbid, data.clipindex]; + for (let t of tables) { + call.push(t); + } + app.insertScore("twine_clipreplacetables", call); + } + + this.editInTwist = function(asUnique) { + if (!window.twist) return twirl.prompt.show("twist is unavailable in this session"); + function edit() { + twist.boot(twine); + twist.bootAudio(twine); + var tables = [data.fnL]; + if (data.fnR) tables.push(data.fnR); + twist.loadFileFromFtable(data.name, tables, function(ndata){ + if (ndata.status > 0) { + twine.setVisible(false); + twist.setVisible(true); + } + }, reloadAfterEdit); + } + if (asUnique) { + setClipAudioUnique(edit); + } else { + edit(); + } + + }; + + this.editInTwigs = function(asUnique) { + if (!window.twigs) return twirl.prompt.show("twigs is unavailable in this session"); + function edit() { + twigs.boot(twine); + var tables = [data.fnL]; + if (data.fnR) tables.push(data.fnR); + twigs.loadFileFromFtable(data.name, tables, function(ndata){ + if (ndata.status > 0) { + twine.setVisible(false); + twigs.setVisible(true); + } + }, reloadAfterEdit); + } + if (asUnique) { + setClipAudioUnique(edit); + } else { + edit(); + } + }; + + this.setData = function(modeString, v, onComplete) { + data[modeString] = v; + if (dataMode[modeString] < 0) { + if (modeString == "name") { + elWaveText.text(data.name); + } + return; + } + + function doSetData() { + if (!twirl.debug) app.getCsound().tableSet(datatable, dataMode[modeString], v); + } + + doSetData(); + if (onComplete) onComplete(); + }; + + this.getPlaybackArgs = function(cbid, time) { + return [(time) ? time: 0, data.playLength, cbid, data.clipindex, data.playLength, clip.channel.getCsChannelName()]; + }; + + this.play = function(onCallback) { + var cbid = app.createCallback(function(ndata) { + if (onCallback) onCallback(ndata); + }, true); + app.insertScore("ecp_playback_tst", clip.getPlaybackArgs(cbid)); + } + + async function getSourceTableData() { + var wavedata = []; + var tbL = await app.getTable(data.fnL); + wavedata.push(tbL); + if (data.hasOwnProperty("fnR") && data.fnR > 0) { + var tbR = await app.getTable(data.fnR); + wavedata.push(tbR); + } + return wavedata; + } + + async function setClipWaveform(noRedraw) { + if (!waveformClip) { + waveformClip = new Waveform({ + target: elWaveClip, + allowSelect: false, + showGrid: false, + bgColor: "rgb(255, 255, 255, 0)", + fgColor: "#000000" + }); + setTimeout(async function(){ + var sourceTables = await getSourceTableData(); + waveformClip.setData(sourceTables, data.duration); + }, 100); + } else { + if (!noRedraw) waveformClip.redraw(); + } + } + + async function showEditWaveform(target) { + target.empty().append(elWaveEdit); + if (!waveformEdit) { + waveformEdit = new Waveform({ + target: elWaveEdit, + allowSelect: true, + showGrid: true, + latencyCorrection: twirl.latencyCorrection // , markers: + }); + setTimeout(async function(){ + var sourceTables = await getSourceTableData(); + waveformEdit.setData(sourceTables, data.duration); + }, 100); + } else { + waveformEdit.redraw(); + } + } + + this.setWarp = function(v) { + clip.setData("warp", v); + if (!data.warp && !data.loop && data.playLength > data.duration) { + data.playLength = data.duration; + clip.setSize(); + } + }; + + this.setLoop = function(v) { + clip.setData("loop", v); + if (!data.warp && !data.loop && data.playLength > data.duration) { + data.playLength = data.duration; + clip.setSize(); + } + }; + + this.setPitch = function(semitones) { + var pitchRatio = Math.pow(2, (semitones / 12)); + clip.setData("pitch", pitchRatio); + if (data.warpMode == 0 && data.loop == 0 && data.warp == 0) { + data.playLength = data.duration / pitchRatio; + clip.setSize(); + } + }; + + this.setWarpMode = function(v) { + var prevMode = data.warpMode; + clip.setData("warpMode", v); + if (prevMode == 0 && data.warpMode != 0 && !data.loop && !data.warp) { + data.playLength = data.duration; + clip.setSize(); + } + }; + + this.setSize = function(noWaveRedraw) { + var width = data.playLength * twine.timeline.pixelsPerBeat; + clip.element.css("width", width + "px"); + setClipWaveform(noWaveRedraw); + } + + this.redraw = function(noWaveRedraw) { + if (!loaded) return; + var b = twine.timeline.beatRegion; + clip.setSize(noWaveRedraw); + if ((data.position + data.playLength) < b[0] || data.position > b[1]) { + return clip.element.hide(); + } + + var css = { + height: clip.channel.height + "px", + left: (data.position - b[0]) * twine.timeline.pixelsPerBeat + "px" + }; + if (data.position < b[0]) { + css.left = "0px"; + css.width = (data.playLength - (b[0] - data.position)) * twine.timeline.pixelsPerBeat + "px"; + } + + clip.element.show().css(css); + }; + + this.clone = function() { + var newData = Object.assign({}, data); + newData.id = twine.getNewID(); + var c = new Clip(twine, newData, clip); + clip.channel.addClip(c); + app.insertScore("twine_cloneclip", [0, 1, app.createCallback(function(ndata) { + datatable = ndata.datatable; + c.loadFromDataTable(ndata.datatable, ndata.clipindex); + }), clip.data.clipindex]); + }; + + + async function loadData(ndata, name, colour, defaultLength) { + twirl.loading.show("Loading"); + if (ndata.status == -1) { + return twirl.errorHandler("File not valid"); + } else if (ndata.status == -2) { + return twirl.errorHandler("File too large"); + } + datatable = ndata.data.datatable; + await getDataFromTable(); + data.clipindex = ndata.data.clipindex; + if (name) { + data.name = name; + } + if (defaultLength) { + data.playLength = data.duration; + } + elWaveText.text(data.name); + if (!colour) colour = twine.randomColour(); + data.colour = colour; + loaded = true; + clip.redraw(); + }; + + this.loadFromDataTable = async function(newDatatable, clipindex) { + datatable = newDatatable; + await getDataFromTable(); + data.clipindex = clipindex; + loaded = true; + clip.redraw(); + }; + + this.loadFromFtables = function(name, tables, colour) { + twirl.loading.show("Loading"); + var cbid = app.createCallback(async function(ndata){ + await loadData(ndata, name, colour); + twirl.loading.hide(); + }); + var call = [0, 1, cbid]; + for (let t of tables) { + call.push(t); + } + app.insertScore("twine_loadftables", call); + }; + + this.loadFromPath = function(path, colour) { + twirl.loading.show("Loading"); + var cbid = app.createCallback(async function(ndata){ + await loadData(ndata, path, colour, true); + twirl.loading.hide(); + }); + app.insertScore("twine_loadpath", [0, 1, cbid, path]); + }; + + function getMaxClipWidth() { + var maxWidth = 9999; + if (!data.warp && !data.loop) { + maxWidth = data.duration * twine.timeline.pixelsPerBeat; + } + return maxWidth; + } + + clip.movement = { + pos1: 0, pos2: 0, pos3: 0, pos4: 0, offset: 0, startX: 0, startY: 0, clipWidth: 0, + clipLeft: 0, clipTop: 0, lastLeft: 0, isCopying: false, + mouseDown: function(e, dragType) { + e.preventDefault(); + twine.timeline.selectedClips.forEach(function(c){ + c.movement.mouseDownInner(e, dragType); + }); + }, + mouseDownInner: function(e, dragType) { + e.preventDefault(); + this.isCopying = false; + this.offset = clip.element.offset().left + this.clipWidth = parseFloat(clip.element.css("width")); + this.clipTop = parseFloat(clip.element.css("top")); + this.clipLeft = parseFloat(clip.element.css("left")); + this.startX = e.clientX - e.target.getBoundingClientRect().left; + this.startY = e.clientY - e.target.getBoundingClientRect().top; + this.pos3 = e.clientX; + this.pos4 = e.drag; + this.lastLeft = (this.pos3 - this.startX - clip.channel.offset.left); + $("html").on("mousemove", function(e){ + clip.movement.doDrag(e, dragType); + }).on("mouseup", this.endDrag); + $("#container").css("cursor", "e-resize"); + }, + endDrag: function(e) { + e.preventDefault(); + this.isCopying = false; + $("html").off("mouseup", this.endDrag).off("mousemove"); //, this.doDrag); + $("#container").css("cursor", "pointer"); + }, + doDrag: function(e, dragType) { + e.preventDefault(); + twine.timeline.selectedClips.forEach(function(c){ + c.movement.doDragInner(e, dragType); + }); + }, + doDragInner: function (e, dragType) { + e.preventDefault(); + this.pos1 = this.pos3 - e.clientX; + this.pos2 = this.pos4 - e.clientY; + this.pos3 = e.clientX; + this.pos4 = e.clientY; + + if (dragType == "right") { + var maxWidth = getMaxClipWidth(); + var newWidth = (this.pos3 - this.startX - clip.channel.offset.left - this.clipLeft); + newWidth = twine.timeline.roundToGrid(newWidth); + if (newWidth > maxWidth) newWidth = maxWidth; + if (newWidth < minWidth) newWidth = minWidth; + data.playLength = newWidth / twine.timeline.pixelsPerBeat; + clip.element.css("width", newWidth + "px"); + + } else if (dragType == "left") { + var maxWidth = getMaxClipWidth(); + var left = (this.pos3 - this.startX - clip.channel.offset.left); + left = twine.timeline.roundToGrid(left); + if (left < 0) left = 0; + var newWidth = (clipWidth - left) + this.clipLeft; + var cWidth, cLeft; + if (newWidth < minWidth) { + cWidth = minWidth, this.clipLeft + minWidth; //(minWidth - left) + clipLeft; + } else if (newWidth > maxWidth) { + cWidth = maxWidth, cLeft = this.lastLeft; + } else { + lastLeft = left; + cWidth = newWidth, cLeft = left; + } + clip.element.css({width: cWidth + "px", left: cLeft + "px"}); + + data.playLength = newWidth / twine.timeline.pixelsPerBeat; + data.position = Math.min(0, (left / twine.timeline.pixelsPerBeat) + twine.timeline.beatRegion[0]); + + } else { + if (e.ctrlKey && !this.isCopying) { + this.isCopying = true; + clip.clone(); + } + + //var left = (this.pos3 - this.startX - clip.channel.offset.left); + var left = (this.pos3 - this.clipLeft - clip.channel.offset.left); + left = twine.timeline.roundToGrid(left); + + //var top = (this.pos4 - this.startY - clip.channel.offset.top); + var top = (this.pos4 - this.clipTop - clip.channel.offset.top); + if (top > clip.channel.height) { + if (clip.channel.index + 1 < twine.timeline.channels.length) { + clip.channel.removeClip(clip); + twine.timeline.channels[clip.channel.index + 1].addClip(clip); + } + } else if (top < 0) { + if (clip.channel.index -1 >= 0) { + clip.channel.removeClip(clip); + twine.timeline.channels[clip.channel.index - 1].addClip(clip); + } + } + if (left < 0) left = 0; + //if (left > clip.channel.width - clipWidth) left = clip.channel.width - clipWidth; + if (left > clip.channel.width) left = clip.channel.width; + data.position = (left / twine.timeline.pixelsPerBeat) + twine.timeline.beatRegion[0]; + clip.element.css("left", left + "px"); + } + } // end doDragInner + }; + + elMove.mousedown(clip.movement.mouseDown); + elResizeRight.mousedown(function(e){ + clip.movement.mouseDown(e, "right"); + }); + elResizeLeft.mousedown(function(e){ + clip.movement.mouseDown(e, "left"); + }); + +}; \ No newline at end of file diff --git a/site/app/twine/_hOLD/index.html b/site/app/twine/_hOLD/index.html new file mode 100644 index 0000000..5e9e2b4 --- /dev/null +++ b/site/app/twine/_hOLD/index.html @@ -0,0 +1,863 @@ + + + + + + + + + +
+
+

Press to begin

+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + +
Read type +
+
+ +
+ +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/site/app/twine/_hOLD/index_old.html b/site/app/twine/_hOLD/index_old.html new file mode 100644 index 0000000..351e50b --- /dev/null +++ b/site/app/twine/_hOLD/index_old.html @@ -0,0 +1,102 @@ + + + + + + + + + +
+ + \ No newline at end of file diff --git a/site/app/twine/_hOLD/index_workingold.html b/site/app/twine/_hOLD/index_workingold.html new file mode 100644 index 0000000..21812d7 --- /dev/null +++ b/site/app/twine/_hOLD/index_workingold.html @@ -0,0 +1,1251 @@ + + +twine + + + + + + + + + + + + +
+
+

Press to begin

+
+
+ +
+ + + + +
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + +
+ + + + + + + +
Read type
+ +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/site/app/twine/_hOLD/timeline.csd b/site/app/twine/_hOLD/timeline.csd new file mode 100644 index 0000000..72e03ae --- /dev/null +++ b/site/app/twine/_hOLD/timeline.csd @@ -0,0 +1,154 @@ + + +-odac + + +sr = 44100 +ksmps = 64 +nchnls = 2 +0dbfs = 1 +seed 0 + +#include "/scss/elasticlip_sequencer.udo" +;#include "/scss/mixer/base.udo" +#include "/interop.udo" +#include "/bussing.udo" +#include "/table_tools.udo" + +opcode ecpweb_getdata, S, iii + ichannel, iclipindex, itime xin + Sname = gSecp_clipnames[iclipindex] + Sresponse = sprintf("{\"-1\":%f,\"-2\":\"%s\",\"-4\":%d", itime, Sname, ichannel) + + index = 2 + while (index < giecp_controlitemnum) do + ival = tab_i(index, giecp_fnclips[iclipindex]) + Sformat = strcat(",\"%d\":%", (frac(ival) == 0) ? "d" : "f") + Sresponse = strcat(Sresponse, sprintf(Sformat, index, ival)) + index += 1 + od + Sresponse = strcat(Sresponse, "}") + xout Sresponse +endop + +opcode ecpweb_getdata, S, i + iseqindex xin + ichannel, iclipindex, itime ecpseq_get iseqindex + Sresponse ecpweb_getdata ichannel, iclipindex, itime + xout Sresponse +endop + +instr ecpweb_getdata + icbid = p4 + iseqindex = p5 +endin + +instr ecpweb_tabdestroy + ifn = p4 + tab_destroy ifn + turnoff +endin + +instr ecpweb_setbpm + ibpm = p4 + gkseq_tempo init ibpm + turnoff +endin + +instr ecpweb_loadsound + icbid = p4 + Spath = strget(p5) + ichannel = p6 + itime = p7 + iforcemono = p8 + + iclipindex ecp_loadsound Spath, 4, iforcemono ;beats contentious, analyse and also set warp mode + iseqindex ecpseq_getnewindex + + ecpseq_set iseqindex, ichannel, iclipindex, itime + Sdata ecpweb_getdata ichannel, iclipindex, itime + + ifnwave ecp_getwaveform iclipindex + + Sresponse = sprintf("{\"cbid\":%d,\"data\":%s,\"waveform\":%d}", icbid, Sdata, ifnwave) + io_sendstring("callback", Sresponse) + turnoff +endin + + +instr ecpweb_copyclip + icbid = p4 + iseqindex = p5 + ichannel = p6 + itime = p7 + + i_, iclipindex, i_ ecpseq_get iseqindex + + iseqindex ecpseq_getnewindex + ecpseq_set iseqindex, ichannel, iclipindex, itime + Sresponse = sprintf("{\"cbid\":%d}", icbid) + io_sendstring("callback", Sresponse) +endin + + +instr ecpweb_setdata + icbid = p4 + iseqindex = p5 + idataindex = p6 + ;p7 is value + ihastwin = p8 + + Sresponse = sprintf("{\"cbid\":%d", icbid) + iapplyupdate = 0 + ichannel, iclipindex, itime ecpseq_get iseqindex + + if (ihastwin == 1 && idataindex != -1) then + iclipindex ecp_cloneclip iclipindex + Sresponse = strcat(Sresponse, sprintf(",\"clipindex\":%d", iclipindex)) ; needed? + endif + + if (idataindex < 0) then + if (idataindex == -2) then ;name + Sname = strget(p7) + ecp_set_name iclipindex, Sname + Sresponse = strcat(Sresponse, sprintf(",\"name\":\"%s\"", Sname)) + elseif (idataindex == -1) then ;position + itime = p7 + iapplyupdate = 1 + elseif (idataindex == -4) then ;channel + ichannel = p7 + iapplyupdate = 1 + endif + + elseif (idataindex >= 2) then + ivalue = p7 + tabw_i ivalue, idataindex, giecp_fnclips[iclipindex] + endif + + if (iapplyupdate == 1) then + ecpseq_set iseqindex, ichannel, iclipindex, itime + endif + + io_sendstring("callback", strcat(Sresponse, "}")) + turnoff +endin + +instr boot + schedule("mx_boot", 0, 1) + + aL0, aR0 bus_read "mxchan0" + aL1, aR1 bus_read "mxchan1" + aL2, aR2 bus_read "mxchan2" + aL3, aR3 bus_read "mxchan3" + + aoutL = aL0 + aL1 + aL2 + aL3 + aoutR = aR0 + aR1 + aR2 + aR3 + outs aoutL, aoutR +endin + + + +i"boot" 0 36000 +f0 z + + \ No newline at end of file diff --git a/site/app/twine/_hOLD/timeline_base.html b/site/app/twine/_hOLD/timeline_base.html new file mode 100644 index 0000000..fc460bd --- /dev/null +++ b/site/app/twine/_hOLD/timeline_base.html @@ -0,0 +1,633 @@ + + + + + + + + +
+
+
+
+
+ + + + + + + + + + +
Read type +
+ +
+
+
+ +
+
+
+
+ + \ No newline at end of file -- cgit v1.2.3