G1EQ

Professional audio enhancement with 10-band EQ, 3D surround sound, bass boost, and spatial audio controls

Size

26.5 KB

Version

1.1.2

Created

Nov 12, 2025

Updated

about 1 month ago

1// ==UserScript==
2// @name		G1EQ
3// @description		Professional audio enhancement with 10-band EQ, 3D surround sound, bass boost, and spatial audio controls
4// @version		1.1.2
5// @match		https://*.chatgpt.com/*
6// @icon		https://cdn.oaistatic.com/assets/favicon-l4nq08hd.svg
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('ChatGPT 3D Audio Enhancer Pro - Initializing...');
12
13    // Audio processing state
14    let audioContext = null;
15    let audioSource = null;
16    let audioElements = new Map();
17    let isProcessingActive = false;
18
19    // Audio nodes
20    let nodes = {
21        splitter: null,
22        merger: null,
23        eqBands: [],
24        bassBoost: null,
25        bassTuner: null,
26        spatialLeft: null,
27        spatialRight: null,
28        surroundDelay: null,
29        surroundGain: null,
30        masterGain: null
31    };
32
33    // EQ frequencies (10 bands as requested)
34    const EQ_FREQUENCIES = [31, 62, 96, 128, 142, 196, 250, 500, 1000, 2000];
35
36    // Default settings
37    let settings = {
38        eqGains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
39        bassBoost: 0,
40        bassTuner: 100,
41        surroundIntensity: 0,
42        surroundWidth: 50,
43        spatialBalance: 0,
44        spatialDepth: 50,
45        enabled: false
46    };
47
48    // Load saved settings
49    async function loadSettings() {
50        try {
51            const saved = await GM.getValue('audioEnhancerSettings');
52            if (saved) {
53                settings = JSON.parse(saved);
54                console.log('Loaded saved settings:', settings);
55            }
56        } catch (error) {
57            console.error('Error loading settings:', error);
58        }
59    }
60
61    // Save settings
62    async function saveSettings() {
63        try {
64            await GM.setValue('audioEnhancerSettings', JSON.stringify(settings));
65            console.log('Settings saved');
66        } catch (error) {
67            console.error('Error saving settings:', error);
68        }
69    }
70
71    // Initialize audio context and nodes
72    function initAudioContext() {
73        if (audioContext) return audioContext;
74
75        audioContext = new (window.AudioContext || window.webkitAudioContext)();
76        console.log('Audio context initialized');
77
78        // Create channel splitter and merger for stereo processing
79        nodes.splitter = audioContext.createChannelSplitter(2);
80        nodes.merger = audioContext.createChannelMerger(2);
81
82        // Create 10-band equalizer
83        EQ_FREQUENCIES.forEach((freq, index) => {
84            const filter = audioContext.createBiquadFilter();
85            filter.type = 'peaking';
86            filter.frequency.value = freq;
87            filter.Q.value = 1.0;
88            filter.gain.value = settings.eqGains[index];
89            nodes.eqBands.push(filter);
90        });
91
92        // Chain EQ bands
93        for (let i = 0; i < nodes.eqBands.length - 1; i++) {
94            nodes.eqBands[i].connect(nodes.eqBands[i + 1]);
95        }
96
97        // Bass boost filter (low shelf)
98        nodes.bassBoost = audioContext.createBiquadFilter();
99        nodes.bassBoost.type = 'lowshelf';
100        nodes.bassBoost.frequency.value = 200;
101        nodes.bassBoost.gain.value = settings.bassBoost;
102
103        // Bass tuner filter (adjustable frequency)
104        nodes.bassTuner = audioContext.createBiquadFilter();
105        nodes.bassTuner.type = 'peaking';
106        nodes.bassTuner.frequency.value = settings.bassTuner;
107        nodes.bassTuner.Q.value = 2.0;
108        nodes.bassTuner.gain.value = 0;
109
110        // 3D Surround processing nodes
111        nodes.surroundDelay = audioContext.createDelay(0.05);
112        nodes.surroundDelay.delayTime.value = 0.02;
113
114        nodes.surroundGain = audioContext.createGain();
115        nodes.surroundGain.gain.value = settings.surroundIntensity / 100;
116
117        // Spatial panning for left and right channels
118        nodes.spatialLeft = audioContext.createStereoPanner();
119        nodes.spatialLeft.pan.value = -0.5;
120
121        nodes.spatialRight = audioContext.createStereoPanner();
122        nodes.spatialRight.pan.value = 0.5;
123
124        // Master gain
125        nodes.masterGain = audioContext.createGain();
126        nodes.masterGain.gain.value = 1.0;
127
128        return audioContext;
129    }
130
131    // Connect audio element to processing chain
132    function connectAudioElement(audioElement) {
133        if (!audioContext || audioElements.has(audioElement)) return;
134
135        try {
136            const source = audioContext.createMediaElementSource(audioElement);
137            
138            // Main signal path: source -> EQ chain -> bass boost -> bass tuner
139            source.connect(nodes.eqBands[0]);
140            nodes.eqBands[nodes.eqBands.length - 1].connect(nodes.bassBoost);
141            nodes.bassBoost.connect(nodes.bassTuner);
142
143            // Split into stereo channels for 3D processing
144            nodes.bassTuner.connect(nodes.splitter);
145
146            // Left channel: splitter -> spatial left -> merger
147            nodes.splitter.connect(nodes.spatialLeft, 0);
148            nodes.spatialLeft.connect(nodes.merger, 0, 0);
149
150            // Right channel: splitter -> spatial right -> merger
151            nodes.splitter.connect(nodes.spatialRight, 1);
152            nodes.spatialRight.connect(nodes.merger, 0, 1);
153
154            // Surround effect: splitter -> delay -> gain -> merger (cross-feed)
155            nodes.splitter.connect(nodes.surroundDelay, 0);
156            nodes.surroundDelay.connect(nodes.surroundGain);
157            nodes.surroundGain.connect(nodes.merger, 0, 1);
158
159            nodes.splitter.connect(nodes.surroundDelay, 1);
160            nodes.surroundDelay.connect(nodes.surroundGain);
161            nodes.surroundGain.connect(nodes.merger, 0, 0);
162
163            // Final output: merger -> master gain -> destination
164            nodes.merger.connect(nodes.masterGain);
165            nodes.masterGain.connect(audioContext.destination);
166
167            audioElements.set(audioElement, source);
168            console.log('Audio element connected to processing chain');
169        } catch (error) {
170            console.error('Error connecting audio element:', error);
171        }
172    }
173
174    // Update EQ band
175    function updateEQBand(bandIndex, gain) {
176        if (nodes.eqBands[bandIndex]) {
177            nodes.eqBands[bandIndex].gain.value = gain;
178            settings.eqGains[bandIndex] = gain;
179            saveSettings();
180        }
181    }
182
183    // Update bass boost
184    function updateBassBoost(gain) {
185        if (nodes.bassBoost) {
186            nodes.bassBoost.gain.value = gain;
187            settings.bassBoost = gain;
188            saveSettings();
189        }
190    }
191
192    // Update bass tuner frequency
193    function updateBassTuner(frequency) {
194        if (nodes.bassTuner) {
195            nodes.bassTuner.frequency.value = frequency;
196            settings.bassTuner = frequency;
197            saveSettings();
198        }
199    }
200
201    // Update 3D surround intensity
202    function updateSurroundIntensity(intensity) {
203        if (nodes.surroundGain) {
204            nodes.surroundGain.gain.value = intensity / 100;
205            settings.surroundIntensity = intensity;
206            saveSettings();
207        }
208    }
209
210    // Update surround width
211    function updateSurroundWidth(width) {
212        if (nodes.spatialLeft && nodes.spatialRight) {
213            const pan = width / 100;
214            nodes.spatialLeft.pan.value = -pan;
215            nodes.spatialRight.pan.value = pan;
216            settings.surroundWidth = width;
217            saveSettings();
218        }
219    }
220
221    // Update spatial balance
222    function updateSpatialBalance(balance) {
223        if (nodes.spatialLeft && nodes.spatialRight) {
224            const offset = balance / 100;
225            const baseWidth = settings.surroundWidth / 100;
226            nodes.spatialLeft.pan.value = -baseWidth + offset;
227            nodes.spatialRight.pan.value = baseWidth + offset;
228            settings.spatialBalance = balance;
229            saveSettings();
230        }
231    }
232
233    // Update spatial depth
234    function updateSpatialDepth(depth) {
235        if (nodes.surroundDelay) {
236            nodes.surroundDelay.delayTime.value = (depth / 100) * 0.05;
237            settings.spatialDepth = depth;
238            saveSettings();
239        }
240    }
241
242    // Monitor for audio elements
243    function monitorAudioElements() {
244        const observer = new MutationObserver(debounce(() => {
245            if (!settings.enabled) return;
246
247            const audioElements = document.querySelectorAll('audio, video');
248            audioElements.forEach(element => {
249                if (!audioElements.has(element) && element.src) {
250                    console.log('New audio element detected:', element);
251                    connectAudioElement(element);
252                }
253            });
254        }, 500));
255
256        observer.observe(document.body, {
257            childList: true,
258            subtree: true
259        });
260
261        console.log('Audio element monitor started');
262    }
263
264    // Debounce function
265    function debounce(func, wait) {
266        let timeout;
267        return function executedFunction(...args) {
268            const later = () => {
269                clearTimeout(timeout);
270                func(...args);
271            };
272            clearTimeout(timeout);
273            timeout = setTimeout(later, wait);
274        };
275    }
276
277    // Toggle audio processing
278    function toggleAudioProcessing(enabled) {
279        settings.enabled = enabled;
280        saveSettings();
281
282        if (enabled) {
283            initAudioContext();
284            const audioElems = document.querySelectorAll('audio, video');
285            audioElems.forEach(elem => {
286                if (elem.src) connectAudioElement(elem);
287            });
288            console.log('Audio processing enabled');
289        } else {
290            console.log('Audio processing disabled');
291        }
292    }
293
294    // Create UI
295    function createUI() {
296        // Main container
297        const container = document.createElement('div');
298        container.id = 'audio-enhancer-panel';
299        container.style.cssText = `
300            position: fixed;
301            top: 20px;
302            right: 20px;
303            width: 420px;
304            max-height: 90vh;
305            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
306            border-radius: 16px;
307            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
308            z-index: 999999;
309            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
310            color: #ffffff;
311            overflow: hidden;
312            display: none;
313        `;
314
315        // Header
316        const header = document.createElement('div');
317        header.style.cssText = `
318            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
319            padding: 16px 20px;
320            display: flex;
321            justify-content: space-between;
322            align-items: center;
323            cursor: move;
324        `;
325        header.innerHTML = `
326            <div style="display: flex; align-items: center; gap: 10px;">
327                <span style="font-size: 24px;">🎵</span>
328                <span style="font-weight: 600; font-size: 16px;">3D Audio Enhancer Pro</span>
329            </div>
330            <button id="close-audio-panel" style="background: rgba(255,255,255,0.2); border: none; color: white; width: 28px; height: 28px; border-radius: 50%; cursor: pointer; font-size: 18px; display: flex; align-items: center; justify-content: center;">×</button>
331        `;
332
333        // Content container with scroll
334        const content = document.createElement('div');
335        content.style.cssText = `
336            padding: 20px;
337            max-height: calc(90vh - 60px);
338            overflow-y: auto;
339        `;
340
341        // Power toggle
342        const powerSection = document.createElement('div');
343        powerSection.style.cssText = `
344            background: rgba(255, 255, 255, 0.05);
345            padding: 16px;
346            border-radius: 12px;
347            margin-bottom: 20px;
348            display: flex;
349            justify-content: space-between;
350            align-items: center;
351        `;
352        powerSection.innerHTML = `
353            <span style="font-weight: 600; font-size: 15px;">🔊 Audio Enhancement</span>
354            <label style="position: relative; display: inline-block; width: 56px; height: 28px;">
355                <input type="checkbox" id="power-toggle" ${settings.enabled ? 'checked' : ''} style="opacity: 0; width: 0; height: 0;">
356                <span style="position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 28px;"></span>
357                <span style="position: absolute; content: ''; height: 20px; width: 20px; left: 4px; bottom: 4px; background-color: white; transition: .4s; border-radius: 50%;"></span>
358            </label>
359        `;
360
361        // 10-Band Equalizer Section
362        const eqSection = document.createElement('div');
363        eqSection.style.cssText = `
364            background: rgba(255, 255, 255, 0.05);
365            padding: 16px;
366            border-radius: 12px;
367            margin-bottom: 20px;
368        `;
369        eqSection.innerHTML = `
370            <div style="font-weight: 600; margin-bottom: 16px; font-size: 15px; display: flex; align-items: center; gap: 8px;">
371                <span>🎚️</span>
372                <span>10-Band Equalizer</span>
373            </div>
374            <div id="eq-bands" style="display: flex; gap: 8px; justify-content: space-between;">
375                ${EQ_FREQUENCIES.map((freq, i) => `
376                    <div style="flex: 1; display: flex; flex-direction: column; align-items: center; gap: 8px;">
377                        <input type="range" id="eq-${i}" min="-12" max="12" step="0.5" value="${settings.eqGains[i]}" orient="vertical" style="writing-mode: bt-lr; -webkit-appearance: slider-vertical; width: 24px; height: 120px; cursor: pointer;">
378                        <span style="font-size: 10px; color: #aaa;">${freq}Hz</span>
379                        <span id="eq-value-${i}" style="font-size: 11px; font-weight: 600; color: #667eea;">${settings.eqGains[i]}dB</span>
380                    </div>
381                `).join('')}
382            </div>
383            <button id="eq-reset" style="width: 100%; margin-top: 12px; padding: 8px; background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); color: white; border-radius: 8px; cursor: pointer; font-size: 13px;">Reset EQ</button>
384        `;
385
386        // Bass Enhancement Section
387        const bassSection = document.createElement('div');
388        bassSection.style.cssText = `
389            background: rgba(255, 255, 255, 0.05);
390            padding: 16px;
391            border-radius: 12px;
392            margin-bottom: 20px;
393        `;
394        bassSection.innerHTML = `
395            <div style="font-weight: 600; margin-bottom: 16px; font-size: 15px; display: flex; align-items: center; gap: 8px;">
396                <span>🔊</span>
397                <span>Bass Enhancement</span>
398            </div>
399            <div style="margin-bottom: 16px;">
400                <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
401                    <span style="font-size: 13px; color: #ccc;">Bass Boost</span>
402                    <span id="bass-boost-value" style="font-size: 13px; font-weight: 600; color: #667eea;">${settings.bassBoost}dB</span>
403                </div>
404                <input type="range" id="bass-boost" min="0" max="20" step="0.5" value="${settings.bassBoost}" style="width: 100%; cursor: pointer;">
405            </div>
406            <div>
407                <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
408                    <span style="font-size: 13px; color: #ccc;">Bass Tuner Frequency</span>
409                    <span id="bass-tuner-value" style="font-size: 13px; font-weight: 600; color: #667eea;">${settings.bassTuner}Hz</span>
410                </div>
411                <input type="range" id="bass-tuner" min="40" max="200" step="5" value="${settings.bassTuner}" style="width: 100%; cursor: pointer;">
412            </div>
413        `;
414
415        // 3D Surround Audio Mixer Panel
416        const surroundSection = document.createElement('div');
417        surroundSection.style.cssText = `
418            background: rgba(255, 255, 255, 0.05);
419            padding: 16px;
420            border-radius: 12px;
421            margin-bottom: 20px;
422        `;
423        surroundSection.innerHTML = `
424            <div style="font-weight: 600; margin-bottom: 16px; font-size: 15px; display: flex; align-items: center; gap: 8px;">
425                <span>🎧</span>
426                <span>3D Surround Audio Mixer</span>
427            </div>
428            <div style="margin-bottom: 16px;">
429                <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
430                    <span style="font-size: 13px; color: #ccc;">Surround Intensity</span>
431                    <span id="surround-intensity-value" style="font-size: 13px; font-weight: 600; color: #667eea;">${settings.surroundIntensity}%</span>
432                </div>
433                <input type="range" id="surround-intensity" min="0" max="100" step="1" value="${settings.surroundIntensity}" style="width: 100%; cursor: pointer;">
434            </div>
435            <div>
436                <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
437                    <span style="font-size: 13px; color: #ccc;">Surround Width</span>
438                    <span id="surround-width-value" style="font-size: 13px; font-weight: 600; color: #667eea;">${settings.surroundWidth}%</span>
439                </div>
440                <input type="range" id="surround-width" min="0" max="100" step="1" value="${settings.surroundWidth}" style="width: 100%; cursor: pointer;">
441            </div>
442        `;
443
444        // 3D Spatial Sound Control Dashboard
445        const spatialSection = document.createElement('div');
446        spatialSection.style.cssText = `
447            background: rgba(255, 255, 255, 0.05);
448            padding: 16px;
449            border-radius: 12px;
450        `;
451        spatialSection.innerHTML = `
452            <div style="font-weight: 600; margin-bottom: 16px; font-size: 15px; display: flex; align-items: center; gap: 8px;">
453                <span>🌐</span>
454                <span>3D Spatial Sound Control</span>
455            </div>
456            <div style="margin-bottom: 16px;">
457                <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
458                    <span style="font-size: 13px; color: #ccc;">Spatial Balance (L/R)</span>
459                    <span id="spatial-balance-value" style="font-size: 13px; font-weight: 600; color: #667eea;">${settings.spatialBalance > 0 ? 'R+' : settings.spatialBalance < 0 ? 'L+' : 'Center'}${Math.abs(settings.spatialBalance)}</span>
460                </div>
461                <input type="range" id="spatial-balance" min="-50" max="50" step="1" value="${settings.spatialBalance}" style="width: 100%; cursor: pointer;">
462            </div>
463            <div>
464                <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
465                    <span style="font-size: 13px; color: #ccc;">Spatial Depth</span>
466                    <span id="spatial-depth-value" style="font-size: 13px; font-weight: 600; color: #667eea;">${settings.spatialDepth}%</span>
467                </div>
468                <input type="range" id="spatial-depth" min="0" max="100" step="1" value="${settings.spatialDepth}" style="width: 100%; cursor: pointer;">
469            </div>
470        `;
471
472        // Assemble UI
473        content.appendChild(powerSection);
474        content.appendChild(eqSection);
475        content.appendChild(bassSection);
476        content.appendChild(surroundSection);
477        content.appendChild(spatialSection);
478        container.appendChild(header);
479        container.appendChild(content);
480        document.body.appendChild(container);
481
482        // Floating toggle button
483        const toggleBtn = document.createElement('button');
484        toggleBtn.id = 'audio-enhancer-toggle';
485        toggleBtn.innerHTML = '🎵';
486        toggleBtn.style.cssText = `
487            position: fixed;
488            bottom: 20px;
489            right: 20px;
490            width: 56px;
491            height: 56px;
492            border-radius: 50%;
493            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
494            border: none;
495            color: white;
496            font-size: 24px;
497            cursor: pointer;
498            box-shadow: 0 4px 16px rgba(102, 126, 234, 0.4);
499            z-index: 999998;
500            transition: transform 0.2s;
501        `;
502        toggleBtn.onmouseenter = () => toggleBtn.style.transform = 'scale(1.1)';
503        toggleBtn.onmouseleave = () => toggleBtn.style.transform = 'scale(1)';
504        document.body.appendChild(toggleBtn);
505
506        // Event listeners
507        toggleBtn.addEventListener('click', () => {
508            container.style.display = container.style.display === 'none' ? 'block' : 'none';
509        });
510
511        document.getElementById('close-audio-panel').addEventListener('click', () => {
512            container.style.display = 'none';
513        });
514
515        // Power toggle with custom styling
516        const powerToggle = document.getElementById('power-toggle');
517        const powerSlider = powerToggle.nextElementSibling;
518        const powerKnob = powerSlider.nextElementSibling;
519        
520        powerToggle.addEventListener('change', (e) => {
521            const enabled = e.target.checked;
522            if (enabled) {
523                powerSlider.style.backgroundColor = '#667eea';
524                powerKnob.style.transform = 'translateX(28px)';
525            } else {
526                powerSlider.style.backgroundColor = '#ccc';
527                powerKnob.style.transform = 'translateX(0)';
528            }
529            toggleAudioProcessing(enabled);
530        });
531
532        // Initialize power toggle appearance
533        if (settings.enabled) {
534            powerSlider.style.backgroundColor = '#667eea';
535            powerKnob.style.transform = 'translateX(28px)';
536        }
537
538        // EQ band controls
539        EQ_FREQUENCIES.forEach((freq, i) => {
540            const slider = document.getElementById(`eq-${i}`);
541            const valueDisplay = document.getElementById(`eq-value-${i}`);
542            slider.addEventListener('input', (e) => {
543                const value = parseFloat(e.target.value);
544                valueDisplay.textContent = `${value}dB`;
545                updateEQBand(i, value);
546            });
547        });
548
549        // EQ reset button
550        document.getElementById('eq-reset').addEventListener('click', () => {
551            EQ_FREQUENCIES.forEach((freq, i) => {
552                document.getElementById(`eq-${i}`).value = 0;
553                document.getElementById(`eq-value-${i}`).textContent = '0dB';
554                updateEQBand(i, 0);
555            });
556        });
557
558        // Bass boost control
559        const bassBoostSlider = document.getElementById('bass-boost');
560        const bassBoostValue = document.getElementById('bass-boost-value');
561        bassBoostSlider.addEventListener('input', (e) => {
562            const value = parseFloat(e.target.value);
563            bassBoostValue.textContent = `${value}dB`;
564            updateBassBoost(value);
565        });
566
567        // Bass tuner control
568        const bassTunerSlider = document.getElementById('bass-tuner');
569        const bassTunerValue = document.getElementById('bass-tuner-value');
570        bassTunerSlider.addEventListener('input', (e) => {
571            const value = parseInt(e.target.value);
572            bassTunerValue.textContent = `${value}Hz`;
573            updateBassTuner(value);
574        });
575
576        // Surround intensity control
577        const surroundIntensitySlider = document.getElementById('surround-intensity');
578        const surroundIntensityValue = document.getElementById('surround-intensity-value');
579        surroundIntensitySlider.addEventListener('input', (e) => {
580            const value = parseInt(e.target.value);
581            surroundIntensityValue.textContent = `${value}%`;
582            updateSurroundIntensity(value);
583        });
584
585        // Surround width control
586        const surroundWidthSlider = document.getElementById('surround-width');
587        const surroundWidthValue = document.getElementById('surround-width-value');
588        surroundWidthSlider.addEventListener('input', (e) => {
589            const value = parseInt(e.target.value);
590            surroundWidthValue.textContent = `${value}%`;
591            updateSurroundWidth(value);
592        });
593
594        // Spatial balance control
595        const spatialBalanceSlider = document.getElementById('spatial-balance');
596        const spatialBalanceValue = document.getElementById('spatial-balance-value');
597        spatialBalanceSlider.addEventListener('input', (e) => {
598            const value = parseInt(e.target.value);
599            const label = value > 0 ? `R+${value}` : value < 0 ? `L+${Math.abs(value)}` : 'Center';
600            spatialBalanceValue.textContent = label;
601            updateSpatialBalance(value);
602        });
603
604        // Spatial depth control
605        const spatialDepthSlider = document.getElementById('spatial-depth');
606        const spatialDepthValue = document.getElementById('spatial-depth-value');
607        spatialDepthSlider.addEventListener('input', (e) => {
608            const value = parseInt(e.target.value);
609            spatialDepthValue.textContent = `${value}%`;
610            updateSpatialDepth(value);
611        });
612
613        // Make header draggable
614        makeDraggable(container, header);
615
616        console.log('UI created successfully');
617    }
618
619    // Make element draggable
620    function makeDraggable(element, handle) {
621        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
622        
623        handle.onmousedown = dragMouseDown;
624
625        function dragMouseDown(e) {
626            e.preventDefault();
627            pos3 = e.clientX;
628            pos4 = e.clientY;
629            document.onmouseup = closeDragElement;
630            document.onmousemove = elementDrag;
631        }
632
633        function elementDrag(e) {
634            e.preventDefault();
635            pos1 = pos3 - e.clientX;
636            pos2 = pos4 - e.clientY;
637            pos3 = e.clientX;
638            pos4 = e.clientY;
639            element.style.top = (element.offsetTop - pos2) + 'px';
640            element.style.left = (element.offsetLeft - pos1) + 'px';
641            element.style.right = 'auto';
642        }
643
644        function closeDragElement() {
645            document.onmouseup = null;
646            document.onmousemove = null;
647        }
648    }
649
650    // Initialize extension
651    async function init() {
652        console.log('Initializing ChatGPT 3D Audio Enhancer Pro...');
653        
654        await loadSettings();
655        createUI();
656        monitorAudioElements();
657
658        if (settings.enabled) {
659            initAudioContext();
660            toggleAudioProcessing(true);
661        }
662
663        console.log('ChatGPT 3D Audio Enhancer Pro initialized successfully!');
664    }
665
666    // Wait for page to load
667    if (document.readyState === 'loading') {
668        document.addEventListener('DOMContentLoaded', init);
669    } else {
670        init();
671    }
672})();
G1EQ | Robomonkey