使用mido拆分Lakh MIDI数据集时遇OSError: undefined status byte 0xf9错误
使用mido拆分Lakh/Clean MIDI子集时遇到OSError: undefined status byte 0xf9错误
错误信息
OSError: undefined status byte 0xf9
删除疑似有问题的MIDI文件后错误仍出现,无法确定是MIDI文件本身还是Python脚本导致问题。以下是运行的完整脚本:
from mido import Message, MidiFile, MidiTrack import os root_dir = r"C:\Users\admin\Desktop\clean_midi" mid = MidiFile(r"C:\Users\admin\Desktop\clean_midi\.38 Special\Caught Up In You.mid") musicain_dirs = os.listdir(root_dir) for dir in musicain_dirs: musicain_dir = os.path.join(root_dir, dir) if not os.path.exists(dir): os.makedirs(dir) musics = os.listdir(musicain_dir) for music in musics: src_mid = MidiFile(os.path.join(musicain_dir, music)) tar_dir = os.path.join(dir, music) if not os.path.exists(tar_dir): os.makedirs(tar_dir) for track in src_mid.tracks: if len(track) > 5: tar_mid = MidiFile() tar_mid.tracks.append(track) tar_name = os.path.join(tar_dir, track.name.replace("/"," ") + "_" + music) if not os.path.exists(tar_name): tar_mid.save(tar_name) print(music)
对SPEC_BY_STATUS和specs.py完全不了解,找不到相关信息。
解决方案
1. 让mido忽略未知MIDI消息
错误中的0xf9是MIDI定时时钟消息,mido默认不处理这类消息。加载MIDI文件时添加ignore_unknown=True参数,即可跳过无法识别的状态字节:
src_mid = MidiFile(os.path.join(musicain_dir, music), ignore_unknown=True)
2. 修复脚本路径问题
原脚本创建目标目录时使用相对路径,会导致文件夹位置混乱,改为绝对路径:
- 替换原代码中创建艺术家目录的逻辑:
# 原代码 # if not os.path.exists(dir): # os.makedirs(dir) # 修改为 artist_target_dir = os.path.join(root_dir, f"{dir}_split") if not os.path.exists(artist_target_dir): os.makedirs(artist_target_dir) - 替换目标轨道目录的逻辑:
# 原代码 # tar_dir = os.path.join(dir, music) # 修改为 tar_dir = os.path.join(artist_target_dir, music.replace('.mid', ''))
3. 优化轨道过滤逻辑
除了按长度过滤,还可以过滤掉仅包含无效消息的轨道:
for track in src_mid.tracks: # 过滤掉短轨道和无有效消息的轨道 valid_messages = [msg for msg in track if hasattr(msg, 'type')] if len(valid_messages) > 5: tar_mid = MidiFile() tar_mid.tracks.append(track) tar_name = os.path.join(tar_dir, track.name.replace("/"," ") + "_" + music) tar_mid.save(tar_name)
修改后的完整脚本
from mido import Message, MidiFile, MidiTrack import os root_dir = r"C:\Users\admin\Desktop\clean_midi" musicain_dirs = os.listdir(root_dir) for dir in musicain_dirs: musicain_dir = os.path.join(root_dir, dir) # 创建艺术家拆分后的目录 artist_target_dir = os.path.join(root_dir, f"{dir}_split") if not os.path.exists(artist_target_dir): os.makedirs(artist_target_dir) if not os.path.isdir(musicain_dir): continue # 跳过非目录文件 musics = os.listdir(musicain_dir) for music in musics: music_path = os.path.join(musicain_dir, music) if not music.endswith('.mid'): continue # 跳过非MIDI文件 # 加载MIDI时忽略未知消息 src_mid = MidiFile(music_path, ignore_unknown=True) # 创建单首歌的轨道目录 tar_dir = os.path.join(artist_target_dir, music.replace('.mid', '')) if not os.path.exists(tar_dir): os.makedirs(tar_dir) for track in src_mid.tracks: # 过滤有效轨道 valid_messages = [msg for msg in track if hasattr(msg, 'type')] if len(valid_messages) > 5: tar_mid = MidiFile() tar_mid.tracks.append(track) # 处理轨道名中的非法字符 safe_track_name = track.name.replace("/"," ").replace("\\"," ").replace(":"," ").replace("*"," ").replace("?"," ").replace('"'," ").replace("<"," ").replace(">"," ").replace("|"," ") tar_name = os.path.join(tar_dir, f"{safe_track_name}_{music}") tar_mid.save(tar_name) print(f"{dir} 处理完成")
内容的提问来源于stack exchange,提问作者jasper song
相关产品推荐
相关产品推荐

