python:用 mido 生成 midi文件,用 pygame 播放 mid文件
pip install mido
Downloading mido-1.3.2-py3-none-any.whl (54 kB)
Downloading packaging-23.2-py3-none-any.whl (53 kB)
Installing collected packages: packaging, mido
Successfully installed mido-1.3.2 packaging-23.2
mido 官网文档
pip intall pygame
pygame 2.5.2
安装文档 D:/Python39/Lib/site-packages/pygame/docs/generated/index.html
编写 test1_mido.py 如下
# -*- coding: utf-8 -*-
from mido import Message, MidiFile, MidiTrack
mid = MidiFile() # 创建MIDI文件
track = MidiTrack() # 创建一个音轨
mid.tracks.append(track)
track.append(Message("program_change", channel=0, program=2, time=0))
# 创建各个音符,并添加到音轨中
map1 = {'C4':60, 'D4':62, 'E4':64, 'F4':65, 'G4':67, 'A4':69, 'B4':71, 'C5':72}
# do: C4 = 60
track.append(Message("note_on", note=60, velocity=96, time=0))
track.append(Message("note_off", note=60, velocity=0, time=500))
# re: D4 = 62
track.append(Message("note_on", note=62, velocity=96, time=0))
track.append(Message("note_off", note=62, velocity=0, time=500))
# mi: E4 = 64
track.append(Message("note_on", note=64, velocity=96, time=0))
track.append(Message("note_off", note=64, velocity=0, time=500))
# fa: F4 = 65
track.append(Message("note_on", note=65, velocity=96, time=0))
track.append(Message("note_off", note=65, velocity=0, time=500))
# sol:G4 = 67
track.append(Message("note_on", note=67, velocity=96, time=0))
track.append(Message("note_off", note=67, velocity=0, time=500))
# la: A4 = 69
track.append(Message("note_on", note=69, velocity=96, time=0))
track.append(Message("note_off", note=69, velocity=0, time=500))
# si: B4 = 71
track.append(Message("note_on", note=71, velocity=96, time=0))
track.append(Message("note_off", note=71, velocity=0, time=500))
# do^: C5 = 72
track.append(Message("note_on", note=72, velocity=96, time=0))
track.append(Message("note_off", note=72, velocity=0, time=500))
mid.save("test1.mid")
运行 python test1_mido.py 生成文件 test1.mid
查看 mid文件内容 (Message),编写 mido_msg.py 如下
# -*- coding: utf-8 -*-
""" https://mido.readthedocs.io/en/latest/ """
import os
import sys
from tkinter import filedialog
from mido import MidiFile
# 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_msg.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)
# mid = MidiFile(f1)
with MidiFile(f1) as mid:
for msg in mid:
print(msg)
运行 python mido_msg.py happy_birthday.mid
编写 play_mid.py 如下
# -*- coding: utf-8 -*-
import os
import sys
import time
from tkinter import filedialog
import traceback
import pygame
from pygame import mixer
def mixer_init():
freq = 44100
bitsize = -16
channels = 2
buffer = 2048
mixer.init(freq, bitsize, channels, buffer)
# optional volume 0 to 1.0
mixer.music.set_volume(0.9)
def play_mid(file):
if mixer.music.get_busy():
mixer.music.fadeout(1000)
mixer.music.stop()
clock = pygame.time.Clock()
try:
mixer.music.load(file)
except:
print(traceback.format_exc())
mixer.music.play()
while mixer.music.get_busy():
clock.tick(30)
# 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 play_mid.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() not in ('.mid','.mp3'):
print('ext is not (.mid , .mp3)')
sys.exit(2)
time1 = time.time()
print(f1)
mixer_init()
try:
play_mid(f1)
except KeyboardInterrupt as ex:
# if user hits Ctrl+C then exit
# (works only in console mode)
mixer.music.fadeout(1000)
mixer.music.stop()
raise SystemExit from ex
mixer.music.stop()
time2 = time.time()
print("run time: %.3f s" % (time2-time1))
运行 python play_mid.py test1.mid
详细参阅:Python编曲实践(一):通过Mido和PyGame来编写和播放单轨MIDI文件
MidiEditor 打开 test1.mid 文件
原因分析
无法打开可能是由于缺乏 freepats.cfg 文件
解决方案
简单直接,打开终端,安装 freepats 即可修复
sudo apt-get install freepats
pip intall pygame