65 lines
2.8 KiB
Python
65 lines
2.8 KiB
Python
from pydub import AudioSegment
|
||
import numpy as np
|
||
import os
|
||
import librosa
|
||
|
||
# 音符频率表(与buzzer.h一致)
|
||
NOTE_FREQS = [
|
||
261, 294, 329, 349, 392, 440, 494, 523, 587, 659, 698, 784, 880, 988, 1047, 1175, 1319, 1397, 1568, 1760, 1976, 2093, 2349, 2637, 2794, 3136, 3520, 3951, 4186
|
||
]
|
||
NOTE_NAMES = [
|
||
"BSP_BUZZER_NOTE_C4", "BSP_BUZZER_NOTE_D4", "BSP_BUZZER_NOTE_E4", "BSP_BUZZER_NOTE_F4", "BSP_BUZZER_NOTE_G4", "BSP_BUZZER_NOTE_A4", "BSP_BUZZER_NOTE_B4",
|
||
"BSP_BUZZER_NOTE_C5", "BSP_BUZZER_NOTE_D5", "BSP_BUZZER_NOTE_E5", "BSP_BUZZER_NOTE_F5", "BSP_BUZZER_NOTE_G5", "BSP_BUZZER_NOTE_A5", "BSP_BUZZER_NOTE_B5",
|
||
"BSP_BUZZER_NOTE_C6", "BSP_BUZZER_NOTE_D6", "BSP_BUZZER_NOTE_E6", "BSP_BUZZER_NOTE_F6", "BSP_BUZZER_NOTE_G6", "BSP_BUZZER_NOTE_A6", "BSP_BUZZER_NOTE_B6",
|
||
"BSP_BUZZER_NOTE_C7", "BSP_BUZZER_NOTE_D7", "BSP_BUZZER_NOTE_E7", "BSP_BUZZER_NOTE_F7", "BSP_BUZZER_NOTE_G7", "BSP_BUZZER_NOTE_A7", "BSP_BUZZER_NOTE_B7",
|
||
"BSP_BUZZER_NOTE_C8"
|
||
]
|
||
|
||
def freq_to_note_name(freq):
|
||
# 找到最接近的音符
|
||
idx = np.argmin(np.abs(np.array(NOTE_FREQS) - freq))
|
||
return NOTE_NAMES[idx], NOTE_FREQS[idx]
|
||
|
||
def mp3_to_note_array(mp3_path, c_array_name="music_notes", out_path=None, interval_sec=0.02):
|
||
y, sr = librosa.load(mp3_path, sr=None, mono=True)
|
||
hop_length = int(sr * interval_sec)
|
||
pitches, magnitudes = librosa.piptrack(y=y, sr=sr, hop_length=hop_length)
|
||
notes = []
|
||
durations = []
|
||
last_note = None
|
||
for t in range(pitches.shape[1]):
|
||
index = magnitudes[:, t].argmax()
|
||
freq = pitches[index, t]
|
||
if freq > 0:
|
||
note_name, note_freq = freq_to_note_name(freq)
|
||
else:
|
||
note_name = "0"
|
||
if note_name == last_note and notes:
|
||
durations[-1] += interval_sec
|
||
else:
|
||
notes.append(note_name)
|
||
durations.append(interval_sec)
|
||
last_note = note_name
|
||
|
||
# 生成C数组字符串
|
||
notes_str = ", ".join(notes)
|
||
durations_str = ", ".join([f"{d:.2f}f" for d in durations])
|
||
c_code = f"// 自动生成的音符数组,每{interval_sec}秒检测一次主旋律\n"
|
||
c_code += f"const BSP_Buzzer_Note_t {c_array_name}[] = {{ {notes_str} }};\n"
|
||
c_code += f"const float {c_array_name}_durations[] = {{ {durations_str} }};\n"
|
||
c_code += f"const unsigned int {c_array_name}_len = {len(notes)};\n"
|
||
|
||
# 自动生成输出路径
|
||
if out_path is None:
|
||
base, _ = os.path.splitext(mp3_path)
|
||
out_path = base + ".c"
|
||
|
||
# 写入C文件
|
||
with open(out_path, "w") as f:
|
||
f.write(c_code)
|
||
print(f"音符数组已写入: {out_path}")
|
||
|
||
if __name__ == "__main__":
|
||
mp3_path = "/Users/lvzucheng/Documents/R/CM_DOG/Utils/222.mp3" # 你的mp3文件路径
|
||
c_array_name = "music_notes" # C数组名
|
||
mp3_to_note_array(mp3_path, c_array_name, interval_sec=0.2) |