python:mido 提取 midi文件中某一音轨的音乐数据

pip install mido

使用 **mido**库可以方便地处理 MIDI 文件,提取其中音轨的音乐数据。

1.下面的程序会读取指定的 MIDI 文件,并提取指定编号音轨的音乐数据,主要包括音符事件等信息。

编写 mido_extract.py 如下

python 复制代码
# -*- coding: utf-8 -*-
""" 用 mido 提取 midi文件中某一音轨的音乐数据 """
import os
import sys
from tkinter import filedialog
import mido

def extract_track_data(midi_file, track_no):
    try:
        track_data = []
        tracks = midi_file.tracks
        for i,track in enumerate(tracks):
            print(f"Track {i}: {track.name}")
        if track_no < len(tracks):
            track = tracks[track_no]
            for msg in track:
                if msg.type in ['note_on', 'note_off', 'control_change', 'program_change']:
                    track_data.append(msg)            
        else:
            print(f"音轨编号 {track_no} 超出范围,该MIDI文件共有 {len(tracks)}条音轨。")
        return track_data
    except:
        print(" 无法读取MIDI文件.")
        return None


def write_track_to_midi(track_data, output_file_path, original_mid):
    new_mid = mido.MidiFile(ticks_per_beat=original_mid.ticks_per_beat)
    new_track = mido.MidiTrack()
    for msg in track_data:
        new_track.append(msg)
    new_mid.tracks.append(new_track)
    new_mid.save(output_file_path)


# main()
if len(sys.argv) ==1:
    filetypes = [('mid file','.mid')]
    f1 = filedialog.askopenfilename(initialdir='D:/Music', filetypes=filetypes)
elif len(sys.argv) ==2:
    f1 = sys.argv[1]
else:
    print('usage: python mido_extract.py file1.mid')
    sys.exit(1)

if not os.path.exists(f1):
    print(f"{f1} is not exists.")
    sys.exit(2)

fn,ext = os.path.splitext(f1)
if ext.lower() != '.mid':
    print('ext is not .mid ')
    sys.exit(2)

midi_file_path = f1  # 替换为实际的MIDI文件路径
x = 1  # 替换为想要提取的音轨编号,从0开始
output_file_path = f"track_{x}.mid"  # 替换为输出的MIDI文件路径
try:
    original_mid = mido.MidiFile(midi_file_path)
    data = extract_track_data(original_mid, x)
    if data:
        write_track_to_midi(data, output_file_path, original_mid)
        print(f"已成功将track {x} 数据写入 {output_file_path}")
except mido.MidiFileError:
    print(f"无法读取MIDI文件 {midi_file_path}")

运行 python mido_extract.py moon_river.mid

生成 track_1.mid

上述代码中,extract_track_data函数负责提取指定音轨的数据,write_track_to_midi函数则将提取的数据写入新的 MIDI 文件。你需要把midi_file_path换成原始 MIDI 文件路径,track_number设为目标音轨编号,output_file_path指定输出文件路径。


2.下面的代码会复制保留原 MIDI 文件中 Track 0 的全部信息,同时提取 Track 1 的音乐数据,然后将它们合并到一个新的 MIDI 文件中。

编写 mido_extract1.py 如下

python 复制代码
# -*- coding: utf-8 -*-
""" 用 mido 复制保留 Track 0 全部信息,提取 Track 1 音乐数据 """
import mido

def copy_track0_and_extract_track1(midi_file_path, output_file_path):
    try:
        # 读取原 MIDI 文件
        original_mid = mido.MidiFile(midi_file_path)

        if len(original_mid.tracks) < 2:
            print("MIDI 文件中没有足够的音轨(至少需要 2 条音轨)。")
            return

        # 创建新的 MIDI 文件,复制原文件的 ticks_per_beat
        new_mid = mido.MidiFile(ticks_per_beat=original_mid.ticks_per_beat)

        # 复制 Track 0 到新的 MIDI 文件
        new_mid.tracks.append(original_mid.tracks[0])

        # 提取 Track 1 的音乐数据
        track1 = original_mid.tracks[1]
        track1_data = []
        for msg in track1:
            if msg.type in ['note_on', 'note_off', 'control_change', 'program_change']:
                track1_data.append(msg)

        # 创建新的音轨并添加 Track 1 的数据
        new_track1 = mido.MidiTrack()
        for msg in track1_data:
            new_track1.append(msg)
        new_mid.tracks.append(new_track1)

        # 保存新的 MIDI 文件
        new_mid.save(output_file_path)
        print(f"已成功将 Track 0 信息和 Track 1 数据写入 {output_file_path}")

    except mido.MidiFileError:
        print(f"无法读取 MIDI 文件 {midi_file_path}")


if __name__ == "__main__":
    midi_file_path = "your_midi_file.mid"  # 替换为实际的 MIDI 文件路径
    output_file_path = "new_midi_file.mid"  # 替换为输出的 MIDI 文件路径
    copy_track0_and_extract_track1(midi_file_path, output_file_path)
    

代码说明:

  1. 读取原 MIDI 文件 :使用 mido.MidiFile 读取指定路径的 MIDI 文件。
  2. 检查音轨数量:确保 MIDI 文件中至少有 2 条音轨。
  3. 创建新的 MIDI 文件 :使用原文件的 ticks_per_beat 创建新的 MIDI 文件。
  4. 复制 Track 0 :将原文件的 Track 0 直接添加到新的 MIDI 文件中。
  5. 提取 Track 1 数据 :遍历 Track 1,提取 note_onnote_offcontrol_changeprogram_change 类型的消息。
  6. 创建新音轨并添加数据 :创建一个新的音轨,并将提取的 Track 1 数据添加到该音轨中,然后将该音轨添加到新的 MIDI 文件中。
  7. 保存新的 MIDI 文件:将新的 MIDI 文件保存到指定的输出路径。

你需要将 midi_file_path 替换为实际的 MIDI 文件路径,将 output_file_path 替换为你希望保存的新 MIDI 文件的路径。

相关推荐
luckys.one37 分钟前
第9篇:Freqtrade量化交易之config.json 基础入门与初始化
javascript·数据库·python·mysql·算法·json·区块链
大翻哥哥2 小时前
Python 2025:量化金融与智能交易的新纪元
开发语言·python·金融
zhousenshan3 小时前
Python爬虫常用框架
开发语言·爬虫·python
IMER SIMPLE4 小时前
人工智能-python-深度学习-经典神经网络AlexNet
人工智能·python·深度学习
CodeCraft Studio4 小时前
国产化Word处理组件Spire.DOC教程:使用 Python 将 Markdown 转换为 HTML 的详细教程
python·html·word·markdown·国产化·spire.doc·文档格式转换
专注API从业者5 小时前
Python/Java 代码示例:手把手教程调用 1688 API 获取商品详情实时数据
java·linux·数据库·python
java1234_小锋5 小时前
[免费]基于Python的协同过滤电影推荐系统(Django+Vue+sqlite+爬虫)【论文+源码+SQL脚本】
python·django·电影推荐系统·协同过滤
看海天一色听风起雨落5 小时前
Python学习之装饰器
开发语言·python·学习
XiaoMu_0016 小时前
基于Python+Streamlit的旅游数据分析与预测系统:从数据可视化到机器学习预测的完整实现
python·信息可视化·旅游
THMAIL6 小时前
深度学习从入门到精通 - 生成对抗网络(GAN)实战:创造逼真图像的魔法艺术
人工智能·python·深度学习·神经网络·机器学习·生成对抗网络·cnn