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)