+
18
-

python如何将曲子文本生成音乐mp3或wav、mid文件

python如何将曲子文本生成音乐mp3或wav、mid文件


网友回复

+
4
-

思路一般是:1) 把“曲子文本”解析成音符序列(音高 + 时值)2) 生成 MIDI 文件3) 用合成器(SoundFont)把 MIDI 渲染成 WAV4) 可选:再转成 MP3

下面给你两个常用做法:高质量(用 SoundFont 渲染)和纯 Python(快速 demo,不依赖外部合成器)。

方法 A:pretty_midi + FluidSynth + SoundFont(音色更真实)

安装依赖:

pip: pip install pretty_midi pyfluidsynth soundfile pydub

系统:需要安装 FluidSynth(pyfluidsynth 调用它)

macOS: brew install fluid-synth

Ubuntu/Debian: sudo apt-get install fluidsynth

Windows: choco install fluidsynth 或下载预编译版本

MP3 需要 ffmpeg

macOS: brew install ffmpeg

Ubuntu/Debian: sudo apt-get install ffmpeg

Windows: 安装 ffmpeg 并把 ffmpeg.exe 加到 PATH

准备一个通用 SoundFont(.sf2),例如 “GeneralUser GS” 或 “Chorium”. 将路径填到 sf2_path

文本格式(简单自定义,可直接用):支持

单音:C4:1 表示 C4 1 拍

升降号:C#4:0.5, Db4:0.5

休止:R:1

和弦:C4+E4+G4:2

默认八度为 4(如 C:1 等同 C4:1),默认时值 1 拍;拍速由 tempo 控制

代码

# -*- coding: utf-8 -*-
# 依赖: pretty_midi, pyfluidsynth, soundfile, pydub, numpy
import re
import numpy as np
import pretty_midi
import soundfile as sf

def parse_text_score(text):
    """
    支持:
      - 单音: C4:1, D#5:0.5, F:2(默认八度=4)
      - 休止: R:1
      - 和弦: C4+E4+G4:2
      - 分隔符: 空格 / 逗号 / 竖线
      - 默认时值: 1 拍
    返回: [{'notes': ['C4','E4'], 'beats': 2.0}, {'notes': [], 'beats': 1.0}, ...]
    """
    tokens = re.split(r'[\s,|]+', text.strip())
    events = []
    for tk in tokens:
        if not tk:
            continue
        if ':' in tk:
            left, dur_str = tk.split(':', 1)
            beats = float(dur_str)
        else:
            left, beats = tk, 1.0

        if left.upper() == 'R':  # 休止
            events.append({'notes': [], 'beats': beats})
            continue

        note_syms = left.split('+')
        notes = []
        for s in note_syms:
            m = re.fullmatch(r'([A-Ga-g])([#b]?)(\d?)', s)
            if not m:
                raise ValueError(f"无法解析音符: {s}")
            letter, acc, octv = m.groups()
            if not octv:
                octv = '4'  # 默认八度
            notes.append(f"{letter.upper()}{acc}{octv}")
        events.append({'notes': notes, 'beats': beats})
    return events

def text_to_pretty_midi(score_text, tempo=120, instrument_name='Acoustic Grand Piano'):
    events = parse_text_score(score_text)
    pm = pretty_midi.PrettyMIDI(initial_tempo=tempo)
    try:
        program = pretty_midi.instrument_name_to_program(instrument_name)
    except:
        program = 0  # 回退到Grand Piano
    inst = pretty_midi.Instrument(program=program)

    t = 0.0
    sec_per_beat = 60.0 / tempo
    for ev in events:
        dur = ev['beats'] * sec_per_beat
        for note_name in ev['notes']:
            pitch = pretty_midi.note_name_to_number(note_name)
            inst.notes.append(pretty_midi.Note(
                velocity=96, pitch=pitch, start=t, end=t + dur
            ))
        t += dur

    pm.instruments.append(inst)
    return pm

if __name...

点击查看剩余70%

我知道答案,我要回答