import streamlit as st import numpy as np from pydub import AudioSegment from pydub.generators import Sine import simpleaudio as sa import time # Constants KEYS = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] OCTAVES = [3, 4, 5] BLUES_PROGRESSIONS = [ ['I', 'I', 'I', 'I', 'IV', 'IV', 'I', 'I', 'V', 'IV', 'I', 'V'], ['I', 'IV', 'I', 'I', 'IV', 'IV', 'I', 'I', 'V', 'IV', 'I', 'V'], ['I', 'I', 'I', 'I', 'IV', 'IV', 'I', 'I', 'V', 'V', 'I', 'V'], ['I', 'I', 'I', 'I', 'IV', 'IV', 'I', 'I', 'V', 'IV', 'I', 'I'], ['I', 'IV', 'I', 'V', 'IV', 'IV', 'I', 'V', 'IV', 'IV', 'I', 'V'], ] def note_to_freq(note): octave = int(note[-1]) key_index = KEYS.index(note[:-1]) return 440 * (2 ** ((key_index - 9) / 12 + (octave - 4))) def get_chord_notes(root, chord_type): root_index = KEYS.index(root) if chord_type == 'I': intervals = [0, 4, 7] elif chord_type == 'IV': intervals = [5, 9, 0] elif chord_type == 'V': intervals = [7, 11, 2] else: intervals = [0, 4, 7] return [KEYS[(root_index + interval) % len(KEYS)] for interval in intervals] def create_tone(freq, duration_ms): return Sine(freq).to_audio_segment(duration=duration_ms) def play_arpeggio(root, chord_type, tempo): chord_notes = get_chord_notes(root, chord_type) duration_ms = int(60 / tempo * 250) # 16th notes arpeggio = AudioSegment.silent(duration=1) for note in chord_notes: freq = note_to_freq(f"{note}4") tone = create_tone(freq, duration_ms) arpeggio = arpeggio.overlay(tone) play_obj = sa.play_buffer( arpeggio.raw_data, num_channels=arpeggio.channels, bytes_per_sample=arpeggio.sample_width, sample_rate=arpeggio.frame_rate ) play_obj.wait_done() def main(): st.title("12-Bar Blues Arpeggio Game") # Sidebar for controls st.sidebar.header("Controls") root_key = st.sidebar.selectbox("Select Root Key", KEYS) tempo = st.sidebar.slider("Tempo (BPM)", 60, 240, 120) # Main area if 'blues_progression' not in st.session_state: st.session_state.blues_progression = BLUES_PROGRESSIONS[0] if 'current_bar' not in st.session_state: st.session_state.current_bar = 0 if 'chord_history' not in st.session_state: st.session_state.chord_history = [] # Display current progression st.write("Current 12-Bar Blues Progression:") progression_display = " ".join([f"**{chord}**" if i == st.session_state.current_bar else chord for i, chord in enumerate(st.session_state.blues_progression)]) st.markdown(progression_display) # Play/Stop button if st.button("Play/Stop 12-Bar Blues"): for i, chord in enumerate(st.session_state.blues_progression): st.session_state.current_bar = i play_arpeggio(root_key, chord, tempo) st.session_state.chord_history.append(f"{root_key}{chord}") st.session_state.chord_history = st.session_state.chord_history[-12:] st.experimental_rerun() # Randomize button if st.button("Randomize Progression"): st.session_state.blues_progression = BLUES_PROGRESSIONS[np.random.randint(len(BLUES_PROGRESSIONS))] st.experimental_rerun() # Display chord history st.write("Chord History:") st.write(" ".join(st.session_state.chord_history)) if __name__ == "__main__": main()