import streamlit as st import streamlit.components.v1 as components import rtmidi import json from pathlib import Path import time def create_midi_output(): """Initialize MIDI output""" 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 MIDI output ports available") midi_out.open_virtual_port("Virtual MIDI Output") return midi_out 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)") # 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 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 ) # Add a loop to continuously check for new MIDI events while True: time.sleep(0.1) # Small delay to prevent excessive CPU usage # Process any pending MIDI events for event in st.session_state.midi_events: handle_midi_event(event) st.session_state.midi_events = [] if __name__ == "__main__": main()