SOURCE

console 命令行工具 X clear

                    
>
console
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>平滑过渡音频可视化器</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            background: linear-gradient(135deg, #121212, #1a1a2e);
            color: #f5f5f5;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            min-height: 100vh;
            padding: 20px;
            overflow-x: hidden;
        }
        
        .container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 20px;
            max-width: 900px;
            width: 100%;
        }
        
        header {
            text-align: center;
            margin-bottom: 15px;
            width: 100%;
        }
        
        .title {
            font-size: 2.8rem;
            background: linear-gradient(to right, #FF5722, #FF9800, #FFC107);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            font-weight: 800;
            letter-spacing: 1px;
            margin-bottom: 8px;
            text-shadow: 0 0 15px rgba(255, 152, 0, 0.3);
        }
        
        .subtitle {
            color: #90caf9;
            font-size: 1.1rem;
            max-width: 600px;
            margin: 0 auto;
            line-height: 1.6;
        }
        
        .visualizer-container {
            position: relative;
            border-radius: 16px;
            width: 100%;
            height: 300px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: rgba(20, 25, 45, 0.7);
            overflow: hidden;
            margin-bottom: 10px;
            box-shadow: 
                0 10px 30px rgba(0, 0, 0, 0.5),
                inset 0 0 20px rgba(255, 152, 0, 0.1);
            border: 1px solid rgba(255, 152, 0, 0.2);
        }
        
        .center-line {
            position: absolute;
            width: 100%;
            height: 1px;
            background: rgba(255, 255, 255, 0.15);
            top: 50%;
            left: 0;
            z-index: 1;
        }
        
        #audioPlayer {
            width: 100%;
            border-radius: 50px;
            background: rgba(30, 40, 70, 0.7);
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4);
            outline: none;
        }
        
        .control-panel {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            background: rgba(20, 25, 45, 0.8);
            padding: 25px;
            border-radius: 16px;
            width: 100%;
            margin-top: 15px;
            border: 1px solid rgba(255, 152, 0, 0.3);
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4);
        }
        
        .control-column {
            flex: 1;
            min-width: 280px;
            display: flex;
            flex-direction: column;
            gap: 15px;
        }
        
        .control-group {
            display: flex;
            flex-direction: column;
            background: rgba(30, 35, 55, 0.6);
            padding: 15px;
            border-radius: 12px;
            border: 1px solid rgba(255, 152, 0, 0.2);
        }
        
        .group-header {
            display: flex;
            align-items: center;
            margin-bottom: 12px;
            color: #FF9800;
            font-size: 1.2rem;
            font-weight: 600;
        }
        
        .control-row {
            display: flex;
            align-items: center;
            margin-bottom: 10px;
        }
        
        .control-row:last-child {
            margin-bottom: 0;
        }
        
        label {
            flex: 1;
            font-size: 1rem;
            color: #e0e0e0;
            min-width: 120px;
        }
        
        input[type="range"] {
            flex: 2;
            height: 8px;
            background: rgba(255, 152, 0, 0.15);
            border-radius: 4px;
            outline: none;
            -webkit-appearance: none;
        }
        
        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 22px;
            height: 22px;
            border-radius: 50%;
            background: #FF9800;
            cursor: pointer;
            box-shadow: 0 0 10px rgba(255, 152, 0, 0.7);
            transition: all 0.2s;
        }
        
        input[type="range"]::-webkit-slider-thumb:hover {
            transform: scale(1.15);
            box-shadow: 0 0 15px rgba(255, 152, 0, 0.9);
        }
        
        .value-display {
            min-width: 70px;
            text-align: center;
            background: rgba(255, 152, 0, 0.15);
            padding: 8px 12px;
            border-radius: 20px;
            font-size: 0.95rem;
            font-weight: 600;
            color: #FFD180;
            margin-left: 15px;
        }
        
        .toggle-group {
            display: flex;
            align-items: center;
            gap: 15px;
        }
        
        .color-picker-group {
            display: flex;
            gap: 15px;
            align-items: center;
        }
        
        .color-picker {
            width: 45px;
            height: 45px;
            border-radius: 10px;
            border: 2px solid rgba(255, 255, 255, 0.3);
            cursor: pointer;
            background: #FF9800;
            transition: all 0.3s;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
            display: flex;
            align-items: center;
            justify-content: center;
        }
        
        .color-picker:hover {
            transform: scale(1.1);
            box-shadow: 0 0 15px rgba(255, 152, 0, 0.7);
        }
        
        .color-picker input {
            width: 100%;
            height: 100%;
            opacity: 0;
            cursor: pointer;
        }
        
        .preview-box {
            width: 100%;
            height: 80px;
            background: rgba(30, 35, 55, 0.7);
            border-radius: 12px;
            margin-top: 15px;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
            overflow: hidden;
        }
        
        .preview-bar {
            width: 60%;
            height: 40px;
            background: #FF9800;
            position: relative;
            z-index: 2;
            transition: all 0.4s ease;
        }
        
        .presets {
            display: flex;
            gap: 12px;
            margin-top: 15px;
            flex-wrap: wrap;
        }
        
        .preset-btn {
            padding: 10px 18px;
            background: rgba(255, 152, 0, 0.1);
            border: 1px solid rgba(255, 152, 0, 0.3);
            color: #FF9800;
            border-radius: 30px;
            cursor: pointer;
            transition: all 0.3s;
            font-size: 0.9rem;
            font-weight: 500;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .preset-btn:hover {
            background: rgba(255, 152, 0, 0.25);
            transform: translateY(-2px);
        }
        
        .mode-toggle {
            display: flex;
            gap: 15px;
            margin-top: 10px;
            flex-wrap: wrap;
        }
        
        .mode-btn {
            flex: 1;
            padding: 14px;
            background: rgba(255, 152, 0, 0.08);
            border: 1px solid rgba(255, 152, 0, 0.3);
            color: #FF9800;
            border-radius: 10px;
            cursor: pointer;
            transition: all 0.3s;
            font-weight: 600;
            font-size: 1.05rem;
            text-align: center;
            min-width: 150px;
        }
        
        .mode-btn:hover {
            background: rgba(255, 152, 0, 0.2);
        }
        
        .mode-btn.active {
            background: linear-gradient(to right, rgba(255, 87, 34, 0.3), rgba(255, 193, 7, 0.3));
            box-shadow: 0 0 15px rgba(255, 152, 0, 0.4);
            border-color: rgba(255, 152, 0, 0.5);
        }
        
        .footer {
            margin-top: 25px;
            color: #82b1ff;
            font-size: 0.9rem;
            text-align: center;
            padding: 15px;
            width: 100%;
            border-top: 1px solid rgba(255, 152, 0, 0.1);
        }
        
        canvas {
            display: block;
        }
        
        .bubble {
            position: absolute;
            border-radius: 50%;
            background: rgba(255, 152, 0, 0.05);
            z-index: -1;
        }
        
        @media (max-width: 768px) {
            .control-column {
                min-width: 100%;
            }
            
            .title {
                font-size: 2.2rem;
            }
            
            .visualizer-container {
                height: 250px;
            }
            
            .mode-btn {
                min-width: 130px;
                padding: 12px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1 class="title">平滑过渡音频可视化器</h1>
            <p class="subtitle">优化的渐变色过渡与精细控制</p>
        </header>
        
        <div class="visualizer-container" id="visualizerContainer">
            <div class="center-line"></div>
            <canvas id="visualizer"></canvas>
        </div>
        
        <audio id="audioPlayer" controls>
            <source src="./mp3/Ugress - Undead Funeral March.mp3" type="audio/mp3">
            您的浏览器不支持 audio 元素
        </audio>
        
        <div class="control-panel">
            <div class="control-column">
                <div class="control-group">
                    <div class="group-header">形状控制</div>
                    
                    <div class="control-row">
                        <label>柱子数量:</label>
                        <input type="range" id="barCountSlider" min="6" max="64" value="32">
                        <span id="barCountValue" class="value-display">32</span>
                    </div>
                    
                    <div class="control-row">
                        <label>柱子间距:</label>
                        <input type="range" id="spacingSlider" min="0" max="20" value="2">
                        <span id="spacingValue" class="value-display">2px</span>
                    </div>
                    
                    <div class="control-row">
                        <label>基础高度:</label>
                        <input type="range" id="baseHeightSlider" min="0" max="40" value="8">
                        <span id="baseHeightValue" class="value-display">8px</span>
                    </div>
                </div>
                
                <div class="control-group">
                    <div class="group-header">圆角效果</div>
                    
                    <div class="control-row">
                        <label>圆角半径:</label>
                        <input type="range" id="borderRadiusSlider" min="0" max="50" value="4">
                        <span id="borderRadiusValue" class="value-display">4px</span>
                    </div>
                    
                    <div class="control-row">
                        <label>圆端效果:</label>
                        <input type="range" id="roundnessSlider" min="0" max="100" value="0">
                        <span id="roundnessValue" class="value-display">0%</span>
                    </div>
                    
                    <div class="preview-box">
                        <div class="preview-bar" id="previewBar"></div>
                    </div>
                </div>
            </div>
            
            <div class="control-column">
                <div class="control-group">
                    <div class="group-header">渐变控制</div>
                    
                    <div class="control-row">
                        <label>主色:</label>
                        <div class="color-picker" style="background: #FF9800;">
                            <input type="color" id="primaryColorPicker" value="#FF9800">
                        </div>
                    </div>
                    
                    <div class="control-row">
                        <label>次色:</label>
                        <div class="color-picker" style="background: #FF6D00;">
                            <input type="color" id="secondaryColorPicker" value="#FF6D00">
                        </div>
                    </div>
                    
                    <div class="control-row">
                        <label>渐变过渡:</label>
                        <input type="range" id="gradientSmoothnessSlider" min="1" max="10" value="5">
                        <span id="gradientSmoothnessValue" class="value-display">5</span>
                    </div>
                    
                    <div class="control-row">
                        <label>渐变偏移:</label>
                        <input type="range" id="gradientOffsetSlider" min="-50" max="50" value="0">
                        <span id="gradientOffsetValue" class="value-display">0%</span>
                    </div>
                    
                    <div class="presets">
                        <button class="preset-btn" data-preset="smoothSunset">
                            �� 日落实景
                        </button>
                        <button class="preset-btn" data-preset="oceanDepth">
                            �� 深海渐变
                        </button>
                        <button class="preset-btn" data-preset="forestCanopy">
                            �� 森林冠层
                        </button>
                        <button class="preset-btn" data-preset="neonGlow">
                            �� 霓虹发光
                        </button>
                    </div>
                </div>
                
                <div class="control-group">
                    <div class="group-header">可视化模式</div>
                    
                    <div class="mode-toggle">
                        <button id="modeBar" class="mode-btn active">
                            ▮ 柱状模式
                        </button>
                        <button id="modeRoundBar" class="mode-btn">
                            ⬤ 圆端模式
                        </button>
                        <button id="modeWave" class="mode-btn">
                            ⌇ 波形模式
                        </button>
                    </div>
                    
                    <div class="control-row" style="margin-top: 15px;">
                        <label>动态灵敏度:</label>
                        <input type="range" id="sensitivitySlider" min="0.1" max="2" step="0.1" value="1">
                        <span id="sensitivityValue" class="value-display">1.0x</span>
                    </div>
                </div>
            </div>
        </div>
        
        <div class="footer">
            <p>平滑过渡音频可视化器 &copy; 2023 | 使用Web Audio API实现</p>
        </div>
    </div>

    <script>
        // 创建背景气泡效果
        function createBubbles() {
            const container = document.querySelector('.visualizer-container');
            const bubbleCount = 12;
            
            for (let i = 0; i < bubbleCount; i++) {
                const bubble = document.createElement('div');
                bubble.className = 'bubble';
                
                // 随机大小和位置
                const size = Math.random() * 80 + 20;
                const posX = Math.random() * 100;
                const posY = Math.random() * 100;
                
                bubble.style.width = `${size}px`;
                bubble.style.height = `${size}px`;
                bubble.style.left = `${posX}%`;
                bubble.style.top = `${posY}%`;
                
                // 随机动画
                const duration = Math.random() * 20 + 20;
                bubble.style.animation = `float ${duration}s infinite ease-in-out`;
                
                container.appendChild(bubble);
            }
        }
        
        // DOM 元素
        const container = document.querySelector(".visualizer-container");
        const canvas = document.getElementById("visualizer");
        const ctx = canvas.getContext("2d");
        const audio = document.getElementById("audioPlayer");
        const previewBar = document.getElementById("previewBar");
        
        // 控制元素
        const barCountSlider = document.getElementById("barCountSlider");
        const spacingSlider = document.getElementById("spacingSlider");
        const baseHeightSlider = document.getElementById("baseHeightSlider");
        const borderRadiusSlider = document.getElementById("borderRadiusSlider");
        const roundnessSlider = document.getElementById("roundnessSlider");
        const primaryColorPicker = document.getElementById("primaryColorPicker");
        const secondaryColorPicker = document.getElementById("secondaryColorPicker");
        const gradientSmoothnessSlider = document.getElementById("gradientSmoothnessSlider");
        const gradientOffsetSlider = document.getElementById("gradientOffsetSlider");
        const sensitivitySlider = document.getElementById("sensitivitySlider");
        const modeBarBtn = document.getElementById("modeBar");
        const modeRoundBarBtn = document.getElementById("modeRoundBar");
        const modeWaveBtn = document.getElementById("modeWave");
        
        // 显示元素
        const barCountValue = document.getElementById("barCountValue");
        const spacingValue = document.getElementById("spacingValue");
        const baseHeightValue = document.getElementById("baseHeightValue");
        const borderRadiusValue = document.getElementById("borderRadiusValue");
        const roundnessValue = document.getElementById("roundnessValue");
        const gradientSmoothnessValue = document.getElementById("gradientSmoothnessValue");
        const gradientOffsetValue = document.getElementById("gradientOffsetValue");
        const sensitivityValue = document.getElementById("sensitivityValue");
        
        // 预设按钮
        const presetButtons = document.querySelectorAll('.preset-btn');

        // 参数配置
        let analyser = null;
        let barCount = 32;
        let barSpacing = 2;
        let barBaseHeight = 8;
        let barBorderRadius = 4;
        let roundness = 0;
        let gradientSmoothness = 5;
        let gradientOffset = 0;
        let primaryColor = "#FF9800";
        let secondaryColor = "#FF6D00";
        let audioContext = null;
        let visualizationMode = "bar";
        let sensitivity = 1.0;
        
        // 历史数据用于平滑
        let history = new Array(64).fill(0);
        
        // 设置canvas尺寸
        function resizeCanvas() {
            canvas.width = container.clientWidth;
            canvas.height = container.clientHeight;
        }
        
        // 创建背景气泡
        createBubbles();
        
        window.addEventListener('resize', resizeCanvas);
        resizeCanvas();
        
        // 更新UI显示
        function updateUIValues() {
            barCountValue.textContent = barCount;
            spacingValue.textContent = `${barSpacing}px`;
            baseHeightValue.textContent = `${barBaseHeight}px`;
            borderRadiusValue.textContent = `${barBorderRadius}px`;
            roundnessValue.textContent = `${roundness}%`;
            gradientSmoothnessValue.textContent = gradientSmoothness;
            gradientOffsetValue.textContent = `${gradientOffset}%`;
            sensitivityValue.textContent = `${sensitivity.toFixed(1)}x`;
            
            // 更新预览条
            const actualRadius = barBorderRadius * (1 + roundness/50);
            previewBar.style.borderRadius = `${actualRadius}px`;
            
            if (roundness > 50) {
                previewBar.style.borderRadius = `50%`;
            }
            
            // 更新预览条的渐变效果
            const smoothnessFactor = gradientSmoothness / 10;
            const offset = gradientOffset / 100;
            
            previewBar.style.background = `linear-gradient(
                to bottom, 
                ${primaryColor}, 
                ${mixColors(primaryColor, secondaryColor, 0.5 + offset/2)},
                ${mixColors(primaryColor, secondaryColor, 0.5 - offset/2)},
                ${secondaryColor}
            )`;
        }
        
        // 事件监听
        barCountSlider.addEventListener('input', function() {
            barCount = parseInt(this.value);
            updateUIValues();
        });
        
        spacingSlider.addEventListener('input', function() {
            barSpacing = parseInt(this.value);
            updateUIValues();
        });
        
        baseHeightSlider.addEventListener('input', function() {
            barBaseHeight = parseInt(this.value);
            updateUIValues();
        });
        
        borderRadiusSlider.addEventListener('input', function() {
            barBorderRadius = parseInt(this.value);
            updateUIValues();
        });
        
        roundnessSlider.addEventListener('input', function() {
            roundness = parseInt(this.value);
            updateUIValues();
        });
        
        gradientSmoothnessSlider.addEventListener('input', function() {
            gradientSmoothness = parseInt(this.value);
            updateUIValues();
        });
        
        gradientOffsetSlider.addEventListener('input', function() {
            gradientOffset = parseInt(this.value);
            updateUIValues();
        });
        
        sensitivitySlider.addEventListener('input', function() {
            sensitivity = parseFloat(this.value);
            updateUIValues();
        });
        
        primaryColorPicker.addEventListener('input', function() {
            primaryColor = this.value;
            updateUIValues();
        });
        
        secondaryColorPicker.addEventListener('input', function() {
            secondaryColor = this.value;
            updateUIValues();
        });
        
        modeBarBtn.addEventListener('click', function() {
            visualizationMode = "bar";
            modeBarBtn.classList.add('active');
            modeRoundBarBtn.classList.remove('active');
            modeWaveBtn.classList.remove('active');
        });
        
        modeRoundBarBtn.addEventListener('click', function() {
            visualizationMode = "roundBar";
            modeBarBtn.classList.remove('active');
            modeRoundBarBtn.classList.add('active');
            modeWaveBtn.classList.remove('active');
        });
        
        modeWaveBtn.addEventListener('click', function() {
            visualizationMode = "wave";
            modeBarBtn.classList.remove('active');
            modeRoundBarBtn.classList.remove('active');
            modeWaveBtn.classList.add('active');
        });
        
        // 混合两种颜色
        function mixColors(color1, color2, weight) {
            // 简单的十六进制到RGB转换
            function hexToRgb(hex) {
                const r = parseInt(hex.slice(1, 3), 16);
                const g = parseInt(hex.slice(3, 5), 16);
                const b = parseInt(hex.slice(5, 7), 16);
                return [r, g, b];
            }
            
            // RGB到十六进制转换
            function rgbToHex(r, g, b) {
                return "#" + [r, g, b].map(x => {
                    const hex = x.toString(16);
                    return hex.length === 1 ? '0' + hex : hex;
                }).join('');
            }
            
            const [r1, g1, b1] = hexToRgb(color1);
            const [r2, g2, b2] = hexToRgb(color2);
            
            const r = Math.round(r1 * (1 - weight) + r2 * weight);
            const g = Math.round(g1 * (1 - weight) + g2 * weight);
            const b = Math.round(b1 * (1 - weight) + b2 * weight);
            
            return rgbToHex(r, g, b);
        }
        
        // 创建优化的渐变色带
        function createOptimizedGradient(x, topY, bottomY, barHeight, barCount) {
            const smoothnessFactor = gradientSmoothness / 8;
            const offset = gradientOffset / 100;
            const gradientHeight = Math.max(barHeight * 2, 100);
            
            // 根据柱子位置创建渐变偏移效果
            const positionOffset = Math.sin(x / canvas.width * Math.PI * 0.5) * offset * 0.1;
            
            // 创建渐变
            const gradient = ctx.createLinearGradient(
                0, topY - barHeight * positionOffset, 
                0, bottomY + barHeight * positionOffset
            );
            
            // 添加颜色断点
            gradient.addColorStop(0, primaryColor);
            
            // 根据平滑度添加中间颜色
            for (let i = 1; i <= smoothnessFactor; i++) {
                const position = i / (smoothnessFactor + 1);
                gradient.addColorStop(
                    position, 
                    mixColors(primaryColor, secondaryColor, position + positionOffset)
                );
            }
            
            gradient.addColorStop(1, secondaryColor);
            
            return gradient;
        }
        
        // 创建圆端矩形
        function createRoundEndedRect(x, y, width, height, radius, roundness) {
            const path = new Path2D();
            
            // 计算实际圆角半径
            const actualRadius = Math.min(width/2, height/2, radius * (1 + roundness/50));
            
            // 对于超过50%圆度的情况,强制使用半圆形端点
            const finalRadius = roundness > 50 ? Math.min(width/2, height/2) : actualRadius;
            
            if (finalRadius <= 0) {
                path.rect(x, y, width, height);
                return path;
            }
            
            // 绘制圆端矩形
            path.moveTo(x + finalRadius, y);
            path.lineTo(x + width - finalRadius, y);
            path.arcTo(x + width, y, x + width, y + finalRadius, finalRadius);
            path.lineTo(x + width, y + height - finalRadius);
            path.arcTo(x + width, y + height, x + width - finalRadius, y + height, finalRadius);
            path.lineTo(x + finalRadius, y + height);
            path.arcTo(x, y + height, x, y + height - finalRadius, finalRadius);
            path.lineTo(x, y + finalRadius);
            path.arcTo(x, y, x + finalRadius, y, finalRadius);
            
            path.closePath();
            return path;
        }
        
        // 生成中间隆起的权重曲线
        function generateWeights(count, intensity) {
            const weights = [];
            const centerIndex = (count - 1) / 2;
            const factor = intensity * 0.1;
            
            for (let i = 0; i < count; i++) {
                const distanceFromCenter = Math.abs(i - centerIndex);
                // 使用高斯函数创建中间高的权重
                const weight = Math.exp(
                    -Math.pow(distanceFromCenter, 2) / (factor * count)
                );
                weights.push(weight);
            }
            
            return weights;
        }
        
        // 绘制柱状可视化
        function drawBarVisualizer() {
            if (!analyser) return;
            
            const bufferLength = analyser.frequencyBinCount;
            const dataArray = new Uint8Array(bufferLength);
            analyser.getByteFrequencyData(dataArray);
            
            // 清除画布
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            // 添加背景效果
            const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
            gradient.addColorStop(0, 'rgba(20, 30, 50, 0.6)');
            gradient.addColorStop(1, 'rgba(10, 20, 40, 0.8)');
            ctx.fillStyle = gradient;
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            // 计算并处理可视化数据
            const barWidth = (canvas.width - barSpacing * (barCount - 1)) / barCount;
            const centerY = canvas.height / 2;
            
            // 生成当前权重
            const weights = generateWeights(barCount, 6);
            
            for (let i = 0; i < barCount; i++) {
                // 选择合适的数据点
                const dataIndex = Math.floor((i / barCount) * bufferLength * 0.5);
                let value = dataArray[dataIndex] / 255;
                
                // 应用灵敏度
                value = Math.min(1, value * sensitivity);
                
                // 应用平滑处理
                history[i] = history[i] * 0.7 + value * 0.3;
                value = history[i];
                
                // 应用权重增强中间柱的高度
                const weightedValue = value * weights[i];
                // 加入基础高度
                const barHeight = Math.max(barBaseHeight, weightedValue * centerY);
                
                // 计算位置
                const x = i * (barWidth + barSpacing);
                
                // 创建优化的渐变色
                ctx.fillStyle = createOptimizedGradient(x, centerY - barHeight, centerY + barHeight, barHeight, barCount);
                
                // 绘制柱子(从中心向上下扩散)
                const y = centerY - barHeight;
                const totalHeight = barHeight * 2;
                
                // 创建柱体形状
                const barPath = createRoundEndedRect(
                    x, 
                    y, 
                    barWidth, 
                    totalHeight, 
                    barBorderRadius,
                    roundness
                );
                ctx.fill(barPath);
                
                // 添加光泽效果
                ctx.globalCompositeOperation = 'screen';
                const highlight = ctx.createLinearGradient(
                    x, y, 
                    x, y + totalHeight
                );
                highlight.addColorStop(0, 'rgba(255, 255, 255, 0.3)');
                highlight.addColorStop(0.5, 'rgba(255, 255, 255, 0.1)');
                highlight.addColorStop(0.5, 'transparent');
                ctx.fillStyle = highlight;
                ctx.fill(barPath);
                ctx.globalCompositeOperation = 'source-over';
            }
        }
        
        // 绘制圆端柱状可视化
        function drawRoundBarVisualizer() {
            return drawBarVisualizer(); // 使用相同的绘制函数
        }
        
        // 绘制波形可视化
        function drawWaveVisualizer() {
            if (!analyser) return;
            
            const bufferLength = analyser.frequencyBinCount;
            const dataArray = new Uint8Array(bufferLength);
            analyser.getByteFrequencyData(dataArray);
            
            // 清除画布
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            const centerY = canvas.height / 2;
            const sliceWidth = canvas.width / barCount;
            
            // 生成当前权重
            const weights = generateWeights(barCount, 6);
            
            ctx.beginPath();
            
            for (let i = 0; i < barCount; i++) {
                const dataIndex = Math.floor((i / barCount) * bufferLength * 0.5);
                let value = dataArray[dataIndex] / 255;
                
                // 应用灵敏度
                value = Math.min(1, value * sensitivity);
                
                // 应用平滑处理
                history[i] = history[i] * 0.7 + value * 0.3;
                value = history[i];
                
                // 应用权重增强中间柱的高度
                const weightedValue = value * weights[i];
                // 加入基础高度
                const barHeight = Math.max(barBaseHeight, weightedValue * centerY);
                
                const x = i * sliceWidth;
                const yTop = centerY - barHeight;
                const yBottom = centerY + barHeight;
                
                // 绘制上半部分波形
                if (i === 0) {
                    ctx.moveTo(x, yTop);
                } else {
                    ctx.lineTo(x, yTop);
                }
            }
            
            // 绘制下半部分波形
            for (let i = barCount - 1; i >= 0; i--) {
                const dataIndex = Math.floor((i / barCount) * bufferLength * 0.5);
                let value = dataArray[dataIndex] / 255;
                
                // 应用灵敏度
                value = Math.min(1, value * sensitivity);
                
                // 应用平滑处理
                history[i] = history[i] * 0.7 + value * 0.3;
                value = history[i];
                
                const weightedValue = value * weights[i];
                const barHeight = Math.max(barBaseHeight, weightedValue * centerY);
                
                const x = i * sliceWidth;
                const yBottom = centerY + barHeight;
                
                ctx.lineTo(x, yBottom);
            }
            
            ctx.closePath();
            
            // 创建渐变填充
            const gradient = ctx.createLinearGradient(
                0, centerY - centerY, 
                0, centerY + centerY
            );
            
            // 添加颜色断点
            const smoothnessFactor = gradientSmoothness / 8;
            gradient.addColorStop(0, primaryColor);
            
            for (let i = 1; i <= smoothnessFactor; i++) {
                const position = i / (smoothnessFactor + 1);
                gradient.addColorStop(
                    position, 
                    mixColors(primaryColor, secondaryColor, position)
                );
            }
            
            gradient.addColorStop(1, secondaryColor);
            
            ctx.fillStyle = gradient;
            ctx.fill();
            
            // 绘制波形轮廓
            ctx.strokeStyle = mixColors(primaryColor, secondaryColor, 0.5);
            ctx.lineWidth = 2;
            ctx.stroke();
        }
        
        // 绘制音频可视化
        function drawVisualizer() {
            requestAnimationFrame(drawVisualizer);
            
            if (visualizationMode === "bar") {
                drawBarVisualizer();
            } else if (visualizationMode === "roundBar") {
                drawRoundBarVisualizer();
            } else {
                drawWaveVisualizer();
            }
        }
        
        // 初始化音频
        function initAudio() {
            audio.onplay = () => {
                // 创建音频上下文
                if (!audioContext) {
                    audioContext = new (window.AudioContext || window.webkitAudioContext)();
                    const source = audioContext.createMediaElementSource(audio);
                    
                    // 创建音频分析器
                    analyser = audioContext.createAnalyser();
                    analyser.fftSize = 2048;
                    
                    // 连接节点
                    source.connect(analyser);
                    analyser.connect(audioContext.destination);
                }
            };
        }
        
        // 初始化
        function init() {
            initAudio();
            drawVisualizer();
            updateUIValues();
        }
        
        // 启动应用
        window.addEventListener("load", init);
    </script>
</body>
</html>