File size: 5,705 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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#%%
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
from src.st_helper import convert_df, show_readme, get_shift
from src.timbre_analysis import (
    spectral_centroid_analysis,
    rolloff_frequency_analysis,
    spectral_bandwidth_analysis,
    harmonic_percussive_source_separation
)

st.title("Timbre Analysis")
#%% 頁面說明
# show_readme("docs/6-Timbre Analysis.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(["Spectral Centroid", "Rolloff Frequency", "Spectral Bandwidth", "Harmonic Percussive Source Separation"])

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

    # spectral_centroid_analysis
    with tab1:
        st.subheader("Spectral Centroid Analysis")
        fig6_1, ax6_1, centroid_value = spectral_centroid_analysis(y_sub, sr, shift_array)
        st.pyplot(fig6_1)
        
        df_centroid = pd.DataFrame(centroid_value.T, columns=["Time(s)", "Centroid"])
        df_centroid["Time(s)"] = df_centroid["Time(s)"] + shift_time
        st.dataframe(df_centroid, use_container_width=True)
        st.download_button(
            label="Download spectral centroid data",
            data=convert_df(df_centroid),
            file_name="centroid.csv",
            mime="text/csv",
        )

    # rolloff_frequency_analysis
    with tab2:
        st.subheader("Rolloff Frequency Analysis")
        roll_percent = st.selectbox("Select rolloff frequency", [0.90, 0.95, 0.99])
        fig6_2, ax6_2, rolloff_value = rolloff_frequency_analysis(y_sub, sr, roll_percent=roll_percent, shift_array=shift_array)
        st.pyplot(fig6_2)
        df_rolloff = pd.DataFrame(rolloff_value.T, columns=["Time(s)", "Rolloff", "Rolloff_min"])
        df_rolloff["Time(s)"] = df_rolloff["Time(s)"] + shift_time
        st.dataframe(df_rolloff, use_container_width=True)
        st.download_button(
            label="Download rolloff frequency data",
            data=convert_df(df_rolloff),
            file_name="rolloff.csv",
            mime="text/csv",
        )

    # spectral_bandwidth_analysis
    with tab3:
        st.subheader("Spectral Bandwidth Analysis")
        fig6_3, ax6_3, bandwidth_value = spectral_bandwidth_analysis(y_sub, sr, shift_array)
        st.pyplot(fig6_3)
        df_bandwidth = pd.DataFrame(bandwidth_value.T, columns=["Time(s)", "Bandwidth"])
        df_bandwidth["Time(s)"] = df_bandwidth["Time(s)"] + shift_time
        st.dataframe(df_bandwidth, use_container_width=True)
        st.download_button(
            label="Download spectral bandwidth data",
            data=convert_df(df_bandwidth),
            file_name="bandwidth.csv",
            mime="text/csv",
        )

    # harmonic_percussive_source_separation
    with tab4:
        st.subheader("Harmonic Percussive Source Separation")
        fig6_4, ax6_4, (Harmonic_data) = harmonic_percussive_source_separation(y_sub, sr, shift_array)
        D, H, P, t = Harmonic_data
        st.pyplot(fig6_4)

        st.download_button(
            label="Download Full power spectrogram data",
            data=convert_df(pd.DataFrame(D)),
            file_name="Full_power_spectrogram.csv",
            use_container_width=True,
        )
        st.download_button(
            label="Download Harmonic power spectrogram data",
            data=convert_df(pd.DataFrame(H)),
            file_name="Harmonic_power_spectrogram.csv",
            use_container_width=True,
        )
        st.download_button(
            label="Download Percussive power spectrogram data",
            data=convert_df(pd.DataFrame(P)),
            file_name="Percussive_power_spectrogram.csv",
            use_container_width=True,
        )
        st.download_button(
            label="Download Time data",
            data=convert_df(pd.DataFrame(t+shift_time, columns=["Time(s)"])),
            file_name="Time_scale.csv",
            use_container_width=True,
        )