Spaces:
Sleeping
Sleeping
import streamlit as st | |
import numpy as np | |
import sounddevice as sd | |
from scipy import signal | |
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'], | |
] | |
SAMPLE_RATE = 44100 | |
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): | |
t = np.linspace(0, duration, int(SAMPLE_RATE * duration), False) | |
return 0.3 * signal.chirp(t, freq, duration, freq, method='linear') | |
def play_arpeggio(root, chord_type, tempo): | |
chord_notes = get_chord_notes(root, chord_type) | |
duration = 60 / tempo / 4 # 16th notes | |
arpeggio = np.array([]) | |
for note in chord_notes: | |
freq = note_to_freq(f"{note}4") | |
tone = create_tone(freq, duration) | |
arpeggio = np.concatenate((arpeggio, tone)) | |
sd.play(arpeggio, SAMPLE_RATE) | |
sd.wait() | |
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() |