I would like to add compressor, and hi and low pass filters. <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Audio Sampler with Effects</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f0f0f0;
            padding: 20px;
        }
        #input-level {
            font-size: 24px;
            margin-top: 10px;
        }
        #volume-slider, #device-selector, #controls {
            margin-top: 20px;
        }
        #controls input[type=range] {
            width: 200px;
        }
    </style>
</head>
<body>
    <h1>Random Audio Sampler with Effects</h1>
    <button id="start">Start Audio</button>
    <div id="device-selector">
        <label for="devices">Select Audio Device:</label>
        <select id="devices"></select>
    </div>
    <div id="input-level">Input Level: 0</div>

    <div id="controls">
        <label>Reverb: <input type="range" min="0" max="1" step="0.01" value="0.5" class="reverbSlider"></label>
        <label>Pitch Shift: <input type="range" min="-24" max="24" step="1" value="0" class="pitchSlider"></label>
        <label>Delay Time (sec): <input type="range" min="0" max="5" step="0.1" value="0.5" class="delaySlider"></label>
        <label>Segment Length Min: <input type="range" min="1" max="5" step="0.1" value="2" class="minSegmentLengthSlider"></label>
        <label>Segment Length Max: <input type="range" min="3" max="10" step="0.1" value="5" class="maxSegmentLengthSlider"></label>
        <label>Repeat Interval Min: <input type="range" min="1" max="10" step="0.1" value="2" class="minRepeatIntervalSlider"></label>
        <label>Repeat Interval Max: <input type="range" min="2" max="10" step="0.1" value="6" class="maxRepeatIntervalSlider"></label>
    </div>

    <script>
    let audioContext, source, reverbNode, delayNode, pitchNode, analyser, isPlayingSegment = false, bufferNode;
    let inputBuffer = [];

    document.getElementById('start').addEventListener('click', async () => {
        if (!audioContext) {
            audioContext = new (window.AudioContext || window.webkitAudioContext)();
        }

        try {
            const devices = await navigator.mediaDevices.enumerateDevices();
            const audioDevices = devices.filter(device => device.kind === 'audioinput');

            const deviceSelector = document.getElementById('devices');
            deviceSelector.innerHTML = '';
            audioDevices.forEach(device => {
                const option = document.createElement('option');
                option.value = device.deviceId;
                option.textContent = device.label || `Device ${device.deviceId}`;
                deviceSelector.appendChild(option);
            });

            deviceSelector.addEventListener('change', async (event) => {
                const deviceId = event.target.value;
                const stream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId } });

                if (source) {
                    source.disconnect();
                }

                source = audioContext.createMediaStreamSource(stream);

                analyser = audioContext.createAnalyser();
                analyser.fftSize = 2048;

                // Reverb Node
                reverbNode = audioContext.createConvolver();
                reverbNode.buffer = await createReverbBuffer();

                // Pitch Node (detune)
                pitchNode = audioContext.createGain(); // Placeholder for pitch shifting
                pitchNode.gain.value = 1; // Default gain value

                // Delay Node
                delayNode = audioContext.createDelay();
                delayNode.delayTime.value = parseFloat(document.querySelector('.delaySlider').value);

                // Connect audio nodes
                source.connect(analyser);
                analyser.connect(pitchNode);
                pitchNode.connect(reverbNode);
                reverbNode.connect(delayNode);
                delayNode.connect(audioContext.destination);

                // Start capturing and repeating segments
                captureAudioSegments();
                updateInputLevel();
            });

            if (audioDevices.length > 0) {
                deviceSelector.value = audioDevices[0].deviceId;
                deviceSelector.dispatchEvent(new Event('change'));
            }
        } catch (error) {
            console.error('Error accessing audio devices:', error);
        }
    });

    function captureAudioSegments() {
        function captureAndRepeat() {
            const minSegmentLength = parseFloat(document.querySelector('.minSegmentLengthSlider').value) * audioContext.sampleRate;
            const maxSegmentLength = parseFloat(document.querySelector('.maxSegmentLengthSlider').value) * audioContext.sampleRate;
            const segmentLength = Math.random() * (maxSegmentLength - minSegmentLength) + minSegmentLength;

            // Create buffer for actual audio input
            let captureBuffer = audioContext.createBuffer(1, segmentLength, audioContext.sampleRate);
            let channelData = captureBuffer.getChannelData(0);

            // Capture real audio input
            analyser.getByteTimeDomainData(inputBuffer);

            for (let i = 0; i < segmentLength; i++) {
                channelData[i] = (inputBuffer[i % inputBuffer.length] - 128) / 128.0;  // Normalize byte data to -1 to 1
            }

            playSegment(captureBuffer);

            // Repeat at a random interval
            const minRepeatInterval = parseFloat(document.querySelector('.minRepeatIntervalSlider').value) * 1000;
            const maxRepeatInterval = parseFloat(document.querySelector('.maxRepeatIntervalSlider').value) * 1000;
            const randomDelay = Math.random() * (maxRepeatInterval - minRepeatInterval) + minRepeatInterval;

            setTimeout(() => {
                captureAndRepeat();
            }, randomDelay);
        }

        captureAndRepeat();  // Start capturing
    }

    function playSegment(buffer) {
        const source = audioContext.createBufferSource();
        source.buffer = buffer;

        const randomPlaybackRate = Math.random() * (4 - 0.25) + 0.25;  // Between 0.25x and 4x speed
        source.playbackRate.value = randomPlaybackRate;

        // Adjust pitch and delay
        pitchNode.gain.value = Math.pow(2, parseFloat(document.querySelector('.pitchSlider').value) / 12);
        delayNode.delayTime.value = parseFloat(document.querySelector('.delaySlider').value);

        source.connect(pitchNode);
        source.connect(audioContext.destination);
        source.start();

        // Optionally fade out (fade over the last 500ms)
        fadeOutSegment(source, 0.1);  // 0.5-second fade-out
    }

    function fadeOutSegment(audioSource, duration) {
        const fadeGain = audioContext.createGain();
        fadeGain.gain.setValueAtTime(1, audioContext.currentTime);
        fadeGain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);

        audioSource.connect(fadeGain);
        fadeGain.connect(audioContext.destination);

        setTimeout(() => {
            audioSource.stop();
        }, duration * 1000);
    }

    async function createReverbBuffer() {
        const length = audioContext.sampleRate * 3; // 3-second reverb
        const reverbBuffer = audioContext.createBuffer(2, length, audioContext.sampleRate);
        for (let channel = 0; channel < reverbBuffer.numberOfChannels; channel++) {
            const nowBuffering = reverbBuffer.getChannelData(channel);
            for (let i = 0; i < length; i++) {
                nowBuffering[i] = Math.random() * 2 - 1; // White noise for reverb effect
            }
        }
        return reverbBuffer;
    }

    function updateInputLevel() {
        const bufferLength = analyser.fftSize;
        inputBuffer = new Uint8Array(bufferLength);

        function analyzeAudio() {
            analyser.getByteTimeDomainData(inputBuffer);
            const rms = Math.sqrt(inputBuffer.reduce((acc, val) => acc + (val * val), 0) / bufferLength);
            document.getElementById('input-level').textContent = `Input Level: ${rms.toFixed(2)}`;
            requestAnimationFrame(analyzeAudio);
        }

        requestAnimationFrame(analyzeAudio);
    }

    </script>
</body>
</html>