import streamlit as st import streamlit.components.v1 as components import json from pathlib import Path import time import subprocess import sys def check_midi_prerequisites(): """Check and report MIDI system status""" issues = [] solutions = [] try: import rtmidi except ImportError: issues.append("python-rtmidi is not installed") solutions.append("pip install python-rtmidi") except OSError as e: issues.append(f"MIDI system error: {str(e)}") solutions.extend([ "sudo apt-get install libasound2-dev", "sudo apt-get install alsa-utils", "sudo modprobe snd-seq-midi" ]) if issues: st.error("MIDI System Issues Detected") st.write("Problems found:") for issue in issues: st.write(f"- {issue}") st.write("Try these solutions:") for solution in solutions: st.code(solution) st.write("After installing prerequisites, restart the application.") return False return True def create_midi_output(): """Initialize MIDI output with fallback options""" try: import rtmidi midi_out = rtmidi.MidiOut() available_ports = midi_out.get_ports() if available_ports: st.sidebar.write("Available MIDI ports:", available_ports) selected_port = st.sidebar.selectbox( "Select MIDI Output", range(len(available_ports)), format_func=lambda x: available_ports[x] ) midi_out.open_port(selected_port) else: st.sidebar.warning("No hardware MIDI ports found. Creating virtual port.") try: midi_out.open_virtual_port("Virtual MIDI Output") except rtmidi.SystemError: st.sidebar.error("Could not create virtual MIDI port. Running in simulation mode.") return None return midi_out except Exception as e: st.sidebar.error(f"MIDI system unavailable: {str(e)}") st.sidebar.info("Running in simulation mode (no MIDI output)") return None def get_piano_html(): """Return the HTML content for the piano keyboard""" return """
""" def main(): st.title("MIDI Piano Keyboard") st.write("Click keys or use your computer keyboard (A-K and W-U for white and black keys)") # Check MIDI prerequisites if not check_midi_prerequisites(): return # Initialize MIDI output midi_out = create_midi_output() # Create a placeholder for MIDI messages midi_message_placeholder = st.empty() # Display the piano keyboard components.html( get_piano_html(), height=200, scrolling=False ) # Handle MIDI events from JavaScript if 'midi_events' not in st.session_state: st.session_state.midi_events = [] def handle_midi_event(event): if midi_out is None: # Simulation mode - just display the events if event['type'] == 'noteOn': midi_message_placeholder.write(f"Simulated Note On: {event['note']} (No MIDI Output)") else: midi_message_placeholder.write(f"Simulated Note Off: {event['note']} (No MIDI Output)") return if event['type'] == 'noteOn': midi_out.send_message([0x90, event['note'], event['velocity']]) midi_message_placeholder.write(f"Note On: {event['note']}") elif event['type'] == 'noteOff': midi_out.send_message([0x80, event['note'], event['velocity']]) midi_message_placeholder.write(f"Note Off: {event['note']}") # JavaScript callback handler components.html( """ """, height=0 ) if __name__ == "__main__": main()