CM_DOG/Utils/music.py

65 lines
2.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)