MATLAB 编写简易电子琴


用MATLAB遍了一个小程序,可以弹奏一些简单的曲子。演示视频:
Bilbili视频:MATLAB 编写简易电子琴
一个电子琴基本的要求应当是能按键盘命令发出特定音高和音色的声音。键盘命令我用的是input 函数,缺点是每按一个键要回车使得弹奏很难连续,但目前没想到合适的替代方法;而声音的音高和音色则分别基频和泛频决定

声音模型

声音本质是机械振动产生的波通过介质传播至人耳,这一振动可由函数 x ( t ) x(t) x(t)表示,离散化后即为向量 x n x_n xn以及采样率 f s f_s fs,且满足 x n = x ( t n ) , t n = n / f s x_n=x(t_n), t_n=n/f_s xn=x(tn),tn=n/fs.
而MATLAB 中可用sound(x,fs)函数发出一段声音,如下面的代码运行后将发出一段白噪声:

 x=normrnd(0,1,1,10000);
 fs=5000;
 sound(x,fs)

琴弦则近似以如下方式振动(数学物理方法等教材有介绍):
x ( t ) = ∑ n = 1 N A n s i n ( 2 π f n t + ϕ n ) x(t)=\sum_{n=1}^{N}A_nsin(2\pi f_nt+\phi_n) x(t)=n=1NAnsin(2πfnt+ϕn)
其中基频 f 1 f_1 f1 决定声音的音高, f n , n > 1 f_n, n>1 fn,n>1决定音色。基频与音阶的部分对应表如下(没有加升降音):
E4 329.63
F4 349.23
G4 392
A4 440
B4 493.88
C5 523.25
D5 587.33
E5 659.25
F5 698.46
G5 783.99
A5 880
B5 987.77
C6 1046.5
D6 1174.66
E6 1318.51
F6 1396.91
G6 1567.98
A6 1760
B6 1975.53

于是,在MATLAB中发出A4音的代码如下:

fs=5000;
t=0:1/fs:1;
f=440;
x=sin(2*pi*f*t);
sound(x,fs)

音色

除基频 f 1 f_1 f1外,还有由高阶模式振动产生的倍频,各本征频频的振幅 A n A_n An以及相位 ϕ n \phi_n ϕn确定了声音的音色,简单起见,假定 ϕ 0 = 0 \phi_0=0 ϕ0=0。并加入一个衰减:
x ( t ) = e − t 2 / 2 t 0 2 ∑ n = 1 N A n s i n ( 2 π f n t ) x(t)=e^{-t^2/2t_0^2}\sum_{n=1}^{N}A_nsin(2\pi f_nt) x(t)=et2/2t02n=1NAnsin(2πfnt)
从网上找到一段任意音高的钢琴音,傅里叶变换后频谱如下:
记录下前八个本征频率对应的振幅 A n A_n An如下:
645.4
183.7
30
20
20
20
20
56

简易电子琴

编写函数piano(f,amp),其中f 为基频,amp为最低的数个本征频率对应的振幅,其中f通过查找键盘输入的音阶对应的频率得到。再循环运行此函数即可
代码如下:

Amp=xlsread('Amp.xlsx');
Amp=1/max(Amp)*Amp;
n=length(Amp);

f=xlsread('frequency.xlsx','B:B');
%To input "exit" to exit
IN=0;
or=1;
while 1
   IN=input('','s');
   switch IN
       case 's'
           or=1;
       case 'a'
           or=0;
       case 'd'
           or=2;
       case '1'
           piano(f(or*7+1),Amp);
       case '2'
           piano(f(or*7+2),Amp);
       case '3'
           piano(f(or*7+3),Amp);
       case '4'
           piano(f(or*7+4),Amp);
       case '5'
           piano(f(or*7+5),Amp);
       case '6'
           piano(f(or*7+6),Amp);
       case '7'
           piano(f(or*7+7),Amp); 
       case 'exit'
           break
       otherwise
           disp('Again');
   end
end

function p=piano(f,amp)
fs=32000;
t=0:1/fs:1;
x=0*t;
n=length(amp);
for i=1:n
   x=x+amp(i)*sin(2*pi*f*i*t); 
end
x=x.*exp(-1/(2*0.3^2)*t.^2);
sound(x,fs)
p=1;
end

这一电子琴小程序是写着玩的,非常简陋,一个较大的问题就是弹奏很难连续。如果有改进建议欢迎留言

猜你喜欢

转载自blog.csdn.net/certate/article/details/113736573
今日推荐