mirror of
https://github.com/ragestudio/comty.git
synced 2025-07-09 01:04:16 +00:00
70 lines
2.6 KiB
JavaScript
70 lines
2.6 KiB
JavaScript
self.onmessage = async (event) => {
|
|
const { videoBuffer, audioBuffer } = event.data;
|
|
const SAMPLE_RATE = 44100;
|
|
|
|
// Extraer energía en rango de frecuencias
|
|
const getEnergy = (buffer, freqRange) => {
|
|
const offlineCtx = new OfflineAudioContext(1, buffer.length, SAMPLE_RATE);
|
|
const source = offlineCtx.createBufferSource();
|
|
source.buffer = buffer;
|
|
|
|
const analyser = offlineCtx.createAnalyser();
|
|
analyser.fftSize = 4096;
|
|
source.connect(analyser);
|
|
analyser.connect(offlineCtx.destination);
|
|
source.start();
|
|
|
|
return offlineCtx.startRendering().then(() => {
|
|
const data = new Float32Array(analyser.frequencyBinCount);
|
|
analyser.getFloatFrequencyData(data);
|
|
|
|
const startBin = Math.floor(freqRange[0] * analyser.fftSize / SAMPLE_RATE);
|
|
const endBin = Math.floor(freqRange[1] * analyser.fftSize / SAMPLE_RATE);
|
|
return data.slice(startBin, endBin);
|
|
});
|
|
};
|
|
|
|
// Cross-correlación optimizada
|
|
const crossCorrelate = (videoFeatures, audioFeatures) => {
|
|
let maxCorr = -Infinity;
|
|
let bestOffset = 0;
|
|
|
|
for (let i = 0; i < videoFeatures.length - audioFeatures.length; i++) {
|
|
let corr = 0;
|
|
for (let j = 0; j < audioFeatures.length; j++) {
|
|
corr += videoFeatures[i + j] * audioFeatures[j];
|
|
}
|
|
if (corr > maxCorr) {
|
|
maxCorr = corr;
|
|
bestOffset = i;
|
|
}
|
|
}
|
|
return bestOffset;
|
|
};
|
|
|
|
// Procesar características
|
|
try {
|
|
const [videoBass, audioBass] = await Promise.all([
|
|
getEnergy(videoBuffer, [60, 250]), // Bajos
|
|
getEnergy(audioBuffer, [60, 250])
|
|
]);
|
|
|
|
const [videoVoice, audioVoice] = await Promise.all([
|
|
getEnergy(videoBuffer, [300, 3400]), // Voces
|
|
getEnergy(audioBuffer, [300, 3400])
|
|
]);
|
|
|
|
// Combinar características (peso dinámico)
|
|
const isElectronic = audioVoice.reduce((a, b) => a + b) < audioBass.reduce((a, b) => a + b);
|
|
const weight = isElectronic ? 0.8 : 0.4;
|
|
|
|
const videoFeatures = videoBass.map((v, i) => weight * v + (1 - weight) * videoVoice[i]);
|
|
const audioFeatures = audioBass.map((v, i) => weight * v + (1 - weight) * audioVoice[i]);
|
|
|
|
// Calcular offset
|
|
const offset = crossCorrelate(videoFeatures, audioFeatures);
|
|
self.postMessage({ offset: offset / SAMPLE_RATE });
|
|
} catch (error) {
|
|
self.postMessage({ error: "Error en el procesamiento" });
|
|
}
|
|
}; |