用Mma给吉他调音

前几日网购一入门吉他,玩了几天后,音便不准了。于是又买了个电子调音器,确实好用,但却花掉20来块钱。日后,用Mma写了段调音的代码,在此与大家分享,为您省下这几十元。

一、乐理

初中物理中就已经指出,音调的高低与发声物体的振动频率有关,频率越高音调越高。下面简单介绍下十二平均律 将八度分成12个相等的部分(半音)的音律叫作十二平均律,它们构成了7个基本音级,详见下表:

音级 频率(Hz) 唱名简谱 公式
C4 261.626 1 $440\times {{2}^{-9/12}}$
C4♯ 277.183 1# $440\times {{2}^{-8/12}}$
D4 293.665 2 $440\times {{2}^{-7/12}}$
D4♯ 311.127 2# $440\times {{2}^{-6/12}}$
E4 329.628 3 $440\times {{2}^{-5/12}}$
F4 349.228 4 $440\times {{2}^{-4/12}}$
F4♯ 369.994 4# $440\times {{2}^{-3/12}}$
G4 391.995 5 $440\times {{2}^{-2/12}}$
G4♯ 415.305 5# $440\times {{2}^{-1/12}}$
A4 440 6 $440\times {{2}^{0}}$
A4♯ 466.164 6# $440\times {{2}^{1/12}}$
B4 493.883 7 $440\times {{2}^{2/12}}$

然而仅仅这12个音级还远远不够,于是,在音级后用数字加以区分。表达方法主要有两种,分别是:科学记音法亥姆霍兹记音法,对照如下:

科学记音法 亥姆霍兹记音法 频率 (Hz) 频率计算 (Hz)
A9 a””” 14080 $440\times {{2}^{5}}$
A8 a””’ 7040 $440\times {{2}^{4}}$
A7 a”” 3520 $440\times {{2}^{3}}$
A6 a”’ 1760 $440\times {{2}^{2}}$
A5 a” 880 $440\times {{2}^{1}}$
A4 a′ 440 $440\times {{2}^{0}}$
A3 a 220 $440\times {{2}^{-1}}$
A2 A 110 $440\times {{2}^{-2}}$
A1 A͵或͵A 55 $440\times {{2}^{-3}}$
A0 A͵͵或͵͵A 27.5 $440\times {{2}^{-4}}$
A−1 A͵͵͵或͵͵͵A 13.75 $440\times {{2}^{-5}}$
吉他六根弦的音级与频率如下表所示:

1 吉他各弦音级与频谱

6弦 5弦 4弦 3弦 2弦 1弦
E2 A2 D3 G3 B3 E4
82.407 110.000 146.832 195.998 246.942 329.628
-29/12 -24/12 -19/12 -14/12 -10/12 -5/12

最后一行为下面表达式的指数部分:$440\times {{2}^{n}}$

吉他与钢琴音级对比如下:

Guitar and Piano

二、泛音

纯音:仅有单一频率的声音。 泛音:有多种频率的声音,且每种频率都是其最小频率的整数倍。泛音中频率最小的频率称为基频(即我们确定音调的频率),对应的声音称为基音,其它的都称为泛音(可依次命名为:一泛音,二泛音,…)。 泛音是影响音色的主要因素,从泛音的比例大致可以推出声音来自何种乐器,或通过泛音来合成电子乐器。在自然界中,几乎所有的声音都不是纯音,因此我们可以区分不同的发音器具。纯音可以通过音叉和软件方式产生。 泛音的产生原理,可以通过弦在振动时产生的驻波现象理解。 由于泛音的存在,给我们识别基频带来的难度,不过这也提供了一种验证方式——去掉基频及其泛音时,频谱能量骤减,但将基频的一半或三分一、四分之一等作为假定基频时,也有会使频谱能量骤减。因此我们要找最大的那个假定基步作为真正的基频。

三、用Mma为吉他调音

★ 函数介绍

  • Fourier:离散傅里叶变换。
  • FindClusters:聚类。
  • Ordering:返回列表的顺序。
  • SystemDialogInput[“RecordSound”]:打开系统录音工具,捕获音频。
  • SystemDialogInput[“FileOpen”]:选择文件路径。
  • 对于WAV文件支持导入的元素:Audio, AudioChannels, AudioEncoding, AudioFile, Data, Duration, Length, MetaInformation, SampleDepth, SampledSoundList, SampleRate, Sound。

★ 分步处理过程

1、定义常量

pinlv=Reverse[440.0 2^(#/12)&/@{-29,-24,-19,-14,-10,-5}];(*吉他六根弦的频率*)
names=Reverse[{“音级:E2(6弦)”,”音级:A2(5弦)”,”音级:D3(4弦)”,”音级:G3(3弦)”,”音级:B3(2弦)”,”音级:E4(1弦)”}];(*吉他六根弦的名称*)
guitar=Thread[pinlv->names];

2、导入数据

path = SystemDialogInput[“FileOpen”];(* 指定文件路径 *)
audioData = Import[path, “Data”];(* 导入数据 *)
(*au=SystemDialogInput[“RecordSound”];*)(* 通过麦克风采集数据,请选择单声道:mono *)
audioDuration = Import[path, “Duration”];(* 录音时长 *)
(*audioSampleRate=Import[path,”SampleRate”];*)(* 采样率 *)
audioLength = Import[path, “Length”];(* 采样点数 *)

3、傅里叶变换

audioFrequency = Abs[Fourier[audioData]];(*傅里叶变换,频域信息*)
audioFrequency=audioFrequency[[;;Floor[audioLength/2]]](*由于傅里叶变换对称,仅取一半,实际可以取得更少*);
boundary=Mean[audioFrequency]+5StandardDeviation[audioFrequency];(*阈值,用于提到特征信息时使用*)
dataForAnalysis=Flatten[Position[audioFrequency,x_/;x>boundary]];(*过滤噪音,根据上面的阈值提取位置*)
dataForAnalysis={(#-1)/audioDuration,audioFrequency[[#]]}&/@dataForAnalysis;(* n 行 2 列的数据:真实频率频率(减1后除以时长),频率对应的能量*)
dataForAnalysis=Select[dataForAnalysis,#[[1]]>10&];(*舍弃小于等于10的频率*)
ListLinePlot[dataForAnalysis,PlotRange->{{0,All},All},Mesh->All,ImageSize->500](* 绘图:频率,能量*)

4、处理泛音,识别基音

overtone=FindClusters[dataForAnalysis[[;;,1]],Method->”NeighborhoodContraction”];(*聚类,每类为一个泛音*)
overtone=Flatten[Table[If[Length[overtone[[k]]]>1&&StandardDeviation[overtone[[k]]]>3,
FindClusters[overtone[[k]],Method->”NeighborhoodContraction”],
{overtone[[k]]}
],{k,Length[overtone]}],1];(*拆分较大的类*)
fundamentalFrequency=Mean[SortBy[overtone,Mean][[1]]];(*泛音最小的那一类,既为基音频率*)

5、输出表格

generateOvertone=fundamentalFrequency Range[20];(*根据基音频率生成泛音*)
diff=Min[(#-generateOvertone)^2]&/@dataForAnalysis[[;;,1]];(*误差的平方*)
mse=Mean[diff];(*均方误差*)
string=First[Nearest[guitar,fundamentalFrequency]];(*对应于哪根弦*)
error=fundamentalFrequency-First[Nearest[pinlv,fundamentalFrequency]];(*与应对的弦的误差*)
Grid[Prepend[{
{“基音频率”,Row[{fundamentalFrequency,”Hz”}]},
{“最可能的弦”,string},
{“误差”,Row[{error,”Hz”}]},
{“建议”,If[error>0,”如果您在调”<>StringTake[string,{-3,-2}]<>”,请调低些”,”如果您在调”<>StringTake[string,{-3,-2}]<>”,请调高些”]},
{“均方误差”,mse}},{“名称”,”值”}],
Background->{None,{Lighter[Yellow,.9],{White,Lighter[Blend[{Blue,Green}],.8]}}},Dividers->{{Darker[Gray,.6],{Lighter[Gray,.5]},Darker[Gray,.6]},{Darker[Gray,.6],Darker[Gray,.6],{False},Darker[Gray,.6]}},
Alignment->{{Center,Center,{Left}}},
ItemSize->{{10,15}},
Frame->Darker[Gray,.6],
ItemStyle->14,
Spacings->{Automatic,.8}]

 

★ 全部代码与输出结果

★ 查看可复制的代码>>

★ 下载测试文件

我录制的吉他6根弦的音频文件Mathematica 文件

百度网盘:链接:http://pan.baidu.com/s/1i53LbzZ  密码:lr1f


更新日期:2017-05-13

About the Author

野鹤

自由学者,爱好广泛,虽无一精通,却常乐在其中...

本博客已停止更新,请您移步到我的新博客阅读更多文章。