Skip to content

Latest commit

 

History

History
346 lines (289 loc) · 10.8 KB

File metadata and controls

346 lines (289 loc) · 10.8 KB
Error in user YAML: (<unknown>): found a tab character that violate indentation while scanning a plain scalar at line 3 column 3
---
- oeasy Python 0756
- 这是 oeasy 系统化 Python 教程,从基础一步步讲,扎实、完整、不跳步。愿意花时间学,就能真正学会。
- 本教程同步发布在: 
	- 个人网站: `https://oeasy.org` 
	- 蓝桥云课: `https://www.lanqiao.cn/courses/3584` 
	- GitHub: `https://github.com/overmind1980/oeasy-python-tutorial` 
	- Gitee: `https://gitee.com/overmind1980/oeasypython` 
---

动态设置打击乐器

  • 可以要求 某种鼓点 比如中国风 布鲁斯 鼓点之类的
from pretty_midi import PrettyMIDI, Instrument, Note
import random

# 创建MIDI对象
midi = PrettyMIDI(resolution=480, initial_tempo=92)

# 只保留鼓的音色配置
instruments = {
    'drums': Instrument(0, is_drum=True)
}

# 鼓组编程 (更复杂的后朋克节奏)
def add_drums():
    time = 0
    # 4小节循环
    for _ in range(4):
        # 底鼓 (不规则节奏)
        kick_pattern = [0, 0.75, 1.5, 2.25, 3, 3.5]
        for t in kick_pattern:
            instruments['drums'].notes.append(
                Note(velocity=100 + int(20 * random.random()),
                     pitch=36,
                     start=time + t,
                     end=time + t + 0.1))

        # 军鼓 (带切分)
        snare_pattern = [1.0, 2.5, 3.75]
        for t in snare_pattern:
            instruments['drums'].notes.append(
                Note(velocity=90,
                     pitch=38,
                     start=time + t,
                     end=time + t + 0.1))

        # 踩镲 (十六分音符但随机省略)
        for i in range(16):
            if random.random() > 0.3:  # 70%概率出现
                instruments['drums'].notes.append(
                    Note(velocity=40 + int(30 * random.random()),
                         pitch=42,
                         start=time + i * 0.25,
                         end=time + i * 0.25 + 0.05))

        # 桶鼓填充 (每小节结尾)
        if random.random() > 0.7:  # 30%概率加花
            for pitch, t in zip([41, 43, 45], [3.5, 3.75, 3.875]):
                instruments['drums'].notes.append(
                    Note(velocity=80,
                         pitch=pitch,
                         start=time + t,
                         end=time + t + 0.1))

        time += 4  # 每小节4拍

# 构建完整结构
add_drums()  # 0-16小节

# 添加鼓轨道
midi.instruments.append(instruments['drums'])

# 修改保存路径为绝对路径
midi.write('/Users/easyo/Downloads/oeasy/drums_only.mid')

print(f"鼓组MIDI已生成!文件保存在:drums_only.mid")

不规则节奏切分

from pretty_midi import PrettyMIDI, Instrument, Note
import random
import numpy as np

# 创建MIDI对象 - 稍慢的节奏适合叙事性
midi = PrettyMIDI(resolution=480, initial_tempo=92)

# 音色配置 (更丰富的配器)
instruments = {
    'drums': Instrument(0, is_drum=True),
    'bass': Instrument(program=34),  # 指弹贝斯
    'rhythm_guitar': Instrument(program=29),  # 过载吉他
    'lead_guitar': Instrument(program=26),  # 清音吉他(万能青年旅店风格)
    'synth_pad': Instrument(program=89),  # 温暖合成背景
    'brass': Instrument(program=61),  # 铜管(用于副歌高潮)
    'vocal': Instrument(program=53)  # 合唱人声
}


# 鼓组编程 (更复杂的后朋克节奏)
def add_drums():
    time = 0
    # 4小节循环
    for _ in range(4):
        # 底鼓 (不规则节奏)
        kick_pattern = [0, 0.75, 1.5, 2.25, 3, 3.5]
        for t in kick_pattern:
            instruments['drums'].notes.append(
                Note(velocity=100 + int(20 * random.random()),
                     pitch=36,
                     start=time + t,
                     end=time + t + 0.1))

        # 军鼓 (带切分)
        snare_pattern = [1.0, 2.5, 3.75]
        for t in snare_pattern:
            instruments['drums'].notes.append(
                Note(velocity=90,
                     pitch=38,
                     start=time + t,
                     end=time + t + 0.1))

        # 踩镲 (十六分音符但随机省略)
        for i in range(16):
            if random.random() > 0.3:  # 70%概率出现
                instruments['drums'].notes.append(
                    Note(velocity=40 + int(30 * random.random()),
                         pitch=42,
                         start=time + i * 0.25,
                         end=time + i * 0.25 + 0.05))

        # 桶鼓填充 (每小节结尾)
        if random.random() > 0.7:  # 30%概率加花
            for pitch, t in zip([41, 43, 45], [3.5, 3.75, 3.875]):
                instruments['drums'].notes.append(
                    Note(velocity=80,
                         pitch=pitch,
                         start=time + t,
                         end=time + t + 0.1))

        time += 4  # 每小节4拍


# 贝斯线 (带滑音和切分)
def add_bass():
    time = 0
    # C小调进行
    chord_progression = [
        (48, 0, 1.5),  # C (根音)
        (46, 1.5, 0.5),  # Bb (经过音)
        (48, 2.0, 1.0),  # C
        (51, 3.0, 1.0)  # Eb
    ]

    for _ in range(4):  # 重复4次
        for note_info in chord_progression:
            pitch, offset, duration = note_info
            # 加入随机微调增加人性化
            actual_pitch = pitch + int(0.5 - random.random())
            instruments['bass'].notes.append(
                Note(velocity=70 + int(20 * random.random()),
                     pitch=actual_pitch,
                     start=time + offset,
                     end=time + offset + duration))

            # 50%概率加入滑音
            if random.random() > 0.5 and duration > 0.5:
                instruments['bass'].notes.append(
                    Note(velocity=50,
                         pitch=actual_pitch + 3,
                         start=time + offset + duration - 0.1,
                         end=time + offset + duration))
        time += 4


# 吉他部分 (万能青年旅店式的分解和弦)
def add_guitars():
    time = 0
    # C小调 + F小调交替
    chord_voicings = [
        [48, 51, 55, 60],  # Cm
        [53, 56, 60, 65],  # Fm
        [51, 55, 58, 63],  # Eb
        [50, 53, 57, 62]  # Ddim
    ]

    for _ in range(8):  # 8小节
        current_chord = chord_voicings[time // 4 % len(chord_voicings)]

        # 节奏吉他 (强力和弦)
        if time % 8 < 4:  # 前4小节强力和弦
            instruments['rhythm_guitar'].notes.append(
                Note(velocity=100,
                     pitch=current_chord[0],
                     start=time,
                     end=time + 0.5))
            instruments['rhythm_guitar'].notes.append(
                Note(velocity=90,
                     pitch=current_chord[1],
                     start=time,
                     end=time + 0.5))

        # 主音吉他 (分解和弦)
        arpeggio_pattern = [0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5]
        for i, t in enumerate(arpeggio_pattern):
            note_idx = i % len(current_chord)
            instruments['lead_guitar'].notes.append(
                Note(velocity=60 + int(20 * random.random()),
                     pitch=current_chord[note_idx] + 12,  # 高八度
                     start=time + t,
                     end=time + t + 0.2))

            # 30%概率加入装饰音
            if random.random() > 0.7:
                instruments['lead_guitar'].notes.append(
                    Note(velocity=40,
                         pitch=current_chord[note_idx] + 10,
                         start=time + t - 0.05,
                         end=time + t))

        time += 4


# 合成器背景 (脆莓风格的氛围铺底)
def add_synth():
    time = 0
    chord_progression = [
        [48, 51, 55],  # Cm
        [53, 56, 60],  # Fm
        [51, 55, 58],  # Eb
        [50, 53, 57]  # Ddim
    ]

    for _ in range(4):  # 4次循环
        for chord in chord_progression:
            # 长持续音
            for note in chord:
                instruments['synth_pad'].notes.append(
                    Note(velocity=50,
                         pitch=note + 24,  # 低两个八度
                         start=time,
                         end=time + 4))

                instruments['synth_pad'].notes.append(
                    Note(velocity=40,
                         pitch=note + 36,  # 高一个八度
                         start=time,
                         end=time + 4))

            # 高频点缀
            if random.random() > 0.5:
                instruments['synth_pad'].notes.append(
                    Note(velocity=30,
                         pitch=chord[1] + 48,
                         start=time + 2,
                         end=time + 2.5))

            time += 4


# 铜管部分 (副歌高潮)
def add_brass():
    time = 16  # 从第16小节开始
    melody = [
        (60, 0.5), (62, 0.5), (63, 1.0),  # C-D-Eb
        (65, 0.25), (63, 0.25), (62, 0.5),  # G-Eb-D
        (60, 2.0)  # C(长音)
    ]

    for _ in range(2):  # 重复2次
        current_time = time
        for note, duration in melody:
            instruments['brass'].notes.append(
                Note(velocity=100,
                     pitch=note,
                     start=current_time,
                     end=current_time + duration))
            current_time += duration

        # 加入和声层
        instruments['brass'].notes.append(
            Note(velocity=80,
                 pitch=note - 3,
                 start=time,
                 end=time + 4))

        time += 4


# 人声模拟 (合唱效果)
def add_vocal():
    time = 8  # 从第8小节进入
    vocal_melody = [
        (60, 1.0), (62, 0.5), (60, 0.5),  # C-D-C
        (58, 1.0), (60, 1.0),  # Bb-C
        (55, 2.0)  # G(长音)
    ]

    for _ in range(4):  # 4次循环
        current_time = time
        for note, duration in vocal_melody:
            # 主旋律
            instruments['vocal'].notes.append(
                Note(velocity=90,
                     pitch=note + 12,
                     start=current_time,
                     end=current_time + duration))

            # 和声(随机三度/五度)
            harmony_pitch = note + [3, 4, 7][int(random.random() * 3)]
            instruments['vocal'].notes.append(
                Note(velocity=70,
                     pitch=harmony_pitch + 12,
                     start=current_time,
                     end=current_time + duration))

            current_time += duration

        time += 4


# 构建完整结构
add_drums()  # 0-16小节
add_bass()  # 0-16小节
add_guitars()  # 0-32小节
add_synth()  # 0-16小节
add_brass()  # 16-24小节(副歌)
add_vocal()  # 8-24小节

# 添加所有轨道
for inst in instruments.values():
    midi.instruments.append(inst)

# 保存文件
midi.write('wanqing_style.mid')

print("万能青年旅店 x 脆莓风格MIDI已生成!")

  • 本文来自 oeasy Python 系统教程。
  • 想完整、扎实学 Python,
  • 搜索 oeasy 即可。