一、原理
我们都知道声音其实是一种波,所以要使用Matlab生成一段音乐其重点就是生成该声音的波。首先我们来看最基本的波是怎么使用Matlab画出来的。使用Matlab画出最简单的正弦波。
| 12
 3
 4
 5
 
 | x = linspace(0, 2*pi, 100);
 y = sin(x);
 
 plot(x, y)
 
 | 

可以看到,该波的波形十分的平滑,这是因为我们在x = linspace(0, 2*pi, 100)中选择取100个点。其中点的个数100在一段完整的声音中,叫做采样率(在一秒钟的声音中,一共取了多少个点)。在Matlab中默认的采样率是8192,采样范围是1000Hz≤FS≤384000Hz,也就是说采样率必须在此范围内,Matlab才能播放声音。
| 12
 3
 4
 5
 6
 
 | % 默认采样率Fs = 8192;
 x = linspace(0, 2*pi, Fs);
 y = sin(x);
 plot(x, y);
 title('采样率为8192Hz')
 
 | 

该代码表示播放一个周期的声音,之后我们使用sound()函数,播放其声音。戴上耳机,仔细听会有两声哼响。(据说这应该听不到,是次声波来着,但我确实听到了/(ㄒoㄒ)/~~)
| 12
 3
 4
 5
 6
 7
 
 | % 默认采样率Fs = 8192;
 x = linspace(0, 2*pi, Fs);
 y = sin(x);
 plot(x, y);
 title('采样率为8192Hz')
 sound(y, Fs);
 
 | 
我们根据乐理知识,有一个标准音高A=440,所以我们改变代码使其发出标准音高声。可以看到这时候的周期特别的多。
| 12
 3
 4
 5
 6
 7
 
 | Fs = 8192;
 x = linspace(0, 2*pi, Fs);
 y = sin(440*x);
 plot(x, y);
 title('采样率为8192Hz')
 sound(y, Fs);
 
 | 

二、探究音高的影响因素
上述,我们已经成功使用Matlab发声,那么影响音高的因素有哪些呢?我们从两个因素考虑:一个是声音的采样率,另一个是声音的频率。使用控制变量法研究以上两个因素。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | % 影响音高的因素% 控制声音频率不变,只改变采样率
 Fs1 = 8192;
 Fs2 = 20000;
 
 x1 = linspace(0, 2*pi, Fs1);
 x2 = linspace(0, 2*pi, Fs2);
 y1 = sin(440 * x1);
 y2 = sin(440 * x2);
 
 sound(y1, Fs1);
 %请先听完第一个声音再打开y2的注释,并注释y1。
 %sound(y2, Fs2);
 
 | 
经过测试,两个声音没有任何区别,如此可以说明,声音的采样率不会对音高产生影响。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | 
 Fz = 8192;
 x = linspace(0, 2 * pi, Fz);
 y1 = sin(440 * x);
 y2 = sin(880 * x);
 
 sound(y1, Fz);
 
 
 
 | 
经过测试,y2的音高较y1有明显提高,综上所述,影响声音音高的只有频率因素。
三、十二平均律
已知声音的音高只与其频率有关,那么如何才能通过调节频率产生一段优美的音乐呢?下面是来自wiki上的十二平均律表,该表计算的是一个八度的频率表,对于一个八度里的声音我们将其分成12份,这里采用以440Hz为主音乘以212x,依次得到下个一个音。会发现从440-880正好跨越一个八度。
下面的十二平均律表最左侧音程名称中带有#1的表示升,带有b1的表示降。不带升号和降号的可以看作是钢琴的白键,带升号和降号的可以看作是钢琴的黑键。这张表我们不需要全部记下来,我们只需要从小三度(C)开始记即可(跳过黑键#),因为C就是八度中的第一个dou音。

| 12
 3
 4
 5
 6
 7
 8
 
 | 常用频率C: 523.2511
 D: 587.3295
 E: 659.2551
 F: 698.4564
 G: 783.9908
 A: 880
 B: 987.7666
 
 | 
如此我们就可以得到一个八度了
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | Fz = 8192;
 x = linspace(0, 2 * pi, Fz);
 freqs = [523.2511, 587.3295, 659.2551, 698.4564, 783.9908, 880, 987.7666];
 y1 = sin(freqs(1) * x);
 y2 = sin(freqs(2) * x);
 y3 = sin(freqs(3) * x);
 y4 = sin(freqs(4) * x);
 y5 = sin(freqs(5) * x);
 y6 = sin(freqs(6) * x);
 y7 = sin(freqs(7) * x);
 y = [y1, y2, y3, y4, y5, y6, y7]
 sound(y, Fz);
 
 | 
四、小星星
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | Fs = 8192;x = linspace(0, 2 * pi, Fs);
 
 freqs = [523.2511, 587.3295, 659.2551, 698.4564, 783.9908, 880, 987.7666];
 y1 = sin(freqs(1) * x);
 y2 = sin(freqs(1) * x);
 y3 = sin(freqs(5) * x);
 y4 = sin(freqs(5) * x);
 y5 = sin(freqs(6) * x);
 y6 = sin(freqs(6) * x);
 y7 = sin(freqs(5) * x);
 y8 = sin(freqs(5) * x);
 
 y = [y1, y2, y3, y4, y5, y6, y7, y8];
 sound(y, Fs);
 
 | 
播放完成后会发现,声音的间隔不是很清楚,我们先看一下y的波形。

如何解决这一问题呢?我们可以通过压缩正弦波解决
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | % 解决声音连在一起的现象Fz = 8192;
 x1 = linspace(0, 2*pi, 8192);
 y1 = sin(x1);
 
 x2 = [0 2 * pi];
 y2 = [1, 0];
 
 
 subplot(1, 2, 1)
 plot(x1, y1);
 
 subplot(1, 2, 2)
 plot(x2, y2); % y = 1- x / (2*pi)
 
 | 

我们对以上小星星的程序进行改写所有正弦波都乘以1−2πx
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | Fs = 8192;x = linspace(0, 2 * pi, Fs);
 x2 =linspace(0, 2 * pi * 2, Fs * 2);
 freqs = [523.2511, 587.3295, 659.2551, 698.4564, 783.9908, 880, 987.7666];
 y1 = sin(freqs(1) * x) .* (1 - x / ( 2 * pi));
 y2 = sin(freqs(1) * x) .* (1 - x / ( 2 * pi));
 y3 = sin(freqs(5) * x) .* (1 - x / ( 2 * pi));
 y4 = sin(freqs(5) * x) .* (1 - x / ( 2 * pi));
 y5 = sin(freqs(6) * x) .* (1 - x / ( 2 * pi));
 y6 = sin(freqs(6) * x) .* (1 - x / ( 2 * pi));
 y7 = sin(freqs(5) * x2);
 
 y = [y1, y2, y3, y4, y5, y6, y7];
 plot(y);
 sound(y, Fs);
 
 | 

最后一个音听着有些不合群
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | Fs = 8192;x = linspace(0, 2 * pi, Fs);
 x2 =linspace(0, 2 * pi * 2, Fs * 2);
 freqs = [523.2511, 587.3295, 659.2551, 698.4564, 783.9908, 880, 987.7666];
 y1 = sin(freqs(1) * x) .* (1 - x / ( 2 * pi));
 y2 = sin(freqs(1) * x) .* (1 - x / ( 2 * pi));
 y3 = sin(freqs(5) * x) .* (1 - x / ( 2 * pi));
 y4 = sin(freqs(5) * x) .* (1 - x / ( 2 * pi));
 y5 = sin(freqs(6) * x) .* (1 - x / ( 2 * pi));
 y6 = sin(freqs(6) * x) .* (1 - x / ( 2 * pi));
 y7 = sin(freqs(5) * x2) .* (1 - x2 / ( 4 * pi));
 
 y = [y1, y2, y3, y4, y5, y6, y7];
 plot(y);
 
 
 | 

五、封装函数
为了简便我们以后完成更长的音乐,可以选择将主要部分封装成函数以便调用。
| 12
 3
 4
 5
 6
 7
 8
 
 | function y = music(tone, rythm)
 
 Fs = 8192;
 freqs = [523.2511, 587.3295, 659.2551, 698.4564, 783.9908, 880, 987.7666];
 x = linspace(0, 2 * pi *rythm, floor(Fs * rythm));
 y = sin(freqs(tone) * x) .* (1 - x / (rythm * 2 * pi));
 end
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | Fs = 8192;
 y1 = music(1, 0.5);
 y2 = music(1, 0.5);
 y3 = music(5, 0.5);
 y4 = music(5, 0.5);
 y5 = music(6, 0.5);
 y6 = music(6, 0.5);
 y7 = music(5, 1);
 y = [y1, y2, y3, y4, y5, y6, y7];
 
 y1 = music(4, 0.5);
 y2 = music(4, 0.5);
 y3 = music(3, 0.5);
 y4 = music(3, 0.5);
 y5 = music(2, 0.5);
 y6 = music(2, 0.5);
 y7 = music(1, 1);
 y = [y, y1, y2, y3, y4, y5, y6, y7];
 sound(y, Fs)
 
 |