Please bookmark this page to avoid losing your image tool!

Image Voice Changer

(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.
async function processImage(originalImg, pitchShift = 0, duration = 1, effect = 'none') {
    /**
     * This function interprets "Image Voice Changer" by sonifying the input image.
     * It analyzes the image's average color and brightness and maps these visual properties
     * to audio properties like pitch, waveform, and volume, generating a sound
     * that represents the "voice" of the image.
     *
     * @param {Image} originalImg - The input Image object.
     * @param {number} pitchShift - Shift the base pitch by a number of semitones. Default is 0.
     * @param {number} duration - The duration of the generated sound in seconds. Default is 1.
     * @param {string} effect - An audio effect to apply. Can be 'none' or 'vibrato'. Default is 'none'.
     * @returns {HTMLElement} A div container with the image and a "Play" button.
     */

    const container = document.createElement('div');
    container.style.position = 'relative';
    container.style.display = 'inline-block';
    
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    ctx.drawImage(originalImg, 0, 0);

    const button = document.createElement('button');
    button.textContent = '▶️ Play Image Voice';
    button.style.position = 'absolute';
    button.style.bottom = '10px';
    button.style.left = '50%';
    button.style.transform = 'translateX(-50%)';
    button.style.padding = '10px 15px';
    button.style.border = 'none';
    button.style.borderRadius = '5px';
    button.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
    button.style.color = 'white';
    button.style.cursor = 'pointer';
    button.style.fontSize = '16px';
    button.style.fontFamily = 'Arial, sans-serif';
    button.style.transition = 'background-color 0.2s';
    
    button.onmouseover = () => button.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
    button.onmouseout = () => button.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';

    container.appendChild(canvas);
    container.appendChild(button);

    // This AudioContext can be reused if the button is clicked multiple times.
    let audioCtx = null;

    button.onclick = () => {
        if (!audioCtx) {
            audioCtx = new(window.AudioContext || window.webkitAudioContext)();
        }
        
        // Resume context if it was suspended
        if (audioCtx.state === 'suspended') {
            audioCtx.resume();
        }

        // --- 1. Analyze Image Data ---
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        const data = imageData.data;
        let totalR = 0, totalG = 0, totalB = 0;

        for (let i = 0; i < data.length; i += 4) {
            totalR += data[i];
            totalG += data[i + 1];
            totalB += data[i + 2];
        }

        const pixelCount = data.length / 4;
        const avgR = totalR / pixelCount;
        const avgG = totalG / pixelCount;
        const avgB = totalB / pixelCount;
        
        // --- 2. Map Image Properties to Audio Properties ---
        
        // Helper to convert RGB to HSL (Hue, Saturation, Lightness)
        function rgbToHsl(r, g, b) {
            r /= 255; g /= 255; b /= 255;
            const max = Math.max(r, g, b), min = Math.min(r, g, b);
            let h, s, l = (max + min) / 2;

            if (max === min) {
                h = s = 0; // achromatic
            } else {
                const d = max - min;
                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                switch (max) {
                    case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                    case g: h = (b - r) / d + 2; break;
                    case b: h = (r - g) / d + 4; break;
                }
                h /= 6;
            }
            return [h * 360, s, l];
        }

        const [hue, saturation, lightness] = rgbToHsl(avgR, avgG, avgB);

        // Map Hue (0-360) to a musical frequency range (e.g., 110Hz to 880Hz)
        const baseFrequency = 110 + (hue / 360) * 770; 
        
        // Apply pitch shift (1 semitone = 2^(1/12))
        const finalFrequency = baseFrequency * Math.pow(2, pitchShift / 12);
        
        // Map Saturation (0-1) to waveform type
        let waveform = 'sine'; // Grayscale/low saturation -> pure tone
        if (saturation > 0.66) {
            waveform = 'sawtooth'; // High saturation -> harsh tone
        } else if (saturation > 0.33) {
            waveform = 'triangle'; // Medium saturation -> richer tone
        }
        
        // Map Lightness (0-1) to volume (Gain)
        const volume = Math.max(0, Math.min(1, lightness));

        // --- 3. Generate Audio using Web Audio API ---
        
        const oscillator = audioCtx.createOscillator();
        const gainNode = audioCtx.createGain();

        oscillator.type = waveform;
        oscillator.frequency.setValueAtTime(finalFrequency, audioCtx.currentTime);

        // Apply a gentle fade in and fade out to prevent clicking
        gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
        gainNode.gain.linearRampToValueAtTime(volume, audioCtx.currentTime + 0.05);
        gainNode.gain.linearRampToValueAtTime(0, audioCtx.currentTime + duration);

        if (effect.toLowerCase() === 'vibrato') {
            const lfo = audioCtx.createOscillator();
            lfo.frequency.setValueAtTime(5, audioCtx.currentTime); // 5hz vibrato
            const lfoGain = audioCtx.createGain();
            lfoGain.gain.setValueAtTime(finalFrequency * 0.05, audioCtx.currentTime); // Vibrato depth
            
            lfo.connect(lfoGain);
            lfoGain.connect(oscillator.frequency); // Modulate the main oscillator's frequency
            lfo.start(audioCtx.currentTime);
            lfo.stop(audioCtx.currentTime + duration);
        }

        oscillator.connect(gainNode);
        gainNode.connect(audioCtx.destination);
        
        oscillator.start(audioCtx.currentTime);
        oscillator.stop(audioCtx.currentTime + duration);
    };

    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

The Image Voice Changer is a unique tool that sonifies images by converting visual properties into sound. Users can upload an image, and the tool analyzes its average color and brightness to produce a corresponding audio representation. This includes mapping image attributes like hue, saturation, and lightness to audio variables such as pitch, waveform, and volume. Users can customize the audio output by adjusting parameters like pitch shift, duration, and audio effects. This tool can be useful for artists, educators, or anyone interested in exploring the intersection of visual art and music, allowing for an innovative way to experience images through sound.

Leave a Reply

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