add recorded to timeline

dependencies hashes:
openFrameworks d78075f4bca6be2a2533c6e51a75cc1f18404501
ofxMsdfgen e14da13d02c4dff04fb69d7923469f606924e6c3
ofxGPUFont d482bb7cbdf6b296fa4ab5abcf73fb5ff8c8b239
ofxVariableLab 0b5f9bdebc1e5550621957e73c040c258ec6317b
ofxProfiler a868e34fa1a79189dd4fbdede2938e308535e5e8
theatre 86d3e07f6f2c75fd6e08fca8c97e3617c9e23b18
This commit is contained in:
themancalledjakob 2024-04-12 16:32:47 +02:00
parent 42c47aa003
commit 18300baf46
9 changed files with 146 additions and 88 deletions

View file

@ -107,8 +107,8 @@ const MicrophoneRecorder = function() {
this.startListener = (event) => { this.startListener = (event) => {
console.log('microphoneRecorder startl received', event); console.log('microphoneRecorder startl received', event);
if (event.detail === record.possibleStates.RECORDING) { if (event.detail === record.possibleStates.RECORDING) {
console.log('microphoneRecorder startibus');
this.start(); this.start();
console.log('microphoneRecorder start', filenameWithoutExtension);
window.removeEventListener('record', this.startListener); window.removeEventListener('record', this.startListener);
} }
}; };
@ -116,7 +116,7 @@ const MicrophoneRecorder = function() {
this.stopListener = (event) => { this.stopListener = (event) => {
console.log('microphoneRecorder stopl received', event); console.log('microphoneRecorder stopl received', event);
if (event.detail === record.possibleStates.STOPPING_RECORDING) { if (event.detail === record.possibleStates.STOPPING_RECORDING) {
console.log('microphoneRecorder stopibus'); console.log('microphoneRecorder stop', filenameWithoutExtension);
this.stop().then((filename) => { this.stop().then((filename) => {
// be happy // be happy
}); });

View file

@ -1,61 +1,35 @@
import {
sanitizeTheatreKey
} from './utils.js';
const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) { const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
// private // private
let props = { let props = { };
time: tp.core.types.boolean(false), if (typeof values === 'string') {
audioFile: tp.core.types.stringLiteral( const filename = sanitizeTheatreKey(values);
'no_audio_file', values = {};
{ values[filename] = false;
no_audio_file: 'no audio file :(', }
}, if (typeof values === 'object') {
), props[Object.keys(values)[0]] = tp.core.types.boolean(false);
}; }
// private functions // private functions
//
const onValuesChange = (values) => { const onValuesChange = (values) => {
console.log(values); console.log(values);
}; };
const updateAudioFiles = () => {
console.log('update audio files');
return new Promise((resolve) => {
moduleFS.readdir(config.fs.idbfsAudioDir).then((files) => {
;
console.log(files);
if (files.length > 0) {
const audioFiles = {
no_audio_file: 'no audio file :(',
};
files.forEach((file) => {
audioFiles[file] = file;
});
props.audioFile = tp.core.types.stringLiteral(
audioFiles[files[0]],
audioFiles
);
tp.changeObject(this.id(), props);
if (typeof this.theatreObject === 'object') {
tp.studio.transaction(({
set
}) => {
set(this.theatreObject.props.audioFile, files[0]);
});
}
}
resolve(files);
});
});
};
const findInjectPanel = () => { const findInjectPanel = () => {
console.log('find and inject'); console.log('find and inject');
}; };
const setTime = (start, stop) => { const setTime = (filename, start, stop) => {
const keyframes = [ filename = sanitizeTheatreKey(filename);
{ return new Promise((resolve) => {
path: ['time'], const keyframes = [{
keyframes: [ path: [filename],
{ keyframes: [{
position: -1, position: -1,
value: false, value: false,
}, },
@ -68,29 +42,34 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
value: false, value: false,
}, },
], ],
}];
if (tp.getKeyframes(this, [filename]).length > 0) {
tp.studio.transaction(({
__experimental_deleteKeyframes
}) => {
__experimental_deleteKeyframes(this.theatreObject.props[filename]);
});
} }
]; tp.addKeyframes(this, keyframes).then(() => {
tp.setKeyframes(this, keyframes); resolve();
});
});
}; };
const init = () => { const init = () => {
return new Promise((resolve) => { return new Promise((resolve) => {
updateAudioFiles().then((files) => {
this.theatreObject = tp.addObject(audioLayerID, this.props, onValuesChange); this.theatreObject = tp.addObject(audioLayerID, this.props, onValuesChange);
tp.changeObject(audioLayerID, this.props);
tp.studio.transaction(({ tp.studio.transaction(({
set set
}) => { }) => {
const mergedValues = {...this.theatreObject.value, ...values}; const mergedValues = {
console.log({values, mergedValues}, this.props); ...this.theatreObject.value,
...values
};
set(this.theatreObject.props, values ? mergedValues : this.theatreObject.value); set(this.theatreObject.props, values ? mergedValues : this.theatreObject.value);
}); });
// this has to be a timeout, because theatre is not ready otherwise
setTime(1,2);
resolve(); resolve();
}); });
});
}; };
const remove = () => { const remove = () => {
@ -101,6 +80,52 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
this.findInjectPanel = findInjectPanel; this.findInjectPanel = findInjectPanel;
this.setFile = (filename) => {
filename = sanitizeTheatreKey(filename);
const values = {};
values[filename] = false;
props = {};
props[filename] = tp.core.types.boolean(values[filename]);
this.props = props;
tp.changeObject(audioLayerID, this.props);
tp.studio.transaction(({
set
}) => {
set(this.theatreObject.props, values);
});
};
this.addFile = (filename) => {
return new Promise((resolve) => {
filename = sanitizeTheatreKey(filename);
const values = this.theatreObject.value;
values[filename] = false;
props[filename] = tp.core.types.boolean(values[filename]);
this.props = props;
tp.changeObject(audioLayerID, {
dummy: true
});
setTimeout(() => {
tp.changeObject(audioLayerID, this.props);
resolve();
}, 100);
});
};
this.removeFile = (filename) => {
return new Promise((resolve) => {
filename = sanitizeTheatreKey(filename);
const values = this.theatreObject.value;
delete values[filename];
delete props[filename];
this.props = props;
tp.changeObject(audioLayerID, {
dummy: true
});
setTimeout(() => {
tp.changeObject(audioLayerID, this.props);
resolve();
}, 100);
});
};
this.setTime = setTime; this.setTime = setTime;
this.init = init; this.init = init;

View file

@ -37,7 +37,7 @@ const AudioPlayer = function() {
} else if(!audioElement.audioDomElement.paused) { } else if(!audioElement.audioDomElement.paused) {
audioElement.audioDomElement.pause(); audioElement.audioDomElement.pause();
audioElement.audioDomElement.currentTime = 0; audioElement.audioDomElement.currentTime = 0;
console.log('paus audioElement ', audioElement.file, audioElement.propTitle, i); console.log('pause audioElement ', audioElement.file, audioElement.propTitle, i);
} }
} else if (!audioElement.audioDomElement.paused) { } else if (!audioElement.audioDomElement.paused) {
audioElement.audioDomElement.pause(); audioElement.audioDomElement.pause();
@ -53,9 +53,9 @@ const AudioPlayer = function() {
this.update(); this.update();
}, updateInterval_ms); }, updateInterval_ms);
}; };
this.listener = (event) => {
let hot = false; let hot = false;
let time = false; let time = false;
this.listener = (event) => {
if (event.detail === record.possibleStates.RECORDING) { if (event.detail === record.possibleStates.RECORDING) {
hot = clone(record.getHot()); hot = clone(record.getHot());
time = tp.sheet.sequence.position; time = tp.sheet.sequence.position;
@ -69,13 +69,15 @@ const AudioPlayer = function() {
const waitForMicrophoneListener = (event) => { const waitForMicrophoneListener = (event) => {
if (event.detail.fileIsRead) { if (event.detail.fileIsRead) {
this.add(layerID, propTitle, time, event.detail.filename); this.add(layerID, propTitle, time, event.detail.filename);
addAudioLayer().then((audioLayer) => { addAudioLayerTrack(event.detail.filename, time, tp.sheet.sequence.position);
m.layer = audioLayer; window.removeEventListener(
}); 'microphoneRecorder',
window.removeEventListener('microphoneRecorder', waitForMicrophoneListener); waitForMicrophoneListener);
} }
}; };
window.addEventListener('microphoneRecorder', waitForMicrophoneListener); window.addEventListener(
'microphoneRecorder',
waitForMicrophoneListener);
} }
} }
}); });
@ -86,14 +88,12 @@ const AudioPlayer = function() {
layerIDs.forEach((layerID) => { layerIDs.forEach((layerID) => {
const propTitles = Object.keys(hot[layerID]); const propTitles = Object.keys(hot[layerID]);
propTitles.forEach((propTitle) => { propTitles.forEach((propTitle) => {
const m = audio.getMapping()[layerID][propTitle]; const m = audio.getSavedMapping()[layerID][propTitle];
if (m.addToTimeline) { if (m.addToTimeline) {
if (m.source === 'microphone') { if (m.source === 'microphone') {
} else { } else {
this.add(layerID, propTitle, time, m.source); this.add(layerID, propTitle, time, m.source);
addAudioLayer().then((audioLayer) => { addAudioLayerTrack(m.source, time, tp.sheet.sequence.position);
m.layer = audioLayer;
});
} }
} }
}); });

View file

@ -578,12 +578,12 @@ const deleteLayer = (id, saveProject = true) => {
} }
}; };
const addAudioLayer = (values = false) => { const addAudioLayer = (filename = false) => {
return new Promise((resolve) => { return new Promise((resolve) => {
const audioLayerID = (() => { const audioLayerID = (() => {
let index = 0; let index = 0;
for (let i = 0; i < audioLayers.length; i++) { for (let i = 0; i < audioLayers.length; i++) {
if (audioLayers.findIndex((audioLayer) => audioLayer.id() !== `audio-${index}`) < 0) { if (audioLayers.findIndex((audioLayer) => audioLayer.id() === `audio-${index}`) < 0) {
break; break;
} }
index++; index++;
@ -591,7 +591,7 @@ const addAudioLayer = (values = false) => {
return `audio-${index}`; return `audio-${index}`;
})(); })();
console.log('adding', audioLayerID); console.log('adding', audioLayerID);
const audioLayer = new AudioLayer(tp, audioLayerID, values, false); const audioLayer = new AudioLayer(tp, audioLayerID, filename, false);
layersById[audioLayerID] = audioLayer; layersById[audioLayerID] = audioLayer;
audioLayers.push(audioLayer); audioLayers.push(audioLayer);
audioLayer.init().then(() => { audioLayer.init().then(() => {
@ -606,7 +606,7 @@ const addExistingAudioLayer = (audioLayerID, values) => {
audioLayers.push(audioLayer); audioLayers.push(audioLayer);
layersById[audioLayerID] = audioLayer; layersById[audioLayerID] = audioLayer;
audioLayer.init().then(() => { audioLayer.init().then(() => {
resolve(); resolve(audioLayer);
}); });
}); });
}; };
@ -623,6 +623,30 @@ const deleteAudioLayer = (audioLayerID) => {
//delete audioLayersById[id]; //delete audioLayersById[id];
}; };
const addAudioLayerTrack = (filename, start = 0, end = 1) => {
const addTrack = () => {
return new Promise((resolve) => {
audioLayers[0].addFile(filename).then(() => {
audioLayers[0].setTime(filename, start, end).then(() => {
resolve();
});
});
});
};
return new Promise((resolve) => {
if (audioLayers.length < 1) {
addAudioLayer().then((audioLayer) => {
addTrack().then(() => {
resolve();
});
});;
} else {
addTrack().then(() => {
resolve();
});
}
});
};
// TODO: better function names // TODO: better function names
// because, come on. it may be funny for a second // because, come on. it may be funny for a second
// but tolerance for fun is low when you're grumpy // but tolerance for fun is low when you're grumpy
@ -650,6 +674,7 @@ window.deleteLayer = deleteLayer;
window.addAudioLayer = addAudioLayer; window.addAudioLayer = addAudioLayer;
window.addExistingAudioLayer = addExistingAudioLayer; window.addExistingAudioLayer = addExistingAudioLayer;
window.deleteAudioLayer = deleteAudioLayer; window.deleteAudioLayer = deleteAudioLayer;
window.addAudioLayerTrack = addAudioLayerTrack;
window.renderFrames = exporter.renderFrames; window.renderFrames = exporter.renderFrames;
const layer_panel = document.querySelector('#layer_panel'); const layer_panel = document.querySelector('#layer_panel');

View file

@ -651,7 +651,7 @@ const TheatrePlay = function(autoInit = false) {
project = projectJson === false ? core.getProject(projectId) : core.getProject(projectId, { project = projectJson === false ? core.getProject(projectId) : core.getProject(projectId, {
state: projectJson state: projectJson
}); });
console.log({project, projectJson}); //console.log({project, projectJson});
window.setLoadingTask('setting up animation', 10); window.setLoadingTask('setting up animation', 10);
project.ready.then(() => { project.ready.then(() => {
this.sheet = project.sheet('mainSheet'); this.sheet = project.sheet('mainSheet');
@ -725,7 +725,7 @@ const TheatrePlay = function(autoInit = false) {
window.project_fontsHashMap = project.fontsHashMap; window.project_fontsHashMap = project.fontsHashMap;
layerPromises.push(window.addExistingLayer(layerId, objects[layerId])); layerPromises.push(window.addExistingLayer(layerId, objects[layerId]));
}); });
console.log(clone(objects)); //console.log(clone(objects));
Object.keys(objects) Object.keys(objects)
.filter((e) => e.indexOf('audio-') === 0) .filter((e) => e.indexOf('audio-') === 0)
.forEach((layerId) => { .forEach((layerId) => {

View file

@ -464,6 +464,9 @@ const sanitizeTheatreKey = (key) => {
theatreKey.pop(); theatreKey.pop();
} }
theatreKey = theatreKey.join(''); theatreKey = theatreKey.join('');
if (theatreKey.substr(0,1).match(/^([0-9])$/i)) {
theatreKey = `t_${theatreKey}`;
}
return theatreKey.replace(/[^a-zA-Z0-9_]/g,""); return theatreKey.replace(/[^a-zA-Z0-9_]/g,"");
}; };

View file

@ -38466,7 +38466,6 @@ Instead found: ${devStringify(butFoundInstead)}` : "";
callback: () => { callback: () => {
getStudio().transaction(({ stateEditors: stateEditors2 }) => { getStudio().transaction(({ stateEditors: stateEditors2 }) => {
const propAddress = __spreadProps(__spreadValues({}, obj.address), { pathToProp }); const propAddress = __spreadProps(__spreadValues({}, obj.address), { pathToProp });
console.log({ propConfig, propAddress });
stateEditors2.coreByProject.historic.sheetsById.sequence.setPrimitivePropAsSequenced(propAddress, propConfig); stateEditors2.coreByProject.historic.sheetsById.sequence.setPrimitivePropAsSequenced(propAddress, propConfig);
}); });
} }
@ -61771,7 +61770,6 @@ Note that it **is okay** to import '@theatre/core' multiple times. But those imp
detail: toVT detail: toVT
}); });
window.dispatchEvent(event); window.dispatchEvent(event);
console.log({ toVT, p: p3 });
} }
sequence2.setPrimitivePropAsSequenced = setPrimitivePropAsSequenced; sequence2.setPrimitivePropAsSequenced = setPrimitivePropAsSequenced;
function setPrimitivePropAsStatic(p3) { function setPrimitivePropAsStatic(p3) {
@ -61840,7 +61838,6 @@ Note that it **is okay** to import '@theatre/core' multiple times. But those imp
}; };
tracks.trackData[trackId] = track; tracks.trackData[trackId] = track;
tracks.trackIdByPropPath[encodedPropPath] = trackId; tracks.trackIdByPropPath[encodedPropPath] = trackId;
console.log({ trackId, encodedPropPath });
} }
} }
const toVT = { const toVT = {
@ -62837,15 +62834,23 @@ Note that it **is okay** to import '@theatre/core' multiple times. But those imp
trackId, trackId,
keyframes keyframes
})); }));
console.log({
a: __spreadValues({}, root3.address),
objectKey,
trackId,
keyframes
});
} else if (propConfig !== void 0) { } else if (propConfig !== void 0) {
throw Error("hmmm"); throw Error("hmmm");
} }
}; };
if (propConfig.type === "compound") { if (propConfig.type === "compound") {
forEachPropDeep(defaultValue, (v6, pathToProp) => { forEachPropDeep(defaultValue, (v6, pathToProp) => {
console.log("comp compoumnD");
addStaticOrKeyframeProp(v6, pathToProp); addStaticOrKeyframeProp(v6, pathToProp);
}, getPointerParts(prop).path); }, getPointerParts(prop).path);
} else { } else {
console.log("singlerer", { defaultValue, path });
addStaticOrKeyframeProp(defaultValue, path); addStaticOrKeyframeProp(defaultValue, path);
} }
} else { } else {

File diff suppressed because one or more lines are too long

View file

@ -7,7 +7,7 @@ cd $DIR
while true; while true;
do do
echo "$(git ls-files bin/em/variabletime/web)" | entr -d ./reloadbrowser.sh echo "$(git ls-files bin/em/variabletime/web && find "$(pwd)/bin/em/variabletime/web/theatre_modules" -iname "*.js")" | entr -d ./reloadbrowser.sh
sleep 1 sleep 1
done done