import librosa
import numpy as np
import matplotlib.pyplot as plt
import librosa.display
# 音階名を取得する関数
def freq_to_note(freq):
if freq == 0:
return "N/A"
A4 = 440.0
C0 = A4 * np.power(2, -4.75)
h = round(12 * np.log2(freq / C0))
octave = h // 12
n = h % 12
note_names = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
return note_names[n] + str(octave)
# WAVファイルのパス
file_path = '/Users/haru/Downloads/|かえるの合唱|アカペラ|歌ってみた|人気童謡|童謡|こどもの歌|.wav'
# WAVファイルを読み込む
y, sr = librosa.load(file_path)
# 短時間フーリエ変換 (STFT)
D = librosa.stft(y)
# 振幅スペクトログラム
S_db = librosa.amplitude_to_db(np.abs(D), ref=np.max)
# 時間軸
times = librosa.times_like(S_db, sr=sr)
# 周波数軸
frequencies = librosa.fft_frequencies(sr=sr)
# dB値の閾値
db_threshold = -1000
# 周波数成分の抽出
peak_frequencies = []
peak_times = []
peak_db = []
for i, time in enumerate(times):
magnitude_spectrum = np.abs(D[:, i])
db_spectrum = S_db[:, i]
if np.max(db_spectrum) > db_threshold:
peak_index = np.argmax(db_spectrum)
if db_spectrum[peak_index] > db_threshold:
peak_frequency = frequencies[peak_index]
peak_db_value = db_spectrum[peak_index]
peak_frequencies.append(peak_frequency)
peak_times.append(time)
peak_db.append(peak_db_value)
note = freq_to_note(peak_frequency)
print(f"Time: {time:.2f}s, Frequency: {peak_frequency:.2f} Hz, dB: {peak_db_value:.2f}, Note: {note}")
# 線で繋いでプロット
plt.figure(figsize=(12, 6))
plt.plot(peak_times, peak_frequencies, color='b', marker='o', linestyle='-', label='Peak Frequency')
plt.xlabel('Time (s)')
plt.ylabel('Frequency (Hz)')
plt.title('Peak Frequency over Time')
plt.grid(True)
plt.legend()
plt.show()
# スペクトログラムをプロット
plt.figure(figsize=(12, 8))
# -30dB以下の部分をNaNにしてプロット
S_db[S_db < db_threshold] = np.nan
librosa.display.specshow(S_db, sr=sr, x_axis='time', y_axis='log', cmap='coolwarm')
plt.colorbar(format='%+2.0f dB')
plt.title('Spectrogram (Filtered, dB > -30)')
plt.xlabel('Time (s)')
plt.ylabel('Frequency (Hz)')
plt.show()
Posted inプログラミング