Fix audio
This commit is contained in:
parent
7b28257d3f
commit
49a7e3f75f
128
src/main.js
128
src/main.js
|
|
@ -585,6 +585,8 @@ let actions = {
|
||||||
},
|
},
|
||||||
execute: (action) => {
|
execute: (action) => {
|
||||||
let shape = pointerList[action.shape];
|
let shape = pointerList[action.shape];
|
||||||
|
console.log(action.shape)
|
||||||
|
console.log(pointerList)
|
||||||
shape.fillStyle = action.newColor;
|
shape.fillStyle = action.newColor;
|
||||||
},
|
},
|
||||||
rollback: (action) => {
|
rollback: (action) => {
|
||||||
|
|
@ -685,6 +687,8 @@ let actions = {
|
||||||
player: player,
|
player: player,
|
||||||
start: action.frameNum,
|
start: action.frameNum,
|
||||||
img: img,
|
img: img,
|
||||||
|
src: action.audiosrc,
|
||||||
|
uuid: action.uuid
|
||||||
};
|
};
|
||||||
pointerList[action.uuid] = soundObj;
|
pointerList[action.uuid] = soundObj;
|
||||||
newAudioLayer.sounds[action.uuid] = soundObj;
|
newAudioLayer.sounds[action.uuid] = soundObj;
|
||||||
|
|
@ -2864,14 +2868,49 @@ class AudioLayer {
|
||||||
const audioLayer = new AudioLayer(json.idx, json.name);
|
const audioLayer = new AudioLayer(json.idx, json.name);
|
||||||
// TODO: load audiolayer from json
|
// TODO: load audiolayer from json
|
||||||
audioLayer.sounds = {};
|
audioLayer.sounds = {};
|
||||||
|
for (let id in json.sounds) {
|
||||||
|
const jsonSound = json.sounds[id]
|
||||||
|
const img = new Image();
|
||||||
|
img.className = "audioWaveform";
|
||||||
|
const player = new Tone.Player().toDestination();
|
||||||
|
player.load(jsonSound.src)
|
||||||
|
.then(() => {
|
||||||
|
generateWaveform(img, player.buffer, 50, 25, config.framerate);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
// Handle any errors that occur during the load or waveform generation
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
let soundObj = {
|
||||||
|
player: player,
|
||||||
|
start: jsonSound.start,
|
||||||
|
img: img,
|
||||||
|
src: jsonSound.src,
|
||||||
|
uuid: jsonSound.uuid
|
||||||
|
};
|
||||||
|
pointerList[jsonSound.uuid] = soundObj;
|
||||||
|
audioLayer.sounds[jsonSound.uuid] = soundObj;
|
||||||
|
// TODO: change start time
|
||||||
|
audioLayer.track.add(0, jsonSound.uuid);
|
||||||
|
}
|
||||||
audioLayer.audible = json.audible;
|
audioLayer.audible = json.audible;
|
||||||
return audioLayer;
|
return audioLayer;
|
||||||
}
|
}
|
||||||
toJSON(randomizeUuid = false) {
|
toJSON(randomizeUuid = false) {
|
||||||
|
console.log(this.sounds)
|
||||||
const json = {};
|
const json = {};
|
||||||
json.type = "AudioLayer";
|
json.type = "AudioLayer";
|
||||||
// TODO: build json from audiolayer
|
// TODO: build json from audiolayer
|
||||||
json.sounds = {};
|
json.sounds = {};
|
||||||
|
for (let id in this.sounds) {
|
||||||
|
const sound = this.sounds[id]
|
||||||
|
json.sounds[id] = {
|
||||||
|
start: sound.start,
|
||||||
|
src: sound.src,
|
||||||
|
uuid: sound.uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
json.audible = this.audible;
|
json.audible = this.audible;
|
||||||
if (randomizeUuid) {
|
if (randomizeUuid) {
|
||||||
json.idx = uuidv4();
|
json.idx = uuidv4();
|
||||||
|
|
@ -4545,6 +4584,60 @@ async function _open(path, returnJson = false) {
|
||||||
undoStack.push(action);
|
undoStack.push(action);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (file.version < "1.7.6") {
|
||||||
|
function restoreLineColors(obj) {
|
||||||
|
// Step 1: Create colorMapping dictionary
|
||||||
|
const colorMapping = (obj.actions || []).reduce((map, action) => {
|
||||||
|
if (action.name === "addShape" && action.action.curves.length > 0) {
|
||||||
|
map[action.action.uuid] = action.action.curves[0].color;
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
// Step 2: Recursive pass to add colors from colorMapping back to curves
|
||||||
|
function recurse(item) {
|
||||||
|
if (item?.curves && item.idx && colorMapping[item.idx]) {
|
||||||
|
item.curves.forEach(curve => {
|
||||||
|
if (Array.isArray(curve)) curve.push(colorMapping[item.idx]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Object.values(item).forEach(value => {
|
||||||
|
if (typeof value === 'object' && value !== null) recurse(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
recurse(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreLineColors(file)
|
||||||
|
|
||||||
|
function restoreAudio(obj) {
|
||||||
|
const audioSrcMapping = (obj.actions || []).reduce((map, action) => {
|
||||||
|
if (action.name === "addAudio") {
|
||||||
|
map[action.action.layeruuid] = action.action;
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
function recurse(item) {
|
||||||
|
if (item.type=="AudioLayer" && audioSrcMapping[item.idx]) {
|
||||||
|
const action = audioSrcMapping[item.idx]
|
||||||
|
item.sounds[action.uuid] = {
|
||||||
|
start: action.frameNum,
|
||||||
|
src: action.audiosrc,
|
||||||
|
uuid: action.uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object.values(item).forEach(value => {
|
||||||
|
if (typeof value === 'object' && value !== null) recurse(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
recurse(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreAudio(file)
|
||||||
|
}
|
||||||
// disabled for now
|
// disabled for now
|
||||||
// for (let action of file.actions) {
|
// for (let action of file.actions) {
|
||||||
// undoStack.push(action)
|
// undoStack.push(action)
|
||||||
|
|
@ -4867,6 +4960,8 @@ async function setupVideoExport(ext, path, canvas, exportContext) {
|
||||||
let muxer;
|
let muxer;
|
||||||
let videoEncoder;
|
let videoEncoder;
|
||||||
let videoConfig;
|
let videoConfig;
|
||||||
|
let audioEncoder;
|
||||||
|
let audioConfig;
|
||||||
const frameTimeMicroseconds = parseInt(1_000_000 / config.framerate)
|
const frameTimeMicroseconds = parseInt(1_000_000 / config.framerate)
|
||||||
const oldContext = context;
|
const oldContext = context;
|
||||||
context = exportContext;
|
context = exportContext;
|
||||||
|
|
@ -4896,6 +4991,14 @@ async function setupVideoExport(ext, path, canvas, exportContext) {
|
||||||
height: config.fileHeight,
|
height: config.fileHeight,
|
||||||
bitrate: bitrate,
|
bitrate: bitrate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Todo: add configuration for mono/stereo
|
||||||
|
audioConfig = {
|
||||||
|
codec: 'mp4a.40.2', // AAC codec
|
||||||
|
sampleRate: 44100,
|
||||||
|
numberOfChannels: 2, // Mono
|
||||||
|
bitrate: 64000,
|
||||||
|
};
|
||||||
} else if (ext === "webm") {
|
} else if (ext === "webm") {
|
||||||
target = new WebMMuxer.ArrayBufferTarget();
|
target = new WebMMuxer.ArrayBufferTarget();
|
||||||
muxer = new WebMMuxer.Muxer({
|
muxer = new WebMMuxer.Muxer({
|
||||||
|
|
@ -4916,6 +5019,13 @@ async function setupVideoExport(ext, path, canvas, exportContext) {
|
||||||
bitrate: bitrate,
|
bitrate: bitrate,
|
||||||
bitrateMode: "constant",
|
bitrateMode: "constant",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
audioConfig = {
|
||||||
|
codec: 'opus', // Use Opus codec for WebM
|
||||||
|
sampleRate: 48000,
|
||||||
|
numberOfChannels: 2,
|
||||||
|
bitrate: 64000,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the video encoder
|
// Initialize the video encoder
|
||||||
|
|
@ -4926,18 +5036,12 @@ async function setupVideoExport(ext, path, canvas, exportContext) {
|
||||||
|
|
||||||
videoEncoder.configure(videoConfig);
|
videoEncoder.configure(videoConfig);
|
||||||
|
|
||||||
async function finishEncoding() {
|
// audioEncoder = new AudioEncoder({
|
||||||
const progressText = document.getElementById('progressText');
|
// output: (chunk, meta) => muxer.addAudioChunk(chunk, meta),
|
||||||
progressText.innerText = 'Finalizing...';
|
// error: (e) => console.error(e),
|
||||||
const progressBar = document.getElementById('progressBar');
|
// });
|
||||||
progressBar.value = 100;
|
|
||||||
await videoEncoder.flush();
|
// audioEncoder.configure(audioConfig)
|
||||||
muxer.finalize();
|
|
||||||
await writeFile(path, new Uint8Array(target.buffer));
|
|
||||||
const modal = document.getElementById('progressModal');
|
|
||||||
modal.style.display = 'none';
|
|
||||||
document.querySelector("body").style.cursor = "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
const processFrame = async (currentFrame) => {
|
const processFrame = async (currentFrame) => {
|
||||||
if (currentFrame < root.maxFrame) {
|
if (currentFrame < root.maxFrame) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue