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/twine/_hOLD/timeline_base.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/twine/_hOLD/timeline_base.html')
-rw-r--r-- | site/app/twine/_hOLD/timeline_base.html | 633 |
1 files changed, 633 insertions, 0 deletions
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 @@ +<html>
+<head>
+<style type="text/css">
+
+body {
+ font-family: Arial, sans-serif;
+ font-size: 11pt;
+}
+
+#header {
+ position: absolute;
+ top: 0px;
+ height: 30px;
+ left: 0px;
+ width: 100%;
+ background-color: #545454;
+}
+
+#headertable {
+ height: 30px;
+}
+
+#clipdetails {
+ display: none;
+}
+
+
+#main {
+ position: absolute;
+ top: 30px;
+ height: 100%;
+ left: 0px;
+ width: 100%;
+}
+
+#timeline {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 70%
+}
+
+.timelinetext {
+ font-size: 8pt;
+ opacity: 0.9;
+ position: absolute;
+ color: #121212;
+ top: 2px;
+}
+
+.timelinemarker {
+ width: 1px;
+ position: absolute;
+ background-color: #bdbdbd;
+ opacity: 0.9;
+ height: 100%;
+ top: 0px;
+ z-index: 50;
+}
+
+.smbut {
+ font-size: 8pt;
+ background-color: #b5b01d;
+ border: 1px solid black;
+}
+
+
+
+#details {
+ position: absolute;
+ left: 0px;
+ top: 70%;
+ width: 100%;
+ height: 30%;
+ background-color: #dcdcdc;
+}
+
+#clipdetailsleft {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 30%;
+ height: 100%;
+ background-color: #acacac;
+}
+
+#clipdetailsright {
+ position: absolute;
+ left: 30%;
+ top: 0px;
+ width: 70%;
+ height: 100%;
+ background-color: #cacaca;
+}
+
+.channel {
+ height: 30px;
+ width: 100%;
+ border-bottom: 1px solid #aaaaaa;
+ left: 0px;
+}
+
+.channeldetails {
+ position: absolute;
+ height: 30px;
+ left: 0px;
+ width: 10%;
+}
+
+.channelclips {
+ position: absolute;
+ height: 30px;
+ left: 10%;
+ width: 90%;
+ background-color: #cdcdcd;
+}
+
+.clip {
+ user-select: none;
+ position: absolute;
+ padding: 0px;
+ cursor: move;
+ z-index: 70;
+ width: 100px;
+ height: 30px;
+ color: #000000;
+ overflow: hidden;
+}
+</style>
+<script type="text/javascript" src="https://apps.csound.1bpm.net/code/jquery.js"></script>
+<script type="text/javascript">
+
+var clips = {};
+var channels = [];
+var maxID = 0;
+var chanHeight = 30;
+
+window.csseq = {};
+
+function getID() {
+ return maxID++;
+}
+
+var TimelineGrid = function(data) {
+ var self = this;
+
+ if (!data) {
+ var data = {
+ snapToGrid: true,
+ gridVisible: true,
+ timeSigMarker: 4,
+ resolution: null,
+ startBeat: 1,
+ endBeat: 16,
+ bpm: null
+ };
+ }
+
+ this.getSaveData = function() {
+ return data;
+ };
+
+ function calcViewport() {
+ data.minLeft = (window.screen.width / 100) * 10;
+ var width = window.screen.width - data.minLeft;
+ var beats = data.endBeat - data.startBeat;
+ data.pixelsPerBeat = width / beats;
+ return {
+ minLeft: data.minLeft,
+ width: width,
+ beats: beats,
+ pixelsPerBeat: Math.round(data.pixelsPerBeat)
+ }
+ }
+
+ function draw() {
+ $(".timelinemarker").remove();
+ $(".timelinetext").remove();
+ if (!data.gridVisible) {
+ return;
+ }
+
+ var target = $("#timeline");
+ var geometry = calcViewport();
+
+ var beat = data.startBeat;
+
+ var width;
+ var fontWeight;
+ for (var x = geometry.minLeft; x < window.screen.width; x += geometry.pixelsPerBeat) {
+ if ((beat - 1) % data.timeSigMarker == 0) {
+ width = 2;
+ fontWeight = "bold";
+ } else {
+ width = 1;
+ fontWeight = "normal";
+ }
+ $("<div />").attr("class", "timelinemarker").appendTo(target).css("width", width).css("left", x);
+ $("<div />").attr("class", "timelinetext").appendTo(target).css("font-weight", fontWeight).css("left", x + 2).text(beat);
+ beat ++;
+ }
+ }
+
+ Object.defineProperty(this, "startBeat", {
+ get: function() { return data.startBeat; },
+ set: function(x) {
+ data.startBeat = x;
+ draw();
+ }
+ });
+
+ Object.defineProperty(this, "endBeat", {
+ get: function() { return data.startBeat; },
+ set: function(x) {
+ data.startBeat = x;
+ draw();
+ }
+ });
+
+ Object.defineProperty(this, "minLeft", {
+ get: function() { return data.minLeft; },
+ set: function(x) {}
+ });
+
+ Object.defineProperty(this, "pixelsPerBeat", {
+ get: function() { return data.pixelsPerBeat; },
+ set: function(x) {}
+ });
+
+ Object.defineProperty(this, "snapToGrid", {
+ get: function() { return data.snapToGrid; },
+ set: function(x) {
+ data.snapToGrid = (x == 1);
+ }
+ });
+
+ Object.defineProperty(this, "gridVisible", {
+ get: function() { return data.gridVisible; },
+ set: function(x) {
+ data.gridVisible = (x == 1);
+ draw();
+ }
+ });
+
+
+
+ draw();
+};
+
+
+var Sequencer = function(data) {
+ var self = this;
+ var gridSnap = 0;
+ var timeScale = 1;
+
+ if (!data) {
+ var data = {
+ tempo: 120,
+ playing: false
+ };
+ }
+
+ this.setTempo = function(v) {
+ insertScore("ecpweb_setglobal", [0, 1, 0, v]);
+ };
+
+ this.getSaveData = function() {
+ var sdata = {"sequencer": data, "channels": [], "clips": {}};
+ for (var x in channels) {
+ sdata.channels.push(channels[x].getSaveData());
+ }
+ for (var x in clips) {
+ sdata.clips[x] = clips[x].getSaveData();
+ }
+ return sdata;
+ };
+
+ this.loadSaveData = function(v) {
+ data = v.sequencer;
+ for (var x in v.channels) {
+ new Channel(v.channels[x]);
+ }
+ };
+
+ Object.defineProperty(this, "playing", {
+ get: function() { return data.playing; },
+ set: function(x) {
+ data.playing = x;
+ }
+ });
+};
+
+
+var Channel = function(data) {
+ var self = this;
+ channels.push(this);
+
+ if (!data) {
+ var index = channels.length;
+ var data = {
+ name: "Channel " + index,
+ index: index
+ };
+ } else {
+ var index = data.index;
+ }
+
+ var element = $("<div />").attr("id", "channel" + index).attr("class", "channel").appendTo("#timeline").append(
+ $("<div />").attr("id", "channeldetails" + index).attr("class", "channeldetails").text(data.name)
+ ).append(
+ $("<div />").attr("id", "channelclips" + index).attr("class", "channelclips")
+ );
+};
+
+var Clip = function(channel, data, parent) {
+ var self = this;
+ var loaded = false;
+
+ if (!data) {
+ var id = getID();
+ var data = {
+ name: "Clip " + id,
+ channel: channel,
+ id: id,
+ clipindex: null,
+ beatTime: 0,
+ colour: "#" + (Math.random() * 0xFFFFFF << 0).toString(16)
+ };
+ } else {
+ var id = data.id;
+ }
+ clips[id] = this;
+ var element = $("<div />").attr("class", "clip").attr("id", "clip" + id).text(data.name).click(function() {
+ csseq.selectedClip = self;
+ $("#clipdetails").show();
+ $("#clip_name").val(data.name);
+ $("#clip_colour").val(data.colour);
+
+ }).css("top", (channel * chanHeight) + "px").css("background-color", data.colour).mousedown(handle_mousedown)
+ .css("left", ((data.beatTime * csseq.timeline.pixelsPerBeat)) + "px")
+ .appendTo($("#channelclips" + channel));
+ // resizable()
+
+ Object.defineProperty(this, "colour", {
+ get: function() { return data.colour; },
+ set: function(x) {
+ data.colour = x;
+ element.css("background-color", data.colour);
+ }
+ });
+
+ var dataMode = {
+ 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,
+ soundPath: -3,
+ channel: -4
+ }
+
+ for (let x in dataMode) {
+ Object.defineProperty(this, x, {
+ get: function() { return data[x] },
+ set: function(v) {
+ self.setData(x, v);
+ }
+ });
+ }
+
+ /*// v should become defunct
+ Object.defineProperty(this, "name", {
+ get: function() { return data.name; },
+ set: function(x) {
+ data.name = x;
+ element.text(data.name);
+
+ // self.setData("name", x);
+ }
+ });*/
+
+
+ /*
+ function getData() {
+ var cbid = app.createCallback(function(ndata) {
+ for (var x in ndata.data) {
+ data[x] = ndata.data[x];
+ }
+ });
+ app.insertScore("ecpweb_getdata", [0, 1, cbid, clipindex]);
+ }*/
+
+ this.setData = function(modeString, v) {
+ var cbid = app.createCallback(function(ndata) {
+ if (ndata.hasOwnProperty("clipindex")) {
+ data.clipindex = ndata.clipindex;
+ }
+ data[modeString] = v;
+ if (modeString == "name") {
+ element.text(data.name);
+ }
+ });
+ app.insertScore("ecpweb_setdata", [0, 1, cbid, id, dataMode[modeString], v, (parent ? 1 : 0)]); // having ecp_cloneclip in if needed
+ }
+
+ this.loadTest = function() {
+ self.loadFromPath("test.mp3");
+ };
+
+ this.loadFromPath = function(path) {
+ var cbid = app.createCallback(function(ndata) {
+ for (var x in ndata.data) {
+ data[x] = ndata.data[x];
+ }
+ data.soundPath = path;
+ loaded = true;
+ });
+ app.insertScore("ecpweb_loadsound", [0, 1, cbid, path]);
+ };
+
+ this.clone = function() {
+ var newdata = Object.assign({}, data);
+ data.id = getID();
+ return new Clip(data.channel, newdata, self);
+ };
+
+ this.randomiseWarpPoints = function(mode) { // mode is -1, 0 or 1 I think..
+ if (!mode) mode = 0;
+ var cbid = app.createCallback(function(ndata) {
+ notify("OK");
+ });
+ app.insertScore("ecpweb_randomisewarppoints", [0, 1, cbid, mode]);
+ };
+
+
+ function handle_mousedown(e){
+
+ window.my_dragging = {};
+ my_dragging.pageX0 = e.pageX;
+ my_dragging.pageY0 = e.pageY;
+ my_dragging.elem = this;
+ my_dragging.offset0 = $(this).offset();
+ var isCopying = e.ctrlKey;
+
+ if (isCopying) { // && loaded
+ self.clone();
+ }
+
+ function handle_dragging(e){
+ var left = my_dragging.offset0.left + (e.pageX - my_dragging.pageX0);
+
+ var minLeft = (window.screen.width / 100) * 10;
+
+ //round
+ // left = Math.ceil(left / pixelsPerBeat) * pixelsPerBeat;
+
+ if (csseq.timeline.snapToGrid) {
+ left = (Math.ceil((left - minLeft) / csseq.timeline.pixelsPerBeat) * csseq.timeline.pixelsPerBeat) + minLeft;
+ }
+
+
+ if (left < minLeft) {
+ left = minLeft
+ }
+ data.beatTime = csseq.timeline.startBeat + ((left - minLeft) / csseq.timeline.pixelsPerBeat);
+
+ var top = my_dragging.offset0.top + (e.pageY - my_dragging.pageY0);
+ top = Math.ceil(top / chanHeight) * chanHeight;
+ var maxTop = chanHeight * channels.length;
+ if (top > maxTop) {
+ top = maxTop;
+ } else if (top < 30) {
+ top = 30;
+ }
+
+
+ $(my_dragging.elem)
+ .offset({top: top, left: left});
+ }
+
+ function handle_mouseup(e){
+ $("body")
+ .off("mousemove", handle_dragging)
+ .off("mouseup", handle_mouseup);
+ }
+
+ $("body").on("mouseup", handle_mouseup).on("mousemove", handle_dragging);
+ }
+
+ /*
+ this.setLength = function(v) {
+ setData("length", v);
+ }; // now made generic above.
+ */
+};
+
+
+
+
+$(function() {
+ csseq.timeline = new TimelineGrid();
+ csseq.seq = new Sequencer();
+
+
+ $(".smbut").attr("value", 0).click(function(){
+ var val;
+ var col;
+ if ($(this).attr("value") == 0) {
+ val = 1;
+ col = "#f2e30c";
+ } else {
+ val = 0;
+ col = "#b5b01d";
+ }
+ $(this).attr("value", val).css("background-color", col);
+ });
+
+ $("#head_snap").click(function() {
+ csseq.timeline.snapToGrid = $(this).attr("value");
+ });
+
+ $("#head_showgrid").click(function() {
+ csseq.timeline.gridVisible = $(this).attr("value");
+ });
+
+ $("#head_play").click(function() {
+ if (csseq.seq.playing) {
+ app.insertScore("ecpseq_stop");
+ } else {
+ var cbid = app.createCallback(function(data) {
+ if (data.state == "playing") {
+ csseq.seq.playing = true;
+ $(this).text("Stop");
+ } else if (data.state == "stopped") {
+ csseq.seq.playing = false;
+ $(this).text("Play");
+ app.removeCallback(data.cbid);
+ }
+ }, true);
+ app.insertScore("ecpseq_play", [0, 36000, cbid, csseq.timeline.startBeat]);
+ }
+ });
+
+ new Channel();
+ new Channel();
+ new Channel();
+ new Clip(0);
+ new Clip(1);
+ new Clip(2);
+
+
+ $("#clip_colour").change(function(){
+ csseq.selectedClip.colour = $(this).val();
+ });
+
+ $("#clip_name").change(function(){
+ csseq.selectedClip.name = $(this).val();
+ });
+
+});
+/*
+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,
+*/
+</script>
+</head>
+<body>
+<div id="header">
+ <table id="headertable"><tbody><tr>
+ <td><button id="play" class="smbut">Play</button></td>
+ <td><button id="head_snap" class="smbut">Snap</button></td>
+ <td><button id="head_showgrid" class="smbut">Grid</button></td>
+ </tr></tbody></table>
+</div>
+<div id="main">
+ <div id="timeline"></div>
+ <div id="details">
+ <div id="clipdetails">
+ <div id="clipdetailsleft">
+ <table><tbody>
+ <tr>
+ <td><input type="color" id="clip_colour"></td><td><input type="text" id="clip_name"></td>
+ </tr>
+ <tr>
+ <td>Read type</td>
+ <td><select id="clip_readtype">
+ <option value="0">Repitch</option>
+ <option value="1">Grain</option>
+ <option value="2">FFT</option>
+ <option value="3">FFTab</option>
+ </select>
+ </td>
+ </tr>
+ <tr><td><button id="clip_warp" class="smbut">Warp</button></td><td><button class="smbut">Loop</button></td></tr>
+ <tr><td>
+ <x-knob divisions="12" min="-12" max="12">
+ </td><td></td></tr>
+ </tbody></table>
+ </div>
+ <div id="clipdetailsright">
+
+ </div>
+ </div>
+ </div>
+</div>
+</body>
+</html>
\ No newline at end of file |