又用Mathematica写了一段卡农

你能在这里听到它

用数学软件演奏音乐早已不是什么新鲜事,很早就有人用Matlab弹奏卡农或是最炫民族风,最近我知道还有人用无理数生成一段音乐,很有趣。而我选择用Mathematica弹奏卡农是因为卡农这种谱曲方式很奇妙,体现在程序上也会是简洁而优美的。可能有人还不了解卡农是什么,卡农不是指某一首曲子,而是一种谱曲方式,它把几段相同的旋律在不同的时刻依次展开,交错的旋律又能相互配合,形成一首完整的卡农。这用Mathematica演奏的卡农就是大家最耳熟的“帕赫贝尔的卡农”,你可以在它的乐谱中一窥其中的奇妙。


我们关注的重点是,这首卡农有三个声部(在乐谱上对应着前三排)和一个背景旋律,但实际上三个声部演奏的旋律是相同的,所以我们只需要输入一个声部的谱子,然后让三个声部在不同的时间进入就可以了。

手动输入乐谱——失败

起初我在网上找到的是巴赫的手稿,当我把一个声部的旋律都输入进去后,最终的效果并不是很理想,我想这个谱子更适合音乐会弹奏,需要乐手控制不同声部的音量与节奏,但这在Mathematica上很难实现。


从Matlab到Mathematica

后来我在网上发现了一个用Matlab弹卡农的程序,听过之后,感觉他的谱子更适合用软件演奏。就决定把Matlab代码翻译到Mathematica上。首先我们分析一下Matlab的代码

Matlab代码

Matlab中的代码一共分三部分

1. 告诉电脑如何弹奏音符

2. 输入一个声部的旋律

3. 组合三个声部

1.告诉电脑如何弹奏音符

我们需要告诉电脑

i.音符名称(do,re,mi,fa...)

ii.音符持续的时间(音符时值t)

iii.音调(频率f)

所以我们输入的应该是如下格式的信息:

                                            音符名称=sin(2πft)

看看这在Matlab中是如何做到的

% 1/4 notes

do0f = mod4.*cos(2*pi*ScaleTable(21)*f0*t4);

re0f = mod4.*cos(2*pi*ScaleTable(22)*f0*t4);

mi0f = mod4.*cos(2*pi*ScaleTable(23)*f0*t4);

% 1/8 notes

fa0e = mod8.*cos(2*pi*ScaleTable(1)*f0*t8);

so0e = mod8.*cos(2*pi*ScaleTable(2)*f0*t8);

la0e = mod8.*cos(2*pi*ScaleTable(3)*f0*t8);

% 1/16 notes

fa0s = mod16.*cos(2*pi*ScaleTable(1)*f0*t16);

so0s = mod16.*cos(2*pi*ScaleTable(2)*f0*t16);

la0s = mod16.*cos(2*pi*ScaleTable(3)*f0*t16);

初看感觉很复杂,但其实它的形式和上面的公式是相同的

i.do0f,re0f,mi0f...代表音符名称

ii.ScaleTable(\space)*f0代表频率f,不同音符的ScaleTable()不同

iii.t4,t8,t16代表持续时间$t$,更具体的,t4=0.5s,t8=0.25s,t16=0.125s

但我们还发现他多出一个mod函数,这其实是一个修正函数(modify),乘上他之后可以让波形变得更柔和,有渐入渐出的效果。


未经mod修正过的波形
经mod修正过的波形

mod后面的数字代表对应音符的持续时间。比如mod4要和t4相乘。

2. 输入一个声部的音符

这一步就很好理解了,这首卡农背景旋律(Base Melody)由大提琴演奏,主旋律(Long Melody )由三把小提琴演奏,我们分别命名cello和violin

% Base Melody

cello = [do1f do1f so0f so0f la0f la0f mi0f mi0f... fa0f fa0f do0f do0f fa0f fa0f so0f so0f];......

% Long Melody

violin = [mi2f mi2f re2f re2f do2f do2f ti1f ti1f... la1f la1f so1f so1f la1f la1f ti1f ti1f ......

3.组合三个声部

正如我前面说的,我们只需要在不同的时间点加入相应的旋律,就像下面这样(blkblock代表空白音符)

% violin1

v1 = [blkblock violin blkblock blkblock];

% violin2

v2 = [blkblock blkblock violin blkblock];

% violin3

v3 = [blkblock blkblock blkblock violin];

% Combination

s = c1+v1+v2+v3;

sound(s,fs);

这样就得到了一段能在Matlab上演奏卡农的代码,接下来就要把它翻译到Mathematica上。

翻译到Mathematica

我们当然要借助Mathematica来翻译,思路跟Matlab上的思路一样

1.建立音符名称和声音的关联(Association)

最终的关联应该像下面这样。我给这个关联起名叫“asswecan”,意思是用这个关联我们能做到「音符名称到声音的转换」,记住这个名字,我们之后会用到。


那么要如何生成这个关联呢?首先我们需要生成声音,这里用到Play函数:


一个频率为440Hz的“中音A”的波形

根据Matlab代码中的音符信息「ScaleTable(),f0,t4,t8,t16」改变Play函数中的参数来发出不同的音调,替换的关系是这样的:


有了这个思路,就可以用StringReplace函数进行替换了。

2.输入一个声部的旋律

Matlab中的旋律代码有许多多余的字符,需要我们处理一下

i.输入Matlab代码中的旋律

cellonoteinfo =

"do1f do1f so0f so0f la0f%% la0f mi0f mi0f...fa0f%% fa0f do0f do0f fa0f \n

fa0f so0f so0f";

这里面有很多我们不希望得到的 ... %% 空格回车这样的字符,需要把他们去掉。

ii.定义去掉无用字符的函数

infotonote[info_] :=

StringPartition[StringJoin@StringCases[info, _?LetterQ | _?DigitQ],4];

iii.得到适用于Mathematica的旋律

In[1]:= cellonote = infotonote[cellonoteinfo]

Out[1]:= {"do1f", "do1f", "so0f", "so0f", "la0f", "la0f", "mi0f", "mi0f", \

"fa0f", "fa0f", "do0f", "do0f", "fa0f", "fa0f", "so0f", "so0f"}

这样我们就得到了旋律中的音符名称列表

3.用声音替换旋律中的音符名称

还记得那个"asswecan"吗?它可以把音符名称替换成声音。用“asswecan”关联完成对几段旋律的转换,并规定好他们开始弹奏的时间,比如vio1末尾的8就代表第一把小提琴在第8秒才开始弹奏。

cello = Sound[Flatten@Table[Replace[cellonote, notetosoundass, 1], 23], {0}];

vio1 = Sound[Replace[violinnote, notetosoundass, 1], {8}];

vio2 = Sound[Replace[violinnote, notetosoundass, 1], {16}];

vio3 = Sound[Replace[violinnote, notetosoundass, 1], {24}];

4.最后把他们组合起来

As we can see, 我们完成了!

你可以在B站听到这段旋律

你也可以前往Wolfram社区下载Matlab及Mathematica代码文件

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 要在计算机内播放或是处理音频文件,也就是要对声音文件进行数、模转换,这个过程同样由采样和量化构成,人耳所能听到的声...
    Viking_Den阅读 10,418评论 1 10
  • 无损压缩是在保证不损失源文件所有码率的前提下,将音频文件压缩的更小,也就是说这两种音频格式都能保证源文件码率的无损...
    风起云涌Hal阅读 8,449评论 1 3
  • 前言 说到视频,大家自己脑子里基本都会想起电影、电视剧、在线视频等等,也会想起一些视频格式 AVI、MP4、RMV...
    ForestSen阅读 23,524评论 10 203
  • 最近在折腾itunes音频处理(裁剪编辑,格式转换,波形绘制) 音频的一些概念 对每个音频文件有两部分:1是文件格...
    osbornZ阅读 2,232评论 1 5
  • 湖畔松间道,微风拂六出。 寒夜未央急展俏,一点北国素。 也拟争芳意,却压墙角竹。 闺楼佳人朝梳头,消失...
    茶诗阅读 203评论 0 0