music-analysis / src /timbre_analysis.py
Keycatowo
init trans commit
bb5feba
import librosa
from librosa import display
from librosa import feature
import numpy as np
from numpy import typing as npt
from matplotlib import pyplot as plt
import scipy
def spectral_centroid_analysis(y: npt.ArrayLike, sr: int, shift_array: npt.ArrayLike) -> None :
S, phase = librosa.magphase(librosa.stft(y=y))
cent = librosa.feature.spectral_centroid(S=S)
times = librosa.times_like(cent, sr)
fig, ax = plt.subplots()
librosa.display.specshow(librosa.amplitude_to_db(S, ref=np.max),
y_axis='log', x_axis='time', ax=ax, sr=sr)
ax.plot(times, cent.T, label='Spectral centroid', color='w')
ax.legend(loc='upper right')
ax.set(title='log Power spectrogram')
ax.set_xticks(shift_array - shift_array[0],
shift_array)
ax.autoscale()
result = np.vstack((times, cent))
return fig, ax, result
def rolloff_frequency_analysis(y: npt.ArrayLike, sr: int, roll_percent:float = 0.99,
shift_array: npt.ArrayLike =None) -> None :
rolloff = librosa.feature.spectral_rolloff(y=y, sr=sr, roll_percent=roll_percent)
rolloff_min = librosa.feature.spectral_rolloff(y=y, sr=sr, roll_percent=0.01)
times = librosa.times_like(rolloff, sr)
S, phase = librosa.magphase(librosa.stft(y))
fig, ax = plt.subplots()
librosa.display.specshow(librosa.amplitude_to_db(S, ref=np.max),
y_axis='log', x_axis='time', ax=ax, sr=sr)
ax.plot(librosa.times_like(rolloff,sr), rolloff[0], label=f'Roll-off frequency ({roll_percent})')
ax.plot(librosa.times_like(rolloff,sr), rolloff_min[0], color='w',
label='Roll-off frequency (0.01)')
ax.legend(loc='lower right')
ax.set(title='log Power spectrogram')
ax.set_xticks(shift_array - shift_array[0],
shift_array)
ax.autoscale()
result = np.vstack((times, rolloff, rolloff_min))
return fig, ax, result
def spectral_bandwidth_analysis(y: npt.ArrayLike, sr: int, shift_array: npt.ArrayLike =None) -> None :
S, phase = librosa.magphase(librosa.stft(y=y))
spec_bw = librosa.feature.spectral_bandwidth(S=S)
times = librosa.times_like(spec_bw, sr)
fig, ax = plt.subplots(nrows=2, sharex=True)
centroid = librosa.feature.spectral_centroid(S=S, sr=sr)
ax[0].semilogy(times, spec_bw[0], label='Spectral bandwidth')
ax[0].set(ylabel='Hz', xticks=[], xlim=[times.min(), times.max()])
ax[0].legend()
ax[0].label_outer()
librosa.display.specshow(librosa.amplitude_to_db(S, ref=np.max),
y_axis='log', x_axis='time', ax=ax[1], sr=sr)
ax[1].set(title='log Power spectrogram')
ax[1].fill_between(times, np.maximum(0, centroid[0] - spec_bw[0]),
np.minimum(centroid[0] + spec_bw[0], sr/2),
alpha=0.5, label='Centroid +- bandwidth')
ax[1].plot(times, centroid[0], label='Spectral centroid', color='w')
ax[1].legend(loc='lower right')
ax[1].set_xticks(shift_array - shift_array[0],
shift_array)
ax[1].autoscale()
result = np.vstack((times, spec_bw))
return fig, ax, result
def harmonic_percussive_source_separation(y: npt.ArrayLike, sr: int,
shift_array: npt.ArrayLike =None
) -> None :
D = librosa.stft(y)
H, P = librosa.decompose.hpss(D)
t = librosa.frames_to_time(np.arange(D.shape[1]), sr=sr)
fig, ax = plt.subplots(nrows=3, sharex=False, sharey=False, figsize=(12, 8))
# 設置子圖之間的水平間距和垂直間距
plt.subplots_adjust(hspace=0.6, wspace=0.3)
img = librosa.display.specshow(librosa.amplitude_to_db(np.abs(D),ref=np.max),
y_axis='log', x_axis='time', ax=ax[0], sr=sr)
ax[0].set(title='Full power spectrogram')
#// ax[0].label_outer()
ax[0].set_xlabel('') # 不顯示x軸名稱
ax[0].set_xticks(shift_array - shift_array[0],
shift_array)
ax[0].autoscale()
librosa.display.specshow(librosa.amplitude_to_db(np.abs(H), ref=np.max(np.abs(D))),
y_axis='log', x_axis='time', ax=ax[1], sr=sr)
ax[1].set(title='Harmonic power spectrogram')
#// ax[1].label_outer()
ax[1].set_xlabel('') # 不顯示x軸名稱
ax[1].set_xticks(shift_array - shift_array[0],
shift_array)
ax[1].autoscale()
librosa.display.specshow(librosa.amplitude_to_db(np.abs(P), ref=np.max(np.abs(D))),
y_axis='log', x_axis='time', ax=ax[2], sr=sr)
ax[2].set(title='Percussive power spectrogram')
ax[2].set_xticks(shift_array - shift_array[0],
shift_array)
ax[2].autoscale()
fig.colorbar(img, ax=ax, format='%+2.0f dB')
return fig, ax, (D, H, P, t)