使用Python将MIDI音频转换为ROM文件

功能介绍:

        该代码可将单轨道的midi文件转换为以最小音符长度为单位的ROM文件(格式为Quartus的mif文件)。

具体转换方式:

        例如一段简谱为:1 22 33 4,则输出为:11 22 33 44,即:音符个数=音符长度/最小音符长度。

注:MIDI文件需为单轨且为单音。

使用说明:

        将MIDI文件放置在.py文件相同目录下,运行python文件即可生成:test1.txt与test2.txt(midi音符信息)、test3.txt(将音符长度转换为最小音符长度)、ROM.txt(适用与Quartus的ROM序列)。

具体文件内容如图所示:

具体代码如下:

import mido
import os

# MIDI音符值到音乐音符的映射
notes = ['C', 'Cs', 'D', 'Ds', 'E', 'F', 'Fs', 'G', 'Gs', 'A', 'As', 'B']
# 删除文件
if os.path.exists("test1.txt"):
    os.remove("test1.txt")
if os.path.exists("test2.txt"):
    os.remove("test2.txt")
if os.path.exists("test3.txt"):
    os.remove("test3.txt")
if os.path.exists("test4.txt"):
    os.remove("test4.txt")

# 读取MIDI文件
mid = mido.MidiFile('untitled.mid')
min = 12  # 音符最小长度
f = open("test1.txt", "a")  # 原文本形式
# 遍历每个音轨
for i, track in enumerate(mid.tracks):
    f.write('\n----------------------\n')
    last_note_on_time = {}
    absolute_time = 0
    last_event_time = 0
    for msg in track:
        # 累加时间戳
        absolute_time += msg.time
        # 检查是否是音符事件
        if msg.type in ['note_on', 'note_off']:
            # 将MIDI音符值转换为音乐音符
            note = notes[msg.note % 12] + str((msg.note // 12)) if msg.note != 0 else '0'  # 音符
            if msg.type == 'note_on':
                # 如果这个note_on事件和上一个事件之间的时间间隔不为0,那么这个时间间隔就表示了一个休止符
                if absolute_time - last_event_time > 0:
                    print('音高: 0, 速度: 64, 长度: {}'.format(absolute_time - last_event_time))
                    f.write('音高: 0, 速度: 64, 长度: {}\n'.format(absolute_time - last_event_time))
                # 记录note_on事件的绝对时间戳
                last_note_on_time[note] = absolute_time
            elif msg.type == 'note_off' and note in last_note_on_time:
                # 计算音符的长度
                note_length = absolute_time - last_note_on_time[note]
                # 打印音符的音高、速度和长度
                print('音高: {}, 速度: {}, 长度: {}'.format(note, msg.velocity, note_length))
                # 将音符的音高、速度和长度写入文件
                f.write('音高: {}, 速度: {}, 长度: {}\n'.format(note, msg.velocity, note_length))
                # if note_length < min:
                #    min = min
            # 记录这个事件的时间戳
            last_event_time = absolute_time
print("最小音符长度:", min)

f2 = open("test2.txt", "a")  # 原文本形式
# 读取音符文件
with open('test1.txt', 'r') as f:
    notes = f.readlines()
# 遍历文件
for i in range(0, len(notes)):
    # 获取音符长度
    note_parts = notes[i].split(' ')
    if note_parts[-1].strip().isdigit():
        note_length = int(note_parts[-1])
        # 判断音符长度如果大于最小音符x倍,则输出x个该音符
        num = note_length / min
        for j in range(int(num)):  # 输出x个该音符
            f2.write(notes[i])  # 写入文件
            print(notes[i])
    else:
        print(f"Skipping line {i}: not a valid note")
f.close()
f2.close()

# 遍历文件,读取音高
f2 = open("test2.txt", "r")
notes = f2.readlines()
f2.close()
f3 = open("test3.txt", "a")  # 音高
for i in range(0, len(notes)):
    note_parts = notes[i].split(' ')
    note = note_parts[1]
    f3.write(note + '\n')
    print(note)
f3.close()

# 音高到rom的映射
# C2 -> 1, Cs2 -> 2, D2 -> 3, Ds2 -> 4, E2 -> 5, F2 -> 6, Fs2 -> 7, G2 -> 8, Gs2 -> 9, A2 -> 10, As2 -> 11, B2 -> 12,
# C3 -> 13, Cs3 -> 14, D3 -> 15, Ds3 -> 16, E3 -> 17, F3 -> 18, Fs3 -> 19, G3 -> 20, Gs3 -> 21, A3 -> 22, As3 -> 23, B3 -> 24,
# C4 -> 25, Cs4 -> 26, D4 -> 27, Ds4 -> 28, E4 -> 29, F4 -> 30, Fs4 -> 31, G4 -> 32, Gs4 -> 33, A4 -> 34, As4 -> 35, B4 -> 36,
# C5 -> 37, Cs5 -> 38, D5 -> 39, Ds5 -> 40, E5 -> 41, F5 -> 42, Fs5 -> 43, G5 -> 44, Gs5 -> 45, A5 -> 46, As5 -> 47, B5 -> 48,
# C6 -> 49, Cs6 -> 50, D6 -> 51, Ds6 -> 52, E6 -> 53, F6 -> 54, Fs6 -> 55, G6 -> 56, Gs6 -> 57, A6 -> 58, As6 -> 59, B6 -> 60,
# LL -> 0

rom_notes = ['0,', 'C4,', 'Cs4,', 'D4,', 'Ds4,', 'E4,', 'F4,', 'Fs4,', 'G4,', 'Gs4,', 'A4,', 'As4,', 'B4,',
             'C5,', 'Cs5,', 'D5,', 'Ds5,', 'E5,', 'F5,', 'Fs5,', 'G5,', 'Gs5,', 'A5,', 'As5,', 'B5,',
            ]
# 遍历文件,读取音高
f3 = open("test3.txt", "r")
notes = f3.readlines()
# 将音高转换为rom
f4 = open("ROM.txt", "a")  # rom
for i in range(0, len(notes)):
    note = notes[i].strip()
    if note == '0':
        rom = 'LL'
    else:
        rom = rom_notes.index(note) + 1
    f4.write(str(i) + " : " + str(rom) + ';\n')
    print(rom)
print("最小音符长度:", min)
f3.close()

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值