music-analysis / pages /4-Chord_recognition.py
Keycatowo
init trans commit
bb5feba
#%%
import streamlit as st
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.pyplot as plt
import numpy as np
import librosa
import pandas as pd
import seaborn as sns
from src.st_helper import convert_df, show_readme, get_shift
from src.chord_recognition import (
plot_chord_recognition,
plot_binary_template_chord_recognition,
chord_table,
compute_chromagram,
chord_recognition_template,
plot_chord,
plot_user_chord
)
st.title("Chord Recognition")
#%% 頁面說明
# show_readme("docs/1-Basic Information.md")
#%% 上傳檔案區塊
with st.expander("上傳檔案(Upload Files)"):
file = st.file_uploader("Upload your music library", type=["mp3", "wav", "ogg"])
if file is not None:
st.audio(file, format="audio/ogg")
st.subheader("File information")
st.write(f"File name: `{file.name}`", )
st.write(f"File type: `{file.type}`")
st.write(f"File size: `{file.size}`")
# 載入音檔
y, sr = librosa.load(file, sr=44100)
st.write(f"Sample rate: `{sr}`")
duration = float(np.round(len(y)/sr-0.005, 2)) # 時間長度,取小數點後2位,向下取整避免超過音檔長度
st.write(f"Duration(s): `{duration}`")
y_all = y
#%%
if file is not None:
### Start of 選擇聲音片段 ###
with st.expander("選擇聲音片段(Select a segment of the audio)"):
# 建立一個滑桿,可以選擇聲音片段,使用時間長度為單位
start_time, end_time = st.slider("Select a segment of the audio",
0.0, duration,
(st.session_state.start_time, duration),
0.01
)
st.session_state.start_time = start_time
st.write(f"Selected segment: `{start_time}` ~ `{end_time}`, duration: `{end_time-start_time}`")
# 根據選擇的聲音片段,取出聲音資料
start_index = int(start_time*sr)
end_index = int(end_time*sr)
y_sub = y_all[start_index:end_index]
# 建立一個y_sub的播放器
st.audio(y_sub, format="audio/ogg", sample_rate=sr)
# 計算y_sub所對應時間的x軸
x_sub = np.arange(len(y_sub))/sr
### End of 選擇聲音片段 ###
tab1, tab2, tab3, tab4 = st.tabs(["STFT Chroma", "Chords Result (Default)", "Chords Result (User)", "dev"])
shift_time, shift_array = get_shift(start_time, end_time) # shift_array為y_sub的時間刻度
# STFT Chroma
with tab1:
chroma, _, _, _, duration = compute_chromagram(y_sub, sr)
fig4_1, ax4_1 = plot_chord(chroma, "STFT Chroma")
st.pyplot(fig4_1)
with tab2:
_, chord_max = chord_recognition_template(chroma, norm_sim='max')
fig4_2, ax4_2 = plot_chord(chord_max, "Chord Recognition Result", cmap="crest", include_minor=True)
st.pyplot(fig4_2)
with tab3:
# 建立chord result dataframe
sec_per_frame = duration/chroma.shape[1]
chord_results_df = pd.DataFrame({
"Frame": np.arange(chroma.shape[1]),
"Time(s)": np.arange(chroma.shape[1])*sec_per_frame + shift_time,
"Chord": chord_table(chord_max)
})
fig4_1b, ax4_1b = plot_user_chord(chord_results_df)
st.pyplot(fig4_1b)
chord_results_df = st.experimental_data_editor(
chord_results_df,
use_container_width=True
)
# plot_binary_template_chord_recognition
with tab4:
st.subheader("plot_binary_template_chord_recognition")
fig4_4, ax4_4 = plot_binary_template_chord_recognition(y_sub, sr)
st.pyplot(fig4_4)