Compare commits

...

4 commits

10 changed files with 230 additions and 139 deletions

29
bin/web/assets/record.svg Normal file
View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 83.2 83.2" style="enable-background:new 0 0 83.2 83.2;" xml:space="preserve">
<style type="text/css">
.st0{fill:#ED2024;}
</style>
<g>
<circle class="st0" cx="41.6" cy="41.6" r="40.9"/>
<g>
<path d="M29,43.8c0.2-0.1,0.4-0.1,0.5-0.2c0.9-0.6,1.5-1.4,2-2.4c0.5-1,0.7-2.1,0.7-3.2c0-2.3-0.8-4-2.3-5.3c-1.6-1.3-3.9-2-7-2
h-2.7c-1,0-2,0-3,0s-2,0-2.9,0c0.2,1,0.3,2.3,0.4,3.9c0.1,1.6,0.1,3.9,0.1,7.1c0,3.2,0,5.5-0.1,7.1c-0.1,1.5-0.2,2.8-0.4,3.9H22
c-0.2-1-0.3-2-0.3-3.2c-0.1-0.9-0.1-2.2-0.1-3.6c0.1,0,0.2,0,0.2,0c0.3,0,0.5,0,0.6,0c0.8,1.6,1.5,3,1.9,3.9
c0.5,1.1,0.9,2.1,1.2,3h8.6c-0.7-1-1.5-2.3-2.3-3.6C31.2,47.8,30.2,46,29,43.8z M24.8,39.9c-0.4,0.4-1.1,0.7-2,0.7
c-0.3,0-0.6,0-0.7,0c-0.1,0-0.3,0-0.4,0c0-1.7,0-3.2,0-4.4c0.2,0,0.4,0,0.6,0h0.5c0.9,0,1.5,0.2,2,0.6c0.4,0.4,0.7,0.9,0.7,1.5
C25.4,38.9,25.2,39.5,24.8,39.9z"/>
<path d="M42.6,47.1h-0.3c0,0-0.1,0-0.1,0c0-0.5-0.1-1-0.1-1.7c0-0.3,0-0.7,0-1c0.2,0,0.3,0,0.5,0c1.4,0,2.6,0,3.5,0.1
c1,0,1.8,0.1,2.6,0.2v-6.2c-0.8,0.1-1.6,0.2-2.6,0.2c-1,0-2.1,0.1-3.5,0.1c-0.2,0-0.3,0-0.5,0c0-0.1,0-0.3,0-0.5
c0-0.9,0-1.6,0.1-2.1c0.1,0,0.3,0,0.4,0c1.6,0,3,0,4.1,0.1c1.1,0.1,2.2,0.2,3.2,0.4l-0.5-6.2c-1.2,0.1-3.7,0.1-7.5,0.1
c-3.1,0-5.5,0-7.2-0.1c0.2,1.1,0.3,2.4,0.4,4c0.1,1.6,0.1,4,0.1,7c0,3.1,0,5.4-0.1,7c-0.1,1.6-0.2,3-0.4,4c2.6-0.1,5-0.1,7.1-0.1
h1.1c2.9,0,5.1,0,6.7,0.1l0.6-6.2c-1.1,0.2-2.3,0.4-3.5,0.5C45.6,47,44.2,47.1,42.6,47.1z"/>
<path d="M66.3,45.7c-0.4,0.3-0.9,0.6-1.5,0.8c-0.6,0.2-1.2,0.3-1.9,0.3c-0.8,0-1.6-0.2-2.3-0.6c-0.7-0.4-1.2-1-1.6-1.8
c-0.4-0.8-0.6-1.8-0.6-3c0-1.2,0.2-2.2,0.6-3c0.4-0.8,0.9-1.4,1.6-1.7c0.7-0.4,1.4-0.6,2.2-0.6c0.6,0,1.3,0.1,1.9,0.3
c0.6,0.2,1.1,0.5,1.5,0.9l2.8-6.2c-0.7-0.4-1.6-0.6-2.6-0.9c-1-0.2-2.1-0.3-3.4-0.3c-2.4,0-4.5,0.5-6.2,1.4c-1.7,0.9-3.1,2.3-4,4
c-0.9,1.7-1.4,3.8-1.4,6.1c0,2.3,0.5,4.3,1.4,6c0.9,1.7,2.2,3,3.9,4c1.7,0.9,3.7,1.4,6.1,1.4c1.3,0,2.5-0.1,3.6-0.4
c1.1-0.2,2-0.5,2.7-0.9L66.3,45.7z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -145,7 +145,6 @@ const Audio = function(tp, record) {
const bb = fft_Dom.getBoundingClientRect();
const x = e.clientX - bb.x;
freq_down = mapValue(e.clientX, bb.x, bb.x + bb.width, 0, 256 * 8 / 2, true);
console.log('up',JSON.parse(JSON.stringify(e)), e);
});
//removeAudioOptions();
@ -182,8 +181,9 @@ const Audio = function(tp, record) {
console.log("Audio::addAudioButton",
`impossible! cannot find panelPropContainer for ${propTitle}`);
} else if (container.querySelector('.audioButton') !== null) {
console.log("Audio::addAudioButton",
`already added an audio button for ${propTitle}`);
// this is super verbose, let's not log by default
//console.log("Audio::addAudioButton",
//`already added an audio button for ${propTitle}`);
} else {
const button = document.createElement('div');
button.classList.add('audioButton');
@ -478,6 +478,7 @@ const Audio = function(tp, record) {
let a = mapValue(max_v, 0, 255, m.min_out, m.max_out, true);
m.value = m.value * m.smoothing + (1.0 - m.smoothing) * a;
propsToSet.push({
title: propTitle,
prop: layer.theatreObject.props[propTitle],
value: m.value,
});
@ -487,6 +488,7 @@ const Audio = function(tp, record) {
let a = mapValue(max_i, 0, bufferLengthAlt-1, m.min_out, m.max_out, true);
m.value = m.value * m.smoothing + (1.0 - m.smoothing) * a;
propsToSet.push({
title: propTitle,
prop: layer.theatreObject.props[propTitle],
value: m.value,
});
@ -501,21 +503,33 @@ const Audio = function(tp, record) {
}
});
if (propsToSet.length > 0 && frameCount % 2 === 0) {
tp.studio.transaction(({
set
}) => {
propsToSet.forEach((p) => {
set(p.prop, p.value, true);
if (!record.isRecording()) {
tp.studio.transaction(({
set
}) => {
propsToSet.forEach((p) => {
set(p.prop, p.value, true);
});
});
});
} else {
propsToSet.forEach((p) => {
// TODO: this does not have to be queried
// but we could store it in a map/set/dictionary/array/object
const inputElement = tp
.getPanelPropContainer(p.title)
.querySelector('input.recording');
if (inputElement !== null) {
inputElement.value = p.value;
inputElement.dispatchEvent(new Event('change'));
}
});
}
}
const panel = tp.getPanel();
const fft_images = panel.querySelectorAll('.audio_fft');
if (fft_images !== null) {
const src = canvas.toDataURL();
if (window.printDebug === true) {
console.log({canvas, src, fft_images, panel}, "DEBUG AUDIO");
}
fft_images.forEach((e) => {
e.src = src;
});

View file

@ -85,6 +85,9 @@ const config = {
ignoreProps: ['transformOrigin', 'fontFamily', 'text', 'mirror_x', 'mirror_y', 'mirror_xy', 'fontVariationAxes', 'color'],
defaultSmoothing: 0.7,
},
record: {
ignoreProps: ['fontVariationAxes','letterDelays','color'],
},
midi: {
touchTimeThreshold_s: 0.5,
smoothingMix: 0.1,

File diff suppressed because one or more lines are too long

View file

@ -55,6 +55,7 @@ const Layer = function(tp, layerID, fontsAndAxes, autoInit = true) {
text: config.layer.defaultTexts[Math.floor(Math.random()*config.layer.defaultTexts.length)],
};
let updateValuesViaTheatre = true;
let lastValues = {};
let fontsHashMap = {};
let sequenceEventBuffer = [];
@ -204,6 +205,8 @@ const Layer = function(tp, layerID, fontsAndAxes, autoInit = true) {
const onValuesChange = (values) => {
if (values.dummy === true)
return;
if (!updateValuesViaTheatre)
return;
window.isRenderDirty = true;
if (Object.keys(values).length > 1) {
values.text = values.text.trim();
@ -792,11 +795,18 @@ const Layer = function(tp, layerID, fontsAndAxes, autoInit = true) {
panel.addEventListener("mouseover", showBoundingBoxDivIfSelected);
panel.addEventListener("mouseleave", hideBoundingBoxDiv);
// should we have an audio object, let's inject the buttons, etc
if (typeof audio === 'object' && audio.hasOwnProperty('injectPanel')) {
audio.injectPanel(this);
} else {
console.log('Layer::findInjectPanel', `cannot inject audio panel for ${this.id()} for some reason.`);
}
// should we have a record object, let's inject the buttons, etc
if (typeof record === 'object' && record.hasOwnProperty('injectPanel')) {
record.injectPanel(this);
} else {
console.log('Layer::findInjectPanel', `cannot inject record panel for ${this.id()} for some reason.`);
}
injectedPanel = true;
const detail = {titles: Object.keys(panelPropTitles), containers: Object.keys(panelPropContainers)};
@ -1036,6 +1046,9 @@ const Layer = function(tp, layerID, fontsAndAxes, autoInit = true) {
return cppProps;
};
this.onValuesChange = onValuesChange;
this.updateValuesViaTheatre = (doIt) => {
updateValuesViaTheatre = doIt;
};
this.prepareForDepartureFromThisBeautifulExperience = () => {
this.hide();
hideBoundingBoxDiv();

View file

@ -72,8 +72,8 @@ const interactor = new Interactor();
const moduleFS = new ModuleFS();
window.moduleFS = moduleFS;
const record = new Record(tp);
window.debug_record = record;
const audio = new Audio(tp, record); // possibly nicer if we pass tp instead of attaching to window
window.record = record;
const audio = new Audio(tp, record);
window.audio = audio;
window.panelFinderTimeout = false;
@ -410,6 +410,10 @@ window.getLayers = () => {
return layers;
};
window.getLayer = (layerID) => {
return layers.find((layer) => layer.id() === layerID);
};
window.moveLayerUp = (layerID) => {
layerOrder.moveUp(layerID);
};

View file

@ -1,8 +1,9 @@
const Record = function(tp) {
const hot = {};
let isRecording = false;
const addRecordButton = (layer, propTitle, isActive) => {
const addRecordButton = (layer, propTitle) => {
const panel = tp.getPanel();
const panelPropTitle = tp.getPanelPropTitle(propTitle);
if (panelPropTitle !== null) {
@ -11,8 +12,9 @@ const Record = function(tp) {
console.log("Record::addRecordButton",
`impossible! cannot find panelPropContainer for ${propTitle}`);
} else if (container.querySelector('.recordButton') !== null) {
console.log("Record::addRecordButton",
`already added an record button for ${propTitle}`);
// this is super verbose, let's not log by default
//console.log("Record::addRecordButton",
//`already added an record button for ${propTitle}`);
} else {
const button = document.createElement('div');
button.classList.add('recordButton');
@ -24,9 +26,13 @@ const Record = function(tp) {
hot[layer.id()] = {};
}
if (!hot[layer.id()].hasOwnProperty(propTitle)) {
hot[layer.id()][propTitle] = {};
hot[layer.id()][propTitle] = {
recording: [],
};
button.classList.add('active');
startRecording();
} else {
stopRecording();
delete hot[layer.id()][propTitle];
if (Object.keys(hot[layer.id()]).length === 0) {
delete hot[layer.id()];
@ -41,8 +47,142 @@ const Record = function(tp) {
}
};
const cloneInput = (layer, propTitle) => {
const panel = tp.getPanel();
const panelPropTitle = tp.getPanelPropTitle(propTitle);
if (panelPropTitle !== null) {
const container = tp.getPanelPropContainer(panelPropTitle);
if (container === null) {
console.log("Record::cloneInput",
`impossible! cannot find panelPropContainer for ${propTitle}`);
} else if (container.querySelector('input.recording') !== null) {
console.log("Record::cloneInput",
`already cloned input for ${propTitle}`);
} else {
const input = container.querySelector('input');
if (input === null) {
console.log("Record::cloneInput",
`uuh.. seems there is no input to clone for ${propTitle}`);
} else {
const input_clone = input.cloneNode();
input_clone.classList.value = '';
input_clone.classList.add('recording');
input.parentNode.after(input_clone);
input.setAttribute('data-previousDisplay', input.style.display);
input.style.display = 'none';
return input_clone;
}
}
}
return null;
};
const uncloneInput = (layer, propTitle) => {
const panel = tp.getPanel();
const panelPropTitle = tp.getPanelPropTitle(propTitle);
if (panelPropTitle !== null) {
const container = tp.getPanelPropContainer(panelPropTitle);
if (container === null) {
console.log("Record::uncloneInput",
`impossible! cannot find panelPropContainer for ${propTitle}`);
} else if (container.querySelector('input.recording') === null) {
console.log("Record::uncloneInput",
`already uncloned input for ${propTitle}`);
} else {
const input = container.querySelector('input:not(.recording)');
const input_clone = container.querySelector('input.recording');
if (input === null ) {
console.log("Record::uncloneInput",
`uuh.. seems there is no input for ${propTitle}`);
} else if (input_clone === null ) {
console.log("Record::uncloneInput",
`uuh.. seems there is no input_clone for ${propTitle}`);
} else {
input_clone.remove();
input.removeAttribute('data-previousDisplay');
const previousInputDisplay = input.getAttribute('data-previousDisplay');
input.style.display = previousInputDisplay;
}
}
}
};
const injectPanel = (layer) => {
const props = Object.keys(layer.theatreObject.value);
props.forEach((propTitle) => {
if (config.record.ignoreProps.indexOf(propTitle) < 0) {
addRecordButton(layer, propTitle);
}
});
};
const startRecording = () => {
tp.sheet.sequence.pause();
const layerKeys = Object.keys(hot);
layerKeys.forEach((layerID) => {
const layer = getLayer(layerID);
layer.updateValuesViaTheatre(false);
const propTitles = Object.keys(hot[layerID]);
propTitles.forEach((propTitle) => {
// NOTE: layerID is not actually used atm
// and should be the layer anyways
const input_clone = cloneInput(layerID, propTitle);
if (input_clone !== null) {
input_clone.addEventListener('change', (e) => {
hot[layerID][propTitle].recording.push({
position: tp.sheet.sequence.position,
value: parseFloat(input_clone.value),
});
});
} else {
console.log('whoops input_clone is null');
}
});
tp.sheet.sequence.position = 0;
tp.sheet.sequence.play();
});
isRecording = true;
};
const stopRecording = () => {
console.log('stoprecording');
const layerKeys = Object.keys(hot);
console.log({layerKeys});
layerKeys.forEach((layerID) => {
console.log(layerID);
const layer = getLayer(layerID);
layer.updateValuesViaTheatre(true);
const propTitles = Object.keys(hot[layerID]);
const keyframes = [];
propTitles.forEach((propTitle) => {
console.log(propTitle);
// NOTE: layerID is not actually used atm
// and should be the layer anyways
uncloneInput(layerID, propTitle);
console.log('should have uncloned input for ' + propTitle);
keyframes.push({
path: [propTitle],
keyframes: hot[layerID][propTitle].recording,
});
});
setTimeout(() => {
console.log('adding the keyframes now because we wnat it to happen right now please');
tp.addKeyframes(layer, keyframes);
}, 2000);
});
isRecording = false;
};
// public
this.addRecordButton = addRecordButton;
this.getHot = () => {
return hot;
};
this.isRecording = () => {
return isRecording;
};
this.injectPanel = injectPanel;
this.startRecording = startRecording;
this.stopRecording = stopRecording;
};
export {

View file

@ -1,118 +0,0 @@
const scannerLine = document.getElementById("scannerLine");
const scannerLineH = document.getElementById("scannerLineH");
$(document).ready(function() {
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
$("body").removeClass("hideBody");
$("body").addClass("mobile");
}else if(('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0) && (testratio<0.7777777) ){
$("body").removeClass("hideBody");
$("body").addClass("mobile mobileOld");
}else{
$("body").removeClass("hideBody");
$("body").addClass("desktop")
};
const img = new Image();
img.crossOrigin = "anonymous";
img.src = "./media/360_F_163966311_qh3qSk57mw9oLPOklZigzX9zlB5DgdaM.jpeg";
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const scanner = $(".scanner");
const destination = document.getElementById("letter");
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
img.addEventListener("load", () => {
canvas.height = canvas.width * (img.height / img.width);
scanner.css("width", $("#canvas").width());
scanner.css("height", $("#canvas").height());
var hRatio = canvas.width / img.width ;
var vRatio = canvas.height / img.height ;
var ratio = Math.min ( hRatio, vRatio );
ctx.drawImage(img, 0,0, img.width, img.height, 0,0,img.width*ratio, img.height*ratio);
// ctx.drawImage(img, 0, 0);
img.style.display = "none";
});
const hoveredColor = document.getElementById("hovered-color");
const selectedColor = document.getElementById("selected-color");
// let rect = scannelLine.getBoundingClientRect();
function pick() {
const bounding = canvas.getBoundingClientRect();
const letters = document.getElementById("typeMaster");
const letter = $(".letter");
letter.each(function(i,e){
let rect = scannerLine.getBoundingClientRect();
let rectH = scannerLineH.getBoundingClientRect();
const x = rect.left - bounding.left;
const y = rectH.top - bounding.top;
const pixel = ctx.getImageData(x - (i*2), y , 1, 1);
const data = pixel.data;
let rgba = `rgba(${data[0]}, ${data[1]}, ${data[2]}, ${data[3] / 255})`;
hoveredColor.style.background = rgba;
hoveredColor.textContent = rgba;
// letters.style.color = rgba;
// $(".typeMaster").css("background",rgba);
$(e).css("color",rgba);
$(e).css("font-variation-settings","'wght' "+ ((data[0]) + (data[1]) + (data[2])));
return rgba;
})
}
const milliseconds = 100;
window.setInterval(pick, milliseconds);
});
$(window).on("load", function(){
$("#typeMaster").html(function(index, html) {
return html.replace(/\w+/g, '<span class="word">$&</span>');
});
$(".word").html(function(index, html) {
return html.replace(/\S/g, '<span class="letter">$&</span>');
})
var length = $(".letter").length;
var currentMousePos = { x: -1, y: -1 };
});
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = "duration X: " + slider.value; // Display the default slider value
var sliderY = document.getElementById("myRangeY");
var outputY = document.getElementById("demoY");
outputY.innerHTML = "duration Y: " + sliderY.value; // Display the default slider value
slider.oninput = function() {
output.innerHTML = "duration X: " + this.value;
scannerLine.style.animationDuration = this.value + "s";
}
sliderY.oninput = function() {
outputY.innerHTML = "duration Y: " + this.value;
scannerLineH.style.animationDuration = this.value + "s";
}

View file

@ -571,10 +571,18 @@ const TheatrePlay = function(autoInit = false) {
}
.audioButton{
width: 20px;
margin: 2px;
}
.audioButton.active{
background: green;
}
.recordButton{
width: 20px;
margin: 2px;
}
.recordButton.active{
background: green;
}
`;
this.shadowRoot.appendChild(style);
}

View file

@ -8,5 +8,5 @@ fly ()
#echo $(fly /usr/bin/chromium --incognito --screen=1 $@)
#/usr/bin/chromium --incognito --screen=1 $@ &
/usr/bin/chromium --screen=1 --enable-logging --password-store=basic --v=1 $@ &
/usr/bin/chromium --screen=1 --disk-cache-dir=/dev/null --disk-cache-size=1 --enable-logging --password-store=basic --v=1 $@ &
echo $!