Osciloscope integrated but video exported is broken
This commit is contained in:
@@ -30,6 +30,7 @@ const Pacman = lazy(() => import("./pages/Pacman"));
|
||||
const Snake = lazy(() => import("./pages/Snake"));
|
||||
const Breakout = lazy(() => import("./pages/Breakout"));
|
||||
const Music = lazy(() => import("./pages/Music"));
|
||||
const Oscilloscope = lazy(() => import("./pages/Oscilloscope"));
|
||||
const AIChat = lazy(() => import("./pages/AIChat"));
|
||||
const Achievements = lazy(() => import("./pages/Achievements"));
|
||||
const Credits = lazy(() => import("./pages/Credits"));
|
||||
@@ -125,6 +126,7 @@ const AppContent = () => {
|
||||
<Route path="games/breakout" element={<Breakout />} />
|
||||
<Route path="faq" element={<FAQ />} />
|
||||
<Route path="music" element={<Music />} />
|
||||
<Route path="oscilloscope" element={<Oscilloscope />} />
|
||||
<Route path="ai" element={<AIChat />} />
|
||||
<Route path="achievements" element={<Achievements />} />
|
||||
<Route path="credits" element={<Credits />} />
|
||||
|
||||
@@ -351,7 +351,7 @@ export const useOfflineVideoExport = () => {
|
||||
};
|
||||
};
|
||||
|
||||
// Memory-efficient muxing using real-time playback
|
||||
// Improved muxing with better synchronization
|
||||
async function muxAudioVideo(
|
||||
videoBlob: Blob,
|
||||
audioFile: File,
|
||||
@@ -367,9 +367,9 @@ async function muxAudioVideo(
|
||||
|
||||
video.src = videoUrl;
|
||||
video.muted = true;
|
||||
video.playbackRate = 4; // Speed up playback
|
||||
video.playbackRate = 1; // Normal playback speed
|
||||
audio.src = audioUrl;
|
||||
audio.playbackRate = 4;
|
||||
audio.playbackRate = 1;
|
||||
|
||||
const cleanup = () => {
|
||||
URL.revokeObjectURL(videoUrl);
|
||||
@@ -428,21 +428,39 @@ async function muxAudioVideo(
|
||||
reject(new Error('Muxing failed'));
|
||||
};
|
||||
|
||||
let lastVideoTime = 0;
|
||||
const drawLoop = () => {
|
||||
if (video.ended || audio.ended) {
|
||||
setTimeout(() => recorder.stop(), 100);
|
||||
if (video.paused || video.ended) {
|
||||
if (video.ended || audio.ended) {
|
||||
setTimeout(() => recorder.stop(), 100);
|
||||
return;
|
||||
}
|
||||
requestAnimationFrame(drawLoop);
|
||||
return;
|
||||
}
|
||||
ctx.drawImage(video, 0, 0);
|
||||
|
||||
// Only draw when video has progressed
|
||||
if (video.currentTime !== lastVideoTime) {
|
||||
lastVideoTime = video.currentTime;
|
||||
ctx.drawImage(video, 0, 0);
|
||||
}
|
||||
requestAnimationFrame(drawLoop);
|
||||
};
|
||||
|
||||
recorder.start(100);
|
||||
|
||||
// Ensure both start at the same time
|
||||
video.currentTime = 0;
|
||||
audio.currentTime = 0;
|
||||
video.play();
|
||||
audio.play();
|
||||
drawLoop();
|
||||
|
||||
// Wait for both to be ready to play
|
||||
Promise.all([video.play(), audio.play()]).then(() => {
|
||||
drawLoop();
|
||||
}).catch(err => {
|
||||
console.error('Playback failed:', err);
|
||||
cleanup();
|
||||
reject(err);
|
||||
});
|
||||
}).catch(err => {
|
||||
cleanup();
|
||||
console.warn('Muxing failed, returning video only:', err);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Oscilloscope } from '@/components/Oscilloscope';
|
||||
|
||||
const OscilloscopePage = () => {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="space-y-6"
|
||||
>
|
||||
<div className="text-center space-y-2">
|
||||
<h1 className="font-minecraft text-3xl md:text-4xl text-primary text-glow-strong">
|
||||
Audio Oscilloscope
|
||||
</h1>
|
||||
<p className="font-pixel text-foreground/80">
|
||||
Visualize audio waveforms in real-time with microphone input or audio files.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Oscilloscope />
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OscilloscopePage;
|
||||
Reference in New Issue
Block a user