oeasy Python 117,Python深度解析音符四要素
相关内容:
- 这是 oeasy 系统化 Python 教程,从基础一步步讲,扎实、完整、不跳步。愿意花时间学,就能真正学会。二维列表_midi深入_列表_音符四要素_嵌套_embeded
视频加载中...
回忆
- 配套视频
- 上次 我们了解了 无序
- 排序 可以 让列表 有序
- 随机 可以 让列表 无序
- 无序有序都用
- 有序带来理性的方便
- 无序带来混沌的快乐

- 洗牌、码牌、抓牌、看牌
- 理牌 可以让手里的牌
- 有适合出牌的次序

- 目前 列表 都是 一维的
- 可以 升到 有更高维度 吗?
去游乐场
help(list)- 分析append和extend的区别

方法名 | 功能说明 |
append | 追加 列表项 |
extend | 拓展 列表 |
例子
lst =
lst.extend()
lst
lst.append()
lst- 效果

- 这还是个列表吗?
观察
type(lst)
len(lst)
lst
lst
lst
lst- lst确实还是列表
- 总共有三个列表项的列表

- 第2个 列表项 是 什么类型 呢?
再观察
lst
lst
type(lst)
len(lst)- 第二个列表项 还是
- 一个列表
- 2个元素的 列表

- 可以 继续 索引 吗?
继续索引
lst
lst
lst- 效果

- lst 是 列表
- 所以 lst是什么?
套娃?
- lst 是 列表的列表

- 容器的容器
- 不就成了套娃吗?
音高与时值
- 这种 套娃
- 我们 之前见过

- 去生成音乐
提问

- 确定之后
- 再提要求
再提要求

结果
- 得到一个嵌套结构
- 每个音符
- 不但 包括 音高
- 而且 包括 时长
from mido import Message, MidiFile, MidiTrack
# 音符对应字典,按简谱 1 - 7 对应 C 调下的音符(1=C 时的对应)
# 修改核心:将原F调的音符数值调整为C调对应值
NOTE_MAP = {
'1': 60, '2': 62, '3': 64, '4': 65,
'5': 67, '6': 69, '7': 71, '_5': 55 # 低音5对应C调低八度的5
}
# 根据简谱和对应时值构建旋律,这里 '-' 表示延长一拍(原旋律结构不变)
MELODY = , , , , # 两只老虎
, , , , # 两只老虎
, , , # 跑的快
, , , # 跑得快
, , , , , , # 一只没有眼睛
, , , , , , # 一只没有尾巴
, , , # 真奇怪
, , , # 真奇怪
]
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)
ticks_per_beat = 480 # 标准 MIDI 时钟,每拍 480 ticks
current_time = 0 # 时间增量
for note_info in MELODY:
note_name = note_info
beats = note_info
if note_name == '-':
# 处理延长音,增加时间增量
current_time += int(beats * ticks_per_beat)
continue
note = NOTE_MAP
duration = int(beats * ticks_per_beat)
# 发送音符开启(当前时间增量)和关闭(持续时间)
track.append(Message('note_on', note=note, velocity=64, time=current_time))
track.append(Message('note_off', note=note, velocity=64, time=duration))
current_time = 0 # 每个音符独立,无间隔
mid.save('two_tigers_c调.mid')
print("已生成《两只老虎》C 调 MIDI 文件:two_tigers_c调.mid")- 想要从c大调改成f大调
修改

# 音符对应字典,按简谱 1 - 7 对应 F 调下的音符(1=F 时的对应)
NOTE_MAP = {
'1': 65, '2': 67, '3': 69, '4': 70,
'5': 72, '6': 74, '7': 76, '_5': 60
}- 除了 音高、时长 之外
- 音符 还有什么 特征指标吗?
音符 属性

要素 | 定义 | 影响因素 | 作用 | 举例 |
音高 | 音符的高低 | 发声体振动频率 | 构建旋律与和声框架 | 钢琴从左到右音高渐高 |
时长 | 音符发声持续的时间 | 发声体振动持续时长 | 时间上的长短比例 形成节奏 | 全音符、四分音符 |
音强 | 音符发声的强弱程度 | 发声体振动幅度 | 情感起伏 动态变化 | 激昂用强音 轻柔 用弱音 |
音色 | 音符声音的特色 | 发声体的材质、结构、发声方式等 | 赋予声音独特个性 | 钢琴清脆明亮 二胡悠扬 |
修改音强

- 定义了 四档 音强
from mido import Message, MidiFile, MidiTrack
# 音符对应字典(F调)
NOTE_MAP = {'_5': 60, '1': 65, '2': 67, '3': 69, '4': 70, '5': 72, '6': 74, '7': 76}
# 定义强弱规律(四四拍:强=90,弱=50,次强=70,最弱=40)
BEAT_VELOCITY = {
1: 90, # 第一拍(强)
2: 50, # 第二拍(弱)
3: 70, # 第三拍(次强)
4: 50 # 第四拍(弱)
}
# 带节拍位置的旋律(格式:,节拍位置从1开始)
MELODY = , , , , # 第一小节
, , , , # 第二小节
, , , # 第三小节(第三拍延长2拍,占第3、4拍)
, , , # 第四小节
, , , , , , # 第五小节
, , , , , , # 第六小节
, , , # 第七小节
, , , # 第八小节
]
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)
ticks_per_beat = 480
current_time = 0
current_beat = 1 # 记录当前节拍位置(每小节从1开始)
for note_info in MELODY:
note_name, beats, beat_pos = note_info
if note_name == '-':
# 处理延长音
current_time += int(beats * ticks_per_beat)
current_beat = (current_beat + int(beats)) % 4 # 更新节拍位置(4拍循环)
continue
# 获取音强(velocity),若节拍位置超出预设,默认中等音量64
velocity = BEAT_VELOCITY.get(beat_pos, 64)
note = NOTE_MAP
duration = int(beats * ticks_per_beat)
# 发送音符消息(带音强)
track.append(Message('note_on', note=note, velocity=velocity, time=current_time))
track.append(Message('note_off', note=note, velocity=velocity, time=duration))
# 更新节拍位置(每拍前进1,超过4则重置为1)
current_beat = (beat_pos + int(beats)) % 4 if int(beats) == 1 else (beat_pos + int(beats)) # 处理连音符
current_time = 0 # 音符间无间隔
mid.save('two_tigers_f调_强弱.mid')
print("已生成带强弱规律的MIDI文件:two_tigers_f调_强弱.mid")导出效果
- 每个音符 音强 已经有了变化
- 强
- 弱
- 次强
- 弱

- 如果想要改变音强呢?
改变音强
- 弱起节奏
- 从 正拍子 改成 反拍子
# 定义强弱规律(四四拍:强=90,弱=50,次强=70,最弱=40)
BEAT_VELOCITY = {
1: 50, # 第一拍(弱)
2: 70, # 第二拍(强)
3: 40, # 第三拍(最弱)
4: 90 # 第四拍(次强)
}- 效果一般

修改
- 修改 映射细节
- 韵脚 强拍
# 带节拍位置的旋律(格式:,节拍位置从1开始)
MELODY = , , , , # 第一小节
, , , , # 第二小节
, , , # 第三小节(第三拍延长2拍,占第3、4拍)
, , , # 第四小节
, , , , , , # 第五小节
, , , , , , # 第六小节
, , , # 第七小节
, , , # 第八小节
]- 还想改变 音色
音色

编码 | 对应乐器 | 编码 | 对应乐器 |
0 | 大钢琴(声学钢琴) | 64 | 合成铜管2 |
1 | 明亮的钢琴 | 65 | 高音萨克斯 |
2 | 电钢琴 | 66 | 中音萨克斯 |
3 | 酒吧钢琴 | 67 | 次中音萨克斯 |
4 | 柔和的电钢琴 | 68 | 上低音萨克斯 |
5 | 加合唱效果的电钢琴 | 69 | 双簧管 |
6 | 羽管键琴(拨弦古钢琴) | 70 | 英国管 |
7 | 科拉维科特琴(击弦古钢琴) | 71 | 大管 |
8 | 钢片琴 | 72 | 单簧管 |
9 | 钟琴 | 73 | 短笛 |
10 | 八音盒 | 74 | 长笛 |
11 | 颤音琴 | 75 | 竖笛 |
12 | 马林巴 | 76 | 排笛 |
13 | 木琴 | 77 | 吹瓶口 |
14 | 管钟 | 78 | 尺八 |
15 | 大扬琴 | 79 | 哨 |
16 | 击杆风琴 | 80 | 洋埙 |
17 | 打击式风琴 | 81 | 合成主音1(方波) |
18 | 摇滚风琴 | 82 | 合成主音2(锯齿波) |
19 | 教堂风琴 | 83 | 合成主音3(汽笛风琴) |
20 | 簧管风琴 | 84 | 合成主音4(吹管) |
21 | 手风琴 | 85 | 合成主音5(吉他) |
22 | 口琴 | 86 | 合成主音6(人声) |
23 | 探戈手风琴 | 87 | 合成主音7(五度) |
24 | 尼龙弦吉他 | 88 | 合成主音8(低音加主音) |
25 | 钢弦吉他 | 89 | 合成柔音1(新时代) |
26 | 爵士电吉他 | 90 | 合成柔音2(暖音) |
27 | 清音电吉他 | 91 | 合成柔音3(复合成) |
28 | 闷音电吉他 | 92 | 合成柔音4(合唱) |
29 | 加驱动效果的电吉他 | 93 | 合成柔音5(弓弦) |
30 | 加失真效果的电吉他 | 94 | 合成柔音6(金属) |
31 | 吉他和音 | 95 | 合成柔音7(光环) |
32 | 大贝司(声学贝司) | 96 | 合成柔音8(扫弦) |
33 | 电贝司(指弹) | 97 | 合成特效1(雨) |
34 | 电贝司(拨片) | 98 | 合成特效2(音轨) |
35 | 无品贝司 | 99 | 合成特效3(水晶) |
36 | 掌击贝司1 | 100 | 合成特效4(大气) |
37 | 掌击贝司2 | 101 | 合成特效5(亮音) |
38 | 电子合成贝司1 | 102 | 合成特效6(小妖) |
39 | 电子合成贝司2 | 103 | 合成特效7(回声) |
40 | 小提琴 | 104 | 合成特效8(科幻) |
41 | 中提琴 | 105 | 锡塔尔 |
42 | 大提琴 | 106 | 班卓 |
43 | 低音大提琴 | 107 | 三味线 |
44 | 弦乐群颤音音色 | 108 | 筝 |
45 | 弦乐群拨弦音色 | 109 | 卡林巴 |
46 | 竖琴 | 110 | 风笛 |
47 | 定音鼓 | 111 | 古提琴 |
48 | 弦乐合奏音色1 | 112 | 唢呐 |
49 | 弦乐合奏音色2 | 113 | 铃铛 |
50 | 合成弦乐1 | 114 | 拉丁打铃 |
51 | 合成弦乐2 | 115 | 钢鼓 |
52 | 合唱“啊”音 | 116 | 木块 |
53 | 人声“嘟”音 | 117 | 太鼓 |
54 | 合成人声 | 118 | 嗵鼓 |
55 | 乐队打击乐 | 119 | 合成鼓 |
56 | 小号 | 120 | 镲波形反转 |
57 | 长号 | 121 | 磨弦声 |
58 | 大号 | 122 | 呼吸声 |
59 | 弱音小号 | 123 | 海浪声 |
60 | 圆号 | 124 | 鸟鸣声 |
61 | 铜管组 | 125 | 电话铃声 |
62 | 合成铜管1 | 126 | / |
选择小号
- 第33行
- 将 乐器
- 从 1(钢琴)
- 修改为 56(小号)
from mido import Message, MidiFile, MidiTrack
# 音符对应字典(F调)
NOTE_MAP = {'_5': 60, '1': 65, '2': 67, '3': 69, '4': 70, '5': 72, '6': 74, '7': 76}
# 定义强弱规律(四四拍:强=90,弱=50,次强=70,最弱=40)
BEAT_VELOCITY = {
1: 50, # 第一拍(弱)
2: 70, # 第二拍(强)
3: 40, # 第三拍(最弱)
4: 90 # 第四拍(次强)
}
# 带节拍位置的旋律(格式:,节拍位置从1开始)
MELODY = , , , , # 第一小节
, , , , # 第二小节
, , , # 第三小节(5占第3、4拍,节拍位置修正为3)
, , , # 第四小节
, , , , , , # 第五小节
, , , , , , # 第六小节
, , , # 第七小节
, , , # 第八小节
]
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)
# 核心修改:添加小号音色选择(MIDI乐器编号:56 = 小号(Trumpet),编号从0开始)
# 乐器编号参考:0=钢琴, 56=小号, 60=萨克斯, 64=长号
track.append(Message('program_change', program=55, time=0)) # 55是小号的MIDI编号(0-based)
ticks_per_beat = 480
current_time = 0
current_beat = 1 # 记录当前节拍位置(每小节从1开始)
for note_info in MELODY:
note_name, beats, beat_pos = note_info
if note_name == '-':
# 处理延长音
current_time += int(beats * ticks_per_beat)
# 正确更新节拍位置(模4后若为0则等于4)
current_beat = (current_beat + int(beats)) % 4
if current_beat == 0:
current_beat = 4
continue
# 获取对应节拍的音量强度
velocity = BEAT_VELOCITY.get(beat_pos, 64)
note = NOTE_MAP
duration = int(beats * ticks_per_beat)
# 发送音符开启/关闭消息(带指定音量)
track.append(Message('note_on', note=note, velocity=velocity, time=current_time))
track.append(Message('note_off', note=note, velocity=velocity, time=duration))
# 修正节拍位置更新逻辑,确保循环正确
current_beat = (beat_pos + int(beats)) % 4
if current_beat == 0:
current_beat = 4
current_time = 0 # 音符间无间隔
mid.save('two_tigers_f调_强弱_小号.mid')
print("已生成带强弱规律的小号音色MIDI文件:two_tigers_f调_强弱_小号.mid")- 试着改成二胡
- 或者 尝试 配器
总结
- 这次了解了 音符四要素
要素 | 定义 | 影响因素 | 作用 | 举例 |
音高 | 音符的高低 | 发声体振动频率 | 构建旋律与和声框架 | 钢琴从左到右音高渐高 |
时长 | 音符发声持续的时间 | 发声体振动持续时长 | 时间上的长短比例 形成节奏 | 全音符、四分音符 |
音强 | 音符发声的强弱程度 | 发声体振动幅度 | 情感起伏 动态变化 | 激昂用强音 轻柔 用弱音 |
音色 | 音符声音的特色 | 发声体的材质、结构、发声方式等 | 赋予声音独特个性 | 钢琴清脆明亮 二胡悠扬 |
- 设置好 音轨的音色之后

- 每个音符 都有自己的四要素
- 音色
- 音高
- 时值
- 音强