首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >聊聊结构化绑定

聊聊结构化绑定

作者头像
高性能架构探索
发布于 2023-09-05 10:18:54
发布于 2023-09-05 10:18:54
45000
代码可运行
举报
文章被收录于专栏:技术随笔心得技术随笔心得
运行总次数:0
代码可运行

094_使用python控制音符列表_midi_文件制作211 播放 · 0 赞同视频

使用python控制音符列表_midi_文件制作 回忆

  • 上次了解了 列表的下标索引
  • 可以是 正数
  • 也可以是 负数

0

1

2

3

4

o

e

a

s

y

-5

-4

-3

-2

-1

  • 有2个函数 都可以
  • 根据 列表项
  • 找到 索引位置

函数

输入

输出

区别

index

列表项

索引值

找不到 就报ValueError

find

列表项

索引值

找不到 不报错 返回-1

  • 这列表 还有什么 好玩的 吗?🤔

midi文件

  • 我想生成 可以播放的mid文件

添加图片注释,不超过 140 字(可选)

  • 先进入 Code文件夹

cd Code

  • 便于 生成mid 的 下载

制作midi

  • 先来个 《两只老虎》的 mid

添加图片注释,不超过 140 字(可选)

构建环境 pip install mido

  • 先安装需要的包mido

添加图片注释,不超过 140 字(可选)

复制代码 from mido import Message, MidiFile, MidiTrack # 定义简谱数字与MIDI note number的映射(以C调为例) note_mapping = { 1: 60, # do 2: 62, # re 3: 64, # mi 4: 65, # fa 5: 67, # sol 6: 69, # la 7: 71 # si } # 《两只老虎》的简谱音符序列 tune_notes = [ 1, 2, 3, 1, 1, 2, 3, 1, 3, 4, 5, 3, 4, 5, 5, 6, 5, 4, 3, 1, 5, 6, 5, 4, 3, 1, 2, 5, 1, 2, 5, 1 ] # 定义每个音符的拍子(这里假设每个音符为1拍,可根据需要调整) beat_per_note = 1 # 定义每拍的tick数(MIDI文件中时间的基本单位) ticks_per_beat = 480 # 创建MIDI文件和音轨 mid = MidiFile() track = MidiTrack() mid.tracks.append(track) # 设置乐器为钢琴(program number 0) track.append(Message('program_change', program=0, time=0)) # 遍历音符序列,生成MIDI消息 for note in tune_notes: if note in note_mapping: note_num = note_mapping[note] # 音符开启消息 track.append(Message('note_on', note=note_num, velocity=64, time=0)) # 计算音符持续的tick数 tick_duration = int(beat_per_note * ticks_per_beat) # 音符关闭消息 track.append(Message('note_off', note=note_num, velocity=64, time=tick_duration)) # 保存MIDI文件 mid.save('两只老虎.mid') 保存并运行

  • 编辑m.py

vi m.py

  • "+p 将代码粘过来

添加图片注释,不超过 140 字(可选)

  • 运行得到结果

添加图片注释,不超过 140 字(可选)

下载试听

  • 点击侧边栏
  • 下载代码
  • 把Code文件夹
  • 打包下载

添加图片注释,不超过 140 字(可选)

  • 下载之后 双击解压

windows下打开mid

  • 在windows系统中
  • 用媒体播放器 打开

添加图片注释,不超过 140 字(可选)

mac下打开mid

  • mac使用库乐队打开

添加图片注释,不超过 140 字(可选)

  • 在蓝桥上 直接看看
  • 这mid 长啥样
  • 可以 吗?

安装midi软件 sudo apt update yes | sudo apt install rosegarden

  • 安装jackd2
  • 选 是 可以降低延迟

添加图片注释,不超过 140 字(可选)

  • 装好 就可以运行了

rosegarden

  • 可以在开始菜单中
  • 找到 rosegarden 点击

添加图片注释,不超过 140 字(可选)

  • 也可以在 终端 直接运行

rosegarden & 运行效果

  • 出现 软件的界面

添加图片注释,不超过 140 字(可选)

打开midi

  • 运行之后
  • 文件 - 导入
  • 两只老虎.mid

添加图片注释,不超过 140 字(可选)

  • 在音轨上
  • 右键 查看 钢琴卷帘

添加图片注释,不超过 140 字(可选)

钢琴卷帘效果

  • midi文件长成这个样子
  • 一段段 的 黄色格子
  • 对应着 一个个音符
  • 可以 上下左右 移动

添加图片注释,不超过 140 字(可选)

  • 音符的 上下位置 代表什么?

音高

  • 上下位置 代表 音高
  • 钢琴卷帘 总是 循环
  • 一会儿 两个黑键 像筷子
  • 一会儿 三个黑键 像叉子
  • 筷子 下面的 是
  • 123
  • 叉子 下面的 是
  • 4567

添加图片注释,不超过 140 字(可选)

  • 这七个音 1234567 音高
  • 构成了 大调音阶
  • 大调音阶 写进代码 了吗?

分析代码

  • 将 大调音阶
  • 编码为 midi音高

添加图片注释,不超过 140 字(可选)

音级对

黑键存在性

半音差

1、2

2

2、3

2

3、4

1

  • 音符 具体是 怎么插入的呢?

旋律列表

添加图片注释,不超过 140 字(可选)

  • 音符 放在 旋律列表 里

添加图片注释,不超过 140 字(可选)

  • 这 旋律列表 放哪儿 呢?

基础框架

  • 建立 mid文件
  • 建立 mid音轨
  • 将 音轨 附加进 mid文件
  • 再把 旋律列表中的音符
  • 放到 音轨 上

# 创建MIDI文件和音轨 mid = MidiFile() track = MidiTrack() mid.tracks.append(track) # 设置乐器为钢琴(program number 0) track.append(Message('program_change', program=0, time=0))

  • 怎么把 旋律列表中的音符 放到 音轨 上呢?

生成旋律 # 《两只老虎》的简谱音符序列 tune_notes = [ 1, 2, 3, 1, 1, 2, 3, 1, 3, 4, 5, 3, 4, 5, 5, 6, 5, 4, 3, 1, 5, 6, 5, 4, 3, 1, 2, 5, 1, 2, 5, 1 ]

  • 遍历 旋律列表
  • 每个列表项 都是 音符音高
  • 将 音符 按次序 放入 音轨

# 遍历音符序列,生成MIDI消息 for note in tune_notes: if note in note_mapping: note_num = note_mapping[note] # 音符开启消息 track.append(Message('note_on', note=note_num, velocity=64, time=0)) # 计算音符持续的tick数 tick_duration = int(beat_per_note * ticks_per_beat) # 音符关闭消息 track.append(Message('note_off', note=note_num, velocity=64, time=tick_duration)) # 保存MIDI文件 mid.save('两只老虎.mid')

  • 目前 音符的 音高 没有问题
  • 但是 时值有问题

继续提要求

  • 让 ai 根据 简谱照片
  • 生成 midi文件

添加图片注释,不超过 140 字(可选)

  • 根据 图片
  • 从C大调 变成 F大调

文件分析

  • 主音 变了
  • 从 1 = C (60)
  • 变成了 1 = F(65)
  • 改从 65 开始 了
  • 每个音符
  • 除了 音高
  • 还增加了 时值

from mido import Message, MidiFile, MidiTrack # 音符对应字典,按简谱 1 - 7 对应 F 调下的音符(1=F 时的对应) NOTE_MAP = { '1': 65, '2': 67, '3': 69, '4': 70, '5': 72, '6': 74, '7': 76 } # 根据简谱和对应时值构建旋律,这里 '-' 表示延长一拍 MELODY = [ ['1', 1], ['2', 1], ['3', 1], ['1', 1], # 两只老虎 ['1', 1], ['2', 1], ['3', 1], ['1', 1], # 两只老虎 ['3', 1], ['4', 1], ['5', 2], # 跑的快 ['3', 1], ['4', 1], ['5', 2], # 跑得快 ['5', 0.5], ['6', 0.5], ['5', 0.5], ['4', 0.5], ['3', 1], ['1', 1], # 一只没有眼睛 ['5', 0.5], ['6', 0.5], ['5', 0.5], ['4', 0.5], ['3', 1], ['1', 1], # 一只没有尾巴 ['2', 1], ['5', 1], ['1', 2], # 真奇怪 ['2', 1], ['5', 1], ['1', 2], # 真奇怪 ['2', 1], ['5', 1], ['1', 2], # 真奇怪 ['2', 1], ['5', 1], ['1', 2] # 真奇怪 ] 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[0] beats = note_info[1] if note_name == '-': # 处理延长音,增加时间增量 current_time += int(beats * ticks_per_beat) continue note = NOTE_MAP[note_name] 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_f调.mid') print("已生成《两只老虎》F 调 MIDI 文件:two_tigers_f调.mid")

  • 运行起来 听听效果
  • 最后的 两个 So(5)
  • 应该是 是 低音So(5)

提问

添加图片注释,不超过 140 字(可选)

增加音阶

  • 低音So(5) 要求 能够表示出
  • 不同八度 的 音阶

from mido import Message, MidiFile, MidiTrack # 音符对应字典,按简谱 1 - 7 对应 F 调下的音符(1=F 时的对应) # 扩展加入高低音的映射 NOTE_MAP = { '1': 65, '2': 67, '3': 69, '4': 70, '5': 72, '6': 74, '7': 76, '1_': 53, '2_': 55, '3_': 57, '4_': 58, '5_': 60, '6_': 62, '7_': 64, # 低音 '1^': 77, '2^': 79, '3^': 81, '4^': 82, '5^': 84, '6^': 86, '7^': 88 # 高音 } # 根据简谱和对应时值构建旋律,这里 '-' 表示延长一拍 MELODY = [ ['1', 1], ['2', 1], ['3', 1], ['1', 1], # 两只老虎 ['1', 1], ['2', 1], ['3', 1], ['1', 1], # 两只老虎 ['3', 1], ['4', 1], ['5', 2], # 跑的快 ['3', 1], ['4', 1], ['5', 2], # 跑得快 ['5', 0.5], ['6', 0.5], ['5', 0.5], ['4', 0.5], ['3', 1], ['1', 1], # 一只没有眼睛 ['5', 0.5], ['6', 0.5], ['5', 0.5], ['4', 0.5], ['3', 1], ['1', 1], # 一只没有尾巴 ['2', 1], ['5_', 1], ['1', 2], # re so do,so 改为低音 so ['2', 1], ['5_', 1], ['1', 2] # re so do,so 改为低音 so ] 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[0] beats = note_info[1] if note_name == '-': # 处理延长音,增加时间增量 current_time += int(beats * ticks_per_beat) continue note = NOTE_MAP[note_name] 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_f调.mid') print("已生成《两只老虎》F 调 MIDI 文件:two_tigers_f调.mid") 最终mid

添加图片注释,不超过 140 字(可选)

总结

  • 这次研究了 midi音乐的制作
  • 使用 旋律列表 生成音乐

# 《两只老虎》的音符序列 melody = [ '1', '2', '3', '1',... ]

  • 这有什么用呢?
  • 比如 按照调性 生成 随机旋律?🤔

添加图片注释,不超过 140 字(可选)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能架构探索 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C++11 auto关键字:原理解析与使用指南
在C++11标准中,auto关键字经历了语义上的彻底革新。在此之前(C++98/03),auto作为存储类说明符,用于标识变量的自动存储周期(默认行为,极少显式使用),几乎处于废弃状态。C++11重新定义了auto的语义,使其成为类型占位符,允许编译器根据变量的初始化表达式自动推导类型。这一特性极大简化了复杂类型声明(如STL容器迭代器、模板类型),提升了代码可读性与维护性,同时避免了手动指定类型可能导致的错误。
码事漫谈
2025/07/12
1100
C++11 auto关键字:原理解析与使用指南
【C++新特性】C++17结构化绑定
另一个比较有意思的使用地方在于可以增加代码可读性,例如输出map中所有的键值对。map如下:
公众号guangcity
2020/10/30
7.7K0
C++17常用新特性(三)---结构化绑定
结构化绑定允许用一个对象的元素或成员同时实例化多个实体。文字说明可能显得苍白无力。下面用代码的方式来说明:
CPP开发前沿
2022/04/13
1.9K0
C++17常用新特性(三)---结构化绑定
​数组和C++ std::array详解
std::array是C++容器库提供的一个固定大小数组的容器。其与内置的数组相比,是一种更安全、更容易使用的数组类型。std::array在头文件<array>中定义,其声明如下:
艰默
2023/09/05
1K0
​数组和C++ std::array详解
现代C++之万能引用、完美转发、引用折叠(万字长文)
0.导语1.问题引入2.引入万能引用3.万能引用出现场合4.理解左值与右值4.1 精简版4.2 完整版4.3 生命周期延长4.4 生命周期延长应用5.区分万能引用6.表达式的左右值性与类型无关7.引用折叠和完美转发7.1 引用折叠之本质细节7.2 示例与使用7.3 std::move()与std::forward()源码剖析8.不要返回本地变量的引用9.总结10.补充
公众号guangcity
2019/12/30
7K0
现代C++之万能引用、完美转发、引用折叠(万字长文)
C++20新特性个人总结
concept乃重头戏之一,用于模板库的开发。功能类似于C#的泛型约束,但是比C#泛型约束更为强大。
用户7886150
2021/02/04
2.1K0
【Modern CPP】结构化绑定
C++17 引入了结构化绑定(Structured Binding)这一强大的特性,它提供了一种简洁的语法,用于从容器、元组、数组等数据结构中解包并绑定其元素到多个变量中。结构化绑定不仅可以提高代码的可读性和简洁性,还能使代码更加灵活和易于维护。
程序员的园
2024/07/18
1520
【Modern CPP】结构化绑定
C++一分钟之-C++17特性:结构化绑定
在C++17这一里程碑式的版本中,引入了许多令人兴奋的新特性,其中之一便是结构化绑定(Structured Binding)。这一特性极大地简化了从聚合类型(如std::tuple, std::array, 或自定义的结构体)中解构数据的过程,使得代码更加简洁、易读。本文将深入浅出地介绍结构化绑定的基本概念、常见应用场景、易错点及避免策略,并通过代码示例加以说明。
Jimaks
2024/06/27
3190
全面盘点17个C++17的高级特性
C++17是目前比较常用的版本之一,今天花时间来梳理一下17个重要特性,所有的特性也不止这么点。
公众号guangcity
2024/03/22
4.3K0
全面盘点17个C++17的高级特性
C++17 在业务代码中最好用的十个特性
作者:jinshang,腾讯 WXG 后台开发工程师 自从步入现代 C++时代开始,C++语言标准形成了三年一个版本的惯例:C++11 标志着现代 C++的开端,C++14 在 11 的基础上查缺补漏,并未加入许多新特性,而 C++17 作为 C++11 后的第一个大版本,标志着现代 C++逐渐走向成熟。WXG 编译器升级到 gcc7.5 已有一段时间,笔者所在项目组也已经将全部代码升级到 C++17。在使用了 C++17 一年多之后,笔者总结了 C++17 在业务代码中最好用的十个特性。 注 1:本文只
腾讯技术工程官方号
2022/05/25
2.9K0
C++17 在业务代码中最好用的十个特性
C++ 20 学习笔记1 --From BiliBili.com
CPP1、一个函数返回多个变量的方式:1、通过引用传递参数,函数内修改参数值后,函数外部自动改变;2、通过指针传递参数,比引用传参好的点是,可以传nullPtr;3、Tuple4、Pair5、std::array 取值麻烦,array.get<0>(sources);不晓得这个0参数具体含义,不直观;6、struct包装多个变量,return {x,y};即可将x,y的值返回给调用方。CPP2:template1、类似java \c#中的泛型2、template<typename T>;3、template
BrianLee
2023/02/11
5260
C++17常用新特性
每次C++版本的发布都会带来很多新的特性,C++17也不例外,虽然有很多期待的特性没有包含进来,但是新增的特性依然挡不住它独特的魅力。
CPP开发前沿
2021/11/16
2.5K0
C++17常用新特性
C++11常用的一部分新特性
C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自 定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
有礼貌的灰绅士
2023/06/14
5070
C++11常用的一部分新特性
C++ 新增的 stl 容器实用方法,你知道几个?(文末赠送 C++20 书籍)
1 原位构造与容器的emplace系列函数 在介绍emplace和emplace_back方法之前,我们先看一段代码: #include <iostream> #include <list> class Test { public:     Test(int a, int b, int c)     {         ma = a;         mb = b;         mc = c;         std::cout << "Test constructed." << std::endl;
范蠡
2022/10/08
1.1K0
C++ 新增的 stl 容器实用方法,你知道几个?(文末赠送 C++20 书籍)
你理解模板型别推导【C++】的原理吗?
auto类别推导其实就是模板类别推导,只不过模板类别推导涉及模板、函数和形参,而auto和它们无关
用户9831583
2022/12/04
6270
【C++进阶篇】C++11新特性(上篇)
列表初始化 { } 几乎适用于任意数据类型,成为现代编码的推荐方式。合理利用其特性可以可显著提升可读性和健壮性。
熬夜学编程的小王
2025/06/10
760
【C++进阶篇】C++11新特性(上篇)
C++一分钟之-C++17特性:结构化绑定
在C++17这一里程碑式的版本中,引入了许多令人兴奋的新特性,其中之一便是结构化绑定(Structured Binding)。这一特性极大地简化了从聚合类型(如std::tuple, std::array, 或自定义的结构体)中解构数据的过程,使得代码更加简洁、易读。本文将深入浅出地介绍结构化绑定的基本概念、常见应用场景、易错点及避免策略,并通过代码示例加以说明。
Jimaks
2024/06/26
9980
【c++】一篇文章带你了解c++11的新特性&&c++11详解
在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。
用户10925563
2024/08/06
3330
【c++】一篇文章带你了解c++11的新特性&&c++11详解
深入解析C++的auto自动类型推导
关键字auto在C++98中的语义是定义一个自动生命周期的变量,但因为定义的变量默认就是自动变量,因此这个关键字几乎没有人使用。于是C++标准委员会在C++11标准中改变了auto关键字的语义,使它变成一个类型占位符,允许在定义变量时不必明确写出确切的类型,让编译器在编译期间根据初始值自动推导出它的类型。这篇文章我们来解析auto自动类型推导的推导规则,以及使用auto有哪些优点,还有罗列出自C++11重新定义了auto的含义以后,在之后发布的C++14、C++17、C++20标准对auto的更新、增强的功能,以及auto有哪些使用限制。
爱分享
2024/04/11
5630
深入解析C++的auto自动类型推导
C++(STL):02---tuple容器
一、tuple的历史概述 Tuple是TR1引入的东西,它扩展了pair的概念,拥有任意数量的元素。在C++11标准之前,tuple最多带有10个类型不同的元素 C++11,tuple被重新定义,采用variadic template概念,被设计为可用于任意大小的异质集合 二、tuple概述 tuple与pair类似,也是一个模板。pair接受两个成员,tuple接受任意数目的成员 当我们希望将一些数据组合成单一对象时,tuple非常有用 tuple的实现 TR1标准时(C++11之前),tuple最多带有
用户3479834
2021/02/03
1.4K0
C++(STL):02---tuple容器
推荐阅读
相关推荐
C++11 auto关键字:原理解析与使用指南
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档