File size: 4,589 Bytes
bb5feba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#%%
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.pitch_estimation import plot_mel_spectrogram, plot_constant_q_transform, pitch_class_type_one_vis, pitch_class_histogram_chroma


st.title("Pitch estimation")
#%% 頁面說明
# show_readme("docs/2-Pitch_estimation.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(["Mel-frequency spectrogram", "Constant-Q transform", "Chroma", "Pitch class"])

    shift_time, shift_array = get_shift(start_time, end_time) # shift_array為y_sub的時間刻度

    # Mel-frequency spectrogram
    with tab1:
        st.subheader("Mel-frequency spectrogram")
        with_pitch = st.checkbox("Show pitch", value=True)
        fig2_1, ax2_1 = plot_mel_spectrogram(y_sub, sr, shift_array, with_pitch)
        st.pyplot(fig2_1)

    # Constant-Q transform
    with tab2:
        st.subheader("Constant-Q transform")
        fig2_2, ax2_2 = plot_constant_q_transform(y_sub, sr, shift_array)
        st.pyplot(fig2_2)
    
    # chroma
    with tab3:
        st.subheader("Chroma")
        
        chroma = librosa.feature.chroma_stft(y=y_sub, sr=sr)
        chroma_t = librosa.times_like(chroma, sr)
        df_chroma = pd.DataFrame(chroma)
        df_chroma_t = pd.DataFrame({"Time(s)": chroma_t})
        df_chroma_t["Time(frame)"] = list(range(len(chroma_t)))
        df_chroma_t["Time(s)"] = df_chroma_t["Time(s)"] + shift_time
        df_chroma_t = df_chroma_t[["Time(frame)", "Time(s)"]]
        
        fig2_3, ax2_3 = plt.subplots(figsize=(10, 4))
        sns.heatmap(chroma, ax=ax2_3)
        ax2_3.set_title("Chroma")
        ax2_3.set_xlabel("Time(frame)")
        ax2_3.invert_yaxis()
        st.pyplot(fig2_3)
        
        st.write("Chroma value")
        st.dataframe(df_chroma, use_container_width=True)
        st.download_button(
            label="Download chroma",
            data=convert_df(df_chroma),
            file_name="chroma_value.csv",
        )
        st.write("Chroma time")
        st.dataframe(df_chroma_t, use_container_width=True)
        st.download_button(
            label="Download chroma time",
            data=convert_df(df_chroma_t),
            file_name="chroma_time.csv",
        )

    # Pitch class type one
    with tab4:
        st.subheader("Pitch class(chroma)")
        high_res = st.checkbox("High resolution", value=False)
        fig2_4, ax2_4, df_pitch_class = pitch_class_histogram_chroma(y_sub, sr, high_res)
        st.pyplot(fig2_4)
        st.write(df_pitch_class)
        st.download_button(
            label="Download pitch class(chroma)",
            data=convert_df(pd.DataFrame(df_pitch_class)),
            file_name="Pitch_class(chroma).csv",
            mime="text/csv",
        )