用Python编程制作一段简单的音乐(I)

前言

对于一些不会写词的业余音乐爱好者来说,可能某一天突然产生了灵感想到一段旋律,然后用一些作曲软件把这段旋律记录下来,然后找一个常见的和弦走向,然后加上两条伴奏和鼓点,再做一些简单的混音。这样,一段“还凑活,听得下去”的音乐就出来了。

我们在编程制作一段音乐的时候,也可以模仿业余爱好者的步骤,将整个流程分成如下五个部分。

使用适当的模块来生成一段音符

让程序生成一段规则的音符,能称得上“主旋律”

给这段主旋律添加一系列和弦

给这段主旋律添加一段伴奏

优化程序生成的音乐

这里,我将用几篇文章来介绍如何使用Python编程制作一段简单的音乐。从随机生成一段杂乱无章的音符,到生成一段“还凑活,听得下去”的音乐。

这个编程制作音乐的流程中暂时不包括作词、配器、混音等,只包括了最简单的几个制作步骤

一、通过程序输出音频的概述

通过程序将一段乐谱并输出成音频时,通常需要先将乐谱保存为midi格式,再根据需求转化为其他格式的音频。因为midi格式存储的是音符、控制指令等信息。相比于其他常见的音频格式,如wav、mp3、ogg等,它和原始乐谱更为贴近。

但是,midi文件的格式较为复杂,直接通过程序将一段音符输出为midi格式存在一定的困难。因此,我们考虑使用现成的模块来完成这个任务。

我使用的midi文件生成的模块是“mido”(版本1.2.8)。

这个库的安装很简单,直接在命令行中输入 pip3 install mido 或 python3 -m pip install mido 即可。

二、通过程序生成一个音符

下面这段Python代码实现了生成一个长度为1拍、音量为75%的中央C音符的功能,并将它以mid文件的形式输出。

import mido

mid = mido.MidiFile()

track = mido.MidiTrack()

mid.tracks.append(track)

track.append(mido.Message('note_on', note=60, velocity=96, time=0))

track.append(mido.Message('note_off', note=60, velocity=96, time=480))

mid.save('a1.mid')

在这段代码中,为mid对象添加一个音符的操作是在 mido.Message('note_on', <......>) 和 mido.Message('note_off', <......>) 这两行实现的。值得说明的是这个 Message 函数的几个参数

type 这个参数确定信号的类型。其中 note_on 表示一个音符的开始,note_off 表示一个音符的结束。

note 这个参数确定音符的音高。60代表中央C,每增加12,音高升高一个八度。

velocity 这个参数确定音符的音量。0表示静音,127表示最大音量。

time 这个参数确定消息所在的时间。这个时间以tick为单位,而在mido的默认配置中,1拍中有480个tick。所以要想生成一个长度为1拍的音符,应该设置其time值为480,而不是1。

每条消息中,time值的含义是这条消息与上一条消息的时间差,而不是一条消息在乐曲中的绝对时间。

想要获取每拍中tick的数量,可以通过 print(mid.ticks_per_beat) 来实现。

上面的 mid.ticks_per_beat 值可以更改。

我们可以用FL Studio等包含midi编辑功能的软件打开这个mid文件,从而看到程序的输出效果。

效果1.PNG

三、调节配置

一个完整的乐谱中,除了有音符组合以外,还应该有一些整体的控制信息,如速度(bpm)、歌名、音色等。这些信息可以通过输入如下代码在程序中进行配置。

设置音色

设置一个音轨的音色的代码是 track.append(mido.Message('program_change', program=1, time=0))。 其中,program 这个参数确定了这个音轨的音色。

如果想要知道 program 的值和具体乐器的对照关系,可以自行搜索“midi音色表”。

除了打击乐通道以外,音色的默认值为Piano 1。

设置速度

设置乐曲速度的代码是 track.append(mido.MetaMessage('set_tempo', tempo=500000, time=0))。其中,tempo 这个参数确定了乐曲的速度。

tempo 值的含义是每一拍为多少微秒。500000表示每一拍为0.5秒,即每分钟120拍。bpm和tempo的关系为

bpm = \frac{60000000}{tempo}

设置音轨名称

设置音轨名称的代码为 track.append(mido.MetaMessage('track_name', name='Piano', time=0))。其中,name这个参数确定了音轨的名称。

四、随机生成一段音符

下面这段Python代码实现的功能是生成长度为16拍的大钢琴。音高和音量都是随机的。

import mido

import random

pitch_list = [[] for t0 in range(32)] # 每个半拍所有音符的音高

vel_list = [[] for t1 in range(32)] # 每个半拍所有音符的音量

# 随机确定每个半拍的音量和音高

for i in range(32):

note_num = random.randint(0, 3)

while True:

pitch_list[i] = [random.randint(60, 84) for t2 in range(note_num)]

vel_list[i] = [random.randint(64, 100) for t3 in range(note_num)]

if len(pitch_list[i]) == len(set(pitch_list[i])): # 同一时间音符的音高不能重合

break

mid = mido.MidiFile()

track = mido.MidiTrack()

mid.tracks.append(track)

track.append(mido.MetaMessage('set_tempo', tempo=500000, time=0))

track.append(mido.MetaMessage('track_name', name='Piano 1', time=0))

track.append(mido.Message('program_change', program=1, time=0)) # 这个音轨使用的乐器

current_beat = 0

for i in range(32):

# 添加这个半拍所有音符的开始

for note in range(len(pitch_list[i])):

note_beat = i * 0.5

track.append(mido.Message('note_on', note=pitch_list[i][note], velocity=vel_list[i][note],

time=round(480 * (note_beat - current_beat))))

current_beat = note_beat

# 添加这个半拍所有音符的终止

for note in range(len(pitch_list[i])):

note_beat = i * 0.5 + 0.4

track.append(mido.Message('note_off', note=pitch_list[i][note], velocity=vel_list[i][note],

time=round(480 * (note_beat - current_beat))))

current_beat = note_beat

mid.save('test.mid')

值得注意的是

在 mido.Message 中, time 值的含义这条消息与上一条消息的时间差。所以我们在程序中,需要将每个音符的起止点在乐谱中的时间,转化为相邻两个音符的时间差。

time 参数的值必须为整数,所以我们需要对时间进行取整。建议用 round 方法进行取整,不要使用 int 。

这段音符用FL Studio打开的效果如下

效果2.PNG

至此,我们介绍了如何通过程序生成一段音符,并修改这段音符的音色、速度。但是用本文的方法,你只能通过程序生成一段杂乱无章的音符,还不能称得上是一段音乐。

至于如何通过程序生成一段有序的音符,能够勉强称得上是一段”旋律”,请看下篇。

(未完待续)

python音乐编程_使用Python编程制作一段Midi音符相关推荐

  1. python音乐相册_用 Python 绘制音乐图谱

    在本文中,我们将探讨一种简洁的方式,以此来可视化你的MP3音乐收藏.此方法最终的结果将是一个映射你所有歌曲的正六边形网格地图,其中相似的音轨将处于相邻的位置.不同区域的颜色对应不同的音乐流派(例如:古 ...

  2. python音乐相册_学Python爬虫,就得从爬高清美图开始!

    写在前面 前几天玩游戏时,lol盒子右下角有条广告,广告大概这个样子 咦,小姐姐,还有cosplay,点进去看看. 哇,发现一个好玩的网站,好多漂亮的妹子,页面打开很流畅,点开后有的浏览页面还有好听的 ...

  3. python 时间序列预测_使用Python进行动手时间序列预测

    python 时间序列预测 Time series analysis is the endeavor of extracting meaningful summary and statistical ...

  4. python 概率分布模型_使用python的概率模型进行公司估值

    python 概率分布模型 Note from Towards Data Science's editors: While we allow independent authors to publis ...

  5. python语言 行业_如何入门编程开发行业 选择Python语言怎么样

    如何入门编程开发行业?选择Python语言怎么样?Python是一种面向对象的解释型计算机程序设计语言,它是纯粹的自由软件,语法简洁清晰,它具有丰富和强大的库.它常被称为胶水语言,能够把用其他语言制作 ...

  6. python 网页编程_通过Python编程检索网页

    python 网页编程 The internet and the World Wide Web (WWW), is probably the most prominent source of info ...

  7. python异步教程_【Python 异步编程入门】

    本文是写给 JavaScript 程序员的 Python 教程. Python 的异步编程,其他人可能觉得很难,但是 JavaScript 程序员应该特别容易理解,因为两者的概念和语法类似.JavaS ...

  8. python环境搭建_搭建Python编程环境

    说明:本文面向信息技术新教材环境下的中学生或者编程小白.Python作为新教材落实计算思维的主要载体,有其独特的魅力.千里之行始于足下,搭建Python运行环境是跨出进入新世界大门的第一步. 搭建Py ...

  9. 用python学编程_用Python学编程

    第1部分 引 论 第1章 关于本书 1.1 什么人要学编程 1.2 本书的内容 1.3 为什么选择Python 1.4 如何阅读本书 1.5 本书内容的组织 第2章 学习编程的要求 2.1 关于编程者 ...

最新文章

  1. 刷过一题之黑魔法师之门
  2. 用户和组命令及相关配置文件
  3. Hadoop 学习总结之一:HDFS简介(转载)
  4. 第四话 想不到办法,就研究规律 ver1.0
  5. java与ios_JAVA和IOS区别是什么?
  6. 后端接口重定向_接口自动化面试题,建议收藏!
  7. AWS 与 Elastic 矛盾再升级!
  8. 30首优秀奥运歌曲获奖作品出炉
  9. [转载] python 字符串方法大全
  10. 论文精读:车尧-《社会网络视角下战略性新兴产业的专利情报研究》
  11. WPE系统NTPWEdit工具无法打开SAM,显示只读文件怎么修改?
  12. haneWIN NFS Server for Windows
  13. 基于c语言的串口通讯,基于C语言的RS232串行接口通信设计与实现
  14. mongodb磁盘碎片整理
  15. 5年培养2000名高端专业人才 阿里巴巴大数据学院落地成都
  16. 使用pandas的话,如何直接删除这个表格里面X值是负数的行?
  17. VISIO2016解决跨线问题
  18. stm32中常见的通信协议之SPI
  19. 物流订舱运输成本 广州力其
  20. 用JS模拟向左移动的侧移式灯箱效果

热门文章

  1. 校运动会mysql索引_大学生春季运动会的数据库,保存了比赛信息的三个表如下:运动员...
  2. 第七章第二节:Java类和对象之封装、包和static成员
  3. 数据治理 Python桑基图处理表关系
  4. 博客园页面风格+代码块美化+分类+深色模式+Mac代码
  5. 辍学的了应该如何自我努力?
  6. 【Android 小功能】双击返回键返回桌面(进入后台),再次进入不加载启动页,物理键双击退回桌面
  7. 2013款宝骏630 见证自身实力的有一次提升
  8. 如何查找CAD建筑图纸中的文字
  9. 监控软件之 阻止系统屏保 阻止系统关闭显示器 阻止系统待机
  10. 基于ssm+vue的研究生推免报名面试系统 计算机毕业设计