Skip to content

Latest commit

 

History

History
330 lines (228 loc) · 7.87 KB

File metadata and controls

330 lines (228 loc) · 7.87 KB
Error in user YAML: (<unknown>): could not find expected ':' while scanning a simple key at line 3 column 1
---
- oeasy Python 0753
- 这是 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` 
---

列表 - 切片 - slice - 步长 - step

模进

  • 音乐中的模进(sequence)

图片描述

  • 下行二度模进
    • Lower second sequence
    • 在调内 二度音程向下模进

图片描述

  • 能用代码实现模进吗?

提问ai

图片描述

代码

from mido import MidiFile, MidiTrack, MetaMessage, Message

def generate_sequence_midi(output_file="melody_sequence.mid"):
    mid = MidiFile()
    track = MidiTrack()
    mid.tracks.append(track)

    # 设置速度(120 BPM)
    track.append(MetaMessage('set_tempo', tempo=60000000 // 120, time=0))
    track.append(Message('program_change', program=0, time=0))  # 钢琴音色

    ticks_per_beat = mid.ticks_per_beat  # 获取 MIDI 时值单位(ticks/拍)
    quarter_note = ticks_per_beat        # 四分音符时值

    # 定义原始动机(C大调,4个四分音符)
    original_motif = [60, 62, 64, 65, 67, 69, 71] 

    # 生成模进片段(大二度下行,共3组)
    for i in range(0, 4):
        print(original_motif[3-i:7-i][::-1])
        for pitch in original_motif[3-i:7-i][::-1]:
            new_pitch = pitch
            # 音符开启(力度64)
            track.append(Message('note_on', note=new_pitch, velocity=64, time=0))
            # 音符关闭(持续1拍)
            track.append(Message('note_off', note=new_pitch, velocity=64, time=quarter_note))

    mid.save(output_file)
    print(f"已生成 MIDI 文件:{output_file}")

if __name__ == "__main__":
    generate_sequence_midi()
  • 输出 音高列表

图片描述

  • 可以 把旋律 可视化 吗?

旋律可视化

  • 规律之中 有变化
    • 变化之中 有规律

图片描述

  • 这个规律 有名字吗?

最终效果

  • 这是 大调调内模进

    • 原始动机 完全是 下行的
    • 序列 也完全是 下行
    • 非常 哀伤
  • 每个音符 落在 白键 上

    • 属于 调内模进
  • 音符 最后 落在 c上

    • 所有音符 都属于 c大调音阶
    • 旋律调式 是 c大调
  • 综合起来就是

    • c大调 下行 调内 模进

图片描述

  • 掌握了 这个 名词
    • 就可以 让ai利用这个规律
    • 创建 py 形成 这类的mid

酒干倘卖无

  • 酒干倘卖无
    • 酒喝光了
    • 瓶子 卖不卖?
    • 收空酒瓶了喽

图片描述

  • 酒干倘卖无
    • 副歌(Chorus)
    • 歌词 完全重复
    • 非常容易大合唱

副歌 分析

  • 酒干倘卖无
    • 歌名 也是 大合唱
    • 副歌(Chorus)
    • 五个字 无脑循环

图片描述

  • 一个动机
    • 循环四次
    • 下行模进

图片描述

  • 什么是 动机 呢?

动机

  • motif

图片描述

  • 动机本身 下行
    • 反应 情感 悲哀

图片描述

  • 动机 有什么 特点 呢?

动机 重复

  • 动机 有 独特的 节奏型
    • 488 488 全
    • 固定下来
    • 容易洗脑

图片描述

  • 按照这种方式 进行下行
    • 形成下行模进
    • descending sequence

图片描述

  • 下行的原则 是什么?

  • 五声调式

    • 只用 其中 5个音符
    • 如果 音阶 围绕着

图片描述

  • 下行 具体什么原则呢?

调内模进下行

  • 五声调式 的 歌曲
    • 1个 8度 里面 用 5个音符
    • 五声调式的 方式模进
    • 叫做 调内模进

图片描述

  • 动机的音符 往下走
    • 叫做 下行 模进
    • 调内的 下行模进
    • 叫 调内下行模进

图片描述

  • 能让ai写成代码吗?🤔

提问

  • 把照片交给ai

图片描述

  • 明确
    • 所有音符来自于 五声调式的 序列
    • 不转调 模进

代码

  • 生成代码
from mido import MetaMessage, MidiFile, MidiTrack, Message
from mido import bpm2tempo

# 定义完整五声调式音阶(从高到低:高音re、高音do、la、sol、mi、低音re)
pentatonic_scale = ['2\'','1\'','6','5','3','2']  # 新增低音re('2')
note_mapping = {note: idx for idx, note in enumerate(pentatonic_scale)}  # 音符到音阶位置的映射

# 实际音高与MIDI编号的映射(包含低音re '2' 对应62)
pitch_mapping = {
    '2\'': 74, '1\'': 72, '6': 69,
    '5': 67, '3': 64, '2': 62  # 新增低音re的MIDI编号
}

# 创建MIDI文件
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)
track.append(MetaMessage('time_signature', numerator=4, denominator=4))
track.append(MetaMessage('set_tempo', tempo=bpm2tempo(120)))

# 基础动机(高音re起始,节奏型不变)
basic_motif = [
    ("2\'", 4), ("2\'", 8), ("2\'", 8),
    ("1\'", 4), ("1\'", 8), ("1\'", 8),
    ("6", 1)
]

note_value_ticks = {4: 480, 8: 240, 1: 1920}

def generate_motif(motif, scale_pos):
    """根据音阶位置生成动机"""
    for note, value in motif:
        if note in pitch_mapping:
            current_pos = note_mapping[note]
            target_pos = current_pos + scale_pos  # 向下移动scale_pos个音阶位置
            if target_pos < len(pentatonic_scale):
                target_note = pentatonic_scale[target_pos]
                transpose = pitch_mapping[target_note] - pitch_mapping[note]
            else:
                transpose = 0  # 超出音阶范围则保持原音高
            # 生成MIDI事件
            track.append(Message('note_on', note=pitch_mapping[note] + transpose, velocity=64, time=0))
            track.append(Message('note_off', note=pitch_mapping[note] + transpose, velocity=64, time=note_value_ticks[value]))

# 生成5次动机(包含原始动机,共5次:step=0到4)
for step in range(4):
    generate_motif(basic_motif, step)  # step=0(原始)、1、2、3、4

# 保存文件
mid.save('full_pentatonic_modulation.mid')

效果

  • 生成 midi成功
    • 只要 有了 2小节
    • 就可 模进 出来 8小节
    • 美滋滋
  • 曲调 很 悲哀
    • 动机 是 下降的
    • 模进序列 也是 下降的

图片描述

  • 可以 体现 高兴 吗?
    • 模进 可以上升 吗?

主歌 和 副歌

  • 在本首歌中

图片描述

位置 类型 名称 英文
前面 大合唱 副歌 Chorus
后面 歌者独唱 主歌 Verse
  • 有升有降
    • 主歌 下行 模进
    • 副歌 上行 模进
    • 大开大合
    • 一气呵成

主歌

  • 独唱的 主歌(Verse)
    • 动机 曲折 上升
    • 是 上行模进

图片描述

  • 依然是 五声调式模进
    • 1个八度 中的 12个音符
    • 只用5个

图片描述

总结🤔

  • 这次研究了

    • 对称、回环的文字
    • 构成 的 回文
  • 回文

    • 可以用 列表切片的方式 截取出来
    • 研究规律

图片描述

  • 可以根据切片

    • 删除列表项 吗?🤔
  • 下次再说 👋


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