matlab卡农,又用Mathematica写了一段卡农

你能在这里听到它

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

87d9f2f8e684

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

手动输入乐谱——失败

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

87d9f2f8e684

从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),乘上他之后可以让波形变得更柔和,有渐入渐出的效果。

87d9f2f8e684

未经mod修正过的波形

87d9f2f8e684

经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”,意思是用这个关联我们能做到「音符名称到声音的转换」,记住这个名字,我们之后会用到。

87d9f2f8e684

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

87d9f2f8e684

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

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

87d9f2f8e684

有了这个思路,就可以用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.最后把他们组合起来

87d9f2f8e684

As we can see, 我们完成了!

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值