注:由于钢琴世界文章无法上传音频,请有需要的读者自行复制代码运行。
实验内容
乐音的基本特征可用基波频率、谐波成分和包络波形三个方面来描述:
1)每个音调对应固定的基波频率。例如对于钢琴,琴键中央音调A 对应的频率值是440Hz,其他A 音是440Hz 的整数倍,如高八度A 音是880Hz,低八度A 音是220Hz。一个八度内频率被等间隔分为12 等分,相邻两音之间的频率倍率关系是2 ^(1/12) 倍,称为半音。
2)谐波成分及其强度的比例影响音色。不同乐器有不同的谐波分布。
3)包络波形与乐器的类型有关。
试查阅相关资料了解相关知识,用MATLAB 合成一小段音乐。
实验脚本
1. 国际标准音高与频率对照表(Scientific Pitch Notation)
八度*10行:0,1,2,3,4,5,6,7,8,9
音符*12列:C(do),C#/Db,D(re),D#/Eb,E(mi),F(fa),F#/Gb,G(so),G#/Ab,A(la),A#/Bb,B(si)
SCP=[...
16.352,17.324,18.354,19.446,20.602,21.827,...
23.125,24.500,25.957,27.501,29.136,30.868;...
32.704,34.649,36.709,38.892,41.204,43.655,...
46.250,49.001,51.914,55.001,58.272,61.737;...
65.408,69.297,73.418,77.784,82.409,87.309,...
92.501,98.001,103.829,110.003,116.544,123.474;...
130.816,138.595,146.836,155.567,164.818,174.618,...
185.002,196.002,207.657,220.005,233.087,246.947;...
261.632,277.189,293.672,311.135,329.636,349.237,...
370.003,392.005,415.315,440.010,466.175,493.895;...
523.264,554.379,587.344,622.269,659.271,698.473,...
740.007,784.010,830.629,880.021,932.350,987.790;...
1046.528,1108.758,1174.688,1244.538,1318.542,1396.947,...
1480.013,1568.019,1661.258,1760.042,1864.699,1975.580;...
2093.056,2217.515,2349.376,2489.076,2637.084,2793.893,...
2960.027,3136.039,3322.517,3520.084,3729.398,3951.160;...
4186.112,4435.031,4698.751,4978.153,5274.169,5587.787,...
5920.053,6272.077,6645.034,7040.168,7458.797,7902.319;...
8372.224,8870.062,9397.502,9956.306,10548.337,11175.573,...
11840.106,12544.155,13290.068,14080.335,14917.594,15804.639...
]; 钢琴88键:大字二/一组,大/小字组,小字一/二/三/四/五组;A0到C8,3+7*12+1=88
SCPT=SCP';
SCP_MAIN=SCP(:,[1,3,5,6,8,10,12]);
SCPT_MAIN=SCPT([1,3,5,6,8,10,12],:);
PIANO=SCPT(10:97);
PIANO_MAIN=SCPT_MAIN(6:57); 全局采样率设为8000
f=8000;2. 模拟钢琴的音色和音量衰减
1)真实钢琴的标准音(A4, 440Hz)
sample=audioread("49.mp3"); %所下载音频为双声道,采样率44100
sample=sample(:,1);
sample=sample/max(sample);
samplet=(1:length(sample))/44100;
clf;subplot(2,2,1);plot(samplet,sample);title("真实钢琴的时域波形");ylim([-1,1]);
samplel=length(samplet);
samplen=2^nextpow2(samplel);
sampley=fft(sample,samplen);
samplep=abs(sampley/samplel);
samplep=samplep/max(samplep);
samplep=samplep(1:ceil(samplen/2));
samplep(2:end-1)=samplep(2:end-1);
subplot(2,2,2);plot(0:(44100/samplen):(44100/2-44100/samplen),samplep);
title("真实钢琴的频域分量");xlim([0,4000]);
%sound(sample,44100);
pause(2);2)虚拟钢琴的标准音(A4, 440Hz)
依据真实钢琴的各级谐波比例,设置k值;根据网络资料的推荐及真实钢琴音效的时域波形,设置包络函数;通过sound函数试听,进一步调整上述两组参数,以最大程度还原真实钢琴的音效。 由此结果编写文末的mypiano函数。
testt=(1:3*f)/f;
testf=440.0100;
wave=sin(2*pi*testf*testt);
k=[1,0.20,0.15,0.15,0.10,0.10,0.01,0.05,0.01,0.01,0.003,0.003,0.002,0.002];
for i=2:14
wave=wave+k(i)*sin(2*pi*testf*i*testt);
end
wave=wave/max(wave); %幅值归一化
wave=wave.*(testt.^0.01.*exp(-3*testt)); %波形包络线
subplot(2,2,3);plot(testt,wave);ylim([-1,1]);title("虚拟钢琴的时域波形");
testl=length(testt);
testn=2^nextpow2(testl);
testy=fft(wave,testn);
testp=abs(testy/testl);
testp=testp/max(testp);
testp=testp(1:ceil(testn/2));
testp(2:end-1)=testp(2:end-1);
subplot(2,2,4);plot(0:(f/testn):(f/2-f/testn),testp);ylim([0,1]);
title("虚拟钢琴的频域分量");
%sound(wave,8000);
3. 创建一段简谱:《天空之城》节选
tune记录音调,其中升1,升2等用8,9来表示,以此类推;0.5代表休止符0,后续会用mod1方法筛选出休止符。
rhythm记录每个音调的持续时间,4/4拍下,以16分音符为1,全音符为16;延音符号的其起始位置,将其值加0.5,同样用mod1筛选。
tune=[...
6,7,8,7,8,10,7,3,3,6,5,6,8,5,0.5,3,3,4,3,4,8,...
3,0.5,8,8,8,7,4,4,7,7,0.5,6,7,8,7,8,10,7,0.5,3,3,6,5,6,8,...
5,0.5,3,4,8,7,7,8,9,9,10,8,0.5,8,7,6,6,7,5,6,0.5,8,9,10,9,10,12,...
9,0.5,5,5,8,7,8,10,10,0.5,0.5,6,7,8,7,9,9,8,5,5,0.5,11,10,9,8,...
10,10,0.5,10,13,12,12,10,9,8,0.5,8,9,8,9,9,12,10,0.5,10,...
13,12,10,9,8,0.5,8,9,8,9,9,7,6,0.5,6,7,6];
rhythm=[...
2.5,2,6.5,2,4,4,12,2,2,6.5,2,4,4,8,4,2,2,6.5,2,2.5,3,...
8,2,2,2,2,6.5,2,4.5,4,8,4,2.5,2,6.5,2,4,4,8,4,2,2,6.5,2,4,4,...
12,2,2,4,2.5,2.5,4,4,2,2,2,4,4,4.5,2,2,2,4,4,8,4,2,2,6.5,2,4,4,...
8,4,2,2,2.5,2,4,4,8,4,4,2.5,2,4,4,2,2,6.5,2.5,4,4,4,4,4,4,...
16.5,8,4,4,8,4,4,2,2,4,2,2,4,2.5,2.5,2,4,8,4,4,...
8,8,2.5,2,8,2,2,2,2,2.5,2,4,8,4,2.5,2,16];
D_L=0+7*4; %此曲为D大调
ftune=tune; %音调转化为频率
for i=1:length(ftune)
if mod(tune(i),1)==0
ftune(i)=SCPT_MAIN(D_L+ftune(i));
else
ftune(i)=0;
end
end
l=sum(rhythm);
speed=100; %曲速(每分钟speed拍)
t0=60/speed/4; %16分音符占t0秒
music=zeros(1,f*l*t0+5*f-1);
position=1;
n=1:length(music);
t=n/f;4. 合成钢琴曲
对简谱的解释不完全同于音乐理论,各种分类方法及参数配置由听感决定。
for i=1:length(ftune)
if mod(tune(i),1)~=0 %休止符:音量同步衰减一半
music(position:position+3*f-1)=...
music(position:position+3*f-1)*0.5;
elseif mod(rhythm(i),1)~=0 %延音符号开始:a=0.01,b=2,衰减变慢
music(position:position+3*f-1)=...
music(position:position+3*f-1)+0.8*mypiano(8000,ftune(i),0.01,2);
elseif i~=0 && mod(rhythm(i-1),1)~=0 %延音符号之中:a=0.05,b=3,开始变慢
music(position:position+3*f-1)=...
music(position:position+3*f-1)+0.4*mypiano(8000,ftune(i),0.05,3);
elseif rhythm(i)>=8 %较长音符(此为全音符),a=0.01,b=1.5,衰减变慢
music(position:position+3*f-1)=...
music(position:position+3*f-1)+mypiano(8000,ftune(i),0.01,1.5);
else
music(position:position+3*f-1)=...
music(position:position+3*f-1)+mypiano(8000,ftune(i),0.01,3);
end
position=position+rhythm(i)*t0*f+1;
end
music=0.75*music/max(music); %音量调节
clf;plot(t,music);title("天空之城");
%sound(music);
audiowrite("天空之城.wav",music,8000);
实验结果与讨论
上文已经详细给出了用以实现钢琴音并演奏曲目《天空之城》的代码,在此做以如下说明:
1)将sound函数的注释取消掉,即可通过试听来实时调整参数k,a,b,这也就是在实验进行中需要做的;
2)代码中通过audioread函数读取了“49.mp3”,此为互联网上下载的钢琴A4标准音音效,用来调整k,a,b等参数;
3)代码最后用audiowrite输出了“天空之城.wav”文件,此为用代码实现演奏的钢琴曲《天空之城》片段。
通过上述MATLAB代码演奏的钢琴曲,对真实钢琴有着较高的还原度。但音色不如真实钢琴清脆饱满,且受限于作者的乐理知识,忽略了乐谱中的复杂成分,故而连贯性和可欣赏性欠佳。真实的钢琴具有更加复杂多样的泛音特征,不同钢琴的音色也不尽相同,真实地还原钢琴音色需要及其复杂的数据作为支撑。
通过本文给出的代码,只要以同样的方式重新条件k,a,b,即可实现小提琴、吉他、二胡等其他乐器音色的模拟,理论上任何乐器,甚至人声,都可以通过相同方式、不同参数模拟出来。若想对此进行验证,可仅仅将a值改为0.5左右,其他保持不变,就可以得到类似管乐器或是弦乐器的声音。
函数mypiano
根据1中的调试结果,构建用以生成单个钢琴音的函数mypiano;
参数a主要作用于开始阶段,a越小,琴音出现越陡峭,听感越清脆;a越大,开始的波形越圆滑,听感向管乐器和弦乐器靠近;
参数b主要起衰减作用,b越大,衰减越快,反之衰减越慢。
此外,为了方便,为每个音调配置了相同的泛音比例,而这与实际情况是不同的。真实的钢琴每个音的泛音比例是有差异的。
function wave=mypiano(f,ftune,a,b) %f:采样频率;ftune:基音频率;a:包络参数1;b:包络参数2.
t=(1:3*f)/f;
wave=sin(2*pi*ftune*t);
k=[1,0.20,0.15,0.15,0.10,0.10,0.01,0.05,0.01,0.01,0.003,0.003,0.002,0.002];
for i=2:14
wave=wave+k(i)*sin(2*pi*ftune*i*t);
end
wave=wave/max(wave);
wave=wave.*(t.^a.*exp(-b*t));
end
附录:国际标准音高与频率对照表和音乐简谱可自行在网络上搜索。
声明:作者并非相关行业从业人员,文中代码和结果均为原创,如有错误敬请批评指正。 |