问题描述
前几天在学习matlab的时候,发现了一篇用matlab演奏音乐的文章,不禁感叹matlab居然还能这么玩!于是我就学着用matlab演奏我最喜欢听的一首歌——周杰伦的《七里香》。最后成果我已经发到B站,链接为:用matlab演奏周杰伦的《七里香》。
matlab播放音乐的原理
matlab播放音乐是由sound(Y,fs,bits)函数完成的,该函数的3个参数代表输入信号、采样率、比特率。先说采样率fs的设置,人耳能够听到的声音范围是20~20000Hz。根据采样定理fs只需要大于40000即可。此处采样率的设置采用了MP3的标准,即fs=44.1k.再说输入信号Y,Y一般是一个正弦波,如A* sin(2* pi* w* t)。其中A控制着声音的大小,w控制着声音的高低,t的范围控制着声音的长短,所以理论上利用这个公式可以发出任何声音,只是不能控制音色和音质(音色音质很难用参数量化,我问了一下学语音的同学,这个东西跟音频谱重心,音频扩展度和音频谱平坦度有关系,这里不作讨论)。比特率采用默认值即可,该参数省略。
于是用下面的公式就可以播放出标准音la:(座机电话提示音就是la,可以用来调吉他)
fs=44100;
t=0: 1/fs: 0.5;
la = sin(2* pi* 440* t); (下文介绍440是怎么来的)
sound(la, fs)
下面介绍一下简单乐理:
看过柯南的同学都知道,音高和频率是指数的关系,它们满足下面的公式,其中p是音高,f是频率
f=440*2^((p-69)/12)
标准音la,即钢琴的A4键,定义为p=69。音高每上升一个半音,p加1。
如上图所示,从C4到B4分别对应着do re mi fa sol la xi,它们的p值分别为 60 62 64 65 67 69 71,注意中间有黑键,你也可以根据下表来查询某个音的频率。
Frequency in hertz (semitones above or below middle C) | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
Octave→ Note↓ |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
C | 16.352 (−48) | 32.703 (−36) | 65.406 (−24) | 130.81 (−12) | 261.63 (0) | 523.25 (+12) | 1046.5 (+24) | 2093.0 (+36) | 4186.0 (+48) | 8372.0 (+60) |
C♯/D♭ | 17.324 (−47) | 34.648 (−35) | 69.296 (−23) | 138.59 (−11) | 277.18 (+1) | 554.37 (+13) | 1108.7 (+25) | 2217.5 (+37) | 4434.9 (+49) | 8869.8 (+61) |
D | 18.354 (−46) | 36.708 (−34) | 73.416 (−22) | 146.83 (−10) | 293.66 (+2) | 587.33 (+14) | 1174.7 (+26) | 2349.3 (+38) | 4698.6 (+50) | 9397.3 (+62) |
D♯/E♭ | 19.445 (−45) | 38.891 (−33) | 77.782 (−21) | 155.56 (−9) | 311.13 (+3) | 622.25 (+15) | 1244.5 (+27) | 2489.0 (+39) | 4978.0 (+51) | 9956.1 (+63) |
E | 20.602 (−44) | 41.203 (−32) | 82.407 (−20) | 164.81 (−8) | 329.63 (+4) | 659.26 (+16) | 1318.5 (+28) | 2637.0 (+40) | 5274.0 (+52) | 10548 (+64) |
F | 21.827 (−43) | 43.654 (−31) | 87.307 (−19) | 174.61 (−7) | 349.23 (+5) | 698.46 (+17) | 1396.9 (+29) | 2793.8 (+41) | 5587.7 (+53) | 11175 (+65) |
F♯/G♭ | 23.125 (−42) | 46.249 (−30) | 92.499 (−18) | 185.00 (−6) | 369.99 (+6) | 739.99 (+18) | 1480.0 (+30) | 2960.0 (+42) | 5919.9 (+54) | 11840 (+66) |
G | 24.500 (−41) | 48.999 (−29) | 97.999 (−17) | 196.00 (−5) | 392.00 (+7) | 783.99 (+19) | 1568.0 (+31) | 3136.0 (+43) | 6271.9 (+55) | 12544 (+67) |
G♯/A♭ | 25.957 (−40) | 51.913 (−28) | 103.83 (−16) | 207.65 (−4) | 415.30 (+8) | 830.61 (+20) | 1661.2 (+32) | 3322.4 (+44) | 6644.9 (+56) | 13290 (+68) |
A | 27.500 (−39) | 55.000 (−27) | 110.00 (−15) | 220.00 (−3) | 440.00 (+9) | 880.00 (+21) | 1760.0 (+33) | 3520.0 (+45) | 7040.0 (+57) | 14080 (+69) |
A♯/B♭ | 29.135 (−38) | 58.270 (−26) | 116.54 (−14) | 233.08 (−2) | 466.16 (+10) | 932.33 (+22) | 1864.7 (+34) | 3729.3 (+46) | 7458.6 (+58) | 14917 (+70) |
B | 30.868 (−37) | 61.735 (−25) | 123.47 (−13) | 246.94 (−1) | 493.88 (+11) | 987.77 (+23) | 1975.5 (+35) | 3951.1 (+47) | 7902.1 (+59) | 15804 (+71) |
有了上面的基础,下面就可以用matlab创作歌曲了。
用matlab演奏的过程
目标音乐的简谱
首先需要搜索目标音乐的简谱。以本文创作的“七里香”为例,在“百度图片”上就能够找到相应的简谱。
对音符的定义
在这个过程中,需要对节拍稍作注意,最常见的像四分之一拍,八分之一拍,以及十六分之一拍。
以四分之一拍的do为例:
do1f= mod4.* cos(2* pi* ScaleTable(5)* f0* t4);
其中涉及节拍,音调以及频率。mod4,ScaleTable及t4的定义,可参见帖子最后的源码。
分享几点我在编程过程中绕的弯路:
像图中所示的这种情况,最初我也是分别做两个do音符数据输出,但是整体听下来的效果比较奇怪,也因为我在乐理基础上的欠缺。
最终,我处理的方式是,这两个个音符作为一个5/16拍的do输出,这样听起来的效果会相对连续些,不知道从音乐方面来看,这么处理的方式是否正确。
类似的情况,这幅图中的mi,可作为3/16拍的mi输出。
那么针对这些情况,需要在节拍以及时间间隔定义上,额外再定义5/16拍,3/16拍等情况的数据。
还有这种情况,两个不同的音符连成一个音节。如果分别用1/16拍的fa和1/8拍的mi输出的话,中间会有所停顿,听起来不够连贯。所以我直接用3/16拍的fa输出,这样听起来只是略微和原曲不同,而不会让人感觉不连贯。
乐谱的定义
在最基本的音符定义完之后,就可以着手通过音符来定义乐谱了。根据简谱依次用所定义的音符定义一个声音矩阵:
violin = [mi1e fa1e so1e mi1f fa1e so1e ti1e];
如果出现有和弦的情况,以同样的方式定义和弦的曲子,并与violin的声音矩阵做加法处理。
之后通过sound函数就能够听到整首歌的效果:
sound(s,fs);
同时,如果你想保存这首歌的话,可以通过audiowrite函数来实现:
audiowrite(‘Qilixiang.wav’,violin,fs)
另外,如果已经有一个音频文件想通过Matlab处理,可以通过audioread函数来读取该音频文件:
audioread(‘Qilixiang.wav’)
以上就是实现Matlab演奏歌曲的整个过程,接下来附上我的源代码,如果你有兴趣想用该代码实现别的歌曲的演奏,只需要将violin矩阵中的乐谱矩阵稍作修改,就能实现你所需的效果。
源代码:
fs = 44100;
dt = 1/fs;
T16 = 0.2;
t16 = [0:dt:T16];
[temp k] = size(t16);
t2 = linspace(0,8*T16,8*k);
t3 = linspace(0,7*T16,7*k);%7/16拍
t4_25=linspace(0,5*T16,5*k);%5/16拍
t4 = linspace(0,4*T16,4*k);
t6 = linspace(0,3*T16,3*k);%3/16拍
t8 = linspace(0,2*T16,2*k);
[temp i] = size(t4);
[temp j] = size(t8);
mod2 = sin(pi*t2/t2(end));
mod3= sin(pi*t3/t3(end));
mod4 = sin(pi*t4/t4(end))