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 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 499 insertions(+) create mode 100644 site/app/twine/_hOLD/clip.js (limited to 'site/app/twine/_hOLD/clip.js') 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 -- cgit v1.2.3