手机端Python语言mido简谱生成mid音频文件程序代码QZQ


import tkinter as tk
from tkinter import messagebox, Menu
import mido
import re

# 音符映射保持不变(同原代码)
note_map = {
    # 超低音区(3个点)
    '1...': 24, '2...': 26, '3...': 28, '4...': 29, '5...': 31, '6...': 33, '7...': 35,
    # 低2音区(2个点)
    '1..': 36, '2..': 38, '3..': 40, '4..': 41, '5..': 43, '6..': 45, '7..': 47,
    # 低音区(1个点)
    '1.': 48, '2.': 50, '3.': 52, '4.': 53, '5.': 55, '6.': 57, '7.': 59,
    # 中音区(无符号)
    '1': 60, '2': 62, '3': 64, '4': 65, '5': 67, '6': 69, '7': 71,
    # 高音区(1个*)
    '1*': 72, '2*': 74, '3*': 76, '4*': 77, '5*': 79, '6*': 81, '7*': 83,
    # 高2音区(2个*)
    '1**': 84, '2**': 86, '3**': 88, '4**': 89, '5**': 91, '6**': 93, '7**': 95,
    # 高3音区(3个*)
    '1***': 96, '2***': 98, '3***': 100, '4***': 101, '5***': 103, '6***': 105, '7***': 107,
    '0': None, '-': None  # 休止符
}

# 解析简谱函数保持不变(同原代码)
def parse_score(s):
    score = []
    i = 0
    while i < len(s):
        if s[i] in ['-', '\n']:
            if s[i] == '-':
                j = i
                while j < len(s) and s[j] == '-':
                    j += 1
                duration = j - i
                score.append(('-', duration))
                i = j
            else:
                i += 1
        else:
            j = i + 1
            while j < len(s) and s[j] in ['.', '*']:
                j += 1
            note = s[i:j]
            k = j
            while k < len(s) and s[k] == '-':
                k += 1
            duration = 1 + (k - j)
            score.append((note, duration))
            i = k
    return score

def generate_midi():
    try:
        简谱 = 简谱文本框.get("1.0", tk.END).strip()
        速度 = int(速度文本框.get())
        乐器编号 = int(乐器编号文本框.get())
        文件名 = 文件名文本框.get().strip()

        if not 简谱:
            messagebox.showwarning("警告", "请输入简谱")
            return
        if not 文件名:
            messagebox.showwarning("警告", "请输入文件名")
            return

        parsed_score = parse_score(简谱)
        
        # 创建MIDI文件
        mid = mido.MidiFile()
        track = mido.MidiTrack()
        mid.tracks.append(track)
        
        # 设置速度(微秒/拍)
        tempo = mido.bpm2tempo(速度)
        track.append(mido.MetaMessage('set_tempo', tempo=tempo, time=0))
        
        # 设置乐器
        track.append(mido.Message('program_change', program=乐器编号, time=0))
        
        time = 0  # 以拍为单位的时间
        
        for note_str, duration in parsed_score:
            if note_str in ['0', '-']:
                time += duration
                continue
                
            midi_pitch = note_map.get(note_str)
            if not midi_pitch:
                messagebox.showwarning("警告", f"未知音符:{note_str}")
                continue
                
            # 计算MIDI时间(假设1拍=480 ticks,可根据需要调整)
            ticks_per_beat = mid.ticks_per_beat
            note_time = int(duration * ticks_per_beat)
            
            # 发送音符开启和关闭事件
            track.append(mido.Message('note_on', note=midi_pitch, velocity=64, time=time))
            track.append(mido.Message('note_off', note=midi_pitch, velocity=64, time=note_time))
            
            time += duration  # 更新当前时间
            
        # 保存文件
        mid.save(f"{文件名}.mid")
        messagebox.showinfo("成功", f"MIDI文件生成成功:{文件名}.mid")
        
    except Exception as e:
        messagebox.showerror("错误", f"生成失败:{str(e)}")

# 以下界面代码与原代码完全相同,仅修改了生成逻辑部分
def create_textbox_menu(textbox):
    menu = Menu(textbox, tearoff=0)
    
    def select_all(event):
        textbox.tag_add(tk.SEL, "1.0", tk.END)
        textbox.icursor(tk.END)
        return "break"
    
    def copy_text(event):
        textbox.event_generate("<>")
        return "break"
    
    def paste_text(event):
        textbox.event_generate("<>")
        return "break"
    
    def show_menu(event):
        try:
            menu.tk_popup(event.x_root, event.y_root)
        finally:
            menu.grab_release()
    
    menu.add_command(label="全选", command=lambda: select_all(None))
    menu.add_separator()
    menu.add_command(label="复制", command=lambda: copy_text(None))
    menu.add_command(label="粘贴", command=lambda: paste_text(None))
    
    textbox.bind("", show_menu)
    textbox.bind("", select_all)
    textbox.bind("", copy_text)
    textbox.bind("", paste_text)

# 主窗口代码不变
窗口 = tk.Tk()
窗口.title("简谱转MIDI工具")
窗口.geometry("500x400")

tk.Label(窗口, text="请输入简谱(使用.-*表示音高):").pack(pady=5)
简谱文本框 = tk.Text(窗口, height=8, width=50)
简谱文本框.pack(pady=5, padx=10)
简谱文本框.insert(tk.END, "5-351*--76-1*-5---5-123-212----5-351*--76-1*-5---5-234--7.1----6-1*-1*---7-671*---671*665312----5-351*--76-1*-5---5-234--7.1------")
create_textbox_menu(简谱文本框)

tk.Label(窗口, text="速度(BPM,默认120):").pack(pady=3)
速度文本框 = tk.Entry(窗口)
速度文本框.pack(pady=3, padx=10)
速度文本框.insert(tk.END, "120")

tk.Label(窗口, text="乐器编号(GM标准,如钢琴=0):").pack(pady=3)
乐器编号文本框 = tk.Entry(窗口)
乐器编号文本框.pack(pady=3, padx=10)
乐器编号文本框.insert(tk.END, "0")

tk.Label(窗口, text="请输入文件名:").pack(pady=3)
文件名文本框 = tk.Entry(窗口)
文件名文本框.pack(pady=3, padx=10)

生成按钮 = tk.Button(窗口, text="生成MIDI文件", command=generate_midi, bg="#4CAF50", fg="white")
生成按钮.pack(pady=15)

窗口.mainloop()





你可能感兴趣的:(python,开发语言)