如何从MIDI转储的JSON中提取信息并存入Python numpy数组?
处理MIDI特征提取:JSON方式与直接Mido操作方案
首先:JSON是不是合适的处理方式?
答案是可以用,但不一定是最优选择。转JSON是一种可行的中间步骤,但Mido本身提供了直接访问MIDI轨道和消息的API,跳过JSON转换会更高效,也能避免双层数组带来的困惑。不过如果你已经转成了JSON,我们也能轻松处理它。
如何处理JSON中的双层数组并提取特征到NumPy数组
假设你的JSON结构大概是这样的(简化版):
{ "tracks": [ [ {"type": "note_on", "note": 60, "velocity": 80, "time": 0}, {"type": "note_off", "note": 60, "velocity": 0, "time": 480} ], [ {"type": "note_on", "note": 64, "velocity": 75, "time": 0}, {"type": "note_off", "note": 64, "velocity": 0, "time": 960} ] ] }
这里的tracks是列表的列表:外层列表代表MIDI里的各个轨道,内层列表代表每个轨道里的MIDI消息。下面是提取特征的具体步骤:
1. 加载JSON数据
首先用Python的json模块加载文件:
import json import numpy as np # 加载JSON文件 with open("your_midi_file.json", "r") as f: midi_data = json.load(f) # 获取tracks的双层数组 tracks = midi_data["tracks"]
2. 提取目标特征(比如note_on消息的音高和力度)
我们可以用嵌套循环或者列表推导式来遍历双层数组,筛选出需要的消息并提取特征:
# 初始化一个列表来存储特征 features = [] # 遍历每个轨道(外层数组) for track in tracks: # 遍历轨道里的每个消息(内层数组) for msg in track: # 只提取note_on类型的消息(根据你的需求调整) if msg["type"] == "note_on" and msg["velocity"] > 0: # 排除velocity为0的note_off伪装 # 提取你需要的特征,比如音高(note)和力度(velocity) features.append([msg["note"], msg["velocity"]]) # 转成NumPy数组 features_array = np.array(features) print(features_array)
3. 扁平化双层数组(如果需要所有消息的扁平列表)
如果你不需要区分轨道,只想把所有消息放在一个一维列表里,可以用列表推导式快速扁平化:
all_messages = [msg for track in tracks for msg in track] # 然后从all_messages里提取特征即可
更高效的方案:直接用Mido提取特征(跳过JSON转换)
其实你完全可以不用转JSON,直接用Mido加载MIDI文件并提取特征,这样更直接,也避免了中间格式转换的问题:
import mido import numpy as np # 直接加载MIDI文件 mid = mido.MidiFile("your_midi_file.mid") features = [] for track in mid.tracks: for msg in track: # 同样筛选note_on消息 if msg.type == "note_on" and msg.velocity > 0: features.append([msg.note, msg.velocity]) # 转成NumPy数组 features_array = np.array(features) print(features_array)
这种方式不需要处理JSON的双层数组,直接通过Mido的对象属性访问消息内容,代码更简洁,也减少了出错的可能。
针对Windows 7 + Python 3.6+的注意事项
- 确保你已经安装了所需的包:
pip install mido numpy(如果用JSON的话还需要json,但json是Python标准库,不需要额外安装) - Python 3.6完全支持上面的代码,没有兼容性问题。
内容的提问来源于stack exchange,提问作者George Petropoulos
相关产品推荐
相关产品推荐

