OpenAI生成的TXT转MIDI代码报错:mido无note_to_midi属性
修复Mido库AttributeError: 'module' has no attribute 'note_to_midi'问题
问题说明
运行Python代码将乐谱TXT转MIDI时触发AttributeError,提示module 'mido' has no attribute 'note_to_midi',重装openai库无效,在WSL2 Ubuntu 22.04 LTS和Windows 10 VS Code环境均复现该问题。
错误根源
note_to_midi并非mido主模块的方法,该函数属于mido.midifiles.meta子模块;- 重装openai库的操作无效,因为问题和openai无关,是mido库的使用方式错误。
修复方案
提供两种可行的修复方式:
方式一:使用mido内置的meta模块函数
修改导入语句引入note_to_midi,同时修复乐器设置的无效写法:
import mido from mido.midifiles.meta import note_to_midi # Function to convert a music chart string into a MIDI track def chart_to_track(chart, instrument): # Split the chart into a list of measures measures = chart.strip().split("|") # Initialize an empty list to store the MIDI events events = [] # Set the current time to zero time = 0 # Iterate through the measures for measure in measures: # Split the measure into a list of notes notes = measure.strip().split() # Iterate through the notes for note in notes: # Convert the note name to a MIDI pitch pitch = note_to_midi(note) # Add a NOTE_ON event to the events list events.append(mido.Message('note_on', note=pitch, velocity=127, time=time)) # Add a NOTE_OFF event to the events list after a quarter note duration events.append(mido.Message('note_off', note=pitch, velocity=127, time=480)) # Increase the current time by a quarter note duration time += 480 # Create a MIDI track with the events and the specified instrument track = mido.MidiTrack() # 修复:添加program_change消息设置乐器,原track.program写法无效 track.append(mido.Message('program_change', program=instrument)) track.extend(events) return track # Function to prompt the user to choose an instrument def choose_instrument(): # Print a list of instrument options print("Choose an instrument:") print("1. Acoustic Grand Piano") print("2. Electric Guitar (clean)") print("3. Violin") print("4. Trumpet") print("5. Clarinet") # Prompt the user to enter a number choice = input("Enter the number of your choice: ") # Return the corresponding instrument number if choice == "1": return 0 elif choice == "2": return 25 elif choice == "3": return 40 elif choice == "4": return 57 elif choice == "5": return 71 else: print("Invalid choice. Please try again.") return choose_instrument() # Main function def main(): # Prompt the user to enter the name of the text file filename = input("Enter the name of the text file: ") # Open the file and read the contents into a string with open(filename, "r") as f: chart = f.read() # Choose an instrument instrument = choose_instrument() # Convert the chart to a MIDI track track = chart_to_track(chart, instrument) # Create a MIDI file and add the track midi = mido.MidiFile() midi.tracks.append(track) # Prompt the user to enter the name of the MIDI file output_filename = input("Enter the name of the MIDI file: ") # Save the MIDI file midi.save(output_filename) # Run the main function main()
方式二:自定义音符转换函数
如果不想依赖mido子模块,可自己实现音符到MIDI音高的映射:
添加以下自定义函数到代码中:
def note_to_midi(note): note_map = { 'C0': 12, 'C#0':13, 'Db0':13, 'D0':14, 'D#0':15, 'Eb0':15, 'E0':16, 'F0':17, 'F#0':18, 'Gb0':18, 'G0':19, 'G#0':20, 'Ab0':20, 'A0':21, 'A#0':22, 'Bb0':22, 'B0':23, 'C1':24, 'C#1':25, 'Db1':25, 'D1':26, 'D#1':27, 'Eb1':27, 'E1':28, 'F1':29, 'F#1':30, 'Gb1':30, 'G1':31, 'G#1':32, 'Ab1':32, 'A1':33, 'A#1':34, 'Bb1':34, 'B1':35, 'C2':36, 'C#2':37, 'Db2':37, 'D2':38, 'D#2':39, 'Eb2':39, 'E2':40, 'F2':41, 'F#2':42, 'Gb2':42, 'G2':43, 'G#2':44, 'Ab2':44, 'A2':45, 'A#2':46, 'Bb2':46, 'B2':47, 'C3':48, 'C#3':49, 'Db3':49, 'D3':50, 'D#3':51, 'Eb3':51, 'E3':52, 'F3':53, 'F#3':54, 'Gb3':54, 'G3':55, 'G#3':56, 'Ab3':56, 'A3':57, 'A#3':58, 'Bb3':58, 'B3':59, 'C4':60, 'C#4':61, 'Db4':61, 'D4':62, 'D#4':63, 'Eb4':63, 'E4':64, 'F4':65, 'F#4':66, 'Gb4':66, 'G4':67, 'G#4':68, 'Ab4':68, 'A4':69, 'A#4':70, 'Bb4':70, 'B4':71, 'C5':72, 'C#5':73, 'Db5':73, 'D5':74, 'D#5':75, 'Eb5':75, 'E5':76, 'F5':77, 'F#5':78, 'Gb5':78, 'G5':79, 'G#5':80, 'Ab5':80, 'A5':81, 'A#5':82, 'Bb5':82, 'B5':83, 'C6':84, 'C#6':85, 'Db6':85, 'D6':86, 'D#6':87, 'Eb6':87, 'E6':88, 'F6':89, 'F#6':90, 'Gb6':90, 'G6':91, 'G#6':92, 'Ab6':92, 'A6':93, 'A#6':94, 'Bb6':94, 'B6':95, 'C7':96, 'C#7':97, 'Db7':97, 'D7':98, 'D#7':99, 'Eb7':99, 'E7':100, 'F7':101, 'F#7':102, 'Gb7':102, 'G7':103, 'G#7':104, 'Ab7':104, 'A7':105, 'A#7':106, 'Bb7':106, 'B7':107, 'C8':108, 'C#8':109, 'Db8':109, 'D8':110, 'D#8':111, 'Eb8':111, 'E8':112, 'F8':113, 'F#8':114, 'Gb8':114, 'G8':115, 'G#8':116, 'Ab8':116, 'A8':117, 'A#8':118, 'Bb8':118, 'B8':119 } return note_map.get(note, 60) # 默认返回中央C(C4)
然后删除原代码中mido.note_to_midi相关的导入和调用,替换为这个自定义函数即可。
内容的提问来源于stack exchange,提问作者Najib
相关产品推荐
相关产品推荐

