individual audiofiles <-> prop mapping

This commit is contained in:
jrkb 2023-10-13 11:29:18 +02:00
parent 16124c755d
commit 748af243fa
3 changed files with 136 additions and 147 deletions

View file

@ -21,6 +21,7 @@ const AudioMappingOptions = function() {
this.sync = 'volume'; this.sync = 'volume';
this.source = 'microphone'; this.source = 'microphone';
this.value = 0.0; this.value = 0.0;
this.muted = true;
}; };
const Audio = function(tp, record) { const Audio = function(tp, record) {
@ -608,10 +609,10 @@ const Audio = function(tp, record) {
} }
}); });
}; };
const audioFileStuff = {}; const audioSourceCombo = {};
const readAudioFiles = () => { const readAudioFiles = () => {
FS.readdir(config.fs.idbfsAudioDir).forEach((file) => { FS.readdir(config.fs.idbfsAudioDir).forEach((file) => {
if (file.indexOf('.') !== 0 && !audioFileStuff.hasOwnProperty(file)) { if (file.indexOf('.') !== 0 && !audioSourceCombo.hasOwnProperty(file)) {
const audioElement = document.createElement('audio'); const audioElement = document.createElement('audio');
audioElement.classList.add('invisible'); audioElement.classList.add('invisible');
audioElement.classList.add('audio_file'); audioElement.classList.add('audio_file');
@ -637,19 +638,23 @@ const Audio = function(tp, record) {
); );
audioElement.src = src; audioElement.src = src;
audioElement.loop = true;
const source = audioCtx.createMediaElementSource(audioElement); const source = audioCtx.createMediaElementSource(audioElement);
source.connect(audioCtx.destination); source.connect(audioCtx.destination);
const analyser = audioCtx.createAnalyser(); const analyser = audioCtx.createAnalyser();
analyser.minDecibels = -90;
analyser.maxDecibels = -10;
analyser.smoothingTimeConstant = 0.85;
analyser.fftSize = config.audio.fftBandsAnalysed; analyser.fftSize = config.audio.fftBandsAnalysed;
const bufferLength = analyser.frequencyBinCount; const bufferLength = analyser.frequencyBinCount / 2;
const dataArray = new Uint8Array(bufferLength); const dataArray = new Uint8Array(bufferLength);
source.connect(analyser); source.connect(analyser);
audioElement.play(); audioElement.play();
audioFileStuff[file] = { audioSourceCombo[file] = {
dataArray, dataArray,
analyser, analyser,
audioElement, audioElement,
@ -715,7 +720,14 @@ const Audio = function(tp, record) {
analyser.minDecibels = -90; analyser.minDecibels = -90;
analyser.maxDecibels = -10; analyser.maxDecibels = -10;
analyser.smoothingTimeConstant = 0.85; analyser.smoothingTimeConstant = 0.85;
window.analyser = analyser; analyser.fftSize = config.audio.fftBandsAnalysed;
const bufferLength = analyser.frequencyBinCount / 2;
audioSourceCombo['microphone'] = {
analyser,
dataArray: new Uint8Array(bufferLength),
audioElement: null,
};
readAudioFiles(); readAudioFiles();
@ -778,6 +790,7 @@ const Audio = function(tp, record) {
canvas.setAttribute("width", config.audio.fftBandsUsed); canvas.setAttribute("width", config.audio.fftBandsUsed);
const visualSelect = audioDom.querySelector("#visual"); const visualSelect = audioDom.querySelector("#visual");
let drawVisual; let drawVisual;
let previousPosition = -1;
// Main block for doing the audio recording // Main block for doing the audio recording
if (navigator.mediaDevices.getUserMedia) { if (navigator.mediaDevices.getUserMedia) {
@ -792,7 +805,6 @@ const Audio = function(tp, record) {
source.connect(analyser); source.connect(analyser);
visualize(); visualize();
voiceChange();
}) })
.catch(function(err) { .catch(function(err) {
console.log("The following gUM error occured: " + err); console.log("The following gUM error occured: " + err);
@ -802,57 +814,8 @@ const Audio = function(tp, record) {
} }
const visualize = () => { const visualize = () => {
const WIDTH = canvas.width;
const HEIGHT = canvas.height;
const visualSetting = visualSelect.value; //analyser.fftSize = config.audio.fftBandsAnalysed;
if (visualSetting === "sinewave") {
//analyser.fftSize = 2048;
//const bufferLength = analyser.fftSize;
//// We can use Float32Array instead of Uint8Array if we want higher precision
//// const dataArray = new Float32Array(bufferLength);
//const dataArray = new Uint8Array(bufferLength);
//canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
//const draw = function() {
//drawVisual = requestAnimationFrame(draw);
//analyser.getByteTimeDomainData(dataArray);
//canvasCtx.fillStyle = "rgb(200, 200, 200)";
//canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
//canvasCtx.lineWidth = 2;
//canvasCtx.strokeStyle = "rgb(0, 0, 0)";
//canvasCtx.beginPath();
//const sliceWidth = (WIDTH * 1.0) / bufferLength;
//let x = 0;
//for (let i = 0; i < bufferLength; i++) {
//let v = dataArray[i] / 128.0;
//let y = (v * HEIGHT) / 2;
//if (i === 0) {
//canvasCtx.moveTo(x, y);
//} else {
//canvasCtx.lineTo(x, y);
//}
//x += sliceWidth;
//}
//canvasCtx.lineTo(canvas.width, canvas.height / 2);
//canvasCtx.stroke();
//};
//draw();
} else if (visualSetting == "frequencybars") {
analyser.fftSize = config.audio.fftBandsAnalysed;
const w = config.audio.fftBandsUsed; const w = config.audio.fftBandsUsed;
const h = config.audio.fftHeight; const h = config.audio.fftHeight;
const verticalFactor = h / 256.0; const verticalFactor = h / 256.0;
@ -869,110 +832,137 @@ const Audio = function(tp, record) {
let frameCount = 0; let frameCount = 0;
const drawAlt = function() { const drawAlt = function() {
const position = tp.sheet.sequence.position;
let positionRollover = false;
if (config.audio.rolloverResetLoop && position < previousPosition) {
positionRollover = true;
}
previousPosition = position;
canvasKeys = Object.keys(canvasCombos); canvasKeys = Object.keys(canvasCombos);
drawVisual = requestAnimationFrame(drawAlt); drawVisual = requestAnimationFrame(drawAlt);
//analyser.getByteFrequencyData(dataArrayAlt); canvasKeys.forEach((k) => {
//Object.keys(audioFileStuff).forEach((afs) => { canvasCombos[k][1].fillStyle = "rgb(0, 0, 0)"; // AUDIO COLOR
//afs.analyser.ByteFrequencyData(afs.dataArray); canvasCombos[k][1].fillRect(0, 0, w, h);
//}); const layerID = canvasCombos[k][2];
audioFileStuff['hito_steyerl_about_suicide_cameras.ogg'].analyser.getByteFrequencyData(dataArrayAlt); const m = mapping[layerID][k];
for (let i = 0; i < canvasKeys.length; i++) {
canvasCombos[canvasKeys[i]][1].fillStyle = "rgb(0, 0, 0)"; // AUDIO COLOR
canvasCombos[canvasKeys[i]][1].fillRect(0, 0, w, h);
const layerID = canvasCombos[canvasKeys[i]][2];
const m = mapping[layerID][canvasKeys[i]];
if (m.sync === 'volume') { if (m.sync === 'volume') {
const sx = m.min_freq; const sx = m.min_freq;
const sw = m.max_freq - m.min_freq; const sw = m.max_freq - m.min_freq;
const sy = h - (m.max_in * verticalFactor); const sy = h - (m.max_in * verticalFactor);
const sh = (m.max_in - m.min_in) * verticalFactor; const sh = (m.max_in - m.min_in) * verticalFactor;
canvasCombos[canvasKeys[i]][1].fillStyle = "rgb(80, 80, 80)"; // AUDIO COLOR canvasCombos[k][1].fillStyle = "rgb(80, 80, 80)"; // AUDIO COLOR
canvasCombos[canvasKeys[i]][1].fillRect(sx, sy, sw, sh); canvasCombos[k][1].fillRect(sx, sy, sw, sh);
} else if (m.sync === 'pitch') { } else if (m.sync === 'pitch') {
const sx = m.min_freq; const sx = m.min_freq;
const sw = m.max_freq - m.min_freq; const sw = m.max_freq - m.min_freq;
const sy = 0; const sy = 0;
const sh = h; const sh = h;
canvasCombos[canvasKeys[i]][1].fillStyle = "rgb(80, 80, 80)"; // AUDIO COLOR canvasCombos[k][1].fillStyle = "rgb(80, 80, 80)"; // AUDIO COLOR
canvasCombos[canvasKeys[i]][1].fillRect(sx, sy, sw, sh); canvasCombos[k][1].fillRect(sx, sy, sw, sh);
}
} }
});
const barWidth = 1;//(w / bufferLengthAlt) * 2.5; //analyser.getByteFrequencyData(dataArrayAlt);
let barHeight; const usedSourceCombos = [];
let x = 0; const analysedResults = {};
Object.keys(mapping).forEach((layerID) => {
let max_i = 0; Object.keys(mapping[layerID]).forEach((propTitle) => {
let max_ri = 0; const m = mapping[layerID][propTitle];
let total_v = 0; const source = m.source;
let max_v = 0; if (usedSourceCombos.indexOf(source) < 0) {
for (let k = 0; k < canvasKeys.length; k++) { usedSourceCombos.push(source);
const layerID = canvasCombos[canvasKeys[k]][2]; analysedResults[source] = {
const m = mapping[layerID][canvasKeys[k]]; max_i: 0,
m.max_v = max_v; max_ri: 0,
m.max_i = max_i; max_v: 0,
m.max_ri = max_ri; total_v: 0,
m.total_v = total_v; mappings: [],
};
} }
for (let i = 0; i < w; i++) { m.max_v = 0;
barHeight = dataArrayAlt[i]; m.max_i = 0;
total_v += barHeight; m.max_ri = 0;
max_ri = barHeight * i; m.total_v = 0;
analysedResults[source].mappings.push(m);
if (barHeight > max_v) { });
max_v = barHeight; });
max_i = i; Object.keys(audioSourceCombo).forEach((k) => {
const asc = audioSourceCombo[k];
if (asc.audioElement !== null) {
if (usedSourceCombos.indexOf(k) >= 0) {
if (positionRollover || asc.audioElement.paused) {
asc.audioElement.currentTime = position % asc.audioElement.duration;
asc.audioElement.play();
} }
for (let k = 0; k < canvasKeys.length; k++) { } else if (!asc.audioElement.paused) {
const layerID = canvasCombos[canvasKeys[k]][2]; asc.audioElement.pause();
const m = mapping[layerID][canvasKeys[k]];
let fillStyle = "rgb(200,200,200)"; // AUDIO COLOR
if (m.min_freq <= i && m.max_freq >= i) {
m.total_v += barHeight;
if (barHeight > m.max_v) {
m.max_v = barHeight;
m.max_i = i;
m.max_ri = barHeight * i;
} }
fillStyle = "rgb(255,255,255)"; // AUDIO COLOR
} }
canvasCombos[canvasKeys[k]][1].fillStyle = fillStyle; });
canvasCombos[canvasKeys[k]][1].fillRect( usedSourceCombos.forEach((source) => {
const afs = audioSourceCombo[source];
const r = analysedResults[source];
afs.analyser.getByteFrequencyData(afs.dataArray);
for (let f = 0; f < w; f++) {
const v = afs.dataArray[f];
r.total_v += v;
if (r.max_v < v) {
r.max_v = v;
r.max_i = v;
}
r.max_ri += v * f;
let fillStyle = 'rgb(200,200,200)';
for (let k_i = 0; k_i < canvasKeys.length; k_i++) {
const k = canvasKeys[k_i];
const x = f;
canvasCombos[k][1].fillStyle = fillStyle;
canvasCombos[k][1].fillRect(
x, x,
h - (barHeight * verticalFactor), h - (v * verticalFactor),
barWidth, 1,
(barHeight * verticalFactor) (v * verticalFactor)
); );
} }
analysedResults[source].mappings.forEach((m) => {
x += barWidth; if (m.min_freq <= f && m.max_freq >= f) {
m.total_v += v;
if (m.max_v < v) {
m.max_v = v;
m.max_i = f;
} }
max_ri /= total_v; m.max_ri += v * f;
for (let k = 0; k < canvasKeys.length; k++) { }
const layerID = canvasCombos[canvasKeys[k]][2]; });
const m = mapping[layerID][canvasKeys[k]]; }
r.max_ri /= r.total_v;
analysedResults[source].mappings.forEach((m) => {
m.max_ri /= m.total_v; m.max_ri /= m.total_v;
});
});
for (let k_i = 0; k_i < canvasKeys.length; k_i++) {
const k = canvasKeys[k_i];
const layerID = canvasCombos[k][2];
const m = mapping[layerID][k];
if (m.sync === 'volume') { if (m.sync === 'volume') {
const sx = m.min_freq; const sx = m.min_freq;
const sw = m.max_freq - m.min_freq; const sw = m.max_freq - m.min_freq;
const sy = h - (m.max_in * verticalFactor); const sy = h - (m.max_in * verticalFactor);
const sh = (m.max_in - m.min_in) * verticalFactor; const sh = (m.max_in - m.min_in) * verticalFactor;
canvasCombos[canvasKeys[k]][1].lineWidth = 1; // AUDIO COLOR canvasCombos[k][1].lineWidth = 1; // AUDIO COLOR
canvasCombos[canvasKeys[k]][1].strokeStyle = "rgb(255,255,255)"; // AUDIO COLOR canvasCombos[k][1].strokeStyle = "rgb(255,255,255)"; // AUDIO COLOR
canvasCombos[canvasKeys[k]][1].strokeRect(sx, sy, sw, sh); canvasCombos[k][1].strokeRect(sx, sy, sw, sh);
} else if (m.sync === 'pitch') { } else if (m.sync === 'pitch') {
const m = mapping[layerID][canvasKeys[k]];
const sx = m.min_freq; const sx = m.min_freq;
const sw = m.max_freq - m.min_freq; const sw = m.max_freq - m.min_freq;
const sy = 0; const sy = 0;
const sh = h; const sh = h;
canvasCombos[canvasKeys[k]][1].lineWidth = 1; // AUDIO COLOR canvasCombos[k][1].lineWidth = 1; // AUDIO COLOR
canvasCombos[canvasKeys[k]][1].strokeStyle = "rgb(255,255,255)"; // AUDIO COLOR canvasCombos[k][1].strokeStyle = "rgb(255,255,255)"; // AUDIO COLOR
canvasCombos[canvasKeys[k]][1].strokeRect(sx, sy, sw, sh); canvasCombos[k][1].strokeRect(sx, sy, sw, sh);
} }
} }
const propsToSet = []; const propsToSet = [];
getLayers().forEach((layer) => { getLayers().forEach((layer) => {
if (mapping.hasOwnProperty(layer.id())) { if (mapping.hasOwnProperty(layer.id())) {
@ -1079,11 +1069,6 @@ const Audio = function(tp, record) {
frameCount++; frameCount++;
}; };
drawAlt(); drawAlt();
} else if (visualSetting == "off") {
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
canvasCtx.fillStyle = "red";
canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
}
} }
const voiceChange = () => { const voiceChange = () => {
@ -1204,9 +1189,11 @@ const Audio = function(tp, record) {
this.addAudioOptions = addAudioOptions; this.addAudioOptions = addAudioOptions;
this.removeAudioOptions = removeAudioOptions; this.removeAudioOptions = removeAudioOptions;
this.AudioMappingOptions = AudioMappingOptions; this.AudioMappingOptions = AudioMappingOptions;
this.readAudioFiles = readAudioFiles;
// debug // debug
this.canvasCombos = canvasCombos; this.canvasCombos = canvasCombos;
this.audioSourceCombo = audioSourceCombo;
}; };
export { export {

View file

@ -102,6 +102,7 @@ const config = {
colorSeparateRGBA: true, colorSeparateRGBA: true,
ignoreOutboundFrequencies: true, ignoreOutboundFrequencies: true,
pitchCombineFrequencies: false, pitchCombineFrequencies: false,
rolloverResetLoop: true,
}, },
record: { record: {
ignoreProps: ['transformOrigin', 'fontFamily', 'text', 'mirror_x', 'mirror_y', 'mirror_xy'], ignoreProps: ['transformOrigin', 'fontFamily', 'text', 'mirror_x', 'mirror_y', 'mirror_xy'],

View file

@ -579,6 +579,7 @@ const initPanels = () => {
.save(file) .save(file)
.then(() => { .then(() => {
console.log('ermh... done uploading?', file); console.log('ermh... done uploading?', file);
audio.readAudioFiles();
}); });
}); });
}); });