Please bookmark this page to avoid losing your image tool!

Image Melody Creator

(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, totalDuration_s = 8, scaleType = 'pentatonicMajor', rootNote = 'C4', octaves = 3, waveform = 'sine', noteDensity = 2, brightnessThreshold = 50) {

    // --- Helper Functions for Music Theory ---

    /**
     * Converts a MIDI note number to a frequency in Hz.
     * @param {number} midi - The MIDI note number (e.g., 69 for A4).
     * @returns {number} The frequency in Hz.
     */
    const midiToFreq = (midi) => {
        return 440 * Math.pow(2, (midi - 69) / 12);
    };

    /**
     * Generates an array of frequencies for a given musical scale.
     * @param {string} rootNoteStr - The root note of the scale (e.g., 'C4', 'A#3').
     * @param {string} scaleType - The type of scale ('major', 'minor', 'pentatonicMajor', etc.).
     * @param {number} numOctaves - The number of octaves to generate.
     * @returns {number[]} An array of note frequencies.
     */
    const generateScaleFrequencies = (rootNoteStr, scaleType, numOctaves) => {
        const scaleIntervals = {
            major: [0, 2, 4, 5, 7, 9, 11],
            minor: [0, 2, 3, 5, 7, 8, 10],
            pentatonicMajor: [0, 2, 4, 7, 9],
            pentatonicMinor: [0, 3, 5, 7, 10],
            chromatic: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
        };

        const noteOffsets = { C: 0, 'C#': 1, D: 2, 'D#': 3, E: 4, F: 5, 'F#': 6, G: 7, 'G#': 8, A: 9, 'A#': 10, B: 11 };
        
        let rootMidi;
        try {
            const match = rootNoteStr.toUpperCase().match(/^([A-G]#?)(-?[0-9])$/);
            if (!match) throw new Error();
            const noteName = match[1];
            const octave = parseInt(match[2], 10);
            rootMidi = 12 * (octave + 1) + noteOffsets[noteName];
        } catch (e) {
            console.error(`Invalid root note format: "${rootNoteStr}". Using C4 as default.`);
            rootMidi = 60; // Default to C4
        }
        
        const intervals = scaleIntervals[scaleType] || scaleIntervals.major;
        const frequencies = [];

        for (let i = 0; i < numOctaves; i++) {
            for (const interval of intervals) {
                const midiNote = rootMidi + (i * 12) + interval;
                frequencies.push(midiToFreq(midiNote));
            }
        }
        // Add the root of the next octave to complete the scale range
        frequencies.push(midiToFreq(rootMidi + numOctaves * 12));

        return frequencies;
    };

    // --- Image Processing and Score Generation ---

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    // Scale image down for performance and to make the melody less dense
    const MAX_WIDTH = 250;
    const scaleFactor = originalImg.width > MAX_WIDTH ? MAX_WIDTH / originalImg.width : 1;
    canvas.width = originalImg.width * scaleFactor;
    canvas.height = originalImg.height * scaleFactor;
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;
    const score = [];
    const scaleFreqs = generateScaleFrequencies(rootNote, scaleType, octaves);
    const noteInterval = totalDuration_s / (canvas.width / noteDensity);

    // Scan image columns to create notes
    for (let x = 0; x < canvas.width; x += noteDensity) {
        let brightestY = -1;
        let maxBrightness = 0;

        // Find the brightest pixel in the current column
        for (let y = 0; y < canvas.height; y++) {
            const i = (y * canvas.width + x) * 4;
            const r = data[i];
            const g = data[i + 1];
            const b = data[i + 2];
            const brightness = (r + g + b) / 3;

            if (brightness > maxBrightness) {
                maxBrightness = brightness;
                brightestY = y;
            }
        }

        if (brightestY !== -1 && maxBrightness > brightnessThreshold) {
            // Map Y-position (top=high, bottom=low) to a note in the scale
            const pitchIndex = Math.floor((1 - (brightestY / canvas.height)) * scaleFreqs.length);
            const frequency = scaleFreqs[Math.min(scaleFreqs.length - 1, Math.max(0, pitchIndex))];

            // Map brightness to volume
            const volume = (maxBrightness / 255) * 0.7; // Max volume at 0.7 to avoid clipping

            // Calculate timing
            const startTime = (x / canvas.width) * totalDuration_s;
            
            score.push({ frequency, volume, startTime, duration: noteInterval * 0.95 });
        }
    }

    // --- UI and Audio Playback ---

    const container = document.createElement('div');
    container.style.fontFamily = 'sans-serif';

    const playButton = document.createElement('button');
    playButton.textContent = `▶️ Play Melody (${score.length} notes)`;
    playButton.style.padding = '10px 15px';
    playButton.style.fontSize = '16px';
    playButton.style.cursor = 'pointer';

    container.appendChild(playButton);

    let audioCtx = null;
    let activeSources = [];
    let isPlaying = false;
    let playbackTimeout = null;

    const stopPlayback = () => {
        if (!isPlaying) return;
        clearTimeout(playbackTimeout);
        activeSources.forEach(source => {
            try { source.stop(0); } catch (e) { /* ignore */ }
        });
        activeSources = [];
        if (audioCtx && audioCtx.state === 'running') {
            audioCtx.close().then(() => {
                audioCtx = null;
            });
        }
        isPlaying = false;
        playButton.textContent = `▶️ Play Melody (${score.length} notes)`;
    };
    
    playButton.onclick = () => {
        if (isPlaying) {
            stopPlayback();
            return;
        }

        if (!score.length) {
            alert("No notes were generated from the image. Try adjusting the brightness threshold or using a different image.");
            return;
        }

        // Initialize AudioContext on user interaction
        if (!audioCtx || audioCtx.state === 'closed') {
            audioCtx = new (window.AudioContext || window.webkitAudioContext)();
        }
        audioCtx.resume();

        isPlaying = true;
        playButton.textContent = '⏹️ Stop';
        const melodyStartTime = audioCtx.currentTime + 0.1;

        score.forEach(note => {
            const oscillator = audioCtx.createOscillator();
            const gainNode = audioCtx.createGain();
            oscillator.connect(gainNode);
            gainNode.connect(audioCtx.destination);
            
            // Set oscillator and gain properties
            oscillator.type = waveform;
            oscillator.frequency.value = note.frequency;
            
            // Simple ADSR-like envelope for a more pleasant sound
            const attackTime = 0.01;
            const releaseTime = Math.min(0.2, note.duration * 0.5);
            const peakGain = note.volume;
            const noteStart = melodyStartTime + note.startTime;
            const noteEnd = noteStart + note.duration;

            gainNode.gain.setValueAtTime(0, noteStart);
            gainNode.gain.linearRampToValueAtTime(peakGain, noteStart + attackTime);
            gainNode.gain.setValueAtTime(peakGain, noteEnd - releaseTime);
            gainNode.gain.linearRampToValueAtTime(0, noteEnd);

            oscillator.start(noteStart);
            oscillator.stop(noteEnd);
            activeSources.push(oscillator);
        });

        playbackTimeout = setTimeout(() => {
            if (isPlaying) {
                stopPlayback();
            }
        }, (totalDuration_s + 2) * 1000); // Add buffer time
    };

    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 Melody Creator is a web tool that transforms images into musical melodies. By analyzing the brightness of pixels in an uploaded image, the tool generates a corresponding sequence of musical notes based on specified musical scales, root notes, and other parameters. This tool is particularly useful for artists, musicians, and educators who want to explore the intersection of visual art and music, creating unique sound compositions from images for projects, performances, or educational purposes.

Leave a Reply

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