import streamlit as st
import streamlit.components.v1 as components

def main():
    st.title("5-Octave Synth with Arpeggiator & Drum Pads")
    
    # Load and embed synth interface
    components.html(get_synth_interface(), height=800)

def get_synth_interface():
    return """
<!DOCTYPE html>
<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/tone@14.8.39/build/Tone.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@magenta/music@1.23.1/dist/magentamusic.min.js"></script>
    <style>
        .container { max-width: 1200px; margin: 0 auto; }
        .keyboard { display: flex; margin: 20px 0; }
        .key { 
            width: 40px; height: 150px; 
            border: 1px solid #000;
            background: white;
            margin-right: 2px;
        }
        .key.black { 
            width: 24px; height: 100px;
            background: black;
            margin: 0 -12px;
            z-index: 1;
        }
        .key.active { background: #ff6961; }
        .drum-grid {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 10px;
            margin: 20px 0;
        }
        .drum-pad {
            aspect-ratio: 1;
            background: #444;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            border-radius: 4px;
        }
        .drum-pad.active { background: #ff6961; }
        .controls {
            display: flex;
            gap: 20px;
            margin: 20px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="controls">
            <div>
                <label>Arpeggiator:</label>
                <select id="arpMode">
                    <option value="off">Off</option>
                    <option value="up">Up</option>
                    <option value="down">Down</option>
                    <option value="updown">Up/Down</option>
                    <option value="random">Random</option>
                </select>
                <input type="range" id="arpSpeed" min="100" max="1000" value="200">
            </div>
            <div>
                <label>Synth Type:</label>
                <select id="synthType">
                    <option value="simple">Simple</option>
                    <option value="fm">FM</option>
                    <option value="am">AM</option>
                </select>
            </div>
        </div>
        <div id="keyboard" class="keyboard"></div>
        <div id="drumPads" class="drum-grid"></div>
    </div>
    <script>
        // WebMIDI initialization
        let midiIn = null;
        
        if (navigator.requestMIDIAccess) {
            navigator.requestMIDIAccess()
                .then(access => {
                    const inputs = access.inputs.values();
                    for (let input of inputs) {
                        midiIn = input;
                        input.onmidimessage = handleMIDIMessage;
                    }
                    
                    access.onstatechange = e => {
                        if (e.port.type === 'input') {
                            if (e.port.state === 'connected') {
                                midiIn = e.port;
                                e.port.onmidimessage = handleMIDIMessage;
                            } else {
                                midiIn = null;
                            }
                        }
                    };
                })
                .catch(err => console.warn('WebMIDI not available:', err));
        }

        function handleMIDIMessage(event) {
            const [status, note, velocity] = event.data;
            const command = status >> 4;
            
            if (command === 9) { // Note On
                playNote(midiToNoteName(note), note, velocity);
            } else if (command === 8) { // Note Off
                stopNote(midiToNoteName(note), note);
            }
        }

        // Initialize Tone.js instruments
        const synth = new Tone.PolySynth().toDestination();
        const drumSampler = new Tone.Sampler({
            'C2': 'https://tonejs.github.io/audio/drum-samples/kicks/kick.mp3',
            'D2': 'https://tonejs.github.io/audio/drum-samples/snare/snare.mp3',
            'E2': 'https://tonejs.github.io/audio/drum-samples/hh/hh.mp3',
            'F2': 'https://tonejs.github.io/audio/drum-samples/tom/tom.mp3'
        }).toDestination();

        // Build 5-octave keyboard (61 keys)
        const startNote = 36; // C2
        const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
        const keyboard = document.getElementById('keyboard');
        
        for (let i = 0; i < 61; i++) {
            const midiNote = startNote + i;
            const octave = Math.floor(midiNote / 12) - 1;
            const noteName = noteNames[midiNote % 12] + octave;
            const isBlack = noteName.includes('#');
            
            const key = document.createElement('div');
            key.className = `key ${isBlack ? 'black' : ''}`;
            key.dataset.note = noteName;
            key.dataset.midi = midiNote;
            
            key.addEventListener('mousedown', () => playNote(noteName, midiNote));
            key.addEventListener('mouseup', () => stopNote(noteName, midiNote));
            key.addEventListener('mouseleave', () => stopNote(noteName, midiNote));
            
            keyboard.appendChild(key);
        }

        // Build 16 drum pads
        const drumPads = document.getElementById('drumPads');
        for (let i = 0; i < 16; i++) {
            const pad = document.createElement('div');
            pad.className = 'drum-pad';
            pad.textContent = `Pad ${i + 1}`;
            pad.addEventListener('mousedown', () => triggerDrum(i));
            drumPads.appendChild(pad);
        }

        // Arpeggiator implementation
        let arpNotes = [];
        let arpInterval = null;

        document.getElementById('arpMode').addEventListener('change', updateArpeggiator);
        document.getElementById('arpSpeed').addEventListener('change', updateArpeggiator);

        function updateArpeggiator() {
            const mode = document.getElementById('arpMode').value;
            const speed = document.getElementById('arpSpeed').value;
            
            if (arpInterval) clearInterval(arpInterval);
            if (mode !== 'off' && arpNotes.length) {
                let index = 0;
                arpInterval = setInterval(() => {
                    const note = arpNotes[index];
                    playNote(note, true);
                    setTimeout(() => stopNote(note), speed * 0.8);
                    
                    switch(mode) {
                        case 'up':
                            index = (index + 1) % arpNotes.length;
                            break;
                        case 'down':
                            index = (index - 1 + arpNotes.length) % arpNotes.length;
                            break;
                        case 'updown':
                            // Implementation for up/down pattern
                            break;
                        case 'random':
                            index = Math.floor(Math.random() * arpNotes.length);
                            break;
                    }
                }, speed);
            }
        }

        function playNote(note, midiNote) {
            Tone.start();
            synth.triggerAttack(note);
            const key = document.querySelector(`[data-midi="${midiNote}"]`);
            if (key) key.classList.add('active');

            if (document.getElementById('arpMode').value !== 'off') {
                if (!arpNotes.includes(note)) {
                    arpNotes.push(note);
                    updateArpeggiator();
                }
            }
        }

        function stopNote(note, midiNote) {
            synth.triggerRelease(note);
            const key = document.querySelector(`[data-midi="${midiNote}"]`);
            if (key) key.classList.remove('active');

            if (document.getElementById('arpMode').value !== 'off') {
                arpNotes = arpNotes.filter(n => n !== note);
                if (!arpNotes.length && arpInterval) {
                    clearInterval(arpInterval);
                    arpInterval = null;
                }
            }
        }

        function triggerDrum(index) {
            const notes = ['C2', 'D2', 'E2', 'F2'];
            const note = notes[index % notes.length];
            drumSampler.triggerAttackRelease(note, '8n');
            
            const pad = drumPads.children[index];
            pad.classList.add('active');
            setTimeout(() => pad.classList.remove('active'), 100);
        }

        // Handle synth type changes
        document.getElementById('synthType').addEventListener('change', (e) => {
            const type = e.target.value;
            let newSynth;
            
            switch(type) {
                case 'fm':
                    newSynth = new Tone.PolySynth(Tone.FMSynth).toDestination();
                    break;
                case 'am':
                    newSynth = new Tone.PolySynth(Tone.AMSynth).toDestination();
                    break;
                default:
                    newSynth = new Tone.PolySynth(Tone.Synth).toDestination();
            }
            
            synth.dispose();
            window.synth = newSynth;
        });
    </script>
</body>
</html>
    """

if __name__ == "__main__":
    main()