diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..0877b45 Binary files /dev/null and b/.DS_Store differ diff --git a/.github/workflows/build_and_deploy.yaml b/.github/workflows/build_and_deploy.yaml new file mode 100644 index 0000000..116e1dd --- /dev/null +++ b/.github/workflows/build_and_deploy.yaml @@ -0,0 +1,64 @@ +name: Build and Push Docker Image + +on: + push: + branches: + - main +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + outputs: + IMAGE_TAG: ${{ github.run_number }} + + steps: + - name: Check out code + uses: actions/checkout@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push Docker image + uses: docker/build-push-action@v3 + env: + IMAGE_TAG: ${{ github.run_number }} + with: + context: . + push: true + tags: minjuncho/blms-fe:${{ env.IMAGE_TAG }} + id: docker_build + + - name: Output the image tag + run: echo "IMAGE_TAG=${{ steps.docker_build.outputs.digest }}" >> $GITHUB_ENV + + deploy: + needs: build + runs-on: ubuntu-latest + steps: + - name: Check out infra-ops repository + uses: actions/checkout@v2 + with: + repository: "keiburu-Tai/infra-ops" + ssh-key: ${{ secrets.SSH_PRIVATE_KEY }} + fetch-depth: 0 + + - name: List directory contents + run: ls -R + + - name: Update Kubernetes Manifests + env: + IMAGE_TAG: ${{ github.run_number }} + run: | + sed -i 's|image:.*|image: minjuncho/blms-fe:${{ env.IMAGE_TAG }}|' service/blms-fe/blms-fe.yaml + + - name: commit and push + run: | + git config user.name github-actions + git config user.email github-actions@github.com + git commit -am "Deploying image ${{ env.IMAGE_TAG }}" + git push origin main diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dd128cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env + +*.mid +*.wav \ No newline at end of file diff --git a/.streamlit/config.toml b/.streamlit/config.toml new file mode 100644 index 0000000..ef393e3 --- /dev/null +++ b/.streamlit/config.toml @@ -0,0 +1,2 @@ +[server] +baseUrlPath = "blms" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e98e1e0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM python:3.9-slim + +WORKDIR /app + +COPY . . + +RUN apt-get update && apt-get install -y \ + build-essential \ + curl \ + software-properties-common \ + git \ + libasound2-dev \ + libsndfile1 \ + portaudio19-dev \ + && rm -rf /var/lib/apt/lists/* + +RUN pip install --upgrade pip +RUN pip install st-pages sounddevice soundfile streamlit streamlit_webrtc bokeh streamlit-bokeh-events + +EXPOSE 8501 + +ENTRYPOINT ["streamlit", "run", "streamlit.py", "--server.port=8501", "--server.address=0.0.0.0"] \ No newline at end of file diff --git a/__pycache__/main.cpython-311.pyc b/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000..4c779a7 Binary files /dev/null and b/__pycache__/main.cpython-311.pyc differ diff --git a/play.py b/play.py new file mode 100644 index 0000000..19c4c1d --- /dev/null +++ b/play.py @@ -0,0 +1,77 @@ +import streamlit as st +import pandas as pd +import numpy as np +from st_pages import Page, Section, show_pages, add_page_title +import time + +import sounddevice as sd +import soundfile as sf + + +st.title('''Playing Guitar!''') + +def list_devices(): + #print("Available audio devices:") + name_dict = {} + devices = sd.query_devices() + i = 0 + for index, device in enumerate(devices): + #print(index, device['name'], ", Core Audio (", device['max_input_channels'], "in,", device['max_output_channels'], "out)") + name_dict[device['name']] = i + i += 1 + #print(name_dict) + return name_dict + +def record_audio(device_index, duration=10, sample_rate=44100): + try: + device_info = sd.query_devices(device_index) + audio_data = sd.rec(int(duration * sample_rate), samplerate=sample_rate, channels=2, device=device_index, dtype='float32') + sd.wait() # Wait until recording is finished + # Save recorded data as a WAV file + output_file = 'recoded_sample/first.wav' + sf.write(output_file, audio_data, sample_rate) + except Exception as e: + print(f"An error occurred: {e}") + st.error(f'An error occurred: {e}') + + +with st.container(border=True): + try: + ele = list_devices() + input_option = st.selectbox( + "Please Select Input Device.", + (ele.keys())) + + output_option = st.selectbox( + "Please Select Output Device", + (ele.keys())) + + time_duration = st.slider("How long recode?", 0, 20, 10) + col1, col2 = st.columns([0.2, 1.4]) + with col1: + if st.button("Recode"): + st.session_state["Recode"] = True + with col2: + if st.button("Save"): + st.session_state["Save"] = True + if 'Recode' in st.session_state and st.session_state['Recode']: + st.write('1') + time.sleep(1) + st.write('2') + time.sleep(1) + st.write('3') + time.sleep(0.5) + st.write("ready") + time.sleep(0.5) + st.write('start!!!') + with st.spinner('recording...'): + + record_audio(ele.get(input_option), duration=time_duration, sample_rate=44100) + st.audio("recoded_sample/first.wav", format="audio/mpeg", loop=False) + st.session_state['Recode'] = False + if 'Save' in st.session_state and st.session_state['Save']: + st.write("Shot Auto Chord") + st.success('This is a success message!') + st.session_state['Save'] = False + except: + pass \ No newline at end of file diff --git a/recoded_sample/.DS_Store b/recoded_sample/.DS_Store new file mode 100644 index 0000000..8f581d1 Binary files /dev/null and b/recoded_sample/.DS_Store differ diff --git a/recoded_sample/recoded_sample/canon_chords.lab b/recoded_sample/recoded_sample/canon_chords.lab new file mode 100644 index 0000000..61d30c7 --- /dev/null +++ b/recoded_sample/recoded_sample/canon_chords.lab @@ -0,0 +1,8 @@ +0.0 1.4396371882086167 C:maj +1.4396371882086167 3.01859410430839 G:maj +3.01859410430839 4.551111111111111 A:min +4.551111111111111 5.944308390022676 E:maj +5.944308390022676 6.03718820861678 N +6.03718820861678 7.476825396825397 F:maj +7.476825396825397 8.962902494331066 G:maj +8.962902494331066 10.031020408163265 C:maj diff --git a/recoded_sample/recoded_sample/dont_lazy.lab b/recoded_sample/recoded_sample/dont_lazy.lab new file mode 100644 index 0000000..eeeb816 --- /dev/null +++ b/recoded_sample/recoded_sample/dont_lazy.lab @@ -0,0 +1,8 @@ +0.0 1.486077097505669 C:maj +1.486077097505669 2.9257142857142857 D:maj +2.9257142857142857 4.2260317460317465 B:min +4.2260317460317465 5.944308390022676 E:min +5.944308390022676 5.990748299319728 N +5.990748299319728 7.058866213151927 C:maj +7.058866213151927 8.40562358276644 D:maj +8.40562358276644 10.031020408163265 E:min diff --git a/recoded_sample/recoded_sample/honey_jet.lab b/recoded_sample/recoded_sample/honey_jet.lab new file mode 100644 index 0000000..d9c9c97 --- /dev/null +++ b/recoded_sample/recoded_sample/honey_jet.lab @@ -0,0 +1,9 @@ +0.0 1.4396371882086167 E:maj +1.4396371882086167 3.4829931972789114 Gb:maj +3.4829931972789114 4.96907029478458 Eb:min +4.96907029478458 5.944308390022676 Ab:min +5.944308390022676 6.269387755102041 N +6.269387755102041 7.801904761904762 Db:min +7.801904761904762 8.684263038548753 Eb:min +8.684263038548753 9.195102040816327 Gb:maj +9.195102040816327 10.031020408163265 E:maj diff --git a/recoded_sample/recoded_sample/honey_jet_pre_skip.lab b/recoded_sample/recoded_sample/honey_jet_pre_skip.lab new file mode 100644 index 0000000..8ff164c --- /dev/null +++ b/recoded_sample/recoded_sample/honey_jet_pre_skip.lab @@ -0,0 +1,9 @@ +0.0 0.18575963718820862 E:maj +0.18575963718820862 2.2291156462585033 Gb:maj +2.2291156462585033 3.1579138321995464 Eb:min +3.1579138321995464 4.08671201814059 N +4.08671201814059 4.96907029478458 Ab:min +4.96907029478458 5.944308390022676 Db:min +5.944308390022676 6.455147392290249 N +6.455147392290249 7.987664399092971 Eb:min +7.987664399092971 10.031020408163265 E:maj diff --git a/recoded_sample/recoded_sample/line.txt b/recoded_sample/recoded_sample/line.txt new file mode 100644 index 0000000..dce6a94 --- /dev/null +++ b/recoded_sample/recoded_sample/line.txt @@ -0,0 +1,11 @@ +허니제트 +E F# D#m G#m C#m D#m E + +dont lazy +C5 D5 B5 E5 D5 C5 D5 E5 + +canon +C G Em Am F G C + +solo +penta 3 C major \ No newline at end of file diff --git a/recoded_sample/recoded_sample/solo.lab b/recoded_sample/recoded_sample/solo.lab new file mode 100644 index 0000000..2e32d7a --- /dev/null +++ b/recoded_sample/recoded_sample/solo.lab @@ -0,0 +1 @@ +0.0 10.031020408163265 N diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8d89d1e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,106 @@ +aioice==0.9.0 +aiortc==1.8.0 +altair==5.3.0 +annotated-types==0.6.0 +anyio==4.3.0 +attrs==23.2.0 +audioread==3.0.1 +av==11.0.0 +beautifulsoup4==4.12.3 +blinker==1.8.1 +cachetools==5.3.3 +certifi==2024.2.2 +cffi==1.16.0 +charset-normalizer==3.3.2 +click==8.1.7 +cryptography==42.0.7 +decorator==5.1.1 +dnspython==2.6.1 +email_validator==2.1.1 +exceptiongroup==1.2.1 +fastapi==0.111.0 +fastapi-cli==0.0.3 +filelock==3.14.0 +gdown==5.2.0 +gitdb==4.0.11 +GitPython==3.1.43 +google-crc32c==1.5.0 +h11==0.14.0 +httpcore==1.0.5 +httptools==0.6.1 +httpx==0.27.0 +idna==3.7 +ifaddr==0.2.0 +Jinja2==3.1.4 +joblib==1.4.2 +jsonschema==4.22.0 +jsonschema-specifications==2023.12.1 +lazy_loader==0.4 +lazycats==0.1.0 +librosa==0.10.2 +llvmlite==0.42.0 +markdown-it-py==3.0.0 +MarkupSafe==2.1.5 +mdurl==0.1.2 +mido==1.3.2 +msgpack==1.0.8 +numba==0.59.1 +numpy==1.26.4 +orjson==3.10.3 +packaging==23.2 +pandas==2.2.2 +pillow==10.3.0 +platformdirs==4.2.1 +pooch==1.8.1 +protobuf==4.25.3 +pyarrow==16.0.0 +pycparser==2.22 +pydantic==2.7.1 +pydantic_core==2.18.2 +pydeck==0.9.0 +pyee==11.1.0 +pygame==2.5.2 +Pygments==2.18.0 +pylibsrtp==0.10.0 +pyOpenSSL==24.1.0 +PySocks==1.7.1 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +python-multipart==0.0.9 +python-rtmidi==1.5.8 +pytz==2024.1 +PyYAML==6.0.1 +referencing==0.35.1 +requests==2.31.0 +rich==13.7.1 +rpds-py==0.18.1 +scikit-learn==1.4.2 +scipy==1.13.0 +shellingham==1.5.4 +six==1.16.0 +smmap==5.0.1 +sniffio==1.3.1 +sounddevice==0.4.6 +soundfile==0.12.1 +soupsieve==2.5 +soxr==0.3.7 +st-pages==0.4.5 +starlette==0.37.2 +streamlit==1.34.0 +streamlit-webrtc==0.47.6 +tenacity==8.2.3 +threadpoolctl==3.5.0 +toml==0.10.2 +toolz==0.12.1 +tornado==6.4 +tqdm==4.66.4 +typer==0.12.3 +typing_extensions==4.11.0 +tzdata==2024.1 +ujson==5.10.0 +urllib3==2.2.1 +uvicorn==0.29.0 +uvloop==0.19.0 +vamp==1.1.0 +watchfiles==0.21.0 +websockets==12.0 diff --git a/session.py b/session.py new file mode 100644 index 0000000..67bfd25 --- /dev/null +++ b/session.py @@ -0,0 +1,127 @@ +import streamlit as st +import pandas as pd +import numpy as np +import time +import sounddevice as sd +import soundfile as sf +import pygame +from queue import Queue +from dotenv import load_dotenv +import os +import requests +from st_pages import Page, Section, show_pages, add_page_title + +load_dotenv() + +st.title('Playing Guitar!') + +# Initialize pygame for MIDI playback +pygame.mixer.init() +pygame.mixer.music.set_endevent(pygame.USEREVENT + 1) + +midi_queue = Queue() + +def list_devices(): + name_dict = {} + devices = sd.query_devices() + i = 0 + for index, device in enumerate(devices): + name_dict[device['name']] = i + i += 1 + return name_dict + +def record_audio(device_index, duration=10, sample_rate=44100): + try: + audio_data = sd.rec(int(duration * sample_rate), samplerate=sample_rate, channels=2, device=device_index, dtype='float32') + sd.wait() # Wait until recording is finished + output_file = 'recorded_sample/output.wav' + os.makedirs('recorded_sample', exist_ok=True) + sf.write(output_file, audio_data, sample_rate) + return output_file + except Exception as e: + st.error(f'An error occurred: {e}') + return None + +def stop_midi(): + pygame.mixer.music.stop() + with midi_queue.mutex: + midi_queue.queue.clear() + st.write("Stopped all MIDI playback and cleared the queue") + +def genrate_midi_and_play_queue(): + while not midi_queue.empty() or st.session_state.get("Start", False): + if midi_queue.empty(): + time.sleep(1) + continue + midi_file = midi_queue.get() + pygame.mixer.music.load(midi_file) + pygame.mixer.music.play() + recorded_file = record_audio(input_device_index, duration=10, sample_rate=44100) + if recorded_file: + url = os.getenv('URL') # Replace with your server URL + with open(recorded_file, 'rb') as f: + files = {'file': f} + response = requests.post(url, files=files) + if response.status_code == 200: + with open("output.mid", 'wb') as mid_file: + mid_file.write(response.content) + midi_queue.put("output.mid") + else: + st.error('Failed to upload file to the server') + + while pygame.mixer.music.get_busy(): + print("busy") + pygame.time.wait(100) + +# Register the event handler for the end of midi playback +pygame.mixer.music.set_endevent(pygame.USEREVENT + 1) + + +with st.container(): + try: + ele = list_devices() + input_option = st.selectbox( + "Please Select Input Device.", + (ele.keys())) + + output_option = st.selectbox( + "Please Select Output Device", + (ele.keys())) + + input_device_index = ele.get(input_option) + output_device_index = ele.get(output_option) + + # Load the initial MIDI file into the queue + midi_path = 'first.mid' # Ensure 'first.mid' exists in the working directory + midi_queue.put(midi_path) + + col1, col2 = st.columns([0.2, 1.4]) + with col1: + if st.button("Start"): + st.session_state["Start"] = True + st.session_state["Stop"] = False + with st.spinner("initial setting..."): + url = os.getenv('URL') # Replace with your server URL + with open("recoded_sample/first.wav", 'rb') as f: + files = {'file': f} + response = requests.post(url, files=files) + if response.status_code == 200: + with open("first.mid", 'wb') as mid_file: + mid_file.write(response.content) + genrate_midi_and_play_queue() + + with col2: + if st.button("Stop"): + st.session_state["Stop"] = True + st.session_state["Start"] = False + stop_midi() + + # Event handling loop + while st.session_state.get("Start", False): + for event in pygame.event.get(): + if event.type == pygame.USEREVENT + 1: + genrate_midi_and_play_queue() + time.sleep(0.1) # To prevent busy waiting + + except Exception as e: + st.error(f"An error occurred: {e}") diff --git a/streamlit.py b/streamlit.py new file mode 100644 index 0000000..cefe967 --- /dev/null +++ b/streamlit.py @@ -0,0 +1,20 @@ +import streamlit as st +import pandas as pd +import numpy as np +from st_pages import Page, Section, show_pages, add_page_title + +#side bar part refer https://github.com/blackary/st_pages +# add_page_title() + +st.title('''BLMS''') + + +# Display the image, which should be centered with the CSS above +show_pages( + [ + Page("streamlit.py", "Main Introduce", "💡"), + Page("play.py", "Ready for Playing!", "🎸"), + Page("session.py", "Session", "🎸"), + # Unless you explicitly say in_section=False + ] +) \ No newline at end of file