Please bookmark this page to avoid losing your image tool!

Image To Vocoder Audio And Carrier 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.
async function processImage(originalImg, durationSec = 5, carrierType = 'sawtooth', carrierFreq = 110, numBands = 40, qFactor = 5, minFreq = 300, maxFreq = 10000) {

    /**
     * Converts an AudioBuffer to a WAV audio format Blob.
     * @param {AudioBuffer} aBuffer The audio buffer to convert.
     * @returns {Blob} A blob containing the WAV audio data.
     */
    function bufferToWave(aBuffer) {
        const numOfChan = aBuffer.numberOfChannels;
        const L = aBuffer.length;
        const length = L * numOfChan * 2 + 44;
        const buffer = new ArrayBuffer(length);
        const view = new DataView(buffer);
        let pos = 0;

        const setUint16 = (data) => {
            view.setUint16(pos, data, true);
            pos += 2;
        };

        const setUint32 = (data) => {
            view.setUint32(pos, data, true);
            pos += 4;
        };

        // RIFF header
        setUint32(0x46464952); // "RIFF"
        setUint32(length - 8);
        setUint32(0x45564157); // "WAVE"

        // "fmt " subchunk
        setUint32(0x20746d66); // "fmt "
        setUint32(16); // 16 for PCM
        setUint16(1); // PCM
        setUint16(numOfChan);
        setUint32(aBuffer.sampleRate);
        setUint32(aBuffer.sampleRate * 2 * numOfChan); // byte rate
        setUint16(numOfChan * 2); // block align
        setUint16(16); // 16-bit

        // "data" subchunk
        setUint32(0x61746164); // "data"
        setUint32(L * numOfChan * 2);

        // write the PCM samples
        const channels = [];
        for (let i = 0; i < numOfChan; i++) {
            channels.push(aBuffer.getChannelData(i));
        }

        for (let i = 0; i < L; i++) {
            for (let j = 0; j < numOfChan; j++) {
                let sample = Math.max(-1, Math.min(1, channels[j][i]));
                sample = sample < 0 ? sample * 0x8000 : sample * 0x7FFF;
                view.setInt16(pos, sample, true);
                pos += 2;
            }
        }
        return new Blob([buffer], {
            type: 'audio/wav'
        });
    }

    // --- Main Logic ---

    const AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext;
    if (!AudioContext) {
        const el = document.createElement('p');
        el.textContent = 'Web Audio API is not supported in this browser.';
        return el;
    }

    if (originalImg.width === 0 || originalImg.height === 0) {
        const el = document.createElement('p');
        el.textContent = 'Image has zero width or height and cannot be processed.';
        return el;
    }

    const validCarrierTypes = ['sine', 'square', 'sawtooth', 'triangle', 'noise'];
    if (!validCarrierTypes.includes(carrierType)) {
        carrierType = 'sawtooth'; // Default to a safe value
    }

    const width = originalImg.width;
    const height = originalImg.height;
    const sampleRate = 44100;
    const bands = Math.min(numBads, height);


    // 1. Analyze image to create gain automation curves for the vocoder bands
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = width;
    tempCanvas.height = height;
    const ctx = tempCanvas.getContext('2d');
    ctx.drawImage(originalImg, 0, 0, width, height);
    const imageData = ctx.getImageData(0, 0, width, height).data;

    const gainCurves = Array.from({ length: bands }, () => new Float32Array(width));
    const bandHeight = height / bands;

    for (let x = 0; x < width; x++) { // Iterate through time (horizontal axis)
        for (let b = 0; b < bands; b++) { // Iterate through frequency bands (vertical axis)
            let sumBrightness = 0;
            let pixelCount = 0;
            const startY = Math.floor(b * bandHeight);
            const endY = Math.min(height, Math.floor((b + 1) * bandHeight));

            for (let y = startY; y < endY; y++) {
                const i = (y * width + x) * 4; // pixel index
                const r = imageData[i];
                const g = imageData[i + 1];
                const b_val = imageData[i + 2];
                const brightness = (r + g + b_val) / 3;
                sumBrightness += brightness;
                pixelCount++;
            }
            const avgBrightness = pixelCount > 0 ? sumBrightness / pixelCount : 0;
            gainCurves[b][x] = avgBrightness / 255.0; // Normalize to 0.0 - 1.0 gain
        }
    }

    // Helper to create a carrier source node for a given AudioContext
    const createCarrier = (context) => {
        if (carrierType === 'noise') {
            const bufferSize = Math.ceil(context.sampleRate * durationSec);
            const noiseBuffer = context.createBuffer(1, bufferSize, context.samplerate);
            const output = noiseBuffer.getChannelData(0);
            for (let i = 0; i < bufferSize; i++) {
                output[i] = Math.random() * 2 - 1; // white noise
            }
            const noiseSource = context.createBufferSource();
            noiseSource.buffer = noiseBuffer;
            noiseSource.loop = true;
            return noiseSource;
        } else {
            const oscillator = context.createOscillator();
            oscillator.type = carrierType;
            oscillator.frequency.value = carrierFreq;
            return oscillator;
        }
    };


    // 2. Render the full vocoded audio using an OfflineAudioContext
    const vocoderContext = new AudioContext(1, sampleRate * durationSec, sampleRate);
    const carrier = createCarrier(vocoderContext);

    // Create a bank of bandpass filters
    const logMin = Math.log(Math.max(1, minFreq));
    const logMax = Math.log(Math.max(1, maxFreq));
    const logRange = logMax - logMin;

    for (let i = 0; i < bands; i++) {
        let centerFreq;
        if (bands > 1) { // Logarithmic spacing for multiple bands
            centerFreq = Math.exp(logMin + logRange * (i / (bands - 1)));
        } else { // Handle the single-band case
            centerFreq = Math.exp(logMin + logRange * 0.5);
        }

        const bandpass = vocoderContext.createBiquadFilter();
        bandpass.type = 'bandpass';
        bandpass.frequency.value = centerFreq;
        bandpass.Q.value = qFactor;

        // Gain node controlled by the image's brightness for this band
        const gainNode = vocoderContext.createGain();
        gainNode.gain.setValueAtTime(0, 0);
        gainNode.gain.setValueCurveAtTime(gainCurves[i], 0, durationSec);

        carrier.connect(bandpass);
        bandpass.connect(gainNode);
        gainNode.connect(vocoderContext.destination);
    }

    carrier.start(0);
    const vocodedBuffer = await vocoderContext.startRendering();


    // 3. Render the raw carrier signal audio separately for comparison
    const carrierContext = new AudioContext(1, sampleRate * durationSec, sampleRate);
    const carrierOnly = createCarrier(carrierContext);
    carrierOnly.connect(carrierContext.destination);
    carrierOnly.start(0);
    const carrierBuffer = await carrierContext.startRendering();

    // 4. Create and return the HTML element with audio players
    const container = document.createElement('div');
    container.style.cssText = 'display: flex; flex-direction: column; gap: 10px; align-items: flex-start;';

    const vocoderBlob = bufferToWave(vocodedBuffer);
    const vocoderUrl = URL.createObjectURL(vocoderBlob);
    const vocoderAudioEl = document.createElement('audio');
    vocoderAudioEl.controls = true;
    vocoderAudioEl.src = vocoderUrl;

    const vocoderHeading = document.createElement('h3');
    vocoderHeading.textContent = 'Vocoded Result';
    container.appendChild(vocoderHeading);
    container.appendChild(vocoderAudioEl);

    const carrierBlob = bufferToWave(carrierBuffer);
    const carrierUrl = URL.createObjectURL(carrierBlob);
    const carrierAudioEl = document.createElement('audio');
    carrierAudioEl.controls = true;
    carrierAudioEl.src = carrierUrl;

    const carrierHeading = document.createElement('h3');
    carrierHeading.textContent = 'Carrier Signal';
    container.appendChild(carrierHeading);
    container.appendChild(carrierAudioEl);

    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 To Vocoder Audio And Carrier Tool transforms images into sound by analyzing pixel brightness to create audio signals. Users can customize audio duration, carrier type, frequency, and other parameters to generate unique vocoded audio outputs and corresponding carrier signals based on the visual content of the image. This tool is suitable for musicians, sound designers, and digital artists looking to explore audio-visual interactions or create innovative soundscapes inspired by images.

Leave a Reply

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