save and load audioLayer and audioPlayer

dependencies hashes:
openFrameworks d78075f4bca6be2a2533c6e51a75cc1f18404501
ofxMsdfgen e14da13d02c4dff04fb69d7923469f606924e6c3
ofxGPUFont d482bb7cbdf6b296fa4ab5abcf73fb5ff8c8b239
ofxVariableLab 0b5f9bdebc1e5550621957e73c040c258ec6317b
ofxProfiler a868e34fa1a79189dd4fbdede2938e308535e5e8
theatre c60e63f5be4466e21b6bf06f6580f6100687306b
This commit is contained in:
themancalledjakob 2024-04-13 18:03:44 +02:00
parent ef308f61b2
commit 8075cf2b16
7 changed files with 172 additions and 32 deletions

View file

@ -1162,7 +1162,7 @@ const Audio = function(tp, record) {
}
});
} else {
console.log("getUserMedia not supported on your browser!");
console.log("Audio::init","getUserMedia not supported on your browser!");
}
const visualize = () => {

View file

@ -1,5 +1,6 @@
import {
sanitizeTheatreKey
sanitizeTheatreKey,
arraysEqual,
} from './utils.js';
const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
@ -14,14 +15,34 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
props[Object.keys(values)[0]] = tp.core.types.boolean(false);
}
const onValuesChangeCallbacks = [];
// private functions
//
const onValuesChange = (values) => {
console.log(values);
const n_callbacks = onValuesChangeCallbacks.length;
const successes = [];
if (n_callbacks > 0) {
for (let i = 0; i < n_callbacks; i++) {
if (typeof onValuesChangeCallbacks[i] === 'function') {
if(onValuesChangeCallbacks[i](values)) {
successes.unshift(i);
}
} else {
console.log('AudioLayer::onValuesChange', 'holy shit, the callback is not a function');
}
}
successes.forEach((i) => {
onValuesChangeCallbacks.splice(i, 1);
});
}
};
const findInjectPanel = () => {
console.log('find and inject');
console.log('AudioLayer::findInjectPanel');
const sequencePanel = tp.getSequencePanel();
const sequencePanelLeft = tp.getSequencePanelLeft();
};
const setTime = (filename, start, stop) => {
@ -104,13 +125,33 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
values[filename] = false;
props[filename] = tp.core.types.boolean(values[filename]);
this.props = props;
tp.changeObject(audioLayerID, {
dummy: true
const setDummy = () => {
tp.changeObject(audioLayerID, {
dummy: true
});
};
onValuesChangeCallbacks.push((changedValues) => {
if (changedValues.dummy) {
// NOTE: any idea how to avoid this ugly nesting?
onValuesChangeCallbacks.push((againChangedValues) => {
const expectedValueKeys = Object.keys(values);
const givenValueKeys = Object.keys(againChangedValues);
if (arraysEqual(expectedValueKeys, givenValueKeys)) {
resolve();
return true;
} else {
return false;
}
});
tp.changeObject(audioLayerID, this.props);
return true;
} else {
return false;
}
});
setTimeout(() => {
tp.changeObject(audioLayerID, this.props);
resolve();
}, 100);
setDummy();
});
};
this.removeFile = (filename) => {
@ -120,13 +161,26 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
delete values[filename];
delete props[filename];
this.props = props;
tp.changeObject(audioLayerID, {
dummy: true
const setDummy = () => {
tp.changeObject(audioLayerID, {
dummy: true
});
};
onValuesChangeCallbacks.push((changedValues) => {
if (changedValues.dummy) {
// NOTE: any idea how to avoid this ugly nesting?
onValuesChangeCallbacks.push((againChangedValues) => {
const expectedValueKeys = Object.keys(values);
const givenValueKeys = Object.keys(againChangedValues);
if (arraysEqual(expectedValueKeys, givenValueKeys)) {
resolve();
}
});
tp.changeObject(audioLayerID, this.props);
}
});
setTimeout(() => {
tp.changeObject(audioLayerID, this.props);
resolve();
}, 100);
setDummy();
});
};
this.setTime = setTime;

View file

@ -30,7 +30,7 @@ const AudioPlayer = function() {
this.addMany = (manyAudioElements) => {
manyAudioElements.forEach((e) => {
this.add(e.audioID, e.layerID, e.propTitle, e.file);
this.add(e.audioID, e.layerID, e.propTitle, e.file, e.startTime);
});
};

View file

@ -604,7 +604,7 @@ const addAudioLayer = (filename = false) => {
});
};
const addExistingAudioLayer = (audioLayerID, values) => {
const addExistingAudioLayer = (audioLayerID, values = false) => {
return new Promise((resolve) => {
const audioLayer = new AudioLayer(tp, audioLayerID, values, false);
audioLayers.push(audioLayer);

View file

@ -248,6 +248,14 @@ const Record = function(tp) {
if (cPropTitle.indexOf('color.') === 0) {
cPropTitle = 'color';
}
const propTitleDom = tp.getPanelPropTitle(cPropTitle);
if (propTitleDom === null) {
// whoops, probably currently transitioning,
// so it will not be necessary to remove the class
// when it will be recreated on demand,
// it won't have the class anyways.
return;
}
const button = tp
.getPanelPropTitle(cPropTitle)
.parentNode.parentNode

View file

@ -23,6 +23,10 @@ const TheatrePlay = function(autoInit = false) {
const theatreObjects = {};
let theatrePanel = null;
let sequencePanelLeft = null;
const getSequencePanel = () => {
sequencePanelLeft = tp.shadowRoot.querySelector('[data-testid="SequencePanel-Object"]');
return sequencePanelLeft;
};
const getSequencePanelLeft = () => {
sequencePanelLeft = tp.shadowRoot.querySelector('[data-testid="SequencePanel-Left"]');
return sequencePanelLeft;
@ -321,6 +325,7 @@ const TheatrePlay = function(autoInit = false) {
};
this.isSequenced = isSequenced;
this.getSequenceButton = getSequenceButton;
this.getSequencePanel = getSequencePanel;
this.getSequencePanelLeft = getSequencePanelLeft;
this.getPanel = getPanel;
this.getPanelPropTitle = getPanelPropTitle;
@ -589,6 +594,28 @@ const TheatrePlay = function(autoInit = false) {
audioMapping: audio.getMapping(),
};
const theatre = tp.studio.createContentOfSaveFile(currentProjectId);
// yeaaaah we don't want to fuck with theatre's saveFile stuff
// let's do this ourselves
const audioLayers = getAudioLayers();
if (audioLayers.length > 0) {
vt_params['audioLayers'] = {};
audioLayers.forEach((audioLayer) => {
vt_params['audioLayers'][audioLayer.id()] = getKeyframes(audioLayer);
});
const audioPlayerElements = audio
.audioPlayer
.audioElements
.map((e) => {
return {
audioID: e.audioID,
layerID: e.layerID,
propTitle: e.propTitle,
file: e.file,
startTime: e.startTime
};
});
vt_params['audioPlayerElements'] = audioPlayerElements;
}
return this.theatre2variableTime(theatre, vt_params);
};
this.saveProject = (projectId = project.address.projectId, vt_project = false, silent = true) => {
@ -709,12 +736,12 @@ const TheatrePlay = function(autoInit = false) {
}) => {
set(window.getArtboard().theatreObject.props, artboardProps);
});
if (project.hasOwnProperty('audioMapping')) {
audio.setMapping(project.audioMapping);
}
if (project.hasOwnProperty('audioSavedMapping')) {
audio.setSavedMapping(project.audioSavedMapping);
}
if (project.hasOwnProperty('audioMapping')) {
audio.setMapping(project.audioMapping);
}
if (project.hasOwnProperty('audioSavedMapping')) {
audio.setSavedMapping(project.audioSavedMapping);
}
// load layers
const layerPromises = [];
@ -723,17 +750,48 @@ const TheatrePlay = function(autoInit = false) {
.forEach((layerId) => {
window.setLoadingTask(`setting up the shapes of ${layerId} to come`, 90);
window.project_fontsHashMap = project.fontsHashMap;
layerPromises.push(window.addExistingLayer(layerId, objects[layerId]));
//layerPromises.push(window.addExistingLayer(layerId, objects[layerId]));
layerPromises.push(() => {
return new Promise((r) => {
window.addExistingLayer(layerId, objects[layerId]).then(() => {
r();
});
});
});
});
//console.log(clone(objects));
Object.keys(objects)
.filter((e) => e.indexOf('audio-') === 0)
.forEach((layerId) => {
window.setLoadingTask(`setting up the sounds of ${layerId} to come`, 90);
window.project_fontsHashMap = project.fontsHashMap;
layerPromises.push(window.addExistingAudioLayer(layerId, objects[layerId]));
if (typeof project['audioPlayerElements'] === 'object') {
audio.audioPlayer.addMany(project['audioPlayerElements']);
}
if (typeof project['audioLayers'] === 'object') {
const audioLayerIDs = Object.keys(project['audioLayers']);
audioLayerIDs.forEach((audioLayerID) => {
layerPromises.push(() => {
window.setLoadingTask(`setting up the sounds of ${audioLayerID} to come`, 90);
return new Promise((r) => {
window.addExistingAudioLayer(audioLayerID).then((audioLayer) => {
const promises = [];
project['audioLayers'][audioLayerID].forEach((keyframeCombo) => {
const filename = keyframeCombo.path.join('');
promises.push(() => {
return new Promise((rr) => {
audioLayer.addFile(filename)
.then(() => {
rr(); // resolve
});
});
});
});
sequencialPromises(promises, () => {
tp.addKeyframes(audioLayer, project['audioLayers'][audioLayerID]);
r(); // resolve
});
});
});
});
});
Promise.all(layerPromises).then(() => {
}
sequencialPromises(layerPromises, () => {
window.layerOrder.set(project.layerOrder);
this.duration = this.core.val(this.sheet.sequence.pointer.length);
if (project.layerOrder.length > 0) {

View file

@ -531,6 +531,25 @@ const getNestedProperty = (o, a, verify = false) => {
return o[b[0]];
};
const findNestedObjectKey = (o, k, exact = true, history = [], result = []) => {
const oks = Object.keys(o);
for (let i = 0; i < oks.length; i++) {
if (k === oks[i] || (!exact && oks[i].indexOf(k) >= 0)) {
history.push(oks[i]);
result.push({found: o[oks[i]], history});
}
if (typeof o[oks[i]] === 'object') {
const ok = Object.keys(o[oks[i]]);
const ok_history = clone(history);
ok_history.push(oks[i]);
findNestedObjectKey(o[oks[i]], k, exact, ok_history, result);
}
}
if (history.length === 0) {
return result;
}
};
// NOTE: all input values are range 0-1
const rgbaToHexa = (rgba) => {
return '#' + (
@ -610,6 +629,7 @@ export {
flattenObject,
deFlattenObject,
getNestedProperty,
findNestedObjectKey,
rgbaToHexa,
hexaToRgba,
getFileExtensionFromMimeType,