Please bookmark this page to avoid losing your image tool!

Audio Effects Voice Changer Tool

(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.
/**
 * Creates an interactive audio voice changer UI using the provided image as a background.
 * This tool uses the Web Audio API to apply real-time effects to microphone input.
 *
 * @param {HTMLImageElement} originalImg The image to use as a background for the UI.
 * @param {string} initialEffect The name of the effect to select by default.
 *   Valid options: 'none', 'robot', 'echo', 'reverb', 'chipmunk', 'monster'. Defaults to 'none'.
 * @param {string} textColor A CSS color string for the text and UI controls. Defaults to '#FFFFFF'.
 * @param {string} overlayColor A CSS color string for the semi-transparent overlay. Defaults to 'rgba(0, 0, 0, 0.6)'.
 * @returns {HTMLElement} A div element containing the interactive voice changer UI.
 */
async function processImage(originalImg, initialEffect = 'none', textColor = '#FFFFFF', overlayColor = 'rgba(0, 0, 0, 0.6)') {
    // --- 1. Create the main container and UI elements ---
    const container = document.createElement('div');
    container.style.position = 'relative';
    container.style.display = 'inline-block';
    container.style.fontFamily = 'Arial, sans-serif';
    container.style.border = '1px solid #ccc';
    container.style.borderRadius = '8px';
    container.style.overflow = 'hidden';
    container.style.width = originalImg.naturalWidth > 0 ? `${originalImg.naturalWidth}px` : '400px';
    container.style.height = originalImg.naturalHeight > 0 ? `${originalImg.naturalHeight}px` : '300px';

    const bgImg = originalImg.cloneNode();
    bgImg.style.display = 'block';
    bgImg.style.width = '100%';
    bgImg.style.height = '100%';
    bgImg.style.objectFit = 'cover';
    container.appendChild(bgImg);

    const overlay = document.createElement('div');
    overlay.style.position = 'absolute';
    overlay.style.top = '0';
    overlay.style.left = '0';
    overlay.style.width = '100%';
    overlay.style.height = '100%';
    overlay.style.backgroundColor = overlayColor;
    overlay.style.color = textColor;
    overlay.style.display = 'flex';
    overlay.style.flexDirection = 'column';
    overlay.style.alignItems = 'center';
    overlay.style.justifyContent = 'center';
    overlay.style.padding = '20px';
    overlay.style.boxSizing = 'border-box';
    overlay.style.textAlign = 'center';
    container.appendChild(overlay);

    const title = document.createElement('h2');
    title.textContent = 'Audio Effects Voice Changer';
    title.style.margin = '0 0 15px 0';
    overlay.appendChild(title);

    const startButton = document.createElement('button');
    startButton.textContent = 'Start Microphone';
    startButton.style.padding = '10px 15px';
    startButton.style.fontSize = '16px';
    startButton.style.cursor = 'pointer';
    startButton.style.borderRadius = '5px';
    startButton.style.border = `1px solid ${textColor}`;
    startButton.style.backgroundColor = 'transparent';
    startButton.style.color = textColor;
    overlay.appendChild(startButton);

    const statusText = document.createElement('p');
    statusText.textContent = 'Click "Start" to enable your microphone.';
    statusText.style.marginTop = '10px';
    statusText.style.fontSize = '14px';
    overlay.appendChild(statusText);

    const controlsContainer = document.createElement('div');
    controlsContainer.style.marginTop = '20px';
    controlsContainer.style.visibility = 'hidden'; // Initially hidden
    overlay.appendChild(controlsContainer);

    const effectLabel = document.createElement('label');
    effectLabel.textContent = 'Effect: ';
    effectLabel.htmlFor = 'effect-select';
    controlsContainer.appendChild(effectLabel);

    const effectSelect = document.createElement('select');
    effectSelect.id = 'effect-select';
    const effects = ['None', 'Robot', 'Echo', 'Reverb', 'Chipmunk', 'Monster'];
    effects.forEach(effectName => {
        const option = document.createElement('option');
        option.value = effectName.toLowerCase();
        option.textContent = effectName;
        effectSelect.appendChild(option);
    });
    // Set initial effect from parameter
    const lowerCaseInitialEffect = initialEffect.toLowerCase();
    if (effects.map(e => e.toLowerCase()).includes(lowerCaseInitialEffect)) {
        effectSelect.value = lowerCaseInitialEffect;
    } else {
        effectSelect.value = 'none';
    }
    controlsContainer.appendChild(effectSelect);
    
    // --- 2. Web Audio API setup and state variables ---
    let audioContext;
    let microphoneSource;
    let mainGainNode;
    let currentEffectNode;
    let impulseResponseBuffer = null;

    const createReverbImpulse = async (context) => {
        const sampleRate = context.sampleRate;
        const duration = 2;
        const decay = 3;
        const length = sampleRate * duration;
        const impulse = context.createBuffer(2, length, sampleRate);
        for (let channel = 0; channel < 2; channel++) {
            const channelData = impulse.getChannelData(channel);
            for (let i = 0; i < length; i++) {
                channelData[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / length, decay);
            }
        }
        return impulse;
    };
    
    const applyEffect = async (effectName) => {
        if (!microphoneSource || !audioContext) return;

        microphoneSource.disconnect();
        if (currentEffectNode) {
            // Special cleanup for complex nodes like echo feedback loop
            if (currentEffectNode.feedbackNode) {
                currentEffectNode.disconnect(currentEffectNode.feedbackNode);
                currentEffectNode.feedbackNode.disconnect(currentEffectNode);
            }
            currentEffectNode.disconnect();
        }

        switch (effectName) {
            case 'robot':
                currentEffectNode = audioContext.createBiquadFilter();
                currentEffectNode.type = 'bandpass';
                currentEffectNode.frequency.setValueAtTime(1500, audioContext.currentTime);
                currentEffectNode.Q.setValueAtTime(25, audioContext.currentTime);
                break;
            
            case 'echo':
                const delayNode = audioContext.createDelay(2.0);
                delayNode.delayTime.setValueAtTime(0.4, audioContext.currentTime);
                const feedbackNode = audioContext.createGain();
                feedbackNode.gain.setValueAtTime(0.6, audioContext.currentTime);
                
                delayNode.connect(feedbackNode);
                feedbackNode.connect(delayNode);
                
                delayNode.feedbackNode = feedbackNode; // Store for cleanup
                currentEffectNode = delayNode;
                
                microphoneSource.connect(delayNode); // Wet signal
                delayNode.connect(mainGainNode);
                microphoneSource.connect(mainGainNode); // Dry signal
                mainGainNode.connect(audioContext.destination);
                return;
            
            case 'reverb':
                currentEffectNode = audioContext.createConvolver();
                if (!impulseResponseBuffer) {
                   impulseResponseBuffer = await createReverbImpulse(audioContext);
                }
                currentEffectNode.buffer = impulseResponseBuffer;
                break;

            case 'chipmunk':
                currentEffectNode = audioContext.createBiquadFilter();
                currentEffectNode.type = 'peaking';
                // This doesn't truly change pitch, but boosts high frequencies to simulate the effect
                currentEffectNode.frequency.setValueAtTime(3500, audioContext.currentTime);
                currentEffectNode.Q.setValueAtTime(5, audioContext.currentTime);
                currentEffectNode.gain.setValueAtTime(25, audioContext.currentTime);
                break;
                
            case 'monster':
                currentEffectNode = audioContext.createBiquadFilter();
                currentEffectNode.type = 'peaking';
                // Boosts low frequencies for a "deeper" voice effect
                currentEffectNode.frequency.setValueAtTime(100, audioContext.currentTime);
                currentEffectNode.Q.setValueAtTime(2, audioContext.currentTime);
                currentEffectNode.gain.setValueAtTime(20, audioContext.currentTime);
                break;

            case 'none':
            default:
                currentEffectNode = null;
                break;
        }

        if (currentEffectNode) {
            microphoneSource.connect(currentEffectNode);
            currentEffectNode.connect(mainGainNode);
        } else {
            microphoneSource.connect(mainGainNode);
        }
        mainGainNode.connect(audioContext.destination);
    };

    // --- 4. Event Listeners ---
    startButton.addEventListener('click', async () => {
        try {
            if (!audioContext) {
                audioContext = new (window.AudioContext || window.webkitAudioContext)();
            }

            if (audioContext.state === 'suspended') {
                await audioContext.resume();
            }

            const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
            microphoneSource = audioContext.createMediaStreamSource(stream);
            mainGainNode = audioContext.createGain();
            
            await applyEffect(effectSelect.value);

            statusText.textContent = 'Microphone is active! Try speaking.';
            startButton.disabled = true;
            startButton.style.cursor = 'not-allowed';
            startButton.style.opacity = '0.7';
            controlsContainer.style.visibility = 'visible';

        } catch (err) {
            console.error('Error accessing microphone:', err);
            statusText.textContent = `Error: ${err.message}. Please allow microphone access.`;
            statusText.style.color = '#ff8a80'; // A light red for errors
        }
    });

    effectSelect.addEventListener('change', (event) => {
        applyEffect(event.target.value);
    });

    // --- 5. Return the created element ---
    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 Audio Effects Voice Changer Tool allows users to modify their voice in real-time using various audio effects. By leveraging the Web Audio API, this tool provides a user-friendly interface where individuals can connect their microphone and apply effects such as ‘robot’, ‘echo’, ‘reverb’, ‘chipmunk’, and ‘monster’. It’s ideal for entertainment purposes like creating fun videos, streaming, gaming, and voice modulation for podcasts or radio shows.

Leave a Reply

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