Please bookmark this page to avoid losing your image tool!

Image Music Scanner Finder

(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, durationMs = 8000, triggerMode = "dark", scaleType = "pentatonic") {
    // Validate and parse parameters
    const duration = Number(durationMs) || 8000;
    const mode = String(triggerMode).toLowerCase();
    const scale = String(scaleType).toLowerCase();
    
    // Create the interactive canvas
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    
    canvas.width = originalImg.width;
    canvas.height = originalImg.height;
    
    // Draw the image and cache the original pixel data for performance
    ctx.drawImage(originalImg, 0, 0);
    let originalImageData;
    try {
        originalImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        // Handle CORS restriction issues
        ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = "red";
        ctx.font = "bold 20px sans-serif";
        ctx.textAlign = "center";
        ctx.fillText("Cannot scan image due to CORS restrictions.", canvas.width / 2, canvas.height / 2);
        return canvas;
    }
    const pixels = originalImageData.data;

    // Audio states & constants
    let audioCtx = null;
    let masterGain = null;
    let gains = [];
    let oscillators = [];
    const NUM_BINS = 48; // Number of vertical scanning bins / notes
    
    // Playback state
    let isPlaying = false;
    let startTime = 0;
    let animFrame = null;
    let currentX = 0;

    // Available scales (in semitone offsets)
    const scales = {
        pentatonic: [0, 3, 5, 7, 10], // Minor pentatonic (default, very musical)
        major: [0, 2, 4, 5, 7, 9, 11],
        chromatic: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    };

    function drawOverlay(text) {
        ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
        ctx.fillRect(0, canvas.height - 60, canvas.width, 60);
        ctx.fillStyle = "white";
        ctx.font = "bold 22px sans-serif";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(text, canvas.width / 2, canvas.height - 30);
    }

    drawOverlay("Click to Start Audio Music Scanner");

    function initAudio() {
        if (audioCtx) return;
        const AudioContext = window.AudioContext || window.webkitAudioContext;
        audioCtx = new AudioContext();
        
        masterGain = audioCtx.createGain();
        masterGain.gain.value = 1.0; 
        
        // Use a compressor to prevent ear-hurting clipping when many notes play
        const compressor = audioCtx.createDynamicsCompressor();
        compressor.threshold.value = -15;
        compressor.knee.value = 10;
        compressor.ratio.value = 12;
        compressor.attack.value = 0;
        compressor.release.value = 0.25;
        
        masterGain.connect(compressor);
        compressor.connect(audioCtx.destination);
        
        const intervals = scales[scale] || scales.pentatonic;
        const baseMidi = 36; // C2
        
        for (let i = 0; i < NUM_BINS; i++) {
            const octave = Math.floor(i / intervals.length);
            const note = i % intervals.length;
            const midiNote = baseMidi + (octave * 12) + intervals[note];
            const freq = 440 * Math.pow(2, (midiNote - 69) / 12);
            
            const osc = audioCtx.createOscillator();
            osc.type = 'sine'; // clean tone
            osc.frequency.value = freq;
            
            const gain = audioCtx.createGain();
            gain.gain.value = 0; // initially silent
            
            osc.connect(gain);
            gain.connect(masterGain);
            
            osc.start();
            oscillators.push(osc);
            gains.push(gain);
        }
    }

    function stopAllAudio() {
        if (!audioCtx) return;
        for (let i = 0; i < NUM_BINS; i++) {
            gains[i].gain.setTargetAtTime(0, audioCtx.currentTime, 0.02);
        }
    }

    function scan() {
        // Stop automatically if canvas is removed from DOM to avoid zombie audio
        if (!canvas.isConnected && audioCtx) {
            isPlaying = false;
            audioCtx.close();
            audioCtx = null;
            return;
        }

        if (!isPlaying) return;

        const now = performance.now();
        const elapsed = now - startTime;
        let progress = (elapsed % duration) / duration;
        
        // End of scan detection line
        currentX = Math.max(0, Math.min(canvas.width - 1, Math.floor(progress * canvas.width)));
        
        // Quickly restore the base frame image
        ctx.putImageData(originalImageData, 0, 0);

        // Max intensity in each vertical bin
        let binMax = new Float32Array(NUM_BINS);
        
        for (let y = 0; y < canvas.height; y++) {
            const idx = (y * canvas.width + currentX) * 4;
            const r = pixels[idx];
            const g = pixels[idx + 1];
            const b = pixels[idx + 2];
            
            const lum = 0.299 * r + 0.587 * g + 0.114 * b;
            
            // By default "dark" looks for black/dark sheet music notes over white paper
            const intensity = (mode === 'bright') ? (lum / 255) : ((255 - lum) / 255);
            
            // Bottom of the image corresponds to bin 0 (lowest notes)
            // Top of the image corresponds to bin NUM_BINS-1 (highest notes)
            const binIdx = Math.floor(((canvas.height - 1 - y) / canvas.height) * NUM_BINS);
            const safeBinIdx = Math.max(0, Math.min(NUM_BINS - 1, binIdx));
            
            if (intensity > binMax[safeBinIdx]) {
                binMax[safeBinIdx] = intensity;
            }
        }

        // Draw the moving red scanner line
        ctx.fillStyle = "rgba(255, 0, 0, 0.8)";
        ctx.fillRect(currentX, 0, 2, canvas.height);

        // Trigger audio notes and visual "Finds"
        ctx.fillStyle = "rgba(0, 255, 0, 0.9)";
        for (let i = 0; i < NUM_BINS; i++) {
            let peak = binMax[i];
            
            // 0.45 serves as an empirical contrast threshold for standard imagery / sheet music
            if (peak > 0.45) {
                // Apply a quadratic curve for dynamic expression
                const targetVolume = Math.min(1.0, Math.pow(peak, 2));
                gains[i].gain.setTargetAtTime(targetVolume, audioCtx.currentTime, 0.02);
                
                // Visually highlight the "Found" note at this bin coordinate
                let yPos = canvas.height - 1 - (i + 0.5) * (canvas.height / NUM_BINS);
                ctx.fillRect(currentX - 3, yPos - 3, 8, 6);
            } else {
                gains[i].gain.setTargetAtTime(0, audioCtx.currentTime, 0.02);
            }
        }

        animFrame = requestAnimationFrame(scan);
    }

    // Interaction handler to manage pausing and resuming
    canvas.addEventListener('click', async () => {
        if (!audioCtx) {
            initAudio();
        }
        
        // Browsers require resuming the audio context upon user gesture
        if (audioCtx.state === 'suspended') {
            await audioCtx.resume();
        }

        if (isPlaying) {
            isPlaying = false;
            cancelAnimationFrame(animFrame);
            stopAllAudio();
            ctx.putImageData(originalImageData, 0, 0);
            drawOverlay("Paused - Click to Resume Music Scanner");
        } else {
            isPlaying = true;
            // Subtract previously elapsed time to resume cleanly from the same position
            startTime = performance.now() - ((currentX / canvas.width) * duration);
            scan();
        }
    });

    // Cursor indication to imply interaction exists
    canvas.style.cursor = "pointer";

    return canvas;
}

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 Music Scanner Finder is an interactive tool that converts visual patterns in an image into musical notes. By scanning an image from left to right, the tool analyzes pixel intensity and maps different vertical positions to specific musical frequencies. Users can customize the experience by selecting different musical scales (such as pentatonic, major, or chromatic) and trigger modes to better suit the image content. This tool is particularly useful for exploring artistic interpretations of images, analyzing the “rhythm” of visual patterns, or creating unique soundscapes from photos and sheet music.

Leave a Reply

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