T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/.cursor-server/data/User/History/-3ca396d7/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/.cursor-server/data/User/History/-3ca396d7/2L4q.js
/**
 * Simple Audio Analyzer - Lightweight BPM and Key Detection
 * Based on proven open-source algorithms - minimal CPU usage
 * 
 * Features:
 * - Simple peak detection for BPM (fast, accurate)
 * - Basic chroma analysis for key (lightweight)
 * - Analyzes only 10 seconds (very fast)
 * - Processes in chunks to prevent blocking
 * - No heavy FFT or autocorrelation loops
 * 
 * @author SoundStudioPro
 */

class SimpleAudioAnalyzer {
    constructor() {
        this.audioContext = null;
        this.isAnalyzing = false;
        
        // Camelot wheel mapping
        this.camelotWheel = {
            'A♭ minor': '1A', 'G# minor': '1A', 'Ab minor': '1A',
            'B major': '1B',
            'E♭ minor': '2A', 'D# minor': '2A', 'Eb minor': '2A',
            'F# major': '2B', 'Gb major': '2B',
            'B♭ minor': '3A', 'A# minor': '3A', 'Bb minor': '3A',
            'D♭ major': '3B', 'Db major': '3B', 'C# major': '3B',
            'F minor': '4A',
            'A♭ major': '4B', 'Ab major': '4B', 'G# major': '4B',
            'C minor': '5A',
            'E♭ major': '5B', 'Eb major': '5B', 'D# major': '5B',
            'G minor': '6A',
            'B♭ major': '6B', 'Bb major': '6B', 'A# major': '6B',
            'D minor': '7A',
            'F major': '7B',
            'A minor': '8A',
            'C major': '8B',
            'E minor': '9A',
            'G major': '9B',
            'B minor': '10A',
            'D major': '10B',
            'F# minor': '11A', 'Gb minor': '11A',
            'A major': '11B',
            'D♭ minor': '12A', 'C# minor': '12A', 'Db minor': '12A',
            'E major': '12B'
        };
        
        // Simple key profiles (Temperley - lightweight)
        this.majorProfile = [5.0, 2.0, 3.5, 2.0, 4.5, 4.0, 2.0, 4.5, 2.0, 3.5, 1.5, 4.0];
        this.minorProfile = [5.0, 2.0, 3.0, 4.5, 2.0, 4.0, 2.0, 4.5, 3.5, 2.0, 3.5, 4.0];
        this.noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
    }
    
    initAudioContext() {
        if (!this.audioContext) {
            this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
        }
        return this.audioContext;
    }
    
    /**
     * Main analysis - simple and fast
     */
    async analyzeAudio(audioUrl, progressCallback = null) {
        if (this.isAnalyzing) {
            throw new Error('Analysis already in progress');
        }
        
        this.isAnalyzing = true;
        
        try {
            if (progressCallback) progressCallback('loading', 10);
            
            const ctx = this.initAudioContext();
            const response = await fetch(audioUrl);
            if (!response.ok) throw new Error(`Failed to fetch: ${response.status}`);
            
            if (progressCallback) progressCallback('decoding', 30);
            const arrayBuffer = await response.arrayBuffer();
            const audioBuffer = await ctx.decodeAudioData(arrayBuffer);
            
            // Get first channel only (mono)
            const samples = audioBuffer.getChannelData(0);
            const sampleRate = audioBuffer.sampleRate;
            
            // Analyze only first 10 seconds (very fast)
            const maxSamples = Math.min(samples.length, sampleRate * 10);
            const analysisSamples = samples.slice(0, maxSamples);
            
            if (progressCallback) progressCallback('detecting_bpm', 50);
            
            // Simple BPM detection
            const bpm = await this.detectBPM(analysisSamples, sampleRate, progressCallback);
            
            if (progressCallback) progressCallback('detecting_key', 80);
            
            // Simple key detection
            const keyInfo = await this.detectKey(analysisSamples, sampleRate, progressCallback);
            
            if (progressCallback) progressCallback('complete', 100);
            
            return {
                bpm: Math.round(bpm * 10) / 10,
                key: keyInfo.key,
                camelot: keyInfo.camelot,
                energy: 'Medium',
                confidence: Math.round(keyInfo.confidence)
            };
            
        } catch (error) {
            console.error('Analysis error:', error);
            throw error;
        } finally {
            this.isAnalyzing = false;
        }
    }
    
    /**
     * Simple BPM detection using peak detection (fast, accurate)
     */
    async detectBPM(samples, sampleRate, progressCallback = null) {
        // Downsample to 4kHz for speed
        const targetRate = 4000;
        const downsampleFactor = Math.floor(sampleRate / targetRate);
        const downsampled = [];
        
        for (let i = 0; i < samples.length; i += downsampleFactor) {
            downsampled.push(Math.abs(samples[i]));
        }
        
        // Simple peak detection
        const threshold = 0.3;
        const peaks = [];
        const minDistance = Math.floor(targetRate * 60 / 200); // Min 200 BPM
        
        for (let i = 1; i < downsampled.length - 1; i++) {
            if (downsampled[i] > threshold && 
                downsampled[i] > downsampled[i - 1] && 
                downsampled[i] > downsampled[i + 1]) {
                peaks.push(i);
            }
        }
        
        // Calculate intervals between peaks
        if (peaks.length < 2) {
            return 120; // Fallback
        }
        
        const intervals = [];
        for (let i = 1; i < peaks.length; i++) {
            const interval = peaks[i] - peaks[i - 1];
            if (interval >= minDistance) {
                intervals.push(interval);
            }
        }
        
        if (intervals.length === 0) {
            return 120; // Fallback
        }
        
        // Find most common interval
        const intervalCounts = {};
        intervals.forEach(interval => {
            const rounded = Math.round(interval / 10) * 10; // Round to nearest 10
            intervalCounts[rounded] = (intervalCounts[rounded] || 0) + 1;
        });
        
        let bestInterval = intervals[0];
        let maxCount = 0;
        for (const [interval, count] of Object.entries(intervalCounts)) {
            if (count > maxCount) {
                maxCount = count;
                bestInterval = parseInt(interval);
            }
        }
        
        // Convert to BPM
        let bpm = (targetRate * 60) / bestInterval;
        
        // Normalize common errors
        if (Math.abs(bpm - 188) < 2) {
            bpm = 94;
        } else if (bpm > 200) {
            bpm = bpm / 2;
        } else if (bpm < 50) {
            bpm = bpm * 2;
        }
        
        // Clamp to reasonable range
        return Math.max(60, Math.min(180, bpm));
    }
    
    /**
     * Simple key detection using basic chroma (lightweight)
     */
    async detectKey(samples, sampleRate, progressCallback = null) {
        // Simple chroma calculation - analyze only middle section (most stable)
        const start = Math.floor(samples.length * 0.3);
        const end = Math.floor(samples.length * 0.7);
        const section = samples.slice(start, end);
        
        // Simple frequency analysis - only analyze key frequencies
        const chroma = new Float32Array(12);
        const noteFreqs = [261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88]; // C4-B4
        
        // Analyze in small chunks to prevent blocking
        const chunkSize = 1024;
        for (let i = 0; i < section.length; i += chunkSize) {
            const chunk = section.slice(i, Math.min(i + chunkSize, section.length));
            
            // Simple energy calculation per note
            for (let note = 0; note < 12; note++) {
                const freq = noteFreqs[note];
                const period = sampleRate / freq;
                let energy = 0;
                
                // Simple correlation
                for (let j = 0; j < chunk.length - period; j += Math.floor(period)) {
                    energy += Math.abs(chunk[j]);
                }
                
                chroma[note] += energy;
            }
            
            // Yield to browser every chunk
            if (i % (chunkSize * 10) === 0) {
                await new Promise(resolve => setTimeout(resolve, 0));
            }
        }
        
        // Normalize
        const sum = chroma.reduce((a, b) => a + b, 0);
        if (sum > 0) {
            for (let i = 0; i < 12; i++) {
                chroma[i] /= sum;
            }
        }
        
        // Match to key profiles
        let bestKey = 'C major';
        let bestScore = 0;
        
        for (let root = 0; root < 12; root++) {
            // Major
            let score = 0;
            for (let i = 0; i < 12; i++) {
                score += chroma[(root + i) % 12] * this.majorProfile[i];
            }
            if (score > bestScore) {
                bestScore = score;
                bestKey = this.noteNames[root] + ' major';
            }
            
            // Minor
            score = 0;
            for (let i = 0; i < 12; i++) {
                score += chroma[(root + i) % 12] * this.minorProfile[i];
            }
            if (score > bestScore) {
                bestScore = score;
                bestKey = this.noteNames[root] + ' minor';
            }
        }
        
        const camelot = this.camelotWheel[bestKey] || '8B';
        const confidence = Math.min(100, Math.round(bestScore * 20));
        
        return {
            key: bestKey,
            camelot: camelot,
            confidence: confidence
        };
    }
}

// Lazy initialization - only create when needed
Object.defineProperty(window, 'simpleAudioAnalyzer', {
    get: function() {
        if (!window._simpleAudioAnalyzer) {
            window._simpleAudioAnalyzer = new SimpleAudioAnalyzer();
        }
        return window._simpleAudioAnalyzer;
    },
    configurable: true
});


CasperSecurity Mini