Please bookmark this page to avoid losing your image tool!

MP3 Audio To MP4 Video Converter

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, defaultAudioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3', visualizerColor = '#4CAF50') {
    // 1. Create a wrapper container (The "Video Player")
    const container = document.createElement('div');
    container.style.fontFamily = 'Arial, sans-serif';
    container.style.width = '100%';
    container.style.maxWidth = '800px';
    container.style.margin = '0 auto';
    container.style.background = '#1a1a1a';
    container.style.borderRadius = '10px';
    container.style.overflow = 'hidden';
    container.style.boxShadow = '0 8px 30px rgba(0,0,0,0.6)';
    container.style.display = 'flex';
    container.style.flexDirection = 'column';

    // 2. Header
    const header = document.createElement('div');
    header.style.padding = '15px';
    header.style.background = '#000';
    header.style.color = '#fff';
    header.style.fontWeight = 'bold';
    header.style.textAlign = 'center';
    header.style.letterSpacing = '1px';
    header.innerText = 'MP3 to MP4 Converter / Video Player';
    container.appendChild(header);

    // 3. Canvas (The Video Screen)
    const canvas = document.createElement('canvas');
    canvas.width = originalImg.width || 800;
    canvas.height = originalImg.height || 600;
    canvas.style.width = '100%';
    canvas.style.display = 'block';
    canvas.style.maxHeight = '60vh'; 
    canvas.style.objectFit = 'contain';
    canvas.style.backgroundColor = '#000';
    
    container.appendChild(canvas);
    const ctx = canvas.getContext('2d');

    // Utility: Draw Image (Background) maintaining max coverage, plus a sleek dark overlay
    function drawBackground() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        
        const canvasRatio = canvas.width / canvas.height;
        const imgRatio = originalImg.width / originalImg.height;
        let drawWidth = canvas.width;
        let drawHeight = canvas.height;
        let offsetX = 0;
        let offsetY = 0;

        if (imgRatio > canvasRatio) {
            drawWidth = canvas.height * imgRatio;
            offsetX = (canvas.width - drawWidth) / 2;
        } else {
            drawHeight = canvas.width / imgRatio;
            offsetY = (canvas.height - drawHeight) / 2;
        }
        
        ctx.drawImage(originalImg, offsetX, offsetY, drawWidth, drawHeight);
        
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; // Darken to make visualizer pop
        ctx.fillRect(0, 0, canvas.width, canvas.height);
    }

    if (originalImg.complete && originalImg.naturalHeight !== 0) {
        drawBackground();
    } else {
        originalImg.onload = drawBackground;
    }

    // 4. Audio Engine
    const audio = new Audio();
    audio.crossOrigin = 'anonymous'; // Important for Web Audio API if URL is external
    audio.src = defaultAudioUrl;

    let audioCtx, analyser, source, dataArray, bufferLength;
    let isPlaying = false;
    let animationId;
    let audioInitialized = false;

    // 5. Controls UI
    const controls = document.createElement('div');
    controls.style.display = 'flex';
    controls.style.alignItems = 'center';
    controls.style.flexWrap = 'wrap';
    controls.style.padding = '15px';
    controls.style.background = '#222';
    controls.style.gap = '15px';
    container.appendChild(controls);

    const btnStyle = `
        padding: 8px 16px;
        border: none;
        border-radius: 5px;
        background: #4CAF50;
        color: #fff;
        cursor: pointer;
        font-weight: bold;
        transition: background 0.2s;
    `;

    const playBtn = document.createElement('button');
    playBtn.innerHTML = '▶ Play';
    playBtn.style.cssText = btnStyle;
    controls.appendChild(playBtn);

    const progressContainer = document.createElement('div');
    progressContainer.style.flex = '1 1 150px';
    progressContainer.style.height = '8px';
    progressContainer.style.background = '#444';
    progressContainer.style.borderRadius = '4px';
    progressContainer.style.cursor = 'pointer';
    progressContainer.style.position = 'relative';
    
    const progressBar = document.createElement('div');
    progressBar.style.height = '100%';
    progressBar.style.width = '0%';
    progressBar.style.background = visualizerColor;
    progressBar.style.borderRadius = '4px';
    progressBar.style.pointerEvents = 'none';
    
    progressContainer.appendChild(progressBar);
    controls.appendChild(progressContainer);

    const timeDisplay = document.createElement('div');
    timeDisplay.style.color = '#ddd';
    timeDisplay.style.fontSize = '14px';
    timeDisplay.style.fontFamily = 'monospace';
    timeDisplay.innerText = '0:00 / 0:00';
    controls.appendChild(timeDisplay);

    const recordBtn = document.createElement('button');
    recordBtn.innerHTML = '📹 Record MP4';
    recordBtn.style.cssText = btnStyle;
    recordBtn.style.background = '#E91E63';
    recordBtn.title = 'Convert current Audio and Visuals to a downloadable Video File';
    controls.appendChild(recordBtn);

    // 6. Functions for Control Handlers
    const formatTime = (time) => {
        if (isNaN(time) || !isFinite(time)) return '0:00';
        const mins = Math.floor(time / 60);
        const secs = Math.floor(time % 60);
        return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
    };

    audio.addEventListener('timeupdate', () => {
        const percent = (audio.currentTime / audio.duration) * 100 || 0;
        progressBar.style.width = `${percent}%`;
        timeDisplay.innerText = `${formatTime(audio.currentTime)} / ${formatTime(audio.duration)}`;
    });

    progressContainer.addEventListener('click', (e) => {
        const rect = progressContainer.getBoundingClientRect();
        const pos = (e.clientX - rect.left) / rect.width;
        if(audio.duration) {
            audio.currentTime = pos * audio.duration;
        }
    });

    // 7. Web Audio API Init for Canvas Visualizer
    function initAudio() {
        if (audioInitialized) return;
        const AudioContext = window.AudioContext || window.webkitAudioContext;
        audioCtx = new AudioContext();
        analyser = audioCtx.createAnalyser();
        analyser.fftSize = 256;
        source = audioCtx.createMediaElementSource(audio);
        source.connect(analyser);
        analyser.connect(audioCtx.destination);
        bufferLength = analyser.frequencyBinCount;
        dataArray = new Uint8Array(bufferLength);
        audioInitialized = true;
    }

    // 8. Visualizer Rendering Loop
    function drawVisualizer() {
        drawBackground(); // Base image

        if (audioInitialized) {
            analyser.getByteFrequencyData(dataArray);

            const width = canvas.width;
            const height = canvas.height;
            const barWidth = (width / bufferLength) * 2.2;
            let barHeight;
            let x = 0;

            for (let i = 0; i < bufferLength; i++) {
                barHeight = dataArray[i] * (height / 350); 
                
                ctx.fillStyle = visualizerColor;
                // Add an alpha fade based on spectrum positioning
                ctx.globalAlpha = Math.max(0.2, 0.9 - (i / bufferLength) * 0.5);
                ctx.fillRect(x, height - barHeight, barWidth, barHeight);
                ctx.globalAlpha = 1.0;

                x += barWidth + 1;
            }
        }
        animationId = requestAnimationFrame(drawVisualizer);
    }

    function togglePlay() {
        if (!audioInitialized) initAudio();
        
        if (audioCtx && audioCtx.state === 'suspended') {
            audioCtx.resume();
        }
        
        if (audio.paused) {
            audio.play();
            isPlaying = true;
            playBtn.innerHTML = '⏸ Pause';
            drawVisualizer();
        } else {
            audio.pause();
            isPlaying = false;
            playBtn.innerHTML = '▶ Play';
            cancelAnimationFrame(animationId);
            drawBackground();
        }
    }

    playBtn.addEventListener('click', togglePlay);

    audio.addEventListener('ended', () => {
        isPlaying = false;
        playBtn.innerHTML = '▶ Play';
        cancelAnimationFrame(animationId);
        drawBackground();
        if (isRecording) stopRecording();
    });

    // 9. Converter API (MediaRecorder captures Canvas + Audio)
    let mediaRecorder;
    let recordedChunks = [];
    let isRecording = false;

    recordBtn.addEventListener('click', () => {
        if (isRecording) {
            stopRecording();
        } else {
            startRecording();
        }
    });

    function startRecording() {
        if (!audioInitialized) initAudio();
        
        try {
            // Capture Video Track from Canvas
            const stream = canvas.captureStream(30); // 30 FPS

            // Mix Audio Track dynamically
            const dest = audioCtx.createMediaStreamDestination();
            analyser.connect(dest);
            const audioTracks = dest.stream.getAudioTracks();
            if (audioTracks.length > 0) {
                stream.addTrack(audioTracks[0]);
            }

            // Negotiate MIME support
            let mimeType = '';
            if (MediaRecorder.isTypeSupported('video/mp4')) {
                mimeType = 'video/mp4';
            } else if (MediaRecorder.isTypeSupported('video/webm; codecs=vp9,opus')) {
                mimeType = 'video/webm; codecs=vp9,opus';
            } else if (MediaRecorder.isTypeSupported('video/webm; codecs=vp8,opus')) {
                mimeType = 'video/webm; codecs=vp8,opus';
            } else {
                mimeType = 'video/webm';
            }

            mediaRecorder = new MediaRecorder(stream, mimeType ? { mimeType } : undefined);

            mediaRecorder.ondataavailable = (e) => {
                if (e.data.size > 0) recordedChunks.push(e.data);
            };

            mediaRecorder.onstop = () => {
                const blob = new Blob(recordedChunks, { type: mimeType || 'video/webm' });
                recordedChunks = [];
                
                const ext = (mimeType && mimeType.includes('mp4')) ? 'mp4' : 'webm';
                const url = URL.createObjectURL(blob);
                
                // Automatically prompt user to download file
                const a = document.createElement('a');
                a.style.display = 'none';
                a.href = url;
                a.download = `converted_video.${ext}`;
                document.body.appendChild(a);
                a.click();
                
                setTimeout(() => {
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                }, 200);
                
                recordBtn.innerHTML = '📹 Record MP4';
                recordBtn.style.background = '#E91E63';
                isRecording = false;
            };

            mediaRecorder.start();
            isRecording = true;
            recordBtn.innerHTML = '⏹ Stop Processing';
            recordBtn.style.background = '#f44336';
            
            if (audio.paused) togglePlay();

        } catch (e) {
            alert("Error initializing screen recording. Your browser may not fully support Canvas web conversions.");
            console.error(e);
        }
    }

    function stopRecording() {
        if (mediaRecorder && mediaRecorder.state !== 'inactive') {
            mediaRecorder.stop();
        }
        if (!audio.paused) togglePlay();
    }

    // 10. Source Load Component
    const inputContainer = document.createElement('div');
    inputContainer.style.display = 'flex';
    inputContainer.style.flexWrap = 'wrap';
    inputContainer.style.padding = '15px';
    inputContainer.style.background = '#111';
    inputContainer.style.gap = '10px';
    container.appendChild(inputContainer);

    const urlInput = document.createElement('input');
    urlInput.type = 'text';
    urlInput.value = defaultAudioUrl;
    urlInput.placeholder = 'Enter MP3 URL or Use Local Audio';
    urlInput.style.flex = '1 1 200px';
    urlInput.style.padding = '8px 12px';
    urlInput.style.border = '1px solid #444';
    urlInput.style.borderRadius = '5px';
    urlInput.style.background = '#222';
    urlInput.style.color = '#fff';
    urlInput.style.outline = 'none';

    const loadBtn = document.createElement('button');
    loadBtn.innerText = 'Load URL';
    loadBtn.style.cssText = btnStyle;
    loadBtn.style.background = '#FF9800';
    
    const fileLabel = document.createElement('label');
    fileLabel.innerText = '📁 Local MP3';
    fileLabel.style.cssText = btnStyle;
    fileLabel.style.background = '#00BCD4';
    
    const fileInput = document.createElement('input');
    fileInput.type = 'file';
    fileInput.accept = 'audio/*';
    fileInput.style.display = 'none';
    
    const applyAudio = (srcStr) => {
        if (isRecording) stopRecording();
        audio.src = srcStr;
        audio.load();
        if (isPlaying) {
            togglePlay();
        } else {
            drawBackground();
        }
        progressBar.style.width = '0%';
        timeDisplay.innerText = '0:00 / 0:00';
    };

    loadBtn.addEventListener('click', () => {
        if (urlInput.value) applyAudio(urlInput.value);
    });

    fileInput.addEventListener('change', (e) => {
        if(e.target.files.length > 0) {
            const file = e.target.files[0];
            const objectUrl = URL.createObjectURL(file);
            urlInput.value = file.name;
            applyAudio(objectUrl);
        }
    });

    fileLabel.appendChild(fileInput);
    inputContainer.appendChild(urlInput);
    inputContainer.appendChild(loadBtn);
    inputContainer.appendChild(fileLabel);

    return container;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

This tool converts MP3 audio files into MP4 video files by combining your audio with a static background image and a dynamic audio visualizer. Users can upload local audio files or provide an audio URL, set a background image, and customize the visualizer color. The tool features a real-time playback engine with a frequency spectrum visualizer, allowing you to preview the result before recording. This is ideal for content creators looking to create music videos for social media, turning static song covers into engaging video content, or generating visualizers for YouTube uploads.

Leave a Reply

Your email address will not be published. Required fields are marked *